組織作成ブロック
CreateOrganization は MUI ベースの制御型組織申請フォームです。
インストール
- npm
- yarn
- pnpm
- bun
npm install @nodeblocks/frontend-create-organization-block
yarn add @nodeblocks/frontend-create-organization-block
pnpm add @nodeblocks/frontend-create-organization-block
bun add @nodeblocks/frontend-create-organization-block
必要なもの
| 項目 | 理由 |
|---|---|
data | フォーム状態の単一の信頼源。構造は establishmentDate のようなカスタムフィールドで拡張できます |
onDataChange | 検証、分析、または副作用のための更新済み状態とメタデータを受け取ります |
errors (optional) | データパスをキーにしたフィールドエラー |
termsOfUseUrl (optional) | コンプライアンスセクションの利用規約リンク先 URL |
privacyAgreementUrl (optional) | コンプライアンスセクションのプライバシーポリシーリンク先 URL |
onSearchAddressClick (optional) | CompanyAddress.PostCode の郵便番号検索ボタンを処理します |
CreateOrganization はフォーム状態を保持しません。状態はアプリ側で管理し、data を通して渡してください。デフォルトのフォームデータには、アカウント保持者フィールド、会社詳細、コンプライアンスチェックボックスが含まれ、establishmentDate のようなカスタムフィールドにも拡張できます。
コード例
- クイックスタート
- ラベルと URL
- フォームエラー
- コンパウンドコンポーネント
- ブロックオーバーライド
function Example() { const defaultData = { applicationUserName: '', applicationUserEmail: '', applicationUserPhoneNumber: '', companyName: '', postcode: '', cityTownVillage: '', townStreetBuilding: '', representivePersonName: '', representativePhoneNumber: '', companyUrl: '', additionalInformation: '', establishmentDate: '', prefecture: '', capital: '', numberOfEmployees: '', userAgreement: '', privacyPolicy: '', }; const [data, setData] = React.useState(defaultData); return ( <CreateOrganization data={data} onDataChange={setData} termsOfUseUrl="/terms-of-use" privacyAgreementUrl="/privacy-policy" onSearchAddressClick={() => { setData((current) => ({ ...current })); }} onSubmit={(event) => { event.preventDefault(); setData((current) => ({ ...current })); }} /> ); }
function Example() { const defaultData = { applicationUserName: '', applicationUserEmail: '', applicationUserPhoneNumber: '', companyName: '', postcode: '', cityTownVillage: '', townStreetBuilding: '', representivePersonName: '', representativePhoneNumber: '', companyUrl: '', additionalInformation: '', establishmentDate: '', prefecture: '', capital: '', numberOfEmployees: '', userAgreement: '', privacyPolicy: '', }; const [data, setData] = React.useState(defaultData); return ( <CreateOrganization data={data} onDataChange={setData} termsOfUseUrl="/terms-of-use" privacyAgreementUrl="/privacy-policy" onSearchAddressClick={() => { setData((current) => ({ ...current })); }} onSubmit={(event) => { event.preventDefault(); setData((current) => ({ ...current })); }} > <CreateOrganization.Title>Apply for your organization</CreateOrganization.Title> <CreateOrganization.Description>Please fill out the form below to register your organization.</CreateOrganization.Description> <CreateOrganization.Form> <CreateOrganization.Form.AccountHolder> <CreateOrganization.Form.AccountHolder.SectionTitle>Account holder</CreateOrganization.Form.AccountHolder.SectionTitle> <CreateOrganization.Form.AccountHolder.Name label="Full name" placeholder="Enter your full name" /> <CreateOrganization.Form.AccountHolder.Email label="Email address" placeholder="Enter your email address" /> <CreateOrganization.Form.AccountHolder.Contact label="Phone number" placeholder="Enter your phone number" /> </CreateOrganization.Form.AccountHolder> <CreateOrganization.Form.CompanyInformation> <CreateOrganization.Form.CompanyInformation.SectionTitle>Company details</CreateOrganization.Form.CompanyInformation.SectionTitle> <CreateOrganization.Form.CompanyInformation.CompanyName label="Company name" placeholder="Enter the company name" /> <CreateOrganization.Form.CompanyInformation.CompanyAddress> <CreateOrganization.Form.CompanyInformation.CompanyAddress.LocationTitle>Head office location</CreateOrganization.Form.CompanyInformation.CompanyAddress.LocationTitle> <CreateOrganization.Form.CompanyInformation.CompanyAddress.PostCode searchAddressLabel="Find address" /> <CreateOrganization.Form.CompanyInformation.CompanyAddress.Prefecture label="Prefecture" placeholder="Select a prefecture" /> <CreateOrganization.Form.CompanyInformation.CompanyAddress.City label="City / Town / Village" placeholder="Enter the city" /> <CreateOrganization.Form.CompanyInformation.CompanyAddress.TownAddress label="Street address" placeholder="Enter the street address" /> <CreateOrganization.Form.CompanyInformation.CompanyAddress.RepresentativePersonName label="Representative name" placeholder="Enter the representative name" /> <CreateOrganization.Form.CompanyInformation.CompanyAddress.RepresentativeContact label="Representative phone number" placeholder="Enter the representative phone number" /> </CreateOrganization.Form.CompanyInformation.CompanyAddress> <CreateOrganization.Form.CompanyInformation.CompanyCapital label="Capital" placeholder="Enter the capital" /> <CreateOrganization.Form.CompanyInformation.CompanySize label="Number of employees" placeholder="Enter the employee count" /> <CreateOrganization.Form.CompanyInformation.HomePageUrl label="Website" placeholder="Enter the website URL" /> <CreateOrganization.Form.CompanyInformation.AdditionalInformation label="Additional information" placeholder="Enter any extra details" /> </CreateOrganization.Form.CompanyInformation> <CreateOrganization.Form.Compliance> <CreateOrganization.Form.Compliance.CheckUserAgreement termsOfUseUrl="/terms-of-use" /> <CreateOrganization.Form.Compliance.CheckPrivacyAgreement privacyAgreementUrl="/privacy-policy" /> </CreateOrganization.Form.Compliance> <CreateOrganization.Form.SubmitButton>Create organization</CreateOrganization.Form.SubmitButton> </CreateOrganization.Form> </CreateOrganization> ); }
labels はありませんこのブロックにはルートの labels prop はありません。代わりに、入れ子の各要素で文言を上書きしてください: Title, Description, Form.AccountHolder.*, Form.CompanyInformation.*, Form.CompanyInformation.CompanyAddress.*, Form.Compliance.*, Form.SubmitButton, CompanyAddress.PostCode.searchAddressLabel。
function Example() { const defaultData = { applicationUserName: '', applicationUserEmail: '', applicationUserPhoneNumber: '', companyName: '', postcode: '', cityTownVillage: '', townStreetBuilding: '', representivePersonName: '', representativePhoneNumber: '', companyUrl: '', additionalInformation: '', establishmentDate: '', prefecture: '', capital: '', numberOfEmployees: '', userAgreement: '', privacyPolicy: '', }; const [data, setData] = React.useState(defaultData); const [errors, setErrors] = React.useState({}); const handleDataChange = (nextData, meta) => { const { [meta.name]: _removed, ...restErrors } = errors; const nextErrors = { ...restErrors }; // Validate required fields on blur (same pattern as storybook) if (meta.cause === 'blur') { const value = nextData[meta.name]; if (value === '' || value == null || (typeof value === 'string' && !value.trim())) { nextErrors[meta.name] = 'This field is required.'; } } setErrors(nextErrors); setData(nextData); }; return ( <CreateOrganization data={data} errors={Object.keys(errors).length ? errors : undefined} onDataChange={handleDataChange} termsOfUseUrl="/terms-of-use" privacyAgreementUrl="/privacy-policy" onSearchAddressClick={() => { setData((current) => ({ ...current })); }} onSubmit={(event) => { event.preventDefault(); setData((current) => ({ ...current })); }} /> ); }
function Example() { const defaultData = { applicationUserName: '', applicationUserEmail: '', applicationUserPhoneNumber: '', companyName: '', postcode: '', cityTownVillage: '', townStreetBuilding: '', representivePersonName: '', representativePhoneNumber: '', companyUrl: '', additionalInformation: '', establishmentDate: '', prefecture: '', capital: '', numberOfEmployees: '', userAgreement: '', privacyPolicy: '', }; const [data, setData] = React.useState(defaultData); return ( <CreateOrganization data={data} onDataChange={setData} termsOfUseUrl="/terms-of-use" privacyAgreementUrl="/privacy-policy" onSearchAddressClick={() => { setData((current) => ({ ...current })); }} onSubmit={(event) => { event.preventDefault(); setData((current) => ({ ...current })); }} > <CreateOrganization.Title>Create your organization</CreateOrganization.Title> <CreateOrganization.Description>Use the form below to register a new organization.</CreateOrganization.Description> <CreateOrganization.Form> <CreateOrganization.Form.AccountHolder> <CreateOrganization.Form.AccountHolder.SectionTitle>Account holder</CreateOrganization.Form.AccountHolder.SectionTitle> <CreateOrganization.Form.AccountHolder.Name /> <CreateOrganization.Form.AccountHolder.Email /> <CreateOrganization.Form.AccountHolder.Contact /> </CreateOrganization.Form.AccountHolder> <CreateOrganization.Form.CompanyInformation> <CreateOrganization.Form.CompanyInformation.SectionTitle>Company information</CreateOrganization.Form.CompanyInformation.SectionTitle> <CreateOrganization.Form.CompanyInformation.CompanyName /> <CreateOrganization.Form.CompanyInformation.CompanyAddress> <CreateOrganization.Form.CompanyInformation.CompanyAddress.LocationTitle>Head office location</CreateOrganization.Form.CompanyInformation.CompanyAddress.LocationTitle> <CreateOrganization.Form.CompanyInformation.CompanyAddress.PostCode /> <CreateOrganization.Form.CompanyInformation.CompanyAddress.Prefecture /> <CreateOrganization.Form.CompanyInformation.CompanyAddress.City /> <CreateOrganization.Form.CompanyInformation.CompanyAddress.TownAddress /> <CreateOrganization.Form.CompanyInformation.CompanyAddress.RepresentativePersonName /> <CreateOrganization.Form.CompanyInformation.CompanyAddress.RepresentativeContact /> </CreateOrganization.Form.CompanyInformation.CompanyAddress> <CreateOrganization.Form.CompanyInformation.CompanyCapital /> <CreateOrganization.Form.CompanyInformation.CompanySize /> <CreateOrganization.Form.CompanyInformation.HomePageUrl /> <CreateOrganization.Form.CompanyInformation.AdditionalInformation /> </CreateOrganization.Form.CompanyInformation> <CreateOrganization.Form.Compliance> <CreateOrganization.Form.Compliance.CheckUserAgreement /> <CreateOrganization.Form.Compliance.CheckPrivacyAgreement /> </CreateOrganization.Form.Compliance> <CreateOrganization.Form.SubmitButton>Submit organization</CreateOrganization.Form.SubmitButton> </CreateOrganization.Form> </CreateOrganization> ); }
function Example() { const defaultData = { applicationUserName: '', applicationUserEmail: '', applicationUserPhoneNumber: '', companyName: '', postcode: '', cityTownVillage: '', townStreetBuilding: '', representivePersonName: '', representativePhoneNumber: '', companyUrl: '', additionalInformation: '', establishmentDate: '', prefecture: '', capital: '', numberOfEmployees: '', userAgreement: '', privacyPolicy: '', }; const [data, setData] = React.useState(defaultData); return ( <CreateOrganization data={data} onDataChange={setData} termsOfUseUrl="/terms-of-use" privacyAgreementUrl="/privacy-policy" onSearchAddressClick={() => { setData((current) => ({ ...current })); }} onSubmit={(event) => { event.preventDefault(); setData((current) => ({ ...current })); }} > {({ defaultBlocks, defaultBlockOrder }) => ({ blocks: { ...defaultBlocks, customNotice: ( <div style={{ width: '100%', border: '1px solid #cddcff', borderRadius: 8, padding: 12, background: '#eef4ff', fontSize: 14, }} > Custom notification added via the block override pattern </div> ), }, blockOrder: ['customNotice', ...defaultBlockOrder], })} </CreateOrganization> ); }
ブロックオーバーライドを使うタイミング
順序を変更したい場合、デフォルト UI ブロックを置き換えたい場合、または共有状態の処理を維持したままカスタムコンテンツを挿入したい場合にオーバーライドを使います。ルートのデフォルト描画順は title, description, form です。DateField はカスタムフロー向けに個別にエクスポートされ、デフォルト描画には含まれません。
重要なプロパティ
コアプロパティ
| プロパティ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
data | CreateOrganizationFormData ({ applicationUserName?, applicationUserEmail?, applicationUserPhoneNumber?, companyName?, postcode?, cityTownVillage?, townStreetBuilding?, representivePersonName?, representativePhoneNumber?, companyUrl?, additionalInformation?, prefecture?, capital?, numberOfEmployees?, userAgreement?, privacyPolicy? } or extended Record<string, unknown>) | Yes | - | 制御されたフォームデータオブジェクト |
onDataChange | (data, meta) => void | Yes | - | 更新時に呼び出されます。meta には name, value, cause(input, change, blur, clear, reset, programmatic)、および任意の event が含まれます |
errors | { [fieldName: string]: string | string[] } | No | undefined | データパスをキーにしたフィールドエラー; common keys include the account-holder fields, company fields, userAgreement, privacyPolicy, and custom extension fields such as establishmentDate |
termsOfUseUrl | string | No | '/terms-of-use' | コンプライアンスチェックボックス内の利用規約リンク先 URL |
privacyAgreementUrl | string | No | '/privacy-policy' | コンプライアンスチェックボックス内のプライバシーポリシーリンク先 URL |
onSearchAddressClick | MouseEventHandler<HTMLButtonElement> | No | undefined | CompanyAddress.PostCode の郵便番号検索ボタンを有効にします |
コンテンツプロパティ
ルートの labels prop は公開されていません。代わりに、入れ子のコンパウンドコンポーネントで文言を上書きしてください。
レイアウトと構成のプロパティ
| プロパティ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
component | StackProps<'form'>['component'] | No | 'form' | ルートコンテナ要素 |
children | ReactNode or block override function | No | undefined | コンパウンドコンポーネント用の JSX children を渡すか、ブロックをオーバーライドする関数を渡します |
className | string | No | undefined | ルートコンテナの追加クラス名 |
sx | StackProps<'form'>['sx'] | No | undefined | ルートコンテナ用の MUI sx スタイリング |
children を除く StackProps<'form'> の props を継承します。ルートはデフォルトで title, description, form を描画します。Form はその後、AccountHolder, CompanyInformation, Compliance, SubmitButton を組み立てます。
デフォルト UI ブロック
| ブロック | MUI ベースコンポーネント | 備考 |
|---|---|---|
CreateOrganization | Stack | ルートプロバイダー兼レイアウトコンテナ。component="form" がデフォルトで、レスポンシブな余白を備えます |
Title | Typography | デフォルト文言は 組織を作成する です |
Description | Typography | デフォルト文言は申請フローを説明し、必須フィールドを示します |
Form | Stack | デフォルトレイアウトはアカウント保持者、会社情報、コンプライアンス、送信セクションをまとめます |
Form.AccountHolder | Stack | デフォルトのセクションタイトルは 連絡先情報 です |
Form.AccountHolder.SectionTitle | Typography | デフォルト文言は 連絡先情報 です |
Form.AccountHolder.Name | TextField | name="applicationUserName"、デフォルトラベルは 氏名、デフォルトプレースホルダーは 名前を入力 です |
Form.AccountHolder.Email | TextField | name="applicationUserEmail"、デフォルトラベルは メールアドレス、デフォルトプレースホルダーは メールアドレスを入力 です |
Form.AccountHolder.Contact | TextField | name="applicationUserPhoneNumber"、デフォルトラベルは 電話番号、デフォルトプレースホルダーは 電話番号を入力 です |
Form.CompanyInformation | Stack | デフォルトのセクションタイトルは 会社情報 です |
Form.CompanyInformation.SectionTitle | Typography | デフォルト文言は 会社情報 です |
Form.CompanyInformation.CompanyName | TextField | name="companyName"、デフォルトラベルは 会社名、デフォルトプレースホルダーは 会社名を入力 です |
Form.CompanyInformation.CompanyAddress | Stack | 郵便番号、都道府県、市区町村、住所、代表者連絡先フィールドをまとめる入れ子の住所セクション |
Form.CompanyInformation.CompanyAddress.LocationTitle | Typography | デフォルト文言は 本社所在地 です |
Form.CompanyInformation.CompanyAddress.PostCode | Stack + TextField + Button | name="postcode"、デフォルトラベルは 郵便番号、デフォルトプレースホルダーは 郵便番号を入力、検索ボタン文言のデフォルトは 住所を検索 です |
Form.CompanyInformation.CompanyAddress.Prefecture | TextField | name="prefecture"、デフォルトラベルは 都道府県、デフォルトプレースホルダーは 都道府県を選択、選択肢のデフォルトは英語表記の都道府県一覧です |
Form.CompanyInformation.CompanyAddress.City | TextField | name="cityTownVillage"、デフォルトラベルは 市区町村、デフォルトプレースホルダーは 市区町村を入力 です |
Form.CompanyInformation.CompanyAddress.TownAddress | TextField | name="townStreetBuilding"、デフォルトラベルは 住所、デフォルトプレースホルダーは 町名、街路、建物番号を入力 です |
Form.CompanyInformation.CompanyAddress.RepresentativePersonName | TextField | name="representivePersonName"、デフォルトラベルは 代表者名、デフォルトプレースホルダーは 代表者の氏名を入力 です |
Form.CompanyInformation.CompanyAddress.RepresentativeContact | TextField | name="representativePhoneNumber"、デフォルトラベルは 代表者電話番号、デフォルトプレースホルダーは 代表者の電話番号を入力 です |
Form.CompanyInformation.CompanyCapital | Stack + TextField + Typography | name="capital"、デフォルトラベルは 資本金、デフォルトプレースホルダーは 会社の資本金を入力、接尾辞は 円 です |
Form.CompanyInformation.CompanySize | Stack + TextField + Typography | name="numberOfEmployees"、デフォルトラベルは 従業員数、デフォルトプレースホルダーは 会社の従業員数を入力、接尾辞は 人 です |
Form.CompanyInformation.HomePageUrl | TextField | name="companyUrl"、デフォルトラベルは ホームページ URL、デフォルトプレースホルダーは 会社のホームページ URL を入力 です |
Form.CompanyInformation.AdditionalInformation | TextField | name="additionalInformation"、デフォルトラベルは 追加情報、デフォルトプレースホルダーは 会社の説明を入力、複数行入力が有効です |
Form.Compliance | Stack | 大画面では横並び、小画面では縦並びのデフォルトのコンプライアンス行 |
Form.Compliance.CheckUserAgreement | FormControl + FormControlLabel + Checkbox + Link | name="userAgreement"、デフォルト文言は 利用規約に同意します。、リンク先は termsOfUseUrl または /terms-of-use(新しいタブで開きます)です |
Form.Compliance.CheckPrivacyAgreement | FormControl + FormControlLabel + Checkbox + Link | name="privacyPolicy"、デフォルト文言は プライバシーポリシーに同意します。、リンク先は privacyAgreementUrl または /privacy-policy(新しいタブで開きます)です |
Form.SubmitButton | Button | デフォルト文言は 送信 です |
追加フィールドプリミティブ
| プリミティブ | MUI ベースコンポーネント | 備考 |
|---|---|---|
DateField | LocalizationProvider + DatePicker | カスタムフロー向けに CreateOrganization.DateField としてエクスポートされます。デフォルトの表示形式は yyyy/MM/dd、保存値の形式は yyyy-MM-dd、デフォルトロケールは en-US です |
TypeScript
export type CreateOrganizationFormData =
| {
applicationUserName?: string;
applicationUserEmail?: string;
applicationUserPhoneNumber?: string;
companyName?: string;
postcode?: string;
cityTownVillage?: string;
townStreetBuilding?: string;
representivePersonName?: string;
representativePhoneNumber?: string;
companyUrl?: string;
additionalInformation?: string;
prefecture?: string;
capital?: string;
numberOfEmployees?: string;
userAgreement?: string;
privacyPolicy?: string;
}
| Record<string, unknown>;