@vmz/ui 0.3.6 → 0.3.7
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 +51 -51
- package/package.json +2 -2
- package/src/components/Accordion.vmz +94 -94
- package/src/components/AppShell.vmz +5 -2
- package/src/components/Autocomplete.vmz +154 -154
- package/src/components/Badge.vmz +70 -70
- package/src/components/Breadcrumb.vmz +72 -72
- package/src/components/BulkActions.vmz +51 -51
- package/src/components/Button.vmz +213 -211
- package/src/components/Callout.vmz +77 -77
- package/src/components/Card.vmz +120 -120
- package/src/components/Checkbox.vmz +55 -55
- package/src/components/CodeBlock.vmz +21 -6
- package/src/components/ConsoleShell.vmz +251 -251
- package/src/components/DataTable.vmz +194 -194
- package/src/components/DatePicker.vmz +674 -674
- package/src/components/Dialog.vmz +17 -1
- package/src/components/Drawer.vmz +427 -427
- package/src/components/Dropdown.vmz +51 -5
- package/src/components/Empty.vmz +54 -54
- package/src/components/Field.vmz +115 -115
- package/src/components/FormItem.vmz +79 -79
- package/src/components/Link.vmz +5 -1
- package/src/components/List.vmz +102 -102
- package/src/components/Menu.vmz +243 -243
- package/src/components/Pagination.vmz +71 -69
- package/src/components/Popover.vmz +223 -223
- package/src/components/Prose.vmz +81 -81
- package/src/components/RadioGroup.vmz +124 -124
- package/src/components/Segmented.vmz +51 -51
- package/src/components/Select.vmz +533 -533
- package/src/components/Steps.vmz +103 -103
- package/src/components/Switch.vmz +98 -98
- package/src/components/Table.vmz +165 -165
- package/src/components/Tabs.vmz +110 -110
- package/src/components/Tag.vmz +43 -43
- package/src/components/TextArea.vmz +118 -118
- package/src/components/Timeline.vmz +76 -76
- package/src/components/Toc.vmz +74 -74
- package/src/components/Tooltip.vmz +58 -58
- package/src/components/Tree.vmz +191 -191
- package/src/components/Upload.vmz +1299 -1289
|
@@ -5,8 +5,13 @@
|
|
|
5
5
|
</summary>
|
|
6
6
|
<div data-vmz-dropdown-menu="1" role="menu" class="vmz-ui-dropdown__menu">
|
|
7
7
|
<div v-for="item in items" :key="item.id" class="vmz-ui-dropdown__row">
|
|
8
|
-
<div v-if="item.divider" role="separator" class="vmz-ui-dropdown__divider"
|
|
9
|
-
<a v-else :href="item.href" role="menuitem" :data-vmz-dropdown-item="item.id" :data-danger="item.danger ? 'true' : 'false'" :data-disabled="item.disabled ? 'true' : 'false'" :aria-disabled="item.disabled ? 'true' : null" :tabindex="item.disabled ? -1 : null" class="vmz-ui-dropdown__item">
|
|
8
|
+
<div v-if="item.divider" role="separator" class="vmz-ui-dropdown__divider" />
|
|
9
|
+
<a v-else-if="hasHref(item)" :href="item.href" role="menuitem" :data-vmz-dropdown-item="item.id" :data-danger="item.danger ? 'true' : 'false'" :data-disabled="item.disabled ? 'true' : 'false'" :aria-disabled="item.disabled ? 'true' : null" :tabindex="item.disabled ? -1 : null" class="vmz-ui-dropdown__item">
|
|
10
|
+
{{ item.title }}
|
|
11
|
+
</a>
|
|
12
|
+
<button v-else type="button" role="menuitem" :data-vmz-dropdown-item="item.id" :data-danger="item.danger ? 'true' : 'false'" :data-disabled="item.disabled ? 'true' : 'false'" :aria-disabled="item.disabled ? 'true' : null" :tabindex="item.disabled ? -1 : null" @click="onItemClick" class="vmz-ui-dropdown__item">
|
|
13
|
+
{{ item.title }}
|
|
14
|
+
</button>
|
|
10
15
|
</div>
|
|
11
16
|
</div>
|
|
12
17
|
</details>
|
|
@@ -114,11 +119,17 @@
|
|
|
114
119
|
|
|
115
120
|
.vmz-ui-dropdown__item {
|
|
116
121
|
display: block;
|
|
122
|
+
width: 100%;
|
|
117
123
|
padding: 0.5rem 0.75rem;
|
|
124
|
+
border: 0;
|
|
118
125
|
border-radius: var(--vmz-radius-sm, 4px);
|
|
126
|
+
background: transparent;
|
|
119
127
|
color: var(--vmz-text-ink);
|
|
128
|
+
cursor: pointer;
|
|
129
|
+
font: inherit;
|
|
120
130
|
font-size: 0.875rem;
|
|
121
131
|
line-height: 1.4286;
|
|
132
|
+
text-align: left;
|
|
122
133
|
text-decoration: none;
|
|
123
134
|
outline: none;
|
|
124
135
|
transition:
|
|
@@ -158,16 +169,18 @@
|
|
|
158
169
|
<script client>
|
|
159
170
|
/**
|
|
160
171
|
* VMZ UI — Dropdown (Menu).
|
|
161
|
-
* Native `<details>` disclosure: works without JS
|
|
162
|
-
*
|
|
172
|
+
* Native `<details>` disclosure: works without JS. An item with a non-empty
|
|
173
|
+
* `href` is a plain link; an item without `href` is an action button that
|
|
174
|
+
* notifies via `onSelect(id)`. Selection handlers never navigate.
|
|
163
175
|
*/
|
|
164
176
|
export type DropdownItem = {
|
|
165
177
|
id: string;
|
|
166
178
|
title: string;
|
|
179
|
+
/** Non-empty → link item (native navigation). Empty/absent → action item. */
|
|
167
180
|
href?: string;
|
|
168
181
|
/** Destructive action styling. */
|
|
169
182
|
danger?: boolean;
|
|
170
|
-
/** Non-interactive state. */
|
|
183
|
+
/** Non-interactive state: neither navigates nor selects. */
|
|
171
184
|
disabled?: boolean;
|
|
172
185
|
/** Render a separator instead of a row (title/href are ignored). */
|
|
173
186
|
divider?: boolean;
|
|
@@ -176,5 +189,38 @@ export type DropdownItem = {
|
|
|
176
189
|
export default class Dropdown {
|
|
177
190
|
public label: string = "Menu";
|
|
178
191
|
public items: DropdownItem[] = [];
|
|
192
|
+
/** Action-item selection callback (`:on-select`). Link items bypass it. */
|
|
193
|
+
public onSelect: ((id: string) => void) | null = null;
|
|
194
|
+
|
|
195
|
+
hasHref(item) {
|
|
196
|
+
return typeof item?.href === "string" && item.href.length > 0;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
onItemClick(ev) {
|
|
200
|
+
const el = ev && ev.currentTarget;
|
|
201
|
+
const id =
|
|
202
|
+
el && typeof el.getAttribute === "function"
|
|
203
|
+
? el.getAttribute("data-vmz-dropdown-item")
|
|
204
|
+
: null;
|
|
205
|
+
if (!id) return;
|
|
206
|
+
const item = this.items.find((candidate) => candidate.id === id);
|
|
207
|
+
if (!item || item.disabled || this.hasHref(item)) return;
|
|
208
|
+
this.close();
|
|
209
|
+
if (typeof this.onSelect === "function") this.onSelect(id);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
close() {
|
|
213
|
+
const root = this.__vmzDomRoot;
|
|
214
|
+
if (!root) return;
|
|
215
|
+
const details =
|
|
216
|
+
root.tagName === "DETAILS"
|
|
217
|
+
? root
|
|
218
|
+
: typeof root.closest === "function"
|
|
219
|
+
? root.closest("details")
|
|
220
|
+
: null;
|
|
221
|
+
if (details && typeof details.removeAttribute === "function") {
|
|
222
|
+
details.removeAttribute("open");
|
|
223
|
+
}
|
|
224
|
+
}
|
|
179
225
|
}
|
|
180
226
|
</script>
|
package/src/components/Empty.vmz
CHANGED
|
@@ -1,54 +1,54 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div data-vmz-ui="empty" class="vmz-ui-empty">
|
|
3
|
-
<h2 class="vmz-ui-empty__title">
|
|
4
|
-
{{ title }}
|
|
5
|
-
</h2>
|
|
6
|
-
<p v-if="description" class="vmz-ui-empty__description">
|
|
7
|
-
{{ description }}
|
|
8
|
-
</p>
|
|
9
|
-
<div class="vmz-ui-empty__actions">
|
|
10
|
-
<slot />
|
|
11
|
-
</div>
|
|
12
|
-
</div>
|
|
13
|
-
</template>
|
|
14
|
-
<style>
|
|
15
|
-
.vmz-ui-empty {
|
|
16
|
-
display: flex;
|
|
17
|
-
flex-direction: column;
|
|
18
|
-
align-items: flex-start;
|
|
19
|
-
gap: 0.625rem;
|
|
20
|
-
padding: 1.5rem 1.15rem;
|
|
21
|
-
border: 1px dashed var(--vmz-line-default);
|
|
22
|
-
border-radius: var(--vmz-radius-md, 6px);
|
|
23
|
-
background: color-mix(in srgb, var(--vmz-surface-mist) 70%, var(--vmz-surface-paper));
|
|
24
|
-
color: var(--vmz-text-ink);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
.vmz-ui-empty__title {
|
|
28
|
-
margin: 0;
|
|
29
|
-
font-family: var(--vmz-font-display);
|
|
30
|
-
font-size: 1.1rem;
|
|
31
|
-
font-weight: 700;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
.vmz-ui-empty__description {
|
|
35
|
-
margin: 0;
|
|
36
|
-
color: var(--vmz-text-steel);
|
|
37
|
-
max-width: 36rem;
|
|
38
|
-
line-height: 1.45;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
.vmz-ui-empty__actions:empty {
|
|
42
|
-
display: none;
|
|
43
|
-
}
|
|
44
|
-
</style>
|
|
45
|
-
<script client>
|
|
46
|
-
/**
|
|
47
|
-
* VMZ UI — Empty (Commercial composition).
|
|
48
|
-
* Empty / zero-state surface with optional action slot.
|
|
49
|
-
*/
|
|
50
|
-
export default class Empty {
|
|
51
|
-
public title: string = "Nothing here yet";
|
|
52
|
-
public description: string = "";
|
|
53
|
-
}
|
|
54
|
-
</script>
|
|
1
|
+
<template>
|
|
2
|
+
<div data-vmz-ui="empty" class="vmz-ui-empty">
|
|
3
|
+
<h2 class="vmz-ui-empty__title">
|
|
4
|
+
{{ title }}
|
|
5
|
+
</h2>
|
|
6
|
+
<p v-if="description" class="vmz-ui-empty__description">
|
|
7
|
+
{{ description }}
|
|
8
|
+
</p>
|
|
9
|
+
<div class="vmz-ui-empty__actions">
|
|
10
|
+
<slot />
|
|
11
|
+
</div>
|
|
12
|
+
</div>
|
|
13
|
+
</template>
|
|
14
|
+
<style>
|
|
15
|
+
.vmz-ui-empty {
|
|
16
|
+
display: flex;
|
|
17
|
+
flex-direction: column;
|
|
18
|
+
align-items: flex-start;
|
|
19
|
+
gap: 0.625rem;
|
|
20
|
+
padding: 1.5rem 1.15rem;
|
|
21
|
+
border: 1px dashed var(--vmz-line-default);
|
|
22
|
+
border-radius: var(--vmz-radius-md, 6px);
|
|
23
|
+
background: color-mix(in srgb, var(--vmz-surface-mist) 70%, var(--vmz-surface-paper));
|
|
24
|
+
color: var(--vmz-text-ink);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.vmz-ui-empty__title {
|
|
28
|
+
margin: 0;
|
|
29
|
+
font-family: var(--vmz-font-display);
|
|
30
|
+
font-size: 1.1rem;
|
|
31
|
+
font-weight: 700;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.vmz-ui-empty__description {
|
|
35
|
+
margin: 0;
|
|
36
|
+
color: var(--vmz-text-steel);
|
|
37
|
+
max-width: 36rem;
|
|
38
|
+
line-height: 1.45;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.vmz-ui-empty__actions:empty {
|
|
42
|
+
display: none;
|
|
43
|
+
}
|
|
44
|
+
</style>
|
|
45
|
+
<script client>
|
|
46
|
+
/**
|
|
47
|
+
* VMZ UI — Empty (Commercial composition).
|
|
48
|
+
* Empty / zero-state surface with optional action slot.
|
|
49
|
+
*/
|
|
50
|
+
export default class Empty {
|
|
51
|
+
public title: string = "Nothing here yet";
|
|
52
|
+
public description: string = "";
|
|
53
|
+
}
|
|
54
|
+
</script>
|
package/src/components/Field.vmz
CHANGED
|
@@ -1,115 +1,115 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div data-vmz-ui="field" :data-invalid="invalidAttr" class="vmz-ui-field">
|
|
3
|
-
<label v-if="label" :for="controlId" class="vmz-ui-field__label">
|
|
4
|
-
{{ label }}
|
|
5
|
-
</label>
|
|
6
|
-
<input :id="controlId" :type="type" :value="value" :min="min" :max="max" :step="step" :disabled="disabled" :aria-invalid="error ? 'true' : 'false'" :aria-describedby="describedBy" @input="onDomInput" class="vmz-ui-field__control" />
|
|
7
|
-
<p v-if="description" :id="descriptionId" class="vmz-ui-field__description">
|
|
8
|
-
{{ description }}
|
|
9
|
-
</p>
|
|
10
|
-
<p v-if="error" :id="errorId" role="alert" class="vmz-ui-field__error">
|
|
11
|
-
{{ error }}
|
|
12
|
-
</p>
|
|
13
|
-
</div>
|
|
14
|
-
</template>
|
|
15
|
-
<style>
|
|
16
|
-
.vmz-ui-field {
|
|
17
|
-
display: flex;
|
|
18
|
-
flex-direction: column;
|
|
19
|
-
gap: 0.375rem;
|
|
20
|
-
max-width: 28rem;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
.vmz-ui-field__label {
|
|
24
|
-
font: inherit;
|
|
25
|
-
font-weight: 500;
|
|
26
|
-
font-size: 0.875rem;
|
|
27
|
-
color: var(--vmz-text-ink, inherit);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
.vmz-ui-field__control {
|
|
31
|
-
box-sizing: border-box;
|
|
32
|
-
width: 100%;
|
|
33
|
-
min-height: var(--vmz-control-height, 2rem);
|
|
34
|
-
font-family: var(--vmz-font-sans, inherit);
|
|
35
|
-
font-size: 0.875rem;
|
|
36
|
-
line-height: 1.5715;
|
|
37
|
-
padding: var(--vmz-density-control-padding-y, 0.25rem)
|
|
38
|
-
var(--vmz-density-control-padding-x, 0.75rem);
|
|
39
|
-
border: 1px solid var(--vmz-line-default, #d9d9d9);
|
|
40
|
-
border-radius: var(--vmz-radius-md, 6px);
|
|
41
|
-
background: var(--vmz-surface-paper, #fff);
|
|
42
|
-
color: var(--vmz-text-ink, inherit);
|
|
43
|
-
outline: none;
|
|
44
|
-
transition:
|
|
45
|
-
border-color var(--vmz-motion-control-duration, 120ms)
|
|
46
|
-
var(--vmz-motion-control-easing, cubic-bezier(0.4, 0, 0.2, 1)),
|
|
47
|
-
box-shadow var(--vmz-motion-control-duration, 120ms)
|
|
48
|
-
var(--vmz-motion-control-easing, cubic-bezier(0.4, 0, 0.2, 1));
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
.vmz-ui-field__control::placeholder {
|
|
52
|
-
color: var(--vmz-text-steel, #8c8c8c);
|
|
53
|
-
opacity: 1;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
.vmz-ui-field[data-invalid="true"] .vmz-ui-field__control {
|
|
57
|
-
border-color: var(--vmz-status-danger-accent);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
.vmz-ui-field__control:hover:not(:disabled):not(:focus-visible) {
|
|
61
|
-
border-color: var(--vmz-action-primary-background);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
.vmz-ui-field__control:focus-visible {
|
|
65
|
-
border-color: var(--vmz-action-primary-background);
|
|
66
|
-
box-shadow: 0 0 0 3px var(--vmz-focus-ring);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
.vmz-ui-field__control:disabled {
|
|
70
|
-
opacity: 0.55;
|
|
71
|
-
cursor: not-allowed;
|
|
72
|
-
background: var(--vmz-surface-mist, #fafafa);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
.vmz-ui-field__description {
|
|
76
|
-
margin: 0;
|
|
77
|
-
color: var(--vmz-text-steel, #8c8c8c);
|
|
78
|
-
font-size: 0.875rem;
|
|
79
|
-
line-height: 1.4;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
.vmz-ui-field__error {
|
|
83
|
-
margin: 0;
|
|
84
|
-
color: var(--vmz-status-danger-foreground);
|
|
85
|
-
font-size: 0.875rem;
|
|
86
|
-
}
|
|
87
|
-
</style>
|
|
88
|
-
<script client>
|
|
89
|
-
/**
|
|
90
|
-
* VMZ UI — Field (UI1).
|
|
91
|
-
* Label / description / error association via for + aria-describedby.
|
|
92
|
-
* Colors only from Style Theme semantic tokens.
|
|
93
|
-
*/
|
|
94
|
-
export default class Field {
|
|
95
|
-
public label: string = "";
|
|
96
|
-
public description: string = "";
|
|
97
|
-
public error: string = "";
|
|
98
|
-
public value: string = "";
|
|
99
|
-
public type: string = "text";
|
|
100
|
-
public min: string = "";
|
|
101
|
-
public max: string = "";
|
|
102
|
-
public step: string = "";
|
|
103
|
-
public disabled: boolean = false;
|
|
104
|
-
public invalidAttr: string = "false";
|
|
105
|
-
public controlId: string = "vmz-field";
|
|
106
|
-
public descriptionId: string = "vmz-field-desc";
|
|
107
|
-
public errorId: string = "vmz-field-err";
|
|
108
|
-
public describedBy: string = "";
|
|
109
|
-
public onInput: ((e: Event) => void) | null = null;
|
|
110
|
-
onDomInput(e: Event) {
|
|
111
|
-
this.emit("input", e);
|
|
112
|
-
if (typeof this.onInput === "function") this.onInput(e);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
</script>
|
|
1
|
+
<template>
|
|
2
|
+
<div data-vmz-ui="field" :data-invalid="invalidAttr" class="vmz-ui-field">
|
|
3
|
+
<label v-if="label" :for="controlId" class="vmz-ui-field__label">
|
|
4
|
+
{{ label }}
|
|
5
|
+
</label>
|
|
6
|
+
<input :id="controlId" :type="type" :value="value" :min="min" :max="max" :step="step" :disabled="disabled" :aria-invalid="error ? 'true' : 'false'" :aria-describedby="describedBy" @input="onDomInput" class="vmz-ui-field__control" />
|
|
7
|
+
<p v-if="description" :id="descriptionId" class="vmz-ui-field__description">
|
|
8
|
+
{{ description }}
|
|
9
|
+
</p>
|
|
10
|
+
<p v-if="error" :id="errorId" role="alert" class="vmz-ui-field__error">
|
|
11
|
+
{{ error }}
|
|
12
|
+
</p>
|
|
13
|
+
</div>
|
|
14
|
+
</template>
|
|
15
|
+
<style>
|
|
16
|
+
.vmz-ui-field {
|
|
17
|
+
display: flex;
|
|
18
|
+
flex-direction: column;
|
|
19
|
+
gap: 0.375rem;
|
|
20
|
+
max-width: 28rem;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.vmz-ui-field__label {
|
|
24
|
+
font: inherit;
|
|
25
|
+
font-weight: 500;
|
|
26
|
+
font-size: 0.875rem;
|
|
27
|
+
color: var(--vmz-text-ink, inherit);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.vmz-ui-field__control {
|
|
31
|
+
box-sizing: border-box;
|
|
32
|
+
width: 100%;
|
|
33
|
+
min-height: var(--vmz-control-height, 2rem);
|
|
34
|
+
font-family: var(--vmz-font-sans, inherit);
|
|
35
|
+
font-size: 0.875rem;
|
|
36
|
+
line-height: 1.5715;
|
|
37
|
+
padding: var(--vmz-density-control-padding-y, 0.25rem)
|
|
38
|
+
var(--vmz-density-control-padding-x, 0.75rem);
|
|
39
|
+
border: 1px solid var(--vmz-line-default, #d9d9d9);
|
|
40
|
+
border-radius: var(--vmz-radius-md, 6px);
|
|
41
|
+
background: var(--vmz-surface-paper, #fff);
|
|
42
|
+
color: var(--vmz-text-ink, inherit);
|
|
43
|
+
outline: none;
|
|
44
|
+
transition:
|
|
45
|
+
border-color var(--vmz-motion-control-duration, 120ms)
|
|
46
|
+
var(--vmz-motion-control-easing, cubic-bezier(0.4, 0, 0.2, 1)),
|
|
47
|
+
box-shadow var(--vmz-motion-control-duration, 120ms)
|
|
48
|
+
var(--vmz-motion-control-easing, cubic-bezier(0.4, 0, 0.2, 1));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.vmz-ui-field__control::placeholder {
|
|
52
|
+
color: var(--vmz-text-steel, #8c8c8c);
|
|
53
|
+
opacity: 1;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.vmz-ui-field[data-invalid="true"] .vmz-ui-field__control {
|
|
57
|
+
border-color: var(--vmz-status-danger-accent);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.vmz-ui-field__control:hover:not(:disabled):not(:focus-visible) {
|
|
61
|
+
border-color: var(--vmz-action-primary-background);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.vmz-ui-field__control:focus-visible {
|
|
65
|
+
border-color: var(--vmz-action-primary-background);
|
|
66
|
+
box-shadow: 0 0 0 3px var(--vmz-focus-ring);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.vmz-ui-field__control:disabled {
|
|
70
|
+
opacity: 0.55;
|
|
71
|
+
cursor: not-allowed;
|
|
72
|
+
background: var(--vmz-surface-mist, #fafafa);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.vmz-ui-field__description {
|
|
76
|
+
margin: 0;
|
|
77
|
+
color: var(--vmz-text-steel, #8c8c8c);
|
|
78
|
+
font-size: 0.875rem;
|
|
79
|
+
line-height: 1.4;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.vmz-ui-field__error {
|
|
83
|
+
margin: 0;
|
|
84
|
+
color: var(--vmz-status-danger-foreground);
|
|
85
|
+
font-size: 0.875rem;
|
|
86
|
+
}
|
|
87
|
+
</style>
|
|
88
|
+
<script client>
|
|
89
|
+
/**
|
|
90
|
+
* VMZ UI — Field (UI1).
|
|
91
|
+
* Label / description / error association via for + aria-describedby.
|
|
92
|
+
* Colors only from Style Theme semantic tokens.
|
|
93
|
+
*/
|
|
94
|
+
export default class Field {
|
|
95
|
+
public label: string = "";
|
|
96
|
+
public description: string = "";
|
|
97
|
+
public error: string = "";
|
|
98
|
+
public value: string = "";
|
|
99
|
+
public type: string = "text";
|
|
100
|
+
public min: string = "";
|
|
101
|
+
public max: string = "";
|
|
102
|
+
public step: string = "";
|
|
103
|
+
public disabled: boolean = false;
|
|
104
|
+
public invalidAttr: string = "false";
|
|
105
|
+
public controlId: string = "vmz-field";
|
|
106
|
+
public descriptionId: string = "vmz-field-desc";
|
|
107
|
+
public errorId: string = "vmz-field-err";
|
|
108
|
+
public describedBy: string = "";
|
|
109
|
+
public onInput: ((e: Event) => void) | null = null;
|
|
110
|
+
onDomInput(e: Event) {
|
|
111
|
+
this.emit("input", e);
|
|
112
|
+
if (typeof this.onInput === "function") this.onInput(e);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
</script>
|
|
@@ -1,79 +1,79 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div data-vmz-ui="form-item" :data-required="requiredAttr" :data-invalid="invalidAttr" class="vmz-ui-form-item">
|
|
3
|
-
<label v-if="label" :for="controlId" class="vmz-ui-form-item__label">
|
|
4
|
-
<span>
|
|
5
|
-
{{ label }}
|
|
6
|
-
</span>
|
|
7
|
-
<span v-if="required" aria-hidden="true" class="vmz-ui-form-item__required">
|
|
8
|
-
*
|
|
9
|
-
</span>
|
|
10
|
-
</label>
|
|
11
|
-
<div class="vmz-ui-form-item__control">
|
|
12
|
-
<slot />
|
|
13
|
-
</div>
|
|
14
|
-
<p v-if="description" :id="descriptionId" class="vmz-ui-form-item__description">
|
|
15
|
-
{{ description }}
|
|
16
|
-
</p>
|
|
17
|
-
<p v-if="error" :id="errorId" role="alert" class="vmz-ui-form-item__error">
|
|
18
|
-
{{ error }}
|
|
19
|
-
</p>
|
|
20
|
-
</div>
|
|
21
|
-
</template>
|
|
22
|
-
<style>
|
|
23
|
-
.vmz-ui-form-item {
|
|
24
|
-
display: flex;
|
|
25
|
-
flex-direction: column;
|
|
26
|
-
gap: 0.375rem;
|
|
27
|
-
max-width: 28rem;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
.vmz-ui-form-item__label {
|
|
31
|
-
display: inline-flex;
|
|
32
|
-
align-items: baseline;
|
|
33
|
-
gap: 0.25rem;
|
|
34
|
-
font: inherit;
|
|
35
|
-
font-weight: 600;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
.vmz-ui-form-item__required {
|
|
39
|
-
color: var(--vmz-status-danger-accent);
|
|
40
|
-
font-weight: 700;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
.vmz-ui-form-item__control {
|
|
44
|
-
min-width: 0;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
.vmz-ui-form-item__description {
|
|
48
|
-
margin: 0;
|
|
49
|
-
opacity: 0.75;
|
|
50
|
-
font-size: 0.9em;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
.vmz-ui-form-item__error {
|
|
54
|
-
margin: 0;
|
|
55
|
-
color: var(--vmz-status-danger-foreground);
|
|
56
|
-
font-size: 0.9em;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
.vmz-ui-form-item[data-invalid="true"] .vmz-ui-form-item__control :where(input, select, textarea) {
|
|
60
|
-
border-color: var(--vmz-status-danger-accent);
|
|
61
|
-
}
|
|
62
|
-
</style>
|
|
63
|
-
<script client>
|
|
64
|
-
/**
|
|
65
|
-
* VMZ UI — FormItem.
|
|
66
|
-
* Label / description / error shell for slotted controls; parent owns validation strings.
|
|
67
|
-
*/
|
|
68
|
-
export default class FormItem {
|
|
69
|
-
public label: string = "";
|
|
70
|
-
public description: string = "";
|
|
71
|
-
public error: string = "";
|
|
72
|
-
public required: boolean = false;
|
|
73
|
-
public requiredAttr: string = "false";
|
|
74
|
-
public invalidAttr: string = "false";
|
|
75
|
-
public controlId: string = "vmz-form-item";
|
|
76
|
-
public descriptionId: string = "vmz-form-item-desc";
|
|
77
|
-
public errorId: string = "vmz-form-item-err";
|
|
78
|
-
}
|
|
79
|
-
</script>
|
|
1
|
+
<template>
|
|
2
|
+
<div data-vmz-ui="form-item" :data-required="requiredAttr" :data-invalid="invalidAttr" class="vmz-ui-form-item">
|
|
3
|
+
<label v-if="label" :for="controlId" class="vmz-ui-form-item__label">
|
|
4
|
+
<span>
|
|
5
|
+
{{ label }}
|
|
6
|
+
</span>
|
|
7
|
+
<span v-if="required" aria-hidden="true" class="vmz-ui-form-item__required">
|
|
8
|
+
*
|
|
9
|
+
</span>
|
|
10
|
+
</label>
|
|
11
|
+
<div class="vmz-ui-form-item__control">
|
|
12
|
+
<slot />
|
|
13
|
+
</div>
|
|
14
|
+
<p v-if="description" :id="descriptionId" class="vmz-ui-form-item__description">
|
|
15
|
+
{{ description }}
|
|
16
|
+
</p>
|
|
17
|
+
<p v-if="error" :id="errorId" role="alert" class="vmz-ui-form-item__error">
|
|
18
|
+
{{ error }}
|
|
19
|
+
</p>
|
|
20
|
+
</div>
|
|
21
|
+
</template>
|
|
22
|
+
<style>
|
|
23
|
+
.vmz-ui-form-item {
|
|
24
|
+
display: flex;
|
|
25
|
+
flex-direction: column;
|
|
26
|
+
gap: 0.375rem;
|
|
27
|
+
max-width: 28rem;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.vmz-ui-form-item__label {
|
|
31
|
+
display: inline-flex;
|
|
32
|
+
align-items: baseline;
|
|
33
|
+
gap: 0.25rem;
|
|
34
|
+
font: inherit;
|
|
35
|
+
font-weight: 600;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.vmz-ui-form-item__required {
|
|
39
|
+
color: var(--vmz-status-danger-accent);
|
|
40
|
+
font-weight: 700;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.vmz-ui-form-item__control {
|
|
44
|
+
min-width: 0;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.vmz-ui-form-item__description {
|
|
48
|
+
margin: 0;
|
|
49
|
+
opacity: 0.75;
|
|
50
|
+
font-size: 0.9em;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.vmz-ui-form-item__error {
|
|
54
|
+
margin: 0;
|
|
55
|
+
color: var(--vmz-status-danger-foreground);
|
|
56
|
+
font-size: 0.9em;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.vmz-ui-form-item[data-invalid="true"] .vmz-ui-form-item__control :where(input, select, textarea) {
|
|
60
|
+
border-color: var(--vmz-status-danger-accent);
|
|
61
|
+
}
|
|
62
|
+
</style>
|
|
63
|
+
<script client>
|
|
64
|
+
/**
|
|
65
|
+
* VMZ UI — FormItem.
|
|
66
|
+
* Label / description / error shell for slotted controls; parent owns validation strings.
|
|
67
|
+
*/
|
|
68
|
+
export default class FormItem {
|
|
69
|
+
public label: string = "";
|
|
70
|
+
public description: string = "";
|
|
71
|
+
public error: string = "";
|
|
72
|
+
public required: boolean = false;
|
|
73
|
+
public requiredAttr: string = "false";
|
|
74
|
+
public invalidAttr: string = "false";
|
|
75
|
+
public controlId: string = "vmz-form-item";
|
|
76
|
+
public descriptionId: string = "vmz-form-item-desc";
|
|
77
|
+
public errorId: string = "vmz-form-item-err";
|
|
78
|
+
}
|
|
79
|
+
</script>
|
package/src/components/Link.vmz
CHANGED
|
@@ -65,7 +65,11 @@ export default class Link {
|
|
|
65
65
|
public href: string = "#";
|
|
66
66
|
public target: string = "";
|
|
67
67
|
public rel: string = "";
|
|
68
|
-
/**
|
|
68
|
+
/**
|
|
69
|
+
* `default` inline prose link · `muted` quiet inline link · `nav` chrome link.
|
|
70
|
+
* Appearance/semantic hint only: navigation, `href`, `target` and `rel` are
|
|
71
|
+
* unaffected, and unknown values render as `default` without error.
|
|
72
|
+
*/
|
|
69
73
|
public variant: string = "default";
|
|
70
74
|
}
|
|
71
75
|
</script>
|