From 1caf0c578856e1e9e500b78517dcb2899c56e0cf Mon Sep 17 00:00:00 2001 From: lmeyer Date: Wed, 22 May 2024 13:21:46 +0200 Subject: [PATCH 1/7] feat(Autocomplete): add Autocomplete component --- packages/components/package.json | 4 + .../Autocomplete/Autocomplete.module.scss | 32 ++++++ .../components/Autocomplete/Autocomplete.tsx | 106 ++++++++++++++++++ .../src/components/Autocomplete/index.ts | 4 + .../Autocomplete/locales/de-DE.locale.json | 3 + .../Autocomplete/locales/en-EN.locale.json | 3 + .../Autocomplete/stories/Default.stories.tsx | 86 ++++++++++++++ .../Options/Options.module.scss | 0 .../components => }/Options/Options.tsx | 2 +- .../components/Option/Option.module.scss | 0 .../components/Option/Option.tsx | 0 .../components/Option/index.ts | 0 .../{Select/components => }/Options/index.ts | 1 + .../src/components/Select/Select.module.scss | 1 + .../src/components/Select/Select.tsx | 5 +- .../components/src/components/Select/index.ts | 2 +- .../Select/stories/Default.stories.tsx | 3 +- .../Select/stories/EdgeCases.stories.tsx | 3 +- .../src/components/propTypes/index.ts | 6 +- .../components/Controller/Controller.tsx | 1 + .../Controller/stories/Default.stories.tsx | 18 ++- packages/components/vite.build.config.ts | 1 + .../autocomplete/examples/default.tsx | 16 +++ .../form-controls/autocomplete/index.mdx | 8 ++ .../form-controls/autocomplete/overview.mdx | 3 + 25 files changed, 300 insertions(+), 8 deletions(-) create mode 100644 packages/components/src/components/Autocomplete/Autocomplete.module.scss create mode 100644 packages/components/src/components/Autocomplete/Autocomplete.tsx create mode 100644 packages/components/src/components/Autocomplete/index.ts create mode 100644 packages/components/src/components/Autocomplete/locales/de-DE.locale.json create mode 100644 packages/components/src/components/Autocomplete/locales/en-EN.locale.json create mode 100644 packages/components/src/components/Autocomplete/stories/Default.stories.tsx rename packages/components/src/components/{Select/components => }/Options/Options.module.scss (100%) rename packages/components/src/components/{Select/components => }/Options/Options.tsx (89%) rename packages/components/src/components/{Select => Options}/components/Option/Option.module.scss (100%) rename packages/components/src/components/{Select => Options}/components/Option/Option.tsx (100%) rename packages/components/src/components/{Select => Options}/components/Option/index.ts (100%) rename packages/components/src/components/{Select/components => }/Options/index.ts (63%) create mode 100644 packages/docs/src/content/03-components/form-controls/autocomplete/examples/default.tsx create mode 100644 packages/docs/src/content/03-components/form-controls/autocomplete/index.mdx create mode 100644 packages/docs/src/content/03-components/form-controls/autocomplete/overview.mdx diff --git a/packages/components/package.json b/packages/components/package.json index a3ce92217..981cd6782 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -14,6 +14,10 @@ "types": "./dist/types/components/Action/index.d.ts", "import": "./dist/Action.js" }, + "./Autocomplete": { + "types": "./dist/types/components/Autocomplete/index.d.ts", + "import": "./dist/Autocomplete.js" + }, "./Avatar": { "types": "./dist/types/components/Avatar/index.d.ts", "import": "./dist/Avatar.js" diff --git a/packages/components/src/components/Autocomplete/Autocomplete.module.scss b/packages/components/src/components/Autocomplete/Autocomplete.module.scss new file mode 100644 index 000000000..0473a5e9d --- /dev/null +++ b/packages/components/src/components/Autocomplete/Autocomplete.module.scss @@ -0,0 +1,32 @@ +@use "@/styles/mixins/formControl.scss"; + +.autocomplete { + .input { + order: 2; + display: grid; + grid-template-areas: "input"; + + input { + @include formControl.formControl(); + grid-area: input; + } + .toggle { + grid-area: input; + justify-self: end; + margin: var(--form-control--border-width); + &:hover { + background-color: transparent; + } + &[data-pressed] { + background-color: transparent; + } + } + + &:hover { + input, + .toggle { + background-color: var(--form-control--background-color--hover); + } + } + } +} diff --git a/packages/components/src/components/Autocomplete/Autocomplete.tsx b/packages/components/src/components/Autocomplete/Autocomplete.tsx new file mode 100644 index 000000000..1912a022e --- /dev/null +++ b/packages/components/src/components/Autocomplete/Autocomplete.tsx @@ -0,0 +1,106 @@ +import type { FC, PropsWithChildren } from "react"; +import React from "react"; +import * as Aria from "react-aria-components"; +import { TunnelExit, TunnelProvider } from "@mittwald/react-tunnel"; +import { Button } from "@/components/Button"; +import { IconChevronDown } from "@/components/Icon/components/icons"; +import { Options } from "@/components/Options"; +import type { PropsContext } from "@/lib/propsContext"; +import { PropsContextProvider } from "@/lib/propsContext"; +import clsx from "clsx"; +import styles from "./Autocomplete.module.scss"; +import formFieldStyles from "@/components/FormField/FormField.module.scss"; +import locales from "./locales/*.locale.json"; +import { useLocalizedStringFormatter } from "react-aria"; +import type { FlowComponentProps } from "@/lib/componentFactory/flowComponent"; +import { flowComponent } from "@/lib/componentFactory/flowComponent"; +import type { Key } from "react-aria-components"; + +export interface AutocompleteProps + extends Omit, "children">, + PropsWithChildren, + FlowComponentProps { + onChange?: (value: string) => void; +} + +export const Autocomplete: FC = flowComponent( + "Autocomplete", + (props) => { + const { + children, + className, + menuTrigger = "focus", + onChange = () => { + // default: do nothing + }, + onSelectionChange = () => { + // default: do nothing + }, + refProp: ref, + ...rest + } = props; + + const stringFormatter = useLocalizedStringFormatter(locales); + + const rootClassName = clsx( + styles.autocomplete, + formFieldStyles.formField, + className, + ); + + const propsContext: PropsContext = { + Label: { + className: formFieldStyles.label, + optional: !props.isRequired, + }, + FieldDescription: { + className: formFieldStyles.fieldDescription, + }, + FieldError: { + className: formFieldStyles.customFieldError, + }, + Option: { + tunnelId: "options", + }, + }; + + const handleOnSelectionChange = (key: Key | null) => { + onChange(String(key)); + onSelectionChange(key); + }; + + return ( + + + +
+ + +
+ + {children} + + + + +
+
+
+ ); + }, +); + +export default Autocomplete; diff --git a/packages/components/src/components/Autocomplete/index.ts b/packages/components/src/components/Autocomplete/index.ts new file mode 100644 index 000000000..2bb390958 --- /dev/null +++ b/packages/components/src/components/Autocomplete/index.ts @@ -0,0 +1,4 @@ +import { Autocomplete } from "./Autocomplete"; +export { type AutocompleteProps, Autocomplete } from "./Autocomplete"; +export * from "@/components/Options/components/Option"; +export default Autocomplete; diff --git a/packages/components/src/components/Autocomplete/locales/de-DE.locale.json b/packages/components/src/components/Autocomplete/locales/de-DE.locale.json new file mode 100644 index 000000000..222be5bf6 --- /dev/null +++ b/packages/components/src/components/Autocomplete/locales/de-DE.locale.json @@ -0,0 +1,3 @@ +{ + "autocomplete.showOptions": "Auswahlmöglichkeiten anzeigen" +} diff --git a/packages/components/src/components/Autocomplete/locales/en-EN.locale.json b/packages/components/src/components/Autocomplete/locales/en-EN.locale.json new file mode 100644 index 000000000..222be5bf6 --- /dev/null +++ b/packages/components/src/components/Autocomplete/locales/en-EN.locale.json @@ -0,0 +1,3 @@ +{ + "autocomplete.showOptions": "Auswahlmöglichkeiten anzeigen" +} diff --git a/packages/components/src/components/Autocomplete/stories/Default.stories.tsx b/packages/components/src/components/Autocomplete/stories/Default.stories.tsx new file mode 100644 index 000000000..7f19795e1 --- /dev/null +++ b/packages/components/src/components/Autocomplete/stories/Default.stories.tsx @@ -0,0 +1,86 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import React from "react"; +import { Label } from "@/components/Label"; +import { Option } from "@/components/Options"; +import FieldDescription from "@/components/FieldDescription"; +import { FieldError } from "@/components/FieldError"; +import { Autocomplete } from "@/components/Autocomplete"; + +const meta: Meta = { + title: "Form Controls/Autocomplete", + component: Autocomplete, + render: (props) => ( + + + + + + + + + + + + ), +}; +export default meta; + +type Story = StoryObj; + +export const Default: Story = {}; + +export const Disabled: Story = { args: { isDisabled: true } }; + +export const Required: Story = { + args: { isRequired: true }, +}; + +export const WithFieldDescription: Story = { + render: (props) => ( + + + + + + + + + + + Select a domain + + ), +}; + +export const WithDefaultValue: Story = { + render: (props) => ( + + + + + + + + + + + + ), +}; + +export const WithFieldError: Story = { + render: (props) => ( + + + + + + + + + + + Select a domain to continue + + ), +}; diff --git a/packages/components/src/components/Select/components/Options/Options.module.scss b/packages/components/src/components/Options/Options.module.scss similarity index 100% rename from packages/components/src/components/Select/components/Options/Options.module.scss rename to packages/components/src/components/Options/Options.module.scss diff --git a/packages/components/src/components/Select/components/Options/Options.tsx b/packages/components/src/components/Options/Options.tsx similarity index 89% rename from packages/components/src/components/Select/components/Options/Options.tsx rename to packages/components/src/components/Options/Options.tsx index 4b4b33fc0..2fcac06d2 100644 --- a/packages/components/src/components/Select/components/Options/Options.tsx +++ b/packages/components/src/components/Options/Options.tsx @@ -3,8 +3,8 @@ import React from "react"; import * as Aria from "react-aria-components"; import { Popover } from "@/components/Popover"; import clsx from "clsx"; -import type { OptionProps } from "@/components/Select"; import styles from "./Options.module.scss"; +import type { OptionProps } from "@/components/Options/components/Option"; export type OptionsProps = Aria.ListBoxProps; diff --git a/packages/components/src/components/Select/components/Option/Option.module.scss b/packages/components/src/components/Options/components/Option/Option.module.scss similarity index 100% rename from packages/components/src/components/Select/components/Option/Option.module.scss rename to packages/components/src/components/Options/components/Option/Option.module.scss diff --git a/packages/components/src/components/Select/components/Option/Option.tsx b/packages/components/src/components/Options/components/Option/Option.tsx similarity index 100% rename from packages/components/src/components/Select/components/Option/Option.tsx rename to packages/components/src/components/Options/components/Option/Option.tsx diff --git a/packages/components/src/components/Select/components/Option/index.ts b/packages/components/src/components/Options/components/Option/index.ts similarity index 100% rename from packages/components/src/components/Select/components/Option/index.ts rename to packages/components/src/components/Options/components/Option/index.ts diff --git a/packages/components/src/components/Select/components/Options/index.ts b/packages/components/src/components/Options/index.ts similarity index 63% rename from packages/components/src/components/Select/components/Options/index.ts rename to packages/components/src/components/Options/index.ts index cc97c5be4..6eb807b19 100644 --- a/packages/components/src/components/Select/components/Options/index.ts +++ b/packages/components/src/components/Options/index.ts @@ -1,3 +1,4 @@ import { Options } from "./Options"; export { Options } from "./Options"; +export * from "@/components/Options/components/Option"; export default Options; diff --git a/packages/components/src/components/Select/Select.module.scss b/packages/components/src/components/Select/Select.module.scss index 425d11885..804c29eca 100644 --- a/packages/components/src/components/Select/Select.module.scss +++ b/packages/components/src/components/Select/Select.module.scss @@ -9,6 +9,7 @@ font-size: var(--font-size--default); @include formControl.formControl(); + padding-right: var(--button--padding); } &[data-invalid] { diff --git a/packages/components/src/components/Select/Select.tsx b/packages/components/src/components/Select/Select.tsx index 74ce12eed..f2f011b58 100644 --- a/packages/components/src/components/Select/Select.tsx +++ b/packages/components/src/components/Select/Select.tsx @@ -10,14 +10,15 @@ import clsx from "clsx"; import { IconChevronDown } from "@/components/Icon/components/icons"; import type { FlowComponentProps } from "@/lib/componentFactory/flowComponent"; import { flowComponent } from "@/lib/componentFactory/flowComponent"; -import { Options } from "@/components/Select/components/Options"; + import { TunnelExit, TunnelProvider } from "@mittwald/react-tunnel"; import type { Key } from "react-aria-components"; import type { PropsWithClassName } from "@/lib/types/props"; +import { Options } from "@/components/Options"; export interface SelectProps extends PropsWithChildren< - Omit, "children" | "className"> + Omit, "children" | "className"> >, FlowComponentProps, PropsWithClassName { diff --git a/packages/components/src/components/Select/index.ts b/packages/components/src/components/Select/index.ts index 2f45cfbd8..b3a1d35d3 100644 --- a/packages/components/src/components/Select/index.ts +++ b/packages/components/src/components/Select/index.ts @@ -1,4 +1,4 @@ import { Select } from "./Select"; export { type SelectProps, Select } from "./Select"; -export * from "./components/Option"; +export * from "@/components/Options/components/Option"; export default Select; diff --git a/packages/components/src/components/Select/stories/Default.stories.tsx b/packages/components/src/components/Select/stories/Default.stories.tsx index c019fd55a..f7ed14aa2 100644 --- a/packages/components/src/components/Select/stories/Default.stories.tsx +++ b/packages/components/src/components/Select/stories/Default.stories.tsx @@ -1,7 +1,8 @@ import type { Meta, StoryObj } from "@storybook/react"; -import Select, { Option } from "../index"; +import Select from "../index"; import React from "react"; import { Label } from "@/components/Label"; +import { Option } from "@/components/Options"; import FieldDescription from "@/components/FieldDescription"; import { FieldError } from "@/components/FieldError"; diff --git a/packages/components/src/components/Select/stories/EdgeCases.stories.tsx b/packages/components/src/components/Select/stories/EdgeCases.stories.tsx index 566b96a57..88ac12564 100644 --- a/packages/components/src/components/Select/stories/EdgeCases.stories.tsx +++ b/packages/components/src/components/Select/stories/EdgeCases.stories.tsx @@ -1,7 +1,8 @@ import type { Meta, StoryObj } from "@storybook/react"; -import Select, { Option } from "../index"; +import Select from "../index"; import React from "react"; import { Label } from "@/components/Label"; +import { Option } from "@/components/Options"; import defaultMeta from "./Default.stories"; const meta: Meta = { diff --git a/packages/components/src/components/propTypes/index.ts b/packages/components/src/components/propTypes/index.ts index add62e216..f5ce429c3 100644 --- a/packages/components/src/components/propTypes/index.ts +++ b/packages/components/src/components/propTypes/index.ts @@ -19,7 +19,7 @@ import type { ButtonGroupProps } from "@/components/ButtonGroup"; import type { AvatarProps } from "@/components/Avatar"; import type { ActionProps } from "@/components/Action"; import type { ContextMenuProps, MenuItemProps } from "@/components/ContextMenu"; -import type { OptionProps, SelectProps } from "@/components/Select"; +import type { SelectProps } from "@/components/Select"; import type { RadioButtonProps, RadioGroupProps, @@ -34,11 +34,14 @@ import type { CheckboxButtonProps } from "@/components/CheckboxButton"; import type { TabsProps } from "@/components/Tabs"; import type { ModalProps } from "@/components/Modal"; import type { SectionProps } from "@/components/Section"; +import type { OptionProps } from "@/components/Options"; +import type { AutocompleteProps } from "@/components/Autocomplete"; export * from "./types"; export interface FlowComponentPropsTypes { Action: ActionProps; + Autocomplete: AutocompleteProps; Avatar: AvatarProps; Button: ButtonProps; ButtonGroup: ButtonGroupProps; @@ -81,6 +84,7 @@ const propsContextSupportingComponentsMap: Record< true > = { Action: true, + Autocomplete: true, Avatar: true, Button: true, ButtonGroup: true, diff --git a/packages/components/src/integrations/react-hook-form/components/Controller/Controller.tsx b/packages/components/src/integrations/react-hook-form/components/Controller/Controller.tsx index 3cd877008..beb4ddb11 100644 --- a/packages/components/src/integrations/react-hook-form/components/Controller/Controller.tsx +++ b/packages/components/src/integrations/react-hook-form/components/Controller/Controller.tsx @@ -50,6 +50,7 @@ export function Controller(props: Props) { TextArea: formControlProps, TextField: formControlProps, Select: formControlProps, + Autocomplete: formControlProps, }; return ( diff --git a/packages/components/src/integrations/react-hook-form/components/Controller/stories/Default.stories.tsx b/packages/components/src/integrations/react-hook-form/components/Controller/stories/Default.stories.tsx index f8e2370fd..d0bb93a05 100644 --- a/packages/components/src/integrations/react-hook-form/components/Controller/stories/Default.stories.tsx +++ b/packages/components/src/integrations/react-hook-form/components/Controller/stories/Default.stories.tsx @@ -4,6 +4,7 @@ import { useForm } from "react-hook-form"; import { action } from "@storybook/addon-actions"; import { TextField } from "@/components/TextField"; import { Label } from "@/components/Label"; +import { Option } from "@/components/Options"; import { Controller, Form, @@ -18,7 +19,8 @@ import { Radio, RadioGroup } from "@/components/RadioGroup"; import { Switch } from "@/components/Switch"; import { CheckboxGroup } from "@/components/CheckboxGroup"; import { Checkbox } from "@/components/Checkbox"; -import Select, { Option } from "@/components/Select"; +import Select from "@/components/Select"; +import { Autocomplete } from "@/components/Autocomplete"; const submitAction = action("submit"); @@ -33,6 +35,7 @@ const meta: Meta = { gender: string; testing: boolean; interests: string[]; + domain: string; } const onSubmit = (values: Values): void => { @@ -131,6 +134,19 @@ const meta: Meta = { + + + + + + + + diff --git a/packages/components/vite.build.config.ts b/packages/components/vite.build.config.ts index dff4723e3..8f2548bc9 100644 --- a/packages/components/vite.build.config.ts +++ b/packages/components/vite.build.config.ts @@ -21,6 +21,7 @@ export default defineConfig( entry: { Accordion: "./src/components/Accordion/index.ts", Action: "./src/components/Action/index.ts", + Autocomplete: "./src/components/Autocomplete/index.ts", Avatar: "./src/components/Avatar/index.ts", Breadcrumb: "./src/components/Breadcrumb/index.ts", Button: "./src/components/Button/index.ts", diff --git a/packages/docs/src/content/03-components/form-controls/autocomplete/examples/default.tsx b/packages/docs/src/content/03-components/form-controls/autocomplete/examples/default.tsx new file mode 100644 index 000000000..bb8ce8109 --- /dev/null +++ b/packages/docs/src/content/03-components/form-controls/autocomplete/examples/default.tsx @@ -0,0 +1,16 @@ +import Autocomplete, { + Option, +} from "@mittwald/flow-react-components/Autocomplete"; +import Label from "@mittwald/flow-react-components/Label"; + + + + + + + + + + + +; diff --git a/packages/docs/src/content/03-components/form-controls/autocomplete/index.mdx b/packages/docs/src/content/03-components/form-controls/autocomplete/index.mdx new file mode 100644 index 000000000..ad684de3b --- /dev/null +++ b/packages/docs/src/content/03-components/form-controls/autocomplete/index.mdx @@ -0,0 +1,8 @@ +--- +component: Autocomplete +description: + Die Autocomplete Komponente verbindet ein Textfield mit einer Auswahl an + Optionen, die durch Eingabe in das Textfield gefiltert wird. +--- + + diff --git a/packages/docs/src/content/03-components/form-controls/autocomplete/overview.mdx b/packages/docs/src/content/03-components/form-controls/autocomplete/overview.mdx new file mode 100644 index 000000000..1efc3058c --- /dev/null +++ b/packages/docs/src/content/03-components/form-controls/autocomplete/overview.mdx @@ -0,0 +1,3 @@ +## Beispiel + + From cfaff34704eefa4c4ee3605e277abd26b0c6ce4a Mon Sep 17 00:00:00 2001 From: lmeyer Date: Wed, 23 Oct 2024 07:08:35 +0200 Subject: [PATCH 2/7] feat(ComboBox): add ComboBox component --- packages/components/package.json | 8 ++--- .../src/components/Autocomplete/index.ts | 4 --- .../Autocomplete/locales/de-DE.locale.json | 3 -- .../Autocomplete/locales/en-EN.locale.json | 3 -- .../ComboBox.module.scss} | 5 ++- .../ComboBox.tsx} | 32 +++++++++++++------ .../src/components/ComboBox/index.ts | 5 +++ .../ComboBox/locales/de-DE.locale.json | 3 ++ .../ComboBox/locales/en-EN.locale.json | 3 ++ .../stories/Default.stories.tsx | 26 +++++++-------- .../src/components/Options/Options.tsx | 12 ++++--- .../src/components/Select/Select.tsx | 31 ++++++++---------- .../src/components/propTypes/index.ts | 6 ++-- .../components/Field/Field.tsx | 2 +- .../Field/stories/Default.stories.tsx | 7 ++-- .../autocomplete/examples/default.tsx | 8 ++--- .../form-controls/autocomplete/index.mdx | 6 ++-- 17 files changed, 90 insertions(+), 74 deletions(-) delete mode 100644 packages/components/src/components/Autocomplete/index.ts delete mode 100644 packages/components/src/components/Autocomplete/locales/de-DE.locale.json delete mode 100644 packages/components/src/components/Autocomplete/locales/en-EN.locale.json rename packages/components/src/components/{Autocomplete/Autocomplete.module.scss => ComboBox/ComboBox.module.scss} (97%) rename packages/components/src/components/{Autocomplete/Autocomplete.tsx => ComboBox/ComboBox.tsx} (77%) create mode 100644 packages/components/src/components/ComboBox/index.ts create mode 100644 packages/components/src/components/ComboBox/locales/de-DE.locale.json create mode 100644 packages/components/src/components/ComboBox/locales/en-EN.locale.json rename packages/components/src/components/{Autocomplete => ComboBox}/stories/Default.stories.tsx (83%) diff --git a/packages/components/package.json b/packages/components/package.json index c34796af9..b601582aa 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -39,10 +39,10 @@ "types": "./dist/js/types/components/AlertIcon/index.d.ts", "import": "./dist/js/AlertIcon.js" }, - "./Autocomplete/styles.css": "./dist/css/Autocomplete.css", - "./Autocomplete": { - "types": "./dist/types/components/Autocomplete/index.d.ts", - "import": "./dist/Autocomplete.js" + "./ComboBox/styles.css": "./dist/css/ComboBox.css", + "./ComboBox": { + "types": "./dist/types/components/ComboBox/index.d.ts", + "import": "./dist/ComboBox.js" }, "./Avatar/styles.css": "./dist/css/Avatar.css", "./Avatar": { diff --git a/packages/components/src/components/Autocomplete/index.ts b/packages/components/src/components/Autocomplete/index.ts deleted file mode 100644 index 2bb390958..000000000 --- a/packages/components/src/components/Autocomplete/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { Autocomplete } from "./Autocomplete"; -export { type AutocompleteProps, Autocomplete } from "./Autocomplete"; -export * from "@/components/Options/components/Option"; -export default Autocomplete; diff --git a/packages/components/src/components/Autocomplete/locales/de-DE.locale.json b/packages/components/src/components/Autocomplete/locales/de-DE.locale.json deleted file mode 100644 index 222be5bf6..000000000 --- a/packages/components/src/components/Autocomplete/locales/de-DE.locale.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "autocomplete.showOptions": "Auswahlmöglichkeiten anzeigen" -} diff --git a/packages/components/src/components/Autocomplete/locales/en-EN.locale.json b/packages/components/src/components/Autocomplete/locales/en-EN.locale.json deleted file mode 100644 index 222be5bf6..000000000 --- a/packages/components/src/components/Autocomplete/locales/en-EN.locale.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "autocomplete.showOptions": "Auswahlmöglichkeiten anzeigen" -} diff --git a/packages/components/src/components/Autocomplete/Autocomplete.module.scss b/packages/components/src/components/ComboBox/ComboBox.module.scss similarity index 97% rename from packages/components/src/components/Autocomplete/Autocomplete.module.scss rename to packages/components/src/components/ComboBox/ComboBox.module.scss index 0473a5e9d..42aefb310 100644 --- a/packages/components/src/components/Autocomplete/Autocomplete.module.scss +++ b/packages/components/src/components/ComboBox/ComboBox.module.scss @@ -1,6 +1,6 @@ @use "@/styles/mixins/formControl.scss"; -.autocomplete { +.comboBox { .input { order: 2; display: grid; @@ -10,13 +10,16 @@ @include formControl.formControl(); grid-area: input; } + .toggle { grid-area: input; justify-self: end; margin: var(--form-control--border-width); + &:hover { background-color: transparent; } + &[data-pressed] { background-color: transparent; } diff --git a/packages/components/src/components/Autocomplete/Autocomplete.tsx b/packages/components/src/components/ComboBox/ComboBox.tsx similarity index 77% rename from packages/components/src/components/Autocomplete/Autocomplete.tsx rename to packages/components/src/components/ComboBox/ComboBox.tsx index 1912a022e..c0d7463dc 100644 --- a/packages/components/src/components/Autocomplete/Autocomplete.tsx +++ b/packages/components/src/components/ComboBox/ComboBox.tsx @@ -1,5 +1,6 @@ import type { FC, PropsWithChildren } from "react"; import React from "react"; +import type { Key } from "react-aria-components"; import * as Aria from "react-aria-components"; import { TunnelExit, TunnelProvider } from "@mittwald/react-tunnel"; import { Button } from "@/components/Button"; @@ -8,23 +9,24 @@ import { Options } from "@/components/Options"; import type { PropsContext } from "@/lib/propsContext"; import { PropsContextProvider } from "@/lib/propsContext"; import clsx from "clsx"; -import styles from "./Autocomplete.module.scss"; +import styles from "./ComboBox.module.scss"; import formFieldStyles from "@/components/FormField/FormField.module.scss"; import locales from "./locales/*.locale.json"; import { useLocalizedStringFormatter } from "react-aria"; import type { FlowComponentProps } from "@/lib/componentFactory/flowComponent"; import { flowComponent } from "@/lib/componentFactory/flowComponent"; -import type { Key } from "react-aria-components"; +import { type OverlayController, useOverlayController } from "@/lib/controller"; -export interface AutocompleteProps +export interface ComboBoxProps extends Omit, "children">, PropsWithChildren, FlowComponentProps { onChange?: (value: string) => void; + controller?: OverlayController; } -export const Autocomplete: FC = flowComponent( - "Autocomplete", +export const ComboBox: FC = flowComponent( + "ComboBox", (props) => { const { children, @@ -36,6 +38,7 @@ export const Autocomplete: FC = flowComponent( onSelectionChange = () => { // default: do nothing }, + controller: controllerFromProps, refProp: ref, ...rest } = props; @@ -43,7 +46,7 @@ export const Autocomplete: FC = flowComponent( const stringFormatter = useLocalizedStringFormatter(locales); const rootClassName = clsx( - styles.autocomplete, + styles.comboBox, formFieldStyles.formField, className, ); @@ -69,6 +72,16 @@ export const Autocomplete: FC = flowComponent( onSelectionChange(key); }; + const controllerFromContext = useOverlayController("ComboBox", { + reuseControllerFromContext: true, + }); + + const controller = controllerFromProps ?? controllerFromContext; + + const isOpen = controller.useIsOpen(); + + console.log(isOpen); + return ( = flowComponent( {...rest} ref={ref} onSelectionChange={handleOnSelectionChange} + onOpenChange={(isOpen) => controller.setOpen(isOpen)} > @@ -83,7 +97,7 @@ export const Autocomplete: FC = flowComponent(