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,83 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { FloatingPortal } from '../../floating-ui-vue'
|
|
3
|
+
import type { BaseUIComponentProps } from '../../utils/types'
|
|
4
|
+
import { computed, provide, shallowRef, toRef, unref, useAttrs } from 'vue'
|
|
5
|
+
import FloatingPortalLite from '../../utils/FloatingPortalLite.vue'
|
|
6
|
+
import { useTooltipRootContext } from '../root/TooltipRootContext'
|
|
7
|
+
import { tooltipPortalContextKey } from './TooltipPortalContext'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* A portal element that moves the popup to a different part of the DOM.
|
|
11
|
+
* By default, the portal element is appended to `<body>`.
|
|
12
|
+
* Renders a `<div>` element.
|
|
13
|
+
*
|
|
14
|
+
* Documentation: [Base UI Vue Tooltip](https://baseui-vue.com/docs/components/tooltip)
|
|
15
|
+
*/
|
|
16
|
+
defineOptions({
|
|
17
|
+
name: 'TooltipPortal',
|
|
18
|
+
inheritAttrs: false,
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
const props = withDefaults(defineProps<TooltipPortalProps>(), {
|
|
22
|
+
keepMounted: false,
|
|
23
|
+
disabled: false,
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
const attrs = useAttrs()
|
|
27
|
+
const ctx = useTooltipRootContext()
|
|
28
|
+
const keepMounted = toRef(props, 'keepMounted')
|
|
29
|
+
const shouldRender = computed(() => ctx.mounted.value || props.keepMounted)
|
|
30
|
+
const portalRef = shallowRef<{
|
|
31
|
+
element?: HTMLElement | null
|
|
32
|
+
} | null>(null)
|
|
33
|
+
const element = computed(() => unref(portalRef.value?.element) ?? null)
|
|
34
|
+
|
|
35
|
+
provide(tooltipPortalContextKey, keepMounted)
|
|
36
|
+
|
|
37
|
+
defineExpose({
|
|
38
|
+
element,
|
|
39
|
+
})
|
|
40
|
+
</script>
|
|
41
|
+
|
|
42
|
+
<script lang="ts">
|
|
43
|
+
export interface TooltipPortalState {}
|
|
44
|
+
|
|
45
|
+
export interface TooltipPortalProps
|
|
46
|
+
extends BaseUIComponentProps<TooltipPortalState> {
|
|
47
|
+
/**
|
|
48
|
+
* Whether to keep the portal mounted in the DOM while the popup is hidden.
|
|
49
|
+
* @default false
|
|
50
|
+
*/
|
|
51
|
+
keepMounted?: boolean
|
|
52
|
+
/**
|
|
53
|
+
* A parent element to render the portal element into.
|
|
54
|
+
*/
|
|
55
|
+
container?: FloatingPortal.Container
|
|
56
|
+
/**
|
|
57
|
+
* Teleport target.
|
|
58
|
+
* @default 'body'
|
|
59
|
+
*/
|
|
60
|
+
to?: FloatingPortal.Target
|
|
61
|
+
/**
|
|
62
|
+
* Disables Vue Teleport while preserving tooltip mounting behavior.
|
|
63
|
+
* @default false
|
|
64
|
+
*/
|
|
65
|
+
disabled?: boolean
|
|
66
|
+
}
|
|
67
|
+
</script>
|
|
68
|
+
|
|
69
|
+
<template>
|
|
70
|
+
<FloatingPortalLite
|
|
71
|
+
v-if="shouldRender"
|
|
72
|
+
ref="portalRef"
|
|
73
|
+
:as="props.as"
|
|
74
|
+
:class="props.class"
|
|
75
|
+
:style="props.style"
|
|
76
|
+
:container="props.container"
|
|
77
|
+
:to="props.to"
|
|
78
|
+
:disabled="props.disabled"
|
|
79
|
+
v-bind="attrs"
|
|
80
|
+
>
|
|
81
|
+
<slot />
|
|
82
|
+
</FloatingPortalLite>
|
|
83
|
+
</template>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { InjectionKey, Ref } from 'vue'
|
|
2
|
+
import { inject } from 'vue'
|
|
3
|
+
|
|
4
|
+
export type TooltipPortalContext = Ref<boolean>
|
|
5
|
+
|
|
6
|
+
export const tooltipPortalContextKey: InjectionKey<TooltipPortalContext>
|
|
7
|
+
= Symbol('TooltipPortalContext')
|
|
8
|
+
|
|
9
|
+
export function useTooltipPortalContext(): TooltipPortalContext {
|
|
10
|
+
const context = inject(tooltipPortalContextKey, undefined)
|
|
11
|
+
|
|
12
|
+
if (context === undefined) {
|
|
13
|
+
throw new Error(
|
|
14
|
+
'Base UI Vue: <TooltipPortal> is missing.',
|
|
15
|
+
)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return context
|
|
19
|
+
}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type {
|
|
3
|
+
Padding,
|
|
4
|
+
Placement,
|
|
5
|
+
Strategy,
|
|
6
|
+
VirtualElement,
|
|
7
|
+
} from '../../floating-ui-vue'
|
|
8
|
+
import type { BaseUIComponentProps } from '../../utils/types'
|
|
9
|
+
import type {
|
|
10
|
+
Align,
|
|
11
|
+
Boundary,
|
|
12
|
+
CollisionAvoidance,
|
|
13
|
+
OffsetFunction,
|
|
14
|
+
Side,
|
|
15
|
+
} from '../../utils/useAnchorPositioning'
|
|
16
|
+
import type { TooltipInstantType } from '../root/TooltipRoot.vue'
|
|
17
|
+
import { computed, provide, useAttrs } from 'vue'
|
|
18
|
+
import { adaptiveOrigin } from '../../utils/adaptiveOriginMiddleware'
|
|
19
|
+
import { POPUP_COLLISION_AVOIDANCE, useAnchorPositioning } from '../../utils/useAnchorPositioning'
|
|
20
|
+
import { useMergedRefs } from '../../utils/useMergedRefs'
|
|
21
|
+
import { usePositioner } from '../../utils/usePositioner'
|
|
22
|
+
import { useTooltipPortalContext } from '../portal/TooltipPortalContext'
|
|
23
|
+
import { useTooltipRootContext } from '../root/TooltipRootContext'
|
|
24
|
+
import { tooltipPositionerContextKey } from './TooltipPositionerContext'
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Positions the tooltip against the trigger.
|
|
28
|
+
* Renders a `<div>` element.
|
|
29
|
+
*
|
|
30
|
+
* Documentation: [Base UI Vue Tooltip](https://baseui-vue.com/docs/components/tooltip)
|
|
31
|
+
*/
|
|
32
|
+
defineOptions({
|
|
33
|
+
name: 'TooltipPositioner',
|
|
34
|
+
inheritAttrs: false,
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
const props = withDefaults(defineProps<TooltipPositionerProps>(), {
|
|
38
|
+
as: 'div',
|
|
39
|
+
positionMethod: 'absolute',
|
|
40
|
+
side: 'top',
|
|
41
|
+
align: 'center',
|
|
42
|
+
sideOffset: 0,
|
|
43
|
+
alignOffset: 0,
|
|
44
|
+
collisionBoundary: 'clipping-ancestors',
|
|
45
|
+
collisionPadding: 5,
|
|
46
|
+
arrowPadding: 5,
|
|
47
|
+
sticky: false,
|
|
48
|
+
disableAnchorTracking: false,
|
|
49
|
+
collisionAvoidance: () => POPUP_COLLISION_AVOIDANCE,
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
const attrs = useAttrs()
|
|
53
|
+
const ctx = useTooltipRootContext()
|
|
54
|
+
const portalKeepMounted = useTooltipPortalContext()
|
|
55
|
+
|
|
56
|
+
const reference = computed(() => props.anchor ?? ctx.activeTrigger.value?.element ?? null)
|
|
57
|
+
|
|
58
|
+
const positioning = useAnchorPositioning({
|
|
59
|
+
anchor: reference,
|
|
60
|
+
positionMethod: () => props.positionMethod,
|
|
61
|
+
mounted: () => ctx.mounted.value,
|
|
62
|
+
keepMounted: () => portalKeepMounted.value,
|
|
63
|
+
side: () => props.side,
|
|
64
|
+
sideOffset: () => props.sideOffset,
|
|
65
|
+
align: () => props.align,
|
|
66
|
+
alignOffset: () => props.alignOffset,
|
|
67
|
+
collisionBoundary: () => props.collisionBoundary,
|
|
68
|
+
collisionPadding: () => props.collisionPadding,
|
|
69
|
+
sticky: () => props.sticky,
|
|
70
|
+
arrowPadding: () => props.arrowPadding,
|
|
71
|
+
disableAnchorTracking: () => props.disableAnchorTracking,
|
|
72
|
+
collisionAvoidance: () => props.collisionAvoidance,
|
|
73
|
+
adaptiveOrigin: () => ctx.hasViewport.value ? adaptiveOrigin : undefined,
|
|
74
|
+
positionerSizeVars: () => !ctx.hasViewport.value,
|
|
75
|
+
autoUpdateOptions: () => ({
|
|
76
|
+
animationFrame: ctx.trackCursorAxis.value === 'both',
|
|
77
|
+
}),
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
const shouldRender = computed(() => ctx.mounted.value || portalKeepMounted.value)
|
|
81
|
+
const inert = computed(() =>
|
|
82
|
+
!ctx.open.value || ctx.trackCursorAxis.value === 'both' || ctx.disableHoverablePopup.value,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
const state = computed<TooltipPositionerState>(() => ({
|
|
86
|
+
open: ctx.open.value,
|
|
87
|
+
side: positioning.side.value,
|
|
88
|
+
align: positioning.align.value,
|
|
89
|
+
anchorHidden: positioning.anchorHidden.value,
|
|
90
|
+
instant: ctx.trackCursorAxis.value !== 'none' ? 'tracking-cursor' : ctx.instantType.value,
|
|
91
|
+
}))
|
|
92
|
+
|
|
93
|
+
const positionerProps = computed(() => {
|
|
94
|
+
return attrs as Record<string, any>
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
const {
|
|
98
|
+
tag,
|
|
99
|
+
mergedProps,
|
|
100
|
+
renderless,
|
|
101
|
+
ref: renderRef,
|
|
102
|
+
} = usePositioner({
|
|
103
|
+
as: props.as,
|
|
104
|
+
class: props.class,
|
|
105
|
+
style: props.style,
|
|
106
|
+
}, state, {
|
|
107
|
+
styles: positioning.positionerStyles,
|
|
108
|
+
transitionStatus: ctx.transitionStatus,
|
|
109
|
+
props: positionerProps,
|
|
110
|
+
refs: useMergedRefs(positioning.positionerRef, ctx.positionerRef),
|
|
111
|
+
hidden: () => !ctx.mounted.value,
|
|
112
|
+
inert,
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
provide(tooltipPositionerContextKey, positioning)
|
|
116
|
+
</script>
|
|
117
|
+
|
|
118
|
+
<script lang="ts">
|
|
119
|
+
export type TooltipSide = Side
|
|
120
|
+
export type TooltipAlign = Align
|
|
121
|
+
export type TooltipPositionerInstantType = TooltipInstantType | 'tracking-cursor'
|
|
122
|
+
export type TooltipFloatingPlacement = Placement
|
|
123
|
+
|
|
124
|
+
export interface TooltipPositionerState {
|
|
125
|
+
/**
|
|
126
|
+
* Whether the tooltip is currently open.
|
|
127
|
+
*/
|
|
128
|
+
open: boolean
|
|
129
|
+
/**
|
|
130
|
+
* The side of the anchor the component is placed on.
|
|
131
|
+
*/
|
|
132
|
+
side: TooltipSide
|
|
133
|
+
/**
|
|
134
|
+
* The alignment of the component relative to the anchor.
|
|
135
|
+
*/
|
|
136
|
+
align: TooltipAlign
|
|
137
|
+
/**
|
|
138
|
+
* Whether the anchor element is hidden.
|
|
139
|
+
*/
|
|
140
|
+
anchorHidden: boolean
|
|
141
|
+
/**
|
|
142
|
+
* Whether CSS transitions should be disabled.
|
|
143
|
+
*/
|
|
144
|
+
instant: TooltipPositionerInstantType
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export interface TooltipPositionerProps
|
|
148
|
+
extends BaseUIComponentProps<TooltipPositionerState> {
|
|
149
|
+
/**
|
|
150
|
+
* An element to position the popup against.
|
|
151
|
+
* By default, the popup will be positioned against the trigger.
|
|
152
|
+
*/
|
|
153
|
+
anchor?: Element | VirtualElement | null
|
|
154
|
+
/**
|
|
155
|
+
* Determines which CSS `position` property to use.
|
|
156
|
+
* @default 'absolute'
|
|
157
|
+
*/
|
|
158
|
+
positionMethod?: Strategy
|
|
159
|
+
/**
|
|
160
|
+
* Which side of the anchor element to align the popup against.
|
|
161
|
+
* May automatically change to avoid collisions.
|
|
162
|
+
* @default 'top'
|
|
163
|
+
*/
|
|
164
|
+
side?: TooltipSide
|
|
165
|
+
/**
|
|
166
|
+
* How to align the popup relative to the specified side.
|
|
167
|
+
* @default 'center'
|
|
168
|
+
*/
|
|
169
|
+
align?: TooltipAlign
|
|
170
|
+
/**
|
|
171
|
+
* Distance between the anchor and the popup in pixels.
|
|
172
|
+
* @default 0
|
|
173
|
+
*/
|
|
174
|
+
sideOffset?: number | OffsetFunction
|
|
175
|
+
/**
|
|
176
|
+
* Additional offset along the alignment axis in pixels.
|
|
177
|
+
* @default 0
|
|
178
|
+
*/
|
|
179
|
+
alignOffset?: number | OffsetFunction
|
|
180
|
+
/**
|
|
181
|
+
* An element or a rectangle that delimits the area that the popup is confined to.
|
|
182
|
+
* @default 'clipping-ancestors'
|
|
183
|
+
*/
|
|
184
|
+
collisionBoundary?: Boundary
|
|
185
|
+
/**
|
|
186
|
+
* Additional space to maintain from the edge of the collision boundary.
|
|
187
|
+
* @default 5
|
|
188
|
+
*/
|
|
189
|
+
collisionPadding?: Padding
|
|
190
|
+
/**
|
|
191
|
+
* Minimum distance to maintain between the arrow and the edges of the popup.
|
|
192
|
+
*
|
|
193
|
+
* Use it to prevent the arrow element from hanging out of the rounded corners of a popup.
|
|
194
|
+
* @default 5
|
|
195
|
+
*/
|
|
196
|
+
arrowPadding?: Padding
|
|
197
|
+
/**
|
|
198
|
+
* Whether to maintain the popup in the viewport after
|
|
199
|
+
* the anchor element was scrolled out of view.
|
|
200
|
+
* @default false
|
|
201
|
+
*/
|
|
202
|
+
sticky?: boolean
|
|
203
|
+
/**
|
|
204
|
+
* Whether to disable the popup from tracking any layout shift of its positioning anchor.
|
|
205
|
+
* @default false
|
|
206
|
+
*/
|
|
207
|
+
disableAnchorTracking?: boolean
|
|
208
|
+
/**
|
|
209
|
+
* Determines how to handle collisions when positioning the popup.
|
|
210
|
+
* @default { fallbackAxisSide: 'end' }
|
|
211
|
+
*/
|
|
212
|
+
collisionAvoidance?: CollisionAvoidance
|
|
213
|
+
}
|
|
214
|
+
</script>
|
|
215
|
+
|
|
216
|
+
<template>
|
|
217
|
+
<slot v-if="renderless && shouldRender" :ref="renderRef" :props="mergedProps" :state="state" />
|
|
218
|
+
<component :is="tag" v-else-if="shouldRender" :ref="renderRef" v-bind="mergedProps">
|
|
219
|
+
<slot :state="state" />
|
|
220
|
+
</component>
|
|
221
|
+
</template>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { InjectionKey } from 'vue'
|
|
2
|
+
import type { UseAnchorPositioningReturnValue } from '../../utils/useAnchorPositioning'
|
|
3
|
+
import { inject } from 'vue'
|
|
4
|
+
|
|
5
|
+
export type TooltipPositionerContext = Pick<
|
|
6
|
+
UseAnchorPositioningReturnValue,
|
|
7
|
+
'side' | 'align' | 'arrowRef' | 'arrowUncentered' | 'arrowStyles'
|
|
8
|
+
>
|
|
9
|
+
|
|
10
|
+
export const tooltipPositionerContextKey: InjectionKey<TooltipPositionerContext>
|
|
11
|
+
= Symbol('TooltipPositionerContext')
|
|
12
|
+
|
|
13
|
+
export function useTooltipPositionerContext(): TooltipPositionerContext {
|
|
14
|
+
const context = inject(tooltipPositionerContextKey, undefined)
|
|
15
|
+
|
|
16
|
+
if (context === undefined) {
|
|
17
|
+
throw new Error(
|
|
18
|
+
'Base UI Vue: TooltipPositionerContext is missing. Tooltip parts must be placed within <TooltipPositioner>.',
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return context
|
|
23
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export enum TooltipPositionerCssVars {
|
|
2
|
+
/**
|
|
3
|
+
* The available width between the trigger and the edge of the viewport.
|
|
4
|
+
* @type {number}
|
|
5
|
+
*/
|
|
6
|
+
availableWidth = '--available-width',
|
|
7
|
+
/**
|
|
8
|
+
* The available height between the trigger and the edge of the viewport.
|
|
9
|
+
* @type {number}
|
|
10
|
+
*/
|
|
11
|
+
availableHeight = '--available-height',
|
|
12
|
+
/**
|
|
13
|
+
* The anchor's width.
|
|
14
|
+
* @type {number}
|
|
15
|
+
*/
|
|
16
|
+
anchorWidth = '--anchor-width',
|
|
17
|
+
/**
|
|
18
|
+
* The anchor's height.
|
|
19
|
+
* @type {number}
|
|
20
|
+
*/
|
|
21
|
+
anchorHeight = '--anchor-height',
|
|
22
|
+
/**
|
|
23
|
+
* The coordinates that this element is anchored to. Used for animations and transitions.
|
|
24
|
+
* @type {string}
|
|
25
|
+
*/
|
|
26
|
+
transformOrigin = '--transform-origin',
|
|
27
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { CommonPopupDataAttributes } from '../../utils/popupStateMapping'
|
|
2
|
+
|
|
3
|
+
export enum TooltipPositionerDataAttributes {
|
|
4
|
+
/**
|
|
5
|
+
* Present when the tooltip is open.
|
|
6
|
+
*/
|
|
7
|
+
open = CommonPopupDataAttributes.open,
|
|
8
|
+
/**
|
|
9
|
+
* Present when the tooltip is closed.
|
|
10
|
+
*/
|
|
11
|
+
closed = CommonPopupDataAttributes.closed,
|
|
12
|
+
/**
|
|
13
|
+
* Present when the anchor is hidden.
|
|
14
|
+
*/
|
|
15
|
+
anchorHidden = CommonPopupDataAttributes.anchorHidden,
|
|
16
|
+
/**
|
|
17
|
+
* Indicates which side the popup is positioned relative to the trigger.
|
|
18
|
+
* @type {'top' | 'bottom' | 'left' | 'right' | 'inline-end' | 'inline-start'}
|
|
19
|
+
*/
|
|
20
|
+
side = CommonPopupDataAttributes.side,
|
|
21
|
+
/**
|
|
22
|
+
* Indicates how the popup is aligned relative to specified side.
|
|
23
|
+
* @type {'start' | 'center' | 'end'}
|
|
24
|
+
*/
|
|
25
|
+
align = CommonPopupDataAttributes.align,
|
|
26
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, provide, shallowRef, toRef } from 'vue'
|
|
3
|
+
import { OPEN_DELAY } from '../utils/constants'
|
|
4
|
+
import { tooltipProviderContextKey } from './TooltipProviderContext'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Provides a shared delay for multiple tooltips. The grouping logic ensures that
|
|
8
|
+
* once a tooltip becomes visible, the adjacent tooltips will be shown instantly.
|
|
9
|
+
*
|
|
10
|
+
* Documentation: [Base UI Vue Tooltip](https://baseui-vue.com/docs/components/tooltip)
|
|
11
|
+
*/
|
|
12
|
+
defineOptions({
|
|
13
|
+
name: 'TooltipProvider',
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
const props = withDefaults(defineProps<TooltipProviderProps>(), {
|
|
17
|
+
timeout: 400,
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const lastCloseTime = shallowRef<number | null>(null)
|
|
21
|
+
|
|
22
|
+
const delay = toRef(props, 'delay')
|
|
23
|
+
const closeDelay = toRef(props, 'closeDelay')
|
|
24
|
+
const timeout = computed(() => props.timeout)
|
|
25
|
+
|
|
26
|
+
provide(tooltipProviderContextKey, {
|
|
27
|
+
delay,
|
|
28
|
+
closeDelay,
|
|
29
|
+
timeout,
|
|
30
|
+
getOpenDelay(triggerDelay) {
|
|
31
|
+
const now = Date.now()
|
|
32
|
+
const instant = lastCloseTime.value != null && now - lastCloseTime.value <= timeout.value
|
|
33
|
+
|
|
34
|
+
if (instant) {
|
|
35
|
+
return { delay: 0, instant: true }
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
delay: triggerDelay ?? delay.value ?? OPEN_DELAY,
|
|
40
|
+
instant: false,
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
getCloseDelay(triggerCloseDelay) {
|
|
44
|
+
return triggerCloseDelay ?? closeDelay.value ?? 0
|
|
45
|
+
},
|
|
46
|
+
notifyOpen() {
|
|
47
|
+
lastCloseTime.value = null
|
|
48
|
+
},
|
|
49
|
+
notifyClose() {
|
|
50
|
+
lastCloseTime.value = Date.now()
|
|
51
|
+
},
|
|
52
|
+
})
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
<script lang="ts">
|
|
56
|
+
export interface TooltipProviderState {}
|
|
57
|
+
|
|
58
|
+
export interface TooltipProviderProps {
|
|
59
|
+
/**
|
|
60
|
+
* How long to wait before opening a tooltip. Specified in milliseconds.
|
|
61
|
+
*/
|
|
62
|
+
delay?: number
|
|
63
|
+
/**
|
|
64
|
+
* How long to wait before closing a tooltip. Specified in milliseconds.
|
|
65
|
+
*/
|
|
66
|
+
closeDelay?: number
|
|
67
|
+
/**
|
|
68
|
+
* Another tooltip will open instantly if the previous tooltip
|
|
69
|
+
* is closed within this timeout. Specified in milliseconds.
|
|
70
|
+
* @default 400
|
|
71
|
+
*/
|
|
72
|
+
timeout?: number
|
|
73
|
+
}
|
|
74
|
+
</script>
|
|
75
|
+
|
|
76
|
+
<template>
|
|
77
|
+
<slot />
|
|
78
|
+
</template>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { InjectionKey, Ref } from 'vue'
|
|
2
|
+
import { inject } from 'vue'
|
|
3
|
+
|
|
4
|
+
export interface TooltipProviderContext {
|
|
5
|
+
delay: Ref<number | undefined>
|
|
6
|
+
closeDelay: Ref<number | undefined>
|
|
7
|
+
timeout: Readonly<Ref<number>>
|
|
8
|
+
getOpenDelay: (triggerDelay: number | undefined) => { delay: number, instant: boolean }
|
|
9
|
+
getCloseDelay: (triggerCloseDelay: number | undefined) => number
|
|
10
|
+
notifyOpen: () => void
|
|
11
|
+
notifyClose: () => void
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const tooltipProviderContextKey: InjectionKey<TooltipProviderContext>
|
|
15
|
+
= Symbol('TooltipProviderContext')
|
|
16
|
+
|
|
17
|
+
export function useTooltipProviderContext(): TooltipProviderContext | undefined {
|
|
18
|
+
return inject(tooltipProviderContextKey, undefined)
|
|
19
|
+
}
|