@vmz/ui 0.3.6 → 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 +53 -51
  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 +127 -94
  6. package/src/components/Alert.vmz +125 -28
  7. package/src/components/AppShell.vmz +125 -57
  8. package/src/components/Autocomplete.vmz +261 -154
  9. package/src/components/Avatar.vmz +20 -12
  10. package/src/components/Badge.vmz +62 -70
  11. package/src/components/Breadcrumb.vmz +86 -72
  12. package/src/components/BulkActions.vmz +56 -51
  13. package/src/components/Button.vmz +237 -211
  14. package/src/components/Callout.vmz +178 -77
  15. package/src/components/Card.vmz +141 -120
  16. package/src/components/Checkbox.vmz +131 -55
  17. package/src/components/CodeBlock.vmz +77 -30
  18. package/src/components/Collapse.vmz +64 -11
  19. package/src/components/ConsoleShell.vmz +405 -251
  20. package/src/components/Content.vmz +15 -1
  21. package/src/components/DataTable.vmz +294 -194
  22. package/src/components/DatePicker.vmz +766 -674
  23. package/src/components/Descriptions.vmz +90 -0
  24. package/src/components/Dialog.vmz +137 -38
  25. package/src/components/Divider.vmz +8 -1
  26. package/src/components/Drawer.vmz +518 -427
  27. package/src/components/Dropdown.vmz +195 -51
  28. package/src/components/Empty.vmz +96 -54
  29. package/src/components/Field.vmz +170 -115
  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 +78 -79
  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 +25 -10
  39. package/src/components/List.vmz +124 -102
  40. package/src/components/Menu.vmz +416 -243
  41. package/src/components/Message.vmz +167 -0
  42. package/src/components/Notification.vmz +132 -37
  43. package/src/components/Pagination.vmz +237 -69
  44. package/src/components/Popconfirm.vmz +287 -0
  45. package/src/components/Popover.vmz +341 -223
  46. package/src/components/Progress.vmz +16 -5
  47. package/src/components/Prose.vmz +180 -81
  48. package/src/components/QueryForm.vmz +31 -9
  49. package/src/components/RadioGroup.vmz +204 -124
  50. package/src/components/Result.vmz +60 -27
  51. package/src/components/Segmented.vmz +86 -51
  52. package/src/components/Select.vmz +620 -533
  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 +118 -103
  58. package/src/components/Switch.vmz +131 -98
  59. package/src/components/Table.vmz +270 -165
  60. package/src/components/Tabs.vmz +125 -110
  61. package/src/components/Tag.vmz +60 -43
  62. package/src/components/TextArea.vmz +125 -118
  63. package/src/components/Timeline.vmz +111 -76
  64. package/src/components/Toc.vmz +90 -74
  65. package/src/components/Tooltip.vmz +107 -58
  66. package/src/components/Tree.vmz +214 -191
  67. package/src/components/Typography.vmz +23 -8
  68. package/src/components/Upload.vmz +1394 -1289
@@ -1,55 +1,131 @@
1
- <template>
2
- <label data-vmz-ui="checkbox" :for="controlId" class="vmz-ui-checkbox">
3
- <input :id="controlId" type="checkbox" :checked="checked" :disabled="disabled" :aria-describedby="describedBy" @change="onToggle" class="vmz-ui-checkbox__input" />
4
- <span class="vmz-ui-checkbox__label">
5
- {{ label }}
6
- </span>
7
- </label>
8
- </template>
9
- <style>
10
- .vmz-ui-checkbox {
11
- display: inline-flex;
12
- align-items: center;
13
- gap: 0.5rem;
14
- font: inherit;
15
- cursor: pointer;
16
- }
17
-
18
- .vmz-ui-checkbox__input {
19
- width: 1rem;
20
- height: 1rem;
21
- accent-color: var(--vmz-action-primary-background);
22
- outline: none;
23
- }
24
-
25
- .vmz-ui-checkbox__input:focus-visible {
26
- box-shadow: 0 0 0 3px var(--vmz-focus-ring);
27
- }
28
-
29
- .vmz-ui-checkbox__input:disabled {
30
- opacity: 0.55;
31
- cursor: not-allowed;
32
- }
33
-
34
- .vmz-ui-checkbox__label {
35
- font-weight: 600;
36
- }
37
- </style>
38
- <script client>
39
- /**
40
- * VMZ UI — Checkbox (UI2).
41
- * Label association via wrapping label + for/id; parent owns checked (no parallel form store).
42
- * Native change reports the committed checked state to the parent.
43
- */
44
- export default class Checkbox {
45
- public label: string = "";
46
- public checked: boolean = false;
47
- public disabled: boolean = false;
48
- public controlId: string = "vmz-checkbox";
49
- public describedBy: string = "";
50
- onToggle(ev) {
51
- if (this.disabled) return;
52
- this.emit("change", !!ev?.target?.checked);
53
- }
54
- }
55
- </script>
1
+ <template>
2
+ <label data-vmz-ui="checkbox" :for="controlId" :data-disabled="disabled ? 'true' : 'false'" class="vmz-ui-checkbox">
3
+ <span class="vmz-ui-checkbox__box">
4
+ <input :id="controlId" type="checkbox" :checked="checked" :disabled="disabled" :aria-describedby="describedBy" @change="onToggle" class="vmz-ui-checkbox__input" />
5
+ <Icon name="action.check" size="md" decorative class="vmz-ui-checkbox__check" />
6
+ </span>
7
+ <span class="vmz-ui-checkbox__label">
8
+ {{ label }}
9
+ </span>
10
+ </label>
11
+ </template>
12
+ <style>
13
+ .vmz-ui-checkbox {
14
+ display: inline-flex;
15
+ align-items: center;
16
+ gap: var(--vmz-space-2);
17
+ font: inherit;
18
+ font-size: 0.875rem;
19
+ line-height: 1.5715;
20
+ color: var(--vmz-text-ink);
21
+ cursor: pointer;
22
+ }
23
+
24
+ .vmz-ui-checkbox__box {
25
+ position: relative;
26
+ display: inline-flex;
27
+ flex: 0 0 auto;
28
+ width: 1rem;
29
+ height: 1rem;
30
+ }
31
+
32
+ .vmz-ui-checkbox__input {
33
+ position: absolute;
34
+ inset: 0;
35
+ z-index: 1;
36
+ box-sizing: border-box;
37
+ width: 1rem;
38
+ height: 1rem;
39
+ margin: 0;
40
+ appearance: none;
41
+ border: 1px solid var(--vmz-line-default);
42
+ border-radius: var(--vmz-radius-sm);
43
+ background: var(--vmz-surface-paper);
44
+ outline: none;
45
+ cursor: pointer;
46
+ transition:
47
+ background-color var(--vmz-motion-control-duration) var(--vmz-motion-control-easing),
48
+ border-color var(--vmz-motion-control-duration) var(--vmz-motion-control-easing),
49
+ box-shadow var(--vmz-motion-control-duration) var(--vmz-motion-control-easing);
50
+ }
51
+
52
+ .vmz-ui-checkbox__input:hover:not(:disabled):not(:checked) {
53
+ border-color: var(--vmz-action-primary-hover);
54
+ }
55
+
56
+ .vmz-ui-checkbox__input:checked {
57
+ border-color: var(--vmz-action-primary-background);
58
+ background: var(--vmz-action-primary-background);
59
+ }
60
+
61
+ .vmz-ui-checkbox__input:checked:hover:not(:disabled) {
62
+ border-color: var(--vmz-action-primary-hover);
63
+ background: var(--vmz-action-primary-hover);
64
+ }
65
+
66
+ .vmz-ui-checkbox__input:focus-visible {
67
+ box-shadow: 0 0 0 3px var(--vmz-focus-ring);
68
+ }
69
+
70
+ .vmz-ui-checkbox__input:disabled {
71
+ cursor: not-allowed;
72
+ }
73
+
74
+ .vmz-ui-checkbox__check {
75
+ position: absolute;
76
+ inset: 0;
77
+ z-index: 2;
78
+ margin: auto;
79
+ color: var(--vmz-action-primary-foreground);
80
+ opacity: 0;
81
+ pointer-events: none;
82
+ transition: opacity var(--vmz-motion-control-duration) var(--vmz-motion-control-easing);
83
+ }
84
+
85
+ .vmz-ui-checkbox .vmz-ui-checkbox__box .vmz-ui-checkbox__check {
86
+ font-size: 0.75rem;
87
+ }
88
+
89
+ .vmz-ui-checkbox__input:checked + .vmz-ui-checkbox__check {
90
+ opacity: 1;
91
+ }
92
+
93
+ .vmz-ui-checkbox[data-disabled="true"] {
94
+ opacity: 0.55;
95
+ cursor: not-allowed;
96
+ }
97
+
98
+ .vmz-ui-checkbox[data-disabled="true"] .vmz-ui-checkbox__input,
99
+ .vmz-ui-checkbox[data-disabled="true"] .vmz-ui-checkbox__label {
100
+ cursor: not-allowed;
101
+ }
102
+
103
+ .vmz-ui-checkbox__label {
104
+ font-weight: 400;
105
+ }
106
+
107
+ @media (prefers-reduced-motion: reduce) {
108
+ .vmz-ui-checkbox__input,
109
+ .vmz-ui-checkbox__check {
110
+ transition: none;
111
+ }
112
+ }
113
+ </style>
114
+ <script client>
115
+ /**
116
+ * VMZ UI — Checkbox (UI2).
117
+ * Label association via wrapping label + for/id; parent owns checked (no parallel form store).
118
+ * Native change reports the committed checked state to the parent.
119
+ */
120
+ export default class Checkbox {
121
+ public label: string = "";
122
+ public checked: boolean = false;
123
+ public disabled: boolean = false;
124
+ public controlId: string = "vmz-checkbox";
125
+ public describedBy: string = "";
126
+ onToggle(ev) {
127
+ if (this.disabled) return;
128
+ this.emit("change", !!ev?.target?.checked);
129
+ }
130
+ }
131
+ </script>
@@ -2,12 +2,21 @@
2
2
  <figure data-vmz-ui="code-block" class="vmz-ui-code-block">
3
3
  <div v-if="barVisible()" class="vmz-ui-code-block__bar">
4
4
  <div class="vmz-ui-code-block__heading">
5
- <span v-if="language" class="vmz-ui-code-block__lang">{{ language }}</span>
6
- <span v-if="title" class="vmz-ui-code-block__caption">{{ title }}</span>
7
- <span v-else-if="caption" class="vmz-ui-code-block__caption">{{ caption }}</span>
5
+ <span v-if="language" class="vmz-ui-code-block__lang">
6
+ {{ language }}
7
+ </span>
8
+ <span v-if="title" class="vmz-ui-code-block__caption">
9
+ {{ title }}
10
+ </span>
11
+ <span v-else-if="caption" class="vmz-ui-code-block__caption">
12
+ {{ caption }}
13
+ </span>
8
14
  </div>
9
- <Button type="button" variant="text" size="sm" class="vmz-ui-code-block__copy" @click="onCopy">
10
- {{ copyLabel }}
15
+ <Button v-if="canCopy()" type="button" variant="text" size="small" @click="onCopy" class="vmz-ui-code-block__copy">
16
+ <Icon name="action.copy" size="md" decorative />
17
+ <span v-if="copyLabel" class="vmz-ui-code-block__copy-text">
18
+ {{ copyLabel }}
19
+ </span>
11
20
  </Button>
12
21
  </div>
13
22
  <pre class="vmz-ui-code-block__pre">
@@ -22,9 +31,8 @@
22
31
  margin: 0;
23
32
  display: flex;
24
33
  flex-direction: column;
25
- border: 1px solid var(--vmz-line-default);
26
34
  border-radius: var(--vmz-radius-lg, 8px);
27
- background: var(--vmz-surface-mist);
35
+ background: var(--vmz-surface-code);
28
36
  overflow: hidden;
29
37
  }
30
38
 
@@ -32,27 +40,27 @@
32
40
  display: flex;
33
41
  align-items: center;
34
42
  justify-content: space-between;
35
- gap: 0.5rem;
43
+ gap: var(--vmz-space-2, 0.5rem);
36
44
  min-height: 2.25rem;
37
- padding: 0 0.5rem 0 0.75rem;
38
- border-bottom: 1px solid var(--vmz-line-subtle, var(--vmz-line-default));
39
- background: var(--vmz-surface-paper);
45
+ padding: 0 var(--vmz-space-2, 0.5rem) 0 var(--vmz-space-3, 0.75rem);
46
+ border-bottom: 1px solid color-mix(in srgb, var(--vmz-text-on-brand) 10%, transparent);
47
+ background: var(--vmz-surface-graphite);
40
48
  }
41
49
 
42
50
  .vmz-ui-code-block__heading {
43
51
  display: flex;
44
52
  align-items: center;
45
- gap: 0.5rem;
53
+ gap: var(--vmz-space-2, 0.5rem);
46
54
  min-width: 0;
47
55
  }
48
56
 
49
57
  .vmz-ui-code-block__lang {
50
58
  flex: none;
51
59
  padding: 0.0625rem 0.4375rem;
52
- border: 1px solid var(--vmz-line-default);
60
+ border: 1px solid color-mix(in srgb, var(--vmz-text-on-brand) 18%, transparent);
53
61
  border-radius: var(--vmz-radius-xs, 2px);
54
- background: var(--vmz-surface-mist);
55
- color: var(--vmz-text-steel);
62
+ background: color-mix(in srgb, var(--vmz-text-on-brand) 8%, transparent);
63
+ color: color-mix(in srgb, var(--vmz-text-on-brand) 72%, transparent);
56
64
  font-family: var(--vmz-font-mono);
57
65
  font-size: 0.6875rem;
58
66
  font-weight: 600;
@@ -63,38 +71,68 @@
63
71
 
64
72
  .vmz-ui-code-block__caption {
65
73
  overflow: hidden;
66
- color: var(--vmz-text-steel);
74
+ color: color-mix(in srgb, var(--vmz-text-on-brand) 72%, transparent);
67
75
  font-size: 0.8125rem;
68
76
  line-height: 1.5;
69
77
  text-overflow: ellipsis;
70
78
  white-space: nowrap;
71
79
  }
72
80
 
73
- .vmz-ui-code-block__copy {
81
+ .vmz-ui-code-block .vmz-ui-code-block__bar .vmz-ui-code-block__copy {
74
82
  flex: none;
75
- opacity: 0.72;
76
- transition: opacity var(--vmz-motion-control-duration, 150ms) var(--vmz-motion-control-easing, cubic-bezier(0.4, 0, 0.2, 1));
83
+ min-height: 1.75rem;
84
+ padding: 0 var(--vmz-space-2, 0.5rem);
85
+ gap: var(--vmz-space-1, 0.25rem);
86
+ border: 1px solid transparent;
87
+ border-radius: var(--vmz-radius-sm, 4px);
88
+ background: transparent;
89
+ color: color-mix(in srgb, var(--vmz-text-on-brand) 72%, transparent);
90
+ font-family: var(--vmz-font-sans);
91
+ font-size: 0.8125rem;
92
+ font-weight: 500;
93
+ line-height: 1.5;
94
+ cursor: pointer;
95
+ outline: none;
96
+ transition:
97
+ color var(--vmz-motion-control-duration, 150ms) var(--vmz-motion-control-easing, cubic-bezier(0.4, 0, 0.2, 1)),
98
+ background-color var(--vmz-motion-control-duration, 150ms) var(--vmz-motion-control-easing, cubic-bezier(0.4, 0, 0.2, 1));
99
+ }
100
+
101
+ .vmz-ui-code-block .vmz-ui-code-block__bar .vmz-ui-code-block__copy:hover:not(:disabled) {
102
+ color: var(--vmz-text-on-brand);
103
+ background: color-mix(in srgb, var(--vmz-text-on-brand) 12%, transparent);
104
+ }
105
+
106
+ .vmz-ui-code-block .vmz-ui-code-block__bar .vmz-ui-code-block__copy:active:not(:disabled) {
107
+ background: color-mix(in srgb, var(--vmz-text-on-brand) 16%, transparent);
108
+ }
109
+
110
+ .vmz-ui-code-block .vmz-ui-code-block__bar .vmz-ui-code-block__copy:focus-visible {
111
+ box-shadow: 0 0 0 3px var(--vmz-focus-ring);
77
112
  }
78
113
 
79
- .vmz-ui-code-block:hover .vmz-ui-code-block__copy,
80
- .vmz-ui-code-block__copy:focus-visible {
81
- opacity: 1;
114
+ .vmz-ui-code-block__copy-text {
115
+ overflow: hidden;
116
+ max-width: 10rem;
117
+ text-overflow: ellipsis;
118
+ white-space: nowrap;
82
119
  }
83
120
 
84
121
  .vmz-ui-code-block__pre {
85
122
  margin: 0;
86
- padding: 0.875rem 1rem;
123
+ padding: var(--vmz-space-4, 1rem) 1.25rem;
87
124
  overflow-x: auto;
88
125
  overflow-y: auto;
89
126
  max-height: 32rem;
127
+ background: var(--vmz-surface-code);
90
128
  }
91
129
 
92
130
  .vmz-ui-code-block__code {
93
131
  display: block;
94
- color: var(--vmz-text-ink);
132
+ color: var(--vmz-text-on-brand);
95
133
  font-family: var(--vmz-font-mono);
96
- font-size: 0.8125rem;
97
- line-height: 1.65;
134
+ font-size: 0.875rem;
135
+ line-height: 1.5714;
98
136
  white-space: pre;
99
137
  tab-size: 2;
100
138
  }
@@ -106,27 +144,36 @@
106
144
 
107
145
  .vmz-ui-code-block__pre::-webkit-scrollbar-thumb {
108
146
  border-radius: var(--vmz-radius-pill, 999px);
109
- background: var(--vmz-line-default);
147
+ background: color-mix(in srgb, var(--vmz-text-on-brand) 20%, transparent);
110
148
  }
111
149
  </style>
112
150
  <script client>
113
151
  /**
114
152
  * VMZ UI — CodeBlock (Document/Product composition).
115
- * Source is readable in SSR HTML; copy is progressive enhancement via onCopy.
153
+ * Dark `<pre><code>` shell: no syntax highlighting (use `<Shiki>` / `<Code>`).
154
+ * `title` wins over legacy `caption`; `language` is a display-only chip.
155
+ * Source and bar are server-rendered; copy is progressive enhancement via onCopy.
116
156
  */
117
157
  export default class CodeBlock {
118
158
  public code: string = "";
159
+ /** Legacy heading text; kept for existing callers and used when `title` is empty. */
119
160
  public caption: string = "";
120
161
  /** Preferred heading text; falls back to `caption` when absent. */
121
162
  public title: string = "";
122
163
  /** Optional syntax label rendered as a chip in the bar (e.g. `ts`, `bash`). */
123
164
  public language: string = "";
124
- public copyLabel: string = "Copy";
165
+ /** Accessible label of the copy control. */
166
+ public copyLabel: string = "";
125
167
  public onCopy: ((e: Event) => void) | null = null;
126
168
 
127
169
  /** The bar renders when there is anything to show in it. */
128
170
  public barVisible(): boolean {
129
- return !!(this.title || this.caption || this.language || this.onCopy);
171
+ return !!(this.title || this.caption || this.language || this.canCopy());
172
+ }
173
+
174
+ /** Copy is a real control only when a handler exists; no dead button. */
175
+ public canCopy(): boolean {
176
+ return typeof this.onCopy === "function";
130
177
  }
131
178
  }
132
179
  </script>
@@ -1,8 +1,11 @@
1
1
  <template>
2
2
  <div data-vmz-ui="collapse" class="vmz-ui-collapse">
3
- <details v-for="item in items" :key="item.id" :data-vmz-collapse-item="item.id">
4
- <summary :data-vmz-collapse-trigger="item.id">
5
- {{ item.title }}
3
+ <details v-for="item in items" :key="item.id" :data-vmz-collapse-item="item.id" class="vmz-ui-collapse__item">
4
+ <summary :data-vmz-collapse-trigger="item.id" class="vmz-ui-collapse__trigger">
5
+ <span class="vmz-ui-collapse__title">
6
+ {{ item.title }}
7
+ </span>
8
+ <Icon name="action.chevron-down" size="sm" decorative />
6
9
  </summary>
7
10
  <div :data-vmz-collapse-body="item.id" class="vmz-ui-collapse__body">
8
11
  {{ item.body }}
@@ -12,27 +15,77 @@
12
15
  </template>
13
16
  <style>
14
17
  .vmz-ui-collapse {
18
+ box-sizing: border-box;
15
19
  border: 1px solid var(--vmz-line-default);
16
- border-radius: var(--vmz-radius-lg, 8px);
20
+ border-radius: var(--vmz-radius-lg);
17
21
  background: var(--vmz-surface-paper);
22
+ color: var(--vmz-text-ink);
18
23
  overflow: hidden;
19
24
  }
20
- .vmz-ui-collapse details + details {
21
- border-top: 1px solid var(--vmz-line-default);
25
+
26
+ .vmz-ui-collapse__item + .vmz-ui-collapse__item {
27
+ border-top: 1px solid var(--vmz-line-subtle);
22
28
  }
23
- .vmz-ui-collapse summary {
24
- padding: 0.85rem 1rem;
29
+
30
+ .vmz-ui-collapse__trigger {
31
+ display: flex;
32
+ align-items: center;
33
+ gap: 12px;
34
+ min-height: 40px;
35
+ box-sizing: border-box;
36
+ padding: 0 16px;
37
+ font-size: 14px;
25
38
  font-weight: 600;
39
+ line-height: 22px;
40
+ list-style: none;
26
41
  cursor: pointer;
27
42
  background: var(--vmz-surface-paper);
43
+ color: var(--vmz-text-ink);
44
+ outline: none;
45
+ transition: background-color var(--vmz-motion-control-duration)
46
+ var(--vmz-motion-control-easing);
28
47
  }
29
- .vmz-ui-collapse summary:hover {
48
+
49
+ .vmz-ui-collapse summary::-webkit-details-marker {
50
+ display: none;
51
+ }
52
+
53
+ .vmz-ui-collapse__trigger:hover {
30
54
  background: var(--vmz-surface-mist);
31
55
  }
56
+
57
+ .vmz-ui-collapse__trigger:focus-visible {
58
+ box-shadow: inset 0 0 0 2px var(--vmz-focus-ring);
59
+ }
60
+
61
+ .vmz-ui-collapse__title {
62
+ flex: 1 1 auto;
63
+ min-width: 0;
64
+ }
65
+
66
+ .vmz-ui-collapse__trigger .vmz-ui-icon {
67
+ flex: 0 0 auto;
68
+ color: var(--vmz-text-tertiary);
69
+ transition: transform var(--vmz-motion-control-duration)
70
+ var(--vmz-motion-control-easing);
71
+ }
72
+
73
+ .vmz-ui-collapse__item[open] > .vmz-ui-collapse__trigger .vmz-ui-icon {
74
+ transform: rotate(180deg);
75
+ }
76
+
32
77
  .vmz-ui-collapse__body {
33
- padding: 0 1rem 1rem;
78
+ padding: 0 16px 16px;
79
+ font-size: 14px;
80
+ line-height: 26px;
34
81
  color: var(--vmz-text-steel);
35
- line-height: 1.6;
82
+ }
83
+
84
+ @media (prefers-reduced-motion: reduce) {
85
+ .vmz-ui-collapse__trigger,
86
+ .vmz-ui-collapse__trigger .vmz-ui-icon {
87
+ transition: none;
88
+ }
36
89
  }
37
90
  </style>
38
91
  <script client>