diff --git a/.changeset/plenty-ants-tickle.md b/.changeset/plenty-ants-tickle.md new file mode 100644 index 0000000000..9a3d668a1b --- /dev/null +++ b/.changeset/plenty-ants-tickle.md @@ -0,0 +1,5 @@ +--- +"@navikt/ds-react": patch +--- + +Combobox: Description is now connected to the input field via aria-describedby diff --git a/@navikt/core/react/src/form/combobox/Combobox.tsx b/@navikt/core/react/src/form/combobox/Combobox.tsx index 185f0b45d7..5923f23d00 100644 --- a/@navikt/core/react/src/form/combobox/Combobox.tsx +++ b/@navikt/core/react/src/form/combobox/Combobox.tsx @@ -10,7 +10,10 @@ import { ComboboxProps } from "./types"; export const Combobox = forwardRef< HTMLInputElement, - Omit + Omit< + ComboboxProps, + "onChange" | "options" | "size" | "onClear" | "value" | "disabled" + > >((props, ref) => { const { className, hideLabel = false, description, label, ...rest } = props; diff --git a/@navikt/core/react/src/form/combobox/ComboboxProvider.tsx b/@navikt/core/react/src/form/combobox/ComboboxProvider.tsx index 7301f30c39..974c6e498d 100644 --- a/@navikt/core/react/src/form/combobox/ComboboxProvider.tsx +++ b/@navikt/core/react/src/form/combobox/ComboboxProvider.tsx @@ -35,6 +35,7 @@ const ComboboxProvider = forwardRef( allowNewValues = false, children, defaultValue, + disabled, error, errorId, filteredOptions: externalFilteredOptions, @@ -60,6 +61,8 @@ const ComboboxProvider = forwardRef( ; - error?: string; + error?: ComboboxProps["error"]; focusInput: () => void; inputRef: React.RefObject; value: string; @@ -24,7 +24,24 @@ const [InputContextProvider, useInputContext] = errorMessage: "useInputContext must be used within an InputContextProvider", }); -const InputProvider = ({ children, value: props }) => { +interface Props { + children: React.ReactNode; + value: { + defaultValue: ComboboxProps["defaultValue"]; + description: ComboboxProps["description"]; + disabled: ComboboxProps["disabled"]; + error: ComboboxProps["error"]; + errorId: ComboboxProps["errorId"]; + id: ComboboxProps["id"]; + value: ComboboxProps["value"]; + onChange: ComboboxProps["onChange"]; + onClear: ComboboxProps["onClear"]; + shouldAutocomplete: ComboboxProps["shouldAutocomplete"]; + size: ComboboxProps["size"]; + }; +} + +const InputProvider = ({ children, value: props }: Props) => { const { defaultValue = "", description, @@ -69,21 +86,14 @@ const InputProvider = ({ children, value: props }) => { [externalValue, externalOnChange], ); - const setValue = useCallback( - (text: string) => { - setInternalValue(text); - }, - [setInternalValue], - ); - const clearInput = useCallback( (event: React.PointerEvent | React.KeyboardEvent | React.MouseEvent) => { onClear?.(event); externalOnChange?.(""); - setValue(""); + setInternalValue(""); setSearchTerm(""); }, - [externalOnChange, onClear, setValue], + [externalOnChange, onClear, setInternalValue], ); const focusInput = useCallback(() => { @@ -103,7 +113,7 @@ const InputProvider = ({ children, value: props }) => { focusInput, inputRef, value, - setValue, + setValue: setInternalValue, onChange, searchTerm, setSearchTerm, diff --git a/@navikt/core/react/src/form/combobox/Input/Input.tsx b/@navikt/core/react/src/form/combobox/Input/Input.tsx index 47182155a5..e4f88be39f 100644 --- a/@navikt/core/react/src/form/combobox/Input/Input.tsx +++ b/@navikt/core/react/src/form/combobox/Input/Input.tsx @@ -13,7 +13,7 @@ import { useSelectedOptionsContext } from "../SelectedOptions/selectedOptionsCon import { useInputContext } from "./Input.context"; interface InputProps - extends Omit, "value"> { + extends Omit, "value" | "disabled"> { ref: React.Ref; inputClassName?: string; value?: string; diff --git a/@navikt/core/react/src/form/combobox/Input/InputController.tsx b/@navikt/core/react/src/form/combobox/Input/InputController.tsx index 07db7efea0..aed9d8a985 100644 --- a/@navikt/core/react/src/form/combobox/Input/InputController.tsx +++ b/@navikt/core/react/src/form/combobox/Input/InputController.tsx @@ -24,6 +24,7 @@ export const InputController = forwardRef< | "size" | "onClear" | "value" + | "disabled" > >((props, ref) => { const { diff --git a/@navikt/core/react/src/form/combobox/combobox.stories.tsx b/@navikt/core/react/src/form/combobox/combobox.stories.tsx index e525d4a18f..e529f1cc81 100644 --- a/@navikt/core/react/src/form/combobox/combobox.stories.tsx +++ b/@navikt/core/react/src/form/combobox/combobox.stories.tsx @@ -46,6 +46,12 @@ Default.args = { onChange: console.log, }; Default.argTypes = { + description: { + control: { type: "text" }, + }, + disabled: { + control: { type: "boolean" }, + }, isListOpen: { control: { type: "boolean" }, }, @@ -403,6 +409,16 @@ export const WithError: StoryFn = () => { ); }; +export const Disabled: StoryFn = () => { + return ( + + ); +}; + export const Chromatic: StoryFn = () => { const H2 = (props: { children: string; style?: React.CSSProperties }) => (

@@ -433,6 +449,8 @@ export const Chromatic: StoryFn = () => {

WithError

+

Disabled

+ ); }; diff --git a/@navikt/core/react/src/form/combobox/types.ts b/@navikt/core/react/src/form/combobox/types.ts index 175d3f0729..2cd14756e6 100644 --- a/@navikt/core/react/src/form/combobox/types.ts +++ b/@navikt/core/react/src/form/combobox/types.ts @@ -29,7 +29,10 @@ export type MaxSelected = { export interface ComboboxProps extends FormFieldProps, - Omit, "size" | "onChange" | "value"> { + Omit< + InputHTMLAttributes, + "size" | "onChange" | "value" | "defaultValue" + > { /** * Combobox label. */ @@ -153,4 +156,8 @@ export interface ComboboxProps * This converts the input to a controlled input, so you have to use onChange to update the value. */ value?: string; + /** + * Initial value of the input field. Only works when the input is uncontrolled. + */ + defaultValue?: string; }