-
Notifications
You must be signed in to change notification settings - Fork 105
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: Coji Mizoguchi <coji@techtalk.jp>
- Loading branch information
1 parent
c540df8
commit 1c6e7e5
Showing
31 changed files
with
3,646 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# Documentation | ||
|
||
- はじめに | ||
- [概要](./overview.md) | ||
- [チュートリアル](./tutorial.md) | ||
- [v1 へのアップグレード](./upgrading-v1.md) | ||
- ガイド | ||
- [バリデーション](./validation.md) | ||
- [ネストされたオブジェクトと配列](./complex-structures.md) | ||
- [インテントボタン](./intent-button.md) | ||
- [チェックボックスとラジオグループ](./checkbox-and-radio-group.md) | ||
- [ファイルのアップロード](./file-upload.md) | ||
- [アクセシビリティ](./accessibility.md) | ||
- インテグレーション | ||
- [UI ライブラリ](./integration/ui-libraries.md) | ||
- [Remix](./integration/remix.md) | ||
- [Next.js](./integration/nextjs.md) | ||
- API リファレンス | ||
- @conform-to/react | ||
- [useForm](./api/react/useForm.md) | ||
- [useField](./api/react/useField.md) | ||
- [useFormMetadata](./api/react/useFormMetadata.md) | ||
- [useInputControl](./api/react/useInputControl.md) | ||
- [FormProvider](./api/react/FormProvider.md) | ||
- [FormStateInput](./api/react/FormStateInput.md) | ||
- [getFormProps](./api/react/getFormProps.md) | ||
- [getFieldsetProps](./api/react/getFieldsetProps.md) | ||
- [getInputProps](./api/react/getInputProps.md) | ||
- [getSelectProps](./api/react/getSelectProps.md) | ||
- [getTextareaProps](./api/react/getTextareaProps.md) | ||
- [getCollectionProps](./api/react/getCollectionProps.md) | ||
- @conform-to/yup | ||
- [parseWithYup](./api/yup/parseWithYup.md) | ||
- [getYupConstraint](./api/yup/getYupConstraint.md) | ||
- @conform-to/zod | ||
- [parseWithZod](./api/zod/parseWithZod.md) | ||
- [getZodConstraint](./api/zod/getZodConstraint.md) | ||
- [conformZodMessage](./api/zod/conformZodMessage.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
# アクセシビリティ | ||
|
||
フォームをアクセシブルにするには、各フォーム要素を適切な属性で設定する必要がありますが、 Conform がその手助けをします。 | ||
|
||
## Aria 属性 | ||
|
||
アクセシビリティに関しては、通常、異なる要素を関連付けるために一意の ID が必要になる Aria 属性が最初に思い浮かびます。Conform は、必要なすべての ID を生成してくれることで、この点でのサポートを提供します。 | ||
|
||
```tsx | ||
import { useForm } from '@conform-to/react'; | ||
|
||
function Example() { | ||
const [form, fields] = useForm(); | ||
|
||
return ( | ||
<form id={form.id}> | ||
<label htmlFor={fields.message.id}>Message</label> | ||
<input | ||
type="text" | ||
id={fields.message.id} | ||
name={fields.message.name} | ||
aria-invalid={!fields.message.valid ? true : undefined} | ||
aria-describedby={ | ||
!fields.message.valid | ||
? `${fields.message.errorId} ${fields.message.descriptionId}` | ||
: fields.message.descriptionId | ||
} | ||
/> | ||
<div id={fields.message.descriptionId}>The message you want to send</div> | ||
<div id={fields.message.errorId}>{fields.message.errors}</div> | ||
<button>Send</button> | ||
</form> | ||
); | ||
} | ||
``` | ||
|
||
## バリデーション属性 | ||
|
||
バリデーション属性も、スクリーンリーダーのヒントを改善するなど、アクセシビリティにおいて重要な役割を果たします。 Conform を使用すると、 zod や yup スキーマからバリデーション属性を導出し、各フィールドのメタデータにそれらを反映させることができます。 | ||
|
||
```tsx | ||
import { parseWithZod, getZodConstraint } from '@conform-to/zod'; | ||
import { useForm } from '@conform-to/react'; | ||
import { z } from 'zod'; | ||
|
||
const schema = z.object({ | ||
message: z | ||
.string() | ||
.min(10) | ||
.max(100) | ||
.regex(/^[A-Za-z0-9 ]{10-100}$/), | ||
}); | ||
|
||
function Example() { | ||
const [form, fields] = useForm({ | ||
constraint: getZodConstraint(schema), | ||
onValidate({ formData }) { | ||
return parseWithZod(formData, { schema }); | ||
}, | ||
}); | ||
|
||
return ( | ||
<form id={form.id}> | ||
<input | ||
type="text" | ||
name={fields.message.name} | ||
required={fields.message.required} | ||
minLength={fields.message.minLength} | ||
maxLength={fields.message.maxLength} | ||
pattern={fields.message.pattern} | ||
/> | ||
<button>Send</button> | ||
</form> | ||
); | ||
} | ||
``` | ||
|
||
## プログレッシブエンハンスメント | ||
|
||
プログレッシブエンハンスメントも、一時的なネットワークの問題の影響を最小限に抑えるなど、アクセシビリティを支援します。たとえば、 Conform を使用すると、ページのリフレッシュをまたいでもフォームデータと状態が保持されるように、フィールドリストを操作できます。 | ||
|
||
```tsx | ||
import { useForm } from '@conform-to/react'; | ||
|
||
export default function Example() { | ||
const [form, fields] = useForm(); | ||
|
||
return ( | ||
<form id={form.id}> | ||
<ul> | ||
{tasks.map((task) => ( | ||
<li key={task.key}> | ||
<input name={task.name} defaultValue={task.initialValue} /> | ||
<button | ||
{...form.remove.getButtonProps({ | ||
name: fields.tasks.name, | ||
index, | ||
})} | ||
> | ||
Delete | ||
</button> | ||
</li> | ||
))} | ||
</ul> | ||
<button | ||
{...form.insert.getButtonProps({ | ||
name: fields.tasks.name, | ||
})} | ||
> | ||
Add task | ||
</button> | ||
<button>Save</button> | ||
</form> | ||
); | ||
} | ||
``` | ||
|
||
## ボイラープレートの削減 | ||
|
||
上記で述べたすべての属性を設定することは、面倒でエラーが発生しやすい作業です。 Conform は 、関連するすべての属性を導出する一連のヘルパーを提供することで、この作業を支援しようとしています。 | ||
|
||
> 注意: これらすべてのヘルパーはネイティブ HTML 要素用に設計されています。 react-aria-components や Radix UI のようなカスタム UI コンポーネントを使用している場合、それらの API を通じて既に属性が設定されている可能性があるため、これらのヘルパーが不要になるかもしれません。 | ||
- [getFormProps](./api/react/getFormProps.md) | ||
- [getFieldsetProps](./api/react/getFieldsetProps.md) | ||
- [getInputProps](./api/react/getInputProps.md) | ||
- [getSelectProps](./api/react/getSelectProps.md) | ||
- [getTextareaProps](./api/react/getTextareaProps.md) | ||
- [getCollectionProps](./api/react/getButtonProps.md) | ||
|
||
以下は、手動設定と比較した場合の例です。ヘルパーについて詳しく知りたい場合は、上記リンクの対応するドキュメントを確認してください。 | ||
|
||
```tsx | ||
import { parseWithZod, getZodConstraint } from '@conform-to/zod'; | ||
import { useForm } from '@conform-to/react'; | ||
import { z } from 'zod'; | ||
|
||
const schema = z.object({ | ||
message: z | ||
.string() | ||
.min(10) | ||
.max(100) | ||
.regex(/^[A-Za-z0-9 ]{10-100}$/), | ||
}); | ||
|
||
function Example() { | ||
const [form, fields] = useForm({ | ||
constraint: getZodConstraint(schema), | ||
onValidate({ formData }) { | ||
return parseWithZod(formData, { schema }); | ||
}, | ||
}); | ||
|
||
return ( | ||
<form id={form.id}> | ||
{/* ビフォー */} | ||
<input | ||
type="text" | ||
id={fields.message.id} | ||
name={fields.message.name} | ||
required={fields.message.required} | ||
minLength={fields.message.minLength} | ||
maxLength={fields.message.maxLength} | ||
pattern={fields.message.pattern} | ||
aria-invalid={!fields.message.valid ? true : undefined} | ||
aria-describedby={ | ||
!fields.message.valid | ||
? `${fields.message.errorId} ${fields.message.descriptionId}` | ||
: fields.message.descriptionId | ||
} | ||
/> | ||
{/* アフター */} | ||
<input | ||
{...getInputProps(fields.message, { | ||
type: 'text', | ||
ariaDescribedBy: fields.message.descriptionId, | ||
})} | ||
/> | ||
<button>Send</button> | ||
</form> | ||
); | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
# FormProvider | ||
|
||
フォームコンテキストのための [Context Provider](https://react.dev/reference/react/createContext#provider) をレンダリングする React コンポーネントです。 [useField](./useField.md) や [useFormMetadata](./useFormMetadata.md) フックを使用したい場合には必須です。 | ||
|
||
```tsx | ||
import { FormProvider, useForm } from '@conform-to/react'; | ||
|
||
export default function SomeParent() { | ||
const [form, fields] = useForm(); | ||
|
||
return <FormProvider context={form.context}>{/* ... */}</FormProvider>; | ||
} | ||
``` | ||
|
||
## プロパティ | ||
|
||
### `context` | ||
|
||
フォームコンテキストです。これは [useForm](./useForm.md) で作成され、 `form.context` を通じてアクセスできます。 | ||
|
||
## Tips | ||
|
||
### FormProvider は、フォームの直接の親である必要はありません。 | ||
|
||
入力が [form 属性](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement#instance_properties_related_to_the_parent_form) を通じて関連付けられている限り、フォームの外部のどこにでも自由に入力を配置できます。 | ||
|
||
```tsx | ||
function Example() { | ||
const [form, fields] = useForm(); | ||
return ( | ||
<FormProvider context={form.context}> | ||
<div> | ||
<form id={form.id} /> | ||
</div> | ||
<div> | ||
<input name={fields.title.name} form={form.id} /> | ||
</div> | ||
</FormProvider> | ||
); | ||
} | ||
``` | ||
|
||
### FormProvider はネストすることができます | ||
|
||
これは、レイアウトの制約のために 1 つのフォームを別のフォームの内部に配置する必要がある場合に便利です。 | ||
|
||
```tsx | ||
import { FormProvider, useForm } from '@conform-to/react'; | ||
|
||
function Field({ name, formId }) { | ||
// formId が指定されていない場合、 useField は最も近い FormContext を探します。 | ||
const [meta] = useField(name, { formId }); | ||
|
||
return <input name={meta.name} form={meta.form} />; | ||
} | ||
|
||
function Parent() { | ||
const [form, fields] = useForm({ id: 'parent' }); | ||
return ( | ||
<FormProvider context={form.context}> | ||
<form id={form.id} /> | ||
|
||
<Field name={fields.category.name} /> | ||
<Child /> | ||
</FormProvider> | ||
); | ||
} | ||
|
||
function Child() { | ||
const [form, fields] = useForm({ id: 'child' }); | ||
|
||
return ( | ||
<FormProvider context={form.context}> | ||
<form id={form.id} /> | ||
<Field name={fields.title.name} /> | ||
|
||
{/* これは代わりに 'id' が 'parent' のフォームコンテキストを探します。 */} | ||
<Field name={fields.bar.name} formId="parent" /> | ||
</FormProvider> | ||
); | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# FormStateInput | ||
|
||
ドキュメントの再読み込みが発生した場合にフォームの状態を維持するために、非表示の入力をレンダリングする React コンポーネントです。 | ||
|
||
```tsx | ||
import { FormProvider, FormStateInput, useForm } from '@conform-to/react'; | ||
|
||
export default function SomeParent() { | ||
const [form, fields] = useForm(); | ||
|
||
return ( | ||
<FormProvider context={form.context}> | ||
<FormStateInput /> | ||
</FormProvider> | ||
); | ||
} | ||
``` | ||
|
||
## プロパティ | ||
|
||
このコンポーネントはプロパティを受け入れません。 | ||
|
||
## Tips | ||
|
||
### 完全なプログレッシブエンハンスメントを求めている場合にのみ、これが必要です。 | ||
|
||
ドキュメントが再読み込みされると、フォームの状態の一部が失われます。例えば、 Conform は検証されたフィールドのエラーのみを表示しますが、新しいフィールドをリストに挿入するなど、サブミット以外の意図でフォームを送信している場合、この情報は失われます。 FormStateInput をレンダリングすることで、 Conform はフォームの状態を復元し、検証されたすべてのフィールドのエラーが引き続き表示されることを保証できます。 |
Oops, something went wrong.