reka-ui 2.9.1 → 2.9.3

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 (127) hide show
  1. package/dist/Autocomplete/AutocompleteInput.cjs +25 -8
  2. package/dist/Autocomplete/AutocompleteInput.cjs.map +1 -1
  3. package/dist/Autocomplete/AutocompleteInput.js +26 -9
  4. package/dist/Autocomplete/AutocompleteInput.js.map +1 -1
  5. package/dist/Calendar/CalendarGrid.cjs +2 -2
  6. package/dist/Calendar/CalendarGrid.cjs.map +1 -1
  7. package/dist/Calendar/CalendarGrid.js +3 -3
  8. package/dist/Calendar/CalendarGrid.js.map +1 -1
  9. package/dist/ColorArea/ColorAreaRoot.cjs +0 -1
  10. package/dist/ColorArea/ColorAreaRoot.cjs.map +1 -1
  11. package/dist/ColorArea/ColorAreaRoot.js +0 -1
  12. package/dist/ColorArea/ColorAreaRoot.js.map +1 -1
  13. package/dist/ColorField/ColorFieldRoot.cjs +0 -1
  14. package/dist/ColorField/ColorFieldRoot.cjs.map +1 -1
  15. package/dist/ColorField/ColorFieldRoot.js +0 -1
  16. package/dist/ColorField/ColorFieldRoot.js.map +1 -1
  17. package/dist/Combobox/ComboboxItem.cjs +1 -1
  18. package/dist/Combobox/ComboboxItem.cjs.map +1 -1
  19. package/dist/Combobox/ComboboxItem.js +1 -1
  20. package/dist/Combobox/ComboboxItem.js.map +1 -1
  21. package/dist/FocusScope/FocusScope.cjs +5 -1
  22. package/dist/FocusScope/FocusScope.cjs.map +1 -1
  23. package/dist/FocusScope/FocusScope.js +5 -1
  24. package/dist/FocusScope/FocusScope.js.map +1 -1
  25. package/dist/HoverCard/HoverCardContentImpl.cjs +5 -0
  26. package/dist/HoverCard/HoverCardContentImpl.cjs.map +1 -1
  27. package/dist/HoverCard/HoverCardContentImpl.js +5 -0
  28. package/dist/HoverCard/HoverCardContentImpl.js.map +1 -1
  29. package/dist/Listbox/ListboxItem.cjs +1 -1
  30. package/dist/Listbox/ListboxItem.cjs.map +1 -1
  31. package/dist/Listbox/ListboxItem.js +1 -1
  32. package/dist/Listbox/ListboxItem.js.map +1 -1
  33. package/dist/Listbox/ListboxRoot.cjs +6 -5
  34. package/dist/Listbox/ListboxRoot.cjs.map +1 -1
  35. package/dist/Listbox/ListboxRoot.js +6 -5
  36. package/dist/Listbox/ListboxRoot.js.map +1 -1
  37. package/dist/Menu/MenuItemImpl.cjs +1 -3
  38. package/dist/Menu/MenuItemImpl.cjs.map +1 -1
  39. package/dist/Menu/MenuItemImpl.js +1 -3
  40. package/dist/Menu/MenuItemImpl.js.map +1 -1
  41. package/dist/MonthPicker/MonthPickerGrid.cjs +2 -2
  42. package/dist/MonthPicker/MonthPickerGrid.cjs.map +1 -1
  43. package/dist/MonthPicker/MonthPickerGrid.js +3 -3
  44. package/dist/MonthPicker/MonthPickerGrid.js.map +1 -1
  45. package/dist/MonthRangePicker/MonthRangePickerGrid.cjs +2 -2
  46. package/dist/MonthRangePicker/MonthRangePickerGrid.cjs.map +1 -1
  47. package/dist/MonthRangePicker/MonthRangePickerGrid.js +3 -3
  48. package/dist/MonthRangePicker/MonthRangePickerGrid.js.map +1 -1
  49. package/dist/PinInput/PinInputInput.cjs +12 -6
  50. package/dist/PinInput/PinInputInput.cjs.map +1 -1
  51. package/dist/PinInput/PinInputInput.js +12 -6
  52. package/dist/PinInput/PinInputInput.js.map +1 -1
  53. package/dist/RangeCalendar/RangeCalendarGrid.cjs +2 -2
  54. package/dist/RangeCalendar/RangeCalendarGrid.cjs.map +1 -1
  55. package/dist/RangeCalendar/RangeCalendarGrid.js +3 -3
  56. package/dist/RangeCalendar/RangeCalendarGrid.js.map +1 -1
  57. package/dist/Splitter/SplitterGroup.cjs +7 -0
  58. package/dist/Splitter/SplitterGroup.cjs.map +1 -1
  59. package/dist/Splitter/SplitterGroup.js +7 -0
  60. package/dist/Splitter/SplitterGroup.js.map +1 -1
  61. package/dist/TagsInput/TagsInputInput.cjs +3 -0
  62. package/dist/TagsInput/TagsInputInput.cjs.map +1 -1
  63. package/dist/TagsInput/TagsInputInput.js +3 -0
  64. package/dist/TagsInput/TagsInputInput.js.map +1 -1
  65. package/dist/Tooltip/TooltipContentImpl.cjs +1 -1
  66. package/dist/Tooltip/TooltipContentImpl.cjs.map +1 -1
  67. package/dist/Tooltip/TooltipContentImpl.js +1 -1
  68. package/dist/Tooltip/TooltipContentImpl.js.map +1 -1
  69. package/dist/YearPicker/YearPickerGrid.cjs +2 -2
  70. package/dist/YearPicker/YearPickerGrid.cjs.map +1 -1
  71. package/dist/YearPicker/YearPickerGrid.js +3 -3
  72. package/dist/YearPicker/YearPickerGrid.js.map +1 -1
  73. package/dist/YearRangePicker/YearRangePickerGrid.cjs +2 -2
  74. package/dist/YearRangePicker/YearRangePickerGrid.cjs.map +1 -1
  75. package/dist/YearRangePicker/YearRangePickerGrid.js +3 -3
  76. package/dist/YearRangePicker/YearRangePickerGrid.js.map +1 -1
  77. package/dist/constant.d.cts.map +1 -1
  78. package/dist/index.d.cts +2 -2
  79. package/dist/index.d.ts +2 -2
  80. package/dist/index2.d.ts.map +1 -1
  81. package/dist/index3.d.cts +999 -993
  82. package/dist/index3.d.cts.map +1 -1
  83. package/dist/index3.d.ts +1048 -1042
  84. package/dist/index3.d.ts.map +1 -1
  85. package/dist/internal.d.cts +4 -2
  86. package/dist/internal.d.cts.map +1 -1
  87. package/dist/internal.d.ts +4 -2
  88. package/dist/internal.d.ts.map +1 -1
  89. package/dist/shared/useForwardProps.cjs.map +1 -1
  90. package/dist/shared/useForwardProps.js.map +1 -1
  91. package/dist/shared/useGraceArea.cjs +1 -0
  92. package/dist/shared/useGraceArea.cjs.map +1 -1
  93. package/dist/shared/useGraceArea.js +1 -0
  94. package/dist/shared/useGraceArea.js.map +1 -1
  95. package/dist/shared/useHideOthers.cjs +5 -1
  96. package/dist/shared/useHideOthers.cjs.map +1 -1
  97. package/dist/shared/useHideOthers.js +5 -1
  98. package/dist/shared/useHideOthers.js.map +1 -1
  99. package/dist/utils/units.cjs +5 -0
  100. package/dist/utils/units.cjs.map +1 -1
  101. package/dist/utils/units.js +5 -0
  102. package/dist/utils/units.js.map +1 -1
  103. package/package.json +3 -3
  104. package/src/Autocomplete/AutocompleteInput.vue +30 -8
  105. package/src/Calendar/CalendarGrid.vue +0 -5
  106. package/src/ColorArea/ColorAreaRoot.vue +0 -4
  107. package/src/ColorField/ColorFieldRoot.vue +0 -4
  108. package/src/Combobox/ComboboxItem.vue +3 -0
  109. package/src/FocusScope/FocusScope.vue +15 -1
  110. package/src/HoverCard/HoverCardContentImpl.vue +7 -0
  111. package/src/Listbox/ListboxItem.vue +2 -2
  112. package/src/Listbox/ListboxRoot.vue +8 -6
  113. package/src/Menu/MenuItemImpl.vue +1 -4
  114. package/src/MonthPicker/MonthPickerGrid.vue +0 -5
  115. package/src/MonthRangePicker/MonthRangePickerGrid.vue +0 -5
  116. package/src/PinInput/PinInputInput.vue +19 -8
  117. package/src/RangeCalendar/RangeCalendarGrid.vue +0 -5
  118. package/src/Select/index.ts +1 -0
  119. package/src/Splitter/SplitterGroup.vue +20 -0
  120. package/src/Splitter/utils/units.ts +12 -0
  121. package/src/TagsInput/TagsInputInput.vue +10 -1
  122. package/src/Tooltip/TooltipContentImpl.vue +1 -1
  123. package/src/YearPicker/YearPickerGrid.vue +0 -5
  124. package/src/YearRangePicker/YearRangePickerGrid.vue +0 -5
  125. package/src/shared/useForwardProps.ts +13 -2
  126. package/src/shared/useGraceArea.ts +5 -3
  127. package/src/shared/useHideOthers.ts +7 -1
@@ -19,6 +19,7 @@ export {
19
19
  export {
20
20
  injectSelectItemContext,
21
21
  default as SelectItem,
22
+ type SelectItemEmits,
22
23
  type SelectItemProps,
23
24
  type SelectEvent as SelectItemSelectEvent,
24
25
  } from './SelectItem.vue'
@@ -121,6 +121,7 @@ const { forwardRef, currentElement: panelGroupElementRef } = useForwardExpose()
121
121
 
122
122
  const dragState = ref<DragState | null>(null)
123
123
  const groupSizeInPixels = ref<number | null>(null)
124
+ const groupSizeAtLastLayoutInit = ref<number | null>(null)
124
125
  const layout = ref<number[]>([])
125
126
  const panelIdToLastNotifiedSizeMapRef = ref<Record<string, number>>({})
126
127
  const panelSizeBeforeCollapseRef = ref<Map<string, number>>(new Map())
@@ -357,6 +358,11 @@ watch(() => eagerValuesRef.value.panelDataArrayChanged, () => {
357
358
  panelConstraints,
358
359
  })
359
360
 
361
+ // Track the group size used for this initialization.
362
+ // Used to detect when a nested px group was measured with an unreliable (too small)
363
+ // container size before the outer group finished layout.
364
+ groupSizeAtLastLayoutInit.value = getGroupSizeInPixels()
365
+
360
366
  if (!areEqual(prevLayout, nextLayout)) {
361
367
  setLayout(nextLayout)
362
368
 
@@ -383,6 +389,20 @@ watch(groupSizeInPixels, (nextSize, prevSize) => {
383
389
  if (!hasPixelSizedPanel(panelDataArray))
384
390
  return
385
391
 
392
+ // Detect if the layout was initialized with an unreliably small container.
393
+ // This happens with nested SplitterGroups using sizeUnit="px": the inner group's
394
+ // ResizeObserver fires before the outer group's flex layout completes, giving a
395
+ // near-zero container size (e.g. 3.45px). When the outer group finishes and the
396
+ // container grows to its real size (e.g. 923px), we must re-initialize rather
397
+ // than recalculate (which would "preserve" the garbage pixel sizes from 3.45px).
398
+ // We guard with initSize < 50 so that legitimately small-but-real containers
399
+ // (e.g. a sidebar at 60px) are not accidentally re-initialized on normal resizes.
400
+ const initSize = groupSizeAtLastLayoutInit.value
401
+ if (initSize != null && initSize > 0 && initSize < 50 && nextSize > initSize * 10) {
402
+ eagerValuesRef.value.panelDataArrayChanged = true
403
+ return
404
+ }
405
+
386
406
  const recalculatedLayout = recalculateLayoutForPixelPanels({
387
407
  layout: prevLayout,
388
408
  panelDataArray,
@@ -157,5 +157,17 @@ export function recalculateLayoutForPixelPanels({
157
157
  nextLayout[index] = prevSize * scaleFactor
158
158
  }
159
159
 
160
+ // Normalize to ensure percentages always sum to exactly 100.
161
+ // Floating-point arithmetic in the px→% conversions above can cause drift
162
+ // (e.g. 99.89% instead of 100%) that gets persisted to localStorage and
163
+ // triggers validation warnings on every subsequent page load.
164
+ const total = nextLayout.reduce((sum, size) => sum + size, 0)
165
+ if (total > 0 && Math.abs(total - 100) > 1e-9) {
166
+ const factor = 100 / total
167
+ for (let index = 0; index < nextLayout.length; index++) {
168
+ nextLayout[index] = (nextLayout[index] ?? 0) * factor
169
+ }
170
+ }
171
+
160
172
  return nextLayout
161
173
  }
@@ -24,13 +24,22 @@ const props = withDefaults(defineProps<TagsInputInputProps>(), {
24
24
  const context = injectTagsInputRootContext()
25
25
  const { forwardRef, currentElement } = useForwardExpose()
26
26
 
27
- function handleBlur(event: Event) {
27
+ function handleBlur(event: FocusEvent) {
28
28
  context.selectedElement.value = undefined
29
29
 
30
30
  if (!context.addOnBlur.value)
31
31
  return
32
32
 
33
33
  const target = event.target as HTMLInputElement
34
+
35
+ // If the blur is caused by clicking an option within the content,
36
+ // we don't trigger the `addOnBlur` action,
37
+ // because the clicked option should be added instead of the input's current value.
38
+ const relatedTarget = event.relatedTarget as HTMLElement | null
39
+ const controlledId = target.getAttribute('aria-controls')
40
+ if (controlledId && relatedTarget?.closest(`#${CSS.escape(controlledId)}`))
41
+ return
42
+
34
43
  if (!target.value)
35
44
  return
36
45
 
@@ -85,7 +85,7 @@ onMounted(() => {
85
85
  const target = event.target as HTMLElement
86
86
  if (target?.contains(rootContext.trigger.value!))
87
87
  rootContext.onClose()
88
- })
88
+ }, { capture: true })
89
89
  // Close this tooltip if another one opens
90
90
  useEventListener(window, TOOLTIP_OPEN, rootContext.onClose)
91
91
  })
@@ -17,11 +17,6 @@ const readonly = computed(() => rootContext.readonly.value ? true : undefined)
17
17
  </script>
18
18
 
19
19
  <template>
20
- <!--
21
- role="application" is intentional: it ensures screen readers like NVDA pass
22
- keyboard events (arrow keys) to the web app instead of intercepting them
23
- for virtual cursor navigation. This is the same pattern used by React Aria.
24
- -->
25
20
  <Primitive
26
21
  v-bind="props"
27
22
  tabindex="-1"
@@ -17,11 +17,6 @@ const readonly = computed(() => rootContext.readonly.value ? true : undefined)
17
17
  </script>
18
18
 
19
19
  <template>
20
- <!--
21
- role="application" is intentional: it ensures screen readers like NVDA pass
22
- keyboard events (arrow keys) to the web app instead of intercepting them
23
- for virtual cursor navigation. This is the same pattern used by React Aria.
24
- -->
25
20
  <Primitive
26
21
  v-bind="props"
27
22
  tabindex="-1"
@@ -7,6 +7,17 @@ interface PropOptions {
7
7
  default?: any
8
8
  }
9
9
 
10
+ /**
11
+ * Vue coerces optional boolean props (e.g. `foo?: boolean`) to non-optional (`foo: boolean`)
12
+ * in the `defineProps` return type. Since `useForwardProps` only returns props that were
13
+ * explicitly assigned, boolean-typed props should remain optional in the return type.
14
+ */
15
+ type WithOptionalBooleans<T> = {
16
+ [K in keyof T as [T[K]] extends [boolean] ? K : never]?: T[K]
17
+ } & {
18
+ [K in keyof T as [T[K]] extends [boolean] ? never : K]: T[K]
19
+ }
20
+
10
21
  /**
11
22
  * The `useForwardProps` function in TypeScript takes in a set of props and returns a computed value
12
23
  * that combines default props with assigned props from the current instance.
@@ -36,8 +47,8 @@ export function useForwardProps<T extends Record<string, any>>(props: MaybeRefOr
36
47
  // Only return value from the props parameter
37
48
  return Object.keys({ ...defaultProps, ...preservedProps }).reduce((prev, curr) => {
38
49
  if (refProps.value[curr] !== undefined)
39
- prev[curr as keyof T] = refProps.value[curr]
50
+ (prev as Record<string, any>)[curr] = refProps.value[curr]
40
51
  return prev
41
- }, {} as T)
52
+ }, {} as WithOptionalBooleans<T>)
42
53
  })
43
54
  }
@@ -21,7 +21,9 @@ export function useGraceArea(triggerElement: Ref<HTMLElement | undefined>, conta
21
21
  isPointerInTransit.value = false
22
22
  }
23
23
 
24
- function handleCreateGraceArea(event: PointerEvent, hoverTarget: HTMLElement) {
24
+ function handleCreateGraceArea(event: PointerEvent, hoverTarget: HTMLElement | undefined) {
25
+ if (!hoverTarget)
26
+ return
25
27
  const currentTarget = event.currentTarget as HTMLElement
26
28
  const exitPoint = { x: event.clientX, y: event.clientY }
27
29
  const exitSide = getExitSideFromRect(exitPoint, currentTarget.getBoundingClientRect())
@@ -34,8 +36,8 @@ export function useGraceArea(triggerElement: Ref<HTMLElement | undefined>, conta
34
36
 
35
37
  watchEffect((cleanupFn) => {
36
38
  if (triggerElement.value && containerElement.value) {
37
- const handleTriggerLeave = (event: PointerEvent) => handleCreateGraceArea(event, containerElement.value!)
38
- const handleContentLeave = (event: PointerEvent) => handleCreateGraceArea(event, triggerElement.value!)
39
+ const handleTriggerLeave = (event: PointerEvent) => handleCreateGraceArea(event, containerElement.value)
40
+ const handleContentLeave = (event: PointerEvent) => handleCreateGraceArea(event, triggerElement.value)
39
41
 
40
42
  triggerElement.value.addEventListener('pointerleave', handleTriggerLeave)
41
43
  containerElement.value.addEventListener('pointerleave', handleContentLeave)
@@ -17,7 +17,13 @@ export function useHideOthers(target: MaybeElementRef) {
17
17
  if (import.meta.env.MODE === 'test')
18
18
  return
19
19
  // Skip if inside a closed native popover
20
- if (el && !el.closest('[popover]:not(:popover-open)'))
20
+ // Use try/catch as `:popover-open` pseudo-class is not supported in all browsers (e.g. Safari 18)
21
+ let isInsideClosedPopover = false
22
+ try {
23
+ isInsideClosedPopover = !!el?.closest('[popover]:not(:popover-open)')
24
+ }
25
+ catch {}
26
+ if (el && !isInsideClosedPopover)
21
27
  undo = hideOthers(el)
22
28
  else if (undo)
23
29
  undo()