base-ui-vue 0.4.0 → 0.5.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 (187) hide show
  1. package/dist/arrow/TooltipArrow.cjs +609 -0
  2. package/dist/arrow/TooltipArrow.cjs.map +1 -0
  3. package/dist/arrow/TooltipArrow.js +478 -0
  4. package/dist/arrow/TooltipArrow.js.map +1 -0
  5. package/dist/button/Button.cjs +5 -317
  6. package/dist/button/Button.cjs.map +1 -1
  7. package/dist/button/Button.js +3 -249
  8. package/dist/button/Button.js.map +1 -1
  9. package/dist/button/ToolbarButton.cjs +13 -6
  10. package/dist/button/ToolbarButton.cjs.map +1 -1
  11. package/dist/button/ToolbarButton.js +3 -2
  12. package/dist/button/ToolbarButton.js.map +1 -1
  13. package/dist/checkbox/index.cjs +20 -9
  14. package/dist/checkbox/index.cjs.map +1 -1
  15. package/dist/checkbox/index.js +7 -2
  16. package/dist/checkbox/index.js.map +1 -1
  17. package/dist/checkbox-group/CheckboxGroup.cjs +14 -13
  18. package/dist/checkbox-group/CheckboxGroup.cjs.map +1 -1
  19. package/dist/checkbox-group/CheckboxGroup.js +2 -1
  20. package/dist/checkbox-group/CheckboxGroup.js.map +1 -1
  21. package/dist/components/FloatingPortal.cjs +66 -0
  22. package/dist/components/FloatingPortal.cjs.map +1 -0
  23. package/dist/components/FloatingPortal.js +55 -0
  24. package/dist/components/FloatingPortal.js.map +1 -0
  25. package/dist/components/FloatingRootStore.cjs +101 -0
  26. package/dist/components/FloatingRootStore.cjs.map +1 -0
  27. package/dist/components/FloatingRootStore.js +84 -0
  28. package/dist/components/FloatingRootStore.js.map +1 -0
  29. package/dist/components/FloatingTree.cjs +33 -0
  30. package/dist/components/FloatingTree.cjs.map +1 -0
  31. package/dist/components/FloatingTree.js +22 -0
  32. package/dist/components/FloatingTree.js.map +1 -0
  33. package/dist/composite/composite.cjs +6 -0
  34. package/dist/composite/composite.js +1 -1
  35. package/dist/content/ScrollAreaContent.cjs +3 -3
  36. package/dist/content/ScrollAreaContent.cjs.map +1 -1
  37. package/dist/content/ScrollAreaContent.js +1 -1
  38. package/dist/control/FieldControl.cjs +3 -3
  39. package/dist/control/FieldControl.cjs.map +1 -1
  40. package/dist/control/FieldControl.js +1 -1
  41. package/dist/control/SliderControl.cjs +3 -3
  42. package/dist/control/SliderControl.cjs.map +1 -1
  43. package/dist/control/SliderControl.js +1 -1
  44. package/dist/corner/ScrollAreaCorner.cjs +3 -3
  45. package/dist/corner/ScrollAreaCorner.cjs.map +1 -1
  46. package/dist/corner/ScrollAreaCorner.js +1 -1
  47. package/dist/decrement/NumberFieldDecrement.cjs +10 -3
  48. package/dist/decrement/NumberFieldDecrement.cjs.map +1 -1
  49. package/dist/decrement/NumberFieldDecrement.js +3 -2
  50. package/dist/decrement/NumberFieldDecrement.js.map +1 -1
  51. package/dist/description/FieldDescription.cjs +2 -2
  52. package/dist/description/FieldDescription.cjs.map +1 -1
  53. package/dist/description/FieldDescription.js +1 -1
  54. package/dist/error/FieldError.cjs +2 -2
  55. package/dist/error/FieldError.cjs.map +1 -1
  56. package/dist/error/FieldError.js +1 -1
  57. package/dist/fallback/AvatarFallback.cjs +2 -2
  58. package/dist/fallback/AvatarFallback.cjs.map +1 -1
  59. package/dist/fallback/AvatarFallback.js +1 -1
  60. package/dist/floating-ui-vue/index.js +638 -0
  61. package/dist/floating-ui-vue/index.js.map +1 -0
  62. package/dist/form/Form.cjs +3 -3
  63. package/dist/form/Form.cjs.map +1 -1
  64. package/dist/form/Form.js +1 -1
  65. package/dist/group/NumberFieldGroup.cjs +3 -3
  66. package/dist/group/NumberFieldGroup.cjs.map +1 -1
  67. package/dist/group/NumberFieldGroup.js +1 -1
  68. package/dist/group/ToolbarGroup.cjs +2 -2
  69. package/dist/group/ToolbarGroup.cjs.map +1 -1
  70. package/dist/group/ToolbarGroup.js +1 -1
  71. package/dist/header/AccordionHeader.cjs +2 -2
  72. package/dist/header/AccordionHeader.cjs.map +1 -1
  73. package/dist/header/AccordionHeader.js +1 -1
  74. package/dist/hooks/useDismiss.cjs +502 -0
  75. package/dist/hooks/useDismiss.cjs.map +1 -0
  76. package/dist/hooks/useHoverFloatingInteraction.cjs +233 -0
  77. package/dist/hooks/useHoverFloatingInteraction.cjs.map +1 -0
  78. package/dist/image/AvatarImage.cjs +4 -4
  79. package/dist/image/AvatarImage.cjs.map +1 -1
  80. package/dist/image/AvatarImage.js +1 -1
  81. package/dist/increment/NumberFieldIncrement.cjs +3 -2
  82. package/dist/increment/NumberFieldIncrement.cjs.map +1 -1
  83. package/dist/increment/NumberFieldIncrement.js +2 -1
  84. package/dist/increment/NumberFieldIncrement.js.map +1 -1
  85. package/dist/index.cjs +60 -7
  86. package/dist/index.d.cts +3838 -1726
  87. package/dist/index.d.cts.map +1 -1
  88. package/dist/index.d.ts +3838 -1726
  89. package/dist/index.d.ts.map +1 -1
  90. package/dist/index.js +4 -3
  91. package/dist/index2.cjs +7475 -3089
  92. package/dist/index2.cjs.map +1 -1
  93. package/dist/index2.js +7215 -3106
  94. package/dist/index2.js.map +1 -1
  95. package/dist/rolldown-runtime.js +36 -0
  96. package/package.json +1 -1
  97. package/src/floating-ui-vue/components/FloatingPortal.ts +171 -0
  98. package/src/floating-ui-vue/components/FloatingPortal.vue +259 -0
  99. package/src/floating-ui-vue/components/FloatingRootStore.ts +83 -0
  100. package/src/floating-ui-vue/components/FloatingTree.ts +64 -0
  101. package/src/floating-ui-vue/components/FloatingTreeStore.ts +21 -0
  102. package/src/floating-ui-vue/hooks/useDismiss.ts +689 -0
  103. package/src/floating-ui-vue/hooks/useHoverFloatingInteraction.ts +244 -0
  104. package/src/floating-ui-vue/hooks/useHoverInteractionSharedState.ts +125 -0
  105. package/src/floating-ui-vue/hooks/useHoverShared.ts +53 -0
  106. package/src/floating-ui-vue/index.ts +48 -0
  107. package/src/floating-ui-vue/middleware/arrow.ts +114 -0
  108. package/src/floating-ui-vue/types.ts +117 -0
  109. package/src/floating-ui-vue/utils/composite.ts +20 -0
  110. package/src/floating-ui-vue/utils/constants.ts +2 -0
  111. package/src/floating-ui-vue/utils/createAttribute.ts +3 -0
  112. package/src/floating-ui-vue/utils/createEventEmitter.ts +20 -0
  113. package/src/floating-ui-vue/utils/element.ts +59 -0
  114. package/src/floating-ui-vue/utils/event.ts +15 -0
  115. package/src/floating-ui-vue/utils/nodes.ts +14 -0
  116. package/src/floating-ui-vue/utils/tabbable.ts +309 -0
  117. package/src/index.ts +4 -0
  118. package/src/radio/index.ts +28 -0
  119. package/src/radio/indicator/RadioIndicator.vue +90 -0
  120. package/src/radio/indicator/RadioIndicatorDataAttributes.ts +54 -0
  121. package/src/radio/root/RadioRoot.vue +544 -0
  122. package/src/radio/root/RadioRootContext.ts +18 -0
  123. package/src/radio/root/RadioRootDataAttributes.ts +46 -0
  124. package/src/radio/utils/stateAttributesMapping.ts +29 -0
  125. package/src/radio-group/RadioGroup.vue +381 -0
  126. package/src/radio-group/RadioGroupContext.ts +42 -0
  127. package/src/radio-group/RadioGroupDataAttributes.ts +6 -0
  128. package/src/radio-group/index.ts +10 -0
  129. package/src/tabs/index.ts +38 -0
  130. package/src/tabs/indicator/TabsIndicator.vue +201 -0
  131. package/src/tabs/indicator/TabsIndicatorCssVars.ts +26 -0
  132. package/src/tabs/indicator/TabsIndicatorDataAttributes.ts +12 -0
  133. package/src/tabs/indicator/prehydrationScript.min.ts +5 -0
  134. package/src/tabs/indicator/prehydrationScript.template.js +87 -0
  135. package/src/tabs/list/TabsList.vue +201 -0
  136. package/src/tabs/list/TabsListContext.ts +29 -0
  137. package/src/tabs/list/TabsListDataAttributes.ts +12 -0
  138. package/src/tabs/panel/TabsPanel.vue +167 -0
  139. package/src/tabs/panel/TabsPanelDataAttributes.ts +28 -0
  140. package/src/tabs/root/TabsRoot.vue +468 -0
  141. package/src/tabs/root/TabsRootContext.ts +56 -0
  142. package/src/tabs/root/TabsRootDataAttributes.ts +12 -0
  143. package/src/tabs/root/stateAttributesMapping.ts +9 -0
  144. package/src/tabs/tab/TabsTab.vue +274 -0
  145. package/src/tabs/tab/TabsTabDataAttributes.ts +20 -0
  146. package/src/tabs/utils/areTabValuesEqual.ts +6 -0
  147. package/src/tooltip/arrow/TooltipArrow.vue +116 -0
  148. package/src/tooltip/arrow/TooltipArrowDataAttributes.ts +31 -0
  149. package/src/tooltip/index.ts +54 -0
  150. package/src/tooltip/popup/TooltipPopup.vue +142 -0
  151. package/src/tooltip/popup/TooltipPopupDataAttributes.ts +35 -0
  152. package/src/tooltip/portal/TooltipPortal.vue +83 -0
  153. package/src/tooltip/portal/TooltipPortalContext.ts +19 -0
  154. package/src/tooltip/positioner/TooltipPositioner.vue +221 -0
  155. package/src/tooltip/positioner/TooltipPositionerContext.ts +23 -0
  156. package/src/tooltip/positioner/TooltipPositionerCssVars.ts +27 -0
  157. package/src/tooltip/positioner/TooltipPositionerDataAttributes.ts +26 -0
  158. package/src/tooltip/provider/TooltipProvider.vue +78 -0
  159. package/src/tooltip/provider/TooltipProviderContext.ts +19 -0
  160. package/src/tooltip/root/TooltipRoot.vue +401 -0
  161. package/src/tooltip/root/TooltipRootContext.ts +71 -0
  162. package/src/tooltip/store/TooltipHandle.ts +215 -0
  163. package/src/tooltip/trigger/TooltipTrigger.vue +343 -0
  164. package/src/tooltip/trigger/TooltipTriggerDataAttributes.ts +12 -0
  165. package/src/tooltip/utils/constants.ts +2 -0
  166. package/src/tooltip/viewport/TooltipViewport.vue +149 -0
  167. package/src/tooltip/viewport/TooltipViewportCssVars.ts +14 -0
  168. package/src/tooltip/viewport/TooltipViewportDataAttributes.ts +26 -0
  169. package/src/utils/FloatingPortalLite.vue +66 -0
  170. package/src/utils/FocusGuard.vue +36 -0
  171. package/src/utils/adaptiveOriginMiddleware.ts +79 -0
  172. package/src/utils/addEventListener.ts +16 -0
  173. package/src/utils/constants.ts +11 -0
  174. package/src/utils/createBaseUIEventDetails.ts +2 -0
  175. package/src/utils/getCssDimensions.ts +19 -0
  176. package/src/utils/getDisabledMountTransitionStyles.ts +9 -0
  177. package/src/utils/hideMiddleware.ts +19 -0
  178. package/src/utils/mergeCleanups.ts +7 -0
  179. package/src/utils/platform.ts +18 -0
  180. package/src/utils/popupStateMapping.ts +103 -0
  181. package/src/utils/reasons.ts +4 -0
  182. package/src/utils/serializeValue.ts +17 -0
  183. package/src/utils/useAnchorPositioning.ts +644 -0
  184. package/src/utils/usePopupAutoResize.ts +254 -0
  185. package/src/utils/usePopupViewport.ts +398 -0
  186. package/src/utils/usePositioner.ts +61 -0
  187. package/src/utils/useRenderElement.ts +3 -0
@@ -0,0 +1,244 @@
1
+ import type { MaybeRefOrGetter } from 'vue'
2
+ import type { Delay, FloatingContext, FloatingRootContext } from '../types'
3
+ import { isElement } from '@floating-ui/utils/dom'
4
+ import { onScopeDispose, toValue, watchEffect } from 'vue'
5
+ import { addEventListener } from '../../utils/addEventListener'
6
+ import { createChangeEventDetails } from '../../utils/createBaseUIEventDetails'
7
+ import { mergeCleanups } from '../../utils/mergeCleanups'
8
+ import { ownerDocument } from '../../utils/owner'
9
+ import { REASONS } from '../../utils/reasons'
10
+ import { useTimeout } from '../../utils/useTimeout'
11
+ import { useFloatingParentNodeId, useFloatingTree } from '../components/FloatingTree'
12
+ import { contains, getTarget } from '../utils/element'
13
+ import { getNodeChildren } from '../utils/nodes'
14
+ import {
15
+ applySafePolygonPointerEventsMutation,
16
+ clearSafePolygonPointerEventsMutation,
17
+ isInteractiveElement,
18
+ useHoverInteractionSharedState,
19
+ } from './useHoverInteractionSharedState'
20
+ import {
21
+ getDelay,
22
+ isClickLikeOpenEvent as isClickLikeOpenEventShared,
23
+ isHoverOpenEvent,
24
+ isInsideEnabledTrigger,
25
+ } from './useHoverShared'
26
+
27
+ export interface UseHoverFloatingInteractionProps {
28
+ /**
29
+ * Whether the Hook is enabled, including all internal Effects and event
30
+ * handlers.
31
+ * @default true
32
+ */
33
+ enabled?: MaybeRefOrGetter<boolean | undefined>
34
+ /**
35
+ * Waits for the specified time when the event listener runs before changing
36
+ * the `open` state.
37
+ * @default 0
38
+ */
39
+ closeDelay?: MaybeRefOrGetter<Delay | (() => Delay) | undefined>
40
+ /**
41
+ * Tree node id override for floating elements that participate in the tree
42
+ * without a `FloatingContext`, such as inline nested navigation menus.
43
+ */
44
+ nodeId?: MaybeRefOrGetter<string | undefined>
45
+ }
46
+
47
+ /**
48
+ * Provides hover interactions that should be attached to the floating element.
49
+ */
50
+ export function useHoverFloatingInteraction(
51
+ context: FloatingRootContext | FloatingContext,
52
+ parameters: UseHoverFloatingInteractionProps = {},
53
+ ): void {
54
+ const store = 'rootStore' in context ? context.rootStore : context
55
+
56
+ const open = store.useState('open')
57
+ const floatingElement = store.useState('floatingElement')
58
+ const domReferenceElement = store.useState('domReferenceElement')
59
+ const { dataRef } = store.context
60
+
61
+ const tree = useFloatingTree()
62
+ const parentId = useFloatingParentNodeId()
63
+ const instance = useHoverInteractionSharedState(store)
64
+
65
+ const childClosedTimeout = useTimeout()
66
+
67
+ function enabled() {
68
+ return toValue(parameters.enabled ?? true) !== false
69
+ }
70
+
71
+ function isClickLikeOpenEvent() {
72
+ return isClickLikeOpenEventShared(dataRef.value.openEvent?.type, instance.interactedInside)
73
+ }
74
+
75
+ function isHoverOpen() {
76
+ return isHoverOpenEvent(dataRef.value.openEvent?.type)
77
+ }
78
+
79
+ function clearPointerEvents() {
80
+ clearSafePolygonPointerEventsMutation(instance)
81
+ }
82
+
83
+ watchEffect(() => {
84
+ if (!open.value) {
85
+ instance.pointerType = undefined
86
+ instance.restTimeoutPending = false
87
+ instance.interactedInside = false
88
+ clearPointerEvents()
89
+ }
90
+ })
91
+
92
+ onScopeDispose(clearPointerEvents)
93
+
94
+ watchEffect((onCleanup) => {
95
+ if (!enabled()) {
96
+ return
97
+ }
98
+
99
+ if (
100
+ open.value
101
+ && instance.handleCloseOptions?.blockPointerEvents
102
+ && isHoverOpen()
103
+ && isElement(domReferenceElement.value)
104
+ && floatingElement.value
105
+ ) {
106
+ const ref = domReferenceElement.value as HTMLElement | SVGSVGElement
107
+ const floatingEl = floatingElement.value
108
+ const doc = ownerDocument(floatingEl)
109
+
110
+ const parentNode = tree?.nodesRef.value.find(node => node.id === parentId)
111
+ const parentFloating = parentNode?.context?.rootStore.select('floatingElement') ?? null
112
+
113
+ if (parentFloating) {
114
+ parentFloating.style.pointerEvents = ''
115
+ }
116
+
117
+ const cachedScopeElement
118
+ = instance.pointerEventsScopeElement !== floatingEl
119
+ ? instance.pointerEventsScopeElement
120
+ : null
121
+ const parentScopeElement = parentFloating !== floatingEl ? parentFloating : null
122
+ const scopeElement
123
+ = instance.handleCloseOptions?.getScope?.()
124
+ ?? cachedScopeElement
125
+ ?? parentScopeElement
126
+ ?? (ref.closest('[data-rootownerid]') as HTMLElement | SVGSVGElement | null)
127
+ ?? doc?.body
128
+
129
+ if (scopeElement) {
130
+ applySafePolygonPointerEventsMutation(instance, {
131
+ scopeElement,
132
+ referenceElement: ref,
133
+ floatingElement: floatingEl,
134
+ })
135
+
136
+ onCleanup(clearPointerEvents)
137
+ }
138
+ }
139
+ })
140
+
141
+ watchEffect((onCleanup) => {
142
+ if (!enabled()) {
143
+ return
144
+ }
145
+
146
+ function hasParentChildren() {
147
+ return Boolean(tree && parentId && getNodeChildren(tree.nodesRef.value, parentId).length > 0)
148
+ }
149
+
150
+ function closeWithDelay(event: MouseEvent) {
151
+ const closeDelay = getDelay(toValue(parameters.closeDelay ?? 0), 'close', instance.pointerType)
152
+ const close = () => {
153
+ store.setOpen(false, createChangeEventDetails(REASONS.triggerHover, event))
154
+ tree?.events.emit('floating.closed', event)
155
+ }
156
+
157
+ if (closeDelay) {
158
+ instance.openChangeTimeout.start(closeDelay, close)
159
+ }
160
+ else {
161
+ instance.openChangeTimeout.clear()
162
+ close()
163
+ }
164
+ }
165
+
166
+ function handleInteractInside(event: PointerEvent) {
167
+ const target = getTarget(event) as Element | null
168
+ if (!isInteractiveElement(target)) {
169
+ instance.interactedInside = false
170
+ return
171
+ }
172
+
173
+ instance.interactedInside = target?.closest('[aria-haspopup]') != null
174
+ }
175
+
176
+ function onFloatingMouseEnter() {
177
+ instance.openChangeTimeout.clear()
178
+ store.context.clearCloseTimer?.()
179
+ childClosedTimeout.clear()
180
+ tree?.events.off('floating.closed', onNodeClosed)
181
+ clearPointerEvents()
182
+ }
183
+
184
+ function onFloatingMouseLeave(event: MouseEvent) {
185
+ if (hasParentChildren() && tree) {
186
+ tree.events.off('floating.closed', onNodeClosed)
187
+ tree.events.on('floating.closed', onNodeClosed)
188
+ return
189
+ }
190
+
191
+ if (isInsideEnabledTrigger(event.relatedTarget, store.context.triggerElements)) {
192
+ return
193
+ }
194
+
195
+ const currentNodeId = dataRef.value.floatingContext?.nodeId ?? toValue(parameters.nodeId)
196
+ const relatedTarget = event.relatedTarget
197
+ const isMovingIntoDescendantFloating
198
+ = tree
199
+ && currentNodeId
200
+ && isElement(relatedTarget)
201
+ && getNodeChildren(tree.nodesRef.value, currentNodeId, false).some(node =>
202
+ contains(node.context?.rootStore.select('floatingElement'), relatedTarget),
203
+ )
204
+
205
+ if (isMovingIntoDescendantFloating) {
206
+ return
207
+ }
208
+
209
+ if (instance.handler) {
210
+ instance.handler(event)
211
+ return
212
+ }
213
+
214
+ clearPointerEvents()
215
+ if (isHoverOpen() && !isClickLikeOpenEvent()) {
216
+ closeWithDelay(event)
217
+ }
218
+ }
219
+
220
+ function onNodeClosed(event: MouseEvent) {
221
+ if (!tree || !parentId || hasParentChildren()) {
222
+ return
223
+ }
224
+
225
+ childClosedTimeout.start(0, () => {
226
+ tree.events.off('floating.closed', onNodeClosed)
227
+ store.setOpen(false, createChangeEventDetails(REASONS.triggerHover, event))
228
+ tree.events.emit('floating.closed', event)
229
+ })
230
+ }
231
+
232
+ const floating = floatingElement.value
233
+ const cleanup = mergeCleanups(
234
+ addEventListener(floating, 'mouseenter', onFloatingMouseEnter),
235
+ addEventListener(floating, 'mouseleave', onFloatingMouseLeave),
236
+ addEventListener(floating, 'pointerdown', handleInteractInside, true),
237
+ () => {
238
+ tree?.events.off('floating.closed', onNodeClosed)
239
+ },
240
+ )
241
+
242
+ onCleanup(cleanup)
243
+ })
244
+ }
@@ -0,0 +1,125 @@
1
+ import type { FloatingRootContext, HandleCloseOptions } from '../types'
2
+ import { onScopeDispose } from 'vue'
3
+ import { Timeout } from '../../utils/useTimeout'
4
+ import { isInteractiveElement } from '../utils/element'
5
+
6
+ export { isInteractiveElement }
7
+
8
+ export class HoverInteraction {
9
+ pointerType: string | undefined
10
+ interactedInside: boolean
11
+ handler: ((event: MouseEvent) => void) | undefined
12
+ blockMouseMove: boolean
13
+ performedPointerEventsMutation: boolean
14
+ pointerEventsScopeElement: HTMLElement | SVGSVGElement | null
15
+ pointerEventsReferenceElement: HTMLElement | SVGSVGElement | null
16
+ pointerEventsFloatingElement: HTMLElement | null
17
+ restTimeoutPending: boolean
18
+ openChangeTimeout: Timeout
19
+ restTimeout: Timeout
20
+ handleCloseOptions: HandleCloseOptions | undefined
21
+
22
+ constructor() {
23
+ this.pointerType = undefined
24
+ this.interactedInside = false
25
+ this.handler = undefined
26
+ this.blockMouseMove = true
27
+ this.performedPointerEventsMutation = false
28
+ this.pointerEventsScopeElement = null
29
+ this.pointerEventsReferenceElement = null
30
+ this.pointerEventsFloatingElement = null
31
+ this.restTimeoutPending = false
32
+ this.openChangeTimeout = new Timeout()
33
+ this.restTimeout = new Timeout()
34
+ this.handleCloseOptions = undefined
35
+ }
36
+
37
+ static create(): HoverInteraction {
38
+ return new HoverInteraction()
39
+ }
40
+
41
+ dispose = () => {
42
+ this.openChangeTimeout.clear()
43
+ this.restTimeout.clear()
44
+ }
45
+ }
46
+
47
+ type PointerEventsMutationState = Pick<
48
+ HoverInteraction,
49
+ | 'performedPointerEventsMutation'
50
+ | 'pointerEventsScopeElement'
51
+ | 'pointerEventsReferenceElement'
52
+ | 'pointerEventsFloatingElement'
53
+ >
54
+
55
+ const pointerEventsMutationOwnerByScopeElement = new WeakMap<
56
+ HTMLElement | SVGSVGElement,
57
+ PointerEventsMutationState
58
+ >()
59
+
60
+ export function clearSafePolygonPointerEventsMutation(instance: PointerEventsMutationState) {
61
+ if (!instance.performedPointerEventsMutation) {
62
+ return
63
+ }
64
+
65
+ const scopeElement = instance.pointerEventsScopeElement
66
+
67
+ if (scopeElement && pointerEventsMutationOwnerByScopeElement.get(scopeElement) === instance) {
68
+ instance.pointerEventsScopeElement?.style.removeProperty('pointer-events')
69
+ instance.pointerEventsReferenceElement?.style.removeProperty('pointer-events')
70
+ instance.pointerEventsFloatingElement?.style.removeProperty('pointer-events')
71
+ pointerEventsMutationOwnerByScopeElement.delete(scopeElement)
72
+ }
73
+
74
+ instance.performedPointerEventsMutation = false
75
+ instance.pointerEventsScopeElement = null
76
+ instance.pointerEventsReferenceElement = null
77
+ instance.pointerEventsFloatingElement = null
78
+ }
79
+
80
+ export function applySafePolygonPointerEventsMutation(
81
+ instance: PointerEventsMutationState,
82
+ options: {
83
+ scopeElement: HTMLElement | SVGSVGElement
84
+ referenceElement: HTMLElement | SVGSVGElement
85
+ floatingElement: HTMLElement
86
+ },
87
+ ) {
88
+ const { scopeElement, referenceElement, floatingElement } = options
89
+
90
+ const existingOwner = pointerEventsMutationOwnerByScopeElement.get(scopeElement)
91
+ if (existingOwner && existingOwner !== instance) {
92
+ clearSafePolygonPointerEventsMutation(existingOwner)
93
+ }
94
+
95
+ clearSafePolygonPointerEventsMutation(instance)
96
+ instance.performedPointerEventsMutation = true
97
+ instance.pointerEventsScopeElement = scopeElement
98
+ instance.pointerEventsReferenceElement = referenceElement
99
+ instance.pointerEventsFloatingElement = floatingElement
100
+ pointerEventsMutationOwnerByScopeElement.set(scopeElement, instance)
101
+
102
+ scopeElement.style.pointerEvents = 'none'
103
+ referenceElement.style.pointerEvents = 'auto'
104
+ floatingElement.style.pointerEvents = 'auto'
105
+ }
106
+
107
+ interface HoverContextData {
108
+ hoverInteractionState?: HoverInteraction
109
+ }
110
+
111
+ export function getHoverInteractionSharedState(store: FloatingRootContext): HoverInteraction {
112
+ const data = store.context.dataRef.value as HoverContextData
113
+
114
+ if (!data.hoverInteractionState) {
115
+ data.hoverInteractionState = HoverInteraction.create()
116
+ }
117
+
118
+ return data.hoverInteractionState
119
+ }
120
+
121
+ export function useHoverInteractionSharedState(store: FloatingRootContext): HoverInteraction {
122
+ const instance = getHoverInteractionSharedState(store)
123
+ onScopeDispose(instance.dispose)
124
+ return instance
125
+ }
@@ -0,0 +1,53 @@
1
+ import type { Delay } from '../types'
2
+ import { isMouseLikePointerType } from '../utils/event'
3
+
4
+ export type {
5
+ HandleClose,
6
+ HandleCloseContext,
7
+ HandleCloseContextBase,
8
+ HandleCloseOptions,
9
+ } from '../types'
10
+ export { isTargetInsideEnabledTrigger as isInsideEnabledTrigger } from '../utils/element'
11
+
12
+ function resolveValue<T>(
13
+ value: T | (() => T) | undefined,
14
+ pointerType?: PointerEvent['pointerType'],
15
+ ): T | 0 | undefined {
16
+ if (pointerType != null && !isMouseLikePointerType(pointerType)) {
17
+ return 0
18
+ }
19
+
20
+ if (typeof value === 'function') {
21
+ return (value as () => T)()
22
+ }
23
+
24
+ return value
25
+ }
26
+
27
+ export function getDelay(
28
+ value: Delay | (() => Delay) | undefined,
29
+ prop: 'open' | 'close',
30
+ pointerType?: PointerEvent['pointerType'],
31
+ ) {
32
+ const result = resolveValue(value, pointerType)
33
+ if (typeof result === 'number') {
34
+ return result
35
+ }
36
+
37
+ return result?.[prop]
38
+ }
39
+
40
+ export function getRestMs(value: number | (() => number)) {
41
+ if (typeof value === 'function') {
42
+ return value()
43
+ }
44
+ return value
45
+ }
46
+
47
+ export function isClickLikeOpenEvent(openEventType: string | undefined, interactedInside: boolean) {
48
+ return interactedInside || openEventType === 'click' || openEventType === 'mousedown'
49
+ }
50
+
51
+ export function isHoverOpenEvent(openEventType: string | undefined) {
52
+ return openEventType?.includes('mouse') && openEventType !== 'mousedown'
53
+ }
@@ -0,0 +1,48 @@
1
+ export { useFloatingPortalNode } from './components/FloatingPortal'
2
+ export type {
3
+ FloatingPortal,
4
+ FloatingPortalContainer,
5
+ FloatingPortalContext,
6
+ FloatingPortalFocusManagerState,
7
+ FloatingPortalProps,
8
+ FloatingPortalState,
9
+ FloatingPortalTarget,
10
+ UseFloatingPortalNodeProps,
11
+ UseFloatingPortalNodeResult,
12
+ } from './components/FloatingPortal'
13
+ export {
14
+ floatingPortalContextKey,
15
+ usePortalContext,
16
+ } from './components/FloatingPortal'
17
+ export { createFloatingRootContext } from './components/FloatingRootStore'
18
+ export {
19
+ provideFloatingNode,
20
+ provideFloatingTree,
21
+ useFloatingNodeId,
22
+ useFloatingParentNodeId,
23
+ useFloatingTree,
24
+ } from './components/FloatingTree'
25
+ export { FloatingTreeStore } from './components/FloatingTreeStore'
26
+ export { useDismiss } from './hooks/useDismiss'
27
+ export type { UseDismissProps } from './hooks/useDismiss'
28
+ export { useHoverFloatingInteraction } from './hooks/useHoverFloatingInteraction'
29
+ export type { UseHoverFloatingInteractionProps } from './hooks/useHoverFloatingInteraction'
30
+ export type * from './types'
31
+ export {
32
+ arrow,
33
+ autoPlacement,
34
+ autoUpdate,
35
+ computePosition,
36
+ detectOverflow,
37
+ flip,
38
+ getOverflowAncestors,
39
+ hide,
40
+ inline,
41
+ limitShift,
42
+ offset,
43
+ platform,
44
+ shift,
45
+ size,
46
+ useFloating,
47
+ } from '@floating-ui/vue'
48
+ export type * from '@floating-ui/vue'
@@ -0,0 +1,114 @@
1
+ import type { Middleware, MiddlewareState, Padding } from '@floating-ui/vue'
2
+ import {
3
+ clamp,
4
+ evaluate,
5
+ getAlignment,
6
+ getAlignmentAxis,
7
+ getAxisLength,
8
+ getPaddingObject,
9
+ } from '@floating-ui/utils'
10
+
11
+ type Derivable<T> = T | ((state: MiddlewareState) => T)
12
+
13
+ export interface ArrowOptions {
14
+ /**
15
+ * The arrow element to be positioned.
16
+ * @default undefined
17
+ */
18
+ element: Element | null | undefined
19
+ /**
20
+ * The padding between the arrow element and the floating element edges.
21
+ * Useful when the floating element has rounded corners.
22
+ * @default 0
23
+ */
24
+ padding?: Padding
25
+ /**
26
+ * Which element to use as the offset parent.
27
+ * @default 'real'
28
+ */
29
+ offsetParent: 'real' | 'floating'
30
+ }
31
+
32
+ /**
33
+ * Fork of the original `arrow` middleware from Floating UI that allows
34
+ * configuring the offset parent.
35
+ */
36
+ export function baseArrow(options: ArrowOptions | Derivable<ArrowOptions>): Middleware {
37
+ return {
38
+ name: 'arrow',
39
+ options,
40
+ async fn(state) {
41
+ const { x, y, placement, rects, platform, elements, middlewareData } = state
42
+ const { element, padding = 0, offsetParent = 'real' } = evaluate(options, state) || {}
43
+
44
+ if (element == null) {
45
+ return {}
46
+ }
47
+
48
+ const paddingObject = getPaddingObject(padding)
49
+ const coords = { x, y }
50
+ const axis = getAlignmentAxis(placement)
51
+ const length = getAxisLength(axis)
52
+ const arrowDimensions = await platform.getDimensions(element)
53
+ const isYAxis = axis === 'y'
54
+ const minProp = isYAxis ? 'top' : 'left'
55
+ const maxProp = isYAxis ? 'bottom' : 'right'
56
+ const clientProp = isYAxis ? 'clientHeight' : 'clientWidth'
57
+
58
+ const endDiff
59
+ = rects.reference[length] + rects.reference[axis] - coords[axis] - rects.floating[length]
60
+ const startDiff = coords[axis] - rects.reference[axis]
61
+
62
+ const arrowOffsetParent = offsetParent === 'real'
63
+ ? await platform.getOffsetParent?.(element)
64
+ : elements.floating
65
+ let clientSize = 0
66
+
67
+ if (arrowOffsetParent && await platform.isElement?.(arrowOffsetParent)) {
68
+ clientSize = arrowOffsetParent[clientProp]
69
+ }
70
+
71
+ if (!clientSize) {
72
+ clientSize = elements.floating[clientProp] || rects.floating[length]
73
+ }
74
+
75
+ const centerToReference = endDiff / 2 - startDiff / 2
76
+ const largestPossiblePadding = clientSize / 2 - arrowDimensions[length] / 2 - 1
77
+ const minPadding = Math.min(paddingObject[minProp], largestPossiblePadding)
78
+ const maxPadding = Math.min(paddingObject[maxProp], largestPossiblePadding)
79
+
80
+ const min = minPadding
81
+ const max = clientSize - arrowDimensions[length] - maxPadding
82
+ const center = clientSize / 2 - arrowDimensions[length] / 2 + centerToReference
83
+ const offset = clamp(min, center, max)
84
+
85
+ const shouldAddOffset
86
+ = !middlewareData.arrow
87
+ && getAlignment(placement) != null
88
+ && center !== offset
89
+ && rects.reference[length] / 2
90
+ - (center < min ? minPadding : maxPadding)
91
+ - arrowDimensions[length] / 2
92
+ < 0
93
+ const alignmentOffset = shouldAddOffset ? (center < min ? center - min : center - max) : 0
94
+
95
+ return {
96
+ [axis]: coords[axis] + alignmentOffset,
97
+ data: {
98
+ [axis]: offset,
99
+ centerOffset: center - offset - alignmentOffset,
100
+ ...(shouldAddOffset && { alignmentOffset }),
101
+ },
102
+ reset: shouldAddOffset,
103
+ }
104
+ },
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Provides data to position an inner element of the floating element so that it
110
+ * appears centered to the reference element.
111
+ */
112
+ export function arrow(options: ArrowOptions | Derivable<ArrowOptions>): Middleware {
113
+ return baseArrow(options)
114
+ }
@@ -1 +1,118 @@
1
+ import type {
2
+ Placement,
3
+ VirtualElement,
4
+ } from '@floating-ui/vue'
5
+ import type { ComputedRef, Ref } from 'vue'
6
+ import type { BaseUIChangeEventDetails } from '../utils/createBaseUIEventDetails'
7
+ import type { TransitionStatus } from '../utils/useTransitionStatus'
8
+ import type { FloatingTreeStore } from './components/FloatingTreeStore'
9
+
1
10
  export type { Coords, Dimensions } from '@floating-ui/dom'
11
+
12
+ export type ReferenceType = Element | VirtualElement
13
+ export type Delay = number | Partial<{ open: number, close: number }>
14
+
15
+ export interface FloatingEvents {
16
+ emit: <T extends string>(event: T, data?: any) => void
17
+ on: (event: string, handler: (data: any) => void) => void
18
+ off: (event: string, handler: (data: any) => void) => void
19
+ }
20
+
21
+ export interface ContextData {
22
+ openEvent?: Event
23
+ floatingContext?: FloatingContext
24
+ insideVueTree?: boolean
25
+ __escapeKeyBubbles?: boolean
26
+ __outsidePressBubbles?: boolean
27
+ [key: string]: any
28
+ }
29
+
30
+ export interface FloatingUIOpenChangeDetails {
31
+ open: boolean
32
+ reason: string
33
+ nativeEvent: Event
34
+ nested: boolean
35
+ triggerElement: Element | undefined
36
+ }
37
+
38
+ export interface FloatingTriggerMap {
39
+ hasElement: (element: Element) => boolean
40
+ hasMatchingElement: (predicate: (element: Element) => boolean) => boolean
41
+ getById: (id: string) => Element | undefined
42
+ entries: () => IterableIterator<[string, HTMLElement]>
43
+ elements: () => IterableIterator<Element>
44
+ readonly size: number
45
+ }
46
+
47
+ export interface FloatingRootState {
48
+ open: boolean
49
+ transitionStatus: TransitionStatus
50
+ domReferenceElement: Element | null
51
+ referenceElement: ReferenceType | null
52
+ floatingElement: HTMLElement | null
53
+ floatingId: string | undefined
54
+ }
55
+
56
+ export interface FloatingRootStoreContext {
57
+ dataRef: Ref<ContextData>
58
+ events: FloatingEvents
59
+ nested: boolean
60
+ triggerElements: FloatingTriggerMap
61
+ clearCloseTimer?: () => void
62
+ }
63
+
64
+ export interface FloatingRootContext {
65
+ context: FloatingRootStoreContext
66
+ useState: <K extends keyof FloatingRootState>(key: K) => ComputedRef<FloatingRootState[K]>
67
+ select: <K extends keyof FloatingRootState>(key: K) => FloatingRootState[K]
68
+ setOpen: (open: boolean, eventDetails: BaseUIChangeEventDetails<string, any>) => void
69
+ dispatchOpenChange: (open: boolean, eventDetails: BaseUIChangeEventDetails<string, any>) => void
70
+ }
71
+
72
+ export interface FloatingContext {
73
+ open: ComputedRef<boolean>
74
+ nodeId: string | undefined
75
+ floatingId: string | undefined
76
+ rootStore: FloatingRootContext
77
+ }
78
+
79
+ export interface FloatingNodeType {
80
+ id: string | undefined
81
+ parentId: string | null
82
+ context?: FloatingContext
83
+ }
84
+
85
+ export type FloatingTreeType = FloatingTreeStore
86
+
87
+ export interface ElementProps {
88
+ reference?: Record<string, any> | undefined
89
+ floating?: Record<string, any> | undefined
90
+ item?: Record<string, any> | undefined
91
+ trigger?: Record<string, any> | undefined
92
+ }
93
+
94
+ export interface HandleCloseOptions {
95
+ blockPointerEvents?: boolean
96
+ getScope?: (() => HTMLElement | SVGSVGElement | null)
97
+ }
98
+
99
+ export interface HandleCloseContext {
100
+ x: number | null
101
+ y: number | null
102
+ placement: Placement | null
103
+ elements: {
104
+ domReference: Element | null
105
+ floating: HTMLElement | null
106
+ }
107
+ onClose: () => void
108
+ nodeId?: string
109
+ tree?: FloatingTreeType | null
110
+ leave?: boolean
111
+ }
112
+
113
+ export type HandleCloseContextBase = Omit<HandleCloseContext, 'onClose' | 'tree' | 'x' | 'y'>
114
+
115
+ export interface HandleClose {
116
+ (context: HandleCloseContext): (event: MouseEvent) => void
117
+ __options?: HandleCloseOptions
118
+ }