@vizejs/ui 0.347.7 → 0.350.2
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/{button-BMIqJ_M5.d.mts → button-CVX8UBXj.d.mts} +6 -7
- package/dist/{button-CaLxP2l2.mjs → button-DT8AKlds.mjs} +2 -2
- package/dist/button.d.mts +1 -1
- package/dist/button.mjs +1 -1
- package/dist/catalog.d.mts +541 -0
- package/dist/catalog.mjs +784 -0
- package/dist/{checkbox-B4y9GUen.mjs → checkbox-BgIvwjyC.mjs} +2 -2
- package/dist/{checkbox-sbhaWekB.d.mts → checkbox-DP3_ko7D.d.mts} +7 -8
- package/dist/checkbox.d.mts +1 -1
- package/dist/checkbox.mjs +1 -1
- package/dist/collection.d.mts +2 -2
- package/dist/collection.mjs +1 -1
- package/dist/composite-navigation-QINW9GLy.d.mts +115 -0
- package/dist/composite-navigation-Skx3LZsv.mjs +354 -0
- package/dist/composite-navigation.d.mts +2 -0
- package/dist/composite-navigation.mjs +2 -0
- package/dist/controllable-state.d.mts +1 -1
- package/dist/dismissable-layer-4icKahVs.d.mts +119 -0
- package/dist/dismissable-layer-CwG1gtdz.mjs +488 -0
- package/dist/dismissable-layer.d.mts +2 -0
- package/dist/dismissable-layer.mjs +2 -0
- package/dist/focus-CAWi_I-0.mjs +318 -0
- package/dist/focus-K6dOifoZ.d.mts +112 -0
- package/dist/focus-guards-Bt0C-0qS.d.mts +81 -0
- package/dist/focus-guards-DhMPQAT8.mjs +299 -0
- package/dist/focus-guards.d.mts +2 -0
- package/dist/focus-guards.mjs +2 -0
- package/dist/focus-scope-CavhKWx0.d.mts +100 -0
- package/dist/focus-scope-D9U1aj67.mjs +340 -0
- package/dist/focus-scope-dom-DBwNEWxG.mjs +264 -0
- package/dist/focus-scope.d.mts +2 -0
- package/dist/focus-scope.mjs +2 -0
- package/dist/focus.d.mts +2 -0
- package/dist/focus.mjs +2 -0
- package/dist/hover-BXwwbSaO.d.mts +80 -0
- package/dist/hover.d.mts +2 -0
- package/dist/hover.mjs +197 -0
- package/dist/{id-BSgJwErt.d.mts → id-5OAUyVPd.d.mts} +2 -3
- package/dist/{id-CPBdeoL3.mjs → id-mziSyAse.mjs} +2 -2
- package/dist/id.d.mts +2 -2
- package/dist/id.mjs +1 -1
- package/dist/index.d.mts +22 -11
- package/dist/index.mjs +21 -10
- package/dist/inert-outside-CyqtoKQ4.mjs +346 -0
- package/dist/inert-outside-tuHRmaqJ.d.mts +43 -0
- package/dist/inert-outside.d.mts +2 -0
- package/dist/inert-outside.mjs +2 -0
- package/dist/interaction-modality.d.mts +2 -2
- package/dist/interaction-modality.mjs +1 -1
- package/dist/long-press-Dsul69gk.mjs +340 -0
- package/dist/{long-press-CRjjjJK2.d.mts → long-press-cll6z2K9.d.mts} +8 -18
- package/dist/long-press.d.mts +2 -2
- package/dist/long-press.mjs +1 -245
- package/dist/media-pdf.d.mts +1 -1
- package/dist/media-pdf.mjs +1 -1
- package/dist/media.d.mts +1 -1
- package/dist/media.mjs +1 -1
- package/dist/move-BOmXDYbh.d.mts +103 -0
- package/dist/move-BVvMHzxr.mjs +386 -0
- package/dist/move.d.mts +2 -0
- package/dist/move.mjs +2 -0
- package/dist/{press-Bp57IOe2.mjs → press-N_mE3Mgx.mjs} +3 -149
- package/dist/press-event-Cd2OPpmw.mjs +149 -0
- package/dist/press.d.mts +1 -1
- package/dist/press.mjs +1 -1
- package/dist/{primitive-BE28SwD7.mjs → primitive-BX31dogp.mjs} +2 -2
- package/dist/{primitive-Bog8qvd8.d.mts → primitive-C8jW7DLd.d.mts} +3 -4
- package/dist/primitive.d.mts +1 -1
- package/dist/primitive.mjs +1 -1
- package/dist/scroll-lock-BgVtX4wT.d.mts +49 -0
- package/dist/scroll-lock-Ckbmm0-J.mjs +313 -0
- package/dist/scroll-lock.d.mts +2 -0
- package/dist/scroll-lock.mjs +2 -0
- package/dist/spatial-navigation-CHj9mDZH.d.mts +106 -0
- package/dist/spatial-navigation-D6-UDavU.mjs +301 -0
- package/dist/spatial-navigation.d.mts +2 -0
- package/dist/spatial-navigation.mjs +2 -0
- package/dist/typeahead-B7KDxE_u.mjs +175 -0
- package/dist/typeahead-BbgUB2Bj.d.mts +71 -0
- package/dist/typeahead.d.mts +2 -0
- package/dist/typeahead.mjs +2 -0
- package/dist/visually-hidden-BOqfqBFt.d.mts +17 -0
- package/dist/{visually-hidden-CTSV3ctZ.mjs → visually-hidden-BwDOx5yf.mjs} +2 -2
- package/dist/visually-hidden.d.mts +1 -1
- package/dist/visually-hidden.mjs +1 -1
- package/package.json +67 -6
- package/dist/visually-hidden-CekDwEwR.d.mts +0 -19
- /package/dist/{_plugin-vue_export-helper-BVN2DL-U.mjs → _plugin-vue_export-helper-BOaGB7Aw.mjs} +0 -0
- /package/dist/{collection-aHZ6Pf0e.d.mts → collection-B_dFZOHO.d.mts} +0 -0
- /package/dist/{collection-CoOROaho.mjs → collection-eHN150dT.mjs} +0 -0
- /package/dist/{controllable-state-B9v6FClp.d.mts → controllable-state-BtoxKahh.d.mts} +0 -0
- /package/dist/{interaction-modality-CO-eQzNy.mjs → interaction-modality-DOZK0BpZ.mjs} +0 -0
- /package/dist/{interaction-modality-tee79ZBZ.d.mts → interaction-modality-jgHKjPFB.d.mts} +0 -0
- /package/dist/{pdf-source-BbZKF_dS.d.mts → pdf-source-BYFK2Pks.d.mts} +0 -0
- /package/dist/{pdf-source-C9zNQd9l.mjs → pdf-source-zu1LkCeE.mjs} +0 -0
- /package/dist/{press-types-B8Ssxqg4.d.mts → press-types-CNqStzJf.d.mts} +0 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { MaybeRefOrGetter, ShallowRef } from "vue";
|
|
2
|
+
|
|
3
|
+
//#region src/dismissable-layer-types.d.ts
|
|
4
|
+
/** Stable pointing-device family captured from an outside pointer event. */
|
|
5
|
+
type DismissableLayerPointerType = "mouse" | "pen" | "pointer" | "touch" | "virtual";
|
|
6
|
+
/** Outside interaction that can request dismissal. */
|
|
7
|
+
type DismissableLayerOutsideReason = "focus-outside" | "pointer-down-outside";
|
|
8
|
+
/** User action that can request dismissal. */
|
|
9
|
+
type DismissableLayerDismissReason = DismissableLayerOutsideReason | "escape-key";
|
|
10
|
+
/** Preventable, immutable snapshot emitted before a pointer dismissal is committed. */
|
|
11
|
+
interface DismissableLayerPointerDownOutsideEvent {
|
|
12
|
+
readonly type: "pointer-down-outside";
|
|
13
|
+
readonly reason: "pointer-down-outside";
|
|
14
|
+
readonly target: Element;
|
|
15
|
+
readonly originalEvent: PointerEvent | MouseEvent | TouchEvent;
|
|
16
|
+
readonly pointerType: DismissableLayerPointerType;
|
|
17
|
+
readonly x: number | null;
|
|
18
|
+
readonly y: number | null;
|
|
19
|
+
readonly altKey: boolean;
|
|
20
|
+
readonly ctrlKey: boolean;
|
|
21
|
+
readonly metaKey: boolean;
|
|
22
|
+
readonly shiftKey: boolean;
|
|
23
|
+
readonly defaultPrevented: boolean;
|
|
24
|
+
readonly preventDefault: () => void;
|
|
25
|
+
}
|
|
26
|
+
/** Preventable, immutable snapshot emitted before a focus dismissal is committed. */
|
|
27
|
+
interface DismissableLayerFocusOutsideEvent {
|
|
28
|
+
readonly type: "focus-outside";
|
|
29
|
+
readonly reason: "focus-outside";
|
|
30
|
+
readonly target: Element;
|
|
31
|
+
readonly relatedTarget: Element | null;
|
|
32
|
+
readonly originalEvent: FocusEvent;
|
|
33
|
+
readonly defaultPrevented: boolean;
|
|
34
|
+
readonly preventDefault: () => void;
|
|
35
|
+
}
|
|
36
|
+
/** Preventable, immutable snapshot emitted before an Escape dismissal is committed. */
|
|
37
|
+
interface DismissableLayerEscapeKeyDownEvent {
|
|
38
|
+
readonly type: "escape-key";
|
|
39
|
+
readonly reason: "escape-key";
|
|
40
|
+
readonly target: Element | null;
|
|
41
|
+
readonly originalEvent: KeyboardEvent;
|
|
42
|
+
readonly altKey: boolean;
|
|
43
|
+
readonly ctrlKey: boolean;
|
|
44
|
+
readonly metaKey: boolean;
|
|
45
|
+
readonly shiftKey: boolean;
|
|
46
|
+
readonly defaultPrevented: boolean;
|
|
47
|
+
readonly preventDefault: () => void;
|
|
48
|
+
}
|
|
49
|
+
/** Preventable outside interaction snapshot shared by pointer and focus callbacks. */
|
|
50
|
+
type DismissableLayerInteractOutsideEvent = DismissableLayerFocusOutsideEvent | DismissableLayerPointerDownOutsideEvent;
|
|
51
|
+
/** Immutable notification emitted after dismissal has not been prevented. */
|
|
52
|
+
interface DismissableLayerDismissEvent {
|
|
53
|
+
readonly type: "dismiss";
|
|
54
|
+
readonly reason: DismissableLayerDismissReason;
|
|
55
|
+
readonly target: Element | null;
|
|
56
|
+
readonly originalEvent: Event;
|
|
57
|
+
}
|
|
58
|
+
/** Native props to merge onto the rendered layer root. */
|
|
59
|
+
interface DismissableLayerProps {
|
|
60
|
+
readonly "data-vize-dismissable-layer": "";
|
|
61
|
+
}
|
|
62
|
+
/** Native props to merge onto optional rendered branch roots. */
|
|
63
|
+
interface DismissableLayerBranchProps {
|
|
64
|
+
readonly "data-vize-dismissable-branch": "";
|
|
65
|
+
}
|
|
66
|
+
/** Reactive configuration for one dismissable overlay layer. */
|
|
67
|
+
interface DismissableLayerOptions {
|
|
68
|
+
/** Primary layer root. It may be `null` during SSR and before mount. */
|
|
69
|
+
readonly root: MaybeRefOrGetter<Element | null | undefined>;
|
|
70
|
+
/** Portalled or exceptional roots that count as inside this layer. @default [] */
|
|
71
|
+
readonly branches?: MaybeRefOrGetter<readonly Element[] | null | undefined>;
|
|
72
|
+
/** Whether an activated layer participates in the document dismissal stack. @default true */
|
|
73
|
+
readonly enabled?: MaybeRefOrGetter<boolean | undefined>;
|
|
74
|
+
/** Whether outside pointer-down events can request dismissal. @default true */
|
|
75
|
+
readonly outsidePointerDown?: MaybeRefOrGetter<boolean | undefined>;
|
|
76
|
+
/** Whether outside focus movement can request dismissal. @default true */
|
|
77
|
+
readonly outsideFocus?: MaybeRefOrGetter<boolean | undefined>;
|
|
78
|
+
/** Whether non-composing Escape keydown can request dismissal. @default true */
|
|
79
|
+
readonly escapeKey?: MaybeRefOrGetter<boolean | undefined>;
|
|
80
|
+
/** Called before an outside pointer-down dismissal is committed. */
|
|
81
|
+
readonly onPointerDownOutside?: (event: DismissableLayerPointerDownOutsideEvent) => void;
|
|
82
|
+
/** Called before an outside focus dismissal is committed. */
|
|
83
|
+
readonly onFocusOutside?: (event: DismissableLayerFocusOutsideEvent) => void;
|
|
84
|
+
/** Called for every outside pointer or focus interaction before dismissal is committed. */
|
|
85
|
+
readonly onInteractOutside?: (event: DismissableLayerInteractOutsideEvent) => void;
|
|
86
|
+
/** Called before an Escape dismissal is committed. */
|
|
87
|
+
readonly onEscapeKeyDown?: (event: DismissableLayerEscapeKeyDownEvent) => void;
|
|
88
|
+
/** Called after a top-layer dismissal request has not been prevented. */
|
|
89
|
+
readonly onDismiss?: (event: DismissableLayerDismissEvent) => void;
|
|
90
|
+
}
|
|
91
|
+
/** Lifecycle, state, and root/branch props for one dismissable layer. */
|
|
92
|
+
interface DismissableLayerController {
|
|
93
|
+
/** Whether this controller has been activated, independently of reactive enablement. */
|
|
94
|
+
readonly isActive: Readonly<ShallowRef<boolean>>;
|
|
95
|
+
/** Whether this layer is the enabled, connected, topmost owner in its document. */
|
|
96
|
+
readonly isTopLayer: Readonly<ShallowRef<boolean>>;
|
|
97
|
+
/** Stable native props to merge onto the rendered layer root. */
|
|
98
|
+
readonly layerProps: Readonly<DismissableLayerProps>;
|
|
99
|
+
/** Stable native props to merge onto optional rendered branch roots. */
|
|
100
|
+
readonly branchProps: Readonly<DismissableLayerBranchProps>;
|
|
101
|
+
/** Register an imperative branch and receive an idempotent release function. */
|
|
102
|
+
readonly registerBranch: (branch: Element) => () => void;
|
|
103
|
+
/** Join the document dismissal stack. Safe to call repeatedly. */
|
|
104
|
+
readonly activate: () => void;
|
|
105
|
+
/** Leave the document dismissal stack. */
|
|
106
|
+
readonly deactivate: () => void;
|
|
107
|
+
/** Re-read roots and options after imperative DOM movement. */
|
|
108
|
+
readonly refresh: () => void;
|
|
109
|
+
/** Permanently release reactive and document-level ownership. */
|
|
110
|
+
readonly dispose: () => void;
|
|
111
|
+
}
|
|
112
|
+
//#endregion
|
|
113
|
+
//#region src/dismissable-layer.d.ts
|
|
114
|
+
/** Create an SSR-safe, document-scoped dismissal layer for overlays and popups. */
|
|
115
|
+
declare function createDismissableLayer(options: DismissableLayerOptions): DismissableLayerController;
|
|
116
|
+
/** Create, mount-activate, and scope-dispose a dismissable overlay layer. */
|
|
117
|
+
declare function useDismissableLayer(options: DismissableLayerOptions): DismissableLayerController;
|
|
118
|
+
//#endregion
|
|
119
|
+
export { DismissableLayerDismissEvent as a, DismissableLayerFocusOutsideEvent as c, DismissableLayerOutsideReason as d, DismissableLayerPointerDownOutsideEvent as f, DismissableLayerController as i, DismissableLayerInteractOutsideEvent as l, DismissableLayerProps as m, useDismissableLayer as n, DismissableLayerDismissReason as o, DismissableLayerPointerType as p, DismissableLayerBranchProps as r, DismissableLayerEscapeKeyDownEvent as s, createDismissableLayer as t, DismissableLayerOptions as u };
|
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
import { getCurrentInstance, getCurrentScope, onMounted, onScopeDispose, shallowReadonly, shallowRef, toValue, watch } from "vue";
|
|
2
|
+
//#region src/dismissable-layer-internal.ts
|
|
3
|
+
const optionDiagnostic = "VIZE_UI_DISMISSABLE_LAYER_OPTION";
|
|
4
|
+
const rootDiagnostic = "VIZE_UI_DISMISSABLE_LAYER_ROOT";
|
|
5
|
+
/** Resolve an event target without assuming it comes from the current realm. */
|
|
6
|
+
function eventElement(value) {
|
|
7
|
+
const candidate = value;
|
|
8
|
+
return candidate?.nodeType === 1 && typeof candidate.getRootNode === "function" ? candidate : null;
|
|
9
|
+
}
|
|
10
|
+
function readBoolean(source, name, fallback) {
|
|
11
|
+
const value = toValue(source);
|
|
12
|
+
if (value === void 0) return fallback;
|
|
13
|
+
if (typeof value !== "boolean") throw new TypeError(`${optionDiagnostic}: ${name} must resolve to a boolean`);
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
function readRoot(source) {
|
|
17
|
+
const value = toValue(source);
|
|
18
|
+
if (value === void 0 || value === null) return null;
|
|
19
|
+
const candidate = value;
|
|
20
|
+
if (candidate.nodeType !== 1 || !candidate.ownerDocument) throw new TypeError(`${rootDiagnostic}: root must resolve to an Element or null`);
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
function readBranches(source, document) {
|
|
24
|
+
const value = toValue(source) ?? [];
|
|
25
|
+
if (!Array.isArray(value)) throw new TypeError(`${optionDiagnostic}: branches must resolve to an array of Elements`);
|
|
26
|
+
return validateBranches(value, document);
|
|
27
|
+
}
|
|
28
|
+
function validateBranches(source, document) {
|
|
29
|
+
const unique = [...new Set(source)];
|
|
30
|
+
for (const branch of unique) {
|
|
31
|
+
const candidate = branch;
|
|
32
|
+
if (candidate.nodeType !== 1 || !candidate.ownerDocument) throw new TypeError(`${optionDiagnostic}: branches must contain only Elements`);
|
|
33
|
+
if (document && candidate.ownerDocument !== document) throw new TypeError(`${optionDiagnostic}: branches must share the root Document`);
|
|
34
|
+
}
|
|
35
|
+
return unique;
|
|
36
|
+
}
|
|
37
|
+
function validateOptions(options) {
|
|
38
|
+
if (!options || typeof options !== "object" || Array.isArray(options)) throw new TypeError(`${optionDiagnostic}: options must be an object`);
|
|
39
|
+
const root = readRoot(options.root);
|
|
40
|
+
readBranches(options.branches, root?.ownerDocument ?? null);
|
|
41
|
+
readBoolean(options.enabled, "enabled", true);
|
|
42
|
+
readBoolean(options.outsidePointerDown, "outsidePointerDown", true);
|
|
43
|
+
readBoolean(options.outsideFocus, "outsideFocus", true);
|
|
44
|
+
readBoolean(options.escapeKey, "escapeKey", true);
|
|
45
|
+
for (const name of [
|
|
46
|
+
"onPointerDownOutside",
|
|
47
|
+
"onFocusOutside",
|
|
48
|
+
"onInteractOutside",
|
|
49
|
+
"onEscapeKeyDown",
|
|
50
|
+
"onDismiss"
|
|
51
|
+
]) if (options[name] !== void 0 && typeof options[name] !== "function") throw new TypeError(`${optionDiagnostic}: ${name} must be a function`);
|
|
52
|
+
}
|
|
53
|
+
function modifier(event, key) {
|
|
54
|
+
return key in event ? Boolean(event[key]) : false;
|
|
55
|
+
}
|
|
56
|
+
function eventPoint(event) {
|
|
57
|
+
if ("clientX" in event && "clientY" in event) return {
|
|
58
|
+
x: Number(event.clientX),
|
|
59
|
+
y: Number(event.clientY)
|
|
60
|
+
};
|
|
61
|
+
if ("changedTouches" in event) {
|
|
62
|
+
const touch = Array.from(event.changedTouches)[0];
|
|
63
|
+
if (touch) return {
|
|
64
|
+
x: touch.clientX,
|
|
65
|
+
y: touch.clientY
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
function pointerTypeOf(event) {
|
|
71
|
+
if ("changedTouches" in event) return "touch";
|
|
72
|
+
if ("pointerType" in event) {
|
|
73
|
+
if (event.pointerId === -1 && event.pointerType === "") return "virtual";
|
|
74
|
+
if (event.pointerType === "mouse" || event.pointerType === "pen") return event.pointerType;
|
|
75
|
+
if (event.pointerType === "touch") return "touch";
|
|
76
|
+
return "pointer";
|
|
77
|
+
}
|
|
78
|
+
return "mouse";
|
|
79
|
+
}
|
|
80
|
+
function preventable() {
|
|
81
|
+
let prevented = false;
|
|
82
|
+
return {
|
|
83
|
+
get defaultPrevented() {
|
|
84
|
+
return prevented;
|
|
85
|
+
},
|
|
86
|
+
preventDefault: () => {
|
|
87
|
+
prevented = true;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/** Build an immutable outside pointer event that is stable after native dispatch mutates. */
|
|
92
|
+
function createPointerDownOutsideEvent(originalEvent, target) {
|
|
93
|
+
const point = eventPoint(originalEvent);
|
|
94
|
+
const prevention = preventable();
|
|
95
|
+
return Object.freeze({
|
|
96
|
+
type: "pointer-down-outside",
|
|
97
|
+
reason: "pointer-down-outside",
|
|
98
|
+
target,
|
|
99
|
+
originalEvent,
|
|
100
|
+
pointerType: pointerTypeOf(originalEvent),
|
|
101
|
+
x: point?.x ?? null,
|
|
102
|
+
y: point?.y ?? null,
|
|
103
|
+
altKey: modifier(originalEvent, "altKey"),
|
|
104
|
+
ctrlKey: modifier(originalEvent, "ctrlKey"),
|
|
105
|
+
metaKey: modifier(originalEvent, "metaKey"),
|
|
106
|
+
shiftKey: modifier(originalEvent, "shiftKey"),
|
|
107
|
+
get defaultPrevented() {
|
|
108
|
+
return prevention.defaultPrevented;
|
|
109
|
+
},
|
|
110
|
+
preventDefault: prevention.preventDefault
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
/** Build an immutable outside focus event that preserves related-target evidence. */
|
|
114
|
+
function createFocusOutsideEvent(originalEvent, target) {
|
|
115
|
+
const prevention = preventable();
|
|
116
|
+
return Object.freeze({
|
|
117
|
+
type: "focus-outside",
|
|
118
|
+
reason: "focus-outside",
|
|
119
|
+
target,
|
|
120
|
+
relatedTarget: eventElement(originalEvent.relatedTarget),
|
|
121
|
+
originalEvent,
|
|
122
|
+
get defaultPrevented() {
|
|
123
|
+
return prevention.defaultPrevented;
|
|
124
|
+
},
|
|
125
|
+
preventDefault: prevention.preventDefault
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
/** Build an immutable Escape event before dismissal is committed. */
|
|
129
|
+
function createEscapeKeyDownEvent(originalEvent, target) {
|
|
130
|
+
const prevention = preventable();
|
|
131
|
+
return Object.freeze({
|
|
132
|
+
type: "escape-key",
|
|
133
|
+
reason: "escape-key",
|
|
134
|
+
target,
|
|
135
|
+
originalEvent,
|
|
136
|
+
altKey: modifier(originalEvent, "altKey"),
|
|
137
|
+
ctrlKey: modifier(originalEvent, "ctrlKey"),
|
|
138
|
+
metaKey: modifier(originalEvent, "metaKey"),
|
|
139
|
+
shiftKey: modifier(originalEvent, "shiftKey"),
|
|
140
|
+
get defaultPrevented() {
|
|
141
|
+
return prevention.defaultPrevented;
|
|
142
|
+
},
|
|
143
|
+
preventDefault: prevention.preventDefault
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
/** Build the final immutable dismissal notification. */
|
|
147
|
+
function createDismissEvent(reason, originalEvent, target) {
|
|
148
|
+
return Object.freeze({
|
|
149
|
+
type: "dismiss",
|
|
150
|
+
reason,
|
|
151
|
+
target,
|
|
152
|
+
originalEvent
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
//#endregion
|
|
156
|
+
//#region src/dismissable-layer-stack.ts
|
|
157
|
+
const documentStates = /* @__PURE__ */ new WeakMap();
|
|
158
|
+
function composedParent(element) {
|
|
159
|
+
if (element.assignedSlot) return element.assignedSlot;
|
|
160
|
+
if (element.parentElement) return element.parentElement;
|
|
161
|
+
return element.getRootNode().host ?? null;
|
|
162
|
+
}
|
|
163
|
+
function containsComposed(root, element) {
|
|
164
|
+
let current = element;
|
|
165
|
+
while (current) {
|
|
166
|
+
if (root === current || root.contains(current)) return true;
|
|
167
|
+
current = composedParent(current);
|
|
168
|
+
}
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
function stackFor(document) {
|
|
172
|
+
let state = documentStates.get(document);
|
|
173
|
+
if (!state) {
|
|
174
|
+
state = {
|
|
175
|
+
document,
|
|
176
|
+
lastPointerTime: Number.NEGATIVE_INFINITY,
|
|
177
|
+
observer: null,
|
|
178
|
+
queued: false,
|
|
179
|
+
releaseListeners: [],
|
|
180
|
+
tokens: []
|
|
181
|
+
};
|
|
182
|
+
documentStates.set(document, state);
|
|
183
|
+
}
|
|
184
|
+
return state;
|
|
185
|
+
}
|
|
186
|
+
function rootsFor(token) {
|
|
187
|
+
const root = token.root;
|
|
188
|
+
if (!root?.isConnected || !token.readEnabled()) return [];
|
|
189
|
+
return [...new Set([root, ...token.readBranches()])].filter((branch) => branch.isConnected);
|
|
190
|
+
}
|
|
191
|
+
function topLayer(state) {
|
|
192
|
+
for (let index = state.tokens.length - 1; index >= 0; index--) {
|
|
193
|
+
const token = state.tokens[index];
|
|
194
|
+
if (token && rootsFor(token).length > 0) return token;
|
|
195
|
+
}
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
function targetElement(event) {
|
|
199
|
+
const path = typeof event.composedPath === "function" ? event.composedPath() : [];
|
|
200
|
+
for (const item of path) {
|
|
201
|
+
const element = item;
|
|
202
|
+
if (element.nodeType === 1 && typeof element.getRootNode === "function") return element;
|
|
203
|
+
}
|
|
204
|
+
const target = event.target;
|
|
205
|
+
return target?.nodeType === 1 && typeof target.getRootNode === "function" ? target : null;
|
|
206
|
+
}
|
|
207
|
+
function eventInside(event, target, roots) {
|
|
208
|
+
const path = typeof event.composedPath === "function" ? event.composedPath() : [];
|
|
209
|
+
return roots.some((root) => path.includes(root) || containsComposed(root, target));
|
|
210
|
+
}
|
|
211
|
+
function recomputeDismissableLayers(document) {
|
|
212
|
+
const state = stackFor(document);
|
|
213
|
+
const owner = topLayer(state);
|
|
214
|
+
for (const token of state.tokens) token.setTopLayer(token === owner);
|
|
215
|
+
}
|
|
216
|
+
function routePointerDown(state, event) {
|
|
217
|
+
if (event.defaultPrevented) return;
|
|
218
|
+
const owner = topLayer(state);
|
|
219
|
+
if (!owner?.readOutsidePointerDown()) return;
|
|
220
|
+
const target = targetElement(event);
|
|
221
|
+
if (!target || eventInside(event, target, rootsFor(owner))) return;
|
|
222
|
+
owner.handlePointerDownOutside(event, target);
|
|
223
|
+
}
|
|
224
|
+
function routeFocusIn(state, event) {
|
|
225
|
+
const owner = topLayer(state);
|
|
226
|
+
if (!owner?.readOutsideFocus()) return;
|
|
227
|
+
const target = targetElement(event);
|
|
228
|
+
if (!target || eventInside(event, target, rootsFor(owner))) return;
|
|
229
|
+
owner.handleFocusOutside(event, target);
|
|
230
|
+
}
|
|
231
|
+
function routeEscape(state, event) {
|
|
232
|
+
if (event.key !== "Escape" || event.defaultPrevented || event.isComposing) return;
|
|
233
|
+
const owner = topLayer(state);
|
|
234
|
+
if (!owner?.readEscapeKey()) return;
|
|
235
|
+
owner.handleEscapeKeyDown(event, targetElement(event));
|
|
236
|
+
}
|
|
237
|
+
function observe(state) {
|
|
238
|
+
if (state.observer) return;
|
|
239
|
+
const Observer = state.document.defaultView?.MutationObserver;
|
|
240
|
+
const root = state.document.documentElement;
|
|
241
|
+
if (!Observer || !root) return;
|
|
242
|
+
state.observer = new Observer(() => {
|
|
243
|
+
if (state.queued) return;
|
|
244
|
+
state.queued = true;
|
|
245
|
+
queueMicrotask(() => {
|
|
246
|
+
state.queued = false;
|
|
247
|
+
if (state.tokens.length > 0) recomputeDismissableLayers(state.document);
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
state.observer.observe(root, {
|
|
251
|
+
childList: true,
|
|
252
|
+
subtree: true
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
function addDocumentListeners(state) {
|
|
256
|
+
if (state.releaseListeners.length > 0) return;
|
|
257
|
+
const document = state.document;
|
|
258
|
+
const listen = (type, callback, options) => {
|
|
259
|
+
document.addEventListener(type, callback, options);
|
|
260
|
+
state.releaseListeners.push(() => document.removeEventListener(type, callback, options));
|
|
261
|
+
};
|
|
262
|
+
listen("pointerdown", ((event) => {
|
|
263
|
+
state.lastPointerTime = event.timeStamp;
|
|
264
|
+
routePointerDown(state, event);
|
|
265
|
+
}), true);
|
|
266
|
+
listen("mousedown", ((event) => {
|
|
267
|
+
const view = document.defaultView;
|
|
268
|
+
const elapsed = event.timeStamp - state.lastPointerTime;
|
|
269
|
+
if (view && "PointerEvent" in view && elapsed >= 0 && elapsed < 800) return;
|
|
270
|
+
routePointerDown(state, event);
|
|
271
|
+
}), true);
|
|
272
|
+
listen("touchstart", ((event) => {
|
|
273
|
+
const view = document.defaultView;
|
|
274
|
+
if (view && "PointerEvent" in view) return;
|
|
275
|
+
routePointerDown(state, event);
|
|
276
|
+
}), true);
|
|
277
|
+
listen("focusin", ((event) => routeFocusIn(state, event)), true);
|
|
278
|
+
listen("keydown", ((event) => routeEscape(state, event)));
|
|
279
|
+
}
|
|
280
|
+
function removeDocumentListeners(state) {
|
|
281
|
+
for (const release of state.releaseListeners.splice(0)) release();
|
|
282
|
+
}
|
|
283
|
+
function attachDismissableLayer(token, root) {
|
|
284
|
+
if (token.document === root.ownerDocument) {
|
|
285
|
+
token.root = root;
|
|
286
|
+
recomputeDismissableLayers(root.ownerDocument);
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
detachDismissableLayer(token);
|
|
290
|
+
const state = stackFor(root.ownerDocument);
|
|
291
|
+
const wasEmpty = state.tokens.length === 0;
|
|
292
|
+
token.document = root.ownerDocument;
|
|
293
|
+
token.root = root;
|
|
294
|
+
state.tokens.push(token);
|
|
295
|
+
if (wasEmpty) {
|
|
296
|
+
addDocumentListeners(state);
|
|
297
|
+
observe(state);
|
|
298
|
+
}
|
|
299
|
+
recomputeDismissableLayers(root.ownerDocument);
|
|
300
|
+
}
|
|
301
|
+
function detachDismissableLayer(token) {
|
|
302
|
+
const document = token.document;
|
|
303
|
+
if (!document) {
|
|
304
|
+
token.root = null;
|
|
305
|
+
token.setTopLayer(false);
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
const state = stackFor(document);
|
|
309
|
+
const index = state.tokens.indexOf(token);
|
|
310
|
+
if (index >= 0) state.tokens.splice(index, 1);
|
|
311
|
+
token.document = null;
|
|
312
|
+
token.root = null;
|
|
313
|
+
token.setTopLayer(false);
|
|
314
|
+
if (state.tokens.length === 0) {
|
|
315
|
+
removeDocumentListeners(state);
|
|
316
|
+
state.observer?.disconnect();
|
|
317
|
+
state.observer = null;
|
|
318
|
+
documentStates.delete(document);
|
|
319
|
+
} else recomputeDismissableLayers(document);
|
|
320
|
+
}
|
|
321
|
+
function refreshDismissableLayer(token) {
|
|
322
|
+
if (token.document) recomputeDismissableLayers(token.document);
|
|
323
|
+
}
|
|
324
|
+
//#endregion
|
|
325
|
+
//#region src/dismissable-layer.ts
|
|
326
|
+
const disposedDiagnostic = "VIZE_UI_DISMISSABLE_LAYER_DISPOSED";
|
|
327
|
+
const setupDiagnostic = "VIZE_UI_DISMISSABLE_LAYER_SETUP";
|
|
328
|
+
function capture(errors, callback) {
|
|
329
|
+
try {
|
|
330
|
+
callback();
|
|
331
|
+
} catch (error) {
|
|
332
|
+
errors.push(error);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
function surfaceErrors(errors, message) {
|
|
336
|
+
if (errors.length === 1) throw errors[0];
|
|
337
|
+
if (errors.length < 2) return;
|
|
338
|
+
throw new AggregateError(errors, message);
|
|
339
|
+
}
|
|
340
|
+
/** Create an SSR-safe, document-scoped dismissal layer for overlays and popups. */
|
|
341
|
+
function createDismissableLayer(options) {
|
|
342
|
+
validateOptions(options);
|
|
343
|
+
const activeState = shallowRef(false);
|
|
344
|
+
const topLayerState = shallowRef(false);
|
|
345
|
+
const registeredBranches = /* @__PURE__ */ new Set();
|
|
346
|
+
const token = {
|
|
347
|
+
document: null,
|
|
348
|
+
root: null,
|
|
349
|
+
readBranches: () => readAllBranches(token.document),
|
|
350
|
+
readEnabled: () => readBoolean(options.enabled, "enabled", true),
|
|
351
|
+
readEscapeKey: () => readBoolean(options.escapeKey, "escapeKey", true),
|
|
352
|
+
readOutsideFocus: () => readBoolean(options.outsideFocus, "outsideFocus", true),
|
|
353
|
+
readOutsidePointerDown: () => readBoolean(options.outsidePointerDown, "outsidePointerDown", true),
|
|
354
|
+
handleEscapeKeyDown: (originalEvent, target) => {
|
|
355
|
+
const event = createEscapeKeyDownEvent(originalEvent, target);
|
|
356
|
+
const errors = [];
|
|
357
|
+
capture(errors, () => options.onEscapeKeyDown?.(event));
|
|
358
|
+
dismissIfAllowed(errors, event.defaultPrevented, "escape-key", originalEvent, target);
|
|
359
|
+
surfaceErrors(errors, "Dismissable layer Escape callbacks failed");
|
|
360
|
+
},
|
|
361
|
+
handleFocusOutside: (originalEvent, target) => {
|
|
362
|
+
const event = createFocusOutsideEvent(originalEvent, target);
|
|
363
|
+
const errors = [];
|
|
364
|
+
capture(errors, () => options.onFocusOutside?.(event));
|
|
365
|
+
notifyOutside(errors, event);
|
|
366
|
+
dismissIfAllowed(errors, event.defaultPrevented, "focus-outside", originalEvent, target);
|
|
367
|
+
surfaceErrors(errors, "Dismissable layer focus callbacks failed");
|
|
368
|
+
},
|
|
369
|
+
handlePointerDownOutside: (originalEvent, target) => {
|
|
370
|
+
const event = createPointerDownOutsideEvent(originalEvent, target);
|
|
371
|
+
const errors = [];
|
|
372
|
+
capture(errors, () => options.onPointerDownOutside?.(event));
|
|
373
|
+
notifyOutside(errors, event);
|
|
374
|
+
dismissIfAllowed(errors, event.defaultPrevented, "pointer-down-outside", originalEvent, target);
|
|
375
|
+
surfaceErrors(errors, "Dismissable layer pointer callbacks failed");
|
|
376
|
+
},
|
|
377
|
+
setTopLayer: (value) => {
|
|
378
|
+
topLayerState.value = value;
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
let disposed = false;
|
|
382
|
+
const assertAlive = () => {
|
|
383
|
+
if (disposed) throw new Error(`${disposedDiagnostic}: the controller has been disposed`);
|
|
384
|
+
};
|
|
385
|
+
const readAllBranches = (document) => {
|
|
386
|
+
const reactiveBranches = readBranches(options.branches, document);
|
|
387
|
+
const imperativeBranches = validateBranches([...registeredBranches], document);
|
|
388
|
+
return [...new Set([...reactiveBranches, ...imperativeBranches])];
|
|
389
|
+
};
|
|
390
|
+
const notifyOutside = (errors, event) => {
|
|
391
|
+
capture(errors, () => options.onInteractOutside?.(event));
|
|
392
|
+
};
|
|
393
|
+
const dismissIfAllowed = (errors, defaultPrevented, reason, originalEvent, target) => {
|
|
394
|
+
if (errors.length > 0 || defaultPrevented) return;
|
|
395
|
+
capture(errors, () => options.onDismiss?.(createDismissEvent(reason, originalEvent, target)));
|
|
396
|
+
};
|
|
397
|
+
const refresh = () => {
|
|
398
|
+
assertAlive();
|
|
399
|
+
if (!activeState.value) return;
|
|
400
|
+
const nextRoot = readRoot(options.root);
|
|
401
|
+
readBoolean(options.enabled, "enabled", true);
|
|
402
|
+
readBoolean(options.escapeKey, "escapeKey", true);
|
|
403
|
+
readBoolean(options.outsideFocus, "outsideFocus", true);
|
|
404
|
+
readBoolean(options.outsidePointerDown, "outsidePointerDown", true);
|
|
405
|
+
readAllBranches(nextRoot?.ownerDocument ?? null);
|
|
406
|
+
if (nextRoot !== token.root) if (nextRoot) attachDismissableLayer(token, nextRoot);
|
|
407
|
+
else detachDismissableLayer(token);
|
|
408
|
+
else refreshDismissableLayer(token);
|
|
409
|
+
};
|
|
410
|
+
const activate = () => {
|
|
411
|
+
assertAlive();
|
|
412
|
+
if (activeState.value) return;
|
|
413
|
+
activeState.value = true;
|
|
414
|
+
try {
|
|
415
|
+
refresh();
|
|
416
|
+
} catch (error) {
|
|
417
|
+
activeState.value = false;
|
|
418
|
+
detachDismissableLayer(token);
|
|
419
|
+
throw error;
|
|
420
|
+
}
|
|
421
|
+
};
|
|
422
|
+
const deactivate = () => {
|
|
423
|
+
assertAlive();
|
|
424
|
+
if (!activeState.value) return;
|
|
425
|
+
try {
|
|
426
|
+
detachDismissableLayer(token);
|
|
427
|
+
} finally {
|
|
428
|
+
activeState.value = false;
|
|
429
|
+
}
|
|
430
|
+
};
|
|
431
|
+
const stopWatch = watch(() => [
|
|
432
|
+
toValue(options.root),
|
|
433
|
+
toValue(options.branches),
|
|
434
|
+
toValue(options.enabled),
|
|
435
|
+
toValue(options.escapeKey),
|
|
436
|
+
toValue(options.outsideFocus),
|
|
437
|
+
toValue(options.outsidePointerDown)
|
|
438
|
+
], () => {
|
|
439
|
+
if (activeState.value) refresh();
|
|
440
|
+
}, { flush: "sync" });
|
|
441
|
+
const registerBranch = (branch) => {
|
|
442
|
+
assertAlive();
|
|
443
|
+
validateBranches([branch], token.document);
|
|
444
|
+
registeredBranches.add(branch);
|
|
445
|
+
if (activeState.value) refresh();
|
|
446
|
+
let released = false;
|
|
447
|
+
return () => {
|
|
448
|
+
if (released) return;
|
|
449
|
+
released = true;
|
|
450
|
+
registeredBranches.delete(branch);
|
|
451
|
+
if (!disposed && activeState.value) refresh();
|
|
452
|
+
};
|
|
453
|
+
};
|
|
454
|
+
const layerProps = Object.freeze({ "data-vize-dismissable-layer": "" });
|
|
455
|
+
const branchProps = Object.freeze({ "data-vize-dismissable-branch": "" });
|
|
456
|
+
return Object.freeze({
|
|
457
|
+
isActive: shallowReadonly(activeState),
|
|
458
|
+
isTopLayer: shallowReadonly(topLayerState),
|
|
459
|
+
layerProps,
|
|
460
|
+
branchProps,
|
|
461
|
+
registerBranch,
|
|
462
|
+
activate,
|
|
463
|
+
deactivate,
|
|
464
|
+
refresh,
|
|
465
|
+
dispose: () => {
|
|
466
|
+
if (disposed) return;
|
|
467
|
+
try {
|
|
468
|
+
detachDismissableLayer(token);
|
|
469
|
+
} finally {
|
|
470
|
+
activeState.value = false;
|
|
471
|
+
disposed = true;
|
|
472
|
+
registeredBranches.clear();
|
|
473
|
+
stopWatch();
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
/** Create, mount-activate, and scope-dispose a dismissable overlay layer. */
|
|
479
|
+
function useDismissableLayer(options) {
|
|
480
|
+
if (!getCurrentScope()) throw new Error(`${setupDiagnostic}: use inside component setup or an active effect scope`);
|
|
481
|
+
const controller = createDismissableLayer(options);
|
|
482
|
+
if (getCurrentInstance()) onMounted(controller.activate);
|
|
483
|
+
else controller.activate();
|
|
484
|
+
onScopeDispose(controller.dispose);
|
|
485
|
+
return controller;
|
|
486
|
+
}
|
|
487
|
+
//#endregion
|
|
488
|
+
export { useDismissableLayer as n, createDismissableLayer as t };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as DismissableLayerDismissEvent, c as DismissableLayerFocusOutsideEvent, d as DismissableLayerOutsideReason, f as DismissableLayerPointerDownOutsideEvent, i as DismissableLayerController, l as DismissableLayerInteractOutsideEvent, m as DismissableLayerProps, n as useDismissableLayer, o as DismissableLayerDismissReason, p as DismissableLayerPointerType, r as DismissableLayerBranchProps, s as DismissableLayerEscapeKeyDownEvent, t as createDismissableLayer, u as DismissableLayerOptions } from "./dismissable-layer-4icKahVs.mjs";
|
|
2
|
+
export { type DismissableLayerBranchProps, type DismissableLayerController, type DismissableLayerDismissEvent, type DismissableLayerDismissReason, type DismissableLayerEscapeKeyDownEvent, type DismissableLayerFocusOutsideEvent, type DismissableLayerInteractOutsideEvent, type DismissableLayerOptions, type DismissableLayerOutsideReason, type DismissableLayerPointerDownOutsideEvent, type DismissableLayerPointerType, type DismissableLayerProps, createDismissableLayer, useDismissableLayer };
|