@vmz/ui 0.3.4 → 0.3.6

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 (43) hide show
  1. package/README.md +51 -51
  2. package/package.json +2 -2
  3. package/presets/web-surface.v0.json +19 -7
  4. package/src/components/Accordion.vmz +94 -94
  5. package/src/components/AppShell.vmz +77 -33
  6. package/src/components/Autocomplete.vmz +154 -154
  7. package/src/components/Badge.vmz +70 -70
  8. package/src/components/Breadcrumb.vmz +72 -72
  9. package/src/components/BulkActions.vmz +51 -51
  10. package/src/components/Button.vmz +211 -192
  11. package/src/components/Callout.vmz +77 -77
  12. package/src/components/Card.vmz +120 -106
  13. package/src/components/Checkbox.vmz +55 -55
  14. package/src/components/CodeBlock.vmz +77 -18
  15. package/src/components/ConsoleShell.vmz +251 -251
  16. package/src/components/DataTable.vmz +194 -194
  17. package/src/components/DatePicker.vmz +674 -674
  18. package/src/components/Dialog.vmz +10 -7
  19. package/src/components/Drawer.vmz +427 -427
  20. package/src/components/Dropdown.vmz +135 -16
  21. package/src/components/Empty.vmz +54 -54
  22. package/src/components/Field.vmz +115 -115
  23. package/src/components/FormItem.vmz +79 -79
  24. package/src/components/Link.vmz +34 -4
  25. package/src/components/List.vmz +102 -102
  26. package/src/components/Menu.vmz +243 -243
  27. package/src/components/Pagination.vmz +69 -69
  28. package/src/components/Popover.vmz +223 -223
  29. package/src/components/Prose.vmz +81 -81
  30. package/src/components/RadioGroup.vmz +124 -124
  31. package/src/components/Segmented.vmz +51 -51
  32. package/src/components/Select.vmz +533 -533
  33. package/src/components/Steps.vmz +103 -103
  34. package/src/components/Switch.vmz +98 -98
  35. package/src/components/Table.vmz +165 -133
  36. package/src/components/Tabs.vmz +110 -110
  37. package/src/components/Tag.vmz +43 -40
  38. package/src/components/TextArea.vmz +118 -118
  39. package/src/components/Timeline.vmz +76 -76
  40. package/src/components/Toc.vmz +74 -74
  41. package/src/components/Tooltip.vmz +58 -58
  42. package/src/components/Tree.vmz +191 -191
  43. package/src/components/Upload.vmz +1289 -1289
@@ -1,154 +1,154 @@
1
- <template>
2
- <div data-vmz-ui="autocomplete" :data-invalid="invalidAttr" :data-open="openAttr" class="vmz-ui-autocomplete">
3
- <label v-if="label" :for="controlId" class="vmz-ui-autocomplete__label">
4
- {{ label }}
5
- </label>
6
- <input :id="controlId" type="text" role="combobox" autocomplete="off" aria-autocomplete="list" :aria-expanded="openAttr" :aria-controls="listId" :aria-invalid="error ? 'true' : 'false'" :aria-describedby="describedBy" :value="value" :disabled="disabled" @input="onDomInput" :onKeyDown="onKeyDown" class="vmz-ui-autocomplete__control" />
7
- <ul v-if="listOpen" :id="listId" role="listbox" data-vmz-autocomplete="list" @click="onListClick" class="vmz-ui-autocomplete__list">
8
- <li v-for="opt in options" :key="opt.value" role="option" :data-vmz-option="opt.value" tabindex="-1" class="vmz-ui-autocomplete__option">
9
- {{ opt.label }}
10
- </li>
11
- </ul>
12
- <p v-if="showEmpty" data-vmz-autocomplete="empty" class="vmz-ui-autocomplete__empty">
13
- {{ emptyText }}
14
- </p>
15
- <p v-if="description" :id="descriptionId" class="vmz-ui-autocomplete__description">
16
- {{ description }}
17
- </p>
18
- <p v-if="error" :id="errorId" role="alert" class="vmz-ui-autocomplete__error">
19
- {{ error }}
20
- </p>
21
- </div>
22
- </template>
23
- <style>
24
- .vmz-ui-autocomplete {
25
- position: relative;
26
- display: flex;
27
- flex-direction: column;
28
- gap: 0.35rem;
29
- max-width: 28rem;
30
- }
31
-
32
- .vmz-ui-autocomplete__label {
33
- font: inherit;
34
- font-weight: 600;
35
- }
36
-
37
- .vmz-ui-autocomplete__control {
38
- font: inherit;
39
- padding: var(--vmz-density-control-padding-y) var(--vmz-density-control-padding-x);
40
- border: 1px solid var(--vmz-line-default);
41
- border-radius: var(--vmz-radius-md, 6px);
42
- background: transparent;
43
- color: inherit;
44
- outline: none;
45
- }
46
-
47
- .vmz-ui-autocomplete[data-invalid="true"] .vmz-ui-autocomplete__control {
48
- border-color: var(--vmz-status-danger-accent);
49
- }
50
-
51
- .vmz-ui-autocomplete__control:focus-visible {
52
- box-shadow: 0 0 0 2px var(--vmz-focus-ring);
53
- }
54
-
55
- .vmz-ui-autocomplete__control:disabled {
56
- opacity: 0.55;
57
- cursor: not-allowed;
58
- }
59
-
60
- .vmz-ui-autocomplete__list {
61
- list-style: none;
62
- margin: 0;
63
- padding: 0.25rem 0;
64
- border: 1px solid var(--vmz-line-default);
65
- border-radius: var(--vmz-radius-md, 6px);
66
- background: var(--vmz-surface-paper);
67
- max-height: 12rem;
68
- overflow: auto;
69
- }
70
-
71
- .vmz-ui-autocomplete__option {
72
- margin: 0;
73
- padding: 0.45rem 0.75rem;
74
- cursor: pointer;
75
- font-weight: 600;
76
- color: var(--vmz-text-ink);
77
- }
78
-
79
- .vmz-ui-autocomplete__option:hover,
80
- .vmz-ui-autocomplete__option:focus {
81
- background: var(--vmz-surface-mist);
82
- outline: none;
83
- }
84
-
85
- .vmz-ui-autocomplete__empty {
86
- margin: 0;
87
- color: var(--vmz-text-steel);
88
- font-size: 0.9em;
89
- }
90
-
91
- .vmz-ui-autocomplete__description {
92
- margin: 0;
93
- opacity: 0.75;
94
- font-size: 0.9em;
95
- }
96
-
97
- .vmz-ui-autocomplete__error {
98
- margin: 0;
99
- color: var(--vmz-status-danger-foreground);
100
- font-size: 0.9em;
101
- }
102
- </style>
103
- <script client>
104
- /**
105
- * VMZ UI — Autocomplete.
106
- * Parent owns value, listOpen, and filtered options — no parallel query/store.
107
- * Selection notifies via onSelect(value); Escape closes via onClose.
108
- */
109
- export default class Autocomplete {
110
- public label: string = "";
111
- public description: string = "";
112
- public error: string = "";
113
- public value: string = "";
114
- public options: Array<{
115
- value: string;
116
- label: string;
117
- }> = [];
118
- public listOpen: boolean = false;
119
- public openAttr: string = "false";
120
- public showEmpty: boolean = false;
121
- public emptyText: string = "No matches";
122
- public disabled: boolean = false;
123
- public invalidAttr: string = "false";
124
- public controlId: string = "vmz-autocomplete";
125
- public listId: string = "vmz-autocomplete-list";
126
- public descriptionId: string = "vmz-autocomplete-desc";
127
- public errorId: string = "vmz-autocomplete-err";
128
- public describedBy: string = "";
129
- public onInput: ((e: Event) => void) | null = null;
130
- public onSelect: ((value: string) => void) | null = null;
131
- public onClose: (() => void) | null = null;
132
- onDomInput(e: Event) {
133
- this.emit("input", e);
134
- if (typeof this.onInput === "function") this.onInput(e);
135
- }
136
- onListClick(ev) {
137
- if (this.disabled) return;
138
- const t = ev && ev.target;
139
- if (!t || typeof t.closest !== "function") return;
140
- const opt = t.closest("[data-vmz-option]");
141
- if (!opt) return;
142
- const next = opt.getAttribute("data-vmz-option") || "";
143
- if (!next) return;
144
- this.emit("select", next);
145
- if (typeof this.onSelect === "function") this.onSelect(next);
146
- }
147
- onKeyDown(ev) {
148
- if (!ev || ev.key !== "Escape") return;
149
- ev.preventDefault();
150
- this.emit("close");
151
- if (typeof this.onClose === "function") this.onClose();
152
- }
153
- }
154
- </script>
1
+ <template>
2
+ <div data-vmz-ui="autocomplete" :data-invalid="invalidAttr" :data-open="openAttr" class="vmz-ui-autocomplete">
3
+ <label v-if="label" :for="controlId" class="vmz-ui-autocomplete__label">
4
+ {{ label }}
5
+ </label>
6
+ <input :id="controlId" type="text" role="combobox" autocomplete="off" aria-autocomplete="list" :aria-expanded="openAttr" :aria-controls="listId" :aria-invalid="error ? 'true' : 'false'" :aria-describedby="describedBy" :value="value" :disabled="disabled" @input="onDomInput" :onKeyDown="onKeyDown" class="vmz-ui-autocomplete__control" />
7
+ <ul v-if="listOpen" :id="listId" role="listbox" data-vmz-autocomplete="list" @click="onListClick" class="vmz-ui-autocomplete__list">
8
+ <li v-for="opt in options" :key="opt.value" role="option" :data-vmz-option="opt.value" tabindex="-1" class="vmz-ui-autocomplete__option">
9
+ {{ opt.label }}
10
+ </li>
11
+ </ul>
12
+ <p v-if="showEmpty" data-vmz-autocomplete="empty" class="vmz-ui-autocomplete__empty">
13
+ {{ emptyText }}
14
+ </p>
15
+ <p v-if="description" :id="descriptionId" class="vmz-ui-autocomplete__description">
16
+ {{ description }}
17
+ </p>
18
+ <p v-if="error" :id="errorId" role="alert" class="vmz-ui-autocomplete__error">
19
+ {{ error }}
20
+ </p>
21
+ </div>
22
+ </template>
23
+ <style>
24
+ .vmz-ui-autocomplete {
25
+ position: relative;
26
+ display: flex;
27
+ flex-direction: column;
28
+ gap: 0.375rem;
29
+ max-width: 28rem;
30
+ }
31
+
32
+ .vmz-ui-autocomplete__label {
33
+ font: inherit;
34
+ font-weight: 600;
35
+ }
36
+
37
+ .vmz-ui-autocomplete__control {
38
+ font: inherit;
39
+ padding: var(--vmz-density-control-padding-y) var(--vmz-density-control-padding-x);
40
+ border: 1px solid var(--vmz-line-default);
41
+ border-radius: var(--vmz-radius-md, 6px);
42
+ background: transparent;
43
+ color: inherit;
44
+ outline: none;
45
+ }
46
+
47
+ .vmz-ui-autocomplete[data-invalid="true"] .vmz-ui-autocomplete__control {
48
+ border-color: var(--vmz-status-danger-accent);
49
+ }
50
+
51
+ .vmz-ui-autocomplete__control:focus-visible {
52
+ box-shadow: 0 0 0 3px var(--vmz-focus-ring);
53
+ }
54
+
55
+ .vmz-ui-autocomplete__control:disabled {
56
+ opacity: 0.55;
57
+ cursor: not-allowed;
58
+ }
59
+
60
+ .vmz-ui-autocomplete__list {
61
+ list-style: none;
62
+ margin: 0;
63
+ padding: 0.25rem 0;
64
+ border: 1px solid var(--vmz-line-default);
65
+ border-radius: var(--vmz-radius-md, 6px);
66
+ background: var(--vmz-surface-paper);
67
+ max-height: 12rem;
68
+ overflow: auto;
69
+ }
70
+
71
+ .vmz-ui-autocomplete__option {
72
+ margin: 0;
73
+ padding: 0.5rem 0.75rem;
74
+ cursor: pointer;
75
+ font-weight: 600;
76
+ color: var(--vmz-text-ink);
77
+ }
78
+
79
+ .vmz-ui-autocomplete__option:hover,
80
+ .vmz-ui-autocomplete__option:focus {
81
+ background: var(--vmz-surface-mist);
82
+ outline: none;
83
+ }
84
+
85
+ .vmz-ui-autocomplete__empty {
86
+ margin: 0;
87
+ color: var(--vmz-text-steel);
88
+ font-size: 0.9em;
89
+ }
90
+
91
+ .vmz-ui-autocomplete__description {
92
+ margin: 0;
93
+ opacity: 0.75;
94
+ font-size: 0.9em;
95
+ }
96
+
97
+ .vmz-ui-autocomplete__error {
98
+ margin: 0;
99
+ color: var(--vmz-status-danger-foreground);
100
+ font-size: 0.9em;
101
+ }
102
+ </style>
103
+ <script client>
104
+ /**
105
+ * VMZ UI — Autocomplete.
106
+ * Parent owns value, listOpen, and filtered options — no parallel query/store.
107
+ * Selection notifies via onSelect(value); Escape closes via onClose.
108
+ */
109
+ export default class Autocomplete {
110
+ public label: string = "";
111
+ public description: string = "";
112
+ public error: string = "";
113
+ public value: string = "";
114
+ public options: Array<{
115
+ value: string;
116
+ label: string;
117
+ }> = [];
118
+ public listOpen: boolean = false;
119
+ public openAttr: string = "false";
120
+ public showEmpty: boolean = false;
121
+ public emptyText: string = "No matches";
122
+ public disabled: boolean = false;
123
+ public invalidAttr: string = "false";
124
+ public controlId: string = "vmz-autocomplete";
125
+ public listId: string = "vmz-autocomplete-list";
126
+ public descriptionId: string = "vmz-autocomplete-desc";
127
+ public errorId: string = "vmz-autocomplete-err";
128
+ public describedBy: string = "";
129
+ public onInput: ((e: Event) => void) | null = null;
130
+ public onSelect: ((value: string) => void) | null = null;
131
+ public onClose: (() => void) | null = null;
132
+ onDomInput(e: Event) {
133
+ this.emit("input", e);
134
+ if (typeof this.onInput === "function") this.onInput(e);
135
+ }
136
+ onListClick(ev) {
137
+ if (this.disabled) return;
138
+ const t = ev && ev.target;
139
+ if (!t || typeof t.closest !== "function") return;
140
+ const opt = t.closest("[data-vmz-option]");
141
+ if (!opt) return;
142
+ const next = opt.getAttribute("data-vmz-option") || "";
143
+ if (!next) return;
144
+ this.emit("select", next);
145
+ if (typeof this.onSelect === "function") this.onSelect(next);
146
+ }
147
+ onKeyDown(ev) {
148
+ if (!ev || ev.key !== "Escape") return;
149
+ ev.preventDefault();
150
+ this.emit("close");
151
+ if (typeof this.onClose === "function") this.onClose();
152
+ }
153
+ }
154
+ </script>
@@ -1,70 +1,70 @@
1
- <template>
2
- <span data-vmz-ui="badge" :data-tone="tone" class="vmz-ui-badge">
3
- <slot />
4
- </span>
5
- </template>
6
- <style>
7
- .vmz-ui-badge {
8
- display: inline-flex;
9
- align-items: center;
10
- gap: 0.25rem;
11
- padding: 0.15rem 0.45rem;
12
- border: 1px solid var(--vmz-line-default);
13
- border-radius: var(--vmz-radius-md, 6px);
14
- font-size: 0.75rem;
15
- font-weight: 700;
16
- letter-spacing: 0.04em;
17
- text-transform: uppercase;
18
- line-height: 1.2;
19
- background: var(--vmz-surface-mist);
20
- color: var(--vmz-text-ink);
21
- }
22
-
23
- .vmz-ui-badge[data-tone="brand"] {
24
- border-color: color-mix(
25
- in srgb,
26
- var(--vmz-action-primary-background) 35%,
27
- var(--vmz-line-default)
28
- );
29
- background: color-mix(
30
- in srgb,
31
- var(--vmz-action-primary-background) 12%,
32
- var(--vmz-surface-paper)
33
- );
34
- color: var(--vmz-action-primary-active);
35
- }
36
-
37
- .vmz-ui-badge[data-tone="info"] {
38
- border-color: var(--vmz-status-info-accent);
39
- background: color-mix(in srgb, var(--vmz-status-info-accent) 12%, var(--vmz-surface-paper));
40
- color: var(--vmz-status-info-foreground);
41
- }
42
-
43
- .vmz-ui-badge[data-tone="success"] {
44
- border-color: var(--vmz-status-success-accent);
45
- background: color-mix(in srgb, var(--vmz-status-success-accent) 12%, var(--vmz-surface-paper));
46
- color: var(--vmz-status-success-foreground);
47
- }
48
-
49
- .vmz-ui-badge[data-tone="warning"] {
50
- border-color: var(--vmz-status-warning-accent);
51
- background: color-mix(in srgb, var(--vmz-status-warning-accent) 12%, var(--vmz-surface-paper));
52
- color: var(--vmz-status-warning-foreground);
53
- }
54
-
55
- .vmz-ui-badge[data-tone="danger"] {
56
- border-color: var(--vmz-status-danger-accent);
57
- background: color-mix(in srgb, var(--vmz-status-danger-accent) 12%, var(--vmz-surface-paper));
58
- color: var(--vmz-status-danger-foreground);
59
- }
60
- </style>
61
- <script client>
62
- /**
63
- * VMZ UI — Badge (Foundation).
64
- * Compact status / label chip; tones share status.* + action tokens.
65
- */
66
- export default class Badge {
67
- static __vmzHostBox = "contents";
68
- public tone: string = "brand";
69
- }
70
- </script>
1
+ <template>
2
+ <span data-vmz-ui="badge" :data-tone="tone" class="vmz-ui-badge">
3
+ <slot />
4
+ </span>
5
+ </template>
6
+ <style>
7
+ .vmz-ui-badge {
8
+ display: inline-flex;
9
+ align-items: center;
10
+ gap: 0.25rem;
11
+ padding: 0.125rem 0.5rem;
12
+ border: 1px solid var(--vmz-line-default);
13
+ border-radius: var(--vmz-radius-md, 6px);
14
+ font-size: 0.75rem;
15
+ font-weight: 700;
16
+ letter-spacing: 0.04em;
17
+ text-transform: uppercase;
18
+ line-height: 1.2;
19
+ background: var(--vmz-surface-mist);
20
+ color: var(--vmz-text-ink);
21
+ }
22
+
23
+ .vmz-ui-badge[data-tone="brand"] {
24
+ border-color: color-mix(
25
+ in srgb,
26
+ var(--vmz-action-primary-background) 35%,
27
+ var(--vmz-line-default)
28
+ );
29
+ background: color-mix(
30
+ in srgb,
31
+ var(--vmz-action-primary-background) 12%,
32
+ var(--vmz-surface-paper)
33
+ );
34
+ color: var(--vmz-action-primary-active);
35
+ }
36
+
37
+ .vmz-ui-badge[data-tone="info"] {
38
+ border-color: var(--vmz-status-info-accent);
39
+ background: color-mix(in srgb, var(--vmz-status-info-accent) 12%, var(--vmz-surface-paper));
40
+ color: var(--vmz-status-info-foreground);
41
+ }
42
+
43
+ .vmz-ui-badge[data-tone="success"] {
44
+ border-color: var(--vmz-status-success-accent);
45
+ background: color-mix(in srgb, var(--vmz-status-success-accent) 12%, var(--vmz-surface-paper));
46
+ color: var(--vmz-status-success-foreground);
47
+ }
48
+
49
+ .vmz-ui-badge[data-tone="warning"] {
50
+ border-color: var(--vmz-status-warning-accent);
51
+ background: color-mix(in srgb, var(--vmz-status-warning-accent) 12%, var(--vmz-surface-paper));
52
+ color: var(--vmz-status-warning-foreground);
53
+ }
54
+
55
+ .vmz-ui-badge[data-tone="danger"] {
56
+ border-color: var(--vmz-status-danger-accent);
57
+ background: color-mix(in srgb, var(--vmz-status-danger-accent) 12%, var(--vmz-surface-paper));
58
+ color: var(--vmz-status-danger-foreground);
59
+ }
60
+ </style>
61
+ <script client>
62
+ /**
63
+ * VMZ UI — Badge (Foundation).
64
+ * Compact status / label chip; tones share status.* + action tokens.
65
+ */
66
+ export default class Badge {
67
+ static __vmzHostBox = "contents";
68
+ public tone: string = "brand";
69
+ }
70
+ </script>
@@ -1,72 +1,72 @@
1
- <template>
2
- <nav data-vmz-ui="breadcrumb" :aria-label="label" class="vmz-ui-breadcrumb">
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">
5
- <a v-if="item.href" :href="item.href" class="vmz-ui-breadcrumb__link">
6
- {{ item.title }}
7
- </a>
8
- <span v-if="!item.href" aria-current="page" class="vmz-ui-breadcrumb__current">
9
- {{ item.title }}
10
- </span>
11
- </li>
12
- </ol>
13
- </nav>
14
- </template>
15
- <style>
16
- .vmz-ui-breadcrumb {
17
- font: inherit;
18
- }
19
-
20
- .vmz-ui-breadcrumb__list {
21
- display: flex;
22
- flex-wrap: wrap;
23
- gap: 0.35rem 0.55rem;
24
- margin: 0;
25
- padding: 0;
26
- list-style: none;
27
- align-items: center;
28
- }
29
-
30
- .vmz-ui-breadcrumb__item {
31
- display: inline-flex;
32
- align-items: center;
33
- gap: 0.55rem;
34
- font-weight: 600;
35
- }
36
-
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
- }
43
-
44
- .vmz-ui-breadcrumb__link {
45
- color: var(--vmz-action-primary-background);
46
- text-decoration: none;
47
- }
48
-
49
- .vmz-ui-breadcrumb__link:focus-visible {
50
- outline: none;
51
- box-shadow: 0 0 0 2px var(--vmz-focus-ring);
52
- }
53
-
54
- .vmz-ui-breadcrumb__current {
55
- color: var(--vmz-action-primary-active);
56
- }
57
- </style>
58
- <script client>
59
- /**
60
- * VMZ UI — Breadcrumb (UI5 Console Surface).
61
- * Parent owns items; last crumb typically has no href (current page).
62
- */
63
- export default class Breadcrumb {
64
- public label: string = "Breadcrumb";
65
- /** @type {{ id: string, title: string, href?: string }[]} */
66
- public items: {
67
- id: string;
68
- title: string;
69
- href?: string;
70
- }[] = [];
71
- }
72
- </script>
1
+ <template>
2
+ <nav data-vmz-ui="breadcrumb" :aria-label="label" class="vmz-ui-breadcrumb">
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">
5
+ <a v-if="item.href" :href="item.href" class="vmz-ui-breadcrumb__link">
6
+ {{ item.title }}
7
+ </a>
8
+ <span v-if="!item.href" aria-current="page" class="vmz-ui-breadcrumb__current">
9
+ {{ item.title }}
10
+ </span>
11
+ </li>
12
+ </ol>
13
+ </nav>
14
+ </template>
15
+ <style>
16
+ .vmz-ui-breadcrumb {
17
+ font: inherit;
18
+ }
19
+
20
+ .vmz-ui-breadcrumb__list {
21
+ display: flex;
22
+ flex-wrap: wrap;
23
+ gap: 0.375rem 0.5rem;
24
+ margin: 0;
25
+ padding: 0;
26
+ list-style: none;
27
+ align-items: center;
28
+ }
29
+
30
+ .vmz-ui-breadcrumb__item {
31
+ display: inline-flex;
32
+ align-items: center;
33
+ gap: 0.5rem;
34
+ font-weight: 600;
35
+ }
36
+
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
+ }
43
+
44
+ .vmz-ui-breadcrumb__link {
45
+ color: var(--vmz-action-primary-background);
46
+ text-decoration: none;
47
+ }
48
+
49
+ .vmz-ui-breadcrumb__link:focus-visible {
50
+ outline: none;
51
+ box-shadow: 0 0 0 3px var(--vmz-focus-ring);
52
+ }
53
+
54
+ .vmz-ui-breadcrumb__current {
55
+ color: var(--vmz-action-primary-active);
56
+ }
57
+ </style>
58
+ <script client>
59
+ /**
60
+ * VMZ UI — Breadcrumb (UI5 Console Surface).
61
+ * Parent owns items; last crumb typically has no href (current page).
62
+ */
63
+ export default class Breadcrumb {
64
+ public label: string = "Breadcrumb";
65
+ /** @type {{ id: string, title: string, href?: string }[]} */
66
+ public items: {
67
+ id: string;
68
+ title: string;
69
+ href?: string;
70
+ }[] = [];
71
+ }
72
+ </script>