@vmz/ui 0.2.3 → 0.2.5

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.
Files changed (63) hide show
  1. package/package.json +1 -1
  2. package/src/components/Accordion.vmz +46 -63
  3. package/src/components/Alert.vmz +35 -38
  4. package/src/components/AppShell.vmz +92 -75
  5. package/src/components/Autocomplete.vmz +91 -119
  6. package/src/components/Avatar.vmz +37 -8
  7. package/src/components/Badge.vmz +29 -23
  8. package/src/components/Breadcrumb.vmz +36 -34
  9. package/src/components/BulkActions.vmz +22 -28
  10. package/src/components/Button.vmz +139 -121
  11. package/src/components/Callout.vmz +33 -36
  12. package/src/components/Card.vmz +68 -51
  13. package/src/components/Checkbox.vmz +28 -47
  14. package/src/components/CodeBlock.vmz +31 -25
  15. package/src/components/Collapse.vmz +34 -16
  16. package/src/components/ConsoleShell.vmz +107 -110
  17. package/src/components/Content.vmz +8 -4
  18. package/src/components/DataTable.vmz +124 -150
  19. package/src/components/DatePicker.vmz +526 -521
  20. package/src/components/Dialog.vmz +408 -327
  21. package/src/components/Divider.vmz +38 -11
  22. package/src/components/Drawer.vmz +325 -318
  23. package/src/components/Dropdown.vmz +53 -19
  24. package/src/components/Empty.vmz +23 -21
  25. package/src/components/Field.vmz +77 -83
  26. package/src/components/FilterBar.vmz +8 -10
  27. package/src/components/Flex.vmz +21 -6
  28. package/src/components/Footer.vmz +9 -4
  29. package/src/components/Form.vmz +35 -46
  30. package/src/components/FormItem.vmz +44 -43
  31. package/src/components/Grid.vmz +22 -6
  32. package/src/components/Header.vmz +11 -4
  33. package/src/components/Icon.vmz +43 -44
  34. package/src/components/Layout.vmz +9 -4
  35. package/src/components/Link.vmz +17 -25
  36. package/src/components/List.vmz +62 -75
  37. package/src/components/Menu.vmz +182 -197
  38. package/src/components/Notification.vmz +35 -38
  39. package/src/components/Pagination.vmz +37 -47
  40. package/src/components/Popover.vmz +157 -171
  41. package/src/components/Progress.vmz +36 -10
  42. package/src/components/Prose.vmz +29 -31
  43. package/src/components/QueryForm.vmz +14 -22
  44. package/src/components/RadioGroup.vmz +70 -84
  45. package/src/components/Result.vmz +36 -38
  46. package/src/components/Segmented.vmz +43 -22
  47. package/src/components/Select.vmz +404 -411
  48. package/src/components/Sider.vmz +21 -4
  49. package/src/components/Skeleton.vmz +34 -42
  50. package/src/components/Space.vmz +24 -9
  51. package/src/components/Spinner.vmz +17 -23
  52. package/src/components/Steps.vmz +48 -51
  53. package/src/components/Switch.vmz +50 -60
  54. package/src/components/Table.vmz +81 -84
  55. package/src/components/Tabs.vmz +66 -88
  56. package/src/components/Tag.vmz +36 -11
  57. package/src/components/TextArea.vmz +73 -77
  58. package/src/components/Timeline.vmz +36 -32
  59. package/src/components/Toc.vmz +31 -37
  60. package/src/components/Tooltip.vmz +25 -35
  61. package/src/components/Tree.vmz +127 -144
  62. package/src/components/Typography.vmz +33 -7
  63. package/src/components/Upload.vmz +1135 -1057
@@ -1,73 +1,47 @@
1
1
  <template>
2
- <div
3
- class="vmz-ui-drawer-root"
4
- data-vmz-ui="drawer"
5
- :data-vmz-overlay-open="open"
6
- >
7
- <div
8
- v-if="open"
9
- class="vmz-ui-drawer"
10
- data-vmz-overlay="drawer"
11
- data-vmz-overlay-owner="drawer"
12
- :data-vmz-overlay-stack="stackLevel"
13
- >
14
- <button
15
- type="button"
16
- class="vmz-ui-drawer__backdrop"
17
- data-vmz-overlay-layer="backdrop"
18
- aria-label="Dismiss drawer"
19
- @click="dismiss"
20
- ></button>
21
- <div
22
- class="vmz-ui-drawer__panel"
23
- role="dialog"
24
- aria-modal="true"
25
- :aria-labelledby="titleId"
26
- tabindex="-1"
27
- data-vmz-overlay-layer="panel"
28
- data-vmz-focus="enter"
29
- data-vmz-motion="overlay-enter"
30
- data-vmz-motion-token="motion.overlay"
31
- :onKeyDown="onPanelKeyDown"
32
- >
33
- <h2 :id="titleId" class="vmz-ui-drawer__title">{{ title }}</h2>
34
- <div class="vmz-ui-drawer__body">
35
- <slot />
36
- </div>
37
- <div class="vmz-ui-drawer__actions">
38
- <button type="button" class="vmz-ui-drawer__close" data-vmz-focus="close" @click="dismiss">
39
- Close
40
- </button>
41
- </div>
2
+ <div data-vmz-ui="drawer" :data-vmz-overlay-open="open" class="vmz-ui-drawer-root">
3
+ <div v-if="open" data-vmz-overlay="drawer" data-vmz-overlay-owner="drawer" :data-vmz-overlay-stack="stackLevel" class="vmz-ui-drawer">
4
+ <button type="button" data-vmz-overlay-layer="backdrop" aria-label="Dismiss drawer" @click="dismiss" class="vmz-ui-drawer__backdrop" />
5
+ <div role="dialog" aria-modal="true" :aria-labelledby="titleId" tabindex="-1" data-vmz-overlay-layer="panel" data-vmz-focus="enter" data-vmz-motion="overlay-enter" data-vmz-motion-token="motion.overlay" :onKeyDown="onPanelKeyDown" class="vmz-ui-drawer__panel">
6
+ <h2 :id="titleId" class="vmz-ui-drawer__title">
7
+ {{ title }}
8
+ </h2>
9
+ <div class="vmz-ui-drawer__body">
10
+ <slot />
11
+ </div>
12
+ <div class="vmz-ui-drawer__actions">
13
+ <button type="button" data-vmz-focus="close" @click="dismiss" class="vmz-ui-drawer__close">
14
+ Close
15
+ </button>
16
+ </div>
17
+ </div>
42
18
  </div>
43
- </div>
44
19
  </div>
45
20
  </template>
46
-
47
21
  <style>
48
- .vmz-ui-drawer-root {
22
+ .vmz-ui-drawer-root {
49
23
  display: block;
50
- }
24
+ }
51
25
 
52
- .vmz-ui-drawer {
26
+ .vmz-ui-drawer {
53
27
  position: fixed;
54
28
  inset: 0;
55
29
  z-index: 40;
56
- }
30
+ }
57
31
 
58
- .vmz-ui-drawer[data-vmz-overlay-stack='1'] {
32
+ .vmz-ui-drawer[data-vmz-overlay-stack="1"] {
59
33
  z-index: 50;
60
- }
34
+ }
61
35
 
62
- .vmz-ui-drawer[data-vmz-overlay-stack='2'] {
36
+ .vmz-ui-drawer[data-vmz-overlay-stack="2"] {
63
37
  z-index: 60;
64
- }
38
+ }
65
39
 
66
- .vmz-ui-drawer[data-vmz-overlay-stack='3'] {
40
+ .vmz-ui-drawer[data-vmz-overlay-stack="3"] {
67
41
  z-index: 70;
68
- }
42
+ }
69
43
 
70
- .vmz-ui-drawer__backdrop {
44
+ .vmz-ui-drawer__backdrop {
71
45
  position: absolute;
72
46
  inset: 0;
73
47
  border: 0;
@@ -75,10 +49,11 @@
75
49
  margin: 0;
76
50
  cursor: pointer;
77
51
  background: rgba(0, 0, 0, 0.45);
78
- animation: vmz-ui-drawer-fade-in var(--vmz-motion-overlay-duration) var(--vmz-motion-overlay-easing);
79
- }
52
+ animation: vmz-ui-drawer-fade-in var(--vmz-motion-overlay-duration)
53
+ var(--vmz-motion-overlay-easing);
54
+ }
80
55
 
81
- .vmz-ui-drawer__panel {
56
+ .vmz-ui-drawer__panel {
82
57
  position: absolute;
83
58
  top: 0;
84
59
  right: 0;
@@ -94,41 +69,44 @@
94
69
  outline: none;
95
70
  display: flex;
96
71
  flex-direction: column;
97
- animation: vmz-ui-drawer-panel-in var(--vmz-motion-overlay-duration) var(--vmz-motion-overlay-easing);
98
- }
72
+ animation: vmz-ui-drawer-panel-in var(--vmz-motion-overlay-duration)
73
+ var(--vmz-motion-overlay-easing);
74
+ }
99
75
 
100
- .vmz-ui-drawer[data-vmz-motion-adopt='true'] .vmz-ui-drawer__backdrop,
101
- .vmz-ui-drawer[data-vmz-motion-adopt='true'] .vmz-ui-drawer__panel {
76
+ .vmz-ui-drawer[data-vmz-motion-adopt="true"] .vmz-ui-drawer__backdrop,
77
+ .vmz-ui-drawer[data-vmz-motion-adopt="true"] .vmz-ui-drawer__panel {
102
78
  animation: none;
103
- }
79
+ }
104
80
 
105
- .vmz-ui-drawer[data-vmz-motion-phase='exit'] .vmz-ui-drawer__backdrop {
106
- animation: vmz-ui-drawer-fade-out var(--vmz-motion-overlay-duration) var(--vmz-motion-overlay-easing);
107
- }
81
+ .vmz-ui-drawer[data-vmz-motion-phase="exit"] .vmz-ui-drawer__backdrop {
82
+ animation: vmz-ui-drawer-fade-out var(--vmz-motion-overlay-duration)
83
+ var(--vmz-motion-overlay-easing);
84
+ }
108
85
 
109
- .vmz-ui-drawer[data-vmz-motion-phase='exit'] .vmz-ui-drawer__panel {
110
- animation: vmz-ui-drawer-panel-out var(--vmz-motion-overlay-duration) var(--vmz-motion-overlay-easing);
111
- }
86
+ .vmz-ui-drawer[data-vmz-motion-phase="exit"] .vmz-ui-drawer__panel {
87
+ animation: vmz-ui-drawer-panel-out var(--vmz-motion-overlay-duration)
88
+ var(--vmz-motion-overlay-easing);
89
+ }
112
90
 
113
- .vmz-ui-drawer__panel:focus-visible {
91
+ .vmz-ui-drawer__panel:focus-visible {
114
92
  box-shadow: 0 0 0 2px var(--vmz-focus-ring);
115
- }
93
+ }
116
94
 
117
- .vmz-ui-drawer__title {
95
+ .vmz-ui-drawer__title {
118
96
  margin: 0 0 0.75rem;
119
97
  font-size: 1rem;
120
98
  font-weight: 600;
121
99
  color: var(--vmz-text-ink);
122
- }
100
+ }
123
101
 
124
- .vmz-ui-drawer__body {
102
+ .vmz-ui-drawer__body {
125
103
  flex: 1;
126
104
  margin-bottom: 1rem;
127
105
  overflow: auto;
128
106
  color: var(--vmz-text-ink);
129
- }
107
+ }
130
108
 
131
- .vmz-ui-drawer__close {
109
+ .vmz-ui-drawer__close {
132
110
  font: inherit;
133
111
  font-size: 0.875rem;
134
112
  font-weight: 400;
@@ -139,282 +117,311 @@
139
117
  cursor: pointer;
140
118
  background: var(--vmz-surface-paper, #fff);
141
119
  color: var(--vmz-text-ink);
142
- }
120
+ }
143
121
 
144
- .vmz-ui-drawer__close:hover {
122
+ .vmz-ui-drawer__close:hover {
145
123
  color: var(--vmz-action-primary-background);
146
124
  border-color: var(--vmz-action-primary-background);
147
- }
125
+ }
148
126
 
149
- .vmz-ui-drawer__close:focus-visible {
127
+ .vmz-ui-drawer__close:focus-visible {
150
128
  box-shadow: 0 0 0 2px var(--vmz-focus-ring);
151
- }
129
+ }
152
130
 
153
- @keyframes vmz-ui-drawer-fade-in {
131
+ @keyframes vmz-ui-drawer-fade-in {
154
132
  from {
155
- opacity: 0;
133
+ opacity: 0;
156
134
  }
157
135
  to {
158
- opacity: 1;
136
+ opacity: 1;
159
137
  }
160
- }
138
+ }
161
139
 
162
- @keyframes vmz-ui-drawer-panel-in {
140
+ @keyframes vmz-ui-drawer-panel-in {
163
141
  from {
164
- opacity: 0;
165
- transform: translateX(0.75rem);
142
+ opacity: 0;
143
+ transform: translateX(0.75rem);
166
144
  }
167
145
  to {
168
- opacity: 1;
169
- transform: none;
146
+ opacity: 1;
147
+ transform: none;
170
148
  }
171
- }
149
+ }
172
150
 
173
- @keyframes vmz-ui-drawer-fade-out {
151
+ @keyframes vmz-ui-drawer-fade-out {
174
152
  from {
175
- opacity: 1;
153
+ opacity: 1;
176
154
  }
177
155
  to {
178
- opacity: 0;
156
+ opacity: 0;
179
157
  }
180
- }
158
+ }
181
159
 
182
- @keyframes vmz-ui-drawer-panel-out {
160
+ @keyframes vmz-ui-drawer-panel-out {
183
161
  from {
184
- opacity: 1;
185
- transform: none;
162
+ opacity: 1;
163
+ transform: none;
186
164
  }
187
165
  to {
188
- opacity: 0;
189
- transform: translateX(0.75rem);
166
+ opacity: 0;
167
+ transform: translateX(0.75rem);
190
168
  }
191
- }
169
+ }
192
170
 
193
- @media (prefers-reduced-motion: reduce) {
171
+ @media (prefers-reduced-motion: reduce) {
194
172
  .vmz-ui-drawer__backdrop,
195
173
  .vmz-ui-drawer__panel,
196
- .vmz-ui-drawer[data-vmz-motion-phase='exit'] .vmz-ui-drawer__backdrop,
197
- .vmz-ui-drawer[data-vmz-motion-phase='exit'] .vmz-ui-drawer__panel {
198
- animation: none;
174
+ .vmz-ui-drawer[data-vmz-motion-phase="exit"] .vmz-ui-drawer__backdrop,
175
+ .vmz-ui-drawer[data-vmz-motion-phase="exit"] .vmz-ui-drawer__panel {
176
+ animation: none;
199
177
  }
200
- }
178
+ }
201
179
  </style>
202
-
203
180
  <script client>
204
181
  /**
205
- * VMZ UI — Drawer (UI2).
206
- * Same overlay ownership / focus / Escape / stack as Dialog.
207
- * SSR/resume adopt skips enter replay; dismiss plays overlay-exit then calls onClose.
208
- */
182
+ * VMZ UI — Drawer (UI2).
183
+ * Same overlay ownership / focus / Escape / stack as Dialog.
184
+ * SSR/resume adopt skips enter replay; dismiss plays overlay-exit then calls onClose.
185
+ */
209
186
  export default class Drawer {
210
- public open: boolean = false;
211
- public title: string = "Drawer";
212
- public titleId: string = "vmz-drawer-title";
213
- public stackLevel: string = "0";
214
- public onClose: (() => void) | null = null;
215
- _restoreFocus = null;
216
- _panel = null;
217
- _docKeyHandler = null;
218
- _observer = null;
219
- _adoptNextEnter = false;
220
- _exiting = false;
221
- _exitTimer = null;
222
- /** Motion generation — exit timer and cancel edges key off this owner counter. */
223
- _motionGen = 0;
224
- async onMount() {
225
- if (typeof document === "undefined" || typeof MutationObserver === "undefined") return;
226
- const root = this.__vmzDomRoot;
227
- if (!root || typeof root.querySelector !== "function") return;
228
- if (root.querySelector("[data-vmz-overlay=\"drawer\"]")) this._adoptNextEnter = true;
229
- this._observer = new MutationObserver(() => this._syncFromDom());
230
- this._observer.observe(root, {
231
- childList: true,
232
- subtree: true
233
- });
234
- this._syncFromDom();
235
- }
236
- onDestroy() {
237
- if (this._exitTimer) {
238
- clearTimeout(this._exitTimer);
239
- this._exitTimer = null;
240
- }
241
- this._exiting = false;
242
- if (this._observer) {
243
- this._observer.disconnect();
244
- this._observer = null;
245
- }
246
- this._teardownDocKey();
247
- this._panel = null;
248
- this._restoreFocus = null;
249
- }
250
- dismiss() {
251
- if (!this._isTopmostStack()) return;
252
- if (this._exiting) {
253
- this._cancelExit("reverse");
254
- return;
255
- }
256
- const panel = this._panel;
257
- const overlay = panel && typeof panel.closest === "function" ? panel.closest("[data-vmz-overlay=\"drawer\"]") : null;
258
- const reduce = typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
259
- if (panel && overlay && !reduce) {
260
- this._exiting = true;
261
- const exitGen = this._motionGen;
262
- overlay.setAttribute("data-vmz-motion-phase", "exit");
263
- overlay.removeAttribute("data-vmz-motion-cancelled");
264
- panel.setAttribute("data-vmz-motion", "overlay-exit");
265
- const ms = this._overlayDurationMs(panel);
266
- this._exitTimer = setTimeout(() => {
267
- this._exitTimer = null;
268
- if (!this._exiting || exitGen !== this._motionGen) return;
269
- this._exiting = false;
270
- this.emit("close");
271
- if (typeof this.onClose === "function") this.onClose();
272
- }, ms);
273
- return;
274
- }
275
- this.emit("close");
276
- if (typeof this.onClose === "function") this.onClose();
277
- }
278
- _cancelExit(reason) {
279
- if (this._exitTimer) {
280
- clearTimeout(this._exitTimer);
281
- this._exitTimer = null;
282
- }
283
- this._exiting = false;
284
- this._motionGen += 1;
285
- const panel = this._panel;
286
- const overlay = panel && typeof panel.closest === "function" ? panel.closest("[data-vmz-overlay=\"drawer\"]") : null;
287
- if (overlay) {
288
- overlay.removeAttribute("data-vmz-motion-phase");
289
- overlay.setAttribute("data-vmz-motion-cancelled", reason || "true");
290
- overlay.setAttribute("data-vmz-motion-gen", String(this._motionGen));
291
- }
292
- if (panel) {
293
- panel.setAttribute("data-vmz-motion", "overlay-enter");
294
- }
295
- }
296
- _overlayDurationMs(panel) {
297
- try {
298
- const raw = (getComputedStyle(panel).getPropertyValue("--vmz-motion-overlay-duration") || "").trim() || "180ms";
299
- if (raw.endsWith("ms")) return Math.max(0, Number.parseFloat(raw) || 180);
300
- if (raw.endsWith("s")) return Math.max(0, (Number.parseFloat(raw) || .18) * 1e3);
301
- return 180;
302
- } catch {
303
- return 180;
304
- }
305
- }
306
- _isTopmostStack() {
307
- if (typeof document === "undefined") return true;
308
- const root = this.__vmzDomRoot;
309
- const mine = root && typeof root.querySelector === "function" ? root.querySelector("[data-vmz-overlay][data-vmz-overlay-stack]") : null;
310
- if (!mine) return true;
311
- const myStack = Number(mine.getAttribute("data-vmz-overlay-stack") || this.stackLevel || "0");
312
- const open = [...document.querySelectorAll("[data-vmz-overlay][data-vmz-overlay-stack]")];
313
- let max = -Infinity;
314
- for (const el of open) {
315
- const n = Number(el.getAttribute("data-vmz-overlay-stack") || "0");
316
- if (Number.isFinite(n) && n > max) max = n;
317
- }
318
- if (!Number.isFinite(max)) return true;
319
- if ((Number.isFinite(myStack) ? myStack : 0) < max) return false;
320
- if ((Number.isFinite(myStack) ? myStack : 0) > max) return true;
321
- const same = open.filter((el) => Number(el.getAttribute("data-vmz-overlay-stack") || "0") === max);
322
- return same[same.length - 1] === mine;
323
- }
324
- onPanelKeyDown(ev) {
325
- if (!ev || ev.key !== "Tab") return;
326
- const panel = this._panel;
327
- if (!panel) return;
328
- const nodes = panel.querySelectorAll("a[href],button:not([disabled]),textarea:not([disabled]),input:not([disabled]),select:not([disabled]),[tabindex]:not([tabindex=\"-1\"])");
329
- const list = [];
330
- for (const n of nodes) {
331
- if (n instanceof HTMLElement && n.offsetParent !== null) list.push(n);
332
- }
333
- if (panel.tabIndex >= 0) list.unshift(panel);
334
- if (!list.length) {
335
- ev.preventDefault();
336
- panel.focus();
337
- return;
338
- }
339
- const first = list[0];
340
- const last = list[list.length - 1];
341
- const active = document.activeElement;
342
- if (ev.shiftKey) {
343
- if (active === first || active === panel) {
344
- ev.preventDefault();
345
- last.focus();
346
- }
347
- } else if (active === last) {
348
- ev.preventDefault();
349
- first.focus();
350
- }
351
- }
352
- _syncFromDom() {
353
- const root = this.__vmzDomRoot;
354
- const panel = root && typeof root.querySelector === "function" ? root.querySelector("[data-vmz-overlay=\"drawer\"] [data-vmz-focus=\"enter\"]") : null;
355
- if (panel && !this._panel) this._enterFocus(panel);
356
- else if (!panel && this._panel) this._exitFocus();
357
- }
358
- _enterFocus(panel) {
359
- if (typeof document === "undefined") return;
360
- const active = document.activeElement;
361
- if (!this._restoreFocus) {
362
- const root = this.__vmzDomRoot;
363
- const outside = active instanceof HTMLElement && active !== document.body && !(root && typeof root.contains === "function" && root.contains(active));
364
- if (outside) this._restoreFocus = active;
365
- }
366
- this._panel = panel instanceof HTMLElement ? panel : null;
367
- const overlay = this._panel && typeof this._panel.closest === "function" ? this._panel.closest("[data-vmz-overlay=\"drawer\"]") : null;
368
- if (this._exiting) {
369
- this._cancelExit("reenter");
370
- } else {
371
- this._motionGen += 1;
372
- }
373
- if (overlay) {
374
- overlay.setAttribute("data-vmz-motion-gen", String(this._motionGen));
375
- }
376
- if (this._adoptNextEnter && overlay) {
377
- overlay.setAttribute("data-vmz-motion-adopt", "true");
378
- this._panel.setAttribute("data-vmz-motion", "overlay-stable");
379
- this._adoptNextEnter = false;
380
- } else if (overlay) {
381
- overlay.removeAttribute("data-vmz-motion-adopt");
382
- overlay.removeAttribute("data-vmz-motion-phase");
383
- overlay.removeAttribute("data-vmz-motion-cancelled");
384
- this._panel.setAttribute("data-vmz-motion", "overlay-enter");
385
- }
386
- if (this._panel && typeof this._panel.focus === "function") this._panel.focus();
387
- if (!this._docKeyHandler) {
388
- this._docKeyHandler = (ev) => {
389
- if (ev.key !== "Escape") return;
390
- if (ev.defaultPrevented) return;
391
- if (!this._isTopmostStack()) return;
392
- ev.preventDefault();
393
- ev.stopPropagation();
394
- this.dismiss();
395
- };
396
- document.addEventListener("keydown", this._docKeyHandler);
397
- }
398
- }
399
- _exitFocus() {
400
- if (this._exitTimer) {
401
- clearTimeout(this._exitTimer);
402
- this._exitTimer = null;
403
- }
404
- this._exiting = false;
405
- this._teardownDocKey();
406
- this._panel = null;
407
- const restore = this._restoreFocus;
408
- this._restoreFocus = null;
409
- if (restore && typeof restore.focus === "function" && document.contains(restore)) {
410
- restore.focus();
411
- }
412
- }
413
- _teardownDocKey() {
414
- if (typeof document !== "undefined" && this._docKeyHandler) {
415
- document.removeEventListener("keydown", this._docKeyHandler);
416
- }
417
- this._docKeyHandler = null;
418
- }
187
+ public open: boolean = false;
188
+ public title: string = "Drawer";
189
+ public titleId: string = "vmz-drawer-title";
190
+ public stackLevel: string = "0";
191
+ public onClose: (() => void) | null = null;
192
+ _restoreFocus = null;
193
+ _panel = null;
194
+ _docKeyHandler = null;
195
+ _observer = null;
196
+ _adoptNextEnter = false;
197
+ _exiting = false;
198
+ _exitTimer = null;
199
+ /** Motion generation — exit timer and cancel edges key off this owner counter. */
200
+ _motionGen = 0;
201
+ async onMount() {
202
+ if (typeof document === "undefined" || typeof MutationObserver === "undefined") return;
203
+ const root = this.__vmzDomRoot;
204
+ if (!root || typeof root.querySelector !== "function") return;
205
+ if (root.querySelector('[data-vmz-overlay="drawer"]')) this._adoptNextEnter = true;
206
+ this._observer = new MutationObserver(() => this._syncFromDom());
207
+ this._observer.observe(root, {
208
+ childList: true,
209
+ subtree: true,
210
+ });
211
+ this._syncFromDom();
212
+ }
213
+ onDestroy() {
214
+ if (this._exitTimer) {
215
+ clearTimeout(this._exitTimer);
216
+ this._exitTimer = null;
217
+ }
218
+ this._exiting = false;
219
+ if (this._observer) {
220
+ this._observer.disconnect();
221
+ this._observer = null;
222
+ }
223
+ this._teardownDocKey();
224
+ this._panel = null;
225
+ this._restoreFocus = null;
226
+ }
227
+ dismiss() {
228
+ if (!this._isTopmostStack()) return;
229
+ if (this._exiting) {
230
+ this._cancelExit("reverse");
231
+ return;
232
+ }
233
+ const panel = this._panel;
234
+ const overlay =
235
+ panel && typeof panel.closest === "function"
236
+ ? panel.closest('[data-vmz-overlay="drawer"]')
237
+ : null;
238
+ const reduce =
239
+ typeof window !== "undefined" &&
240
+ typeof window.matchMedia === "function" &&
241
+ window.matchMedia("(prefers-reduced-motion: reduce)").matches;
242
+ if (panel && overlay && !reduce) {
243
+ this._exiting = true;
244
+ const exitGen = this._motionGen;
245
+ overlay.setAttribute("data-vmz-motion-phase", "exit");
246
+ overlay.removeAttribute("data-vmz-motion-cancelled");
247
+ panel.setAttribute("data-vmz-motion", "overlay-exit");
248
+ const ms = this._overlayDurationMs(panel);
249
+ this._exitTimer = setTimeout(() => {
250
+ this._exitTimer = null;
251
+ if (!this._exiting || exitGen !== this._motionGen) return;
252
+ this._exiting = false;
253
+ this.emit("close");
254
+ if (typeof this.onClose === "function") this.onClose();
255
+ }, ms);
256
+ return;
257
+ }
258
+ this.emit("close");
259
+ if (typeof this.onClose === "function") this.onClose();
260
+ }
261
+ _cancelExit(reason) {
262
+ if (this._exitTimer) {
263
+ clearTimeout(this._exitTimer);
264
+ this._exitTimer = null;
265
+ }
266
+ this._exiting = false;
267
+ this._motionGen += 1;
268
+ const panel = this._panel;
269
+ const overlay =
270
+ panel && typeof panel.closest === "function"
271
+ ? panel.closest('[data-vmz-overlay="drawer"]')
272
+ : null;
273
+ if (overlay) {
274
+ overlay.removeAttribute("data-vmz-motion-phase");
275
+ overlay.setAttribute("data-vmz-motion-cancelled", reason || "true");
276
+ overlay.setAttribute("data-vmz-motion-gen", String(this._motionGen));
277
+ }
278
+ if (panel) {
279
+ panel.setAttribute("data-vmz-motion", "overlay-enter");
280
+ }
281
+ }
282
+ _overlayDurationMs(panel) {
283
+ try {
284
+ const raw =
285
+ (
286
+ getComputedStyle(panel).getPropertyValue("--vmz-motion-overlay-duration") || ""
287
+ ).trim() || "180ms";
288
+ if (raw.endsWith("ms")) return Math.max(0, Number.parseFloat(raw) || 180);
289
+ if (raw.endsWith("s")) return Math.max(0, (Number.parseFloat(raw) || 0.18) * 1e3);
290
+ return 180;
291
+ } catch {
292
+ return 180;
293
+ }
294
+ }
295
+ _isTopmostStack() {
296
+ if (typeof document === "undefined") return true;
297
+ const root = this.__vmzDomRoot;
298
+ const mine =
299
+ root && typeof root.querySelector === "function"
300
+ ? root.querySelector("[data-vmz-overlay][data-vmz-overlay-stack]")
301
+ : null;
302
+ if (!mine) return true;
303
+ const myStack = Number(
304
+ mine.getAttribute("data-vmz-overlay-stack") || this.stackLevel || "0",
305
+ );
306
+ const open = [...document.querySelectorAll("[data-vmz-overlay][data-vmz-overlay-stack]")];
307
+ let max = -Infinity;
308
+ for (const el of open) {
309
+ const n = Number(el.getAttribute("data-vmz-overlay-stack") || "0");
310
+ if (Number.isFinite(n) && n > max) max = n;
311
+ }
312
+ if (!Number.isFinite(max)) return true;
313
+ if ((Number.isFinite(myStack) ? myStack : 0) < max) return false;
314
+ if ((Number.isFinite(myStack) ? myStack : 0) > max) return true;
315
+ const same = open.filter(
316
+ (el) => Number(el.getAttribute("data-vmz-overlay-stack") || "0") === max,
317
+ );
318
+ return same[same.length - 1] === mine;
319
+ }
320
+ onPanelKeyDown(ev) {
321
+ if (!ev || ev.key !== "Tab") return;
322
+ const panel = this._panel;
323
+ if (!panel) return;
324
+ const nodes = panel.querySelectorAll(
325
+ 'a[href],button:not([disabled]),textarea:not([disabled]),input:not([disabled]),select:not([disabled]),[tabindex]:not([tabindex="-1"])',
326
+ );
327
+ const list = [];
328
+ for (const n of nodes) {
329
+ if (n instanceof HTMLElement && n.offsetParent !== null) list.push(n);
330
+ }
331
+ if (panel.tabIndex >= 0) list.unshift(panel);
332
+ if (!list.length) {
333
+ ev.preventDefault();
334
+ panel.focus();
335
+ return;
336
+ }
337
+ const first = list[0];
338
+ const last = list[list.length - 1];
339
+ const active = document.activeElement;
340
+ if (ev.shiftKey) {
341
+ if (active === first || active === panel) {
342
+ ev.preventDefault();
343
+ last.focus();
344
+ }
345
+ } else if (active === last) {
346
+ ev.preventDefault();
347
+ first.focus();
348
+ }
349
+ }
350
+ _syncFromDom() {
351
+ const root = this.__vmzDomRoot;
352
+ const panel =
353
+ root && typeof root.querySelector === "function"
354
+ ? root.querySelector('[data-vmz-overlay="drawer"] [data-vmz-focus="enter"]')
355
+ : null;
356
+ if (panel && !this._panel) this._enterFocus(panel);
357
+ else if (!panel && this._panel) this._exitFocus();
358
+ }
359
+ _enterFocus(panel) {
360
+ if (typeof document === "undefined") return;
361
+ const active = document.activeElement;
362
+ if (!this._restoreFocus) {
363
+ const root = this.__vmzDomRoot;
364
+ const outside =
365
+ active instanceof HTMLElement &&
366
+ active !== document.body &&
367
+ !(root && typeof root.contains === "function" && root.contains(active));
368
+ if (outside) this._restoreFocus = active;
369
+ }
370
+ this._panel = panel instanceof HTMLElement ? panel : null;
371
+ const overlay =
372
+ this._panel && typeof this._panel.closest === "function"
373
+ ? this._panel.closest('[data-vmz-overlay="drawer"]')
374
+ : null;
375
+ if (this._exiting) {
376
+ this._cancelExit("reenter");
377
+ } else {
378
+ this._motionGen += 1;
379
+ }
380
+ if (overlay) {
381
+ overlay.setAttribute("data-vmz-motion-gen", String(this._motionGen));
382
+ }
383
+ if (this._adoptNextEnter && overlay) {
384
+ overlay.setAttribute("data-vmz-motion-adopt", "true");
385
+ this._panel.setAttribute("data-vmz-motion", "overlay-stable");
386
+ this._adoptNextEnter = false;
387
+ } else if (overlay) {
388
+ overlay.removeAttribute("data-vmz-motion-adopt");
389
+ overlay.removeAttribute("data-vmz-motion-phase");
390
+ overlay.removeAttribute("data-vmz-motion-cancelled");
391
+ this._panel.setAttribute("data-vmz-motion", "overlay-enter");
392
+ }
393
+ if (this._panel && typeof this._panel.focus === "function") this._panel.focus();
394
+ if (!this._docKeyHandler) {
395
+ this._docKeyHandler = (ev) => {
396
+ if (ev.key !== "Escape") return;
397
+ if (ev.defaultPrevented) return;
398
+ if (!this._isTopmostStack()) return;
399
+ ev.preventDefault();
400
+ ev.stopPropagation();
401
+ this.dismiss();
402
+ };
403
+ document.addEventListener("keydown", this._docKeyHandler);
404
+ }
405
+ }
406
+ _exitFocus() {
407
+ if (this._exitTimer) {
408
+ clearTimeout(this._exitTimer);
409
+ this._exitTimer = null;
410
+ }
411
+ this._exiting = false;
412
+ this._teardownDocKey();
413
+ this._panel = null;
414
+ const restore = this._restoreFocus;
415
+ this._restoreFocus = null;
416
+ if (restore && typeof restore.focus === "function" && document.contains(restore)) {
417
+ restore.focus();
418
+ }
419
+ }
420
+ _teardownDocKey() {
421
+ if (typeof document !== "undefined" && this._docKeyHandler) {
422
+ document.removeEventListener("keydown", this._docKeyHandler);
423
+ }
424
+ this._docKeyHandler = null;
425
+ }
419
426
  }
420
427
  </script>