@simplybusiness/mobius 5.15.0 → 5.15.1
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/CHANGELOG.md +7 -0
- package/dist/cjs/components/Combobox/Combobox.js +5 -4
- package/dist/cjs/components/Combobox/Combobox.js.map +1 -1
- package/dist/cjs/components/Combobox/useComboboxOptions.js +3 -3
- package/dist/cjs/components/Combobox/useComboboxOptions.js.map +1 -1
- package/dist/cjs/components/TextField/TextField.js +2 -1
- package/dist/cjs/components/TextField/TextField.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/components/Combobox/Combobox.js +5 -4
- package/dist/esm/components/Combobox/Combobox.js.map +1 -1
- package/dist/esm/components/Combobox/types.js.map +1 -1
- package/dist/esm/components/Combobox/useComboboxOptions.js +3 -3
- package/dist/esm/components/Combobox/useComboboxOptions.js.map +1 -1
- package/dist/esm/components/TextField/TextField.js +2 -1
- package/dist/esm/components/TextField/TextField.js.map +1 -1
- package/dist/types/components/Combobox/types.d.ts +2 -2
- package/dist/types/components/Combobox/useComboboxOptions.d.ts +2 -2
- package/package.json +1 -1
- package/src/components/Combobox/Combobox.mdx +25 -0
- package/src/components/Combobox/Combobox.test.tsx +105 -168
- package/src/components/Combobox/Combobox.tsx +5 -4
- package/src/components/Combobox/types.tsx +2 -2
- package/src/components/Combobox/useComboboxOptions.test.ts +1 -1
- package/src/components/Combobox/useComboboxOptions.ts +4 -4
- package/src/components/TextField/TextField.tsx +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 5.15.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 734306e: Rename `minLength` property of `Combobox` to `minSearchLength` to avoid clashing with standard `minLength` DOM property
|
|
8
|
+
- 7e34f6f: Fix unknown `isReadOnly` prop on DOM in `TextField` component
|
|
9
|
+
|
|
3
10
|
## 5.15.0
|
|
4
11
|
|
|
5
12
|
### Minor Changes
|
|
@@ -24,7 +24,7 @@ function _interop_require_default(obj) {
|
|
|
24
24
|
};
|
|
25
25
|
}
|
|
26
26
|
const ComboboxInner = /*#__PURE__*/ (0, _react.forwardRef)((props, ref)=>{
|
|
27
|
-
const { id, defaultValue, options, asyncOptions, delay,
|
|
27
|
+
const { id, defaultValue, options, asyncOptions, delay, minSearchLength, onSelected, className, placeholder, icon, onBlur, onFocus, onChange, ...otherProps } = props;
|
|
28
28
|
// Avoid re-fetching after selecting an option
|
|
29
29
|
const skipNextDebounceRef = (0, _react.useRef)(false);
|
|
30
30
|
const fallbackRef = (0, _react.useRef)(null);
|
|
@@ -35,7 +35,7 @@ const ComboboxInner = /*#__PURE__*/ (0, _react.forwardRef)((props, ref)=>{
|
|
|
35
35
|
asyncOptions,
|
|
36
36
|
inputValue,
|
|
37
37
|
delay,
|
|
38
|
-
|
|
38
|
+
minSearchLength,
|
|
39
39
|
skipNextDebounceRef
|
|
40
40
|
});
|
|
41
41
|
const { highlightedIndex, highlightedGroupIndex, highlightNextOption, highlightPreviousOption, highlightFirstOption, highlightLastOption, clearHighlight } = (0, _useComboboxHighlight.useComboboxHighlight)(filteredOptions);
|
|
@@ -49,9 +49,10 @@ const ComboboxInner = /*#__PURE__*/ (0, _react.forwardRef)((props, ref)=>{
|
|
|
49
49
|
if (blurTimeoutRef.current) {
|
|
50
50
|
clearTimeout(blurTimeoutRef.current);
|
|
51
51
|
blurTimeoutRef.current = null;
|
|
52
|
+
} else {
|
|
53
|
+
onFocus === null || onFocus === void 0 ? void 0 : onFocus(e);
|
|
52
54
|
}
|
|
53
55
|
setIsOpen(true);
|
|
54
|
-
onFocus === null || onFocus === void 0 ? void 0 : onFocus(e);
|
|
55
56
|
};
|
|
56
57
|
(0, _hooks.useOnUnmount)(()=>{
|
|
57
58
|
if (blurTimeoutRef.current) {
|
|
@@ -113,9 +114,9 @@ const ComboboxInner = /*#__PURE__*/ (0, _react.forwardRef)((props, ref)=>{
|
|
|
113
114
|
handleOptionSelect(highlightedOption);
|
|
114
115
|
}
|
|
115
116
|
blurTimeoutRef.current = setTimeout(()=>{
|
|
117
|
+
onBlur === null || onBlur === void 0 ? void 0 : onBlur(e);
|
|
116
118
|
setIsOpen(false);
|
|
117
119
|
}, 150);
|
|
118
|
-
onBlur === null || onBlur === void 0 ? void 0 : onBlur(e);
|
|
119
120
|
};
|
|
120
121
|
const handleKeyDown = (e)=>{
|
|
121
122
|
switch(e.key){
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/Combobox/Combobox.tsx"],"sourcesContent":["import classNames from \"classnames/dedupe\";\nimport { FocusEvent, forwardRef, useId, useRef, useState } from \"react\";\nimport { useOnUnmount } from \"../../hooks\";\nimport { TextField } from \"../TextField\";\nimport { VisuallyHidden } from \"../VisuallyHidden\";\nimport { Listbox } from \"./Listbox\"; // Import Listbox component\nimport type { ComboboxOption, ComboboxProps, ComboboxRef } from \"./types\";\nimport { useComboboxHighlight } from \"./useComboboxHighlight\";\nimport { useComboboxOptions } from \"./useComboboxOptions\";\nimport { getOptionLabel, getOptionValue, isOptionGroup } from \"./utils\";\n\nconst ComboboxInner = forwardRef(\n <T extends ComboboxOption>(props: ComboboxProps<T>, ref: ComboboxRef) => {\n const {\n id,\n defaultValue,\n options,\n asyncOptions,\n delay,\n minLength,\n onSelected,\n className,\n placeholder,\n icon,\n onBlur,\n onFocus,\n onChange,\n ...otherProps\n } = props;\n\n // Avoid re-fetching after selecting an option\n const skipNextDebounceRef = useRef(false);\n const fallbackRef = useRef<HTMLInputElement>(null);\n const [inputValue, setInputValue] = useState(defaultValue || \"\");\n const [isOpen, setIsOpen] = useState(false);\n const { filteredOptions, updateFilteredOptions, isLoading } =\n useComboboxOptions({\n options,\n asyncOptions,\n inputValue,\n delay,\n minLength,\n skipNextDebounceRef,\n });\n const {\n highlightedIndex,\n highlightedGroupIndex,\n highlightNextOption,\n highlightPreviousOption,\n highlightFirstOption,\n highlightLastOption,\n clearHighlight,\n } = useComboboxHighlight(filteredOptions);\n\n const inputRef = ref || fallbackRef;\n const listboxId = useId();\n const statusId = useId();\n const blurTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n const showListbox = isOpen && filteredOptions.length > 0;\n\n const handleFocus = (e: FocusEvent) => {\n if (filteredOptions.length === 0) return;\n if (blurTimeoutRef.current) {\n clearTimeout(blurTimeoutRef.current);\n blurTimeoutRef.current = null;\n }\n setIsOpen(true);\n onFocus?.(e);\n };\n\n useOnUnmount(() => {\n if (blurTimeoutRef.current) {\n clearTimeout(blurTimeoutRef.current);\n }\n });\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value;\n setInputValue(newValue);\n setIsOpen(true);\n clearHighlight();\n onChange?.(e);\n };\n\n const handleOptionSelect = (option: T) => {\n const value = getOptionValue(option);\n if (!value) return;\n\n // TODO: Declare this in the types\n if (\n typeof option === \"object\" &&\n \"callback\" in option &&\n option.callback &&\n typeof option.callback === \"function\"\n ) {\n // @ts-expect-error ref types are hard\n setTimeout(() => inputRef.current.focus(), 0);\n updateFilteredOptions(option.callback());\n return;\n }\n\n // Prevent re-fetching options after selecting an option\n skipNextDebounceRef.current = true;\n\n setIsOpen(false);\n setInputValue(value);\n onSelected?.(option as T);\n };\n\n const getFirstOption = () => {\n if (isOptionGroup(filteredOptions)) {\n return filteredOptions[0]?.options[0];\n }\n\n return filteredOptions[0];\n };\n\n const getHighlightedOption = () => {\n if (highlightedIndex === -1) return undefined;\n\n if (isOptionGroup(filteredOptions)) {\n const group = filteredOptions[highlightedGroupIndex];\n return group?.options[highlightedIndex];\n }\n\n return filteredOptions[highlightedIndex];\n };\n\n const getHighlightedOptionId = () => {\n const option = getHighlightedOption();\n if (!option) return undefined;\n\n if (isOptionGroup(filteredOptions)) {\n return `${listboxId}-option-${highlightedGroupIndex}-${highlightedIndex}`;\n }\n\n return `${listboxId}-option-${highlightedIndex}`;\n };\n\n const handleBlur = (e: FocusEvent<Element, Element>) => {\n // Force selection if user has matched an entry\n const typedText = inputValue.trim().toLowerCase();\n const highlightedOption = getHighlightedOption();\n const label = getOptionLabel(highlightedOption);\n\n if (typedText === label?.toLowerCase()) {\n handleOptionSelect(highlightedOption as T);\n }\n\n blurTimeoutRef.current = setTimeout(() => {\n setIsOpen(false);\n }, 150);\n onBlur?.(e);\n };\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n switch (e.key) {\n case \"ArrowDown\":\n e.preventDefault();\n setIsOpen(true);\n highlightNextOption();\n break;\n case \"ArrowUp\":\n e.preventDefault();\n setIsOpen(true);\n highlightPreviousOption();\n break;\n case \"Home\":\n e.preventDefault();\n setIsOpen(true);\n highlightFirstOption();\n break;\n case \"End\":\n e.preventDefault();\n setIsOpen(true);\n highlightLastOption();\n break;\n case \"Enter\":\n e.preventDefault();\n if (isOpen) {\n const selectedOption = getHighlightedOption() || getFirstOption();\n if (selectedOption) {\n handleOptionSelect(selectedOption);\n }\n }\n break;\n case \"Escape\":\n e.preventDefault();\n setInputValue(\"\");\n setIsOpen(false);\n clearHighlight();\n break;\n default:\n // Do nothing\n }\n };\n\n const classes = classNames(\n \"mobius mobius-combobox\",\n {\n \"mobius-combobox--is-expanded\": isOpen,\n \"mobius-combobox--is-loading\": isLoading,\n },\n className,\n );\n\n return (\n <div id={id} data-testid=\"mobius-combobox__wrapper\" className={classes}>\n {isLoading && (\n <VisuallyHidden\n role=\"status\"\n aria-live=\"polite\"\n id={statusId}\n elementType=\"div\"\n className=\"mobius-combobox__status\"\n >\n Loading options\n </VisuallyHidden>\n )}\n <TextField\n {...otherProps}\n className=\"mobius-combobox__input\"\n role=\"combobox\"\n value={inputValue}\n placeholder={placeholder}\n onFocus={handleFocus}\n onBlur={handleBlur}\n onKeyDown={handleKeyDown}\n onChange={handleInputChange}\n autoComplete=\"off\"\n aria-describedby={isLoading ? statusId : undefined}\n aria-autocomplete=\"list\"\n aria-haspopup=\"listbox\"\n aria-controls={listboxId}\n aria-expanded={isOpen}\n aria-activedescendant={\n highlightedIndex === -1 ? undefined : getHighlightedOptionId()\n }\n prefixInside={icon}\n ref={inputRef}\n />\n {showListbox && (\n <Listbox\n id={listboxId}\n options={filteredOptions}\n highlightedIndex={highlightedIndex}\n highlightedGroupIndex={highlightedGroupIndex}\n onOptionSelect={handleOptionSelect}\n />\n )}\n </div>\n );\n },\n);\n\nexport const Combobox = ComboboxInner as <T extends ComboboxOption>(\n props: ComboboxProps<T> & { ref?: ComboboxRef },\n) => JSX.Element;\n"],"names":["Combobox","ComboboxInner","forwardRef","props","ref","id","defaultValue","options","asyncOptions","delay","minLength","onSelected","className","placeholder","icon","onBlur","onFocus","onChange","otherProps","skipNextDebounceRef","useRef","fallbackRef","inputValue","setInputValue","useState","isOpen","setIsOpen","filteredOptions","updateFilteredOptions","isLoading","useComboboxOptions","highlightedIndex","highlightedGroupIndex","highlightNextOption","highlightPreviousOption","highlightFirstOption","highlightLastOption","clearHighlight","useComboboxHighlight","inputRef","listboxId","useId","statusId","blurTimeoutRef","showListbox","length","handleFocus","e","current","clearTimeout","useOnUnmount","handleInputChange","newValue","target","value","handleOptionSelect","option","getOptionValue","callback","setTimeout","focus","getFirstOption","isOptionGroup","getHighlightedOption","undefined","group","getHighlightedOptionId","handleBlur","typedText","trim","toLowerCase","highlightedOption","label","getOptionLabel","handleKeyDown","key","preventDefault","selectedOption","classes","classNames","div","data-testid","VisuallyHidden","role","aria-live","elementType","TextField","onKeyDown","autoComplete","aria-describedby","aria-autocomplete","aria-haspopup","aria-controls","aria-expanded","aria-activedescendant","prefixInside","Listbox","onOptionSelect"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/Combobox/Combobox.tsx"],"sourcesContent":["import classNames from \"classnames/dedupe\";\nimport { FocusEvent, forwardRef, useId, useRef, useState } from \"react\";\nimport { useOnUnmount } from \"../../hooks\";\nimport { TextField } from \"../TextField\";\nimport { VisuallyHidden } from \"../VisuallyHidden\";\nimport { Listbox } from \"./Listbox\"; // Import Listbox component\nimport type { ComboboxOption, ComboboxProps, ComboboxRef } from \"./types\";\nimport { useComboboxHighlight } from \"./useComboboxHighlight\";\nimport { useComboboxOptions } from \"./useComboboxOptions\";\nimport { getOptionLabel, getOptionValue, isOptionGroup } from \"./utils\";\n\nconst ComboboxInner = forwardRef(\n <T extends ComboboxOption>(props: ComboboxProps<T>, ref: ComboboxRef) => {\n const {\n id,\n defaultValue,\n options,\n asyncOptions,\n delay,\n minSearchLength,\n onSelected,\n className,\n placeholder,\n icon,\n onBlur,\n onFocus,\n onChange,\n ...otherProps\n } = props;\n\n // Avoid re-fetching after selecting an option\n const skipNextDebounceRef = useRef(false);\n const fallbackRef = useRef<HTMLInputElement>(null);\n const [inputValue, setInputValue] = useState(defaultValue || \"\");\n const [isOpen, setIsOpen] = useState(false);\n const { filteredOptions, updateFilteredOptions, isLoading } =\n useComboboxOptions({\n options,\n asyncOptions,\n inputValue,\n delay,\n minSearchLength,\n skipNextDebounceRef,\n });\n const {\n highlightedIndex,\n highlightedGroupIndex,\n highlightNextOption,\n highlightPreviousOption,\n highlightFirstOption,\n highlightLastOption,\n clearHighlight,\n } = useComboboxHighlight(filteredOptions);\n\n const inputRef = ref || fallbackRef;\n const listboxId = useId();\n const statusId = useId();\n const blurTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n const showListbox = isOpen && filteredOptions.length > 0;\n\n const handleFocus = (e: FocusEvent) => {\n if (filteredOptions.length === 0) return;\n if (blurTimeoutRef.current) {\n clearTimeout(blurTimeoutRef.current);\n blurTimeoutRef.current = null;\n } else {\n onFocus?.(e);\n }\n setIsOpen(true);\n };\n\n useOnUnmount(() => {\n if (blurTimeoutRef.current) {\n clearTimeout(blurTimeoutRef.current);\n }\n });\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value;\n setInputValue(newValue);\n setIsOpen(true);\n clearHighlight();\n onChange?.(e);\n };\n\n const handleOptionSelect = (option: T) => {\n const value = getOptionValue(option);\n if (!value) return;\n\n // TODO: Declare this in the types\n if (\n typeof option === \"object\" &&\n \"callback\" in option &&\n option.callback &&\n typeof option.callback === \"function\"\n ) {\n // @ts-expect-error ref types are hard\n setTimeout(() => inputRef.current.focus(), 0);\n updateFilteredOptions(option.callback());\n return;\n }\n\n // Prevent re-fetching options after selecting an option\n skipNextDebounceRef.current = true;\n\n setIsOpen(false);\n setInputValue(value);\n onSelected?.(option as T);\n };\n\n const getFirstOption = () => {\n if (isOptionGroup(filteredOptions)) {\n return filteredOptions[0]?.options[0];\n }\n\n return filteredOptions[0];\n };\n\n const getHighlightedOption = () => {\n if (highlightedIndex === -1) return undefined;\n\n if (isOptionGroup(filteredOptions)) {\n const group = filteredOptions[highlightedGroupIndex];\n return group?.options[highlightedIndex];\n }\n\n return filteredOptions[highlightedIndex];\n };\n\n const getHighlightedOptionId = () => {\n const option = getHighlightedOption();\n if (!option) return undefined;\n\n if (isOptionGroup(filteredOptions)) {\n return `${listboxId}-option-${highlightedGroupIndex}-${highlightedIndex}`;\n }\n\n return `${listboxId}-option-${highlightedIndex}`;\n };\n\n const handleBlur = (e: FocusEvent<Element, Element>) => {\n // Force selection if user has matched an entry\n const typedText = inputValue.trim().toLowerCase();\n const highlightedOption = getHighlightedOption();\n const label = getOptionLabel(highlightedOption);\n\n if (typedText === label?.toLowerCase()) {\n handleOptionSelect(highlightedOption as T);\n }\n\n blurTimeoutRef.current = setTimeout(() => {\n onBlur?.(e);\n setIsOpen(false);\n }, 150);\n };\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n switch (e.key) {\n case \"ArrowDown\":\n e.preventDefault();\n setIsOpen(true);\n highlightNextOption();\n break;\n case \"ArrowUp\":\n e.preventDefault();\n setIsOpen(true);\n highlightPreviousOption();\n break;\n case \"Home\":\n e.preventDefault();\n setIsOpen(true);\n highlightFirstOption();\n break;\n case \"End\":\n e.preventDefault();\n setIsOpen(true);\n highlightLastOption();\n break;\n case \"Enter\":\n e.preventDefault();\n if (isOpen) {\n const selectedOption = getHighlightedOption() || getFirstOption();\n if (selectedOption) {\n handleOptionSelect(selectedOption);\n }\n }\n break;\n case \"Escape\":\n e.preventDefault();\n setInputValue(\"\");\n setIsOpen(false);\n clearHighlight();\n break;\n default:\n // Do nothing\n }\n };\n\n const classes = classNames(\n \"mobius mobius-combobox\",\n {\n \"mobius-combobox--is-expanded\": isOpen,\n \"mobius-combobox--is-loading\": isLoading,\n },\n className,\n );\n\n return (\n <div id={id} data-testid=\"mobius-combobox__wrapper\" className={classes}>\n {isLoading && (\n <VisuallyHidden\n role=\"status\"\n aria-live=\"polite\"\n id={statusId}\n elementType=\"div\"\n className=\"mobius-combobox__status\"\n >\n Loading options\n </VisuallyHidden>\n )}\n <TextField\n {...otherProps}\n className=\"mobius-combobox__input\"\n role=\"combobox\"\n value={inputValue}\n placeholder={placeholder}\n onFocus={handleFocus}\n onBlur={handleBlur}\n onKeyDown={handleKeyDown}\n onChange={handleInputChange}\n autoComplete=\"off\"\n aria-describedby={isLoading ? statusId : undefined}\n aria-autocomplete=\"list\"\n aria-haspopup=\"listbox\"\n aria-controls={listboxId}\n aria-expanded={isOpen}\n aria-activedescendant={\n highlightedIndex === -1 ? undefined : getHighlightedOptionId()\n }\n prefixInside={icon}\n ref={inputRef}\n />\n {showListbox && (\n <Listbox\n id={listboxId}\n options={filteredOptions}\n highlightedIndex={highlightedIndex}\n highlightedGroupIndex={highlightedGroupIndex}\n onOptionSelect={handleOptionSelect}\n />\n )}\n </div>\n );\n },\n);\n\nexport const Combobox = ComboboxInner as <T extends ComboboxOption>(\n props: ComboboxProps<T> & { ref?: ComboboxRef },\n) => JSX.Element;\n"],"names":["Combobox","ComboboxInner","forwardRef","props","ref","id","defaultValue","options","asyncOptions","delay","minSearchLength","onSelected","className","placeholder","icon","onBlur","onFocus","onChange","otherProps","skipNextDebounceRef","useRef","fallbackRef","inputValue","setInputValue","useState","isOpen","setIsOpen","filteredOptions","updateFilteredOptions","isLoading","useComboboxOptions","highlightedIndex","highlightedGroupIndex","highlightNextOption","highlightPreviousOption","highlightFirstOption","highlightLastOption","clearHighlight","useComboboxHighlight","inputRef","listboxId","useId","statusId","blurTimeoutRef","showListbox","length","handleFocus","e","current","clearTimeout","useOnUnmount","handleInputChange","newValue","target","value","handleOptionSelect","option","getOptionValue","callback","setTimeout","focus","getFirstOption","isOptionGroup","getHighlightedOption","undefined","group","getHighlightedOptionId","handleBlur","typedText","trim","toLowerCase","highlightedOption","label","getOptionLabel","handleKeyDown","key","preventDefault","selectedOption","classes","classNames","div","data-testid","VisuallyHidden","role","aria-live","elementType","TextField","onKeyDown","autoComplete","aria-describedby","aria-autocomplete","aria-haspopup","aria-controls","aria-expanded","aria-activedescendant","prefixInside","Listbox","onOptionSelect"],"mappings":"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"}
|
|
@@ -11,7 +11,7 @@ Object.defineProperty(exports, "useComboboxOptions", {
|
|
|
11
11
|
const _react = require("react");
|
|
12
12
|
const _utils = require("./utils");
|
|
13
13
|
const _hooks = require("../../hooks");
|
|
14
|
-
function useComboboxOptions({ options, asyncOptions, delay = 300,
|
|
14
|
+
function useComboboxOptions({ options, asyncOptions, delay = 300, minSearchLength = 3, inputValue = "", skipNextDebounceRef }) {
|
|
15
15
|
const [filteredOptions, setFilteredOptions] = (0, _react.useState)([]);
|
|
16
16
|
const debouncedInputValue = (0, _hooks.useDebouncedValue)(inputValue, // Don't debounce synchronous options
|
|
17
17
|
options ? 0 : delay);
|
|
@@ -25,7 +25,7 @@ function useComboboxOptions({ options, asyncOptions, delay = 300, minLength = 3,
|
|
|
25
25
|
setError(null);
|
|
26
26
|
try {
|
|
27
27
|
if (asyncOptions) {
|
|
28
|
-
if (debouncedInputValue.length <
|
|
28
|
+
if (debouncedInputValue.length < minSearchLength) {
|
|
29
29
|
setFilteredOptions([]);
|
|
30
30
|
return;
|
|
31
31
|
}
|
|
@@ -61,7 +61,7 @@ function useComboboxOptions({ options, asyncOptions, delay = 300, minLength = 3,
|
|
|
61
61
|
options,
|
|
62
62
|
asyncOptions,
|
|
63
63
|
delay,
|
|
64
|
-
|
|
64
|
+
minSearchLength,
|
|
65
65
|
skipNextDebounceRef
|
|
66
66
|
]);
|
|
67
67
|
function updateFilteredOptions(newOptions) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/Combobox/useComboboxOptions.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport type { ComboboxOption, ComboboxOptions, ComboboxProps } from \"./types\";\nimport { filterOptions } from \"./utils\";\nimport { useDebouncedValue } from \"../../hooks\";\n\nexport type UseComboboxOptionsProps<T extends ComboboxOption> = Pick<\n ComboboxProps<T>,\n \"options\" | \"asyncOptions\" | \"delay\" | \"
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/Combobox/useComboboxOptions.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport type { ComboboxOption, ComboboxOptions, ComboboxProps } from \"./types\";\nimport { filterOptions } from \"./utils\";\nimport { useDebouncedValue } from \"../../hooks\";\n\nexport type UseComboboxOptionsProps<T extends ComboboxOption> = Pick<\n ComboboxProps<T>,\n \"options\" | \"asyncOptions\" | \"delay\" | \"minSearchLength\"\n> & {\n skipNextDebounceRef?: React.MutableRefObject<boolean>;\n inputValue?: string;\n};\n\nexport function useComboboxOptions<T extends ComboboxOption>({\n options,\n asyncOptions,\n delay = 300,\n minSearchLength = 3,\n inputValue = \"\",\n skipNextDebounceRef,\n}: UseComboboxOptionsProps<T>) {\n const [filteredOptions, setFilteredOptions] = useState<ComboboxOptions<T>>(\n [],\n );\n const debouncedInputValue = useDebouncedValue(\n inputValue,\n // Don't debounce synchronous options\n options ? 0 : delay,\n );\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n useEffect(() => {\n const controller = new AbortController();\n const { signal } = controller;\n\n const fetchOptions = async () => {\n setIsLoading(true);\n setError(null);\n try {\n if (asyncOptions) {\n if (debouncedInputValue.length < minSearchLength) {\n setFilteredOptions([]);\n return;\n }\n const result = await asyncOptions(debouncedInputValue, { signal });\n setFilteredOptions(result);\n } else {\n // @ts-expect-error options is erroneously typed as possibly undefined\n setFilteredOptions(filterOptions(options, debouncedInputValue));\n }\n } catch (e: unknown) {\n if (e instanceof DOMException && e.name === \"AbortError\") {\n // Ignore abort errors\n return;\n }\n setError(e as Error);\n } finally {\n setIsLoading(false);\n }\n };\n\n if (!skipNextDebounceRef?.current) {\n fetchOptions();\n } else {\n // eslint-disable-next-line no-param-reassign\n skipNextDebounceRef.current = false;\n }\n\n return () => {\n controller.abort();\n };\n }, [\n debouncedInputValue,\n options,\n asyncOptions,\n delay,\n minSearchLength,\n skipNextDebounceRef,\n ]);\n\n function updateFilteredOptions(newOptions: Promise<ComboboxOptions<T>>) {\n setIsLoading(true);\n return newOptions\n .then(setFilteredOptions)\n .catch(setError)\n .finally(() => setIsLoading(false));\n }\n\n return {\n filteredOptions,\n updateFilteredOptions,\n isLoading,\n error,\n isError: error != null,\n };\n}\n"],"names":["useComboboxOptions","options","asyncOptions","delay","minSearchLength","inputValue","skipNextDebounceRef","filteredOptions","setFilteredOptions","useState","debouncedInputValue","useDebouncedValue","isLoading","setIsLoading","error","setError","useEffect","controller","AbortController","signal","fetchOptions","length","result","filterOptions","e","DOMException","name","current","abort","updateFilteredOptions","newOptions","then","catch","finally","isError"],"mappings":";;;;+BAagBA;;;eAAAA;;;uBAboB;uBAEN;uBACI;AAU3B,SAASA,mBAA6C,EAC3DC,OAAO,EACPC,YAAY,EACZC,QAAQ,GAAG,EACXC,kBAAkB,CAAC,EACnBC,aAAa,EAAE,EACfC,mBAAmB,EACQ;IAC3B,MAAM,CAACC,iBAAiBC,mBAAmB,GAAGC,IAAAA,eAAQ,EACpD,EAAE;IAEJ,MAAMC,sBAAsBC,IAAAA,wBAAiB,EAC3CN,YACA,qCAAqC;IACrCJ,UAAU,IAAIE;IAEhB,MAAM,CAACS,WAAWC,aAAa,GAAGJ,IAAAA,eAAQ,EAAC;IAC3C,MAAM,CAACK,OAAOC,SAAS,GAAGN,IAAAA,eAAQ,EAAe;IAEjDO,IAAAA,gBAAS,EAAC;QACR,MAAMC,aAAa,IAAIC;QACvB,MAAM,EAAEC,MAAM,EAAE,GAAGF;QAEnB,MAAMG,eAAe;YACnBP,aAAa;YACbE,SAAS;YACT,IAAI;gBACF,IAAIb,cAAc;oBAChB,IAAIQ,oBAAoBW,MAAM,GAAGjB,iBAAiB;wBAChDI,mBAAmB,EAAE;wBACrB;oBACF;oBACA,MAAMc,SAAS,MAAMpB,aAAaQ,qBAAqB;wBAAES;oBAAO;oBAChEX,mBAAmBc;gBACrB,OAAO;oBACL,sEAAsE;oBACtEd,mBAAmBe,IAAAA,oBAAa,EAACtB,SAASS;gBAC5C;YACF,EAAE,OAAOc,GAAY;gBACnB,IAAIA,aAAaC,gBAAgBD,EAAEE,IAAI,KAAK,cAAc;oBACxD,sBAAsB;oBACtB;gBACF;gBACAX,SAASS;YACX,SAAU;gBACRX,aAAa;YACf;QACF;QAEA,IAAI,EAACP,gCAAAA,0CAAAA,oBAAqBqB,OAAO,GAAE;YACjCP;QACF,OAAO;YACL,6CAA6C;YAC7Cd,oBAAoBqB,OAAO,GAAG;QAChC;QAEA,OAAO;YACLV,WAAWW,KAAK;QAClB;IACF,GAAG;QACDlB;QACAT;QACAC;QACAC;QACAC;QACAE;KACD;IAED,SAASuB,sBAAsBC,UAAuC;QACpEjB,aAAa;QACb,OAAOiB,WACJC,IAAI,CAACvB,oBACLwB,KAAK,CAACjB,UACNkB,OAAO,CAAC,IAAMpB,aAAa;IAChC;IAEA,OAAO;QACLN;QACAsB;QACAjB;QACAE;QACAoB,SAASpB,SAAS;IACpB;AACF"}
|
|
@@ -23,7 +23,8 @@ function _interop_require_default(obj) {
|
|
|
23
23
|
};
|
|
24
24
|
}
|
|
25
25
|
const TextField = /*#__PURE__*/ (0, _react.forwardRef)((props, ref)=>{
|
|
26
|
-
const { isDisabled, type = "text", validationState, isInvalid, className, label, errorMessage, children, isRequired, prefixInside, prefixOutside, suffixInside, suffixOutside,
|
|
26
|
+
const { isDisabled, type = "text", validationState, isInvalid, className, label, errorMessage, children, isRequired, prefixInside, prefixOutside, suffixInside, suffixOutside, // eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
27
|
+
isReadOnly, ...otherProps } = props;
|
|
27
28
|
const { inputProps, labelProps, errorMessageProps } = (0, _hooks.useTextField)({
|
|
28
29
|
...props,
|
|
29
30
|
"aria-errormessage": errorMessage
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/TextField/TextField.tsx"],"sourcesContent":["\"use client\";\n\nimport classNames from \"classnames/dedupe\";\nimport {\n HTMLInputTypeAttribute,\n ReactElement,\n ReactNode,\n Ref,\n RefAttributes,\n forwardRef,\n} from \"react\";\nimport {\n UseTextFieldProps,\n useTextField,\n useValidationClasses,\n} from \"../../hooks\";\nimport { DOMProps, FocusEvents } from \"../../types\";\nimport { ForwardedRefComponent } from \"../../types/components\";\nimport { ErrorMessage } from \"../ErrorMessage\";\nimport { Label } from \"../Label\";\nimport { Stack } from \"../Stack\";\nimport { adornmentWithClassName } from \"./adornmentWithClassName\";\n\nexport type TextFieldElementType = HTMLInputElement;\nexport interface TextFieldProps\n extends DOMProps,\n FocusEvents,\n UseTextFieldProps,\n RefAttributes<TextFieldElementType> {\n className?: string;\n errorMessage?: string;\n children?: ReactNode;\n label?: string;\n type?: Exclude<\n HTMLInputTypeAttribute,\n | \"button\"\n | \"checkbox\"\n | \"color\"\n | \"date\"\n | \"datetime-local\"\n | \"file\"\n | \"image\"\n | \"month\"\n | \"radio\"\n | \"range\"\n | \"reset\"\n | \"submit\"\n | \"week\"\n >;\n prefixInside?: ReactElement;\n prefixOutside?: ReactElement;\n suffixInside?: ReactElement;\n suffixOutside?: ReactElement;\n}\n\nexport type TextFieldRef = Ref<TextFieldElementType>;\n\nconst TextField: ForwardedRefComponent<TextFieldProps, TextFieldElementType> =\n forwardRef((props: TextFieldProps, ref: TextFieldRef) => {\n const {\n isDisabled,\n type = \"text\",\n validationState,\n isInvalid,\n className,\n label,\n errorMessage,\n children,\n isRequired,\n prefixInside,\n prefixOutside,\n suffixInside,\n suffixOutside,\n ...otherProps\n } = props;\n\n const { inputProps, labelProps, errorMessageProps } = useTextField({\n ...props,\n \"aria-errormessage\": errorMessage,\n });\n\n const hidden = type === \"hidden\";\n\n const validationClasses = useValidationClasses({\n validationState,\n isInvalid,\n });\n\n const textfieldClasses = {\n \"--is-disabled\": isDisabled,\n \"--is-required\": typeof isRequired === \"boolean\" && isRequired,\n \"--is-optional\": typeof isRequired === \"boolean\" && !isRequired,\n \"--is-hidden\": hidden,\n [className || \"\"]: true,\n };\n\n const sharedClasses = classNames(validationClasses, textfieldClasses);\n\n const labelClasses = classNames(\n {\n \"--is-disabled\": isDisabled,\n },\n validationClasses,\n );\n\n const containerClasses = classNames(\n \"mobius\",\n \"mobius-text-field\",\n sharedClasses,\n );\n\n const inputClasses = classNames(\n \"mobius\",\n \"mobius-text-field__input\",\n sharedClasses,\n );\n\n const inputWrapperClasses = classNames(\n \"mobius-text-field__input-wrapper\",\n sharedClasses,\n );\n\n return (\n <Stack gap=\"xs\" className={containerClasses}>\n {label && !hidden && (\n <Label {...labelProps} className={labelClasses}>\n {label}\n </Label>\n )}\n <div className=\"mobius-text-field__inner-container\">\n {adornmentWithClassName(\n prefixOutside,\n labelClasses,\n \"mobius-text-field__prefix-outside\",\n )}\n <div className={inputWrapperClasses}>\n {adornmentWithClassName(\n prefixInside,\n labelClasses,\n \"mobius-text-field__prefix-inside\",\n )}\n <input\n {...otherProps}\n {...inputProps}\n ref={ref}\n type={type}\n className={inputClasses}\n />\n {adornmentWithClassName(\n suffixInside,\n labelClasses,\n \"mobius-text-field__suffix-inside\",\n )}\n </div>\n {adornmentWithClassName(\n suffixOutside,\n labelClasses,\n \"mobius-text-field__suffix-outside\",\n )}\n </div>\n {children && (\n <div className=\"mobius-text-field__children\">{children}</div>\n )}\n\n <ErrorMessage {...errorMessageProps} errorMessage={errorMessage} />\n </Stack>\n );\n });\n\nTextField.displayName = \"TextField\";\nexport { TextField };\n"],"names":["TextField","forwardRef","props","ref","isDisabled","type","validationState","isInvalid","className","label","errorMessage","children","isRequired","prefixInside","prefixOutside","suffixInside","suffixOutside","otherProps","inputProps","labelProps","errorMessageProps","useTextField","hidden","validationClasses","useValidationClasses","textfieldClasses","sharedClasses","classNames","labelClasses","containerClasses","inputClasses","inputWrapperClasses","Stack","gap","Label","div","adornmentWithClassName","input","ErrorMessage","displayName"],"mappings":"AAAA;;;;;+
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/TextField/TextField.tsx"],"sourcesContent":["\"use client\";\n\nimport classNames from \"classnames/dedupe\";\nimport {\n HTMLInputTypeAttribute,\n ReactElement,\n ReactNode,\n Ref,\n RefAttributes,\n forwardRef,\n} from \"react\";\nimport {\n UseTextFieldProps,\n useTextField,\n useValidationClasses,\n} from \"../../hooks\";\nimport { DOMProps, FocusEvents } from \"../../types\";\nimport { ForwardedRefComponent } from \"../../types/components\";\nimport { ErrorMessage } from \"../ErrorMessage\";\nimport { Label } from \"../Label\";\nimport { Stack } from \"../Stack\";\nimport { adornmentWithClassName } from \"./adornmentWithClassName\";\n\nexport type TextFieldElementType = HTMLInputElement;\nexport interface TextFieldProps\n extends DOMProps,\n FocusEvents,\n UseTextFieldProps,\n RefAttributes<TextFieldElementType> {\n className?: string;\n errorMessage?: string;\n children?: ReactNode;\n label?: string;\n type?: Exclude<\n HTMLInputTypeAttribute,\n | \"button\"\n | \"checkbox\"\n | \"color\"\n | \"date\"\n | \"datetime-local\"\n | \"file\"\n | \"image\"\n | \"month\"\n | \"radio\"\n | \"range\"\n | \"reset\"\n | \"submit\"\n | \"week\"\n >;\n prefixInside?: ReactElement;\n prefixOutside?: ReactElement;\n suffixInside?: ReactElement;\n suffixOutside?: ReactElement;\n}\n\nexport type TextFieldRef = Ref<TextFieldElementType>;\n\nconst TextField: ForwardedRefComponent<TextFieldProps, TextFieldElementType> =\n forwardRef((props: TextFieldProps, ref: TextFieldRef) => {\n const {\n isDisabled,\n type = \"text\",\n validationState,\n isInvalid,\n className,\n label,\n errorMessage,\n children,\n isRequired,\n prefixInside,\n prefixOutside,\n suffixInside,\n suffixOutside,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n isReadOnly,\n ...otherProps\n } = props;\n\n const { inputProps, labelProps, errorMessageProps } = useTextField({\n ...props,\n \"aria-errormessage\": errorMessage,\n });\n\n const hidden = type === \"hidden\";\n\n const validationClasses = useValidationClasses({\n validationState,\n isInvalid,\n });\n\n const textfieldClasses = {\n \"--is-disabled\": isDisabled,\n \"--is-required\": typeof isRequired === \"boolean\" && isRequired,\n \"--is-optional\": typeof isRequired === \"boolean\" && !isRequired,\n \"--is-hidden\": hidden,\n [className || \"\"]: true,\n };\n\n const sharedClasses = classNames(validationClasses, textfieldClasses);\n\n const labelClasses = classNames(\n {\n \"--is-disabled\": isDisabled,\n },\n validationClasses,\n );\n\n const containerClasses = classNames(\n \"mobius\",\n \"mobius-text-field\",\n sharedClasses,\n );\n\n const inputClasses = classNames(\n \"mobius\",\n \"mobius-text-field__input\",\n sharedClasses,\n );\n\n const inputWrapperClasses = classNames(\n \"mobius-text-field__input-wrapper\",\n sharedClasses,\n );\n\n return (\n <Stack gap=\"xs\" className={containerClasses}>\n {label && !hidden && (\n <Label {...labelProps} className={labelClasses}>\n {label}\n </Label>\n )}\n <div className=\"mobius-text-field__inner-container\">\n {adornmentWithClassName(\n prefixOutside,\n labelClasses,\n \"mobius-text-field__prefix-outside\",\n )}\n <div className={inputWrapperClasses}>\n {adornmentWithClassName(\n prefixInside,\n labelClasses,\n \"mobius-text-field__prefix-inside\",\n )}\n <input\n {...otherProps}\n {...inputProps}\n ref={ref}\n type={type}\n className={inputClasses}\n />\n {adornmentWithClassName(\n suffixInside,\n labelClasses,\n \"mobius-text-field__suffix-inside\",\n )}\n </div>\n {adornmentWithClassName(\n suffixOutside,\n labelClasses,\n \"mobius-text-field__suffix-outside\",\n )}\n </div>\n {children && (\n <div className=\"mobius-text-field__children\">{children}</div>\n )}\n\n <ErrorMessage {...errorMessageProps} errorMessage={errorMessage} />\n </Stack>\n );\n });\n\nTextField.displayName = \"TextField\";\nexport { TextField };\n"],"names":["TextField","forwardRef","props","ref","isDisabled","type","validationState","isInvalid","className","label","errorMessage","children","isRequired","prefixInside","prefixOutside","suffixInside","suffixOutside","isReadOnly","otherProps","inputProps","labelProps","errorMessageProps","useTextField","hidden","validationClasses","useValidationClasses","textfieldClasses","sharedClasses","classNames","labelClasses","containerClasses","inputClasses","inputWrapperClasses","Stack","gap","Label","div","adornmentWithClassName","input","ErrorMessage","displayName"],"mappings":"AAAA;;;;;+BA4KSA;;;eAAAA;;;;+DA1Kc;uBAQhB;uBAKA;8BAGsB;uBACP;uBACA;wCACiB;;;;;;AAoCvC,MAAMA,0BACJC,IAAAA,iBAAU,EAAC,CAACC,OAAuBC;IACjC,MAAM,EACJC,UAAU,EACVC,OAAO,MAAM,EACbC,eAAe,EACfC,SAAS,EACTC,SAAS,EACTC,KAAK,EACLC,YAAY,EACZC,QAAQ,EACRC,UAAU,EACVC,YAAY,EACZC,aAAa,EACbC,YAAY,EACZC,aAAa,EACb,6DAA6D;IAC7DC,UAAU,EACV,GAAGC,YACJ,GAAGhB;IAEJ,MAAM,EAAEiB,UAAU,EAAEC,UAAU,EAAEC,iBAAiB,EAAE,GAAGC,IAAAA,mBAAY,EAAC;QACjE,GAAGpB,KAAK;QACR,qBAAqBQ;IACvB;IAEA,MAAMa,SAASlB,SAAS;IAExB,MAAMmB,oBAAoBC,IAAAA,2BAAoB,EAAC;QAC7CnB;QACAC;IACF;IAEA,MAAMmB,mBAAmB;QACvB,iBAAiBtB;QACjB,iBAAiB,OAAOQ,eAAe,aAAaA;QACpD,iBAAiB,OAAOA,eAAe,aAAa,CAACA;QACrD,eAAeW;QACf,CAACf,aAAa,GAAG,EAAE;IACrB;IAEA,MAAMmB,gBAAgBC,IAAAA,eAAU,EAACJ,mBAAmBE;IAEpD,MAAMG,eAAeD,IAAAA,eAAU,EAC7B;QACE,iBAAiBxB;IACnB,GACAoB;IAGF,MAAMM,mBAAmBF,IAAAA,eAAU,EACjC,UACA,qBACAD;IAGF,MAAMI,eAAeH,IAAAA,eAAU,EAC7B,UACA,4BACAD;IAGF,MAAMK,sBAAsBJ,IAAAA,eAAU,EACpC,oCACAD;IAGF,qBACE,sBAACM,YAAK;QAACC,KAAI;QAAK1B,WAAWsB;;YACxBrB,SAAS,CAACc,wBACT,qBAACY,YAAK;gBAAE,GAAGf,UAAU;gBAAEZ,WAAWqB;0BAC/BpB;;0BAGL,sBAAC2B;gBAAI5B,WAAU;;oBACZ6B,IAAAA,8CAAsB,EACrBvB,eACAe,cACA;kCAEF,sBAACO;wBAAI5B,WAAWwB;;4BACbK,IAAAA,8CAAsB,EACrBxB,cACAgB,cACA;0CAEF,qBAACS;gCACE,GAAGpB,UAAU;gCACb,GAAGC,UAAU;gCACdhB,KAAKA;gCACLE,MAAMA;gCACNG,WAAWuB;;4BAEZM,IAAAA,8CAAsB,EACrBtB,cACAc,cACA;;;oBAGHQ,IAAAA,8CAAsB,EACrBrB,eACAa,cACA;;;YAGHlB,0BACC,qBAACyB;gBAAI5B,WAAU;0BAA+BG;;0BAGhD,qBAAC4B,0BAAY;gBAAE,GAAGlB,iBAAiB;gBAAEX,cAAcA;;;;AAGzD;AAEFV,UAAUwC,WAAW,GAAG"}
|