@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
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <section data-vmz-ui="card" :data-size="size" :data-bordered="bordered ? 'true' : 'false'" :data-hoverable="hoverable ? 'true' : 'false'" class="vmz-ui-card">
3
- <header v-if="title" class="vmz-ui-card__header">
4
- <h2 class="vmz-ui-card__title">
3
+ <header v-if="title || description" class="vmz-ui-card__header">
4
+ <h2 v-if="title" class="vmz-ui-card__title">
5
5
  {{ title }}
6
6
  </h2>
7
7
  <p v-if="description" class="vmz-ui-card__description">
@@ -11,108 +11,129 @@
11
11
  <div class="vmz-ui-card__body">
12
12
  <slot />
13
13
  </div>
14
+ <footer v-if="footer" class="vmz-ui-card__footer">
15
+ {{ footer }}
16
+ </footer>
14
17
  </section>
15
18
  </template>
16
19
  <style>
17
20
  .vmz-ui-card {
18
21
  display: flex;
19
22
  flex-direction: column;
20
- gap: 0.75rem;
21
- padding: 1.25rem 1.5rem;
22
- border: 1px solid var(--vmz-line-subtle, var(--vmz-line-default));
23
+ box-sizing: border-box;
24
+ height: 100%;
25
+ border: 1px solid var(--vmz-line-default, var(--vmz-line-strong));
23
26
  border-radius: var(--vmz-radius-lg, 8px);
24
27
  background: var(--vmz-surface-paper);
25
28
  color: var(--vmz-text-ink);
26
- box-shadow: var(--vmz-shadow-card, none);
29
+ font-family: var(--vmz-font-sans, inherit);
30
+ box-shadow: none;
27
31
  }
32
+
28
33
  .vmz-ui-card[data-bordered="false"] {
29
34
  border-color: transparent;
30
35
  }
36
+
31
37
  .vmz-ui-card[data-hoverable="true"] {
32
- transition:
33
- border-color var(--vmz-motion-emphasis-duration, 240ms) var(--vmz-motion-emphasis-easing, cubic-bezier(0.16, 1, 0.3, 1)),
34
- box-shadow var(--vmz-motion-emphasis-duration, 240ms) var(--vmz-motion-emphasis-easing, cubic-bezier(0.16, 1, 0.3, 1)),
35
- transform var(--vmz-motion-emphasis-duration, 240ms) var(--vmz-motion-emphasis-easing, cubic-bezier(0.16, 1, 0.3, 1));
38
+ transition: border-color var(--vmz-motion-control-duration, 120ms)
39
+ var(--vmz-motion-control-easing, cubic-bezier(0.2, 0, 0, 1));
36
40
  }
41
+
37
42
  .vmz-ui-card[data-hoverable="true"]:hover {
38
- border-color: var(--vmz-line-default);
39
- box-shadow: var(
40
- --vmz-shadow-card-hover,
41
- 0 1px 2px -2px rgba(0, 0, 0, 0.08),
42
- 0 3px 6px 0 rgba(0, 0, 0, 0.06)
43
- );
44
- transform: translateY(-1px);
43
+ border-color: var(--vmz-line-strong);
45
44
  }
45
+
46
46
  .vmz-ui-card[data-hoverable="true"]:focus-within {
47
47
  border-color: var(--vmz-action-primary-background);
48
48
  }
49
+
49
50
  @media (prefers-reduced-motion: reduce) {
50
51
  .vmz-ui-card[data-hoverable="true"] {
51
52
  transition: none;
52
53
  }
53
- .vmz-ui-card[data-hoverable="true"]:hover {
54
- transform: none;
55
- }
56
- }
57
- .vmz-ui-card[data-size="small"] {
58
- gap: 0.5rem;
59
- padding: 0.875rem 1rem;
60
54
  }
61
55
 
62
- :where([data-density="compact"]) .vmz-ui-card {
63
- gap: var(--vmz-density-compact-gap);
64
- padding: var(--vmz-density-compact-padding-y) var(--vmz-density-compact-padding-x);
56
+ .vmz-ui-card__header {
57
+ display: flex;
58
+ flex-direction: column;
59
+ gap: var(--vmz-space-1, 0.25rem);
60
+ padding: var(--vmz-space-5, 1.5rem);
61
+ border-bottom: 1px solid var(--vmz-line-subtle, var(--vmz-line-default));
65
62
  }
66
63
 
67
- :where([data-density="dense"]) .vmz-ui-card {
68
- gap: var(--vmz-density-dense-gap);
69
- padding: var(--vmz-density-dense-padding-y) var(--vmz-density-dense-padding-x);
64
+ .vmz-ui-card__body {
65
+ display: flex;
66
+ flex-direction: column;
67
+ flex: 1 1 auto;
68
+ gap: var(--vmz-space-3, 0.75rem);
69
+ padding: var(--vmz-space-5, 1.5rem);
70
70
  }
71
71
 
72
- .vmz-ui-card__header {
72
+ .vmz-ui-card__footer {
73
73
  display: flex;
74
- flex-direction: column;
75
- gap: 0.375rem;
74
+ align-items: center;
75
+ gap: var(--vmz-space-2, 0.5rem);
76
+ padding: var(--vmz-space-4, 1rem) var(--vmz-space-5, 1.5rem);
77
+ border-top: 1px solid var(--vmz-line-subtle, var(--vmz-line-default));
78
+ color: var(--vmz-text-steel);
79
+ font-size: 0.875rem;
80
+ }
81
+
82
+ .vmz-ui-card[data-size="small"] .vmz-ui-card__header,
83
+ .vmz-ui-card[data-size="small"] .vmz-ui-card__body {
84
+ gap: var(--vmz-space-2, 0.5rem);
85
+ padding: var(--vmz-space-3, 0.75rem) var(--vmz-space-4, 1rem);
86
+ }
87
+
88
+ .vmz-ui-card[data-size="small"] .vmz-ui-card__footer {
89
+ padding: var(--vmz-space-2, 0.5rem) var(--vmz-space-4, 1rem);
76
90
  }
77
91
 
78
92
  .vmz-ui-card__title {
79
93
  margin: 0;
80
- font-family: var(--vmz-font-sans, inherit);
94
+ font-family: var(--vmz-font-display, var(--vmz-font-sans, inherit));
81
95
  font-size: 1rem;
82
96
  font-weight: 600;
97
+ line-height: 1.4;
83
98
  color: var(--vmz-text-ink);
84
99
  }
85
100
 
86
101
  .vmz-ui-card__description {
87
102
  margin: 0;
88
- color: var(--vmz-text-steel);
89
- line-height: 1.45;
103
+ font-size: 0.875rem;
104
+ line-height: 1.55;
105
+ color: var(--vmz-text-tertiary);
90
106
  }
91
107
 
92
- .vmz-ui-card__body {
93
- display: flex;
94
- flex-direction: column;
95
- gap: var(--vmz-density-control-gap);
108
+ :where([data-density="compact"]) .vmz-ui-card__header,
109
+ :where([data-density="compact"]) .vmz-ui-card__body {
110
+ gap: var(--vmz-space-2, 0.5rem);
111
+ padding: var(--vmz-space-3, 0.75rem) var(--vmz-space-4, 1rem);
96
112
  }
97
113
 
98
- /* Direct host default is display:contents (runtime); Badge-only CSS special-case removed. */
99
-
100
- :where([data-density="compact"]) .vmz-ui-card__body {
101
- gap: var(--vmz-density-compact-gap);
114
+ :where([data-density="compact"]) .vmz-ui-card__footer {
115
+ padding: var(--vmz-space-2, 0.5rem) var(--vmz-space-4, 1rem);
102
116
  }
103
117
 
118
+ :where([data-density="dense"]) .vmz-ui-card__header,
104
119
  :where([data-density="dense"]) .vmz-ui-card__body {
105
- gap: var(--vmz-density-dense-gap);
120
+ gap: var(--vmz-space-1, 0.25rem);
121
+ padding: var(--vmz-space-2, 0.5rem) var(--vmz-space-3, 0.75rem);
122
+ }
123
+
124
+ :where([data-density="dense"]) .vmz-ui-card__footer {
125
+ padding: var(--vmz-space-1, 0.25rem) var(--vmz-space-3, 0.75rem);
106
126
  }
107
127
  </style>
108
128
  <script client>
109
129
  /**
110
130
  * VMZ UI — Card (Commercial Surface).
111
- * Surface container; spacing from density.*; chrome from surface/line/text.
131
+ * Surface container: paper + 1px line + radius.lg; spacing from space/density tokens.
112
132
  */
113
133
  export default class Card {
114
134
  public title: string = "";
115
135
  public description: string = "";
136
+ public footer: string = "";
116
137
  public size: string = "middle";
117
138
  public bordered: boolean = true;
118
139
  public hoverable: boolean = false;
@@ -1,6 +1,9 @@
1
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" />
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>
4
7
  <span class="vmz-ui-checkbox__label">
5
8
  {{ label }}
6
9
  </span>
@@ -10,16 +13,54 @@
10
13
  .vmz-ui-checkbox {
11
14
  display: inline-flex;
12
15
  align-items: center;
13
- gap: 0.5rem;
16
+ gap: var(--vmz-space-2);
14
17
  font: inherit;
18
+ font-size: 0.875rem;
19
+ line-height: 1.5715;
20
+ color: var(--vmz-text-ink);
15
21
  cursor: pointer;
16
22
  }
17
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
+
18
32
  .vmz-ui-checkbox__input {
33
+ position: absolute;
34
+ inset: 0;
35
+ z-index: 1;
36
+ box-sizing: border-box;
19
37
  width: 1rem;
20
38
  height: 1rem;
21
- accent-color: var(--vmz-action-primary-background);
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);
22
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);
23
64
  }
24
65
 
25
66
  .vmz-ui-checkbox__input:focus-visible {
@@ -27,12 +68,47 @@
27
68
  }
28
69
 
29
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"] {
30
94
  opacity: 0.55;
31
95
  cursor: not-allowed;
32
96
  }
33
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
+
34
103
  .vmz-ui-checkbox__label {
35
- font-weight: 600;
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
+ }
36
112
  }
37
113
  </style>
38
114
  <script client>
@@ -12,8 +12,11 @@
12
12
  {{ caption }}
13
13
  </span>
14
14
  </div>
15
- <Button v-if="canCopy()" type="button" variant="text" size="sm" @click="onCopy" class="vmz-ui-code-block__copy">
16
- {{ 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>
17
20
  </Button>
18
21
  </div>
19
22
  <pre class="vmz-ui-code-block__pre">
@@ -28,9 +31,8 @@
28
31
  margin: 0;
29
32
  display: flex;
30
33
  flex-direction: column;
31
- border: 1px solid var(--vmz-line-default);
32
34
  border-radius: var(--vmz-radius-lg, 8px);
33
- background: var(--vmz-surface-mist);
35
+ background: var(--vmz-surface-code);
34
36
  overflow: hidden;
35
37
  }
36
38
 
@@ -38,27 +40,27 @@
38
40
  display: flex;
39
41
  align-items: center;
40
42
  justify-content: space-between;
41
- gap: 0.5rem;
43
+ gap: var(--vmz-space-2, 0.5rem);
42
44
  min-height: 2.25rem;
43
- padding: 0 0.5rem 0 0.75rem;
44
- border-bottom: 1px solid var(--vmz-line-subtle, var(--vmz-line-default));
45
- 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);
46
48
  }
47
49
 
48
50
  .vmz-ui-code-block__heading {
49
51
  display: flex;
50
52
  align-items: center;
51
- gap: 0.5rem;
53
+ gap: var(--vmz-space-2, 0.5rem);
52
54
  min-width: 0;
53
55
  }
54
56
 
55
57
  .vmz-ui-code-block__lang {
56
58
  flex: none;
57
59
  padding: 0.0625rem 0.4375rem;
58
- border: 1px solid var(--vmz-line-default);
60
+ border: 1px solid color-mix(in srgb, var(--vmz-text-on-brand) 18%, transparent);
59
61
  border-radius: var(--vmz-radius-xs, 2px);
60
- background: var(--vmz-surface-mist);
61
- 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);
62
64
  font-family: var(--vmz-font-mono);
63
65
  font-size: 0.6875rem;
64
66
  font-weight: 600;
@@ -69,38 +71,68 @@
69
71
 
70
72
  .vmz-ui-code-block__caption {
71
73
  overflow: hidden;
72
- color: var(--vmz-text-steel);
74
+ color: color-mix(in srgb, var(--vmz-text-on-brand) 72%, transparent);
73
75
  font-size: 0.8125rem;
74
76
  line-height: 1.5;
75
77
  text-overflow: ellipsis;
76
78
  white-space: nowrap;
77
79
  }
78
80
 
79
- .vmz-ui-code-block__copy {
81
+ .vmz-ui-code-block .vmz-ui-code-block__bar .vmz-ui-code-block__copy {
80
82
  flex: none;
81
- opacity: 0.72;
82
- 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);
83
108
  }
84
109
 
85
- .vmz-ui-code-block:hover .vmz-ui-code-block__copy,
86
- .vmz-ui-code-block__copy:focus-visible {
87
- opacity: 1;
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);
112
+ }
113
+
114
+ .vmz-ui-code-block__copy-text {
115
+ overflow: hidden;
116
+ max-width: 10rem;
117
+ text-overflow: ellipsis;
118
+ white-space: nowrap;
88
119
  }
89
120
 
90
121
  .vmz-ui-code-block__pre {
91
122
  margin: 0;
92
- padding: 0.875rem 1rem;
123
+ padding: var(--vmz-space-4, 1rem) 1.25rem;
93
124
  overflow-x: auto;
94
125
  overflow-y: auto;
95
126
  max-height: 32rem;
127
+ background: var(--vmz-surface-code);
96
128
  }
97
129
 
98
130
  .vmz-ui-code-block__code {
99
131
  display: block;
100
- color: var(--vmz-text-ink);
132
+ color: var(--vmz-text-on-brand);
101
133
  font-family: var(--vmz-font-mono);
102
- font-size: 0.8125rem;
103
- line-height: 1.65;
134
+ font-size: 0.875rem;
135
+ line-height: 1.5714;
104
136
  white-space: pre;
105
137
  tab-size: 2;
106
138
  }
@@ -112,13 +144,13 @@
112
144
 
113
145
  .vmz-ui-code-block__pre::-webkit-scrollbar-thumb {
114
146
  border-radius: var(--vmz-radius-pill, 999px);
115
- background: var(--vmz-line-default);
147
+ background: color-mix(in srgb, var(--vmz-text-on-brand) 20%, transparent);
116
148
  }
117
149
  </style>
118
150
  <script client>
119
151
  /**
120
152
  * VMZ UI — CodeBlock (Document/Product composition).
121
- * Readable `<pre><code>` shell: no syntax highlighting (use `<Shiki>` / `<Code>`).
153
+ * Dark `<pre><code>` shell: no syntax highlighting (use `<Shiki>` / `<Code>`).
122
154
  * `title` wins over legacy `caption`; `language` is a display-only chip.
123
155
  * Source and bar are server-rendered; copy is progressive enhancement via onCopy.
124
156
  */
@@ -130,8 +162,8 @@ export default class CodeBlock {
130
162
  public title: string = "";
131
163
  /** Optional syntax label rendered as a chip in the bar (e.g. `ts`, `bash`). */
132
164
  public language: string = "";
133
- /** Visible label of the copy control. */
134
- public copyLabel: string = "Copy";
165
+ /** Accessible label of the copy control. */
166
+ public copyLabel: string = "";
135
167
  public onCopy: ((e: Event) => void) | null = null;
136
168
 
137
169
  /** The bar renders when there is anything to show in it. */
@@ -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>