@reactzero/combo 0.1.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.
Files changed (124) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/LICENSE +21 -0
  3. package/README.md +188 -0
  4. package/dist/Combo-Cx3kSkop.cjs +2 -0
  5. package/dist/Combo-Cx3kSkop.cjs.map +1 -0
  6. package/dist/Combo-qs6_L512.js +439 -0
  7. package/dist/Combo-qs6_L512.js.map +1 -0
  8. package/dist/components/Combo.d.ts +71 -0
  9. package/dist/components/Combo.d.ts.map +1 -0
  10. package/dist/components/LiveRegion.d.ts +7 -0
  11. package/dist/components/LiveRegion.d.ts.map +1 -0
  12. package/dist/components/Portal.d.ts +8 -0
  13. package/dist/components/Portal.d.ts.map +1 -0
  14. package/dist/components/slots/CheckboxItem.d.ts +38 -0
  15. package/dist/components/slots/CheckboxItem.d.ts.map +1 -0
  16. package/dist/components/slots/CustomItem.d.ts +35 -0
  17. package/dist/components/slots/CustomItem.d.ts.map +1 -0
  18. package/dist/components/slots/FooterActions.d.ts +42 -0
  19. package/dist/components/slots/FooterActions.d.ts.map +1 -0
  20. package/dist/components/slots/GroupSeparator.d.ts +30 -0
  21. package/dist/components/slots/GroupSeparator.d.ts.map +1 -0
  22. package/dist/components/slots/index.d.ts +9 -0
  23. package/dist/components/slots/index.d.ts.map +1 -0
  24. package/dist/components/tabs/TabbedCombo.d.ts +45 -0
  25. package/dist/components/tabs/TabbedCombo.d.ts.map +1 -0
  26. package/dist/components/tabs/index.d.ts +3 -0
  27. package/dist/components/tabs/index.d.ts.map +1 -0
  28. package/dist/core/announce.d.ts +10 -0
  29. package/dist/core/announce.d.ts.map +1 -0
  30. package/dist/core/ids.d.ts +13 -0
  31. package/dist/core/ids.d.ts.map +1 -0
  32. package/dist/core/keyboard.d.ts +13 -0
  33. package/dist/core/keyboard.d.ts.map +1 -0
  34. package/dist/core/scroll.d.ts +5 -0
  35. package/dist/core/scroll.d.ts.map +1 -0
  36. package/dist/core/stateMachine.d.ts +32 -0
  37. package/dist/core/stateMachine.d.ts.map +1 -0
  38. package/dist/core/utils.d.ts +26 -0
  39. package/dist/core/utils.d.ts.map +1 -0
  40. package/dist/defaults-iFGq2Q-7.cjs +2 -0
  41. package/dist/defaults-iFGq2Q-7.cjs.map +1 -0
  42. package/dist/defaults-rhC5DFTg.js +53 -0
  43. package/dist/defaults-rhC5DFTg.js.map +1 -0
  44. package/dist/entries/hook-bare.d.ts +4 -0
  45. package/dist/entries/hook-bare.d.ts.map +1 -0
  46. package/dist/entries/hook.d.ts +4 -0
  47. package/dist/entries/hook.d.ts.map +1 -0
  48. package/dist/entries/icons.d.ts +4 -0
  49. package/dist/entries/icons.d.ts.map +1 -0
  50. package/dist/entries/index.d.ts +9 -0
  51. package/dist/entries/index.d.ts.map +1 -0
  52. package/dist/entries/position.d.ts +3 -0
  53. package/dist/entries/position.d.ts.map +1 -0
  54. package/dist/entries/slots.d.ts +9 -0
  55. package/dist/entries/slots.d.ts.map +1 -0
  56. package/dist/entries/tabs.d.ts +4 -0
  57. package/dist/entries/tabs.d.ts.map +1 -0
  58. package/dist/hook-bare.cjs +2 -0
  59. package/dist/hook-bare.cjs.map +1 -0
  60. package/dist/hook-bare.js +9 -0
  61. package/dist/hook-bare.js.map +1 -0
  62. package/dist/hook.cjs +2 -0
  63. package/dist/hook.cjs.map +1 -0
  64. package/dist/hook.js +11 -0
  65. package/dist/hook.js.map +1 -0
  66. package/dist/hooks/useCombo.d.ts +3 -0
  67. package/dist/hooks/useCombo.d.ts.map +1 -0
  68. package/dist/hooks/usePosition.d.ts +16 -0
  69. package/dist/hooks/usePosition.d.ts.map +1 -0
  70. package/dist/icons/defaults.d.ts +16 -0
  71. package/dist/icons/defaults.d.ts.map +1 -0
  72. package/dist/icons/icons.d.ts +30 -0
  73. package/dist/icons/icons.d.ts.map +1 -0
  74. package/dist/icons-Ch1Q5AhF.js +40 -0
  75. package/dist/icons-Ch1Q5AhF.js.map +1 -0
  76. package/dist/icons-vzkEacAb.cjs +2 -0
  77. package/dist/icons-vzkEacAb.cjs.map +1 -0
  78. package/dist/icons.cjs +2 -0
  79. package/dist/icons.cjs.map +1 -0
  80. package/dist/icons.js +20 -0
  81. package/dist/icons.js.map +1 -0
  82. package/dist/index.cjs +2 -0
  83. package/dist/index.cjs.map +1 -0
  84. package/dist/index.d.ts +2 -0
  85. package/dist/index.d.ts.map +1 -0
  86. package/dist/index.js +12 -0
  87. package/dist/index.js.map +1 -0
  88. package/dist/position.cjs +2 -0
  89. package/dist/position.cjs.map +1 -0
  90. package/dist/position.js +5 -0
  91. package/dist/position.js.map +1 -0
  92. package/dist/slots.cjs +2 -0
  93. package/dist/slots.cjs.map +1 -0
  94. package/dist/slots.js +92 -0
  95. package/dist/slots.js.map +1 -0
  96. package/dist/style.css +1 -0
  97. package/dist/styles/base.css +205 -0
  98. package/dist/styles/checkbox.css +36 -0
  99. package/dist/styles/chips.css +71 -0
  100. package/dist/styles/custom-item.css +64 -0
  101. package/dist/styles/footer.css +73 -0
  102. package/dist/styles/groups.css +23 -0
  103. package/dist/styles/meta.css +30 -0
  104. package/dist/styles/radio.css +36 -0
  105. package/dist/styles/select.css +35 -0
  106. package/dist/styles/states.css +22 -0
  107. package/dist/tabs.cjs +2 -0
  108. package/dist/tabs.cjs.map +1 -0
  109. package/dist/tabs.js +132 -0
  110. package/dist/tabs.js.map +1 -0
  111. package/dist/themes/dark.css +96 -0
  112. package/dist/themes/default.css +126 -0
  113. package/dist/themes/high-contrast.css +98 -0
  114. package/dist/types.d.ts +168 -0
  115. package/dist/types.d.ts.map +1 -0
  116. package/dist/useCombo-D_vriwVz.cjs +2 -0
  117. package/dist/useCombo-D_vriwVz.cjs.map +1 -0
  118. package/dist/useCombo-gPeBdkRf.js +887 -0
  119. package/dist/useCombo-gPeBdkRf.js.map +1 -0
  120. package/dist/usePosition-6GfutqGX.cjs +2 -0
  121. package/dist/usePosition-6GfutqGX.cjs.map +1 -0
  122. package/dist/usePosition-DVw8IlwA.js +36 -0
  123. package/dist/usePosition-DVw8IlwA.js.map +1 -0
  124. package/package.json +219 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCombo-gPeBdkRf.js","sources":["../src/core/utils.ts","../src/core/stateMachine.ts","../src/core/keyboard.ts","../src/core/ids.ts","../src/core/announce.ts","../src/core/scroll.ts","../src/hooks/useCombo.ts"],"sourcesContent":["import type { MutableRefObject, RefObject } from 'react';\n\n/**\n * Compose multiple event handlers — user's handler runs first, then ours.\n */\nexport const callAll =\n <E extends (...args: never[]) => void>(\n ...fns: (E | undefined)[]\n ) =>\n (...args: Parameters<E>) => {\n fns.forEach((fn) => fn?.(...args));\n };\n\n/**\n * Default itemToString — handles strings, objects with `.label`, null.\n */\nexport const defaultItemToString = <T>(item: T | null): string => {\n if (item == null) return '';\n if (typeof item === 'string') return item;\n if (typeof item === 'object' && 'label' in (item as object))\n return String((item as Record<string, unknown>).label);\n return String(item);\n};\n\n/**\n * Default itemToValue — handles objects with `.value`, primitives.\n */\nexport const defaultItemToValue = <T>(item: T): string | number => {\n if (typeof item === 'string' || typeof item === 'number') return item;\n if (typeof item === 'object' && item != null && 'value' in (item as object))\n return (item as Record<string, unknown>).value as string | number;\n return String(item);\n};\n\n/**\n * Default case-insensitive substring filter.\n */\nexport const defaultFilter = <T>(\n items: T[],\n inputValue: string,\n itemToString: (item: T) => string,\n): T[] => {\n if (!inputValue) return items;\n const lower = inputValue.toLowerCase();\n return items.filter((item) =>\n itemToString(item).toLowerCase().includes(lower),\n );\n};\n\n/**\n * Clamp a number to a range.\n */\nexport const clamp = (value: number, min: number, max: number): number =>\n Math.min(Math.max(value, min), max);\n\n/**\n * Merge multiple refs (callback refs, RefObjects, or null).\n */\nexport function mergeRefs<T>(\n ...refs: (\n | MutableRefObject<T | null>\n | RefObject<T | null>\n | ((instance: T | null) => void)\n | null\n | undefined\n )[]\n): (instance: T | null) => void {\n return (instance: T | null) => {\n refs.forEach((ref) => {\n if (typeof ref === 'function') {\n ref(instance);\n } else if (ref != null) {\n (ref as MutableRefObject<T | null>).current = instance;\n }\n });\n };\n}\n","import type {\n ComboState,\n ComboAction,\n ComboStatus,\n UseComboOptions,\n} from '../types';\nimport { defaultFilter, defaultItemToString } from './utils';\n\n// ---------------------------------------------------------------------------\n// Reducer context — passed alongside state and action\n// ---------------------------------------------------------------------------\n\nexport interface ReducerContext<T> {\n items: T[];\n itemToString: (item: T | null) => string;\n itemToValue: (item: T) => string | number;\n filterFunction?: (items: T[], inputValue: string) => T[];\n closeOnSelect: boolean;\n commitOnBlur: boolean;\n deselectionAllowed: boolean;\n isItemDisabled: (item: T) => boolean;\n disabledItemBehavior: 'skip' | 'focus';\n hideDisabled: boolean;\n variant: 'input' | 'select';\n mode: 'single' | 'multi';\n maxSelected?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction isOpenStatus(status: ComboStatus): boolean {\n return status === 'OPEN_IDLE' || status === 'OPEN_HIGHLIGHTED';\n}\n\nfunction filterItems<T>(\n items: T[],\n inputValue: string,\n ctx: ReducerContext<T>,\n): T[] {\n const filtered = ctx.filterFunction\n ? ctx.filterFunction(items, inputValue)\n : defaultFilter(items, inputValue, (item: T) => ctx.itemToString(item));\n\n if (ctx.hideDisabled) {\n return filtered.filter((item) => !ctx.isItemDisabled(item));\n }\n return filtered;\n}\n\n/**\n * Find the next enabled index in a given direction, wrapping around.\n * Returns -1 if no enabled items exist.\n */\nexport function getNextEnabledIndex<T>(\n filteredItems: T[],\n currentIndex: number,\n direction: 1 | -1,\n isItemDisabled: (item: T) => boolean,\n behavior: 'skip' | 'focus',\n): number {\n const len = filteredItems.length;\n if (len === 0) return -1;\n\n // If behavior is 'focus', disabled items are still focusable\n if (behavior === 'focus') {\n let next = currentIndex + direction;\n if (next >= len) next = 0;\n if (next < 0) next = len - 1;\n return next;\n }\n\n // Skip disabled items\n let next = currentIndex + direction;\n let attempts = 0;\n while (attempts < len) {\n if (next >= len) next = 0;\n if (next < 0) next = len - 1;\n if (!isItemDisabled(filteredItems[next])) return next;\n next += direction;\n attempts++;\n }\n return -1; // All items disabled\n}\n\n/**\n * Find the first enabled index from a given starting position.\n */\nexport function getFirstEnabledIndex<T>(\n filteredItems: T[],\n isItemDisabled: (item: T) => boolean,\n behavior: 'skip' | 'focus',\n): number {\n if (filteredItems.length === 0) return -1;\n if (behavior === 'focus') return 0;\n for (let i = 0; i < filteredItems.length; i++) {\n if (!isItemDisabled(filteredItems[i])) return i;\n }\n return -1;\n}\n\n/**\n * Find the last enabled index.\n */\nexport function getLastEnabledIndex<T>(\n filteredItems: T[],\n isItemDisabled: (item: T) => boolean,\n behavior: 'skip' | 'focus',\n): number {\n if (filteredItems.length === 0) return -1;\n if (behavior === 'focus') return filteredItems.length - 1;\n for (let i = filteredItems.length - 1; i >= 0; i--) {\n if (!isItemDisabled(filteredItems[i])) return i;\n }\n return -1;\n}\n\n// ---------------------------------------------------------------------------\n// Initial state\n// ---------------------------------------------------------------------------\n\nexport function getInitialState<T>(\n options: UseComboOptions<T>,\n): ComboState<T> {\n const its = options.itemToString ?? defaultItemToString;\n const selectedItem = options.selectedItem ?? options.defaultSelectedItem ?? null;\n\n return {\n status: 'IDLE' as ComboStatus,\n selectedItem,\n selectedItems: options.selectedItems ?? options.defaultSelectedItems ?? [],\n inputValue:\n options.inputValue ??\n options.defaultInputValue ??\n (selectedItem ? its(selectedItem) : ''),\n lastConfirmedValue: selectedItem ? its(selectedItem) : '',\n highlightedIndex: -1,\n filteredItems: options.items,\n expandedItems: new Set<string>(),\n activeTabId: null,\n isLoading: options.isLoading ?? false,\n isLoadingMore: false,\n error: null,\n visibleChipCount: 0,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Reducer\n// ---------------------------------------------------------------------------\n\nexport function comboReducer<T>(\n state: ComboState<T>,\n action: ComboAction<T>,\n ctx: ReducerContext<T>,\n): ComboState<T> {\n switch (action.type) {\n case 'FOCUS': {\n if (state.status !== 'IDLE') return state;\n return {\n ...state,\n status: 'FOCUSED_CLOSED',\n lastConfirmedValue: state.inputValue,\n };\n }\n\n case 'BLUR': {\n if (state.status === 'IDLE') return state;\n\n // Multi mode: clear input text on blur, don't revert to a label\n if (ctx.mode === 'multi') {\n return {\n ...state,\n status: 'IDLE',\n inputValue: '',\n lastConfirmedValue: '',\n highlightedIndex: -1,\n filteredItems: ctx.items,\n };\n }\n\n // If commitOnBlur and something is highlighted, select it\n if (\n ctx.commitOnBlur &&\n isOpenStatus(state.status) &&\n state.highlightedIndex >= 0 &&\n state.highlightedIndex < state.filteredItems.length\n ) {\n const item = state.filteredItems[state.highlightedIndex];\n if (!ctx.isItemDisabled(item)) {\n const label = ctx.itemToString(item);\n return {\n ...state,\n status: 'IDLE',\n selectedItem: item,\n inputValue: label,\n lastConfirmedValue: label,\n highlightedIndex: -1,\n };\n }\n }\n\n // Revert input to last confirmed value\n return {\n ...state,\n status: 'IDLE',\n inputValue: state.lastConfirmedValue,\n highlightedIndex: -1,\n };\n }\n\n case 'INPUT_CHANGE': {\n // In select variant, input changes are ignored\n if (ctx.variant === 'select') return state;\n\n const filtered = filterItems(ctx.items, action.value, ctx);\n return {\n ...state,\n status: 'OPEN_IDLE',\n inputValue: action.value,\n filteredItems: filtered,\n highlightedIndex: -1,\n };\n }\n\n case 'TOGGLE_MENU': {\n if (isOpenStatus(state.status)) {\n return {\n ...state,\n status: 'FOCUSED_CLOSED',\n inputValue: ctx.mode === 'multi' ? '' : state.lastConfirmedValue,\n highlightedIndex: -1,\n ...(ctx.mode === 'multi' ? { filteredItems: ctx.items } : {}),\n };\n }\n // Single mode: clear input so re-open shows all items (not filtered by selected label)\n const toggleSearchValue = ctx.mode === 'multi' ? state.inputValue : '';\n const filtered = filterItems(ctx.items, toggleSearchValue, ctx);\n return {\n ...state,\n status: 'OPEN_IDLE',\n inputValue: toggleSearchValue,\n filteredItems: filtered,\n highlightedIndex: -1,\n };\n }\n\n case 'OPEN_MENU': {\n if (isOpenStatus(state.status)) return state;\n // Single mode: clear input so re-open shows all items (not filtered by selected label)\n const searchValue = ctx.mode === 'multi' ? state.inputValue : '';\n const filtered = filterItems(ctx.items, searchValue, ctx);\n return {\n ...state,\n status: 'OPEN_IDLE',\n inputValue: searchValue,\n filteredItems: filtered,\n highlightedIndex: -1,\n };\n }\n\n case 'CLOSE_MENU': {\n if (!isOpenStatus(state.status)) return state;\n return {\n ...state,\n status: 'FOCUSED_CLOSED',\n inputValue: ctx.mode === 'multi' ? '' : state.lastConfirmedValue,\n highlightedIndex: -1,\n ...(ctx.mode === 'multi' ? { filteredItems: ctx.items } : {}),\n };\n }\n\n case 'HIGHLIGHT_ITEM': {\n if (!isOpenStatus(state.status) && state.status !== 'FOCUSED_CLOSED')\n return state;\n const idx = action.index;\n if (idx < 0) {\n return { ...state, status: 'OPEN_IDLE', highlightedIndex: -1 };\n }\n // Bounds check\n if (idx >= state.filteredItems.length) return state;\n // If behavior is skip and item is disabled, don't highlight\n if (\n ctx.disabledItemBehavior === 'skip' &&\n ctx.isItemDisabled(state.filteredItems[idx])\n ) {\n return state;\n }\n return {\n ...state,\n status: 'OPEN_HIGHLIGHTED',\n highlightedIndex: idx,\n };\n }\n\n case 'HIGHLIGHT_FIRST': {\n const idx = getFirstEnabledIndex(\n state.filteredItems,\n ctx.isItemDisabled,\n ctx.disabledItemBehavior,\n );\n if (idx < 0) return { ...state, status: 'OPEN_IDLE', highlightedIndex: -1 };\n return {\n ...state,\n status: 'OPEN_HIGHLIGHTED',\n highlightedIndex: idx,\n };\n }\n\n case 'HIGHLIGHT_LAST': {\n const idx = getLastEnabledIndex(\n state.filteredItems,\n ctx.isItemDisabled,\n ctx.disabledItemBehavior,\n );\n if (idx < 0) return { ...state, status: 'OPEN_IDLE', highlightedIndex: -1 };\n return {\n ...state,\n status: 'OPEN_HIGHLIGHTED',\n highlightedIndex: idx,\n };\n }\n\n case 'HIGHLIGHT_NEXT': {\n const current = state.highlightedIndex;\n const idx = getNextEnabledIndex(\n state.filteredItems,\n current,\n 1,\n ctx.isItemDisabled,\n ctx.disabledItemBehavior,\n );\n if (idx < 0) return state;\n return {\n ...state,\n status: 'OPEN_HIGHLIGHTED',\n highlightedIndex: idx,\n };\n }\n\n case 'HIGHLIGHT_PREV': {\n const current = state.highlightedIndex;\n const idx = getNextEnabledIndex(\n state.filteredItems,\n current,\n -1,\n ctx.isItemDisabled,\n ctx.disabledItemBehavior,\n );\n if (idx < 0) return state;\n return {\n ...state,\n status: 'OPEN_HIGHLIGHTED',\n highlightedIndex: idx,\n };\n }\n\n case 'SELECT_HIGHLIGHTED': {\n if (state.highlightedIndex < 0) return state;\n if (state.highlightedIndex >= state.filteredItems.length) return state;\n\n const item = state.filteredItems[state.highlightedIndex];\n if (ctx.isItemDisabled(item)) return state;\n\n // Multi mode: toggle item in/out of selectedItems\n if (ctx.mode === 'multi') {\n const itemVal = ctx.itemToValue(item);\n const alreadySelected = state.selectedItems.some(\n (si) => ctx.itemToValue(si) === itemVal,\n );\n\n // Block adding beyond maxSelected (deselection always allowed)\n if (\n !alreadySelected &&\n ctx.maxSelected != null &&\n state.selectedItems.length >= ctx.maxSelected\n ) {\n return state;\n }\n\n const nextSelectedItems = alreadySelected\n ? state.selectedItems.filter((si) => ctx.itemToValue(si) !== itemVal)\n : [...state.selectedItems, item];\n\n return {\n ...state,\n status: ctx.closeOnSelect ? 'FOCUSED_CLOSED' : state.status,\n selectedItems: nextSelectedItems,\n highlightedIndex: ctx.closeOnSelect ? -1 : state.highlightedIndex,\n };\n }\n\n // Deselection check\n if (ctx.deselectionAllowed && state.selectedItem != null) {\n const currentVal = ctx.itemToValue(state.selectedItem);\n const newVal = ctx.itemToValue(item);\n if (currentVal === newVal) {\n // Deselect\n return {\n ...state,\n status: ctx.closeOnSelect ? 'FOCUSED_CLOSED' : state.status,\n selectedItem: null,\n inputValue: '',\n lastConfirmedValue: '',\n highlightedIndex: ctx.closeOnSelect ? -1 : state.highlightedIndex,\n };\n }\n }\n\n const label = ctx.itemToString(item);\n return {\n ...state,\n status: ctx.closeOnSelect ? 'FOCUSED_CLOSED' : state.status,\n selectedItem: item,\n inputValue: label,\n lastConfirmedValue: label,\n highlightedIndex: ctx.closeOnSelect ? -1 : state.highlightedIndex,\n };\n }\n\n case 'SELECT_ITEM': {\n const item = action.item;\n if (ctx.isItemDisabled(item)) return state;\n\n // Multi mode: toggle item in/out of selectedItems\n if (ctx.mode === 'multi') {\n const itemVal = ctx.itemToValue(item);\n const alreadySelected = state.selectedItems.some(\n (si) => ctx.itemToValue(si) === itemVal,\n );\n\n // Block adding beyond maxSelected (deselection always allowed)\n if (\n !alreadySelected &&\n ctx.maxSelected != null &&\n state.selectedItems.length >= ctx.maxSelected\n ) {\n return state;\n }\n\n const nextSelectedItems = alreadySelected\n ? state.selectedItems.filter((si) => ctx.itemToValue(si) !== itemVal)\n : [...state.selectedItems, item];\n\n return {\n ...state,\n status: ctx.closeOnSelect ? 'FOCUSED_CLOSED' : state.status,\n selectedItems: nextSelectedItems,\n highlightedIndex: ctx.closeOnSelect ? -1 : state.highlightedIndex,\n };\n }\n\n // Deselection check\n if (ctx.deselectionAllowed && state.selectedItem != null) {\n const currentVal = ctx.itemToValue(state.selectedItem);\n const newVal = ctx.itemToValue(item);\n if (currentVal === newVal) {\n return {\n ...state,\n status: ctx.closeOnSelect ? 'FOCUSED_CLOSED' : state.status,\n selectedItem: null,\n inputValue: '',\n lastConfirmedValue: '',\n highlightedIndex: ctx.closeOnSelect ? -1 : state.highlightedIndex,\n };\n }\n }\n\n const label = ctx.itemToString(item);\n return {\n ...state,\n status: ctx.closeOnSelect ? 'FOCUSED_CLOSED' : state.status,\n selectedItem: item,\n inputValue: label,\n lastConfirmedValue: label,\n highlightedIndex: ctx.closeOnSelect ? -1 : state.highlightedIndex,\n };\n }\n\n case 'DESELECT_ITEM': {\n // Multi mode: remove specific item from selectedItems\n if (ctx.mode === 'multi') {\n const itemVal = ctx.itemToValue(action.item);\n return {\n ...state,\n selectedItems: state.selectedItems.filter(\n (si) => ctx.itemToValue(si) !== itemVal,\n ),\n };\n }\n if (state.selectedItem == null) return state;\n return {\n ...state,\n selectedItem: null,\n inputValue: '',\n lastConfirmedValue: '',\n };\n }\n\n case 'CLEAR_SELECTION': {\n return {\n ...state,\n selectedItem: null,\n selectedItems: [],\n inputValue: '',\n lastConfirmedValue: '',\n filteredItems: ctx.items,\n };\n }\n\n case 'REMOVE_LAST_CHIP': {\n if (ctx.mode !== 'multi') return state;\n if (state.selectedItems.length === 0) return state;\n if (state.inputValue !== '') return state; // Only remove when input is empty\n return {\n ...state,\n selectedItems: state.selectedItems.slice(0, -1),\n };\n }\n\n case 'SELECT_ALL': {\n if (ctx.mode !== 'multi') return state;\n let enabledItems = state.filteredItems.filter(\n (item) => !ctx.isItemDisabled(item),\n );\n if (ctx.maxSelected != null) {\n enabledItems = enabledItems.slice(0, ctx.maxSelected);\n }\n return {\n ...state,\n selectedItems: enabledItems,\n };\n }\n\n case 'SYNC_ITEMS': {\n const filtered = filterItems(ctx.items, state.inputValue, ctx);\n return {\n ...state,\n filteredItems: filtered,\n highlightedIndex: -1,\n };\n }\n\n case 'RESET': {\n return getInitialState({\n items: ctx.items,\n itemToString: ctx.itemToString,\n itemToValue: ctx.itemToValue,\n });\n }\n\n default:\n return state;\n }\n}\n","import type { ComboAction, ComboState } from '../types';\nimport { clamp } from './utils';\n\ninterface KeyboardOptions {\n variant: 'input' | 'select';\n commitOnBlur: boolean;\n mode: 'single' | 'multi';\n}\n\n/**\n * Creates a keydown handler that dispatches combo actions.\n * The handler is a pure mapping from keyboard events to dispatch calls.\n */\nexport function createKeyboardHandler<T>(\n dispatch: (action: ComboAction<T>) => void,\n state: ComboState<T>,\n options: KeyboardOptions,\n): (event: React.KeyboardEvent) => void {\n return (event: React.KeyboardEvent) => {\n const isOpen =\n state.status === 'OPEN_IDLE' || state.status === 'OPEN_HIGHLIGHTED';\n\n switch (event.key) {\n case 'ArrowDown': {\n event.preventDefault();\n if (!isOpen) {\n dispatch({ type: 'OPEN_MENU' });\n dispatch({ type: 'HIGHLIGHT_FIRST' });\n } else {\n dispatch({ type: 'HIGHLIGHT_NEXT' });\n }\n break;\n }\n\n case 'ArrowUp': {\n event.preventDefault();\n if (!isOpen) {\n dispatch({ type: 'OPEN_MENU' });\n dispatch({ type: 'HIGHLIGHT_LAST' });\n } else {\n dispatch({ type: 'HIGHLIGHT_PREV' });\n }\n break;\n }\n\n case 'Enter': {\n if (isOpen && state.highlightedIndex >= 0) {\n event.preventDefault();\n dispatch({ type: 'SELECT_HIGHLIGHTED' });\n }\n break;\n }\n\n case 'Escape': {\n if (isOpen) {\n event.preventDefault();\n dispatch({ type: 'CLOSE_MENU' });\n }\n break;\n }\n\n case 'Home': {\n if (isOpen) {\n event.preventDefault();\n dispatch({ type: 'HIGHLIGHT_FIRST' });\n }\n break;\n }\n\n case 'End': {\n if (isOpen) {\n event.preventDefault();\n dispatch({ type: 'HIGHLIGHT_LAST' });\n }\n break;\n }\n\n case 'PageDown': {\n if (isOpen) {\n event.preventDefault();\n const maxIdx = state.filteredItems.length - 1;\n dispatch({\n type: 'HIGHLIGHT_ITEM',\n index: clamp(state.highlightedIndex + 10, 0, maxIdx),\n });\n }\n break;\n }\n\n case 'PageUp': {\n if (isOpen) {\n event.preventDefault();\n dispatch({\n type: 'HIGHLIGHT_ITEM',\n index: clamp(state.highlightedIndex - 10, 0, state.filteredItems.length - 1),\n });\n }\n break;\n }\n\n case 'Tab': {\n // Do NOT preventDefault — let focus move naturally\n if (isOpen) {\n if (options.commitOnBlur && state.highlightedIndex >= 0) {\n dispatch({ type: 'SELECT_HIGHLIGHTED' });\n }\n dispatch({ type: 'CLOSE_MENU' });\n }\n break;\n }\n\n case 'Backspace': {\n // In multi mode, remove last chip when input is empty\n if (state.inputValue === '') {\n dispatch({ type: 'REMOVE_LAST_CHIP' });\n }\n break;\n }\n\n case ' ': {\n // Space opens the menu in select variant (button trigger)\n if (options.variant === 'select' && !isOpen) {\n event.preventDefault();\n dispatch({ type: 'OPEN_MENU' });\n dispatch({ type: 'HIGHLIGHT_FIRST' });\n } else if (options.variant === 'select' && isOpen && state.highlightedIndex >= 0) {\n event.preventDefault();\n dispatch({ type: 'SELECT_HIGHLIGHTED' });\n }\n break;\n }\n\n case 'a':\n case 'A': {\n // Ctrl+A / Cmd+A selects all in multi mode\n if ((event.ctrlKey || event.metaKey) && options.mode === 'multi') {\n event.preventDefault();\n dispatch({ type: 'SELECT_ALL' });\n }\n break;\n }\n }\n };\n}\n","import { useId, useRef } from 'react';\n\nconst PREFIX = 'rzero';\n\nexport interface ComboIds {\n base: string;\n input: string;\n label: string;\n listbox: string;\n toggleButton: string;\n clearButton: string;\n liveRegion: string;\n item: (index: number) => string;\n group: (index: number) => string;\n}\n\nfunction buildIds(id: string): ComboIds {\n return {\n base: id,\n input: `${PREFIX}-input-${id}`,\n label: `${PREFIX}-label-${id}`,\n listbox: `${PREFIX}-listbox-${id}`,\n toggleButton: `${PREFIX}-toggle-${id}`,\n clearButton: `${PREFIX}-clear-${id}`,\n liveRegion: `${PREFIX}-live-${id}`,\n item: (index: number) => `${PREFIX}-item-${id}-${index}`,\n group: (index: number) => `${PREFIX}-group-${id}-${index}`,\n };\n}\n\nexport function useComboIds(userProvidedId?: string): ComboIds {\n const reactId = useId();\n const id = userProvidedId ?? reactId;\n\n const idsRef = useRef<ComboIds | null>(null);\n if (!idsRef.current || idsRef.current.base !== id) {\n idsRef.current = buildIds(id);\n }\n return idsRef.current;\n}\n","let liveRegionElement: HTMLElement | null = null;\nlet clearTimer: ReturnType<typeof setTimeout> | null = null;\n\nfunction ensureRegion(): HTMLElement | null {\n if (typeof document === 'undefined') return null;\n if (liveRegionElement && document.body.contains(liveRegionElement)) {\n return liveRegionElement;\n }\n liveRegionElement = document.createElement('div');\n liveRegionElement.setAttribute('role', 'status');\n liveRegionElement.setAttribute('aria-live', 'polite');\n liveRegionElement.setAttribute('aria-atomic', 'true');\n liveRegionElement.setAttribute('data-rzero-live', '');\n Object.assign(liveRegionElement.style, {\n position: 'absolute',\n width: '1px',\n height: '1px',\n padding: '0',\n margin: '-1px',\n overflow: 'hidden',\n clip: 'rect(0,0,0,0)',\n whiteSpace: 'nowrap',\n borderWidth: '0',\n });\n document.body.appendChild(liveRegionElement);\n return liveRegionElement;\n}\n\n/**\n * Announce a message to screen readers via a live region.\n * Clear-then-set pattern forces screen readers to re-read.\n */\nexport function announce(message: string, clearAfterMs = 3000): void {\n const region = ensureRegion();\n if (!region) return;\n if (clearTimer) clearTimeout(clearTimer);\n // Clear first, then set on next frame — forces re-announcement\n region.textContent = '';\n requestAnimationFrame(() => {\n region.textContent = message;\n });\n clearTimer = setTimeout(() => {\n region.textContent = '';\n }, clearAfterMs);\n}\n\n/**\n * Cleanup for tests.\n */\nexport function destroyAnnouncer(): void {\n if (typeof document !== 'undefined' && liveRegionElement && document.body.contains(liveRegionElement)) {\n document.body.removeChild(liveRegionElement);\n }\n liveRegionElement = null;\n if (clearTimer) clearTimeout(clearTimer);\n clearTimer = null;\n}\n","/**\n * Scroll a highlighted item into view within a scrollable listbox.\n */\nexport function scrollIntoView(\n listboxElement: HTMLElement | null,\n highlightedIndex: number,\n): void {\n if (!listboxElement || highlightedIndex < 0) return;\n const item = listboxElement.querySelector(\n `[data-rzero-index=\"${highlightedIndex}\"]`,\n );\n if (item && typeof item.scrollIntoView === 'function') {\n item.scrollIntoView({ block: 'nearest' });\n }\n}\n","import {\n useReducer,\n useRef,\n useCallback,\n useEffect,\n useMemo,\n} from 'react';\nimport type {\n UseComboOptions,\n UseComboReturn,\n ComboState,\n ComboAction,\n ComboGroup,\n} from '../types';\nimport {\n comboReducer,\n getInitialState,\n type ReducerContext,\n} from '../core/stateMachine';\nimport { createKeyboardHandler } from '../core/keyboard';\nimport { useComboIds } from '../core/ids';\nimport { announce } from '../core/announce';\nimport { scrollIntoView } from '../core/scroll';\nimport { resolveIcons, resolveChevron } from '../icons/icons';\nimport {\n callAll,\n defaultItemToString,\n defaultItemToValue,\n mergeRefs,\n} from '../core/utils';\n\nexport function useCombo<T>(\n options: UseComboOptions<T>,\n): UseComboReturn<T> {\n const {\n items,\n itemToString: userItemToString,\n itemToValue: userItemToValue,\n mode = 'single',\n variant = 'input',\n filterFunction,\n closeOnSelect = mode === 'single',\n commitOnBlur = false,\n deselectionAllowed = true,\n disabled = false,\n readOnly = false,\n isItemDisabled: userIsItemDisabled,\n hideDisabled = false,\n disabledItemBehavior = 'skip',\n ariaLabel,\n ariaLabelledBy,\n icons: iconOverrides,\n chevronStyle = 'caret',\n onSelectedItemChange,\n onSelectedItemsChange,\n onIsOpenChange,\n onHighlightedIndexChange,\n onStateChange,\n onInputChange,\n } = options;\n\n const itemToString = userItemToString ?? defaultItemToString;\n const itemToValue = userItemToValue ?? defaultItemToValue;\n const isItemDisabled = userIsItemDisabled ?? (() => false);\n\n // IDs\n const ids = useComboIds(options.id);\n\n // Refs\n const inputRef = useRef<HTMLInputElement | null>(null);\n const listboxRef = useRef<HTMLElement | null>(null);\n const triggerRef = useRef<HTMLElement | null>(null);\n\n // Reducer context\n const ctxRef = useRef<ReducerContext<T>>(null!);\n ctxRef.current = {\n items,\n itemToString,\n itemToValue,\n filterFunction,\n closeOnSelect,\n commitOnBlur,\n deselectionAllowed,\n isItemDisabled,\n disabledItemBehavior,\n hideDisabled,\n variant,\n mode,\n maxSelected: options.maxSelected,\n };\n\n // Reducer\n const [state, dispatch] = useReducer(\n (s: ComboState<T>, a: ComboAction<T>) =>\n comboReducer(s, a, ctxRef.current),\n options,\n getInitialState,\n );\n\n // Sync items when they change externally (e.g. tab switch in TabbedCombo)\n const prevItemsRef = useRef(items);\n useEffect(() => {\n if (prevItemsRef.current !== items) {\n prevItemsRef.current = items;\n dispatch({ type: 'SYNC_ITEMS' });\n }\n }, [items]);\n\n // Derived state\n const isOpen =\n state.status === 'OPEN_IDLE' || state.status === 'OPEN_HIGHLIGHTED';\n const hasSelection = mode === 'multi'\n ? state.selectedItems.length > 0\n : state.selectedItem != null;\n const triggerLabel = mode === 'multi'\n ? state.selectedItems.map(itemToString).join(', ')\n : state.selectedItem != null\n ? itemToString(state.selectedItem)\n : '';\n\n // Icons\n const icons = useMemo(\n () => resolveIcons(iconOverrides),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [iconOverrides],\n );\n const chevronIcon = useMemo(\n () => resolveChevron(chevronStyle, iconOverrides?.chevronDown),\n [chevronStyle, iconOverrides?.chevronDown],\n );\n\n // Keyboard handler — use ref-based approach to avoid stale closures\n const stateRef = useRef(state);\n stateRef.current = state;\n\n const handleKeyDown = useCallback(\n (event: React.KeyboardEvent) => {\n if (disabled || readOnly) return;\n const handler = createKeyboardHandler<T>(dispatch, stateRef.current, {\n variant,\n commitOnBlur,\n mode,\n });\n handler(event);\n },\n [disabled, readOnly, variant, commitOnBlur, mode],\n );\n\n // Scroll into view on highlight change\n useEffect(() => {\n if (state.highlightedIndex >= 0) {\n scrollIntoView(listboxRef.current, state.highlightedIndex);\n }\n }, [state.highlightedIndex]);\n\n // Announce filtered results count\n const prevIsOpenRef = useRef(false);\n const prevFilteredLenRef = useRef(0);\n useEffect(() => {\n const wasOpen = prevIsOpenRef.current;\n const prevLen = prevFilteredLenRef.current;\n prevIsOpenRef.current = isOpen;\n prevFilteredLenRef.current = state.filteredItems.length;\n\n if (isOpen && (!wasOpen || prevLen !== state.filteredItems.length)) {\n const count = state.filteredItems.length;\n announce(\n count === 0\n ? 'No options available'\n : `${count} option${count !== 1 ? 's' : ''} available`,\n );\n }\n }, [isOpen, state.filteredItems.length]);\n\n // Fire callbacks on state changes\n const prevStateRef = useRef(state);\n useEffect(() => {\n const prev = prevStateRef.current;\n prevStateRef.current = state;\n\n if (prev.selectedItem !== state.selectedItem) {\n onSelectedItemChange?.(state.selectedItem);\n if (state.selectedItem) {\n announce(`${itemToString(state.selectedItem)} selected`);\n } else if (prev.selectedItem) {\n announce(`${itemToString(prev.selectedItem)} deselected`);\n }\n }\n\n if (prev.selectedItems !== state.selectedItems) {\n onSelectedItemsChange?.(state.selectedItems);\n // Announce additions and removals in multi-select\n if (state.selectedItems.length > prev.selectedItems.length) {\n const added = state.selectedItems[state.selectedItems.length - 1];\n if (added) {\n announce(`${itemToString(added)} selected, ${state.selectedItems.length} total`);\n }\n } else if (state.selectedItems.length < prev.selectedItems.length) {\n announce(`Item removed, ${state.selectedItems.length} selected`);\n }\n }\n\n const wasOpen =\n prev.status === 'OPEN_IDLE' || prev.status === 'OPEN_HIGHLIGHTED';\n if (wasOpen !== isOpen) {\n onIsOpenChange?.(isOpen);\n }\n\n if (prev.highlightedIndex !== state.highlightedIndex) {\n onHighlightedIndexChange?.(state.highlightedIndex);\n }\n\n if (prev.inputValue !== state.inputValue) {\n onInputChange?.(state.inputValue);\n }\n\n onStateChange?.(state);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [state]);\n\n // ---- PROP GETTERS ----\n\n const getLabelProps = useCallback(\n (userProps: Record<string, unknown> = {}) => ({\n id: ids.label,\n htmlFor: ids.input,\n ...userProps,\n }),\n [ids],\n );\n\n const getInputProps = useCallback(\n (userProps: Record<string, unknown> = {}) => ({\n id: ids.input,\n role: 'combobox' as const,\n 'aria-expanded': isOpen,\n 'aria-haspopup': 'listbox' as const,\n 'aria-controls': ids.listbox,\n 'aria-autocomplete': (variant === 'select' ? 'none' : 'list') as\n | 'none'\n | 'list',\n 'aria-activedescendant':\n state.highlightedIndex >= 0\n ? ids.item(state.highlightedIndex)\n : undefined,\n 'aria-labelledby': ariaLabelledBy ?? ids.label,\n 'aria-label': ariaLabel,\n 'aria-disabled': disabled ? true : undefined,\n readOnly: readOnly || variant === 'select',\n disabled: disabled === true,\n autoComplete: 'off',\n value: state.inputValue,\n ...userProps,\n onChange: callAll(\n userProps.onChange as (() => void) | undefined,\n (e: React.ChangeEvent<HTMLInputElement>) => {\n if (disabled || readOnly) return;\n dispatch({ type: 'INPUT_CHANGE', value: e.target.value });\n },\n ),\n onKeyDown: callAll(\n userProps.onKeyDown as (() => void) | undefined,\n handleKeyDown,\n ),\n onFocus: callAll(\n userProps.onFocus as (() => void) | undefined,\n () => {\n if (disabled) return;\n dispatch({ type: 'FOCUS' });\n },\n ),\n onBlur: callAll(\n userProps.onBlur as (() => void) | undefined,\n () => {\n dispatch({ type: 'BLUR' });\n },\n ),\n onClick: callAll(\n userProps.onClick as (() => void) | undefined,\n () => {\n if (disabled || readOnly) return;\n if (!isOpen) dispatch({ type: 'OPEN_MENU' });\n },\n ),\n ref: mergeRefs(\n inputRef,\n userProps.ref as React.RefObject<HTMLInputElement | null> | undefined,\n ),\n }),\n [\n ids,\n isOpen,\n state.highlightedIndex,\n state.inputValue,\n ariaLabel,\n ariaLabelledBy,\n disabled,\n readOnly,\n variant,\n handleKeyDown,\n ],\n );\n\n const getToggleButtonProps = useCallback(\n (userProps: Record<string, unknown> = {}) => ({\n id: ids.toggleButton,\n type: 'button' as const,\n 'aria-label': isOpen ? 'Close options' : 'Open options',\n 'aria-expanded': isOpen,\n 'aria-haspopup': 'listbox' as const,\n 'aria-controls': ids.listbox,\n tabIndex: -1,\n 'aria-disabled': disabled ? true : undefined,\n ...userProps,\n onMouseDown: callAll(\n userProps.onMouseDown as (() => void) | undefined,\n (e: React.MouseEvent) => e.preventDefault(), // prevent input blur\n ),\n onClick: callAll(\n userProps.onClick as (() => void) | undefined,\n () => {\n if (disabled || readOnly) return;\n dispatch({ type: 'TOGGLE_MENU' });\n inputRef.current?.focus();\n },\n ),\n }),\n [ids, isOpen, disabled, readOnly],\n );\n\n const getClearButtonProps = useCallback(\n (userProps: Record<string, unknown> = {}) => ({\n id: ids.clearButton,\n type: 'button' as const,\n 'aria-label': 'Clear selection',\n tabIndex: -1,\n ...userProps,\n onMouseDown: callAll(\n userProps.onMouseDown as (() => void) | undefined,\n (e: React.MouseEvent) => e.preventDefault(), // prevent input blur\n ),\n onClick: callAll(\n userProps.onClick as (() => void) | undefined,\n () => {\n if (disabled || readOnly) return;\n dispatch({ type: 'CLEAR_SELECTION' });\n inputRef.current?.focus();\n },\n ),\n }),\n [ids, disabled, readOnly],\n );\n\n const getMenuProps = useCallback(\n (userProps: Record<string, unknown> = {}) => ({\n id: ids.listbox,\n role: 'listbox' as const,\n 'aria-labelledby': ariaLabelledBy ?? ids.label,\n 'aria-label': ariaLabel,\n 'aria-multiselectable': mode === 'multi' ? true : undefined,\n ...userProps,\n onMouseDown: callAll(\n userProps.onMouseDown as (() => void) | undefined,\n (e: React.MouseEvent) => e.preventDefault(), // prevent input blur\n ),\n ref: mergeRefs(\n listboxRef,\n userProps.ref as React.RefObject<HTMLElement | null> | undefined,\n ),\n }),\n [ids, ariaLabel, ariaLabelledBy, mode],\n );\n\n const getItemProps = useCallback(\n ({\n item,\n index,\n variant: itemVariant,\n ...userProps\n }: { item: T; index: number; variant?: string } & Record<\n string,\n unknown\n >) => {\n const isSelected = mode === 'multi'\n ? state.selectedItems.some((si) => itemToValue(si) === itemToValue(item))\n : state.selectedItem != null &&\n itemToValue(state.selectedItem) === itemToValue(item);\n const isHighlighted = state.highlightedIndex === index;\n const itemIsDisabled = isItemDisabled(item);\n\n const useChecked = itemVariant === 'checkbox' || itemVariant === 'radio';\n\n return {\n id: ids.item(index),\n role: 'option' as const,\n 'aria-selected': isSelected,\n 'aria-checked': useChecked ? isSelected : undefined,\n 'aria-disabled': itemIsDisabled || undefined,\n 'data-rzero-index': index,\n 'data-highlighted': isHighlighted || undefined,\n 'data-selected': isSelected || undefined,\n 'data-disabled': itemIsDisabled || undefined,\n 'data-variant': itemVariant || undefined,\n ...userProps,\n onClick: callAll(\n userProps?.onClick as (() => void) | undefined,\n () => {\n if (itemIsDisabled) return;\n dispatch({ type: 'SELECT_ITEM', item });\n },\n ),\n onMouseEnter: callAll(\n userProps?.onMouseEnter as (() => void) | undefined,\n () => {\n if (itemIsDisabled && disabledItemBehavior === 'skip') return;\n dispatch({ type: 'HIGHLIGHT_ITEM', index });\n },\n ),\n onMouseLeave: callAll(\n userProps?.onMouseLeave as (() => void) | undefined,\n () => {\n dispatch({ type: 'HIGHLIGHT_ITEM', index: -1 });\n },\n ),\n };\n },\n [\n state.selectedItem,\n state.selectedItems,\n state.highlightedIndex,\n ids,\n itemToValue,\n isItemDisabled,\n disabledItemBehavior,\n mode,\n ],\n );\n\n const getGroupProps = useCallback(\n ({\n group,\n index,\n ...userProps\n }: {\n group: ComboGroup<T>;\n index: number;\n } & Record<string, unknown>) => ({\n role: 'group' as const,\n 'aria-label': group.label,\n id: ids.group(index),\n 'data-disabled': group.disabled || undefined,\n ...userProps,\n }),\n [ids],\n );\n\n const getChevronProps = useCallback(\n (userProps: Record<string, unknown> = {}) => ({\n 'data-rzero-chevron': '',\n 'aria-hidden': true as const,\n ...userProps,\n }),\n [],\n );\n\n const getTriggerProps = useCallback(\n (userProps: Record<string, unknown> = {}) => ({\n role: 'combobox' as const,\n 'aria-expanded': isOpen,\n 'aria-haspopup': 'listbox' as const,\n 'aria-controls': ids.listbox,\n 'aria-activedescendant':\n state.highlightedIndex >= 0\n ? ids.item(state.highlightedIndex)\n : undefined,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-disabled': disabled ? true : undefined,\n 'data-rzero-trigger': '',\n 'data-disabled': disabled || undefined,\n 'data-readonly': readOnly || undefined,\n 'data-loading': disabled === 'loading' || undefined,\n tabIndex: 0,\n ...userProps,\n onKeyDown: callAll(\n userProps.onKeyDown as (() => void) | undefined,\n handleKeyDown,\n ),\n onClick: callAll(\n userProps.onClick as (() => void) | undefined,\n () => {\n if (disabled || readOnly) return;\n dispatch({ type: 'TOGGLE_MENU' });\n },\n ),\n onFocus: callAll(\n userProps.onFocus as (() => void) | undefined,\n () => {\n if (disabled) return;\n dispatch({ type: 'FOCUS' });\n },\n ),\n onBlur: callAll(\n userProps.onBlur as (() => void) | undefined,\n () => {\n dispatch({ type: 'BLUR' });\n },\n ),\n ref: mergeRefs(\n triggerRef,\n userProps.ref as React.RefObject<HTMLElement | null> | undefined,\n ),\n }),\n [\n ids,\n isOpen,\n state.highlightedIndex,\n ariaLabel,\n ariaLabelledBy,\n disabled,\n readOnly,\n handleKeyDown,\n ],\n );\n\n // ---- IMPERATIVE ACTIONS ----\n const openMenu = useCallback(() => dispatch({ type: 'OPEN_MENU' }), []);\n const closeMenu = useCallback(() => dispatch({ type: 'CLOSE_MENU' }), []);\n const toggleMenu = useCallback(\n () => dispatch({ type: 'TOGGLE_MENU' }),\n [],\n );\n const selectItem = useCallback(\n (item: T) => dispatch({ type: 'SELECT_ITEM', item }),\n [],\n );\n const removeItem = useCallback(\n (item: T) => dispatch({ type: 'DESELECT_ITEM', item }),\n [],\n );\n const selectAll = useCallback(\n () => dispatch({ type: 'SELECT_ALL' }),\n [],\n );\n const clearSelection = useCallback(\n () => dispatch({ type: 'CLEAR_SELECTION' }),\n [],\n );\n const setInputValue = useCallback(\n (v: string) => dispatch({ type: 'INPUT_CHANGE', value: v }),\n [],\n );\n const reset = useCallback(() => dispatch({ type: 'RESET' }), []);\n\n return {\n // Prop getters\n getInputProps: getInputProps as UseComboReturn<T>['getInputProps'],\n getToggleButtonProps:\n getToggleButtonProps as UseComboReturn<T>['getToggleButtonProps'],\n getLabelProps: getLabelProps as UseComboReturn<T>['getLabelProps'],\n getClearButtonProps:\n getClearButtonProps as UseComboReturn<T>['getClearButtonProps'],\n getMenuProps: getMenuProps as UseComboReturn<T>['getMenuProps'],\n getItemProps,\n getGroupProps,\n getChevronProps: getChevronProps as UseComboReturn<T>['getChevronProps'],\n getTriggerProps:\n getTriggerProps as UseComboReturn<T>['getTriggerProps'],\n getControlProps:\n getTriggerProps as UseComboReturn<T>['getControlProps'],\n\n // State\n isOpen,\n inputValue: state.inputValue,\n selectedItem: state.selectedItem,\n selectedItems: state.selectedItems,\n highlightedIndex: state.highlightedIndex,\n filteredItems: state.filteredItems,\n hasSelection,\n triggerLabel,\n isLoading: state.isLoading,\n isEmpty: isOpen && state.filteredItems.length === 0,\n isError: state.error != null,\n error: state.error,\n\n // Icons\n icons,\n chevronIcon,\n\n // Actions\n openMenu,\n closeMenu,\n toggleMenu,\n selectItem,\n removeItem,\n selectAll,\n clearSelection,\n setInputValue,\n reset,\n\n // Refs\n inputRef,\n listboxRef,\n triggerRef,\n };\n}\n"],"names":["callAll","fns","args","fn","defaultItemToString","item","defaultItemToValue","defaultFilter","items","inputValue","itemToString","lower","clamp","value","min","max","mergeRefs","refs","instance","ref","isOpenStatus","status","filterItems","ctx","filtered","getNextEnabledIndex","filteredItems","currentIndex","direction","isItemDisabled","behavior","len","next","attempts","getFirstEnabledIndex","i","getLastEnabledIndex","getInitialState","options","its","selectedItem","comboReducer","state","action","label","toggleSearchValue","searchValue","idx","current","itemVal","alreadySelected","si","nextSelectedItems","currentVal","newVal","enabledItems","createKeyboardHandler","dispatch","event","isOpen","maxIdx","PREFIX","buildIds","id","index","useComboIds","userProvidedId","reactId","useId","idsRef","useRef","liveRegionElement","clearTimer","ensureRegion","announce","message","clearAfterMs","region","scrollIntoView","listboxElement","highlightedIndex","useCombo","userItemToString","userItemToValue","mode","variant","filterFunction","closeOnSelect","commitOnBlur","deselectionAllowed","disabled","readOnly","userIsItemDisabled","hideDisabled","disabledItemBehavior","ariaLabel","ariaLabelledBy","iconOverrides","chevronStyle","onSelectedItemChange","onSelectedItemsChange","onIsOpenChange","onHighlightedIndexChange","onStateChange","onInputChange","itemToValue","ids","inputRef","listboxRef","triggerRef","ctxRef","useReducer","s","prevItemsRef","useEffect","hasSelection","triggerLabel","icons","useMemo","resolveIcons","chevronIcon","resolveChevron","stateRef","handleKeyDown","useCallback","prevIsOpenRef","prevFilteredLenRef","wasOpen","prevLen","count","prevStateRef","prev","added","getLabelProps","userProps","getInputProps","e","getToggleButtonProps","getClearButtonProps","getMenuProps","getItemProps","itemVariant","isSelected","isHighlighted","itemIsDisabled","useChecked","getGroupProps","group","getChevronProps","getTriggerProps","openMenu","closeMenu","toggleMenu","selectItem","removeItem","selectAll","clearSelection","setInputValue","v","reset"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ "use strict";const h=require("react"),b={top:0,left:0,width:0,placement:"bottom-start",maxHeight:0},r=8,R=.4;function z(x){const{triggerRef:i,listboxRef:m,isOpen:o,matchTriggerWidth:u=!0}=x,[H,M]=h.useState(b),e=h.useCallback(()=>{const n=i.current;if(!n||!o)return;const t=n.getBoundingClientRect(),g=window.innerHeight,p=window.innerWidth,c=g*R,I=g-t.bottom,E=t.top,a=Math.min(c,I-r),v=Math.min(c,E-r),s=a<c&&v>a?"top-start":"bottom-start",l=s==="bottom-start"?a:v,f=m.current,L=s==="top-start"&&f?Math.min(f.scrollHeight,Math.max(l,0)):Math.max(l,0),O=s==="bottom-start"?t.bottom+window.scrollY+r:t.top+window.scrollY-L-r,w=u?t.width:Math.max(t.width,200);let d=t.left+window.scrollX;d+w>p&&(d=Math.max(0,p-w)),M({top:O,left:d,width:w,placement:s,maxHeight:Math.max(l,0)})},[i,m,o,u]);return h.useLayoutEffect(()=>{if(!o)return;e();const n=i.current;let t;return n&&typeof ResizeObserver<"u"&&(t=new ResizeObserver(e),t.observe(n)),window.addEventListener("scroll",e,{passive:!0}),window.addEventListener("resize",e,{passive:!0}),()=>{t?.disconnect(),window.removeEventListener("scroll",e),window.removeEventListener("resize",e)}},[o,e,i]),o?H:b}exports.usePosition=z;
2
+ //# sourceMappingURL=usePosition-6GfutqGX.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePosition-6GfutqGX.cjs","sources":["../src/hooks/usePosition.ts"],"sourcesContent":["import { useLayoutEffect, useState, useCallback, type RefObject } from 'react';\n\nexport interface Position {\n top: number;\n left: number;\n width: number;\n placement: 'bottom-start' | 'top-start';\n maxHeight: number;\n}\n\nexport interface UsePositionOptions {\n triggerRef: RefObject<HTMLElement | null>;\n listboxRef: RefObject<HTMLElement | null>;\n isOpen: boolean;\n matchTriggerWidth?: boolean;\n}\n\nconst INITIAL_POSITION: Position = {\n top: 0,\n left: 0,\n width: 0,\n placement: 'bottom-start',\n maxHeight: 0,\n};\n\nconst MARGIN = 8;\nconst MAX_HEIGHT_VH = 0.4;\n\nexport function usePosition(options: UsePositionOptions): Position {\n const { triggerRef, listboxRef, isOpen, matchTriggerWidth = true } = options;\n\n const [position, setPosition] = useState<Position>(INITIAL_POSITION);\n\n const calculate = useCallback(() => {\n const trigger = triggerRef.current;\n if (!trigger || !isOpen) return;\n\n const rect = trigger.getBoundingClientRect();\n const viewportHeight = window.innerHeight;\n const viewportWidth = window.innerWidth;\n const maxHeightValue = viewportHeight * MAX_HEIGHT_VH;\n\n // Flip: prefer bottom, flip to top if list would be clipped and there's more room above\n const spaceBelow = viewportHeight - rect.bottom;\n const spaceAbove = rect.top;\n const maxHeightBelow = Math.min(maxHeightValue, spaceBelow - MARGIN);\n const maxHeightAbove = Math.min(maxHeightValue, spaceAbove - MARGIN);\n const needsFlip = maxHeightBelow < maxHeightValue && maxHeightAbove > maxHeightBelow;\n const placement = needsFlip ? 'top-start' : 'bottom-start';\n\n const effectiveMaxHeight =\n placement === 'bottom-start' ? maxHeightBelow : maxHeightAbove;\n\n // For top placement, use actual listbox height (clamped to max) so popover\n // sits flush against the trigger instead of reserving full maxHeight space\n const listbox = listboxRef.current;\n const actualHeight =\n placement === 'top-start' && listbox\n ? Math.min(listbox.scrollHeight, Math.max(effectiveMaxHeight, 0))\n : Math.max(effectiveMaxHeight, 0);\n\n const top =\n placement === 'bottom-start'\n ? rect.bottom + window.scrollY + MARGIN\n : rect.top + window.scrollY - actualHeight - MARGIN;\n\n // Shift: keep within horizontal viewport bounds\n const width = matchTriggerWidth\n ? rect.width\n : Math.max(rect.width, 200);\n let left = rect.left + window.scrollX;\n if (left + width > viewportWidth) {\n left = Math.max(0, viewportWidth - width);\n }\n\n setPosition({\n top,\n left,\n width,\n placement,\n maxHeight: Math.max(effectiveMaxHeight, 0),\n });\n }, [triggerRef, listboxRef, isOpen, matchTriggerWidth]);\n\n useLayoutEffect(() => {\n if (!isOpen) return;\n calculate();\n\n const trigger = triggerRef.current;\n let resizeObserver: ResizeObserver | undefined;\n if (trigger && typeof ResizeObserver !== 'undefined') {\n resizeObserver = new ResizeObserver(calculate);\n resizeObserver.observe(trigger);\n }\n\n window.addEventListener('scroll', calculate, { passive: true });\n window.addEventListener('resize', calculate, { passive: true });\n\n return () => {\n resizeObserver?.disconnect();\n window.removeEventListener('scroll', calculate);\n window.removeEventListener('resize', calculate);\n };\n }, [isOpen, calculate, triggerRef]);\n\n return isOpen ? position : INITIAL_POSITION;\n}\n"],"names":["INITIAL_POSITION","MARGIN","MAX_HEIGHT_VH","usePosition","options","triggerRef","listboxRef","isOpen","matchTriggerWidth","position","setPosition","useState","calculate","useCallback","trigger","rect","viewportHeight","viewportWidth","maxHeightValue","spaceBelow","spaceAbove","maxHeightBelow","maxHeightAbove","placement","effectiveMaxHeight","listbox","actualHeight","top","width","left","useLayoutEffect","resizeObserver"],"mappings":"sCAiBMA,EAA6B,CACjC,IAAK,EACL,KAAM,EACN,MAAO,EACP,UAAW,eACX,UAAW,CACb,EAEMC,EAAS,EACTC,EAAgB,GAEf,SAASC,EAAYC,EAAuC,CACjE,KAAM,CAAE,WAAAC,EAAY,WAAAC,EAAY,OAAAC,EAAQ,kBAAAC,EAAoB,IAASJ,EAE/D,CAACK,EAAUC,CAAW,EAAIC,EAAAA,SAAmBX,CAAgB,EAE7DY,EAAYC,EAAAA,YAAY,IAAM,CAClC,MAAMC,EAAUT,EAAW,QAC3B,GAAI,CAACS,GAAW,CAACP,EAAQ,OAEzB,MAAMQ,EAAOD,EAAQ,sBAAA,EACfE,EAAiB,OAAO,YACxBC,EAAgB,OAAO,WACvBC,EAAiBF,EAAiBd,EAGlCiB,EAAaH,EAAiBD,EAAK,OACnCK,EAAaL,EAAK,IAClBM,EAAiB,KAAK,IAAIH,EAAgBC,EAAalB,CAAM,EAC7DqB,EAAiB,KAAK,IAAIJ,EAAgBE,EAAanB,CAAM,EAE7DsB,EADYF,EAAiBH,GAAkBI,EAAiBD,EACxC,YAAc,eAEtCG,EACJD,IAAc,eAAiBF,EAAiBC,EAI5CG,EAAUnB,EAAW,QACrBoB,EACJH,IAAc,aAAeE,EACzB,KAAK,IAAIA,EAAQ,aAAc,KAAK,IAAID,EAAoB,CAAC,CAAC,EAC9D,KAAK,IAAIA,EAAoB,CAAC,EAE9BG,EACJJ,IAAc,eACVR,EAAK,OAAS,OAAO,QAAUd,EAC/Bc,EAAK,IAAM,OAAO,QAAUW,EAAezB,EAG3C2B,EAAQpB,EACVO,EAAK,MACL,KAAK,IAAIA,EAAK,MAAO,GAAG,EAC5B,IAAIc,EAAOd,EAAK,KAAO,OAAO,QAC1Bc,EAAOD,EAAQX,IACjBY,EAAO,KAAK,IAAI,EAAGZ,EAAgBW,CAAK,GAG1ClB,EAAY,CACV,IAAAiB,EACA,KAAAE,EACA,MAAAD,EACA,UAAAL,EACA,UAAW,KAAK,IAAIC,EAAoB,CAAC,CAAA,CAC1C,CACH,EAAG,CAACnB,EAAYC,EAAYC,EAAQC,CAAiB,CAAC,EAEtDsB,OAAAA,EAAAA,gBAAgB,IAAM,CACpB,GAAI,CAACvB,EAAQ,OACbK,EAAA,EAEA,MAAME,EAAUT,EAAW,QAC3B,IAAI0B,EACJ,OAAIjB,GAAW,OAAO,eAAmB,MACvCiB,EAAiB,IAAI,eAAenB,CAAS,EAC7CmB,EAAe,QAAQjB,CAAO,GAGhC,OAAO,iBAAiB,SAAUF,EAAW,CAAE,QAAS,GAAM,EAC9D,OAAO,iBAAiB,SAAUA,EAAW,CAAE,QAAS,GAAM,EAEvD,IAAM,CACXmB,GAAgB,WAAA,EAChB,OAAO,oBAAoB,SAAUnB,CAAS,EAC9C,OAAO,oBAAoB,SAAUA,CAAS,CAChD,CACF,EAAG,CAACL,EAAQK,EAAWP,CAAU,CAAC,EAE3BE,EAASE,EAAWT,CAC7B"}
@@ -0,0 +1,36 @@
1
+ import { useState as O, useCallback as R, useLayoutEffect as z } from "react";
2
+ const v = {
3
+ top: 0,
4
+ left: 0,
5
+ width: 0,
6
+ placement: "bottom-start",
7
+ maxHeight: 0
8
+ }, r = 8, A = 0.4;
9
+ function N(b) {
10
+ const { triggerRef: i, listboxRef: h, isOpen: o, matchTriggerWidth: m = !0 } = b, [x, H] = O(v), e = R(() => {
11
+ const n = i.current;
12
+ if (!n || !o) return;
13
+ const t = n.getBoundingClientRect(), u = window.innerHeight, p = window.innerWidth, c = u * A, M = u - t.bottom, I = t.top, a = Math.min(c, M - r), g = Math.min(c, I - r), s = a < c && g > a ? "top-start" : "bottom-start", l = s === "bottom-start" ? a : g, f = h.current, E = s === "top-start" && f ? Math.min(f.scrollHeight, Math.max(l, 0)) : Math.max(l, 0), L = s === "bottom-start" ? t.bottom + window.scrollY + r : t.top + window.scrollY - E - r, w = m ? t.width : Math.max(t.width, 200);
14
+ let d = t.left + window.scrollX;
15
+ d + w > p && (d = Math.max(0, p - w)), H({
16
+ top: L,
17
+ left: d,
18
+ width: w,
19
+ placement: s,
20
+ maxHeight: Math.max(l, 0)
21
+ });
22
+ }, [i, h, o, m]);
23
+ return z(() => {
24
+ if (!o) return;
25
+ e();
26
+ const n = i.current;
27
+ let t;
28
+ return n && typeof ResizeObserver < "u" && (t = new ResizeObserver(e), t.observe(n)), window.addEventListener("scroll", e, { passive: !0 }), window.addEventListener("resize", e, { passive: !0 }), () => {
29
+ t?.disconnect(), window.removeEventListener("scroll", e), window.removeEventListener("resize", e);
30
+ };
31
+ }, [o, e, i]), o ? x : v;
32
+ }
33
+ export {
34
+ N as u
35
+ };
36
+ //# sourceMappingURL=usePosition-DVw8IlwA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePosition-DVw8IlwA.js","sources":["../src/hooks/usePosition.ts"],"sourcesContent":["import { useLayoutEffect, useState, useCallback, type RefObject } from 'react';\n\nexport interface Position {\n top: number;\n left: number;\n width: number;\n placement: 'bottom-start' | 'top-start';\n maxHeight: number;\n}\n\nexport interface UsePositionOptions {\n triggerRef: RefObject<HTMLElement | null>;\n listboxRef: RefObject<HTMLElement | null>;\n isOpen: boolean;\n matchTriggerWidth?: boolean;\n}\n\nconst INITIAL_POSITION: Position = {\n top: 0,\n left: 0,\n width: 0,\n placement: 'bottom-start',\n maxHeight: 0,\n};\n\nconst MARGIN = 8;\nconst MAX_HEIGHT_VH = 0.4;\n\nexport function usePosition(options: UsePositionOptions): Position {\n const { triggerRef, listboxRef, isOpen, matchTriggerWidth = true } = options;\n\n const [position, setPosition] = useState<Position>(INITIAL_POSITION);\n\n const calculate = useCallback(() => {\n const trigger = triggerRef.current;\n if (!trigger || !isOpen) return;\n\n const rect = trigger.getBoundingClientRect();\n const viewportHeight = window.innerHeight;\n const viewportWidth = window.innerWidth;\n const maxHeightValue = viewportHeight * MAX_HEIGHT_VH;\n\n // Flip: prefer bottom, flip to top if list would be clipped and there's more room above\n const spaceBelow = viewportHeight - rect.bottom;\n const spaceAbove = rect.top;\n const maxHeightBelow = Math.min(maxHeightValue, spaceBelow - MARGIN);\n const maxHeightAbove = Math.min(maxHeightValue, spaceAbove - MARGIN);\n const needsFlip = maxHeightBelow < maxHeightValue && maxHeightAbove > maxHeightBelow;\n const placement = needsFlip ? 'top-start' : 'bottom-start';\n\n const effectiveMaxHeight =\n placement === 'bottom-start' ? maxHeightBelow : maxHeightAbove;\n\n // For top placement, use actual listbox height (clamped to max) so popover\n // sits flush against the trigger instead of reserving full maxHeight space\n const listbox = listboxRef.current;\n const actualHeight =\n placement === 'top-start' && listbox\n ? Math.min(listbox.scrollHeight, Math.max(effectiveMaxHeight, 0))\n : Math.max(effectiveMaxHeight, 0);\n\n const top =\n placement === 'bottom-start'\n ? rect.bottom + window.scrollY + MARGIN\n : rect.top + window.scrollY - actualHeight - MARGIN;\n\n // Shift: keep within horizontal viewport bounds\n const width = matchTriggerWidth\n ? rect.width\n : Math.max(rect.width, 200);\n let left = rect.left + window.scrollX;\n if (left + width > viewportWidth) {\n left = Math.max(0, viewportWidth - width);\n }\n\n setPosition({\n top,\n left,\n width,\n placement,\n maxHeight: Math.max(effectiveMaxHeight, 0),\n });\n }, [triggerRef, listboxRef, isOpen, matchTriggerWidth]);\n\n useLayoutEffect(() => {\n if (!isOpen) return;\n calculate();\n\n const trigger = triggerRef.current;\n let resizeObserver: ResizeObserver | undefined;\n if (trigger && typeof ResizeObserver !== 'undefined') {\n resizeObserver = new ResizeObserver(calculate);\n resizeObserver.observe(trigger);\n }\n\n window.addEventListener('scroll', calculate, { passive: true });\n window.addEventListener('resize', calculate, { passive: true });\n\n return () => {\n resizeObserver?.disconnect();\n window.removeEventListener('scroll', calculate);\n window.removeEventListener('resize', calculate);\n };\n }, [isOpen, calculate, triggerRef]);\n\n return isOpen ? position : INITIAL_POSITION;\n}\n"],"names":["INITIAL_POSITION","MARGIN","MAX_HEIGHT_VH","usePosition","options","triggerRef","listboxRef","isOpen","matchTriggerWidth","position","setPosition","useState","calculate","useCallback","trigger","rect","viewportHeight","viewportWidth","maxHeightValue","spaceBelow","spaceAbove","maxHeightBelow","maxHeightAbove","placement","effectiveMaxHeight","listbox","actualHeight","top","width","left","useLayoutEffect","resizeObserver"],"mappings":";AAiBA,MAAMA,IAA6B;AAAA,EACjC,KAAK;AAAA,EACL,MAAM;AAAA,EACN,OAAO;AAAA,EACP,WAAW;AAAA,EACX,WAAW;AACb,GAEMC,IAAS,GACTC,IAAgB;AAEf,SAASC,EAAYC,GAAuC;AACjE,QAAM,EAAE,YAAAC,GAAY,YAAAC,GAAY,QAAAC,GAAQ,mBAAAC,IAAoB,OAASJ,GAE/D,CAACK,GAAUC,CAAW,IAAIC,EAAmBX,CAAgB,GAE7DY,IAAYC,EAAY,MAAM;AAClC,UAAMC,IAAUT,EAAW;AAC3B,QAAI,CAACS,KAAW,CAACP,EAAQ;AAEzB,UAAMQ,IAAOD,EAAQ,sBAAA,GACfE,IAAiB,OAAO,aACxBC,IAAgB,OAAO,YACvBC,IAAiBF,IAAiBd,GAGlCiB,IAAaH,IAAiBD,EAAK,QACnCK,IAAaL,EAAK,KAClBM,IAAiB,KAAK,IAAIH,GAAgBC,IAAalB,CAAM,GAC7DqB,IAAiB,KAAK,IAAIJ,GAAgBE,IAAanB,CAAM,GAE7DsB,IADYF,IAAiBH,KAAkBI,IAAiBD,IACxC,cAAc,gBAEtCG,IACJD,MAAc,iBAAiBF,IAAiBC,GAI5CG,IAAUnB,EAAW,SACrBoB,IACJH,MAAc,eAAeE,IACzB,KAAK,IAAIA,EAAQ,cAAc,KAAK,IAAID,GAAoB,CAAC,CAAC,IAC9D,KAAK,IAAIA,GAAoB,CAAC,GAE9BG,IACJJ,MAAc,iBACVR,EAAK,SAAS,OAAO,UAAUd,IAC/Bc,EAAK,MAAM,OAAO,UAAUW,IAAezB,GAG3C2B,IAAQpB,IACVO,EAAK,QACL,KAAK,IAAIA,EAAK,OAAO,GAAG;AAC5B,QAAIc,IAAOd,EAAK,OAAO,OAAO;AAC9B,IAAIc,IAAOD,IAAQX,MACjBY,IAAO,KAAK,IAAI,GAAGZ,IAAgBW,CAAK,IAG1ClB,EAAY;AAAA,MACV,KAAAiB;AAAA,MACA,MAAAE;AAAA,MACA,OAAAD;AAAA,MACA,WAAAL;AAAA,MACA,WAAW,KAAK,IAAIC,GAAoB,CAAC;AAAA,IAAA,CAC1C;AAAA,EACH,GAAG,CAACnB,GAAYC,GAAYC,GAAQC,CAAiB,CAAC;AAEtD,SAAAsB,EAAgB,MAAM;AACpB,QAAI,CAACvB,EAAQ;AACb,IAAAK,EAAA;AAEA,UAAME,IAAUT,EAAW;AAC3B,QAAI0B;AACJ,WAAIjB,KAAW,OAAO,iBAAmB,QACvCiB,IAAiB,IAAI,eAAenB,CAAS,GAC7CmB,EAAe,QAAQjB,CAAO,IAGhC,OAAO,iBAAiB,UAAUF,GAAW,EAAE,SAAS,IAAM,GAC9D,OAAO,iBAAiB,UAAUA,GAAW,EAAE,SAAS,IAAM,GAEvD,MAAM;AACX,MAAAmB,GAAgB,WAAA,GAChB,OAAO,oBAAoB,UAAUnB,CAAS,GAC9C,OAAO,oBAAoB,UAAUA,CAAS;AAAA,IAChD;AAAA,EACF,GAAG,CAACL,GAAQK,GAAWP,CAAU,CAAC,GAE3BE,IAASE,IAAWT;AAC7B;"}
package/package.json ADDED
@@ -0,0 +1,219 @@
1
+ {
2
+ "name": "@reactzero/combo",
3
+ "version": "0.1.0",
4
+ "description": "Headless, accessible React combo & select. Attach a dropdown to anything. Zero dependencies, ARIA 1.2 compliant, <7 kB.",
5
+ "keywords": [
6
+ "react",
7
+ "combo",
8
+ "combobox",
9
+ "autocomplete",
10
+ "select",
11
+ "multi-select",
12
+ "accessible",
13
+ "a11y",
14
+ "headless",
15
+ "zero-dependency",
16
+ "css-variables",
17
+ "themes",
18
+ "typescript"
19
+ ],
20
+ "license": "MIT",
21
+ "author": {
22
+ "name": "Luis Vargas",
23
+ "email": "lvargasdesign@gmail.com",
24
+ "url": "https://github.com/motiondesignlv"
25
+ },
26
+ "type": "module",
27
+ "exports": {
28
+ ".": {
29
+ "import": {
30
+ "types": "./dist/index.d.ts",
31
+ "default": "./dist/index.js"
32
+ },
33
+ "require": {
34
+ "types": "./dist/index.d.ts",
35
+ "default": "./dist/index.cjs"
36
+ }
37
+ },
38
+ "./hook": {
39
+ "import": {
40
+ "types": "./dist/entries/hook.d.ts",
41
+ "default": "./dist/hook.js"
42
+ },
43
+ "require": {
44
+ "types": "./dist/entries/hook.d.ts",
45
+ "default": "./dist/hook.cjs"
46
+ }
47
+ },
48
+ "./headless": {
49
+ "import": {
50
+ "types": "./dist/entries/hook.d.ts",
51
+ "default": "./dist/hook.js"
52
+ },
53
+ "require": {
54
+ "types": "./dist/entries/hook.d.ts",
55
+ "default": "./dist/hook.cjs"
56
+ }
57
+ },
58
+ "./slots": {
59
+ "import": {
60
+ "types": "./dist/entries/slots.d.ts",
61
+ "default": "./dist/slots.js"
62
+ },
63
+ "require": {
64
+ "types": "./dist/entries/slots.d.ts",
65
+ "default": "./dist/slots.cjs"
66
+ }
67
+ },
68
+ "./tabs": {
69
+ "import": {
70
+ "types": "./dist/entries/tabs.d.ts",
71
+ "default": "./dist/tabs.js"
72
+ },
73
+ "require": {
74
+ "types": "./dist/entries/tabs.d.ts",
75
+ "default": "./dist/tabs.cjs"
76
+ }
77
+ },
78
+ "./hook-bare": {
79
+ "import": {
80
+ "types": "./dist/entries/hook-bare.d.ts",
81
+ "default": "./dist/hook-bare.js"
82
+ },
83
+ "require": {
84
+ "types": "./dist/entries/hook-bare.d.ts",
85
+ "default": "./dist/hook-bare.cjs"
86
+ }
87
+ },
88
+ "./icons": {
89
+ "import": {
90
+ "types": "./dist/entries/icons.d.ts",
91
+ "default": "./dist/icons.js"
92
+ },
93
+ "require": {
94
+ "types": "./dist/entries/icons.d.ts",
95
+ "default": "./dist/icons.cjs"
96
+ }
97
+ },
98
+ "./position": {
99
+ "import": {
100
+ "types": "./dist/entries/position.d.ts",
101
+ "default": "./dist/position.js"
102
+ },
103
+ "require": {
104
+ "types": "./dist/entries/position.d.ts",
105
+ "default": "./dist/position.cjs"
106
+ }
107
+ },
108
+ "./styles": "./dist/style.css",
109
+ "./styles/base": "./dist/styles/base.css",
110
+ "./styles/select": "./dist/styles/select.css",
111
+ "./styles/states": "./dist/styles/states.css",
112
+ "./styles/footer": "./dist/styles/footer.css",
113
+ "./styles/groups": "./dist/styles/groups.css",
114
+ "./styles/checkbox": "./dist/styles/checkbox.css",
115
+ "./styles/radio": "./dist/styles/radio.css",
116
+ "./styles/custom-item": "./dist/styles/custom-item.css",
117
+ "./styles/chips": "./dist/styles/chips.css",
118
+ "./styles/meta": "./dist/styles/meta.css",
119
+ "./styles/tabs": "./dist/tabs.css",
120
+ "./themes/*": "./dist/themes/*.css",
121
+ "./package.json": "./package.json"
122
+ },
123
+ "main": "./dist/index.cjs",
124
+ "module": "./dist/index.js",
125
+ "types": "./dist/index.d.ts",
126
+ "files": [
127
+ "dist",
128
+ "LICENSE",
129
+ "README.md",
130
+ "CHANGELOG.md"
131
+ ],
132
+ "sideEffects": [
133
+ "*.css"
134
+ ],
135
+ "scripts": {
136
+ "dev": "npm run demo:dev",
137
+ "build": "vite build && tsc -p tsconfig.build.json && cp -r src/themes dist/themes && mkdir -p dist/styles && cp src/styles/base.css src/styles/select.css src/styles/states.css src/styles/footer.css src/styles/groups.css src/styles/checkbox.css src/styles/radio.css src/styles/custom-item.css src/styles/chips.css src/styles/meta.css dist/styles/",
138
+ "postbuild": "node -e \"const fs=require('fs');const css=fs.readFileSync('dist/style.css','utf8');if(css.includes('@import')){console.error('ERROR: CSS still contains @import');process.exit(1);}if(!fs.existsSync('dist/styles/base.css')){console.error('ERROR: dist/styles/base.css missing');process.exit(1);}const js=fs.readFileSync('dist/index.js','utf8');console.log('Build OK — JS:',Math.round(js.length/1024)+'kB, CSS:',Math.round(css.length/1024)+'kB');\"",
139
+ "typecheck": "tsc --noEmit",
140
+ "lint": "eslint src --ext .ts,.tsx --report-unused-disable-directives --max-warnings 0",
141
+ "test": "vitest run",
142
+ "test:watch": "vitest",
143
+ "test:coverage": "vitest run --coverage",
144
+ "ci": "npm run typecheck && npm run lint && npm run test",
145
+ "size": "size-limit",
146
+ "size:check": "size-limit --limit",
147
+ "demo:dev": "vite dev --config demo/vite.config.ts",
148
+ "demo:build": "vite build --config demo/vite.config.ts",
149
+ "demo:preview": "vite preview --config demo/vite.config.ts"
150
+ },
151
+ "peerDependencies": {
152
+ "react": ">=18.0.0",
153
+ "react-dom": ">=18.0.0"
154
+ },
155
+ "devDependencies": {
156
+ "@size-limit/preset-small-lib": "^11.2.0",
157
+ "@tailwindcss/postcss": "^4.2.1",
158
+ "@testing-library/dom": "^10.4.1",
159
+ "@testing-library/jest-dom": "^6.4.0",
160
+ "@testing-library/react": "^16.0.0",
161
+ "@testing-library/user-event": "^14.5.0",
162
+ "@types/jest-axe": "^3.5.0",
163
+ "@types/react": "^18.3.0",
164
+ "@types/react-dom": "^18.3.0",
165
+ "@typescript-eslint/eslint-plugin": "^8.0.0",
166
+ "@typescript-eslint/parser": "^8.0.0",
167
+ "@vitejs/plugin-react": "^4.3.0",
168
+ "@vitest/coverage-v8": "^2.0.0",
169
+ "autoprefixer": "^10.4.27",
170
+ "eslint": "^9.0.0",
171
+ "eslint-plugin-jsx-a11y": "^6.10.0",
172
+ "eslint-plugin-react": "^7.37.0",
173
+ "eslint-plugin-react-hooks": "^5.0.0",
174
+ "jest-axe": "^9.0.0",
175
+ "jsdom": "^25.0.0",
176
+ "postcss": "^8.5.8",
177
+ "react": "^19.2.4",
178
+ "react-dom": "^19.2.4",
179
+ "size-limit": "^11.2.0",
180
+ "tailwindcss": "^4.2.1",
181
+ "typescript": "^6.0.0",
182
+ "vite": "^5.0.0",
183
+ "vitest": "^2.0.0"
184
+ },
185
+ "size-limit": [
186
+ {
187
+ "path": "dist/hook.js",
188
+ "limit": "5 kB"
189
+ },
190
+ {
191
+ "path": "dist/hook-bare.js",
192
+ "limit": "5 kB"
193
+ },
194
+ {
195
+ "path": "dist/index.js",
196
+ "limit": "9 kB"
197
+ },
198
+ {
199
+ "path": "dist/slots.js",
200
+ "limit": "1.5 kB"
201
+ },
202
+ {
203
+ "path": "dist/tabs.js",
204
+ "limit": "7.5 kB"
205
+ },
206
+ {
207
+ "path": "dist/icons.js",
208
+ "limit": "2 kB"
209
+ },
210
+ {
211
+ "path": "dist/position.js",
212
+ "limit": "1.5 kB"
213
+ },
214
+ {
215
+ "path": "dist/style.css",
216
+ "limit": "5 kB"
217
+ }
218
+ ]
219
+ }