招待承諾ブロック
AcceptInvitation は MUI 上に構築された制御済みの招待承諾フォームブロックです。
インストール
- npm
- yarn
- pnpm
- bun
npm install @nodeblocks/frontend-accept-invitation-block
yarn add @nodeblocks/frontend-accept-invitation-block
pnpm add @nodeblocks/frontend-accept-invitation-block
bun add @nodeblocks/frontend-accept-invitation-block
必要なもの
| 項目 | 重要な理由 |
|---|---|
data | フォーム状態の単一の信頼できる情報源 (name, password, confirmPassword) |
onDataChange | フィールド変更時に更新済みの state とメタデータを受け取る |
email (optional) | フォームの上に表示される読み取り専用の招待メール |
errors (optional) | フィールド単位のエラー表示を行う |
制御されたコンポーネント
AcceptInvitation はフォーム state を所有しません。state はアプリ側で保持し、data を通じて渡してください。
コード例
- Quick Start
- Labels and URLs
- Compound Components
- Block Override
ライブエディター
function Example() { const defaultData = { name: '', password: '', confirmPassword: '', }; const [data, setData] = React.useState(defaultData); const [errors, setErrors] = React.useState({}); const handleDataChange = (nextData, meta) => { const {[meta.name]: _removed, ...restErrors} = errors; let nextErrors = restErrors; // Validate required fields on blur (same pattern as storybook) if (meta.cause === 'blur') { nextErrors = {...restErrors}; if (meta.name === 'name' && !String(nextData.name || '').trim()) { nextErrors.name = 'Name is required.'; } if (meta.name === 'password' && !nextData.password) { nextErrors.password = 'Password is required.'; } if (meta.name === 'confirmPassword' && !nextData.confirmPassword) { nextErrors.confirmPassword = 'Please confirm your password.'; } } setErrors(nextErrors); setData(nextData); }; return ( <AcceptInvitation data={data} email="invited@example.com" errors={Object.keys(errors).length ? errors : undefined} onDataChange={handleDataChange} onSubmit={e => { e.preventDefault(); alert(`Submit:\n${JSON.stringify(data, null, 2)}`); }} /> ); }
結果
Loading...
ラベル、プレースホルダー、招待メール、検証エラーをカスタマイズします。
ライブエディター
function Example() { const defaultData = { name: '', password: 'short', confirmPassword: 'nomatch', }; const [data, setData] = React.useState(defaultData); return ( <AcceptInvitation data={data} email="invited@example.com" labels={{ acceptInvitationTitle: 'Create your account', emailDisplay: 'Invited email', nameField: 'Full name', passwordField: 'Password', confirmPasswordField: 'Confirm password', acceptInvitationButton: 'Complete setup', }} placeholders={{ nameField: 'Enter your name', passwordField: 'Choose a password', confirmPasswordField: 'Re-enter your password', }} errors={{ name: 'Name is required.', password: 'Use at least 8 characters.', confirmPassword: 'Passwords do not match.', }} onDataChange={setData} onSubmit={e => { e.preventDefault(); alert(`Submit:\n${JSON.stringify(data, null, 2)}`); }} /> ); }
結果
Loading...
ラベルとプレースホルダー
labels と placeholders はルートで渡してコピー文言を上書きするか、個別のサブコンポーネントに設定してください(Compound Components タブを参照)。
子ブロックを使って、制御された state の動作を保ちながらレイアウトをカスタマイズします。
ライブエディター
function Example() { const defaultData = { name: '', password: '', confirmPassword: '', }; const [data, setData] = React.useState(defaultData); const [errors, setErrors] = React.useState({}); const handleDataChange = (nextData, meta) => { const {[meta.name]: _removed, ...restErrors} = errors; let nextErrors = restErrors; // Validate required fields on blur (same pattern as storybook) if (meta.cause === 'blur') { nextErrors = {...restErrors}; if (meta.name === 'name' && !String(nextData.name || '').trim()) { nextErrors.name = 'Name is required.'; } if (meta.name === 'password' && !nextData.password) { nextErrors.password = 'Password is required.'; } if (meta.name === 'confirmPassword' && !nextData.confirmPassword) { nextErrors.confirmPassword = 'Please confirm your password.'; } } setErrors(nextErrors); setData(nextData); }; return ( <AcceptInvitation data={data} email="invited@example.com" errors={Object.keys(errors).length ? errors : undefined} onDataChange={handleDataChange} onSubmit={e => { e.preventDefault(); alert(`Submit:\n${JSON.stringify(data, null, 2)}`); }} > <AcceptInvitation.AcceptInvitationTitle>Create your account</AcceptInvitation.AcceptInvitationTitle> <AcceptInvitation.Form> <AcceptInvitation.Form.EmailDisplay email="invited@example.com" /> <AcceptInvitation.Form.NameField label="Full name" placeholder="Enter your name" /> <AcceptInvitation.Form.PasswordField label="Password" placeholder="Choose a password" /> <AcceptInvitation.Form.ConfirmPasswordField label="Confirm password" placeholder="Re-enter your password" /> <AcceptInvitation.Form.AcceptInvitationButton>Complete setup</AcceptInvitation.Form.AcceptInvitationButton> </AcceptInvitation.Form> </AcceptInvitation> ); }
結果
Loading...
関数 children を使ってデフォルトのブロックと順序を上書きします。
ライブエディター
function Example() { const defaultData = { name: '', password: '', confirmPassword: '', }; const [data, setData] = React.useState(defaultData); const [errors, setErrors] = React.useState({}); const handleDataChange = (nextData, meta) => { const {[meta.name]: _removed, ...restErrors} = errors; let nextErrors = restErrors; // Validate required fields on blur (same pattern as storybook) if (meta.cause === 'blur') { nextErrors = {...restErrors}; if (meta.name === 'name' && !String(nextData.name || '').trim()) { nextErrors.name = 'Name is required.'; } if (meta.name === 'password' && !nextData.password) { nextErrors.password = 'Password is required.'; } if (meta.name === 'confirmPassword' && !nextData.confirmPassword) { nextErrors.confirmPassword = 'Please confirm your password.'; } } setErrors(nextErrors); setData(nextData); }; return ( <AcceptInvitation data={data} email="invited@example.com" errors={Object.keys(errors).length ? errors : undefined} onDataChange={handleDataChange} onSubmit={e => { e.preventDefault(); alert(`Submit:\n${JSON.stringify(data, null, 2)}`); }} > {({defaultBlocks, defaultBlockOrder}) => ({ blocks: { ...defaultBlocks, customNotice: ( <div style={{ background: '#eef4ff', border: '1px solid #cddcff', borderRadius: '8px', padding: '12px', fontSize: '14px', marginBottom: 16, }} > You were invited to join. Set your name and password below. </div> ), form: ( <AcceptInvitation.Form> <AcceptInvitation.Form.EmailDisplay email="invited@example.com" /> <AcceptInvitation.Form.NameField label="Full name" placeholder="Enter your name" /> <AcceptInvitation.Form.PasswordField label="Password" placeholder="Choose a password" /> <AcceptInvitation.Form.ConfirmPasswordField label="Confirm password" placeholder="Re-enter your password" /> <AcceptInvitation.Form.AcceptInvitationButton> Complete setup </AcceptInvitation.Form.AcceptInvitationButton> </AcceptInvitation.Form> ), }, blockOrder: [ 'acceptInvitationTitle', 'customNotice', ...defaultBlockOrder.filter(k => k !== 'acceptInvitationTitle'), ], })} </AcceptInvitation> ); }
結果
Loading...
ブロックオーバーライドを使うタイミング
順序を変えたいとき、デフォルトの UI ブロックを置き換えたいとき、共有 state の処理を維持しながらカスタムコンテンツを挿入したいときにオーバーライドを使います。デフォルトの順序は acceptInvitationTitle, form です。
重要な props
コア props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
data | AcceptInvitationFormData ({ name, password, confirmPassword } or extended Record<string, unknown>) | Yes | - | 現在のフォーム data オブジェクト |
onDataChange | (data, meta) => void | Yes | - | 更新時に呼び出されます。meta には name, value, cause (input, change, blur, clear, reset, programmatic), optional event が含まれます |
errors | { [fieldName: string]: string | string[] } | No | undefined | data のフィールド名 (name, password, confirmPassword) に紐づくフィールドエラーを表示します |
コンテンツ props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
email | string | No | undefined | 読み取り専用の招待メールアドレス |
labels | { acceptInvitationTitle?, emailDisplay?, nameField?, passwordField?, confirmPasswordField?, acceptInvitationButton? } | No | acceptInvitationTitle: 'アカウント作成', emailDisplay: 'メールアドレス', nameField: '氏名', passwordField: 'パスワード', confirmPasswordField: 'パスワード再入力', acceptInvitationButton: 'アカウントを作成' | デフォルトのテキストラベルを上書き |
placeholders | { nameField?, passwordField?, confirmPasswordField? } | No | nameField: '氏名を入力', passwordField: 'パスワードを入力', confirmPasswordField: 'パスワードを再入力' | フィールドのプレースホルダーを上書き |
レイアウトと構成 props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
children | BlocksOverride | ReactNode | No | undefined | デフォルトのブロックを上書きするか、カスタムの JSX children を提供します |
component | React.ElementType | No | 'form' | ルート要素の型 |
className | string | No | undefined | ルートコンテナのクラス名 |
sx | SxProps | No | undefined | ルートコンテナ向けの MUI システムスタイル |
AcceptInvitation は StackProps<'form'>(children を除く)も継承するため、onSubmit、id、noValidate などの標準的なフォーム props がサポートされます。オーバーライドなしのデフォルトのブロック順は acceptInvitationTitle, form (defaultBlockOrder) です。
デフォルト UI ブロック
| Block | Built on | Notes |
|---|---|---|
AcceptInvitation (root) | Stack (component="form") | 制御されたフォームコンテナ。デフォルトの最大幅は 496px |
AcceptInvitation.AcceptInvitationTitle | Typography | タイトルテキストブロック。デフォルトは アカウント作成 |
AcceptInvitation.Form | Stack | フォームフィールドのコンテナ(送信はルート form が処理) |
AcceptInvitation.Form.EmailDisplay | Typography + Stack | 読み取り専用の招待メール表示。ラベルのデフォルトは メールアドレス。ルートの email prop を使用 |
AcceptInvitation.Form.NameField | TextField | name="name"; required; autoComplete="name"; デフォルト 氏名 / 氏名を入力 |
AcceptInvitation.Form.PasswordField | TextField + IconButton | name="password"; required; autoComplete="new-password"; デフォルト パスワード / パスワードを入力; 表示切替あり |
AcceptInvitation.Form.ConfirmPasswordField | TextField + IconButton | name="confirmPassword"; required; autoComplete="new-password"; デフォルト パスワード再入力 / パスワードを再入力; 表示切替あり |
AcceptInvitation.Form.AcceptInvitationButton | Button | 送信ボタン (variant="contained", size="large", fullWidth, type="submit"); デフォルト アカウントを作成 |
TypeScript
import {AcceptInvitation, AcceptInvitationFormData} from '@nodeblocks/frontend-accept-invitation-block';
type MyAcceptInvitationData = AcceptInvitationFormData & {
inviteToken?: string;
};