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,343 @@
1
+ <script setup lang="ts" generic="Payload = unknown">
2
+ import type { BaseUIComponentProps, NativeButtonProps } from '../../utils/types'
3
+ import type { TooltipRootChangeEventDetails } from '../root/TooltipRoot.vue'
4
+ import type { TooltipHandle } from '../store/TooltipHandle'
5
+ import { computed, shallowRef, useAttrs, watch } from 'vue'
6
+ import { mergeProps } from '../../merge-props/mergeProps'
7
+ import { useButton } from '../../use-button'
8
+ import { triggerStateMapping } from '../../utils/popupStateMapping'
9
+ import { REASONS } from '../../utils/reasons'
10
+ import { useBaseUiId } from '../../utils/useBaseUiId'
11
+ import { useMergedRefs } from '../../utils/useMergedRefs'
12
+ import { useRenderElement } from '../../utils/useRenderElement'
13
+ import { useTimeout } from '../../utils/useTimeout'
14
+ import { useTooltipRootContext } from '../root/TooltipRootContext'
15
+ import { createTooltipChangeEventDetails } from '../store/TooltipHandle'
16
+ import { HOVERABLE_CLOSE_GRACE_DELAY } from '../utils/constants'
17
+ import { TooltipTriggerDataAttributes } from './TooltipTriggerDataAttributes'
18
+
19
+ /**
20
+ * An element to attach the tooltip to.
21
+ * Renders a `<button>` element.
22
+ *
23
+ * Documentation: [Base UI Vue Tooltip](https://baseui-vue.com/docs/components/tooltip)
24
+ */
25
+ defineOptions({
26
+ name: 'TooltipTrigger',
27
+ inheritAttrs: false,
28
+ })
29
+
30
+ const props = withDefaults(defineProps<TooltipTriggerProps<Payload>>(), {
31
+ as: 'button',
32
+ closeOnClick: true,
33
+ disabled: false,
34
+ nativeButton: true,
35
+ })
36
+
37
+ const attrs = useAttrs()
38
+ const injectedRootContext = useTooltipRootContext(true)
39
+ const store = props.handle?.store ?? injectedRootContext?.store
40
+
41
+ if (!store) {
42
+ throw new Error(
43
+ 'Base UI Vue: <TooltipTrigger> must be used within a <TooltipRoot> component or receive a tooltip handle.',
44
+ )
45
+ }
46
+
47
+ const triggerId = useBaseUiId(props.id)!
48
+ const triggerRef = shallowRef<HTMLElement | null>(null)
49
+ const openTimer = useTimeout()
50
+ const pointerType = shallowRef<string | undefined>(undefined)
51
+
52
+ const root = computed(() => store.controller.value)
53
+ const disabled = computed(() => props.disabled || root.value?.disabled.value || false)
54
+ const open = computed(() =>
55
+ Boolean(root.value?.open.value && root.value?.activeTriggerId.value === triggerId),
56
+ )
57
+
58
+ const { getButtonProps, buttonRef } = useButton({
59
+ disabled,
60
+ focusableWhenDisabled: () => true,
61
+ native: () => props.nativeButton ?? true,
62
+ })
63
+
64
+ const triggerState = computed<TooltipTriggerState>(() => ({
65
+ open: open.value,
66
+ disabled: disabled.value,
67
+ }))
68
+
69
+ function triggerElement() {
70
+ return triggerRef.value ?? undefined
71
+ }
72
+
73
+ function makeDetails(
74
+ reason: TooltipRootChangeEventDetails['reason'],
75
+ event?: MouseEvent | FocusEvent | KeyboardEvent | PointerEvent,
76
+ ) {
77
+ return createTooltipChangeEventDetails(reason, event, triggerElement())
78
+ }
79
+
80
+ function requestOpen(event: MouseEvent | FocusEvent) {
81
+ const context = root.value
82
+
83
+ if (!context) {
84
+ return
85
+ }
86
+
87
+ context.requestOpenChange(true, makeDetails(event.type === 'focus' ? REASONS.triggerFocus : REASONS.triggerHover, event), triggerId)
88
+ }
89
+
90
+ function requestClose(event: MouseEvent | FocusEvent | KeyboardEvent | PointerEvent) {
91
+ const context = root.value
92
+
93
+ if (!context) {
94
+ return
95
+ }
96
+
97
+ const reason = event.type === 'keydown'
98
+ ? REASONS.escapeKey
99
+ : event.type === 'click' || event.type === 'pointerdown'
100
+ ? REASONS.triggerPress
101
+ : event.type === 'blur'
102
+ ? REASONS.triggerFocus
103
+ : REASONS.triggerHover
104
+
105
+ context.requestOpenChange(false, makeDetails(reason, event), triggerId)
106
+ }
107
+
108
+ function handleMouseEnter(event: MouseEvent) {
109
+ const context = root.value
110
+
111
+ if (!context) {
112
+ return
113
+ }
114
+
115
+ if (pointerType.value === 'touch') {
116
+ return
117
+ }
118
+
119
+ context.clearCloseTimer()
120
+ openTimer.clear()
121
+
122
+ if (disabled.value) {
123
+ if (context.open.value) {
124
+ context.requestOpenChange(false, makeDetails(REASONS.triggerHover, event), triggerId)
125
+ }
126
+ return
127
+ }
128
+
129
+ if (context.open.value && context.activeTriggerId.value !== triggerId) {
130
+ requestOpen(event)
131
+ return
132
+ }
133
+
134
+ const { delay, instant } = context.getOpenDelay(props.delay)
135
+
136
+ if (instant) {
137
+ context.instantType.value = 'delay'
138
+ }
139
+
140
+ if (delay <= 0) {
141
+ requestOpen(event)
142
+ return
143
+ }
144
+
145
+ openTimer.start(delay, () => {
146
+ requestOpen(event)
147
+ })
148
+ }
149
+
150
+ function handleMouseLeave(event: MouseEvent) {
151
+ const context = root.value
152
+
153
+ openTimer.clear()
154
+
155
+ if (!context || context.activeTriggerId.value !== triggerId) {
156
+ return
157
+ }
158
+
159
+ const closeDelay = context.getCloseDelay(props.closeDelay)
160
+ const delay = closeDelay === 0 && !context.disableHoverablePopup.value && context.trackCursorAxis.value !== 'both'
161
+ ? HOVERABLE_CLOSE_GRACE_DELAY
162
+ : closeDelay
163
+
164
+ context.scheduleClose(delay, makeDetails(REASONS.triggerHover, event), triggerId)
165
+ }
166
+
167
+ function handleFocus(event: FocusEvent) {
168
+ const context = root.value
169
+
170
+ if (!context) {
171
+ return
172
+ }
173
+
174
+ openTimer.clear()
175
+ context.clearCloseTimer()
176
+
177
+ if (disabled.value) {
178
+ if (context.open.value) {
179
+ context.requestOpenChange(false, makeDetails(REASONS.triggerFocus, event), triggerId)
180
+ }
181
+ return
182
+ }
183
+
184
+ requestOpen(event)
185
+ }
186
+
187
+ function handleBlur(event: FocusEvent) {
188
+ openTimer.clear()
189
+ requestClose(event)
190
+ }
191
+
192
+ function handlePointerDown(event: PointerEvent) {
193
+ pointerType.value = event.pointerType
194
+
195
+ if (props.closeOnClick && !open.value) {
196
+ openTimer.clear()
197
+ }
198
+ }
199
+
200
+ function handleClick(event: MouseEvent) {
201
+ if (!props.closeOnClick) {
202
+ return
203
+ }
204
+
205
+ openTimer.clear()
206
+
207
+ if (open.value) {
208
+ requestClose(event)
209
+ }
210
+ }
211
+
212
+ function handleKeydown(event: KeyboardEvent) {
213
+ if (event.key === 'Escape' && root.value?.open.value) {
214
+ requestClose(event)
215
+ }
216
+ }
217
+
218
+ watch(
219
+ [
220
+ triggerRef,
221
+ () => props.payload,
222
+ () => props.closeOnClick,
223
+ () => props.closeDelay,
224
+ ],
225
+ ([element], _previous, onCleanup) => {
226
+ if (!element) {
227
+ return
228
+ }
229
+
230
+ store.registerTrigger({
231
+ id: triggerId,
232
+ element,
233
+ payload: props.payload,
234
+ closeOnClick: props.closeOnClick ?? true,
235
+ closeDelay: props.closeDelay,
236
+ })
237
+
238
+ onCleanup(() => {
239
+ store.unregisterTrigger(triggerId, element)
240
+ })
241
+ },
242
+ { immediate: true },
243
+ )
244
+
245
+ const renderRef = useMergedRefs(buttonRef, triggerRef)
246
+
247
+ const triggerProps = computed(() =>
248
+ getButtonProps(mergeProps(
249
+ attrs,
250
+ root.value?.dismiss.reference,
251
+ {
252
+ 'id': triggerId,
253
+ 'aria-describedby': open.value ? root.value?.popupId.value : undefined,
254
+ 'data-base-ui-tooltip-trigger': disabled.value ? undefined : '',
255
+ onPointerenter(event: PointerEvent) {
256
+ pointerType.value = event.pointerType
257
+ },
258
+ 'onPointerdown': handlePointerDown,
259
+ 'onMouseenter': handleMouseEnter,
260
+ 'onMouseleave': handleMouseLeave,
261
+ 'onFocus': handleFocus,
262
+ 'onBlur': handleBlur,
263
+ 'onClick': handleClick,
264
+ 'onKeydown': handleKeydown,
265
+ },
266
+ )),
267
+ )
268
+
269
+ const {
270
+ tag,
271
+ mergedProps,
272
+ renderless,
273
+ } = useRenderElement({
274
+ componentProps: props,
275
+ state: triggerState,
276
+ props: triggerProps,
277
+ stateAttributesMapping: {
278
+ ...triggerStateMapping,
279
+ disabled(value) {
280
+ return value ? { [TooltipTriggerDataAttributes.triggerDisabled]: '' } : null
281
+ },
282
+ },
283
+ defaultTagName: 'button',
284
+ ref: renderRef,
285
+ })
286
+ </script>
287
+
288
+ <script lang="ts">
289
+ export interface TooltipTriggerState {
290
+ /**
291
+ * Whether the tooltip is currently open.
292
+ */
293
+ open: boolean
294
+ /**
295
+ * Whether this trigger should ignore interaction.
296
+ */
297
+ disabled: boolean
298
+ }
299
+
300
+ export interface TooltipTriggerProps<Payload = unknown>
301
+ extends NativeButtonProps, BaseUIComponentProps<TooltipTriggerState> {
302
+ /**
303
+ * A handle to associate the trigger with a tooltip.
304
+ */
305
+ handle?: TooltipHandle<Payload>
306
+ /**
307
+ * A payload to pass to the tooltip when it is opened.
308
+ */
309
+ payload?: Payload
310
+ /**
311
+ * How long to wait before opening the tooltip. Specified in milliseconds.
312
+ * @default 600
313
+ */
314
+ delay?: number
315
+ /**
316
+ * Whether the tooltip should close when this trigger is clicked.
317
+ * @default true
318
+ */
319
+ closeOnClick?: boolean
320
+ /**
321
+ * How long to wait before closing the tooltip. Specified in milliseconds.
322
+ * @default 0
323
+ */
324
+ closeDelay?: number
325
+ /**
326
+ * If `true`, the tooltip will not open when interacting with this trigger.
327
+ * Note that this doesn't apply the `disabled` attribute to the trigger element.
328
+ * @default false
329
+ */
330
+ disabled?: boolean
331
+ /**
332
+ * The trigger id.
333
+ */
334
+ id?: string
335
+ }
336
+ </script>
337
+
338
+ <template>
339
+ <slot v-if="renderless" :ref="renderRef" :props="mergedProps" :state="triggerState" />
340
+ <component :is="tag" v-else :ref="renderRef" v-bind="mergedProps">
341
+ <slot :state="triggerState" />
342
+ </component>
343
+ </template>
@@ -0,0 +1,12 @@
1
+ import { CommonTriggerDataAttributes } from '../../utils/popupStateMapping'
2
+
3
+ export enum TooltipTriggerDataAttributes {
4
+ /**
5
+ * Present when the corresponding tooltip is open.
6
+ */
7
+ popupOpen = CommonTriggerDataAttributes.popupOpen,
8
+ /**
9
+ * Present when the trigger is disabled, either by the `disabled` prop or by a parent `<TooltipRoot>`.
10
+ */
11
+ triggerDisabled = CommonTriggerDataAttributes.triggerDisabled,
12
+ }
@@ -0,0 +1,2 @@
1
+ export const OPEN_DELAY = 600
2
+ export const HOVERABLE_CLOSE_GRACE_DELAY = 100
@@ -0,0 +1,149 @@
1
+ <script setup lang="ts">
2
+ import type { BaseUIComponentProps } from '../../utils/types'
3
+ import type { TooltipInstantType } from '../root/TooltipRoot.vue'
4
+ import { computed, onBeforeUnmount, onMounted, useAttrs } from 'vue'
5
+ import { useDirection } from '../../direction-provider/DirectionContext'
6
+ import { usePopupViewport } from '../../utils/usePopupViewport'
7
+ import { useRenderElement } from '../../utils/useRenderElement'
8
+ import { useTooltipPositionerContext } from '../positioner/TooltipPositionerContext'
9
+ import { useTooltipRootContext } from '../root/TooltipRootContext'
10
+ import { TooltipViewportCssVars } from './TooltipViewportCssVars'
11
+ import { TooltipViewportDataAttributes } from './TooltipViewportDataAttributes'
12
+
13
+ /**
14
+ * A viewport for displaying content transitions.
15
+ * This component is only required if one popup can be opened by multiple triggers, its content
16
+ * changes based on the trigger, and switching between them is animated.
17
+ * Renders a `<div>` element.
18
+ *
19
+ * Documentation: [Base UI Vue Tooltip](https://baseui-vue.com/docs/components/tooltip)
20
+ */
21
+ defineOptions({
22
+ name: 'TooltipViewport',
23
+ inheritAttrs: false,
24
+ })
25
+
26
+ const props = withDefaults(defineProps<TooltipViewportProps>(), {
27
+ as: 'div',
28
+ })
29
+
30
+ const attrs = useAttrs()
31
+ const ctx = useTooltipRootContext()
32
+ const positioner = useTooltipPositionerContext()
33
+ const direction = useDirection()
34
+
35
+ onMounted(() => {
36
+ ctx.setHasViewport(true)
37
+ })
38
+
39
+ onBeforeUnmount(() => {
40
+ ctx.setHasViewport(false)
41
+ })
42
+
43
+ const viewport = usePopupViewport({
44
+ activeTriggerElement: () => ctx.activeTrigger.value?.element,
45
+ activeTriggerId: ctx.activeTriggerId,
46
+ open: ctx.open,
47
+ mounted: ctx.mounted,
48
+ popupElement: ctx.popupRef,
49
+ positionerElement: ctx.positionerRef,
50
+ side: positioner.side,
51
+ direction,
52
+ payload: ctx.payload,
53
+ cssVars: TooltipViewportCssVars,
54
+ })
55
+
56
+ const {
57
+ currentContainerRef,
58
+ previousContainerRef,
59
+ currentContentKey,
60
+ currentContainerProps,
61
+ previousContainerProps,
62
+ transitioning,
63
+ } = viewport
64
+
65
+ const state = computed<TooltipViewportState>(() => ({
66
+ activationDirection: viewport.state.value.activationDirection,
67
+ transitioning: viewport.state.value.transitioning,
68
+ instant: ctx.instantType.value,
69
+ }))
70
+
71
+ const viewportProps = computed(() => {
72
+ return {
73
+ ...attrs,
74
+ }
75
+ })
76
+
77
+ const {
78
+ tag,
79
+ mergedProps,
80
+ renderless,
81
+ ref: renderRef,
82
+ } = useRenderElement({
83
+ componentProps: {
84
+ as: props.as,
85
+ class: props.class,
86
+ style: props.style,
87
+ },
88
+ state,
89
+ props: viewportProps,
90
+ stateAttributesMapping: {
91
+ activationDirection(value) {
92
+ return value ? { [TooltipViewportDataAttributes.activationDirection]: value } : null
93
+ },
94
+ transitioning(value) {
95
+ return value ? { [TooltipViewportDataAttributes.transitioning]: '' } : null
96
+ },
97
+ instant(value) {
98
+ return value ? { [TooltipViewportDataAttributes.instant]: value } : null
99
+ },
100
+ },
101
+ defaultTagName: 'div',
102
+ })
103
+ </script>
104
+
105
+ <script lang="ts">
106
+ export interface TooltipViewportState {
107
+ /**
108
+ * The activation direction of the transitioned content.
109
+ */
110
+ activationDirection: string | undefined
111
+ /**
112
+ * Whether the viewport is currently transitioning between contents.
113
+ */
114
+ transitioning: boolean
115
+ /**
116
+ * Present if animations should be instant.
117
+ */
118
+ instant: TooltipInstantType
119
+ }
120
+
121
+ export interface TooltipViewportProps extends BaseUIComponentProps<TooltipViewportState> {}
122
+ </script>
123
+
124
+ <template>
125
+ <slot v-if="renderless" :ref="renderRef" :props="mergedProps" :state="state" />
126
+ <component :is="tag" v-else :ref="renderRef" v-bind="mergedProps">
127
+ <template v-if="transitioning">
128
+ <div
129
+ ref="previousContainerRef"
130
+ v-bind="previousContainerProps"
131
+ />
132
+ <div
133
+ :key="currentContentKey"
134
+ ref="currentContainerRef"
135
+ v-bind="currentContainerProps"
136
+ >
137
+ <slot :state="state" />
138
+ </div>
139
+ </template>
140
+ <div
141
+ v-else
142
+ :key="currentContentKey"
143
+ ref="currentContainerRef"
144
+ v-bind="currentContainerProps"
145
+ >
146
+ <slot :state="state" />
147
+ </div>
148
+ </component>
149
+ </template>
@@ -0,0 +1,14 @@
1
+ export enum TooltipViewportCssVars {
2
+ /**
3
+ * The width of the parent popup.
4
+ * This variable is placed on the 'previous' container and stores the width of the popup when the previous content was rendered.
5
+ * It can be used to freeze the dimensions of the popup when animating between different content.
6
+ */
7
+ popupWidth = '--popup-width',
8
+ /**
9
+ * The height of the parent popup.
10
+ * This variable is placed on the 'previous' container and stores the height of the popup when the previous content was rendered.
11
+ * It can be used to freeze the dimensions of the popup when animating between different content.
12
+ */
13
+ popupHeight = '--popup-height',
14
+ }
@@ -0,0 +1,26 @@
1
+ export enum TooltipViewportDataAttributes {
2
+ /**
3
+ * Applied to the direct child of the viewport when no transitions are present or the new content when it's entering.
4
+ */
5
+ current = 'data-current',
6
+ /**
7
+ * Applied to the direct child of the viewport that contains the exiting content when transitions are present.
8
+ */
9
+ previous = 'data-previous',
10
+ /**
11
+ * Indicates the direction from which the popup was activated.
12
+ * This can be used to create directional animations based on how the popup was triggered.
13
+ * Contains space-separated values for both horizontal and vertical axes.
14
+ * @type {`${'left' | 'right' | ''} ${'down' | 'up' | ''}`}
15
+ */
16
+ activationDirection = 'data-activation-direction',
17
+ /**
18
+ * Indicates that the viewport is currently transitioning between old and new content.
19
+ */
20
+ transitioning = 'data-transitioning',
21
+ /**
22
+ * Present if animations should be instant.
23
+ * @type {'delay' | 'dismiss' | 'focus'}
24
+ */
25
+ instant = 'data-instant',
26
+ }
@@ -0,0 +1,66 @@
1
+ <script setup lang="ts">
2
+ import type { FloatingPortal } from '../floating-ui-vue'
3
+ import { computed, useAttrs } from 'vue'
4
+ import { useFloatingPortalNode } from '../floating-ui-vue'
5
+
6
+ defineOptions({
7
+ name: 'FloatingPortalLite',
8
+ inheritAttrs: false,
9
+ })
10
+
11
+ const props = withDefaults(defineProps<FloatingPortalLiteProps>(), {
12
+ as: 'div',
13
+ disabled: false,
14
+ })
15
+
16
+ const attrs = useAttrs()
17
+
18
+ const state = computed<FloatingPortalLiteState>(() => ({}))
19
+
20
+ const {
21
+ portalNode,
22
+ portalTarget,
23
+ shouldRender,
24
+ tag,
25
+ mergedProps,
26
+ renderless,
27
+ ref: renderRef,
28
+ } = useFloatingPortalNode({
29
+ container: () => props.container,
30
+ to: () => props.to,
31
+ componentProps: props,
32
+ elementProps: computed(() => attrs),
33
+ state,
34
+ })
35
+
36
+ defineExpose({
37
+ element: portalNode,
38
+ })
39
+ </script>
40
+
41
+ <script lang="ts">
42
+ export interface FloatingPortalLiteState {}
43
+
44
+ export interface FloatingPortalLiteProps
45
+ extends FloatingPortal.Props<FloatingPortalLiteState> {
46
+ /**
47
+ * Vue Teleport target. Prefer `container` for React API parity.
48
+ * @default 'body'
49
+ */
50
+ to?: FloatingPortal.Target
51
+ /**
52
+ * Disables Vue Teleport while preserving portal mounting behavior.
53
+ * @default false
54
+ */
55
+ disabled?: boolean
56
+ }
57
+ </script>
58
+
59
+ <template>
60
+ <Teleport v-if="shouldRender" :to="portalTarget" :disabled="disabled">
61
+ <slot v-if="renderless" :ref="renderRef" :props="mergedProps" :state="state" />
62
+ <component :is="tag" v-else :ref="renderRef" v-bind="mergedProps">
63
+ <slot :state="state" />
64
+ </component>
65
+ </Teleport>
66
+ </template>
@@ -0,0 +1,36 @@
1
+ <script setup lang="ts">
2
+ import { onMounted, shallowRef, useAttrs } from 'vue'
3
+ import { platform } from './platform'
4
+ import { visuallyHidden } from './visuallyHidden'
5
+
6
+ defineOptions({
7
+ name: 'FocusGuard',
8
+ inheritAttrs: false,
9
+ })
10
+
11
+ const attrs = useAttrs()
12
+ const element = shallowRef<HTMLSpanElement | null>(null)
13
+ const role = shallowRef<'button' | undefined>(undefined)
14
+
15
+ onMounted(() => {
16
+ if (platform.screenReader.voiceOver && platform.engine.webkit) {
17
+ role.value = 'button'
18
+ }
19
+ })
20
+
21
+ defineExpose({
22
+ element,
23
+ })
24
+ </script>
25
+
26
+ <template>
27
+ <span
28
+ ref="element"
29
+ v-bind="attrs"
30
+ :style="visuallyHidden"
31
+ :tabindex="0"
32
+ :role="role"
33
+ :aria-hidden="role ? undefined : 'true'"
34
+ data-base-ui-vue-focus-guard=""
35
+ />
36
+ </template>