From 7ab42aa01b0ab20e11c1d48733676ac66d6eaec1 Mon Sep 17 00:00:00 2001 From: Johannes Obermair Date: Tue, 4 Jun 2024 17:20:16 +0200 Subject: [PATCH] Add `AutocompleteField` and `AsyncAutocompleteField` components **Examples** ```tsx option.label} isOptionEqualToValue={(option: Option, value: Option) => option.value === value.value} fullWidth /> ``` ```tsx { // Load options here }} getOptionLabel={(option: Option) => option.label} isOptionEqualToValue={(option: Option, value: Option) => option.value === value.value} fullWidth /> ``` --- .changeset/olive-panthers-act.md | 35 +++++++++++++++++++ .../form/fields/AsyncAutocompleteField.tsx | 25 +++++++++++++ .../src/form/fields/AutocompleteField.tsx | 26 ++++++++++++++ packages/admin/admin/src/index.ts | 2 ++ .../src/admin/form/AllFieldComponents.tsx | 26 +++++++++++++- 5 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 .changeset/olive-panthers-act.md create mode 100644 packages/admin/admin/src/form/fields/AsyncAutocompleteField.tsx create mode 100644 packages/admin/admin/src/form/fields/AutocompleteField.tsx diff --git a/.changeset/olive-panthers-act.md b/.changeset/olive-panthers-act.md new file mode 100644 index 0000000000..4b41a47941 --- /dev/null +++ b/.changeset/olive-panthers-act.md @@ -0,0 +1,35 @@ +--- +"@comet/admin": minor +--- + +Add `AutocompleteField` and `AsyncAutocompleteField` components + +**Examples** + +```tsx + option.label} + isOptionEqualToValue={(option: Option, value: Option) => option.value === value.value} + fullWidth +/> +``` + +```tsx + { + // Load options here + }} + getOptionLabel={(option: Option) => option.label} + isOptionEqualToValue={(option: Option, value: Option) => option.value === value.value} + fullWidth +/> +``` diff --git a/packages/admin/admin/src/form/fields/AsyncAutocompleteField.tsx b/packages/admin/admin/src/form/fields/AsyncAutocompleteField.tsx new file mode 100644 index 0000000000..01e35fa18a --- /dev/null +++ b/packages/admin/admin/src/form/fields/AsyncAutocompleteField.tsx @@ -0,0 +1,25 @@ +import { AutocompleteProps } from "@mui/material"; +import React from "react"; + +import { Field, FieldProps } from "../Field"; +import { FinalFormAsyncAutocomplete } from "../FinalFormAsyncAutocomplete"; + +export type AsyncAutocompleteFieldProps< + T extends Record, + Multiple extends boolean | undefined, + DisableClearable extends boolean | undefined, + FreeSolo extends boolean | undefined, +> = FieldProps & { + loadOptions: () => Promise; +} & Omit, "options" | "renderInput"> & { + clearable?: boolean; + }; + +export function AsyncAutocompleteField< + T extends Record, + Multiple extends boolean | undefined, + DisableClearable extends boolean | undefined, + FreeSolo extends boolean | undefined, +>(props: AsyncAutocompleteFieldProps) { + return ; +} diff --git a/packages/admin/admin/src/form/fields/AutocompleteField.tsx b/packages/admin/admin/src/form/fields/AutocompleteField.tsx new file mode 100644 index 0000000000..242e510b14 --- /dev/null +++ b/packages/admin/admin/src/form/fields/AutocompleteField.tsx @@ -0,0 +1,26 @@ +import { AutocompleteProps } from "@mui/material"; +import React from "react"; + +import { AsyncOptionsProps } from "../../hooks/useAsyncOptionsProps"; +import FinalFormAutocomplete from "../Autocomplete"; +import { Field, FieldProps } from "../Field"; + +export type AutocompleteFieldProps< + T extends Record, + Multiple extends boolean | undefined, + DisableClearable extends boolean | undefined, + FreeSolo extends boolean | undefined, +> = FieldProps & + Partial> & + Omit, "renderInput"> & { + clearable?: boolean; + }; + +export function AutocompleteField< + T extends Record, + Multiple extends boolean | undefined, + DisableClearable extends boolean | undefined, + FreeSolo extends boolean | undefined, +>(props: AutocompleteFieldProps) { + return ; +} diff --git a/packages/admin/admin/src/index.ts b/packages/admin/admin/src/index.ts index 865948bfbb..ea3dd6c3ba 100644 --- a/packages/admin/admin/src/index.ts +++ b/packages/admin/admin/src/index.ts @@ -80,7 +80,9 @@ export { FinalFormAutocomplete, FinalFormAutocompleteProps } from "./form/Autoco export { FinalFormCheckbox, FinalFormCheckboxProps } from "./form/Checkbox"; export { Field, FieldProps } from "./form/Field"; export { FieldContainer, FieldContainerClassKey, FieldContainerComponent, FieldContainerProps } from "./form/FieldContainer"; +export { AsyncAutocompleteField, AsyncAutocompleteFieldProps } from "./form/fields/AsyncAutocompleteField"; export { AsyncSelectField, AsyncSelectFieldProps } from "./form/fields/AsyncSelectField"; +export { AutocompleteField, AutocompleteFieldProps } from "./form/fields/AutocompleteField"; export { CheckboxField, CheckboxFieldProps } from "./form/fields/CheckboxField"; export { SearchField, SearchFieldProps } from "./form/fields/SearchField"; export { SelectField, SelectFieldProps } from "./form/fields/SelectField"; diff --git a/storybook/src/admin/form/AllFieldComponents.tsx b/storybook/src/admin/form/AllFieldComponents.tsx index a5e307f155..c70f43a075 100644 --- a/storybook/src/admin/form/AllFieldComponents.tsx +++ b/storybook/src/admin/form/AllFieldComponents.tsx @@ -1,5 +1,7 @@ import { + AsyncAutocompleteField, AsyncSelectField, + AutocompleteField, CheckboxField, Field, FieldContainer, @@ -23,18 +25,22 @@ import * as React from "react"; import { Form } from "react-final-form"; function Story() { + type Option = { value: string; label: string }; + const options = [ { value: "chocolate", label: "Chocolate" }, { value: "strawberry", label: "Strawberry" }, { value: "vanilla", label: "Vanilla" }, ]; + const initalValues = React.useMemo(() => ({ multiSelect: [] }), []); + return (
{ alert(JSON.stringify(values, undefined, 2)); }} - initialValues={{ multiSelect: [] }} + initialValues={initalValues} render={({ handleSubmit, values }) => ( @@ -61,6 +67,24 @@ function Story() { getOptionLabel={(option) => option.label} fullWidth /> + option.label} + isOptionEqualToValue={(option: Option, value: Option) => option.value === value.value} + fullWidth + /> + { + return new Promise((resolve) => setTimeout(() => resolve(options), 1000)); + }} + getOptionLabel={(option: Option) => option.label} + isOptionEqualToValue={(option: Option, value: Option) => option.value === value.value} + fullWidth + />