@lmvz-ds/components 0.25.0 → 0.27.0

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 (158) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/cjs/{reactive-controller-host-DrtMkMd7.js → aria-validation-controller-BMV2tv9-.js} +0 -41
  3. package/cjs/{ds.constants-DSnxZ3ia.js → ds.constants-8fh6ItAF.js} +1 -1
  4. package/cjs/index.cjs.js +196 -2
  5. package/cjs/list-keyboard-controller-CzZdPBeH.js +173 -0
  6. package/cjs/lmvz-button-group.cjs.entry.js +183 -0
  7. package/cjs/lmvz-button_2.cjs.entry.js +199 -0
  8. package/cjs/lmvz-card.cjs.entry.js +1 -1
  9. package/cjs/lmvz-checkbox.cjs.entry.js +8 -4
  10. package/cjs/lmvz-chip.cjs.entry.js +5 -4
  11. package/cjs/lmvz-components.cjs.js +1 -1
  12. package/cjs/lmvz-header_2.cjs.entry.js +7 -51
  13. package/cjs/lmvz-input.cjs.entry.js +3 -2
  14. package/cjs/lmvz-menuitem.cjs.entry.js +4 -3
  15. package/cjs/lmvz-modal.cjs.entry.js +4 -3
  16. package/cjs/lmvz-radio.cjs.entry.js +4 -3
  17. package/cjs/lmvz-select.cjs.entry.js +3 -2
  18. package/cjs/lmvz-snackbar.cjs.entry.js +83 -0
  19. package/cjs/lmvz-tab.cjs.entry.js +31 -0
  20. package/cjs/lmvz-tabs.cjs.entry.js +256 -0
  21. package/cjs/lmvz-toggle.cjs.entry.js +5 -4
  22. package/cjs/loader.cjs.js +1 -1
  23. package/cjs/reactive-controller-host-B_lZtcA6.js +43 -0
  24. package/collection/api/ds.constants.js +4 -1
  25. package/collection/collection-manifest.json +3 -0
  26. package/collection/components/lmvz-button/lmvz-button.css +6 -6
  27. package/collection/components/lmvz-button-group/lmvz-button-group.css +2 -2
  28. package/collection/components/lmvz-card/lmvz-card.css +9 -9
  29. package/collection/components/lmvz-checkbox/lmvz-checkbox.css +14 -12
  30. package/collection/components/lmvz-checkbox/lmvz-checkbox.js +4 -1
  31. package/collection/components/lmvz-chip/lmvz-chip.css +2 -2
  32. package/collection/components/lmvz-header/lmvz-header.js +3 -3
  33. package/collection/components/lmvz-icon/lmvz-icon.js +1 -1
  34. package/collection/components/lmvz-menuitem/lmvz-menuitem.css +1 -1
  35. package/collection/components/lmvz-modal/lmvz-modal.css +4 -16
  36. package/collection/components/lmvz-radio/lmvz-radio.css +4 -4
  37. package/collection/components/lmvz-snackbar/lmvz-snackbar.css +101 -0
  38. package/collection/components/lmvz-snackbar/lmvz-snackbar.js +266 -0
  39. package/collection/components/lmvz-snackbar/public.js +1 -0
  40. package/collection/components/lmvz-snackbar/snackbar-controller.js +194 -0
  41. package/collection/components/lmvz-tab/lmvz-tab.css +148 -0
  42. package/collection/components/lmvz-tab/lmvz-tab.js +125 -0
  43. package/collection/components/lmvz-tabs/lmvz-tabs.css +58 -0
  44. package/collection/components/lmvz-tabs/lmvz-tabs.js +399 -0
  45. package/collection/components/lmvz-toggle/lmvz-toggle.css +2 -2
  46. package/collection/components/lmvz-toggle/lmvz-toggle.js +1 -1
  47. package/collection/index.js +1 -0
  48. package/collection/integration/header-integration/header-integration.js +1 -1
  49. package/collection/utils/aria/list-keyboard-controller.js +151 -28
  50. package/components/index.d.ts +6 -0
  51. package/components/index.d.ts.bak +6 -0
  52. package/components/index.js +1 -1
  53. package/components/lmvz-action.js +1 -1
  54. package/components/lmvz-button-group.js +1 -1
  55. package/components/lmvz-button.js +1 -1
  56. package/components/lmvz-card.js +1 -1
  57. package/components/lmvz-checkbox.js +1 -1
  58. package/components/lmvz-chip.js +1 -1
  59. package/components/lmvz-header.js +1 -1
  60. package/components/lmvz-icon.js +1 -1
  61. package/components/lmvz-input.js +1 -1
  62. package/components/lmvz-menuitem.js +1 -1
  63. package/components/lmvz-modal.js +1 -1
  64. package/components/lmvz-radio.js +1 -1
  65. package/components/lmvz-select.js +1 -1
  66. package/components/lmvz-snackbar.d.ts +11 -0
  67. package/components/lmvz-snackbar.d.ts.bak +11 -0
  68. package/components/lmvz-snackbar.js +1 -0
  69. package/components/lmvz-tab.d.ts +11 -0
  70. package/components/lmvz-tab.d.ts.bak +11 -0
  71. package/components/lmvz-tab.js +1 -0
  72. package/components/lmvz-tabs.d.ts +11 -0
  73. package/components/lmvz-tabs.d.ts.bak +11 -0
  74. package/components/lmvz-tabs.js +1 -0
  75. package/components/lmvz-toggle.js +1 -1
  76. package/components/p-0P2Wb3pE.js +1 -0
  77. package/components/p-2VdcUIrr.js +1 -0
  78. package/components/p-BJEQw1Sz.js +1 -0
  79. package/components/{p-Bb-kEOmU.js → p-Cs7RCOHZ.js} +1 -1
  80. package/components/p-CtaMrBNE.js +1 -0
  81. package/components/p-DjvbwRyl.js +1 -0
  82. package/components/{p-DYr7Jc0V.js → p-c7OzBK8f.js} +1 -1
  83. package/esm/{reactive-controller-host-ZrGf1F2-.js → aria-validation-controller-D-KO0Asb.js} +1 -41
  84. package/esm/{ds.constants-Bmi89ll1.js → ds.constants-BOOwq5dE.js} +1 -1
  85. package/esm/index.js +198 -1
  86. package/esm/list-keyboard-controller-Coi8XfUH.js +171 -0
  87. package/esm/lmvz-button-group.entry.js +181 -0
  88. package/esm/lmvz-button_2.entry.js +196 -0
  89. package/esm/lmvz-card.entry.js +1 -1
  90. package/esm/lmvz-checkbox.entry.js +7 -3
  91. package/esm/lmvz-chip.entry.js +4 -3
  92. package/esm/lmvz-components.js +1 -1
  93. package/esm/lmvz-header_2.entry.js +6 -50
  94. package/esm/lmvz-input.entry.js +2 -1
  95. package/esm/lmvz-menuitem.entry.js +3 -2
  96. package/esm/lmvz-modal.entry.js +3 -2
  97. package/esm/lmvz-radio.entry.js +3 -2
  98. package/esm/lmvz-select.entry.js +2 -1
  99. package/esm/lmvz-snackbar.entry.js +81 -0
  100. package/esm/lmvz-tab.entry.js +29 -0
  101. package/esm/lmvz-tabs.entry.js +254 -0
  102. package/esm/lmvz-toggle.entry.js +4 -3
  103. package/esm/loader.js +1 -1
  104. package/esm/reactive-controller-host-FBuCCcFC.js +41 -0
  105. package/hydrate/index.js +565 -40
  106. package/hydrate/index.mjs +565 -40
  107. package/lmvz-components/index.esm.js +1 -1
  108. package/lmvz-components/lmvz-components.esm.js +1 -1
  109. package/lmvz-components/p-0a37e0f2.entry.js +1 -0
  110. package/lmvz-components/p-25f045b2.entry.js +1 -0
  111. package/lmvz-components/p-43b463bf.entry.js +1 -0
  112. package/lmvz-components/p-4bd71a3c.entry.js +1 -0
  113. package/lmvz-components/p-6484fbc6.entry.js +1 -0
  114. package/lmvz-components/p-6988c3ea.entry.js +1 -0
  115. package/lmvz-components/p-6de9981f.entry.js +1 -0
  116. package/lmvz-components/p-758dbb82.entry.js +1 -0
  117. package/lmvz-components/p-7b15cdce.entry.js +1 -0
  118. package/lmvz-components/p-8874ff19.entry.js +1 -0
  119. package/lmvz-components/p-BOOwq5dE.js +1 -0
  120. package/lmvz-components/p-CtaMrBNE.js +1 -0
  121. package/lmvz-components/p-FBuCCcFC.js +1 -0
  122. package/lmvz-components/p-a5c921dc.entry.js +1 -0
  123. package/lmvz-components/p-bb46a884.entry.js +1 -0
  124. package/lmvz-components/p-bd23eab3.entry.js +1 -0
  125. package/lmvz-components/p-c6228cee.entry.js +1 -0
  126. package/lmvz-components/p-da16ff58.entry.js +1 -0
  127. package/lmvz-components/p-hRb38wX6.js +1 -0
  128. package/manifest.json +858 -186
  129. package/package.json +13 -1
  130. package/types/api/ds.constants.d.ts +9 -1
  131. package/types/components/lmvz-checkbox/lmvz-checkbox.d.ts +1 -0
  132. package/types/components/lmvz-header/lmvz-header.d.ts +2 -2
  133. package/types/components/lmvz-snackbar/lmvz-snackbar.d.ts +21 -0
  134. package/types/components/lmvz-snackbar/public.d.ts +2 -0
  135. package/types/components/lmvz-snackbar/snackbar-controller.d.ts +32 -0
  136. package/types/components/lmvz-tab/lmvz-tab.d.ts +11 -0
  137. package/types/components/lmvz-tabs/lmvz-tabs.d.ts +43 -0
  138. package/types/components.d.ts +212 -1
  139. package/types/index.d.ts +1 -0
  140. package/types/utils/aria/list-keyboard-controller.d.ts +28 -5
  141. package/cjs/lmvz-button_3.cjs.entry.js +0 -375
  142. package/components/p-CCcoDnH-.js +0 -1
  143. package/components/p-CNmHnJ1D.js +0 -1
  144. package/components/p-vUYpZZoR.js +0 -1
  145. package/esm/lmvz-button_3.entry.js +0 -371
  146. package/lmvz-components/p-01aeca60.entry.js +0 -1
  147. package/lmvz-components/p-0dced359.entry.js +0 -1
  148. package/lmvz-components/p-2044a9ac.entry.js +0 -1
  149. package/lmvz-components/p-3c2adbb4.entry.js +0 -1
  150. package/lmvz-components/p-3df070b0.entry.js +0 -1
  151. package/lmvz-components/p-758078db.entry.js +0 -1
  152. package/lmvz-components/p-90f5a19d.entry.js +0 -1
  153. package/lmvz-components/p-Bmi89ll1.js +0 -1
  154. package/lmvz-components/p-CwX1wKkM.js +0 -1
  155. package/lmvz-components/p-acfeae08.entry.js +0 -1
  156. package/lmvz-components/p-c01a6c70.entry.js +0 -1
  157. package/lmvz-components/p-e1eaa7a2.entry.js +0 -1
  158. package/lmvz-components/p-e23d0054.entry.js +0 -1
@@ -0,0 +1,125 @@
1
+ import { Host, h } from "@stencil/core";
2
+ export class LmvzTab {
3
+ el;
4
+ mediaSlotEl;
5
+ value;
6
+ disabled = false;
7
+ selected = false;
8
+ vertical = false;
9
+ handleMediaSlotChange = () => {
10
+ this.el.toggleAttribute('has-media', (this.mediaSlotEl?.assignedElements() ?? []).length > 0);
11
+ };
12
+ componentDidLoad() {
13
+ this.handleMediaSlotChange();
14
+ this.el.dispatchEvent(new CustomEvent('lmvzTabReady', { bubbles: true, composed: false }));
15
+ }
16
+ render() {
17
+ return (h(Host, { key: 'f02b0624ac752f25e3996071ab88be1364dd27c3' }, h("button", { key: '1666fea6a68c66d5bf88141660067a66e0164891', part: "button", role: "tab", disabled: this.disabled, "aria-selected": String(this.selected), "aria-disabled": this.disabled ? 'true' : undefined, tabIndex: 0 }, h("slot", { key: '23d1ef98da2a72efa3a5ec1563298fc4c08da441', name: "media", ref: (el) => (this.mediaSlotEl = el), onSlotchange: this.handleMediaSlotChange }), h("span", { key: 'bd96765d2228817c621a2ad4fd4f3b05fcdb3a21', class: "label" }, h("slot", { key: 'ef51c25169a1d993797a86b89fa296218e264969' })), h("span", { key: '28dda1631d62325a29e285909ee3f1c0ea9da3ad', "aria-hidden": "true", part: "indicator", class: "indicator" }))));
18
+ }
19
+ static get is() { return "lmvz-tab"; }
20
+ static get encapsulation() { return "shadow"; }
21
+ static get delegatesFocus() { return true; }
22
+ static get originalStyleUrls() {
23
+ return {
24
+ "$": ["lmvz-tab.css"]
25
+ };
26
+ }
27
+ static get styleUrls() {
28
+ return {
29
+ "$": ["lmvz-tab.css"]
30
+ };
31
+ }
32
+ static get properties() {
33
+ return {
34
+ "value": {
35
+ "type": "string",
36
+ "mutable": false,
37
+ "complexType": {
38
+ "original": "string",
39
+ "resolved": "string",
40
+ "references": {}
41
+ },
42
+ "required": true,
43
+ "optional": false,
44
+ "docs": {
45
+ "tags": [],
46
+ "text": "Unique value that identifies this tab within its `lmvz-tabs` parent.\nThe parent uses this to track the selected tab."
47
+ },
48
+ "getter": false,
49
+ "setter": false,
50
+ "reflect": true,
51
+ "attribute": "value"
52
+ },
53
+ "disabled": {
54
+ "type": "boolean",
55
+ "mutable": false,
56
+ "complexType": {
57
+ "original": "boolean",
58
+ "resolved": "boolean",
59
+ "references": {}
60
+ },
61
+ "required": false,
62
+ "optional": false,
63
+ "docs": {
64
+ "tags": [{
65
+ "name": "default",
66
+ "text": "false"
67
+ }],
68
+ "text": "Whether the tab is disabled.\nDisabled tabs are not activatable and are skipped by arrow-key navigation in `lmvz-tabs`."
69
+ },
70
+ "getter": false,
71
+ "setter": false,
72
+ "reflect": true,
73
+ "attribute": "disabled",
74
+ "defaultValue": "false"
75
+ },
76
+ "selected": {
77
+ "type": "boolean",
78
+ "mutable": false,
79
+ "complexType": {
80
+ "original": "boolean",
81
+ "resolved": "boolean",
82
+ "references": {}
83
+ },
84
+ "required": false,
85
+ "optional": false,
86
+ "docs": {
87
+ "tags": [{
88
+ "name": "default",
89
+ "text": "false"
90
+ }],
91
+ "text": "Whether this tab is currently selected.\nSet by the parent `lmvz-tabs` component \u2014 do not set manually."
92
+ },
93
+ "getter": false,
94
+ "setter": false,
95
+ "reflect": true,
96
+ "attribute": "selected",
97
+ "defaultValue": "false"
98
+ },
99
+ "vertical": {
100
+ "type": "boolean",
101
+ "mutable": false,
102
+ "complexType": {
103
+ "original": "boolean",
104
+ "resolved": "boolean",
105
+ "references": {}
106
+ },
107
+ "required": false,
108
+ "optional": false,
109
+ "docs": {
110
+ "tags": [{
111
+ "name": "default",
112
+ "text": "false"
113
+ }],
114
+ "text": "Vertical orientation context.\nSet by the parent `lmvz-tabs` when `orientation=\"vertical\"` \u2014 do not set manually.\nWhen true the selection indicator moves to the inline-start edge."
115
+ },
116
+ "getter": false,
117
+ "setter": false,
118
+ "reflect": true,
119
+ "attribute": "vertical",
120
+ "defaultValue": "false"
121
+ }
122
+ };
123
+ }
124
+ static get elementRef() { return "el"; }
125
+ }
@@ -0,0 +1,58 @@
1
+
2
+ @layer lmvz-ds.reset, lmvz-ds.theme, lmvz-ds.components, lmvz-ds.overrides;
3
+ /**
4
+ * This defines the order of our lmvz-ds' CSS layers. See readme.md for details.
5
+ * Important: Always import this file _before_ layering your own styles!
6
+ */
7
+ @layer lmvz-ds.reset {
8
+ body {
9
+ margin: 0;
10
+ }
11
+
12
+ h1,
13
+ h2,
14
+ h3,
15
+ h4,
16
+ h5,
17
+ h6 {
18
+ margin: 0;
19
+ }
20
+
21
+ *[hidden] {
22
+ display: none !important;
23
+ }
24
+
25
+ }
26
+ :host {
27
+ display: inline-block;
28
+ }
29
+ .tablist {
30
+ display: inline-flex;
31
+ flex-direction: row;
32
+ background: var(--lmvz-semantic-color-int-secondary, #f0f0f0);
33
+ border-radius: var(--lmvz-semantic-border-radius-round, 999px);
34
+ /* Horizontal overflow: tabs scroll when they overflow the container */
35
+ overflow: auto hidden;
36
+ /* Hide scrollbar visually while keeping scroll functionality */
37
+ scrollbar-width: none; /* Firefox */
38
+ }
39
+ .tablist::-webkit-scrollbar {
40
+ display: none; /* Chrome/Safari */
41
+ }
42
+ :host([has-icon-tabs]) .tablist {
43
+ gap: var(--lmvz-dimension-6-8, clamp(0.38rem, 0.34rem + 0.13vw, 0.5rem));
44
+ background: none;
45
+ border-radius: 0;
46
+ }
47
+ /* ── Vertical orientation ────────────────────────────────────────────────── */
48
+ :host([orientation='vertical']) .tablist {
49
+ flex-direction: column;
50
+ overflow: visible auto;
51
+ }
52
+ /* The panels slot renders inline; individual panels control their own display */
53
+ ::slotted([role='tabpanel']) {
54
+ display: block;
55
+ }
56
+ ::slotted([role='tabpanel'][hidden]) {
57
+ display: none;
58
+ }
@@ -0,0 +1,399 @@
1
+ import { Host, h } from "@stencil/core";
2
+ import { DirectionalFocusController } from "../../utils/aria/list-keyboard-controller";
3
+ import { ReactiveControllerHost } from "../../utils/reactive-controller-host";
4
+ let tabsIdCounter = 0;
5
+ export class LmvzTabs extends ReactiveControllerHost {
6
+ el;
7
+ instanceId = ++tabsIdCounter;
8
+ tabSlotEl;
9
+ panelSlotEl;
10
+ focusController = new DirectionalFocusController(this, {
11
+ orientation: 'horizontal',
12
+ manageTabIndex: true,
13
+ enableHomeAndEnd: true,
14
+ });
15
+ value;
16
+ orientation = 'horizontal';
17
+ lmvzChange;
18
+ resolvedValue;
19
+ constructor() {
20
+ super();
21
+ this.addController(this.focusController);
22
+ }
23
+ componentWillLoad() {
24
+ super.componentWillLoad();
25
+ this.syncOrientation();
26
+ }
27
+ componentDidLoad() {
28
+ this.tabSlotEl?.addEventListener('slotchange', this.handleTabSlotChange);
29
+ this.panelSlotEl?.addEventListener('slotchange', this.handlePanelSlotChange);
30
+ this.el.addEventListener('lmvzTabReady', this.handleTabReady);
31
+ this.handleTabSlotChange();
32
+ super.componentDidLoad();
33
+ }
34
+ disconnectedCallback() {
35
+ this.el.removeEventListener('lmvzTabReady', this.handleTabReady);
36
+ super.disconnectedCallback();
37
+ }
38
+ handleValueChange(newValue) {
39
+ this.applySelection(newValue);
40
+ }
41
+ handleOrientationChange() {
42
+ this.syncOrientation();
43
+ this.syncFocusTargets();
44
+ this.syncTabOrientation();
45
+ }
46
+ async activateTab(value) {
47
+ const tab = this.findTabByValue(value);
48
+ if (!tab || this.isTabDisabled(tab))
49
+ return;
50
+ this.selectTab(value);
51
+ }
52
+ async getTabElements() {
53
+ return this.slottedTabs;
54
+ }
55
+ async setTabPanelIds(pairs) {
56
+ const tabs = this.slottedTabs;
57
+ const panels = this.slottedPanels;
58
+ pairs.forEach(([tabId, panelId], index) => {
59
+ const tab = tabs[index];
60
+ const panel = panels[index];
61
+ const btnId = `${tabId}-btn`;
62
+ if (tab) {
63
+ tab.id = tabId;
64
+ const btn = tab.shadowRoot?.querySelector('button');
65
+ if (btn) {
66
+ btn.id = btnId;
67
+ btn.setAttribute('aria-controls', panelId);
68
+ }
69
+ }
70
+ if (panel) {
71
+ panel.id = panelId;
72
+ panel.setAttribute('aria-labelledby', btnId);
73
+ }
74
+ });
75
+ }
76
+ get slottedTabs() {
77
+ return (this.tabSlotEl?.assignedElements({ flatten: false }) ?? []).filter((el) => el.tagName.toLowerCase() === 'lmvz-tab');
78
+ }
79
+ get slottedPanels() {
80
+ return (this.panelSlotEl?.assignedElements({ flatten: false }) ?? []);
81
+ }
82
+ handleTabSlotChange = () => {
83
+ this.syncFocusTargets();
84
+ this.syncTabOrientation();
85
+ this.wireAriaIds();
86
+ this.applySelection(this.value);
87
+ this.updateIconTabsAttr();
88
+ };
89
+ handlePanelSlotChange = () => {
90
+ this.wireAriaIds();
91
+ this.applySelection(this.resolvedValue ?? this.value);
92
+ };
93
+ handleTabReady = () => {
94
+ this.syncFocusTargets();
95
+ this.wireAriaIds();
96
+ this.applySelection(this.resolvedValue ?? this.value);
97
+ this.updateIconTabsAttr();
98
+ };
99
+ updateIconTabsAttr() {
100
+ this.el.toggleAttribute('has-icon-tabs', this.slottedTabs.some((t) => t.hasAttribute('has-media')));
101
+ }
102
+ syncFocusTargets() {
103
+ const buttons = this.slottedTabs.map((tab) => tab.shadowRoot?.querySelector('button')).filter((b) => !!b);
104
+ this.focusController.updateElements(buttons);
105
+ }
106
+ syncOrientation() {
107
+ this.removeController(this.focusController);
108
+ this.focusController.hostDisconnected?.();
109
+ this.focusController = new DirectionalFocusController(this, {
110
+ orientation: this.orientation,
111
+ manageTabIndex: true,
112
+ enableHomeAndEnd: true,
113
+ });
114
+ this.addController(this.focusController);
115
+ if (this.el.isConnected) {
116
+ this.focusController.hostConnected?.();
117
+ }
118
+ }
119
+ syncTabOrientation() {
120
+ const isVertical = this.orientation === 'vertical';
121
+ this.slottedTabs.forEach((tab) => {
122
+ tab.toggleAttribute('vertical', isVertical);
123
+ });
124
+ }
125
+ wireAriaIds() {
126
+ const tabs = this.slottedTabs;
127
+ const panels = this.slottedPanels;
128
+ const prefix = `lmvz-tabs-${this.instanceId}`;
129
+ tabs.forEach((tab, index) => {
130
+ const tabId = tab.id || `${prefix}-tab-${index}`;
131
+ tab.id = tabId;
132
+ const panel = panels[index];
133
+ if (!panel)
134
+ return;
135
+ const panelId = panel.id || `${prefix}-panel-${index}`;
136
+ panel.id = panelId;
137
+ const btn = tab.shadowRoot?.querySelector('button');
138
+ if (btn) {
139
+ btn.setAttribute('aria-controls', panelId);
140
+ btn.setAttribute('id', `${tabId}-btn`);
141
+ }
142
+ panel.setAttribute('role', panel.getAttribute('role') ?? 'tabpanel');
143
+ panel.setAttribute('aria-labelledby', `${tabId}-btn`);
144
+ });
145
+ }
146
+ applySelection(requested) {
147
+ const tabs = this.slottedTabs;
148
+ if (!tabs.length)
149
+ return;
150
+ let target = this.findTabByValue(requested);
151
+ if (!target || this.isTabDisabled(target)) {
152
+ target = this.findNearestEnabled(requested) ?? undefined;
153
+ }
154
+ if (!target)
155
+ return;
156
+ const effectiveValue = target.getAttribute('value') ?? '';
157
+ this.resolvedValue = effectiveValue;
158
+ if (this.value !== effectiveValue) {
159
+ this.value = effectiveValue;
160
+ }
161
+ tabs.forEach((tab) => {
162
+ const isSelected = tab.getAttribute('value') === effectiveValue;
163
+ tab.toggleAttribute('selected', isSelected);
164
+ const btn = tab.shadowRoot?.querySelector('button');
165
+ if (btn)
166
+ btn.setAttribute('aria-selected', String(isSelected));
167
+ });
168
+ this.slottedPanels.forEach((panel, index) => {
169
+ const tab = tabs[index];
170
+ const isActive = tab?.getAttribute('value') === effectiveValue;
171
+ panel.toggleAttribute('hidden', !isActive);
172
+ });
173
+ const selectedBtn = target.shadowRoot?.querySelector('button');
174
+ if (selectedBtn) {
175
+ this.focusController.setCurrentElement(selectedBtn);
176
+ }
177
+ }
178
+ isTabDisabled(tab) {
179
+ return tab.hasAttribute('disabled') || !!tab.disabled;
180
+ }
181
+ findTabByValue(value) {
182
+ return this.slottedTabs.find((tab) => tab.getAttribute('value') === value);
183
+ }
184
+ findNearestEnabled(fromValue) {
185
+ const tabs = this.slottedTabs;
186
+ const fromIndex = tabs.findIndex((t) => t.getAttribute('value') === fromValue);
187
+ for (let offset = 1; offset < tabs.length; offset++) {
188
+ const next = tabs[(fromIndex + offset) % tabs.length];
189
+ if (next && !this.isTabDisabled(next))
190
+ return next;
191
+ const prev = tabs[(fromIndex - offset + tabs.length) % tabs.length];
192
+ if (prev && !this.isTabDisabled(prev))
193
+ return prev;
194
+ }
195
+ return undefined;
196
+ }
197
+ selectTab(value) {
198
+ if (value === this.resolvedValue)
199
+ return;
200
+ this.applySelection(value);
201
+ this.lmvzChange.emit({ value });
202
+ }
203
+ handleTabClick = (event) => {
204
+ const target = event.target;
205
+ const tab = target.closest('lmvz-tab');
206
+ if (!tab)
207
+ return;
208
+ const value = tab.getAttribute('value');
209
+ if (!value || this.isTabDisabled(tab))
210
+ return;
211
+ this.selectTab(value);
212
+ };
213
+ handleKeydown = (event) => {
214
+ if (event.key !== 'Enter' && event.key !== ' ')
215
+ return;
216
+ const active = this.el.ownerDocument.activeElement;
217
+ if (!active)
218
+ return;
219
+ let tab = null;
220
+ for (const t of this.slottedTabs) {
221
+ if (t === active) {
222
+ tab = t;
223
+ break;
224
+ }
225
+ }
226
+ if (!tab)
227
+ return;
228
+ const value = tab.getAttribute('value');
229
+ if (!value || this.isTabDisabled(tab))
230
+ return;
231
+ event.preventDefault();
232
+ this.selectTab(value);
233
+ };
234
+ render() {
235
+ return (h(Host, { key: '3a503531069e0d83be9bde0e9bc2e1747498baf2', onClick: this.handleTabClick, onKeydown: this.handleKeydown }, h("div", { key: '25a37d52ba6c8c1b46c1e624da13b918e9bd33d1', role: "tablist", "aria-orientation": this.orientation, class: "tablist" }, h("slot", { key: '00b4ba4cf88081d8cd4ee21976398646e4f19679', ref: (el) => (this.tabSlotEl = el) })), h("div", { key: '872aba20a4d26facafc71821f7fc88cf96b05a33', part: "panels-container", class: "panels-container" }, h("slot", { key: '7681c24945e7d50e95f749bd5c056704db120b11', name: "panels", ref: (el) => (this.panelSlotEl = el) }))));
236
+ }
237
+ static get is() { return "lmvz-tabs"; }
238
+ static get encapsulation() { return "shadow"; }
239
+ static get originalStyleUrls() {
240
+ return {
241
+ "$": ["lmvz-tabs.css"]
242
+ };
243
+ }
244
+ static get styleUrls() {
245
+ return {
246
+ "$": ["lmvz-tabs.css"]
247
+ };
248
+ }
249
+ static get properties() {
250
+ return {
251
+ "value": {
252
+ "type": "string",
253
+ "mutable": true,
254
+ "complexType": {
255
+ "original": "string",
256
+ "resolved": "string",
257
+ "references": {}
258
+ },
259
+ "required": true,
260
+ "optional": false,
261
+ "docs": {
262
+ "tags": [],
263
+ "text": "The `value` of the currently selected tab."
264
+ },
265
+ "getter": false,
266
+ "setter": false,
267
+ "reflect": true,
268
+ "attribute": "value"
269
+ },
270
+ "orientation": {
271
+ "type": "string",
272
+ "mutable": true,
273
+ "complexType": {
274
+ "original": "'horizontal' | 'vertical'",
275
+ "resolved": "\"horizontal\" | \"vertical\"",
276
+ "references": {}
277
+ },
278
+ "required": false,
279
+ "optional": false,
280
+ "docs": {
281
+ "tags": [{
282
+ "name": "default",
283
+ "text": "'horizontal'"
284
+ }],
285
+ "text": "Layout and keyboard-navigation orientation."
286
+ },
287
+ "getter": false,
288
+ "setter": false,
289
+ "reflect": true,
290
+ "attribute": "orientation",
291
+ "defaultValue": "'horizontal'"
292
+ }
293
+ };
294
+ }
295
+ static get states() {
296
+ return {
297
+ "resolvedValue": {}
298
+ };
299
+ }
300
+ static get events() {
301
+ return [{
302
+ "method": "lmvzChange",
303
+ "name": "lmvzChange",
304
+ "bubbles": true,
305
+ "cancelable": true,
306
+ "composed": true,
307
+ "docs": {
308
+ "tags": [],
309
+ "text": "Emitted when a tab is activated.\nDetail: `{ value: string }`."
310
+ },
311
+ "complexType": {
312
+ "original": "{ value: string }",
313
+ "resolved": "{ value: string; }",
314
+ "references": {}
315
+ }
316
+ }];
317
+ }
318
+ static get methods() {
319
+ return {
320
+ "activateTab": {
321
+ "complexType": {
322
+ "signature": "(value: string) => Promise<void>",
323
+ "parameters": [{
324
+ "name": "value",
325
+ "type": "string",
326
+ "docs": ""
327
+ }],
328
+ "references": {
329
+ "Promise": {
330
+ "location": "global",
331
+ "id": "global::Promise"
332
+ }
333
+ },
334
+ "return": "Promise<void>"
335
+ },
336
+ "docs": {
337
+ "text": "Programmatically activate a tab by value.\nDisabled tabs are ignored; emits `lmvzChange` on change.",
338
+ "tags": []
339
+ }
340
+ },
341
+ "getTabElements": {
342
+ "complexType": {
343
+ "signature": "() => Promise<HTMLElement[]>",
344
+ "parameters": [],
345
+ "references": {
346
+ "Promise": {
347
+ "location": "global",
348
+ "id": "global::Promise"
349
+ },
350
+ "HTMLElement": {
351
+ "location": "global",
352
+ "id": "global::HTMLElement"
353
+ }
354
+ },
355
+ "return": "Promise<HTMLElement[]>"
356
+ },
357
+ "docs": {
358
+ "text": "Returns all slotted `lmvz-tab` elements.\nExposed for external orchestration.",
359
+ "tags": []
360
+ }
361
+ },
362
+ "setTabPanelIds": {
363
+ "complexType": {
364
+ "signature": "(pairs: Array<[string, string]>) => Promise<void>",
365
+ "parameters": [{
366
+ "name": "pairs",
367
+ "type": "[string, string][]",
368
+ "docs": ""
369
+ }],
370
+ "references": {
371
+ "Promise": {
372
+ "location": "global",
373
+ "id": "global::Promise"
374
+ },
375
+ "Array": {
376
+ "location": "global",
377
+ "id": "global::Array"
378
+ }
379
+ },
380
+ "return": "Promise<void>"
381
+ },
382
+ "docs": {
383
+ "text": "Wires `aria-controls` on each tab and `aria-labelledby` on each panel\nusing the provided ordered array of `[tabId, panelId]` pairs.\nCallers only need this for explicit control; `lmvz-tabs` wires positional\npairs automatically on `slotchange`.",
384
+ "tags": []
385
+ }
386
+ }
387
+ };
388
+ }
389
+ static get elementRef() { return "el"; }
390
+ static get watchers() {
391
+ return [{
392
+ "propName": "value",
393
+ "methodName": "handleValueChange"
394
+ }, {
395
+ "propName": "orientation",
396
+ "methodName": "handleOrientationChange"
397
+ }];
398
+ }
399
+ }
@@ -40,7 +40,7 @@
40
40
  :host {
41
41
  display: inline-flex;
42
42
  align-items: center;
43
- gap: var(--lmvz-component-input-gap-md, clamp(0.75rem, 0.69rem + 0.26vw, 1rem));
43
+ gap: var(--lmvz-component-input-gap-md, clamp(0.5rem, 0.44rem + 0.26vw, 0.75rem));
44
44
  padding-block: var(--lmvz-dimension-2-8, clamp(0.13rem, 0.03rem + 0.39vw, 0.5rem));
45
45
  padding-inline: var(--lmvz-dimension-4-10, clamp(0.25rem, 0.16rem + 0.39vw, 0.63rem));
46
46
  /* TODO[LDHCID-136]: min-height currently below accessibility requirements for tap targets (44px) */
@@ -110,7 +110,7 @@ input {
110
110
  background-color: var(--lmvz-semantic-color-status-on-active, #0e7ab4);
111
111
  }
112
112
  label {
113
- font: var(--lmvz-typography-body-md, 400 clamp(0.88rem, 0.84rem + 0.13vw, 1rem) / 1.4
113
+ font: var(--lmvz-typography-body-md, 400 clamp(0.88rem, 0.84rem + 0.13vw, 1rem) / 1.5
114
114
  Router);
115
115
  color: var(--lmvz-semantic-color-on-surface-primary, #000000);
116
116
  cursor: pointer;
@@ -65,7 +65,7 @@ export class LmvzToggle extends ReactiveControllerHost {
65
65
  this.lmvzChange.emit(newChecked);
66
66
  };
67
67
  render() {
68
- return (h(Host, { key: '4bb633301740c3e69a836615e2266242980ac17a' }, h("span", { key: 'cc7188d8e2caff2968ad6c64c72565a71c89ec74', class: "track" }, h("input", { key: '867f7865711b9224b89f0f491df8a19589342729', type: "checkbox", role: "switch", id: this.toggleId, checked: this.checked, disabled: this.disabled, required: this.required, name: this.name, value: this.value, form: this.form, ref: (el) => (this.nativeInputElement = el), onChange: this.handleChange }), h("span", { key: '426ee9f042afcc3d74b2137d2edbe95573b3c136', class: "thumb", "aria-hidden": "true" })), h("label", { key: '600cb22f2915d86edafa9ac57b77707055f6ae16', htmlFor: this.toggleId }, this.label)));
68
+ return (h(Host, { key: '452ea30df1191b45c606d7512982a0f743b7bf7a' }, h("span", { key: 'c538806b64de8bce70d0bc55c6a9eb279f4eff4c', class: "track" }, h("input", { key: 'afe04f4305744b3110092f9bfcbe8b4ee6f21c37', type: "checkbox", role: "switch", id: this.toggleId, checked: this.checked, disabled: this.disabled, required: this.required, name: this.name, value: this.value, form: this.form, ref: (el) => (this.nativeInputElement = el), onChange: this.handleChange }), h("span", { key: 'e8089a6e8ee084b3f316c837cf3225017c33a15e', class: "thumb", "aria-hidden": "true" })), h("label", { key: '085055f461f4240df2eb2b4ea441a5e782240276', htmlFor: this.toggleId }, this.label)));
69
69
  }
70
70
  static get is() { return "lmvz-toggle"; }
71
71
  static get encapsulation() { return "scoped"; }
@@ -1,3 +1,4 @@
1
1
  export * from '@lmvz-ds/aria-validation';
2
2
  export { chipSizes, chipTypes, iconSizes, iconWeights, inputTypes, textSizes } from './api/ds.constants';
3
3
  export * from './utils/public';
4
+ export * from './components/lmvz-snackbar/public';
@@ -20,7 +20,7 @@ export class HeaderIntegration {
20
20
  this.activeNav = navId;
21
21
  }
22
22
  render() {
23
- return (h(Host, { key: '7c381821f1839fd61368f10878fcd77a89e3f6fc' }, h("lmvz-header", { key: '93d1b351824b01b0124e0c038c569f959f8a449a', lmvzActiveNav: this.activeNav }, h("lmvz-menuitem", { key: '96db71af9361829426af3cf431d481f5a2f6678a', slot: "nav-primary", id: "lehrmittel", onLmvzActivation: this.activate.bind(this) }, h("a", { key: '0e0110287b032895b72b76f00226c95d795feeea', href: "#" }, "Lehrmittel")), h("lmvz-menuitem", { key: '42edf9a666a8f3a6603d323190135607466ae75f', slot: "nav-primary", id: "verwaltung", onLmvzActivation: this.activate.bind(this) }, h("a", { key: '507b858cf867eb3568f470baeca0be664f717c46', href: "#" }, "Verwaltung")), h("lmvz-menuitem", { key: '7adaa0324fa4996965bc5d3a148dcc17238ce3ba', slot: "connect-nav-lehrmittel" }, h("lmvz-icon", { key: 'adb86d8a2fc921a5205f78c101beb51b8926a4be', ...typedIconFromSet('lmvz', 'edit') }), "Deutsch 7"), h("lmvz-menuitem", { key: 'bc65dc75f17dca9859234c29b327166da04ed37f', slot: "connect-nav-lehrmittel" }, h("lmvz-icon", { key: '506530a75db127cb3aab58b3d9628af618c0e628', ...typedIconFromSet('lmvz', 'edit') }), "Mathe 2"), h("lmvz-menuitem", { key: '6618dfb601a99f6ef60631ff7ef51daaeb770aba', slot: "connect-nav-verwaltung" }, h("lmvz-icon", { key: '9bc773a8378b4dc711c6874675c0ffb6bda47335', ...typedIconFromSet('lmvz', 'settings') }), "iwas mit Verwaltung"), h("lmvz-menuitem", { key: 'c3becfeba08589f33a6530e77928121b88eb1aa0', slot: "connect-nav-verwaltung", "aria-label": "Einstellungen" }, h("lmvz-icon", { key: 'a7ddd7b3f99d496591cccc79bebcaeec8a27db9f', ...typedIconFromSet('lmvz', 'settings') })), h("lmvz-button", { key: '16454fea1422c61ecdabf4190b494a993b7affd2', slot: "actions", "aria-label": "Benutzerkonto" }, h("lmvz-icon", { key: '9b467e5187d1b7e39752554611c51ccb844f79da', ...typedIconFromSet('lmvz', 'user'), size: "lg" })))));
23
+ return (h(Host, { key: '472abfaab29d554ecfa263b1f6b85d2c1990ceb1' }, h("lmvz-header", { key: '633622c96723608bfac8a9bc7ae9e1a972b105bf', lmvzActiveNav: this.activeNav }, h("lmvz-menuitem", { key: '15f74edb9e88bb246775d540c05cbdc81a3a618f', slot: "nav-primary", id: "lehrmittel", onLmvzActivation: this.activate.bind(this) }, h("a", { key: '6b82ecbd8e2ba53a68d5e05ca3f8ce8800b8dd5a', href: "#" }, "Lehrmittel")), h("lmvz-menuitem", { key: '97922b8a6c0dfba9c5d5b410b1d55aa288e67e88', slot: "nav-primary", id: "verwaltung", onLmvzActivation: this.activate.bind(this) }, h("a", { key: 'bacddd5a3fafecb3573a30dabff10a54f1996288', href: "#" }, "Verwaltung")), h("lmvz-menuitem", { key: 'bbfba0969436a5c95338ff01163658df0b64d680', slot: "connect-nav-lehrmittel" }, h("lmvz-icon", { key: '474927ef7491b1512f7849899859fddb6f368696', ...typedIconFromSet('lmvz', 'edit') }), "Deutsch 7"), h("lmvz-menuitem", { key: '32ef36d6787e3368a4c4e36fdaf00f765192cc6d', slot: "connect-nav-lehrmittel" }, h("lmvz-icon", { key: '58811b4b344a0168478ecda8fa7eee109ae51ea8', ...typedIconFromSet('lmvz', 'edit') }), "Mathe 2"), h("lmvz-menuitem", { key: '079715602610bd44465756e0b5a6daa0f67ea758', slot: "connect-nav-verwaltung" }, h("lmvz-icon", { key: '0c8b1d230579ab20e9dc9ef3b20c5f08a7a16d91', ...typedIconFromSet('lmvz', 'settings') }), "iwas mit Verwaltung"), h("lmvz-menuitem", { key: '31408441bbfd25dd66b209526709280613e1fd48', slot: "connect-nav-verwaltung", "aria-label": "Einstellungen" }, h("lmvz-icon", { key: 'e56d4b45f05d155561730d5298f7e6596eb8e64c', ...typedIconFromSet('lmvz', 'settings') })), h("lmvz-button", { key: '322f1858d41d8416ac8e4a073da348497d6f7557', slot: "actions", "aria-label": "Benutzerkonto" }, h("lmvz-icon", { key: 'd6b22f6b3e7357f9bf89b20463d146855feab625', ...typedIconFromSet('lmvz', 'user'), size: "lg" })))));
24
24
  }
25
25
  static get is() { return "header-integration"; }
26
26
  static get encapsulation() { return "shadow"; }