@lmvz-ds/components 0.37.0 → 0.39.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.
- package/CHANGELOG.md +21 -0
- package/README.md +12 -20
- package/cjs/{aria-validation-controller-Do0uEK4t.js → aria-validation-controller-DKNXjnQr.js} +1 -1
- package/cjs/checkmark-CuKDPAcx.js +5 -0
- package/cjs/{directional-focus-controller-8Xd_7MHT.js → directional-focus-controller-DDnhfX5w.js} +15 -5
- package/cjs/{index-BgvZ4y-3.js → index-DWy4nuyZ.js} +41 -0
- package/cjs/index.cjs.js +3 -195
- package/cjs/lmvz-action-list.cjs.entry.js +4 -4
- package/cjs/lmvz-action.cjs.entry.js +1 -1
- package/cjs/lmvz-button-group.cjs.entry.js +5 -1
- package/cjs/lmvz-button_2.cjs.entry.js +3 -3
- package/cjs/lmvz-card.cjs.entry.js +2 -2
- package/cjs/lmvz-checkbox.cjs.entry.js +4 -5
- package/cjs/lmvz-chip.cjs.entry.js +5 -5
- package/cjs/lmvz-components.cjs.js +2 -2
- package/cjs/lmvz-datepicker.cjs.entry.js +1 -1
- package/cjs/lmvz-header_2.cjs.entry.js +5 -5
- package/cjs/lmvz-input.cjs.entry.js +4 -7
- package/cjs/lmvz-link.cjs.entry.js +1 -1
- package/cjs/lmvz-menuitem.cjs.entry.js +2 -2
- package/cjs/lmvz-message.cjs.entry.js +4 -2
- package/cjs/lmvz-modal.cjs.entry.js +2 -2
- package/cjs/lmvz-popover.cjs.entry.js +5 -14
- package/cjs/lmvz-radio.cjs.entry.js +2 -2
- package/cjs/lmvz-select.cjs.entry.js +110 -16
- package/cjs/lmvz-snackbar.cjs.entry.js +1 -1
- package/cjs/lmvz-spinner.cjs.entry.js +1 -1
- package/cjs/lmvz-tab.cjs.entry.js +1 -1
- package/cjs/lmvz-tabs.cjs.entry.js +9 -3
- package/cjs/lmvz-toggle.cjs.entry.js +2 -2
- package/cjs/loader.cjs.js +2 -2
- package/cjs/public-DTgpEs1_.js +206 -0
- package/collection/components/lmvz-action-list/lmvz-action-list.css +119 -116
- package/collection/components/lmvz-button/lmvz-button.css +109 -106
- package/collection/components/lmvz-card/lmvz-card.css +106 -103
- package/collection/components/lmvz-chip/lmvz-chip.css +1 -1
- package/collection/components/lmvz-chip/lmvz-chip.js +2 -2
- package/collection/components/lmvz-header/lmvz-header.js +2 -2
- package/collection/components/lmvz-input/lmvz-input.js +2 -5
- package/collection/components/lmvz-message/lmvz-message.css +1 -1
- package/collection/components/lmvz-popover/lmvz-popover.css +1 -1
- package/collection/components/lmvz-popover/lmvz-popover.js +2 -11
- package/collection/components/lmvz-select/lmvz-select.css +102 -53
- package/collection/components/lmvz-select/lmvz-select.js +151 -41
- package/collection/components/lmvz-snackbar/public.js +3 -0
- package/collection/components/lmvz-tabs/lmvz-tabs.js +7 -1
- package/collection/utils/aria/directional-focus-controller.js +16 -7
- package/collection/utils/icons/public.js +3 -0
- package/components/index.js +1 -1
- package/components/lmvz-action-list.js +1 -1
- package/components/lmvz-action.js +1 -1
- package/components/lmvz-button-group.js +1 -1
- package/components/lmvz-button.js +1 -1
- package/components/lmvz-card.js +1 -1
- package/components/lmvz-checkbox.js +1 -1
- package/components/lmvz-chip.js +1 -1
- package/components/lmvz-datepicker.js +1 -1
- package/components/lmvz-header.js +1 -1
- package/components/lmvz-icon.js +1 -1
- package/components/lmvz-input.js +1 -1
- package/components/lmvz-link.js +1 -1
- package/components/lmvz-menuitem.js +1 -1
- package/components/lmvz-message.js +1 -1
- package/components/lmvz-modal.js +1 -1
- package/components/lmvz-popover.js +1 -1
- package/components/lmvz-radio.js +1 -1
- package/components/lmvz-select.js +1 -1
- package/components/lmvz-snackbar.js +1 -1
- package/components/lmvz-spinner.js +1 -1
- package/components/lmvz-tab.js +1 -1
- package/components/lmvz-tabs.js +1 -1
- package/components/lmvz-toggle.js +1 -1
- package/components/{p-BLMXiDE0.js → p--mU29mrX.js} +1 -1
- package/components/p-BPa0FHVO.js +1 -0
- package/components/p-Bc5MM0zh.js +1 -0
- package/components/p-CyDgnpOB.js +1 -0
- package/components/p-DAikapVO.js +1 -0
- package/components/{p-C-pRMuMh.js → p-DIyiticz.js} +1 -1
- package/components/{p-BhALzK62.js → p-DJLdOjL4.js} +1 -1
- package/components/p-DSDBThqb.js +1 -0
- package/components/{p-diOze8wI.js → p-DXFoXTse.js} +1 -1
- package/components/p-DXhP6UeF.js +1 -0
- package/components/p-D_mff3n7.js +1 -0
- package/components/p-DbBJxuBm.js +1 -0
- package/components/p-DsTgD0_a.js +1 -0
- package/components/p-DyQ1GbaN.js +1 -0
- package/components/p-niXjuPxe.js +1 -0
- package/components/{p-BAj4FkUt.js → p-sACbyedu.js} +1 -1
- package/esm/{aria-validation-controller-Cp6pofER.js → aria-validation-controller-Dwv7n0rk.js} +1 -1
- package/esm/checkmark-DAikapVO.js +3 -0
- package/esm/{directional-focus-controller-QukTTWBE.js → directional-focus-controller-CJ0yNC00.js} +15 -5
- package/esm/{index-BOXP1Vx0.js → index-DVab4vzV.js} +41 -1
- package/esm/index.js +1 -197
- package/esm/lmvz-action-list.entry.js +4 -4
- package/esm/lmvz-action.entry.js +1 -1
- package/esm/lmvz-button-group.entry.js +5 -1
- package/esm/lmvz-button_2.entry.js +3 -3
- package/esm/lmvz-card.entry.js +2 -2
- package/esm/lmvz-checkbox.entry.js +3 -4
- package/esm/lmvz-chip.entry.js +5 -5
- package/esm/lmvz-components.js +3 -3
- package/esm/lmvz-datepicker.entry.js +1 -1
- package/esm/lmvz-header_2.entry.js +5 -5
- package/esm/lmvz-input.entry.js +4 -7
- package/esm/lmvz-link.entry.js +1 -1
- package/esm/lmvz-menuitem.entry.js +2 -2
- package/esm/lmvz-message.entry.js +4 -2
- package/esm/lmvz-modal.entry.js +2 -2
- package/esm/lmvz-popover.entry.js +5 -14
- package/esm/lmvz-radio.entry.js +2 -2
- package/esm/lmvz-select.entry.js +110 -16
- package/esm/lmvz-snackbar.entry.js +1 -1
- package/esm/lmvz-spinner.entry.js +1 -1
- package/esm/lmvz-tab.entry.js +1 -1
- package/esm/lmvz-tabs.entry.js +9 -3
- package/esm/lmvz-toggle.entry.js +2 -2
- package/esm/loader.js +3 -3
- package/esm/public-m6pRVUeP.js +204 -0
- package/hydrate/index.js +394 -50
- package/hydrate/index.mjs +394 -50
- package/lmvz-components/index.esm.js +1 -1
- package/lmvz-components/lmvz-components.esm.js +1 -1
- package/lmvz-components/p-1ba1af8d.entry.js +1 -0
- package/lmvz-components/{p-0f65d001.entry.js → p-27e8b4fa.entry.js} +1 -1
- package/lmvz-components/p-304c7554.entry.js +1 -0
- package/lmvz-components/p-316dd61a.entry.js +1 -0
- package/lmvz-components/{p-3d5867df.entry.js → p-335b3867.entry.js} +1 -1
- package/lmvz-components/{p-7872a6b4.entry.js → p-3b7203a3.entry.js} +1 -1
- package/lmvz-components/p-41286514.entry.js +1 -0
- package/lmvz-components/p-6aae1df9.entry.js +1 -0
- package/lmvz-components/p-743616c0.entry.js +1 -0
- package/lmvz-components/{p-26dd9684.entry.js → p-773e9d95.entry.js} +1 -1
- package/lmvz-components/{p-a6fe9b61.entry.js → p-7cbfbc88.entry.js} +1 -1
- package/lmvz-components/p-87f21ac9.entry.js +1 -0
- package/lmvz-components/{p-a680a7b2.entry.js → p-8ba6ec19.entry.js} +1 -1
- package/lmvz-components/p-93b781ca.entry.js +1 -0
- package/lmvz-components/p-BPa0FHVO.js +1 -0
- package/lmvz-components/p-BlkpdeQI.js +1 -0
- package/lmvz-components/p-DAikapVO.js +1 -0
- package/lmvz-components/p-DVab4vzV.js +2 -0
- package/lmvz-components/{p-BeY96W7m.js → p-Wi9d2-w9.js} +1 -1
- package/lmvz-components/p-c884c76e.entry.js +1 -0
- package/lmvz-components/{p-eabbf901.entry.js → p-d73bb7fd.entry.js} +1 -1
- package/lmvz-components/{p-137b1fe1.entry.js → p-e35f49a1.entry.js} +1 -1
- package/lmvz-components/p-ebad823c.entry.js +1 -0
- package/lmvz-components/p-edec4d09.entry.js +1 -0
- package/lmvz-components/{p-88661c50.entry.js → p-efd9d50e.entry.js} +1 -1
- package/lmvz-components/p-f24f5207.entry.js +1 -0
- package/lmvz-components/p-f911691c.entry.js +1 -0
- package/manifest.json +72 -39
- package/package.json +2 -1
- package/types/components/lmvz-input/lmvz-input.d.ts +0 -2
- package/types/components/lmvz-popover/lmvz-popover.d.ts +0 -1
- package/types/components/lmvz-select/lmvz-select.d.ts +12 -3
- package/types/components/lmvz-snackbar/public.d.ts +6 -0
- package/types/components/lmvz-tabs/lmvz-tabs.d.ts +1 -0
- package/types/components.d.ts +39 -19
- package/types/index.d.ts +5 -0
- package/types/utils/aria/directional-focus-controller.d.ts +9 -7
- package/types/utils/icons/public.d.ts +6 -0
- package/components/p--FDdvoIg.js +0 -1
- package/components/p-BApwCp0R.js +0 -1
- package/components/p-BPYBmylI.js +0 -1
- package/components/p-C5gRiLRR.js +0 -1
- package/components/p-CrQCHVKL.js +0 -1
- package/components/p-DiRcp9V6.js +0 -1
- package/components/p-DqdrUt_G.js +0 -1
- package/lmvz-components/p-00489151.entry.js +0 -1
- package/lmvz-components/p-0af0211a.entry.js +0 -1
- package/lmvz-components/p-398b5cf4.entry.js +0 -1
- package/lmvz-components/p-40716828.entry.js +0 -1
- package/lmvz-components/p-492adf21.entry.js +0 -1
- package/lmvz-components/p-4deaa010.entry.js +0 -1
- package/lmvz-components/p-4fa6e72f.entry.js +0 -1
- package/lmvz-components/p-57a366e6.entry.js +0 -1
- package/lmvz-components/p-70f1e31a.entry.js +0 -1
- package/lmvz-components/p-91eb71bb.entry.js +0 -1
- package/lmvz-components/p-BOXP1Vx0.js +0 -2
- package/lmvz-components/p-CHxiS3ja.js +0 -1
- package/lmvz-components/p-e14058e1.entry.js +0 -1
- package/lmvz-components/p-f3f0ed49.entry.js +0 -1
- package/lmvz-components/p-f516a949.entry.js +0 -1
|
@@ -39,7 +39,6 @@ export class LmvzPopover {
|
|
|
39
39
|
}
|
|
40
40
|
componentDidLoad() {
|
|
41
41
|
autoAssignId(this.el);
|
|
42
|
-
this.syncContainerId();
|
|
43
42
|
}
|
|
44
43
|
handleOpenChange(isOpen) {
|
|
45
44
|
if (isOpen) {
|
|
@@ -66,23 +65,16 @@ export class LmvzPopover {
|
|
|
66
65
|
this.removeCloseHandlers();
|
|
67
66
|
this.extEventController.abort();
|
|
68
67
|
}
|
|
69
|
-
syncContainerId() {
|
|
70
|
-
const hostId = this.el.getAttribute('id');
|
|
71
|
-
if (!hostId || !this.containerEl)
|
|
72
|
-
return;
|
|
73
|
-
this.containerEl.id = hostId;
|
|
74
|
-
}
|
|
75
68
|
setupAnchorEl() {
|
|
76
69
|
const { anchorEl } = this;
|
|
77
70
|
if (!anchorEl) {
|
|
78
71
|
console.warn('no anchor element set for', this);
|
|
79
72
|
return;
|
|
80
73
|
}
|
|
81
|
-
this.syncContainerId();
|
|
82
74
|
if (!anchorEl.hasAttribute('aria-haspopup')) {
|
|
83
75
|
anchorEl.setAttribute('aria-haspopup', this.containerRole === 'dialog' ? 'dialog' : this.containerRole);
|
|
84
76
|
}
|
|
85
|
-
anchorEl.setAttribute('aria-controls', this.
|
|
77
|
+
anchorEl.setAttribute('aria-controls', this.el.getAttribute('id'));
|
|
86
78
|
if (!anchorEl.hasAttribute('aria-expanded')) {
|
|
87
79
|
anchorEl.setAttribute('aria-expanded', this.open ? 'true' : 'false');
|
|
88
80
|
}
|
|
@@ -110,7 +102,6 @@ export class LmvzPopover {
|
|
|
110
102
|
await waitFrame();
|
|
111
103
|
await this.updatePosition();
|
|
112
104
|
autoAssignId(this.el);
|
|
113
|
-
this.syncContainerId();
|
|
114
105
|
this.applyAnchorAriaOpen();
|
|
115
106
|
this.lmvzOpen.emit();
|
|
116
107
|
await waitFrame();
|
|
@@ -189,7 +180,7 @@ export class LmvzPopover {
|
|
|
189
180
|
this.closureController?.abort();
|
|
190
181
|
}
|
|
191
182
|
render() {
|
|
192
|
-
return (h(Host, { key: '
|
|
183
|
+
return (h(Host, { key: '83529aeac05cdc706193fa8bbbcc8f8672756111', role: this.containerRole, "aria-label": this.label || undefined }, h("div", { key: '97c255e788806c0dec2f4ed04c6fc815150912a2', part: "container", class: `container lmvz-wrapper-card-${this.size}`, ref: (el) => (this.containerEl = el) }, h("slot", { key: 'e4ea69d179557e7d34f1475c07c9284ea8d10a67', ref: (el) => (this.slotEl = el) }))));
|
|
193
184
|
}
|
|
194
185
|
static get is() { return "lmvz-popover"; }
|
|
195
186
|
static get encapsulation() { return "shadow"; }
|
|
@@ -60,6 +60,8 @@
|
|
|
60
60
|
--lmvz-select-helper-color: var(--lmvz-semantic-color-on-surface-input-secondary, #545454);
|
|
61
61
|
--lmvz-select-focus-color: var(--lmvz-semantic-color-status-on-active, #0e7ab4);
|
|
62
62
|
--lmvz-select-error-color: var(--lmvz-semantic-color-status-on-danger, #a31419);
|
|
63
|
+
/* Sizes the trailing chevron icon, shared by single- and multiselect modes. */
|
|
64
|
+
--lmvz-select-chevron-size: var(--lmvz-component-icon-size-2xs, clamp(0.63rem, 0.59rem + 0.13vw, 0.75rem));
|
|
63
65
|
|
|
64
66
|
padding-top: var(--lmvz-internal-select-floating-label-top-offset);
|
|
65
67
|
}
|
|
@@ -124,24 +126,12 @@ label > span[aria-hidden='true'],
|
|
|
124
126
|
z-index: 1;
|
|
125
127
|
transition: border-color 0.15s ease;
|
|
126
128
|
}
|
|
127
|
-
:host(:not([disabled], [
|
|
129
|
+
:host(:not([disabled], [error])) .select-wrapper:hover .select-trigger {
|
|
128
130
|
border-color: var(--lmvz-select-border-color-hover);
|
|
129
131
|
}
|
|
130
132
|
:host([error]) .select-trigger {
|
|
131
133
|
border-color: var(--lmvz-select-error-color);
|
|
132
134
|
}
|
|
133
|
-
:host([highlighted]) .select-trigger {
|
|
134
|
-
background-color: var(--lmvz-semantic-color-status-active-alternate, #0f8acc);
|
|
135
|
-
border-color: var(--lmvz-semantic-color-border-active, #0f8acc);
|
|
136
|
-
color: var(--lmvz-semantic-color-status-on-active-alternate, #ffffff);
|
|
137
|
-
}
|
|
138
|
-
:host([highlighted]) .select-trigger > span:first-child {
|
|
139
|
-
color: var(--lmvz-semantic-color-status-on-active-alternate, #ffffff);
|
|
140
|
-
}
|
|
141
|
-
:host([highlighted]) label.floating-label {
|
|
142
|
-
background-color: var(--lmvz-semantic-color-status-active-alternate, #0f8acc);
|
|
143
|
-
color: var(--lmvz-semantic-color-status-on-active-alternate, #ffffff);
|
|
144
|
-
}
|
|
145
135
|
:host:has(:focus-visible) .select-trigger {
|
|
146
136
|
outline: var(--lmvz-ds-outline, 1px solid #0e7ab4);
|
|
147
137
|
outline-offset: var(--lmvz-ds-outline-offset, clamp(0.25rem, 0.19rem + 0.26vw, 0.5rem));
|
|
@@ -156,21 +146,31 @@ label > span[aria-hidden='true'],
|
|
|
156
146
|
white-space: nowrap;
|
|
157
147
|
text-align: left;
|
|
158
148
|
}
|
|
159
|
-
|
|
160
|
-
:host(:not([highlighted])) .select-wrapper.has-value .select-trigger > span:first-child {
|
|
149
|
+
.select-wrapper.has-value .select-trigger > span:first-child {
|
|
161
150
|
color: var(--lmvz-semantic-color-int-on-secondary-active, #000000);
|
|
162
151
|
}
|
|
163
|
-
|
|
152
|
+
/* Trailing chevron child span, shared by single- and multiselect modes. Scoped with the
|
|
153
|
+
adjacent-sibling combinator (rather than :last-child) so it never matches the leading text/chip
|
|
154
|
+
span. */
|
|
155
|
+
.select-trigger > span:first-child + span {
|
|
164
156
|
flex-shrink: 0;
|
|
165
157
|
display: flex;
|
|
166
158
|
align-items: center;
|
|
167
159
|
justify-content: center;
|
|
168
160
|
}
|
|
169
161
|
.select-trigger svg {
|
|
170
|
-
width: var(--lmvz-
|
|
171
|
-
height: var(--lmvz-
|
|
162
|
+
width: var(--lmvz-select-chevron-size);
|
|
163
|
+
height: var(--lmvz-select-chevron-size);
|
|
172
164
|
flex-shrink: 0;
|
|
173
165
|
}
|
|
166
|
+
/* Chip row — rendered inline inside the trigger's leading text span (.select-trigger >
|
|
167
|
+
span:first-child). Overflowing chips are truncated with an ellipsis to enforce single line. */
|
|
168
|
+
.select-trigger > span:first-child lmvz-chip {
|
|
169
|
+
vertical-align: middle;
|
|
170
|
+
}
|
|
171
|
+
.select-trigger > span:first-child lmvz-chip + lmvz-chip {
|
|
172
|
+
margin-inline-start: var(--lmvz-select-gap);
|
|
173
|
+
}
|
|
174
174
|
/* Native <option>/<optgroup> markup is only a data source for the internal listbox; never shown. */
|
|
175
175
|
.lmvz-select-native-options {
|
|
176
176
|
display: none;
|
|
@@ -199,61 +199,84 @@ label > span[aria-hidden='true'],
|
|
|
199
199
|
--lmvz-select-padding-x: var(--lmvz-component-input-padding-sm, clamp(0.75rem, 0.72rem + 0.13vw, 0.88rem));
|
|
200
200
|
--lmvz-select-gap: var(--lmvz-component-input-gap-sm, clamp(0.38rem, 0.31rem + 0.26vw, 0.63rem));
|
|
201
201
|
--lmvz-select-label-font-size: var(--lmvz-component-body-2xs-font-size, clamp(0.5rem, 0.47rem + 0.13vw, 0.63rem));
|
|
202
|
+
--lmvz-select-chevron-size: var(--lmvz-component-icon-size-4xs, clamp(0.5rem, 0.47rem + 0.13vw, 0.63rem));
|
|
202
203
|
}
|
|
203
204
|
:host([size='small']) .select-trigger > span:first-child {
|
|
204
205
|
font-size: var(--lmvz-component-body-sm-font-size, clamp(0.75rem, 0.72rem + 0.13vw, 0.88rem));
|
|
205
206
|
}
|
|
206
|
-
:host([size='small']) .select-trigger svg {
|
|
207
|
-
width: var(--lmvz-component-icon-size-4xs, clamp(0.5rem, 0.47rem + 0.13vw, 0.63rem));
|
|
208
|
-
height: var(--lmvz-component-icon-size-4xs, clamp(0.5rem, 0.47rem + 0.13vw, 0.63rem));
|
|
209
|
-
}
|
|
210
207
|
:host([size='large']) {
|
|
211
208
|
--lmvz-select-height: var(--lmvz-component-input-size-lg, clamp(2.75rem, 2.69rem + 0.26vw, 3rem));
|
|
212
209
|
--lmvz-select-padding-x: var(--lmvz-component-input-padding-lg, clamp(1rem, 0.94rem + 0.26vw, 1.25rem));
|
|
213
210
|
--lmvz-select-gap: var(--lmvz-component-input-gap-lg, clamp(0.75rem, 0.69rem + 0.26vw, 1rem));
|
|
214
211
|
--lmvz-select-label-font-size: var(--lmvz-component-body-sm-font-size, clamp(0.75rem, 0.72rem + 0.13vw, 0.88rem));
|
|
212
|
+
--lmvz-select-chevron-size: var(--lmvz-component-icon-size-xs, clamp(0.75rem, 0.72rem + 0.13vw, 0.88rem));
|
|
215
213
|
}
|
|
216
214
|
:host([size='large']) .select-trigger > span:first-child {
|
|
217
215
|
font-size: var(--lmvz-component-body-lg-font-size, clamp(1rem, 0.97rem + 0.13vw, 1.13rem));
|
|
218
216
|
}
|
|
219
|
-
:host([size='large']) .select-trigger svg {
|
|
220
|
-
width: var(--lmvz-component-icon-size-xs, clamp(0.75rem, 0.72rem + 0.13vw, 0.88rem));
|
|
221
|
-
height: var(--lmvz-component-icon-size-xs, clamp(0.75rem, 0.72rem + 0.13vw, 0.88rem));
|
|
222
|
-
}
|
|
223
|
-
/*
|
|
224
|
-
* Option-list item styling for the `role="option"` elements rendered inside the
|
|
225
|
-
* `lmvz-popover` (containerRole="listbox") popup. The token set mirrors the states
|
|
226
|
-
* `lmvz-action-list` applies to its `<lmvz-button>`/`<button>` items (tertiary variant),
|
|
227
|
-
* so the listbox looks visually identical to an action-list item:
|
|
228
|
-
* - default: --lmvz-semantic-color-int-tertiary / --lmvz-semantic-color-int-on-tertiary
|
|
229
|
-
* - hover: --lmvz-semantic-color-int-tertiary-hover / --lmvz-semantic-color-int-on-tertiary-hover
|
|
230
|
-
* - active: --lmvz-semantic-color-int-tertiary-active / --lmvz-semantic-color-int-on-tertiary-active
|
|
231
|
-
* - disabled: --lmvz-component-input-disabled-opacity (opacity, same token as lib-styles buttons fragment)
|
|
232
|
-
* - focus: --lmvz-ds-outline / --lmvz-ds-outline-offset (same as lib-styles buttons fragment focus-visible)
|
|
233
|
-
* "selected" has no action-list equivalent (action-list is a menu, not a listbox), so it
|
|
234
|
-
* reuses this component's own highlighted-state tokens for consistency with the trigger.
|
|
235
|
-
* "active" (`data-active="true"`) is this component's own addition: since the combobox uses
|
|
236
|
-
* the activedescendant model, the highlighted option never receives real DOM focus, so
|
|
237
|
-
* `:hover`/`:focus-visible` cannot indicate it to sighted keyboard users — `data-active` is
|
|
238
|
-
* set by the host from `ListboxController`'s active id and styled the same as hover/focus.
|
|
239
|
-
*/
|
|
240
217
|
.lmvz-select-option {
|
|
241
218
|
--lmvz-select-option-background: var(--lmvz-semantic-color-int-tertiary, #ffffff);
|
|
242
219
|
--lmvz-select-option-color: var(--lmvz-semantic-color-int-on-tertiary, #000000);
|
|
243
220
|
|
|
244
|
-
|
|
221
|
+
/* The configuration here will match lmvz-action-list's items, though semantic states might differ intentionally */
|
|
222
|
+
--lmvz-button-background-override: var(--lmvz-select-option-background);
|
|
223
|
+
--lmvz-button-color-override: var(--lmvz-select-option-color);
|
|
224
|
+
--lmvz-button-radius-override: var(--lmvz-semantic-border-radius-md, 6px);
|
|
225
|
+
--lmvz-button-padding-inline-override: var(--lmvz-component-input-padding-sm, clamp(0.75rem, 0.72rem + 0.13vw, 0.88rem));
|
|
226
|
+
--lmvz-button-padding-block-override: var(--lmvz-component-input-padding-sm, clamp(0.75rem, 0.72rem + 0.13vw, 0.88rem));
|
|
227
|
+
--lmvz-button-content-justification: normal;
|
|
228
|
+
--lmvz-button-font-override: var(--lmvz-typography-body-md-strong, 500 clamp(0.88rem, 0.84rem + 0.13vw, 1rem) / 1.5
|
|
229
|
+
Router);
|
|
230
|
+
|
|
231
|
+
/* the (invalid nested) import will be handled by postcss */
|
|
232
|
+
/* stylelint-disable-next-line no-invalid-position-at-import-rule */
|
|
233
|
+
/* stylelint-disable nesting-selector-no-missing-scoping-root */
|
|
234
|
+
& {
|
|
235
|
+
/* variables are declared on :host
|
|
236
|
+
so that outer ::slotted(lmvz-button) overrides are inherited correctly via shadow inheritance.
|
|
237
|
+
They are also declared here so that non-shadow consumers have the default values in scope. */
|
|
238
|
+
|
|
239
|
+
/* secondary styling is default, primary is explicit */
|
|
240
|
+
|
|
241
|
+
--lmvz-button-background: var(--lmvz-button-background-override, var(--lmvz-semantic-color-int-secondary, #f0f0f0));
|
|
242
|
+
--lmvz-button-color: var(--lmvz-button-color-override, var(--lmvz-semantic-color-int-on-secondary, #000000));
|
|
243
|
+
--lmvz-button-radius: var(--lmvz-button-radius-override, var(--lmvz-component-input-radius-default, 999px));
|
|
244
|
+
--lmvz-button-padding-inline: var(--lmvz-button-padding-inline-override, var(--lmvz-button-padding, var(--lmvz-component-input-padding-md, clamp(0.88rem, 0.84rem + 0.13vw, 1rem))));
|
|
245
|
+
--lmvz-button-padding-block: var(--lmvz-button-padding-block-override, var(--lmvz-button-padding, var(--lmvz-component-input-padding-md, clamp(0.88rem, 0.84rem + 0.13vw, 1rem))));
|
|
246
|
+
--lmvz-button-gap: var(--lmvz-button-gap-override, var(--lmvz-component-input-gap-md, clamp(0.5rem, 0.44rem + 0.26vw, 0.75rem)));
|
|
247
|
+
--lmvz-button-min-height: var(--lmvz-button-min-height-override, var(--lmvz-component-input-size-md, clamp(2.5rem, 2.44rem + 0.26vw, 2.75rem)));
|
|
248
|
+
--lmvz-button-font: var(--lmvz-button-font-override, var(--lmvz-typography-label-md-strong, normal 700 clamp(0.88rem, 0.84rem + 0.13vw, 1rem) / 1.5
|
|
249
|
+
Router));
|
|
250
|
+
--lmvz-button-border-width: var(--lmvz-button-border-width-override, 0);
|
|
251
|
+
--lmvz-button-border-color: var(--lmvz-button-border-color-override, transparent);
|
|
252
|
+
|
|
253
|
+
display: inline-flex;
|
|
245
254
|
align-items: center;
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
255
|
+
justify-content: var(--lmvz-button-content-justification, center);
|
|
256
|
+
gap: var(--lmvz-button-gap, var(--lmvz-component-input-gap-md, clamp(0.5rem, 0.44rem + 0.26vw, 0.75rem)));
|
|
257
|
+
|
|
258
|
+
box-sizing: border-box; /* to inlclude paddings & border in min-height */
|
|
259
|
+
padding-block: var(--lmvz-button-padding-block, var(--lmvz-component-input-padding-md, clamp(0.88rem, 0.84rem + 0.13vw, 1rem)));
|
|
260
|
+
padding-inline: var(--lmvz-button-padding-inline, var(--lmvz-component-input-padding-md, clamp(0.88rem, 0.84rem + 0.13vw, 1rem)));
|
|
261
|
+
min-height: var(--lmvz-button-min-height, var(--lmvz-component-input-size-md, clamp(2.5rem, 2.44rem + 0.26vw, 2.75rem)));
|
|
262
|
+
border: var(--lmvz-button-border-width, 0) solid var(--lmvz-button-border-color, transparent);
|
|
263
|
+
border-radius: var(--lmvz-button-radius, var(--lmvz-component-input-radius-default, 999px));
|
|
264
|
+
|
|
265
|
+
background-color: var(--lmvz-button-background);
|
|
266
|
+
color: var(--lmvz-button-color);
|
|
251
267
|
cursor: pointer;
|
|
252
|
-
font: var(--lmvz-
|
|
253
|
-
|
|
268
|
+
font: var(--lmvz-button-font);
|
|
269
|
+
text-decoration: none;
|
|
270
|
+
white-space: nowrap;
|
|
254
271
|
transition:
|
|
255
272
|
background-color 0.15s ease,
|
|
256
|
-
color 0.15s ease
|
|
273
|
+
color 0.15s ease,
|
|
274
|
+
border-color 0.15s ease,
|
|
275
|
+
box-shadow 0.15s ease;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
display: flex;
|
|
257
280
|
}
|
|
258
281
|
.lmvz-select-option:not([aria-disabled='true']):hover {
|
|
259
282
|
--lmvz-select-option-background: var(--lmvz-semantic-color-int-tertiary-hover, #f0f0f0);
|
|
@@ -273,7 +296,7 @@ label > span[aria-hidden='true'],
|
|
|
273
296
|
--lmvz-select-option-background: var(--lmvz-semantic-color-int-tertiary-hover, #f0f0f0);
|
|
274
297
|
--lmvz-select-option-color: var(--lmvz-semantic-color-int-on-tertiary-hover, #000000);
|
|
275
298
|
}
|
|
276
|
-
.lmvz-select-option[aria-selected='true'] {
|
|
299
|
+
:host(:not([multiple])) .lmvz-select-option[aria-selected='true'] {
|
|
277
300
|
--lmvz-select-option-background: var(--lmvz-semantic-color-status-active-alternate, #0f8acc);
|
|
278
301
|
--lmvz-select-option-color: var(--lmvz-semantic-color-status-on-active-alternate, #ffffff);
|
|
279
302
|
}
|
|
@@ -282,3 +305,29 @@ label > span[aria-hidden='true'],
|
|
|
282
305
|
pointer-events: none;
|
|
283
306
|
opacity: var(--lmvz-component-input-disabled-opacity, 40%);
|
|
284
307
|
}
|
|
308
|
+
/*
|
|
309
|
+
* Decorative, aria-hidden checkbox-style indicator shown per option in multiselect mode.
|
|
310
|
+
* Mirrors lmvz-checkbox's box/indicator sizing tokens for visual consistency across the DS.
|
|
311
|
+
* `aria-selected` on the option (above) remains the real, sole selection semantic; this is
|
|
312
|
+
* purely a visual affordance.
|
|
313
|
+
*/
|
|
314
|
+
.lmvz-select-option-checkbox {
|
|
315
|
+
display: flex;
|
|
316
|
+
align-items: center;
|
|
317
|
+
justify-content: center;
|
|
318
|
+
width: var(--lmvz-global-s18, 18px);
|
|
319
|
+
height: var(--lmvz-global-s18, 18px);
|
|
320
|
+
border: var(--lmvz-semantic-border-width-default, 1px) solid currentcolor;
|
|
321
|
+
border-radius: var(--lmvz-global-s4, 4px);
|
|
322
|
+
flex-shrink: 0;
|
|
323
|
+
}
|
|
324
|
+
.lmvz-select-option-checkbox-indicator {
|
|
325
|
+
display: flex;
|
|
326
|
+
align-items: center;
|
|
327
|
+
justify-content: center;
|
|
328
|
+
line-height: 0;
|
|
329
|
+
}
|
|
330
|
+
.lmvz-select-option-checkbox-indicator svg {
|
|
331
|
+
width: 100%;
|
|
332
|
+
height: 100%;
|
|
333
|
+
}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
import checkmark from "@lmvz-ds/icons/assets/checkmark.svg";
|
|
2
|
+
import { toValidSvgStringWithFallback } from "@lmvz-ds/lib-ts/validation/svg.js";
|
|
3
|
+
import { Fragment, h, Host } from "@stencil/core";
|
|
2
4
|
import { AriaValidationController } from "../../utils/aria/aria-validation-controller";
|
|
3
5
|
import { ListboxController } from "../../utils/aria/listbox-controller";
|
|
4
6
|
import { ReactiveControllerHost } from "../../utils/stencil/reactive-controller-host";
|
|
5
7
|
let selectIdCounter = 0;
|
|
8
|
+
const CHECKMARK_SVG = toValidSvgStringWithFallback(checkmark);
|
|
6
9
|
export class LmvzSelect extends ReactiveControllerHost {
|
|
7
10
|
el;
|
|
8
11
|
get validationEl() {
|
|
@@ -17,6 +20,8 @@ export class LmvzSelect extends ReactiveControllerHost {
|
|
|
17
20
|
optionsMutationObserver;
|
|
18
21
|
initialValue;
|
|
19
22
|
initialValueCaptured = false;
|
|
23
|
+
initialValues;
|
|
24
|
+
initialValuesCaptured = false;
|
|
20
25
|
flatOptions = [];
|
|
21
26
|
optionsById = new Map();
|
|
22
27
|
listboxController = new ListboxController({
|
|
@@ -50,6 +55,8 @@ export class LmvzSelect extends ReactiveControllerHost {
|
|
|
50
55
|
}
|
|
51
56
|
lmvzChange;
|
|
52
57
|
value;
|
|
58
|
+
multiple = false;
|
|
59
|
+
values;
|
|
53
60
|
label;
|
|
54
61
|
helperText;
|
|
55
62
|
nativeError = false;
|
|
@@ -65,14 +72,23 @@ export class LmvzSelect extends ReactiveControllerHost {
|
|
|
65
72
|
required = false;
|
|
66
73
|
name;
|
|
67
74
|
size = 'default';
|
|
68
|
-
highlighted = false;
|
|
69
75
|
selectedLabel = '';
|
|
70
76
|
selectedId;
|
|
71
77
|
activeId;
|
|
72
78
|
isOpen = false;
|
|
73
79
|
optionGroups = [];
|
|
74
80
|
get hasValue() {
|
|
75
|
-
return Boolean(this.value);
|
|
81
|
+
return this.multiple ? Boolean(this.values && this.values.length > 0) : Boolean(this.value);
|
|
82
|
+
}
|
|
83
|
+
get triggerAriaLabel() {
|
|
84
|
+
if (this.multiple) {
|
|
85
|
+
const count = this.values?.length ?? 0;
|
|
86
|
+
return count > 0 ? `${this.label}, ${count} selected` : this.label;
|
|
87
|
+
}
|
|
88
|
+
return this.hasValue ? `${this.label}, ${this.selectedLabel}` : this.label;
|
|
89
|
+
}
|
|
90
|
+
get chipSize() {
|
|
91
|
+
return this.size === 'small' ? 'small' : 'default';
|
|
76
92
|
}
|
|
77
93
|
componentWillLoad() {
|
|
78
94
|
this.updateValidity();
|
|
@@ -119,17 +135,28 @@ export class LmvzSelect extends ReactiveControllerHost {
|
|
|
119
135
|
formAssociatedCallback(form) {
|
|
120
136
|
if (!form)
|
|
121
137
|
return;
|
|
122
|
-
this.
|
|
138
|
+
this.syncFormValue();
|
|
123
139
|
}
|
|
124
140
|
formResetCallback() {
|
|
125
141
|
this.internals.setValidity?.({});
|
|
126
|
-
this.
|
|
142
|
+
if (this.multiple) {
|
|
143
|
+
this.values = this.initialValues ? [...this.initialValues] : [];
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
this.value = this.initialValue;
|
|
147
|
+
}
|
|
127
148
|
this.updateValidity();
|
|
128
149
|
}
|
|
129
150
|
formStateRestoreCallback(state) {
|
|
151
|
+
if (this.multiple) {
|
|
152
|
+
this.values = state instanceof FormData && this.name ? state.getAll(this.name).map(String) : [];
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
130
155
|
this.value = state;
|
|
131
156
|
}
|
|
132
157
|
handleValueChange(newValue) {
|
|
158
|
+
if (this.multiple)
|
|
159
|
+
return;
|
|
133
160
|
this.applySelectionFromValue();
|
|
134
161
|
if (this.selectedId && !this.isOpen) {
|
|
135
162
|
this.listboxController.setActiveId(this.selectedId);
|
|
@@ -137,6 +164,12 @@ export class LmvzSelect extends ReactiveControllerHost {
|
|
|
137
164
|
this.internals.setFormValue?.(newValue ?? '');
|
|
138
165
|
this.updateValidity();
|
|
139
166
|
}
|
|
167
|
+
handleValuesChange() {
|
|
168
|
+
if (!this.multiple)
|
|
169
|
+
return;
|
|
170
|
+
this.syncFormValue();
|
|
171
|
+
this.updateValidity();
|
|
172
|
+
}
|
|
140
173
|
handleRequiredChange() {
|
|
141
174
|
this.updateValidity();
|
|
142
175
|
}
|
|
@@ -154,15 +187,31 @@ export class LmvzSelect extends ReactiveControllerHost {
|
|
|
154
187
|
this.flatOptions = flat;
|
|
155
188
|
this.optionsById = new Map(flat.map((option) => [option.id, option]));
|
|
156
189
|
this.optionGroups = groups;
|
|
157
|
-
if (
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
190
|
+
if (this.multiple) {
|
|
191
|
+
if (!this.values) {
|
|
192
|
+
const preselected = flat.filter((option) => option.selected && !option.disabled).map((option) => option.value);
|
|
193
|
+
if (preselected.length > 0) {
|
|
194
|
+
this.values = preselected;
|
|
195
|
+
}
|
|
161
196
|
}
|
|
162
197
|
}
|
|
163
|
-
|
|
198
|
+
else {
|
|
199
|
+
if (!this.value) {
|
|
200
|
+
const preselected = flat.find((option) => option.selected && !option.disabled);
|
|
201
|
+
if (preselected) {
|
|
202
|
+
this.value = preselected.value;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
this.applySelectionFromValue();
|
|
206
|
+
}
|
|
164
207
|
this.listboxController.setOptions(flat.map(({ id, label, disabled }) => ({ id, label, disabled })));
|
|
165
|
-
if (
|
|
208
|
+
if (this.multiple) {
|
|
209
|
+
if (!this.initialValuesCaptured) {
|
|
210
|
+
this.initialValues = this.values ? [...this.values] : [];
|
|
211
|
+
this.initialValuesCaptured = true;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
else if (!this.initialValueCaptured) {
|
|
166
215
|
this.initialValue = this.value;
|
|
167
216
|
this.initialValueCaptured = true;
|
|
168
217
|
}
|
|
@@ -173,8 +222,28 @@ export class LmvzSelect extends ReactiveControllerHost {
|
|
|
173
222
|
this.selectedLabel = match?.label ?? '';
|
|
174
223
|
this.listboxController.setSelectedId(match?.id);
|
|
175
224
|
}
|
|
225
|
+
isOptionSelected(option) {
|
|
226
|
+
if (this.multiple) {
|
|
227
|
+
return (this.values ?? []).includes(option.value);
|
|
228
|
+
}
|
|
229
|
+
return option.id === this.selectedId;
|
|
230
|
+
}
|
|
231
|
+
syncFormValue() {
|
|
232
|
+
if (this.multiple) {
|
|
233
|
+
const formData = new FormData();
|
|
234
|
+
if (this.name) {
|
|
235
|
+
for (const value of this.values ?? []) {
|
|
236
|
+
formData.append(this.name, value);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
this.internals.setFormValue?.(formData);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
this.internals.setFormValue?.(this.value ?? '');
|
|
243
|
+
}
|
|
176
244
|
updateValidity() {
|
|
177
|
-
|
|
245
|
+
const missing = this.multiple ? !(this.values && this.values.length > 0) : !this.value;
|
|
246
|
+
if (this.required && missing) {
|
|
178
247
|
this.internals.setValidity?.({ valueMissing: true }, 'Please select a value.', this.triggerEl);
|
|
179
248
|
return;
|
|
180
249
|
}
|
|
@@ -188,6 +257,13 @@ export class LmvzSelect extends ReactiveControllerHost {
|
|
|
188
257
|
const option = this.optionsById.get(id);
|
|
189
258
|
if (!option)
|
|
190
259
|
return;
|
|
260
|
+
if (this.multiple) {
|
|
261
|
+
const current = this.values ?? [];
|
|
262
|
+
const updated = current.includes(option.value) ? current.filter((value) => value !== option.value) : [...current, option.value];
|
|
263
|
+
this.values = updated;
|
|
264
|
+
this.lmvzChange.emit(updated);
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
191
267
|
const isNewValue = option.value !== this.value;
|
|
192
268
|
this.value = option.value;
|
|
193
269
|
if (isNewValue) {
|
|
@@ -250,12 +326,26 @@ export class LmvzSelect extends ReactiveControllerHost {
|
|
|
250
326
|
return this.optionGroups.map((group, groupIndex) => group.label ? (h("div", { role: "group", "aria-label": group.label, key: `lmvz-select-group-${groupIndex}` }, group.options.map((option) => this.renderOption(option)))) : (group.options.map((option) => this.renderOption(option))));
|
|
251
327
|
}
|
|
252
328
|
renderOption(option) {
|
|
253
|
-
|
|
329
|
+
const selected = this.isOptionSelected(option);
|
|
330
|
+
return (h("div", { id: option.id, key: option.id, role: "option", class: "lmvz-select-option", "aria-selected": selected ? 'true' : 'false', "aria-disabled": option.disabled ? 'true' : undefined, "data-active": option.id === this.activeId ? 'true' : undefined, onMouseDown: (event) => event.preventDefault(), onClick: () => this.handleOptionClick(option) }, this.multiple && (h("span", { class: "lmvz-select-option-checkbox", "aria-hidden": "true" }, selected && h("span", { class: "lmvz-select-option-checkbox-indicator", innerHTML: CHECKMARK_SVG }))), option.label));
|
|
331
|
+
}
|
|
332
|
+
renderChips() {
|
|
333
|
+
const values = this.values ?? [];
|
|
334
|
+
const occurrenceCounts = new Map();
|
|
335
|
+
return (h(Fragment, null, values.map((value) => {
|
|
336
|
+
const occurrence = occurrenceCounts.get(value) ?? 0;
|
|
337
|
+
occurrenceCounts.set(value, occurrence + 1);
|
|
338
|
+
const chipKey = occurrence === 0 ? value : `${value}-dup-${occurrence}`;
|
|
339
|
+
const option = this.flatOptions.find((candidate) => candidate.value === value);
|
|
340
|
+
const chipLabel = option?.label ?? value;
|
|
341
|
+
return (h("lmvz-chip", { key: chipKey, size: this.chipSize }, chipLabel));
|
|
342
|
+
})));
|
|
254
343
|
}
|
|
255
344
|
render() {
|
|
256
345
|
const hasValue = this.hasValue;
|
|
257
346
|
const shouldShowLabel = hasValue;
|
|
258
|
-
|
|
347
|
+
const showChips = this.multiple && hasValue;
|
|
348
|
+
return (h(Host, { key: '77cb72cdce635eae0f9a29cb9121dd7d16955219' }, h("div", { key: 'cc6c04090457df17c6a9e74354fc21875d378642', class: hasValue ? 'select-wrapper has-value' : 'select-wrapper' }, h("label", { key: '8dc52469a7b3333578494b2f7bdb4e870044ac6c', htmlFor: this.triggerId, class: shouldShowLabel ? 'floating-label' : 'assistive-label', onMouseDown: (event) => event.preventDefault(), onClick: this.handleLabelClick }, this.label, this.required && shouldShowLabel && h("span", { key: 'c198fb4944e46c5219a42e16ae24dc3c414b1b00', "aria-hidden": "true" }, " *")), h("div", { key: '034cc67405aac73a6557036dea90e4644c1578ed', id: this.triggerId, ref: (el) => (this.triggerEl = el), class: "select-trigger", role: "combobox", tabIndex: this.disabled ? -1 : 0, "aria-haspopup": "listbox", "aria-expanded": String(this.isOpen), "aria-controls": this.popoverId, "aria-activedescendant": this.isOpen ? this.activeId : undefined, "aria-label": this.triggerAriaLabel, "aria-disabled": this.disabled ? 'true' : undefined, "aria-required": this.required ? 'true' : 'false', "aria-invalid": this.error ? 'true' : 'false', "aria-errormessage": this.showErrorMessage ? this.errorId : undefined, "aria-describedby": this.describedBy, onClick: this.handleTriggerClick, onKeyDown: this.handleTriggerKeydown, onBlur: this.handleTriggerBlur }, h("span", { key: 'c61c136bfaab211572a988d3b16c2746f80b1ac6' }, showChips ? this.renderChips() : hasValue ? this.selectedLabel : this.label, this.required && !hasValue && h("span", { key: '24201baae63a4f6fdaef2441d304cd8f69430fb5', "aria-hidden": "true" }, " *")), h("span", { key: '547c61dfdc83f89cf7cd0582c785b9552190e533', "aria-hidden": "true" }, h("svg", { key: 'f6a0cb7c77682aec03cd146e84712c17df5ff910', width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, h("path", { key: '35a8a50e27f18e54003974ae5b5ed578602664d3', d: "M20.3334 8.66663L12.0001 17L3.66675 8.66663", stroke: "currentColor", "stroke-width": "1.75", "stroke-linecap": "round", "stroke-linejoin": "round" })))), h("lmvz-popover", { key: '0d5b94659c23763d59638046a397963d79a5e588', id: this.popoverId, anchor: this.triggerId, open: this.isOpen, containerRole: "listbox", autoFocus: false, label: this.label, "aria-multiselectable": this.multiple ? 'true' : undefined, onLmvzClose: this.handlePopoverClose, size: "sm" }, this.renderOptionGroups()), h("div", { key: 'c4a313fe4b6c53678a4f3dafced210f00e3c93d5', class: "lmvz-select-native-options", hidden: true, "aria-hidden": "true", ref: (el) => (this.optionsSourceEl = el) }, h("slot", { key: '1fb311e6938812e68ae5155184af2e2ba7c19861', onSlotchange: this.handleSlotChange }))), this.helperText && (h("div", { key: 'accade9aae4cb2e23fa1d8f62dd9b6efdf3ddfb5', id: this.helperId, role: "status" }, this.helperText)), this.showErrorMessage && (h("div", { key: 'faa5eba225adda67b44b8a63ae98a678fddf49ad', id: this.errorId, role: "alert" }, this.errorMessage))));
|
|
259
349
|
}
|
|
260
350
|
static get is() { return "lmvz-select"; }
|
|
261
351
|
static get encapsulation() { return "scoped"; }
|
|
@@ -284,13 +374,53 @@ export class LmvzSelect extends ReactiveControllerHost {
|
|
|
284
374
|
"optional": true,
|
|
285
375
|
"docs": {
|
|
286
376
|
"tags": [],
|
|
287
|
-
"text": "Currently selected value."
|
|
377
|
+
"text": "Currently selected value. Ignored (not read or written) when `multiple` is `true` \u2014 use\n`values` instead."
|
|
288
378
|
},
|
|
289
379
|
"getter": false,
|
|
290
380
|
"setter": false,
|
|
291
381
|
"reflect": false,
|
|
292
382
|
"attribute": "value"
|
|
293
383
|
},
|
|
384
|
+
"multiple": {
|
|
385
|
+
"type": "boolean",
|
|
386
|
+
"mutable": false,
|
|
387
|
+
"complexType": {
|
|
388
|
+
"original": "boolean",
|
|
389
|
+
"resolved": "boolean",
|
|
390
|
+
"references": {}
|
|
391
|
+
},
|
|
392
|
+
"required": false,
|
|
393
|
+
"optional": false,
|
|
394
|
+
"docs": {
|
|
395
|
+
"tags": [{
|
|
396
|
+
"name": "default",
|
|
397
|
+
"text": "false"
|
|
398
|
+
}],
|
|
399
|
+
"text": "Enables multiselect mode. When `true`, `values` becomes the sole selection source (`value`\nis not read or written by the component), options toggle membership on selection instead of\nreplacing a single value, the popup stays open after selecting/deselecting an option, and the\nclosed trigger renders one `lmvz-chip` per selected value for display only. Removing a value\nis done by reselecting it in the open listbox (via `handleOptionSelect`'s toggle-off path),\nnot from a control on the chip itself."
|
|
400
|
+
},
|
|
401
|
+
"getter": false,
|
|
402
|
+
"setter": false,
|
|
403
|
+
"reflect": true,
|
|
404
|
+
"attribute": "multiple",
|
|
405
|
+
"defaultValue": "false"
|
|
406
|
+
},
|
|
407
|
+
"values": {
|
|
408
|
+
"type": "unknown",
|
|
409
|
+
"mutable": true,
|
|
410
|
+
"complexType": {
|
|
411
|
+
"original": "string[]",
|
|
412
|
+
"resolved": "string[] | undefined",
|
|
413
|
+
"references": {}
|
|
414
|
+
},
|
|
415
|
+
"required": false,
|
|
416
|
+
"optional": true,
|
|
417
|
+
"docs": {
|
|
418
|
+
"tags": [],
|
|
419
|
+
"text": "Currently selected values in multiselect mode (`multiple` true). Not attribute-reflected;\nset/read as a JS property. Preselection collects every enabled `<option selected>` (not just\nthe first) into the initial value when unset."
|
|
420
|
+
},
|
|
421
|
+
"getter": false,
|
|
422
|
+
"setter": false
|
|
423
|
+
},
|
|
294
424
|
"label": {
|
|
295
425
|
"type": "string",
|
|
296
426
|
"mutable": false,
|
|
@@ -461,29 +591,6 @@ export class LmvzSelect extends ReactiveControllerHost {
|
|
|
461
591
|
"reflect": true,
|
|
462
592
|
"attribute": "size",
|
|
463
593
|
"defaultValue": "'default'"
|
|
464
|
-
},
|
|
465
|
-
"highlighted": {
|
|
466
|
-
"type": "boolean",
|
|
467
|
-
"mutable": false,
|
|
468
|
-
"complexType": {
|
|
469
|
-
"original": "boolean",
|
|
470
|
-
"resolved": "boolean",
|
|
471
|
-
"references": {}
|
|
472
|
-
},
|
|
473
|
-
"required": false,
|
|
474
|
-
"optional": false,
|
|
475
|
-
"docs": {
|
|
476
|
-
"tags": [{
|
|
477
|
-
"name": "default",
|
|
478
|
-
"text": "false"
|
|
479
|
-
}],
|
|
480
|
-
"text": "Whether the select has an active filter or selection that should be visually\ndistinguished (e.g. a filter chip is applied).\n\nWhen `true`:\n- The host attribute `highlighted` is present (CSS: `:host([highlighted])`).\n- The host attribute `data-highlighted=\"true\"` is set for assistive-technology\n consumers that observe data attributes. When `false`, `data-highlighted` is\n set to `\"false\"`.\n\nNote: `aria-pressed` is intentionally not used here; it is reserved for toggle-button\nroles. `aria-selected` is reserved for this component's own `role=\"option\"` elements.\nThe `data-highlighted` attribute provides the accessible contract for this state."
|
|
481
|
-
},
|
|
482
|
-
"getter": false,
|
|
483
|
-
"setter": false,
|
|
484
|
-
"reflect": true,
|
|
485
|
-
"attribute": "highlighted",
|
|
486
|
-
"defaultValue": "false"
|
|
487
594
|
}
|
|
488
595
|
};
|
|
489
596
|
}
|
|
@@ -506,11 +613,11 @@ export class LmvzSelect extends ReactiveControllerHost {
|
|
|
506
613
|
"composed": true,
|
|
507
614
|
"docs": {
|
|
508
615
|
"tags": [],
|
|
509
|
-
"text": "Emitted when the user
|
|
616
|
+
"text": "Emitted when the user changes the selection. Detail contains the new value:\na `string` in single-select mode (`multiple` false/unset \u2014 same shape as before), or the\nfull updated `string[]` of selected values in multiselect mode (`multiple` true)."
|
|
510
617
|
},
|
|
511
618
|
"complexType": {
|
|
512
|
-
"original": "string",
|
|
513
|
-
"resolved": "string",
|
|
619
|
+
"original": "string | string[]",
|
|
620
|
+
"resolved": "string | string[]",
|
|
514
621
|
"references": {}
|
|
515
622
|
}
|
|
516
623
|
}];
|
|
@@ -609,6 +716,9 @@ export class LmvzSelect extends ReactiveControllerHost {
|
|
|
609
716
|
return [{
|
|
610
717
|
"propName": "value",
|
|
611
718
|
"methodName": "handleValueChange"
|
|
719
|
+
}, {
|
|
720
|
+
"propName": "values",
|
|
721
|
+
"methodName": "handleValuesChange"
|
|
612
722
|
}, {
|
|
613
723
|
"propName": "required",
|
|
614
724
|
"methodName": "handleRequiredChange"
|
|
@@ -7,10 +7,12 @@ export class LmvzTabs extends ReactiveControllerHost {
|
|
|
7
7
|
instanceId = ++tabsIdCounter;
|
|
8
8
|
tabSlotEl;
|
|
9
9
|
panelSlotEl;
|
|
10
|
+
tablistEl;
|
|
10
11
|
focusController = new DirectionalFocusController(this, {
|
|
11
12
|
orientation: 'horizontal',
|
|
12
13
|
manageTabIndex: true,
|
|
13
14
|
enableHomeAndEnd: true,
|
|
15
|
+
listenerTarget: this.tablistEl,
|
|
14
16
|
});
|
|
15
17
|
value;
|
|
16
18
|
orientation = 'horizontal';
|
|
@@ -29,6 +31,9 @@ export class LmvzTabs extends ReactiveControllerHost {
|
|
|
29
31
|
this.panelSlotEl?.addEventListener('slotchange', this.handlePanelSlotChange);
|
|
30
32
|
this.el.addEventListener('lmvzTabReady', this.handleTabReady);
|
|
31
33
|
this.handleTabSlotChange();
|
|
34
|
+
if (this.tablistEl) {
|
|
35
|
+
this.focusController.updateListenerTarget(this.tablistEl);
|
|
36
|
+
}
|
|
32
37
|
super.componentDidLoad();
|
|
33
38
|
}
|
|
34
39
|
disconnectedCallback() {
|
|
@@ -113,6 +118,7 @@ export class LmvzTabs extends ReactiveControllerHost {
|
|
|
113
118
|
orientation: this.orientation,
|
|
114
119
|
manageTabIndex: true,
|
|
115
120
|
enableHomeAndEnd: true,
|
|
121
|
+
listenerTarget: this.tablistEl,
|
|
116
122
|
});
|
|
117
123
|
this.addController(this.focusController);
|
|
118
124
|
if (this.el.isConnected) {
|
|
@@ -235,7 +241,7 @@ export class LmvzTabs extends ReactiveControllerHost {
|
|
|
235
241
|
this.selectTab(value);
|
|
236
242
|
};
|
|
237
243
|
render() {
|
|
238
|
-
return (h(Host, { key: '
|
|
244
|
+
return (h(Host, { key: 'be4fe04b1374a2793d3b1e9a658a449474efdd03', onClick: this.handleTabClick, onKeydown: this.handleKeydown }, h("div", { key: 'd91015eddf16dfad5d49e942eb86e9f568978f34', role: "tablist", "aria-orientation": this.orientation, class: "tablist", ref: (el) => (this.tablistEl = el) }, h("slot", { key: 'be0990a7c668bc96a67c01561e3142ec028dabd0', ref: (el) => (this.tabSlotEl = el) })), h("div", { key: '338323738dfdbb436d86cdb4f6041a67c1af433d', part: "panels-container", class: "panels-container" }, h("slot", { key: 'd225be099c8cb902776ce0a7dbf7dcb2aef2d03b', name: "panels", ref: (el) => (this.panelSlotEl = el) }))));
|
|
239
245
|
}
|
|
240
246
|
static get is() { return "lmvz-tabs"; }
|
|
241
247
|
static get encapsulation() { return "shadow"; }
|