@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.
- package/README.md +37 -23
- package/dist/components/_shared/adopt-styles.d.ts +8 -0
- package/dist/components/_shared/date-range-validator.d.ts +86 -0
- package/dist/components/_shared/dropdown-controller.d.ts +60 -0
- package/dist/components/_shared/selectable-card.d.ts +10 -0
- package/dist/components/bv-alert-banner/bv-alert-banner.js +19 -17
- package/dist/components/bv-avatar/bv-avatar.js +19 -11
- package/dist/components/bv-badge/bv-badge.js +19 -11
- package/dist/components/bv-button/bv-button.js +18 -16
- package/dist/components/bv-category-pill/bv-category-pill.js +18 -16
- package/dist/components/bv-checkbox/bv-checkbox.js +19 -11
- package/dist/components/bv-chip/bv-chip.js +19 -11
- package/dist/components/bv-course-detail/bv-course-detail.js +20 -34
- package/dist/components/bv-course-detail-modal/bv-course-detail-modal.js +24 -90
- package/dist/components/bv-course-grid-card/bv-course-grid-card.d.ts +2 -6
- package/dist/components/bv-course-grid-card/bv-course-grid-card.js +98 -105
- package/dist/components/bv-course-list-card/bv-course-list-card.d.ts +2 -6
- package/dist/components/bv-course-list-card/bv-course-list-card.js +98 -105
- package/dist/components/bv-course-outline/bv-course-outline.js +19 -11
- package/dist/components/bv-date-range-input/bv-date-range-input.d.ts +10 -6
- package/dist/components/bv-date-range-input/bv-date-range-input.js +602 -125
- package/dist/components/bv-date-range-picker/bv-date-range-picker.d.ts +71 -4
- package/dist/components/bv-date-range-picker/bv-date-range-picker.js +441 -76
- package/dist/components/bv-empty-state/bv-empty-state.js +20 -28
- package/dist/components/bv-filter-dropdown/bv-filter-dropdown.d.ts +1 -4
- package/dist/components/bv-filter-dropdown/bv-filter-dropdown.js +80 -53
- package/dist/components/bv-filter-panel/bv-filter-panel.js +20 -22
- package/dist/components/bv-icon/bv-icon.js +19 -11
- package/dist/components/bv-input/bv-input.js +18 -16
- package/dist/components/bv-input-dropdown/bv-input-dropdown.d.ts +1 -4
- package/dist/components/bv-input-dropdown/bv-input-dropdown.js +79 -78
- package/dist/components/bv-modal/bv-modal.js +19 -11
- package/dist/components/bv-page-title/bv-page-title.js +19 -6
- package/dist/components/bv-pagination/bv-pagination.d.ts +1 -0
- package/dist/components/bv-pagination/bv-pagination.js +23 -186
- package/dist/components/bv-portal-header/bv-portal-header.js +25 -83
- package/dist/components/bv-portal-layout/bv-portal-layout.js +19 -11
- package/dist/components/bv-progress-bar/bv-progress-bar.js +19 -11
- package/dist/components/bv-promo-banner/bv-promo-banner.js +19 -11
- package/dist/components/bv-radio/bv-radio.js +19 -11
- package/dist/components/bv-searchbox/bv-searchbox.js +19 -11
- package/dist/components/bv-segmented-control/bv-segmented-control.js +18 -16
- package/dist/components/bv-select/bv-select.d.ts +1 -4
- package/dist/components/bv-select/bv-select.js +78 -44
- package/dist/components/bv-split-button/bv-split-button.d.ts +1 -4
- package/dist/components/bv-split-button/bv-split-button.js +78 -42
- package/dist/components/bv-star-rating/bv-star-rating.js +19 -11
- package/dist/components/bv-table/bv-table.d.ts +5 -0
- package/dist/components/bv-table/bv-table.js +70 -19
- package/dist/components/bv-toggle/bv-toggle.js +19 -11
- package/dist/components/bv-tooltip/bv-tooltip.js +20 -17
- package/dist/components/bv-user-row/bv-user-row.js +22 -50
- package/dist/components/bv-view-switcher/bv-view-switcher.js +19 -11
- package/dist/themes/base.css +1 -1
- package/package.json +8 -1
- package/themes/base.css +1 -1
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
// css-inline:/home/runner/work/BV_lumen/BV_lumen/components/bv-course-grid-card/bv-course-grid-card.css
|
|
2
2
|
var bv_course_grid_card_default = ":host {\n display: block;\n}\n\n.card {\n display: flex;\n flex-direction: column;\n gap: var(--bv-spacing-sm);\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 width: 100%;\n height: 153px;\n border-radius: var(--bv-radius-lg);\n overflow: hidden;\n background: var(--bv-color-neutral-200);\n flex-shrink: 0;\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 gap: 4px;\n flex: 1;\n min-width: 0;\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 {\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 min-height: 40px; /* Reserve space for 2 lines so cards align at the bottom in the grid, matching the list card's .description-wrap. */\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n margin: 0;\n}\n\n.info-row {\n display: flex;\n gap: var(--bv-spacing-md);\n margin-top: 2px;\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 gap: var(--bv-spacing-sm);\n align-items: stretch;\n}\n\n.primary-action {\n display: block;\n flex: 1;\n min-width: 0;\n}\n\n.secondary-action {\n display: block;\n width: 48px;\n flex-shrink: 0;\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 flex-direction: column;\n gap: var(--bv-spacing-sm);\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 width: 100%;\n height: 153px;\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-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: 70%;\n}\n\n.skeleton-short-line {\n width: 45%;\n}\n\n.skeleton-actions {\n display: flex;\n gap: var(--bv-spacing-sm);\n align-items: stretch;\n margin-top: 2px;\n}\n\n.skeleton-button {\n height: 44px;\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.skeleton-primary {\n flex: 1;\n min-width: 0;\n}\n\n.skeleton-icon-btn {\n width: 48px;\n flex-shrink: 0;\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-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";
|
|
6
24
|
|
|
@@ -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
|
-
|
|
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-grid-card/bv-course-grid-card.ts
|
|
223
284
|
var BvCourseGridCard = class extends HTMLElement {
|
|
224
285
|
static observedAttributes = [
|
|
@@ -286,12 +347,7 @@ var BvCourseGridCard = class extends HTMLElement {
|
|
|
286
347
|
_els = {};
|
|
287
348
|
constructor() {
|
|
288
349
|
super();
|
|
289
|
-
this.attachShadow({ mode: "open" });
|
|
290
|
-
if ("replaceSync" in CSSStyleSheet.prototype) {
|
|
291
|
-
const sheet = new CSSStyleSheet();
|
|
292
|
-
sheet.replaceSync(bv_course_grid_card_default);
|
|
293
|
-
this.shadowRoot.adoptedStyleSheets = [sheet];
|
|
294
|
-
}
|
|
350
|
+
adoptStyles(this.attachShadow({ mode: "open" }), bv_course_grid_card_default);
|
|
295
351
|
}
|
|
296
352
|
connectedCallback() {
|
|
297
353
|
this._render();
|
|
@@ -299,6 +355,7 @@ var BvCourseGridCard = class extends HTMLElement {
|
|
|
299
355
|
attributeChangedCallback(name, _old, val) {
|
|
300
356
|
var _a;
|
|
301
357
|
if (!this._rendered) return;
|
|
358
|
+
const card = this._els.card;
|
|
302
359
|
const map = {
|
|
303
360
|
thumbnail: () => {
|
|
304
361
|
var _a2;
|
|
@@ -311,23 +368,21 @@ var BvCourseGridCard = class extends HTMLElement {
|
|
|
311
368
|
}
|
|
312
369
|
},
|
|
313
370
|
title: () => {
|
|
314
|
-
var _a2;
|
|
315
371
|
if (this._els.title) this._els.title.textContent = val ?? "";
|
|
316
|
-
|
|
372
|
+
card == null ? void 0 : card.setAttribute("aria-label", buildAriaLabel(this));
|
|
317
373
|
},
|
|
318
374
|
publisher: () => {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
(_a2 = this._els.card) == null ? void 0 : _a2.setAttribute("aria-label", this._buildAriaLabel());
|
|
375
|
+
setPrefixedStrong(this._els.publisher, "By ", val);
|
|
376
|
+
card == null ? void 0 : card.setAttribute("aria-label", buildAriaLabel(this));
|
|
322
377
|
},
|
|
323
378
|
description: () => {
|
|
324
379
|
if (this._els.description) this._els.description.textContent = val ?? "";
|
|
325
380
|
},
|
|
326
381
|
duration: () => {
|
|
327
|
-
|
|
382
|
+
setPrefixedStrong(this._els.duration, "", val);
|
|
328
383
|
},
|
|
329
384
|
"last-updated": () => {
|
|
330
|
-
|
|
385
|
+
setPrefixedStrong(this._els.lastUpdated, "Last Updated: ", val);
|
|
331
386
|
},
|
|
332
387
|
"primary-label": () => {
|
|
333
388
|
if (this._els.primaryBtn) this._els.primaryBtn.textContent = val ?? "";
|
|
@@ -358,15 +413,16 @@ var BvCourseGridCard = class extends HTMLElement {
|
|
|
358
413
|
if (this._els.secondaryBtn) this._els.secondaryBtn.hidden = this.hideSecondary;
|
|
359
414
|
},
|
|
360
415
|
selected: () => {
|
|
361
|
-
|
|
362
|
-
(_a2 = this._els.card) == null ? void 0 : _a2.setAttribute("aria-checked", this.selected ? "true" : "false");
|
|
416
|
+
card == null ? void 0 : card.setAttribute("aria-checked", this.selected ? "true" : "false");
|
|
363
417
|
},
|
|
364
418
|
"disable-selection": () => {
|
|
365
|
-
|
|
419
|
+
if (card) syncSelectionA11y(this, card);
|
|
366
420
|
},
|
|
367
421
|
loading: () => {
|
|
368
|
-
|
|
369
|
-
|
|
422
|
+
if (card) {
|
|
423
|
+
syncCardLoading(this, card);
|
|
424
|
+
syncSelectionA11y(this, card);
|
|
425
|
+
}
|
|
370
426
|
}
|
|
371
427
|
};
|
|
372
428
|
(_a = map[name]) == null ? void 0 : _a.call(map);
|
|
@@ -375,17 +431,11 @@ var BvCourseGridCard = class extends HTMLElement {
|
|
|
375
431
|
if (this._rendered) return;
|
|
376
432
|
this._rendered = true;
|
|
377
433
|
const shadow = this.shadowRoot;
|
|
378
|
-
if (!shadow.adoptedStyleSheets.length) {
|
|
379
|
-
const s = document.createElement("style");
|
|
380
|
-
s.textContent = bv_course_grid_card_default;
|
|
381
|
-
shadow.appendChild(s);
|
|
382
|
-
}
|
|
383
434
|
const card = document.createElement("div");
|
|
384
435
|
card.className = "card";
|
|
385
436
|
card.setAttribute("role", "checkbox");
|
|
386
|
-
card.setAttribute("tabindex", "0");
|
|
387
437
|
card.setAttribute("aria-checked", this.selected ? "true" : "false");
|
|
388
|
-
card.setAttribute("aria-label", this
|
|
438
|
+
card.setAttribute("aria-label", buildAriaLabel(this));
|
|
389
439
|
this._els.card = card;
|
|
390
440
|
const thumbWrap = document.createElement("div");
|
|
391
441
|
thumbWrap.className = "thumbnail-wrap";
|
|
@@ -410,7 +460,7 @@ var BvCourseGridCard = class extends HTMLElement {
|
|
|
410
460
|
const publisher = document.createElement("span");
|
|
411
461
|
publisher.className = "publisher";
|
|
412
462
|
this._els.publisher = publisher;
|
|
413
|
-
|
|
463
|
+
setPrefixedStrong(publisher, "By ", this.getAttribute("publisher"));
|
|
414
464
|
const description = document.createElement("p");
|
|
415
465
|
description.className = "description";
|
|
416
466
|
description.textContent = this.getAttribute("description") ?? "";
|
|
@@ -420,11 +470,11 @@ var BvCourseGridCard = class extends HTMLElement {
|
|
|
420
470
|
const duration = document.createElement("span");
|
|
421
471
|
duration.className = "info-item";
|
|
422
472
|
this._els.duration = duration;
|
|
423
|
-
|
|
473
|
+
setPrefixedStrong(duration, "", this.getAttribute("duration"));
|
|
424
474
|
const lastUpdated = document.createElement("span");
|
|
425
475
|
lastUpdated.className = "info-item";
|
|
426
476
|
this._els.lastUpdated = lastUpdated;
|
|
427
|
-
|
|
477
|
+
setPrefixedStrong(lastUpdated, "Last Updated: ", this.getAttribute("last-updated"));
|
|
428
478
|
infoRow.append(duration, lastUpdated);
|
|
429
479
|
content.append(title, publisher, description, infoRow);
|
|
430
480
|
const actions = document.createElement("div");
|
|
@@ -463,66 +513,9 @@ var BvCourseGridCard = class extends HTMLElement {
|
|
|
463
513
|
this._els.skeleton = skeleton;
|
|
464
514
|
card.append(thumbWrap, content, actions, skeleton);
|
|
465
515
|
shadow.appendChild(card);
|
|
466
|
-
this
|
|
467
|
-
this
|
|
468
|
-
|
|
469
|
-
if (this.disableSelection || this.loading) return;
|
|
470
|
-
const actionsEl = this._els.actions;
|
|
471
|
-
if (actionsEl && e.composedPath().includes(actionsEl)) return;
|
|
472
|
-
this._toggleSelected();
|
|
473
|
-
});
|
|
474
|
-
card.addEventListener("keydown", (e) => {
|
|
475
|
-
if (e.key !== "Enter" && e.key !== " ") return;
|
|
476
|
-
if (this.disableSelection || this.loading) return;
|
|
477
|
-
const actionsEl = this._els.actions;
|
|
478
|
-
if (actionsEl && e.composedPath().includes(actionsEl)) return;
|
|
479
|
-
e.preventDefault();
|
|
480
|
-
this._toggleSelected();
|
|
481
|
-
});
|
|
482
|
-
}
|
|
483
|
-
_toggleSelected() {
|
|
484
|
-
this.selected = !this.selected;
|
|
485
|
-
this.dispatchEvent(
|
|
486
|
-
new CustomEvent("bv-select", {
|
|
487
|
-
bubbles: true,
|
|
488
|
-
composed: true,
|
|
489
|
-
detail: { selected: this.selected }
|
|
490
|
-
})
|
|
491
|
-
);
|
|
492
|
-
}
|
|
493
|
-
_buildAriaLabel() {
|
|
494
|
-
const title = this.getAttribute("title") ?? "";
|
|
495
|
-
const publisher = this.getAttribute("publisher") ?? "";
|
|
496
|
-
const parts = [];
|
|
497
|
-
if (title) parts.push(title);
|
|
498
|
-
if (publisher) parts.push(`by ${publisher}`);
|
|
499
|
-
return parts.join(", ");
|
|
500
|
-
}
|
|
501
|
-
_setPrefixedStrong(el, prefix, val) {
|
|
502
|
-
if (!el) return;
|
|
503
|
-
const value = val ?? "";
|
|
504
|
-
if (!value) {
|
|
505
|
-
el.hidden = true;
|
|
506
|
-
el.replaceChildren();
|
|
507
|
-
return;
|
|
508
|
-
}
|
|
509
|
-
el.hidden = false;
|
|
510
|
-
const strong = document.createElement("strong");
|
|
511
|
-
strong.textContent = value;
|
|
512
|
-
if (prefix) el.replaceChildren(document.createTextNode(prefix), strong);
|
|
513
|
-
else el.replaceChildren(strong);
|
|
514
|
-
}
|
|
515
|
-
_syncSelectionA11y() {
|
|
516
|
-
var _a, _b, _c;
|
|
517
|
-
const inert = this.disableSelection || this.loading;
|
|
518
|
-
(_a = this._els.card) == null ? void 0 : _a.setAttribute("tabindex", inert ? "-1" : "0");
|
|
519
|
-
if (inert) (_b = this._els.card) == null ? void 0 : _b.setAttribute("aria-disabled", "true");
|
|
520
|
-
else (_c = this._els.card) == null ? void 0 : _c.removeAttribute("aria-disabled");
|
|
521
|
-
}
|
|
522
|
-
_syncLoading() {
|
|
523
|
-
var _a;
|
|
524
|
-
const loading = this.loading;
|
|
525
|
-
(_a = this._els.card) == null ? void 0 : _a.setAttribute("aria-busy", loading ? "true" : "false");
|
|
516
|
+
syncCardLoading(this, card);
|
|
517
|
+
syncSelectionA11y(this, card);
|
|
518
|
+
bindCardSelection(this, card, actions);
|
|
526
519
|
}
|
|
527
520
|
};
|
|
528
521
|
if (!customElements.get("bv-course-grid-card")) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import '../bv-button/bv-button.ts';
|
|
2
|
-
|
|
2
|
+
import { type SelectableHost } from '../_shared/selectable-card.ts';
|
|
3
|
+
export declare class BvCourseListCard extends HTMLElement implements SelectableHost {
|
|
3
4
|
static readonly observedAttributes: string[];
|
|
4
5
|
get selected(): boolean;
|
|
5
6
|
set selected(v: boolean);
|
|
@@ -19,9 +20,4 @@ export declare class BvCourseListCard extends HTMLElement {
|
|
|
19
20
|
connectedCallback(): void;
|
|
20
21
|
attributeChangedCallback(name: string, _old: string | null, val: string | null): void;
|
|
21
22
|
private _render;
|
|
22
|
-
private _toggleSelected;
|
|
23
|
-
private _buildAriaLabel;
|
|
24
|
-
private _setPrefixedStrong;
|
|
25
|
-
private _syncSelectionA11y;
|
|
26
|
-
private _syncLoading;
|
|
27
23
|
}
|