@vmz/ui 0.0.3 → 0.1.0

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 (53) hide show
  1. package/README.md +28 -1
  2. package/conformance/fixtures/button-control-motion.json +22 -0
  3. package/conformance/fixtures/dialog-overlay-motion.json +27 -0
  4. package/conformance/fixtures/drawer-overlay-motion.json +27 -0
  5. package/conformance/pack.v0.json +7 -0
  6. package/contracts/token-requirements.v0.json +643 -2
  7. package/package.json +50 -2
  8. package/presets/web-surface.v0.json +34 -0
  9. package/src/components/Accordion.vmz +112 -0
  10. package/src/components/Alert.vmz +84 -0
  11. package/src/components/AppShell.vmz +97 -0
  12. package/src/components/Autocomplete.vmz +176 -0
  13. package/src/components/Badge.vmz +63 -0
  14. package/src/components/Breadcrumb.vmz +66 -0
  15. package/src/components/BulkActions.vmz +52 -0
  16. package/src/components/Button.vmz +78 -5
  17. package/src/components/Callout.vmz +80 -0
  18. package/src/components/Card.vmz +80 -0
  19. package/src/components/Checkbox.vmz +69 -0
  20. package/src/components/CodeBlock.vmz +67 -0
  21. package/src/components/ConsoleShell.vmz +127 -0
  22. package/src/components/DataTable.vmz +220 -0
  23. package/src/components/DatePicker.vmz +591 -0
  24. package/src/components/Dialog.vmz +442 -0
  25. package/src/components/Drawer.vmz +435 -0
  26. package/src/components/Empty.vmz +52 -0
  27. package/src/components/Field.vmz +88 -0
  28. package/src/components/FilterBar.vmz +27 -0
  29. package/src/components/Form.vmz +72 -0
  30. package/src/components/FormItem.vmz +78 -0
  31. package/src/components/Link.vmz +48 -0
  32. package/src/components/List.vmz +116 -0
  33. package/src/components/Menu.vmz +270 -0
  34. package/src/components/Notification.vmz +83 -0
  35. package/src/components/Pagination.vmz +81 -0
  36. package/src/components/Popover.vmz +253 -0
  37. package/src/components/Prose.vmz +83 -0
  38. package/src/components/QueryForm.vmz +39 -0
  39. package/src/components/RadioGroup.vmz +135 -0
  40. package/src/components/Result.vmz +84 -0
  41. package/src/components/Select.vmz +355 -0
  42. package/src/components/Skeleton.vmz +80 -0
  43. package/src/components/Spinner.vmz +45 -0
  44. package/src/components/Steps.vmz +107 -0
  45. package/src/components/Switch.vmz +109 -0
  46. package/src/components/Table.vmz +134 -0
  47. package/src/components/Tabs.vmz +132 -0
  48. package/src/components/TextArea.vmz +91 -0
  49. package/src/components/Timeline.vmz +67 -0
  50. package/src/components/Toc.vmz +77 -0
  51. package/src/components/Tooltip.vmz +68 -0
  52. package/src/components/Tree.vmz +215 -0
  53. package/src/components/Upload.vmz +1233 -0
@@ -0,0 +1,215 @@
1
+ <template>
2
+ <div class="vmz-ui-tree" data-vmz-ui="tree">
3
+ <p if={label} class="vmz-ui-tree__label" id={labelId}>{label}</p>
4
+ <ul
5
+ class="vmz-ui-tree__items"
6
+ role="tree"
7
+ aria-labelledby={labelId}
8
+ aria-label={label}
9
+ onClick={onTreeClick}
10
+ onKeyDown={onTreeKeyDown}
11
+ >
12
+ <li
13
+ each={items}
14
+ as="item"
15
+ key={item.id}
16
+ class="vmz-ui-tree__item"
17
+ role="treeitem"
18
+ id={item.id}
19
+ data-vmz-tree-item={item.id}
20
+ data-depth={item.depth}
21
+ aria-selected={selected === item.id ? 'true' : 'false'}
22
+ aria-expanded={item.expandedAttr}
23
+ tabindex={selected === item.id ? 0 : -1}
24
+ style={item.padStyle}
25
+ >
26
+ <button
27
+ if={item.expandable}
28
+ type="button"
29
+ class="vmz-ui-tree__twist"
30
+ data-vmz-tree-twist={item.id}
31
+ aria-label={item.twistLabel}
32
+ tabindex="-1"
33
+ >
34
+ {item.expanded ? '−' : '+'}
35
+ </button>
36
+ <span if={!item.expandable} class="vmz-ui-tree__twist-spacer" aria-hidden="true"></span>
37
+ <span class="vmz-ui-tree__title" data-vmz-tree-title={item.id}>{item.title}</span>
38
+ </li>
39
+ </ul>
40
+ </div>
41
+ </template>
42
+
43
+ <style>
44
+ .vmz-ui-tree {
45
+ display: flex;
46
+ flex-direction: column;
47
+ gap: 0.35rem;
48
+ max-width: 28rem;
49
+ }
50
+
51
+ .vmz-ui-tree__label {
52
+ margin: 0;
53
+ font-weight: 600;
54
+ color: var(--vmz-text-ink);
55
+ }
56
+
57
+ .vmz-ui-tree__items {
58
+ margin: 0;
59
+ padding: 0.25rem;
60
+ list-style: none;
61
+ border: 1px solid var(--vmz-line-default);
62
+ border-radius: 2px;
63
+ background: var(--vmz-surface-paper);
64
+ color: var(--vmz-text-ink);
65
+ }
66
+
67
+ .vmz-ui-tree__item {
68
+ display: flex;
69
+ align-items: center;
70
+ gap: 0.35rem;
71
+ padding: var(--vmz-density-compact-padding-y) var(--vmz-density-compact-padding-x);
72
+ border-radius: 2px;
73
+ cursor: pointer;
74
+ outline: none;
75
+ }
76
+
77
+ .vmz-ui-tree__item[aria-selected='true'] {
78
+ background: var(--vmz-action-primary-background);
79
+ color: var(--vmz-action-primary-foreground);
80
+ }
81
+
82
+ .vmz-ui-tree__item:hover {
83
+ background: color-mix(in srgb, var(--vmz-action-primary-background) 14%, transparent);
84
+ }
85
+
86
+ .vmz-ui-tree__item[aria-selected='true']:hover {
87
+ background: var(--vmz-action-primary-hover);
88
+ }
89
+
90
+ .vmz-ui-tree__item:focus-visible {
91
+ box-shadow: 0 0 0 2px var(--vmz-focus-ring);
92
+ }
93
+
94
+ .vmz-ui-tree__twist {
95
+ flex: 0 0 auto;
96
+ width: 1.35rem;
97
+ height: 1.35rem;
98
+ padding: 0;
99
+ border: 1px solid var(--vmz-line-default);
100
+ border-radius: 2px;
101
+ background: var(--vmz-surface-mist);
102
+ color: inherit;
103
+ font: inherit;
104
+ font-weight: 700;
105
+ line-height: 1;
106
+ cursor: pointer;
107
+ outline: none;
108
+ }
109
+
110
+ .vmz-ui-tree__twist:focus-visible {
111
+ box-shadow: 0 0 0 2px var(--vmz-focus-ring);
112
+ }
113
+
114
+ .vmz-ui-tree__twist-spacer {
115
+ flex: 0 0 auto;
116
+ width: 1.35rem;
117
+ }
118
+
119
+ .vmz-ui-tree__title {
120
+ flex: 1 1 auto;
121
+ }
122
+ </style>
123
+
124
+ <script client>
125
+ /**
126
+ * VMZ UI — Tree (ordinary hierarchy).
127
+ * Parent owns visible flat rows + selected + expand state.
128
+ * Not virtualized / not DataGrid tree mode.
129
+ */
130
+ export default class Tree {
131
+ public label: string = 'Tree';
132
+ public labelId: string = 'vmz-tree-label';
133
+ public selected: string = '';
134
+ /**
135
+ * @type {{
136
+ * id: string,
137
+ * title: string,
138
+ * depth: string,
139
+ * expandable: boolean,
140
+ * expanded: boolean,
141
+ * expandedAttr: string,
142
+ * twistLabel: string,
143
+ * padStyle: string
144
+ * }[]}
145
+ */
146
+ public items: {
147
+ id: string;
148
+ title: string;
149
+ depth: string;
150
+ expandable: boolean;
151
+ expanded: boolean;
152
+ expandedAttr: string;
153
+ twistLabel: string;
154
+ padStyle: string;
155
+ }[] = [];
156
+ public onSelect: ((id: string) => void) | null = null;
157
+ public onToggle: ((id: string) => void) | null = null;
158
+
159
+ select(id) {
160
+ if (typeof this.onSelect === 'function') this.onSelect(id);
161
+ }
162
+
163
+ toggle(id) {
164
+ if (typeof this.onToggle === 'function') this.onToggle(id);
165
+ }
166
+
167
+ onTreeClick(ev) {
168
+ const t = ev && ev.target;
169
+ const twist =
170
+ t && typeof t.closest === 'function' ? t.closest('[data-vmz-tree-twist]') : null;
171
+ if (twist) {
172
+ const id =
173
+ typeof twist.getAttribute === 'function' ? twist.getAttribute('data-vmz-tree-twist') : null;
174
+ if (id) {
175
+ ev.preventDefault();
176
+ ev.stopPropagation();
177
+ this.toggle(id);
178
+ }
179
+ return;
180
+ }
181
+ const el = t && typeof t.closest === 'function' ? t.closest('[data-vmz-tree-item]') : null;
182
+ const id = el && typeof el.getAttribute === 'function' ? el.getAttribute('data-vmz-tree-item') : null;
183
+ if (id) this.select(id);
184
+ }
185
+
186
+ onTreeKeyDown(ev) {
187
+ if (!ev || !this.items?.length) return;
188
+ const ids = this.items.map((it) => it.id);
189
+ const idx = Math.max(0, ids.indexOf(this.selected));
190
+ const cur = this.items[idx];
191
+ if (ev.key === 'ArrowRight' && cur?.expandable && !cur.expanded) {
192
+ ev.preventDefault();
193
+ this.toggle(cur.id);
194
+ return;
195
+ }
196
+ if (ev.key === 'ArrowLeft' && cur?.expandable && cur.expanded) {
197
+ ev.preventDefault();
198
+ this.toggle(cur.id);
199
+ return;
200
+ }
201
+ let next = idx;
202
+ if (ev.key === 'ArrowDown') next = (idx + 1) % ids.length;
203
+ else if (ev.key === 'ArrowUp') next = (idx - 1 + ids.length) % ids.length;
204
+ else if (ev.key === 'Home') next = 0;
205
+ else if (ev.key === 'End') next = ids.length - 1;
206
+ else if (ev.key === 'Enter' || ev.key === ' ') {
207
+ ev.preventDefault();
208
+ if (cur) this.select(cur.id);
209
+ return;
210
+ } else return;
211
+ ev.preventDefault();
212
+ this.select(ids[next]);
213
+ }
214
+ }
215
+ </script>