@vmz/ui 0.1.0 → 0.1.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/README.md +8 -0
- package/contracts/token-requirements.v0.json +2 -6
- package/package.json +18 -2
- package/presets/web-surface.v0.json +24 -10
- package/src/components/Accordion.vmz +88 -89
- package/src/components/Alert.vmz +64 -63
- package/src/components/AppShell.vmz +64 -45
- package/src/components/Autocomplete.vmz +152 -151
- package/src/components/Avatar.vmz +16 -0
- package/src/components/Badge.vmz +46 -46
- package/src/components/Breadcrumb.vmz +52 -48
- package/src/components/BulkActions.vmz +37 -37
- package/src/components/Button.vmz +90 -75
- package/src/components/Callout.vmz +61 -61
- package/src/components/Card.vmz +58 -51
- package/src/components/Checkbox.vmz +56 -53
- package/src/components/CodeBlock.vmz +51 -51
- package/src/components/Collapse.vmz +20 -0
- package/src/components/ConsoleShell.vmz +134 -99
- package/src/components/Content.vmz +11 -0
- package/src/components/DataTable.vmz +197 -196
- package/src/components/DatePicker.vmz +613 -536
- package/src/components/Dialog.vmz +365 -384
- package/src/components/Divider.vmz +19 -0
- package/src/components/Drawer.vmz +361 -378
- package/src/components/Dropdown.vmz +22 -0
- package/src/components/Empty.vmz +36 -36
- package/src/components/Field.vmz +69 -40
- package/src/components/FilterBar.vmz +15 -15
- package/src/components/Flex.vmz +12 -0
- package/src/components/Footer.vmz +11 -0
- package/src/components/Form.vmz +56 -58
- package/src/components/FormItem.vmz +59 -59
- package/src/components/Grid.vmz +12 -0
- package/src/components/Header.vmz +11 -0
- package/src/components/Icon.vmz +86 -0
- package/src/components/Layout.vmz +11 -0
- package/src/components/Link.vmz +33 -33
- package/src/components/List.vmz +96 -96
- package/src/components/Menu.vmz +229 -240
- package/src/components/Notification.vmz +62 -62
- package/src/components/Pagination.vmz +63 -65
- package/src/components/Popover.vmz +202 -219
- package/src/components/Progress.vmz +18 -0
- package/src/components/Prose.vmz +61 -61
- package/src/components/QueryForm.vmz +26 -27
- package/src/components/RadioGroup.vmz +116 -113
- package/src/components/Result.vmz +63 -63
- package/src/components/Segmented.vmz +29 -0
- package/src/components/Select.vmz +462 -290
- package/src/components/Sider.vmz +6 -0
- package/src/components/Skeleton.vmz +58 -58
- package/src/components/Space.vmz +15 -0
- package/src/components/Spinner.vmz +29 -29
- package/src/components/Steps.vmz +86 -86
- package/src/components/Switch.vmz +86 -88
- package/src/components/Table.vmz +116 -114
- package/src/components/Tabs.vmz +113 -112
- package/src/components/Tag.vmz +8 -0
- package/src/components/TextArea.vmz +76 -49
- package/src/components/Timeline.vmz +55 -50
- package/src/components/Toc.vmz +64 -60
- package/src/components/Tooltip.vmz +51 -51
- package/src/components/Tree.vmz +184 -190
- package/src/components/Typography.vmz +9 -0
- package/src/components/Upload.vmz +1130 -1151
|
@@ -1,81 +1,79 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<nav class="vmz-ui-pagination" data-vmz-ui="pagination" aria-label={label}>
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
3
|
+
<button
|
|
4
|
+
type="button"
|
|
5
|
+
class="vmz-ui-pagination__btn"
|
|
6
|
+
disabled={prevDisabled}
|
|
7
|
+
onClick={onPrevClick}
|
|
8
|
+
>
|
|
9
|
+
Previous
|
|
10
|
+
</button>
|
|
11
|
+
<p class="vmz-ui-pagination__status" data-dogfood="page-status">{status}</p>
|
|
12
|
+
<button
|
|
13
|
+
type="button"
|
|
14
|
+
class="vmz-ui-pagination__btn"
|
|
15
|
+
disabled={nextDisabled}
|
|
16
|
+
onClick={onNextClick}
|
|
17
|
+
>
|
|
18
|
+
Next
|
|
19
|
+
</button>
|
|
20
|
+
</nav>
|
|
21
21
|
</template>
|
|
22
22
|
|
|
23
23
|
<style>
|
|
24
|
-
.vmz-ui-pagination {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
24
|
+
.vmz-ui-pagination {
|
|
25
|
+
display: flex;
|
|
26
|
+
flex-wrap: wrap;
|
|
27
|
+
align-items: center;
|
|
28
|
+
gap: 0.65rem 1rem;
|
|
29
|
+
}
|
|
30
30
|
|
|
31
|
-
.vmz-ui-pagination__btn {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
31
|
+
.vmz-ui-pagination__btn {
|
|
32
|
+
font: inherit;
|
|
33
|
+
font-weight: 600;
|
|
34
|
+
padding: 0.35rem 0.7rem;
|
|
35
|
+
border: 1px solid var(--vmz-line-default);
|
|
36
|
+
border-radius: var(--vmz-radius-md, 6px);
|
|
37
|
+
background: transparent;
|
|
38
|
+
color: var(--vmz-action-primary-active);
|
|
39
|
+
cursor: pointer;
|
|
40
|
+
outline: none;
|
|
41
|
+
}
|
|
42
42
|
|
|
43
|
-
.vmz-ui-pagination__btn:focus-visible {
|
|
44
|
-
|
|
45
|
-
}
|
|
43
|
+
.vmz-ui-pagination__btn:focus-visible {
|
|
44
|
+
box-shadow: 0 0 0 2px var(--vmz-focus-ring);
|
|
45
|
+
}
|
|
46
46
|
|
|
47
|
-
.vmz-ui-pagination__btn:disabled {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
47
|
+
.vmz-ui-pagination__btn:disabled {
|
|
48
|
+
opacity: 0.55;
|
|
49
|
+
cursor: not-allowed;
|
|
50
|
+
}
|
|
51
51
|
|
|
52
|
-
.vmz-ui-pagination__status {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
52
|
+
.vmz-ui-pagination__status {
|
|
53
|
+
margin: 0;
|
|
54
|
+
font-weight: 600;
|
|
55
|
+
}
|
|
56
56
|
</style>
|
|
57
57
|
|
|
58
58
|
<script client>
|
|
59
59
|
/**
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
* VMZ UI — Pagination (Console composition skeleton).
|
|
61
|
+
* Parent owns page / pageCount; buttons call onPrev / onNext.
|
|
62
|
+
*/
|
|
63
63
|
export default class Pagination {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
if (typeof this.onNext === 'function') this.onNext();
|
|
79
|
-
}
|
|
64
|
+
public label: string = "Pagination";
|
|
65
|
+
public status: string = "Page 1 / 1";
|
|
66
|
+
public prevDisabled: boolean = true;
|
|
67
|
+
public nextDisabled: boolean = true;
|
|
68
|
+
public onPrev: (() => void) | null = null;
|
|
69
|
+
public onNext: (() => void) | null = null;
|
|
70
|
+
onPrevClick() {
|
|
71
|
+
if (this.prevDisabled) return;
|
|
72
|
+
if (typeof this.onPrev === "function") this.onPrev();
|
|
73
|
+
}
|
|
74
|
+
onNextClick() {
|
|
75
|
+
if (this.nextDisabled) return;
|
|
76
|
+
if (typeof this.onNext === "function") this.onNext();
|
|
77
|
+
}
|
|
80
78
|
}
|
|
81
79
|
</script>
|
|
@@ -1,253 +1,236 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
>
|
|
7
|
-
<div
|
|
8
|
-
if={open}
|
|
9
|
-
class="vmz-ui-popover"
|
|
10
|
-
data-vmz-overlay="popover"
|
|
11
|
-
data-vmz-overlay-owner="popover"
|
|
12
|
-
data-vmz-overlay-stack={stackLevel}
|
|
3
|
+
class="vmz-ui-popover-root"
|
|
4
|
+
data-vmz-ui="popover"
|
|
5
|
+
data-vmz-overlay-open={open}
|
|
13
6
|
>
|
|
14
|
-
<button
|
|
15
|
-
type="button"
|
|
16
|
-
class="vmz-ui-popover__backdrop"
|
|
17
|
-
data-vmz-overlay-layer="backdrop"
|
|
18
|
-
aria-label="Dismiss popover"
|
|
19
|
-
onClick={dismiss}
|
|
20
|
-
></button>
|
|
21
7
|
<div
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
data-vmz-overlay-layer="panel"
|
|
28
|
-
data-vmz-focus="enter"
|
|
29
|
-
onKeyDown={onPanelKeyDown}
|
|
8
|
+
if={open}
|
|
9
|
+
class="vmz-ui-popover"
|
|
10
|
+
data-vmz-overlay="popover"
|
|
11
|
+
data-vmz-overlay-owner="popover"
|
|
12
|
+
data-vmz-overlay-stack={stackLevel}
|
|
30
13
|
>
|
|
31
|
-
<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
14
|
+
<button
|
|
15
|
+
type="button"
|
|
16
|
+
class="vmz-ui-popover__backdrop"
|
|
17
|
+
data-vmz-overlay-layer="backdrop"
|
|
18
|
+
aria-label="Dismiss popover"
|
|
19
|
+
onClick={dismiss}
|
|
20
|
+
></button>
|
|
21
|
+
<div
|
|
22
|
+
class="vmz-ui-popover__panel"
|
|
23
|
+
role="dialog"
|
|
24
|
+
aria-modal="false"
|
|
25
|
+
aria-labelledby={titleId}
|
|
26
|
+
tabindex="-1"
|
|
27
|
+
data-vmz-overlay-layer="panel"
|
|
28
|
+
data-vmz-focus="enter"
|
|
29
|
+
onKeyDown={onPanelKeyDown}
|
|
30
|
+
>
|
|
31
|
+
<h2 id={titleId} class="vmz-ui-popover__title">{title}</h2>
|
|
32
|
+
<div class="vmz-ui-popover__body">
|
|
33
|
+
<slot />
|
|
34
|
+
</div>
|
|
35
|
+
<div class="vmz-ui-popover__actions">
|
|
36
|
+
<button type="button" class="vmz-ui-popover__close" data-vmz-focus="close" onClick={dismiss}>
|
|
37
|
+
Close
|
|
38
|
+
</button>
|
|
39
|
+
</div>
|
|
39
40
|
</div>
|
|
40
41
|
</div>
|
|
41
42
|
</div>
|
|
42
|
-
</div>
|
|
43
43
|
</template>
|
|
44
44
|
|
|
45
45
|
<style>
|
|
46
|
-
.vmz-ui-popover-root {
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
.vmz-ui-popover {
|
|
51
|
-
position: fixed;
|
|
52
|
-
inset: 0;
|
|
53
|
-
z-index: 35;
|
|
54
|
-
pointer-events: none;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
.vmz-ui-popover[data-vmz-overlay-stack='1'] {
|
|
58
|
-
z-index: 50;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
.vmz-ui-popover[data-vmz-overlay-stack='2'] {
|
|
62
|
-
z-index: 60;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
.vmz-ui-popover[data-vmz-overlay-stack='3'] {
|
|
66
|
-
z-index: 70;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
.vmz-ui-popover__backdrop {
|
|
70
|
-
position: absolute;
|
|
71
|
-
inset: 0;
|
|
72
|
-
border: 0;
|
|
73
|
-
padding: 0;
|
|
74
|
-
margin: 0;
|
|
75
|
-
cursor: default;
|
|
76
|
-
background: transparent;
|
|
77
|
-
pointer-events: auto;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
.vmz-ui-popover__panel {
|
|
81
|
-
position: absolute;
|
|
82
|
-
z-index: 1;
|
|
83
|
-
top: 30%;
|
|
84
|
-
left: 50%;
|
|
85
|
-
transform: translateX(-50%);
|
|
86
|
-
box-sizing: border-box;
|
|
87
|
-
width: min(20rem, calc(100vw - 2rem));
|
|
88
|
-
min-height: 8rem;
|
|
89
|
-
padding: 0.85rem 1rem 1rem;
|
|
90
|
-
border: 1px solid var(--vmz-action-primary-background);
|
|
91
|
-
border-radius: 2px;
|
|
92
|
-
background: var(--vmz-action-primary-foreground);
|
|
93
|
-
color: var(--vmz-action-primary-active);
|
|
94
|
-
outline: none;
|
|
95
|
-
pointer-events: auto;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
.vmz-ui-popover__panel:focus-visible {
|
|
99
|
-
box-shadow: 0 0 0 2px var(--vmz-focus-ring);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
.vmz-ui-popover__title {
|
|
103
|
-
margin: 0 0 0.5rem;
|
|
104
|
-
font-size: 1rem;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
.vmz-ui-popover__body {
|
|
108
|
-
margin-bottom: 0.75rem;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
.vmz-ui-popover__close {
|
|
112
|
-
font: inherit;
|
|
113
|
-
font-weight: 600;
|
|
114
|
-
padding: 0.4rem 0.7rem;
|
|
115
|
-
border: 1px solid transparent;
|
|
116
|
-
border-radius: 2px;
|
|
117
|
-
cursor: pointer;
|
|
118
|
-
background: var(--vmz-action-primary-background);
|
|
119
|
-
color: var(--vmz-action-primary-foreground);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
.vmz-ui-popover__close:focus-visible {
|
|
123
|
-
box-shadow: 0 0 0 2px var(--vmz-focus-ring);
|
|
124
|
-
}
|
|
125
|
-
</style>
|
|
126
|
-
|
|
127
|
-
<script client>
|
|
128
|
-
/**
|
|
129
|
-
* VMZ UI — Popover (UI2).
|
|
130
|
-
* Non-modal disclosure: Escape + outside dismiss + focus enter/restore.
|
|
131
|
-
* Parent owns live `open`. Fixed min size for layout stability.
|
|
132
|
-
* `stackLevel` raises z-index; Escape dismisses only the topmost stacked overlay.
|
|
133
|
-
*/
|
|
134
|
-
export default class Popover {
|
|
135
|
-
public open: boolean = false;
|
|
136
|
-
public title: string = 'Popover';
|
|
137
|
-
public titleId: string = 'vmz-popover-title';
|
|
138
|
-
public stackLevel: string = '0';
|
|
139
|
-
public onClose: (() => void) | null = null;
|
|
46
|
+
.vmz-ui-popover-root {
|
|
47
|
+
display: block;
|
|
48
|
+
}
|
|
140
49
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
50
|
+
.vmz-ui-popover {
|
|
51
|
+
position: fixed;
|
|
52
|
+
inset: 0;
|
|
53
|
+
z-index: 35;
|
|
54
|
+
pointer-events: none;
|
|
55
|
+
}
|
|
145
56
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
const root = this.__vmzDomRoot;
|
|
149
|
-
if (!root || typeof root.querySelector !== 'function') return;
|
|
150
|
-
this._observer = new MutationObserver(() => this._syncFromDom());
|
|
151
|
-
this._observer.observe(root, { childList: true, subtree: true });
|
|
152
|
-
this._syncFromDom();
|
|
57
|
+
.vmz-ui-popover[data-vmz-overlay-stack='1'] {
|
|
58
|
+
z-index: 50;
|
|
153
59
|
}
|
|
154
60
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
this._observer.disconnect();
|
|
158
|
-
this._observer = null;
|
|
159
|
-
}
|
|
160
|
-
this._teardownDocKey();
|
|
161
|
-
this._panel = null;
|
|
162
|
-
this._restoreFocus = null;
|
|
61
|
+
.vmz-ui-popover[data-vmz-overlay-stack='2'] {
|
|
62
|
+
z-index: 60;
|
|
163
63
|
}
|
|
164
64
|
|
|
165
|
-
|
|
166
|
-
|
|
65
|
+
.vmz-ui-popover[data-vmz-overlay-stack='3'] {
|
|
66
|
+
z-index: 70;
|
|
167
67
|
}
|
|
168
68
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
69
|
+
.vmz-ui-popover__backdrop {
|
|
70
|
+
position: absolute;
|
|
71
|
+
inset: 0;
|
|
72
|
+
border: 0;
|
|
73
|
+
padding: 0;
|
|
74
|
+
margin: 0;
|
|
75
|
+
cursor: default;
|
|
76
|
+
background: transparent;
|
|
77
|
+
pointer-events: auto;
|
|
172
78
|
}
|
|
173
79
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
80
|
+
.vmz-ui-popover__panel {
|
|
81
|
+
position: absolute;
|
|
82
|
+
z-index: 1;
|
|
83
|
+
top: 30%;
|
|
84
|
+
left: 50%;
|
|
85
|
+
transform: translateX(-50%);
|
|
86
|
+
box-sizing: border-box;
|
|
87
|
+
width: min(20rem, calc(100vw - 2rem));
|
|
88
|
+
min-height: 8rem;
|
|
89
|
+
padding: 0.85rem 1rem 1rem;
|
|
90
|
+
border: 1px solid var(--vmz-line-default);
|
|
91
|
+
border-radius: var(--vmz-radius-md, 6px);
|
|
92
|
+
background: var(--vmz-action-primary-foreground);
|
|
93
|
+
color: var(--vmz-action-primary-active);
|
|
94
|
+
outline: none;
|
|
95
|
+
pointer-events: auto;
|
|
190
96
|
}
|
|
191
97
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
if (!this._isTopmostStack()) return;
|
|
195
|
-
ev.preventDefault();
|
|
196
|
-
ev.stopPropagation();
|
|
197
|
-
this.dismiss();
|
|
98
|
+
.vmz-ui-popover__panel:focus-visible {
|
|
99
|
+
box-shadow: 0 0 0 2px var(--vmz-focus-ring);
|
|
198
100
|
}
|
|
199
101
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
root && typeof root.querySelector === 'function'
|
|
204
|
-
? root.querySelector('[data-vmz-overlay="popover"] [data-vmz-focus="enter"]')
|
|
205
|
-
: null;
|
|
206
|
-
if (panel && !this._panel) this._enterFocus(panel);
|
|
207
|
-
else if (!panel && this._panel) this._exitFocus();
|
|
102
|
+
.vmz-ui-popover__title {
|
|
103
|
+
margin: 0 0 0.5rem;
|
|
104
|
+
font-size: 1rem;
|
|
208
105
|
}
|
|
209
106
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
const active = document.activeElement;
|
|
213
|
-
if (!this._restoreFocus) {
|
|
214
|
-
const root = this.__vmzDomRoot;
|
|
215
|
-
const outside =
|
|
216
|
-
active instanceof HTMLElement &&
|
|
217
|
-
active !== document.body &&
|
|
218
|
-
!(root && typeof root.contains === 'function' && root.contains(active));
|
|
219
|
-
if (outside) this._restoreFocus = active;
|
|
220
|
-
}
|
|
221
|
-
this._panel = panel instanceof HTMLElement ? panel : null;
|
|
222
|
-
if (this._panel && typeof this._panel.focus === 'function') this._panel.focus();
|
|
223
|
-
if (!this._docKeyHandler) {
|
|
224
|
-
this._docKeyHandler = (ev) => {
|
|
225
|
-
if (ev.key !== 'Escape') return;
|
|
226
|
-
if (ev.defaultPrevented) return;
|
|
227
|
-
if (!this._isTopmostStack()) return;
|
|
228
|
-
ev.preventDefault();
|
|
229
|
-
ev.stopPropagation();
|
|
230
|
-
this.dismiss();
|
|
231
|
-
};
|
|
232
|
-
document.addEventListener('keydown', this._docKeyHandler);
|
|
233
|
-
}
|
|
107
|
+
.vmz-ui-popover__body {
|
|
108
|
+
margin-bottom: 0.75rem;
|
|
234
109
|
}
|
|
235
110
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
111
|
+
.vmz-ui-popover__close {
|
|
112
|
+
font: inherit;
|
|
113
|
+
font-weight: 600;
|
|
114
|
+
padding: 0.4rem 0.7rem;
|
|
115
|
+
border: 1px solid transparent;
|
|
116
|
+
border-radius: var(--vmz-radius-md, 6px);
|
|
117
|
+
cursor: pointer;
|
|
118
|
+
background: var(--vmz-action-primary-background);
|
|
119
|
+
color: var(--vmz-action-primary-foreground);
|
|
244
120
|
}
|
|
245
121
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
document.removeEventListener('keydown', this._docKeyHandler);
|
|
249
|
-
}
|
|
250
|
-
this._docKeyHandler = null;
|
|
122
|
+
.vmz-ui-popover__close:focus-visible {
|
|
123
|
+
box-shadow: 0 0 0 2px var(--vmz-focus-ring);
|
|
251
124
|
}
|
|
125
|
+
</style>
|
|
126
|
+
|
|
127
|
+
<script client>
|
|
128
|
+
/**
|
|
129
|
+
* VMZ UI — Popover (UI2).
|
|
130
|
+
* Non-modal disclosure: Escape + outside dismiss + focus enter/restore.
|
|
131
|
+
* Parent owns live `open`. Fixed min size for layout stability.
|
|
132
|
+
* `stackLevel` raises z-index; Escape dismisses only the topmost stacked overlay.
|
|
133
|
+
*/
|
|
134
|
+
export default class Popover {
|
|
135
|
+
public open: boolean = false;
|
|
136
|
+
public title: string = "Popover";
|
|
137
|
+
public titleId: string = "vmz-popover-title";
|
|
138
|
+
public stackLevel: string = "0";
|
|
139
|
+
public onClose: (() => void) | null = null;
|
|
140
|
+
_restoreFocus = null;
|
|
141
|
+
_panel = null;
|
|
142
|
+
_docKeyHandler = null;
|
|
143
|
+
_observer = null;
|
|
144
|
+
async onMount() {
|
|
145
|
+
if (typeof document === "undefined" || typeof MutationObserver === "undefined") return;
|
|
146
|
+
const root = this.__vmzDomRoot;
|
|
147
|
+
if (!root || typeof root.querySelector !== "function") return;
|
|
148
|
+
this._observer = new MutationObserver(() => this._syncFromDom());
|
|
149
|
+
this._observer.observe(root, {
|
|
150
|
+
childList: true,
|
|
151
|
+
subtree: true
|
|
152
|
+
});
|
|
153
|
+
this._syncFromDom();
|
|
154
|
+
}
|
|
155
|
+
onDestroy() {
|
|
156
|
+
if (this._observer) {
|
|
157
|
+
this._observer.disconnect();
|
|
158
|
+
this._observer = null;
|
|
159
|
+
}
|
|
160
|
+
this._teardownDocKey();
|
|
161
|
+
this._panel = null;
|
|
162
|
+
this._restoreFocus = null;
|
|
163
|
+
}
|
|
164
|
+
dismiss() {
|
|
165
|
+
if (typeof this.onClose === "function") this.onClose();
|
|
166
|
+
}
|
|
167
|
+
_stackValue() {
|
|
168
|
+
const n = Number(this.stackLevel);
|
|
169
|
+
return Number.isFinite(n) ? n : 0;
|
|
170
|
+
}
|
|
171
|
+
_isTopmostStack() {
|
|
172
|
+
if (typeof document === "undefined") return true;
|
|
173
|
+
const root = this.__vmzDomRoot;
|
|
174
|
+
const mine = root && typeof root.querySelector === "function" ? root.querySelector("[data-vmz-overlay][data-vmz-overlay-stack]") : null;
|
|
175
|
+
const myStack = Number(mine?.getAttribute("data-vmz-overlay-stack") || this.stackLevel || "0");
|
|
176
|
+
const open = document.querySelectorAll("[data-vmz-overlay][data-vmz-overlay-stack]");
|
|
177
|
+
let max = -Infinity;
|
|
178
|
+
for (const el of open) {
|
|
179
|
+
const n = Number(el.getAttribute("data-vmz-overlay-stack") || "0");
|
|
180
|
+
if (Number.isFinite(n) && n > max) max = n;
|
|
181
|
+
}
|
|
182
|
+
if (!Number.isFinite(max)) return true;
|
|
183
|
+
return (Number.isFinite(myStack) ? myStack : 0) >= max;
|
|
184
|
+
}
|
|
185
|
+
onPanelKeyDown(ev) {
|
|
186
|
+
if (!ev || ev.key !== "Escape") return;
|
|
187
|
+
if (!this._isTopmostStack()) return;
|
|
188
|
+
ev.preventDefault();
|
|
189
|
+
ev.stopPropagation();
|
|
190
|
+
this.dismiss();
|
|
191
|
+
}
|
|
192
|
+
_syncFromDom() {
|
|
193
|
+
const root = this.__vmzDomRoot;
|
|
194
|
+
const panel = root && typeof root.querySelector === "function" ? root.querySelector("[data-vmz-overlay=\"popover\"] [data-vmz-focus=\"enter\"]") : null;
|
|
195
|
+
if (panel && !this._panel) this._enterFocus(panel);
|
|
196
|
+
else if (!panel && this._panel) this._exitFocus();
|
|
197
|
+
}
|
|
198
|
+
_enterFocus(panel) {
|
|
199
|
+
if (typeof document === "undefined") return;
|
|
200
|
+
const active = document.activeElement;
|
|
201
|
+
if (!this._restoreFocus) {
|
|
202
|
+
const root = this.__vmzDomRoot;
|
|
203
|
+
const outside = active instanceof HTMLElement && active !== document.body && !(root && typeof root.contains === "function" && root.contains(active));
|
|
204
|
+
if (outside) this._restoreFocus = active;
|
|
205
|
+
}
|
|
206
|
+
this._panel = panel instanceof HTMLElement ? panel : null;
|
|
207
|
+
if (this._panel && typeof this._panel.focus === "function") this._panel.focus();
|
|
208
|
+
if (!this._docKeyHandler) {
|
|
209
|
+
this._docKeyHandler = (ev) => {
|
|
210
|
+
if (ev.key !== "Escape") return;
|
|
211
|
+
if (ev.defaultPrevented) return;
|
|
212
|
+
if (!this._isTopmostStack()) return;
|
|
213
|
+
ev.preventDefault();
|
|
214
|
+
ev.stopPropagation();
|
|
215
|
+
this.dismiss();
|
|
216
|
+
};
|
|
217
|
+
document.addEventListener("keydown", this._docKeyHandler);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
_exitFocus() {
|
|
221
|
+
this._teardownDocKey();
|
|
222
|
+
this._panel = null;
|
|
223
|
+
const restore = this._restoreFocus;
|
|
224
|
+
this._restoreFocus = null;
|
|
225
|
+
if (restore && typeof restore.focus === "function" && document.contains(restore)) {
|
|
226
|
+
restore.focus();
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
_teardownDocKey() {
|
|
230
|
+
if (typeof document !== "undefined" && this._docKeyHandler) {
|
|
231
|
+
document.removeEventListener("keydown", this._docKeyHandler);
|
|
232
|
+
}
|
|
233
|
+
this._docKeyHandler = null;
|
|
234
|
+
}
|
|
252
235
|
}
|
|
253
236
|
</script>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="vmz-ui-progress" data-vmz-ui="progress" role="progressbar" aria-valuemin={0} aria-valuemax={100} aria-valuenow={percent}>
|
|
3
|
+
<div class="vmz-ui-progress__track"><span style={'width:' + percent + '%'}></span></div>
|
|
4
|
+
<span if={showInfo} class="vmz-ui-progress__text">{percent}%</span>
|
|
5
|
+
</div>
|
|
6
|
+
</template>
|
|
7
|
+
<style>
|
|
8
|
+
.vmz-ui-progress{display:flex;align-items:center;gap:.75rem;width:100%}
|
|
9
|
+
.vmz-ui-progress__track{height:.5rem;flex:1;overflow:hidden;border-radius:999px;background:var(--vmz-surface-mist)}
|
|
10
|
+
.vmz-ui-progress__track span{display:block;height:100%;border-radius:inherit;background:var(--vmz-action-primary-background);transition:width var(--vmz-motion-control-duration,.16s)}
|
|
11
|
+
.vmz-ui-progress__text{min-width:2.5rem;color:var(--vmz-text-steel);font-size:.875rem}
|
|
12
|
+
</style>
|
|
13
|
+
<script client>
|
|
14
|
+
export default class Progress {
|
|
15
|
+
public percent: number = 0;
|
|
16
|
+
public showInfo: boolean = true;
|
|
17
|
+
}
|
|
18
|
+
</script>
|