@simplybusiness/mobius 5.6.0 → 5.7.0
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 +12 -0
- package/dist/cjs/components/Combobox/Combobox.js +5 -4
- package/dist/cjs/components/Combobox/Combobox.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/types/components/Combobox/types.d.ts +18 -3
- package/package.json +1 -1
- package/src/components/Combobox/Combobox.tsx +12 -5
- package/src/components/Combobox/types.tsx +24 -6
- package/src/public-whitelist.test.ts +1 -1
|
@@ -6,7 +6,7 @@ import { Listbox } from "./Listbox"; // Import Listbox component
|
|
|
6
6
|
import { useComboboxHighlight } from "./useComboboxHighlight";
|
|
7
7
|
import { filterOptions, getOptionValue, isOptionGroup } from "./utils";
|
|
8
8
|
export const Combobox = /*#__PURE__*/ forwardRef((props, ref)=>{
|
|
9
|
-
const { defaultValue, options, onSelected, className, placeholder, icon } = props;
|
|
9
|
+
const { defaultValue, options, asyncOptions, onSelected, className, placeholder, icon } = props;
|
|
10
10
|
const fallbackRef = useRef(null);
|
|
11
11
|
const [inputValue, setInputValue] = useState(defaultValue || "");
|
|
12
12
|
const [isOpen, setIsOpen] = useState(false);
|
|
@@ -17,8 +17,8 @@ export const Combobox = /*#__PURE__*/ forwardRef((props, ref)=>{
|
|
|
17
17
|
const blurTimeoutRef = useRef(null);
|
|
18
18
|
useEffect(()=>{
|
|
19
19
|
const fetchOptions = async ()=>{
|
|
20
|
-
if (
|
|
21
|
-
const result = await
|
|
20
|
+
if (asyncOptions) {
|
|
21
|
+
const result = await asyncOptions(inputValue);
|
|
22
22
|
setFilteredOptions(result);
|
|
23
23
|
} else {
|
|
24
24
|
setFilteredOptions(filterOptions(options, inputValue));
|
|
@@ -27,7 +27,8 @@ export const Combobox = /*#__PURE__*/ forwardRef((props, ref)=>{
|
|
|
27
27
|
fetchOptions();
|
|
28
28
|
}, [
|
|
29
29
|
inputValue,
|
|
30
|
-
options
|
|
30
|
+
options,
|
|
31
|
+
asyncOptions
|
|
31
32
|
]);
|
|
32
33
|
const handleFocus = ()=>{
|
|
33
34
|
if (blurTimeoutRef.current) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/Combobox/Combobox.tsx"],"sourcesContent":["import classNames from \"classnames/dedupe\";\nimport { forwardRef, useEffect, useId, useRef, useState } from \"react\";\nimport type { ForwardedRefComponent } from \"../../types\";\nimport { TextField } from \"../TextField\";\nimport { Listbox } from \"./Listbox\"; // Import Listbox component\nimport type {\n ComboboxElementType,\n ComboboxOption,\n ComboboxOptions,\n ComboboxProps,\n ComboboxRef,\n} from \"./types\";\nimport { useComboboxHighlight } from \"./useComboboxHighlight\";\nimport { filterOptions, getOptionValue, isOptionGroup } from \"./utils\";\n\nexport const Combobox: ForwardedRefComponent<\n ComboboxProps,\n ComboboxElementType\n> = forwardRef((props: ComboboxProps, ref: ComboboxRef) => {\n const {
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/Combobox/Combobox.tsx"],"sourcesContent":["import classNames from \"classnames/dedupe\";\nimport { forwardRef, useEffect, useId, useRef, useState } from \"react\";\nimport type { ForwardedRefComponent } from \"../../types\";\nimport { TextField } from \"../TextField\";\nimport { Listbox } from \"./Listbox\"; // Import Listbox component\nimport type {\n ComboboxElementType,\n ComboboxOption,\n ComboboxOptions,\n ComboboxProps,\n ComboboxRef,\n} from \"./types\";\nimport { useComboboxHighlight } from \"./useComboboxHighlight\";\nimport { filterOptions, getOptionValue, isOptionGroup } from \"./utils\";\n\nexport const Combobox: ForwardedRefComponent<\n ComboboxProps,\n ComboboxElementType\n> = forwardRef((props: ComboboxProps, ref: ComboboxRef) => {\n const {\n defaultValue,\n options,\n asyncOptions,\n onSelected,\n className,\n placeholder,\n icon,\n } = props;\n\n const fallbackRef = useRef<HTMLInputElement>(null);\n const [inputValue, setInputValue] = useState(defaultValue || \"\");\n const [isOpen, setIsOpen] = useState(false);\n const [filteredOptions, setFilteredOptions] = useState<ComboboxOptions>([]);\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 blurTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n\n useEffect(() => {\n const fetchOptions = async () => {\n if (asyncOptions) {\n const result = await asyncOptions(inputValue);\n setFilteredOptions(result);\n } else {\n setFilteredOptions(filterOptions(options, inputValue));\n }\n };\n\n fetchOptions();\n }, [inputValue, options, asyncOptions]);\n\n const handleFocus = () => {\n if (blurTimeoutRef.current) {\n clearTimeout(blurTimeoutRef.current);\n blurTimeoutRef.current = null;\n }\n setIsOpen(true);\n };\n\n const handleBlur = () => {\n blurTimeoutRef.current = setTimeout(() => {\n setIsOpen(false);\n }, 150);\n };\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value;\n setInputValue(newValue);\n setIsOpen(true);\n clearHighlight();\n };\n\n const handleOptionSelect = (option: ComboboxOption) => {\n const value = getOptionValue(option);\n if (!value) return;\n setIsOpen(false);\n setInputValue(value);\n onSelected?.(value);\n };\n\n function 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 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 handleOptionSelect(getHighlightedOption()!);\n }\n break;\n case \"Escape\":\n e.preventDefault();\n setIsOpen(false);\n clearHighlight();\n break;\n default:\n // Do nothing\n }\n };\n\n const classes = classNames(\n \"mobius mobius-combobox\",\n { expanded: isOpen },\n className,\n );\n\n return (\n <div className={classes}>\n <TextField\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-autocomplete=\"list\"\n aria-haspopup=\"listbox\"\n aria-controls={listboxId}\n aria-expanded={isOpen}\n aria-activedescendant={\n highlightedIndex === -1\n ? undefined\n : `${listboxId}-option-${highlightedGroupIndex}-${highlightedIndex}`\n }\n prefixInside={icon}\n ref={inputRef}\n />\n {isOpen && (\n <Listbox\n id={listboxId}\n options={filteredOptions}\n highlightedIndex={highlightedIndex}\n highlightedGroupIndex={highlightedGroupIndex}\n onOptionSelect={handleOptionSelect}\n expanded={isOpen}\n />\n )}\n </div>\n );\n});\n"],"names":["classNames","forwardRef","useEffect","useId","useRef","useState","TextField","Listbox","useComboboxHighlight","filterOptions","getOptionValue","isOptionGroup","Combobox","props","ref","defaultValue","options","asyncOptions","onSelected","className","placeholder","icon","fallbackRef","inputValue","setInputValue","isOpen","setIsOpen","filteredOptions","setFilteredOptions","highlightedIndex","highlightedGroupIndex","highlightNextOption","highlightPreviousOption","highlightFirstOption","highlightLastOption","clearHighlight","inputRef","listboxId","blurTimeoutRef","fetchOptions","result","handleFocus","current","clearTimeout","handleBlur","setTimeout","handleInputChange","e","newValue","target","value","handleOptionSelect","option","getHighlightedOption","undefined","group","handleKeyDown","key","preventDefault","classes","expanded","div","role","onFocus","onBlur","onKeyDown","onChange","autoComplete","aria-autocomplete","aria-haspopup","aria-controls","aria-expanded","aria-activedescendant","prefixInside","id","onOptionSelect"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/Combobox/types.tsx"],"sourcesContent":["import type { ReactElement, Ref } from \"react\";\nimport type { TextFieldElementType, TextFieldProps } from \"../TextField\";\n\nexport type
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/Combobox/types.tsx"],"sourcesContent":["import type { ReactElement, Ref } from \"react\";\nimport type { TextFieldElementType, TextFieldProps } from \"../TextField\";\n\nexport type ComboboxBaseProps = TextFieldProps & {\n /** An icon to display in TextField (left side) */\n icon?: ReactElement;\n /** The default value of the selected option */\n defaultValue?: string | undefined;\n /** Callback when the selected option changes */\n onSelected?: ((value: string) => void) | undefined;\n};\n\nexport type ComboboxSyncProps = ComboboxBaseProps & {\n /** The list of options to display in the dropdown */\n options: ComboboxOptions;\n asyncOptions?: never;\n delay?: never;\n minLength?: never;\n};\n\nexport type ComboboxAsyncProps = ComboboxBaseProps & {\n options?: never;\n delay?: number;\n minLength?: number;\n /** A function that returns a list of options to display in the dropdown */\n asyncOptions:\n | ((inputValue: string) => ComboboxOptions)\n | ((\n inputValue: string,\n options?: { signal?: AbortSignal },\n ) => Promise<ComboboxOptions>);\n};\n\nexport type ComboboxProps = ComboboxAsyncProps | ComboboxSyncProps;\n\nexport type ComboboxOption = string | { label: string; value: string };\n\nexport type ComboboxOptionGroup = {\n heading: string;\n options: ComboboxOption[];\n};\n\nexport type ComboboxOptions = ComboboxOption[] | ComboboxOptionGroup[];\n\nexport type ComboboxElementType = TextFieldElementType;\n\nexport type ComboboxRef = Ref<ComboboxElementType>;\n\nexport type ComboboxOptionProps = {\n option: ComboboxOption;\n index: number;\n groupIndex?: number;\n isHighlighted: boolean;\n onOptionSelect: (option: ComboboxOption) => void;\n id: string;\n};\n"],"names":[],"mappings":"AAgDA,WAOE"}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import type { ReactElement, Ref } from "react";
|
|
2
2
|
import type { TextFieldElementType, TextFieldProps } from "../TextField";
|
|
3
|
-
export type
|
|
4
|
-
/** The list of options to display in the dropdown */
|
|
5
|
-
options: ComboboxOptions | ((filter: string) => ComboboxOptions) | ((filter: string) => Promise<ComboboxOptions>);
|
|
3
|
+
export type ComboboxBaseProps = TextFieldProps & {
|
|
6
4
|
/** An icon to display in TextField (left side) */
|
|
7
5
|
icon?: ReactElement;
|
|
8
6
|
/** The default value of the selected option */
|
|
@@ -10,6 +8,23 @@ export type ComboboxProps = TextFieldProps & {
|
|
|
10
8
|
/** Callback when the selected option changes */
|
|
11
9
|
onSelected?: ((value: string) => void) | undefined;
|
|
12
10
|
};
|
|
11
|
+
export type ComboboxSyncProps = ComboboxBaseProps & {
|
|
12
|
+
/** The list of options to display in the dropdown */
|
|
13
|
+
options: ComboboxOptions;
|
|
14
|
+
asyncOptions?: never;
|
|
15
|
+
delay?: never;
|
|
16
|
+
minLength?: never;
|
|
17
|
+
};
|
|
18
|
+
export type ComboboxAsyncProps = ComboboxBaseProps & {
|
|
19
|
+
options?: never;
|
|
20
|
+
delay?: number;
|
|
21
|
+
minLength?: number;
|
|
22
|
+
/** A function that returns a list of options to display in the dropdown */
|
|
23
|
+
asyncOptions: ((inputValue: string) => ComboboxOptions) | ((inputValue: string, options?: {
|
|
24
|
+
signal?: AbortSignal;
|
|
25
|
+
}) => Promise<ComboboxOptions>);
|
|
26
|
+
};
|
|
27
|
+
export type ComboboxProps = ComboboxAsyncProps | ComboboxSyncProps;
|
|
13
28
|
export type ComboboxOption = string | {
|
|
14
29
|
label: string;
|
|
15
30
|
value: string;
|
package/package.json
CHANGED
|
@@ -17,8 +17,15 @@ export const Combobox: ForwardedRefComponent<
|
|
|
17
17
|
ComboboxProps,
|
|
18
18
|
ComboboxElementType
|
|
19
19
|
> = forwardRef((props: ComboboxProps, ref: ComboboxRef) => {
|
|
20
|
-
const {
|
|
21
|
-
|
|
20
|
+
const {
|
|
21
|
+
defaultValue,
|
|
22
|
+
options,
|
|
23
|
+
asyncOptions,
|
|
24
|
+
onSelected,
|
|
25
|
+
className,
|
|
26
|
+
placeholder,
|
|
27
|
+
icon,
|
|
28
|
+
} = props;
|
|
22
29
|
|
|
23
30
|
const fallbackRef = useRef<HTMLInputElement>(null);
|
|
24
31
|
const [inputValue, setInputValue] = useState(defaultValue || "");
|
|
@@ -40,8 +47,8 @@ export const Combobox: ForwardedRefComponent<
|
|
|
40
47
|
|
|
41
48
|
useEffect(() => {
|
|
42
49
|
const fetchOptions = async () => {
|
|
43
|
-
if (
|
|
44
|
-
const result = await
|
|
50
|
+
if (asyncOptions) {
|
|
51
|
+
const result = await asyncOptions(inputValue);
|
|
45
52
|
setFilteredOptions(result);
|
|
46
53
|
} else {
|
|
47
54
|
setFilteredOptions(filterOptions(options, inputValue));
|
|
@@ -49,7 +56,7 @@ export const Combobox: ForwardedRefComponent<
|
|
|
49
56
|
};
|
|
50
57
|
|
|
51
58
|
fetchOptions();
|
|
52
|
-
}, [inputValue, options]);
|
|
59
|
+
}, [inputValue, options, asyncOptions]);
|
|
53
60
|
|
|
54
61
|
const handleFocus = () => {
|
|
55
62
|
if (blurTimeoutRef.current) {
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import type { ReactElement, Ref } from "react";
|
|
2
2
|
import type { TextFieldElementType, TextFieldProps } from "../TextField";
|
|
3
3
|
|
|
4
|
-
export type
|
|
5
|
-
/** The list of options to display in the dropdown */
|
|
6
|
-
options:
|
|
7
|
-
| ComboboxOptions
|
|
8
|
-
| ((filter: string) => ComboboxOptions)
|
|
9
|
-
| ((filter: string) => Promise<ComboboxOptions>);
|
|
4
|
+
export type ComboboxBaseProps = TextFieldProps & {
|
|
10
5
|
/** An icon to display in TextField (left side) */
|
|
11
6
|
icon?: ReactElement;
|
|
12
7
|
/** The default value of the selected option */
|
|
@@ -15,6 +10,29 @@ export type ComboboxProps = TextFieldProps & {
|
|
|
15
10
|
onSelected?: ((value: string) => void) | undefined;
|
|
16
11
|
};
|
|
17
12
|
|
|
13
|
+
export type ComboboxSyncProps = ComboboxBaseProps & {
|
|
14
|
+
/** The list of options to display in the dropdown */
|
|
15
|
+
options: ComboboxOptions;
|
|
16
|
+
asyncOptions?: never;
|
|
17
|
+
delay?: never;
|
|
18
|
+
minLength?: never;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type ComboboxAsyncProps = ComboboxBaseProps & {
|
|
22
|
+
options?: never;
|
|
23
|
+
delay?: number;
|
|
24
|
+
minLength?: number;
|
|
25
|
+
/** A function that returns a list of options to display in the dropdown */
|
|
26
|
+
asyncOptions:
|
|
27
|
+
| ((inputValue: string) => ComboboxOptions)
|
|
28
|
+
| ((
|
|
29
|
+
inputValue: string,
|
|
30
|
+
options?: { signal?: AbortSignal },
|
|
31
|
+
) => Promise<ComboboxOptions>);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export type ComboboxProps = ComboboxAsyncProps | ComboboxSyncProps;
|
|
35
|
+
|
|
18
36
|
export type ComboboxOption = string | { label: string; value: string };
|
|
19
37
|
|
|
20
38
|
export type ComboboxOptionGroup = {
|