@bluevolt-tech/lumen 2.0.0 → 2.1.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 +61 -0
  4. package/dist/components/_shared/dropdown-controller.d.ts +31 -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 -2
  16. package/dist/components/bv-course-grid-card/bv-course-grid-card.js +105 -55
  17. package/dist/components/bv-course-list-card/bv-course-list-card.d.ts +2 -2
  18. package/dist/components/bv-course-list-card/bv-course-list-card.js +105 -55
  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 +4 -6
  21. package/dist/components/bv-date-range-input/bv-date-range-input.js +460 -122
  22. package/dist/components/bv-date-range-picker/bv-date-range-picker.d.ts +17 -3
  23. package/dist/components/bv-date-range-picker/bv-date-range-picker.js +339 -73
  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 +78 -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 +77 -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 +76 -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 +76 -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 +69 -19
  50. package/dist/components/bv-toggle/bv-toggle.js +19 -11
  51. package/dist/components/bv-tooltip/bv-tooltip.js +19 -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 +2 -1
  55. package/package.json +8 -1
  56. package/themes/base.css +2 -1
@@ -1,5 +1,23 @@
1
1
  // css-inline:/home/runner/work/BV_lumen/BV_lumen/components/bv-course-list-card/bv-course-list-card.css
2
- var bv_course_list_card_default = ":host {\n display: block;\n}\n\n.card {\n display: flex;\n align-items: stretch;\n gap: var(--bv-spacing-md);\n padding: 12px;\n background: var(--bv-color-neutral-0);\n border: 1px solid var(--bv-color-neutral-300);\n border-radius: var(--bv-radius-xl);\n box-shadow: var(--bv-shadow-sm);\n cursor: pointer;\n transition:\n background var(--bv-transition-fast),\n border-color var(--bv-transition-fast),\n box-shadow var(--bv-transition-fast);\n}\n\n:host([selected]) .card {\n background: var(--bv-color-primary-50);\n border-color: var(--bv-color-primary);\n box-shadow: none;\n}\n\n/* Thumbnail */\n.thumbnail-wrap {\n position: relative;\n flex-shrink: 0;\n width: 200px;\n min-height: 123px;\n border-radius: var(--bv-radius-lg);\n overflow: hidden;\n background: var(--bv-color-neutral-200);\n}\n\n.thumbnail {\n width: 100%;\n height: 100%;\n object-fit: cover;\n display: block;\n}\n\n.status-badge {\n position: absolute;\n top: 6px;\n right: 6px;\n padding: 0 var(--bv-spacing-sm);\n border-radius: var(--bv-radius-sm);\n font-family: var(--bv-font-family-base);\n font-size: var(--bv-font-size-xs);\n font-weight: var(--bv-font-weight-medium);\n line-height: 18px;\n background: var(--bv-color-success-light);\n color: var(--bv-color-success-dark);\n}\n\n/* Content */\n.content {\n display: flex;\n flex-direction: column;\n flex: 1;\n min-width: 0;\n justify-content: space-between;\n}\n\n.meta {\n display: flex;\n flex-direction: column;\n gap: 3px;\n}\n\n.title {\n font-family: var(--bv-font-family-base);\n font-size: var(--bv-font-size-md);\n font-weight: var(--bv-font-weight-semibold);\n color: var(--bv-color-neutral-900);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.publisher {\n font-family: var(--bv-font-family-base);\n font-size: var(--bv-font-size-xs);\n font-weight: var(--bv-font-weight-regular);\n color: var(--bv-color-neutral-500);\n}\n\n.publisher strong {\n font-weight: var(--bv-font-weight-medium);\n color: var(--bv-color-neutral-900);\n}\n\n.description-wrap {\n height: 40px;\n display: flex;\n align-items: center;\n overflow: hidden;\n}\n\n.description {\n margin: 0;\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-700);\n line-height: 20px;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.info-row {\n display: flex;\n gap: var(--bv-spacing-md);\n}\n\n.info-item {\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-900);\n}\n\n.info-item strong {\n font-weight: var(--bv-font-weight-bold);\n}\n\n/* Actions */\n.actions {\n display: flex;\n flex-direction: column;\n gap: var(--bv-spacing-sm);\n flex-shrink: 0;\n width: 209px;\n justify-content: center;\n}\n\n/* Disabled selection: card body is no longer interactive */\n:host([disable-selection]) .card {\n cursor: default;\n}\n\n/* Loading skeleton */\n.skeleton {\n display: none;\n align-items: stretch;\n gap: var(--bv-spacing-md);\n flex: 1;\n min-width: 0;\n}\n\n:host([loading]) .card {\n cursor: default;\n}\n\n:host([loading]) .thumbnail-wrap,\n:host([loading]) .content,\n:host([loading]) .actions {\n display: none;\n}\n\n:host([loading]) .skeleton {\n display: flex;\n}\n\n.skeleton-thumb {\n flex-shrink: 0;\n width: 200px;\n min-height: 123px;\n border-radius: var(--bv-radius-lg);\n background: var(--bv-color-neutral-200);\n animation: bv-skeleton-shimmer 1.5s ease-in-out infinite;\n}\n\n.skeleton-content {\n display: flex;\n flex-direction: column;\n gap: var(--bv-spacing-sm);\n flex: 1;\n min-width: 0;\n justify-content: center;\n}\n\n.skeleton-line {\n height: 12px;\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-title-line {\n height: 20px;\n width: 60%;\n}\n\n.skeleton-short-line {\n width: 40%;\n}\n\n.skeleton-actions {\n display: flex;\n flex-direction: column;\n gap: var(--bv-spacing-sm);\n flex-shrink: 0;\n width: 209px;\n justify-content: center;\n}\n\n.skeleton-button {\n height: 40px;\n border-radius: var(--bv-radius-md);\n background: var(--bv-color-neutral-200);\n animation: bv-skeleton-shimmer 1.5s ease-in-out infinite;\n}\n\n@keyframes bv-skeleton-shimmer {\n 0%,\n 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0.5;\n }\n}\n";
2
+ var bv_course_list_card_default = ":host {\n display: block;\n}\n\n.card {\n display: flex;\n align-items: stretch;\n gap: var(--bv-spacing-md);\n padding: 12px;\n background: var(--bv-color-neutral-0);\n border: 1px solid var(--bv-color-neutral-300);\n border-radius: var(--bv-radius-xl);\n box-shadow: var(--bv-shadow-sm);\n cursor: pointer;\n transition:\n background var(--bv-transition-fast),\n border-color var(--bv-transition-fast),\n box-shadow var(--bv-transition-fast);\n}\n\n:host([selected]) .card {\n background: var(--bv-color-primary-50);\n border-color: var(--bv-color-primary);\n box-shadow: none;\n}\n\n.card:focus-visible {\n outline: var(--bv-focus-ring);\n outline-offset: 2px;\n}\n\n/* Thumbnail */\n.thumbnail-wrap {\n position: relative;\n flex-shrink: 0;\n width: 200px;\n min-height: 123px;\n border-radius: var(--bv-radius-lg);\n overflow: hidden;\n background: var(--bv-color-neutral-200);\n}\n\n.thumbnail {\n width: 100%;\n height: 100%;\n object-fit: cover;\n display: block;\n}\n\n.status-badge {\n position: absolute;\n top: 6px;\n right: 6px;\n padding: 0 var(--bv-spacing-sm);\n border-radius: var(--bv-radius-sm);\n font-family: var(--bv-font-family-base);\n font-size: var(--bv-font-size-xs);\n font-weight: var(--bv-font-weight-medium);\n line-height: 18px;\n background: var(--bv-color-success-light);\n color: var(--bv-color-success-dark);\n}\n\n/* Content */\n.content {\n display: flex;\n flex-direction: column;\n flex: 1;\n min-width: 0;\n justify-content: space-between;\n}\n\n.meta {\n display: flex;\n flex-direction: column;\n gap: 3px;\n}\n\n.title {\n font-family: var(--bv-font-family-base);\n font-size: var(--bv-font-size-md);\n font-weight: var(--bv-font-weight-semibold);\n color: var(--bv-color-neutral-900);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.publisher {\n font-family: var(--bv-font-family-base);\n font-size: var(--bv-font-size-xs);\n font-weight: var(--bv-font-weight-regular);\n color: var(--bv-color-neutral-500);\n}\n\n.publisher strong {\n font-weight: var(--bv-font-weight-medium);\n color: var(--bv-color-neutral-900);\n}\n\n.description-wrap {\n height: 40px;\n display: flex;\n align-items: center;\n overflow: hidden;\n}\n\n.description {\n margin: 0;\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-700);\n line-height: 20px;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.info-row {\n display: flex;\n gap: var(--bv-spacing-md);\n}\n\n.info-item {\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-900);\n}\n\n.info-item strong {\n font-weight: var(--bv-font-weight-bold);\n}\n\n/* Actions */\n.actions {\n display: flex;\n flex-direction: column;\n gap: var(--bv-spacing-sm);\n flex-shrink: 0;\n width: 209px;\n justify-content: center;\n}\n\n/* Disabled selection: card body is no longer interactive */\n:host([disable-selection]) .card {\n cursor: default;\n}\n\n/* Loading skeleton */\n.skeleton {\n display: none;\n align-items: stretch;\n gap: var(--bv-spacing-md);\n flex: 1;\n min-width: 0;\n}\n\n:host([loading]) .card {\n cursor: default;\n}\n\n:host([loading]) .thumbnail-wrap,\n:host([loading]) .content,\n:host([loading]) .actions {\n display: none;\n}\n\n:host([loading]) .skeleton {\n display: flex;\n}\n\n.skeleton-thumb {\n flex-shrink: 0;\n width: 200px;\n min-height: 123px;\n border-radius: var(--bv-radius-lg);\n background: var(--bv-color-neutral-200);\n animation: bv-skeleton-shimmer 1.5s ease-in-out infinite;\n}\n\n.skeleton-content {\n display: flex;\n flex-direction: column;\n gap: var(--bv-spacing-sm);\n flex: 1;\n min-width: 0;\n justify-content: center;\n}\n\n.skeleton-line {\n height: 12px;\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-title-line {\n height: 20px;\n width: 60%;\n}\n\n.skeleton-short-line {\n width: 40%;\n}\n\n.skeleton-actions {\n display: flex;\n flex-direction: column;\n gap: var(--bv-spacing-sm);\n flex-shrink: 0;\n width: 209px;\n justify-content: center;\n}\n\n.skeleton-button {\n height: 40px;\n border-radius: var(--bv-radius-md);\n background: var(--bv-color-neutral-200);\n animation: bv-skeleton-shimmer 1.5s ease-in-out infinite;\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
+
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
+ }
3
21
 
4
22
  // css-inline:/home/runner/work/BV_lumen/BV_lumen/components/bv-button/bv-button.css
5
23
  var bv_button_default = "/* \u2500\u2500 Public theming API \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 Apps can override these three properties per-instance:\n\n HTML: <bv-button style=\"--bv-button-bg: #e53e3e;\">\n Angular: <bv-button [style.--bv-button-bg]=\"brandColor\">\n JavaScript: btn.style.setProperty('--bv-button-bg', value)\n\n Hover is auto-computed from the base colors via color-mix().\n Override --bv-button-bg-hover / --bv-button-border-color-hover\n if you need explicit control over the hovered state.\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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:host {\n /* Default values \u2014 map to global tokens (primary variant) */\n --bv-button-bg: var(--bv-color-primary);\n --bv-button-bg-hover: color-mix(in srgb, var(--bv-button-bg) 82%, black);\n --bv-button-color: var(--bv-color-neutral-0);\n --bv-button-border-color: var(--bv-color-primary);\n --bv-button-border-color-hover: color-mix(in srgb, var(--bv-button-border-color) 82%, black);\n --bv-button-font-family: var(--bv-font-family-base);\n --bv-button-font-size: var(--bv-font-size-sm);\n\n display: inline-block;\n font-family: var(--bv-font-family-base);\n}\n\n:host([hidden]) {\n /* `!important` so `hidden` always wins over :host([full-width]) / other display rules. */\n display: none !important;\n}\n\n:host([full-width]) {\n display: block;\n width: 100%;\n}\n\n/* \u2500\u2500 Variant 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\n Each variant re-points the component tokens to different global\n tokens. Apps can still override with inline styles \u2014 inline style\n always wins due to higher specificity.\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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([variant='secondary']) {\n --bv-button-bg: var(--bv-color-secondary);\n --bv-button-border-color: var(--bv-color-secondary);\n --bv-button-color: var(--bv-color-secondary-foreground);\n}\n\n:host([variant='tertiary']) {\n --bv-button-bg: var(--bv-color-tertiary);\n --bv-button-border-color: var(--bv-color-tertiary);\n}\n\n:host([variant='danger']) {\n --bv-button-bg: var(--bv-color-danger);\n --bv-button-border-color: var(--bv-color-danger);\n}\n\n:host([variant='ghost']) {\n --bv-button-bg: transparent;\n --bv-button-bg-hover: var(--bv-color-primary-light);\n --bv-button-color: var(--bv-color-primary);\n --bv-button-border-color: transparent;\n --bv-button-border-color-hover: transparent;\n}\n\n:host([variant='outline']) {\n --bv-button-bg: transparent;\n --bv-button-bg-hover: var(--bv-color-primary-light);\n --bv-button-color: var(--bv-color-primary);\n --bv-button-border-color: var(--bv-color-primary);\n --bv-button-border-color-hover: var(--bv-color-primary);\n}\n\n:host([variant='outline-secondary']) {\n --bv-button-bg: transparent;\n --bv-button-bg-hover: var(--bv-color-neutral-100);\n --bv-button-color: var(--bv-color-neutral-700);\n --bv-button-border-color: var(--bv-color-neutral-300);\n --bv-button-border-color-hover: var(--bv-color-neutral-300);\n}\n\n/* \u2500\u2500 Base button \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 All visual properties read from the component-level tokens above.\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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.btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--bv-spacing-xs);\n padding: 10px var(--bv-spacing-md);\n min-height: 40px;\n width: auto;\n font-family: var(--bv-button-font-family);\n font-size: var(--bv-button-font-size);\n font-style: normal;\n font-weight: var(--bv-font-weight-semibold);\n line-height: 20px;\n border: 1px solid var(--bv-button-border-color);\n border-radius: var(--bv-radius-lg);\n cursor: pointer;\n transition:\n background var(--bv-transition-fast),\n color var(--bv-transition-fast),\n border-color var(--bv-transition-fast),\n box-shadow var(--bv-transition-fast),\n opacity var(--bv-transition-fast);\n white-space: nowrap;\n user-select: none;\n text-decoration: none;\n outline: none;\n box-sizing: border-box;\n background: var(--bv-button-bg);\n color: var(--bv-button-color);\n box-shadow: var(--bv-shadow-sm);\n}\n\n:host([full-width]) .btn {\n width: 100%;\n}\n\n.btn:hover:not(:disabled) {\n background: var(--bv-button-bg-hover);\n border-color: var(--bv-button-border-color-hover);\n}\n\n.btn:active:not(:disabled) {\n transform: translateY(1px);\n}\n\n.btn:focus-visible {\n outline: 2px solid var(--bv-button-border-color);\n outline-offset: 2px;\n}\n\n.btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n pointer-events: none;\n}\n\n/* \u2500\u2500 Sizes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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([size='sm']) .btn {\n padding: 6px 12px;\n min-height: 32px;\n font-size: var(--bv-font-size-sm);\n}\n\n:host([size='lg']) .btn {\n padding: 12px var(--bv-spacing-lg);\n min-height: 48px;\n font-size: var(--bv-font-size-md);\n}\n\n/* \u2500\u2500 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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500*/\n\n.btn-icon {\n display: inline-flex;\n align-items: center;\n flex-shrink: 0;\n line-height: 0;\n}\n\n/* \u2500\u2500 Count badge \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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.btn-count {\n opacity: 0.8;\n font-weight: var(--bv-font-weight-regular);\n}\n\n/* \u2500\u2500 Loading spinner \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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.spinner {\n display: inline-block;\n width: 1em;\n height: 1em;\n border: 2px solid currentColor;\n border-top-color: transparent;\n border-radius: 50%;\n flex-shrink: 0;\n animation: bv-spin 700ms linear infinite;\n}\n\n@keyframes bv-spin {\n to {\n transform: rotate(360deg);\n }\n}\n";
@@ -78,14 +96,6 @@ var rawIcons = {
78
96
  };
79
97
 
80
98
  // components/bv-button/bv-button.ts
81
- var _sheet = null;
82
- function getSheet() {
83
- if (!_sheet) {
84
- _sheet = new CSSStyleSheet();
85
- _sheet.replaceSync(bv_button_default);
86
- }
87
- return _sheet;
88
- }
89
99
  var BvButton = class extends HTMLElement {
90
100
  static observedAttributes = [
91
101
  "variant",
@@ -101,10 +111,7 @@ var BvButton = class extends HTMLElement {
101
111
  ];
102
112
  constructor() {
103
113
  super();
104
- const shadow = this.attachShadow({ mode: "open" });
105
- if ("adoptedStyleSheets" in ShadowRoot.prototype) {
106
- shadow.adoptedStyleSheets = [getSheet()];
107
- }
114
+ adoptStyles(this.attachShadow({ mode: "open" }), bv_button_default);
108
115
  }
109
116
  // ── Accessors ────────────────────────────────────────────────
110
117
  get variant() {
@@ -161,11 +168,6 @@ var BvButton = class extends HTMLElement {
161
168
  const shadow = this.shadowRoot;
162
169
  let btn = shadow.querySelector("button");
163
170
  if (!btn) {
164
- if (!shadow.adoptedStyleSheets.length) {
165
- const styleEl = document.createElement("style");
166
- styleEl.textContent = bv_button_default;
167
- shadow.appendChild(styleEl);
168
- }
169
171
  btn = document.createElement("button");
170
172
  btn.setAttribute("part", "button");
171
173
  btn.appendChild(document.createElement("slot"));
@@ -219,6 +221,65 @@ if (!customElements.get("bv-button")) {
219
221
  customElements.define("bv-button", BvButton);
220
222
  }
221
223
 
224
+ // components/_shared/selectable-card.ts
225
+ function buildAriaLabel(host) {
226
+ const title = host.getAttribute("title") ?? "";
227
+ const publisher = host.getAttribute("publisher") ?? "";
228
+ const parts = [];
229
+ if (title) parts.push(title);
230
+ if (publisher) parts.push(`by ${publisher}`);
231
+ return parts.join(", ");
232
+ }
233
+ function setPrefixedStrong(el, prefix, val) {
234
+ if (!el) return;
235
+ const value = val ?? "";
236
+ if (!value) {
237
+ el.hidden = true;
238
+ el.replaceChildren();
239
+ return;
240
+ }
241
+ el.hidden = false;
242
+ const strong = document.createElement("strong");
243
+ strong.textContent = value;
244
+ if (prefix) el.replaceChildren(document.createTextNode(prefix), strong);
245
+ else el.replaceChildren(strong);
246
+ }
247
+ function syncSelectionA11y(host, card) {
248
+ const inert = host.disableSelection || host.loading;
249
+ card.setAttribute("tabindex", inert ? "-1" : "0");
250
+ if (inert) card.setAttribute("aria-disabled", "true");
251
+ else card.removeAttribute("aria-disabled");
252
+ }
253
+ function syncCardLoading(host, card) {
254
+ card.setAttribute("aria-busy", host.loading ? "true" : "false");
255
+ }
256
+ function bindCardSelection(host, card, actions) {
257
+ const toggle = () => {
258
+ host.selected = !host.selected;
259
+ host.dispatchEvent(
260
+ new CustomEvent("bv-select", {
261
+ bubbles: true,
262
+ composed: true,
263
+ detail: { selected: host.selected }
264
+ })
265
+ );
266
+ };
267
+ const isInert = () => host.disableSelection || host.loading;
268
+ const originatesFromActions = (e) => e.composedPath().includes(actions);
269
+ card.addEventListener("click", (e) => {
270
+ if (isInert()) return;
271
+ if (originatesFromActions(e)) return;
272
+ toggle();
273
+ });
274
+ card.addEventListener("keydown", (e) => {
275
+ if (e.key !== "Enter" && e.key !== " ") return;
276
+ if (isInert()) return;
277
+ if (originatesFromActions(e)) return;
278
+ e.preventDefault();
279
+ toggle();
280
+ });
281
+ }
282
+
222
283
  // components/bv-course-list-card/bv-course-list-card.ts
223
284
  var BvCourseListCard = class extends HTMLElement {
224
285
  static observedAttributes = [
@@ -287,12 +348,7 @@ var BvCourseListCard = class extends HTMLElement {
287
348
  _els = {};
288
349
  constructor() {
289
350
  super();
290
- this.attachShadow({ mode: "open" });
291
- if ("replaceSync" in CSSStyleSheet.prototype) {
292
- const sheet = new CSSStyleSheet();
293
- sheet.replaceSync(bv_course_list_card_default);
294
- this.shadowRoot.adoptedStyleSheets = [sheet];
295
- }
351
+ adoptStyles(this.attachShadow({ mode: "open" }), bv_course_list_card_default);
296
352
  }
297
353
  connectedCallback() {
298
354
  this._render();
@@ -300,6 +356,7 @@ var BvCourseListCard = class extends HTMLElement {
300
356
  attributeChangedCallback(name, _old, val) {
301
357
  var _a;
302
358
  if (!this._rendered) return;
359
+ const card = this._els.card;
303
360
  const map = {
304
361
  thumbnail: () => {
305
362
  var _a2;
@@ -313,19 +370,20 @@ var BvCourseListCard = class extends HTMLElement {
313
370
  },
314
371
  title: () => {
315
372
  if (this._els.title) this._els.title.textContent = val ?? "";
373
+ card == null ? void 0 : card.setAttribute("aria-label", buildAriaLabel(this));
316
374
  },
317
375
  publisher: () => {
318
- if (this._els.publisher) this._els.publisher.innerHTML = `By <strong>${val ?? ""}</strong>`;
376
+ setPrefixedStrong(this._els.publisher, "By ", val);
377
+ card == null ? void 0 : card.setAttribute("aria-label", buildAriaLabel(this));
319
378
  },
320
379
  description: () => {
321
380
  if (this._els.description) this._els.description.textContent = val ?? "";
322
381
  },
323
382
  duration: () => {
324
- if (this._els.duration) this._els.duration.innerHTML = `<strong>${val ?? ""}</strong>`;
383
+ setPrefixedStrong(this._els.duration, "", val);
325
384
  },
326
385
  "last-updated": () => {
327
- if (this._els.lastUpdated)
328
- this._els.lastUpdated.innerHTML = `Last Updated: <strong>${val ?? ""}</strong>`;
386
+ setPrefixedStrong(this._els.lastUpdated, "Last Updated: ", val);
329
387
  },
330
388
  "primary-label": () => {
331
389
  if (this._els.primaryBtn) this._els.primaryBtn.textContent = val ?? "";
@@ -358,8 +416,17 @@ var BvCourseListCard = class extends HTMLElement {
358
416
  "hide-secondary": () => {
359
417
  if (this._els.secondaryBtn) this._els.secondaryBtn.hidden = this.hideSecondary;
360
418
  },
419
+ selected: () => {
420
+ card == null ? void 0 : card.setAttribute("aria-checked", this.selected ? "true" : "false");
421
+ },
422
+ "disable-selection": () => {
423
+ if (card) syncSelectionA11y(this, card);
424
+ },
361
425
  loading: () => {
362
- this._syncLoading();
426
+ if (card) {
427
+ syncCardLoading(this, card);
428
+ syncSelectionA11y(this, card);
429
+ }
363
430
  }
364
431
  };
365
432
  (_a = map[name]) == null ? void 0 : _a.call(map);
@@ -368,13 +435,11 @@ var BvCourseListCard = class extends HTMLElement {
368
435
  if (this._rendered) return;
369
436
  this._rendered = true;
370
437
  const shadow = this.shadowRoot;
371
- if (!shadow.adoptedStyleSheets.length) {
372
- const s = document.createElement("style");
373
- s.textContent = bv_course_list_card_default;
374
- shadow.appendChild(s);
375
- }
376
438
  const card = document.createElement("div");
377
439
  card.className = "card";
440
+ card.setAttribute("role", "checkbox");
441
+ card.setAttribute("aria-checked", this.selected ? "true" : "false");
442
+ card.setAttribute("aria-label", buildAriaLabel(this));
378
443
  this._els.card = card;
379
444
  const thumbWrap = document.createElement("div");
380
445
  thumbWrap.className = "thumbnail-wrap";
@@ -400,8 +465,8 @@ var BvCourseListCard = class extends HTMLElement {
400
465
  this._els.title = title;
401
466
  const publisher = document.createElement("span");
402
467
  publisher.className = "publisher";
403
- publisher.innerHTML = `By <strong>${this.getAttribute("publisher") ?? ""}</strong>`;
404
468
  this._els.publisher = publisher;
469
+ setPrefixedStrong(publisher, "By ", this.getAttribute("publisher"));
405
470
  meta.append(title, publisher);
406
471
  const descriptionWrap = document.createElement("div");
407
472
  descriptionWrap.className = "description-wrap";
@@ -414,12 +479,12 @@ var BvCourseListCard = class extends HTMLElement {
414
479
  infoRow.className = "info-row";
415
480
  const duration = document.createElement("span");
416
481
  duration.className = "info-item";
417
- duration.innerHTML = `<strong>${this.getAttribute("duration") ?? ""}</strong>`;
418
482
  this._els.duration = duration;
483
+ setPrefixedStrong(duration, "", this.getAttribute("duration"));
419
484
  const lastUpdated = document.createElement("span");
420
485
  lastUpdated.className = "info-item";
421
- lastUpdated.innerHTML = `Last Updated: <strong>${this.getAttribute("last-updated") ?? ""}</strong>`;
422
486
  this._els.lastUpdated = lastUpdated;
487
+ setPrefixedStrong(lastUpdated, "Last Updated: ", this.getAttribute("last-updated"));
423
488
  infoRow.append(duration, lastUpdated);
424
489
  content.append(meta, descriptionWrap, infoRow);
425
490
  const actions = document.createElement("div");
@@ -454,24 +519,9 @@ var BvCourseListCard = class extends HTMLElement {
454
519
  this._els.skeleton = skeleton;
455
520
  card.append(thumbWrap, content, actions, skeleton);
456
521
  shadow.appendChild(card);
457
- this._syncLoading();
458
- card.addEventListener("click", (e) => {
459
- if (this.disableSelection || this.loading) return;
460
- if (e.composedPath().includes(this._els.actions)) return;
461
- this.selected = !this.selected;
462
- this.dispatchEvent(
463
- new CustomEvent("bv-select", {
464
- bubbles: true,
465
- composed: true,
466
- detail: { selected: this.selected }
467
- })
468
- );
469
- });
470
- }
471
- _syncLoading() {
472
- var _a;
473
- const loading = this.loading;
474
- (_a = this._els.card) == null ? void 0 : _a.setAttribute("aria-busy", loading ? "true" : "false");
522
+ syncCardLoading(this, card);
523
+ syncSelectionA11y(this, card);
524
+ bindCardSelection(this, card, actions);
475
525
  }
476
526
  };
477
527
  if (!customElements.get("bv-course-list-card")) {
@@ -1,6 +1,24 @@
1
1
  // css-inline:/home/runner/work/BV_lumen/BV_lumen/components/bv-course-outline/bv-course-outline.css
2
2
  var bv_course_outline_default = ":host {\n display: block;\n font-family: var(--bv-font-family-base);\n}\n\n/* \u2500\u2500 Outer container \u2500\u2500 */\n\n.container {\n border: 0.5px solid var(--bv-color-neutral-300);\n border-radius: var(--bv-radius-xl);\n overflow: hidden;\n}\n\n.container-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 20px 24px;\n background: #f9fafb;\n border-bottom: 0.5px solid var(--bv-color-neutral-300);\n}\n\n.container-title {\n font-size: var(--bv-font-size-2xl);\n font-weight: var(--bv-font-weight-medium);\n color: var(--bv-color-neutral-700);\n line-height: 32px;\n}\n\n.expand-all-btn {\n background: none;\n border: none;\n padding: 0;\n cursor: pointer;\n font-family: var(--bv-font-family-base);\n font-size: var(--bv-font-size-md);\n font-weight: var(--bv-font-weight-bold);\n color: var(--bv-color-primary);\n line-height: 24px;\n white-space: nowrap;\n}\n\n.expand-all-btn:hover {\n text-decoration: underline;\n}\n\n.outline {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 24px;\n background: var(--bv-color-neutral-0);\n}\n\n/* \u2500\u2500 Section \u2500\u2500 */\n\n.section {\n background: var(--bv-color-neutral-0);\n border: 0.5px solid var(--bv-color-neutral-300);\n border-radius: var(--bv-radius-xl);\n overflow: hidden;\n}\n\n.section-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n padding: 20px;\n cursor: pointer;\n user-select: none;\n}\n\n.section-header:hover {\n background: linear-gradient(90deg, #fff, #f9fafb 15% 85%, #fff);\n}\n\n.section-header:focus-visible {\n outline: 2px solid var(--bv-color-primary);\n outline-offset: -2px;\n border-radius: var(--bv-radius-xl);\n}\n\n.section-header-left {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n flex: 1;\n min-width: 0;\n gap: 12px;\n}\n\n.section-title-row {\n display: flex;\n align-items: center;\n gap: 12px;\n width: 100%;\n}\n\n.section-title {\n font-size: var(--bv-font-size-lg);\n font-weight: var(--bv-font-weight-medium);\n color: var(--bv-color-neutral-900);\n line-height: 28px;\n}\n\n.section-badge {\n display: inline-flex;\n align-items: center;\n padding: 0 8px;\n border: 1px solid var(--bv-color-neutral-300);\n border-radius: var(--bv-radius-full);\n font-size: 10px;\n font-weight: var(--bv-font-weight-regular);\n color: var(--bv-color-neutral-500);\n line-height: 18px;\n white-space: nowrap;\n}\n\n.section-chevron {\n flex-shrink: 0;\n width: 24px;\n height: 24px;\n color: var(--bv-color-neutral-500);\n transition: transform var(--bv-transition-fast);\n}\n\n.section-chevron svg {\n width: 100%;\n height: 100%;\n}\n\n.section--expanded .section-chevron {\n transform: rotate(180deg);\n}\n\n/* \u2500\u2500 Section body \u2500\u2500 */\n\n.section-body {\n display: none;\n border-top: 0.5px solid var(--bv-color-neutral-300);\n}\n\n.section--expanded .section-body {\n display: block;\n}\n\n/* \u2500\u2500 Description \u2500\u2500 */\n\n.section-desc-wrap {\n padding: 16px 20px 20px;\n}\n\n.section-desc {\n margin: 0 0 4px;\n font-size: var(--bv-font-size-md);\n font-weight: var(--bv-font-weight-regular);\n color: var(--bv-color-neutral-700);\n line-height: 24px;\n display: -webkit-box;\n -webkit-line-clamp: 3;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.section-desc-wrap--expanded .section-desc {\n -webkit-line-clamp: unset;\n}\n\n.read-more {\n background: none;\n border: none;\n padding: 0;\n cursor: pointer;\n font-family: var(--bv-font-family-base);\n font-size: var(--bv-font-size-md);\n font-weight: var(--bv-font-weight-semibold);\n color: var(--bv-color-primary);\n line-height: 24px;\n}\n\n.read-more:hover {\n text-decoration: underline;\n}\n\n/* \u2500\u2500 Module list \u2500\u2500 */\n\n.module-list {\n padding-left: 20px;\n padding-right: 20px;\n}\n\n.module-sep {\n height: 0;\n border-top: 0.5px solid var(--bv-color-neutral-300);\n margin-left: 20px;\n}\n\n.desc-sep {\n height: 0;\n border-top: 0.5px solid var(--bv-color-neutral-300);\n margin: 0 20px;\n}\n\n.module-row {\n display: flex;\n align-items: center;\n gap: 12px;\n min-height: 72px;\n padding: 0 0 0 20px;\n}\n\n.module-row:hover {\n background: linear-gradient(90deg, #fff, #f9fafb 15% 85%, #fff);\n}\n\n/* \u2500\u2500 Module icon \u2500\u2500 */\n\n.module-icon {\n flex-shrink: 0;\n width: 34px;\n height: 34px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.module-icon svg {\n width: 100%;\n height: 100%;\n display: block;\n}\n\n/* \u2500\u2500 Module content \u2500\u2500 */\n\n.module-content {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.module-title-row {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.module-type-icon {\n flex-shrink: 0;\n width: 18px;\n height: 18px;\n color: var(--bv-color-neutral-500);\n display: flex;\n align-items: center;\n}\n\n.module-type-icon svg {\n width: 100%;\n height: 100%;\n display: block;\n}\n\n.module-title {\n flex: 1;\n min-width: 0;\n font-size: var(--bv-font-size-md);\n font-weight: var(--bv-font-weight-medium);\n color: var(--bv-color-neutral-700);\n line-height: 24px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* \u2500\u2500 Module status \u2500\u2500 */\n\n.module-status {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: var(--bv-font-size-sm);\n font-weight: var(--bv-font-weight-bold);\n line-height: 20px;\n}\n\n.module-status span {\n white-space: nowrap;\n}\n\n.status-icon {\n width: 18px;\n height: 18px;\n flex-shrink: 0;\n}\n\n.module-status--completed,\n.module-status--viewed,\n.module-status--pending-review {\n color: var(--bv-color-success-dark);\n}\n\n.module-status--in-progress,\n.module-status--not-started {\n color: var(--bv-color-neutral-700);\n}\n\n.module-status--max-retakes,\n.module-status--rejected {\n color: #f04438;\n}\n\n.module-status--seat-time {\n color: var(--bv-color-primary);\n}\n\n/* \u2500\u2500 Module actions \u2500\u2500 */\n\n.module-actions {\n display: flex;\n align-items: center;\n gap: 16px;\n flex-shrink: 0;\n}\n\n.module-action-btn {\n background: none;\n border: none;\n padding: 0;\n cursor: pointer;\n font-family: var(--bv-font-family-base);\n font-size: var(--bv-font-size-sm);\n font-weight: var(--bv-font-weight-bold);\n color: var(--bv-color-primary);\n line-height: 20px;\n white-space: nowrap;\n}\n\n.module-action-btn:hover {\n text-decoration: underline;\n}\n\n/* \u2500\u2500 Pre-enrollment section \u2500\u2500 */\n\n.section--pre-enrollment .section-header {\n align-items: flex-start;\n}\n\n.pre-title-row {\n display: flex;\n align-items: center;\n gap: 16px;\n width: 100%;\n}\n\n.section-count-text {\n flex-shrink: 0;\n font-size: var(--bv-font-size-sm);\n font-weight: var(--bv-font-weight-regular);\n color: var(--bv-color-neutral-500);\n line-height: 20px;\n white-space: nowrap;\n}\n\n.section--pre-enrollment .section-chevron {\n margin-top: 2px;\n}\n\n.pre-section-desc-wrap {\n width: 100%;\n}\n\n/* \u2500\u2500 Pre-enrollment module list \u2500\u2500 */\n\n.pre-module-list {\n display: flex;\n flex-direction: column;\n padding: 0 20px;\n}\n\n.pre-module-list .module-sep {\n margin-left: 0;\n}\n\n.pre-module-wrap {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.pre-module-row {\n display: flex;\n align-items: center;\n gap: 8px;\n min-height: 24px;\n padding: 16px 0;\n}\n\n.pre-module-list > .pre-module-wrap:first-child .pre-module-row {\n padding-top: 16px;\n}\n.pre-module-list > .pre-module-wrap:last-child .pre-module-row {\n padding-bottom: 16px;\n}\n\n.pre-module-row:hover {\n background: linear-gradient(90deg, #fff, #f9fafb 15% 85%, #fff);\n}\n\n.pre-module-title-group {\n display: flex;\n align-items: center;\n gap: 8px;\n flex: 1;\n min-width: 0;\n}\n\n.pre-module-title {\n min-width: 0;\n font-size: var(--bv-font-size-md);\n font-weight: var(--bv-font-weight-medium);\n color: var(--bv-color-neutral-700);\n line-height: 24px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.pre-module-badges {\n display: flex;\n gap: 4px;\n align-items: center;\n flex-shrink: 0;\n}\n\n.pre-badge {\n display: inline-flex;\n align-items: center;\n padding: 2px 8px;\n border-radius: var(--bv-radius-full);\n font-size: var(--bv-font-size-xs);\n font-weight: var(--bv-font-weight-medium);\n line-height: 18px;\n white-space: nowrap;\n}\n\n.pre-badge--inactive {\n background: var(--bv-color-neutral-700);\n color: var(--bv-color-neutral-0);\n}\n\n.pre-badge--optional {\n background: var(--bv-color-neutral-100);\n color: var(--bv-color-neutral-700);\n}\n\n.pre-module-toggle {\n flex-shrink: 0;\n width: 24px;\n height: 24px;\n background: none;\n border: none;\n padding: 0;\n cursor: pointer;\n color: var(--bv-color-neutral-700);\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.pre-module-toggle:hover {\n color: var(--bv-color-primary);\n}\n\n.pre-module-toggle svg {\n width: 100%;\n height: 100%;\n}\n\n.pre-module-wrap--expanded .pre-module-row {\n padding-bottom: 0;\n}\n\n.pre-module-desc {\n padding: 0 0 16px;\n margin: 0;\n font-size: var(--bv-font-size-sm);\n color: var(--bv-color-neutral-700);\n line-height: 20px;\n}\n\n/* Empty state */\n.pre-section-empty {\n padding: 20px;\n margin: 0;\n font-size: var(--bv-font-size-md);\n color: var(--bv-color-neutral-500);\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-course-outline/bv-course-outline.ts
5
23
  var BvCourseOutline = class extends HTMLElement {
6
24
  static observedAttributes = ["sections", "mode"];
@@ -26,12 +44,7 @@ var BvCourseOutline = class extends HTMLElement {
26
44
  }
27
45
  constructor() {
28
46
  super();
29
- this.attachShadow({ mode: "open" });
30
- if ("replaceSync" in CSSStyleSheet.prototype) {
31
- const sheet = new CSSStyleSheet();
32
- sheet.replaceSync(bv_course_outline_default);
33
- this.shadowRoot.adoptedStyleSheets = [sheet];
34
- }
47
+ adoptStyles(this.attachShadow({ mode: "open" }), bv_course_outline_default);
35
48
  }
36
49
  connectedCallback() {
37
50
  this._render();
@@ -54,11 +67,6 @@ var BvCourseOutline = class extends HTMLElement {
54
67
  if (this._rendered) return;
55
68
  this._rendered = true;
56
69
  const shadow = this.shadowRoot;
57
- if (!shadow.adoptedStyleSheets.length) {
58
- const s = document.createElement("style");
59
- s.textContent = bv_course_outline_default;
60
- shadow.appendChild(s);
61
- }
62
70
  const attr = this.getAttribute("sections");
63
71
  if (attr !== null) {
64
72
  try {
@@ -1,11 +1,12 @@
1
1
  import '../bv-date-range-picker/bv-date-range-picker.ts';
2
2
  export declare class BvDateRangeInput extends HTMLElement {
3
- static readonly observedAttributes: readonly ["label", "start", "end", "placeholder", "required"];
3
+ static readonly observedAttributes: readonly ["label", "start", "end", "placeholder", "required", "min", "max", "max-range-years", "validate-order", "validate-format", "show-range-limit-banner", "error-min", "error-max", "error-order", "error-format", "range-limit-message", "range-limit-heading"];
4
4
  private _rendered;
5
5
  private _labelEl;
6
6
  private _displayEl;
7
+ private _triggerEl;
7
8
  private _pickerEl;
8
- private _offClick;
9
+ private _dropdown;
9
10
  constructor();
10
11
  get start(): string;
11
12
  set start(v: string);
@@ -13,11 +14,8 @@ export declare class BvDateRangeInput extends HTMLElement {
13
14
  set end(v: string);
14
15
  connectedCallback(): void;
15
16
  disconnectedCallback(): void;
16
- attributeChangedCallback(name: string, _old: string | null, _val: string | null): void;
17
+ attributeChangedCallback(name: string, _old: string | null, val: string | null): void;
17
18
  private _render;
18
- private _toggle;
19
- private _open;
20
- private _close;
21
19
  private _syncLabel;
22
20
  private _syncDisplay;
23
21
  }