組織編集ブロック
EditOrganization は、MUI 上に構築された制御型の組織編集フォームブロックで、会社表示アセット、住所、会社詳細、送信アクションのためのネストされたセクションを備えています。
インストール
- npm
- yarn
- pnpm
- bun
npm install @nodeblocks/frontend-edit-organization-block@0.1.0
yarn add @nodeblocks/frontend-edit-organization-block@0.1.0
pnpm add @nodeblocks/frontend-edit-organization-block@0.1.0
bun add @nodeblocks/frontend-edit-organization-block@0.1.0
必要なもの
| 項目 | 理由 |
|---|---|
data | 制御されたフォーム状態。標準の形には住所、会社、業種、概要、設立日、任意の icon / logo メディア値が含まれます。 |
onDataChange | 変更されたフィールドパス(meta.name)、最新の値(meta.value)、原因(meta.cause)、任意のイベント(meta.event)に関するメタデータとともに、次のデータスナップショットを受け取ります。 |
errors (optional) | ブラケット記法のパスをキーにしたフィールドレベルのバリデーション。 |
companyName (optional) | Form.CompanyDisplay.CompanyName に表示する表示専用の会社名(data には含まれません)。 |
labels / placeholders / selectOptions (optional) | デフォルトフィールドのルート文言とセレクトオプションの上書き。 |
onSearchAddressClick (optional) | CompanyAddress.PostCode の郵便番号検索ボタンを有効にします。 |
dateFormat / dateLuxon / locale (optional) | 設立日の表示フォーマット、保存時のパース、MUI 日付ピッカーのロケールを制御します。 |
iconFns / logoFns / uploadGuidelinesText (optional) | 会社表示セクション用の任意の画像アクションコールバックとアップロードガイドライン文言。 |
children (optional) | 複合セクションまたはブロックのオーバーライド関数を使用します。 |
制御コンポーネント
EditOrganization はフォーム状態を所有しません。data はアプリ側で保持し、更新は onDataChange 経由で渡してください。data.icon と data.logo は File、{ url, type?, id? }、または null にできます。設立日はデフォルトで yyyy-MM-dd 文字列として保存されます。
コード例
- クイックスタート
- ラベルとコピー
- フォームエラー
- 複合コンポーネント
- ブロックオーバーライド
ライブエディター
function Example() { const defaultData = { postcode: '', cityTownVillage: '', townStreetBuilding: '', representativePhoneNumber: '', companyUrl: '', prefecture: '', capital: '', numberOfEmployees: '', representativePersonName: '', industryCategory: '', industry: '', companyOverview: '', businessDescription: '', establishmentDate: '', icon: null, logo: null, }; const [data, setData] = React.useState(defaultData); return ( <EditOrganization data={data} companyName="Sample Company Ltd." uploadGuidelinesText="Use a square PNG or JPEG icon and a wide horizontal logo. Max 5 MB per file." onDataChange={nextData => { setData(nextData); }} onSearchAddressClick={() => { setData(current => ({...current})); }} onSubmit={event => { event.preventDefault(); }} /> ); }
結果
Loading...
ライブエディター
function Example() { const defaultData = { postcode: '', cityTownVillage: '', townStreetBuilding: '', representativePhoneNumber: '', companyUrl: '', prefecture: '', capital: '', numberOfEmployees: '', representativePersonName: '', industryCategory: '', industry: '', companyOverview: '', businessDescription: '', establishmentDate: '', icon: null, logo: null, }; const [data, setData] = React.useState(defaultData); return ( <EditOrganization data={data} companyName="Acme Corporation" uploadGuidelinesText="Prefer a square icon and a wide logo. Replacements can take a few minutes to appear." labels={{ title: 'Edit your organization', companyName: 'Legal company name', companyIcon: 'Company icon', companyLogo: 'Company logo', locationTitle: 'Head office location', postcode: 'Postal code', postcodeButton: 'Find address', prefecture: 'Prefecture', city: 'City', townAddress: 'Street address', representativeContact: 'Representative phone', homePageUrl: 'Website', companyCapital: 'Capital', companySize: 'Headcount', representativePersonName: 'Representative name', industryCategory: 'Industry category', industry: 'Industry', companyOverview: 'Company overview', businessDescription: 'Business description', establishmentDate: 'Date established', submitButton: 'Save changes', }} placeholders={{ postcode: 'Enter the postal code', prefecture: 'Select a prefecture', city: 'Enter the city', townAddress: 'Enter the street and building', representativeContact: 'Enter a phone number', homePageUrl: 'https://example.com', companyCapital: 'Enter capital', companySize: 'Enter headcount', representativePersonName: 'Enter representative name', industryCategory: 'Select a category', industry: 'Select an industry', companyOverview: 'Summarize the company', businessDescription: 'Describe the business', }} selectOptions={{ industryCategory: [ {value: 'Information technology', label: 'Information technology'}, {value: 'Manufacturing', label: 'Manufacturing'}, ], industry: [ {value: 'Software development', label: 'Software development'}, {value: 'Cloud and IT services', label: 'Cloud and IT services'}, ], }} onDataChange={nextData => { setData(nextData); }} onSearchAddressClick={() => { setData(current => ({...current})); }} onSubmit={event => { event.preventDefault(); }} /> ); }
結果
Loading...
ラベルはルートに置く
文言の上書きはルートの labels、placeholders、selectOptions で行うか、個別の複合セクションをカスタマイズしてください。companyName、uploadGuidelinesText、currencySymbol、quantityLabel は labels には含まれません。
ライブエディター
function Example() { const defaultData = { postcode: '', cityTownVillage: '', townStreetBuilding: '', representativePhoneNumber: '', companyUrl: '', prefecture: '', capital: '', numberOfEmployees: '', representativePersonName: '', industryCategory: '', industry: '', companyOverview: '', businessDescription: '', establishmentDate: '', icon: null, logo: null, }; const [data, setData] = React.useState(defaultData); const [errors, setErrors] = React.useState({}); const handleDataChange = (nextData, meta) => { const {[meta.name]: _removed, ...restErrors} = errors; let nextErrors = restErrors; if (meta.cause === 'blur') { nextErrors = {...restErrors}; 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 ( <EditOrganization data={data} companyName="Sample Company Ltd." errors={Object.keys(errors).length ? errors : undefined} onDataChange={handleDataChange} onSearchAddressClick={() => { setData(current => ({...current})); }} onSubmit={event => { event.preventDefault(); }} /> ); }
結果
Loading...
ライブエディター
function Example() { const defaultData = { postcode: '', cityTownVillage: '', townStreetBuilding: '', representativePhoneNumber: '', companyUrl: '', prefecture: '', capital: '', numberOfEmployees: '', representativePersonName: '', industryCategory: '', industry: '', companyOverview: '', businessDescription: '', establishmentDate: '', icon: null, logo: null, }; const [data, setData] = React.useState(defaultData); return ( <EditOrganization data={data} companyName="Acme Corporation" uploadGuidelinesText="Use a square PNG or JPEG icon and a wide horizontal logo." onDataChange={nextData => { setData(nextData); }} onSearchAddressClick={() => { setData(current => ({...current})); }} onSubmit={event => { event.preventDefault(); }} > <EditOrganization.Title>Edit your organization</EditOrganization.Title> <EditOrganization.Form> <EditOrganization.Form.CompanyDisplay> <EditOrganization.Form.CompanyDisplay.CompanyName /> <EditOrganization.Form.CompanyDisplay.CompanyIcon /> <EditOrganization.Form.CompanyDisplay.CompanyLogo /> <EditOrganization.Form.CompanyDisplay.UploadGuidelines /> </EditOrganization.Form.CompanyDisplay> <EditOrganization.Form.CompanyInformation> <EditOrganization.Form.CompanyInformation.CompanyAddress> <EditOrganization.Form.CompanyInformation.CompanyAddress.LocationTitle> Head office location </EditOrganization.Form.CompanyInformation.CompanyAddress.LocationTitle> <EditOrganization.Form.CompanyInformation.CompanyAddress.PostCode /> <EditOrganization.Form.CompanyInformation.CompanyAddress.Prefecture /> <EditOrganization.Form.CompanyInformation.CompanyAddress.City /> <EditOrganization.Form.CompanyInformation.CompanyAddress.TownAddress /> <EditOrganization.Form.CompanyInformation.CompanyAddress.RepresentativeContact /> </EditOrganization.Form.CompanyInformation.CompanyAddress> <EditOrganization.Form.CompanyInformation.CompanyCapital currencySymbol="$" /> <EditOrganization.Form.CompanyInformation.CompanySize quantityLabel="employees" /> <EditOrganization.Form.CompanyInformation.IndustryCategory /> <EditOrganization.Form.CompanyInformation.Industry /> <EditOrganization.Form.CompanyInformation.HomePageUrl /> <EditOrganization.Form.CompanyInformation.CompanyOverview /> <EditOrganization.Form.CompanyInformation.BusinessDescription /> <EditOrganization.Form.CompanyInformation.EstablishmentDate /> <EditOrganization.Form.CompanyInformation.RepresentativePersonName /> </EditOrganization.Form.CompanyInformation> <EditOrganization.Form.SubmitButton>Save changes</EditOrganization.Form.SubmitButton> </EditOrganization.Form> </EditOrganization> ); }
結果
Loading...
ライブエディター
function Example() { const defaultData = { postcode: '', cityTownVillage: '', townStreetBuilding: '', representativePhoneNumber: '', companyUrl: '', prefecture: '', capital: '', numberOfEmployees: '', representativePersonName: '', industryCategory: '', industry: '', companyOverview: '', businessDescription: '', establishmentDate: '', icon: null, logo: null, }; const [data, setData] = React.useState(defaultData); return ( <EditOrganization data={data} companyName="Sample Company Ltd." onDataChange={nextData => { setData(nextData); }} onSearchAddressClick={() => { setData(current => ({...current})); }} onSubmit={event => { event.preventDefault(); }} > {({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], })} </EditOrganization> ); }
結果
Loading...
ブロックオーバーライドを使うタイミング
共有の状態処理を保ったまま、順序の変更、デフォルト UI ブロックの差し替え、またはカスタムコンテンツの挿入が必要なときにオーバーライドを使います。ルートのデフォルト描画順は title、form です。ネストされたデフォルトは続けて companyDisplay、companyInformation、submitButton を描画します。
主要プロパティ
コアプロパティ
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
data | EditOrganizationFormData ({ applicationUserName?, applicationUserEmail?, applicationUserPhoneNumber?, postcode?, cityTownVillage?, townStreetBuilding?, representativePhoneNumber?, companyUrl?, prefecture?, capital?, numberOfEmployees?, industryCategory?, industry?, companyOverview?, businessDescription?, establishmentDate?, representativePersonName?, logo?, icon? } or extended Record<string, unknown>) | Yes | - | 制御されたフォームデータ。デフォルトフィールドは会社住所 / 情報 UI にバインドされ、icon / logo は File、{ url, type?, id? }、または null を受け付けます。 |
onDataChange | (data, meta) => void | Yes | - | 更新時に呼び出されます。meta には name、value、cause(input、change、blur、clear、reset、programmatic)、任意の event が含まれます。 |
errors | { [fieldPath: string]: string | string[] } | No | - | ブラケット記法のデータパスをキーにしたフィールドエラー。 |
onSearchAddressClick | MouseEventHandler<HTMLButtonElement> | No | - | CompanyAddress.PostCode の郵便番号検索ボタンを有効にします。 |
companyName | string | No | - | CompanyDisplay.CompanyName 用の表示専用名。 |
iconFns / logoFns | { onAddImage?, onChangeImage?, onDeleteImage? } | No | - | アイコン / ロゴの追加、変更、削除アクション用の任意コールバック。 |
dateLuxon | { parseDateStringToDateTime; formatDateTimeToString } | No | Strict yyyy-MM-dd parsers | establishmentDate 用のカスタム保存パース / フォーマットヘルパー。 |
dateFormat | string | No | 'yyyy/MM/dd' | EstablishmentDate にマージされる Luxon 表示フォーマット。 |
locale | string | No | 'en-US' | MUI LocalizationProvider の adapterLocale として渡されます。 |
コンテンツプロパティ
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
labels | { title?; companyName?; companyIcon?; companyIconNoImageLabel?; companyIconAddImageLabel?; companyIconChangeImageLabel?; companyIconDeleteImageLabel?; companyLogo?; companyLogoNoImageLabel?; companyLogoAddImageLabel?; companyLogoChangeImageLabel?; companyLogoDeleteImageLabel?; locationTitle?; postcode?; postcodeButton?; prefecture?; city?; townAddress?; representativeContact?; homePageUrl?; companyCapital?; companySize?; representativePersonName?; industryCategory?; industry?; companyOverview?; businessDescription?; establishmentDate?; submitButton? } | No | - | タイトル、フィールドラベル、画像アクション、送信ボタンの文言上書き。 |
placeholders | { postcode?; prefecture?; city?; townAddress?; representativeContact?; homePageUrl?; companyCapital?; companySize?; representativePersonName?; industryCategory?; industry?; companyOverview?; businessDescription? } | No | - | テキストフィールドとセレクトフィールドのプレースホルダーテキスト。 |
selectOptions | { prefecture?; industryCategory?; industry? } | No | Built-in English prefecture / industry lists | セレクトフィールド用のドロップダウンオプション。 |
uploadGuidelinesText | ReactNode | No | - | CompanyDisplay.UploadGuidelines の本文コンテンツ。 |
レイアウトと構成プロパティ
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
component | StackProps<'form'>['component'] | No | 'form' | ルートコンテナ要素。 |
children | ReactNode or block override function | No | - | 複合コンポーネント用の JSX 子要素、またはブロックをオーバーライドする関数を渡します。 |
className | string | No | - | ルートコンテナの追加クラス名。 |
sx | StackProps<'form'>['sx'] | No | - | ルートコンテナの MUI sx スタイリング。 |
children を除く StackProps<'form'> を継承します。ルートはデフォルトで title と form を描画します。Form は続けて CompanyDisplay、CompanyInformation、SubmitButton を構成します。
デフォルト UI ブロック
| Block | Built on | Notes |
|---|---|---|
EditOrganization (root) | Stack + LocalizationProvider | レスポンシブなパディング付きのルートプロバイダーとフォームシェル。デフォルトは component="form"。 |
Title | Typography | 中央揃えの h4/h2。デフォルト文言は Edit Organization。 |
Form | Stack | 会社表示、会社情報、送信をグループ化します。 |
Form.CompanyDisplay | Stack | 会社名、アイコン、ロゴ、アップロードガイドライン。 |
Form.CompanyDisplay.CompanyName | Stack + Typography | ルートの companyName を表示。デフォルトラベルは Company Name。 |
Form.CompanyDisplay.CompanyIcon | Stack + Box + Button + Divider | icon にバインド。デフォルトラベルは Icon、空状態は No image、アクションは Add / Change / Delete。 |
Form.CompanyDisplay.CompanyLogo | Stack + Box + Button + Divider | logo にバインド。デフォルトラベルは Logo、空状態は No image、アクションは Add / Change / Delete。 |
Form.CompanyDisplay.UploadGuidelines | Stack + Typography | ルートの uploadGuidelinesText を描画。 |
Form.CompanyInformation | Stack | 住所、資本金、規模、業種、概要、日付、代表者名。 |
Form.CompanyInformation.CompanyAddress | Stack | ネストされた住所セクション。 |
Form.CompanyInformation.CompanyAddress.LocationTitle | Typography | デフォルト文言は Head Office Location。 |
Form.CompanyInformation.CompanyAddress.PostCode | Stack + TextField + Button | name="postcode"。デフォルトラベルは Post Code、プレースホルダーは Enter the post code。onSearchAddressClick があるとき検索ボタンは Search Address。 |
Form.CompanyInformation.CompanyAddress.Prefecture | TextField | name="prefecture"。デフォルトラベルは Prefecture、プレースホルダーは Select the prefecture、英語の都道府県オプション。 |
Form.CompanyInformation.CompanyAddress.City | TextField | name="cityTownVillage"。デフォルトラベルは City、プレースホルダーは Enter the city。 |
Form.CompanyInformation.CompanyAddress.TownAddress | TextField | name="townStreetBuilding"。デフォルトラベルは Address、プレースホルダーは Enter the town, street, and building number。 |
Form.CompanyInformation.CompanyAddress.RepresentativeContact | TextField | name="representativePhoneNumber"。デフォルトラベルは Representative Phone Number、プレースホルダーは Enter the phone number of a representative。 |
Form.CompanyInformation.CompanyCapital | Stack + TextField + Typography | name="capital"。デフォルトラベルは Capital、プレースホルダーは Enter the company's capital、接尾辞は 円。 |
Form.CompanyInformation.CompanySize | Stack + TextField + Typography | name="numberOfEmployees"。デフォルトラベルは Number of Employees、プレースホルダーは Enter the company's number of employees、接尾辞は 人。 |
Form.CompanyInformation.IndustryCategory | TextField | name="industryCategory"。デフォルトラベルは Industry Category、プレースホルダーは Select the category。 |
Form.CompanyInformation.Industry | TextField | name="industry"。デフォルトラベルは Industry、プレースホルダーは Select the industry。 |
Form.CompanyInformation.HomePageUrl | TextField | name="companyUrl"。デフォルトラベルは Home Page URL、プレースホルダーは Enter the company's home page URL。 |
Form.CompanyInformation.CompanyOverview | TextField | 複数行の name="companyOverview"。デフォルトラベルは Company Overview。 |
Form.CompanyInformation.BusinessDescription | TextField | 複数行の name="businessDescription"。デフォルトラベルは Business Description。 |
Form.CompanyInformation.EstablishmentDate | DatePicker | name="establishmentDate"。デフォルトラベルは Establishment Date、表示フォーマットは yyyy/MM/dd、保存値は yyyy-MM-dd。 |
Form.CompanyInformation.RepresentativePersonName | TextField | name="representativePersonName"。デフォルトラベルは Representative Name。 |
Form.SubmitButton | Button | variant="contained"、size="large"、type="submit"。デフォルト文言は Submit。 |
TypeScript
import {EditOrganization, type EditOrganizationFormData} from '@nodeblocks/frontend-edit-organization-block';
type OrganizationEditData = EditOrganizationFormData & {
internalNotes?: string;
};