@vmz/ui 0.2.3 → 0.2.4

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 (63) hide show
  1. package/package.json +1 -1
  2. package/src/components/Accordion.vmz +46 -63
  3. package/src/components/Alert.vmz +35 -38
  4. package/src/components/AppShell.vmz +92 -75
  5. package/src/components/Autocomplete.vmz +91 -119
  6. package/src/components/Avatar.vmz +37 -8
  7. package/src/components/Badge.vmz +29 -23
  8. package/src/components/Breadcrumb.vmz +36 -34
  9. package/src/components/BulkActions.vmz +22 -28
  10. package/src/components/Button.vmz +139 -121
  11. package/src/components/Callout.vmz +33 -36
  12. package/src/components/Card.vmz +68 -51
  13. package/src/components/Checkbox.vmz +28 -47
  14. package/src/components/CodeBlock.vmz +31 -25
  15. package/src/components/Collapse.vmz +34 -16
  16. package/src/components/ConsoleShell.vmz +107 -110
  17. package/src/components/Content.vmz +8 -4
  18. package/src/components/DataTable.vmz +124 -150
  19. package/src/components/DatePicker.vmz +526 -521
  20. package/src/components/Dialog.vmz +408 -327
  21. package/src/components/Divider.vmz +38 -11
  22. package/src/components/Drawer.vmz +325 -318
  23. package/src/components/Dropdown.vmz +53 -19
  24. package/src/components/Empty.vmz +23 -21
  25. package/src/components/Field.vmz +77 -83
  26. package/src/components/FilterBar.vmz +8 -10
  27. package/src/components/Flex.vmz +21 -6
  28. package/src/components/Footer.vmz +9 -4
  29. package/src/components/Form.vmz +35 -46
  30. package/src/components/FormItem.vmz +44 -43
  31. package/src/components/Grid.vmz +22 -6
  32. package/src/components/Header.vmz +11 -4
  33. package/src/components/Icon.vmz +43 -44
  34. package/src/components/Layout.vmz +9 -4
  35. package/src/components/Link.vmz +17 -25
  36. package/src/components/List.vmz +62 -75
  37. package/src/components/Menu.vmz +182 -197
  38. package/src/components/Notification.vmz +35 -38
  39. package/src/components/Pagination.vmz +37 -47
  40. package/src/components/Popover.vmz +157 -171
  41. package/src/components/Progress.vmz +36 -10
  42. package/src/components/Prose.vmz +29 -31
  43. package/src/components/QueryForm.vmz +14 -22
  44. package/src/components/RadioGroup.vmz +70 -84
  45. package/src/components/Result.vmz +36 -38
  46. package/src/components/Segmented.vmz +43 -22
  47. package/src/components/Select.vmz +404 -411
  48. package/src/components/Sider.vmz +21 -4
  49. package/src/components/Skeleton.vmz +34 -42
  50. package/src/components/Space.vmz +24 -9
  51. package/src/components/Spinner.vmz +17 -23
  52. package/src/components/Steps.vmz +48 -51
  53. package/src/components/Switch.vmz +50 -60
  54. package/src/components/Table.vmz +81 -84
  55. package/src/components/Tabs.vmz +66 -88
  56. package/src/components/Tag.vmz +36 -11
  57. package/src/components/TextArea.vmz +73 -77
  58. package/src/components/Timeline.vmz +36 -32
  59. package/src/components/Toc.vmz +31 -37
  60. package/src/components/Tooltip.vmz +25 -35
  61. package/src/components/Tree.vmz +127 -144
  62. package/src/components/Typography.vmz +33 -7
  63. package/src/components/Upload.vmz +1135 -1057
@@ -1,78 +1,79 @@
1
1
  <template>
2
- <div
3
- class="vmz-ui-form-item"
4
- data-vmz-ui="form-item"
5
- :data-required="requiredAttr"
6
- :data-invalid="invalidAttr"
7
- >
8
- <label v-if="label" class="vmz-ui-form-item__label" :for="controlId">
9
- <span>{{ label }}</span>
10
- <span v-if="required" class="vmz-ui-form-item__required" aria-hidden="true">*</span>
11
- </label>
12
- <div class="vmz-ui-form-item__control">
13
- <slot />
14
- </div>
15
- <p v-if="description" :id="descriptionId" class="vmz-ui-form-item__description">{{ description }}</p>
16
- <p v-if="error" :id="errorId" class="vmz-ui-form-item__error" role="alert">{{ error }}</p>
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>
17
20
  </div>
18
21
  </template>
19
-
20
22
  <style>
21
- .vmz-ui-form-item {
23
+ .vmz-ui-form-item {
22
24
  display: flex;
23
25
  flex-direction: column;
24
26
  gap: 0.35rem;
25
27
  max-width: 28rem;
26
- }
28
+ }
27
29
 
28
- .vmz-ui-form-item__label {
30
+ .vmz-ui-form-item__label {
29
31
  display: inline-flex;
30
32
  align-items: baseline;
31
33
  gap: 0.25rem;
32
34
  font: inherit;
33
35
  font-weight: 600;
34
- }
36
+ }
35
37
 
36
- .vmz-ui-form-item__required {
38
+ .vmz-ui-form-item__required {
37
39
  color: var(--vmz-status-danger-accent);
38
40
  font-weight: 700;
39
- }
41
+ }
40
42
 
41
- .vmz-ui-form-item__control {
43
+ .vmz-ui-form-item__control {
42
44
  min-width: 0;
43
- }
45
+ }
44
46
 
45
- .vmz-ui-form-item__description {
47
+ .vmz-ui-form-item__description {
46
48
  margin: 0;
47
49
  opacity: 0.75;
48
50
  font-size: 0.9em;
49
- }
51
+ }
50
52
 
51
- .vmz-ui-form-item__error {
53
+ .vmz-ui-form-item__error {
52
54
  margin: 0;
53
55
  color: var(--vmz-status-danger-foreground);
54
56
  font-size: 0.9em;
55
- }
57
+ }
56
58
 
57
- .vmz-ui-form-item[data-invalid='true'] .vmz-ui-form-item__control :where(input, select, textarea) {
59
+ .vmz-ui-form-item[data-invalid="true"] .vmz-ui-form-item__control :where(input, select, textarea) {
58
60
  border-color: var(--vmz-status-danger-accent);
59
- }
61
+ }
60
62
  </style>
61
-
62
63
  <script client>
63
64
  /**
64
- * VMZ UI — FormItem.
65
- * Label / description / error shell for slotted controls; parent owns validation strings.
66
- */
65
+ * VMZ UI — FormItem.
66
+ * Label / description / error shell for slotted controls; parent owns validation strings.
67
+ */
67
68
  export default class FormItem {
68
- public label: string = "";
69
- public description: string = "";
70
- public error: string = "";
71
- public required: boolean = false;
72
- public requiredAttr: string = "false";
73
- public invalidAttr: string = "false";
74
- public controlId: string = "vmz-form-item";
75
- public descriptionId: string = "vmz-form-item-desc";
76
- public errorId: string = "vmz-form-item-err";
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";
77
78
  }
78
79
  </script>
@@ -1,12 +1,28 @@
1
- <template><div class="vmz-ui-grid" data-vmz-ui="grid" :style="'--ui-grid-columns:' + columns + ';--ui-grid-gap:' + gap"><slot /></div></template>
1
+ <template>
2
+ <div data-vmz-ui="grid" class="vmz-ui-grid" :style='"--ui-grid-columns:" + columns + ";--ui-grid-gap:" + gap'>
3
+ <slot />
4
+ </div>
5
+ </template>
2
6
  <style>
3
- .vmz-ui-grid{display:grid;grid-template-columns:repeat(var(--ui-grid-columns,3),minmax(0,1fr));gap:var(--ui-grid-gap,1rem)}
4
- @media(max-width:900px){.vmz-ui-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
5
- @media(max-width:600px){.vmz-ui-grid{grid-template-columns:1fr}}
7
+ .vmz-ui-grid {
8
+ display: grid;
9
+ grid-template-columns: repeat(var(--ui-grid-columns, 3), minmax(0, 1fr));
10
+ gap: var(--ui-grid-gap, 1rem);
11
+ }
12
+ @media (max-width: 900px) {
13
+ .vmz-ui-grid {
14
+ grid-template-columns: repeat(2, minmax(0, 1fr));
15
+ }
16
+ }
17
+ @media (max-width: 600px) {
18
+ .vmz-ui-grid {
19
+ grid-template-columns: 1fr;
20
+ }
21
+ }
6
22
  </style>
7
23
  <script client>
8
24
  export default class Grid {
9
- public columns: number = 3;
10
- public gap: string = '1rem';
25
+ public columns: number = 3;
26
+ public gap: string = "1rem";
11
27
  }
12
28
  </script>
@@ -1,11 +1,18 @@
1
1
  <template>
2
- <header class="vmz-ui-header" data-vmz-ui="header"><slot /></header>
2
+ <header data-vmz-ui="header" class="vmz-ui-header">
3
+ <slot />
4
+ </header>
3
5
  </template>
4
-
5
6
  <style>
6
- .vmz-ui-header{min-height:4rem;display:flex;align-items:center;padding:0 1.5rem;border-bottom:1px solid var(--vmz-line-default,#d9d9d9);background:var(--vmz-surface-paper,#fff)}
7
+ .vmz-ui-header {
8
+ min-height: 4rem;
9
+ display: flex;
10
+ 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);
14
+ }
7
15
  </style>
8
-
9
16
  <script client>
10
17
  export default class Header {}
11
18
  </script>
@@ -6,30 +6,30 @@
6
6
  </span>
7
7
  </template>
8
8
  <style>
9
- .vmz-ui-icon {
10
- display: inline-flex;
11
- align-items: center;
12
- justify-content: center;
13
- width: 1em;
14
- height: 1em;
15
- vertical-align: -0.125em;
16
- color: inherit;
17
- line-height: 1;
18
- }
19
- .vmz-ui-icon[data-size="sm"] {
20
- font-size: 0.875rem;
21
- }
22
- .vmz-ui-icon[data-size="md"] {
23
- font-size: 1rem;
24
- }
25
- .vmz-ui-icon[data-size="lg"] {
26
- font-size: 1.25rem;
27
- }
28
- .vmz-ui-icon__svg {
29
- width: 1em;
30
- height: 1em;
31
- display: block;
32
- }
9
+ .vmz-ui-icon {
10
+ display: inline-flex;
11
+ align-items: center;
12
+ justify-content: center;
13
+ width: 1em;
14
+ height: 1em;
15
+ vertical-align: -0.125em;
16
+ color: inherit;
17
+ line-height: 1;
18
+ }
19
+ .vmz-ui-icon[data-size="sm"] {
20
+ font-size: 0.875rem;
21
+ }
22
+ .vmz-ui-icon[data-size="md"] {
23
+ font-size: 1rem;
24
+ }
25
+ .vmz-ui-icon[data-size="lg"] {
26
+ font-size: 1.25rem;
27
+ }
28
+ .vmz-ui-icon__svg {
29
+ width: 1em;
30
+ height: 1em;
31
+ display: block;
32
+ }
33
33
  </style>
34
34
  <script client>
35
35
  /**
@@ -37,41 +37,40 @@
37
37
  * Pass `pathD` for custom SVG paths, or `name` for the built-in chrome set.
38
38
  * Full semantic registries live in optional `@vmz/ui-icons`.
39
39
  */
40
- const FALLBACK_PATH =
41
- 'M12 2a10 10 0 1 1 0 20 10 10 0 0 1 0-20zm1 5h-2v2h2zm0 4h-2v7h2z';
40
+ const FALLBACK_PATH = "M12 2a10 10 0 1 1 0 20 10 10 0 0 1 0-20zm1 5h-2v2h2zm0 4h-2v7h2z";
42
41
 
43
42
  const CHROME_PATHS = {
44
- check: 'M9.2 16.6 4.8 12.2l1.4-1.4 3 3 8-8 1.4 1.4z',
45
- close: 'M6.4 7.8 7.8 6.4 12 10.6 16.2 6.4 17.6 7.8 13.4 12 17.6 16.2 16.2 17.6 12 13.4 7.8 17.6 6.4 16.2 10.6 12z',
46
- search: 'M10.5 3a7.5 7.5 0 0 1 5.9 12.1l4 4-1.4 1.4-4-4A7.5 7.5 0 1 1 10.5 3zm0 2a5.5 5.5 0 1 0 0 11 5.5 5.5 0 0 0 0-11z',
47
- 'chevron-down': 'M7.4 9.1 12 13.7l4.6-4.6 1.4 1.4L12 16.5 6 10.5z',
48
- 'chevron-right': 'M9.1 6 15.1 12l-6 6-1.4-1.4L12.3 12 7.7 7.4z',
49
- info: 'M12 2a10 10 0 1 1 0 20 10 10 0 0 1 0-20zm0 8.2a1 1 0 0 0-1 1V17a1 1 0 1 0 2 0v-5.8a1 1 0 0 0-1-1zm0-3.7a1.2 1.2 0 1 0 0 2.4 1.2 1.2 0 0 0 0-2.4z',
43
+ check: "M9.2 16.6 4.8 12.2l1.4-1.4 3 3 8-8 1.4 1.4z",
44
+ close: "M6.4 7.8 7.8 6.4 12 10.6 16.2 6.4 17.6 7.8 13.4 12 17.6 16.2 16.2 17.6 12 13.4 7.8 17.6 6.4 16.2 10.6 12z",
45
+ search: "M10.5 3a7.5 7.5 0 0 1 5.9 12.1l4 4-1.4 1.4-4-4A7.5 7.5 0 1 1 10.5 3zm0 2a5.5 5.5 0 1 0 0 11 5.5 5.5 0 0 0 0-11z",
46
+ "chevron-down": "M7.4 9.1 12 13.7l4.6-4.6 1.4 1.4L12 16.5 6 10.5z",
47
+ "chevron-right": "M9.1 6 15.1 12l-6 6-1.4-1.4L12.3 12 7.7 7.4z",
48
+ info: "M12 2a10 10 0 1 1 0 20 10 10 0 0 1 0-20zm0 8.2a1 1 0 0 0-1 1V17a1 1 0 1 0 2 0v-5.8a1 1 0 0 0-1-1zm0-3.7a1.2 1.2 0 1 0 0 2.4 1.2 1.2 0 0 0 0-2.4z",
50
49
  warning:
51
- 'M12 3.2 21 19H3L12 3.2zm0 5.3a1 1 0 0 0-1 1v4.2a1 1 0 1 0 2 0V9.5a1 1 0 0 0-1-1zm0 8.1a1.2 1.2 0 1 0 0 2.4 1.2 1.2 0 0 0 0-2.4z',
52
- success: 'M12 2a10 10 0 1 1 0 20 10 10 0 0 1 0-20zm-2.5 10.3-2-2 1.4-1.4 2 2 5-5 1.4 1.4z',
53
- danger: 'M12 2a10 10 0 1 1 0 20 10 10 0 0 1 0-20zm-1 5h2v6h-2zm0 8h2v2h-2z',
54
- menu: 'M4 7h16v2H4zm0 4h16v2H4zm0 4h16v2H4z',
55
- plus: 'M11 5h2v6h6v2h-6v6h-2v-6H5v-2h6z',
50
+ "M12 3.2 21 19H3L12 3.2zm0 5.3a1 1 0 0 0-1 1v4.2a1 1 0 1 0 2 0V9.5a1 1 0 0 0-1-1zm0 8.1a1.2 1.2 0 1 0 0 2.4 1.2 1.2 0 0 0 0-2.4z",
51
+ success: "M12 2a10 10 0 1 1 0 20 10 10 0 0 1 0-20zm-2.5 10.3-2-2 1.4-1.4 2 2 5-5 1.4 1.4z",
52
+ danger: "M12 2a10 10 0 1 1 0 20 10 10 0 0 1 0-20zm-1 5h2v6h-2zm0 8h2v2h-2z",
53
+ menu: "M4 7h16v2H4zm0 4h16v2H4zm0 4h16v2H4z",
54
+ plus: "M11 5h2v6h6v2h-6v6h-2v-6H5v-2h6z",
56
55
  };
57
56
 
58
57
  function resolveChromePath(name) {
59
- const key = String(name || '').trim();
58
+ const key = String(name || "").trim();
60
59
  if (!key) return FALLBACK_PATH;
61
60
  return CHROME_PATHS[key] || FALLBACK_PATH;
62
61
  }
63
62
 
64
63
  export default class Icon {
65
- static __vmzHostBox = 'contents';
66
- public name: string = 'info';
67
- public size: string = 'md';
68
- public label: string = '';
64
+ static __vmzHostBox = "contents";
65
+ public name: string = "info";
66
+ public size: string = "md";
67
+ public label: string = "";
69
68
  public decorative: boolean = true;
70
69
  /** Optional author SVG path override. When set, `name` is ignored for rendering. */
71
- public pathD: string = '';
70
+ public pathD: string = "";
72
71
 
73
72
  iconPath() {
74
- const explicit = String(this.pathD || '').trim();
73
+ const explicit = String(this.pathD || "").trim();
75
74
  return explicit || resolveChromePath(this.name);
76
75
  }
77
76
  }
@@ -1,11 +1,16 @@
1
1
  <template>
2
- <div class="vmz-ui-layout" data-vmz-ui="layout"><slot /></div>
2
+ <div data-vmz-ui="layout" class="vmz-ui-layout">
3
+ <slot />
4
+ </div>
3
5
  </template>
4
-
5
6
  <style>
6
- .vmz-ui-layout{display:flex;flex-direction:column;min-height:100%;background:var(--vmz-surface-page,var(--vmz-surface-mist,#f5f5f5))}
7
+ .vmz-ui-layout {
8
+ display: flex;
9
+ flex-direction: column;
10
+ min-height: 100%;
11
+ background: var(--vmz-surface-page, var(--vmz-surface-mist, #f5f5f5));
12
+ }
7
13
  </style>
8
-
9
14
  <script client>
10
15
  export default class Layout {}
11
16
  </script>
@@ -1,17 +1,10 @@
1
1
  <template>
2
- <a
3
- class="vmz-ui-link"
4
- data-vmz-ui="link"
5
- :href="href"
6
- :target="target"
7
- :rel="rel"
8
- >
9
- <slot />
2
+ <a data-vmz-ui="link" :href="href" :target="target" :rel="rel" class="vmz-ui-link">
3
+ <slot />
10
4
  </a>
11
5
  </template>
12
-
13
6
  <style>
14
- .vmz-ui-link {
7
+ .vmz-ui-link {
15
8
  font: inherit;
16
9
  font-weight: 600;
17
10
  color: var(--vmz-action-primary-background);
@@ -19,31 +12,30 @@
19
12
  text-underline-offset: 0.15em;
20
13
  text-decoration-thickness: 1px;
21
14
  outline: none;
22
- }
15
+ }
23
16
 
24
- .vmz-ui-link:hover {
17
+ .vmz-ui-link:hover {
25
18
  color: var(--vmz-action-primary-hover);
26
- }
19
+ }
27
20
 
28
- .vmz-ui-link:active {
21
+ .vmz-ui-link:active {
29
22
  color: var(--vmz-action-primary-active);
30
- }
23
+ }
31
24
 
32
- .vmz-ui-link:focus-visible {
25
+ .vmz-ui-link:focus-visible {
33
26
  box-shadow: 0 0 0 2px var(--vmz-focus-ring);
34
27
  border-radius: var(--vmz-radius-md, 6px);
35
- }
28
+ }
36
29
  </style>
37
-
38
30
  <script client>
39
31
  /**
40
- * VMZ UI — Link (Foundation).
41
- * Navigation / inline text link; tokens only, no brand hex.
42
- */
32
+ * VMZ UI — Link (Foundation).
33
+ * Navigation / inline text link; tokens only, no brand hex.
34
+ */
43
35
  export default class Link {
44
- static __vmzHostBox = 'contents';
45
- public href: string = "#";
46
- public target: string = "";
47
- public rel: string = "";
36
+ static __vmzHostBox = "contents";
37
+ public href: string = "#";
38
+ public target: string = "";
39
+ public rel: string = "";
48
40
  }
49
41
  </script>
@@ -1,45 +1,30 @@
1
1
  <template>
2
- <div class="vmz-ui-list" data-vmz-ui="list">
3
- <p v-if="label" class="vmz-ui-list__label" :id="labelId">{{ label }}</p>
4
- <ul
5
- class="vmz-ui-list__items"
6
- role="listbox"
7
- :aria-labelledby="labelId"
8
- :aria-label="label"
9
- @click="onListClick"
10
- :onKeyDown="onListKeyDown"
11
- >
12
- <li
13
- v-for="item in items"
14
- :key="item.id"
15
- class="vmz-ui-list__item"
16
- role="option"
17
- :id="item.id"
18
- :data-vmz-list-item="item.id"
19
- :aria-selected="selected === item.id ? 'true' : 'false'"
20
- :tabindex="selected === item.id ? 0 : -1"
21
- >
22
- {{ item.title }}
23
- </li>
24
- </ul>
2
+ <div data-vmz-ui="list" class="vmz-ui-list">
3
+ <p v-if="label" :id="labelId" class="vmz-ui-list__label">
4
+ {{ label }}
5
+ </p>
6
+ <ul role="listbox" :aria-labelledby="labelId" :aria-label="label" @click="onListClick" :onKeyDown="onListKeyDown" class="vmz-ui-list__items">
7
+ <li v-for="item in items" :key="item.id" role="option" :id="item.id" :data-vmz-list-item="item.id" :aria-selected='selected === item.id ? "true" : "false"' :tabindex="selected === item.id ? 0 : -1" class="vmz-ui-list__item">
8
+ {{ item.title }}
9
+ </li>
10
+ </ul>
25
11
  </div>
26
12
  </template>
27
-
28
13
  <style>
29
- .vmz-ui-list {
14
+ .vmz-ui-list {
30
15
  display: flex;
31
16
  flex-direction: column;
32
17
  gap: 0.35rem;
33
18
  max-width: 28rem;
34
- }
19
+ }
35
20
 
36
- .vmz-ui-list__label {
21
+ .vmz-ui-list__label {
37
22
  margin: 0;
38
23
  font-weight: 600;
39
24
  color: var(--vmz-text-ink);
40
- }
25
+ }
41
26
 
42
- .vmz-ui-list__items {
27
+ .vmz-ui-list__items {
43
28
  margin: 0;
44
29
  padding: 0.25rem;
45
30
  list-style: none;
@@ -47,69 +32,71 @@
47
32
  border-radius: var(--vmz-radius-md, 6px);
48
33
  background: var(--vmz-surface-paper);
49
34
  color: var(--vmz-text-ink);
50
- }
35
+ }
51
36
 
52
- .vmz-ui-list__item {
37
+ .vmz-ui-list__item {
53
38
  padding: var(--vmz-density-control-padding-y) var(--vmz-density-control-padding-x);
54
39
  border-radius: var(--vmz-radius-md, 6px);
55
40
  cursor: pointer;
56
41
  outline: none;
57
- }
42
+ }
58
43
 
59
- .vmz-ui-list__item[aria-selected='true'] {
44
+ .vmz-ui-list__item[aria-selected="true"] {
60
45
  background: var(--vmz-action-primary-background);
61
46
  color: var(--vmz-action-primary-foreground);
62
- }
47
+ }
63
48
 
64
- .vmz-ui-list__item:hover {
49
+ .vmz-ui-list__item:hover {
65
50
  background: color-mix(in srgb, var(--vmz-action-primary-background) 14%, transparent);
66
- }
51
+ }
67
52
 
68
- .vmz-ui-list__item[aria-selected='true']:hover {
53
+ .vmz-ui-list__item[aria-selected="true"]:hover {
69
54
  background: var(--vmz-action-primary-hover);
70
- }
55
+ }
71
56
 
72
- .vmz-ui-list__item:focus-visible {
57
+ .vmz-ui-list__item:focus-visible {
73
58
  box-shadow: 0 0 0 2px var(--vmz-focus-ring);
74
- }
59
+ }
75
60
  </style>
76
-
77
61
  <script client>
78
62
  /**
79
- * VMZ UI — List (ordinary selectable list).
80
- * Parent owns `selected` id; click + Arrow/Home/End. Not a DataGrid.
81
- */
63
+ * VMZ UI — List (ordinary selectable list).
64
+ * Parent owns `selected` id; click + Arrow/Home/End. Not a DataGrid.
65
+ */
82
66
  export default class List {
83
- public label: string = "List";
84
- public labelId: string = "vmz-list-label";
85
- public selected: string = "";
86
- /** @type {{ id: string, title: string }[]} */
87
- public items: {
88
- id: string;
89
- title: string;
90
- }[] = [];
91
- public onSelect: ((id: string) => void) | null = null;
92
- select(id) {
93
- if (typeof this.onSelect === "function") this.onSelect(id);
94
- }
95
- onListClick(ev) {
96
- const t = ev && ev.target;
97
- const el = t && typeof t.closest === "function" ? t.closest("[data-vmz-list-item]") : null;
98
- const id = el && typeof el.getAttribute === "function" ? el.getAttribute("data-vmz-list-item") : null;
99
- if (id) this.select(id);
100
- }
101
- onListKeyDown(ev) {
102
- if (!ev || !this.items?.length) return;
103
- const ids = this.items.map((it) => it.id);
104
- const idx = Math.max(0, ids.indexOf(this.selected));
105
- let next = idx;
106
- if (ev.key === "ArrowDown") next = (idx + 1) % ids.length;
107
- else if (ev.key === "ArrowUp") next = (idx - 1 + ids.length) % ids.length;
108
- else if (ev.key === "Home") next = 0;
109
- else if (ev.key === "End") next = ids.length - 1;
110
- else return;
111
- ev.preventDefault();
112
- this.select(ids[next]);
113
- }
67
+ public label: string = "List";
68
+ public labelId: string = "vmz-list-label";
69
+ public selected: string = "";
70
+ /** @type {{ id: string, title: string }[]} */
71
+ public items: {
72
+ id: string;
73
+ title: string;
74
+ }[] = [];
75
+ public onSelect: ((id: string) => void) | null = null;
76
+ select(id) {
77
+ if (typeof this.onSelect === "function") this.onSelect(id);
78
+ }
79
+ onListClick(ev) {
80
+ const t = ev && ev.target;
81
+ const el = t && typeof t.closest === "function" ? t.closest("[data-vmz-list-item]") : null;
82
+ const id =
83
+ el && typeof el.getAttribute === "function"
84
+ ? el.getAttribute("data-vmz-list-item")
85
+ : null;
86
+ if (id) this.select(id);
87
+ }
88
+ onListKeyDown(ev) {
89
+ if (!ev || !this.items?.length) return;
90
+ const ids = this.items.map((it) => it.id);
91
+ const idx = Math.max(0, ids.indexOf(this.selected));
92
+ let next = idx;
93
+ if (ev.key === "ArrowDown") next = (idx + 1) % ids.length;
94
+ else if (ev.key === "ArrowUp") next = (idx - 1 + ids.length) % ids.length;
95
+ else if (ev.key === "Home") next = 0;
96
+ else if (ev.key === "End") next = ids.length - 1;
97
+ else return;
98
+ ev.preventDefault();
99
+ this.select(ids[next]);
100
+ }
114
101
  }
115
102
  </script>