@lmvz-ds/components 0.20.0 → 0.22.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 (107) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/assets/icons/close-sm.svg +3 -0
  3. package/cjs/{component-Csg9MtNK.js → component-C7cavwmZ.js} +3 -0
  4. package/cjs/{index-C2yDXRqP.js → index-lW-SEvL7.js} +67 -3
  5. package/cjs/lmvz-action.cjs.entry.js +2 -2
  6. package/cjs/{lmvz-button.cjs.entry.js → lmvz-button_2.cjs.entry.js} +139 -14
  7. package/cjs/lmvz-card.cjs.entry.js +2 -2
  8. package/cjs/lmvz-checkbox.cjs.entry.js +3 -3
  9. package/cjs/lmvz-chip.cjs.entry.js +4 -4
  10. package/cjs/lmvz-components.cjs.js +2 -2
  11. package/cjs/lmvz-header_2.cjs.entry.js +3 -3
  12. package/cjs/lmvz-input.cjs.entry.js +4 -4
  13. package/cjs/lmvz-menuitem.cjs.entry.js +3 -3
  14. package/cjs/lmvz-modal.cjs.entry.js +349 -0
  15. package/cjs/lmvz-select.cjs.entry.js +4 -4
  16. package/cjs/lmvz-toggle.cjs.entry.js +96 -0
  17. package/cjs/loader.cjs.js +2 -2
  18. package/cjs/{reactive-controller-host-BA4ZhjKA.js → reactive-controller-host-DnSTWHCF.js} +1 -1
  19. package/collection/assets/icons/close-sm.svg +3 -0
  20. package/collection/collection-manifest.json +2 -0
  21. package/collection/components/lmvz-button/lmvz-button.js +98 -10
  22. package/collection/components/lmvz-chip/lmvz-chip.js +2 -2
  23. package/collection/components/lmvz-modal/lmvz-modal.css +120 -0
  24. package/collection/components/lmvz-modal/lmvz-modal.js +448 -0
  25. package/collection/components/lmvz-select/lmvz-select.js +1 -1
  26. package/collection/components/lmvz-toggle/lmvz-toggle.css +118 -0
  27. package/collection/components/lmvz-toggle/lmvz-toggle.js +358 -0
  28. package/collection/integration/header-integration/header-integration.js +1 -1
  29. package/components/index.d.ts +4 -0
  30. package/components/index.d.ts.bak +4 -0
  31. package/components/index.js +1 -1
  32. package/components/lmvz-action.js +1 -1
  33. package/components/lmvz-button.js +1 -1
  34. package/components/lmvz-card.js +1 -1
  35. package/components/lmvz-checkbox.js +1 -1
  36. package/components/lmvz-chip.js +1 -1
  37. package/components/lmvz-header.js +1 -1
  38. package/components/lmvz-icon.js +1 -1
  39. package/components/lmvz-input.js +1 -1
  40. package/components/lmvz-menuitem.js +1 -1
  41. package/components/lmvz-modal.d.ts +11 -0
  42. package/components/lmvz-modal.d.ts.bak +11 -0
  43. package/components/lmvz-modal.js +1 -0
  44. package/components/lmvz-select.js +1 -1
  45. package/components/lmvz-toggle.d.ts +11 -0
  46. package/components/lmvz-toggle.d.ts.bak +11 -0
  47. package/components/lmvz-toggle.js +1 -0
  48. package/components/p-Boj0PCdB.js +1 -0
  49. package/components/p-CK8cAKcB.js +1 -0
  50. package/components/p-Cc6dOWwS.js +1 -0
  51. package/components/{p-BuFx0tTm.js → p-DBc1BzQb.js} +1 -1
  52. package/components/p-DOTK1OW3.js +1 -0
  53. package/esm/{component-DIrAQ4IB.js → component-DOTK1OW3.js} +3 -0
  54. package/esm/{index-saW7O-EW.js → index-Aa_425iY.js} +67 -3
  55. package/esm/lmvz-action.entry.js +2 -2
  56. package/esm/{lmvz-button.entry.js → lmvz-button_2.entry.js} +139 -15
  57. package/esm/lmvz-card.entry.js +2 -2
  58. package/esm/lmvz-checkbox.entry.js +3 -3
  59. package/esm/lmvz-chip.entry.js +4 -4
  60. package/esm/lmvz-components.js +3 -3
  61. package/esm/lmvz-header_2.entry.js +3 -3
  62. package/esm/lmvz-input.entry.js +4 -4
  63. package/esm/lmvz-menuitem.entry.js +3 -3
  64. package/esm/lmvz-modal.entry.js +347 -0
  65. package/esm/lmvz-select.entry.js +4 -4
  66. package/esm/lmvz-toggle.entry.js +94 -0
  67. package/esm/loader.js +3 -3
  68. package/esm/{reactive-controller-host-DHcPpJW7.js → reactive-controller-host-lF2kXM1x.js} +1 -1
  69. package/hydrate/index.js +559 -24
  70. package/hydrate/index.mjs +559 -24
  71. package/lmvz-components/lmvz-components.esm.js +1 -1
  72. package/lmvz-components/p-08a08b63.entry.js +1 -0
  73. package/lmvz-components/p-1b181e90.entry.js +1 -0
  74. package/lmvz-components/p-23fb2476.entry.js +1 -0
  75. package/lmvz-components/p-3846ba08.entry.js +1 -0
  76. package/lmvz-components/p-6bb145e4.entry.js +1 -0
  77. package/lmvz-components/{p-2f83d7a2.entry.js → p-7a310b1e.entry.js} +1 -1
  78. package/lmvz-components/p-Aa_425iY.js +2 -0
  79. package/lmvz-components/{p-GdMr6Qlp.js → p-DCTzMRMQ.js} +1 -1
  80. package/lmvz-components/p-DOTK1OW3.js +1 -0
  81. package/lmvz-components/p-b7940687.entry.js +1 -0
  82. package/lmvz-components/p-d984e118.entry.js +1 -0
  83. package/lmvz-components/p-db8306a5.entry.js +1 -0
  84. package/lmvz-components/p-ea335543.entry.js +1 -0
  85. package/lmvz-components/p-f8ea0eb2.entry.js +1 -0
  86. package/manifest.json +599 -5
  87. package/package.json +9 -1
  88. package/types/api/index.d.ts +6 -0
  89. package/types/components/lmvz-button/lmvz-button.d.ts +4 -0
  90. package/types/components/lmvz-modal/lmvz-modal.d.ts +58 -0
  91. package/types/components/lmvz-toggle/lmvz-toggle.d.ts +31 -0
  92. package/types/components.d.ts +196 -0
  93. package/cjs/lmvz-icon.cjs.entry.js +0 -100
  94. package/components/p-C_bScbrd.js +0 -1
  95. package/components/p-DIrAQ4IB.js +0 -1
  96. package/esm/lmvz-icon.entry.js +0 -98
  97. package/lmvz-components/p-0f7a4236.entry.js +0 -1
  98. package/lmvz-components/p-32171f4f.entry.js +0 -1
  99. package/lmvz-components/p-400b2318.entry.js +0 -1
  100. package/lmvz-components/p-43e295ba.entry.js +0 -1
  101. package/lmvz-components/p-851969bd.entry.js +0 -1
  102. package/lmvz-components/p-9f9d845d.entry.js +0 -1
  103. package/lmvz-components/p-DIrAQ4IB.js +0 -1
  104. package/lmvz-components/p-a12f95da.entry.js +0 -1
  105. package/lmvz-components/p-ab4437dc.entry.js +0 -1
  106. package/lmvz-components/p-d0a0e206.entry.js +0 -1
  107. package/lmvz-components/p-saW7O-EW.js +0 -2
@@ -0,0 +1,448 @@
1
+ import { toValidSvgStringWithFallback } from "@lmvz-ds/lib-ts/validation/svg.js";
2
+ import { Host, h } from "@stencil/core";
3
+ import closeIcon from "../../assets/icons/close-sm.svg";
4
+ import { AriaValidationController, isAriaValidationEnabled } from "../../utils/aria/aria-validation-controller";
5
+ import { getDeepActiveElement, inheritAriaAttributes } from "../../utils/component";
6
+ import { ReactiveControllerHost } from "../../utils/reactive-controller-host";
7
+ const closeIconSvg = toValidSvgStringWithFallback(closeIcon);
8
+ let modalIdCounter = 0;
9
+ export class LmvzModal extends ReactiveControllerHost {
10
+ el;
11
+ inheritedAriaAttributes = {};
12
+ dialogEl;
13
+ dialogStateObserver;
14
+ actionsStateObserver;
15
+ headerSlot;
16
+ actionsSlot;
17
+ closeButtonEl;
18
+ previouslyFocusedElement = null;
19
+ wrappedDialogShowModal;
20
+ lastActionValidationMessage;
21
+ pendingCloseReturnValue;
22
+ dialogTitleId = `lmvz-modal-title-${modalIdCounter++}`;
23
+ hasActions = false;
24
+ hasHeader = false;
25
+ open = false;
26
+ closeLabel = 'Schliessen';
27
+ dialogClose;
28
+ dialogCancel;
29
+ get dialog() {
30
+ return this.dialogEl;
31
+ }
32
+ get validationEl() {
33
+ return this.dialogEl ?? this.el;
34
+ }
35
+ get validationSlot() {
36
+ return this.actionsSlot;
37
+ }
38
+ constructor() {
39
+ super();
40
+ this.addController(new AriaValidationController(this, { validationTiming: 'slot' }));
41
+ }
42
+ handleFormDialogSubmit(event) {
43
+ const form = event.target;
44
+ const submitter = event.submitter;
45
+ const isDialogForm = form.method === 'dialog' || submitter?.getAttribute('formmethod') === 'dialog';
46
+ if (!isDialogForm)
47
+ return;
48
+ event.preventDefault();
49
+ this.dialogEl?.close(submitter?.value ?? '');
50
+ }
51
+ connectedCallback() {
52
+ this.inheritedAriaAttributes = inheritAriaAttributes(this.el, ['role']);
53
+ Object.defineProperty(this.el, 'dialog', {
54
+ configurable: true,
55
+ enumerable: true,
56
+ get: () => {
57
+ this.ensureDialogShowModalCapture();
58
+ return this.dialogEl;
59
+ },
60
+ });
61
+ super.connectedCallback();
62
+ }
63
+ componentDidLoad() {
64
+ this.handleHeaderSlotChange();
65
+ this.handleActionsSlotChange();
66
+ this.observeDialogState();
67
+ this.syncDialogVisibility();
68
+ super.componentDidLoad();
69
+ }
70
+ disconnectedCallback() {
71
+ this.actionsStateObserver?.disconnect();
72
+ this.dialogStateObserver?.disconnect();
73
+ super.disconnectedCallback();
74
+ }
75
+ componentDidRender() {
76
+ if (this.open) {
77
+ this.focusPrimaryAction();
78
+ }
79
+ super.componentDidRender();
80
+ }
81
+ handleOpenChange() {
82
+ this.syncDialogVisibility();
83
+ }
84
+ get dialogAccessibilityAttributes() {
85
+ const attributes = { ...this.inheritedAriaAttributes };
86
+ delete attributes['aria-label'];
87
+ delete attributes['aria-labelledby'];
88
+ if (this.hasHeader) {
89
+ attributes['aria-labelledby'] = this.dialogTitleId;
90
+ return attributes;
91
+ }
92
+ const inheritedLabelledBy = this.inheritedAriaAttributes['aria-labelledby'];
93
+ if (typeof inheritedLabelledBy === 'string') {
94
+ attributes['aria-labelledby'] = inheritedLabelledBy;
95
+ return attributes;
96
+ }
97
+ const inheritedLabel = this.inheritedAriaAttributes['aria-label'];
98
+ if (typeof inheritedLabel === 'string') {
99
+ attributes['aria-label'] = inheritedLabel;
100
+ }
101
+ return attributes;
102
+ }
103
+ get actionButtons() {
104
+ return (this.actionsSlot?.assignedElements({ flatten: true }) ?? []).filter((element) => {
105
+ return this.isVisibleActionButton(element);
106
+ });
107
+ }
108
+ get enabledActionButtons() {
109
+ return this.actionButtons.filter((element) => {
110
+ return !this.isDisabledActionButton(element);
111
+ });
112
+ }
113
+ get assignedActionElements() {
114
+ return this.actionsSlot?.assignedElements({ flatten: true }) ?? [];
115
+ }
116
+ isDisabledActionButton(element) {
117
+ return element.hasAttribute('disabled') || element.disabled === true;
118
+ }
119
+ getActionVariant(element) {
120
+ const variant = element.getAttribute('variant') ?? element.variant;
121
+ return variant === 'primary' || variant === 'secondary' || variant === 'tertiary' ? variant : 'secondary';
122
+ }
123
+ getActionValidationResult() {
124
+ if (!this.actionButtons.length) {
125
+ return {};
126
+ }
127
+ const primaryActions = this.actionButtons.filter((element) => this.getActionVariant(element) === 'primary');
128
+ const secondaryActions = this.actionButtons.filter((element) => this.getActionVariant(element) === 'secondary');
129
+ const issues = [
130
+ primaryActions.length !== 1 ? `${primaryActions.length} primary action${primaryActions.length === 1 ? '' : 's'}` : undefined,
131
+ secondaryActions.length > 1 ? `${secondaryActions.length} secondary actions` : undefined,
132
+ ].filter((issue) => Boolean(issue));
133
+ return {
134
+ errorMessage: issues.length
135
+ ? `LmvzModal actions slot must contain exactly one primary action, at most one secondary action, and optional tertiary actions. Received ${issues.join(' and ')}.`
136
+ : undefined,
137
+ primaryAction: primaryActions[0],
138
+ };
139
+ }
140
+ hasAssignedContent(slot) {
141
+ return Boolean(slot?.assignedNodes({ flatten: true }).some((node) => {
142
+ if (node.nodeType === Node.TEXT_NODE) {
143
+ return Boolean(node.textContent?.trim());
144
+ }
145
+ return node.nodeType === Node.ELEMENT_NODE;
146
+ }));
147
+ }
148
+ observeDialogState() {
149
+ if (!this.dialogEl || typeof MutationObserver === 'undefined')
150
+ return;
151
+ this.dialogStateObserver?.disconnect();
152
+ this.dialogStateObserver = new MutationObserver(() => {
153
+ if (!this.dialogEl || this.dialogEl.open === this.open)
154
+ return;
155
+ if (this.dialogEl.open) {
156
+ this.open = true;
157
+ return;
158
+ }
159
+ this.open = false;
160
+ });
161
+ this.dialogStateObserver.observe(this.dialogEl, {
162
+ attributes: true,
163
+ attributeFilter: ['open'],
164
+ });
165
+ }
166
+ isVisibleActionButton(element) {
167
+ return element.tagName === 'LMVZ-BUTTON' && !element.hasAttribute('hidden');
168
+ }
169
+ capturePreviouslyFocusedElement() {
170
+ const dialog = this.dialogEl;
171
+ const activeElement = getDeepActiveElement(document);
172
+ if (!dialog || !activeElement || dialog.contains(activeElement))
173
+ return;
174
+ this.previouslyFocusedElement = activeElement;
175
+ }
176
+ ensureDialogShowModalCapture() {
177
+ const dialog = this.dialogEl;
178
+ if (!dialog || typeof dialog.showModal !== 'function')
179
+ return;
180
+ const showModal = dialog.showModal;
181
+ if (showModal === this.wrappedDialogShowModal)
182
+ return;
183
+ const wrappedShowModal = () => {
184
+ this.capturePreviouslyFocusedElement();
185
+ return showModal.call(dialog);
186
+ };
187
+ Object.defineProperty(dialog, 'showModal', {
188
+ configurable: true,
189
+ value: wrappedShowModal,
190
+ });
191
+ this.wrappedDialogShowModal = wrappedShowModal;
192
+ }
193
+ syncDialogVisibility() {
194
+ const dialog = this.dialogEl;
195
+ if (!dialog)
196
+ return;
197
+ if (this.open) {
198
+ if (!dialog.open) {
199
+ this.capturePreviouslyFocusedElement();
200
+ if (typeof dialog.showModal === 'function') {
201
+ dialog.showModal();
202
+ }
203
+ else {
204
+ dialog.setAttribute('open', '');
205
+ }
206
+ }
207
+ this.focusPrimaryAction();
208
+ return;
209
+ }
210
+ if (!dialog.open)
211
+ return;
212
+ if (typeof dialog.close === 'function') {
213
+ dialog.close();
214
+ }
215
+ else {
216
+ dialog.removeAttribute('open');
217
+ this.handleDialogClose();
218
+ }
219
+ }
220
+ focusPrimaryAction() {
221
+ const primaryAction = this.enabledActionButtons.find((element) => {
222
+ return this.getActionVariant(element) === 'primary';
223
+ }) ?? this.enabledActionButtons[0];
224
+ const focusTarget = primaryAction ?? this.closeButtonEl;
225
+ if (!focusTarget || typeof window === 'undefined')
226
+ return;
227
+ window.requestAnimationFrame(() => {
228
+ if (this.open) {
229
+ focusTarget.focus();
230
+ }
231
+ });
232
+ }
233
+ restoreFocus() {
234
+ if (!this.previouslyFocusedElement?.isConnected)
235
+ return;
236
+ this.previouslyFocusedElement.focus();
237
+ this.previouslyFocusedElement = null;
238
+ }
239
+ handleCloseButtonClick = () => {
240
+ if (!this.dialogEl)
241
+ return;
242
+ const dialogWithRequestClose = this.dialogEl;
243
+ if (typeof dialogWithRequestClose.requestClose === 'function') {
244
+ this.pendingCloseReturnValue = 'close';
245
+ dialogWithRequestClose.requestClose('close');
246
+ return;
247
+ }
248
+ if (typeof this.dialogEl.close === 'function') {
249
+ this.dialogEl.close('close');
250
+ return;
251
+ }
252
+ this.handleDialogClose();
253
+ };
254
+ handleDialogCancel = (event) => {
255
+ event.preventDefault();
256
+ const emitted = this.dialogCancel.emit();
257
+ if (emitted.defaultPrevented) {
258
+ this.pendingCloseReturnValue = undefined;
259
+ return;
260
+ }
261
+ const returnValue = this.pendingCloseReturnValue;
262
+ this.pendingCloseReturnValue = undefined;
263
+ this.dialogEl?.close(returnValue);
264
+ };
265
+ handleDialogClose = () => {
266
+ console.log('Dialog close handler called');
267
+ if (this.open) {
268
+ this.open = false;
269
+ }
270
+ this.restoreFocus();
271
+ this.dialogClose.emit();
272
+ };
273
+ handleHeaderSlotChange = () => {
274
+ this.hasHeader = this.hasAssignedContent(this.headerSlot);
275
+ };
276
+ observeActionState() {
277
+ if (typeof MutationObserver === 'undefined')
278
+ return;
279
+ this.actionsStateObserver?.disconnect();
280
+ if (!this.assignedActionElements.length)
281
+ return;
282
+ this.actionsStateObserver = new MutationObserver(() => {
283
+ this.syncActionsState();
284
+ });
285
+ this.assignedActionElements.forEach((element) => {
286
+ this.actionsStateObserver?.observe(element, {
287
+ attributes: true,
288
+ attributeFilter: ['disabled', 'hidden', 'variant'],
289
+ });
290
+ });
291
+ }
292
+ syncActionsState() {
293
+ const assignedElements = this.assignedActionElements;
294
+ assignedElements.forEach((element) => {
295
+ const isAllowedAction = ['LMVZ-BUTTON', 'BUTTON'].includes(element.tagName.toUpperCase());
296
+ if (isAllowedAction)
297
+ return;
298
+ if (!element.hasAttribute('hidden')) {
299
+ element.setAttribute('hidden', '');
300
+ }
301
+ if (element.getAttribute('aria-hidden') !== 'true') {
302
+ element.setAttribute('aria-hidden', 'true');
303
+ }
304
+ });
305
+ this.hasActions = assignedElements.some((element) => this.isVisibleActionButton(element));
306
+ this.checkActions();
307
+ if (this.open) {
308
+ this.focusPrimaryAction();
309
+ }
310
+ }
311
+ handleActionsSlotChange = () => {
312
+ this.syncActionsState();
313
+ this.observeActionState();
314
+ };
315
+ checkActions() {
316
+ if (!isAriaValidationEnabled())
317
+ return;
318
+ const { errorMessage } = this.getActionValidationResult();
319
+ if (!errorMessage) {
320
+ this.lastActionValidationMessage = undefined;
321
+ return;
322
+ }
323
+ if (this.lastActionValidationMessage === errorMessage)
324
+ return;
325
+ console.error(errorMessage);
326
+ this.lastActionValidationMessage = errorMessage;
327
+ }
328
+ render() {
329
+ return (h(Host, { key: 'f319dcb33aaa6426e568fba1bfb6c8c3927432cb' }, h("dialog", { key: '1c5b1659b243a2af19ec5b41d19a2096b522671c', ref: (element) => (this.dialogEl = element), onCancel: this.handleDialogCancel, onClose: this.handleDialogClose, ...this.dialogAccessibilityAttributes }, h("div", { key: '2d0260f11a75e28688a14b0263df0d00f8ba54b9', class: "modal-shell" }, h("header", { key: 'd96739e3b0a7f2c04e46585ddf4e431c91a698ce', class: { header: true, 'has-title': this.hasHeader } }, h("div", { key: 'f5202ac26195a3571e3767e0d3683c2bc960c2ec', class: "title", id: this.dialogTitleId, hidden: !this.hasHeader }, h("slot", { key: '2568ee3465bc070e353e647c58735a34005907d7', name: "header", ref: (element) => (this.headerSlot = element), onSlotchange: this.handleHeaderSlotChange })), h("lmvz-button", { key: '7978e838dc84ce83ee674aa111523b260d1861da', ref: (element) => (this.closeButtonEl = element), type: "button", class: "close-button", "aria-label": this.closeLabel, onClick: this.handleCloseButtonClick, variant: "tertiary" }, h("lmvz-icon", { key: '9f235507acbf2ee42747bfc44302fcae47d9ba0e', icon: closeIconSvg }))), h("div", { key: '7eeab9b2f0fd5d41c0218380436e2f092481813a', class: "body" }, h("slot", { key: '8904e87fa438caf2b7f34c4025ff688d94f4dea2' })), h("footer", { key: '0610abd150de228da893092e9f38721087144564', class: "actions", hidden: !this.hasActions }, h("slot", { key: '0f5457cb2544602a3b980f90e7297ed700d62fee', name: "actions", ref: (element) => (this.actionsSlot = element), onSlotchange: this.handleActionsSlotChange }))))));
330
+ }
331
+ static get is() { return "lmvz-modal"; }
332
+ static get encapsulation() { return "shadow"; }
333
+ static get originalStyleUrls() {
334
+ return {
335
+ "$": ["lmvz-modal.css"]
336
+ };
337
+ }
338
+ static get styleUrls() {
339
+ return {
340
+ "$": ["lmvz-modal.css"]
341
+ };
342
+ }
343
+ static get properties() {
344
+ return {
345
+ "open": {
346
+ "type": "boolean",
347
+ "mutable": true,
348
+ "complexType": {
349
+ "original": "boolean",
350
+ "resolved": "boolean",
351
+ "references": {}
352
+ },
353
+ "required": false,
354
+ "optional": false,
355
+ "docs": {
356
+ "tags": [{
357
+ "name": "default",
358
+ "text": "false"
359
+ }],
360
+ "text": "Controls the native dialog visibility."
361
+ },
362
+ "getter": false,
363
+ "setter": false,
364
+ "reflect": true,
365
+ "attribute": "open",
366
+ "defaultValue": "false"
367
+ },
368
+ "closeLabel": {
369
+ "type": "string",
370
+ "mutable": false,
371
+ "complexType": {
372
+ "original": "string",
373
+ "resolved": "string",
374
+ "references": {}
375
+ },
376
+ "required": false,
377
+ "optional": false,
378
+ "docs": {
379
+ "tags": [{
380
+ "name": "default",
381
+ "text": "'Schliessen'"
382
+ }],
383
+ "text": "Accessible label for the internal close button."
384
+ },
385
+ "getter": false,
386
+ "setter": false,
387
+ "reflect": false,
388
+ "attribute": "close-label",
389
+ "defaultValue": "'Schliessen'"
390
+ }
391
+ };
392
+ }
393
+ static get states() {
394
+ return {
395
+ "hasActions": {},
396
+ "hasHeader": {}
397
+ };
398
+ }
399
+ static get events() {
400
+ return [{
401
+ "method": "dialogClose",
402
+ "name": "close",
403
+ "bubbles": true,
404
+ "cancelable": false,
405
+ "composed": true,
406
+ "docs": {
407
+ "tags": [],
408
+ "text": "Re-emitted from the host whenever the native dialog closes so framework wrappers can synchronize bound state."
409
+ },
410
+ "complexType": {
411
+ "original": "void",
412
+ "resolved": "void",
413
+ "references": {}
414
+ }
415
+ }, {
416
+ "method": "dialogCancel",
417
+ "name": "cancel",
418
+ "bubbles": false,
419
+ "cancelable": true,
420
+ "composed": false,
421
+ "docs": {
422
+ "tags": [],
423
+ "text": "Re-emitted from the host whenever the native dialog receives a `cancel` event (e.g. Escape key).\nCall `event.preventDefault()` to keep the dialog open."
424
+ },
425
+ "complexType": {
426
+ "original": "void",
427
+ "resolved": "void",
428
+ "references": {}
429
+ }
430
+ }];
431
+ }
432
+ static get elementRef() { return "el"; }
433
+ static get watchers() {
434
+ return [{
435
+ "propName": "open",
436
+ "methodName": "handleOpenChange"
437
+ }];
438
+ }
439
+ static get listeners() {
440
+ return [{
441
+ "name": "submit",
442
+ "method": "handleFormDialogSubmit",
443
+ "target": undefined,
444
+ "capture": false,
445
+ "passive": false
446
+ }];
447
+ }
448
+ }
@@ -50,7 +50,7 @@ export class LmvzSelect extends ReactiveControllerHost {
50
50
  render() {
51
51
  const hasValue = this.hasValue;
52
52
  const shouldShowLabel = hasValue;
53
- return (h(Host, { key: '1bdd53df4a33c5292cc072b0a9abc45fa01b237f' }, h("div", { key: 'e38d81e620d8c27cd34e1a7799c42d5640d4b0db', class: "select-wrapper" }, h("label", { key: '3995206b564c7e17ac273709577eb8dd7a3b0ff1', htmlFor: this.selectId, class: shouldShowLabel ? 'floating-label' : 'assistive-label' }, this.label, this.required && shouldShowLabel && h("span", { key: '7c04028f9ff3e0f365f76d10b0139dc6805f2af4', "aria-hidden": "true" }, " *")), h("div", { key: '7b428d22a32181fc13e837b6821ab163ac286453', "aria-hidden": "true" }, h("span", { key: '385ddb473337869777e835cc5b533f9a41c1fbe3' }, hasValue ? this.selectedLabel : this.label, this.required && !hasValue && h("span", { key: 'c53036bd718b916b910225297b40df998729650c', "aria-hidden": "true" }, " *")), h("span", { key: '06db17fbe01d9fea9904aa04e72b6cbfc9d93652' }, h("img", { key: 'b4d46ada048e931aa71f2ace33c93ff9fc67e479', src: chevronDownSvg, alt: "" }))), h("select", { key: '841c86f1d340cd36475a7757e9cad5f33aeac710', id: this.selectId, ref: (el) => (this.nativeSelectEl = el), name: this.name, disabled: this.disabled, required: this.required, "aria-label": this.label, onChange: this.handleChange }, !hasValue && h("option", { key: '4bd193f7878da2077c9185cd093d61c62406a7b9', value: "", disabled: true, selected: true, hidden: true }), h("slot", { key: 'c14a15e022f08ad72a5ad9d29befe0db7c6f24db' }))), this.helperText && h("div", { key: '833eaa383f8a9722fd990fadcdff4a93aa0a79df', role: "status" }, this.helperText)));
53
+ return (h(Host, { key: '4a78608686bd771615d1bd6f5c5df243b813f0a3' }, h("div", { key: 'fc526485d7c1718c0044a8076151954fb0db680d', class: "select-wrapper" }, h("label", { key: '16c68d944b626f06b36c458daa351b05f0d6de92', htmlFor: this.selectId, class: shouldShowLabel ? 'floating-label' : 'assistive-label' }, this.label, this.required && shouldShowLabel && h("span", { key: '06ea7ab990b1119c726d39620cda2f2f53d6342a', "aria-hidden": "true" }, " *")), h("div", { key: '46e77a996cd17db6e882fdc0f5ac65fb90f71df5', "aria-hidden": "true" }, h("span", { key: '6b1e9f849e7e876f704816de6f55128e3d462587' }, hasValue ? this.selectedLabel : this.label, this.required && !hasValue && h("span", { key: 'd90c6b965c594a45f6699aaca3bc85de38bf5584', "aria-hidden": "true" }, " *")), h("span", { key: 'd91ce778422521a0b414aceb7161a871023730d9' }, h("img", { key: '3e405cebf0c02d91448c9db412837f4af554c4b2', src: chevronDownSvg, alt: "" }))), h("select", { key: 'b443a08e1436f75af572e102e8d43a9c3d031810', id: this.selectId, ref: (el) => (this.nativeSelectEl = el), name: this.name, disabled: this.disabled, required: this.required, "aria-label": this.label, onChange: this.handleChange }, !hasValue && h("option", { key: '7125eccebfb3541522d0461adcf1e203514d8af6', value: "", disabled: true, selected: true, hidden: true }), h("slot", { key: '80f7edf9e20b19ec8041d23b84752f2cd7c1a72e' }))), this.helperText && h("div", { key: '49cdd7ce54b5bc9031db2ef9826891d6a4f666b1', role: "status" }, this.helperText)));
54
54
  }
55
55
  static get is() { return "lmvz-select"; }
56
56
  static get encapsulation() { return "scoped"; }
@@ -0,0 +1,118 @@
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.theme {
8
+ @font-face {
9
+ font-family: Router;
10
+ src:
11
+ local('Router-Book'),
12
+ url('/assets/fonts/Router-Book.woff') format('woff'),
13
+ local('Router');
14
+ font-weight: 400 normal;
15
+ }
16
+
17
+ @font-face {
18
+ font-family: Router;
19
+ src:
20
+ local('Router-Medium'),
21
+ url('/assets/fonts/Router-Medium.woff') format('woff'),
22
+ local('Router');
23
+ font-weight: 500;
24
+ }
25
+
26
+ @font-face {
27
+ font-family: Router;
28
+ src:
29
+ local('Router-Bold'),
30
+ url('/assets/fonts/Router-Bold.woff') format('woff'),
31
+ local('Router');
32
+ font-weight: 700 bold;
33
+ }
34
+
35
+ }
36
+ :host {
37
+ display: inline-flex;
38
+ align-items: center;
39
+ gap: var(--lmvz-component-input-gap-md, clamp(0.5rem, 0.44rem + 0.26vw, 0.75rem));
40
+ padding-block: var(--lmvz-dimension-2-8, clamp(0.13rem, 0.03rem + 0.39vw, 0.5rem));
41
+ padding-inline: var(--lmvz-dimension-4-10, clamp(0.25rem, 0.16rem + 0.39vw, 0.63rem));
42
+ /* TODO[LDHCID-136]: min-height currently below accessibility requirements for tap targets (44px) */
43
+ /* min-height: 38px; */
44
+ border-radius: var(--lmvz-semantic-border-radius-round, 999px);
45
+ cursor: pointer;
46
+ background-color: transparent;
47
+ user-select: none;
48
+ }
49
+ :host(:not([disabled]):hover) {
50
+ background-color: var(--lmvz-semantic-color-int-tertiary-hover, #f0f0f0);
51
+ }
52
+ :host([checked]) {
53
+ background-color: var(--lmvz-semantic-color-status-active, #f1f9fe);
54
+ }
55
+ :host([disabled][checked]) {
56
+ background-color: var(--lmvz-semantic-color-status-active, #f1f9fe);
57
+ }
58
+ :host([disabled]) {
59
+ cursor: not-allowed;
60
+ opacity: var(--lmvz-component-input-disabled-opacity, 40%);
61
+ pointer-events: none;
62
+ }
63
+ .track {
64
+ position: relative;
65
+ flex-shrink: 0;
66
+ width: var(--lmvz-global-s32, 32px);
67
+ height: var(--lmvz-global-s20, 20px);
68
+ border-radius: var(--lmvz-semantic-border-radius-round, 999px);
69
+ background-color: var(--lmvz-semantic-color-surface-input-primary, #ffffff);
70
+ border: var(--lmvz-semantic-border-width-default, 1px) solid var(--lmvz-semantic-color-border-default, #e0e0e0);
71
+ }
72
+ :host(:not([disabled]):hover) .track {
73
+ border-color: var(--lmvz-semantic-color-border-hover, #c7c7c7);
74
+ }
75
+ :host([checked]) .track {
76
+ border-color: var(--lmvz-semantic-color-border-active, #0f8acc);
77
+ }
78
+ input {
79
+ /* visually hidden, keyboard-accessible */
80
+ position: absolute;
81
+ top: 0;
82
+ left: 0;
83
+ width: 100%;
84
+ height: 100%;
85
+ opacity: 0;
86
+ margin: 0;
87
+ cursor: inherit;
88
+ }
89
+ :host(:focus-within) {
90
+ /* TODO[LDHCID-136]: no focus-visible token in DS */
91
+ outline: 2px solid var(--lmvz-semantic-color-border-active, #0f8acc);
92
+ outline-offset: 2px;
93
+ }
94
+ .thumb {
95
+ position: absolute;
96
+ width: var(--lmvz-global-s13, 13px);
97
+ height: var(--lmvz-global-s13, 13px);
98
+ border-radius: 50%;
99
+ background-color: var(--lmvz-semantic-color-on-surface-input-secondary, #7a7a7a);
100
+ top: 50%;
101
+ transform: translateY(-50%);
102
+ left: var(--lmvz-global-s4, 4px);
103
+ /* TODO[LDHCID-136]: no DS motion/duration token — 0.2s ease from Figma interaction baseline */
104
+ transition:
105
+ left 0.2s ease,
106
+ background-color 0.2s ease;
107
+ pointer-events: none;
108
+ }
109
+ :host([checked]) .thumb {
110
+ left: calc(var(--lmvz-global-s4, 4px) + var(--lmvz-global-s11, 11px));
111
+ background-color: var(--lmvz-semantic-color-status-on-active, #0e7ab4);
112
+ }
113
+ label {
114
+ font: var(--lmvz-typography-body-md, 400 clamp(0.88rem, 0.84rem + 0.13vw, 1rem) / 1.4
115
+ Router);
116
+ color: var(--lmvz-semantic-color-on-surface-primary, #000000);
117
+ cursor: pointer;
118
+ }