@vmz/ui 0.3.7 → 0.3.9

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 +249 -69
  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,13 +1,16 @@
1
1
  <template>
2
2
  <nav data-vmz-ui="breadcrumb" :aria-label="label" class="vmz-ui-breadcrumb">
3
3
  <ol class="vmz-ui-breadcrumb__list">
4
- <li v-for="item in items" :key="item.id" :data-vmz-crumb="item.id" class="vmz-ui-breadcrumb__item">
4
+ <li v-for="(item, index) in items" :key="item.id" :data-vmz-crumb="item.id" class="vmz-ui-breadcrumb__item">
5
5
  <a v-if="item.href" :href="item.href" class="vmz-ui-breadcrumb__link">
6
6
  {{ item.title }}
7
7
  </a>
8
8
  <span v-if="!item.href" aria-current="page" class="vmz-ui-breadcrumb__current">
9
9
  {{ item.title }}
10
10
  </span>
11
+ <span v-if="index < items.length - 1" aria-hidden="true" class="vmz-ui-breadcrumb__sep">
12
+ <Icon name="action.chevron-right" size="xs" decorative />
13
+ </span>
11
14
  </li>
12
15
  </ol>
13
16
  </nav>
@@ -15,12 +18,14 @@
15
18
  <style>
16
19
  .vmz-ui-breadcrumb {
17
20
  font: inherit;
21
+ font-size: 0.875rem;
22
+ color: var(--vmz-text-steel);
18
23
  }
19
24
 
20
25
  .vmz-ui-breadcrumb__list {
21
26
  display: flex;
22
27
  flex-wrap: wrap;
23
- gap: 0.375rem 0.5rem;
28
+ gap: 0.25rem;
24
29
  margin: 0;
25
30
  padding: 0;
26
31
  list-style: none;
@@ -30,20 +35,20 @@
30
35
  .vmz-ui-breadcrumb__item {
31
36
  display: inline-flex;
32
37
  align-items: center;
33
- gap: 0.5rem;
34
- font-weight: 600;
38
+ gap: 0.25rem;
39
+ min-width: 0;
35
40
  }
36
41
 
37
- .vmz-ui-breadcrumb__item:not(:last-child)::after {
38
- content: "/";
39
- color: var(--vmz-action-primary-active);
40
- opacity: 0.55;
41
- font-weight: 400;
42
+ .vmz-ui-breadcrumb__link {
43
+ color: var(--vmz-text-steel);
44
+ text-decoration: none;
45
+ border-radius: var(--vmz-radius-xs, 2px);
46
+ transition: color var(--vmz-motion-control-duration, 150ms)
47
+ var(--vmz-motion-control-easing, cubic-bezier(0.4, 0, 0.2, 1));
42
48
  }
43
49
 
44
- .vmz-ui-breadcrumb__link {
50
+ .vmz-ui-breadcrumb__link:hover {
45
51
  color: var(--vmz-action-primary-background);
46
- text-decoration: none;
47
52
  }
48
53
 
49
54
  .vmz-ui-breadcrumb__link:focus-visible {
@@ -52,16 +57,25 @@
52
57
  }
53
58
 
54
59
  .vmz-ui-breadcrumb__current {
55
- color: var(--vmz-action-primary-active);
60
+ color: var(--vmz-text-ink);
61
+ font-weight: 500;
62
+ }
63
+
64
+ .vmz-ui-breadcrumb__sep {
65
+ display: inline-flex;
66
+ align-items: center;
67
+ font-size: 0.75rem;
68
+ color: var(--vmz-text-tertiary);
56
69
  }
57
70
  </style>
58
71
  <script client>
59
72
  /**
60
- * VMZ UI — Breadcrumb (UI5 Console Surface).
73
+ * VMZ UI — Breadcrumb (commercial path).
61
74
  * Parent owns items; last crumb typically has no href (current page).
75
+ * Separators use the shared chevron-right Icon (no CSS pseudo-elements).
62
76
  */
63
77
  export default class Breadcrumb {
64
- public label: string = "Breadcrumb";
78
+ public label: string = "";
65
79
  /** @type {{ id: string, title: string, href?: string }[]} */
66
80
  public items: {
67
81
  id: string;
@@ -14,11 +14,12 @@
14
14
  flex-wrap: wrap;
15
15
  align-items: center;
16
16
  justify-content: space-between;
17
- gap: 0.625rem 1rem;
18
- padding: 0.625rem 0.85rem;
19
- border: 1px solid var(--vmz-line-default);
17
+ gap: 0.5rem 1rem;
18
+ padding: 0.5rem 0.75rem;
19
+ border: 1px solid var(--vmz-action-primary-background);
20
20
  border-radius: var(--vmz-radius-md, 6px);
21
- background: transparent;
21
+ background: var(--vmz-action-primary-soft);
22
+ color: var(--vmz-text-ink);
22
23
  }
23
24
 
24
25
  /* Keep host+slot mounted so default slot projects at create time (not inside v-if). */
@@ -28,23 +29,27 @@
28
29
 
29
30
  .vmz-ui-bulk-actions__count {
30
31
  margin: 0;
31
- font-weight: 700;
32
- color: var(--vmz-action-primary-active);
32
+ font-size: 0.875rem;
33
+ font-weight: 500;
34
+ color: var(--vmz-text-ink);
33
35
  }
34
36
 
35
37
  .vmz-ui-bulk-actions__actions {
36
38
  display: flex;
37
39
  flex-wrap: wrap;
40
+ align-items: center;
38
41
  gap: 0.5rem;
42
+ margin-left: auto;
39
43
  }
40
44
  </style>
41
45
  <script client>
42
46
  /**
43
- * VMZ UI — BulkActions (Console composition).
47
+ * VMZ UI — BulkActions (selection toolbar).
44
48
  * Hides when selectedCount is falsy but keeps the tree mounted so parent slot children project.
49
+ * Count copy is parent-owned via `count-label`.
45
50
  */
46
51
  export default class BulkActions {
47
- public label: string = "Bulk actions";
52
+ public label: string = "";
48
53
  public selectedCount: number = 0;
49
54
  public countLabel: string = "";
50
55
  }
@@ -1,9 +1,9 @@
1
1
  <template>
2
- <a v-if="href" data-vmz-ui="button" data-vmz-motion="control" data-vmz-motion-token="motion.control" :data-variant="variant" :data-size="size" :data-block="block ? 'true' : 'false'" :href="href" :target="target" :rel="rel" @click="onDomClick" class="vmz-ui-btn">
2
+ <a v-if="href" data-vmz-ui="button" data-vmz-motion="control" data-vmz-motion-token="motion.control" :data-variant="variant" :data-size="size" :data-block="block ? 'true' : 'false'" :href="href" :target="target" :rel="rel" :aria-busy="loading ? 'true' : 'false'" @click="onDomClick" class="vmz-ui-btn">
3
3
  <span v-if="loading" aria-hidden="true" class="vmz-ui-btn__spinner" />
4
4
  <slot />
5
5
  </a>
6
- <button v-else :type="type" data-vmz-ui="button" data-vmz-motion="control" data-vmz-motion-token="motion.control" :data-variant="variant" :data-size="size" :data-block="block ? 'true' : 'false'" :data-loading="loading ? 'true' : 'false'" :disabled="disabled" :aria-busy="loading ? 'true' : 'false'" :aria-haspopup="ariaHaspopup" :aria-controls="ariaControls" @click="onDomClick" class="vmz-ui-btn">
6
+ <button v-else :type="type" data-vmz-ui="button" data-vmz-motion="control" data-vmz-motion-token="motion.control" :data-variant="variant" :data-size="size" :data-block="block ? 'true' : 'false'" :data-loading="loading ? 'true' : 'false'" :disabled="disabled" :aria-busy="loading ? 'true' : 'false'" :aria-haspopup="ariaHaspopup" :aria-controls="ariaControls" :aria-expanded="ariaExpanded ? ariaExpanded : null" @click="onDomClick" class="vmz-ui-btn">
7
7
  <span v-if="loading" aria-hidden="true" class="vmz-ui-btn__spinner" />
8
8
  <slot />
9
9
  </button>
@@ -13,13 +13,14 @@
13
13
  display: inline-flex;
14
14
  align-items: center;
15
15
  justify-content: center;
16
- gap: 0.375rem;
16
+ gap: var(--vmz-space-2);
17
17
  /* Inline control: never stretch when the parent is a flex column (shells, card bodies). */
18
18
  width: fit-content;
19
- min-height: var(--vmz-control-height, 2rem);
19
+ box-sizing: border-box;
20
+ min-height: var(--vmz-control-height);
20
21
  padding: var(--vmz-density-control-padding-y) var(--vmz-density-control-padding-x);
21
22
  border: 1px solid transparent;
22
- border-radius: var(--vmz-radius-md, 6px);
23
+ border-radius: var(--vmz-radius-md);
23
24
  font: inherit;
24
25
  font-size: 0.875rem;
25
26
  font-weight: 500;
@@ -29,39 +30,46 @@
29
30
  background: var(--vmz-action-primary-background);
30
31
  color: var(--vmz-action-primary-foreground);
31
32
  outline: none;
32
- box-shadow: 0 2px 0 color-mix(in srgb, var(--vmz-action-primary-background) 12%, transparent);
33
+ box-shadow: none;
33
34
  transition:
34
- background-color var(--vmz-motion-control-duration, 120ms) var(--vmz-motion-control-easing, cubic-bezier(0.4, 0, 0.2, 1)),
35
- border-color var(--vmz-motion-control-duration, 120ms) var(--vmz-motion-control-easing, cubic-bezier(0.4, 0, 0.2, 1)),
36
- color var(--vmz-motion-control-duration, 120ms) var(--vmz-motion-control-easing, cubic-bezier(0.4, 0, 0.2, 1)),
37
- box-shadow var(--vmz-motion-control-duration, 120ms) var(--vmz-motion-control-easing, cubic-bezier(0.4, 0, 0.2, 1));
35
+ background-color var(--vmz-motion-control-duration) var(--vmz-motion-control-easing),
36
+ border-color var(--vmz-motion-control-duration) var(--vmz-motion-control-easing),
37
+ color var(--vmz-motion-control-duration) var(--vmz-motion-control-easing),
38
+ box-shadow var(--vmz-motion-control-duration) var(--vmz-motion-control-easing);
38
39
  }
39
40
 
40
41
  .vmz-ui-btn[data-size="small"] {
41
- min-height: var(--vmz-control-height-sm, 1.5rem);
42
- padding: 0 0.625rem;
43
- font-size: 0.8125rem;
42
+ min-height: var(--vmz-control-height-sm);
43
+ padding: 0 var(--vmz-space-3);
44
+ font-size: 0.875rem;
44
45
  }
46
+
45
47
  .vmz-ui-btn[data-size="large"] {
46
- min-height: var(--vmz-control-height-lg, 2.5rem);
47
- padding: 0.4375rem 1.125rem;
48
- font-size: 1rem;
48
+ min-height: var(--vmz-control-height-lg);
49
+ padding: var(--vmz-density-control-padding-y) var(--vmz-space-4);
50
+ font-size: 0.875rem;
49
51
  }
52
+
50
53
  .vmz-ui-btn[data-block="true"] {
51
54
  width: 100%;
52
55
  }
56
+
53
57
  .vmz-ui-btn[data-loading="true"] {
54
58
  cursor: wait;
55
59
  }
60
+
56
61
  .vmz-ui-btn__spinner {
62
+ flex: 0 0 auto;
57
63
  width: 1em;
58
64
  height: 1em;
59
65
  border: 1.5px solid currentColor;
60
66
  border-right-color: transparent;
61
- border-radius: 50%;
62
- opacity: 0.8;
67
+ border-radius: var(--vmz-radius-pill);
68
+ color: currentColor;
69
+ opacity: 0.9;
63
70
  animation: vmz-btn-spin 0.7s linear infinite;
64
71
  }
72
+
65
73
  @keyframes vmz-btn-spin {
66
74
  to {
67
75
  transform: rotate(360deg);
@@ -74,49 +82,73 @@
74
82
 
75
83
  .vmz-ui-btn:active:not(:disabled) {
76
84
  background: var(--vmz-action-primary-active);
77
- transform: translateY(0.5px);
78
85
  }
79
86
 
80
87
  .vmz-ui-btn[data-variant="secondary"] {
81
88
  background: var(--vmz-action-secondary-background);
82
89
  color: var(--vmz-action-secondary-foreground);
83
90
  border-color: var(--vmz-action-secondary-border);
84
- box-shadow: none;
85
91
  }
92
+
86
93
  .vmz-ui-btn[data-variant="default"] {
87
- background: var(--vmz-surface-paper);
94
+ background: var(--vmz-action-secondary-background);
88
95
  color: var(--vmz-text-ink);
89
96
  border-color: var(--vmz-line-default);
90
- box-shadow: none;
91
97
  }
98
+
92
99
  .vmz-ui-btn[data-variant="default"]:hover:not(:disabled) {
93
100
  color: var(--vmz-action-primary-hover);
94
101
  border-color: var(--vmz-action-primary-hover);
95
- background: var(--vmz-surface-paper);
102
+ background: var(--vmz-action-secondary-background);
103
+ }
104
+
105
+ .vmz-ui-btn[data-variant="default"]:active:not(:disabled) {
106
+ color: var(--vmz-action-primary-active);
107
+ border-color: var(--vmz-action-primary-active);
108
+ background: var(--vmz-action-secondary-active);
96
109
  }
110
+
97
111
  .vmz-ui-btn[data-variant="text"],
98
112
  .vmz-ui-btn[data-variant="link"] {
99
113
  min-height: auto;
100
- padding: 0.25rem 0.5rem;
114
+ padding: var(--vmz-space-1) var(--vmz-space-2);
101
115
  border-color: transparent;
102
116
  background: transparent;
103
- color: var(--vmz-action-primary-background);
104
- box-shadow: none;
117
+ color: var(--vmz-action-link-foreground);
118
+ }
119
+
120
+ .vmz-ui-btn[data-variant="text"]:hover:not(:disabled),
121
+ .vmz-ui-btn[data-variant="link"]:hover:not(:disabled) {
122
+ background: var(--vmz-surface-mist);
123
+ color: var(--vmz-action-link-hover);
105
124
  }
125
+
126
+ .vmz-ui-btn[data-variant="text"]:active:not(:disabled),
127
+ .vmz-ui-btn[data-variant="link"]:active:not(:disabled) {
128
+ background: var(--vmz-surface-fill);
129
+ }
130
+
106
131
  .vmz-ui-btn[data-variant="dashed"] {
107
- background: var(--vmz-surface-paper);
132
+ background: var(--vmz-action-secondary-background);
108
133
  color: var(--vmz-text-ink);
109
134
  border: 1px dashed var(--vmz-line-default);
110
- box-shadow: none;
135
+ }
136
+
137
+ .vmz-ui-btn[data-variant="dashed"]:hover:not(:disabled) {
138
+ color: var(--vmz-action-primary-hover);
139
+ border-color: var(--vmz-action-primary-hover);
111
140
  }
112
141
 
113
142
  .vmz-ui-btn[data-variant="secondary"]:hover:not(:disabled) {
114
143
  background: var(--vmz-action-secondary-hover);
144
+ border-color: var(--vmz-action-primary-hover);
145
+ color: var(--vmz-action-primary-hover);
115
146
  }
116
147
 
117
148
  .vmz-ui-btn[data-variant="secondary"]:active:not(:disabled) {
118
- background: var(--vmz-action-secondary-hover);
149
+ background: var(--vmz-action-secondary-active);
119
150
  border-color: var(--vmz-action-primary-active);
151
+ color: var(--vmz-action-primary-active);
120
152
  }
121
153
 
122
154
  .vmz-ui-btn[data-variant="ghost"] {
@@ -126,11 +158,11 @@
126
158
  }
127
159
 
128
160
  .vmz-ui-btn[data-variant="ghost"]:hover:not(:disabled) {
129
- background: color-mix(in srgb, var(--vmz-surface-mist) 85%, transparent);
161
+ background: var(--vmz-surface-mist);
130
162
  }
131
163
 
132
164
  .vmz-ui-btn[data-variant="ghost"]:active:not(:disabled) {
133
- background: var(--vmz-surface-mist);
165
+ background: var(--vmz-surface-fill);
134
166
  }
135
167
 
136
168
  .vmz-ui-btn[data-variant="danger"] {
@@ -140,7 +172,7 @@
140
172
  }
141
173
 
142
174
  .vmz-ui-btn[data-variant="danger"]:hover:not(:disabled) {
143
- background: color-mix(in srgb, var(--vmz-status-danger-accent) 82%, var(--vmz-text-ink));
175
+ background: var(--vmz-status-danger-foreground);
144
176
  }
145
177
 
146
178
  .vmz-ui-btn[data-variant="danger"]:active:not(:disabled) {
@@ -151,15 +183,6 @@
151
183
  box-shadow: 0 0 0 3px var(--vmz-focus-ring);
152
184
  }
153
185
 
154
- .vmz-ui-btn[data-variant="default"]:focus-visible,
155
- .vmz-ui-btn[data-variant="dashed"]:focus-visible,
156
- .vmz-ui-btn[data-variant="secondary"]:focus-visible,
157
- .vmz-ui-btn[data-variant="ghost"]:focus-visible,
158
- .vmz-ui-btn[data-variant="text"]:focus-visible,
159
- .vmz-ui-btn[data-variant="link"]:focus-visible {
160
- box-shadow: 0 0 0 3px var(--vmz-focus-ring);
161
- }
162
-
163
186
  .vmz-ui-btn:disabled {
164
187
  opacity: 0.55;
165
188
  cursor: not-allowed;
@@ -179,8 +202,8 @@
179
202
  .vmz-ui-btn {
180
203
  transition: none;
181
204
  }
182
- .vmz-ui-btn:active:not(:disabled) {
183
- transform: none;
205
+ .vmz-ui-btn__spinner {
206
+ animation-duration: 1.4s;
184
207
  }
185
208
  }
186
209
  </style>
@@ -188,7 +211,7 @@
188
211
  /**
189
212
  * VMZ UI — Button (variants + motion control feedback).
190
213
  * Colors / motion come only from Style Theme semantic tokens — never brand hex.
191
- * Variants: primary | secondary | ghost | danger
214
+ * Variants: primary | secondary | default | dashed | ghost | text | link | danger
192
215
  */
193
216
  export default class Button {
194
217
  /** @type {'contents'} Direct host: no layout box (`ui-direct-host-box`). */
@@ -204,6 +227,7 @@ export default class Button {
204
227
  public rel: string = "";
205
228
  public ariaHaspopup: string = "";
206
229
  public ariaControls: string = "";
230
+ public ariaExpanded: string = "";
207
231
  public onClick: ((e: Event) => void) | null = null;
208
232
  onDomClick(e: Event) {
209
233
  this.emit("click", e);
@@ -1,77 +1,178 @@
1
1
  <template>
2
2
  <aside data-vmz-ui="callout" :data-tone="tone" :role="roleName" class="vmz-ui-callout">
3
- <p v-if="title" class="vmz-ui-callout__title">
4
- {{ title }}
5
- </p>
6
- <p v-if="description" class="vmz-ui-callout__description">
7
- {{ description }}
8
- </p>
9
- <div class="vmz-ui-callout__body">
10
- <slot />
3
+ <span aria-hidden="true" class="vmz-ui-callout__icon">
4
+ <Icon :name="toneIcon()" size="md" decorative />
5
+ </span>
6
+ <div class="vmz-ui-callout__content">
7
+ <p v-if="title" class="vmz-ui-callout__title">
8
+ {{ title }}
9
+ </p>
10
+ <p v-if="description" class="vmz-ui-callout__description">
11
+ {{ description }}
12
+ </p>
13
+ <div class="vmz-ui-callout__body">
14
+ <slot />
15
+ </div>
11
16
  </div>
17
+ <button v-if="closable" type="button" :aria-label="closeLabel" @click="dismiss" class="vmz-ui-callout__close">
18
+ <Icon name="action.close" size="md" decorative />
19
+ </button>
12
20
  </aside>
13
21
  </template>
14
22
  <style>
15
23
  .vmz-ui-callout {
16
24
  display: flex;
17
- flex-direction: column;
18
- gap: 0.5rem;
19
- padding: var(--vmz-density-control-padding-y) var(--vmz-density-control-padding-x);
20
- border: 1px solid var(--vmz-status-info-accent);
21
- border-left-width: 1px;
22
- border-radius: var(--vmz-radius-md, 6px);
23
- background: color-mix(in srgb, var(--vmz-status-info-accent) 10%, var(--vmz-surface-paper));
25
+ align-items: flex-start;
26
+ gap: var(--vmz-space-2, 0.5rem);
27
+ padding: var(--vmz-space-4, 1rem);
28
+ border: 1px solid var(--vmz-status-info-border, var(--vmz-line-default));
29
+ border-radius: var(--vmz-radius-lg, 8px);
30
+ background: var(--vmz-status-info-background, var(--vmz-surface-paper));
24
31
  color: var(--vmz-status-info-foreground);
25
32
  }
26
33
 
27
34
  .vmz-ui-callout[data-tone="info"] {
28
- border-color: var(--vmz-status-info-accent);
29
- background: color-mix(in srgb, var(--vmz-status-info-accent) 10%, var(--vmz-surface-paper));
35
+ border-color: var(--vmz-status-info-border, var(--vmz-line-default));
36
+ background: var(--vmz-status-info-background, var(--vmz-surface-paper));
30
37
  color: var(--vmz-status-info-foreground);
31
38
  }
32
39
 
33
40
  .vmz-ui-callout[data-tone="success"] {
34
- border-color: var(--vmz-status-success-accent);
35
- background: color-mix(in srgb, var(--vmz-status-success-accent) 10%, var(--vmz-surface-paper));
41
+ border-color: var(--vmz-status-success-border, var(--vmz-line-default));
42
+ background: var(--vmz-status-success-background, var(--vmz-surface-paper));
36
43
  color: var(--vmz-status-success-foreground);
37
44
  }
38
45
 
39
46
  .vmz-ui-callout[data-tone="warning"] {
40
- border-color: var(--vmz-status-warning-accent);
41
- background: color-mix(in srgb, var(--vmz-status-warning-accent) 10%, var(--vmz-surface-paper));
47
+ border-color: var(--vmz-status-warning-border, var(--vmz-line-default));
48
+ background: var(--vmz-status-warning-background, var(--vmz-surface-paper));
42
49
  color: var(--vmz-status-warning-foreground);
43
50
  }
44
51
 
45
52
  .vmz-ui-callout[data-tone="danger"] {
46
- border-color: var(--vmz-status-danger-accent);
47
- background: color-mix(in srgb, var(--vmz-status-danger-accent) 10%, var(--vmz-surface-paper));
53
+ border-color: var(--vmz-status-danger-border, var(--vmz-line-default));
54
+ background: var(--vmz-status-danger-background, var(--vmz-surface-paper));
48
55
  color: var(--vmz-status-danger-foreground);
49
56
  }
50
57
 
58
+ .vmz-ui-callout[data-tone="info"] .vmz-ui-callout__icon {
59
+ color: var(--vmz-status-info-accent);
60
+ }
61
+
62
+ .vmz-ui-callout[data-tone="success"] .vmz-ui-callout__icon {
63
+ color: var(--vmz-status-success-accent);
64
+ }
65
+
66
+ .vmz-ui-callout[data-tone="warning"] .vmz-ui-callout__icon {
67
+ color: var(--vmz-status-warning-accent);
68
+ }
69
+
70
+ .vmz-ui-callout[data-tone="danger"] .vmz-ui-callout__icon {
71
+ color: var(--vmz-status-danger-accent);
72
+ }
73
+
74
+ .vmz-ui-callout__icon {
75
+ flex: 0 0 auto;
76
+ display: inline-flex;
77
+ align-items: center;
78
+ justify-content: center;
79
+ height: 1.5rem;
80
+ }
81
+
82
+ .vmz-ui-callout__content {
83
+ flex: 1 1 auto;
84
+ display: flex;
85
+ flex-direction: column;
86
+ gap: var(--vmz-space-1, 0.25rem);
87
+ min-width: 0;
88
+ }
89
+
51
90
  .vmz-ui-callout__title {
52
91
  margin: 0;
53
- font-family: var(--vmz-font-display);
54
- font-weight: 700;
92
+ font-family: var(--vmz-font-display, inherit);
93
+ font-size: 0.9375rem;
94
+ font-weight: 600;
95
+ line-height: 1.5;
96
+ color: inherit;
55
97
  }
56
98
 
57
99
  .vmz-ui-callout__description {
58
100
  margin: 0;
59
- line-height: 1.5;
101
+ color: var(--vmz-text-steel);
102
+ }
103
+
104
+ .vmz-ui-callout__body {
105
+ display: flex;
106
+ flex-direction: column;
107
+ gap: var(--vmz-space-2, 0.5rem);
108
+ color: var(--vmz-text-ink);
60
109
  }
61
110
 
62
111
  .vmz-ui-callout__body:empty {
63
112
  display: none;
64
113
  }
114
+
115
+ .vmz-ui-callout__close {
116
+ flex: 0 0 auto;
117
+ display: inline-flex;
118
+ align-items: center;
119
+ justify-content: center;
120
+ width: 1.5rem;
121
+ height: 1.5rem;
122
+ padding: 0;
123
+ border: 1px solid transparent;
124
+ border-radius: var(--vmz-radius-sm, 4px);
125
+ background: transparent;
126
+ color: var(--vmz-text-tertiary);
127
+ cursor: pointer;
128
+ outline: none;
129
+ transition:
130
+ color var(--vmz-motion-control-duration, 120ms) var(--vmz-motion-control-easing, cubic-bezier(0.2, 0, 0, 1)),
131
+ background-color var(--vmz-motion-control-duration, 120ms) var(--vmz-motion-control-easing, cubic-bezier(0.2, 0, 0, 1));
132
+ }
133
+
134
+ .vmz-ui-callout__close:hover {
135
+ color: var(--vmz-text-ink);
136
+ background: var(--vmz-surface-paper);
137
+ }
138
+
139
+ .vmz-ui-callout__close:focus-visible {
140
+ box-shadow: 0 0 0 3px var(--vmz-focus-ring);
141
+ }
142
+
143
+ :where([data-density="compact"]) .vmz-ui-callout {
144
+ gap: var(--vmz-space-2, 0.5rem);
145
+ padding: var(--vmz-space-3, 0.75rem);
146
+ }
147
+
148
+ :where([data-density="dense"]) .vmz-ui-callout {
149
+ gap: var(--vmz-space-1, 0.25rem);
150
+ padding: var(--vmz-space-3, 0.75rem);
151
+ }
65
152
  </style>
66
153
  <script client>
67
154
  /**
68
155
  * VMZ UI — Callout (Document/Product composition).
69
- * Inline guidance block for prose; shares status.* tones with Alert.
156
+ * Inline guidance block for prose; shares status.{accent|foreground|background|border} tones with Alert.
70
157
  */
71
158
  export default class Callout {
72
159
  public title: string = "";
73
160
  public description: string = "";
74
161
  public tone: string = "info";
75
162
  public roleName: string = "note";
163
+ public closable: boolean = false;
164
+ public closeLabel: string = "";
165
+ public onClose: (() => void) | null = null;
166
+
167
+ toneIcon() {
168
+ const tone = String(this.tone || "").toLowerCase();
169
+ if (tone === "success" || tone === "warning" || tone === "danger") return `status.${tone}`;
170
+ return "status.info";
171
+ }
172
+
173
+ dismiss() {
174
+ this.emit("close");
175
+ if (typeof this.onClose === "function") this.onClose();
176
+ }
76
177
  }
77
178
  </script>