@bluevolt-tech/lumen 2.0.1 → 2.2.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 (56) hide show
  1. package/README.md +37 -23
  2. package/dist/components/_shared/adopt-styles.d.ts +8 -0
  3. package/dist/components/_shared/date-range-validator.d.ts +86 -0
  4. package/dist/components/_shared/dropdown-controller.d.ts +60 -0
  5. package/dist/components/_shared/selectable-card.d.ts +10 -0
  6. package/dist/components/bv-alert-banner/bv-alert-banner.js +19 -17
  7. package/dist/components/bv-avatar/bv-avatar.js +19 -11
  8. package/dist/components/bv-badge/bv-badge.js +19 -11
  9. package/dist/components/bv-button/bv-button.js +18 -16
  10. package/dist/components/bv-category-pill/bv-category-pill.js +18 -16
  11. package/dist/components/bv-checkbox/bv-checkbox.js +19 -11
  12. package/dist/components/bv-chip/bv-chip.js +19 -11
  13. package/dist/components/bv-course-detail/bv-course-detail.js +20 -34
  14. package/dist/components/bv-course-detail-modal/bv-course-detail-modal.js +24 -90
  15. package/dist/components/bv-course-grid-card/bv-course-grid-card.d.ts +2 -6
  16. package/dist/components/bv-course-grid-card/bv-course-grid-card.js +98 -105
  17. package/dist/components/bv-course-list-card/bv-course-list-card.d.ts +2 -6
  18. package/dist/components/bv-course-list-card/bv-course-list-card.js +98 -105
  19. package/dist/components/bv-course-outline/bv-course-outline.js +19 -11
  20. package/dist/components/bv-date-range-input/bv-date-range-input.d.ts +10 -6
  21. package/dist/components/bv-date-range-input/bv-date-range-input.js +602 -125
  22. package/dist/components/bv-date-range-picker/bv-date-range-picker.d.ts +71 -4
  23. package/dist/components/bv-date-range-picker/bv-date-range-picker.js +441 -76
  24. package/dist/components/bv-empty-state/bv-empty-state.js +20 -28
  25. package/dist/components/bv-filter-dropdown/bv-filter-dropdown.d.ts +1 -4
  26. package/dist/components/bv-filter-dropdown/bv-filter-dropdown.js +80 -53
  27. package/dist/components/bv-filter-panel/bv-filter-panel.js +20 -22
  28. package/dist/components/bv-icon/bv-icon.js +19 -11
  29. package/dist/components/bv-input/bv-input.js +18 -16
  30. package/dist/components/bv-input-dropdown/bv-input-dropdown.d.ts +1 -4
  31. package/dist/components/bv-input-dropdown/bv-input-dropdown.js +79 -78
  32. package/dist/components/bv-modal/bv-modal.js +19 -11
  33. package/dist/components/bv-page-title/bv-page-title.js +19 -6
  34. package/dist/components/bv-pagination/bv-pagination.d.ts +1 -0
  35. package/dist/components/bv-pagination/bv-pagination.js +23 -186
  36. package/dist/components/bv-portal-header/bv-portal-header.js +25 -83
  37. package/dist/components/bv-portal-layout/bv-portal-layout.js +19 -11
  38. package/dist/components/bv-progress-bar/bv-progress-bar.js +19 -11
  39. package/dist/components/bv-promo-banner/bv-promo-banner.js +19 -11
  40. package/dist/components/bv-radio/bv-radio.js +19 -11
  41. package/dist/components/bv-searchbox/bv-searchbox.js +19 -11
  42. package/dist/components/bv-segmented-control/bv-segmented-control.js +18 -16
  43. package/dist/components/bv-select/bv-select.d.ts +1 -4
  44. package/dist/components/bv-select/bv-select.js +78 -44
  45. package/dist/components/bv-split-button/bv-split-button.d.ts +1 -4
  46. package/dist/components/bv-split-button/bv-split-button.js +78 -42
  47. package/dist/components/bv-star-rating/bv-star-rating.js +19 -11
  48. package/dist/components/bv-table/bv-table.d.ts +5 -0
  49. package/dist/components/bv-table/bv-table.js +70 -19
  50. package/dist/components/bv-toggle/bv-toggle.js +19 -11
  51. package/dist/components/bv-tooltip/bv-tooltip.js +20 -17
  52. package/dist/components/bv-user-row/bv-user-row.js +22 -50
  53. package/dist/components/bv-view-switcher/bv-view-switcher.js +19 -11
  54. package/dist/themes/base.css +1 -1
  55. package/package.json +8 -1
  56. package/themes/base.css +1 -1
@@ -1,6 +1,24 @@
1
1
  // css-inline:/home/runner/work/BV_lumen/BV_lumen/components/bv-empty-state/bv-empty-state.css
2
2
  var bv_empty_state_default = ":host {\n display: flex;\n width: 100%;\n}\n\n.wrap {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n text-align: center;\n padding: 48px 24px 56px;\n width: 100%;\n font-family: var(--bv-font-family-base);\n}\n\n.icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 48px;\n height: 48px;\n margin-bottom: 16px;\n border-radius: var(--bv-radius-lg);\n background: var(--bv-color-neutral-100);\n color: var(--bv-color-neutral-500);\n}\n\n.text {\n display: flex;\n flex-direction: column;\n gap: 4px;\n margin-bottom: 8px;\n max-width: 360px;\n}\n\n.title {\n font-size: var(--bv-font-size-md);\n font-weight: var(--bv-font-weight-semibold);\n color: var(--bv-color-neutral-800);\n margin: 0;\n line-height: 24px;\n}\n\n.description {\n font-size: var(--bv-font-size-sm);\n color: var(--bv-color-neutral-500);\n margin: 0;\n line-height: 20px;\n}\n\n.contact-support-link {\n font-size: var(--bv-font-size-sm);\n font-weight: var(--bv-font-weight-semibold);\n color: var(--bv-color-primary);\n text-decoration: none;\n}\n\n.contact-support-link:hover {\n text-decoration: underline;\n}\n\n.wrap.hero .contact-support-link {\n font-size: var(--bv-font-size-md);\n}\n\n/* Hero layout \u2014 used automatically when a preset `illustration` is set */\n.wrap.hero {\n padding: 64px 24px 72px;\n}\n\n.icon.hero {\n width: auto;\n height: auto;\n margin-bottom: 24px;\n background: none;\n border-radius: 0;\n}\n\n.icon.hero ::slotted(svg),\n.icon.hero slot svg {\n display: block;\n width: 160px;\n height: auto;\n}\n\n.wrap.hero .text {\n gap: 8px;\n margin-bottom: 12px;\n max-width: 480px;\n}\n\n.wrap.hero .title {\n font-size: var(--bv-font-size-2xl);\n line-height: 32px;\n}\n\n.wrap.hero .description {\n font-size: var(--bv-font-size-md);\n line-height: 24px;\n}\n";
3
3
 
4
+ // components/_shared/adopt-styles.ts
5
+ var _sheetCache = /* @__PURE__ */ new Map();
6
+ function adoptStyles(shadow, css) {
7
+ if ("adoptedStyleSheets" in ShadowRoot.prototype && typeof CSSStyleSheet !== "undefined" && "replaceSync" in CSSStyleSheet.prototype) {
8
+ let sheet = _sheetCache.get(css);
9
+ if (!sheet) {
10
+ sheet = new CSSStyleSheet();
11
+ sheet.replaceSync(css);
12
+ _sheetCache.set(css, sheet);
13
+ }
14
+ shadow.adoptedStyleSheets = [sheet];
15
+ return;
16
+ }
17
+ const style = document.createElement("style");
18
+ style.textContent = css;
19
+ shadow.appendChild(style);
20
+ }
21
+
4
22
  // components/bv-empty-state/illustrations.ts
5
23
  var illustrations = {
6
24
  empty: `<svg viewBox="-18.66 -18.67 248.82 248.82" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
@@ -161,14 +179,6 @@ var rawIcons = {
161
179
  };
162
180
 
163
181
  // components/bv-button/bv-button.ts
164
- var _sheet = null;
165
- function getSheet() {
166
- if (!_sheet) {
167
- _sheet = new CSSStyleSheet();
168
- _sheet.replaceSync(bv_button_default);
169
- }
170
- return _sheet;
171
- }
172
182
  var BvButton = class extends HTMLElement {
173
183
  static observedAttributes = [
174
184
  "variant",
@@ -184,10 +194,7 @@ var BvButton = class extends HTMLElement {
184
194
  ];
185
195
  constructor() {
186
196
  super();
187
- const shadow = this.attachShadow({ mode: "open" });
188
- if ("adoptedStyleSheets" in ShadowRoot.prototype) {
189
- shadow.adoptedStyleSheets = [getSheet()];
190
- }
197
+ adoptStyles(this.attachShadow({ mode: "open" }), bv_button_default);
191
198
  }
192
199
  // ── Accessors ────────────────────────────────────────────────
193
200
  get variant() {
@@ -244,11 +251,6 @@ var BvButton = class extends HTMLElement {
244
251
  const shadow = this.shadowRoot;
245
252
  let btn = shadow.querySelector("button");
246
253
  if (!btn) {
247
- if (!shadow.adoptedStyleSheets.length) {
248
- const styleEl = document.createElement("style");
249
- styleEl.textContent = bv_button_default;
250
- shadow.appendChild(styleEl);
251
- }
252
254
  btn = document.createElement("button");
253
255
  btn.setAttribute("part", "button");
254
256
  btn.appendChild(document.createElement("slot"));
@@ -327,12 +329,7 @@ var BvEmptyState = class extends HTMLElement {
327
329
  _wrapEl = null;
328
330
  constructor() {
329
331
  super();
330
- this.attachShadow({ mode: "open" });
331
- if ("replaceSync" in CSSStyleSheet.prototype) {
332
- const sheet = new CSSStyleSheet();
333
- sheet.replaceSync(bv_empty_state_default);
334
- this.shadowRoot.adoptedStyleSheets = [sheet];
335
- }
332
+ adoptStyles(this.attachShadow({ mode: "open" }), bv_empty_state_default);
336
333
  }
337
334
  get iconSvg() {
338
335
  return this.getAttribute("icon-svg") ?? "";
@@ -393,11 +390,6 @@ var BvEmptyState = class extends HTMLElement {
393
390
  if (this._rendered) return;
394
391
  this._rendered = true;
395
392
  const shadow = this.shadowRoot;
396
- if (!shadow.adoptedStyleSheets.length) {
397
- const s = document.createElement("style");
398
- s.textContent = bv_empty_state_default;
399
- shadow.appendChild(s);
400
- }
401
393
  const wrap = document.createElement("div");
402
394
  wrap.className = "wrap";
403
395
  this._wrapEl = wrap;
@@ -15,7 +15,7 @@ export declare class BvFilterDropdown extends HTMLElement {
15
15
  private _selectedValues;
16
16
  private _showInactive;
17
17
  private _searchQuery;
18
- private _offClick;
18
+ private _dropdown;
19
19
  constructor();
20
20
  get value(): string;
21
21
  get values(): string[];
@@ -27,9 +27,6 @@ export declare class BvFilterDropdown extends HTMLElement {
27
27
  attributeChangedCallback(name: string, _old: string | null, val: string | null): void;
28
28
  private _parseValuesAttr;
29
29
  private _render;
30
- private _toggle;
31
- private _open;
32
- private _close;
33
30
  private _syncLabel;
34
31
  private _rebuildPanel;
35
32
  private _buildSinglePanel;
@@ -1,18 +1,79 @@
1
1
  // css-inline:/home/runner/work/BV_lumen/BV_lumen/components/bv-filter-dropdown/bv-filter-dropdown.css
2
- var bv_filter_dropdown_default = ":host {\n display: inline-block;\n position: relative;\n font-family: var(--bv-font-family-base);\n}\n\n/* \u2500\u2500 Trigger \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.trigger {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 12px 16px;\n background: var(--bv-color-neutral-0);\n border: 1px solid var(--bv-color-neutral-300);\n border-radius: var(--bv-radius-lg);\n box-shadow: var(--bv-shadow-sm);\n cursor: pointer;\n font-family: inherit;\n font-size: var(--bv-font-size-sm);\n font-weight: var(--bv-font-weight-semibold);\n color: var(--bv-color-secondary-foreground);\n line-height: 20px;\n white-space: nowrap;\n user-select: none;\n transition:\n border-color var(--bv-transition-fast),\n background var(--bv-transition-fast);\n}\n\n.trigger:hover {\n background: var(--bv-color-secondary-light);\n}\n\n:host([open]) .trigger {\n border-color: var(--bv-color-primary);\n background: var(--bv-color-neutral-0);\n}\n\n:host([disabled]) .trigger {\n opacity: 0.5;\n cursor: not-allowed;\n pointer-events: none;\n background: var(--bv-color-neutral-100);\n}\n\n:host([disabled]) .trigger:hover {\n background: var(--bv-color-neutral-100);\n}\n\n.trigger-chevron {\n display: flex;\n color: var(--bv-color-secondary-foreground);\n transition: transform var(--bv-transition-fast);\n flex-shrink: 0;\n}\n\n:host([open]) .trigger-chevron {\n transform: rotate(180deg);\n}\n\n/* \u2500\u2500 Dropdown panel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.panel {\n display: none;\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n width: max-content;\n min-width: 100%;\n max-width: 600px;\n background: var(--bv-color-neutral-0);\n border: 1px solid var(--bv-color-neutral-200);\n border-radius: var(--bv-radius-lg);\n box-shadow: var(--bv-shadow-md);\n z-index: 200;\n overflow: hidden;\n padding: 4px 0;\n}\n\n:host([open]) .panel {\n display: block;\n}\n\n/* \u2500\u2500 Single-mode options \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.option {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n padding: 9px 14px;\n font-size: var(--bv-font-size-sm);\n font-weight: var(--bv-font-weight-regular);\n color: var(--bv-color-neutral-700);\n cursor: pointer;\n white-space: nowrap;\n transition: background var(--bv-transition-fast);\n}\n\n.option:hover {\n background: var(--bv-color-secondary);\n}\n\n.option[aria-selected='true'] {\n font-weight: var(--bv-font-weight-medium);\n color: var(--bv-color-neutral-900);\n background: var(--bv-color-secondary-light);\n}\n\n.option-check {\n display: none;\n color: var(--bv-color-primary);\n flex-shrink: 0;\n}\n\n.option[aria-selected='true'] .option-check {\n display: flex;\n}\n\n/* \u2500\u2500 Multi-mode search \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.panel-search {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-bottom: 1px solid var(--bv-color-neutral-200);\n}\n\n.search-icon {\n display: flex;\n color: var(--bv-color-neutral-400);\n flex-shrink: 0;\n}\n\n.search-input {\n flex: 1;\n border: none;\n outline: none;\n font-family: var(--bv-font-family-base);\n font-size: var(--bv-font-size-sm);\n color: var(--bv-color-neutral-700);\n background: transparent;\n min-width: 0;\n}\n\n.search-input::placeholder {\n color: var(--bv-color-neutral-400);\n}\n\n/* \u2500\u2500 Multi-mode header (Select All + toggle) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 12px;\n}\n\n.select-all-row {\n display: flex;\n align-items: center;\n gap: 8px;\n cursor: pointer;\n font-size: var(--bv-font-size-sm);\n font-weight: var(--bv-font-weight-semibold);\n color: var(--bv-color-neutral-700);\n user-select: none;\n flex: 1;\n padding: 2px 0;\n}\n\n.select-all-row:hover {\n color: var(--bv-color-neutral-900);\n}\n\n/* \u2500\u2500 Show Inactive toggle \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.inactive-toggle-label {\n display: flex;\n align-items: center;\n gap: 6px;\n cursor: pointer;\n user-select: none;\n flex-shrink: 0;\n}\n\n.toggle-input {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n pointer-events: none;\n}\n\n.toggle-track {\n display: inline-flex;\n align-items: center;\n width: 28px;\n height: 16px;\n background: var(--bv-color-neutral-300);\n border-radius: var(--bv-radius-full);\n padding: 2px;\n transition: background var(--bv-transition-fast);\n flex-shrink: 0;\n}\n\n.toggle-input:checked ~ .toggle-track {\n background: var(--bv-color-primary);\n}\n\n.toggle-thumb {\n width: 12px;\n height: 12px;\n background: var(--bv-color-neutral-0);\n border-radius: var(--bv-radius-full);\n transition: transform var(--bv-transition-fast);\n flex-shrink: 0;\n}\n\n.toggle-input:checked ~ .toggle-track .toggle-thumb {\n transform: translateX(12px);\n}\n\n.toggle-text {\n font-size: var(--bv-font-size-xs);\n font-weight: var(--bv-font-weight-medium);\n color: var(--bv-color-neutral-600);\n white-space: nowrap;\n}\n\n/* \u2500\u2500 Panel divider \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.panel-divider {\n height: 1px;\n background: var(--bv-color-neutral-200);\n margin: 0;\n}\n\n/* \u2500\u2500 Multi-mode options list \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.options-list {\n max-height: 260px;\n overflow-y: auto;\n padding: 4px 0;\n}\n\n.option--multi {\n justify-content: flex-start;\n white-space: normal;\n min-width: 200px;\n}\n\n/* Depth-based indentation */\n.option--multi[data-depth='1'] {\n padding-left: 30px;\n}\n\n.option--multi[data-depth='2'] {\n padding-left: 46px;\n}\n\n/* In multi mode, checkbox is always visible */\n.option--multi .option-check {\n display: flex;\n width: 16px;\n height: 16px;\n border: 1.5px solid var(--bv-color-neutral-300);\n border-radius: var(--bv-radius-sm);\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n background: var(--bv-color-neutral-0);\n color: transparent;\n transition:\n border-color var(--bv-transition-fast),\n background var(--bv-transition-fast);\n}\n\n.option--multi .option-check.checked {\n background: var(--bv-color-primary);\n border-color: var(--bv-color-primary);\n color: var(--bv-color-neutral-0);\n}\n\n.option--multi:hover .option-check:not(.checked) {\n border-color: var(--bv-color-primary);\n}\n\n/* In multi mode, override the single-mode aria-selected styles */\n.option--multi[aria-selected='true'] {\n font-weight: var(--bv-font-weight-regular);\n background: transparent;\n color: var(--bv-color-neutral-700);\n}\n\n.option--multi:hover {\n background: var(--bv-color-secondary);\n}\n\n/* Inactive options */\n.option--inactive .option-label {\n color: var(--bv-color-neutral-400);\n}\n\n/* Italic labels (Uncategorized, Ungrouped) */\n.option-label--italic {\n font-style: italic;\n color: var(--bv-color-neutral-500);\n}\n\n.option-label {\n line-height: 1.4;\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Select All row checkbox */\n.select-all-row .option-check {\n display: flex;\n width: 16px;\n height: 16px;\n border: 1.5px solid var(--bv-color-neutral-300);\n border-radius: var(--bv-radius-sm);\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n background: var(--bv-color-neutral-0);\n color: transparent;\n transition:\n border-color var(--bv-transition-fast),\n background var(--bv-transition-fast);\n}\n\n.select-all-row .option-check.checked {\n background: var(--bv-color-primary);\n border-color: var(--bv-color-primary);\n color: var(--bv-color-neutral-0);\n}\n";
2
+ var bv_filter_dropdown_default = ":host {\n display: inline-block;\n position: relative;\n font-family: var(--bv-font-family-base);\n}\n\n/* \u2500\u2500 Trigger \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.trigger {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 12px 16px;\n background: var(--bv-color-neutral-0);\n border: 1px solid var(--bv-color-neutral-300);\n border-radius: var(--bv-radius-lg);\n box-shadow: var(--bv-shadow-sm);\n cursor: pointer;\n font-family: inherit;\n font-size: var(--bv-font-size-sm);\n font-weight: var(--bv-font-weight-semibold);\n color: var(--bv-color-secondary-foreground);\n line-height: 20px;\n white-space: nowrap;\n user-select: none;\n transition:\n border-color var(--bv-transition-fast),\n background var(--bv-transition-fast);\n}\n\n.trigger:hover {\n background: var(--bv-color-secondary-light);\n}\n\n:host([open]) .trigger {\n border-color: var(--bv-color-primary);\n background: var(--bv-color-neutral-0);\n}\n\n:host([disabled]) .trigger {\n opacity: 0.5;\n cursor: not-allowed;\n pointer-events: none;\n background: var(--bv-color-neutral-100);\n}\n\n:host([disabled]) .trigger:hover {\n background: var(--bv-color-neutral-100);\n}\n\n.trigger-chevron {\n display: flex;\n color: var(--bv-color-secondary-foreground);\n transition: transform var(--bv-transition-fast);\n flex-shrink: 0;\n}\n\n:host([open]) .trigger-chevron {\n transform: rotate(180deg);\n}\n\n/* \u2500\u2500 Dropdown panel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.panel {\n display: none;\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n width: max-content;\n min-width: 100%;\n max-width: 600px;\n background: var(--bv-color-neutral-0);\n border: 1px solid var(--bv-color-neutral-200);\n border-radius: var(--bv-radius-lg);\n box-shadow: var(--bv-shadow-md);\n z-index: 200;\n overflow: hidden;\n padding: 4px 0;\n}\n\n:host([open]) .panel {\n display: block;\n}\n\n/* \u2500\u2500 Single-mode options \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.option {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n padding: 9px 14px;\n font-size: var(--bv-font-size-sm);\n font-weight: var(--bv-font-weight-regular);\n color: var(--bv-color-neutral-700);\n cursor: pointer;\n white-space: nowrap;\n transition: background var(--bv-transition-fast);\n}\n\n.option:hover {\n background: var(--bv-color-secondary);\n}\n\n.option[aria-selected='true'] {\n font-weight: var(--bv-font-weight-medium);\n color: var(--bv-color-neutral-900);\n background: var(--bv-color-secondary-light);\n}\n\n.option-check {\n display: none;\n color: var(--bv-color-primary);\n flex-shrink: 0;\n}\n\n.option[aria-selected='true'] .option-check {\n display: flex;\n}\n\n/* \u2500\u2500 Multi-mode search \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.panel-search {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-bottom: 1px solid var(--bv-color-neutral-200);\n}\n\n.search-icon {\n display: flex;\n color: var(--bv-color-neutral-400);\n flex-shrink: 0;\n}\n\n.search-input {\n flex: 1;\n border: none;\n outline: none;\n font-family: var(--bv-font-family-base);\n font-size: var(--bv-font-size-sm);\n color: var(--bv-color-neutral-700);\n background: transparent;\n min-width: 0;\n}\n\n.search-input::placeholder {\n color: var(--bv-color-neutral-400);\n}\n\n/* \u2500\u2500 Multi-mode header (Select All + toggle) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 12px;\n}\n\n.select-all-row {\n display: flex;\n align-items: center;\n gap: 8px;\n cursor: pointer;\n font-size: var(--bv-font-size-sm);\n font-weight: var(--bv-font-weight-semibold);\n color: var(--bv-color-neutral-700);\n user-select: none;\n flex: 1;\n padding: 2px 0;\n}\n\n.select-all-row:hover {\n color: var(--bv-color-neutral-900);\n}\n\n/* \u2500\u2500 Show Inactive toggle \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.inactive-toggle-label {\n display: flex;\n align-items: center;\n gap: 6px;\n cursor: pointer;\n user-select: none;\n flex-shrink: 0;\n}\n\n.toggle-input {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n pointer-events: none;\n}\n\n.toggle-track {\n display: inline-flex;\n align-items: center;\n width: 28px;\n height: 16px;\n background: var(--bv-color-neutral-300);\n border-radius: var(--bv-radius-full);\n padding: 2px;\n transition: background var(--bv-transition-fast);\n flex-shrink: 0;\n}\n\n.toggle-input:checked ~ .toggle-track {\n background: var(--bv-color-primary);\n}\n\n.toggle-thumb {\n width: 12px;\n height: 12px;\n background: var(--bv-color-neutral-0);\n border-radius: var(--bv-radius-full);\n transition: transform var(--bv-transition-fast);\n flex-shrink: 0;\n}\n\n.toggle-input:checked ~ .toggle-track .toggle-thumb {\n transform: translateX(12px);\n}\n\n.toggle-text {\n font-size: var(--bv-font-size-xs);\n font-weight: var(--bv-font-weight-medium);\n color: var(--bv-color-neutral-600);\n white-space: nowrap;\n}\n\n/* \u2500\u2500 Panel divider \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.panel-divider {\n height: 1px;\n background: var(--bv-color-neutral-200);\n margin: 0;\n}\n\n/* \u2500\u2500 Multi-mode options list \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.options-list {\n max-height: 260px;\n overflow-y: auto;\n padding: 4px 0;\n}\n\n.option--multi {\n justify-content: flex-start;\n white-space: normal;\n min-width: 200px;\n}\n\n/* Depth-based indentation */\n.option--multi[data-depth='1'] {\n padding-left: 30px;\n}\n\n.option--multi[data-depth='2'] {\n padding-left: 46px;\n}\n\n/* In multi mode, checkbox is always visible. Visual mirrors bv-checkbox:\n outlined by default, primary-50 tint + primary check when checked. */\n.option--multi .option-check {\n display: flex;\n width: 16px;\n height: 16px;\n border: 1px solid var(--bv-color-neutral-300);\n border-radius: var(--bv-radius-sm);\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n background: var(--bv-color-neutral-0);\n color: transparent;\n transition:\n border-color var(--bv-transition-fast),\n background var(--bv-transition-fast);\n}\n\n.option--multi .option-check.checked {\n background: var(--bv-color-primary-50);\n border-color: var(--bv-color-primary);\n color: var(--bv-color-primary);\n}\n\n.option--multi:hover .option-check:not(.checked) {\n border-color: var(--bv-color-primary);\n}\n\n/* In multi mode, override the single-mode aria-selected styles */\n.option--multi[aria-selected='true'] {\n font-weight: var(--bv-font-weight-regular);\n background: transparent;\n color: var(--bv-color-neutral-700);\n}\n\n.option--multi:hover {\n background: var(--bv-color-secondary);\n}\n\n/* Inactive options */\n.option--inactive .option-label {\n color: var(--bv-color-neutral-400);\n}\n\n/* Italic labels (Uncategorized, Ungrouped) */\n.option-label--italic {\n font-style: italic;\n color: var(--bv-color-neutral-500);\n}\n\n.option-label {\n line-height: 1.4;\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Select All row checkbox \u2014 same visual as bv-checkbox */\n.select-all-row .option-check {\n display: flex;\n width: 16px;\n height: 16px;\n border: 1px solid var(--bv-color-neutral-300);\n border-radius: var(--bv-radius-sm);\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n background: var(--bv-color-neutral-0);\n color: transparent;\n transition:\n border-color var(--bv-transition-fast),\n background var(--bv-transition-fast);\n}\n\n.select-all-row .option-check.checked {\n background: var(--bv-color-primary-50);\n border-color: var(--bv-color-primary);\n color: var(--bv-color-primary);\n}\n";
3
+
4
+ // components/_shared/adopt-styles.ts
5
+ var _sheetCache = /* @__PURE__ */ new Map();
6
+ function adoptStyles(shadow, css) {
7
+ if ("adoptedStyleSheets" in ShadowRoot.prototype && typeof CSSStyleSheet !== "undefined" && "replaceSync" in CSSStyleSheet.prototype) {
8
+ let sheet = _sheetCache.get(css);
9
+ if (!sheet) {
10
+ sheet = new CSSStyleSheet();
11
+ sheet.replaceSync(css);
12
+ _sheetCache.set(css, sheet);
13
+ }
14
+ shadow.adoptedStyleSheets = [sheet];
15
+ return;
16
+ }
17
+ const style = document.createElement("style");
18
+ style.textContent = css;
19
+ shadow.appendChild(style);
20
+ }
21
+
22
+ // components/_shared/dropdown-controller.ts
23
+ function bindDropdownController(host, options = {}) {
24
+ if (!host.shadowRoot) {
25
+ throw new Error("bindDropdownController requires the host to have an open shadow root.");
26
+ }
27
+ const syncExpanded = () => {
28
+ var _a;
29
+ (_a = options.trigger) == null ? void 0 : _a.setAttribute("aria-expanded", host.hasAttribute("open") ? "true" : "false");
30
+ };
31
+ const open = () => {
32
+ var _a;
33
+ if (host.hasAttribute("open")) return;
34
+ (_a = options.onBeforeOpen) == null ? void 0 : _a.call(options);
35
+ host.setAttribute("open", "");
36
+ syncExpanded();
37
+ host.dispatchEvent(new CustomEvent("bv-open", { bubbles: true, composed: true }));
38
+ };
39
+ const closeWithReason = (reason) => {
40
+ var _a;
41
+ if (!host.hasAttribute("open")) return;
42
+ if (options.canClose && !options.canClose(reason)) return;
43
+ host.removeAttribute("open");
44
+ syncExpanded();
45
+ (_a = options.onAfterClose) == null ? void 0 : _a.call(options);
46
+ };
47
+ const close = () => closeWithReason("programmatic");
48
+ const toggle = () => {
49
+ if (host.hasAttribute("open")) closeWithReason("programmatic");
50
+ else open();
51
+ };
52
+ const offClick = (e) => {
53
+ if (!host.hasAttribute("open")) return;
54
+ if (e.composedPath().includes(host)) return;
55
+ closeWithReason("outside-click");
56
+ };
57
+ document.addEventListener("click", offClick);
58
+ const onKeyDown = (e) => {
59
+ if (e.key === "Escape") closeWithReason("escape");
60
+ };
61
+ host.addEventListener("keydown", onKeyDown);
62
+ const observer = new MutationObserver(syncExpanded);
63
+ observer.observe(host, { attributes: true, attributeFilter: ["open"] });
64
+ const cleanup = () => {
65
+ observer.disconnect();
66
+ document.removeEventListener("click", offClick);
67
+ host.removeEventListener("keydown", onKeyDown);
68
+ };
69
+ syncExpanded();
70
+ return { open, close, toggle, cleanup };
71
+ }
3
72
 
4
73
  // components/bv-filter-dropdown/bv-filter-dropdown.ts
5
74
  var CHEVRON_DOWN = `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 9l6 6 6-6"/></svg>`;
6
75
  var CHECK = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>`;
7
76
  var SEARCH_ICON = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/></svg>`;
8
- var _sheet = null;
9
- function getSheet() {
10
- if (!_sheet) {
11
- _sheet = new CSSStyleSheet();
12
- _sheet.replaceSync(bv_filter_dropdown_default);
13
- }
14
- return _sheet;
15
- }
16
77
  var BvFilterDropdown = class extends HTMLElement {
17
78
  static observedAttributes = [
18
79
  "options",
@@ -35,13 +96,10 @@ var BvFilterDropdown = class extends HTMLElement {
35
96
  _selectedValues = null;
36
97
  _showInactive = false;
37
98
  _searchQuery = "";
38
- _offClick = null;
99
+ _dropdown = null;
39
100
  constructor() {
40
101
  super();
41
- const shadow = this.attachShadow({ mode: "open" });
42
- if ("adoptedStyleSheets" in ShadowRoot.prototype) {
43
- shadow.adoptedStyleSheets = [getSheet()];
44
- }
102
+ adoptStyles(this.attachShadow({ mode: "open" }), bv_filter_dropdown_default);
45
103
  }
46
104
  get value() {
47
105
  return this._value;
@@ -63,10 +121,10 @@ var BvFilterDropdown = class extends HTMLElement {
63
121
  this._render();
64
122
  }
65
123
  disconnectedCallback() {
66
- if (this._offClick) document.removeEventListener("click", this._offClick);
124
+ var _a;
125
+ (_a = this._dropdown) == null ? void 0 : _a.cleanup();
67
126
  }
68
127
  attributeChangedCallback(name, _old, val) {
69
- var _a;
70
128
  if (name === "options") {
71
129
  try {
72
130
  this._options = JSON.parse(val ?? "[]");
@@ -93,11 +151,6 @@ var BvFilterDropdown = class extends HTMLElement {
93
151
  if ((name === "multi" || name === "searchable" || name === "show-inactive-toggle") && this._rendered) {
94
152
  this._rebuildPanel();
95
153
  }
96
- if (name === "open" && this._rendered) {
97
- const trigger = this.shadowRoot.querySelector(".trigger");
98
- if (trigger) trigger.setAttribute("aria-expanded", val !== null ? "true" : "false");
99
- if (val === null) (_a = this._panelEl) == null ? void 0 : _a.style.removeProperty("display");
100
- }
101
154
  }
102
155
  _parseValuesAttr(val) {
103
156
  if (!val) {
@@ -115,11 +168,6 @@ var BvFilterDropdown = class extends HTMLElement {
115
168
  if (this._rendered) return;
116
169
  this._rendered = true;
117
170
  const shadow = this.shadowRoot;
118
- if (!shadow.adoptedStyleSheets.length) {
119
- const s = document.createElement("style");
120
- s.textContent = bv_filter_dropdown_default;
121
- shadow.appendChild(s);
122
- }
123
171
  try {
124
172
  this._options = JSON.parse(this.getAttribute("options") ?? "[]");
125
173
  } catch {
@@ -140,8 +188,10 @@ var BvFilterDropdown = class extends HTMLElement {
140
188
  chevron.innerHTML = CHEVRON_DOWN;
141
189
  trigger.append(label, chevron);
142
190
  trigger.addEventListener("click", (e) => {
191
+ var _a;
143
192
  e.stopPropagation();
144
- this._toggle();
193
+ if (this.disabled) return;
194
+ (_a = this._dropdown) == null ? void 0 : _a.toggle();
145
195
  });
146
196
  const panel = document.createElement("div");
147
197
  panel.className = "panel";
@@ -151,31 +201,7 @@ var BvFilterDropdown = class extends HTMLElement {
151
201
  shadow.append(trigger, panel);
152
202
  this._syncLabel();
153
203
  this._rebuildPanel();
154
- this._offClick = (e) => {
155
- if (!this.contains(e.target) && !shadow.contains(e.target)) {
156
- this._close();
157
- }
158
- };
159
- document.addEventListener("click", this._offClick);
160
- this.addEventListener("keydown", (e) => {
161
- if (e.key === "Escape") this._close();
162
- });
163
- }
164
- _toggle() {
165
- if (this.hasAttribute("disabled")) return;
166
- if (this.hasAttribute("open")) this._close();
167
- else this._open();
168
- }
169
- _open() {
170
- var _a;
171
- this.setAttribute("open", "");
172
- (_a = this.shadowRoot.querySelector(".trigger")) == null ? void 0 : _a.setAttribute("aria-expanded", "true");
173
- this.dispatchEvent(new CustomEvent("bv-open", { bubbles: true, composed: true }));
174
- }
175
- _close() {
176
- var _a;
177
- this.removeAttribute("open");
178
- (_a = this.shadowRoot.querySelector(".trigger")) == null ? void 0 : _a.setAttribute("aria-expanded", "false");
204
+ this._dropdown = bindDropdownController(this, { trigger });
179
205
  }
180
206
  _syncLabel() {
181
207
  if (!this._labelEl) return;
@@ -228,11 +254,12 @@ var BvFilterDropdown = class extends HTMLElement {
228
254
  this._syncLabel();
229
255
  }
230
256
  _selectSingle(opt) {
257
+ var _a;
231
258
  this._value = opt.value;
232
259
  this.setAttribute("value", opt.value);
233
260
  this._syncLabel();
234
261
  this._syncSingleSelected();
235
- this._close();
262
+ (_a = this._dropdown) == null ? void 0 : _a.close();
236
263
  this.dispatchEvent(
237
264
  new CustomEvent("bv-change", {
238
265
  bubbles: true,
@@ -1,6 +1,24 @@
1
1
  // css-inline:/home/runner/work/BV_lumen/BV_lumen/components/bv-filter-panel/bv-filter-panel.css
2
2
  var bv_filter_panel_default = ":host {\n display: block;\n background: var(--bv-color-neutral-0);\n border: 1px solid var(--bv-color-neutral-200);\n}\n\n/* Self-hide when there are no groups to show. */\n:host([empty]) {\n display: none;\n}\n\n.panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--bv-spacing-md) var(--bv-spacing-lg);\n border-bottom: 1px solid var(--bv-color-neutral-200);\n}\n\n.panel-title {\n margin: 0;\n font-family: var(--bv-font-family-base);\n font-size: var(--bv-font-size-2xl);\n font-weight: var(--bv-font-weight-medium);\n color: var(--bv-color-neutral-900);\n}\n\n.clear-btn {\n background: none;\n border: none;\n padding: 0;\n font-family: var(--bv-font-family-base);\n font-size: var(--bv-font-size-sm);\n font-weight: var(--bv-font-weight-medium);\n color: var(--bv-color-primary);\n cursor: pointer;\n}\n\n.clear-btn:hover {\n text-decoration: underline;\n}\n\n.groups {\n display: flex;\n flex-direction: column;\n gap: var(--bv-spacing-lg);\n padding: var(--bv-spacing-md) var(--bv-spacing-lg);\n}\n\n.group {\n}\n\n.group-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n cursor: pointer;\n padding-bottom: var(--bv-spacing-sm);\n}\n\n.group-label {\n font-family: var(--bv-font-family-base);\n font-size: var(--bv-font-size-lg);\n font-weight: var(--bv-font-weight-medium);\n color: var(--bv-color-neutral-900);\n}\n\n.group-chevron {\n width: 20px;\n height: 20px;\n color: var(--bv-color-neutral-500);\n transition: transform var(--bv-transition-fast);\n}\n\n.group-chevron.collapsed {\n transform: rotate(180deg);\n}\n\n.group-options {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.group-options.hidden {\n display: none;\n}\n\n.option {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--bv-spacing-xs);\n}\n\n.option bv-checkbox {\n flex: 1;\n min-width: 0;\n}\n\n.option-count {\n display: inline-flex;\n align-items: center;\n padding: 2px var(--bv-spacing-sm);\n background: var(--bv-color-neutral-200);\n border-radius: var(--bv-radius-full);\n font-family: var(--bv-font-family-base);\n font-size: var(--bv-font-size-sm);\n font-weight: var(--bv-font-weight-regular);\n color: var(--bv-color-neutral-600);\n white-space: nowrap;\n flex-shrink: 0;\n}\n\n/* Loading skeleton */\n.skeleton {\n display: none;\n flex-direction: column;\n gap: var(--bv-spacing-lg);\n padding: var(--bv-spacing-md) var(--bv-spacing-lg);\n}\n\n:host([loading]) .groups {\n display: none;\n}\n\n:host([loading]) .skeleton {\n display: flex;\n}\n\n.skeleton-group {\n display: flex;\n flex-direction: column;\n gap: var(--bv-spacing-sm);\n}\n\n.skeleton-line {\n height: 14px;\n border-radius: var(--bv-radius-sm);\n background: var(--bv-color-neutral-200);\n animation: bv-skeleton-shimmer 1.5s ease-in-out infinite;\n}\n\n.skeleton-heading {\n height: 20px;\n width: 55%;\n margin-bottom: 4px;\n}\n\n.skeleton-short-line {\n width: 70%;\n}\n\n@keyframes bv-skeleton-shimmer {\n 0%,\n 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0.5;\n }\n}\n";
3
3
 
4
+ // components/_shared/adopt-styles.ts
5
+ var _sheetCache = /* @__PURE__ */ new Map();
6
+ function adoptStyles(shadow, css) {
7
+ if ("adoptedStyleSheets" in ShadowRoot.prototype && typeof CSSStyleSheet !== "undefined" && "replaceSync" in CSSStyleSheet.prototype) {
8
+ let sheet = _sheetCache.get(css);
9
+ if (!sheet) {
10
+ sheet = new CSSStyleSheet();
11
+ sheet.replaceSync(css);
12
+ _sheetCache.set(css, sheet);
13
+ }
14
+ shadow.adoptedStyleSheets = [sheet];
15
+ return;
16
+ }
17
+ const style = document.createElement("style");
18
+ style.textContent = css;
19
+ shadow.appendChild(style);
20
+ }
21
+
4
22
  // css-inline:/home/runner/work/BV_lumen/BV_lumen/components/bv-checkbox/bv-checkbox.css
5
23
  var bv_checkbox_default = ":host {\n display: inline-flex;\n font-family: var(--bv-font-family-base);\n}\n\n/* \u2500\u2500 Size tokens \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n:host,\n:host([size='sm']) {\n --_box-size: 16px;\n --_box-radius: 4px;\n --_gap: 8px;\n --_check-size: 10px;\n --_label-size: var(--bv-font-size-sm);\n --_label-lh: 20px;\n}\n\n:host([size='md']) {\n --_box-size: 20px;\n --_box-radius: 6px;\n --_gap: 12px;\n --_check-size: 12px;\n --_label-size: var(--bv-font-size-md);\n --_label-lh: 24px;\n}\n\n/* \u2500\u2500 Layout \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.wrap {\n display: inline-flex;\n align-items: flex-start;\n gap: var(--_gap);\n cursor: pointer;\n user-select: none;\n}\n\n:host([disabled]) .wrap {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n/* \u2500\u2500 Box \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.box {\n width: var(--_box-size);\n height: var(--_box-size);\n border-radius: var(--_box-radius);\n border: 1px solid var(--bv-color-neutral-300);\n background: var(--bv-color-neutral-0);\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n margin-top: 2px;\n transition:\n background var(--bv-transition-fast),\n border-color var(--bv-transition-fast);\n}\n\n:host([checked]) .box,\n:host([indeterminate]) .box {\n background: var(--bv-color-primary-50);\n border-color: var(--bv-color-primary);\n}\n\n/* \u2500\u2500 Check icon \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.check {\n display: none;\n width: var(--_check-size);\n height: var(--_check-size);\n color: var(--bv-color-primary);\n line-height: 0;\n}\n\n.check svg {\n width: 100%;\n height: 100%;\n display: block;\n}\n\n:host([checked]) .check,\n:host([indeterminate]) .check {\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n/* \u2500\u2500 Label \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.label {\n font-size: var(--_label-size);\n font-weight: var(--bv-font-weight-medium);\n color: var(--bv-color-secondary-foreground);\n line-height: var(--_label-lh);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n}\n";
6
24
 
@@ -18,12 +36,7 @@ var BvCheckbox = class extends HTMLElement {
18
36
  _labelEl = null;
19
37
  constructor() {
20
38
  super();
21
- this.attachShadow({ mode: "open" });
22
- if ("replaceSync" in CSSStyleSheet.prototype) {
23
- const sheet = new CSSStyleSheet();
24
- sheet.replaceSync(bv_checkbox_default);
25
- this.shadowRoot.adoptedStyleSheets = [sheet];
26
- }
39
+ adoptStyles(this.attachShadow({ mode: "open" }), bv_checkbox_default);
27
40
  }
28
41
  connectedCallback() {
29
42
  this._render();
@@ -47,11 +60,6 @@ var BvCheckbox = class extends HTMLElement {
47
60
  if (this._rendered) return;
48
61
  this._rendered = true;
49
62
  const shadow = this.shadowRoot;
50
- if (!shadow.adoptedStyleSheets.length) {
51
- const s = document.createElement("style");
52
- s.textContent = bv_checkbox_default;
53
- shadow.appendChild(s);
54
- }
55
63
  const wrap = document.createElement("label");
56
64
  wrap.className = "wrap";
57
65
  const box = document.createElement("span");
@@ -107,12 +115,7 @@ var BvFilterPanel = class extends HTMLElement {
107
115
  _skeletonEl = null;
108
116
  constructor() {
109
117
  super();
110
- this.attachShadow({ mode: "open" });
111
- if ("replaceSync" in CSSStyleSheet.prototype) {
112
- const sheet = new CSSStyleSheet();
113
- sheet.replaceSync(bv_filter_panel_default);
114
- this.shadowRoot.adoptedStyleSheets = [sheet];
115
- }
118
+ adoptStyles(this.attachShadow({ mode: "open" }), bv_filter_panel_default);
116
119
  }
117
120
  connectedCallback() {
118
121
  this._parseGroups();
@@ -138,11 +141,6 @@ var BvFilterPanel = class extends HTMLElement {
138
141
  if (this._rendered) return;
139
142
  this._rendered = true;
140
143
  const shadow = this.shadowRoot;
141
- if (!shadow.adoptedStyleSheets.length) {
142
- const s = document.createElement("style");
143
- s.textContent = bv_filter_panel_default;
144
- shadow.appendChild(s);
145
- }
146
144
  const header = document.createElement("div");
147
145
  header.className = "panel-header";
148
146
  const title = document.createElement("h2");
@@ -1,6 +1,24 @@
1
1
  // css-inline:/home/runner/work/BV_lumen/BV_lumen/components/bv-icon/bv-icon.css
2
2
  var bv_icon_default = ":host {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n color: inherit;\n}\n\n.icon-wrap {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n line-height: 0;\n}\n\n.icon-wrap svg {\n display: block;\n}\n";
3
3
 
4
+ // components/_shared/adopt-styles.ts
5
+ var _sheetCache = /* @__PURE__ */ new Map();
6
+ function adoptStyles(shadow, css) {
7
+ if ("adoptedStyleSheets" in ShadowRoot.prototype && typeof CSSStyleSheet !== "undefined" && "replaceSync" in CSSStyleSheet.prototype) {
8
+ let sheet = _sheetCache.get(css);
9
+ if (!sheet) {
10
+ sheet = new CSSStyleSheet();
11
+ sheet.replaceSync(css);
12
+ _sheetCache.set(css, sheet);
13
+ }
14
+ shadow.adoptedStyleSheets = [sheet];
15
+ return;
16
+ }
17
+ const style = document.createElement("style");
18
+ style.textContent = css;
19
+ shadow.appendChild(style);
20
+ }
21
+
4
22
  // components/bv-icon/icons.ts
5
23
  var icons = {
6
24
  // Navigation
@@ -81,12 +99,7 @@ var BvIcon = class extends HTMLElement {
81
99
  _wrap = null;
82
100
  constructor() {
83
101
  super();
84
- this.attachShadow({ mode: "open" });
85
- if ("replaceSync" in CSSStyleSheet.prototype) {
86
- const sheet = new CSSStyleSheet();
87
- sheet.replaceSync(bv_icon_default);
88
- this.shadowRoot.adoptedStyleSheets = [sheet];
89
- }
102
+ adoptStyles(this.attachShadow({ mode: "open" }), bv_icon_default);
90
103
  }
91
104
  connectedCallback() {
92
105
  this._render();
@@ -98,11 +111,6 @@ var BvIcon = class extends HTMLElement {
98
111
  if (this._rendered) return;
99
112
  this._rendered = true;
100
113
  const shadow = this.shadowRoot;
101
- if (!shadow.adoptedStyleSheets.length) {
102
- const s = document.createElement("style");
103
- s.textContent = bv_icon_default;
104
- shadow.appendChild(s);
105
- }
106
114
  this._wrap = document.createElement("span");
107
115
  this._wrap.className = "icon-wrap";
108
116
  shadow.appendChild(this._wrap);
@@ -1,15 +1,25 @@
1
1
  // css-inline:/home/runner/work/BV_lumen/BV_lumen/components/bv-input/bv-input.css
2
2
  var bv_input_default = ":host {\n display: block;\n font-family: var(--bv-font-family-base);\n}\n\n/* \u2500\u2500 Label \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.field-label {\n display: block;\n font-size: var(--bv-font-size-sm);\n font-weight: var(--bv-font-weight-semibold);\n color: var(--bv-color-neutral-800);\n margin-bottom: 6px;\n}\n\n.required-mark {\n color: var(--bv-color-danger);\n margin-left: 2px;\n}\n\n/* \u2500\u2500 Input \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.field-input {\n display: block;\n width: 100%;\n box-sizing: border-box;\n height: 44px;\n padding: 0 var(--bv-spacing-md);\n font-family: inherit;\n font-size: var(--bv-font-size-sm);\n color: var(--bv-color-neutral-800);\n background: var(--bv-color-neutral-0);\n border: 1px solid var(--bv-color-neutral-300);\n border-radius: var(--bv-radius-lg);\n outline: none;\n transition:\n border-color var(--bv-transition-fast),\n box-shadow var(--bv-transition-fast);\n}\n\n.field-input::placeholder {\n color: var(--bv-color-neutral-400);\n}\n\n.field-input:focus {\n border-color: var(--bv-color-primary);\n box-shadow:\n 0 0 0 3px var(--bv-color-primary-light),\n 0 1px 2px 0 rgba(16, 24, 40, 0.05);\n}\n\n.field-input:disabled {\n background: var(--bv-color-neutral-100);\n color: var(--bv-color-neutral-400);\n cursor: not-allowed;\n}\n\n:host([error]:not([error=''])) .field-input {\n border-color: var(--bv-color-danger);\n}\n\n:host([error]:not([error=''])) .field-input:focus {\n border-color: var(--bv-color-danger);\n box-shadow:\n 0 0 0 3px var(--bv-color-danger-light),\n 0 1px 2px 0 rgba(16, 24, 40, 0.05);\n}\n\n/* \u2500\u2500 Error message \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.field-error {\n display: block;\n font-size: var(--bv-font-size-xs);\n color: var(--bv-color-danger);\n margin-top: var(--bv-spacing-xs);\n}\n";
3
3
 
4
- // components/bv-input/bv-input.ts
5
- var _sheet = null;
6
- function getSheet() {
7
- if (!_sheet) {
8
- _sheet = new CSSStyleSheet();
9
- _sheet.replaceSync(bv_input_default);
4
+ // components/_shared/adopt-styles.ts
5
+ var _sheetCache = /* @__PURE__ */ new Map();
6
+ function adoptStyles(shadow, css) {
7
+ if ("adoptedStyleSheets" in ShadowRoot.prototype && typeof CSSStyleSheet !== "undefined" && "replaceSync" in CSSStyleSheet.prototype) {
8
+ let sheet = _sheetCache.get(css);
9
+ if (!sheet) {
10
+ sheet = new CSSStyleSheet();
11
+ sheet.replaceSync(css);
12
+ _sheetCache.set(css, sheet);
13
+ }
14
+ shadow.adoptedStyleSheets = [sheet];
15
+ return;
10
16
  }
11
- return _sheet;
17
+ const style = document.createElement("style");
18
+ style.textContent = css;
19
+ shadow.appendChild(style);
12
20
  }
21
+
22
+ // components/bv-input/bv-input.ts
13
23
  var BvInput = class extends HTMLElement {
14
24
  static observedAttributes = [
15
25
  "label",
@@ -27,10 +37,7 @@ var BvInput = class extends HTMLElement {
27
37
  _errorEl = null;
28
38
  constructor() {
29
39
  super();
30
- const shadow = this.attachShadow({ mode: "open" });
31
- if ("adoptedStyleSheets" in ShadowRoot.prototype) {
32
- shadow.adoptedStyleSheets = [getSheet()];
33
- }
40
+ adoptStyles(this.attachShadow({ mode: "open" }), bv_input_default);
34
41
  }
35
42
  get value() {
36
43
  var _a;
@@ -73,11 +80,6 @@ var BvInput = class extends HTMLElement {
73
80
  if (this._rendered) return;
74
81
  this._rendered = true;
75
82
  const shadow = this.shadowRoot;
76
- if (!shadow.adoptedStyleSheets.length) {
77
- const s = document.createElement("style");
78
- s.textContent = bv_input_default;
79
- shadow.appendChild(s);
80
- }
81
83
  const label = document.createElement("label");
82
84
  label.className = "field-label";
83
85
  this._labelEl = label;
@@ -22,7 +22,7 @@ export declare class BvInputDropdown extends HTMLElement {
22
22
  private _selectAllEl;
23
23
  private _toggleEl;
24
24
  private _errorEl;
25
- private _offClick;
25
+ private _dropdown;
26
26
  constructor();
27
27
  get value(): string;
28
28
  set value(v: string);
@@ -34,9 +34,6 @@ export declare class BvInputDropdown extends HTMLElement {
34
34
  disconnectedCallback(): void;
35
35
  attributeChangedCallback(name: string, _old: string | null, _val: string | null): void;
36
36
  private _render;
37
- private _toggle;
38
- private _open;
39
- private _close;
40
37
  private _syncLabel;
41
38
  private _syncTriggerLabel;
42
39
  private _syncError;