@vmz/ui 0.1.0 → 0.1.2

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 (66) hide show
  1. package/README.md +8 -0
  2. package/contracts/token-requirements.v0.json +2 -6
  3. package/package.json +18 -2
  4. package/presets/web-surface.v0.json +24 -10
  5. package/src/components/Accordion.vmz +88 -89
  6. package/src/components/Alert.vmz +64 -63
  7. package/src/components/AppShell.vmz +64 -45
  8. package/src/components/Autocomplete.vmz +152 -151
  9. package/src/components/Avatar.vmz +16 -0
  10. package/src/components/Badge.vmz +46 -46
  11. package/src/components/Breadcrumb.vmz +52 -48
  12. package/src/components/BulkActions.vmz +37 -37
  13. package/src/components/Button.vmz +90 -75
  14. package/src/components/Callout.vmz +61 -61
  15. package/src/components/Card.vmz +58 -51
  16. package/src/components/Checkbox.vmz +56 -53
  17. package/src/components/CodeBlock.vmz +51 -51
  18. package/src/components/Collapse.vmz +20 -0
  19. package/src/components/ConsoleShell.vmz +134 -99
  20. package/src/components/Content.vmz +11 -0
  21. package/src/components/DataTable.vmz +197 -196
  22. package/src/components/DatePicker.vmz +613 -536
  23. package/src/components/Dialog.vmz +365 -384
  24. package/src/components/Divider.vmz +19 -0
  25. package/src/components/Drawer.vmz +361 -378
  26. package/src/components/Dropdown.vmz +22 -0
  27. package/src/components/Empty.vmz +36 -36
  28. package/src/components/Field.vmz +69 -40
  29. package/src/components/FilterBar.vmz +15 -15
  30. package/src/components/Flex.vmz +12 -0
  31. package/src/components/Footer.vmz +11 -0
  32. package/src/components/Form.vmz +56 -58
  33. package/src/components/FormItem.vmz +59 -59
  34. package/src/components/Grid.vmz +12 -0
  35. package/src/components/Header.vmz +11 -0
  36. package/src/components/Icon.vmz +86 -0
  37. package/src/components/Layout.vmz +11 -0
  38. package/src/components/Link.vmz +33 -33
  39. package/src/components/List.vmz +96 -96
  40. package/src/components/Menu.vmz +229 -240
  41. package/src/components/Notification.vmz +62 -62
  42. package/src/components/Pagination.vmz +63 -65
  43. package/src/components/Popover.vmz +202 -219
  44. package/src/components/Progress.vmz +18 -0
  45. package/src/components/Prose.vmz +61 -61
  46. package/src/components/QueryForm.vmz +26 -27
  47. package/src/components/RadioGroup.vmz +116 -113
  48. package/src/components/Result.vmz +63 -63
  49. package/src/components/Segmented.vmz +29 -0
  50. package/src/components/Select.vmz +462 -290
  51. package/src/components/Sider.vmz +6 -0
  52. package/src/components/Skeleton.vmz +58 -58
  53. package/src/components/Space.vmz +15 -0
  54. package/src/components/Spinner.vmz +29 -29
  55. package/src/components/Steps.vmz +86 -86
  56. package/src/components/Switch.vmz +86 -88
  57. package/src/components/Table.vmz +116 -114
  58. package/src/components/Tabs.vmz +113 -112
  59. package/src/components/Tag.vmz +8 -0
  60. package/src/components/TextArea.vmz +76 -49
  61. package/src/components/Timeline.vmz +55 -50
  62. package/src/components/Toc.vmz +64 -60
  63. package/src/components/Tooltip.vmz +51 -51
  64. package/src/components/Tree.vmz +184 -190
  65. package/src/components/Typography.vmz +9 -0
  66. package/src/components/Upload.vmz +1130 -1151
@@ -1,83 +1,83 @@
1
1
  <template>
2
2
  <article class="vmz-ui-prose" data-vmz-ui="prose">
3
- <slot />
4
- </article>
3
+ <slot />
4
+ </article>
5
5
  </template>
6
6
 
7
7
  <style>
8
- .vmz-ui-prose {
9
- display: flex;
10
- flex-direction: column;
11
- gap: 1rem;
12
- max-width: 42rem;
13
- color: var(--vmz-text-ink);
14
- font-family: var(--vmz-font-sans);
15
- line-height: 1.65;
16
- }
8
+ .vmz-ui-prose {
9
+ display: flex;
10
+ flex-direction: column;
11
+ gap: 1rem;
12
+ max-width: 42rem;
13
+ color: var(--vmz-text-ink);
14
+ font-family: var(--vmz-font-sans);
15
+ line-height: 1.65;
16
+ }
17
17
 
18
- .vmz-ui-prose :where(h1, h2, h3) {
19
- margin: 0;
20
- font-family: var(--vmz-font-display);
21
- font-weight: 700;
22
- letter-spacing: -0.02em;
23
- line-height: 1.2;
24
- color: var(--vmz-text-ink);
25
- scroll-margin-top: 1.25rem;
26
- }
18
+ .vmz-ui-prose :where(h1, h2, h3) {
19
+ margin: 0;
20
+ font-family: var(--vmz-font-display);
21
+ font-weight: 700;
22
+ letter-spacing: -0.02em;
23
+ line-height: 1.2;
24
+ color: var(--vmz-text-ink);
25
+ scroll-margin-top: 1.25rem;
26
+ }
27
27
 
28
- .vmz-ui-prose :where(h1) {
29
- font-size: clamp(1.85rem, 4vw, 2.35rem);
30
- }
28
+ .vmz-ui-prose :where(h1) {
29
+ font-size: clamp(1.85rem, 4vw, 2.35rem);
30
+ }
31
31
 
32
- .vmz-ui-prose :where(h2) {
33
- font-size: 1.35rem;
34
- margin-top: 0.5rem;
35
- }
32
+ .vmz-ui-prose :where(h2) {
33
+ font-size: 1.35rem;
34
+ margin-top: 0.5rem;
35
+ }
36
36
 
37
- .vmz-ui-prose :where(h3) {
38
- font-size: 1.1rem;
39
- }
37
+ .vmz-ui-prose :where(h3) {
38
+ font-size: 1.1rem;
39
+ }
40
40
 
41
- .vmz-ui-prose :where(p) {
42
- margin: 0;
43
- color: var(--vmz-text-ink);
44
- }
41
+ .vmz-ui-prose :where(p) {
42
+ margin: 0;
43
+ color: var(--vmz-text-ink);
44
+ }
45
45
 
46
- .vmz-ui-prose :where(p.lead) {
47
- font-size: 1.05rem;
48
- color: var(--vmz-text-steel);
49
- }
46
+ .vmz-ui-prose :where(p.lead) {
47
+ font-size: 1.05rem;
48
+ color: var(--vmz-text-steel);
49
+ }
50
50
 
51
- .vmz-ui-prose :where(ul, ol) {
52
- margin: 0;
53
- padding-left: 1.25rem;
54
- color: var(--vmz-text-ink);
55
- }
51
+ .vmz-ui-prose :where(ul, ol) {
52
+ margin: 0;
53
+ padding-left: 1.25rem;
54
+ color: var(--vmz-text-ink);
55
+ }
56
56
 
57
- .vmz-ui-prose :where(li + li) {
58
- margin-top: 0.35rem;
59
- }
57
+ .vmz-ui-prose :where(li + li) {
58
+ margin-top: 0.35rem;
59
+ }
60
60
 
61
- .vmz-ui-prose :where(a) {
62
- color: var(--vmz-action-primary-background);
63
- text-underline-offset: 0.15em;
64
- }
61
+ .vmz-ui-prose :where(a) {
62
+ color: var(--vmz-action-primary-background);
63
+ text-underline-offset: 0.15em;
64
+ }
65
65
 
66
- .vmz-ui-prose :where(a:hover) {
67
- color: var(--vmz-action-primary-hover);
68
- }
66
+ .vmz-ui-prose :where(a:hover) {
67
+ color: var(--vmz-action-primary-hover);
68
+ }
69
69
 
70
- .vmz-ui-prose :where(hr) {
71
- border: 0;
72
- border-top: 1px solid var(--vmz-line-default);
73
- margin: 0.5rem 0;
74
- }
70
+ .vmz-ui-prose :where(hr) {
71
+ border: 0;
72
+ border-top: 1px solid var(--vmz-line-default);
73
+ margin: 0.5rem 0;
74
+ }
75
75
  </style>
76
76
 
77
77
  <script client>
78
78
  /**
79
- * VMZ UI — Prose (Document/Product composition).
80
- * Typography measure for long-form content; values from Style Theme only.
81
- */
79
+ * VMZ UI — Prose (Document/Product composition).
80
+ * Typography measure for long-form content; values from Style Theme only.
81
+ */
82
82
  export default class Prose {}
83
83
  </script>
@@ -1,39 +1,38 @@
1
1
  <template>
2
2
  <form
3
- class="vmz-ui-query-form"
4
- data-vmz-ui="query-form"
5
- data-dense="true"
6
- aria-label={label}
7
- onSubmit={onSubmitGuard}
8
- >
9
- <slot />
10
- </form>
3
+ class="vmz-ui-query-form"
4
+ data-vmz-ui="query-form"
5
+ data-dense="true"
6
+ aria-label={label}
7
+ onSubmit={onSubmitGuard}
8
+ >
9
+ <slot />
10
+ </form>
11
11
  </template>
12
12
 
13
13
  <style>
14
- .vmz-ui-query-form {
15
- display: flex;
16
- flex-wrap: wrap;
17
- align-items: flex-end;
18
- gap: var(--vmz-density-compact-gap);
19
- padding: var(--vmz-density-compact-padding-y) var(--vmz-density-compact-padding-x);
20
- border: 1px solid var(--vmz-action-primary-background);
21
- border-radius: 2px;
22
- }
14
+ .vmz-ui-query-form {
15
+ display: flex;
16
+ flex-wrap: wrap;
17
+ align-items: flex-end;
18
+ gap: var(--vmz-density-compact-gap);
19
+ padding: var(--vmz-density-compact-padding-y) var(--vmz-density-compact-padding-x);
20
+ border: 1px solid var(--vmz-line-default);
21
+ border-radius: var(--vmz-radius-md, 6px);
22
+ }
23
23
  </style>
24
24
 
25
25
  <script client>
26
26
  /**
27
- * VMZ UI — QueryForm (UI5 Console Surface).
28
- * Dense multi-field query landmark; spacing from density.compact.* tokens.
29
- */
27
+ * VMZ UI — QueryForm (UI5 Console Surface).
28
+ * Dense multi-field query landmark; spacing from density.compact.* tokens.
29
+ */
30
30
  export default class QueryForm {
31
- public label: string = 'Query';
32
- public onSubmit: (() => void) | null = null;
33
-
34
- onSubmitGuard(ev) {
35
- if (ev && typeof ev.preventDefault === 'function') ev.preventDefault();
36
- if (typeof this.onSubmit === 'function') this.onSubmit();
37
- }
31
+ public label: string = "Query";
32
+ public onSubmit: (() => void) | null = null;
33
+ onSubmitGuard(ev) {
34
+ if (ev && typeof ev.preventDefault === "function") ev.preventDefault();
35
+ if (typeof this.onSubmit === "function") this.onSubmit();
36
+ }
38
37
  }
39
38
  </script>
@@ -1,135 +1,138 @@
1
1
  <template>
2
2
  <fieldset
3
- class="vmz-ui-radio-group"
4
- data-vmz-ui="radio-group"
5
- data-invalid={invalidAttr}
6
- aria-describedby={describedBy}
7
- disabled={disabled}
8
- >
9
- <legend class="vmz-ui-radio-group__legend">{label}</legend>
10
- <div class="vmz-ui-radio-group__list" role="radiogroup" aria-label={label} onClick={onListClick}>
11
- <label
12
- each={items}
13
- as="item"
14
- key={item.value}
15
- class="vmz-ui-radio-group__option"
16
- for={item.id}
17
- >
18
- <input
19
- id={item.id}
20
- class="vmz-ui-radio-group__input"
21
- type="radio"
22
- name={name}
23
- value={item.value}
24
- checked={value === item.value}
25
- disabled={disabled}
26
- data-vmz-radio={item.value}
27
- />
28
- <span class="vmz-ui-radio-group__text">{item.label}</span>
29
- </label>
30
- </div>
31
- <p if={description} id={descriptionId} class="vmz-ui-radio-group__description">{description}</p>
32
- <p if={error} id={errorId} class="vmz-ui-radio-group__error" role="alert">{error}</p>
33
- </fieldset>
3
+ class="vmz-ui-radio-group"
4
+ data-vmz-ui="radio-group"
5
+ data-invalid={invalidAttr}
6
+ aria-describedby={describedBy}
7
+ disabled={disabled}
8
+ >
9
+ <legend class="vmz-ui-radio-group__legend">{label}</legend>
10
+ <div class="vmz-ui-radio-group__list" role="radiogroup" aria-label={label} onClick={onListClick}>
11
+ <label
12
+ each={items}
13
+ as="item"
14
+ key={item.value}
15
+ class="vmz-ui-radio-group__option"
16
+ for={item.id}
17
+ >
18
+ <input
19
+ id={item.id}
20
+ class="vmz-ui-radio-group__input"
21
+ type="radio"
22
+ name={name}
23
+ value={item.value}
24
+ checked={value === item.value}
25
+ disabled={disabled}
26
+ data-vmz-radio={item.value}
27
+ />
28
+ <span class="vmz-ui-radio-group__text">{item.label}</span>
29
+ </label>
30
+ </div>
31
+ <p if={description} id={descriptionId} class="vmz-ui-radio-group__description">{description}</p>
32
+ <p if={error} id={errorId} class="vmz-ui-radio-group__error" role="alert">{error}</p>
33
+ </fieldset>
34
34
  </template>
35
35
 
36
36
  <style>
37
- .vmz-ui-radio-group {
38
- display: flex;
39
- flex-direction: column;
40
- gap: 0.45rem;
41
- max-width: 28rem;
42
- margin: 0;
43
- padding: 0;
44
- border: 0;
45
- min-width: 0;
46
- }
37
+ .vmz-ui-radio-group {
38
+ display: flex;
39
+ flex-direction: column;
40
+ gap: 0.45rem;
41
+ max-width: 28rem;
42
+ margin: 0;
43
+ padding: 0;
44
+ border: 0;
45
+ min-width: 0;
46
+ }
47
47
 
48
- .vmz-ui-radio-group__legend {
49
- padding: 0;
50
- font: inherit;
51
- font-weight: 600;
52
- }
48
+ .vmz-ui-radio-group__legend {
49
+ padding: 0;
50
+ font: inherit;
51
+ font-weight: 600;
52
+ }
53
53
 
54
- .vmz-ui-radio-group__list {
55
- display: flex;
56
- flex-direction: column;
57
- gap: 0.35rem;
58
- }
54
+ .vmz-ui-radio-group__list {
55
+ display: flex;
56
+ flex-direction: column;
57
+ gap: 0.35rem;
58
+ }
59
59
 
60
- .vmz-ui-radio-group__option {
61
- display: inline-flex;
62
- align-items: center;
63
- gap: 0.45rem;
64
- font: inherit;
65
- cursor: pointer;
66
- }
60
+ .vmz-ui-radio-group__option {
61
+ display: inline-flex;
62
+ align-items: center;
63
+ gap: 0.45rem;
64
+ font: inherit;
65
+ cursor: pointer;
66
+ }
67
67
 
68
- .vmz-ui-radio-group__input {
69
- width: 1rem;
70
- height: 1rem;
71
- accent-color: var(--vmz-action-primary-background);
72
- outline: none;
73
- }
68
+ .vmz-ui-radio-group__input {
69
+ width: 1rem;
70
+ height: 1rem;
71
+ accent-color: var(--vmz-action-primary-background);
72
+ outline: none;
73
+ }
74
74
 
75
- .vmz-ui-radio-group__input:focus-visible {
76
- box-shadow: 0 0 0 2px var(--vmz-focus-ring);
77
- }
75
+ .vmz-ui-radio-group__input:focus-visible {
76
+ box-shadow: 0 0 0 2px var(--vmz-focus-ring);
77
+ }
78
78
 
79
- .vmz-ui-radio-group__input:disabled {
80
- opacity: 0.55;
81
- cursor: not-allowed;
82
- }
79
+ .vmz-ui-radio-group__input:disabled {
80
+ opacity: 0.55;
81
+ cursor: not-allowed;
82
+ }
83
83
 
84
- .vmz-ui-radio-group__text {
85
- font-weight: 600;
86
- }
84
+ .vmz-ui-radio-group__text {
85
+ font-weight: 600;
86
+ }
87
87
 
88
- .vmz-ui-radio-group__description {
89
- margin: 0;
90
- opacity: 0.75;
91
- font-size: 0.9em;
92
- }
88
+ .vmz-ui-radio-group__description {
89
+ margin: 0;
90
+ opacity: 0.75;
91
+ font-size: 0.9em;
92
+ }
93
93
 
94
- .vmz-ui-radio-group__error {
95
- margin: 0;
96
- color: var(--vmz-status-danger-foreground);
97
- font-size: 0.9em;
98
- }
94
+ .vmz-ui-radio-group__error {
95
+ margin: 0;
96
+ color: var(--vmz-status-danger-foreground);
97
+ font-size: 0.9em;
98
+ }
99
99
 
100
- .vmz-ui-radio-group[data-invalid='true'] .vmz-ui-radio-group__legend {
101
- color: var(--vmz-status-danger-foreground);
102
- }
100
+ .vmz-ui-radio-group[data-invalid='true'] .vmz-ui-radio-group__legend {
101
+ color: var(--vmz-status-danger-foreground);
102
+ }
103
103
  </style>
104
104
 
105
105
  <script client>
106
106
  /**
107
- * VMZ UI — RadioGroup.
108
- * Parent owns selected value; click path updates via onChange (live prop remains authoritative).
109
- */
107
+ * VMZ UI — RadioGroup.
108
+ * Parent owns selected value; click path updates via onChange (live prop remains authoritative).
109
+ */
110
110
  export default class RadioGroup {
111
- public label: string = '';
112
- public description: string = '';
113
- public error: string = '';
114
- public name: string = 'vmz-radio';
115
- public value: string = '';
116
- public items: Array<{ id: string; value: string; label: string }> = [];
117
- public disabled: boolean = false;
118
- public invalidAttr: string = 'false';
119
- public descriptionId: string = 'vmz-radio-desc';
120
- public errorId: string = 'vmz-radio-err';
121
- public describedBy: string = '';
122
- public onChange: ((value: string) => void) | null = null;
123
-
124
- onListClick(ev) {
125
- if (this.disabled) return;
126
- const t = ev && ev.target;
127
- if (!t || typeof t.closest !== 'function') return;
128
- const input = t.closest('input[data-vmz-radio]');
129
- if (!input) return;
130
- const next = input.getAttribute('data-vmz-radio') || input.value || '';
131
- if (!next || next === this.value) return;
132
- if (typeof this.onChange === 'function') this.onChange(next);
133
- }
111
+ public label: string = "";
112
+ public description: string = "";
113
+ public error: string = "";
114
+ public name: string = "vmz-radio";
115
+ public value: string = "";
116
+ public items: Array<{
117
+ id: string;
118
+ value: string;
119
+ label: string;
120
+ }> = [];
121
+ public disabled: boolean = false;
122
+ public invalidAttr: string = "false";
123
+ public descriptionId: string = "vmz-radio-desc";
124
+ public errorId: string = "vmz-radio-err";
125
+ public describedBy: string = "";
126
+ public onChange: ((value: string) => void) | null = null;
127
+ onListClick(ev) {
128
+ if (this.disabled) return;
129
+ const t = ev && ev.target;
130
+ if (!t || typeof t.closest !== "function") return;
131
+ const input = t.closest("input[data-vmz-radio]");
132
+ if (!input) return;
133
+ const next = input.getAttribute("data-vmz-radio") || input.value || "";
134
+ if (!next || next === this.value) return;
135
+ if (typeof this.onChange === "function") this.onChange(next);
136
+ }
134
137
  }
135
138
  </script>
@@ -1,84 +1,84 @@
1
1
  <template>
2
2
  <section
3
- class="vmz-ui-result"
4
- data-vmz-ui="result"
5
- data-status={status}
6
- >
7
- <p class="vmz-ui-result__title">{title}</p>
8
- <p if={description} class="vmz-ui-result__description">{description}</p>
9
- <div class="vmz-ui-result__actions">
10
- <slot />
11
- </div>
12
- </section>
3
+ class="vmz-ui-result"
4
+ data-vmz-ui="result"
5
+ data-status={status}
6
+ >
7
+ <p class="vmz-ui-result__title">{title}</p>
8
+ <p if={description} class="vmz-ui-result__description">{description}</p>
9
+ <div class="vmz-ui-result__actions">
10
+ <slot />
11
+ </div>
12
+ </section>
13
13
  </template>
14
14
 
15
15
  <style>
16
- .vmz-ui-result {
17
- display: flex;
18
- flex-direction: column;
19
- align-items: flex-start;
20
- gap: var(--vmz-density-control-gap);
21
- padding: calc(var(--vmz-density-control-padding-y) * 1.5) var(--vmz-density-control-padding-x);
22
- border: 1px solid var(--vmz-status-info-accent);
23
- border-radius: 2px;
24
- color: var(--vmz-status-info-foreground);
25
- }
16
+ .vmz-ui-result {
17
+ display: flex;
18
+ flex-direction: column;
19
+ align-items: flex-start;
20
+ gap: var(--vmz-density-control-gap);
21
+ padding: calc(var(--vmz-density-control-padding-y) * 1.5) var(--vmz-density-control-padding-x);
22
+ border: 1px solid var(--vmz-status-info-accent);
23
+ border-radius: var(--vmz-radius-md, 6px);
24
+ color: var(--vmz-status-info-foreground);
25
+ }
26
26
 
27
- .vmz-ui-result[data-status='info'] {
28
- border-color: var(--vmz-status-info-accent);
29
- color: var(--vmz-status-info-foreground);
30
- }
27
+ .vmz-ui-result[data-status='info'] {
28
+ border-color: var(--vmz-status-info-accent);
29
+ color: var(--vmz-status-info-foreground);
30
+ }
31
31
 
32
- .vmz-ui-result[data-status='success'] {
33
- border-color: var(--vmz-status-success-accent);
34
- color: var(--vmz-status-success-foreground);
35
- }
32
+ .vmz-ui-result[data-status='success'] {
33
+ border-color: var(--vmz-status-success-accent);
34
+ color: var(--vmz-status-success-foreground);
35
+ }
36
36
 
37
- .vmz-ui-result[data-status='warning'] {
38
- border-color: var(--vmz-status-warning-accent);
39
- color: var(--vmz-status-warning-foreground);
40
- }
37
+ .vmz-ui-result[data-status='warning'] {
38
+ border-color: var(--vmz-status-warning-accent);
39
+ color: var(--vmz-status-warning-foreground);
40
+ }
41
41
 
42
- .vmz-ui-result[data-status='danger'] {
43
- border-color: var(--vmz-status-danger-accent);
44
- color: var(--vmz-status-danger-foreground);
45
- }
42
+ .vmz-ui-result[data-status='danger'] {
43
+ border-color: var(--vmz-status-danger-accent);
44
+ color: var(--vmz-status-danger-foreground);
45
+ }
46
46
 
47
- :where([data-density='compact']) .vmz-ui-result {
48
- gap: var(--vmz-density-compact-gap);
49
- padding: var(--vmz-density-compact-padding-y) var(--vmz-density-compact-padding-x);
50
- }
47
+ :where([data-density='compact']) .vmz-ui-result {
48
+ gap: var(--vmz-density-compact-gap);
49
+ padding: var(--vmz-density-compact-padding-y) var(--vmz-density-compact-padding-x);
50
+ }
51
51
 
52
- .vmz-ui-result__title {
53
- margin: 0;
54
- font-size: 1.15rem;
55
- font-weight: 700;
56
- }
52
+ .vmz-ui-result__title {
53
+ margin: 0;
54
+ font-size: 1.15rem;
55
+ font-weight: 700;
56
+ }
57
57
 
58
- .vmz-ui-result__description {
59
- margin: 0;
60
- opacity: 0.9;
61
- }
58
+ .vmz-ui-result__description {
59
+ margin: 0;
60
+ opacity: 0.9;
61
+ }
62
62
 
63
- .vmz-ui-result__actions {
64
- display: flex;
65
- flex-wrap: wrap;
66
- gap: 0.5rem;
67
- }
63
+ .vmz-ui-result__actions {
64
+ display: flex;
65
+ flex-wrap: wrap;
66
+ gap: 0.5rem;
67
+ }
68
68
 
69
- .vmz-ui-result__actions:empty {
70
- display: none;
71
- }
69
+ .vmz-ui-result__actions:empty {
70
+ display: none;
71
+ }
72
72
  </style>
73
73
 
74
74
  <script client>
75
75
  /**
76
- * VMZ UI — Result (UI4 Commercial Surface).
77
- * Outcome block for success/error flows; status → status.* tokens.
78
- */
76
+ * VMZ UI — Result (UI4 Commercial Surface).
77
+ * Outcome block for success/error flows; status → status.* tokens.
78
+ */
79
79
  export default class Result {
80
- public title: string = '';
81
- public description: string = '';
82
- public status: string = 'info';
80
+ public title: string = "";
81
+ public description: string = "";
82
+ public status: string = "info";
83
83
  }
84
84
  </script>
@@ -0,0 +1,29 @@
1
+ <template>
2
+ <div class="vmz-ui-segmented" data-vmz-ui="segmented" role="group" aria-label={label}>
3
+ <button
4
+ each={options}
5
+ as="opt"
6
+ key={opt.value}
7
+ type="button"
8
+ aria-pressed={opt.value === value ? 'true' : 'false'}
9
+ onClick={() => onPick(opt.value)}
10
+ >{opt.label}</button>
11
+ </div>
12
+ </template>
13
+ <style>
14
+ .vmz-ui-segmented{display:inline-flex;max-width:100%;padding:.2rem;border-radius:var(--vmz-radius-md,6px);background:var(--vmz-surface-mist);overflow-x:auto}
15
+ .vmz-ui-segmented button{min-height:2rem;padding:.3rem .75rem;border:0;border-radius:calc(var(--vmz-radius-md,6px) - 2px);background:transparent;color:var(--vmz-text-steel);font:inherit;font-size:.875rem;font-weight:550;white-space:nowrap;cursor:pointer}
16
+ .vmz-ui-segmented button[aria-pressed='true']{background:var(--vmz-surface-paper);color:var(--vmz-text-ink);box-shadow:0 1px 3px rgba(0,0,0,.1)}
17
+ .vmz-ui-segmented button:focus-visible{outline:2px solid var(--vmz-focus-ring);outline-offset:-2px}
18
+ </style>
19
+ <script client>
20
+ export default class Segmented {
21
+ public label: string = 'Segments';
22
+ public value: string = '';
23
+ public options: Array<{ value: string; label: string }> = [];
24
+ public onChange: ((value: string) => void) | null = null;
25
+ onPick(next: string) {
26
+ if (typeof this.onChange === 'function') this.onChange(next);
27
+ }
28
+ }
29
+ </script>