wj-elements 0.5.0 → 0.5.2

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.
@@ -4,7 +4,15 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
4
4
  import WJElement from "./wje-element.js";
5
5
  import { WjElementUtils } from "./element-utils.js";
6
6
  import { event } from "./event.js";
7
- const styles = "/*\n[ WJ Breadcrumb ]\n*/\n\n:host {\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n line-height: 1.5;\n\n .native-breadcrumb {\n display: flex;\n align-items: center;\n width: 100%;\n outline: none;\n background: inherit;\n padding: 0.25rem 0.75rem;\n color: var(--wje-breadcrumb-a);\n text-decoration: none;\n font-size: var(--wje-breadcrumb-font-size);\n &.hidden {\n display: none;\n }\n &.active {\n font-weight: var(--wje-breadcrumb-active-font-weight);\n font-size: var(--wje-breadcrumb-active-font-size);\n }\n &.disabled {\n cursor: default;\n opacity: 0.6;\n }\n &:hover {\n color: var(--wje-breadcrumb-a-hover);\n }\n }\n\n button {\n margin-inline: 0.75rem;\n border: 0 solid transparent;\n border-radius: 3px;\n background-color: transparent;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n }\n\n .separator {\n display: inline-flex;\n align-items: center;\n }\n}\n\n:host(.collapsed) {\n display: none;\n}\n\n::slotted([slot='start']) {\n margin-inline: 0 0.5rem;\n}\n\n::slotted([slot='end']) {\n margin-inline: 0.5rem 0;\n}\n";
7
+ import "./wje-button.js";
8
+ import "./wje-dropdown.js";
9
+ import "./icon-CReYMzAK.js";
10
+ import "./wje-menu.js";
11
+ import "./wje-menu-item.js";
12
+ import "./wje-popup.js";
13
+ import "./wje-tooltip.js";
14
+ const styles = "/*\n[ WJ Breadcrumb ]\n*/\n\n:host {\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n line-height: var(--wje-breadcrumb-line-height, 1.5);\n\n .native-breadcrumb {\n display: flex;\n align-items: center;\n width: 100%;\n outline: none;\n background: inherit;\n margin: var(--wje-breadcrumb-margin, var(--wje-breadcrumb-native-margin, 0));\n padding: var(--wje-breadcrumb-padding, var(--wje-breadcrumb-native-padding, 0.25rem 0.75rem));\n color: var(--wje-breadcrumb-a);\n text-decoration: none;\n font-size: var(--wje-breadcrumb-font-size);\n line-height: var(--wje-breadcrumb-native-line-height, var(--wje-breadcrumb-line-height, 1.5));\n &.hidden {\n display: none;\n }\n &.active {\n font-weight: var(--wje-breadcrumb-active-font-weight);\n font-size: var(--wje-breadcrumb-active-font-size);\n }\n &.disabled {\n cursor: default;\n opacity: 0.6;\n }\n &:hover {\n color: var(--wje-breadcrumb-a-hover);\n }\n }\n\n button {\n margin-inline: 0.75rem;\n border: 0 solid transparent;\n border-radius: 3px;\n background-color: transparent;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n }\n\n .separator {\n display: inline-flex;\n align-items: center;\n }\n}\n\n:host(.collapsed) {\n display: none;\n}\n\n:host([mobile-collapsed-indicator]) {\n flex: 1 1 auto;\n min-width: 0;\n max-width: 100%;\n overflow: hidden;\n}\n\n.breadcrumb-mobile {\n display: flex;\n align-items: center;\n min-width: 0;\n max-width: 100%;\n color: var(--wje-breadcrumb-a);\n font-size: var(--wje-breadcrumb-font-size);\n line-height: var(--wje-breadcrumb-line-height, 1.5);\n}\n\n.breadcrumb-mobile--text,\n.breadcrumb-mobile--back,\n.breadcrumb-mobile--parent-title {\n width: 100%;\n}\n\n.breadcrumb-mobile--back,\n.breadcrumb-mobile--parent-title {\n flex-direction: column;\n align-items: flex-start;\n gap: 0.125rem;\n}\n\n.breadcrumb-mobile-dropdown,\n.breadcrumb-mobile__menu {\n min-width: 0;\n max-width: 100%;\n}\n\n.breadcrumb-mobile__menu {\n --wje-button-margin-inline: 0;\n --wje-padding-top: 0;\n --wje-padding-bottom: 0;\n --wje-padding-start: 0;\n --wje-padding-end: 0;\n gap: 0.35rem;\n color: var(--wje-breadcrumb-a);\n}\n\n.breadcrumb-mobile__back,\n.breadcrumb-mobile__parent,\n.breadcrumb-mobile__title {\n min-width: 0;\n max-width: 100%;\n overflow: hidden;\n color: inherit;\n font: inherit;\n line-height: inherit;\n text-align: start;\n text-decoration: none;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.breadcrumb-mobile__back,\n.breadcrumb-mobile__parent {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0;\n border: 0;\n background: transparent;\n color: var(--wje-breadcrumb-a);\n cursor: default;\n font-size: var(--wje-breadcrumb-mobile-parent-font-size, 0.8125rem);\n opacity: 0.72;\n}\n\nbutton.breadcrumb-mobile__back,\nbutton.breadcrumb-mobile__parent,\nbutton.breadcrumb-mobile__title {\n margin-inline: 0;\n cursor: pointer;\n}\n\nbutton.breadcrumb-mobile__back:hover,\nbutton.breadcrumb-mobile__parent:hover,\nbutton.breadcrumb-mobile__title:hover,\n.breadcrumb-mobile__menu:hover {\n color: var(--wje-breadcrumb-a-hover);\n}\n\n.breadcrumb-mobile__title {\n display: block;\n font-weight: var(--wje-breadcrumb-active-font-weight, 600);\n font-size: var(--wje-breadcrumb-active-font-size, inherit);\n}\n\n.breadcrumb-mobile__label {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.breadcrumb-mobile__icon {\n flex: 0 0 auto;\n}\n\n::slotted([slot='start']) {\n margin-inline: 0 0.5rem;\n}\n\n::slotted([slot='end']) {\n margin-inline: 0.5rem 0;\n}\n";
15
+ const MOBILE_COLLAPSED_VARIANTS = /* @__PURE__ */ new Set(["TEXT", "BACK", "PARENT-TITLE", "MENU-TITLE", "SHEET"]);
8
16
  class Breadcrumb extends WJElement {
9
17
  /**
10
18
  * Breadcrumb constructor method.
@@ -79,9 +87,15 @@ class Breadcrumb extends WJElement {
79
87
  * @returns {string} The collapsed variant value in uppercase.
80
88
  */
81
89
  get collapsedVariant() {
90
+ return this.collapsedVariantName.toUpperCase();
91
+ }
92
+ /**
93
+ * Get collapsed variant token.
94
+ * @returns {string}
95
+ */
96
+ get collapsedVariantName() {
82
97
  var _a, _b;
83
- let variant = ((_a = this.parentElement) == null ? void 0 : _a.collapsedVariant) || ((_b = this.parentElement) == null ? void 0 : _b.variant) || this._collapsedVariant || "button";
84
- return variant.toUpperCase();
98
+ return String(((_a = this.parentElement) == null ? void 0 : _a.collapsedVariant) || ((_b = this.parentElement) == null ? void 0 : _b.variant) || this._collapsedVariant || "button").trim();
85
99
  }
86
100
  /**
87
101
  * Get CSS stylesheet for the Breadcrumb element.
@@ -97,7 +111,7 @@ class Breadcrumb extends WJElement {
97
111
  * @returns {Array<string>} - The observed attributes array for the Breadcrumb element.
98
112
  */
99
113
  static get observedAttributes() {
100
- return ["show-collapsed-indicator", "collapsed", "last", "href", "target", "rel", "download", "disabled"];
114
+ return ["show-collapsed-indicator", "collapsed", "last", "href", "target", "rel", "download", "disabled", "title", "aria-label"];
101
115
  }
102
116
  /**
103
117
  * Handles attribute changes for the custom element and updates its behavior or appearance accordingly.
@@ -115,6 +129,7 @@ class Breadcrumb extends WJElement {
115
129
  (_a = super.attributeChangedCallback) == null ? void 0 : _a.call(this, name, oldValue, newValue);
116
130
  const isOn = newValue !== null && WjElementUtils.stringToBoolean(newValue);
117
131
  this._showCollapsedIndicator = isOn;
132
+ this.classList.toggle("collapsed", this.hasAttribute("collapsed") && !isOn);
118
133
  this.refresh();
119
134
  } else if (name === "last") {
120
135
  (_b = super.attributeChangedCallback) == null ? void 0 : _b.call(this, name, oldValue, newValue);
@@ -165,7 +180,7 @@ class Breadcrumb extends WJElement {
165
180
  fragment.append(this.drawCollapsedIndicator());
166
181
  native.classList.add("hidden");
167
182
  }
168
- if (this.showSeparator) {
183
+ if (this.shouldRenderSeparator()) {
169
184
  let separator = document.createElement("span");
170
185
  separator.classList.add("separator");
171
186
  separator.setAttribute("part", "separator");
@@ -180,6 +195,34 @@ class Breadcrumb extends WJElement {
180
195
  }
181
196
  return fragment;
182
197
  }
198
+ /**
199
+ * Returns whether the separator should be visible after this breadcrumb.
200
+ * @returns {boolean}
201
+ */
202
+ shouldRenderSeparator() {
203
+ return this.showSeparator && this.hasVisibleBreadcrumbAfter();
204
+ }
205
+ /**
206
+ * Returns whether any later breadcrumb is still visible in the rendered trail.
207
+ * @returns {boolean}
208
+ */
209
+ hasVisibleBreadcrumbAfter() {
210
+ var _a, _b;
211
+ const breadcrumbs = (_b = (_a = this.parentElement) == null ? void 0 : _a.getBreadcrumbs) == null ? void 0 : _b.call(_a);
212
+ if (!Array.isArray(breadcrumbs)) return true;
213
+ const index = breadcrumbs.indexOf(this);
214
+ if (index === -1) return true;
215
+ return breadcrumbs.slice(index + 1).some((breadcrumb) => this.isBreadcrumbVisibleInTrail(breadcrumb));
216
+ }
217
+ /**
218
+ * Returns whether a breadcrumb is visible in the rendered trail.
219
+ * @param {Element} breadcrumb Breadcrumb element to inspect.
220
+ * @returns {boolean}
221
+ */
222
+ isBreadcrumbVisibleInTrail(breadcrumb) {
223
+ var _a, _b;
224
+ return !(((_a = breadcrumb == null ? void 0 : breadcrumb.hasAttribute) == null ? void 0 : _a.call(breadcrumb, "collapsed")) && !((_b = breadcrumb == null ? void 0 : breadcrumb.hasAttribute) == null ? void 0 : _b.call(breadcrumb, "show-collapsed-indicator")));
225
+ }
183
226
  /**
184
227
  * Synchronizes host attributes to the internal anchor.
185
228
  */
@@ -201,6 +244,13 @@ class Breadcrumb extends WJElement {
201
244
  native.removeAttribute(attr);
202
245
  }
203
246
  });
247
+ ["title", "aria-label"].forEach((attr) => {
248
+ if (this.hasAttribute(attr)) {
249
+ native.setAttribute(attr, this.getAttribute(attr));
250
+ } else {
251
+ native.removeAttribute(attr);
252
+ }
253
+ });
204
254
  native.classList.toggle("active", Boolean(this.active));
205
255
  native.classList.toggle("disabled", isDisabled);
206
256
  if (this.active) native.setAttribute("aria-current", "page");
@@ -241,17 +291,25 @@ class Breadcrumb extends WJElement {
241
291
  /**
242
292
  * Renders the collapsed indicator based on the current collapsed variant.
243
293
  * If the collapsed variant is 'DROPDOWN', it invokes the collapseDropdown method.
244
- * Otherwise, it invokes the collapseButton method.
294
+ * Mobile breakpoint variants render compact breadcrumb summaries, otherwise the default button is used.
245
295
  * @returns {any} The rendered collapsed indicator, either as a dropdown or a button.
246
296
  */
247
297
  drawCollapsedIndicator() {
248
- let collapsedIndicator = null;
249
- if (this.collapsedVariant === "DROPDOWN") {
250
- collapsedIndicator = this.collapseDropdown();
251
- } else {
252
- collapsedIndicator = this.collapseButton();
298
+ const variant = this.collapsedVariant;
299
+ if (variant === "DROPDOWN") {
300
+ return this.collapseDropdown();
301
+ }
302
+ if (this.isMobileCollapsedVariant() && this.isBreakpointMenuIndicator()) {
303
+ return this.collapseMobileVariant(variant);
253
304
  }
254
- return collapsedIndicator;
305
+ return this.collapseButton();
306
+ }
307
+ /**
308
+ * Returns whether the current collapsed variant is a compact mobile layout.
309
+ * @returns {boolean}
310
+ */
311
+ isMobileCollapsedVariant() {
312
+ return MOBILE_COLLAPSED_VARIANTS.has(this.collapsedVariant);
255
313
  }
256
314
  /**
257
315
  * Creates and returns a dropdown UI component for collapsed breadcrumbs.
@@ -262,51 +320,418 @@ class Breadcrumb extends WJElement {
262
320
  * @returns {HTMLElement} A configured dropdown element containing a button as trigger and a menu with breadcrumb items.
263
321
  */
264
322
  collapseDropdown() {
265
- let dropdown = document.createElement("wje-dropdown");
266
- dropdown.setAttribute("placement", "bottom");
323
+ const isBreakpointMenuIndicator = this.isBreakpointMenuIndicator();
324
+ const breadcrumbs = this.getCollapsedMenuBreadcrumbs(isBreakpointMenuIndicator);
325
+ const trigger = this.createCollapsedDropdownTrigger(isBreakpointMenuIndicator);
326
+ return this.createBreadcrumbDropdown({
327
+ breadcrumbs,
328
+ trigger,
329
+ placement: isBreakpointMenuIndicator ? "bottom-start" : "bottom"
330
+ });
331
+ }
332
+ /**
333
+ * Creates a dropdown containing breadcrumb menu items.
334
+ * @param {object} options Configuration for the dropdown shell.
335
+ * @param {Array<HTMLElement>} options.breadcrumbs Breadcrumb elements to mirror in the menu.
336
+ * @param {HTMLElement} options.trigger Element assigned to the dropdown trigger slot.
337
+ * @param {string} options.placement Floating UI placement token for the popup.
338
+ * @returns {HTMLElement}
339
+ */
340
+ createBreadcrumbDropdown({ breadcrumbs, trigger, placement = "bottom" }) {
341
+ const dropdown = document.createElement("wje-dropdown");
342
+ dropdown.setAttribute("placement", placement);
267
343
  dropdown.setAttribute("offset", "10");
268
- let button = document.createElement("wje-button");
269
- button.setAttribute("slot", "trigger");
270
- button.setAttribute("fill", "link");
271
- button.innerHTML = `<wje-icon name="dots"></wje-icon>`;
272
- let menu = document.createElement("wje-menu");
344
+ const menu = this.createCollapsedBreadcrumbMenu(breadcrumbs);
345
+ dropdown.append(trigger, menu);
346
+ return dropdown;
347
+ }
348
+ /**
349
+ * Creates the menu used by collapsed dropdown variants.
350
+ * @param {Array<HTMLElement>} breadcrumbs Breadcrumb items represented by menu items.
351
+ * @returns {HTMLElement}
352
+ */
353
+ createCollapsedBreadcrumbMenu(breadcrumbs) {
354
+ const menu = document.createElement("wje-menu");
273
355
  menu.setAttribute("variant", "context");
356
+ menu.style.setProperty("--wje-menu-item-justify-content", "flex-start");
274
357
  menu.addEventListener("click", (e) => {
275
358
  var _a;
276
359
  e.stopPropagation();
277
360
  (_a = e.stopImmediatePropagation) == null ? void 0 : _a.call(e);
278
361
  });
279
- this.getBreadcrumbs().getBreadcrumbsCollapsed().forEach((b) => {
280
- let menuItem = document.createElement("wje-menu-item");
281
- menuItem.innerHTML = b.innerHTML;
282
- menuItem.__breadcrumb = b;
362
+ breadcrumbs.forEach((breadcrumb) => {
363
+ const menuItem = document.createElement("wje-menu-item");
364
+ this.populateCollapsedMenuItem(menuItem, breadcrumb);
365
+ menuItem.__breadcrumb = breadcrumb;
283
366
  menuItem.addEventListener("wje-menu-item:click", (e) => {
284
- var _a, _b, _c;
367
+ var _a, _b;
285
368
  (_a = e.preventDefault) == null ? void 0 : _a.call(e);
286
369
  e.stopPropagation();
287
370
  (_b = e.stopImmediatePropagation) == null ? void 0 : _b.call(e);
288
- const breadcrumb = e.currentTarget.__breadcrumb;
289
- if (!breadcrumb) return;
290
- const native = breadcrumb.native || ((_c = breadcrumb.context) == null ? void 0 : _c.querySelector("a.native-breadcrumb"));
291
- if (native && typeof native.click === "function") {
292
- native.click();
293
- } else if (typeof breadcrumb.click === "function") {
294
- breadcrumb.click();
295
- } else {
296
- breadcrumb.dispatchEvent(
297
- new MouseEvent("click", {
298
- bubbles: true,
299
- composed: true,
300
- cancelable: true
301
- })
302
- );
303
- }
371
+ this.forwardBreadcrumbClick(e.currentTarget.__breadcrumb);
304
372
  });
305
373
  menu.append(menuItem);
306
374
  });
307
- dropdown.append(button, menu);
375
+ return menu;
376
+ }
377
+ /**
378
+ * Returns breadcrumbs that should be exposed in a collapsed menu.
379
+ * @param {boolean} isBreakpointMenuIndicator Whether this trigger controls the full breakpoint menu.
380
+ * @returns {Array<HTMLElement>}
381
+ */
382
+ getCollapsedMenuBreadcrumbs(isBreakpointMenuIndicator) {
383
+ var _a, _b;
384
+ const breadcrumbs = this.getBreadcrumbs();
385
+ if (isBreakpointMenuIndicator) {
386
+ return ((_a = breadcrumbs == null ? void 0 : breadcrumbs.getBreadcrumbs) == null ? void 0 : _a.call(breadcrumbs)) || [];
387
+ }
388
+ return ((_b = breadcrumbs == null ? void 0 : breadcrumbs.getBreadcrumbsCollapsed) == null ? void 0 : _b.call(breadcrumbs)) || [];
389
+ }
390
+ /**
391
+ * Renders one of the compact mobile breakpoint variants.
392
+ * @param {string} variant Normalized uppercase variant token.
393
+ * @returns {HTMLElement}
394
+ */
395
+ collapseMobileVariant(variant) {
396
+ if (variant === "TEXT") return this.collapseMobileText();
397
+ if (variant === "BACK") return this.collapseMobileBack();
398
+ if (variant === "PARENT-TITLE") return this.collapseMobileParentTitle();
399
+ if (variant === "MENU-TITLE") return this.collapseMobileMenuTitle();
400
+ if (variant === "SHEET") return this.collapseMobileSheet();
401
+ return this.collapseButton();
402
+ }
403
+ /**
404
+ * Renders only the current breadcrumb title.
405
+ * @returns {HTMLElement}
406
+ */
407
+ collapseMobileText() {
408
+ const current = this.getCurrentBreadcrumb();
409
+ const container = this.createMobileContainer("breadcrumb-mobile--text");
410
+ const title = this.createMobileBreadcrumbControl(current, "breadcrumb-mobile__title", {
411
+ ariaCurrent: true,
412
+ actionable: this.isBreadcrumbActionable(current)
413
+ });
414
+ container.append(title);
415
+ return container;
416
+ }
417
+ /**
418
+ * Renders a parent back action above the current title.
419
+ * @returns {HTMLElement}
420
+ */
421
+ collapseMobileBack() {
422
+ const current = this.getCurrentBreadcrumb();
423
+ const parent = this.getParentBreadcrumb();
424
+ const container = this.createMobileContainer("breadcrumb-mobile--back");
425
+ if (parent) {
426
+ const back = this.createMobileBreadcrumbControl(parent, "breadcrumb-mobile__back", {
427
+ ariaLabel: "Go to parent",
428
+ icon: "arrow-left",
429
+ actionable: this.isBreadcrumbActionable(parent)
430
+ });
431
+ container.append(back);
432
+ }
433
+ const title = this.createMobileBreadcrumbControl(current, "breadcrumb-mobile__title", {
434
+ ariaCurrent: true,
435
+ actionable: false
436
+ });
437
+ container.append(title);
438
+ return container;
439
+ }
440
+ /**
441
+ * Renders parent context above the current title.
442
+ * @returns {HTMLElement}
443
+ */
444
+ collapseMobileParentTitle() {
445
+ const current = this.getCurrentBreadcrumb();
446
+ const parent = this.getParentBreadcrumb();
447
+ const container = this.createMobileContainer("breadcrumb-mobile--parent-title");
448
+ if (parent) {
449
+ const parentControl = this.createMobileBreadcrumbControl(parent, "breadcrumb-mobile__parent", {
450
+ actionable: this.isBreadcrumbActionable(parent)
451
+ });
452
+ container.append(parentControl);
453
+ }
454
+ const title = this.createMobileBreadcrumbControl(current, "breadcrumb-mobile__title", {
455
+ ariaCurrent: true,
456
+ actionable: false
457
+ });
458
+ container.append(title);
459
+ return container;
460
+ }
461
+ /**
462
+ * Renders a menu trigger with the current title.
463
+ * @returns {HTMLElement}
464
+ */
465
+ collapseMobileMenuTitle() {
466
+ const trigger = this.createMobileDropdownTrigger({
467
+ icon: "dots",
468
+ label: this.getBreadcrumbLabel(this.getCurrentBreadcrumb()),
469
+ ariaLabel: "Show breadcrumb menu",
470
+ className: "breadcrumb-mobile--menu-title"
471
+ });
472
+ return this.createMobileDropdown(trigger);
473
+ }
474
+ /**
475
+ * Renders the future sheet variant using the dropdown fallback for now.
476
+ * @returns {HTMLElement}
477
+ */
478
+ collapseMobileSheet() {
479
+ const trigger = this.createMobileDropdownTrigger({
480
+ icon: "chevron-down",
481
+ iconPosition: "end",
482
+ label: this.getBreadcrumbLabel(this.getCurrentBreadcrumb()),
483
+ ariaLabel: "Show breadcrumb path",
484
+ className: "breadcrumb-mobile--sheet"
485
+ });
486
+ return this.createMobileDropdown(trigger);
487
+ }
488
+ /**
489
+ * Creates a dropdown fallback for mobile menu-like variants.
490
+ * @param {HTMLElement} trigger Element that opens the fallback dropdown.
491
+ * @returns {HTMLElement}
492
+ */
493
+ createMobileDropdown(trigger) {
494
+ const dropdown = this.createBreadcrumbDropdown({
495
+ breadcrumbs: this.getTrailBreadcrumbs(),
496
+ trigger,
497
+ placement: "bottom-start"
498
+ });
499
+ dropdown.classList.add("breadcrumb-mobile-dropdown");
308
500
  return dropdown;
309
501
  }
502
+ /**
503
+ * Creates a compact mobile dropdown trigger.
504
+ * @param {object} options Visual settings for the compact trigger.
505
+ * @param {string} options.icon Icon shown next to the title.
506
+ * @param {string} options.iconPosition Whether the icon renders at the start or end.
507
+ * @param {string} options.label Current breadcrumb label shown beside the icon.
508
+ * @param {string} options.ariaLabel Accessible name for the dropdown trigger.
509
+ * @param {string} options.className Variant-specific class applied to the trigger.
510
+ * @returns {HTMLElement}
511
+ */
512
+ createMobileDropdownTrigger({ icon, iconPosition = "start", label, ariaLabel, className }) {
513
+ const trigger = document.createElement("wje-button");
514
+ trigger.setAttribute("slot", "trigger");
515
+ trigger.setAttribute("fill", "link");
516
+ trigger.setAttribute("aria-label", ariaLabel);
517
+ trigger.classList.add("breadcrumb-mobile", "breadcrumb-mobile__menu", className);
518
+ const iconElement = document.createElement("wje-icon");
519
+ iconElement.setAttribute("name", icon);
520
+ iconElement.setAttribute("slot", iconPosition === "end" ? "end" : "start");
521
+ iconElement.classList.add("breadcrumb-mobile__icon");
522
+ const title = document.createElement("span");
523
+ title.classList.add("breadcrumb-mobile__title");
524
+ title.setAttribute("aria-current", "page");
525
+ title.textContent = label;
526
+ if (label) title.setAttribute("title", label);
527
+ if (iconPosition === "end") {
528
+ trigger.append(title, iconElement);
529
+ } else {
530
+ trigger.append(iconElement, title);
531
+ }
532
+ return trigger;
533
+ }
534
+ /**
535
+ * Creates a wrapper for compact mobile breadcrumb variants.
536
+ * @param {string} className Variant class.
537
+ * @returns {HTMLElement}
538
+ */
539
+ createMobileContainer(className) {
540
+ const container = document.createElement("div");
541
+ container.classList.add("breadcrumb-mobile", className);
542
+ return container;
543
+ }
544
+ /**
545
+ * Creates a text or button control for a breadcrumb.
546
+ * @param {HTMLElement|null} breadcrumb Source breadcrumb.
547
+ * @param {string} className Class applied to the created control.
548
+ * @param {object} options Behavior and accessibility settings for the control.
549
+ * @param {boolean} options.actionable Whether clicks should forward to the source breadcrumb.
550
+ * @param {boolean} options.ariaCurrent Whether the control marks the current page.
551
+ * @param {string} options.ariaLabel Accessible name for action controls.
552
+ * @param {string} options.icon Optional icon shown before the label.
553
+ * @returns {HTMLElement}
554
+ */
555
+ createMobileBreadcrumbControl(breadcrumb, className, { actionable = false, ariaCurrent = false, ariaLabel, icon } = {}) {
556
+ const label = this.getBreadcrumbLabel(breadcrumb);
557
+ const control = document.createElement(actionable ? "button" : "span");
558
+ control.classList.add(className);
559
+ if (actionable) {
560
+ control.setAttribute("type", "button");
561
+ control.addEventListener("click", (e) => {
562
+ var _a;
563
+ e.preventDefault();
564
+ e.stopPropagation();
565
+ (_a = e.stopImmediatePropagation) == null ? void 0 : _a.call(e);
566
+ this.forwardBreadcrumbClick(breadcrumb);
567
+ });
568
+ }
569
+ if (ariaCurrent) control.setAttribute("aria-current", "page");
570
+ if (ariaLabel && actionable) control.setAttribute("aria-label", ariaLabel);
571
+ if (label) control.setAttribute("title", label);
572
+ if (icon) {
573
+ const iconElement = document.createElement("wje-icon");
574
+ iconElement.setAttribute("name", icon);
575
+ iconElement.classList.add("breadcrumb-mobile__icon");
576
+ control.append(iconElement);
577
+ }
578
+ const text = document.createElement("span");
579
+ text.classList.add("breadcrumb-mobile__label");
580
+ text.textContent = label;
581
+ control.append(text);
582
+ return control;
583
+ }
584
+ /**
585
+ * Returns the full trail of sibling breadcrumbs.
586
+ * @returns {Array<HTMLElement>}
587
+ */
588
+ getTrailBreadcrumbs() {
589
+ var _a, _b;
590
+ return ((_b = (_a = this.getBreadcrumbs()) == null ? void 0 : _a.getBreadcrumbs) == null ? void 0 : _b.call(_a)) || [];
591
+ }
592
+ /**
593
+ * Returns the current breadcrumb item.
594
+ * @returns {HTMLElement|null}
595
+ */
596
+ getCurrentBreadcrumb() {
597
+ const breadcrumbs = this.getTrailBreadcrumbs();
598
+ return breadcrumbs[breadcrumbs.length - 1] || null;
599
+ }
600
+ /**
601
+ * Returns the parent breadcrumb item.
602
+ * @returns {HTMLElement|null}
603
+ */
604
+ getParentBreadcrumb() {
605
+ const breadcrumbs = this.getTrailBreadcrumbs();
606
+ return breadcrumbs.length > 1 ? breadcrumbs[breadcrumbs.length - 2] : null;
607
+ }
608
+ /**
609
+ * Returns whether a breadcrumb has a known action to forward.
610
+ * @param {HTMLElement|null} breadcrumb Breadcrumb to inspect.
611
+ * @returns {boolean}
612
+ */
613
+ isBreadcrumbActionable(breadcrumb) {
614
+ var _a, _b, _c, _d;
615
+ if (!breadcrumb || breadcrumb.disabled || ((_a = breadcrumb.hasAttribute) == null ? void 0 : _a.call(breadcrumb, "disabled"))) return false;
616
+ return Boolean(
617
+ ((_b = breadcrumb.hasAttribute) == null ? void 0 : _b.call(breadcrumb, "href")) || ((_c = breadcrumb.hasAttribute) == null ? void 0 : _c.call(breadcrumb, "onclick")) || breadcrumb.__wjeBreadcrumbManaged || ((_d = breadcrumb.hasAttribute) == null ? void 0 : _d.call(breadcrumb, "data-wje-breadcrumbs-item"))
618
+ );
619
+ }
620
+ /**
621
+ * Forwards a compact control or menu item click to the original breadcrumb.
622
+ * @param {HTMLElement|null} breadcrumb Source breadcrumb.
623
+ */
624
+ forwardBreadcrumbClick(breadcrumb) {
625
+ var _a;
626
+ if (!breadcrumb) return;
627
+ const native = breadcrumb.native || ((_a = breadcrumb.context) == null ? void 0 : _a.querySelector("a.native-breadcrumb"));
628
+ if (native && typeof native.click === "function") {
629
+ native.click();
630
+ } else if (typeof breadcrumb.click === "function") {
631
+ breadcrumb.click();
632
+ } else {
633
+ breadcrumb.dispatchEvent(
634
+ new MouseEvent("click", {
635
+ bubbles: true,
636
+ composed: true,
637
+ cancelable: true
638
+ })
639
+ );
640
+ }
641
+ }
642
+ /**
643
+ * Creates the dropdown trigger for collapsed breadcrumbs.
644
+ * @param {boolean} isBreakpointMenuIndicator Whether this trigger controls the full breakpoint menu.
645
+ * @returns {HTMLElement}
646
+ */
647
+ createCollapsedDropdownTrigger(isBreakpointMenuIndicator) {
648
+ var _a, _b;
649
+ if (isBreakpointMenuIndicator) {
650
+ const customTrigger = (_b = (_a = this.getBreadcrumbs()) == null ? void 0 : _a.getBreakpointCollapseTrigger) == null ? void 0 : _b.call(_a);
651
+ if (customTrigger) {
652
+ const trigger = customTrigger.cloneNode(true);
653
+ trigger.setAttribute("slot", "trigger");
654
+ if (!trigger.hasAttribute("aria-label")) {
655
+ trigger.setAttribute("aria-label", "Show breadcrumb menu");
656
+ }
657
+ return trigger;
658
+ }
659
+ }
660
+ let button = document.createElement("wje-button");
661
+ button.setAttribute("slot", "trigger");
662
+ button.setAttribute("fill", "link");
663
+ button.setAttribute("aria-label", "Show more breadcrumbs");
664
+ button.innerHTML = `<wje-icon name="${this.getCollapsedDropdownIcon(isBreakpointMenuIndicator)}"></wje-icon>`;
665
+ return button;
666
+ }
667
+ /**
668
+ * Resolves the icon used by the default dropdown trigger.
669
+ * @param {boolean} isBreakpointMenuIndicator Whether this trigger controls the full breakpoint menu.
670
+ * @returns {string}
671
+ */
672
+ getCollapsedDropdownIcon(isBreakpointMenuIndicator) {
673
+ var _a;
674
+ if (!isBreakpointMenuIndicator) return "dots";
675
+ return ((_a = this.getBreadcrumbs()) == null ? void 0 : _a.breakpointCollapseIcon) || "menu";
676
+ }
677
+ /**
678
+ * Copies breadcrumb content into a collapsed menu item.
679
+ * @param {HTMLElement} menuItem Menu item receiving the content.
680
+ * @param {HTMLElement} breadcrumb Source breadcrumb.
681
+ */
682
+ populateCollapsedMenuItem(menuItem, breadcrumb) {
683
+ const nodes = Array.from(breadcrumb.childNodes).map((node) => node.cloneNode(true));
684
+ menuItem.replaceChildren(...nodes);
685
+ if (menuItem.textContent.trim()) return;
686
+ const label = this.getBreadcrumbLabel(breadcrumb);
687
+ if (label) {
688
+ menuItem.append(document.createTextNode(label));
689
+ }
690
+ }
691
+ /**
692
+ * Resolves a readable label for a breadcrumb item.
693
+ * @param {HTMLElement|null} breadcrumb Source breadcrumb.
694
+ * @returns {string}
695
+ */
696
+ getBreadcrumbLabel(breadcrumb) {
697
+ if (!breadcrumb) return "";
698
+ return this.getCollapsedMenuItemLabel(breadcrumb);
699
+ }
700
+ /**
701
+ * Resolves a readable label for icon-only collapsed menu items.
702
+ * @param {HTMLElement} breadcrumb Source breadcrumb.
703
+ * @returns {string}
704
+ */
705
+ getCollapsedMenuItemLabel(breadcrumb) {
706
+ var _a;
707
+ const explicitLabel = breadcrumb.getAttribute("aria-label") || breadcrumb.getAttribute("title");
708
+ if (explicitLabel == null ? void 0 : explicitLabel.trim()) return explicitLabel.trim();
709
+ const text = breadcrumb.textContent.trim();
710
+ if (text) return text;
711
+ const iconName = (_a = breadcrumb.querySelector('wje-icon[slot="start"]')) == null ? void 0 : _a.getAttribute("name");
712
+ if (iconName === "home") return "Home";
713
+ const href = breadcrumb.getAttribute("href");
714
+ const path = (href == null ? void 0 : href.split(/[?#]/)[0]) || "";
715
+ const segment = path.split("/").filter(Boolean).pop();
716
+ return segment ? this.humanizeCollapsedMenuItemLabel(segment) : "";
717
+ }
718
+ /**
719
+ * Turns a URL segment into a readable menu label.
720
+ * @param {string} value URL segment.
721
+ * @returns {string}
722
+ */
723
+ humanizeCollapsedMenuItemLabel(value) {
724
+ return decodeURIComponent(value).replace(/[-_]+/g, " ").replace(/\b\w/g, (letter) => letter.toUpperCase());
725
+ }
726
+ /**
727
+ * Returns whether this collapsed indicator represents the full breakpoint menu.
728
+ * @returns {boolean}
729
+ */
730
+ isBreakpointMenuIndicator() {
731
+ var _a;
732
+ const breadcrumbs = this.parentElement;
733
+ return this.hasAttribute("show-collapsed-indicator") && this.hasAttribute("collapsed") && ((_a = breadcrumbs == null ? void 0 : breadcrumbs.isBreakpointMenuCollapseActive) == null ? void 0 : _a.call(breadcrumbs));
734
+ }
310
735
  /**
311
736
  * Creates a button element that expands hidden breadcrumbs when clicked.
312
737
  * The button is set with appropriate attributes and event listeners to handle