@vmz/ui 0.3.7 → 0.3.9

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 +2 -0
  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 +49 -16
  6. package/src/components/Alert.vmz +125 -28
  7. package/src/components/AppShell.vmz +121 -56
  8. package/src/components/Autocomplete.vmz +136 -29
  9. package/src/components/Avatar.vmz +20 -12
  10. package/src/components/Badge.vmz +18 -26
  11. package/src/components/Breadcrumb.vmz +28 -14
  12. package/src/components/BulkActions.vmz +13 -8
  13. package/src/components/Button.vmz +68 -44
  14. package/src/components/Callout.vmz +128 -27
  15. package/src/components/Card.vmz +67 -46
  16. package/src/components/Checkbox.vmz +81 -5
  17. package/src/components/CodeBlock.vmz +59 -27
  18. package/src/components/Collapse.vmz +64 -11
  19. package/src/components/ConsoleShell.vmz +249 -69
  20. package/src/components/Content.vmz +15 -1
  21. package/src/components/DataTable.vmz +123 -23
  22. package/src/components/DatePicker.vmz +171 -79
  23. package/src/components/Descriptions.vmz +90 -0
  24. package/src/components/Dialog.vmz +133 -50
  25. package/src/components/Divider.vmz +8 -1
  26. package/src/components/Drawer.vmz +131 -40
  27. package/src/components/Dropdown.vmz +147 -49
  28. package/src/components/Empty.vmz +56 -14
  29. package/src/components/Field.vmz +78 -23
  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 +2 -3
  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 +20 -9
  39. package/src/components/List.vmz +35 -13
  40. package/src/components/Menu.vmz +198 -25
  41. package/src/components/Message.vmz +167 -0
  42. package/src/components/Notification.vmz +132 -37
  43. package/src/components/Pagination.vmz +186 -20
  44. package/src/components/Popconfirm.vmz +287 -0
  45. package/src/components/Popover.vmz +152 -34
  46. package/src/components/Progress.vmz +16 -5
  47. package/src/components/Prose.vmz +131 -32
  48. package/src/components/QueryForm.vmz +31 -9
  49. package/src/components/RadioGroup.vmz +91 -11
  50. package/src/components/Result.vmz +60 -27
  51. package/src/components/Segmented.vmz +46 -11
  52. package/src/components/Select.vmz +174 -87
  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 +40 -25
  58. package/src/components/Switch.vmz +48 -15
  59. package/src/components/Table.vmz +130 -25
  60. package/src/components/Tabs.vmz +28 -13
  61. package/src/components/Tag.vmz +29 -12
  62. package/src/components/TextArea.vmz +32 -25
  63. package/src/components/Timeline.vmz +65 -30
  64. package/src/components/Toc.vmz +45 -29
  65. package/src/components/Tooltip.vmz +70 -21
  66. package/src/components/Tree.vmz +48 -25
  67. package/src/components/Typography.vmz +23 -8
  68. package/src/components/Upload.vmz +191 -96
@@ -5,9 +5,12 @@
5
5
  </template>
6
6
  <style>
7
7
  .vmz-ui-footer {
8
- padding: 1.5rem;
9
- color: var(--vmz-text-steel, #646a73);
10
- font-size: 0.875rem;
8
+ padding: var(--vmz-space-6, 2rem) var(--vmz-space-5, 1.5rem);
9
+ border-top: 1px solid var(--vmz-line-subtle);
10
+ background: var(--vmz-surface-paper);
11
+ color: var(--vmz-text-tertiary);
12
+ font-size: 0.8125rem;
13
+ line-height: 1.5;
11
14
  text-align: center;
12
15
  }
13
16
  </style>
@@ -34,6 +34,9 @@
34
34
  /**
35
35
  * VMZ UI — Form (hand-written commercial form shell).
36
36
  * Parent owns field values + validation presentation; no parallel form store.
37
+ * `rules` + `values` are evaluated at submit only: failures emit `invalid`
38
+ * (field -> rule key: required | min | max | pattern | custom) and suppress
39
+ * `submit`. Copy stays author-supplied.
37
40
  * Native submit/reset guarded; browser HTML5 validation left off (data-novalidate + preventDefault).
38
41
  */
39
42
  export default class Form {
@@ -43,14 +46,52 @@ export default class Form {
43
46
  public describedBy: string = "";
44
47
  public disabled: boolean = false;
45
48
  public disabledAttr: string = "false";
49
+ public rules: Record<string, {
50
+ required?: boolean;
51
+ minLength?: number;
52
+ maxLength?: number;
53
+ pattern?: string;
54
+ test?: (value: string, values: Record<string, unknown>) => boolean;
55
+ }> = {};
56
+ public values: Record<string, unknown> = {};
46
57
  public onSubmit: (() => void) | null = null;
47
58
  public onReset: (() => void) | null = null;
59
+ public onInvalid: ((errors: Record<string, string>) => void) | null = null;
48
60
  onSubmitGuard(ev) {
49
61
  if (ev && typeof ev.preventDefault === "function") ev.preventDefault();
50
62
  if (this.disabled) return;
63
+ const errors = this.collectErrors();
64
+ if (Object.keys(errors).length > 0) {
65
+ this.emit("invalid", errors);
66
+ if (typeof this.onInvalid === "function") this.onInvalid(errors);
67
+ return;
68
+ }
51
69
  this.emit("submit");
52
70
  if (typeof this.onSubmit === "function") this.onSubmit();
53
71
  }
72
+ collectErrors() {
73
+ const errors: Record<string, string> = {};
74
+ const rules = this.rules || {};
75
+ const values = this.values || {};
76
+ for (const field of Object.keys(rules)) {
77
+ const rule = rules[field] || {};
78
+ const raw = values[field];
79
+ const text = raw == null ? "" : String(raw);
80
+ const filled = text.trim().length > 0;
81
+ if (rule.required && !filled) {
82
+ errors[field] = "required";
83
+ } else if (rule.minLength && filled && text.length < Number(rule.minLength)) {
84
+ errors[field] = "min";
85
+ } else if (rule.maxLength && text.length > Number(rule.maxLength)) {
86
+ errors[field] = "max";
87
+ } else if (rule.pattern && filled && !new RegExp(String(rule.pattern)).test(text)) {
88
+ errors[field] = "pattern";
89
+ } else if (typeof rule.test === "function" && !rule.test(text, values)) {
90
+ errors[field] = "custom";
91
+ }
92
+ }
93
+ return errors;
94
+ }
54
95
  onResetGuard(ev) {
55
96
  if (ev && typeof ev.preventDefault === "function") ev.preventDefault();
56
97
  if (this.disabled) return;
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div data-vmz-ui="form-item" :data-required="requiredAttr" :data-invalid="invalidAttr" class="vmz-ui-form-item">
2
+ <div data-vmz-ui="form-item" :data-required="required ? 'true' : 'false'" :data-invalid="error ? 'true' : 'false'" class="vmz-ui-form-item">
3
3
  <label v-if="label" :for="controlId" class="vmz-ui-form-item__label">
4
4
  <span>
5
5
  {{ label }}
@@ -24,6 +24,7 @@
24
24
  display: flex;
25
25
  flex-direction: column;
26
26
  gap: 0.375rem;
27
+ width: 100%;
27
28
  max-width: 28rem;
28
29
  }
29
30
 
@@ -70,8 +71,6 @@ export default class FormItem {
70
71
  public description: string = "";
71
72
  public error: string = "";
72
73
  public required: boolean = false;
73
- public requiredAttr: string = "false";
74
- public invalidAttr: string = "false";
75
74
  public controlId: string = "vmz-form-item";
76
75
  public descriptionId: string = "vmz-form-item-desc";
77
76
  public errorId: string = "vmz-form-item-err";
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div data-vmz-ui="grid" class="vmz-ui-grid" :style="'--ui-grid-columns:' + columns + ';--ui-grid-gap:' + gap">
2
+ <div data-vmz-ui="grid" :data-columns="columns" class="vmz-ui-grid" :style="'--ui-grid-columns:' + columns + ';--ui-grid-gap:' + gap">
3
3
  <slot />
4
4
  </div>
5
5
  </template>
@@ -7,13 +7,16 @@
7
7
  .vmz-ui-grid {
8
8
  display: grid;
9
9
  grid-template-columns: repeat(var(--ui-grid-columns, 3), minmax(0, 1fr));
10
- gap: var(--ui-grid-gap, 1rem);
10
+ gap: var(--ui-grid-gap, var(--vmz-space-4));
11
+ align-items: stretch;
11
12
  }
13
+
12
14
  @media (max-width: 900px) {
13
15
  .vmz-ui-grid {
14
16
  grid-template-columns: repeat(2, minmax(0, 1fr));
15
17
  }
16
18
  }
19
+
17
20
  @media (max-width: 600px) {
18
21
  .vmz-ui-grid {
19
22
  grid-template-columns: 1fr;
@@ -23,6 +26,6 @@
23
26
  <script client>
24
27
  export default class Grid {
25
28
  public columns: number = 3;
26
- public gap: string = "1rem";
29
+ public gap: string = "var(--vmz-space-4)";
27
30
  }
28
31
  </script>
@@ -1,18 +1,205 @@
1
1
  <template>
2
- <header data-vmz-ui="header" class="vmz-ui-header">
2
+ <header data-vmz-ui="header" :data-structured="hasNav() ? 'true' : 'false'" :onKeyDown="onMenuKeyDown" class="vmz-ui-header">
3
+ <div v-if="hasNav()" class="vmz-ui-header__inner">
4
+ <a v-if="brand" :href="homeHref" class="vmz-ui-header__brand">
5
+ {{ brand }}
6
+ </a>
7
+ <nav :id="navId" :aria-label="navLabel" :data-open="menuOpen ? 'true' : null" class="vmz-ui-header__nav">
8
+ <a v-for="item in nav" :key="item.id" :href="item.href" :data-vmz-nav="item.id" :data-active="item.id === activeId ? 'true' : 'false'" :aria-current="item.id === activeId ? 'page' : null" @click="closeMenu" class="vmz-ui-header__nav-item">
9
+ {{ item.title }}
10
+ </a>
11
+ </nav>
12
+ <div class="vmz-ui-header__actions">
13
+ <slot name="actions" />
14
+ </div>
15
+ <button type="button" :aria-label="menuLabel ? menuLabel : navLabel" :aria-expanded="menuOpen ? 'true' : 'false'" :aria-controls="navId" @click="toggleMenu" class="vmz-ui-header__menu">
16
+ <Icon :name="menuOpen ? 'action.close' : 'action.menu'" size="md" decorative />
17
+ </button>
18
+ </div>
3
19
  <slot />
4
20
  </header>
5
21
  </template>
6
22
  <style>
7
23
  .vmz-ui-header {
8
- min-height: 4rem;
24
+ position: sticky;
25
+ top: 0;
26
+ z-index: 30;
27
+ background: var(--vmz-surface-paper);
28
+ border-bottom: 1px solid var(--vmz-line-subtle);
29
+ }
30
+ .vmz-ui-header[data-structured="false"] {
31
+ display: flex;
32
+ align-items: center;
33
+ gap: var(--vmz-space-6, 2rem);
34
+ min-height: var(--vmz-layout-header-height, 4rem);
35
+ padding: 0 var(--vmz-layout-gutter, 1rem);
36
+ }
37
+ .vmz-ui-header__inner {
38
+ width: min(var(--vmz-layout-max-width, 75rem), calc(100% - (var(--vmz-layout-gutter, 1rem) * 2)));
39
+ height: var(--vmz-layout-header-height, 4rem);
40
+ margin: 0 auto;
9
41
  display: flex;
10
42
  align-items: center;
11
- padding: 0 1.5rem;
12
- border-bottom: 1px solid var(--vmz-line-default, #d9d9d9);
13
- background: var(--vmz-surface-paper, #fff);
43
+ gap: var(--vmz-space-6, 2rem);
44
+ }
45
+ .vmz-ui-header__brand {
46
+ flex: none;
47
+ color: var(--vmz-text-ink);
48
+ font-family: var(--vmz-font-sans);
49
+ font-size: 1.0625rem;
50
+ font-weight: 600;
51
+ line-height: 1.25;
52
+ letter-spacing: -0.01em;
53
+ text-decoration: none;
54
+ border-radius: var(--vmz-radius-sm, 4px);
55
+ outline: none;
56
+ transition: color var(--vmz-motion-control-duration, 150ms) var(--vmz-motion-control-easing, cubic-bezier(0.4, 0, 0.2, 1));
57
+ }
58
+ .vmz-ui-header__brand:hover {
59
+ color: var(--vmz-action-primary-background);
60
+ }
61
+ .vmz-ui-header__brand:focus-visible {
62
+ box-shadow: 0 0 0 3px var(--vmz-focus-ring);
63
+ }
64
+ .vmz-ui-header__nav {
65
+ flex: 0 1 auto;
66
+ min-width: 0;
67
+ height: 100%;
68
+ display: flex;
69
+ align-items: center;
70
+ gap: var(--vmz-space-5, 1.5rem);
71
+ }
72
+ .vmz-ui-header__nav-item {
73
+ position: relative;
74
+ display: inline-flex;
75
+ align-items: center;
76
+ height: 100%;
77
+ box-sizing: border-box;
78
+ border-bottom: 2px solid transparent;
79
+ color: var(--vmz-text-steel);
80
+ font-size: 0.875rem;
81
+ font-weight: 500;
82
+ line-height: 1;
83
+ text-decoration: none;
84
+ white-space: nowrap;
85
+ outline: none;
86
+ transition:
87
+ color var(--vmz-motion-control-duration, 150ms) var(--vmz-motion-control-easing, cubic-bezier(0.4, 0, 0.2, 1)),
88
+ border-color var(--vmz-motion-control-duration, 150ms) var(--vmz-motion-control-easing, cubic-bezier(0.4, 0, 0.2, 1));
89
+ }
90
+ .vmz-ui-header__nav-item:hover {
91
+ color: var(--vmz-action-primary-background);
92
+ }
93
+ .vmz-ui-header__nav-item[data-active="true"] {
94
+ color: var(--vmz-action-primary-background);
95
+ border-bottom-color: var(--vmz-action-primary-background);
96
+ }
97
+ .vmz-ui-header__nav-item:focus-visible {
98
+ border-radius: var(--vmz-radius-sm, 4px);
99
+ box-shadow: 0 0 0 3px var(--vmz-focus-ring);
100
+ }
101
+ .vmz-ui-header__actions {
102
+ flex: none;
103
+ display: flex;
104
+ align-items: center;
105
+ gap: var(--vmz-space-2, 0.5rem);
106
+ margin-left: auto;
107
+ }
108
+ .vmz-ui-header__menu {
109
+ display: none;
110
+ }
111
+ @media (max-width: 720px) {
112
+ .vmz-ui-header[data-structured="false"] {
113
+ min-height: var(--vmz-layout-header-height-compact, 3.5rem);
114
+ gap: var(--vmz-space-3, 0.75rem);
115
+ }
116
+ .vmz-ui-header__inner {
117
+ height: var(--vmz-layout-header-height-compact, 3.5rem);
118
+ gap: var(--vmz-space-3, 0.75rem);
119
+ }
120
+ .vmz-ui-header__nav {
121
+ display: none;
122
+ position: absolute;
123
+ top: 100%;
124
+ left: 0;
125
+ right: 0;
126
+ height: auto;
127
+ flex-direction: column;
128
+ align-items: stretch;
129
+ gap: 0;
130
+ padding: var(--vmz-space-2, 0.5rem) var(--vmz-layout-gutter, 1rem) var(--vmz-space-4, 1rem);
131
+ border-bottom: 1px solid var(--vmz-line-subtle);
132
+ background: var(--vmz-surface-paper);
133
+ box-shadow: var(--vmz-shadow-popup);
134
+ }
135
+ .vmz-ui-header__nav[data-open="true"] {
136
+ display: flex;
137
+ }
138
+ .vmz-ui-header__nav-item {
139
+ height: 2.5rem;
140
+ padding: 0 var(--vmz-space-1, 0.25rem);
141
+ border-bottom: 0;
142
+ }
143
+ .vmz-ui-header__menu {
144
+ flex: none;
145
+ display: inline-flex;
146
+ align-items: center;
147
+ justify-content: center;
148
+ width: 2.5rem;
149
+ height: 2.5rem;
150
+ padding: 0;
151
+ border: 0;
152
+ border-radius: var(--vmz-radius-md, 6px);
153
+ background: transparent;
154
+ color: var(--vmz-text-ink);
155
+ cursor: pointer;
156
+ outline: none;
157
+ transition: background-color var(--vmz-motion-control-duration, 150ms) var(--vmz-motion-control-easing, cubic-bezier(0.4, 0, 0.2, 1));
158
+ }
159
+ .vmz-ui-header__menu:hover {
160
+ background: var(--vmz-surface-mist);
161
+ }
162
+ .vmz-ui-header__menu:focus-visible {
163
+ box-shadow: 0 0 0 3px var(--vmz-focus-ring);
164
+ }
14
165
  }
15
166
  </style>
16
167
  <script client>
17
- export default class Header {}
168
+ /**
169
+ * VMZ UI — Header (Commercial chrome).
170
+ * Flat nav links plus a named `actions` slot. With no `nav` items the default
171
+ * slot renders as a plain padded bar. Copy stays with the parent.
172
+ */
173
+ export default class Header {
174
+ public brand: string = "";
175
+ public homeHref: string = "/";
176
+ public navLabel: string = "";
177
+ public menuLabel: string = "";
178
+ /** Id of the nav item representing the current page. */
179
+ public activeId: string = "";
180
+ public navId: string = "vmz-ui-header-nav";
181
+ /** Parent-supplied labels; the component never hardcodes copy. */
182
+ public nav: {
183
+ id: string;
184
+ title: string;
185
+ href: string;
186
+ }[] = [];
187
+ menuOpen = false;
188
+
189
+ hasNav() {
190
+ return Array.isArray(this.nav) && this.nav.length > 0;
191
+ }
192
+
193
+ toggleMenu() {
194
+ this.menuOpen = !this.menuOpen;
195
+ }
196
+
197
+ closeMenu() {
198
+ if (this.menuOpen) this.menuOpen = false;
199
+ }
200
+
201
+ onMenuKeyDown(e) {
202
+ if (e && e.key === "Escape") this.closeMenu();
203
+ }
204
+ }
18
205
  </script>
@@ -8,7 +8,9 @@
8
8
  display: flex;
9
9
  flex-direction: column;
10
10
  min-height: 100%;
11
- background: var(--vmz-surface-page, var(--vmz-surface-mist, #f5f5f5));
11
+ color: var(--vmz-text-ink);
12
+ background: var(--vmz-surface-page);
13
+ font-family: var(--vmz-font-sans);
12
14
  }
13
15
  </style>
14
16
  <script client>
@@ -6,22 +6,21 @@
6
6
  <style>
7
7
  .vmz-ui-link {
8
8
  font: inherit;
9
- font-weight: 600;
10
- color: var(--vmz-action-primary-background);
9
+ font-weight: 500;
10
+ color: var(--vmz-action-link-foreground);
11
11
  text-decoration: underline;
12
12
  text-underline-offset: 0.2em;
13
13
  text-decoration-thickness: 1px;
14
- text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
14
+ text-decoration-color: currentColor;
15
15
  outline: none;
16
- border-radius: var(--vmz-radius-sm, 4px);
16
+ border-radius: var(--vmz-radius-sm);
17
17
  transition:
18
- color var(--vmz-motion-control-duration, 150ms) var(--vmz-motion-control-easing, cubic-bezier(0.4, 0, 0.2, 1)),
19
- text-decoration-color var(--vmz-motion-control-duration, 150ms) var(--vmz-motion-control-easing, cubic-bezier(0.4, 0, 0.2, 1));
18
+ color var(--vmz-motion-control-duration) var(--vmz-motion-control-easing),
19
+ text-decoration-color var(--vmz-motion-control-duration) var(--vmz-motion-control-easing);
20
20
  }
21
21
 
22
22
  .vmz-ui-link:hover {
23
- color: var(--vmz-action-primary-hover);
24
- text-decoration-color: currentColor;
23
+ color: var(--vmz-action-link-hover);
25
24
  }
26
25
 
27
26
  .vmz-ui-link:active {
@@ -39,21 +38,33 @@
39
38
  }
40
39
 
41
40
  .vmz-ui-link[data-variant="muted"]:hover {
42
- color: var(--vmz-action-primary-background);
41
+ color: var(--vmz-action-link-hover);
43
42
  text-decoration-color: currentColor;
44
43
  }
45
44
 
46
45
  /* Navigation link: chrome, not prose — underline is the hover affordance. */
47
46
  .vmz-ui-link[data-variant="nav"] {
48
47
  font-weight: 500;
48
+ color: var(--vmz-text-ink);
49
49
  text-decoration: none;
50
50
  text-decoration-color: transparent;
51
51
  }
52
52
 
53
53
  .vmz-ui-link[data-variant="nav"]:hover {
54
+ color: var(--vmz-action-link-hover);
54
55
  text-decoration: underline;
55
56
  text-decoration-color: currentColor;
56
57
  }
58
+
59
+ .vmz-ui-link[data-variant="nav"]:active {
60
+ color: var(--vmz-action-primary-active);
61
+ }
62
+
63
+ @media (prefers-reduced-motion: reduce) {
64
+ .vmz-ui-link {
65
+ transition: none;
66
+ }
67
+ }
57
68
  </style>
58
69
  <script client>
59
70
  /**
@@ -14,48 +14,70 @@
14
14
  .vmz-ui-list {
15
15
  display: flex;
16
16
  flex-direction: column;
17
- gap: 0.375rem;
17
+ gap: var(--vmz-space-2, 0.5rem);
18
18
  max-width: 28rem;
19
19
  }
20
20
 
21
21
  .vmz-ui-list__label {
22
22
  margin: 0;
23
+ font-size: 0.875rem;
23
24
  font-weight: 600;
24
25
  color: var(--vmz-text-ink);
25
26
  }
26
27
 
27
28
  .vmz-ui-list__items {
28
29
  margin: 0;
29
- padding: 0.25rem;
30
+ padding: 0;
30
31
  list-style: none;
31
- border: 1px solid var(--vmz-line-default);
32
- border-radius: var(--vmz-radius-md, 6px);
32
+ overflow: hidden;
33
+ border: 1px solid var(--vmz-line-default, var(--vmz-line-strong));
34
+ border-radius: var(--vmz-radius-lg, 8px);
33
35
  background: var(--vmz-surface-paper);
34
36
  color: var(--vmz-text-ink);
35
37
  }
36
38
 
37
39
  .vmz-ui-list__item {
38
- padding: var(--vmz-density-control-padding-y) var(--vmz-density-control-padding-x);
39
- border-radius: var(--vmz-radius-md, 6px);
40
+ display: flex;
41
+ align-items: center;
42
+ min-height: var(--vmz-control-height, 2rem);
43
+ padding: var(--vmz-space-2, 0.5rem) var(--vmz-space-4, 1rem);
44
+ font-size: 0.875rem;
45
+ line-height: 1.5;
40
46
  cursor: pointer;
41
47
  outline: none;
48
+ transition:
49
+ background-color var(--vmz-motion-control-duration, 120ms) var(--vmz-motion-control-easing, cubic-bezier(0.2, 0, 0, 1)),
50
+ color var(--vmz-motion-control-duration, 120ms) var(--vmz-motion-control-easing, cubic-bezier(0.2, 0, 0, 1));
42
51
  }
43
52
 
44
- .vmz-ui-list__item[aria-selected="true"] {
45
- background: var(--vmz-action-primary-background);
46
- color: var(--vmz-action-primary-foreground);
53
+ .vmz-ui-list__item + .vmz-ui-list__item {
54
+ border-top: 1px solid var(--vmz-line-subtle, var(--vmz-line-default));
47
55
  }
48
56
 
49
57
  .vmz-ui-list__item:hover {
50
- background: color-mix(in srgb, var(--vmz-action-primary-background) 14%, transparent);
58
+ background: var(--vmz-surface-mist);
59
+ }
60
+
61
+ .vmz-ui-list__item[aria-selected="true"] {
62
+ background: var(--vmz-action-primary-soft, var(--vmz-surface-mist));
63
+ color: var(--vmz-action-primary-active);
64
+ font-weight: 500;
51
65
  }
52
66
 
53
67
  .vmz-ui-list__item[aria-selected="true"]:hover {
54
- background: var(--vmz-action-primary-hover);
68
+ background: var(--vmz-action-primary-soft, var(--vmz-surface-mist));
55
69
  }
56
70
 
57
71
  .vmz-ui-list__item:focus-visible {
58
- box-shadow: 0 0 0 3px var(--vmz-focus-ring);
72
+ box-shadow: inset 0 0 0 2px var(--vmz-focus-ring);
73
+ }
74
+
75
+ :where([data-density="compact"]) .vmz-ui-list__item {
76
+ padding: var(--vmz-density-compact-padding-y) var(--vmz-density-compact-padding-x);
77
+ }
78
+
79
+ :where([data-density="dense"]) .vmz-ui-list__item {
80
+ padding: var(--vmz-density-dense-padding-y) var(--vmz-density-dense-padding-x);
59
81
  }
60
82
  </style>
61
83
  <script client>
@@ -64,7 +86,7 @@
64
86
  * Parent owns `selected` id; click + Arrow/Home/End. Not a DataGrid.
65
87
  */
66
88
  export default class List {
67
- public label: string = "List";
89
+ public label: string = "";
68
90
  public labelId: string = "vmz-list-label";
69
91
  public selected: string = "";
70
92
  /** @type {{ id: string, title: string }[]} */