@vmz/ui 0.3.6 → 0.3.8

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 (68) hide show
  1. package/README.md +53 -51
  2. package/contracts/token-requirements.v0.json +58 -1
  3. package/package.json +5 -2
  4. package/presets/web-surface.v0.json +14 -12
  5. package/src/components/Accordion.vmz +127 -94
  6. package/src/components/Alert.vmz +125 -28
  7. package/src/components/AppShell.vmz +125 -57
  8. package/src/components/Autocomplete.vmz +261 -154
  9. package/src/components/Avatar.vmz +20 -12
  10. package/src/components/Badge.vmz +62 -70
  11. package/src/components/Breadcrumb.vmz +86 -72
  12. package/src/components/BulkActions.vmz +56 -51
  13. package/src/components/Button.vmz +237 -211
  14. package/src/components/Callout.vmz +178 -77
  15. package/src/components/Card.vmz +141 -120
  16. package/src/components/Checkbox.vmz +131 -55
  17. package/src/components/CodeBlock.vmz +77 -30
  18. package/src/components/Collapse.vmz +64 -11
  19. package/src/components/ConsoleShell.vmz +405 -251
  20. package/src/components/Content.vmz +15 -1
  21. package/src/components/DataTable.vmz +294 -194
  22. package/src/components/DatePicker.vmz +766 -674
  23. package/src/components/Descriptions.vmz +90 -0
  24. package/src/components/Dialog.vmz +137 -38
  25. package/src/components/Divider.vmz +8 -1
  26. package/src/components/Drawer.vmz +518 -427
  27. package/src/components/Dropdown.vmz +195 -51
  28. package/src/components/Empty.vmz +96 -54
  29. package/src/components/Field.vmz +170 -115
  30. package/src/components/FilterBar.vmz +34 -4
  31. package/src/components/Flex.vmz +3 -1
  32. package/src/components/Footer.vmz +6 -3
  33. package/src/components/Form.vmz +41 -0
  34. package/src/components/FormItem.vmz +78 -79
  35. package/src/components/Grid.vmz +6 -3
  36. package/src/components/Header.vmz +193 -6
  37. package/src/components/Layout.vmz +3 -1
  38. package/src/components/Link.vmz +25 -10
  39. package/src/components/List.vmz +124 -102
  40. package/src/components/Menu.vmz +416 -243
  41. package/src/components/Message.vmz +167 -0
  42. package/src/components/Notification.vmz +132 -37
  43. package/src/components/Pagination.vmz +237 -69
  44. package/src/components/Popconfirm.vmz +287 -0
  45. package/src/components/Popover.vmz +341 -223
  46. package/src/components/Progress.vmz +16 -5
  47. package/src/components/Prose.vmz +180 -81
  48. package/src/components/QueryForm.vmz +31 -9
  49. package/src/components/RadioGroup.vmz +204 -124
  50. package/src/components/Result.vmz +60 -27
  51. package/src/components/Segmented.vmz +86 -51
  52. package/src/components/Select.vmz +620 -533
  53. package/src/components/Sider.vmz +120 -7
  54. package/src/components/Skeleton.vmz +9 -7
  55. package/src/components/Space.vmz +9 -3
  56. package/src/components/Spinner.vmz +5 -4
  57. package/src/components/Steps.vmz +118 -103
  58. package/src/components/Switch.vmz +131 -98
  59. package/src/components/Table.vmz +270 -165
  60. package/src/components/Tabs.vmz +125 -110
  61. package/src/components/Tag.vmz +60 -43
  62. package/src/components/TextArea.vmz +125 -118
  63. package/src/components/Timeline.vmz +111 -76
  64. package/src/components/Toc.vmz +90 -74
  65. package/src/components/Tooltip.vmz +107 -58
  66. package/src/components/Tree.vmz +214 -191
  67. package/src/components/Typography.vmz +23 -8
  68. package/src/components/Upload.vmz +1394 -1289
@@ -1,154 +1,261 @@
1
- <template>
2
- <div data-vmz-ui="autocomplete" :data-invalid="invalidAttr" :data-open="openAttr" class="vmz-ui-autocomplete">
3
- <label v-if="label" :for="controlId" class="vmz-ui-autocomplete__label">
4
- {{ label }}
5
- </label>
6
- <input :id="controlId" type="text" role="combobox" autocomplete="off" aria-autocomplete="list" :aria-expanded="openAttr" :aria-controls="listId" :aria-invalid="error ? 'true' : 'false'" :aria-describedby="describedBy" :value="value" :disabled="disabled" @input="onDomInput" :onKeyDown="onKeyDown" class="vmz-ui-autocomplete__control" />
7
- <ul v-if="listOpen" :id="listId" role="listbox" data-vmz-autocomplete="list" @click="onListClick" class="vmz-ui-autocomplete__list">
8
- <li v-for="opt in options" :key="opt.value" role="option" :data-vmz-option="opt.value" tabindex="-1" class="vmz-ui-autocomplete__option">
9
- {{ opt.label }}
10
- </li>
11
- </ul>
12
- <p v-if="showEmpty" data-vmz-autocomplete="empty" class="vmz-ui-autocomplete__empty">
13
- {{ emptyText }}
14
- </p>
15
- <p v-if="description" :id="descriptionId" class="vmz-ui-autocomplete__description">
16
- {{ description }}
17
- </p>
18
- <p v-if="error" :id="errorId" role="alert" class="vmz-ui-autocomplete__error">
19
- {{ error }}
20
- </p>
21
- </div>
22
- </template>
23
- <style>
24
- .vmz-ui-autocomplete {
25
- position: relative;
26
- display: flex;
27
- flex-direction: column;
28
- gap: 0.375rem;
29
- max-width: 28rem;
30
- }
31
-
32
- .vmz-ui-autocomplete__label {
33
- font: inherit;
34
- font-weight: 600;
35
- }
36
-
37
- .vmz-ui-autocomplete__control {
38
- font: inherit;
39
- padding: var(--vmz-density-control-padding-y) var(--vmz-density-control-padding-x);
40
- border: 1px solid var(--vmz-line-default);
41
- border-radius: var(--vmz-radius-md, 6px);
42
- background: transparent;
43
- color: inherit;
44
- outline: none;
45
- }
46
-
47
- .vmz-ui-autocomplete[data-invalid="true"] .vmz-ui-autocomplete__control {
48
- border-color: var(--vmz-status-danger-accent);
49
- }
50
-
51
- .vmz-ui-autocomplete__control:focus-visible {
52
- box-shadow: 0 0 0 3px var(--vmz-focus-ring);
53
- }
54
-
55
- .vmz-ui-autocomplete__control:disabled {
56
- opacity: 0.55;
57
- cursor: not-allowed;
58
- }
59
-
60
- .vmz-ui-autocomplete__list {
61
- list-style: none;
62
- margin: 0;
63
- padding: 0.25rem 0;
64
- border: 1px solid var(--vmz-line-default);
65
- border-radius: var(--vmz-radius-md, 6px);
66
- background: var(--vmz-surface-paper);
67
- max-height: 12rem;
68
- overflow: auto;
69
- }
70
-
71
- .vmz-ui-autocomplete__option {
72
- margin: 0;
73
- padding: 0.5rem 0.75rem;
74
- cursor: pointer;
75
- font-weight: 600;
76
- color: var(--vmz-text-ink);
77
- }
78
-
79
- .vmz-ui-autocomplete__option:hover,
80
- .vmz-ui-autocomplete__option:focus {
81
- background: var(--vmz-surface-mist);
82
- outline: none;
83
- }
84
-
85
- .vmz-ui-autocomplete__empty {
86
- margin: 0;
87
- color: var(--vmz-text-steel);
88
- font-size: 0.9em;
89
- }
90
-
91
- .vmz-ui-autocomplete__description {
92
- margin: 0;
93
- opacity: 0.75;
94
- font-size: 0.9em;
95
- }
96
-
97
- .vmz-ui-autocomplete__error {
98
- margin: 0;
99
- color: var(--vmz-status-danger-foreground);
100
- font-size: 0.9em;
101
- }
102
- </style>
103
- <script client>
104
- /**
105
- * VMZ UI — Autocomplete.
106
- * Parent owns value, listOpen, and filtered options — no parallel query/store.
107
- * Selection notifies via onSelect(value); Escape closes via onClose.
108
- */
109
- export default class Autocomplete {
110
- public label: string = "";
111
- public description: string = "";
112
- public error: string = "";
113
- public value: string = "";
114
- public options: Array<{
115
- value: string;
116
- label: string;
117
- }> = [];
118
- public listOpen: boolean = false;
119
- public openAttr: string = "false";
120
- public showEmpty: boolean = false;
121
- public emptyText: string = "No matches";
122
- public disabled: boolean = false;
123
- public invalidAttr: string = "false";
124
- public controlId: string = "vmz-autocomplete";
125
- public listId: string = "vmz-autocomplete-list";
126
- public descriptionId: string = "vmz-autocomplete-desc";
127
- public errorId: string = "vmz-autocomplete-err";
128
- public describedBy: string = "";
129
- public onInput: ((e: Event) => void) | null = null;
130
- public onSelect: ((value: string) => void) | null = null;
131
- public onClose: (() => void) | null = null;
132
- onDomInput(e: Event) {
133
- this.emit("input", e);
134
- if (typeof this.onInput === "function") this.onInput(e);
135
- }
136
- onListClick(ev) {
137
- if (this.disabled) return;
138
- const t = ev && ev.target;
139
- if (!t || typeof t.closest !== "function") return;
140
- const opt = t.closest("[data-vmz-option]");
141
- if (!opt) return;
142
- const next = opt.getAttribute("data-vmz-option") || "";
143
- if (!next) return;
144
- this.emit("select", next);
145
- if (typeof this.onSelect === "function") this.onSelect(next);
146
- }
147
- onKeyDown(ev) {
148
- if (!ev || ev.key !== "Escape") return;
149
- ev.preventDefault();
150
- this.emit("close");
151
- if (typeof this.onClose === "function") this.onClose();
152
- }
153
- }
154
- </script>
1
+ <template>
2
+ <div data-vmz-ui="autocomplete" :data-invalid="invalidAttr" :data-open="openAttr" class="vmz-ui-autocomplete">
3
+ <label v-if="label" :for="controlId" class="vmz-ui-autocomplete__label">
4
+ {{ label }}
5
+ </label>
6
+ <div class="vmz-ui-autocomplete__field">
7
+ <div class="vmz-ui-autocomplete__control-wrap">
8
+ <Icon name="action.search" size="md" decorative class="vmz-ui-autocomplete__search-icon" />
9
+ <input :id="controlId" type="text" role="combobox" autocomplete="off" aria-autocomplete="list" :aria-expanded="openAttr" :aria-controls="listId" :aria-invalid="error ? 'true' : 'false'" :aria-describedby="describedBy" :value="value" :placeholder="placeholder" :disabled="disabled" @input="onDomInput" :onKeyDown="onKeyDown" class="vmz-ui-autocomplete__control" />
10
+ </div>
11
+ <div v-if="listOpen || (showEmpty && emptyText)" class="vmz-ui-autocomplete__panel">
12
+ <ul v-if="listOpen" :id="listId" role="listbox" data-vmz-autocomplete="list" @click="onListClick" class="vmz-ui-autocomplete__list">
13
+ <li v-for="opt in options" :key="opt.value" role="option" :data-vmz-option="opt.value" :aria-selected="opt.value === value ? 'true' : 'false'" tabindex="-1" :class='"vmz-ui-autocomplete__option" + (opt.value === value ? " is-on" : "")'>
14
+ <span class="vmz-ui-autocomplete__option-label">
15
+ {{ opt.label }}
16
+ </span>
17
+ <Icon v-if="opt.value === value" name="action.check" size="md" decorative class="vmz-ui-autocomplete__option-check" />
18
+ </li>
19
+ </ul>
20
+ <p v-if="showEmpty && emptyText" data-vmz-autocomplete="empty" class="vmz-ui-autocomplete__empty">
21
+ {{ emptyText }}
22
+ </p>
23
+ </div>
24
+ </div>
25
+ <p v-if="description" :id="descriptionId" class="vmz-ui-autocomplete__description">
26
+ {{ description }}
27
+ </p>
28
+ <p v-if="error" :id="errorId" role="alert" class="vmz-ui-autocomplete__error">
29
+ {{ error }}
30
+ </p>
31
+ </div>
32
+ </template>
33
+ <style>
34
+ .vmz-ui-autocomplete {
35
+ position: relative;
36
+ display: flex;
37
+ flex-direction: column;
38
+ gap: var(--vmz-space-2);
39
+ width: 100%;
40
+ max-width: 28rem;
41
+ }
42
+
43
+ .vmz-ui-autocomplete__field {
44
+ position: relative;
45
+ display: flex;
46
+ flex-direction: column;
47
+ width: 100%;
48
+ }
49
+
50
+ .vmz-ui-autocomplete__label {
51
+ font: inherit;
52
+ font-weight: 500;
53
+ font-size: 0.875rem;
54
+ line-height: 1.5715;
55
+ color: var(--vmz-text-ink);
56
+ }
57
+
58
+ .vmz-ui-autocomplete__control-wrap {
59
+ position: relative;
60
+ display: flex;
61
+ align-items: center;
62
+ width: 100%;
63
+ }
64
+
65
+ .vmz-ui-autocomplete__search-icon {
66
+ position: absolute;
67
+ left: var(--vmz-density-control-padding-x);
68
+ z-index: 1;
69
+ color: var(--vmz-text-tertiary);
70
+ pointer-events: none;
71
+ }
72
+
73
+ .vmz-ui-autocomplete__control {
74
+ box-sizing: border-box;
75
+ width: 100%;
76
+ min-height: var(--vmz-control-height);
77
+ font-family: inherit;
78
+ font-size: 0.875rem;
79
+ line-height: 1.5715;
80
+ padding: var(--vmz-density-control-padding-y) var(--vmz-density-control-padding-x);
81
+ padding-left: calc(
82
+ var(--vmz-density-control-padding-x) + var(--vmz-space-4) + var(--vmz-space-1)
83
+ );
84
+ border: 1px solid var(--vmz-line-default);
85
+ border-radius: var(--vmz-radius-lg);
86
+ background: var(--vmz-surface-paper);
87
+ color: var(--vmz-text-ink);
88
+ outline: none;
89
+ transition:
90
+ border-color var(--vmz-motion-control-duration) var(--vmz-motion-control-easing),
91
+ box-shadow var(--vmz-motion-control-duration) var(--vmz-motion-control-easing),
92
+ background-color var(--vmz-motion-control-duration) var(--vmz-motion-control-easing);
93
+ }
94
+
95
+ .vmz-ui-autocomplete__control::placeholder {
96
+ color: var(--vmz-text-tertiary);
97
+ opacity: 1;
98
+ }
99
+
100
+ .vmz-ui-autocomplete[data-invalid="true"] .vmz-ui-autocomplete__control {
101
+ border-color: var(--vmz-status-danger-accent);
102
+ }
103
+
104
+ .vmz-ui-autocomplete[data-invalid="true"] .vmz-ui-autocomplete__control:hover:not(:disabled),
105
+ .vmz-ui-autocomplete[data-invalid="true"] .vmz-ui-autocomplete__control:focus-visible {
106
+ border-color: var(--vmz-status-danger-foreground);
107
+ }
108
+
109
+ .vmz-ui-autocomplete__control:hover:not(:disabled):not(:focus-visible) {
110
+ border-color: var(--vmz-action-primary-hover);
111
+ }
112
+
113
+ .vmz-ui-autocomplete__control:focus-visible {
114
+ border-color: var(--vmz-action-primary-background);
115
+ box-shadow: 0 0 0 3px var(--vmz-focus-ring);
116
+ }
117
+
118
+ .vmz-ui-autocomplete__control:disabled {
119
+ opacity: 0.6;
120
+ color: var(--vmz-text-muted);
121
+ cursor: not-allowed;
122
+ background: var(--vmz-surface-mist);
123
+ }
124
+
125
+ .vmz-ui-autocomplete__panel {
126
+ position: absolute;
127
+ z-index: 40;
128
+ top: calc(100% + var(--vmz-space-1));
129
+ left: 0;
130
+ right: 0;
131
+ padding: var(--vmz-space-1);
132
+ border: 1px solid var(--vmz-line-default);
133
+ border-radius: var(--vmz-radius-lg);
134
+ background: var(--vmz-surface-paper);
135
+ box-shadow: var(--vmz-shadow-popup);
136
+ }
137
+
138
+ .vmz-ui-autocomplete__list {
139
+ list-style: none;
140
+ margin: 0;
141
+ padding: 0;
142
+ max-height: 12rem;
143
+ overflow: auto;
144
+ }
145
+
146
+ .vmz-ui-autocomplete__option {
147
+ display: flex;
148
+ align-items: center;
149
+ justify-content: space-between;
150
+ gap: var(--vmz-space-2);
151
+ box-sizing: border-box;
152
+ min-height: var(--vmz-control-height);
153
+ margin: 0;
154
+ padding: 0 var(--vmz-density-control-padding-x);
155
+ border-radius: var(--vmz-radius-md);
156
+ color: var(--vmz-text-ink);
157
+ font-size: 0.875rem;
158
+ line-height: 1.5715;
159
+ cursor: pointer;
160
+ outline: none;
161
+ }
162
+
163
+ .vmz-ui-autocomplete__option-label {
164
+ flex: 1 1 auto;
165
+ min-width: 0;
166
+ overflow: hidden;
167
+ text-overflow: ellipsis;
168
+ white-space: nowrap;
169
+ }
170
+
171
+ .vmz-ui-autocomplete__option-check {
172
+ flex: 0 0 auto;
173
+ color: var(--vmz-action-primary-background);
174
+ }
175
+
176
+ .vmz-ui-autocomplete__option:hover,
177
+ .vmz-ui-autocomplete__option:focus {
178
+ background: var(--vmz-surface-mist);
179
+ outline: none;
180
+ }
181
+
182
+ .vmz-ui-autocomplete__option.is-on {
183
+ background: var(--vmz-action-primary-soft);
184
+ color: var(--vmz-action-primary-active);
185
+ }
186
+
187
+ .vmz-ui-autocomplete__empty {
188
+ margin: 0;
189
+ padding: var(--vmz-space-2) var(--vmz-density-control-padding-x);
190
+ color: var(--vmz-text-tertiary);
191
+ font-size: 0.875rem;
192
+ line-height: 1.5715;
193
+ }
194
+
195
+ .vmz-ui-autocomplete__description {
196
+ margin: 0;
197
+ color: var(--vmz-text-steel);
198
+ font-size: 0.875rem;
199
+ line-height: 1.5715;
200
+ }
201
+
202
+ .vmz-ui-autocomplete__error {
203
+ margin: 0;
204
+ color: var(--vmz-status-danger-foreground);
205
+ font-size: 0.875rem;
206
+ line-height: 1.5715;
207
+ }
208
+ </style>
209
+ <script client>
210
+ /**
211
+ * VMZ UI — Autocomplete.
212
+ * Parent owns value, listOpen, and filtered options — no parallel query/store.
213
+ * Selection notifies via onSelect(value); Escape closes via onClose.
214
+ */
215
+ export default class Autocomplete {
216
+ public label: string = "";
217
+ public description: string = "";
218
+ public error: string = "";
219
+ public value: string = "";
220
+ public placeholder: string = "";
221
+ public options: Array<{
222
+ value: string;
223
+ label: string;
224
+ }> = [];
225
+ public listOpen: boolean = false;
226
+ public openAttr: string = "false";
227
+ public showEmpty: boolean = false;
228
+ public emptyText: string = "";
229
+ public disabled: boolean = false;
230
+ public invalidAttr: string = "false";
231
+ public controlId: string = "vmz-autocomplete";
232
+ public listId: string = "vmz-autocomplete-list";
233
+ public descriptionId: string = "vmz-autocomplete-desc";
234
+ public errorId: string = "vmz-autocomplete-err";
235
+ public describedBy: string = "";
236
+ public onInput: ((e: Event) => void) | null = null;
237
+ public onSelect: ((value: string) => void) | null = null;
238
+ public onClose: (() => void) | null = null;
239
+ onDomInput(e: Event) {
240
+ this.emit("input", e);
241
+ if (typeof this.onInput === "function") this.onInput(e);
242
+ }
243
+ onListClick(ev) {
244
+ if (this.disabled) return;
245
+ const t = ev && ev.target;
246
+ if (!t || typeof t.closest !== "function") return;
247
+ const opt = t.closest("[data-vmz-option]");
248
+ if (!opt) return;
249
+ const next = opt.getAttribute("data-vmz-option") || "";
250
+ if (!next) return;
251
+ this.emit("select", next);
252
+ if (typeof this.onSelect === "function") this.onSelect(next);
253
+ }
254
+ onKeyDown(ev) {
255
+ if (!ev || ev.key !== "Escape") return;
256
+ ev.preventDefault();
257
+ this.emit("close");
258
+ if (typeof this.onClose === "function") this.onClose();
259
+ }
260
+ }
261
+ </script>
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <span data-vmz-ui="avatar" :data-size="size" :aria-label="label" class="vmz-ui-avatar">
3
- <img v-if="src" :src="src" alt />
3
+ <img v-if="src" :src="src" :alt="label" />
4
4
  <span v-if="!src">
5
5
  {{ text }}
6
6
  </span>
@@ -9,26 +9,34 @@
9
9
  <style>
10
10
  .vmz-ui-avatar {
11
11
  display: inline-flex;
12
+ flex: 0 0 auto;
12
13
  align-items: center;
13
14
  justify-content: center;
14
- width: 2rem;
15
- height: 2rem;
15
+ box-sizing: border-box;
16
+ width: var(--vmz-control-height);
17
+ height: var(--vmz-control-height);
16
18
  overflow: hidden;
17
- border-radius: 50%;
18
- background: color-mix(in srgb, var(--vmz-action-primary-background, #1677ff) 14%, white);
19
- color: var(--vmz-action-primary-active, #0958d9);
20
- font-weight: 650;
19
+ border-radius: var(--vmz-radius-pill);
20
+ background: var(--vmz-action-primary-soft);
21
+ color: var(--vmz-action-primary-active);
22
+ font-size: 0.875rem;
23
+ font-weight: 500;
24
+ line-height: 1;
25
+ user-select: none;
21
26
  }
27
+
22
28
  .vmz-ui-avatar[data-size="small"] {
23
- width: 1.5rem;
24
- height: 1.5rem;
29
+ width: var(--vmz-control-height-sm);
30
+ height: var(--vmz-control-height-sm);
25
31
  font-size: 0.75rem;
26
32
  }
33
+
27
34
  .vmz-ui-avatar[data-size="large"] {
28
- width: 2.75rem;
29
- height: 2.75rem;
30
- font-size: 1.1rem;
35
+ width: var(--vmz-control-height-lg);
36
+ height: var(--vmz-control-height-lg);
37
+ font-size: 1rem;
31
38
  }
39
+
32
40
  .vmz-ui-avatar img {
33
41
  width: 100%;
34
42
  height: 100%;
@@ -1,70 +1,62 @@
1
- <template>
2
- <span data-vmz-ui="badge" :data-tone="tone" class="vmz-ui-badge">
3
- <slot />
4
- </span>
5
- </template>
6
- <style>
7
- .vmz-ui-badge {
8
- display: inline-flex;
9
- align-items: center;
10
- gap: 0.25rem;
11
- padding: 0.125rem 0.5rem;
12
- border: 1px solid var(--vmz-line-default);
13
- border-radius: var(--vmz-radius-md, 6px);
14
- font-size: 0.75rem;
15
- font-weight: 700;
16
- letter-spacing: 0.04em;
17
- text-transform: uppercase;
18
- line-height: 1.2;
19
- background: var(--vmz-surface-mist);
20
- color: var(--vmz-text-ink);
21
- }
22
-
23
- .vmz-ui-badge[data-tone="brand"] {
24
- border-color: color-mix(
25
- in srgb,
26
- var(--vmz-action-primary-background) 35%,
27
- var(--vmz-line-default)
28
- );
29
- background: color-mix(
30
- in srgb,
31
- var(--vmz-action-primary-background) 12%,
32
- var(--vmz-surface-paper)
33
- );
34
- color: var(--vmz-action-primary-active);
35
- }
36
-
37
- .vmz-ui-badge[data-tone="info"] {
38
- border-color: var(--vmz-status-info-accent);
39
- background: color-mix(in srgb, var(--vmz-status-info-accent) 12%, var(--vmz-surface-paper));
40
- color: var(--vmz-status-info-foreground);
41
- }
42
-
43
- .vmz-ui-badge[data-tone="success"] {
44
- border-color: var(--vmz-status-success-accent);
45
- background: color-mix(in srgb, var(--vmz-status-success-accent) 12%, var(--vmz-surface-paper));
46
- color: var(--vmz-status-success-foreground);
47
- }
48
-
49
- .vmz-ui-badge[data-tone="warning"] {
50
- border-color: var(--vmz-status-warning-accent);
51
- background: color-mix(in srgb, var(--vmz-status-warning-accent) 12%, var(--vmz-surface-paper));
52
- color: var(--vmz-status-warning-foreground);
53
- }
54
-
55
- .vmz-ui-badge[data-tone="danger"] {
56
- border-color: var(--vmz-status-danger-accent);
57
- background: color-mix(in srgb, var(--vmz-status-danger-accent) 12%, var(--vmz-surface-paper));
58
- color: var(--vmz-status-danger-foreground);
59
- }
60
- </style>
61
- <script client>
62
- /**
63
- * VMZ UI — Badge (Foundation).
64
- * Compact status / label chip; tones share status.* + action tokens.
65
- */
66
- export default class Badge {
67
- static __vmzHostBox = "contents";
68
- public tone: string = "brand";
69
- }
70
- </script>
1
+ <template>
2
+ <span data-vmz-ui="badge" :data-tone="tone" class="vmz-ui-badge">
3
+ <slot />
4
+ </span>
5
+ </template>
6
+ <style>
7
+ .vmz-ui-badge {
8
+ display: inline-flex;
9
+ align-items: center;
10
+ gap: var(--vmz-space-1);
11
+ max-width: 100%;
12
+ padding: 0 var(--vmz-space-2);
13
+ border: 1px solid var(--vmz-line-default);
14
+ border-radius: var(--vmz-radius-sm);
15
+ font-size: 0.75rem;
16
+ font-weight: 500;
17
+ line-height: 1.6667;
18
+ white-space: nowrap;
19
+ background: var(--vmz-surface-mist);
20
+ color: var(--vmz-text-steel);
21
+ }
22
+
23
+ .vmz-ui-badge[data-tone="brand"] {
24
+ border-color: var(--vmz-action-primary-hover);
25
+ background: var(--vmz-action-primary-soft);
26
+ color: var(--vmz-action-primary-active);
27
+ }
28
+
29
+ .vmz-ui-badge[data-tone="info"] {
30
+ border-color: var(--vmz-status-info-border);
31
+ background: var(--vmz-status-info-background);
32
+ color: var(--vmz-status-info-foreground);
33
+ }
34
+
35
+ .vmz-ui-badge[data-tone="success"] {
36
+ border-color: var(--vmz-status-success-border);
37
+ background: var(--vmz-status-success-background);
38
+ color: var(--vmz-status-success-foreground);
39
+ }
40
+
41
+ .vmz-ui-badge[data-tone="warning"] {
42
+ border-color: var(--vmz-status-warning-border);
43
+ background: var(--vmz-status-warning-background);
44
+ color: var(--vmz-status-warning-foreground);
45
+ }
46
+
47
+ .vmz-ui-badge[data-tone="danger"] {
48
+ border-color: var(--vmz-status-danger-border);
49
+ background: var(--vmz-status-danger-background);
50
+ color: var(--vmz-status-danger-foreground);
51
+ }
52
+ </style>
53
+ <script client>
54
+ /**
55
+ * VMZ UI — Badge (Foundation).
56
+ * Compact status / label chip; tones share status.* + action tokens.
57
+ */
58
+ export default class Badge {
59
+ static __vmzHostBox = "contents";
60
+ public tone: string = "brand";
61
+ }
62
+ </script>