@eodash/eodash 5.0.0-alpha.2.9 → 5.0.0-rc
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/README.md +1 -1
- package/core/client/App.vue +13 -1
- package/core/client/asWebComponent.js +13 -4
- package/core/client/components/DashboardLayout.vue +36 -14
- package/core/client/components/Loading.vue +6 -9
- package/core/client/components/MobileLayout.vue +16 -14
- package/core/client/composables/DefineEodash.js +14 -4
- package/core/client/composables/DefineTemplate.js +67 -0
- package/core/client/composables/DefineWidgets.js +3 -2
- package/core/client/composables/EodashMap.js +360 -0
- package/core/client/composables/EodashProcess.js +574 -0
- package/core/client/composables/index.js +136 -28
- package/core/client/eodash.js +395 -80
- package/core/client/eodashSTAC/EodashCollection.js +432 -0
- package/core/client/eodashSTAC/createLayers.js +315 -0
- package/core/client/eodashSTAC/helpers.js +375 -0
- package/core/client/eodashSTAC/triggers.js +43 -0
- package/core/client/plugins/axios.js +8 -0
- package/core/client/plugins/index.js +2 -1
- package/core/client/plugins/vuetify.js +2 -1
- package/core/client/store/actions.js +79 -0
- package/core/client/store/index.js +4 -18
- package/core/client/store/stac.js +99 -9
- package/core/client/store/states.js +37 -0
- package/core/client/{types.d.ts → types.ts} +66 -20
- package/core/client/utils/keys.js +2 -0
- package/core/client/utils/states.js +22 -0
- package/core/client/views/Dashboard.vue +22 -49
- package/core/client/vite-env.d.ts +2 -10
- package/dist/client/DashboardLayout-232tRmjz.js +84 -0
- package/dist/client/DynamicWebComponent-Cl4LqHU6.js +88 -0
- package/dist/client/EodashDatePicker-Pok6bZwU.js +306 -0
- package/dist/client/EodashItemFilter-16eMMjTV.js +151 -0
- package/dist/client/EodashLayerControl-De7IlCm_.js +120 -0
- package/dist/client/EodashLayoutSwitcher-C-3-jjn5.js +52 -0
- package/dist/client/EodashMap-CMvbfI6-.js +549 -0
- package/dist/client/EodashMapBtns-BeknGDtc.js +107 -0
- package/dist/client/EodashProcess-BwKAa9Ee.js +1476 -0
- package/dist/client/EodashStacInfo-_BfonNUG.js +85 -0
- package/dist/client/EodashTools-PD3XPYuR.js +103 -0
- package/dist/client/ExportState-DOrT7M15.js +644 -0
- package/dist/client/Footer-CCigxYBo.js +141 -0
- package/dist/client/Header-C2cdx4gb.js +437 -0
- package/dist/client/IframeWrapper-BgM9aU8f.js +28 -0
- package/dist/client/MobileLayout-BdiFjHg7.js +1207 -0
- package/dist/client/PopUp--_xn1Cms.js +410 -0
- package/dist/client/VImg-9xu2l99m.js +384 -0
- package/dist/client/VMain-BUs3kDTd.js +43 -0
- package/dist/client/VOverlay-D89omJis.js +1453 -0
- package/dist/client/VTooltip-CDu3bErh.js +86 -0
- package/dist/client/WidgetsContainer-aFG9yFT6.js +83 -0
- package/dist/client/asWebComponent-BRGyP_j5.js +11943 -0
- package/dist/client/{style.css → eo-dash.css} +2 -2
- package/dist/client/eo-dash.js +2 -6
- package/dist/client/forwardRefs-CYrR6bMw.js +245 -0
- package/dist/client/index-BZwk0V42.js +199 -0
- package/dist/client/ssrBoot-BP7SYRyC.js +22 -0
- package/dist/client/transition-DG9nRSW4.js +37 -0
- package/dist/node/cli.js +4 -4
- package/dist/node/types.d.ts +2 -0
- package/package.json +73 -38
- package/widgets/EodashDatePicker.vue +176 -134
- package/widgets/EodashItemFilter.vue +79 -38
- package/widgets/EodashLayerControl.vue +111 -0
- package/widgets/EodashLayoutSwitcher.vue +36 -0
- package/widgets/EodashMap.vue +108 -133
- package/widgets/EodashMapBtns.vue +62 -8
- package/widgets/EodashProcess.vue +143 -0
- package/widgets/EodashStacInfo.vue +82 -0
- package/widgets/EodashTools.vue +83 -0
- package/widgets/ExportState.vue +17 -13
- package/widgets/PopUp.vue +24 -2
- package/core/client/SuspensedDashboard.ce.vue +0 -105
- package/core/client/asWebComponent.d.ts +0 -23
- package/core/client/store/Actions.js +0 -14
- package/core/client/store/States.js +0 -16
- package/core/client/utils/eodashSTAC.js +0 -249
- package/core/client/utils/helpers.js +0 -38
- package/dist/client/DashboardLayout-D0ZF6V2S.js +0 -156
- package/dist/client/DynamicWebComponent-CPsMSBHi.js +0 -57
- package/dist/client/EodashDatePicker-CBQP7u2X.js +0 -252
- package/dist/client/EodashItemFilter-DL2ScI-5.js +0 -7671
- package/dist/client/EodashMap-CkKoQlmR.js +0 -86917
- package/dist/client/EodashMapBtns-yuO2QmiR.js +0 -36
- package/dist/client/ExportState-CCzOhppU.js +0 -558
- package/dist/client/Footer-BPAND0yG.js +0 -115
- package/dist/client/Header-DLhebNvG.js +0 -350
- package/dist/client/IframeWrapper-1GEMHlsW.js +0 -19
- package/dist/client/MobileLayout-mGkOYRhu.js +0 -945
- package/dist/client/PopUp-1d2bBFjw.js +0 -300
- package/dist/client/VImg-DxHcztfM.js +0 -291
- package/dist/client/VMain-BLX5vRRn.js +0 -39
- package/dist/client/VOverlay-CvrYEmLu.js +0 -967
- package/dist/client/WidgetsContainer-CmYjvGm7.js +0 -129
- package/dist/client/_commonjsHelpers-DaMA6jEr.js +0 -8
- package/dist/client/asWebComponent-B91uK0U7.js +0 -20361
- package/dist/client/basedecoder-DHcBySSe-BmCFNFnw.js +0 -88
- package/dist/client/decoder-CP4lv0Kb-B6yqkcfC.js +0 -10
- package/dist/client/deflate-BXt-9JA_-CWfClgpK.js +0 -10
- package/dist/client/eodashSTAC-DBjqe_Ho.js +0 -2788
- package/dist/client/eox-stacinfo-l7ALSV90.js +0 -13969
- package/dist/client/forwardRefs-BJJiadQP.js +0 -185
- package/dist/client/index-Q-bHLjxx.js +0 -153
- package/dist/client/jpeg-BAgeD1d3-oeHbFPUL.js +0 -514
- package/dist/client/lerc-DzVumYtB-P-KXC0TO.js +0 -1027
- package/dist/client/lzw-LAGDNbSC-DkP96qO9.js +0 -84
- package/dist/client/packbits-BlDR4Kj5-C66n1-zr.js +0 -24
- package/dist/client/pako.esm-CB1uQYY0-DB0PYm1P.js +0 -1081
- package/dist/client/raw-CMGvRjfu-BRi6E4i1.js +0 -9
- package/dist/client/ssrBoot-yo11mybw.js +0 -17
- package/dist/client/transition-CSJhuYGK.js +0 -34
- package/dist/client/webfontloader-qotgY98I.js +0 -435
- package/dist/client/webimage-BM_pbLN3-L2cGWK5l.js +0 -19
|
@@ -0,0 +1,1453 @@
|
|
|
1
|
+
import { ref, watch, onScopeDispose, computed, nextTick, watchEffect, effectScope, inject, mergeProps, shallowRef, onMounted, reactive, provide, readonly, toRaw, warn, toRef, onBeforeUnmount, createVNode, Fragment, Teleport, withDirectives, vShow, resolveDirective, Transition } from 'vue';
|
|
2
|
+
import { aJ as isOn, aK as eventName, p as propsFactory, x as IN_BROWSER, U as useToggleScope, aL as destructComputed, aM as parseAnchor, aN as flipSide, aO as flipAlign, aP as flipCorner, Y as consoleError, aQ as getAxis, q as convertToUnit, R as clamp, aR as defer, aH as getCurrentInstance, aS as templateRef, aT as matchesSelector, t as useDisplay, b as makeComponentProps, H as makeDimensionProps, d as makeThemeProps, g as genericComponent, j as useProxiedModel, e as provideTheme, f as useRtl, C as useBackgroundColor, J as useDimension, aU as useRouter, a as useRender, aV as useBackButton } from './asWebComponent-BRGyP_j5.js';
|
|
3
|
+
import { g as getTargetBox, B as Box, e as getOverflow, n as nullifyTransforms, m as makeLazyProps, u as useLazy, b as useScopeId, a as animate, s as standardEasing } from './forwardRefs-CYrR6bMw.js';
|
|
4
|
+
import { m as makeTransitionProps, M as MaybeTransition } from './transition-DG9nRSW4.js';
|
|
5
|
+
|
|
6
|
+
// Utilities
|
|
7
|
+
const handlers = new WeakMap();
|
|
8
|
+
function bindProps(el, props) {
|
|
9
|
+
Object.keys(props).forEach(k => {
|
|
10
|
+
if (isOn(k)) {
|
|
11
|
+
const name = eventName(k);
|
|
12
|
+
const handler = handlers.get(el);
|
|
13
|
+
if (props[k] == null) {
|
|
14
|
+
handler?.forEach(v => {
|
|
15
|
+
const [n, fn] = v;
|
|
16
|
+
if (n === name) {
|
|
17
|
+
el.removeEventListener(name, fn);
|
|
18
|
+
handler.delete(v);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
} else if (!handler || ![...handler]?.some(v => v[0] === name && v[1] === props[k])) {
|
|
22
|
+
el.addEventListener(name, props[k]);
|
|
23
|
+
const _handler = handler || new Set();
|
|
24
|
+
_handler.add([name, props[k]]);
|
|
25
|
+
if (!handlers.has(el)) handlers.set(el, _handler);
|
|
26
|
+
}
|
|
27
|
+
} else {
|
|
28
|
+
if (props[k] == null) {
|
|
29
|
+
el.removeAttribute(k);
|
|
30
|
+
} else {
|
|
31
|
+
el.setAttribute(k, props[k]);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function unbindProps(el, props) {
|
|
37
|
+
Object.keys(props).forEach(k => {
|
|
38
|
+
if (isOn(k)) {
|
|
39
|
+
const name = eventName(k);
|
|
40
|
+
const handler = handlers.get(el);
|
|
41
|
+
handler?.forEach(v => {
|
|
42
|
+
const [n, fn] = v;
|
|
43
|
+
if (n === name) {
|
|
44
|
+
el.removeEventListener(name, fn);
|
|
45
|
+
handler.delete(v);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
} else {
|
|
49
|
+
el.removeAttribute(k);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Returns:
|
|
56
|
+
* - 'null' if the node is not attached to the DOM
|
|
57
|
+
* - the root node (HTMLDocument | ShadowRoot) otherwise
|
|
58
|
+
*/
|
|
59
|
+
function attachedRoot(node) {
|
|
60
|
+
/* istanbul ignore next */
|
|
61
|
+
if (typeof node.getRootNode !== 'function') {
|
|
62
|
+
// Shadow DOM not supported (IE11), lets find the root of this node
|
|
63
|
+
while (node.parentNode) node = node.parentNode;
|
|
64
|
+
|
|
65
|
+
// The root parent is the document if the node is attached to the DOM
|
|
66
|
+
if (node !== document) return null;
|
|
67
|
+
return document;
|
|
68
|
+
}
|
|
69
|
+
const root = node.getRootNode();
|
|
70
|
+
|
|
71
|
+
// The composed root node is the document if the node is attached to the DOM
|
|
72
|
+
if (root !== document && root.getRootNode({
|
|
73
|
+
composed: true
|
|
74
|
+
}) !== document) return null;
|
|
75
|
+
return root;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function getScrollParent(el) {
|
|
79
|
+
let includeHidden = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
80
|
+
while (el) {
|
|
81
|
+
if (includeHidden ? isPotentiallyScrollable(el) : hasScrollbar(el)) return el;
|
|
82
|
+
el = el.parentElement;
|
|
83
|
+
}
|
|
84
|
+
return document.scrollingElement;
|
|
85
|
+
}
|
|
86
|
+
function getScrollParents(el, stopAt) {
|
|
87
|
+
const elements = [];
|
|
88
|
+
if (stopAt && el && !stopAt.contains(el)) return elements;
|
|
89
|
+
while (el) {
|
|
90
|
+
if (hasScrollbar(el)) elements.push(el);
|
|
91
|
+
if (el === stopAt) break;
|
|
92
|
+
el = el.parentElement;
|
|
93
|
+
}
|
|
94
|
+
return elements;
|
|
95
|
+
}
|
|
96
|
+
function hasScrollbar(el) {
|
|
97
|
+
if (!el || el.nodeType !== Node.ELEMENT_NODE) return false;
|
|
98
|
+
const style = window.getComputedStyle(el);
|
|
99
|
+
return style.overflowY === 'scroll' || style.overflowY === 'auto' && el.scrollHeight > el.clientHeight;
|
|
100
|
+
}
|
|
101
|
+
function isPotentiallyScrollable(el) {
|
|
102
|
+
if (!el || el.nodeType !== Node.ELEMENT_NODE) return false;
|
|
103
|
+
const style = window.getComputedStyle(el);
|
|
104
|
+
return ['scroll', 'auto'].includes(style.overflowY);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function isFixedPosition(el) {
|
|
108
|
+
while (el) {
|
|
109
|
+
if (window.getComputedStyle(el).position === 'fixed') {
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
el = el.offsetParent;
|
|
113
|
+
}
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Utilities
|
|
118
|
+
function defaultConditional() {
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
function checkEvent(e, el, binding) {
|
|
122
|
+
// The include element callbacks below can be expensive
|
|
123
|
+
// so we should avoid calling them when we're not active.
|
|
124
|
+
// Explicitly check for false to allow fallback compatibility
|
|
125
|
+
// with non-toggleable components
|
|
126
|
+
if (!e || checkIsActive(e, binding) === false) return false;
|
|
127
|
+
|
|
128
|
+
// If we're clicking inside the shadowroot, then the app root doesn't get the same
|
|
129
|
+
// level of introspection as to _what_ we're clicking. We want to check to see if
|
|
130
|
+
// our target is the shadowroot parent container, and if it is, ignore.
|
|
131
|
+
const root = attachedRoot(el);
|
|
132
|
+
if (typeof ShadowRoot !== 'undefined' && root instanceof ShadowRoot && root.host === e.target) return false;
|
|
133
|
+
|
|
134
|
+
// Check if additional elements were passed to be included in check
|
|
135
|
+
// (click must be outside all included elements, if any)
|
|
136
|
+
const elements = (typeof binding.value === 'object' && binding.value.include || (() => []))();
|
|
137
|
+
// Add the root element for the component this directive was defined on
|
|
138
|
+
elements.push(el);
|
|
139
|
+
|
|
140
|
+
// Check if it's a click outside our elements, and then if our callback returns true.
|
|
141
|
+
// Non-toggleable components should take action in their callback and return falsy.
|
|
142
|
+
// Toggleable can return true if it wants to deactivate.
|
|
143
|
+
// Note that, because we're in the capture phase, this callback will occur before
|
|
144
|
+
// the bubbling click event on any outside elements.
|
|
145
|
+
return !elements.some(el => el?.contains(e.target));
|
|
146
|
+
}
|
|
147
|
+
function checkIsActive(e, binding) {
|
|
148
|
+
const isActive = typeof binding.value === 'object' && binding.value.closeConditional || defaultConditional;
|
|
149
|
+
return isActive(e);
|
|
150
|
+
}
|
|
151
|
+
function directive(e, el, binding) {
|
|
152
|
+
const handler = typeof binding.value === 'function' ? binding.value : binding.value.handler;
|
|
153
|
+
|
|
154
|
+
// Clicks in the Shadow DOM change their target while using setTimeout, so the original target is saved here
|
|
155
|
+
e.shadowTarget = e.target;
|
|
156
|
+
el._clickOutside.lastMousedownWasOutside && checkEvent(e, el, binding) && setTimeout(() => {
|
|
157
|
+
checkIsActive(e, binding) && handler && handler(e);
|
|
158
|
+
}, 0);
|
|
159
|
+
}
|
|
160
|
+
function handleShadow(el, callback) {
|
|
161
|
+
const root = attachedRoot(el);
|
|
162
|
+
callback(document);
|
|
163
|
+
if (typeof ShadowRoot !== 'undefined' && root instanceof ShadowRoot) {
|
|
164
|
+
callback(root);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
const ClickOutside = {
|
|
168
|
+
// [data-app] may not be found
|
|
169
|
+
// if using bind, inserted makes
|
|
170
|
+
// sure that the root element is
|
|
171
|
+
// available, iOS does not support
|
|
172
|
+
// clicks on body
|
|
173
|
+
mounted(el, binding) {
|
|
174
|
+
const onClick = e => directive(e, el, binding);
|
|
175
|
+
const onMousedown = e => {
|
|
176
|
+
el._clickOutside.lastMousedownWasOutside = checkEvent(e, el, binding);
|
|
177
|
+
};
|
|
178
|
+
handleShadow(el, app => {
|
|
179
|
+
app.addEventListener('click', onClick, true);
|
|
180
|
+
app.addEventListener('mousedown', onMousedown, true);
|
|
181
|
+
});
|
|
182
|
+
if (!el._clickOutside) {
|
|
183
|
+
el._clickOutside = {
|
|
184
|
+
lastMousedownWasOutside: false
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
el._clickOutside[binding.instance.$.uid] = {
|
|
188
|
+
onClick,
|
|
189
|
+
onMousedown
|
|
190
|
+
};
|
|
191
|
+
},
|
|
192
|
+
beforeUnmount(el, binding) {
|
|
193
|
+
if (!el._clickOutside) return;
|
|
194
|
+
handleShadow(el, app => {
|
|
195
|
+
if (!app || !el._clickOutside?.[binding.instance.$.uid]) return;
|
|
196
|
+
const {
|
|
197
|
+
onClick,
|
|
198
|
+
onMousedown
|
|
199
|
+
} = el._clickOutside[binding.instance.$.uid];
|
|
200
|
+
app.removeEventListener('click', onClick, true);
|
|
201
|
+
app.removeEventListener('mousedown', onMousedown, true);
|
|
202
|
+
});
|
|
203
|
+
delete el._clickOutside[binding.instance.$.uid];
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
// Types
|
|
208
|
+
|
|
209
|
+
/** Convert a point in local space to viewport space */
|
|
210
|
+
function elementToViewport(point, offset) {
|
|
211
|
+
return {
|
|
212
|
+
x: point.x + offset.x,
|
|
213
|
+
y: point.y + offset.y
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** Get the difference between two points */
|
|
218
|
+
function getOffset(a, b) {
|
|
219
|
+
return {
|
|
220
|
+
x: a.x - b.x,
|
|
221
|
+
y: a.y - b.y
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/** Convert an anchor object to a point in local space */
|
|
226
|
+
function anchorToPoint(anchor, box) {
|
|
227
|
+
if (anchor.side === 'top' || anchor.side === 'bottom') {
|
|
228
|
+
const {
|
|
229
|
+
side,
|
|
230
|
+
align
|
|
231
|
+
} = anchor;
|
|
232
|
+
const x = align === 'left' ? 0 : align === 'center' ? box.width / 2 : align === 'right' ? box.width : align;
|
|
233
|
+
const y = side === 'top' ? 0 : side === 'bottom' ? box.height : side;
|
|
234
|
+
return elementToViewport({
|
|
235
|
+
x,
|
|
236
|
+
y
|
|
237
|
+
}, box);
|
|
238
|
+
} else if (anchor.side === 'left' || anchor.side === 'right') {
|
|
239
|
+
const {
|
|
240
|
+
side,
|
|
241
|
+
align
|
|
242
|
+
} = anchor;
|
|
243
|
+
const x = side === 'left' ? 0 : side === 'right' ? box.width : side;
|
|
244
|
+
const y = align === 'top' ? 0 : align === 'center' ? box.height / 2 : align === 'bottom' ? box.height : align;
|
|
245
|
+
return elementToViewport({
|
|
246
|
+
x,
|
|
247
|
+
y
|
|
248
|
+
}, box);
|
|
249
|
+
}
|
|
250
|
+
return elementToViewport({
|
|
251
|
+
x: box.width / 2,
|
|
252
|
+
y: box.height / 2
|
|
253
|
+
}, box);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Composables
|
|
257
|
+
const locationStrategies = {
|
|
258
|
+
static: staticLocationStrategy,
|
|
259
|
+
// specific viewport position, usually centered
|
|
260
|
+
connected: connectedLocationStrategy // connected to a certain element
|
|
261
|
+
};
|
|
262
|
+
const makeLocationStrategyProps = propsFactory({
|
|
263
|
+
locationStrategy: {
|
|
264
|
+
type: [String, Function],
|
|
265
|
+
default: 'static',
|
|
266
|
+
validator: val => typeof val === 'function' || val in locationStrategies
|
|
267
|
+
},
|
|
268
|
+
location: {
|
|
269
|
+
type: String,
|
|
270
|
+
default: 'bottom'
|
|
271
|
+
},
|
|
272
|
+
origin: {
|
|
273
|
+
type: String,
|
|
274
|
+
default: 'auto'
|
|
275
|
+
},
|
|
276
|
+
offset: [Number, String, Array]
|
|
277
|
+
}, 'VOverlay-location-strategies');
|
|
278
|
+
function useLocationStrategies(props, data) {
|
|
279
|
+
const contentStyles = ref({});
|
|
280
|
+
const updateLocation = ref();
|
|
281
|
+
if (IN_BROWSER) {
|
|
282
|
+
useToggleScope(() => !!(data.isActive.value && props.locationStrategy), reset => {
|
|
283
|
+
watch(() => props.locationStrategy, reset);
|
|
284
|
+
onScopeDispose(() => {
|
|
285
|
+
window.removeEventListener('resize', onResize);
|
|
286
|
+
updateLocation.value = undefined;
|
|
287
|
+
});
|
|
288
|
+
window.addEventListener('resize', onResize, {
|
|
289
|
+
passive: true
|
|
290
|
+
});
|
|
291
|
+
if (typeof props.locationStrategy === 'function') {
|
|
292
|
+
updateLocation.value = props.locationStrategy(data, props, contentStyles)?.updateLocation;
|
|
293
|
+
} else {
|
|
294
|
+
updateLocation.value = locationStrategies[props.locationStrategy](data, props, contentStyles)?.updateLocation;
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
function onResize(e) {
|
|
299
|
+
updateLocation.value?.(e);
|
|
300
|
+
}
|
|
301
|
+
return {
|
|
302
|
+
contentStyles,
|
|
303
|
+
updateLocation
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
function staticLocationStrategy() {
|
|
307
|
+
// TODO
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/** Get size of element ignoring max-width/max-height */
|
|
311
|
+
function getIntrinsicSize(el, isRtl) {
|
|
312
|
+
// const scrollables = new Map<Element, [number, number]>()
|
|
313
|
+
// el.querySelectorAll('*').forEach(el => {
|
|
314
|
+
// const x = el.scrollLeft
|
|
315
|
+
// const y = el.scrollTop
|
|
316
|
+
// if (x || y) {
|
|
317
|
+
// scrollables.set(el, [x, y])
|
|
318
|
+
// }
|
|
319
|
+
// })
|
|
320
|
+
|
|
321
|
+
// const initialMaxWidth = el.style.maxWidth
|
|
322
|
+
// const initialMaxHeight = el.style.maxHeight
|
|
323
|
+
// el.style.removeProperty('max-width')
|
|
324
|
+
// el.style.removeProperty('max-height')
|
|
325
|
+
|
|
326
|
+
/* eslint-disable-next-line sonarjs/prefer-immediate-return */
|
|
327
|
+
const contentBox = nullifyTransforms(el);
|
|
328
|
+
if (isRtl) {
|
|
329
|
+
contentBox.x += parseFloat(el.style.right || 0);
|
|
330
|
+
} else {
|
|
331
|
+
contentBox.x -= parseFloat(el.style.left || 0);
|
|
332
|
+
}
|
|
333
|
+
contentBox.y -= parseFloat(el.style.top || 0);
|
|
334
|
+
|
|
335
|
+
// el.style.maxWidth = initialMaxWidth
|
|
336
|
+
// el.style.maxHeight = initialMaxHeight
|
|
337
|
+
// scrollables.forEach((position, el) => {
|
|
338
|
+
// el.scrollTo(...position)
|
|
339
|
+
// })
|
|
340
|
+
|
|
341
|
+
return contentBox;
|
|
342
|
+
}
|
|
343
|
+
function connectedLocationStrategy(data, props, contentStyles) {
|
|
344
|
+
const activatorFixed = Array.isArray(data.target.value) || isFixedPosition(data.target.value);
|
|
345
|
+
if (activatorFixed) {
|
|
346
|
+
Object.assign(contentStyles.value, {
|
|
347
|
+
position: 'fixed',
|
|
348
|
+
top: 0,
|
|
349
|
+
[data.isRtl.value ? 'right' : 'left']: 0
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
const {
|
|
353
|
+
preferredAnchor,
|
|
354
|
+
preferredOrigin
|
|
355
|
+
} = destructComputed(() => {
|
|
356
|
+
const parsedAnchor = parseAnchor(props.location, data.isRtl.value);
|
|
357
|
+
const parsedOrigin = props.origin === 'overlap' ? parsedAnchor : props.origin === 'auto' ? flipSide(parsedAnchor) : parseAnchor(props.origin, data.isRtl.value);
|
|
358
|
+
|
|
359
|
+
// Some combinations of props may produce an invalid origin
|
|
360
|
+
if (parsedAnchor.side === parsedOrigin.side && parsedAnchor.align === flipAlign(parsedOrigin).align) {
|
|
361
|
+
return {
|
|
362
|
+
preferredAnchor: flipCorner(parsedAnchor),
|
|
363
|
+
preferredOrigin: flipCorner(parsedOrigin)
|
|
364
|
+
};
|
|
365
|
+
} else {
|
|
366
|
+
return {
|
|
367
|
+
preferredAnchor: parsedAnchor,
|
|
368
|
+
preferredOrigin: parsedOrigin
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
const [minWidth, minHeight, maxWidth, maxHeight] = ['minWidth', 'minHeight', 'maxWidth', 'maxHeight'].map(key => {
|
|
373
|
+
return computed(() => {
|
|
374
|
+
const val = parseFloat(props[key]);
|
|
375
|
+
return isNaN(val) ? Infinity : val;
|
|
376
|
+
});
|
|
377
|
+
});
|
|
378
|
+
const offset = computed(() => {
|
|
379
|
+
if (Array.isArray(props.offset)) {
|
|
380
|
+
return props.offset;
|
|
381
|
+
}
|
|
382
|
+
if (typeof props.offset === 'string') {
|
|
383
|
+
const offset = props.offset.split(' ').map(parseFloat);
|
|
384
|
+
if (offset.length < 2) offset.push(0);
|
|
385
|
+
return offset;
|
|
386
|
+
}
|
|
387
|
+
return typeof props.offset === 'number' ? [props.offset, 0] : [0, 0];
|
|
388
|
+
});
|
|
389
|
+
let observe = false;
|
|
390
|
+
const observer = new ResizeObserver(() => {
|
|
391
|
+
if (observe) updateLocation();
|
|
392
|
+
});
|
|
393
|
+
watch([data.target, data.contentEl], (_ref, _ref2) => {
|
|
394
|
+
let [newTarget, newContentEl] = _ref;
|
|
395
|
+
let [oldTarget, oldContentEl] = _ref2;
|
|
396
|
+
if (oldTarget && !Array.isArray(oldTarget)) observer.unobserve(oldTarget);
|
|
397
|
+
if (newTarget && !Array.isArray(newTarget)) observer.observe(newTarget);
|
|
398
|
+
if (oldContentEl) observer.unobserve(oldContentEl);
|
|
399
|
+
if (newContentEl) observer.observe(newContentEl);
|
|
400
|
+
}, {
|
|
401
|
+
immediate: true
|
|
402
|
+
});
|
|
403
|
+
onScopeDispose(() => {
|
|
404
|
+
observer.disconnect();
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
// eslint-disable-next-line max-statements
|
|
408
|
+
function updateLocation() {
|
|
409
|
+
observe = false;
|
|
410
|
+
requestAnimationFrame(() => observe = true);
|
|
411
|
+
if (!data.target.value || !data.contentEl.value) return;
|
|
412
|
+
const targetBox = getTargetBox(data.target.value);
|
|
413
|
+
const contentBox = getIntrinsicSize(data.contentEl.value, data.isRtl.value);
|
|
414
|
+
const scrollParents = getScrollParents(data.contentEl.value);
|
|
415
|
+
const viewportMargin = 12;
|
|
416
|
+
if (!scrollParents.length) {
|
|
417
|
+
scrollParents.push(document.documentElement);
|
|
418
|
+
if (!(data.contentEl.value.style.top && data.contentEl.value.style.left)) {
|
|
419
|
+
contentBox.x -= parseFloat(document.documentElement.style.getPropertyValue('--v-body-scroll-x') || 0);
|
|
420
|
+
contentBox.y -= parseFloat(document.documentElement.style.getPropertyValue('--v-body-scroll-y') || 0);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
const viewport = scrollParents.reduce((box, el) => {
|
|
424
|
+
const rect = el.getBoundingClientRect();
|
|
425
|
+
const scrollBox = new Box({
|
|
426
|
+
x: el === document.documentElement ? 0 : rect.x,
|
|
427
|
+
y: el === document.documentElement ? 0 : rect.y,
|
|
428
|
+
width: el.clientWidth,
|
|
429
|
+
height: el.clientHeight
|
|
430
|
+
});
|
|
431
|
+
if (box) {
|
|
432
|
+
return new Box({
|
|
433
|
+
x: Math.max(box.left, scrollBox.left),
|
|
434
|
+
y: Math.max(box.top, scrollBox.top),
|
|
435
|
+
width: Math.min(box.right, scrollBox.right) - Math.max(box.left, scrollBox.left),
|
|
436
|
+
height: Math.min(box.bottom, scrollBox.bottom) - Math.max(box.top, scrollBox.top)
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
return scrollBox;
|
|
440
|
+
}, undefined);
|
|
441
|
+
viewport.x += viewportMargin;
|
|
442
|
+
viewport.y += viewportMargin;
|
|
443
|
+
viewport.width -= viewportMargin * 2;
|
|
444
|
+
viewport.height -= viewportMargin * 2;
|
|
445
|
+
let placement = {
|
|
446
|
+
anchor: preferredAnchor.value,
|
|
447
|
+
origin: preferredOrigin.value
|
|
448
|
+
};
|
|
449
|
+
function checkOverflow(_placement) {
|
|
450
|
+
const box = new Box(contentBox);
|
|
451
|
+
const targetPoint = anchorToPoint(_placement.anchor, targetBox);
|
|
452
|
+
const contentPoint = anchorToPoint(_placement.origin, box);
|
|
453
|
+
let {
|
|
454
|
+
x,
|
|
455
|
+
y
|
|
456
|
+
} = getOffset(targetPoint, contentPoint);
|
|
457
|
+
switch (_placement.anchor.side) {
|
|
458
|
+
case 'top':
|
|
459
|
+
y -= offset.value[0];
|
|
460
|
+
break;
|
|
461
|
+
case 'bottom':
|
|
462
|
+
y += offset.value[0];
|
|
463
|
+
break;
|
|
464
|
+
case 'left':
|
|
465
|
+
x -= offset.value[0];
|
|
466
|
+
break;
|
|
467
|
+
case 'right':
|
|
468
|
+
x += offset.value[0];
|
|
469
|
+
break;
|
|
470
|
+
}
|
|
471
|
+
switch (_placement.anchor.align) {
|
|
472
|
+
case 'top':
|
|
473
|
+
y -= offset.value[1];
|
|
474
|
+
break;
|
|
475
|
+
case 'bottom':
|
|
476
|
+
y += offset.value[1];
|
|
477
|
+
break;
|
|
478
|
+
case 'left':
|
|
479
|
+
x -= offset.value[1];
|
|
480
|
+
break;
|
|
481
|
+
case 'right':
|
|
482
|
+
x += offset.value[1];
|
|
483
|
+
break;
|
|
484
|
+
}
|
|
485
|
+
box.x += x;
|
|
486
|
+
box.y += y;
|
|
487
|
+
box.width = Math.min(box.width, maxWidth.value);
|
|
488
|
+
box.height = Math.min(box.height, maxHeight.value);
|
|
489
|
+
const overflows = getOverflow(box, viewport);
|
|
490
|
+
return {
|
|
491
|
+
overflows,
|
|
492
|
+
x,
|
|
493
|
+
y
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
let x = 0;
|
|
497
|
+
let y = 0;
|
|
498
|
+
const available = {
|
|
499
|
+
x: 0,
|
|
500
|
+
y: 0
|
|
501
|
+
};
|
|
502
|
+
const flipped = {
|
|
503
|
+
x: false,
|
|
504
|
+
y: false
|
|
505
|
+
};
|
|
506
|
+
let resets = -1;
|
|
507
|
+
while (true) {
|
|
508
|
+
if (resets++ > 10) {
|
|
509
|
+
consoleError('Infinite loop detected in connectedLocationStrategy');
|
|
510
|
+
break;
|
|
511
|
+
}
|
|
512
|
+
const {
|
|
513
|
+
x: _x,
|
|
514
|
+
y: _y,
|
|
515
|
+
overflows
|
|
516
|
+
} = checkOverflow(placement);
|
|
517
|
+
x += _x;
|
|
518
|
+
y += _y;
|
|
519
|
+
contentBox.x += _x;
|
|
520
|
+
contentBox.y += _y;
|
|
521
|
+
|
|
522
|
+
// flip
|
|
523
|
+
{
|
|
524
|
+
const axis = getAxis(placement.anchor);
|
|
525
|
+
const hasOverflowX = overflows.x.before || overflows.x.after;
|
|
526
|
+
const hasOverflowY = overflows.y.before || overflows.y.after;
|
|
527
|
+
let reset = false;
|
|
528
|
+
['x', 'y'].forEach(key => {
|
|
529
|
+
if (key === 'x' && hasOverflowX && !flipped.x || key === 'y' && hasOverflowY && !flipped.y) {
|
|
530
|
+
const newPlacement = {
|
|
531
|
+
anchor: {
|
|
532
|
+
...placement.anchor
|
|
533
|
+
},
|
|
534
|
+
origin: {
|
|
535
|
+
...placement.origin
|
|
536
|
+
}
|
|
537
|
+
};
|
|
538
|
+
const flip = key === 'x' ? axis === 'y' ? flipAlign : flipSide : axis === 'y' ? flipSide : flipAlign;
|
|
539
|
+
newPlacement.anchor = flip(newPlacement.anchor);
|
|
540
|
+
newPlacement.origin = flip(newPlacement.origin);
|
|
541
|
+
const {
|
|
542
|
+
overflows: newOverflows
|
|
543
|
+
} = checkOverflow(newPlacement);
|
|
544
|
+
if (newOverflows[key].before <= overflows[key].before && newOverflows[key].after <= overflows[key].after || newOverflows[key].before + newOverflows[key].after < (overflows[key].before + overflows[key].after) / 2) {
|
|
545
|
+
placement = newPlacement;
|
|
546
|
+
reset = flipped[key] = true;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
});
|
|
550
|
+
if (reset) continue;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// shift
|
|
554
|
+
if (overflows.x.before) {
|
|
555
|
+
x += overflows.x.before;
|
|
556
|
+
contentBox.x += overflows.x.before;
|
|
557
|
+
}
|
|
558
|
+
if (overflows.x.after) {
|
|
559
|
+
x -= overflows.x.after;
|
|
560
|
+
contentBox.x -= overflows.x.after;
|
|
561
|
+
}
|
|
562
|
+
if (overflows.y.before) {
|
|
563
|
+
y += overflows.y.before;
|
|
564
|
+
contentBox.y += overflows.y.before;
|
|
565
|
+
}
|
|
566
|
+
if (overflows.y.after) {
|
|
567
|
+
y -= overflows.y.after;
|
|
568
|
+
contentBox.y -= overflows.y.after;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
// size
|
|
572
|
+
{
|
|
573
|
+
const overflows = getOverflow(contentBox, viewport);
|
|
574
|
+
available.x = viewport.width - overflows.x.before - overflows.x.after;
|
|
575
|
+
available.y = viewport.height - overflows.y.before - overflows.y.after;
|
|
576
|
+
x += overflows.x.before;
|
|
577
|
+
contentBox.x += overflows.x.before;
|
|
578
|
+
y += overflows.y.before;
|
|
579
|
+
contentBox.y += overflows.y.before;
|
|
580
|
+
}
|
|
581
|
+
break;
|
|
582
|
+
}
|
|
583
|
+
const axis = getAxis(placement.anchor);
|
|
584
|
+
Object.assign(contentStyles.value, {
|
|
585
|
+
'--v-overlay-anchor-origin': `${placement.anchor.side} ${placement.anchor.align}`,
|
|
586
|
+
transformOrigin: `${placement.origin.side} ${placement.origin.align}`,
|
|
587
|
+
// transform: `translate(${pixelRound(x)}px, ${pixelRound(y)}px)`,
|
|
588
|
+
top: convertToUnit(pixelRound(y)),
|
|
589
|
+
left: data.isRtl.value ? undefined : convertToUnit(pixelRound(x)),
|
|
590
|
+
right: data.isRtl.value ? convertToUnit(pixelRound(-x)) : undefined,
|
|
591
|
+
minWidth: convertToUnit(axis === 'y' ? Math.min(minWidth.value, targetBox.width) : minWidth.value),
|
|
592
|
+
maxWidth: convertToUnit(pixelCeil(clamp(available.x, minWidth.value === Infinity ? 0 : minWidth.value, maxWidth.value))),
|
|
593
|
+
maxHeight: convertToUnit(pixelCeil(clamp(available.y, minHeight.value === Infinity ? 0 : minHeight.value, maxHeight.value)))
|
|
594
|
+
});
|
|
595
|
+
return {
|
|
596
|
+
available,
|
|
597
|
+
contentBox
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
watch(() => [preferredAnchor.value, preferredOrigin.value, props.offset, props.minWidth, props.minHeight, props.maxWidth, props.maxHeight], () => updateLocation());
|
|
601
|
+
nextTick(() => {
|
|
602
|
+
const result = updateLocation();
|
|
603
|
+
|
|
604
|
+
// TODO: overflowing content should only require a single updateLocation call
|
|
605
|
+
// Icky hack to make sure the content is positioned consistently
|
|
606
|
+
if (!result) return;
|
|
607
|
+
const {
|
|
608
|
+
available,
|
|
609
|
+
contentBox
|
|
610
|
+
} = result;
|
|
611
|
+
if (contentBox.height > available.y) {
|
|
612
|
+
requestAnimationFrame(() => {
|
|
613
|
+
updateLocation();
|
|
614
|
+
requestAnimationFrame(() => {
|
|
615
|
+
updateLocation();
|
|
616
|
+
});
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
});
|
|
620
|
+
return {
|
|
621
|
+
updateLocation
|
|
622
|
+
};
|
|
623
|
+
}
|
|
624
|
+
function pixelRound(val) {
|
|
625
|
+
return Math.round(val * devicePixelRatio) / devicePixelRatio;
|
|
626
|
+
}
|
|
627
|
+
function pixelCeil(val) {
|
|
628
|
+
return Math.ceil(val * devicePixelRatio) / devicePixelRatio;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
let clean = true;
|
|
632
|
+
const frames = [];
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* Schedule a task to run in an animation frame on its own
|
|
636
|
+
* This is useful for heavy tasks that may cause jank if all ran together
|
|
637
|
+
*/
|
|
638
|
+
function requestNewFrame(cb) {
|
|
639
|
+
if (!clean || frames.length) {
|
|
640
|
+
frames.push(cb);
|
|
641
|
+
run();
|
|
642
|
+
} else {
|
|
643
|
+
clean = false;
|
|
644
|
+
cb();
|
|
645
|
+
run();
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
let raf = -1;
|
|
649
|
+
function run() {
|
|
650
|
+
cancelAnimationFrame(raf);
|
|
651
|
+
raf = requestAnimationFrame(() => {
|
|
652
|
+
const frame = frames.shift();
|
|
653
|
+
if (frame) frame();
|
|
654
|
+
if (frames.length) run();else clean = true;
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
// Utilities
|
|
659
|
+
const scrollStrategies = {
|
|
660
|
+
none: null,
|
|
661
|
+
close: closeScrollStrategy,
|
|
662
|
+
block: blockScrollStrategy,
|
|
663
|
+
reposition: repositionScrollStrategy
|
|
664
|
+
};
|
|
665
|
+
const makeScrollStrategyProps = propsFactory({
|
|
666
|
+
scrollStrategy: {
|
|
667
|
+
type: [String, Function],
|
|
668
|
+
default: 'block',
|
|
669
|
+
validator: val => typeof val === 'function' || val in scrollStrategies
|
|
670
|
+
}
|
|
671
|
+
}, 'VOverlay-scroll-strategies');
|
|
672
|
+
function useScrollStrategies(props, data) {
|
|
673
|
+
if (!IN_BROWSER) return;
|
|
674
|
+
let scope;
|
|
675
|
+
watchEffect(async () => {
|
|
676
|
+
scope?.stop();
|
|
677
|
+
if (!(data.isActive.value && props.scrollStrategy)) return;
|
|
678
|
+
scope = effectScope();
|
|
679
|
+
await new Promise(resolve => setTimeout(resolve));
|
|
680
|
+
scope.active && scope.run(() => {
|
|
681
|
+
if (typeof props.scrollStrategy === 'function') {
|
|
682
|
+
props.scrollStrategy(data, props, scope);
|
|
683
|
+
} else {
|
|
684
|
+
scrollStrategies[props.scrollStrategy]?.(data, props, scope);
|
|
685
|
+
}
|
|
686
|
+
});
|
|
687
|
+
});
|
|
688
|
+
onScopeDispose(() => {
|
|
689
|
+
scope?.stop();
|
|
690
|
+
});
|
|
691
|
+
}
|
|
692
|
+
function closeScrollStrategy(data) {
|
|
693
|
+
function onScroll(e) {
|
|
694
|
+
data.isActive.value = false;
|
|
695
|
+
}
|
|
696
|
+
bindScroll(data.targetEl.value ?? data.contentEl.value, onScroll);
|
|
697
|
+
}
|
|
698
|
+
function blockScrollStrategy(data, props) {
|
|
699
|
+
const offsetParent = data.root.value?.offsetParent;
|
|
700
|
+
const scrollElements = [...new Set([...getScrollParents(data.targetEl.value, props.contained ? offsetParent : undefined), ...getScrollParents(data.contentEl.value, props.contained ? offsetParent : undefined)])].filter(el => !el.classList.contains('v-overlay-scroll-blocked'));
|
|
701
|
+
const scrollbarWidth = window.innerWidth - document.documentElement.offsetWidth;
|
|
702
|
+
const scrollableParent = (el => hasScrollbar(el) && el)(offsetParent || document.documentElement);
|
|
703
|
+
if (scrollableParent) {
|
|
704
|
+
data.root.value.classList.add('v-overlay--scroll-blocked');
|
|
705
|
+
}
|
|
706
|
+
scrollElements.forEach((el, i) => {
|
|
707
|
+
el.style.setProperty('--v-body-scroll-x', convertToUnit(-el.scrollLeft));
|
|
708
|
+
el.style.setProperty('--v-body-scroll-y', convertToUnit(-el.scrollTop));
|
|
709
|
+
if (el !== document.documentElement) {
|
|
710
|
+
el.style.setProperty('--v-scrollbar-offset', convertToUnit(scrollbarWidth));
|
|
711
|
+
}
|
|
712
|
+
el.classList.add('v-overlay-scroll-blocked');
|
|
713
|
+
});
|
|
714
|
+
onScopeDispose(() => {
|
|
715
|
+
scrollElements.forEach((el, i) => {
|
|
716
|
+
const x = parseFloat(el.style.getPropertyValue('--v-body-scroll-x'));
|
|
717
|
+
const y = parseFloat(el.style.getPropertyValue('--v-body-scroll-y'));
|
|
718
|
+
const scrollBehavior = el.style.scrollBehavior;
|
|
719
|
+
el.style.scrollBehavior = 'auto';
|
|
720
|
+
el.style.removeProperty('--v-body-scroll-x');
|
|
721
|
+
el.style.removeProperty('--v-body-scroll-y');
|
|
722
|
+
el.style.removeProperty('--v-scrollbar-offset');
|
|
723
|
+
el.classList.remove('v-overlay-scroll-blocked');
|
|
724
|
+
el.scrollLeft = -x;
|
|
725
|
+
el.scrollTop = -y;
|
|
726
|
+
el.style.scrollBehavior = scrollBehavior;
|
|
727
|
+
});
|
|
728
|
+
if (scrollableParent) {
|
|
729
|
+
data.root.value.classList.remove('v-overlay--scroll-blocked');
|
|
730
|
+
}
|
|
731
|
+
});
|
|
732
|
+
}
|
|
733
|
+
function repositionScrollStrategy(data, props, scope) {
|
|
734
|
+
let slow = false;
|
|
735
|
+
let raf = -1;
|
|
736
|
+
let ric = -1;
|
|
737
|
+
function update(e) {
|
|
738
|
+
requestNewFrame(() => {
|
|
739
|
+
const start = performance.now();
|
|
740
|
+
data.updateLocation.value?.(e);
|
|
741
|
+
const time = performance.now() - start;
|
|
742
|
+
slow = time / (1000 / 60) > 2;
|
|
743
|
+
});
|
|
744
|
+
}
|
|
745
|
+
ric = (typeof requestIdleCallback === 'undefined' ? cb => cb() : requestIdleCallback)(() => {
|
|
746
|
+
scope.run(() => {
|
|
747
|
+
bindScroll(data.targetEl.value ?? data.contentEl.value, e => {
|
|
748
|
+
if (slow) {
|
|
749
|
+
// If the position calculation is slow,
|
|
750
|
+
// defer updates until scrolling is finished.
|
|
751
|
+
// Browsers usually fire one scroll event per frame so
|
|
752
|
+
// we just wait until we've got two frames without an event
|
|
753
|
+
cancelAnimationFrame(raf);
|
|
754
|
+
raf = requestAnimationFrame(() => {
|
|
755
|
+
raf = requestAnimationFrame(() => {
|
|
756
|
+
update(e);
|
|
757
|
+
});
|
|
758
|
+
});
|
|
759
|
+
} else {
|
|
760
|
+
update(e);
|
|
761
|
+
}
|
|
762
|
+
});
|
|
763
|
+
});
|
|
764
|
+
});
|
|
765
|
+
onScopeDispose(() => {
|
|
766
|
+
typeof cancelIdleCallback !== 'undefined' && cancelIdleCallback(ric);
|
|
767
|
+
cancelAnimationFrame(raf);
|
|
768
|
+
});
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
/** @private */
|
|
772
|
+
function bindScroll(el, onScroll) {
|
|
773
|
+
const scrollElements = [document, ...getScrollParents(el)];
|
|
774
|
+
scrollElements.forEach(el => {
|
|
775
|
+
el.addEventListener('scroll', onScroll, {
|
|
776
|
+
passive: true
|
|
777
|
+
});
|
|
778
|
+
});
|
|
779
|
+
onScopeDispose(() => {
|
|
780
|
+
scrollElements.forEach(el => {
|
|
781
|
+
el.removeEventListener('scroll', onScroll);
|
|
782
|
+
});
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
// Types
|
|
787
|
+
|
|
788
|
+
const VMenuSymbol = Symbol.for('vuetify:v-menu');
|
|
789
|
+
|
|
790
|
+
// Utilities
|
|
791
|
+
// Composables
|
|
792
|
+
const makeDelayProps = propsFactory({
|
|
793
|
+
closeDelay: [Number, String],
|
|
794
|
+
openDelay: [Number, String]
|
|
795
|
+
}, 'delay');
|
|
796
|
+
function useDelay(props, cb) {
|
|
797
|
+
let clearDelay = () => {};
|
|
798
|
+
function runDelay(isOpening) {
|
|
799
|
+
clearDelay?.();
|
|
800
|
+
const delay = Number(isOpening ? props.openDelay : props.closeDelay);
|
|
801
|
+
return new Promise(resolve => {
|
|
802
|
+
clearDelay = defer(delay, () => {
|
|
803
|
+
cb?.(isOpening);
|
|
804
|
+
resolve(isOpening);
|
|
805
|
+
});
|
|
806
|
+
});
|
|
807
|
+
}
|
|
808
|
+
function runOpenDelay() {
|
|
809
|
+
return runDelay(true);
|
|
810
|
+
}
|
|
811
|
+
function runCloseDelay() {
|
|
812
|
+
return runDelay(false);
|
|
813
|
+
}
|
|
814
|
+
return {
|
|
815
|
+
clearDelay,
|
|
816
|
+
runOpenDelay,
|
|
817
|
+
runCloseDelay
|
|
818
|
+
};
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
// Components
|
|
822
|
+
const makeActivatorProps = propsFactory({
|
|
823
|
+
target: [String, Object],
|
|
824
|
+
activator: [String, Object],
|
|
825
|
+
activatorProps: {
|
|
826
|
+
type: Object,
|
|
827
|
+
default: () => ({})
|
|
828
|
+
},
|
|
829
|
+
openOnClick: {
|
|
830
|
+
type: Boolean,
|
|
831
|
+
default: undefined
|
|
832
|
+
},
|
|
833
|
+
openOnHover: Boolean,
|
|
834
|
+
openOnFocus: {
|
|
835
|
+
type: Boolean,
|
|
836
|
+
default: undefined
|
|
837
|
+
},
|
|
838
|
+
closeOnContentClick: Boolean,
|
|
839
|
+
...makeDelayProps()
|
|
840
|
+
}, 'VOverlay-activator');
|
|
841
|
+
function useActivator(props, _ref) {
|
|
842
|
+
let {
|
|
843
|
+
isActive,
|
|
844
|
+
isTop,
|
|
845
|
+
contentEl
|
|
846
|
+
} = _ref;
|
|
847
|
+
const vm = getCurrentInstance('useActivator');
|
|
848
|
+
const activatorEl = ref();
|
|
849
|
+
let isHovered = false;
|
|
850
|
+
let isFocused = false;
|
|
851
|
+
let firstEnter = true;
|
|
852
|
+
const openOnFocus = computed(() => props.openOnFocus || props.openOnFocus == null && props.openOnHover);
|
|
853
|
+
const openOnClick = computed(() => props.openOnClick || props.openOnClick == null && !props.openOnHover && !openOnFocus.value);
|
|
854
|
+
const {
|
|
855
|
+
runOpenDelay,
|
|
856
|
+
runCloseDelay
|
|
857
|
+
} = useDelay(props, value => {
|
|
858
|
+
if (value === (props.openOnHover && isHovered || openOnFocus.value && isFocused) && !(props.openOnHover && isActive.value && !isTop.value)) {
|
|
859
|
+
if (isActive.value !== value) {
|
|
860
|
+
firstEnter = true;
|
|
861
|
+
}
|
|
862
|
+
isActive.value = value;
|
|
863
|
+
}
|
|
864
|
+
});
|
|
865
|
+
const cursorTarget = ref();
|
|
866
|
+
const availableEvents = {
|
|
867
|
+
onClick: e => {
|
|
868
|
+
e.stopPropagation();
|
|
869
|
+
activatorEl.value = e.currentTarget || e.target;
|
|
870
|
+
if (!isActive.value) {
|
|
871
|
+
cursorTarget.value = [e.clientX, e.clientY];
|
|
872
|
+
}
|
|
873
|
+
isActive.value = !isActive.value;
|
|
874
|
+
},
|
|
875
|
+
onMouseenter: e => {
|
|
876
|
+
if (e.sourceCapabilities?.firesTouchEvents) return;
|
|
877
|
+
isHovered = true;
|
|
878
|
+
activatorEl.value = e.currentTarget || e.target;
|
|
879
|
+
runOpenDelay();
|
|
880
|
+
},
|
|
881
|
+
onMouseleave: e => {
|
|
882
|
+
isHovered = false;
|
|
883
|
+
runCloseDelay();
|
|
884
|
+
},
|
|
885
|
+
onFocus: e => {
|
|
886
|
+
if (matchesSelector(e.target, ':focus-visible') === false) return;
|
|
887
|
+
isFocused = true;
|
|
888
|
+
e.stopPropagation();
|
|
889
|
+
activatorEl.value = e.currentTarget || e.target;
|
|
890
|
+
runOpenDelay();
|
|
891
|
+
},
|
|
892
|
+
onBlur: e => {
|
|
893
|
+
isFocused = false;
|
|
894
|
+
e.stopPropagation();
|
|
895
|
+
runCloseDelay();
|
|
896
|
+
}
|
|
897
|
+
};
|
|
898
|
+
const activatorEvents = computed(() => {
|
|
899
|
+
const events = {};
|
|
900
|
+
if (openOnClick.value) {
|
|
901
|
+
events.onClick = availableEvents.onClick;
|
|
902
|
+
}
|
|
903
|
+
if (props.openOnHover) {
|
|
904
|
+
events.onMouseenter = availableEvents.onMouseenter;
|
|
905
|
+
events.onMouseleave = availableEvents.onMouseleave;
|
|
906
|
+
}
|
|
907
|
+
if (openOnFocus.value) {
|
|
908
|
+
events.onFocus = availableEvents.onFocus;
|
|
909
|
+
events.onBlur = availableEvents.onBlur;
|
|
910
|
+
}
|
|
911
|
+
return events;
|
|
912
|
+
});
|
|
913
|
+
const contentEvents = computed(() => {
|
|
914
|
+
const events = {};
|
|
915
|
+
if (props.openOnHover) {
|
|
916
|
+
events.onMouseenter = () => {
|
|
917
|
+
isHovered = true;
|
|
918
|
+
runOpenDelay();
|
|
919
|
+
};
|
|
920
|
+
events.onMouseleave = () => {
|
|
921
|
+
isHovered = false;
|
|
922
|
+
runCloseDelay();
|
|
923
|
+
};
|
|
924
|
+
}
|
|
925
|
+
if (openOnFocus.value) {
|
|
926
|
+
events.onFocusin = () => {
|
|
927
|
+
isFocused = true;
|
|
928
|
+
runOpenDelay();
|
|
929
|
+
};
|
|
930
|
+
events.onFocusout = () => {
|
|
931
|
+
isFocused = false;
|
|
932
|
+
runCloseDelay();
|
|
933
|
+
};
|
|
934
|
+
}
|
|
935
|
+
if (props.closeOnContentClick) {
|
|
936
|
+
const menu = inject(VMenuSymbol, null);
|
|
937
|
+
events.onClick = () => {
|
|
938
|
+
isActive.value = false;
|
|
939
|
+
menu?.closeParents();
|
|
940
|
+
};
|
|
941
|
+
}
|
|
942
|
+
return events;
|
|
943
|
+
});
|
|
944
|
+
const scrimEvents = computed(() => {
|
|
945
|
+
const events = {};
|
|
946
|
+
if (props.openOnHover) {
|
|
947
|
+
events.onMouseenter = () => {
|
|
948
|
+
if (firstEnter) {
|
|
949
|
+
isHovered = true;
|
|
950
|
+
firstEnter = false;
|
|
951
|
+
runOpenDelay();
|
|
952
|
+
}
|
|
953
|
+
};
|
|
954
|
+
events.onMouseleave = () => {
|
|
955
|
+
isHovered = false;
|
|
956
|
+
runCloseDelay();
|
|
957
|
+
};
|
|
958
|
+
}
|
|
959
|
+
return events;
|
|
960
|
+
});
|
|
961
|
+
watch(isTop, val => {
|
|
962
|
+
if (val && (props.openOnHover && !isHovered && (!openOnFocus.value || !isFocused) || openOnFocus.value && !isFocused && (!props.openOnHover || !isHovered)) && !contentEl.value?.contains(document.activeElement)) {
|
|
963
|
+
isActive.value = false;
|
|
964
|
+
}
|
|
965
|
+
});
|
|
966
|
+
watch(isActive, val => {
|
|
967
|
+
if (!val) {
|
|
968
|
+
setTimeout(() => {
|
|
969
|
+
cursorTarget.value = undefined;
|
|
970
|
+
});
|
|
971
|
+
}
|
|
972
|
+
}, {
|
|
973
|
+
flush: 'post'
|
|
974
|
+
});
|
|
975
|
+
const activatorRef = templateRef();
|
|
976
|
+
watchEffect(() => {
|
|
977
|
+
if (!activatorRef.value) return;
|
|
978
|
+
nextTick(() => {
|
|
979
|
+
activatorEl.value = activatorRef.el;
|
|
980
|
+
});
|
|
981
|
+
});
|
|
982
|
+
const targetRef = templateRef();
|
|
983
|
+
const target = computed(() => {
|
|
984
|
+
if (props.target === 'cursor' && cursorTarget.value) return cursorTarget.value;
|
|
985
|
+
if (targetRef.value) return targetRef.el;
|
|
986
|
+
return getTarget(props.target, vm) || activatorEl.value;
|
|
987
|
+
});
|
|
988
|
+
const targetEl = computed(() => {
|
|
989
|
+
return Array.isArray(target.value) ? undefined : target.value;
|
|
990
|
+
});
|
|
991
|
+
let scope;
|
|
992
|
+
watch(() => !!props.activator, val => {
|
|
993
|
+
if (val && IN_BROWSER) {
|
|
994
|
+
scope = effectScope();
|
|
995
|
+
scope.run(() => {
|
|
996
|
+
_useActivator(props, vm, {
|
|
997
|
+
activatorEl,
|
|
998
|
+
activatorEvents
|
|
999
|
+
});
|
|
1000
|
+
});
|
|
1001
|
+
} else if (scope) {
|
|
1002
|
+
scope.stop();
|
|
1003
|
+
}
|
|
1004
|
+
}, {
|
|
1005
|
+
flush: 'post',
|
|
1006
|
+
immediate: true
|
|
1007
|
+
});
|
|
1008
|
+
onScopeDispose(() => {
|
|
1009
|
+
scope?.stop();
|
|
1010
|
+
});
|
|
1011
|
+
return {
|
|
1012
|
+
activatorEl,
|
|
1013
|
+
activatorRef,
|
|
1014
|
+
target,
|
|
1015
|
+
targetEl,
|
|
1016
|
+
targetRef,
|
|
1017
|
+
activatorEvents,
|
|
1018
|
+
contentEvents,
|
|
1019
|
+
scrimEvents
|
|
1020
|
+
};
|
|
1021
|
+
}
|
|
1022
|
+
function _useActivator(props, vm, _ref2) {
|
|
1023
|
+
let {
|
|
1024
|
+
activatorEl,
|
|
1025
|
+
activatorEvents
|
|
1026
|
+
} = _ref2;
|
|
1027
|
+
watch(() => props.activator, (val, oldVal) => {
|
|
1028
|
+
if (oldVal && val !== oldVal) {
|
|
1029
|
+
const activator = getActivator(oldVal);
|
|
1030
|
+
activator && unbindActivatorProps(activator);
|
|
1031
|
+
}
|
|
1032
|
+
if (val) {
|
|
1033
|
+
nextTick(() => bindActivatorProps());
|
|
1034
|
+
}
|
|
1035
|
+
}, {
|
|
1036
|
+
immediate: true
|
|
1037
|
+
});
|
|
1038
|
+
watch(() => props.activatorProps, () => {
|
|
1039
|
+
bindActivatorProps();
|
|
1040
|
+
});
|
|
1041
|
+
onScopeDispose(() => {
|
|
1042
|
+
unbindActivatorProps();
|
|
1043
|
+
});
|
|
1044
|
+
function bindActivatorProps() {
|
|
1045
|
+
let el = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getActivator();
|
|
1046
|
+
let _props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : props.activatorProps;
|
|
1047
|
+
if (!el) return;
|
|
1048
|
+
bindProps(el, mergeProps(activatorEvents.value, _props));
|
|
1049
|
+
}
|
|
1050
|
+
function unbindActivatorProps() {
|
|
1051
|
+
let el = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getActivator();
|
|
1052
|
+
let _props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : props.activatorProps;
|
|
1053
|
+
if (!el) return;
|
|
1054
|
+
unbindProps(el, mergeProps(activatorEvents.value, _props));
|
|
1055
|
+
}
|
|
1056
|
+
function getActivator() {
|
|
1057
|
+
let selector = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : props.activator;
|
|
1058
|
+
const activator = getTarget(selector, vm);
|
|
1059
|
+
|
|
1060
|
+
// The activator should only be a valid element (Ignore comments and text nodes)
|
|
1061
|
+
activatorEl.value = activator?.nodeType === Node.ELEMENT_NODE ? activator : undefined;
|
|
1062
|
+
return activatorEl.value;
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
function getTarget(selector, vm) {
|
|
1066
|
+
if (!selector) return;
|
|
1067
|
+
let target;
|
|
1068
|
+
if (selector === 'parent') {
|
|
1069
|
+
let el = vm?.proxy?.$el?.parentNode;
|
|
1070
|
+
while (el?.hasAttribute('data-no-activator')) {
|
|
1071
|
+
el = el.parentNode;
|
|
1072
|
+
}
|
|
1073
|
+
target = el;
|
|
1074
|
+
} else if (typeof selector === 'string') {
|
|
1075
|
+
// Selector
|
|
1076
|
+
target = document.querySelector(selector);
|
|
1077
|
+
} else if ('$el' in selector) {
|
|
1078
|
+
// Component (ref)
|
|
1079
|
+
target = selector.$el;
|
|
1080
|
+
} else {
|
|
1081
|
+
// HTMLElement | Element | [x, y]
|
|
1082
|
+
target = selector;
|
|
1083
|
+
}
|
|
1084
|
+
return target;
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
// Composables
|
|
1088
|
+
function useHydration() {
|
|
1089
|
+
if (!IN_BROWSER) return shallowRef(false);
|
|
1090
|
+
const {
|
|
1091
|
+
ssr
|
|
1092
|
+
} = useDisplay();
|
|
1093
|
+
if (ssr) {
|
|
1094
|
+
const isMounted = shallowRef(false);
|
|
1095
|
+
onMounted(() => {
|
|
1096
|
+
isMounted.value = true;
|
|
1097
|
+
});
|
|
1098
|
+
return isMounted;
|
|
1099
|
+
} else {
|
|
1100
|
+
return shallowRef(true);
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
// Composables
|
|
1105
|
+
const StackSymbol = Symbol.for('vuetify:stack');
|
|
1106
|
+
const globalStack = reactive([]);
|
|
1107
|
+
function useStack(isActive, zIndex, disableGlobalStack) {
|
|
1108
|
+
const vm = getCurrentInstance('useStack');
|
|
1109
|
+
const createStackEntry = !disableGlobalStack;
|
|
1110
|
+
const parent = inject(StackSymbol, undefined);
|
|
1111
|
+
const stack = reactive({
|
|
1112
|
+
activeChildren: new Set()
|
|
1113
|
+
});
|
|
1114
|
+
provide(StackSymbol, stack);
|
|
1115
|
+
const _zIndex = shallowRef(+zIndex.value);
|
|
1116
|
+
useToggleScope(isActive, () => {
|
|
1117
|
+
const lastZIndex = globalStack.at(-1)?.[1];
|
|
1118
|
+
_zIndex.value = lastZIndex ? lastZIndex + 10 : +zIndex.value;
|
|
1119
|
+
if (createStackEntry) {
|
|
1120
|
+
globalStack.push([vm.uid, _zIndex.value]);
|
|
1121
|
+
}
|
|
1122
|
+
parent?.activeChildren.add(vm.uid);
|
|
1123
|
+
onScopeDispose(() => {
|
|
1124
|
+
if (createStackEntry) {
|
|
1125
|
+
const idx = toRaw(globalStack).findIndex(v => v[0] === vm.uid);
|
|
1126
|
+
globalStack.splice(idx, 1);
|
|
1127
|
+
}
|
|
1128
|
+
parent?.activeChildren.delete(vm.uid);
|
|
1129
|
+
});
|
|
1130
|
+
});
|
|
1131
|
+
const globalTop = shallowRef(true);
|
|
1132
|
+
if (createStackEntry) {
|
|
1133
|
+
watchEffect(() => {
|
|
1134
|
+
const _isTop = globalStack.at(-1)?.[0] === vm.uid;
|
|
1135
|
+
setTimeout(() => globalTop.value = _isTop);
|
|
1136
|
+
});
|
|
1137
|
+
}
|
|
1138
|
+
const localTop = computed(() => !stack.activeChildren.size);
|
|
1139
|
+
return {
|
|
1140
|
+
globalTop: readonly(globalTop),
|
|
1141
|
+
localTop,
|
|
1142
|
+
stackStyles: computed(() => ({
|
|
1143
|
+
zIndex: _zIndex.value
|
|
1144
|
+
}))
|
|
1145
|
+
};
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
// Utilities
|
|
1149
|
+
function useTeleport(target) {
|
|
1150
|
+
const teleportTarget = computed(() => {
|
|
1151
|
+
const _target = target();
|
|
1152
|
+
if (_target === true || !IN_BROWSER) return undefined;
|
|
1153
|
+
const targetElement = _target === false ? document.body : typeof _target === 'string' ? document.querySelector(_target) : _target;
|
|
1154
|
+
if (targetElement == null) {
|
|
1155
|
+
warn(`Unable to locate target ${_target}`);
|
|
1156
|
+
return undefined;
|
|
1157
|
+
}
|
|
1158
|
+
let container = [...targetElement.children].find(el => el.matches('.v-overlay-container'));
|
|
1159
|
+
if (!container) {
|
|
1160
|
+
container = document.createElement('div');
|
|
1161
|
+
container.className = 'v-overlay-container';
|
|
1162
|
+
targetElement.appendChild(container);
|
|
1163
|
+
}
|
|
1164
|
+
return container;
|
|
1165
|
+
});
|
|
1166
|
+
return {
|
|
1167
|
+
teleportTarget
|
|
1168
|
+
};
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
function Scrim(props) {
|
|
1172
|
+
const {
|
|
1173
|
+
modelValue,
|
|
1174
|
+
color,
|
|
1175
|
+
...rest
|
|
1176
|
+
} = props;
|
|
1177
|
+
return createVNode(Transition, {
|
|
1178
|
+
"name": "fade-transition",
|
|
1179
|
+
"appear": true
|
|
1180
|
+
}, {
|
|
1181
|
+
default: () => [props.modelValue && createVNode("div", mergeProps({
|
|
1182
|
+
"class": ['v-overlay__scrim', props.color.backgroundColorClasses.value],
|
|
1183
|
+
"style": props.color.backgroundColorStyles.value
|
|
1184
|
+
}, rest), null)]
|
|
1185
|
+
});
|
|
1186
|
+
}
|
|
1187
|
+
const makeVOverlayProps = propsFactory({
|
|
1188
|
+
absolute: Boolean,
|
|
1189
|
+
attach: [Boolean, String, Object],
|
|
1190
|
+
closeOnBack: {
|
|
1191
|
+
type: Boolean,
|
|
1192
|
+
default: true
|
|
1193
|
+
},
|
|
1194
|
+
contained: Boolean,
|
|
1195
|
+
contentClass: null,
|
|
1196
|
+
contentProps: null,
|
|
1197
|
+
disabled: Boolean,
|
|
1198
|
+
opacity: [Number, String],
|
|
1199
|
+
noClickAnimation: Boolean,
|
|
1200
|
+
modelValue: Boolean,
|
|
1201
|
+
persistent: Boolean,
|
|
1202
|
+
scrim: {
|
|
1203
|
+
type: [Boolean, String],
|
|
1204
|
+
default: true
|
|
1205
|
+
},
|
|
1206
|
+
zIndex: {
|
|
1207
|
+
type: [Number, String],
|
|
1208
|
+
default: 2000
|
|
1209
|
+
},
|
|
1210
|
+
...makeActivatorProps(),
|
|
1211
|
+
...makeComponentProps(),
|
|
1212
|
+
...makeDimensionProps(),
|
|
1213
|
+
...makeLazyProps(),
|
|
1214
|
+
...makeLocationStrategyProps(),
|
|
1215
|
+
...makeScrollStrategyProps(),
|
|
1216
|
+
...makeThemeProps(),
|
|
1217
|
+
...makeTransitionProps()
|
|
1218
|
+
}, 'VOverlay');
|
|
1219
|
+
const VOverlay = genericComponent()({
|
|
1220
|
+
name: 'VOverlay',
|
|
1221
|
+
directives: {
|
|
1222
|
+
ClickOutside
|
|
1223
|
+
},
|
|
1224
|
+
inheritAttrs: false,
|
|
1225
|
+
props: {
|
|
1226
|
+
_disableGlobalStack: Boolean,
|
|
1227
|
+
...makeVOverlayProps()
|
|
1228
|
+
},
|
|
1229
|
+
emits: {
|
|
1230
|
+
'click:outside': e => true,
|
|
1231
|
+
'update:modelValue': value => true,
|
|
1232
|
+
afterEnter: () => true,
|
|
1233
|
+
afterLeave: () => true
|
|
1234
|
+
},
|
|
1235
|
+
setup(props, _ref) {
|
|
1236
|
+
let {
|
|
1237
|
+
slots,
|
|
1238
|
+
attrs,
|
|
1239
|
+
emit
|
|
1240
|
+
} = _ref;
|
|
1241
|
+
const vm = getCurrentInstance('VOverlay');
|
|
1242
|
+
const root = ref();
|
|
1243
|
+
const scrimEl = ref();
|
|
1244
|
+
const contentEl = ref();
|
|
1245
|
+
const model = useProxiedModel(props, 'modelValue');
|
|
1246
|
+
const isActive = computed({
|
|
1247
|
+
get: () => model.value,
|
|
1248
|
+
set: v => {
|
|
1249
|
+
if (!(v && props.disabled)) model.value = v;
|
|
1250
|
+
}
|
|
1251
|
+
});
|
|
1252
|
+
const {
|
|
1253
|
+
themeClasses
|
|
1254
|
+
} = provideTheme(props);
|
|
1255
|
+
const {
|
|
1256
|
+
rtlClasses,
|
|
1257
|
+
isRtl
|
|
1258
|
+
} = useRtl();
|
|
1259
|
+
const {
|
|
1260
|
+
hasContent,
|
|
1261
|
+
onAfterLeave: _onAfterLeave
|
|
1262
|
+
} = useLazy(props, isActive);
|
|
1263
|
+
const scrimColor = useBackgroundColor(computed(() => {
|
|
1264
|
+
return typeof props.scrim === 'string' ? props.scrim : null;
|
|
1265
|
+
}));
|
|
1266
|
+
const {
|
|
1267
|
+
globalTop,
|
|
1268
|
+
localTop,
|
|
1269
|
+
stackStyles
|
|
1270
|
+
} = useStack(isActive, toRef(props, 'zIndex'), props._disableGlobalStack);
|
|
1271
|
+
const {
|
|
1272
|
+
activatorEl,
|
|
1273
|
+
activatorRef,
|
|
1274
|
+
target,
|
|
1275
|
+
targetEl,
|
|
1276
|
+
targetRef,
|
|
1277
|
+
activatorEvents,
|
|
1278
|
+
contentEvents,
|
|
1279
|
+
scrimEvents
|
|
1280
|
+
} = useActivator(props, {
|
|
1281
|
+
isActive,
|
|
1282
|
+
isTop: localTop,
|
|
1283
|
+
contentEl
|
|
1284
|
+
});
|
|
1285
|
+
const {
|
|
1286
|
+
teleportTarget
|
|
1287
|
+
} = useTeleport(() => {
|
|
1288
|
+
const target = props.attach || props.contained;
|
|
1289
|
+
if (target) return target;
|
|
1290
|
+
const rootNode = activatorEl?.value?.getRootNode() || vm.proxy?.$el?.getRootNode();
|
|
1291
|
+
if (rootNode instanceof ShadowRoot) return rootNode;
|
|
1292
|
+
return false;
|
|
1293
|
+
});
|
|
1294
|
+
const {
|
|
1295
|
+
dimensionStyles
|
|
1296
|
+
} = useDimension(props);
|
|
1297
|
+
const isMounted = useHydration();
|
|
1298
|
+
const {
|
|
1299
|
+
scopeId
|
|
1300
|
+
} = useScopeId();
|
|
1301
|
+
watch(() => props.disabled, v => {
|
|
1302
|
+
if (v) isActive.value = false;
|
|
1303
|
+
});
|
|
1304
|
+
const {
|
|
1305
|
+
contentStyles,
|
|
1306
|
+
updateLocation
|
|
1307
|
+
} = useLocationStrategies(props, {
|
|
1308
|
+
isRtl,
|
|
1309
|
+
contentEl,
|
|
1310
|
+
target,
|
|
1311
|
+
isActive
|
|
1312
|
+
});
|
|
1313
|
+
useScrollStrategies(props, {
|
|
1314
|
+
root,
|
|
1315
|
+
contentEl,
|
|
1316
|
+
targetEl,
|
|
1317
|
+
isActive,
|
|
1318
|
+
updateLocation
|
|
1319
|
+
});
|
|
1320
|
+
function onClickOutside(e) {
|
|
1321
|
+
emit('click:outside', e);
|
|
1322
|
+
if (!props.persistent) isActive.value = false;else animateClick();
|
|
1323
|
+
}
|
|
1324
|
+
function closeConditional(e) {
|
|
1325
|
+
return isActive.value && globalTop.value && (
|
|
1326
|
+
// If using scrim, only close if clicking on it rather than anything opened on top
|
|
1327
|
+
!props.scrim || e.target === scrimEl.value || e instanceof MouseEvent && e.shadowTarget === scrimEl.value);
|
|
1328
|
+
}
|
|
1329
|
+
IN_BROWSER && watch(isActive, val => {
|
|
1330
|
+
if (val) {
|
|
1331
|
+
window.addEventListener('keydown', onKeydown);
|
|
1332
|
+
} else {
|
|
1333
|
+
window.removeEventListener('keydown', onKeydown);
|
|
1334
|
+
}
|
|
1335
|
+
}, {
|
|
1336
|
+
immediate: true
|
|
1337
|
+
});
|
|
1338
|
+
onBeforeUnmount(() => {
|
|
1339
|
+
if (!IN_BROWSER) return;
|
|
1340
|
+
window.removeEventListener('keydown', onKeydown);
|
|
1341
|
+
});
|
|
1342
|
+
function onKeydown(e) {
|
|
1343
|
+
if (e.key === 'Escape' && globalTop.value) {
|
|
1344
|
+
if (!props.persistent) {
|
|
1345
|
+
isActive.value = false;
|
|
1346
|
+
if (contentEl.value?.contains(document.activeElement)) {
|
|
1347
|
+
activatorEl.value?.focus();
|
|
1348
|
+
}
|
|
1349
|
+
} else animateClick();
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
const router = useRouter();
|
|
1353
|
+
useToggleScope(() => props.closeOnBack, () => {
|
|
1354
|
+
useBackButton(router, next => {
|
|
1355
|
+
if (globalTop.value && isActive.value) {
|
|
1356
|
+
next(false);
|
|
1357
|
+
if (!props.persistent) isActive.value = false;else animateClick();
|
|
1358
|
+
} else {
|
|
1359
|
+
next();
|
|
1360
|
+
}
|
|
1361
|
+
});
|
|
1362
|
+
});
|
|
1363
|
+
const top = ref();
|
|
1364
|
+
watch(() => isActive.value && (props.absolute || props.contained) && teleportTarget.value == null, val => {
|
|
1365
|
+
if (val) {
|
|
1366
|
+
const scrollParent = getScrollParent(root.value);
|
|
1367
|
+
if (scrollParent && scrollParent !== document.scrollingElement) {
|
|
1368
|
+
top.value = scrollParent.scrollTop;
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
});
|
|
1372
|
+
|
|
1373
|
+
// Add a quick "bounce" animation to the content
|
|
1374
|
+
function animateClick() {
|
|
1375
|
+
if (props.noClickAnimation) return;
|
|
1376
|
+
contentEl.value && animate(contentEl.value, [{
|
|
1377
|
+
transformOrigin: 'center'
|
|
1378
|
+
}, {
|
|
1379
|
+
transform: 'scale(1.03)'
|
|
1380
|
+
}, {
|
|
1381
|
+
transformOrigin: 'center'
|
|
1382
|
+
}], {
|
|
1383
|
+
duration: 150,
|
|
1384
|
+
easing: standardEasing
|
|
1385
|
+
});
|
|
1386
|
+
}
|
|
1387
|
+
function onAfterEnter() {
|
|
1388
|
+
emit('afterEnter');
|
|
1389
|
+
}
|
|
1390
|
+
function onAfterLeave() {
|
|
1391
|
+
_onAfterLeave();
|
|
1392
|
+
emit('afterLeave');
|
|
1393
|
+
}
|
|
1394
|
+
useRender(() => createVNode(Fragment, null, [slots.activator?.({
|
|
1395
|
+
isActive: isActive.value,
|
|
1396
|
+
targetRef,
|
|
1397
|
+
props: mergeProps({
|
|
1398
|
+
ref: activatorRef
|
|
1399
|
+
}, activatorEvents.value, props.activatorProps)
|
|
1400
|
+
}), isMounted.value && hasContent.value && createVNode(Teleport, {
|
|
1401
|
+
"disabled": !teleportTarget.value,
|
|
1402
|
+
"to": teleportTarget.value
|
|
1403
|
+
}, {
|
|
1404
|
+
default: () => [createVNode("div", mergeProps({
|
|
1405
|
+
"class": ['v-overlay', {
|
|
1406
|
+
'v-overlay--absolute': props.absolute || props.contained,
|
|
1407
|
+
'v-overlay--active': isActive.value,
|
|
1408
|
+
'v-overlay--contained': props.contained
|
|
1409
|
+
}, themeClasses.value, rtlClasses.value, props.class],
|
|
1410
|
+
"style": [stackStyles.value, {
|
|
1411
|
+
'--v-overlay-opacity': props.opacity,
|
|
1412
|
+
top: convertToUnit(top.value)
|
|
1413
|
+
}, props.style],
|
|
1414
|
+
"ref": root
|
|
1415
|
+
}, scopeId, attrs), [createVNode(Scrim, mergeProps({
|
|
1416
|
+
"color": scrimColor,
|
|
1417
|
+
"modelValue": isActive.value && !!props.scrim,
|
|
1418
|
+
"ref": scrimEl
|
|
1419
|
+
}, scrimEvents.value), null), createVNode(MaybeTransition, {
|
|
1420
|
+
"appear": true,
|
|
1421
|
+
"persisted": true,
|
|
1422
|
+
"transition": props.transition,
|
|
1423
|
+
"target": target.value,
|
|
1424
|
+
"onAfterEnter": onAfterEnter,
|
|
1425
|
+
"onAfterLeave": onAfterLeave
|
|
1426
|
+
}, {
|
|
1427
|
+
default: () => [withDirectives(createVNode("div", mergeProps({
|
|
1428
|
+
"ref": contentEl,
|
|
1429
|
+
"class": ['v-overlay__content', props.contentClass],
|
|
1430
|
+
"style": [dimensionStyles.value, contentStyles.value]
|
|
1431
|
+
}, contentEvents.value, props.contentProps), [slots.default?.({
|
|
1432
|
+
isActive
|
|
1433
|
+
})]), [[vShow, isActive.value], [resolveDirective("click-outside"), {
|
|
1434
|
+
handler: onClickOutside,
|
|
1435
|
+
closeConditional,
|
|
1436
|
+
include: () => [activatorEl.value]
|
|
1437
|
+
}]])]
|
|
1438
|
+
})])]
|
|
1439
|
+
})]));
|
|
1440
|
+
return {
|
|
1441
|
+
activatorEl,
|
|
1442
|
+
scrimEl,
|
|
1443
|
+
target,
|
|
1444
|
+
animateClick,
|
|
1445
|
+
contentEl,
|
|
1446
|
+
globalTop,
|
|
1447
|
+
localTop,
|
|
1448
|
+
updateLocation
|
|
1449
|
+
};
|
|
1450
|
+
}
|
|
1451
|
+
});
|
|
1452
|
+
|
|
1453
|
+
export { VOverlay as V, makeVOverlayProps as m };
|