@vmz/ui 0.3.4 → 0.3.6

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 (43) hide show
  1. package/README.md +51 -51
  2. package/package.json +2 -2
  3. package/presets/web-surface.v0.json +19 -7
  4. package/src/components/Accordion.vmz +94 -94
  5. package/src/components/AppShell.vmz +77 -33
  6. package/src/components/Autocomplete.vmz +154 -154
  7. package/src/components/Badge.vmz +70 -70
  8. package/src/components/Breadcrumb.vmz +72 -72
  9. package/src/components/BulkActions.vmz +51 -51
  10. package/src/components/Button.vmz +211 -192
  11. package/src/components/Callout.vmz +77 -77
  12. package/src/components/Card.vmz +120 -106
  13. package/src/components/Checkbox.vmz +55 -55
  14. package/src/components/CodeBlock.vmz +77 -18
  15. package/src/components/ConsoleShell.vmz +251 -251
  16. package/src/components/DataTable.vmz +194 -194
  17. package/src/components/DatePicker.vmz +674 -674
  18. package/src/components/Dialog.vmz +10 -7
  19. package/src/components/Drawer.vmz +427 -427
  20. package/src/components/Dropdown.vmz +135 -16
  21. package/src/components/Empty.vmz +54 -54
  22. package/src/components/Field.vmz +115 -115
  23. package/src/components/FormItem.vmz +79 -79
  24. package/src/components/Link.vmz +34 -4
  25. package/src/components/List.vmz +102 -102
  26. package/src/components/Menu.vmz +243 -243
  27. package/src/components/Pagination.vmz +69 -69
  28. package/src/components/Popover.vmz +223 -223
  29. package/src/components/Prose.vmz +81 -81
  30. package/src/components/RadioGroup.vmz +124 -124
  31. package/src/components/Segmented.vmz +51 -51
  32. package/src/components/Select.vmz +533 -533
  33. package/src/components/Steps.vmz +103 -103
  34. package/src/components/Switch.vmz +98 -98
  35. package/src/components/Table.vmz +165 -133
  36. package/src/components/Tabs.vmz +110 -110
  37. package/src/components/Tag.vmz +43 -40
  38. package/src/components/TextArea.vmz +118 -118
  39. package/src/components/Timeline.vmz +76 -76
  40. package/src/components/Toc.vmz +74 -74
  41. package/src/components/Tooltip.vmz +58 -58
  42. package/src/components/Tree.vmz +191 -191
  43. package/src/components/Upload.vmz +1289 -1289
@@ -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.35rem;
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>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <a data-vmz-ui="link" :href="href" :target="target" :rel="rel" class="vmz-ui-link">
2
+ <a data-vmz-ui="link" :data-variant="variant" :href="href" :target="target" :rel="rel" class="vmz-ui-link">
3
3
  <slot />
4
4
  </a>
5
5
  </template>
@@ -9,13 +9,19 @@
9
9
  font-weight: 600;
10
10
  color: var(--vmz-action-primary-background);
11
11
  text-decoration: underline;
12
- text-underline-offset: 0.15em;
12
+ text-underline-offset: 0.2em;
13
13
  text-decoration-thickness: 1px;
14
+ text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
14
15
  outline: none;
16
+ border-radius: var(--vmz-radius-sm, 4px);
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));
15
20
  }
16
21
 
17
22
  .vmz-ui-link:hover {
18
23
  color: var(--vmz-action-primary-hover);
24
+ text-decoration-color: currentColor;
19
25
  }
20
26
 
21
27
  .vmz-ui-link:active {
@@ -23,8 +29,30 @@
23
29
  }
24
30
 
25
31
  .vmz-ui-link:focus-visible {
26
- box-shadow: 0 0 0 2px var(--vmz-focus-ring);
27
- border-radius: var(--vmz-radius-md, 6px);
32
+ box-shadow: 0 0 0 3px var(--vmz-focus-ring);
33
+ }
34
+
35
+ /* Quiet inline link: neutral ink, underline appears only on intent. */
36
+ .vmz-ui-link[data-variant="muted"] {
37
+ color: var(--vmz-text-steel);
38
+ text-decoration-color: transparent;
39
+ }
40
+
41
+ .vmz-ui-link[data-variant="muted"]:hover {
42
+ color: var(--vmz-action-primary-background);
43
+ text-decoration-color: currentColor;
44
+ }
45
+
46
+ /* Navigation link: chrome, not prose — underline is the hover affordance. */
47
+ .vmz-ui-link[data-variant="nav"] {
48
+ font-weight: 500;
49
+ text-decoration: none;
50
+ text-decoration-color: transparent;
51
+ }
52
+
53
+ .vmz-ui-link[data-variant="nav"]:hover {
54
+ text-decoration: underline;
55
+ text-decoration-color: currentColor;
28
56
  }
29
57
  </style>
30
58
  <script client>
@@ -37,5 +65,7 @@ export default class Link {
37
65
  public href: string = "#";
38
66
  public target: string = "";
39
67
  public rel: string = "";
68
+ /** `default` inline prose link · `muted` quiet inline link · `nav` chrome link. */
69
+ public variant: string = "default";
40
70
  }
41
71
  </script>
@@ -1,102 +1,102 @@
1
- <template>
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>
11
- </div>
12
- </template>
13
- <style>
14
- .vmz-ui-list {
15
- display: flex;
16
- flex-direction: column;
17
- gap: 0.35rem;
18
- max-width: 28rem;
19
- }
20
-
21
- .vmz-ui-list__label {
22
- margin: 0;
23
- font-weight: 600;
24
- color: var(--vmz-text-ink);
25
- }
26
-
27
- .vmz-ui-list__items {
28
- margin: 0;
29
- padding: 0.25rem;
30
- list-style: none;
31
- border: 1px solid var(--vmz-line-default);
32
- border-radius: var(--vmz-radius-md, 6px);
33
- background: var(--vmz-surface-paper);
34
- color: var(--vmz-text-ink);
35
- }
36
-
37
- .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
- cursor: pointer;
41
- outline: none;
42
- }
43
-
44
- .vmz-ui-list__item[aria-selected="true"] {
45
- background: var(--vmz-action-primary-background);
46
- color: var(--vmz-action-primary-foreground);
47
- }
48
-
49
- .vmz-ui-list__item:hover {
50
- background: color-mix(in srgb, var(--vmz-action-primary-background) 14%, transparent);
51
- }
52
-
53
- .vmz-ui-list__item[aria-selected="true"]:hover {
54
- background: var(--vmz-action-primary-hover);
55
- }
56
-
57
- .vmz-ui-list__item:focus-visible {
58
- box-shadow: 0 0 0 2px var(--vmz-focus-ring);
59
- }
60
- </style>
61
- <script client>
62
- /**
63
- * VMZ UI — List (ordinary selectable list).
64
- * Parent owns `selected` id; click + Arrow/Home/End. Not a DataGrid.
65
- */
66
- export default class List {
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
- }
101
- }
102
- </script>
1
+ <template>
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>
11
+ </div>
12
+ </template>
13
+ <style>
14
+ .vmz-ui-list {
15
+ display: flex;
16
+ flex-direction: column;
17
+ gap: 0.375rem;
18
+ max-width: 28rem;
19
+ }
20
+
21
+ .vmz-ui-list__label {
22
+ margin: 0;
23
+ font-weight: 600;
24
+ color: var(--vmz-text-ink);
25
+ }
26
+
27
+ .vmz-ui-list__items {
28
+ margin: 0;
29
+ padding: 0.25rem;
30
+ list-style: none;
31
+ border: 1px solid var(--vmz-line-default);
32
+ border-radius: var(--vmz-radius-md, 6px);
33
+ background: var(--vmz-surface-paper);
34
+ color: var(--vmz-text-ink);
35
+ }
36
+
37
+ .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
+ cursor: pointer;
41
+ outline: none;
42
+ }
43
+
44
+ .vmz-ui-list__item[aria-selected="true"] {
45
+ background: var(--vmz-action-primary-background);
46
+ color: var(--vmz-action-primary-foreground);
47
+ }
48
+
49
+ .vmz-ui-list__item:hover {
50
+ background: color-mix(in srgb, var(--vmz-action-primary-background) 14%, transparent);
51
+ }
52
+
53
+ .vmz-ui-list__item[aria-selected="true"]:hover {
54
+ background: var(--vmz-action-primary-hover);
55
+ }
56
+
57
+ .vmz-ui-list__item:focus-visible {
58
+ box-shadow: 0 0 0 3px var(--vmz-focus-ring);
59
+ }
60
+ </style>
61
+ <script client>
62
+ /**
63
+ * VMZ UI — List (ordinary selectable list).
64
+ * Parent owns `selected` id; click + Arrow/Home/End. Not a DataGrid.
65
+ */
66
+ export default class List {
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
+ }
101
+ }
102
+ </script>