shadcn/uiを使ったサジェストフォームのサンプルとして下記のようなものがあります。 https://www.armand-salle.fr/post/autocomplete-select-shadcn-ui
運営されているarmandさんのgithubのソースコード
placeof - プレイスオブの物件スペックを入力する画面では、このサンプルにreact-hook-formやzodを使った実装をしています。
suggestのロジックの変更
上記実装で使われている、shadcn/uiのCombobox はcmdkのComboboxをwrapしたものです。suggestのロジックを変更したかった(+日本語だと上手くいかない気がした)ので、cmdkのドキュメントに記載されている通りfilterに独自実装を追加してます。sortとかも出来るようです。 https://github.com/armandsalle/my-site/blob/main/src/components/autocomplete.tsx#L88 を下記のようにします
<CommandPrimitive filter={(value, search) => { if (value.includes(search)) return 1 return 0 }} ... />
keyの値でvalueのバリデーションをする
keyの追加時の処理
keyとvalueの2つのフォームがあり、keyの値でvalueの値をvalidationする必要するときの実装です。suggestをするkeyがhandleKeyDownなどで確定するときに、onValueChangeで親のComponentの関数を呼び出していますが、そのときに、
onValueChange={(key: SuggestKey) => { form.setValue("suggestKeyId", key.suggestKeyId) form.setValue("suggestValueType", key.valueType) }}
のようにreact-hook-formのsetValue関数を使い、確定したkeyをformに追加します。なお、このときに下記のようにreact-hook-formのformが定義されています。
type Inputs = z.infer<typeof SuggestKeyFormSchema> const form = useForm<Inputs>({ resolver: zodResolver(SuggestKeyFormSchema), defaultValues: defaultValues, })
valueの追加時の処理
下記のようにvalueをregisterします。
<FormItem> <FormControl> {specKey?.valueType === SpecValueType.TEXTAREA ? (( <Input aria-invalid={!!form.formState.errors.value} {...form.register("value")} /> )} </FormControl> </FormItem>
そして、下記のようにzodのsuperRefineを使ってvalidateします。このときkeyを追加したときのvalueTypeが使われます。
export const SuggestKeyFormSchema = z .object({ suggestKeyId: z.string().min(1), valueType: SuggestValueTypeSchema, value: z.string().min(1), }) .superRefine((values, ctx) => { if ( values.valueType === SuggestValueTypeSchema.STRING && values.value.length >= 20 ) { ctx.addIssue({ message: "need to be less than 20 words", code: z.ZodIssueCode.custom, path: ["value"], }) } .... })
i18n
ちなみに、keyはi18nのファイルを参照するようにして表示しています。
suggest一覧の変換箇所 https://github.com/armandsalle/my-site/blob/main/src/components/autocomplete.tsx#L36
確定したkeyの変換箇所 https://github.com/armandsalle/my-site/blob/main/src/components/autocomplete.tsx#L128
詳しくは下記のzenn記事にあります。 i18n一般 https://zenn.dev/k0kishima/articles/956ba3f3dc9629
zodのi18n https://zenn.dev/aiji42/articles/171f26af4e5b5c
サーバーからデータを取得
サーバーからデータを取得する場合は、こちらのzenn記事が参考になるかと思います https://zenn.dev/mktu/articles/2f9166374d09a0
まとめ
マスターデータをまだそこまで用意できていないのですが、もっと完成度を高めて物件のありとあらゆるスペックが入力できるフォームにしていきたいと考えています。