@vmz/ui 0.3.7 → 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 +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 +217 -63
  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
@@ -4,48 +4,51 @@
4
4
  {{ label }}
5
5
  </label>
6
6
  <button type="button" :id="controlId" :disabled="disabled" aria-haspopup="dialog" :aria-expanded="open ? 'true' : 'false'" :aria-controls="panelId" :aria-invalid="error ? 'true' : 'false'" :aria-describedby="describedBy" @click="toggle" :onKeyDown="onTriggerKeyDown" class="vmz-ui-date-picker__control">
7
+ <Icon name="action.calendar" size="md" decorative />
7
8
  <span data-vmz-date="value" class="vmz-ui-date-picker__value">
8
9
  {{ displayLabel }}
9
10
  </span>
10
- <span aria-hidden="true" class="vmz-ui-date-picker__chev" />
11
+ <span class="vmz-ui-date-picker__chev">
12
+ <Icon name="action.chevron-down" size="sm" decorative />
13
+ </span>
11
14
  </button>
12
- <div v-if="open" :id="panelId" role="dialog" aria-modal="false" :aria-label="panelLabel" tabindex="-1" data-vmz-overlay="date-picker" data-vmz-overlay-owner="date-picker" data-vmz-focus="enter" data-vmz-date="panel" :onKeyDown="onPanelKeyDown" class="vmz-ui-date-picker__panel">
15
+ <div v-if="open" :id="panelId" role="dialog" aria-modal="false" :aria-label="panelLabel || monthLabel" tabindex="-1" data-vmz-overlay="date-picker" data-vmz-overlay-owner="date-picker" data-vmz-focus="enter" data-vmz-date="panel" :onKeyDown="onPanelKeyDown" class="vmz-ui-date-picker__panel">
13
16
  <div class="vmz-ui-date-picker__monthbar">
14
- <button type="button" data-vmz-date="prev" aria-label="Previous month" @click="prevMonth" class="vmz-ui-date-picker__nav">
15
- ‹
17
+ <button type="button" data-vmz-date="prev" :aria-label="prevMonthLabel || monthLabel" @click="prevMonth" class="vmz-ui-date-picker__nav">
18
+ <Icon name="action.chevron-left" size="sm" decorative />
16
19
  </button>
17
20
  <p data-vmz-date="month" class="vmz-ui-date-picker__month">
18
21
  {{ monthLabel }}
19
22
  </p>
20
- <button type="button" data-vmz-date="next" aria-label="Next month" @click="nextMonth" class="vmz-ui-date-picker__nav">
21
- ›
23
+ <button type="button" data-vmz-date="next" :aria-label="nextMonthLabel || monthLabel" @click="nextMonth" class="vmz-ui-date-picker__nav">
24
+ <Icon name="action.chevron-right" size="sm" decorative />
22
25
  </button>
23
26
  </div>
24
27
  <div aria-hidden="true" class="vmz-ui-date-picker__weekdays">
25
28
  <span>
26
- Mo
29
+ {{ weekdayLabel(0) }}
27
30
  </span>
28
31
  <span>
29
- Tu
32
+ {{ weekdayLabel(1) }}
30
33
  </span>
31
34
  <span>
32
- We
35
+ {{ weekdayLabel(2) }}
33
36
  </span>
34
37
  <span>
35
- Th
38
+ {{ weekdayLabel(3) }}
36
39
  </span>
37
40
  <span>
38
- Fr
41
+ {{ weekdayLabel(4) }}
39
42
  </span>
40
43
  <span>
41
- Sa
44
+ {{ weekdayLabel(5) }}
42
45
  </span>
43
46
  <span>
44
- Su
47
+ {{ weekdayLabel(6) }}
45
48
  </span>
46
49
  </div>
47
50
  <div role="grid" :aria-labelledby="panelId" class="vmz-ui-date-picker__grid">
48
- <button v-for="day in days" :key="day.key" type="button" role="gridcell" :data-vmz-date-iso="day.iso" :aria-selected="day.selected ? 'true' : 'false'" :aria-disabled="day.disabled ? 'true' : 'false'" :disabled="day.disabled" @click="onDayClick" :class='"vmz-ui-date-picker__day" + (day.inMonth ? "" : " is-outside") + (day.selected ? " is-on" : "") + (day.inRange ? " is-in-range" : "") + (day.rangeEdge ? " is-range-edge" : "") + (day.disabled ? " is-disabled" : "")'>
51
+ <button v-for="day in days" :key="day.key" type="button" role="gridcell" :data-vmz-date-iso="day.iso" :aria-selected="day.selected ? 'true' : 'false'" :aria-disabled="day.disabled ? 'true' : 'false'" :disabled="day.disabled" @click="onDayClick" :class='"vmz-ui-date-picker__day" + (day.inMonth ? "" : " is-outside") + (day.selected ? " is-on" : "") + (day.inRange ? " is-in-range" : "") + (day.rangeEdge ? " is-range-edge" : "") + (day.today ? " is-today" : "") + (day.disabled ? " is-disabled" : "")'>
49
52
  {{ day.label }}
50
53
  </button>
51
54
  </div>
@@ -63,31 +66,43 @@
63
66
  position: relative;
64
67
  display: flex;
65
68
  flex-direction: column;
66
- gap: 0.375rem;
69
+ gap: 6px;
70
+ width: 100%;
67
71
  max-width: 28rem;
68
72
  }
69
73
 
70
74
  .vmz-ui-date-picker__label {
71
- font: inherit;
75
+ font-size: 14px;
72
76
  font-weight: 600;
77
+ line-height: 22px;
78
+ color: var(--vmz-text-ink);
73
79
  }
74
80
 
75
81
  .vmz-ui-date-picker__control {
76
82
  display: inline-flex;
77
83
  align-items: center;
78
- justify-content: space-between;
79
- gap: 0.5rem;
84
+ gap: 8px;
80
85
  width: 100%;
86
+ min-height: var(--vmz-control-height, 32px);
81
87
  box-sizing: border-box;
82
88
  font: inherit;
89
+ font-size: 14px;
90
+ line-height: 22px;
83
91
  text-align: left;
84
92
  padding: var(--vmz-density-control-padding-y) var(--vmz-density-control-padding-x);
85
93
  border: 1px solid var(--vmz-line-default);
86
- border-radius: var(--vmz-radius-md, 6px);
87
- background: var(--vmz-surface-paper, transparent);
88
- color: inherit;
94
+ border-radius: var(--vmz-radius-md);
95
+ background: var(--vmz-surface-paper);
96
+ color: var(--vmz-text-ink);
89
97
  outline: none;
90
98
  cursor: pointer;
99
+ transition:
100
+ border-color var(--vmz-motion-control-duration) var(--vmz-motion-control-easing),
101
+ box-shadow var(--vmz-motion-control-duration) var(--vmz-motion-control-easing);
102
+ }
103
+
104
+ .vmz-ui-date-picker__control:hover:not(:disabled) {
105
+ border-color: var(--vmz-action-primary-hover);
91
106
  }
92
107
 
93
108
  .vmz-ui-date-picker[data-invalid="true"] .vmz-ui-date-picker__control {
@@ -96,6 +111,7 @@
96
111
 
97
112
  .vmz-ui-date-picker__control:focus-visible,
98
113
  .vmz-ui-date-picker.is-opened .vmz-ui-date-picker__control {
114
+ border-color: var(--vmz-action-primary-background);
99
115
  box-shadow: 0 0 0 3px var(--vmz-focus-ring);
100
116
  }
101
117
 
@@ -104,151 +120,215 @@
104
120
  cursor: not-allowed;
105
121
  }
106
122
 
123
+ .vmz-ui-date-picker__control .vmz-ui-icon {
124
+ flex: 0 0 auto;
125
+ color: var(--vmz-text-tertiary);
126
+ }
127
+
107
128
  .vmz-ui-date-picker__value {
108
129
  flex: 1 1 auto;
109
130
  min-width: 0;
110
131
  overflow: hidden;
111
132
  text-overflow: ellipsis;
112
133
  white-space: nowrap;
134
+ color: var(--vmz-text-ink);
113
135
  }
114
136
 
115
137
  .vmz-ui-date-picker__chev {
116
138
  flex: 0 0 auto;
117
- width: 0.45rem;
118
- height: 0.45rem;
119
- border-right: 1.5px solid currentColor;
120
- border-bottom: 1.5px solid currentColor;
121
- transform: rotate(45deg) translate(-1px, -2px);
122
- opacity: 0.7;
139
+ display: inline-flex;
140
+ transition: transform var(--vmz-motion-control-duration)
141
+ var(--vmz-motion-control-easing);
123
142
  }
124
143
 
125
144
  .vmz-ui-date-picker.is-opened .vmz-ui-date-picker__chev {
126
- transform: rotate(225deg) translate(-1px, -1px);
145
+ transform: rotate(180deg);
127
146
  }
128
147
 
129
148
  .vmz-ui-date-picker__panel {
130
149
  position: absolute;
131
150
  z-index: 40;
132
- top: calc(100% + 0.25rem);
151
+ top: calc(100% + 6px);
133
152
  left: 0;
134
- right: 0;
135
153
  box-sizing: border-box;
136
- padding: 0.625rem 0.75rem 0.75rem;
137
- border: 1px solid var(--vmz-line-default);
138
- border-radius: var(--vmz-radius-md, 6px);
139
- background: var(--vmz-surface-paper, #fff);
140
- color: inherit;
141
- box-shadow: 0 10px 24px color-mix(in srgb, #000 16%, transparent);
154
+ width: 280px;
155
+ max-width: calc(100vw - 32px);
156
+ padding: 12px;
157
+ border: 1px solid var(--vmz-line-subtle);
158
+ border-radius: var(--vmz-radius-lg);
159
+ background: var(--vmz-surface-paper);
160
+ color: var(--vmz-text-ink);
161
+ box-shadow: var(--vmz-shadow-popup);
142
162
  outline: none;
163
+ animation: vmz-ui-date-picker-in var(--vmz-motion-overlay-duration)
164
+ var(--vmz-motion-overlay-easing);
165
+ }
166
+
167
+ .vmz-ui-date-picker__panel:focus-visible {
168
+ box-shadow: 0 0 0 3px var(--vmz-focus-ring), var(--vmz-shadow-popup);
143
169
  }
144
170
 
145
171
  .vmz-ui-date-picker__monthbar {
146
172
  display: flex;
147
173
  align-items: center;
148
174
  justify-content: space-between;
149
- gap: 0.5rem;
150
- margin-bottom: 0.5rem;
175
+ gap: 4px;
176
+ margin-bottom: 8px;
151
177
  }
152
178
 
153
179
  .vmz-ui-date-picker__month {
180
+ flex: 1 1 auto;
154
181
  margin: 0;
155
- font: inherit;
182
+ font-size: 14px;
156
183
  font-weight: 600;
184
+ line-height: 22px;
157
185
  text-align: center;
158
- flex: 1 1 auto;
186
+ color: var(--vmz-text-ink);
159
187
  }
160
188
 
161
189
  .vmz-ui-date-picker__nav {
162
190
  flex: 0 0 auto;
163
- width: 2rem;
164
- height: 2rem;
165
- font: inherit;
166
- font-size: 1.15rem;
167
- line-height: 1;
168
- border: 1px solid transparent;
169
- border-radius: var(--vmz-radius-md, 6px);
191
+ display: inline-flex;
192
+ align-items: center;
193
+ justify-content: center;
194
+ width: 28px;
195
+ height: 28px;
196
+ padding: 0;
197
+ border: 0;
198
+ border-radius: var(--vmz-radius-md);
170
199
  background: transparent;
171
- color: inherit;
200
+ color: var(--vmz-text-steel);
172
201
  cursor: pointer;
173
202
  outline: none;
203
+ transition:
204
+ color var(--vmz-motion-control-duration) var(--vmz-motion-control-easing),
205
+ background-color var(--vmz-motion-control-duration) var(--vmz-motion-control-easing);
206
+ }
207
+
208
+ .vmz-ui-date-picker__nav:hover {
209
+ background: var(--vmz-surface-mist);
210
+ color: var(--vmz-text-ink);
174
211
  }
175
212
 
176
- .vmz-ui-date-picker__nav:hover,
177
213
  .vmz-ui-date-picker__nav:focus-visible {
178
- border-color: var(--vmz-action-primary-background);
179
214
  box-shadow: 0 0 0 3px var(--vmz-focus-ring);
180
215
  }
181
216
 
182
217
  .vmz-ui-date-picker__weekdays {
183
218
  display: grid;
184
219
  grid-template-columns: repeat(7, 1fr);
185
- gap: 0.125rem;
186
- margin-bottom: 0.25rem;
187
- font-size: 0.75rem;
188
- opacity: 0.7;
220
+ gap: 2px;
221
+ margin-bottom: 4px;
222
+ font-size: 12px;
223
+ line-height: 28px;
224
+ color: var(--vmz-text-tertiary);
189
225
  text-align: center;
190
226
  }
191
227
 
192
228
  .vmz-ui-date-picker__grid {
193
229
  display: grid;
194
230
  grid-template-columns: repeat(7, 1fr);
195
- gap: 0.125rem;
231
+ gap: 2px;
196
232
  }
197
233
 
198
234
  .vmz-ui-date-picker__day {
199
- aspect-ratio: 1;
200
- min-height: 2rem;
235
+ display: inline-flex;
236
+ align-items: center;
237
+ justify-content: center;
238
+ width: 100%;
239
+ height: 32px;
240
+ box-sizing: border-box;
201
241
  font: inherit;
202
- font-size: 0.9rem;
242
+ font-size: 14px;
243
+ line-height: 22px;
244
+ padding: 0;
203
245
  border: 0;
204
- border-radius: var(--vmz-radius-md, 6px);
246
+ border-radius: var(--vmz-radius-md);
205
247
  background: transparent;
206
- color: inherit;
248
+ color: var(--vmz-text-ink);
207
249
  cursor: pointer;
208
250
  outline: none;
251
+ transition:
252
+ background-color var(--vmz-motion-control-duration) var(--vmz-motion-control-easing),
253
+ color var(--vmz-motion-control-duration) var(--vmz-motion-control-easing);
254
+ }
255
+
256
+ .vmz-ui-date-picker__day:hover {
257
+ background: var(--vmz-surface-mist);
209
258
  }
210
259
 
211
- .vmz-ui-date-picker__day:hover,
212
260
  .vmz-ui-date-picker__day:focus-visible {
213
- background: color-mix(in srgb, var(--vmz-action-primary-background) 18%, transparent);
214
- box-shadow: 0 0 0 3px var(--vmz-focus-ring);
261
+ box-shadow: inset 0 0 0 2px var(--vmz-focus-ring);
215
262
  }
216
263
 
217
264
  .vmz-ui-date-picker__day.is-outside {
218
- opacity: 0.4;
265
+ color: var(--vmz-text-tertiary);
266
+ opacity: 0.6;
267
+ }
268
+
269
+ .vmz-ui-date-picker__day.is-today {
270
+ box-shadow: inset 0 0 0 1px var(--vmz-action-primary-background);
219
271
  }
220
272
 
221
- .vmz-ui-date-picker__day.is-on {
222
- background: color-mix(in srgb, var(--vmz-action-primary-background) 28%, transparent);
273
+ .vmz-ui-date-picker__day.is-on,
274
+ .vmz-ui-date-picker__day.is-range-edge {
275
+ background: var(--vmz-action-primary-background);
276
+ color: var(--vmz-action-primary-foreground);
223
277
  font-weight: 600;
224
278
  }
225
279
 
226
- .vmz-ui-date-picker__day.is-in-range {
227
- background: color-mix(in srgb, var(--vmz-action-primary-background) 14%, transparent);
280
+ .vmz-ui-date-picker__day.is-on:hover,
281
+ .vmz-ui-date-picker__day.is-range-edge:hover {
282
+ background: var(--vmz-action-primary-hover);
228
283
  }
229
284
 
230
- .vmz-ui-date-picker__day.is-range-edge {
231
- background: color-mix(in srgb, var(--vmz-action-primary-background) 36%, transparent);
232
- font-weight: 600;
285
+ .vmz-ui-date-picker__day.is-in-range {
286
+ background: color-mix(in srgb, var(--vmz-action-primary-background) 12%, transparent);
233
287
  }
234
288
 
235
289
  .vmz-ui-date-picker__day.is-disabled,
236
290
  .vmz-ui-date-picker__day:disabled {
237
291
  opacity: 0.35;
238
292
  cursor: not-allowed;
293
+ background: transparent;
239
294
  box-shadow: none;
295
+ color: var(--vmz-text-tertiary);
240
296
  }
241
297
 
242
298
  .vmz-ui-date-picker__description {
243
299
  margin: 0;
244
- opacity: 0.75;
245
- font-size: 0.9em;
300
+ font-size: 14px;
301
+ line-height: 22px;
302
+ color: var(--vmz-text-tertiary);
246
303
  }
247
304
 
248
305
  .vmz-ui-date-picker__error {
249
306
  margin: 0;
307
+ font-size: 14px;
308
+ line-height: 22px;
250
309
  color: var(--vmz-status-danger-foreground);
251
- font-size: 0.9em;
310
+ }
311
+
312
+ @keyframes vmz-ui-date-picker-in {
313
+ from {
314
+ opacity: 0;
315
+ transform: translateY(-4px);
316
+ }
317
+ to {
318
+ opacity: 1;
319
+ transform: none;
320
+ }
321
+ }
322
+
323
+ @media (prefers-reduced-motion: reduce) {
324
+ .vmz-ui-date-picker__panel,
325
+ .vmz-ui-date-picker__control,
326
+ .vmz-ui-date-picker__chev,
327
+ .vmz-ui-date-picker__nav,
328
+ .vmz-ui-date-picker__day {
329
+ animation: none;
330
+ transition: none;
331
+ }
252
332
  }
253
333
  </style>
254
334
  <script client>
@@ -258,6 +338,10 @@
258
338
  * Parent owns ISO value (YYYY-MM-DD) via onChange Event-like { target: { value } }.
259
339
  * mode=range: parent owns rangeStart + rangeEnd; onChange { target: { value, start, end } }.
260
340
  * Not @vmz/ui-scheduler — month grid only; no time / recurrence / resource layout.
341
+ *
342
+ * Localization props: `prevMonthLabel`, `nextMonthLabel`, `panelLabel` and
343
+ * `weekdayLabels` (7 entries, Monday-first). Empty defaults keep visible chrome
344
+ * free of hard-coded copy.
261
345
  */
262
346
  export default class DatePicker {
263
347
  public label: string = "";
@@ -276,6 +360,11 @@ export default class DatePicker {
276
360
  public descriptionId: string = "vmz-date-desc";
277
361
  public errorId: string = "vmz-date-err";
278
362
  public describedBy: string = "";
363
+ public prevMonthLabel: string = "";
364
+ public nextMonthLabel: string = "";
365
+ public panelLabel: string = "";
366
+ /** Seven Monday-first weekday headings. */
367
+ public weekdayLabels: string[] = [];
279
368
  public onInput:
280
369
  | ((e: {
281
370
  target: {
@@ -297,7 +386,6 @@ export default class DatePicker {
297
386
  open = false;
298
387
  displayLabel = "—";
299
388
  panelId = "vmz-date-panel";
300
- panelLabel = "Choose date";
301
389
  monthLabel = "";
302
390
  viewYear = 0;
303
391
  viewMonth = 0;
@@ -311,6 +399,7 @@ export default class DatePicker {
311
399
  selected: boolean;
312
400
  inRange: boolean;
313
401
  rangeEdge: boolean;
402
+ today: boolean;
314
403
  disabled: boolean;
315
404
  }> = [];
316
405
  _docKeyHandler = null;
@@ -335,6 +424,10 @@ export default class DatePicker {
335
424
  }
336
425
  this._teardownDoc();
337
426
  }
427
+ weekdayLabel(index: number) {
428
+ const labels = Array.isArray(this.weekdayLabels) ? this.weekdayLabels : [];
429
+ return labels[index] || "";
430
+ }
338
431
  syncFromValue(resetView: boolean) {
339
432
  const isRange = String(this.mode) === "range";
340
433
  const parsed = this._parseIso(
@@ -508,10 +601,8 @@ export default class DatePicker {
508
601
  this.viewYear = y;
509
602
  this.viewMonth = m;
510
603
  this.monthLabel = `${this._monthName(m)} ${y}`;
511
- this.panelLabel =
512
- String(this.mode) === "range"
513
- ? `Choose date range — ${this.monthLabel}`
514
- : `Choose date — ${this.monthLabel}`;
604
+ const today = this._todayParts();
605
+ const todayIso = this._toIso(today.y, today.m, today.d);
515
606
  const firstDow = (new Date(y, m - 1, 1).getDay() + 6) % 7;
516
607
  const dim = new Date(y, m, 0).getDate();
517
608
  const prevDim = new Date(y, m - 1, 0).getDate();
@@ -569,6 +660,7 @@ export default class DatePicker {
569
660
  selected,
570
661
  inRange: inRange && !rangeEdge,
571
662
  rangeEdge,
663
+ today: iso === todayIso,
572
664
  disabled: this._isOutOfRange(iso),
573
665
  });
574
666
  }
@@ -0,0 +1,90 @@
1
+ <template>
2
+ <dl data-vmz-ui="descriptions" :data-columns="normalizeColumns()" :data-bordered="bordered ? 'true' : 'false'" class="vmz-ui-descriptions">
3
+ <div v-for="item in items" :key="item.term" class="vmz-ui-descriptions__item">
4
+ <dt class="vmz-ui-descriptions__term">
5
+ {{ item.term }}
6
+ </dt>
7
+ <dd :data-vmz-fixture="item.fixture || null" class="vmz-ui-descriptions__detail">
8
+ {{ item.detail }}
9
+ </dd>
10
+ </div>
11
+ <slot />
12
+ </dl>
13
+ </template>
14
+ <style>
15
+ .vmz-ui-descriptions {
16
+ display: grid;
17
+ grid-template-columns: repeat(2, minmax(0, 1fr));
18
+ gap: 0.85rem 1.25rem;
19
+ margin: 0;
20
+ color: var(--vmz-text-ink);
21
+ }
22
+
23
+ .vmz-ui-descriptions[data-columns="1"] {
24
+ grid-template-columns: minmax(0, 1fr);
25
+ }
26
+
27
+ .vmz-ui-descriptions[data-columns="3"] {
28
+ grid-template-columns: repeat(3, minmax(0, 1fr));
29
+ }
30
+
31
+ .vmz-ui-descriptions__item {
32
+ display: grid;
33
+ gap: 0.2rem;
34
+ min-width: 0;
35
+ }
36
+
37
+ .vmz-ui-descriptions__term {
38
+ margin: 0;
39
+ color: var(--vmz-text-steel);
40
+ font-size: 0.8125rem;
41
+ line-height: 1.25rem;
42
+ }
43
+
44
+ .vmz-ui-descriptions__detail {
45
+ margin: 0;
46
+ color: var(--vmz-text-ink);
47
+ font-size: 0.875rem;
48
+ line-height: 1.375rem;
49
+ overflow-wrap: anywhere;
50
+ }
51
+
52
+ .vmz-ui-descriptions[data-bordered="true"] {
53
+ gap: 0;
54
+ border: 1px solid var(--vmz-line-default);
55
+ border-radius: var(--vmz-radius-md);
56
+ overflow: hidden;
57
+ }
58
+
59
+ .vmz-ui-descriptions[data-bordered="true"] .vmz-ui-descriptions__item {
60
+ padding: 0.65rem 0.85rem;
61
+ border-bottom: 1px solid var(--vmz-line-subtle);
62
+ }
63
+
64
+ .vmz-ui-descriptions[data-bordered="true"] .vmz-ui-descriptions__item:last-child {
65
+ border-bottom: 0;
66
+ }
67
+
68
+ @media (max-width: 40rem) {
69
+ .vmz-ui-descriptions,
70
+ .vmz-ui-descriptions[data-columns="3"] {
71
+ grid-template-columns: minmax(0, 1fr);
72
+ }
73
+ }
74
+ </style>
75
+ <script client>
76
+ /**
77
+ * VMZ UI — Descriptions.
78
+ * Read-only key/value detail block (drawer and record detail). Parent owns `items`.
79
+ * No data fetching, no column inference, no editing.
80
+ */
81
+ export default class Descriptions {
82
+ public items: { term: string; detail: string; fixture?: string }[] = [];
83
+ public columns: string = "2";
84
+ public bordered: boolean = false;
85
+ normalizeColumns() {
86
+ const n = Number(this.columns);
87
+ return n === 1 || n === 2 || n === 3 ? String(n) : "2";
88
+ }
89
+ }
90
+ </script>