base-ui-vue 0.3.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.
- package/dist/arrow/TooltipArrow.cjs +609 -0
- package/dist/arrow/TooltipArrow.cjs.map +1 -0
- package/dist/arrow/TooltipArrow.js +478 -0
- package/dist/arrow/TooltipArrow.js.map +1 -0
- package/dist/button/Button.cjs +5 -317
- package/dist/button/Button.cjs.map +1 -1
- package/dist/button/Button.js +3 -249
- package/dist/button/Button.js.map +1 -1
- package/dist/button/ToolbarButton.cjs +19 -6
- package/dist/button/ToolbarButton.cjs.map +1 -1
- package/dist/button/ToolbarButton.js +3 -2
- package/dist/button/ToolbarButton.js.map +1 -1
- package/dist/checkbox/index.cjs +20 -9
- package/dist/checkbox/index.cjs.map +1 -1
- package/dist/checkbox/index.js +7 -2
- package/dist/checkbox/index.js.map +1 -1
- package/dist/checkbox-group/CheckboxGroup.cjs +14 -13
- package/dist/checkbox-group/CheckboxGroup.cjs.map +1 -1
- package/dist/checkbox-group/CheckboxGroup.js +2 -1
- package/dist/checkbox-group/CheckboxGroup.js.map +1 -1
- package/dist/components/FloatingPortal.cjs +66 -0
- package/dist/components/FloatingPortal.cjs.map +1 -0
- package/dist/components/FloatingPortal.js +55 -0
- package/dist/components/FloatingPortal.js.map +1 -0
- package/dist/components/FloatingRootStore.cjs +101 -0
- package/dist/components/FloatingRootStore.cjs.map +1 -0
- package/dist/components/FloatingRootStore.js +84 -0
- package/dist/components/FloatingRootStore.js.map +1 -0
- package/dist/components/FloatingTree.cjs +33 -0
- package/dist/components/FloatingTree.cjs.map +1 -0
- package/dist/components/FloatingTree.js +22 -0
- package/dist/components/FloatingTree.js.map +1 -0
- package/dist/composite/composite.cjs +6 -0
- package/dist/composite/composite.js +1 -1
- package/dist/content/ScrollAreaContent.cjs +3 -3
- package/dist/content/ScrollAreaContent.cjs.map +1 -1
- package/dist/content/ScrollAreaContent.js +1 -1
- package/dist/control/FieldControl.cjs +3 -3
- package/dist/control/FieldControl.cjs.map +1 -1
- package/dist/control/FieldControl.js +1 -1
- package/dist/control/SliderControl.cjs +3 -3
- package/dist/control/SliderControl.cjs.map +1 -1
- package/dist/control/SliderControl.js +3 -3
- package/dist/corner/ScrollAreaCorner.cjs +3 -3
- package/dist/corner/ScrollAreaCorner.cjs.map +1 -1
- package/dist/corner/ScrollAreaCorner.js +1 -1
- package/dist/decrement/NumberFieldDecrement.cjs +868 -0
- package/dist/decrement/NumberFieldDecrement.cjs.map +1 -0
- package/dist/decrement/NumberFieldDecrement.js +701 -0
- package/dist/decrement/NumberFieldDecrement.js.map +1 -0
- package/dist/description/FieldDescription.cjs +2 -2
- package/dist/description/FieldDescription.cjs.map +1 -1
- package/dist/description/FieldDescription.js +1 -1
- package/dist/error/FieldError.cjs +2 -2
- package/dist/error/FieldError.cjs.map +1 -1
- package/dist/error/FieldError.js +1 -1
- package/dist/fallback/AvatarFallback.cjs +4 -48
- package/dist/fallback/AvatarFallback.cjs.map +1 -1
- package/dist/fallback/AvatarFallback.js +4 -42
- package/dist/fallback/AvatarFallback.js.map +1 -1
- package/dist/floating-ui-vue/index.js +638 -0
- package/dist/floating-ui-vue/index.js.map +1 -0
- package/dist/form/Form.cjs +3 -3
- package/dist/form/Form.cjs.map +1 -1
- package/dist/form/Form.js +1 -1
- package/dist/group/NumberFieldGroup.cjs +72 -0
- package/dist/group/NumberFieldGroup.cjs.map +1 -0
- package/dist/group/NumberFieldGroup.js +67 -0
- package/dist/group/NumberFieldGroup.js.map +1 -0
- package/dist/group/ToolbarGroup.cjs +2 -2
- package/dist/group/ToolbarGroup.cjs.map +1 -1
- package/dist/group/ToolbarGroup.js +1 -1
- package/dist/header/AccordionHeader.cjs +2 -2
- package/dist/header/AccordionHeader.cjs.map +1 -1
- package/dist/header/AccordionHeader.js +1 -1
- package/dist/hooks/useDismiss.cjs +502 -0
- package/dist/hooks/useDismiss.cjs.map +1 -0
- package/dist/hooks/useHoverFloatingInteraction.cjs +233 -0
- package/dist/hooks/useHoverFloatingInteraction.cjs.map +1 -0
- package/dist/image/AvatarImage.cjs +4 -4
- package/dist/image/AvatarImage.cjs.map +1 -1
- package/dist/image/AvatarImage.js +1 -1
- package/dist/increment/NumberFieldIncrement.cjs +113 -0
- package/dist/increment/NumberFieldIncrement.cjs.map +1 -0
- package/dist/increment/NumberFieldIncrement.js +108 -0
- package/dist/increment/NumberFieldIncrement.js.map +1 -0
- package/dist/index.cjs +80 -8
- package/dist/index.d.cts +4328 -1600
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +4328 -1600
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -4
- package/dist/index2.cjs +9435 -3236
- package/dist/index2.cjs.map +1 -1
- package/dist/index2.js +8905 -3049
- package/dist/index2.js.map +1 -1
- package/dist/rolldown-runtime.js +36 -0
- package/package.json +1 -1
- package/src/floating-ui-vue/components/FloatingPortal.ts +171 -0
- package/src/floating-ui-vue/components/FloatingPortal.vue +259 -0
- package/src/floating-ui-vue/components/FloatingRootStore.ts +83 -0
- package/src/floating-ui-vue/components/FloatingTree.ts +64 -0
- package/src/floating-ui-vue/components/FloatingTreeStore.ts +21 -0
- package/src/floating-ui-vue/hooks/useDismiss.ts +689 -0
- package/src/floating-ui-vue/hooks/useHoverFloatingInteraction.ts +244 -0
- package/src/floating-ui-vue/hooks/useHoverInteractionSharedState.ts +125 -0
- package/src/floating-ui-vue/hooks/useHoverShared.ts +53 -0
- package/src/floating-ui-vue/index.ts +48 -0
- package/src/floating-ui-vue/middleware/arrow.ts +114 -0
- package/src/floating-ui-vue/types.ts +117 -0
- package/src/floating-ui-vue/utils/composite.ts +20 -0
- package/src/floating-ui-vue/utils/constants.ts +2 -0
- package/src/floating-ui-vue/utils/createAttribute.ts +3 -0
- package/src/floating-ui-vue/utils/createEventEmitter.ts +20 -0
- package/src/floating-ui-vue/utils/element.ts +59 -0
- package/src/floating-ui-vue/utils/event.ts +15 -0
- package/src/floating-ui-vue/utils/nodes.ts +14 -0
- package/src/floating-ui-vue/utils/tabbable.ts +309 -0
- package/src/index.ts +7 -1
- package/src/number-field/decrement/NumberFieldDecrement.vue +109 -0
- package/src/number-field/group/NumberFieldGroup.vue +47 -0
- package/src/number-field/increment/NumberFieldIncrement.vue +109 -0
- package/src/number-field/index.ts +42 -0
- package/src/number-field/input/NumberFieldInput.vue +455 -0
- package/src/number-field/root/NumberFieldRoot.vue +626 -0
- package/src/number-field/root/NumberFieldRootContext.ts +94 -0
- package/src/number-field/root/useNumberFieldButton.ts +171 -0
- package/src/number-field/scrub-area/NumberFieldScrubArea.vue +359 -0
- package/src/number-field/scrub-area/NumberFieldScrubAreaContext.ts +26 -0
- package/src/number-field/scrub-area-cursor/NumberFieldScrubAreaCursor.vue +75 -0
- package/src/number-field/utils/constants.ts +4 -0
- package/src/number-field/utils/getViewportRect.ts +34 -0
- package/src/number-field/utils/parse.ts +248 -0
- package/src/number-field/utils/stateAttributesMapping.ts +9 -0
- package/src/number-field/utils/subscribeToVisualViewportResize.ts +27 -0
- package/src/number-field/utils/types.ts +24 -0
- package/src/number-field/utils/validate.ts +120 -0
- package/src/otp-field/index.ts +22 -0
- package/src/otp-field/input/OtpFieldInput.vue +336 -0
- package/src/otp-field/root/OtpFieldRoot.vue +583 -0
- package/src/otp-field/root/OtpFieldRootContext.ts +81 -0
- package/src/otp-field/utils/otp.ts +135 -0
- package/src/otp-field/utils/stateAttributesMapping.ts +16 -0
- package/src/radio/index.ts +28 -0
- package/src/radio/indicator/RadioIndicator.vue +90 -0
- package/src/radio/indicator/RadioIndicatorDataAttributes.ts +54 -0
- package/src/radio/root/RadioRoot.vue +544 -0
- package/src/radio/root/RadioRootContext.ts +18 -0
- package/src/radio/root/RadioRootDataAttributes.ts +46 -0
- package/src/radio/utils/stateAttributesMapping.ts +29 -0
- package/src/radio-group/RadioGroup.vue +381 -0
- package/src/radio-group/RadioGroupContext.ts +42 -0
- package/src/radio-group/RadioGroupDataAttributes.ts +6 -0
- package/src/radio-group/index.ts +10 -0
- package/src/tabs/index.ts +38 -0
- package/src/tabs/indicator/TabsIndicator.vue +201 -0
- package/src/tabs/indicator/TabsIndicatorCssVars.ts +26 -0
- package/src/tabs/indicator/TabsIndicatorDataAttributes.ts +12 -0
- package/src/tabs/indicator/prehydrationScript.min.ts +5 -0
- package/src/tabs/indicator/prehydrationScript.template.js +87 -0
- package/src/tabs/list/TabsList.vue +201 -0
- package/src/tabs/list/TabsListContext.ts +29 -0
- package/src/tabs/list/TabsListDataAttributes.ts +12 -0
- package/src/tabs/panel/TabsPanel.vue +167 -0
- package/src/tabs/panel/TabsPanelDataAttributes.ts +28 -0
- package/src/tabs/root/TabsRoot.vue +468 -0
- package/src/tabs/root/TabsRootContext.ts +56 -0
- package/src/tabs/root/TabsRootDataAttributes.ts +12 -0
- package/src/tabs/root/stateAttributesMapping.ts +9 -0
- package/src/tabs/tab/TabsTab.vue +274 -0
- package/src/tabs/tab/TabsTabDataAttributes.ts +20 -0
- package/src/tabs/utils/areTabValuesEqual.ts +6 -0
- package/src/tooltip/arrow/TooltipArrow.vue +116 -0
- package/src/tooltip/arrow/TooltipArrowDataAttributes.ts +31 -0
- package/src/tooltip/index.ts +54 -0
- package/src/tooltip/popup/TooltipPopup.vue +142 -0
- package/src/tooltip/popup/TooltipPopupDataAttributes.ts +35 -0
- package/src/tooltip/portal/TooltipPortal.vue +83 -0
- package/src/tooltip/portal/TooltipPortalContext.ts +19 -0
- package/src/tooltip/positioner/TooltipPositioner.vue +221 -0
- package/src/tooltip/positioner/TooltipPositionerContext.ts +23 -0
- package/src/tooltip/positioner/TooltipPositionerCssVars.ts +27 -0
- package/src/tooltip/positioner/TooltipPositionerDataAttributes.ts +26 -0
- package/src/tooltip/provider/TooltipProvider.vue +78 -0
- package/src/tooltip/provider/TooltipProviderContext.ts +19 -0
- package/src/tooltip/root/TooltipRoot.vue +401 -0
- package/src/tooltip/root/TooltipRootContext.ts +71 -0
- package/src/tooltip/store/TooltipHandle.ts +215 -0
- package/src/tooltip/trigger/TooltipTrigger.vue +343 -0
- package/src/tooltip/trigger/TooltipTriggerDataAttributes.ts +12 -0
- package/src/tooltip/utils/constants.ts +2 -0
- package/src/tooltip/viewport/TooltipViewport.vue +149 -0
- package/src/tooltip/viewport/TooltipViewportCssVars.ts +14 -0
- package/src/tooltip/viewport/TooltipViewportDataAttributes.ts +26 -0
- package/src/utils/FloatingPortalLite.vue +66 -0
- package/src/utils/FocusGuard.vue +36 -0
- package/src/utils/adaptiveOriginMiddleware.ts +79 -0
- package/src/utils/addEventListener.ts +16 -0
- package/src/utils/constants.ts +11 -0
- package/src/utils/createBaseUIEventDetails.ts +2 -0
- package/src/utils/detectBrowser.ts +15 -0
- package/src/utils/formatNumber.ts +35 -2
- package/src/utils/getCssDimensions.ts +19 -0
- package/src/utils/getDisabledMountTransitionStyles.ts +9 -0
- package/src/utils/hideMiddleware.ts +19 -0
- package/src/utils/mergeCleanups.ts +7 -0
- package/src/utils/platform.ts +18 -0
- package/src/utils/popupStateMapping.ts +103 -0
- package/src/utils/reasons.ts +4 -0
- package/src/utils/serializeValue.ts +17 -0
- package/src/utils/useAnchorPositioning.ts +644 -0
- package/src/utils/useInterval.ts +45 -0
- package/src/utils/usePopupAutoResize.ts +254 -0
- package/src/utils/usePopupViewport.ts +398 -0
- package/src/utils/usePositioner.ts +61 -0
- package/src/utils/usePressAndHold.ts +260 -0
- package/src/utils/useRenderElement.ts +3 -0
- package/src/utils/useValueChanged.ts +21 -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,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>
|