@mrshmllw/smores-react 16.10.3 → 16.10.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/CurrencyInput/CurrencyInput.js +7 -2
- package/dist/CurrencyInput/CurrencyInput.js.map +1 -1
- package/dist/Dropdown/Dropdown.js +7 -12
- package/dist/Dropdown/Dropdown.js.map +1 -1
- package/dist/NumberInput/NumberInput.js +7 -2
- package/dist/NumberInput/NumberInput.js.map +1 -1
- package/dist/SearchInput/SearchInput.js +7 -2
- package/dist/SearchInput/SearchInput.js.map +1 -1
- package/dist/TextInput/TextInput.js +7 -2
- package/dist/TextInput/TextInput.js.map +1 -1
- package/dist/Textarea/Textarea.js +7 -2
- package/dist/Textarea/Textarea.js.map +1 -1
- package/dist/fields/fieldAria.d.ts +16 -0
- package/dist/fields/fieldAria.js +23 -0
- package/dist/fields/fieldAria.js.map +1 -0
- package/package.json +1 -1
|
@@ -4,12 +4,17 @@ import { Box } from '../Box';
|
|
|
4
4
|
import { Field } from '../fields/Field';
|
|
5
5
|
import { Input, InputLeadingIconContainer, } from '../fields/components/CommonInput';
|
|
6
6
|
import { useUniqueId } from '../utils/id';
|
|
7
|
+
import { getFieldAria } from '../fields/fieldAria';
|
|
7
8
|
import { faSterlingSign } from '@awesome.me/kit-46ca99185c/icons/classic/regular';
|
|
8
9
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
9
10
|
import { useTheme } from 'styled-components';
|
|
10
11
|
export const CurrencyInput = forwardRef(function CurrencyInput({ id: idProp, placeholder, name, value, decimalNumber = true, onChange, onInputChange, onBlur, min, max, disabled = false, error = false, fallbackStyle, ...fieldProps }, ref) {
|
|
11
12
|
const theme = useTheme();
|
|
12
13
|
const id = useUniqueId(idProp);
|
|
14
|
+
const { assistiveTextId, errorMsgId, controlAria } = getFieldAria(id, {
|
|
15
|
+
...fieldProps,
|
|
16
|
+
error,
|
|
17
|
+
});
|
|
13
18
|
const formatCurrency = (value) => {
|
|
14
19
|
const decimalIndex = value.indexOf('.');
|
|
15
20
|
if (!decimalNumber) {
|
|
@@ -44,10 +49,10 @@ export const CurrencyInput = forwardRef(function CurrencyInput({ id: idProp, pla
|
|
|
44
49
|
onChange(normalisedValue);
|
|
45
50
|
}
|
|
46
51
|
};
|
|
47
|
-
return (_jsx(Field, { ...fieldProps, htmlFor: id, error: error, children: _jsxs(Box, { flex: true, alignItems: "center", justifyContent: "flex-start", children: [_jsx(InputLeadingIconContainer, { $size: 20, $disabled: disabled, style: { top: '-1px' }, children: _jsx(FontAwesomeIcon, { icon: faSterlingSign, color: theme.color.text.subtle }) }), _jsx(Input, { ref: ref, $error: error, disabled: disabled, type: "number", id: id, name: name, placeholder: placeholder, value: value, $frontIcon: true, $fallbackStyle: fallbackStyle, onChange: (e) => {
|
|
52
|
+
return (_jsx(Field, { ...fieldProps, htmlFor: id, error: error, assistiveTextId: assistiveTextId, errorMsgId: errorMsgId, children: _jsxs(Box, { flex: true, alignItems: "center", justifyContent: "flex-start", children: [_jsx(InputLeadingIconContainer, { $size: 20, $disabled: disabled, style: { top: '-1px' }, children: _jsx(FontAwesomeIcon, { icon: faSterlingSign, color: theme.color.text.subtle }) }), _jsx(Input, { ref: ref, $error: error, disabled: disabled, type: "number", id: id, name: name, placeholder: placeholder, value: value, $frontIcon: true, $fallbackStyle: fallbackStyle, onChange: (e) => {
|
|
48
53
|
if (onChange)
|
|
49
54
|
handleChange(e.currentTarget.value);
|
|
50
55
|
onInputChange?.(e);
|
|
51
|
-
}, onWheel: (e) => e.currentTarget.blur(), onBlur: onBlur })] }) }));
|
|
56
|
+
}, onWheel: (e) => e.currentTarget.blur(), ...controlAria, onBlur: onBlur })] }) }));
|
|
52
57
|
});
|
|
53
58
|
//# sourceMappingURL=CurrencyInput.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CurrencyInput.js","sourceRoot":"","sources":["../../src/CurrencyInput/CurrencyInput.tsx"],"names":[],"mappings":";AAAA,OAAO,EAKL,UAAU,GACX,MAAM,OAAO,CAAA;AAEd,OAAO,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAA;AAC5B,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AAGvC,OAAO,EACL,KAAK,EACL,yBAAyB,GAC1B,MAAM,kCAAkC,CAAA;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,kDAAkD,CAAA;AACjF,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAA;AAChE,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AA2B5C,MAAM,CAAC,MAAM,aAAa,GAAG,UAAU,CAAC,SAAS,aAAa,CAC5D,EACE,EAAE,EAAE,MAAM,EACV,WAAW,EACX,IAAI,EACJ,KAAK,EACL,aAAa,GAAG,IAAI,EACpB,QAAQ,EACR,aAAa,EACb,MAAM,EACN,GAAG,EACH,GAAG,EACH,QAAQ,GAAG,KAAK,EAChB,KAAK,GAAG,KAAK,EACb,aAAa,EACb,GAAG,UAAU,EACM,EACrB,GAAmC;IAEnC,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAA;IACxB,MAAM,EAAE,GAAG,WAAW,CAAC,MAAM,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"CurrencyInput.js","sourceRoot":"","sources":["../../src/CurrencyInput/CurrencyInput.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n FocusEvent,\n FormEvent,\n ForwardedRef,\n WheelEvent,\n forwardRef,\n} from 'react'\n\nimport { Box } from '../Box'\nimport { Field } from '../fields/Field'\nimport { CommonFieldProps } from '../fields/commonFieldTypes'\n\nimport {\n Input,\n InputLeadingIconContainer,\n} from '../fields/components/CommonInput'\nimport { useUniqueId } from '../utils/id'\nimport { getFieldAria } from '../fields/fieldAria'\nimport { faSterlingSign } from '@awesome.me/kit-46ca99185c/icons/classic/regular'\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\nimport { useTheme } from 'styled-components'\n\nexport interface Props extends CommonFieldProps {\n placeholder: string\n name?: string\n value: string\n decimalNumber?: boolean\n onBlur?: (e: FocusEvent<HTMLInputElement>) => void\n min?: number\n max?: number\n}\n\n/** on change or on input required */\ntype InputProps =\n | {\n /** on change is required and on input optional */\n onChange: (e: string) => void\n onInputChange?: (e: FormEvent<HTMLInputElement>) => void\n }\n | {\n /** on input is required and on change optional */\n onChange?: (e: string) => void\n onInputChange: (e: FormEvent<HTMLInputElement>) => void\n }\n\nexport type CurrencyInputProps = Props & InputProps\n\nexport const CurrencyInput = forwardRef(function CurrencyInput(\n {\n id: idProp,\n placeholder,\n name,\n value,\n decimalNumber = true,\n onChange,\n onInputChange,\n onBlur,\n min,\n max,\n disabled = false,\n error = false,\n fallbackStyle,\n ...fieldProps\n }: CurrencyInputProps,\n ref: ForwardedRef<HTMLInputElement>,\n) {\n const theme = useTheme()\n const id = useUniqueId(idProp)\n const { assistiveTextId, errorMsgId, controlAria } = getFieldAria(id, {\n ...fieldProps,\n error,\n })\n\n const formatCurrency = (value: string) => {\n const decimalIndex = value.indexOf('.')\n\n if (!decimalNumber) {\n return Math.trunc(Number(value)).toString()\n }\n\n if (decimalIndex >= 0 && value.length > decimalIndex + 1) {\n const fractionalString = value.substring(decimalIndex + 1).substring(0, 2)\n return `${value.substring(0, decimalIndex)}.${fractionalString}`\n } else {\n return value\n }\n }\n\n const applyMinMax = (value: string) => {\n const numberValue = Number(value)\n if (min && numberValue < min) return min.toString()\n if (max && numberValue > max) return max.toString()\n return value\n }\n\n const handleChange = (value: string) => {\n if (onChange === undefined) return\n const EMPTY_INPUT = ''\n\n if (value === EMPTY_INPUT) {\n onChange(value)\n } else {\n const amount = formatCurrency(value)\n const normalisedValue = applyMinMax(amount)\n\n onChange(normalisedValue)\n }\n }\n\n return (\n <Field\n {...fieldProps}\n htmlFor={id}\n error={error}\n assistiveTextId={assistiveTextId}\n errorMsgId={errorMsgId}\n >\n <Box flex alignItems=\"center\" justifyContent=\"flex-start\">\n <InputLeadingIconContainer\n $size={20}\n $disabled={disabled}\n style={{ top: '-1px' }}\n >\n <FontAwesomeIcon\n icon={faSterlingSign}\n color={theme.color.text.subtle}\n />\n </InputLeadingIconContainer>\n <Input\n ref={ref}\n $error={error}\n disabled={disabled}\n type=\"number\"\n id={id}\n name={name}\n placeholder={placeholder}\n value={value}\n $frontIcon={true}\n $fallbackStyle={fallbackStyle}\n onChange={(e: FormEvent<HTMLInputElement>) => {\n if (onChange) handleChange(e.currentTarget.value)\n onInputChange?.(e)\n }}\n onWheel={(e: WheelEvent<HTMLInputElement>) => e.currentTarget.blur()}\n {...controlAria}\n onBlur={onBlur}\n />\n </Box>\n </Field>\n )\n})\n"]}
|
|
@@ -6,6 +6,7 @@ import { Field } from '../fields/Field';
|
|
|
6
6
|
import { InputLeadingIconContainer, StyledFrontIcon, } from '../fields/components/CommonInput';
|
|
7
7
|
import { fieldDisabledStyle, fieldFocusAttrs, fieldFocusRing, fieldHoverBorderColor, } from '../fields/components/fieldStyles';
|
|
8
8
|
import { useUniqueId } from '../utils/id';
|
|
9
|
+
import { getFieldAria } from '../fields/fieldAria';
|
|
9
10
|
import { useControllableState } from '../utils/useControlledState';
|
|
10
11
|
import { IconContainer } from '../sharedStyles/shared.styles';
|
|
11
12
|
import { faChevronDown } from '@awesome.me/kit-46ca99185c/icons/classic/solid';
|
|
@@ -17,8 +18,11 @@ export const Dropdown = forwardRef(function Dropdown({ id: idProp, placeholder,
|
|
|
17
18
|
stateProp: valueProp,
|
|
18
19
|
});
|
|
19
20
|
const id = useUniqueId(idProp);
|
|
20
|
-
const assistiveTextId =
|
|
21
|
-
|
|
21
|
+
const { assistiveTextId, errorMsgId, controlAria } = getFieldAria(id, {
|
|
22
|
+
...fieldProps,
|
|
23
|
+
error,
|
|
24
|
+
required,
|
|
25
|
+
});
|
|
22
26
|
const hasOptGroups = list.findIndex((item) => !!item.optionGroupLabel) !== -1;
|
|
23
27
|
const dropdownItemsGroups = useMemo(() => {
|
|
24
28
|
const itemsPerGroupLabel = new Map();
|
|
@@ -36,22 +40,13 @@ export const Dropdown = forwardRef(function Dropdown({ id: idProp, placeholder,
|
|
|
36
40
|
}
|
|
37
41
|
return customDefaultOption ?? 'Select an option';
|
|
38
42
|
};
|
|
39
|
-
// Only reference messages that the field actually renders.
|
|
40
|
-
const describedBy = [
|
|
41
|
-
fieldProps.assistiveText &&
|
|
42
|
-
(!fieldProps.renderAsTitle || fieldProps.label) &&
|
|
43
|
-
assistiveTextId,
|
|
44
|
-
error && fieldProps.errorMsg && errorMsgId,
|
|
45
|
-
]
|
|
46
|
-
.filter(Boolean)
|
|
47
|
-
.join(' ') || undefined;
|
|
48
43
|
const iconToRender = iconComponent ? (_jsx(InputLeadingIconContainer, { $size: 16, $iconColor: theme.color.text.base, children: iconComponent })) : frontIcon ? (_jsx(StyledFrontIcon, { render: frontIcon, color: "color.icon.subtle" })) : null;
|
|
49
44
|
return (_jsx(Field, { ...fieldProps, htmlFor: id, error: error, required: required, assistiveTextId: assistiveTextId, errorMsgId: errorMsgId, children: _jsxs(Box, { flex: true, alignItems: "center", style: { position: 'relative' }, children: [iconToRender, _jsxs(StyledSelect, { id: id, disabled: disabled || list.length < 1, onChange: (event) => {
|
|
50
45
|
const value = event.currentTarget.value;
|
|
51
46
|
onSelect?.(value);
|
|
52
47
|
onInputChange?.(event);
|
|
53
48
|
setValue(value);
|
|
54
|
-
}, $error: error, ref: ref, onBlur: onBlur, name: name, autoComplete: autoComplete, "aria-label": ariaLabel,
|
|
49
|
+
}, $error: error, ref: ref, onBlur: onBlur, name: name, autoComplete: autoComplete, "aria-label": ariaLabel, ...controlAria, $frontIcon: !!iconToRender, $fallbackStyle: fallbackStyle, value: value ?? '', children: [_jsx("option", { value: "", hidden: !showDefaultOption, disabled: true, children: defaultOptionLabel() }), dropdownItemsGroups.map((groupItems, i) => hasOptGroups ? (_jsx("optgroup", { label: groupItems[0].optionGroupLabel ?? 'Other', children: groupItems.map((el, j) => (_jsx("option", { value: el.value, children: el.label }, `${i}-${j}`))) }, i)) : (groupItems.map((el, j) => (_jsx("option", { value: el.value, children: el.label }, j)))))] }), _jsx(Caret, { children: _jsx(IconContainer, { $size: CHEVRON_SIZE, children: _jsx(FontAwesomeIcon, { icon: faChevronDown, color: theme.color.icon.subtle }) }) })] }) }));
|
|
55
50
|
});
|
|
56
51
|
const CHEVRON_SIZE = 16;
|
|
57
52
|
const CHEVRON_INSET = 16;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Dropdown.js","sourceRoot":"","sources":["../../src/Dropdown/Dropdown.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n FocusEvent,\n FormEvent,\n ForwardedRef,\n forwardRef,\n ReactNode,\n useMemo,\n} from 'react'\nimport styled, { css, useTheme } from 'styled-components'\n\nimport { Box } from '../Box'\nimport { Icons } from '../Icon'\n\nimport { Field } from '../fields/Field'\nimport { CommonFieldProps } from '../fields/commonFieldTypes'\nimport {\n InputLeadingIconContainer,\n StyledFrontIcon,\n} from '../fields/components/CommonInput'\nimport {\n fieldDisabledStyle,\n fieldFocusAttrs,\n fieldFocusRing,\n fieldHoverBorderColor,\n} from '../fields/components/fieldStyles'\nimport { useUniqueId } from '../utils/id'\nimport { useControllableState } from '../utils/useControlledState'\nimport { IconContainer } from '../sharedStyles/shared.styles'\nimport { faChevronDown } from '@awesome.me/kit-46ca99185c/icons/classic/solid'\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\n\nexport type DropdownItem = {\n optionGroupLabel?: string\n label: string\n value: string\n}\n\nexport interface Props extends CommonFieldProps {\n placeholder?: string\n showDefaultOption?: boolean\n customDefaultOption?: string\n name?: string\n value?: string | null\n defaultValue?: string\n disabled?: boolean\n list: DropdownItem[]\n frontIcon?: Icons\n iconComponent?: ReactNode\n fallbackStyle?: boolean\n /** Accessible name, for when there is no visible `label` */\n 'aria-label'?: string\n /** Lets the browser autofill the field, e.g. `honorific-prefix` */\n autoComplete?: string\n onSelect?: (element: string) => void\n onBlur?: (e: FocusEvent<HTMLSelectElement>) => void\n}\n\ntype TruncateProps =\n | {\n onSelect: (e: string) => void\n onInputChange?: (e: FormEvent<HTMLSelectElement>) => void\n }\n | {\n onSelect?: (e: string) => void\n onInputChange: (e: FormEvent<HTMLSelectElement>) => void\n }\n\nexport type DropdownProps = Props & TruncateProps\n\nexport const Dropdown = forwardRef(function Dropdown(\n {\n id: idProp,\n placeholder,\n showDefaultOption = false,\n customDefaultOption,\n name,\n value: valueProp,\n defaultValue,\n disabled = false,\n list,\n onSelect,\n error = false,\n onInputChange,\n onBlur,\n frontIcon,\n iconComponent,\n fallbackStyle,\n required,\n 'aria-label': ariaLabel,\n autoComplete,\n ...fieldProps\n }: DropdownProps,\n ref: ForwardedRef<HTMLSelectElement>,\n) {\n const theme = useTheme()\n const [value, setValue] = useControllableState({\n initialState: defaultValue,\n stateProp: valueProp,\n })\n const id = useUniqueId(idProp)\n const assistiveTextId = `${id}-assistive-text`\n const errorMsgId = `${id}-error`\n const hasOptGroups = list.findIndex((item) => !!item.optionGroupLabel) !== -1\n\n const dropdownItemsGroups = useMemo(() => {\n const itemsPerGroupLabel = new Map<string, DropdownItem[]>()\n\n list.forEach((item) => {\n const key = item.optionGroupLabel ?? ''\n const group = itemsPerGroupLabel.get(key) ?? []\n\n group.push(item)\n itemsPerGroupLabel.set(key, group)\n })\n\n return Array.from(itemsPerGroupLabel.values())\n }, [list])\n\n const defaultOptionLabel = () => {\n if (!showDefaultOption) {\n return placeholder\n }\n return customDefaultOption ?? 'Select an option'\n }\n\n // Only reference messages that the field actually renders.\n const describedBy =\n [\n fieldProps.assistiveText &&\n (!fieldProps.renderAsTitle || fieldProps.label) &&\n assistiveTextId,\n error && fieldProps.errorMsg && errorMsgId,\n ]\n .filter(Boolean)\n .join(' ') || undefined\n\n const iconToRender = iconComponent ? (\n <InputLeadingIconContainer $size={16} $iconColor={theme.color.text.base}>\n {iconComponent}\n </InputLeadingIconContainer>\n ) : frontIcon ? (\n <StyledFrontIcon render={frontIcon} color=\"color.icon.subtle\" />\n ) : null\n\n return (\n <Field\n {...fieldProps}\n htmlFor={id}\n error={error}\n required={required}\n assistiveTextId={assistiveTextId}\n errorMsgId={errorMsgId}\n >\n <Box flex alignItems=\"center\" style={{ position: 'relative' }}>\n {iconToRender}\n <StyledSelect\n id={id}\n disabled={disabled || list.length < 1}\n onChange={(event) => {\n const value = event.currentTarget.value\n\n onSelect?.(value)\n onInputChange?.(event)\n setValue(value)\n }}\n $error={error}\n ref={ref}\n onBlur={onBlur}\n name={name}\n autoComplete={autoComplete}\n aria-label={ariaLabel}\n aria-invalid={error || undefined}\n aria-required={required || undefined}\n aria-describedby={describedBy}\n $frontIcon={!!iconToRender}\n $fallbackStyle={fallbackStyle}\n value={value ?? ''}\n >\n <option value=\"\" hidden={!showDefaultOption} disabled>\n {defaultOptionLabel()}\n </option>\n\n {dropdownItemsGroups.map((groupItems, i) =>\n hasOptGroups ? (\n <optgroup\n key={i}\n label={groupItems[0].optionGroupLabel ?? 'Other'}\n >\n {groupItems.map((el, j) => (\n <option key={`${i}-${j}`} value={el.value}>\n {el.label}\n </option>\n ))}\n </optgroup>\n ) : (\n groupItems.map((el, j) => (\n <option key={j} value={el.value}>\n {el.label}\n </option>\n ))\n ),\n )}\n </StyledSelect>\n <Caret>\n <IconContainer $size={CHEVRON_SIZE}>\n <FontAwesomeIcon\n icon={faChevronDown}\n color={theme.color.icon.subtle}\n />\n </IconContainer>\n </Caret>\n </Box>\n </Field>\n )\n})\n\ninterface SSelect {\n $error: boolean\n $frontIcon: boolean\n $fallbackStyle?: boolean\n value?: string | null\n}\n\nconst CHEVRON_SIZE = 16\nconst CHEVRON_INSET = 16\nconst CHEVRON_TEXT_GAP = 4\nconst TEXT_PADDING_RIGHT = CHEVRON_INSET + CHEVRON_SIZE + CHEVRON_TEXT_GAP\n\nconst StyledSelect = styled.select.attrs(fieldFocusAttrs)<SSelect>(\n ({ theme, $error, $frontIcon, $fallbackStyle, value }) => {\n const borderColor = (color: string) =>\n $error ? theme.color.feedback.negative[200] : color\n\n return css`\n appearance: none;\n width: 100%;\n height: 48px;\n margin: 0;\n padding: 12px ${TEXT_PADDING_RIGHT}px 12px ${$frontIcon ? '42px' : '12px'};\n border: 2px solid ${borderColor(theme.color.border.subtle)};\n border-radius: 12px;\n background-color: ${\n $fallbackStyle\n ? theme.color.surface.base[300]\n : theme.color.background['000']\n };\n color: ${value === '' ? theme.color.text.subtle : theme.color.text.base};\n font-family: inherit;\n font-size: 16px;\n line-height: 20px;\n text-overflow: clip;\n cursor: pointer;\n outline: none;\n\n option,\n optgroup {\n color: ${theme.color.text.base};\n }\n\n // Hover mustn't override the focus border while the pointer is over a\n // focused field.\n &:hover:not(:disabled):not(:focus) {\n border-color: ${fieldHoverBorderColor(theme, $error)};\n }\n\n &:focus {\n border-color: ${borderColor(theme.color.border.contrast)};\n }\n\n ${fieldFocusRing}\n ${fieldDisabledStyle}\n `\n },\n)\n\nconst Caret = styled.div`\n position: absolute;\n z-index: 1;\n right: ${CHEVRON_INSET}px;\n display: flex;\n pointer-events: none;\n`\n"]}
|
|
1
|
+
{"version":3,"file":"Dropdown.js","sourceRoot":"","sources":["../../src/Dropdown/Dropdown.tsx"],"names":[],"mappings":";AAAA,OAAO,EAIL,UAAU,EAEV,OAAO,GACR,MAAM,OAAO,CAAA;AACd,OAAO,MAAM,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAEzD,OAAO,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAA;AAG5B,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AAEvC,OAAO,EACL,yBAAyB,EACzB,eAAe,GAChB,MAAM,kCAAkC,CAAA;AACzC,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,cAAc,EACd,qBAAqB,GACtB,MAAM,kCAAkC,CAAA;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAA;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,gDAAgD,CAAA;AAC9E,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAA;AAwChE,MAAM,CAAC,MAAM,QAAQ,GAAG,UAAU,CAAC,SAAS,QAAQ,CAClD,EACE,EAAE,EAAE,MAAM,EACV,WAAW,EACX,iBAAiB,GAAG,KAAK,EACzB,mBAAmB,EACnB,IAAI,EACJ,KAAK,EAAE,SAAS,EAChB,YAAY,EACZ,QAAQ,GAAG,KAAK,EAChB,IAAI,EACJ,QAAQ,EACR,KAAK,GAAG,KAAK,EACb,aAAa,EACb,MAAM,EACN,SAAS,EACT,aAAa,EACb,aAAa,EACb,QAAQ,EACR,YAAY,EAAE,SAAS,EACvB,YAAY,EACZ,GAAG,UAAU,EACC,EAChB,GAAoC;IAEpC,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAA;IACxB,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,oBAAoB,CAAC;QAC7C,YAAY,EAAE,YAAY;QAC1B,SAAS,EAAE,SAAS;KACrB,CAAC,CAAA;IACF,MAAM,EAAE,GAAG,WAAW,CAAC,MAAM,CAAC,CAAA;IAC9B,MAAM,EAAE,eAAe,EAAE,UAAU,EAAE,WAAW,EAAE,GAAG,YAAY,CAAC,EAAE,EAAE;QACpE,GAAG,UAAU;QACb,KAAK;QACL,QAAQ;KACT,CAAC,CAAA;IACF,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAA;IAE7E,MAAM,mBAAmB,GAAG,OAAO,CAAC,GAAG,EAAE;QACvC,MAAM,kBAAkB,GAAG,IAAI,GAAG,EAA0B,CAAA;QAE5D,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YACpB,MAAM,GAAG,GAAG,IAAI,CAAC,gBAAgB,IAAI,EAAE,CAAA;YACvC,MAAM,KAAK,GAAG,kBAAkB,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAA;YAE/C,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAChB,kBAAkB,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;QACpC,CAAC,CAAC,CAAA;QAEF,OAAO,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,MAAM,EAAE,CAAC,CAAA;IAChD,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAA;IAEV,MAAM,kBAAkB,GAAG,GAAG,EAAE;QAC9B,IAAI,CAAC,iBAAiB,EAAE,CAAC;YACvB,OAAO,WAAW,CAAA;QACpB,CAAC;QACD,OAAO,mBAAmB,IAAI,kBAAkB,CAAA;IAClD,CAAC,CAAA;IAED,MAAM,YAAY,GAAG,aAAa,CAAC,CAAC,CAAC,CACnC,KAAC,yBAAyB,IAAC,KAAK,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,YACpE,aAAa,GACY,CAC7B,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CACd,KAAC,eAAe,IAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAC,mBAAmB,GAAG,CACjE,CAAC,CAAC,CAAC,IAAI,CAAA;IAER,OAAO,CACL,KAAC,KAAK,OACA,UAAU,EACd,OAAO,EAAE,EAAE,EACX,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,QAAQ,EAClB,eAAe,EAAE,eAAe,EAChC,UAAU,EAAE,UAAU,YAEtB,MAAC,GAAG,IAAC,IAAI,QAAC,UAAU,EAAC,QAAQ,EAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,aAC1D,YAAY,EACb,MAAC,YAAY,IACX,EAAE,EAAE,EAAE,EACN,QAAQ,EAAE,QAAQ,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EACrC,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;wBAClB,MAAM,KAAK,GAAG,KAAK,CAAC,aAAa,CAAC,KAAK,CAAA;wBAEvC,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAA;wBACjB,aAAa,EAAE,CAAC,KAAK,CAAC,CAAA;wBACtB,QAAQ,CAAC,KAAK,CAAC,CAAA;oBACjB,CAAC,EACD,MAAM,EAAE,KAAK,EACb,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,YAAY,gBACd,SAAS,KACjB,WAAW,EACf,UAAU,EAAE,CAAC,CAAC,YAAY,EAC1B,cAAc,EAAE,aAAa,EAC7B,KAAK,EAAE,KAAK,IAAI,EAAE,aAElB,iBAAQ,KAAK,EAAC,EAAE,EAAC,MAAM,EAAE,CAAC,iBAAiB,EAAE,QAAQ,kBAClD,kBAAkB,EAAE,GACd,EAER,mBAAmB,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,CAAC,EAAE,EAAE,CACzC,YAAY,CAAC,CAAC,CAAC,CACb,mBAEE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,gBAAgB,IAAI,OAAO,YAE/C,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CACzB,iBAA0B,KAAK,EAAE,EAAE,CAAC,KAAK,YACtC,EAAE,CAAC,KAAK,IADE,GAAG,CAAC,IAAI,CAAC,EAAE,CAEf,CACV,CAAC,IAPG,CAAC,CAQG,CACZ,CAAC,CAAC,CAAC,CACF,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CACxB,iBAAgB,KAAK,EAAE,EAAE,CAAC,KAAK,YAC5B,EAAE,CAAC,KAAK,IADE,CAAC,CAEL,CACV,CAAC,CACH,CACF,IACY,EACf,KAAC,KAAK,cACJ,KAAC,aAAa,IAAC,KAAK,EAAE,YAAY,YAChC,KAAC,eAAe,IACd,IAAI,EAAE,aAAa,EACnB,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAC9B,GACY,GACV,IACJ,GACA,CACT,CAAA;AACH,CAAC,CAAC,CAAA;AASF,MAAM,YAAY,GAAG,EAAE,CAAA;AACvB,MAAM,aAAa,GAAG,EAAE,CAAA;AACxB,MAAM,gBAAgB,GAAG,CAAC,CAAA;AAC1B,MAAM,kBAAkB,GAAG,aAAa,GAAG,YAAY,GAAG,gBAAgB,CAAA;AAE1E,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,CACvD,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,KAAK,EAAE,EAAE,EAAE;IACvD,MAAM,WAAW,GAAG,CAAC,KAAa,EAAE,EAAE,CACpC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;IAErD,OAAO,GAAG,CAAA;;;;;sBAKQ,kBAAkB,WAAW,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;0BACrD,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC;;0BAGxD,cAAc;QACZ,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC;QAC/B,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAClC;eACS,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI;;;;;;;;;;iBAU5D,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI;;;;;;wBAMd,qBAAqB,CAAC,KAAK,EAAE,MAAM,CAAC;;;;wBAIpC,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC;;;QAGxD,cAAc;QACd,kBAAkB;KACrB,CAAA;AACH,CAAC,CACF,CAAA;AAED,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAA;;;WAGb,aAAa;;;CAGvB,CAAA","sourcesContent":["import {\n FocusEvent,\n FormEvent,\n ForwardedRef,\n forwardRef,\n ReactNode,\n useMemo,\n} from 'react'\nimport styled, { css, useTheme } from 'styled-components'\n\nimport { Box } from '../Box'\nimport { Icons } from '../Icon'\n\nimport { Field } from '../fields/Field'\nimport { CommonFieldProps } from '../fields/commonFieldTypes'\nimport {\n InputLeadingIconContainer,\n StyledFrontIcon,\n} from '../fields/components/CommonInput'\nimport {\n fieldDisabledStyle,\n fieldFocusAttrs,\n fieldFocusRing,\n fieldHoverBorderColor,\n} from '../fields/components/fieldStyles'\nimport { useUniqueId } from '../utils/id'\nimport { getFieldAria } from '../fields/fieldAria'\nimport { useControllableState } from '../utils/useControlledState'\nimport { IconContainer } from '../sharedStyles/shared.styles'\nimport { faChevronDown } from '@awesome.me/kit-46ca99185c/icons/classic/solid'\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\n\nexport type DropdownItem = {\n optionGroupLabel?: string\n label: string\n value: string\n}\n\nexport interface Props extends CommonFieldProps {\n placeholder?: string\n showDefaultOption?: boolean\n customDefaultOption?: string\n name?: string\n value?: string | null\n defaultValue?: string\n disabled?: boolean\n list: DropdownItem[]\n frontIcon?: Icons\n iconComponent?: ReactNode\n fallbackStyle?: boolean\n /** Accessible name, for when there is no visible `label` */\n 'aria-label'?: string\n /** Lets the browser autofill the field, e.g. `honorific-prefix` */\n autoComplete?: string\n onSelect?: (element: string) => void\n onBlur?: (e: FocusEvent<HTMLSelectElement>) => void\n}\n\ntype TruncateProps =\n | {\n onSelect: (e: string) => void\n onInputChange?: (e: FormEvent<HTMLSelectElement>) => void\n }\n | {\n onSelect?: (e: string) => void\n onInputChange: (e: FormEvent<HTMLSelectElement>) => void\n }\n\nexport type DropdownProps = Props & TruncateProps\n\nexport const Dropdown = forwardRef(function Dropdown(\n {\n id: idProp,\n placeholder,\n showDefaultOption = false,\n customDefaultOption,\n name,\n value: valueProp,\n defaultValue,\n disabled = false,\n list,\n onSelect,\n error = false,\n onInputChange,\n onBlur,\n frontIcon,\n iconComponent,\n fallbackStyle,\n required,\n 'aria-label': ariaLabel,\n autoComplete,\n ...fieldProps\n }: DropdownProps,\n ref: ForwardedRef<HTMLSelectElement>,\n) {\n const theme = useTheme()\n const [value, setValue] = useControllableState({\n initialState: defaultValue,\n stateProp: valueProp,\n })\n const id = useUniqueId(idProp)\n const { assistiveTextId, errorMsgId, controlAria } = getFieldAria(id, {\n ...fieldProps,\n error,\n required,\n })\n const hasOptGroups = list.findIndex((item) => !!item.optionGroupLabel) !== -1\n\n const dropdownItemsGroups = useMemo(() => {\n const itemsPerGroupLabel = new Map<string, DropdownItem[]>()\n\n list.forEach((item) => {\n const key = item.optionGroupLabel ?? ''\n const group = itemsPerGroupLabel.get(key) ?? []\n\n group.push(item)\n itemsPerGroupLabel.set(key, group)\n })\n\n return Array.from(itemsPerGroupLabel.values())\n }, [list])\n\n const defaultOptionLabel = () => {\n if (!showDefaultOption) {\n return placeholder\n }\n return customDefaultOption ?? 'Select an option'\n }\n\n const iconToRender = iconComponent ? (\n <InputLeadingIconContainer $size={16} $iconColor={theme.color.text.base}>\n {iconComponent}\n </InputLeadingIconContainer>\n ) : frontIcon ? (\n <StyledFrontIcon render={frontIcon} color=\"color.icon.subtle\" />\n ) : null\n\n return (\n <Field\n {...fieldProps}\n htmlFor={id}\n error={error}\n required={required}\n assistiveTextId={assistiveTextId}\n errorMsgId={errorMsgId}\n >\n <Box flex alignItems=\"center\" style={{ position: 'relative' }}>\n {iconToRender}\n <StyledSelect\n id={id}\n disabled={disabled || list.length < 1}\n onChange={(event) => {\n const value = event.currentTarget.value\n\n onSelect?.(value)\n onInputChange?.(event)\n setValue(value)\n }}\n $error={error}\n ref={ref}\n onBlur={onBlur}\n name={name}\n autoComplete={autoComplete}\n aria-label={ariaLabel}\n {...controlAria}\n $frontIcon={!!iconToRender}\n $fallbackStyle={fallbackStyle}\n value={value ?? ''}\n >\n <option value=\"\" hidden={!showDefaultOption} disabled>\n {defaultOptionLabel()}\n </option>\n\n {dropdownItemsGroups.map((groupItems, i) =>\n hasOptGroups ? (\n <optgroup\n key={i}\n label={groupItems[0].optionGroupLabel ?? 'Other'}\n >\n {groupItems.map((el, j) => (\n <option key={`${i}-${j}`} value={el.value}>\n {el.label}\n </option>\n ))}\n </optgroup>\n ) : (\n groupItems.map((el, j) => (\n <option key={j} value={el.value}>\n {el.label}\n </option>\n ))\n ),\n )}\n </StyledSelect>\n <Caret>\n <IconContainer $size={CHEVRON_SIZE}>\n <FontAwesomeIcon\n icon={faChevronDown}\n color={theme.color.icon.subtle}\n />\n </IconContainer>\n </Caret>\n </Box>\n </Field>\n )\n})\n\ninterface SSelect {\n $error: boolean\n $frontIcon: boolean\n $fallbackStyle?: boolean\n value?: string | null\n}\n\nconst CHEVRON_SIZE = 16\nconst CHEVRON_INSET = 16\nconst CHEVRON_TEXT_GAP = 4\nconst TEXT_PADDING_RIGHT = CHEVRON_INSET + CHEVRON_SIZE + CHEVRON_TEXT_GAP\n\nconst StyledSelect = styled.select.attrs(fieldFocusAttrs)<SSelect>(\n ({ theme, $error, $frontIcon, $fallbackStyle, value }) => {\n const borderColor = (color: string) =>\n $error ? theme.color.feedback.negative[200] : color\n\n return css`\n appearance: none;\n width: 100%;\n height: 48px;\n margin: 0;\n padding: 12px ${TEXT_PADDING_RIGHT}px 12px ${$frontIcon ? '42px' : '12px'};\n border: 2px solid ${borderColor(theme.color.border.subtle)};\n border-radius: 12px;\n background-color: ${\n $fallbackStyle\n ? theme.color.surface.base[300]\n : theme.color.background['000']\n };\n color: ${value === '' ? theme.color.text.subtle : theme.color.text.base};\n font-family: inherit;\n font-size: 16px;\n line-height: 20px;\n text-overflow: clip;\n cursor: pointer;\n outline: none;\n\n option,\n optgroup {\n color: ${theme.color.text.base};\n }\n\n // Hover mustn't override the focus border while the pointer is over a\n // focused field.\n &:hover:not(:disabled):not(:focus) {\n border-color: ${fieldHoverBorderColor(theme, $error)};\n }\n\n &:focus {\n border-color: ${borderColor(theme.color.border.contrast)};\n }\n\n ${fieldFocusRing}\n ${fieldDisabledStyle}\n `\n },\n)\n\nconst Caret = styled.div`\n position: absolute;\n z-index: 1;\n right: ${CHEVRON_INSET}px;\n display: flex;\n pointer-events: none;\n`\n"]}
|
|
@@ -5,11 +5,16 @@ import { Box } from '../Box';
|
|
|
5
5
|
import { Field } from '../fields/Field';
|
|
6
6
|
import { Input, InputLeadingIconContainer, InputTrailingIconContainer, StyledFrontIcon, StyledTrailingIcon, } from '../fields/components/CommonInput';
|
|
7
7
|
import { useUniqueId } from '../utils/id';
|
|
8
|
+
import { getFieldAria } from '../fields/fieldAria';
|
|
8
9
|
import { faChevronDown, faChevronUp, } from '@awesome.me/kit-46ca99185c/icons/classic/regular';
|
|
9
10
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
10
11
|
import { IconContainer } from '../sharedStyles/shared.styles';
|
|
11
12
|
export const NumberInput = forwardRef(function NumberInput({ id: idProp, type = 'number', placeholder, name, value, onChange, onInputChange, onBlur, min = -999999, max = 999999, step = 0, disabled = false, error = false, frontIcon, frontIconComponent, trailingIconComponent, trailingIcon, fallbackStyle, ...fieldProps }, ref) {
|
|
12
13
|
const id = useUniqueId(idProp);
|
|
14
|
+
const { assistiveTextId, errorMsgId, controlAria } = getFieldAria(id, {
|
|
15
|
+
...fieldProps,
|
|
16
|
+
error,
|
|
17
|
+
});
|
|
13
18
|
const theme = useTheme();
|
|
14
19
|
// Check whether the min/max value exists is within the specified range
|
|
15
20
|
const isInRange = (value) => {
|
|
@@ -66,11 +71,11 @@ export const NumberInput = forwardRef(function NumberInput({ id: idProp, type =
|
|
|
66
71
|
};
|
|
67
72
|
const frontIconToRender = frontIconComponent ? (_jsx(InputLeadingIconContainer, { $size: 20, $iconColor: theme.color.text.subtle, children: frontIconComponent })) : frontIcon ? (_jsx(StyledFrontIcon, { $disabled: disabled, render: frontIcon, color: "sesame" })) : null;
|
|
68
73
|
const trailingIconToRender = trailingIconComponent ? (_jsx(InputTrailingIconContainer, { $size: 20, $iconColor: theme.color.text.subtle, children: trailingIconComponent })) : trailingIcon ? (_jsx(StyledTrailingIcon, { $disabled: disabled, render: trailingIcon, color: "sesame" })) : null;
|
|
69
|
-
return (_jsx(Field, { ...fieldProps, htmlFor: id, error: error, children: _jsxs(Box, { flex: true, alignItems: "center", justifyContent: "flex-start", children: [frontIconToRender, _jsx(Input, { ref: ref, $error: error, disabled: disabled, type: type, id: id, name: name, placeholder: placeholder, value: value, $frontIcon: Boolean(frontIconToRender), step: step, $fallbackStyle: fallbackStyle, onWheel: (e) => e.currentTarget.blur(), onChange: (e) => {
|
|
74
|
+
return (_jsx(Field, { ...fieldProps, htmlFor: id, error: error, assistiveTextId: assistiveTextId, errorMsgId: errorMsgId, children: _jsxs(Box, { flex: true, alignItems: "center", justifyContent: "flex-start", children: [frontIconToRender, _jsx(Input, { ref: ref, $error: error, disabled: disabled, type: type, id: id, name: name, placeholder: placeholder, value: value, $frontIcon: Boolean(frontIconToRender), step: step, $fallbackStyle: fallbackStyle, onWheel: (e) => e.currentTarget.blur(), ...controlAria, onChange: (e) => {
|
|
70
75
|
if (onChange)
|
|
71
76
|
handleChange(e.currentTarget.value);
|
|
72
77
|
onInputChange?.(e);
|
|
73
|
-
}, onBlur: onBlur }), onChange && step > 0 && (_jsxs(Spinner, { children: [_jsx(SpinnerButton, { "aria-label": "
|
|
78
|
+
}, onBlur: onBlur }), onChange && step > 0 && (_jsxs(Spinner, { children: [_jsx(SpinnerButton, { "aria-label": "Increase", onClick: incrementValue, disabled: disabled, children: _jsx(IconContainer, { $size: 20, children: _jsx(FontAwesomeIcon, { icon: faChevronDown, color: theme.color.text.subtle }) }) }), _jsx(SpinnerButton, { "aria-label": "Decrease", onClick: decrementValue, disabled: disabled, children: _jsx(IconContainer, { $size: 20, children: _jsx(FontAwesomeIcon, { icon: faChevronUp, color: theme.color.text.subtle }) }) })] })), trailingIconToRender && !step && trailingIconToRender] }) }));
|
|
74
79
|
});
|
|
75
80
|
const Spinner = styled.div `
|
|
76
81
|
position: relative;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NumberInput.js","sourceRoot":"","sources":["../../src/NumberInput/NumberInput.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n FocusEvent,\n FormEvent,\n ForwardedRef,\n MouseEvent,\n forwardRef,\n} from 'react'\nimport styled, { useTheme } from 'styled-components'\n\nimport { Box } from '../Box'\nimport { Field } from '../fields/Field'\nimport { CommonFieldProps } from '../fields/commonFieldTypes'\n\nimport {\n Input,\n InputLeadingIconContainer,\n InputTrailingIconContainer,\n StyledFrontIcon,\n StyledTrailingIcon,\n} from '../fields/components/CommonInput'\nimport { useUniqueId } from '../utils/id'\nimport {\n faChevronDown,\n faChevronUp,\n} from '@awesome.me/kit-46ca99185c/icons/classic/regular'\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\nimport { IconContainer } from '../sharedStyles/shared.styles'\n\nexport interface Props extends CommonFieldProps {\n type?: 'number'\n placeholder: string\n name?: string\n value: string\n onBlur?: (e: FocusEvent<HTMLInputElement>) => void\n min?: number\n max?: number\n step?: number\n}\n\n/** on change or on input required */\ntype InputProps =\n | {\n /** on change is required and on input optional */\n onChange: (e: string | number) => void\n onInputChange?: (e: FormEvent<HTMLInputElement>) => void\n }\n | {\n /** on input is required and on change optional */\n onChange?: (e: string | number) => void\n onInputChange: (e: FormEvent<HTMLInputElement>) => void\n }\n\nexport type NumberInputProps = Props & InputProps\n\nexport const NumberInput = forwardRef(function NumberInput(\n {\n id: idProp,\n type = 'number',\n placeholder,\n name,\n value,\n onChange,\n onInputChange,\n onBlur,\n min = -999999,\n max = 999999,\n step = 0,\n disabled = false,\n error = false,\n frontIcon,\n frontIconComponent,\n trailingIconComponent,\n trailingIcon,\n fallbackStyle,\n ...fieldProps\n }: NumberInputProps,\n ref: ForwardedRef<HTMLInputElement>,\n) {\n const id = useUniqueId(idProp)\n const theme = useTheme()\n // Check whether the min/max value exists is within the specified range\n const isInRange = (value: number) => {\n if (min && value < min) {\n return false\n }\n\n if (max && value > max) {\n return false\n }\n\n return true\n }\n\n // Round the number to two decimal places\n const roundNumber = (event: number) => {\n return Math.round(event * 100) / 100\n }\n\n const applyMinMax = (value: number) => {\n if (min && value < min) return min\n if (max && value > max) return max\n return value\n }\n\n const handleChange = (event: string) => {\n if (onChange === undefined) return\n const EMPTY_INPUT = ''\n\n if (event === EMPTY_INPUT) {\n onChange(event)\n } else {\n const amount = Number(event)\n const normalisedValue = applyMinMax(amount)\n\n onChange(normalisedValue)\n }\n }\n // Increment or decrement the value when clicking the Spinner controls\n const incrementValue = (event: MouseEvent<HTMLButtonElement>) => {\n if (onChange === undefined) return\n event.preventDefault()\n const currentValue = Number(value) + step\n\n if (isInRange(currentValue)) {\n onChange(roundNumber(currentValue))\n }\n }\n\n const decrementValue = (event: MouseEvent<HTMLButtonElement>) => {\n if (onChange === undefined) return\n event.preventDefault()\n const currentValue = Number(value) - step\n\n if (isInRange(currentValue)) {\n onChange(roundNumber(currentValue))\n }\n }\n\n const frontIconToRender = frontIconComponent ? (\n <InputLeadingIconContainer $size={20} $iconColor={theme.color.text.subtle}>\n {frontIconComponent}\n </InputLeadingIconContainer>\n ) : frontIcon ? (\n <StyledFrontIcon $disabled={disabled} render={frontIcon} color=\"sesame\" />\n ) : null\n\n const trailingIconToRender = trailingIconComponent ? (\n <InputTrailingIconContainer $size={20} $iconColor={theme.color.text.subtle}>\n {trailingIconComponent}\n </InputTrailingIconContainer>\n ) : trailingIcon ? (\n <StyledTrailingIcon\n $disabled={disabled}\n render={trailingIcon}\n color=\"sesame\"\n />\n ) : null\n\n return (\n <Field {...fieldProps} htmlFor={id} error={error}>\n <Box flex alignItems=\"center\" justifyContent=\"flex-start\">\n {frontIconToRender}\n <Input\n ref={ref}\n $error={error}\n disabled={disabled}\n type={type}\n id={id}\n name={name}\n placeholder={placeholder}\n value={value}\n $frontIcon={Boolean(frontIconToRender)}\n step={step}\n $fallbackStyle={fallbackStyle}\n onWheel={(e) => e.currentTarget.blur()}\n onChange={(e: FormEvent<HTMLInputElement>) => {\n if (onChange) handleChange(e.currentTarget.value)\n onInputChange?.(e)\n }}\n onBlur={onBlur}\n />\n\n {onChange && step > 0 && (\n <Spinner>\n <SpinnerButton\n aria-label=\"step-up\"\n onClick={incrementValue}\n disabled={disabled}\n >\n <IconContainer $size={20}>\n <FontAwesomeIcon\n icon={faChevronDown}\n color={theme.color.text.subtle}\n />\n </IconContainer>\n </SpinnerButton>\n\n <SpinnerButton\n aria-label=\"step-down\"\n onClick={decrementValue}\n disabled={disabled}\n >\n <IconContainer $size={20}>\n <FontAwesomeIcon\n icon={faChevronUp}\n color={theme.color.text.subtle}\n />\n </IconContainer>\n </SpinnerButton>\n </Spinner>\n )}\n {trailingIconToRender && !step && trailingIconToRender}\n </Box>\n </Field>\n )\n})\n\nconst Spinner = styled.div`\n position: relative;\n display: flex;\n right: 58px;\n margin-right: -58px;\n`\n\ninterface IButton {\n disabled: boolean\n}\n\nconst SpinnerButton = styled.button<IButton>`\n width: 24px;\n height: 24px;\n background-color: transparent;\n border: 0;\n padding: 0;\n cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')};\n`\n"]}
|
|
1
|
+
{"version":3,"file":"NumberInput.js","sourceRoot":"","sources":["../../src/NumberInput/NumberInput.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n FocusEvent,\n FormEvent,\n ForwardedRef,\n MouseEvent,\n forwardRef,\n} from 'react'\nimport styled, { useTheme } from 'styled-components'\n\nimport { Box } from '../Box'\nimport { Field } from '../fields/Field'\nimport { CommonFieldProps } from '../fields/commonFieldTypes'\n\nimport {\n Input,\n InputLeadingIconContainer,\n InputTrailingIconContainer,\n StyledFrontIcon,\n StyledTrailingIcon,\n} from '../fields/components/CommonInput'\nimport { useUniqueId } from '../utils/id'\nimport { getFieldAria } from '../fields/fieldAria'\nimport {\n faChevronDown,\n faChevronUp,\n} from '@awesome.me/kit-46ca99185c/icons/classic/regular'\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\nimport { IconContainer } from '../sharedStyles/shared.styles'\n\nexport interface Props extends CommonFieldProps {\n type?: 'number'\n placeholder: string\n name?: string\n value: string\n onBlur?: (e: FocusEvent<HTMLInputElement>) => void\n min?: number\n max?: number\n step?: number\n}\n\n/** on change or on input required */\ntype InputProps =\n | {\n /** on change is required and on input optional */\n onChange: (e: string | number) => void\n onInputChange?: (e: FormEvent<HTMLInputElement>) => void\n }\n | {\n /** on input is required and on change optional */\n onChange?: (e: string | number) => void\n onInputChange: (e: FormEvent<HTMLInputElement>) => void\n }\n\nexport type NumberInputProps = Props & InputProps\n\nexport const NumberInput = forwardRef(function NumberInput(\n {\n id: idProp,\n type = 'number',\n placeholder,\n name,\n value,\n onChange,\n onInputChange,\n onBlur,\n min = -999999,\n max = 999999,\n step = 0,\n disabled = false,\n error = false,\n frontIcon,\n frontIconComponent,\n trailingIconComponent,\n trailingIcon,\n fallbackStyle,\n ...fieldProps\n }: NumberInputProps,\n ref: ForwardedRef<HTMLInputElement>,\n) {\n const id = useUniqueId(idProp)\n const { assistiveTextId, errorMsgId, controlAria } = getFieldAria(id, {\n ...fieldProps,\n error,\n })\n const theme = useTheme()\n // Check whether the min/max value exists is within the specified range\n const isInRange = (value: number) => {\n if (min && value < min) {\n return false\n }\n\n if (max && value > max) {\n return false\n }\n\n return true\n }\n\n // Round the number to two decimal places\n const roundNumber = (event: number) => {\n return Math.round(event * 100) / 100\n }\n\n const applyMinMax = (value: number) => {\n if (min && value < min) return min\n if (max && value > max) return max\n return value\n }\n\n const handleChange = (event: string) => {\n if (onChange === undefined) return\n const EMPTY_INPUT = ''\n\n if (event === EMPTY_INPUT) {\n onChange(event)\n } else {\n const amount = Number(event)\n const normalisedValue = applyMinMax(amount)\n\n onChange(normalisedValue)\n }\n }\n // Increment or decrement the value when clicking the Spinner controls\n const incrementValue = (event: MouseEvent<HTMLButtonElement>) => {\n if (onChange === undefined) return\n event.preventDefault()\n const currentValue = Number(value) + step\n\n if (isInRange(currentValue)) {\n onChange(roundNumber(currentValue))\n }\n }\n\n const decrementValue = (event: MouseEvent<HTMLButtonElement>) => {\n if (onChange === undefined) return\n event.preventDefault()\n const currentValue = Number(value) - step\n\n if (isInRange(currentValue)) {\n onChange(roundNumber(currentValue))\n }\n }\n\n const frontIconToRender = frontIconComponent ? (\n <InputLeadingIconContainer $size={20} $iconColor={theme.color.text.subtle}>\n {frontIconComponent}\n </InputLeadingIconContainer>\n ) : frontIcon ? (\n <StyledFrontIcon $disabled={disabled} render={frontIcon} color=\"sesame\" />\n ) : null\n\n const trailingIconToRender = trailingIconComponent ? (\n <InputTrailingIconContainer $size={20} $iconColor={theme.color.text.subtle}>\n {trailingIconComponent}\n </InputTrailingIconContainer>\n ) : trailingIcon ? (\n <StyledTrailingIcon\n $disabled={disabled}\n render={trailingIcon}\n color=\"sesame\"\n />\n ) : null\n\n return (\n <Field\n {...fieldProps}\n htmlFor={id}\n error={error}\n assistiveTextId={assistiveTextId}\n errorMsgId={errorMsgId}\n >\n <Box flex alignItems=\"center\" justifyContent=\"flex-start\">\n {frontIconToRender}\n <Input\n ref={ref}\n $error={error}\n disabled={disabled}\n type={type}\n id={id}\n name={name}\n placeholder={placeholder}\n value={value}\n $frontIcon={Boolean(frontIconToRender)}\n step={step}\n $fallbackStyle={fallbackStyle}\n onWheel={(e) => e.currentTarget.blur()}\n {...controlAria}\n onChange={(e: FormEvent<HTMLInputElement>) => {\n if (onChange) handleChange(e.currentTarget.value)\n onInputChange?.(e)\n }}\n onBlur={onBlur}\n />\n\n {onChange && step > 0 && (\n <Spinner>\n <SpinnerButton\n aria-label=\"Increase\"\n onClick={incrementValue}\n disabled={disabled}\n >\n <IconContainer $size={20}>\n <FontAwesomeIcon\n icon={faChevronDown}\n color={theme.color.text.subtle}\n />\n </IconContainer>\n </SpinnerButton>\n\n <SpinnerButton\n aria-label=\"Decrease\"\n onClick={decrementValue}\n disabled={disabled}\n >\n <IconContainer $size={20}>\n <FontAwesomeIcon\n icon={faChevronUp}\n color={theme.color.text.subtle}\n />\n </IconContainer>\n </SpinnerButton>\n </Spinner>\n )}\n {trailingIconToRender && !step && trailingIconToRender}\n </Box>\n </Field>\n )\n})\n\nconst Spinner = styled.div`\n position: relative;\n display: flex;\n right: 58px;\n margin-right: -58px;\n`\n\ninterface IButton {\n disabled: boolean\n}\n\nconst SpinnerButton = styled.button<IButton>`\n width: 24px;\n height: 24px;\n background-color: transparent;\n border: 0;\n padding: 0;\n cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')};\n`\n"]}
|
|
@@ -7,6 +7,7 @@ import { Field } from '../fields/Field';
|
|
|
7
7
|
import { Input, InputLeadingIconContainer, } from '../fields/components/CommonInput';
|
|
8
8
|
import { useOnClickOutside } from '../hooks';
|
|
9
9
|
import { useUniqueId } from '../utils/id';
|
|
10
|
+
import { getFieldAria } from '../fields/fieldAria';
|
|
10
11
|
import { useControllableState } from '../utils/useControlledState';
|
|
11
12
|
import { SearchOptions } from './components/SearchOptions';
|
|
12
13
|
import { visuallyHidden } from '../utils/visuallyHidden';
|
|
@@ -34,6 +35,10 @@ export const SearchInput = forwardRef(function SearchInput({ id: idProp, name =
|
|
|
34
35
|
const wrapperRef = useRef(null);
|
|
35
36
|
const theme = useTheme();
|
|
36
37
|
const id = useUniqueId(idProp);
|
|
38
|
+
const { assistiveTextId, errorMsgId, controlAria } = getFieldAria(id, {
|
|
39
|
+
...otherProps,
|
|
40
|
+
renderAsTitle,
|
|
41
|
+
});
|
|
37
42
|
const [showOptions, setShowOptions] = useState(false);
|
|
38
43
|
const [selectedValue, setSelectedValue] = useControllableState({
|
|
39
44
|
initialState: null,
|
|
@@ -192,14 +197,14 @@ export const SearchInput = forwardRef(function SearchInput({ id: idProp, name =
|
|
|
192
197
|
}
|
|
193
198
|
};
|
|
194
199
|
const showClearSearchButton = !!clearSearch && (!!value || !!selectedValue || !!searchQuery);
|
|
195
|
-
return (_jsxs(Wrapper, { ref: wrapperRef, children: [_jsxs(Field, { className: className, renderAsTitle: renderAsTitle, htmlFor: id, ...otherProps, children: [_jsxs(Box, { flex: true, alignItems: "center", justifyContent: "flex-start", children: [showIcon && (_jsx(InputLeadingIconContainer, { $size: 20, children: _jsx(FontAwesomeIcon, { icon: faSearch, color: theme.color.text.subtle }) })), _jsx(Input, { id: id, name: name, ref: ref, placeholder: placeholder, $error: otherProps.error, $frontIcon: showIcon, $fallbackStyle: fallbackStyle, autoComplete: "off", role: "combobox", "aria-autocomplete": "list", "aria-expanded": hasResults, "aria-controls": hasResults ? listboxId : undefined, "aria-activedescendant": hasHighlight ? getOptionId(highlightedIndex) : undefined, value: displayedInputText, onFocus: handleClick, onChange: handleInputChange, selected: isSelected, onClick: handleClick, onMouseDown: handleMouseDown, onKeyDown: (event) => {
|
|
200
|
+
return (_jsxs(Wrapper, { ref: wrapperRef, children: [_jsxs(Field, { className: className, renderAsTitle: renderAsTitle, htmlFor: id, assistiveTextId: assistiveTextId, errorMsgId: errorMsgId, ...otherProps, children: [_jsxs(Box, { flex: true, alignItems: "center", justifyContent: "flex-start", children: [showIcon && (_jsx(InputLeadingIconContainer, { $size: 20, children: _jsx(FontAwesomeIcon, { icon: faSearch, color: theme.color.text.subtle }) })), _jsx(Input, { id: id, name: name, ref: ref, placeholder: placeholder, $error: otherProps.error, $frontIcon: showIcon, $fallbackStyle: fallbackStyle, autoComplete: "off", role: "combobox", "aria-autocomplete": "list", "aria-expanded": hasResults, "aria-controls": hasResults ? listboxId : undefined, "aria-activedescendant": hasHighlight ? getOptionId(highlightedIndex) : undefined, value: displayedInputText, onFocus: handleClick, onChange: handleInputChange, selected: isSelected, onClick: handleClick, onMouseDown: handleMouseDown, onKeyDown: (event) => {
|
|
196
201
|
if (event.key === 'ArrowDown' && shouldSelectLabel) {
|
|
197
202
|
event.currentTarget.select();
|
|
198
203
|
}
|
|
199
204
|
handleKeyDown(event);
|
|
200
205
|
}, onBlur: (e) => {
|
|
201
206
|
onBlur?.(e);
|
|
202
|
-
} }), _jsxs(Icons, { flex: true, alignItems: "center", gap: "space.100", $clearSearch: showClearSearchButton, children: [showClearSearchButton && (_jsx(IconContainer, { title: "Clear search", onClick: handleClearSearch, type: "button", as: "button", $size: 20, style: { cursor: 'pointer' }, children: _jsx(FontAwesomeIcon, { icon: faXmark, color: theme.color.illustration.neutral[400] }) })), _jsx(Line, {}), _jsx(IconContainer, { type: "button", title: "icon-button", as: "button", onClick: handleCaretClick, $size: 20, children: _jsx(FontAwesomeIcon, { style: {
|
|
207
|
+
}, ...controlAria }), _jsxs(Icons, { flex: true, alignItems: "center", gap: "space.100", $clearSearch: showClearSearchButton, children: [showClearSearchButton && (_jsx(IconContainer, { title: "Clear search", onClick: handleClearSearch, type: "button", as: "button", $size: 20, style: { cursor: 'pointer' }, children: _jsx(FontAwesomeIcon, { icon: faXmark, color: theme.color.illustration.neutral[400] }) })), _jsx(Line, {}), _jsx(IconContainer, { type: "button", title: "icon-button", as: "button", onClick: handleCaretClick, $size: 20, children: _jsx(FontAwesomeIcon, { style: {
|
|
203
208
|
rotate: showOptions ? '180deg' : '0deg',
|
|
204
209
|
}, icon: faChevronDown, color: theme.color.illustration.neutral[400] }) })] })] }), showOptions && (_jsx(SearchOptions, { displayedList: filteredList, selectedValue: selectedValue, highlightedIndex: highlightedIndex, setHighlightedIndex: setHighlightedIndex, onKeyDown: handleKeyDown, listboxId: listboxId, listboxLabel: otherProps.label ?? placeholder ?? 'Search results', getOptionId: getOptionId, searchTerm: searchQuery || '', onSelect: handleSelect, positionRelative: resultsRelativePosition, resultsBorder: resultsBorder, onNotFound: onNotFound, onEmptyMessageChange: setEmptyMessage, notFoundComponent: notFoundComponent?.(searchQuery ?? '') }))] }), _jsx(LiveRegion, { role: "status", children: noResults ? emptyMessage : '' })] }));
|
|
205
210
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SearchInput.js","sourceRoot":"","sources":["../../src/SearchInput/SearchInput.tsx"],"names":[],"mappings":"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","sourcesContent":["import Fuse, { IFuseOptions } from 'fuse.js'\nimport {\n ChangeEvent,\n FocusEvent,\n MouseEvent,\n ReactNode,\n forwardRef,\n useMemo,\n useRef,\n useState,\n} from 'react'\nimport styled, { useTheme } from 'styled-components'\nimport { Box } from '../Box'\nimport { Field } from '../fields/Field'\nimport { CommonFieldProps } from '../fields/commonFieldTypes'\nimport {\n Input,\n InputLeadingIconContainer,\n} from '../fields/components/CommonInput'\nimport { useOnClickOutside } from '../hooks'\nimport { useUniqueId } from '../utils/id'\nimport { useControllableState } from '../utils/useControlledState'\nimport { SearchKeyEvent, SearchOptions } from './components/SearchOptions'\nimport { visuallyHidden } from '../utils/visuallyHidden'\nimport { IconContainer } from '../sharedStyles/shared.styles'\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\nimport {\n faXmark,\n faChevronDown,\n faSearch,\n} from '@awesome.me/kit-46ca99185c/icons/classic/regular'\n\nexport type SearchInputItem = {\n label: string\n value: string\n tags?: any[]\n}\n\nexport interface SearchInputProps extends CommonFieldProps {\n /** Optional input className */\n name?: string\n /** Optional placeholder text */\n placeholder?: string\n /** List of input items to search on*/\n searchList: SearchInputItem[]\n /** callback to handle found item click */\n onFound: (element: string) => void\n /** optional callback to run when no results found */\n onNotFound?: (searchTerm: string) => void\n /** optional Component to render when no results found */\n notFoundComponent?: (searchTerm: string) => ReactNode\n /** optional boolean to show search icon */\n showIcon?: boolean\n /** optional boolean to show a clear search button */\n clearSearch?: boolean\n /** Optional callback to run on blur */\n onBlur?: (e: FocusEvent<HTMLInputElement>) => void\n /** Optional default value for input */\n value?: string\n /** Optional boolean to move results to a realtive position */\n resultsRelativePosition?: boolean\n /** optional boolean to add border to results */\n resultsBorder?: boolean\n /** optional boolean to enable fuzzy search via fuse.js */\n enableFuzzySearch?: boolean\n /** optional config of fuzzy search\n * passing a value to this prop, automatically enables fuzzy search\n */\n fuzzySearchOptions?: IFuseOptions<SearchInputItem>\n}\n\nconst defaultFuzzySearchOptions = {\n keys: [\n {\n name: 'label',\n weight: 0.6,\n },\n {\n name: 'tags',\n weight: 0.4,\n },\n ],\n findAllMatches: true,\n minMatchCharLength: 1,\n location: 0,\n threshold: 0.45,\n distance: 55,\n}\n\nexport const SearchInput = forwardRef<HTMLInputElement, SearchInputProps>(\n function SearchInput(\n {\n id: idProp,\n name = 'search_input',\n className = '',\n placeholder,\n searchList,\n showIcon = false,\n renderAsTitle = false,\n value,\n onBlur,\n onFound,\n onNotFound,\n notFoundComponent,\n fallbackStyle,\n resultsRelativePosition = false,\n resultsBorder = true,\n enableFuzzySearch = false,\n fuzzySearchOptions,\n clearSearch,\n ...otherProps\n },\n ref,\n ) {\n const wrapperRef = useRef(null)\n const theme = useTheme()\n const id = useUniqueId(idProp)\n const [showOptions, setShowOptions] = useState(false)\n const [selectedValue, setSelectedValue] = useControllableState<\n string | null\n >({\n initialState: null,\n stateProp: value,\n })\n const [searchQuery, setSearchQuery] = useState<string | null>(null)\n const [highlightedIndex, setHighlightedIndex] = useState(-1)\n const [emptyMessage, setEmptyMessage] = useState('')\n\n const selectedValueLabel = searchList.find(\n (option) =>\n option.label === selectedValue || option.value === selectedValue,\n )?.label\n\n const handleBlur = () => {\n setSearchQuery(null)\n }\n\n // Every way of closing the list goes through here, so a reopened list\n // never starts with a stale highlighted option.\n const closeOptions = () => {\n setShowOptions(false)\n setHighlightedIndex(-1)\n }\n\n useOnClickOutside({\n ref: wrapperRef,\n callback: () => {\n handleBlur()\n closeOptions()\n },\n })\n\n const isFuzzySearch = enableFuzzySearch || !!fuzzySearchOptions\n\n const fuse = useMemo(() => {\n if (!isFuzzySearch) {\n return null\n }\n return new Fuse(searchList, {\n ...defaultFuzzySearchOptions,\n ...fuzzySearchOptions,\n })\n }, [isFuzzySearch, searchList, fuzzySearchOptions])\n\n const filteredList = useMemo(() => {\n if (searchQuery === null || searchQuery === '') {\n return searchList\n }\n\n if (fuse) {\n return fuse.search(searchQuery).map(({ item }) => item)\n }\n\n return searchList.filter(({ label }) =>\n label.toLowerCase().includes(searchQuery.toLocaleLowerCase()),\n )\n }, [searchQuery, searchList, fuse])\n\n // If the options change under a highlighted one (e.g. searchList is\n // swapped), clear the highlight so Enter can't pick a different option.\n // Compare values, not identity, so an inline searchList that re-renders\n // with the same options keeps the highlight.\n const optionsKey = useMemo(\n () => filteredList.map((option) => option.value).join('\\n'),\n [filteredList],\n )\n const [highlightedOptionsKey, setHighlightedOptionsKey] =\n useState(optionsKey)\n if (optionsKey !== highlightedOptionsKey) {\n setHighlightedOptionsKey(optionsKey)\n setHighlightedIndex(-1)\n }\n\n const getDisplayedInputText = () => {\n if (searchQuery !== null) {\n return searchQuery\n }\n if (selectedValue !== null) {\n return selectedValueLabel || ''\n }\n return ''\n }\n\n const isSelected = selectedValue !== null\n const displayedInputText = getDisplayedInputText()\n\n const updateSearchQuery = (query: string | null) => {\n setSearchQuery(query)\n setHighlightedIndex(-1)\n\n if (query === null) {\n setSelectedValue(null)\n closeOptions()\n } else {\n setShowOptions(true)\n }\n }\n\n // Reopening a field with a selection usually means changing it, so\n // select the label and let typing replace it rather than append to it\n const shouldSelectLabel =\n !showOptions && searchQuery === null && selectedValue !== null\n\n const handleMouseDown = (event: MouseEvent<HTMLInputElement>) => {\n // Focus and select ourselves, so the browser doesn't place a caret\n // (Safari can otherwise undo the selection on mouseup)\n const input = event.currentTarget\n if (shouldSelectLabel && document.activeElement !== input) {\n event.preventDefault()\n input.focus()\n }\n }\n\n const handleClick = (event: { currentTarget: HTMLInputElement }) => {\n if (shouldSelectLabel) {\n event.currentTarget.select()\n }\n setShowOptions(true)\n if (searchQuery !== null) {\n updateSearchQuery(searchQuery)\n setShowOptions(true)\n }\n }\n\n const handleInputChange = (event: ChangeEvent<HTMLInputElement>): void => {\n const nextValue = event.currentTarget.value\n updateSearchQuery(nextValue)\n }\n\n const handleSelect = (nextValue: SearchInputItem): void => {\n updateSearchQuery(null)\n setSelectedValue(nextValue.label)\n onFound(nextValue.value)\n }\n\n const handleClearSearch = () => {\n updateSearchQuery(null)\n setSelectedValue(null)\n onFound('')\n }\n\n const handleCaretClick = () => {\n if (showOptions) {\n closeOptions()\n } else {\n setShowOptions(true)\n }\n }\n\n const listboxId = `${id}-listbox`\n const getOptionId = (index: number) => `${id}-option-${index}`\n const hasResults = showOptions && filteredList.length > 0\n const hasHighlight =\n hasResults &&\n highlightedIndex >= 0 &&\n highlightedIndex < filteredList.length\n const noResults = showOptions && filteredList.length === 0\n\n const handleKeyDown = (event: SearchKeyEvent) => {\n if (event.key === 'Escape') {\n if (!showOptions) return\n event.preventDefault()\n event.stopPropagation()\n closeOptions()\n } else if (event.key === 'Enter') {\n if (hasHighlight) {\n event.preventDefault()\n handleSelect(filteredList[highlightedIndex])\n }\n } else if (event.key === 'ArrowDown') {\n event.preventDefault()\n if (!showOptions) {\n setShowOptions(true)\n } else if (filteredList.length > 0) {\n setHighlightedIndex((highlightedIndex + 1) % filteredList.length)\n }\n } else if (event.key === 'ArrowUp') {\n event.preventDefault()\n if (showOptions && filteredList.length > 0) {\n setHighlightedIndex(\n (highlightedIndex - 1 + filteredList.length) % filteredList.length,\n )\n }\n }\n }\n\n const showClearSearchButton =\n !!clearSearch && (!!value || !!selectedValue || !!searchQuery)\n\n return (\n <Wrapper ref={wrapperRef}>\n <Field\n className={className}\n renderAsTitle={renderAsTitle}\n htmlFor={id}\n {...otherProps}\n >\n <Box flex alignItems=\"center\" justifyContent=\"flex-start\">\n {showIcon && (\n <InputLeadingIconContainer $size={20}>\n <FontAwesomeIcon\n icon={faSearch}\n color={theme.color.text.subtle}\n />\n </InputLeadingIconContainer>\n )}\n <Input\n id={id}\n name={name}\n ref={ref}\n placeholder={placeholder}\n $error={otherProps.error}\n $frontIcon={showIcon}\n $fallbackStyle={fallbackStyle}\n autoComplete=\"off\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n aria-expanded={hasResults}\n aria-controls={hasResults ? listboxId : undefined}\n aria-activedescendant={\n hasHighlight ? getOptionId(highlightedIndex) : undefined\n }\n value={displayedInputText}\n onFocus={handleClick}\n onChange={handleInputChange}\n selected={isSelected}\n onClick={handleClick}\n onMouseDown={handleMouseDown}\n onKeyDown={(event) => {\n if (event.key === 'ArrowDown' && shouldSelectLabel) {\n event.currentTarget.select()\n }\n handleKeyDown(event)\n }}\n onBlur={(e) => {\n onBlur?.(e)\n }}\n />\n <Icons\n flex\n alignItems=\"center\"\n gap=\"space.100\"\n $clearSearch={showClearSearchButton}\n >\n {showClearSearchButton && (\n <IconContainer\n title=\"Clear search\"\n onClick={handleClearSearch}\n type=\"button\"\n as=\"button\"\n $size={20}\n style={{ cursor: 'pointer' }}\n >\n <FontAwesomeIcon\n icon={faXmark}\n color={theme.color.illustration.neutral[400]}\n />\n </IconContainer>\n )}\n <Line />\n <IconContainer\n type=\"button\"\n title=\"icon-button\"\n as=\"button\"\n onClick={handleCaretClick}\n $size={20}\n >\n <FontAwesomeIcon\n style={{\n rotate: showOptions ? '180deg' : '0deg',\n }}\n icon={faChevronDown}\n color={theme.color.illustration.neutral[400]}\n />\n </IconContainer>\n </Icons>\n </Box>\n\n {showOptions && (\n <SearchOptions\n displayedList={filteredList}\n selectedValue={selectedValue}\n highlightedIndex={highlightedIndex}\n setHighlightedIndex={setHighlightedIndex}\n onKeyDown={handleKeyDown}\n listboxId={listboxId}\n listboxLabel={otherProps.label ?? placeholder ?? 'Search results'}\n getOptionId={getOptionId}\n searchTerm={searchQuery || ''}\n onSelect={handleSelect}\n positionRelative={resultsRelativePosition}\n resultsBorder={resultsBorder}\n onNotFound={onNotFound}\n onEmptyMessageChange={setEmptyMessage}\n notFoundComponent={notFoundComponent?.(searchQuery ?? '')}\n />\n )}\n </Field>\n <LiveRegion role=\"status\">{noResults ? emptyMessage : ''}</LiveRegion>\n </Wrapper>\n )\n },\n)\n\nconst Wrapper = styled(Box)`\n position: relative;\n`\n\nconst LiveRegion = styled.div`\n ${visuallyHidden}\n`\n\nconst Line = styled(Box)`\n background: ${({ theme }) => theme.color.border.subtle};\n height: 24px;\n width: 1px;\n`\n\nconst Icons = styled(Box)<{ $clearSearch: boolean }>`\n position: relative;\n right: ${({ $clearSearch }) => ($clearSearch ? '80px' : '48px')};\n margin-right: ${({ $clearSearch }) => ($clearSearch ? '-80px' : '-48px')};\n`\n"]}
|
|
1
|
+
{"version":3,"file":"SearchInput.js","sourceRoot":"","sources":["../../src/SearchInput/SearchInput.tsx"],"names":[],"mappings":"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","sourcesContent":["import Fuse, { IFuseOptions } from 'fuse.js'\nimport {\n ChangeEvent,\n FocusEvent,\n MouseEvent,\n ReactNode,\n forwardRef,\n useMemo,\n useRef,\n useState,\n} from 'react'\nimport styled, { useTheme } from 'styled-components'\nimport { Box } from '../Box'\nimport { Field } from '../fields/Field'\nimport { CommonFieldProps } from '../fields/commonFieldTypes'\nimport {\n Input,\n InputLeadingIconContainer,\n} from '../fields/components/CommonInput'\nimport { useOnClickOutside } from '../hooks'\nimport { useUniqueId } from '../utils/id'\nimport { getFieldAria } from '../fields/fieldAria'\nimport { useControllableState } from '../utils/useControlledState'\nimport { SearchKeyEvent, SearchOptions } from './components/SearchOptions'\nimport { visuallyHidden } from '../utils/visuallyHidden'\nimport { IconContainer } from '../sharedStyles/shared.styles'\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\nimport {\n faXmark,\n faChevronDown,\n faSearch,\n} from '@awesome.me/kit-46ca99185c/icons/classic/regular'\n\nexport type SearchInputItem = {\n label: string\n value: string\n tags?: any[]\n}\n\nexport interface SearchInputProps extends CommonFieldProps {\n /** Optional input className */\n name?: string\n /** Optional placeholder text */\n placeholder?: string\n /** List of input items to search on*/\n searchList: SearchInputItem[]\n /** callback to handle found item click */\n onFound: (element: string) => void\n /** optional callback to run when no results found */\n onNotFound?: (searchTerm: string) => void\n /** optional Component to render when no results found */\n notFoundComponent?: (searchTerm: string) => ReactNode\n /** optional boolean to show search icon */\n showIcon?: boolean\n /** optional boolean to show a clear search button */\n clearSearch?: boolean\n /** Optional callback to run on blur */\n onBlur?: (e: FocusEvent<HTMLInputElement>) => void\n /** Optional default value for input */\n value?: string\n /** Optional boolean to move results to a realtive position */\n resultsRelativePosition?: boolean\n /** optional boolean to add border to results */\n resultsBorder?: boolean\n /** optional boolean to enable fuzzy search via fuse.js */\n enableFuzzySearch?: boolean\n /** optional config of fuzzy search\n * passing a value to this prop, automatically enables fuzzy search\n */\n fuzzySearchOptions?: IFuseOptions<SearchInputItem>\n}\n\nconst defaultFuzzySearchOptions = {\n keys: [\n {\n name: 'label',\n weight: 0.6,\n },\n {\n name: 'tags',\n weight: 0.4,\n },\n ],\n findAllMatches: true,\n minMatchCharLength: 1,\n location: 0,\n threshold: 0.45,\n distance: 55,\n}\n\nexport const SearchInput = forwardRef<HTMLInputElement, SearchInputProps>(\n function SearchInput(\n {\n id: idProp,\n name = 'search_input',\n className = '',\n placeholder,\n searchList,\n showIcon = false,\n renderAsTitle = false,\n value,\n onBlur,\n onFound,\n onNotFound,\n notFoundComponent,\n fallbackStyle,\n resultsRelativePosition = false,\n resultsBorder = true,\n enableFuzzySearch = false,\n fuzzySearchOptions,\n clearSearch,\n ...otherProps\n },\n ref,\n ) {\n const wrapperRef = useRef(null)\n const theme = useTheme()\n const id = useUniqueId(idProp)\n const { assistiveTextId, errorMsgId, controlAria } = getFieldAria(id, {\n ...otherProps,\n renderAsTitle,\n })\n const [showOptions, setShowOptions] = useState(false)\n const [selectedValue, setSelectedValue] = useControllableState<\n string | null\n >({\n initialState: null,\n stateProp: value,\n })\n const [searchQuery, setSearchQuery] = useState<string | null>(null)\n const [highlightedIndex, setHighlightedIndex] = useState(-1)\n const [emptyMessage, setEmptyMessage] = useState('')\n\n const selectedValueLabel = searchList.find(\n (option) =>\n option.label === selectedValue || option.value === selectedValue,\n )?.label\n\n const handleBlur = () => {\n setSearchQuery(null)\n }\n\n // Every way of closing the list goes through here, so a reopened list\n // never starts with a stale highlighted option.\n const closeOptions = () => {\n setShowOptions(false)\n setHighlightedIndex(-1)\n }\n\n useOnClickOutside({\n ref: wrapperRef,\n callback: () => {\n handleBlur()\n closeOptions()\n },\n })\n\n const isFuzzySearch = enableFuzzySearch || !!fuzzySearchOptions\n\n const fuse = useMemo(() => {\n if (!isFuzzySearch) {\n return null\n }\n return new Fuse(searchList, {\n ...defaultFuzzySearchOptions,\n ...fuzzySearchOptions,\n })\n }, [isFuzzySearch, searchList, fuzzySearchOptions])\n\n const filteredList = useMemo(() => {\n if (searchQuery === null || searchQuery === '') {\n return searchList\n }\n\n if (fuse) {\n return fuse.search(searchQuery).map(({ item }) => item)\n }\n\n return searchList.filter(({ label }) =>\n label.toLowerCase().includes(searchQuery.toLocaleLowerCase()),\n )\n }, [searchQuery, searchList, fuse])\n\n // If the options change under a highlighted one (e.g. searchList is\n // swapped), clear the highlight so Enter can't pick a different option.\n // Compare values, not identity, so an inline searchList that re-renders\n // with the same options keeps the highlight.\n const optionsKey = useMemo(\n () => filteredList.map((option) => option.value).join('\\n'),\n [filteredList],\n )\n const [highlightedOptionsKey, setHighlightedOptionsKey] =\n useState(optionsKey)\n if (optionsKey !== highlightedOptionsKey) {\n setHighlightedOptionsKey(optionsKey)\n setHighlightedIndex(-1)\n }\n\n const getDisplayedInputText = () => {\n if (searchQuery !== null) {\n return searchQuery\n }\n if (selectedValue !== null) {\n return selectedValueLabel || ''\n }\n return ''\n }\n\n const isSelected = selectedValue !== null\n const displayedInputText = getDisplayedInputText()\n\n const updateSearchQuery = (query: string | null) => {\n setSearchQuery(query)\n setHighlightedIndex(-1)\n\n if (query === null) {\n setSelectedValue(null)\n closeOptions()\n } else {\n setShowOptions(true)\n }\n }\n\n // Reopening a field with a selection usually means changing it, so\n // select the label and let typing replace it rather than append to it\n const shouldSelectLabel =\n !showOptions && searchQuery === null && selectedValue !== null\n\n const handleMouseDown = (event: MouseEvent<HTMLInputElement>) => {\n // Focus and select ourselves, so the browser doesn't place a caret\n // (Safari can otherwise undo the selection on mouseup)\n const input = event.currentTarget\n if (shouldSelectLabel && document.activeElement !== input) {\n event.preventDefault()\n input.focus()\n }\n }\n\n const handleClick = (event: { currentTarget: HTMLInputElement }) => {\n if (shouldSelectLabel) {\n event.currentTarget.select()\n }\n setShowOptions(true)\n if (searchQuery !== null) {\n updateSearchQuery(searchQuery)\n setShowOptions(true)\n }\n }\n\n const handleInputChange = (event: ChangeEvent<HTMLInputElement>): void => {\n const nextValue = event.currentTarget.value\n updateSearchQuery(nextValue)\n }\n\n const handleSelect = (nextValue: SearchInputItem): void => {\n updateSearchQuery(null)\n setSelectedValue(nextValue.label)\n onFound(nextValue.value)\n }\n\n const handleClearSearch = () => {\n updateSearchQuery(null)\n setSelectedValue(null)\n onFound('')\n }\n\n const handleCaretClick = () => {\n if (showOptions) {\n closeOptions()\n } else {\n setShowOptions(true)\n }\n }\n\n const listboxId = `${id}-listbox`\n const getOptionId = (index: number) => `${id}-option-${index}`\n const hasResults = showOptions && filteredList.length > 0\n const hasHighlight =\n hasResults &&\n highlightedIndex >= 0 &&\n highlightedIndex < filteredList.length\n const noResults = showOptions && filteredList.length === 0\n\n const handleKeyDown = (event: SearchKeyEvent) => {\n if (event.key === 'Escape') {\n if (!showOptions) return\n event.preventDefault()\n event.stopPropagation()\n closeOptions()\n } else if (event.key === 'Enter') {\n if (hasHighlight) {\n event.preventDefault()\n handleSelect(filteredList[highlightedIndex])\n }\n } else if (event.key === 'ArrowDown') {\n event.preventDefault()\n if (!showOptions) {\n setShowOptions(true)\n } else if (filteredList.length > 0) {\n setHighlightedIndex((highlightedIndex + 1) % filteredList.length)\n }\n } else if (event.key === 'ArrowUp') {\n event.preventDefault()\n if (showOptions && filteredList.length > 0) {\n setHighlightedIndex(\n (highlightedIndex - 1 + filteredList.length) % filteredList.length,\n )\n }\n }\n }\n\n const showClearSearchButton =\n !!clearSearch && (!!value || !!selectedValue || !!searchQuery)\n\n return (\n <Wrapper ref={wrapperRef}>\n <Field\n className={className}\n renderAsTitle={renderAsTitle}\n htmlFor={id}\n assistiveTextId={assistiveTextId}\n errorMsgId={errorMsgId}\n {...otherProps}\n >\n <Box flex alignItems=\"center\" justifyContent=\"flex-start\">\n {showIcon && (\n <InputLeadingIconContainer $size={20}>\n <FontAwesomeIcon\n icon={faSearch}\n color={theme.color.text.subtle}\n />\n </InputLeadingIconContainer>\n )}\n <Input\n id={id}\n name={name}\n ref={ref}\n placeholder={placeholder}\n $error={otherProps.error}\n $frontIcon={showIcon}\n $fallbackStyle={fallbackStyle}\n autoComplete=\"off\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n aria-expanded={hasResults}\n aria-controls={hasResults ? listboxId : undefined}\n aria-activedescendant={\n hasHighlight ? getOptionId(highlightedIndex) : undefined\n }\n value={displayedInputText}\n onFocus={handleClick}\n onChange={handleInputChange}\n selected={isSelected}\n onClick={handleClick}\n onMouseDown={handleMouseDown}\n onKeyDown={(event) => {\n if (event.key === 'ArrowDown' && shouldSelectLabel) {\n event.currentTarget.select()\n }\n handleKeyDown(event)\n }}\n onBlur={(e) => {\n onBlur?.(e)\n }}\n {...controlAria}\n />\n <Icons\n flex\n alignItems=\"center\"\n gap=\"space.100\"\n $clearSearch={showClearSearchButton}\n >\n {showClearSearchButton && (\n <IconContainer\n title=\"Clear search\"\n onClick={handleClearSearch}\n type=\"button\"\n as=\"button\"\n $size={20}\n style={{ cursor: 'pointer' }}\n >\n <FontAwesomeIcon\n icon={faXmark}\n color={theme.color.illustration.neutral[400]}\n />\n </IconContainer>\n )}\n <Line />\n <IconContainer\n type=\"button\"\n title=\"icon-button\"\n as=\"button\"\n onClick={handleCaretClick}\n $size={20}\n >\n <FontAwesomeIcon\n style={{\n rotate: showOptions ? '180deg' : '0deg',\n }}\n icon={faChevronDown}\n color={theme.color.illustration.neutral[400]}\n />\n </IconContainer>\n </Icons>\n </Box>\n\n {showOptions && (\n <SearchOptions\n displayedList={filteredList}\n selectedValue={selectedValue}\n highlightedIndex={highlightedIndex}\n setHighlightedIndex={setHighlightedIndex}\n onKeyDown={handleKeyDown}\n listboxId={listboxId}\n listboxLabel={otherProps.label ?? placeholder ?? 'Search results'}\n getOptionId={getOptionId}\n searchTerm={searchQuery || ''}\n onSelect={handleSelect}\n positionRelative={resultsRelativePosition}\n resultsBorder={resultsBorder}\n onNotFound={onNotFound}\n onEmptyMessageChange={setEmptyMessage}\n notFoundComponent={notFoundComponent?.(searchQuery ?? '')}\n />\n )}\n </Field>\n <LiveRegion role=\"status\">{noResults ? emptyMessage : ''}</LiveRegion>\n </Wrapper>\n )\n },\n)\n\nconst Wrapper = styled(Box)`\n position: relative;\n`\n\nconst LiveRegion = styled.div`\n ${visuallyHidden}\n`\n\nconst Line = styled(Box)`\n background: ${({ theme }) => theme.color.border.subtle};\n height: 24px;\n width: 1px;\n`\n\nconst Icons = styled(Box)<{ $clearSearch: boolean }>`\n position: relative;\n right: ${({ $clearSearch }) => ($clearSearch ? '80px' : '48px')};\n margin-right: ${({ $clearSearch }) => ($clearSearch ? '-80px' : '-48px')};\n`\n"]}
|
|
@@ -4,6 +4,7 @@ import { Box } from '../Box';
|
|
|
4
4
|
import { Field } from '../fields/Field';
|
|
5
5
|
import { Input, InputLeadingIconContainer, StyledFrontIcon, StyledTrailingIcon, } from '../fields/components/CommonInput';
|
|
6
6
|
import { useUniqueId } from '../utils/id';
|
|
7
|
+
import { getFieldAria } from '../fields/fieldAria';
|
|
7
8
|
import { useTheme } from 'styled-components';
|
|
8
9
|
/**
|
|
9
10
|
* A reusable TextInput component that supports various input types, custom styling, icons,
|
|
@@ -15,6 +16,10 @@ import { useTheme } from 'styled-components';
|
|
|
15
16
|
*/
|
|
16
17
|
export const TextInput = forwardRef(function TextInput({ id: idProp, type = 'text', placeholder, name, value, error = false, onBlur, onChange, onInputChange, onAutoFill, disabled = false, frontIcon, frontIconComponent, trailingIconComponent, trailingIcon, fallbackStyle, autoCompleteAttr = 'off', inputModeAttr, ...fieldProps }, ref) {
|
|
17
18
|
const id = useUniqueId(idProp);
|
|
19
|
+
const { assistiveTextId, errorMsgId, controlAria } = getFieldAria(id, {
|
|
20
|
+
...fieldProps,
|
|
21
|
+
error,
|
|
22
|
+
});
|
|
18
23
|
const theme = useTheme();
|
|
19
24
|
const handleAnimationEnd = (e) => {
|
|
20
25
|
if (e.animationName === 'onAutoFillStart' && onAutoFill && !!value) {
|
|
@@ -23,9 +28,9 @@ export const TextInput = forwardRef(function TextInput({ id: idProp, type = 'tex
|
|
|
23
28
|
};
|
|
24
29
|
const frontIconToRender = frontIconComponent ? (_jsx(InputLeadingIconContainer, { $size: 20, $iconColor: theme.color.text.subtle, children: frontIconComponent })) : frontIcon ? (_jsx(StyledFrontIcon, { $disabled: disabled, render: frontIcon, color: "color.icon.base" })) : null;
|
|
25
30
|
const trailingIconToRender = trailingIconComponent ? (_jsx(InputLeadingIconContainer, { $size: 20, $iconColor: theme.color.text.subtle, children: trailingIconComponent })) : trailingIcon ? (_jsx(StyledTrailingIcon, { $disabled: disabled, render: trailingIcon, color: "color.icon.base" })) : null;
|
|
26
|
-
return (_jsx(Field, { ...fieldProps, htmlFor: id, error: error, children: _jsxs(Box, { flex: true, alignItems: "center", justifyContent: "flex-start", children: [frontIconToRender, _jsx(Input, { disabled: disabled, type: type, id: id, name: name, ref: ref, onAnimationEnd: handleAnimationEnd, placeholder: placeholder, value: value, $error: error, $frontIcon: Boolean(frontIconToRender), $fallbackStyle: fallbackStyle, autoComplete: autoCompleteAttr, onChange: (e) => {
|
|
31
|
+
return (_jsx(Field, { ...fieldProps, htmlFor: id, error: error, assistiveTextId: assistiveTextId, errorMsgId: errorMsgId, children: _jsxs(Box, { flex: true, alignItems: "center", justifyContent: "flex-start", children: [frontIconToRender, _jsx(Input, { disabled: disabled, type: type, id: id, name: name, ref: ref, onAnimationEnd: handleAnimationEnd, placeholder: placeholder, value: value, $error: error, $frontIcon: Boolean(frontIconToRender), $fallbackStyle: fallbackStyle, autoComplete: autoCompleteAttr, onChange: (e) => {
|
|
27
32
|
onChange?.(e.currentTarget.value);
|
|
28
33
|
onInputChange?.(e);
|
|
29
|
-
}, onBlur: onBlur, inputMode: inputModeAttr }), trailingIconToRender] }) }));
|
|
34
|
+
}, onBlur: onBlur, inputMode: inputModeAttr, ...controlAria }), trailingIconToRender] }) }));
|
|
30
35
|
});
|
|
31
36
|
//# sourceMappingURL=TextInput.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextInput.js","sourceRoot":"","sources":["../../src/TextInput/TextInput.tsx"],"names":[],"mappings":";AAAA,OAAO,EAKL,UAAU,GAEX,MAAM,OAAO,CAAA;AAEd,OAAO,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAA;AAC5B,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AAEvC,OAAO,EACL,KAAK,EACL,yBAAyB,EACzB,eAAe,EACf,kBAAkB,GACnB,MAAM,kCAAkC,CAAA;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAoC5C;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,UAAU,CAAC,SAAS,SAAS,CACpD,EACE,EAAE,EAAE,MAAM,EACV,IAAI,GAAG,MAAM,EACb,WAAW,EACX,IAAI,EACJ,KAAK,EACL,KAAK,GAAG,KAAK,EACb,MAAM,EACN,QAAQ,EACR,aAAa,EACb,UAAU,EACV,QAAQ,GAAG,KAAK,EAChB,SAAS,EACT,kBAAkB,EAClB,qBAAqB,EACrB,YAAY,EACZ,aAAa,EACb,gBAAgB,GAAG,KAAK,EACxB,aAAa,EACb,GAAG,UAAU,EACE,EACjB,GAAmC;IAEnC,MAAM,EAAE,GAAG,WAAW,CAAC,MAAM,CAAC,CAAA;IAC9B,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAA;IAExB,MAAM,kBAAkB,GAAG,CAAC,CAAmC,EAAE,EAAE;QACjE,IAAI,CAAC,CAAC,aAAa,KAAK,iBAAiB,IAAI,UAAU,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;YACnE,UAAU,EAAE,CAAA;QACd,CAAC;IACH,CAAC,CAAA;IAED,MAAM,iBAAiB,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAC7C,KAAC,yBAAyB,IAAC,KAAK,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,YACtE,kBAAkB,GACO,CAC7B,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CACd,KAAC,eAAe,IACd,SAAS,EAAE,QAAQ,EACnB,MAAM,EAAE,SAAS,EACjB,KAAK,EAAC,iBAAiB,GACvB,CACH,CAAC,CAAC,CAAC,IAAI,CAAA;IAER,MAAM,oBAAoB,GAAG,qBAAqB,CAAC,CAAC,CAAC,CACnD,KAAC,yBAAyB,IAAC,KAAK,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,YACtE,qBAAqB,GACI,CAC7B,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CACjB,KAAC,kBAAkB,IACjB,SAAS,EAAE,QAAQ,EACnB,MAAM,EAAE,YAAY,EACpB,KAAK,EAAC,iBAAiB,GACvB,CACH,CAAC,CAAC,CAAC,IAAI,CAAA;IAER,OAAO,CACL,KAAC,KAAK,
|
|
1
|
+
{"version":3,"file":"TextInput.js","sourceRoot":"","sources":["../../src/TextInput/TextInput.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n FocusEvent,\n AnimationEvent,\n FormEvent,\n ForwardedRef,\n forwardRef,\n HTMLInputAutoCompleteAttribute,\n} from 'react'\n\nimport { Box } from '../Box'\nimport { Field } from '../fields/Field'\nimport { CommonFieldProps } from '../fields/commonFieldTypes'\nimport {\n Input,\n InputLeadingIconContainer,\n StyledFrontIcon,\n StyledTrailingIcon,\n} from '../fields/components/CommonInput'\nimport { useUniqueId } from '../utils/id'\nimport { getFieldAria } from '../fields/fieldAria'\nimport { useTheme } from 'styled-components'\n\ninterface Props extends CommonFieldProps {\n type?: 'text' | 'email' | 'password' | 'time' | 'date' | 'tel'\n placeholder: string\n name?: string\n value: string\n onBlur?: (e: FocusEvent<HTMLInputElement>) => void\n /**\n * Triggers after animation end (animation duration is 2s),\n * the animation starts when a user selects or hovers over an autofill option\n */\n onAutoFill?: () => void\n}\n\ntype InputMode = 'text' | 'email' | 'numeric'\n\n/** on change or on input required */\ntype InputProps = (\n | {\n /** on change is required and on input optional */\n onChange: (e: string) => void\n onInputChange?: (e: FormEvent<HTMLInputElement>) => void\n }\n | {\n /** on input is required and on change optional */\n onChange?: (e: string) => void\n onInputChange: (e: FormEvent<HTMLInputElement>) => void\n }\n) & {\n autoCompleteAttr?: HTMLInputAutoCompleteAttribute\n inputModeAttr?: InputMode\n}\n\nexport type TextInputProps = Props & InputProps\n\n/**\n * A reusable TextInput component that supports various input types, custom styling, icons,\n * and autofill detection.\n *\n * ### Caveats:\n * - `onAutoFill` triggers after animation end (animation duration is 2s),\n * the animation starts when a user selects or hovers over an autofill option\n */\nexport const TextInput = forwardRef(function TextInput(\n {\n id: idProp,\n type = 'text',\n placeholder,\n name,\n value,\n error = false,\n onBlur,\n onChange,\n onInputChange,\n onAutoFill,\n disabled = false,\n frontIcon,\n frontIconComponent,\n trailingIconComponent,\n trailingIcon,\n fallbackStyle,\n autoCompleteAttr = 'off',\n inputModeAttr,\n ...fieldProps\n }: TextInputProps,\n ref: ForwardedRef<HTMLInputElement>,\n) {\n const id = useUniqueId(idProp)\n const { assistiveTextId, errorMsgId, controlAria } = getFieldAria(id, {\n ...fieldProps,\n error,\n })\n const theme = useTheme()\n\n const handleAnimationEnd = (e: AnimationEvent<HTMLInputElement>) => {\n if (e.animationName === 'onAutoFillStart' && onAutoFill && !!value) {\n onAutoFill()\n }\n }\n\n const frontIconToRender = frontIconComponent ? (\n <InputLeadingIconContainer $size={20} $iconColor={theme.color.text.subtle}>\n {frontIconComponent}\n </InputLeadingIconContainer>\n ) : frontIcon ? (\n <StyledFrontIcon\n $disabled={disabled}\n render={frontIcon}\n color=\"color.icon.base\"\n />\n ) : null\n\n const trailingIconToRender = trailingIconComponent ? (\n <InputLeadingIconContainer $size={20} $iconColor={theme.color.text.subtle}>\n {trailingIconComponent}\n </InputLeadingIconContainer>\n ) : trailingIcon ? (\n <StyledTrailingIcon\n $disabled={disabled}\n render={trailingIcon}\n color=\"color.icon.base\"\n />\n ) : null\n\n return (\n <Field\n {...fieldProps}\n htmlFor={id}\n error={error}\n assistiveTextId={assistiveTextId}\n errorMsgId={errorMsgId}\n >\n <Box flex alignItems=\"center\" justifyContent=\"flex-start\">\n {frontIconToRender}\n <Input\n disabled={disabled}\n type={type}\n id={id}\n name={name}\n ref={ref}\n onAnimationEnd={handleAnimationEnd}\n placeholder={placeholder}\n value={value}\n $error={error}\n $frontIcon={Boolean(frontIconToRender)}\n $fallbackStyle={fallbackStyle}\n autoComplete={autoCompleteAttr}\n onChange={(e: FormEvent<HTMLInputElement>) => {\n onChange?.(e.currentTarget.value)\n onInputChange?.(e)\n }}\n onBlur={onBlur}\n inputMode={inputModeAttr}\n {...controlAria}\n />\n {trailingIconToRender}\n </Box>\n </Field>\n )\n})\n"]}
|
|
@@ -3,12 +3,17 @@ import { forwardRef } from 'react';
|
|
|
3
3
|
import styled from 'styled-components';
|
|
4
4
|
import { Field } from '../fields/Field';
|
|
5
5
|
import { useUniqueId } from '../utils/id';
|
|
6
|
+
import { getFieldAria } from '../fields/fieldAria';
|
|
6
7
|
export const Textarea = forwardRef(function Textarea({ id: idProp, name, value, onChange, onInputChange, resize = 'none', error = false, placeholder, disabled = false, maxLength, onBlur, rows = 4, fallbackStyle, ...fieldProps }, ref) {
|
|
7
8
|
const id = useUniqueId(idProp);
|
|
8
|
-
|
|
9
|
+
const { assistiveTextId, errorMsgId, controlAria } = getFieldAria(id, {
|
|
10
|
+
...fieldProps,
|
|
11
|
+
error,
|
|
12
|
+
});
|
|
13
|
+
return (_jsx(Field, { ...fieldProps, htmlFor: id, error: error, assistiveTextId: assistiveTextId, errorMsgId: errorMsgId, children: _jsx(StyledTextArea, { ref: ref, $error: error, id: id, name: name, disabled: disabled, $resize: resize, $fallbackStyle: fallbackStyle, placeholder: placeholder, value: value, onChange: (e) => {
|
|
9
14
|
onChange?.(e.currentTarget.value);
|
|
10
15
|
onInputChange?.(e);
|
|
11
|
-
}, maxLength: maxLength, onBlur: onBlur, rows: rows }) }));
|
|
16
|
+
}, maxLength: maxLength, onBlur: onBlur, rows: rows, ...controlAria }) }));
|
|
12
17
|
});
|
|
13
18
|
const StyledTextArea = styled.textarea `
|
|
14
19
|
font-size: 16px;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Textarea.js","sourceRoot":"","sources":["../../src/Textarea/Textarea.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAuC,UAAU,EAAE,MAAM,OAAO,CAAA;AACvE,OAAO,MAAM,MAAM,mBAAmB,CAAA;AAEtC,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AAEvC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AA+
|
|
1
|
+
{"version":3,"file":"Textarea.js","sourceRoot":"","sources":["../../src/Textarea/Textarea.tsx"],"names":[],"mappings":"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","sourcesContent":["import { FocusEvent, FormEvent, ForwardedRef, forwardRef } from 'react'\nimport styled from 'styled-components'\n\nimport { Field } from '../fields/Field'\nimport { CommonFieldProps } from '../fields/commonFieldTypes'\nimport { useUniqueId } from '../utils/id'\nimport { getFieldAria } from '../fields/fieldAria'\nimport { MarginProps } from '../utils/space'\n\ntype BaseProps = {\n id?: string\n placeholder?: string\n name?: string\n value: string\n error?: boolean\n errorMsg?: string\n resize?: 'none' | 'both'\n disabled?: boolean\n maxLength?: number\n onBlur?: (e: FocusEvent<HTMLTextAreaElement>) => void\n rows?: number\n fallbackStyle?: boolean\n} & CommonFieldProps &\n MarginProps\n\ntype TruncateProps =\n | {\n onChange: (e: string) => void\n onInputChange?: (e: FormEvent<HTMLTextAreaElement>) => void\n }\n | {\n onChange?: (e: string) => void\n onInputChange: (e: FormEvent<HTMLTextAreaElement>) => void\n }\n\nexport type TextareaProps = BaseProps & TruncateProps\n\nexport const Textarea = forwardRef(function Textarea(\n {\n id: idProp,\n name,\n value,\n onChange,\n onInputChange,\n resize = 'none',\n error = false,\n placeholder,\n disabled = false,\n maxLength,\n onBlur,\n rows = 4,\n fallbackStyle,\n ...fieldProps\n }: TextareaProps,\n ref: ForwardedRef<HTMLTextAreaElement>,\n) {\n const id = useUniqueId(idProp)\n const { assistiveTextId, errorMsgId, controlAria } = getFieldAria(id, {\n ...fieldProps,\n error,\n })\n return (\n <Field\n {...fieldProps}\n htmlFor={id}\n error={error}\n assistiveTextId={assistiveTextId}\n errorMsgId={errorMsgId}\n >\n <StyledTextArea\n ref={ref}\n $error={error}\n id={id}\n name={name}\n disabled={disabled}\n $resize={resize}\n $fallbackStyle={fallbackStyle}\n placeholder={placeholder}\n value={value}\n onChange={(e: FormEvent<HTMLTextAreaElement>) => {\n onChange?.(e.currentTarget.value)\n onInputChange?.(e)\n }}\n maxLength={maxLength}\n onBlur={onBlur}\n rows={rows}\n {...controlAria}\n />\n </Field>\n )\n})\n\ninterface TextArea {\n $resize: 'none' | 'both'\n disabled: boolean\n $error: boolean\n $fallbackStyle?: boolean\n}\n\nconst StyledTextArea = styled.textarea<TextArea>`\n font-size: 16px;\n font: inherit;\n line-height: 20px;\n background: ${({ $fallbackStyle, theme }) =>\n $fallbackStyle\n ? theme.color.surface.base[300]\n : theme.color.background['000']};\n border: 2px solid ${({ theme }) => theme.color.border.subtle};\n box-sizing: border-box;\n border-radius: 12px;\n width: 100%;\n padding: 12px;\n color: ${({ theme }) => theme.color.text.base};\n resize: ${({ $resize }) => $resize};\n cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'text')};\n opacity: ${({ disabled }) => (disabled ? '0.5' : '1')};\n border-color: ${({ $error, theme }) =>\n $error ? theme.color.feedback.negative[200] : theme.color.border.subtle};\n outline: none;\n\n &:hover,\n &:focus,\n &:focus-visible {\n border-color: ${({ $error, theme }) =>\n $error ? theme.color.feedback.negative[200] : theme.color.border.base};\n }\n`\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { CommonFieldProps } from './commonFieldTypes';
|
|
2
|
+
type FieldAriaInput = Pick<CommonFieldProps, 'assistiveText' | 'label' | 'renderAsTitle' | 'error' | 'errorMsg' | 'required'>;
|
|
3
|
+
/**
|
|
4
|
+
* Ids for a field's help and error text, and the ARIA attributes for its control.
|
|
5
|
+
* `aria-describedby` only references messages that the Field actually renders.
|
|
6
|
+
*/
|
|
7
|
+
export declare const getFieldAria: (id: string, field: FieldAriaInput) => {
|
|
8
|
+
assistiveTextId: string;
|
|
9
|
+
errorMsgId: string;
|
|
10
|
+
controlAria: {
|
|
11
|
+
'aria-invalid': true | undefined;
|
|
12
|
+
'aria-required': true | undefined;
|
|
13
|
+
'aria-describedby': string | undefined;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ids for a field's help and error text, and the ARIA attributes for its control.
|
|
3
|
+
* `aria-describedby` only references messages that the Field actually renders.
|
|
4
|
+
*/
|
|
5
|
+
export const getFieldAria = (id, field) => {
|
|
6
|
+
const assistiveTextId = `${id}-assistive-text`;
|
|
7
|
+
const errorMsgId = `${id}-error`;
|
|
8
|
+
const showsAssistiveText = !!field.assistiveText && (!field.renderAsTitle || !!field.label);
|
|
9
|
+
const showsErrorMsg = !!field.error && !!field.errorMsg;
|
|
10
|
+
const describedBy = [showsAssistiveText && assistiveTextId, showsErrorMsg && errorMsgId]
|
|
11
|
+
.filter(Boolean)
|
|
12
|
+
.join(' ') || undefined;
|
|
13
|
+
return {
|
|
14
|
+
assistiveTextId,
|
|
15
|
+
errorMsgId,
|
|
16
|
+
controlAria: {
|
|
17
|
+
'aria-invalid': field.error || undefined,
|
|
18
|
+
'aria-required': field.required || undefined,
|
|
19
|
+
'aria-describedby': describedBy,
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=fieldAria.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fieldAria.js","sourceRoot":"","sources":["../../src/fields/fieldAria.ts"],"names":[],"mappings":"AAYA;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,EAAU,EAAE,KAAqB,EAAE,EAAE;IAChE,MAAM,eAAe,GAAG,GAAG,EAAE,iBAAiB,CAAA;IAC9C,MAAM,UAAU,GAAG,GAAG,EAAE,QAAQ,CAAA;IAEhC,MAAM,kBAAkB,GACtB,CAAC,CAAC,KAAK,CAAC,aAAa,IAAI,CAAC,CAAC,KAAK,CAAC,aAAa,IAAI,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IAClE,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAA;IAEvD,MAAM,WAAW,GACf,CAAC,kBAAkB,IAAI,eAAe,EAAE,aAAa,IAAI,UAAU,CAAC;SACjE,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,GAAG,CAAC,IAAI,SAAS,CAAA;IAE3B,OAAO;QACL,eAAe;QACf,UAAU;QACV,WAAW,EAAE;YACX,cAAc,EAAE,KAAK,CAAC,KAAK,IAAI,SAAS;YACxC,eAAe,EAAE,KAAK,CAAC,QAAQ,IAAI,SAAS;YAC5C,kBAAkB,EAAE,WAAW;SAChC;KACF,CAAA;AACH,CAAC,CAAA","sourcesContent":["import { CommonFieldProps } from './commonFieldTypes'\n\ntype FieldAriaInput = Pick<\n CommonFieldProps,\n | 'assistiveText'\n | 'label'\n | 'renderAsTitle'\n | 'error'\n | 'errorMsg'\n | 'required'\n>\n\n/**\n * Ids for a field's help and error text, and the ARIA attributes for its control.\n * `aria-describedby` only references messages that the Field actually renders.\n */\nexport const getFieldAria = (id: string, field: FieldAriaInput) => {\n const assistiveTextId = `${id}-assistive-text`\n const errorMsgId = `${id}-error`\n\n const showsAssistiveText =\n !!field.assistiveText && (!field.renderAsTitle || !!field.label)\n const showsErrorMsg = !!field.error && !!field.errorMsg\n\n const describedBy =\n [showsAssistiveText && assistiveTextId, showsErrorMsg && errorMsgId]\n .filter(Boolean)\n .join(' ') || undefined\n\n return {\n assistiveTextId,\n errorMsgId,\n controlAria: {\n 'aria-invalid': field.error || undefined,\n 'aria-required': field.required || undefined,\n 'aria-describedby': describedBy,\n },\n }\n}\n"]}
|