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,689 @@
|
|
|
1
|
+
import type { MaybeRefOrGetter } from 'vue'
|
|
2
|
+
import type { FloatingTreeStore } from '../components/FloatingTreeStore'
|
|
3
|
+
import type { ElementProps, FloatingContext, FloatingRootContext } from '../types'
|
|
4
|
+
import {
|
|
5
|
+
getComputedStyle,
|
|
6
|
+
getParentNode,
|
|
7
|
+
isElement,
|
|
8
|
+
isHTMLElement,
|
|
9
|
+
isLastTraversableNode,
|
|
10
|
+
isShadowRoot,
|
|
11
|
+
} from '@floating-ui/utils/dom'
|
|
12
|
+
import { onScopeDispose, shallowRef, toValue, watchEffect } from 'vue'
|
|
13
|
+
import { addEventListener } from '../../utils/addEventListener'
|
|
14
|
+
import { createChangeEventDetails } from '../../utils/createBaseUIEventDetails'
|
|
15
|
+
import { mergeCleanups } from '../../utils/mergeCleanups'
|
|
16
|
+
import { ownerDocument } from '../../utils/owner'
|
|
17
|
+
import { platform } from '../../utils/platform'
|
|
18
|
+
import { REASONS } from '../../utils/reasons'
|
|
19
|
+
import { Timeout, useTimeout } from '../../utils/useTimeout'
|
|
20
|
+
import { useFloatingTree } from '../components/FloatingTree'
|
|
21
|
+
import { createAttribute } from '../utils/createAttribute'
|
|
22
|
+
import { contains, getTarget, isEventTargetWithin, isRootElement } from '../utils/element'
|
|
23
|
+
import { getNodeChildren } from '../utils/nodes'
|
|
24
|
+
|
|
25
|
+
type PressType = 'intentional' | 'sloppy'
|
|
26
|
+
|
|
27
|
+
function alwaysFalse() {
|
|
28
|
+
return false
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function normalizeProp(
|
|
32
|
+
normalizable?: boolean | { escapeKey?: boolean | undefined, outsidePress?: boolean | undefined },
|
|
33
|
+
) {
|
|
34
|
+
return {
|
|
35
|
+
escapeKey:
|
|
36
|
+
typeof normalizable === 'boolean' ? normalizable : (normalizable?.escapeKey ?? false),
|
|
37
|
+
outsidePress:
|
|
38
|
+
typeof normalizable === 'boolean' ? normalizable : (normalizable?.outsidePress ?? true),
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface UseDismissProps {
|
|
43
|
+
/**
|
|
44
|
+
* Whether the Hook is enabled, including all internal Effects and event
|
|
45
|
+
* handlers.
|
|
46
|
+
* @default true
|
|
47
|
+
*/
|
|
48
|
+
enabled?: MaybeRefOrGetter<boolean | undefined>
|
|
49
|
+
/**
|
|
50
|
+
* Whether to dismiss the floating element upon pressing the `esc` key.
|
|
51
|
+
* @default true
|
|
52
|
+
*/
|
|
53
|
+
escapeKey?: MaybeRefOrGetter<boolean | undefined>
|
|
54
|
+
/**
|
|
55
|
+
* Whether to dismiss the floating element upon pressing the reference
|
|
56
|
+
* element.
|
|
57
|
+
*
|
|
58
|
+
* A lazy getter invoked when handling reference press events.
|
|
59
|
+
* @default false
|
|
60
|
+
*/
|
|
61
|
+
referencePress?: (() => boolean) | undefined
|
|
62
|
+
/**
|
|
63
|
+
* Whether to dismiss the floating element upon pressing outside of the
|
|
64
|
+
* floating element.
|
|
65
|
+
* @default true
|
|
66
|
+
*/
|
|
67
|
+
outsidePress?: boolean | ((event: MouseEvent | TouchEvent) => boolean) | undefined
|
|
68
|
+
/**
|
|
69
|
+
* The type of event to use to determine an outside "press".
|
|
70
|
+
*/
|
|
71
|
+
outsidePressEvent?:
|
|
72
|
+
| PressType
|
|
73
|
+
| {
|
|
74
|
+
mouse: PressType
|
|
75
|
+
touch: PressType
|
|
76
|
+
}
|
|
77
|
+
| (() =>
|
|
78
|
+
| PressType
|
|
79
|
+
| {
|
|
80
|
+
mouse: PressType
|
|
81
|
+
touch: PressType
|
|
82
|
+
})
|
|
83
|
+
| undefined
|
|
84
|
+
/**
|
|
85
|
+
* Determines whether event listeners bubble upwards through a tree of
|
|
86
|
+
* floating elements.
|
|
87
|
+
*/
|
|
88
|
+
bubbles?:
|
|
89
|
+
| MaybeRefOrGetter<boolean
|
|
90
|
+
| { escapeKey?: boolean | undefined, outsidePress?: boolean | undefined }
|
|
91
|
+
| undefined>
|
|
92
|
+
/**
|
|
93
|
+
* External FloatingTree to use when the one provided by context can't be used.
|
|
94
|
+
*/
|
|
95
|
+
externalTree?: FloatingTreeStore | undefined
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Closes the floating element when a dismissal is requested — by default, when
|
|
100
|
+
* the user presses the `escape` key or outside of the floating element.
|
|
101
|
+
* @see https://floating-ui.com/docs/useDismiss
|
|
102
|
+
*/
|
|
103
|
+
export function useDismiss(
|
|
104
|
+
context: FloatingRootContext | FloatingContext,
|
|
105
|
+
props: UseDismissProps = {},
|
|
106
|
+
): ElementProps {
|
|
107
|
+
const store = 'rootStore' in context ? context.rootStore : context
|
|
108
|
+
|
|
109
|
+
const open = store.useState('open')
|
|
110
|
+
const floatingElement = store.useState('floatingElement')
|
|
111
|
+
const domReferenceElement = store.useState('domReferenceElement')
|
|
112
|
+
const { dataRef } = store.context
|
|
113
|
+
|
|
114
|
+
const tree = useFloatingTree(props.externalTree)
|
|
115
|
+
|
|
116
|
+
const pressStartedInsideRef = shallowRef(false)
|
|
117
|
+
const pressStartPreventedRef = shallowRef(false)
|
|
118
|
+
const suppressNextOutsideClickRef = shallowRef(false)
|
|
119
|
+
const isComposingRef = shallowRef(false)
|
|
120
|
+
const currentPointerTypeRef = shallowRef<PointerEvent['pointerType']>('')
|
|
121
|
+
|
|
122
|
+
const touchStateRef = shallowRef<{
|
|
123
|
+
startTime: number
|
|
124
|
+
startX: number
|
|
125
|
+
startY: number
|
|
126
|
+
dismissOnTouchEnd: boolean
|
|
127
|
+
dismissOnMouseDown: boolean
|
|
128
|
+
} | null>(null)
|
|
129
|
+
|
|
130
|
+
const cancelDismissOnEndTimeout = useTimeout()
|
|
131
|
+
const clearInsideVueTreeTimeout = useTimeout()
|
|
132
|
+
|
|
133
|
+
function enabled() {
|
|
134
|
+
return toValue(props.enabled ?? true) !== false
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function escapeKey() {
|
|
138
|
+
return toValue(props.escapeKey ?? true) !== false
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function referencePress() {
|
|
142
|
+
return (props.referencePress ?? alwaysFalse)()
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function outsidePress() {
|
|
146
|
+
return props.outsidePress ?? true
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function outsidePressEnabled() {
|
|
150
|
+
return outsidePress() !== false
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function getBubbles() {
|
|
154
|
+
return normalizeProp(toValue(props.bubbles))
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function clearInsideVueTree() {
|
|
158
|
+
clearInsideVueTreeTimeout.clear()
|
|
159
|
+
dataRef.value.insideVueTree = false
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function hasBlockingChild(bubbleKey: '__escapeKeyBubbles' | '__outsidePressBubbles') {
|
|
163
|
+
const nodeId = dataRef.value.floatingContext?.nodeId
|
|
164
|
+
const children = tree ? getNodeChildren(tree.nodesRef.value, nodeId) : []
|
|
165
|
+
|
|
166
|
+
return children.some((child) => {
|
|
167
|
+
return child.context?.open.value && !child.context.rootStore.context.dataRef.value[bubbleKey]
|
|
168
|
+
})
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function isEventWithinOwnElements(event: Event) {
|
|
172
|
+
return (
|
|
173
|
+
isEventTargetWithin(event, store.select('floatingElement'))
|
|
174
|
+
|| isEventTargetWithin(event, store.select('domReferenceElement'))
|
|
175
|
+
)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function closeOnReferencePress(event: Event) {
|
|
179
|
+
if (!enabled() || !referencePress()) {
|
|
180
|
+
return
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
store.setOpen(
|
|
184
|
+
false,
|
|
185
|
+
createChangeEventDetails(
|
|
186
|
+
REASONS.triggerPress,
|
|
187
|
+
event as MouseEvent | PointerEvent | TouchEvent | KeyboardEvent,
|
|
188
|
+
),
|
|
189
|
+
)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function closeOnEscapeKeyDown(event: KeyboardEvent) {
|
|
193
|
+
if (!open.value || !enabled() || !escapeKey() || event.key !== 'Escape') {
|
|
194
|
+
return
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (isComposingRef.value) {
|
|
198
|
+
return
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const { escapeKey: escapeKeyBubbles } = getBubbles()
|
|
202
|
+
|
|
203
|
+
if (!escapeKeyBubbles && hasBlockingChild('__escapeKeyBubbles')) {
|
|
204
|
+
return
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const eventDetails = createChangeEventDetails(REASONS.escapeKey, event)
|
|
208
|
+
|
|
209
|
+
store.setOpen(false, eventDetails)
|
|
210
|
+
|
|
211
|
+
if (!eventDetails.isCanceled) {
|
|
212
|
+
event.preventDefault()
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (!escapeKeyBubbles && !eventDetails.isPropagationAllowed) {
|
|
216
|
+
event.stopPropagation()
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function markInsideVueTree() {
|
|
221
|
+
dataRef.value.insideVueTree = true
|
|
222
|
+
clearInsideVueTreeTimeout.start(0, clearInsideVueTree)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function markPressStartedInsideVueTree(event: PointerEvent | MouseEvent) {
|
|
226
|
+
if (!open.value || !enabled() || event.button !== 0) {
|
|
227
|
+
return
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const target = getTarget(event) as Element | null
|
|
231
|
+
|
|
232
|
+
if (!contains(store.select('floatingElement'), target)) {
|
|
233
|
+
return
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (!pressStartedInsideRef.value) {
|
|
237
|
+
pressStartedInsideRef.value = true
|
|
238
|
+
pressStartPreventedRef.value = false
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function markInsidePressStartPrevented(event: PointerEvent | MouseEvent) {
|
|
243
|
+
if (!open.value || !enabled()) {
|
|
244
|
+
return
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (!event.defaultPrevented) {
|
|
248
|
+
return
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (pressStartedInsideRef.value) {
|
|
252
|
+
pressStartPreventedRef.value = true
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function resetPressStartState() {
|
|
257
|
+
pressStartedInsideRef.value = false
|
|
258
|
+
pressStartPreventedRef.value = false
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function getOutsidePressEvent(): PressType {
|
|
262
|
+
const type = currentPointerTypeRef.value as 'pen' | 'mouse' | 'touch' | ''
|
|
263
|
+
const computedType = type === 'pen' || !type ? 'mouse' : type
|
|
264
|
+
const outsidePressEvent = props.outsidePressEvent ?? 'sloppy'
|
|
265
|
+
const resolved = typeof outsidePressEvent === 'function'
|
|
266
|
+
? outsidePressEvent()
|
|
267
|
+
: outsidePressEvent
|
|
268
|
+
|
|
269
|
+
if (resolved == null) {
|
|
270
|
+
return 'sloppy'
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (typeof resolved === 'string') {
|
|
274
|
+
return resolved
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return resolved[computedType] ?? 'sloppy'
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function shouldIgnoreEvent(event: Event) {
|
|
281
|
+
const computedOutsidePressEvent = getOutsidePressEvent()
|
|
282
|
+
return (
|
|
283
|
+
(computedOutsidePressEvent === 'intentional' && event.type !== 'click')
|
|
284
|
+
|| (computedOutsidePressEvent === 'sloppy' && event.type === 'click')
|
|
285
|
+
)
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function isEventWithinFloatingTree(event: Event) {
|
|
289
|
+
const nodeId = dataRef.value.floatingContext?.nodeId
|
|
290
|
+
const targetIsInsideChildren
|
|
291
|
+
= tree
|
|
292
|
+
&& getNodeChildren(tree.nodesRef.value, nodeId).some(node =>
|
|
293
|
+
isEventTargetWithin(event, node.context?.rootStore.select('floatingElement')),
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
return isEventWithinOwnElements(event) || Boolean(targetIsInsideChildren)
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function addTargetEventListenerOnce<EventType extends Event>(
|
|
300
|
+
event: EventType,
|
|
301
|
+
listener: (event: EventType) => void,
|
|
302
|
+
) {
|
|
303
|
+
const target = getTarget(event)
|
|
304
|
+
|
|
305
|
+
if (!target) {
|
|
306
|
+
return
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const eventTarget = target as EventTarget
|
|
310
|
+
const handler = () => {
|
|
311
|
+
listener(event)
|
|
312
|
+
eventTarget.removeEventListener(event.type, handler)
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
eventTarget.addEventListener(event.type, handler)
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
watchEffect((onCleanup) => {
|
|
319
|
+
if (!open.value || !enabled()) {
|
|
320
|
+
return
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const { escapeKey: escapeKeyBubbles, outsidePress: outsidePressBubbles } = getBubbles()
|
|
324
|
+
dataRef.value.__escapeKeyBubbles = escapeKeyBubbles
|
|
325
|
+
dataRef.value.__outsidePressBubbles = outsidePressBubbles
|
|
326
|
+
|
|
327
|
+
const compositionTimeout = new Timeout()
|
|
328
|
+
const preventedPressSuppressionTimeout = new Timeout()
|
|
329
|
+
|
|
330
|
+
function handleCompositionStart() {
|
|
331
|
+
compositionTimeout.clear()
|
|
332
|
+
isComposingRef.value = true
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function handleCompositionEnd() {
|
|
336
|
+
compositionTimeout.start(
|
|
337
|
+
platform.engine.webkit ? 5 : 0,
|
|
338
|
+
() => {
|
|
339
|
+
isComposingRef.value = false
|
|
340
|
+
},
|
|
341
|
+
)
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
function suppressImmediateOutsideClickAfterPreventedStart() {
|
|
345
|
+
suppressNextOutsideClickRef.value = true
|
|
346
|
+
preventedPressSuppressionTimeout.start(0, () => {
|
|
347
|
+
suppressNextOutsideClickRef.value = false
|
|
348
|
+
})
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function closeOnPressOutside(event: MouseEvent | PointerEvent | TouchEvent) {
|
|
352
|
+
if (shouldIgnoreEvent(event)) {
|
|
353
|
+
if (event.type !== 'click' && !isEventWithinOwnElements(event)) {
|
|
354
|
+
preventedPressSuppressionTimeout.clear()
|
|
355
|
+
suppressNextOutsideClickRef.value = false
|
|
356
|
+
}
|
|
357
|
+
clearInsideVueTree()
|
|
358
|
+
return
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
if (dataRef.value.insideVueTree) {
|
|
362
|
+
clearInsideVueTree()
|
|
363
|
+
return
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const target = getTarget(event)
|
|
367
|
+
const inertSelector = `[${createAttribute('inert')}]`
|
|
368
|
+
const targetRoot = isElement(target) ? target.getRootNode() : null
|
|
369
|
+
const doc = ownerDocument(store.select('floatingElement'))
|
|
370
|
+
const markers = Array.from(
|
|
371
|
+
(isShadowRoot(targetRoot) ? targetRoot : doc)?.querySelectorAll(inertSelector) ?? [],
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
const triggers = store.context.triggerElements
|
|
375
|
+
|
|
376
|
+
if (
|
|
377
|
+
target
|
|
378
|
+
&& (triggers.hasElement(target as Element)
|
|
379
|
+
|| triggers.hasMatchingElement(trigger => contains(trigger, target as Element)))
|
|
380
|
+
) {
|
|
381
|
+
return
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
let targetRootAncestor = isElement(target) ? target : null
|
|
385
|
+
while (targetRootAncestor && !isLastTraversableNode(targetRootAncestor)) {
|
|
386
|
+
const nextParent = getParentNode(targetRootAncestor)
|
|
387
|
+
if (isLastTraversableNode(nextParent) || !isElement(nextParent)) {
|
|
388
|
+
break
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
targetRootAncestor = nextParent
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
if (
|
|
395
|
+
markers.length
|
|
396
|
+
&& isElement(target)
|
|
397
|
+
&& !isRootElement(target)
|
|
398
|
+
&& !contains(target, store.select('floatingElement'))
|
|
399
|
+
&& markers.every(marker => !contains(targetRootAncestor, marker))
|
|
400
|
+
) {
|
|
401
|
+
return
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if (isHTMLElement(target) && !('touches' in event)) {
|
|
405
|
+
const lastTraversableNode = isLastTraversableNode(target)
|
|
406
|
+
const style = getComputedStyle(target)
|
|
407
|
+
const scrollRe = /auto|scroll/
|
|
408
|
+
const isScrollableX = lastTraversableNode || scrollRe.test(style.overflowX)
|
|
409
|
+
const isScrollableY = lastTraversableNode || scrollRe.test(style.overflowY)
|
|
410
|
+
|
|
411
|
+
const canScrollX
|
|
412
|
+
= isScrollableX && target.clientWidth > 0 && target.scrollWidth > target.clientWidth
|
|
413
|
+
const canScrollY
|
|
414
|
+
= isScrollableY && target.clientHeight > 0 && target.scrollHeight > target.clientHeight
|
|
415
|
+
|
|
416
|
+
const isRTL = style.direction === 'rtl'
|
|
417
|
+
const pressedVerticalScrollbar
|
|
418
|
+
= canScrollY
|
|
419
|
+
&& (isRTL
|
|
420
|
+
? event.offsetX <= target.offsetWidth - target.clientWidth
|
|
421
|
+
: event.offsetX > target.clientWidth)
|
|
422
|
+
const pressedHorizontalScrollbar = canScrollX && event.offsetY > target.clientHeight
|
|
423
|
+
|
|
424
|
+
if (pressedVerticalScrollbar || pressedHorizontalScrollbar) {
|
|
425
|
+
return
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
if (isEventWithinFloatingTree(event)) {
|
|
430
|
+
return
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
if (getOutsidePressEvent() === 'intentional' && suppressNextOutsideClickRef.value) {
|
|
434
|
+
preventedPressSuppressionTimeout.clear()
|
|
435
|
+
suppressNextOutsideClickRef.value = false
|
|
436
|
+
return
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
const shouldDismiss = outsidePress()
|
|
440
|
+
if (typeof shouldDismiss === 'function' && !shouldDismiss(event)) {
|
|
441
|
+
return
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
if (hasBlockingChild('__outsidePressBubbles')) {
|
|
445
|
+
return
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
store.setOpen(false, createChangeEventDetails(REASONS.outsidePress, event))
|
|
449
|
+
clearInsideVueTree()
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
function handlePointerDown(event: PointerEvent) {
|
|
453
|
+
if (
|
|
454
|
+
getOutsidePressEvent() !== 'sloppy'
|
|
455
|
+
|| event.pointerType === 'touch'
|
|
456
|
+
|| !store.select('open')
|
|
457
|
+
|| !enabled()
|
|
458
|
+
|| isEventWithinOwnElements(event)
|
|
459
|
+
) {
|
|
460
|
+
return
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
closeOnPressOutside(event)
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
function handleTouchStart(event: TouchEvent) {
|
|
467
|
+
if (
|
|
468
|
+
getOutsidePressEvent() !== 'sloppy'
|
|
469
|
+
|| !store.select('open')
|
|
470
|
+
|| !enabled()
|
|
471
|
+
|| isEventWithinOwnElements(event)
|
|
472
|
+
) {
|
|
473
|
+
return
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
const touch = event.touches[0]
|
|
477
|
+
if (touch) {
|
|
478
|
+
touchStateRef.value = {
|
|
479
|
+
startTime: Date.now(),
|
|
480
|
+
startX: touch.clientX,
|
|
481
|
+
startY: touch.clientY,
|
|
482
|
+
dismissOnTouchEnd: false,
|
|
483
|
+
dismissOnMouseDown: true,
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
cancelDismissOnEndTimeout.start(1000, () => {
|
|
487
|
+
if (touchStateRef.value) {
|
|
488
|
+
touchStateRef.value.dismissOnTouchEnd = false
|
|
489
|
+
touchStateRef.value.dismissOnMouseDown = false
|
|
490
|
+
}
|
|
491
|
+
})
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
function handleTouchStartCapture(event: TouchEvent) {
|
|
496
|
+
currentPointerTypeRef.value = 'touch'
|
|
497
|
+
addTargetEventListenerOnce(event, handleTouchStart)
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
function closeOnPressOutsideCapture(event: PointerEvent | MouseEvent) {
|
|
501
|
+
cancelDismissOnEndTimeout.clear()
|
|
502
|
+
|
|
503
|
+
if (event.type === 'pointerdown') {
|
|
504
|
+
currentPointerTypeRef.value = (event as PointerEvent).pointerType
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
if (
|
|
508
|
+
event.type === 'mousedown'
|
|
509
|
+
&& touchStateRef.value
|
|
510
|
+
&& !touchStateRef.value.dismissOnMouseDown
|
|
511
|
+
) {
|
|
512
|
+
return
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
addTargetEventListenerOnce(event, (targetEvent) => {
|
|
516
|
+
if (targetEvent.type === 'pointerdown') {
|
|
517
|
+
handlePointerDown(targetEvent as PointerEvent)
|
|
518
|
+
}
|
|
519
|
+
else {
|
|
520
|
+
closeOnPressOutside(targetEvent as MouseEvent)
|
|
521
|
+
}
|
|
522
|
+
})
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
function handlePressEndCapture(event: PointerEvent | MouseEvent) {
|
|
526
|
+
if (!pressStartedInsideRef.value) {
|
|
527
|
+
return
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
const pressStartedInsideDefaultPrevented = pressStartPreventedRef.value
|
|
531
|
+
resetPressStartState()
|
|
532
|
+
|
|
533
|
+
if (getOutsidePressEvent() !== 'intentional') {
|
|
534
|
+
return
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
if (event.type === 'pointercancel') {
|
|
538
|
+
if (pressStartedInsideDefaultPrevented) {
|
|
539
|
+
suppressImmediateOutsideClickAfterPreventedStart()
|
|
540
|
+
}
|
|
541
|
+
return
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
if (isEventWithinFloatingTree(event)) {
|
|
545
|
+
return
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
if (pressStartedInsideDefaultPrevented) {
|
|
549
|
+
suppressImmediateOutsideClickAfterPreventedStart()
|
|
550
|
+
return
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
const shouldDismiss = outsidePress()
|
|
554
|
+
if (typeof shouldDismiss === 'function' && !shouldDismiss(event as MouseEvent)) {
|
|
555
|
+
return
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
preventedPressSuppressionTimeout.clear()
|
|
559
|
+
suppressNextOutsideClickRef.value = true
|
|
560
|
+
clearInsideVueTree()
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
function handleTouchMove(event: TouchEvent) {
|
|
564
|
+
if (
|
|
565
|
+
getOutsidePressEvent() !== 'sloppy'
|
|
566
|
+
|| !touchStateRef.value
|
|
567
|
+
|| isEventWithinOwnElements(event)
|
|
568
|
+
) {
|
|
569
|
+
return
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
const touch = event.touches[0]
|
|
573
|
+
if (!touch) {
|
|
574
|
+
return
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
const deltaX = Math.abs(touch.clientX - touchStateRef.value.startX)
|
|
578
|
+
const deltaY = Math.abs(touch.clientY - touchStateRef.value.startY)
|
|
579
|
+
const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY)
|
|
580
|
+
|
|
581
|
+
if (distance > 5) {
|
|
582
|
+
touchStateRef.value.dismissOnTouchEnd = true
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
if (distance > 10) {
|
|
586
|
+
closeOnPressOutside(event)
|
|
587
|
+
cancelDismissOnEndTimeout.clear()
|
|
588
|
+
touchStateRef.value = null
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
function handleTouchMoveCapture(event: TouchEvent) {
|
|
593
|
+
addTargetEventListenerOnce(event, handleTouchMove)
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
function handleTouchEnd(event: TouchEvent) {
|
|
597
|
+
if (
|
|
598
|
+
getOutsidePressEvent() !== 'sloppy'
|
|
599
|
+
|| !touchStateRef.value
|
|
600
|
+
|| isEventWithinOwnElements(event)
|
|
601
|
+
) {
|
|
602
|
+
return
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
if (touchStateRef.value.dismissOnTouchEnd) {
|
|
606
|
+
closeOnPressOutside(event)
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
cancelDismissOnEndTimeout.clear()
|
|
610
|
+
touchStateRef.value = null
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
function handleTouchEndCapture(event: TouchEvent) {
|
|
614
|
+
addTargetEventListenerOnce(event, handleTouchEnd)
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
const doc = ownerDocument(floatingElement.value ?? domReferenceElement.value)
|
|
618
|
+
const unsubscribe = mergeCleanups(
|
|
619
|
+
escapeKey()
|
|
620
|
+
? mergeCleanups(
|
|
621
|
+
addEventListener(doc, 'keydown', closeOnEscapeKeyDown),
|
|
622
|
+
addEventListener(doc, 'compositionstart', handleCompositionStart),
|
|
623
|
+
addEventListener(doc, 'compositionend', handleCompositionEnd),
|
|
624
|
+
)
|
|
625
|
+
: undefined,
|
|
626
|
+
outsidePressEnabled()
|
|
627
|
+
? mergeCleanups(
|
|
628
|
+
addEventListener(doc, 'click', closeOnPressOutsideCapture, true),
|
|
629
|
+
addEventListener(doc, 'pointerdown', closeOnPressOutsideCapture, true),
|
|
630
|
+
addEventListener(doc, 'pointerup', handlePressEndCapture, true),
|
|
631
|
+
addEventListener(doc, 'pointercancel', handlePressEndCapture, true),
|
|
632
|
+
addEventListener(doc, 'mousedown', closeOnPressOutsideCapture, true),
|
|
633
|
+
addEventListener(doc, 'mouseup', handlePressEndCapture, true),
|
|
634
|
+
addEventListener(doc, 'touchstart', handleTouchStartCapture, true),
|
|
635
|
+
addEventListener(doc, 'touchmove', handleTouchMoveCapture, true),
|
|
636
|
+
addEventListener(doc, 'touchend', handleTouchEndCapture, true),
|
|
637
|
+
)
|
|
638
|
+
: undefined,
|
|
639
|
+
)
|
|
640
|
+
|
|
641
|
+
onCleanup(() => {
|
|
642
|
+
unsubscribe()
|
|
643
|
+
compositionTimeout.clear()
|
|
644
|
+
preventedPressSuppressionTimeout.clear()
|
|
645
|
+
resetPressStartState()
|
|
646
|
+
suppressNextOutsideClickRef.value = false
|
|
647
|
+
})
|
|
648
|
+
})
|
|
649
|
+
|
|
650
|
+
watchEffect(() => {
|
|
651
|
+
outsidePress()
|
|
652
|
+
clearInsideVueTree()
|
|
653
|
+
})
|
|
654
|
+
|
|
655
|
+
onScopeDispose(() => {
|
|
656
|
+
cancelDismissOnEndTimeout.clear()
|
|
657
|
+
clearInsideVueTreeTimeout.clear()
|
|
658
|
+
})
|
|
659
|
+
|
|
660
|
+
const reference = {
|
|
661
|
+
onKeydown: closeOnEscapeKeyDown,
|
|
662
|
+
onPointerdown: closeOnReferencePress,
|
|
663
|
+
onClick: closeOnReferencePress,
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
const floating = {
|
|
667
|
+
onKeydown: closeOnEscapeKeyDown,
|
|
668
|
+
onPointerdown: markInsidePressStartPrevented,
|
|
669
|
+
onMousedown: markInsidePressStartPrevented,
|
|
670
|
+
onClickCapture: markInsideVueTree,
|
|
671
|
+
onMousedownCapture(event: MouseEvent) {
|
|
672
|
+
markInsideVueTree()
|
|
673
|
+
markPressStartedInsideVueTree(event)
|
|
674
|
+
},
|
|
675
|
+
onPointerdownCapture(event: PointerEvent) {
|
|
676
|
+
markInsideVueTree()
|
|
677
|
+
markPressStartedInsideVueTree(event)
|
|
678
|
+
},
|
|
679
|
+
onMouseupCapture: markInsideVueTree,
|
|
680
|
+
onTouchendCapture: markInsideVueTree,
|
|
681
|
+
onTouchmoveCapture: markInsideVueTree,
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
return {
|
|
685
|
+
reference,
|
|
686
|
+
floating,
|
|
687
|
+
trigger: reference,
|
|
688
|
+
}
|
|
689
|
+
}
|