@economic/taco 2.45.0-alpha.12 → 2.45.0-alpha.14

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.
@@ -4,8 +4,8 @@ import { isElementInsideTable3OrReport } from '../../utils/dom.js';
4
4
  import { v4 } from 'uuid';
5
5
  import debounce from 'lodash-es/debounce';
6
6
  import { getId } from '../Listbox/ScrollableList.js';
7
- import { createCustomKeyboardEvent } from '../../utils/input.js';
8
- import { useFlattenedData, filterData, getIndexFromValue, setInputValueByRef, findByValue, sanitizeItem, getOptionParents } from '../Listbox/util.js';
7
+ import { createCustomEvent, createCustomKeyboardEvent } from '../../utils/input.js';
8
+ import { useFlattenedData, filterData, getIndexFromValue, findByValue, sanitizeItem, getOptionParents } from '../Listbox/util.js';
9
9
 
10
10
  const debouncer = /*#__PURE__*/debounce(f => f(), 200);
11
11
  const convertToInputValue = value => String(value !== null && value !== void 0 ? value : '');
@@ -32,7 +32,6 @@ const useCombobox = ({
32
32
  const [open, setOpen] = useState(false);
33
33
  const listId = useMemo(() => v4(), []);
34
34
  const [inputValue, setInputValue] = useState(convertToInputValue(value));
35
- const inputValueRef = useRef(inputValue);
36
35
  const shouldFilterData = !onSearch && (!inline || inline && inputValue !== convertToInputValue(value));
37
36
  const flattenedData = useFlattenedData(unfilteredData);
38
37
  const data = useMemo(() => shouldFilterData ? filterData(flattenedData, inputValue) : flattenedData, [shouldFilterData, inputValue, flattenedData]);
@@ -42,7 +41,7 @@ const useCombobox = ({
42
41
  if (index !== undefined) {
43
42
  const option = data[index];
44
43
  if (option && !option.disabled) {
45
- setInputValueByRef(inputRef.current, option.value, 'focusout');
44
+ handleChange(option.value);
46
45
  }
47
46
  }
48
47
  };
@@ -64,7 +63,7 @@ const useCombobox = ({
64
63
  if (defaultValue && !value) {
65
64
  setInputValueByIndex(getIndexFromValue(data, defaultValue));
66
65
  }
67
- }, [data]);
66
+ }, [defaultValue]);
68
67
  // update input value if it changed 'externally', e.g. clicking/entering an item in the listbox, from a modal etc
69
68
  useEffect(() => {
70
69
  if (value !== undefined && value !== inputValue) {
@@ -99,28 +98,29 @@ const useCombobox = ({
99
98
  setCurrentIndex(undefined);
100
99
  }
101
100
  }, [open]);
101
+ const handleChange = nextValue => {
102
+ const event = createCustomEvent('change');
103
+ if (onChange && nextValue !== String(value)) {
104
+ const item = findByValue(flattenedData, nextValue);
105
+ event.detail = sanitizeItem(item);
106
+ const parents = getOptionParents(flattenedData, item === null || item === void 0 ? void 0 : item.path);
107
+ if (parents !== null && parents.length > 0) {
108
+ event.detail.parents = parents;
109
+ }
110
+ onChange(event);
111
+ }
112
+ };
102
113
  // event handlers
103
114
  const handleInputBlur = event => {
104
115
  if (listRef.current && event.relatedTarget === listRef.current) {
105
116
  event.preventDefault();
106
117
  return;
107
118
  }
108
- // event.target.value is always a string so it is important to cast value to a string before checking the equality
109
- if (onChange && event.target.value !== String(value)) {
110
- const item = findByValue(flattenedData, event.target.value || inputValueRef.current);
111
- event.detail = sanitizeItem(item);
112
- const parents = getOptionParents(flattenedData, item === null || item === void 0 ? void 0 : item.path);
113
- if (parents !== null && parents.length > 0) {
114
- event.detail.parents = parents;
115
- }
116
- const isComboboxChangeEvent = event => {
117
- return typeof event.detail === 'object'; // this makes sure we only take our own custom event, and not the browser default blur on tab.
118
- };
119
- // Only trigger onChange if this is our custom event (not a browser blur event)
120
- // or if the input was cleared.
121
- if (isComboboxChangeEvent(event) || event.target.value === '' && !inline) {
122
- onChange(event);
123
- }
119
+ // listbox is open
120
+ if (currentIndex !== undefined) {
121
+ handleChange(data[currentIndex].value);
122
+ } else if (inputValue === '') {
123
+ handleChange(undefined);
124
124
  }
125
125
  if (props.onBlur) {
126
126
  props.onBlur(event);
@@ -128,7 +128,6 @@ const useCombobox = ({
128
128
  };
129
129
  const handleInputChange = event => {
130
130
  setInputValue(event.target.value);
131
- inputValueRef.current = event.target.value;
132
131
  };
133
132
  const handleInputClick = event => {
134
133
  if (inline || !open && inputValue && data.length) {
@@ -154,7 +153,6 @@ const useCombobox = ({
154
153
  }
155
154
  case 'Tab':
156
155
  {
157
- setCurrentValue(currentIndex);
158
156
  setOpen(false);
159
157
  return;
160
158
  }
@@ -1 +1 @@
1
- {"version":3,"file":"useCombobox.js","sources":["../../../../../../../src/components/Combobox/useCombobox.tsx"],"sourcesContent":["import * as React from 'react';\nimport { v4 as uuid } from 'uuid';\nimport debounce from 'lodash/debounce';\nimport { ComboboxProps } from './Combobox';\nimport {\n setInputValueByRef,\n getIndexFromValue,\n findByValue,\n useFlattenedData,\n sanitizeItem,\n getOptionParents,\n filterData,\n} from '../Listbox/util';\nimport { createCustomKeyboardEvent } from '../../utils/input';\nimport { useMergedRef } from '../../hooks/useMergedRef';\nimport { getId, ScrollableListItemValue, ScrollableListPropsWithRef } from '../Listbox/ScrollableList';\nimport { InputProps } from '../Input/Input';\nimport { isElementInsideTable3OrReport } from '../../utils/dom';\n\nconst debouncer = debounce(f => f(), 200);\n\nconst convertToInputValue = (value: ScrollableListItemValue | undefined) => String(value ?? '');\n\ntype useCombobox = React.HTMLAttributes<HTMLDivElement> & {\n combobox: React.HTMLAttributes<HTMLSpanElement>;\n input: Omit<InputProps, 'defaultValue'> & { ref: React.RefObject<HTMLInputElement> };\n list: ScrollableListPropsWithRef;\n button: { ref: any };\n popover: { open: boolean; onOpenChange: (open: boolean) => void };\n};\n\nexport const useCombobox = (\n {\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n data: unfilteredData = [],\n defaultValue,\n disabled,\n id: nativeId,\n inline,\n loading: __,\n onChange,\n onClick,\n onKeyDown,\n onSearch,\n readOnly,\n value,\n ...props\n }: Omit<ComboboxProps, 'dialog'>,\n ref: React.Ref<HTMLInputElement>\n): useCombobox => {\n const inputRef = useMergedRef<HTMLInputElement>(ref);\n const buttonRef = React.useRef<HTMLButtonElement>(null);\n const listRef = React.useRef<HTMLUListElement>(null);\n const [open, setOpen] = React.useState(false);\n const listId = React.useMemo(() => uuid(), []);\n const [inputValue, setInputValue] = React.useState<string>(convertToInputValue(value));\n const inputValueRef = React.useRef<string>(inputValue);\n const shouldFilterData = !onSearch && (!inline || (inline && inputValue !== convertToInputValue(value)));\n const flattenedData = useFlattenedData(unfilteredData);\n const data = React.useMemo(\n () => (shouldFilterData ? filterData(flattenedData, inputValue) : flattenedData),\n [shouldFilterData, inputValue, flattenedData]\n );\n // listbox/select change value _with_ the index, but combobox changes on select of an index (click/enter), so we need state\n const [currentIndex, setCurrentIndex] = React.useState<number | undefined>(\n inputValue !== undefined ? getIndexFromValue(data, inputValue) : undefined\n );\n\n const setInputValueByIndex = (index: number | undefined): void => {\n if (index !== undefined) {\n const option = data[index];\n\n if (option && !option.disabled) {\n setInputValueByRef(inputRef.current, option.value, 'focusout');\n }\n }\n };\n\n const setCurrentValue = (index: number | undefined) => {\n if (index === undefined) {\n return;\n }\n\n const option = data[index];\n\n // if the selected option is not already selected, trigger blur event\n if (option.value !== value) {\n setInputValueByIndex(index);\n } else {\n // if the selected option is already selected, refill input with its value\n setInputValue(convertToInputValue(value));\n }\n };\n\n // ensure the external value is synced with the internal value when mounting, e.g. incase a default value was set\n React.useEffect(() => {\n if (defaultValue && !value) {\n setInputValueByIndex(getIndexFromValue(data, defaultValue));\n }\n }, [data]);\n\n // update input value if it changed 'externally', e.g. clicking/entering an item in the listbox, from a modal etc\n React.useEffect(() => {\n if (value !== undefined && value !== inputValue) {\n setInputValue(convertToInputValue(value));\n }\n }, [value]);\n\n React.useEffect(() => {\n if (onSearch) {\n debouncer(() => {\n onSearch(inputValue);\n });\n }\n }, [inputValue]);\n\n // show listbox based on input value\n React.useEffect(() => {\n // don't show the popover if the internal (input) value already is the current value\n // this prevents the popover showing after selecting a value or pressing escape\n const isCurrentValue = value !== undefined && value !== null && inputValue === String(value);\n\n if (inputValue && data.length && !isCurrentValue) {\n setCurrentIndex(0);\n\n if (!open) {\n setOpen(true);\n }\n } else {\n setOpen(false);\n }\n }, [inputValue, data]);\n\n React.useEffect(() => {\n if (open) {\n setCurrentIndex(getIndexFromValue(data, inputValue) || 0);\n } else {\n setCurrentIndex(undefined);\n }\n }, [open]);\n\n // event handlers\n const handleInputBlur = (event: React.FocusEvent<HTMLInputElement>): void => {\n if (listRef.current && event.relatedTarget === listRef.current) {\n event.preventDefault();\n return;\n }\n\n // event.target.value is always a string so it is important to cast value to a string before checking the equality\n if (onChange && event.target.value !== String(value)) {\n const item = findByValue(flattenedData, event.target.value || inputValueRef.current);\n (event as any).detail = sanitizeItem(item);\n\n const parents = getOptionParents(flattenedData, item?.path);\n\n if (parents !== null && parents.length > 0) {\n (event as any).detail.parents = parents;\n }\n\n const isComboboxChangeEvent = event => {\n return typeof (event as any).detail === 'object'; // this makes sure we only take our own custom event, and not the browser default blur on tab.\n };\n\n // Only trigger onChange if this is our custom event (not a browser blur event)\n // or if the input was cleared.\n if (isComboboxChangeEvent(event) || (event.target.value === '' && !inline)) {\n onChange(event);\n }\n }\n\n if (props.onBlur) {\n props.onBlur(event);\n }\n };\n\n const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>): void => {\n setInputValue(event.target.value);\n inputValueRef.current = event.target.value;\n };\n\n const handleInputClick = (event: React.MouseEvent<HTMLInputElement>): void => {\n if (inline || (!open && inputValue && data.length)) {\n setOpen(true);\n }\n\n if (onClick) {\n onClick(event);\n }\n };\n\n const handleInputKeyDown = (event: React.KeyboardEvent<HTMLInputElement>): void => {\n if (!event.ctrlKey && !event.metaKey) {\n switch (event.key) {\n case 'Backspace': {\n return;\n }\n\n case 'Escape': {\n event.preventDefault();\n setInputValue(convertToInputValue(value));\n setOpen(false);\n return;\n }\n\n case 'Tab': {\n setCurrentValue(currentIndex);\n setOpen(false);\n return;\n }\n\n case 'Enter': {\n event.preventDefault();\n\n if (isElementInsideTable3OrReport(event.currentTarget)) {\n if (inline && !open) {\n setOpen(true);\n } else if (buttonRef.current && !open) {\n buttonRef.current.click();\n }\n }\n\n if (open) {\n setCurrentValue(currentIndex);\n setOpen(false);\n }\n\n return;\n }\n\n case 'ArrowDown':\n if (open) {\n event.preventDefault();\n } else {\n if (!inline && buttonRef.current && !isElementInsideTable3OrReport(event.currentTarget)) {\n buttonRef.current.click();\n }\n }\n break;\n\n case 'ArrowUp':\n case 'Home':\n case 'End': {\n if (open) {\n event.preventDefault();\n }\n break;\n }\n\n default:\n }\n\n // we aren't focused on the list, so manually forward the keydown event to it\n if (listRef.current) {\n listRef.current.dispatchEvent(createCustomKeyboardEvent(event));\n }\n\n if (inline && !open) {\n if (\n (event.key === 'ArrowUp' || event.key === 'ArrowDown') &&\n !isElementInsideTable3OrReport(event.currentTarget)\n ) {\n event.preventDefault();\n const initialIndex = event.key === 'ArrowUp' ? data.length - 1 : 0;\n setCurrentIndex(currentIndex !== undefined ? currentIndex : initialIndex);\n setOpen(true);\n }\n }\n }\n\n if (!event.isDefaultPrevented() && onKeyDown) {\n onKeyDown(event);\n }\n };\n\n const handleListboxChange = (index: number): void => {\n setCurrentIndex(index);\n };\n\n const handleListboxClick = (event: React.MouseEvent<HTMLLIElement>, index: number): void => {\n event.preventDefault();\n setCurrentValue(index);\n setOpen(false);\n };\n\n const combobox = {\n 'aria-expanded': open,\n 'aria-owns': listId,\n 'aria-haspopup': 'listbox' as const,\n role: 'combobox',\n };\n\n const input = {\n ...props,\n 'aria-controls': listId,\n // Indicates that the autocomplete behavior of the text input is to suggest a list of possible values in a popup and that the suggestions\n // are related to the string that is present in the textbox\n 'aria-autocomplete': 'list' as const,\n // Enables assistive technologies to know which element the application regards as focused while DOM focus remains on the input element\n 'aria-activedescendant':\n currentIndex !== undefined && data[currentIndex] ? getId(listId, String(data[currentIndex].value)) : undefined,\n 'aria-labelledby': ariaLabelledBy,\n disabled,\n onBlur: !disabled && !readOnly ? handleInputBlur : undefined,\n onChange: !disabled && !readOnly ? handleInputChange : undefined,\n onClick: !disabled && !readOnly ? handleInputClick : undefined,\n onKeyDown: !disabled && !readOnly ? handleInputKeyDown : undefined,\n readOnly,\n ref: inputRef,\n type: 'text',\n value: inputValue ?? '',\n };\n\n const list: ScrollableListPropsWithRef = {\n 'aria-labelledby': ariaLabelledBy,\n data,\n disabled,\n id: listId,\n onChange: handleListboxChange,\n onClick: handleListboxClick,\n ref: listRef,\n scrollOnFocus: false,\n tabIndex: -1,\n value: currentIndex,\n };\n\n const button = {\n ref: buttonRef,\n };\n\n return {\n combobox,\n input,\n list,\n button,\n popover: {\n open,\n onOpenChange: setOpen,\n //visible: !data.length ? false : open,\n },\n };\n};\n"],"names":["debouncer","debounce","f","convertToInputValue","value","String","useCombobox","ariaLabel","ariaLabelledBy","data","unfilteredData","defaultValue","disabled","id","nativeId","inline","loading","__","onChange","onClick","onKeyDown","onSearch","readOnly","props","ref","inputRef","useMergedRef","buttonRef","React","listRef","open","setOpen","listId","uuid","inputValue","setInputValue","inputValueRef","shouldFilterData","flattenedData","useFlattenedData","filterData","currentIndex","setCurrentIndex","undefined","getIndexFromValue","setInputValueByIndex","index","option","setInputValueByRef","current","setCurrentValue","isCurrentValue","length","handleInputBlur","event","relatedTarget","preventDefault","target","item","findByValue","detail","sanitizeItem","parents","getOptionParents","path","isComboboxChangeEvent","onBlur","handleInputChange","handleInputClick","handleInputKeyDown","ctrlKey","metaKey","key","isElementInsideTable3OrReport","currentTarget","click","dispatchEvent","createCustomKeyboardEvent","initialIndex","isDefaultPrevented","handleListboxChange","handleListboxClick","combobox","role","input","getId","type","list","scrollOnFocus","tabIndex","button","popover","onOpenChange"],"mappings":"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"}
1
+ {"version":3,"file":"useCombobox.js","sources":["../../../../../../../src/components/Combobox/useCombobox.tsx"],"sourcesContent":["import * as React from 'react';\nimport { v4 as uuid } from 'uuid';\nimport debounce from 'lodash/debounce';\nimport { ComboboxProps } from './Combobox';\nimport { getIndexFromValue, findByValue, useFlattenedData, sanitizeItem, getOptionParents, filterData } from '../Listbox/util';\nimport { createCustomEvent, createCustomKeyboardEvent } from '../../utils/input';\nimport { useMergedRef } from '../../hooks/useMergedRef';\nimport { getId, ScrollableListItemValue, ScrollableListPropsWithRef } from '../Listbox/ScrollableList';\nimport { InputProps } from '../Input/Input';\nimport { isElementInsideTable3OrReport } from '../../utils/dom';\n\nconst debouncer = debounce(f => f(), 200);\n\nconst convertToInputValue = (value: ScrollableListItemValue | undefined) => String(value ?? '');\n\ntype useCombobox = React.HTMLAttributes<HTMLDivElement> & {\n combobox: React.HTMLAttributes<HTMLSpanElement>;\n input: Omit<InputProps, 'defaultValue'> & { ref: React.RefObject<HTMLInputElement> };\n list: ScrollableListPropsWithRef;\n button: { ref: any };\n popover: { open: boolean; onOpenChange: (open: boolean) => void };\n};\n\nexport const useCombobox = (\n {\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n data: unfilteredData = [],\n defaultValue,\n disabled,\n id: nativeId,\n inline,\n loading: __,\n onChange,\n onClick,\n onKeyDown,\n onSearch,\n readOnly,\n value,\n ...props\n }: Omit<ComboboxProps, 'dialog'>,\n ref: React.Ref<HTMLInputElement>\n): useCombobox => {\n const inputRef = useMergedRef<HTMLInputElement>(ref);\n const buttonRef = React.useRef<HTMLButtonElement>(null);\n const listRef = React.useRef<HTMLUListElement>(null);\n const [open, setOpen] = React.useState(false);\n const listId = React.useMemo(() => uuid(), []);\n const [inputValue, setInputValue] = React.useState<string>(convertToInputValue(value));\n\n const shouldFilterData = !onSearch && (!inline || (inline && inputValue !== convertToInputValue(value)));\n const flattenedData = useFlattenedData(unfilteredData);\n const data = React.useMemo(\n () => (shouldFilterData ? filterData(flattenedData, inputValue) : flattenedData),\n [shouldFilterData, inputValue, flattenedData]\n );\n // listbox/select change value _with_ the index, but combobox changes on select of an index (click/enter), so we need state\n const [currentIndex, setCurrentIndex] = React.useState<number | undefined>(\n inputValue !== undefined ? getIndexFromValue(data, inputValue) : undefined\n );\n\n const setInputValueByIndex = (index: number | undefined): void => {\n if (index !== undefined) {\n const option = data[index];\n\n if (option && !option.disabled) {\n handleChange(option.value);\n }\n }\n };\n\n const setCurrentValue = (index: number | undefined) => {\n if (index === undefined) {\n return;\n }\n\n const option = data[index];\n\n // if the selected option is not already selected, trigger blur event\n if (option.value !== value) {\n setInputValueByIndex(index);\n } else {\n // if the selected option is already selected, refill input with its value\n setInputValue(convertToInputValue(value));\n }\n };\n\n // ensure the external value is synced with the internal value when mounting, e.g. incase a default value was set\n React.useEffect(() => {\n if (defaultValue && !value) {\n setInputValueByIndex(getIndexFromValue(data, defaultValue));\n }\n }, [defaultValue]);\n\n // update input value if it changed 'externally', e.g. clicking/entering an item in the listbox, from a modal etc\n React.useEffect(() => {\n if (value !== undefined && value !== inputValue) {\n setInputValue(convertToInputValue(value));\n }\n }, [value]);\n\n React.useEffect(() => {\n if (onSearch) {\n debouncer(() => {\n onSearch(inputValue);\n });\n }\n }, [inputValue]);\n\n // show listbox based on input value\n React.useEffect(() => {\n // don't show the popover if the internal (input) value already is the current value\n // this prevents the popover showing after selecting a value or pressing escape\n const isCurrentValue = value !== undefined && value !== null && inputValue === String(value);\n\n if (inputValue && data.length && !isCurrentValue) {\n setCurrentIndex(0);\n\n if (!open) {\n setOpen(true);\n }\n } else {\n setOpen(false);\n }\n }, [inputValue, data]);\n\n React.useEffect(() => {\n if (open) {\n setCurrentIndex(getIndexFromValue(data, inputValue) || 0);\n } else {\n setCurrentIndex(undefined);\n }\n }, [open]);\n\n const handleChange = nextValue => {\n const event = createCustomEvent('change');\n\n if (onChange && nextValue !== String(value)) {\n const item = findByValue(flattenedData, nextValue);\n\n (event as any).detail = sanitizeItem(item);\n\n const parents = getOptionParents(flattenedData, item?.path);\n\n if (parents !== null && parents.length > 0) {\n (event as any).detail.parents = parents;\n }\n\n onChange(event);\n }\n };\n\n // event handlers\n const handleInputBlur = (event: React.FocusEvent<HTMLInputElement>): void => {\n if (listRef.current && event.relatedTarget === listRef.current) {\n event.preventDefault();\n return;\n }\n\n // listbox is open\n if (currentIndex !== undefined) {\n handleChange(data[currentIndex].value);\n } else if (inputValue === '') {\n handleChange(undefined);\n }\n\n if (props.onBlur) {\n props.onBlur(event);\n }\n };\n\n const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>): void => {\n setInputValue(event.target.value);\n };\n\n const handleInputClick = (event: React.MouseEvent<HTMLInputElement>): void => {\n if (inline || (!open && inputValue && data.length)) {\n setOpen(true);\n }\n\n if (onClick) {\n onClick(event);\n }\n };\n\n const handleInputKeyDown = (event: React.KeyboardEvent<HTMLInputElement>): void => {\n if (!event.ctrlKey && !event.metaKey) {\n switch (event.key) {\n case 'Backspace': {\n return;\n }\n\n case 'Escape': {\n event.preventDefault();\n setInputValue(convertToInputValue(value));\n setOpen(false);\n return;\n }\n\n case 'Tab': {\n setOpen(false);\n return;\n }\n\n case 'Enter': {\n event.preventDefault();\n\n if (isElementInsideTable3OrReport(event.currentTarget)) {\n if (inline && !open) {\n setOpen(true);\n } else if (buttonRef.current && !open) {\n buttonRef.current.click();\n }\n }\n\n if (open) {\n setCurrentValue(currentIndex);\n setOpen(false);\n }\n\n return;\n }\n\n case 'ArrowDown':\n if (open) {\n event.preventDefault();\n } else {\n if (!inline && buttonRef.current && !isElementInsideTable3OrReport(event.currentTarget)) {\n buttonRef.current.click();\n }\n }\n break;\n\n case 'ArrowUp':\n case 'Home':\n case 'End': {\n if (open) {\n event.preventDefault();\n }\n break;\n }\n\n default:\n }\n\n // we aren't focused on the list, so manually forward the keydown event to it\n if (listRef.current) {\n listRef.current.dispatchEvent(createCustomKeyboardEvent(event));\n }\n\n if (inline && !open) {\n if (\n (event.key === 'ArrowUp' || event.key === 'ArrowDown') &&\n !isElementInsideTable3OrReport(event.currentTarget)\n ) {\n event.preventDefault();\n const initialIndex = event.key === 'ArrowUp' ? data.length - 1 : 0;\n setCurrentIndex(currentIndex !== undefined ? currentIndex : initialIndex);\n setOpen(true);\n }\n }\n }\n\n if (!event.isDefaultPrevented() && onKeyDown) {\n onKeyDown(event);\n }\n };\n\n const handleListboxChange = (index: number): void => {\n setCurrentIndex(index);\n };\n\n const handleListboxClick = (event: React.MouseEvent<HTMLLIElement>, index: number): void => {\n event.preventDefault();\n setCurrentValue(index);\n setOpen(false);\n };\n\n const combobox = {\n 'aria-expanded': open,\n 'aria-owns': listId,\n 'aria-haspopup': 'listbox' as const,\n role: 'combobox',\n };\n\n const input = {\n ...props,\n 'aria-controls': listId,\n // Indicates that the autocomplete behavior of the text input is to suggest a list of possible values in a popup and that the suggestions\n // are related to the string that is present in the textbox\n 'aria-autocomplete': 'list' as const,\n // Enables assistive technologies to know which element the application regards as focused while DOM focus remains on the input element\n 'aria-activedescendant':\n currentIndex !== undefined && data[currentIndex] ? getId(listId, String(data[currentIndex].value)) : undefined,\n 'aria-labelledby': ariaLabelledBy,\n disabled,\n onBlur: !disabled && !readOnly ? handleInputBlur : undefined,\n onChange: !disabled && !readOnly ? handleInputChange : undefined,\n onClick: !disabled && !readOnly ? handleInputClick : undefined,\n onKeyDown: !disabled && !readOnly ? handleInputKeyDown : undefined,\n readOnly,\n ref: inputRef,\n type: 'text',\n value: inputValue ?? '',\n };\n\n const list: ScrollableListPropsWithRef = {\n 'aria-labelledby': ariaLabelledBy,\n data,\n disabled,\n id: listId,\n onChange: handleListboxChange,\n onClick: handleListboxClick,\n ref: listRef,\n scrollOnFocus: false,\n tabIndex: -1,\n value: currentIndex,\n };\n\n const button = {\n ref: buttonRef,\n };\n\n return {\n combobox,\n input,\n list,\n button,\n popover: {\n open,\n onOpenChange: setOpen,\n //visible: !data.length ? false : open,\n },\n };\n};\n"],"names":["debouncer","debounce","f","convertToInputValue","value","String","useCombobox","ariaLabel","ariaLabelledBy","data","unfilteredData","defaultValue","disabled","id","nativeId","inline","loading","__","onChange","onClick","onKeyDown","onSearch","readOnly","props","ref","inputRef","useMergedRef","buttonRef","React","listRef","open","setOpen","listId","uuid","inputValue","setInputValue","shouldFilterData","flattenedData","useFlattenedData","filterData","currentIndex","setCurrentIndex","undefined","getIndexFromValue","setInputValueByIndex","index","option","handleChange","setCurrentValue","isCurrentValue","length","nextValue","event","createCustomEvent","item","findByValue","detail","sanitizeItem","parents","getOptionParents","path","handleInputBlur","current","relatedTarget","preventDefault","onBlur","handleInputChange","target","handleInputClick","handleInputKeyDown","ctrlKey","metaKey","key","isElementInsideTable3OrReport","currentTarget","click","dispatchEvent","createCustomKeyboardEvent","initialIndex","isDefaultPrevented","handleListboxChange","handleListboxClick","combobox","role","input","getId","type","list","scrollOnFocus","tabIndex","button","popover","onOpenChange"],"mappings":"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"}
@@ -5996,7 +5996,6 @@ const useCombobox = ({
5996
5996
  const [open, setOpen] = React.useState(false);
5997
5997
  const listId = React.useMemo(() => uuid.v4(), []);
5998
5998
  const [inputValue, setInputValue] = React.useState(convertToInputValue(value));
5999
- const inputValueRef = React.useRef(inputValue);
6000
5999
  const shouldFilterData = !onSearch && (!inline || inline && inputValue !== convertToInputValue(value));
6001
6000
  const flattenedData = useFlattenedData(unfilteredData);
6002
6001
  const data = React.useMemo(() => shouldFilterData ? filterData(flattenedData, inputValue) : flattenedData, [shouldFilterData, inputValue, flattenedData]);
@@ -6006,7 +6005,7 @@ const useCombobox = ({
6006
6005
  if (index !== undefined) {
6007
6006
  const option = data[index];
6008
6007
  if (option && !option.disabled) {
6009
- setInputValueByRef$1(inputRef.current, option.value, 'focusout');
6008
+ handleChange(option.value);
6010
6009
  }
6011
6010
  }
6012
6011
  };
@@ -6028,7 +6027,7 @@ const useCombobox = ({
6028
6027
  if (defaultValue && !value) {
6029
6028
  setInputValueByIndex(getIndexFromValue(data, defaultValue));
6030
6029
  }
6031
- }, [data]);
6030
+ }, [defaultValue]);
6032
6031
  // update input value if it changed 'externally', e.g. clicking/entering an item in the listbox, from a modal etc
6033
6032
  React.useEffect(() => {
6034
6033
  if (value !== undefined && value !== inputValue) {
@@ -6063,28 +6062,29 @@ const useCombobox = ({
6063
6062
  setCurrentIndex(undefined);
6064
6063
  }
6065
6064
  }, [open]);
6065
+ const handleChange = nextValue => {
6066
+ const event = createCustomEvent('change');
6067
+ if (onChange && nextValue !== String(value)) {
6068
+ const item = findByValue(flattenedData, nextValue);
6069
+ event.detail = sanitizeItem(item);
6070
+ const parents = getOptionParents(flattenedData, item === null || item === void 0 ? void 0 : item.path);
6071
+ if (parents !== null && parents.length > 0) {
6072
+ event.detail.parents = parents;
6073
+ }
6074
+ onChange(event);
6075
+ }
6076
+ };
6066
6077
  // event handlers
6067
6078
  const handleInputBlur = event => {
6068
6079
  if (listRef.current && event.relatedTarget === listRef.current) {
6069
6080
  event.preventDefault();
6070
6081
  return;
6071
6082
  }
6072
- // event.target.value is always a string so it is important to cast value to a string before checking the equality
6073
- if (onChange && event.target.value !== String(value)) {
6074
- const item = findByValue(flattenedData, event.target.value || inputValueRef.current);
6075
- event.detail = sanitizeItem(item);
6076
- const parents = getOptionParents(flattenedData, item === null || item === void 0 ? void 0 : item.path);
6077
- if (parents !== null && parents.length > 0) {
6078
- event.detail.parents = parents;
6079
- }
6080
- const isComboboxChangeEvent = event => {
6081
- return typeof event.detail === 'object'; // this makes sure we only take our own custom event, and not the browser default blur on tab.
6082
- };
6083
- // Only trigger onChange if this is our custom event (not a browser blur event)
6084
- // or if the input was cleared.
6085
- if (isComboboxChangeEvent(event) || event.target.value === '' && !inline) {
6086
- onChange(event);
6087
- }
6083
+ // listbox is open
6084
+ if (currentIndex !== undefined) {
6085
+ handleChange(data[currentIndex].value);
6086
+ } else if (inputValue === '') {
6087
+ handleChange(undefined);
6088
6088
  }
6089
6089
  if (props.onBlur) {
6090
6090
  props.onBlur(event);
@@ -6092,7 +6092,6 @@ const useCombobox = ({
6092
6092
  };
6093
6093
  const handleInputChange = event => {
6094
6094
  setInputValue(event.target.value);
6095
- inputValueRef.current = event.target.value;
6096
6095
  };
6097
6096
  const handleInputClick = event => {
6098
6097
  if (inline || !open && inputValue && data.length) {
@@ -6118,7 +6117,6 @@ const useCombobox = ({
6118
6117
  }
6119
6118
  case 'Tab':
6120
6119
  {
6121
- setCurrentValue(currentIndex);
6122
6120
  setOpen(false);
6123
6121
  return;
6124
6122
  }