@luzmo/lucero 0.0.18 → 0.0.20

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.
@@ -0,0 +1,460 @@
1
+ /*! * Lucero - The design system for Luzmo.
2
+ *
3
+ * Copyright © 2025 Luzmo
4
+ * All rights reserved.
5
+ * Lucero (“Luzmo Design System”) must be used according to the Luzmo Terms of Service.
6
+ * This license allows users with a current active Luzmo account to use Lucero.
7
+ * This license terminates automatically if a user no longer has an active Luzmo account.
8
+ * Please view the Luzmo Terms of Service at: https://www.luzmo.com/information-pages/terms-of-use.
9
+ *
10
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
13
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
16
+ * SOFTWARE.
17
+ * */
18
+ import { x as r, E as h, B as b, r as v, n as a } from "./base-CawdqE7p.js";
19
+ import { r as p } from "./state-CYxk12SV.js";
20
+ import { e as m } from "./query-D_KR_GUc.js";
21
+ import { e as I } from "./class-map-CJko4aXp.js";
22
+ import { o as c } from "./if-defined-BSAr_4u4.js";
23
+ import { o as $ } from "./style-map-Ct2LiEds.js";
24
+ import { F as w } from "./focusable-cj2QhwDT.js";
25
+ import { D as S } from "./dependency-manger-CEXvGQUV.js";
26
+ import { M, I as C, s as y, p as E } from "./strategies-CzfvQU_H.js";
27
+ import { P as A } from "./pending-state-TJj1x9xn.js";
28
+ import { S as D } from "./sized-mixin-BxMraZLS.js";
29
+ import { luzmoIcon as f, luzmoAngleDown as z, luzmoAlert as _ } from "@luzmo/icons";
30
+ import "./menu/index.js";
31
+ import "./overlay/index.js";
32
+ import "./progress-circle/index.js";
33
+ import "./tooltip/index.js";
34
+ var F = Object.defineProperty, P = Object.getOwnPropertyDescriptor, n = (d, e, t, s) => {
35
+ for (var l = s > 1 ? void 0 : s ? P(e, t) : e, o = d.length - 1, u; o >= 0; o--)
36
+ (u = d[o]) && (l = (s ? u(e, t, l) : u(l)) || l);
37
+ return s && l && F(e, t, l), l;
38
+ };
39
+ const x = () => r`
40
+ <div class="disclosure-icon icon">
41
+ ${f(z, { className: "indicator" })}
42
+ </div>
43
+ `, B = () => r`
44
+ <div class="icon-container validation-icon icon">
45
+ ${f(_)}
46
+ </div>
47
+ `, g = "option-picker";
48
+ class i extends D(w, {
49
+ noDefaultSize: !0
50
+ }) {
51
+ /**
52
+ * Initializes the `PendingStateController` for the Picker component.
53
+ * The `PendingStateController` manages the pending state of the Picker.
54
+ */
55
+ constructor() {
56
+ super(), this.disabled = !1, this.focused = !1, this.invalid = !1, this.pending = !1, this.pendingLabel = "Pending", this.open = !1, this.readonly = !1, this.placement = "bottom-start", this.quiet = !1, this.value = "", this.selects = "single", this.dependencyManager = new S(this), this.isMobile = new M(this, C), this.listRole = "listbox", this.itemRole = "option", this.hasRenderedOverlay = !1, this._selfManageFocusElement = !1, this.deprecatedMenu = null, this.selectionPromise = Promise.resolve(), this.willManageSelection = !1, this.recentlyConnected = !1, this.enterKeydownOn = null, this.handleSlottableRequest = (e) => {
57
+ }, this.applyFocusElementLabel = (e, t) => {
58
+ this.appliedLabel = e, this.labelAlignment = t.sideAligned ? "inline" : void 0;
59
+ }, this.handleKeydown = (e) => {
60
+ this.focused = !0, !(e.code !== "ArrowDown" && e.code !== "ArrowUp") && (e.stopPropagation(), e.preventDefault(), this.toggle(!0));
61
+ }, this.renderAngleIcon = () => x(), this.renderAlertIcon = () => B(), this.handleEnterKeydown = (e) => {
62
+ if (e.code === "Enter") {
63
+ if (this.enterKeydownOn) {
64
+ e.preventDefault();
65
+ return;
66
+ }
67
+ this.enterKeydownOn = e.target, this.addEventListener(
68
+ "keyup",
69
+ (t) => {
70
+ t.code === "Enter" && (this.enterKeydownOn = null);
71
+ },
72
+ { once: !0 }
73
+ );
74
+ }
75
+ }, this.pendingStateController = new A(this);
76
+ }
77
+ get selectedItem() {
78
+ return this._selectedItem;
79
+ }
80
+ get selectedItemContent() {
81
+ return this._selectedItemContent || { icon: [], content: [] };
82
+ }
83
+ get selfManageFocusElement() {
84
+ return this._selfManageFocusElement;
85
+ }
86
+ get menuItems() {
87
+ return this.optionsMenu.childItems;
88
+ }
89
+ set selectedItem(e) {
90
+ const t = e == null ? void 0 : e.querySelector('[slot="icon"]');
91
+ if (this.selectedItemContent = e ? e.itemChildren : void 0, e === this.selectedItem)
92
+ return;
93
+ const s = this.selectedItem;
94
+ this._selectedItem = e, this._selectedItemIcon = (t == null ? void 0 : t.icon) ?? void 0, this.requestUpdate("selectedItem", s);
95
+ }
96
+ get focusElement() {
97
+ return this.open ? this.optionsMenu : this.button;
98
+ }
99
+ forceFocusVisible() {
100
+ this.disabled || (this.focused = !0);
101
+ }
102
+ click() {
103
+ this.disabled || this.toggle();
104
+ }
105
+ handleButtonBlur() {
106
+ this.focused = !1;
107
+ }
108
+ focus(e) {
109
+ super.focus(e), !this.disabled && this.focusElement && (this.focused = this.hasVisibleFocusInTree());
110
+ }
111
+ handleHelperFocus() {
112
+ this.focused = !0, this.button.focus();
113
+ }
114
+ handleChange(e) {
115
+ this.strategy && (this.strategy.preventNextToggle = "no");
116
+ const t = e.target, [s] = t.selectedItems;
117
+ e.stopPropagation(), e.cancelable ? this.setValueFromItem(s, e) : (this.open = !1, this.strategy && (this.strategy.open = !1));
118
+ }
119
+ handleButtonFocus(e) {
120
+ var t;
121
+ (t = this.strategy) == null || t.handleButtonFocus(e);
122
+ }
123
+ toggle(e) {
124
+ this.readonly || this.pending || (this.open = e === void 0 ? !this.open : e, this.strategy && (this.strategy.open = this.open), this._selfManageFocusElement = this.open);
125
+ }
126
+ close() {
127
+ this.readonly || this.strategy && (this.open = !1, this.strategy.open = !1);
128
+ }
129
+ bindEvents() {
130
+ var e;
131
+ (e = this.strategy) == null || e.abort(), this.strategy = this.isMobile.matches ? new y.mobile(this.button, this) : new y.desktop(this.button, this);
132
+ }
133
+ connectedCallback() {
134
+ super.connectedCallback(), this.recentlyConnected = this.hasUpdated;
135
+ }
136
+ disconnectedCallback() {
137
+ var e;
138
+ this.close(), (e = this.strategy) == null || e.releaseDescription(), super.disconnectedCallback();
139
+ }
140
+ async setValueFromItem(e, t) {
141
+ this.open = !1, this.strategy && (this.strategy.open = !1);
142
+ const s = this.selectedItem, l = this.value;
143
+ if (this.selectedItem = e, this.value = (e == null ? void 0 : e.value) ?? "", await this.updateComplete, !this.dispatchEvent(
144
+ new CustomEvent("change", {
145
+ bubbles: !0,
146
+ // Allow it to be prevented.
147
+ cancelable: !0,
148
+ composed: !0,
149
+ detail: this.value
150
+ })
151
+ ) && this.selects) {
152
+ t && t.preventDefault(), this.setMenuItemSelected(this.selectedItem, !1), s && this.setMenuItemSelected(s, !0), this.selectedItem = s, this.value = l, this.open = !0, this.strategy && (this.strategy.open = !0);
153
+ return;
154
+ } else if (!this.selects) {
155
+ this.selectedItem = s, this.value = l;
156
+ return;
157
+ }
158
+ s && this.setMenuItemSelected(s, !1), this.setMenuItemSelected(e, !!this.selects);
159
+ }
160
+ setMenuItemSelected(e, t) {
161
+ this.selects != null && (e.selected = t);
162
+ }
163
+ get containerStyles() {
164
+ return this.isMobile.matches ? {
165
+ "--swc-menu-width": "100%"
166
+ } : {};
167
+ }
168
+ set selectedItemContent(e) {
169
+ if (e === this.selectedItemContent)
170
+ return;
171
+ const t = this.selectedItemContent;
172
+ this._selectedItemContent = e, this.requestUpdate("selectedItemContent", t);
173
+ }
174
+ handleTooltipSlotchange(e) {
175
+ this.tooltipEl = e.target.assignedElements()[0];
176
+ }
177
+ renderLabelContent(e) {
178
+ return this.value && this.selectedItem ? e : r`
179
+ <slot name="label" id="label">
180
+ <span aria-hidden=${c(this.appliedLabel ? void 0 : "true")}>
181
+ ${this.label}
182
+ </span>
183
+ </slot>
184
+ `;
185
+ }
186
+ get buttonContent() {
187
+ const e = {
188
+ "visually-hidden": this.icons === "only" && !!this.value,
189
+ placeholder: !this.value,
190
+ label: !0
191
+ }, t = this.appliedLabel || this.label, s = r` <div id="icon" ?hidden=${this.icons === "none"}>
192
+ ${this._selectedItemIcon ? f(this._selectedItemIcon) : h}
193
+ </div>`;
194
+ return [
195
+ r`
196
+ ${this._selectedItemIcon ? s : h}
197
+ <div
198
+ id=${c(this.value && this.selectedItem ? "label" : void 0)}
199
+ class=${I(e)}
200
+ >
201
+ ${this.renderLabelContent(this.selectedItemContent.content)}
202
+ </div>
203
+ ${this.value && this.selectedItem ? r`
204
+ <div
205
+ aria-hidden="true"
206
+ class="visually-hidden"
207
+ id="applied-label"
208
+ >
209
+ ${t}
210
+ <slot name="label"></slot>
211
+ </div>
212
+ ` : r` <span hidden id="applied-label">${t}</span> `}
213
+ ${this.invalid && !this.pending ? r` ${this.renderAlertIcon()} ` : h}
214
+ ${this.pendingStateController.renderPendingState()}
215
+ ${this.readonly ? h : this.renderAngleIcon()}
216
+ <slot
217
+ aria-hidden="true"
218
+ name="tooltip"
219
+ id="tooltip"
220
+ @slotchange=${this.handleTooltipSlotchange}
221
+ ></slot>
222
+ `
223
+ ];
224
+ }
225
+ renderOverlay(e) {
226
+ var s, l, o;
227
+ if (((s = this.strategy) == null ? void 0 : s.overlay) === void 0)
228
+ return e;
229
+ const t = this.renderContainer(e);
230
+ return b(t, (l = this.strategy) == null ? void 0 : l.overlay, {
231
+ host: this
232
+ }), (o = this.strategy) == null ? void 0 : o.overlay;
233
+ }
234
+ get renderDescriptionSlot() {
235
+ return r`
236
+ <div id=${g}>
237
+ <slot name="description"></slot>
238
+ </div>
239
+ `;
240
+ }
241
+ // a helper to throw focus to the button is needed because Safari
242
+ // won't include buttons in the tab order even with tabindex="0"
243
+ render() {
244
+ return this.tooltipEl && (this.tooltipEl.disabled = this.open), r`
245
+ <span
246
+ id="focus-helper"
247
+ tabindex=${this.focused || this.open ? "-1" : "0"}
248
+ @focus=${this.handleHelperFocus}
249
+ aria-describedby=${g}
250
+ ></span>
251
+ <button
252
+ aria-controls=${c(this.open ? "menu" : void 0)}
253
+ aria-describedby="tooltip"
254
+ aria-expanded=${this.open ? "true" : "false"}
255
+ aria-haspopup="true"
256
+ aria-labelledby="loader icon label applied-label"
257
+ id="button"
258
+ class=${c(
259
+ this.labelAlignment ? `label-${this.labelAlignment}` : void 0
260
+ )}
261
+ @blur=${this.handleButtonBlur}
262
+ @keydown=${{
263
+ handleEvent: this.handleEnterKeydown,
264
+ capture: !0
265
+ }}
266
+ ?disabled=${this.disabled}
267
+ tabindex="-1"
268
+ >
269
+ ${this.buttonContent}
270
+ </button>
271
+ ${this.renderMenu} ${this.renderDescriptionSlot}
272
+ `;
273
+ }
274
+ update(e) {
275
+ var t, s;
276
+ this.selects && (this.selects = "single"), e.has("disabled") && this.disabled && this.strategy && (this.open = !1, this.strategy.open = !1), e.has("pending") && this.pending && this.strategy && (this.open = !1, this.strategy.open = !1), e.has("value") && this.shouldScheduleManageSelection(), this.hasUpdated || (this.deprecatedMenu = this.querySelector(":scope > luzmo-menu"), (t = this.deprecatedMenu) == null || t.toggleAttribute("ignore", !0), (s = this.deprecatedMenu) == null || s.setAttribute("selects", "inherit")), super.update(e);
277
+ }
278
+ bindButtonKeydownListener() {
279
+ this.button.addEventListener("keydown", this.handleKeydown);
280
+ }
281
+ updated(e) {
282
+ super.updated(e), e.has("open") && (this.strategy.open = this.open);
283
+ }
284
+ firstUpdated(e) {
285
+ super.firstUpdated(e), this.bindButtonKeydownListener(), this.bindEvents();
286
+ }
287
+ get dismissHelper() {
288
+ return r`
289
+ <div class="visually-hidden">
290
+ <button
291
+ tabindex="-1"
292
+ aria-label="Dismiss"
293
+ @click=${this.close}
294
+ ></button>
295
+ </div>
296
+ `;
297
+ }
298
+ renderContainer(e) {
299
+ const t = r`
300
+ ${this.dismissHelper} ${e} ${this.dismissHelper}
301
+ `;
302
+ return this.dependencyManager.add("luzmo-popover"), import("./popover/index.js"), r`
303
+ <luzmo-popover
304
+ id="popover"
305
+ size=${this.size}
306
+ role="presentation"
307
+ style=${$(this.containerStyles)}
308
+ placement=${this.placement}
309
+ >
310
+ ${t}
311
+ </luzmo-popover>
312
+ `;
313
+ }
314
+ get renderMenu() {
315
+ const e = r`
316
+ <luzmo-menu
317
+ aria-labelledby="applied-label"
318
+ @change=${this.handleChange}
319
+ id="menu"
320
+ @keydown=${{
321
+ handleEvent: this.handleEnterKeydown,
322
+ capture: !0
323
+ }}
324
+ @scroll=${this.onScroll}
325
+ role=${this.listRole}
326
+ .selects=${this.selects}
327
+ .selected=${this.value ? [this.value] : []}
328
+ size=${this.size}
329
+ @luzmo-menu-item-added-or-updated=${this.shouldManageSelection}
330
+ >
331
+ <slot @slotchange=${this.shouldScheduleManageSelection}></slot>
332
+ </luzmo-menu>
333
+ `;
334
+ return this.hasRenderedOverlay = this.hasRenderedOverlay || this.focused || this.open || !!this.deprecatedMenu, this.hasRenderedOverlay ? (this.dependencyManager.loaded && this.dependencyManager.add("luzmo-overlay"), this.renderOverlay(e)) : e;
335
+ }
336
+ shouldScheduleManageSelection(e) {
337
+ !this.willManageSelection && (!e || e.target.getRootNode().host === this) && (this.willManageSelection = !0, requestAnimationFrame(() => {
338
+ requestAnimationFrame(() => {
339
+ this.manageSelection();
340
+ });
341
+ }));
342
+ }
343
+ shouldManageSelection() {
344
+ this.willManageSelection || (this.willManageSelection = !0, this.manageSelection());
345
+ }
346
+ async manageSelection() {
347
+ if (this.selects == null)
348
+ return;
349
+ this.selectionPromise = new Promise(
350
+ (t) => this.selectionResolver = t
351
+ );
352
+ let e;
353
+ await this.optionsMenu.updateComplete, this.recentlyConnected && (await new Promise((t) => requestAnimationFrame(() => t(!0))), this.recentlyConnected = !1), this.menuItems.forEach((t) => {
354
+ this.value === t.value && !t.disabled ? e = t : t.selected = !1;
355
+ }), e ? (e.selected = !!this.selects, this.selectedItem = e) : (this.value = "", this.selectedItem = void 0), this.open && (await this.optionsMenu.updateComplete, this.optionsMenu.updateSelectedItemIndex()), this.selectionResolver(), this.willManageSelection = !1;
356
+ }
357
+ async getUpdateComplete() {
358
+ const e = await super.getUpdateComplete();
359
+ return await this.selectionPromise, e;
360
+ }
361
+ onScroll() {
362
+ this.dispatchEvent(
363
+ new Event("scroll", {
364
+ cancelable: !0,
365
+ composed: !0
366
+ })
367
+ );
368
+ }
369
+ }
370
+ n([
371
+ p()
372
+ ], i.prototype, "appliedLabel", 2);
373
+ n([
374
+ m("#button")
375
+ ], i.prototype, "button", 2);
376
+ n([
377
+ a({ type: Boolean, reflect: !0 })
378
+ ], i.prototype, "disabled", 2);
379
+ n([
380
+ a({ type: Boolean, reflect: !0 })
381
+ ], i.prototype, "focused", 2);
382
+ n([
383
+ a({ type: String, reflect: !0 })
384
+ ], i.prototype, "icons", 2);
385
+ n([
386
+ a({ type: String, reflect: !0 })
387
+ ], i.prototype, "variant", 2);
388
+ n([
389
+ a({ type: Boolean, reflect: !0 })
390
+ ], i.prototype, "invalid", 2);
391
+ n([
392
+ a({ type: Boolean, reflect: !0 })
393
+ ], i.prototype, "pending", 2);
394
+ n([
395
+ a({ type: String, attribute: "pending-label" })
396
+ ], i.prototype, "pendingLabel", 2);
397
+ n([
398
+ a()
399
+ ], i.prototype, "label", 2);
400
+ n([
401
+ a({ type: Boolean, reflect: !0 })
402
+ ], i.prototype, "open", 2);
403
+ n([
404
+ a({ type: Boolean, reflect: !0 })
405
+ ], i.prototype, "readonly", 2);
406
+ n([
407
+ p()
408
+ ], i.prototype, "labelAlignment", 2);
409
+ n([
410
+ m("luzmo-menu")
411
+ ], i.prototype, "optionsMenu", 2);
412
+ n([
413
+ m("luzmo-overlay")
414
+ ], i.prototype, "overlayElement", 2);
415
+ n([
416
+ a()
417
+ ], i.prototype, "placement", 2);
418
+ n([
419
+ a({ type: Boolean, reflect: !0 })
420
+ ], i.prototype, "quiet", 2);
421
+ n([
422
+ a({ type: String })
423
+ ], i.prototype, "value", 2);
424
+ n([
425
+ a({ attribute: !1 })
426
+ ], i.prototype, "selectedItem", 1);
427
+ n([
428
+ p()
429
+ ], i.prototype, "selectedItemContent", 1);
430
+ class X extends i {
431
+ constructor() {
432
+ super(...arguments), this.handleKeydown = (e) => {
433
+ const { code: t } = e;
434
+ if (this.focused = !0, !t.startsWith("Arrow") || this.readonly || this.pending)
435
+ return;
436
+ if (t === "ArrowUp" || t === "ArrowDown") {
437
+ this.toggle(!0), e.preventDefault();
438
+ return;
439
+ }
440
+ e.preventDefault();
441
+ const s = this.selectedItem ? this.menuItems.indexOf(this.selectedItem) : -1, l = s < 0 || t === "ArrowRight" ? 1 : -1;
442
+ let o = s + l;
443
+ for (; this.menuItems[o] && this.menuItems[o].disabled; )
444
+ o += l;
445
+ !this.menuItems[o] || this.menuItems[o].disabled || (!this.value || o !== s) && this.setValueFromItem(this.menuItems[o]);
446
+ };
447
+ }
448
+ static get styles() {
449
+ return [v(E)];
450
+ }
451
+ get containerStyles() {
452
+ const e = super.containerStyles;
453
+ return this.quiet || (e["min-width"] = `${this.offsetWidth}px`), e;
454
+ }
455
+ }
456
+ export {
457
+ g as D,
458
+ i as L,
459
+ X as a
460
+ };