From e1b0e4fdc261a1d014ba2609d15f038804cbcd76 Mon Sep 17 00:00:00 2001 From: ivam5 <69048022+ivam5@users.noreply.github.com> Date: Thu, 13 Apr 2023 13:51:04 +0200 Subject: [PATCH] #104 Add valueTransform prop to Autocomplete (#105) * #104 Add valueTransform prop to Autocomplete * #104 Update Stories --------- Co-authored-by: imikulec --- .../formik-elements/src/AutocompleteField.tsx | 6 +++++- libs/selectors/src/Autocomplete.tsx | 21 +++++++++++++++++++ .../AutocompleteField.stories.tsx | 15 +++++++++++++ .../src/selectors/Autocomplete.stories.tsx | 14 +++++++++++++ 4 files changed, 55 insertions(+), 1 deletion(-) diff --git a/libs/formik-elements/src/AutocompleteField.tsx b/libs/formik-elements/src/AutocompleteField.tsx index b6edd5f..5b78bdc 100644 --- a/libs/formik-elements/src/AutocompleteField.tsx +++ b/libs/formik-elements/src/AutocompleteField.tsx @@ -22,6 +22,7 @@ import { isEqual } from "lodash"; import { Autocomplete, AutocompleteProps } from "@tiller-ds/selectors"; +import { InputFieldProps } from "./InputField"; import useShouldValidate from "./useShouldValidate"; import useFormikBypass from "./useFormikBypass"; @@ -48,13 +49,15 @@ export type AutocompleteFieldProps = { * On by default. */ sendOptionValue?: boolean; -} & Omit, AutocompleteOnlyPropsUnion>; +} & Omit, AutocompleteOnlyPropsUnion> & + Pick; export default function AutocompleteField({ name, options, getOptionValue, sendOptionValue = true, + valueTransform, ...props }: AutocompleteFieldProps) { const [field, meta, helpers] = useField(name); @@ -149,6 +152,7 @@ export default function AutocompleteField({ onBlur={onBlur} onReset={onReset} error={meta.touched && (initialError.current ? initialError.current : meta.error)} + valueTransform={valueTransform} /> ); } diff --git a/libs/selectors/src/Autocomplete.tsx b/libs/selectors/src/Autocomplete.tsx index fe817d3..e0f2b0b 100644 --- a/libs/selectors/src/Autocomplete.tsx +++ b/libs/selectors/src/Autocomplete.tsx @@ -243,6 +243,12 @@ export type AutocompleteProps = { * The value(s) of the field sent on submit and/or retrieved on component render. */ value?: T | T[] | null; + + /** + * Function or a string that determines how the input value should be transformed when the user types into the input field. + * In case it's a function, it will be called every time the input value changes. The function can then modify the value as needed and return the modified value. + */ + valueTransform?: "uppercase" | "lowercase" | "capitalize" | ((value: string) => string); } & AutocompleteTokensProps; type AutocompleteTokensProps = { @@ -279,6 +285,7 @@ function Autocomplete({ className, children, onChange, + valueTransform, ...props }: AutocompleteProps) { const autocompleteTokens = useTokens("Autocomplete", props.autocompleteTokens); @@ -966,6 +973,20 @@ function Autocomplete({ onBlur: onBlur ? onBlur : undefined, onKeyDown, onClick, + onInput: (event) => { + const input = event.target as HTMLInputElement; + let transformedValue = input.value; + if (typeof valueTransform === "function") { + transformedValue = valueTransform(transformedValue); + } else if (valueTransform === "uppercase") { + transformedValue = transformedValue.toUpperCase(); + } else if (valueTransform === "lowercase") { + transformedValue = transformedValue.toLowerCase(); + } else if (valueTransform === "capitalize") { + transformedValue = transformedValue.charAt(0).toUpperCase() + transformedValue.slice(1); + } + input.value = transformedValue; + }, })} {...getComboboxProps({}, { suppressRefError: true })} /> diff --git a/storybook/src/formik-elements/AutocompleteField.stories.tsx b/storybook/src/formik-elements/AutocompleteField.stories.tsx index 495f1f9..01a1337 100644 --- a/storybook/src/formik-elements/AutocompleteField.stories.tsx +++ b/storybook/src/formik-elements/AutocompleteField.stories.tsx @@ -131,6 +131,11 @@ export default { useTokens: { name: "Use Tokens", control: "boolean" }, autocompleteTokens: { name: "Autocomplete Tokens", control: "object" }, selectTokens: { name: "Select Tokens", control: "object" }, + valueTransform: { + name: "Transform Value", + options: ["uppercase", "lowercase", "capitalize"], + control: { type: "radio" }, + }, }, }; @@ -238,6 +243,7 @@ export const AutocompleteFieldFactory = ({ useTokens, autocompleteTokens, selectTokens, + valueTransform, }) => ( ); @@ -323,6 +330,7 @@ AutocompleteFieldFactory.args = { useTokens: false, autocompleteTokens: defaultThemeConfig.component["Autocomplete"], selectTokens: defaultThemeConfig.component["Select"], + valueTransform: "lowercase", }; AutocompleteFieldFactory.parameters = { @@ -341,6 +349,10 @@ export const WithValue = () => ( } name={nameWithValue} /> ); +export const WithTransformedValue = () => ( + } name={nameWithValue} valueTransform="uppercase" /> +); + export const Disabled = () => ( } disabled={true} {...backendProps} name={nameWithValue} /> ); @@ -397,6 +409,7 @@ export const WithMultipleSelectionAndVisibleLabels = () => ( allowMultiple={true} getMultipleSelectedLabel={(items: Item[]) => items.map((item) => `${item.name} ${item.surname}`).join(", ")} name={nameWithMultipleValues} + valueTransform="uppercase" /> ); @@ -504,11 +517,13 @@ const HideControls = { useTokens: { control: { disable: true } }, autocompleteTokens: { control: { disable: true } }, selectTokens: { control: { disable: true } }, + valueTransform: { control: { disable: true } }, }; WithLabel.argTypes = HideControls; WithoutLabel.argTypes = HideControls; WithValue.argTypes = HideControls; +WithTransformedValue.argTypes = HideControls; Disabled.argTypes = HideControls; WithPlaceholder.argTypes = HideControls; WithHelp.argTypes = HideControls; diff --git a/storybook/src/selectors/Autocomplete.stories.tsx b/storybook/src/selectors/Autocomplete.stories.tsx index 063c8c6..60dba63 100644 --- a/storybook/src/selectors/Autocomplete.stories.tsx +++ b/storybook/src/selectors/Autocomplete.stories.tsx @@ -101,6 +101,11 @@ export default { error: { control: false }, tooltip: { control: false }, value: { control: false }, + valueTransform: { + name: "Transform Value", + options: ["uppercase", "lowercase", "capitalize"], + control: { type: "radio" }, + }, }, }; @@ -219,6 +224,7 @@ export const AutocompleteFactory = ({ useTokens, autocompleteTokens, selectTokens, + valueTransform, }) => ( ); @@ -304,6 +311,7 @@ AutocompleteFactory.args = { useTokens: false, autocompleteTokens: defaultThemeConfig.component["Autocomplete"], selectTokens: defaultThemeConfig.component["Select"], + valueTransform: "lowercase", }; AutocompleteFactory.parameters = { @@ -322,6 +330,10 @@ export const WithValue = () => ( } name={name} value={value} /> ); +export const WithTransformedValue = () => ( + } name={name} value={value} valueTransform="uppercase" /> +); + export const Disabled = () => ( } disabled={true} {...backendProps} name={name} /> ); @@ -479,11 +491,13 @@ const HideControls = { useTokens: { control: { disable: true } }, autocompleteTokens: { control: { disable: true } }, selectTokens: { control: { disable: true } }, + valueTransform: { control: { disable: true } }, }; WithLabel.argTypes = HideControls; WithoutLabel.argTypes = HideControls; WithValue.argTypes = HideControls; +WithTransformedValue.argTypes = HideControls; Disabled.argTypes = HideControls; WithPlaceholder.argTypes = HideControls; WithHelp.argTypes = HideControls;