@bluevolt-tech/lumen 2.3.1 → 2.6.1
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 +1 -1
- package/dist/components/_shared/attribute-dispatch.d.ts +44 -0
- package/dist/components/_shared/tree-selection.d.ts +67 -0
- package/dist/components/bv-alert-banner/bv-alert-banner.js +1 -1
- package/dist/components/bv-avatar/bv-avatar.js +1 -1
- package/dist/components/bv-badge/bv-badge.js +1 -1
- package/dist/components/bv-button/bv-button.js +8 -6
- package/dist/components/bv-category-pill/bv-category-pill.js +1 -1
- package/dist/components/bv-checkbox/bv-checkbox.d.ts +15 -1
- package/dist/components/bv-checkbox/bv-checkbox.js +50 -5
- package/dist/components/bv-chip/bv-chip.js +1 -1
- package/dist/components/bv-course-detail/bv-course-detail.js +2 -2
- package/dist/components/bv-course-detail-modal/bv-course-detail-modal.js +26 -22
- package/dist/components/bv-course-grid-card/bv-course-grid-card.js +28 -21
- package/dist/components/bv-course-list-card/bv-course-list-card.js +28 -21
- package/dist/components/bv-course-outline/bv-course-outline.js +14 -12
- package/dist/components/bv-date-range-input/bv-date-range-input.js +3 -3
- package/dist/components/bv-date-range-picker/bv-date-range-picker.js +2 -2
- package/dist/components/bv-empty-state/bv-empty-state.js +21 -15
- package/dist/components/bv-filter-dropdown/bv-filter-dropdown.js +1 -1
- package/dist/components/bv-filter-panel/bv-filter-panel.d.ts +14 -0
- package/dist/components/bv-filter-panel/bv-filter-panel.js +87 -6
- package/dist/components/bv-icon/bv-icon.js +9 -7
- package/dist/components/bv-input/bv-input.js +1 -1
- package/dist/components/bv-input-dropdown/bv-input-dropdown.d.ts +123 -1
- package/dist/components/bv-input-dropdown/bv-input-dropdown.js +418 -14
- package/dist/components/bv-modal/bv-modal.js +1 -1
- package/dist/components/bv-page-title/bv-page-title.js +1 -1
- package/dist/components/bv-pagination/bv-pagination.js +1 -1
- package/dist/components/bv-portal-header/bv-portal-header.js +43 -37
- package/dist/components/bv-portal-layout/bv-portal-layout.js +1 -1
- package/dist/components/bv-progress-bar/bv-progress-bar.js +1 -1
- package/dist/components/bv-promo-banner/bv-promo-banner.js +1 -1
- package/dist/components/bv-radio/bv-radio.js +1 -1
- package/dist/components/bv-search-picker/bv-search-picker.d.ts +59 -0
- package/dist/components/bv-search-picker/bv-search-picker.js +175 -23
- package/dist/components/bv-segmented-control/bv-segmented-control.d.ts +13 -0
- package/dist/components/bv-segmented-control/bv-segmented-control.js +1 -1
- package/dist/components/bv-select/bv-select.js +1 -1
- package/dist/components/bv-split-button/bv-split-button.js +8 -6
- package/dist/components/bv-star-rating/bv-star-rating.js +1 -1
- package/dist/components/bv-table/bv-table.d.ts +50 -0
- package/dist/components/bv-table/bv-table.js +275 -34
- package/dist/components/bv-toggle/bv-toggle.d.ts +15 -0
- package/dist/components/bv-toggle/bv-toggle.js +40 -3
- package/dist/components/bv-user-row/bv-user-row.js +22 -15
- package/dist/components/bv-view-switcher/bv-view-switcher.js +1 -1
- package/dist/themes/base.css +0 -5
- package/package.json +11 -8
- package/themes/base.css +0 -5
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// css-inline:/home/runner/work/BV_lumen/BV_lumen/components/bv-filter-panel/bv-filter-panel.css
|
|
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";
|
|
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:host([hidden]) {\n display: none;\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
4
|
// components/_shared/adopt-styles.ts
|
|
5
5
|
var _sheetCache = /* @__PURE__ */ new Map();
|
|
@@ -20,7 +20,7 @@ function adoptStyles(shadow, css) {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
// css-inline:/home/runner/work/BV_lumen/BV_lumen/components/bv-checkbox/bv-checkbox.css
|
|
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:
|
|
23
|
+
var bv_checkbox_default = ":host {\n display: inline-flex;\n font-family: var(--bv-font-family-base);\n}\n/* `:host { display: inline-flex }` is an author rule, and author rules beat the\n user-agent's `[hidden] { display: none }` regardless of specificity. Without\n this, `el.hidden = true` on a bv-checkbox sets the property and changes\n nothing on screen \u2014 which is how bv-input-dropdown shipped a \"Select All\"\n that stayed visible with `select-all` unset (found in BTN-11521). */\n:host([hidden]) {\n display: none;\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/* BTN-10252 \u2014 `flex`, not `inline-flex`.\n *\n * In the default case this changes nothing: `:host` is `inline-flex`, so\n * `.wrap` is a flex item and its display is blockified either way. It matters\n * when a consumer overrides the host's display, which bv-input-dropdown does \u2014\n * `::slotted(*) { display: block }` wins over our `:host`. An inline-level\n * `.wrap` inside a block host lives in a line box, and a line box is sized off\n * the baseline. Checking the box switches `.check` from `display: none` to\n * `display: flex`, which moves `.wrap`'s baseline, which resizes the line:\n * measured at 35.33px unchecked and 32px checked, with four of five rows in the\n * dropdown jumping every time one was ticked. As a block-level flex container\n * there is no line box and no baseline to move. */\n.wrap {\n display: flex;\n align-items: flex-start;\n gap: var(--_gap);\n cursor: pointer;\n user-select: none;\n border-radius: var(--bv-radius-sm);\n}\n\n.wrap:focus-visible {\n outline: 2px solid var(--bv-color-primary);\n outline-offset: 2px;\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\n/* BTN-10252 \u2014 the label span is always in the DOM, even when the consumer\n * passes the text through the default slot instead of the `label` attribute.\n * Empty, it is still a flex item, so `gap` applied twice and the text sat 16px\n * from the box instead of 8px. That is the \"extra padding\" in the ticket, and\n * it is the path CET Light takes: `<bv-checkbox>{{ label }}</bv-checkbox>`. */\n.label:empty {\n display: none;\n}\n\n/* BTN-10252 \u2014 give slotted content the same typography as the attribute path,\n * so the two ways of labelling a checkbox line up identically.\n *\n * On the `slot` element rather than `::slotted(*)` on purpose: `::slotted()`\n * only matches elements, and the case that was broken passes a bare text node.\n * Inheritance runs down the flattened tree, so a text node assigned here picks\n * these up from the slot; `::slotted()` never would. */\nslot {\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}\n";
|
|
24
24
|
|
|
25
25
|
// components/bv-checkbox/bv-checkbox.ts
|
|
26
26
|
var CHECK_ICON = `<svg viewBox="0 0 11.3333 8.41667" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
@@ -30,8 +30,15 @@ var INDETERMINATE_ICON = `<svg viewBox="0 0 12 12" fill="none" xmlns="http://www
|
|
|
30
30
|
<path d="M2 6H10" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
|
31
31
|
</svg>`;
|
|
32
32
|
var BvCheckbox = class extends HTMLElement {
|
|
33
|
-
static observedAttributes = [
|
|
33
|
+
static observedAttributes = [
|
|
34
|
+
"checked",
|
|
35
|
+
"indeterminate",
|
|
36
|
+
"disabled",
|
|
37
|
+
"label",
|
|
38
|
+
"size"
|
|
39
|
+
];
|
|
34
40
|
_rendered = false;
|
|
41
|
+
_wrapEl = null;
|
|
35
42
|
_checkEl = null;
|
|
36
43
|
_labelEl = null;
|
|
37
44
|
constructor() {
|
|
@@ -43,7 +50,11 @@ var BvCheckbox = class extends HTMLElement {
|
|
|
43
50
|
}
|
|
44
51
|
attributeChangedCallback(name, _old, val) {
|
|
45
52
|
if (!this._rendered) return;
|
|
46
|
-
if (name === "checked" || name === "indeterminate")
|
|
53
|
+
if (name === "checked" || name === "indeterminate") {
|
|
54
|
+
this._syncIcon();
|
|
55
|
+
this._syncAria();
|
|
56
|
+
}
|
|
57
|
+
if (name === "disabled") this._syncAria();
|
|
47
58
|
if (name === "label" && this._labelEl) this._labelEl.textContent = val ?? "";
|
|
48
59
|
}
|
|
49
60
|
get checked() {
|
|
@@ -56,12 +67,31 @@ var BvCheckbox = class extends HTMLElement {
|
|
|
56
67
|
get indeterminate() {
|
|
57
68
|
return this.hasAttribute("indeterminate");
|
|
58
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* Focus the checkbox. The focusable element is the internal `.wrap`, not the
|
|
72
|
+
* host, so `hostEl.focus()` would otherwise be a silent no-op. Consumers that
|
|
73
|
+
* rebuild a list of checkboxes (bv-filter-panel, and any screen re-rendering
|
|
74
|
+
* a tree into bv-input-dropdown) need this to restore focus after the rebuild
|
|
75
|
+
* without reaching into this component's shadow root.
|
|
76
|
+
*
|
|
77
|
+
* No-op before the first render, and when disabled — a native disabled
|
|
78
|
+
* checkbox cannot be focused programmatically either, and `tabindex="-1"`
|
|
79
|
+
* alone would not have stopped it (that only removes it from Tab order).
|
|
80
|
+
*/
|
|
81
|
+
focus(options) {
|
|
82
|
+
var _a;
|
|
83
|
+
if (this.hasAttribute("disabled")) return;
|
|
84
|
+
(_a = this._wrapEl) == null ? void 0 : _a.focus(options);
|
|
85
|
+
}
|
|
59
86
|
_render() {
|
|
60
87
|
if (this._rendered) return;
|
|
61
88
|
this._rendered = true;
|
|
62
89
|
const shadow = this.shadowRoot;
|
|
63
|
-
const wrap = document.createElement("
|
|
90
|
+
const wrap = document.createElement("div");
|
|
64
91
|
wrap.className = "wrap";
|
|
92
|
+
wrap.setAttribute("role", "checkbox");
|
|
93
|
+
wrap.setAttribute("part", "checkbox");
|
|
94
|
+
this._wrapEl = wrap;
|
|
65
95
|
const box = document.createElement("span");
|
|
66
96
|
box.className = "box";
|
|
67
97
|
this._checkEl = document.createElement("span");
|
|
@@ -74,7 +104,7 @@ var BvCheckbox = class extends HTMLElement {
|
|
|
74
104
|
const slot = document.createElement("slot");
|
|
75
105
|
wrap.append(box, this._labelEl, slot);
|
|
76
106
|
shadow.appendChild(wrap);
|
|
77
|
-
|
|
107
|
+
const toggle = () => {
|
|
78
108
|
if (this.hasAttribute("disabled")) return;
|
|
79
109
|
this.checked = !this.checked;
|
|
80
110
|
this.removeAttribute("indeterminate");
|
|
@@ -85,12 +115,27 @@ var BvCheckbox = class extends HTMLElement {
|
|
|
85
115
|
detail: { checked: this.checked }
|
|
86
116
|
})
|
|
87
117
|
);
|
|
118
|
+
};
|
|
119
|
+
wrap.addEventListener("click", toggle);
|
|
120
|
+
wrap.addEventListener("keydown", (e) => {
|
|
121
|
+
if (e.key !== "Enter" && e.key !== " ") return;
|
|
122
|
+
if (e.key === " ") e.preventDefault();
|
|
123
|
+
toggle();
|
|
88
124
|
});
|
|
125
|
+
this._syncAria();
|
|
89
126
|
}
|
|
90
127
|
_syncIcon() {
|
|
91
128
|
if (!this._checkEl) return;
|
|
92
129
|
this._checkEl.innerHTML = this.indeterminate ? INDETERMINATE_ICON : CHECK_ICON;
|
|
93
130
|
}
|
|
131
|
+
_syncAria() {
|
|
132
|
+
if (!this._wrapEl) return;
|
|
133
|
+
const disabled = this.hasAttribute("disabled");
|
|
134
|
+
this._wrapEl.tabIndex = disabled ? -1 : 0;
|
|
135
|
+
this._wrapEl.setAttribute("aria-checked", this.indeterminate ? "mixed" : String(this.checked));
|
|
136
|
+
if (disabled) this._wrapEl.setAttribute("aria-disabled", "true");
|
|
137
|
+
else this._wrapEl.removeAttribute("aria-disabled");
|
|
138
|
+
}
|
|
94
139
|
};
|
|
95
140
|
if (!customElements.get("bv-checkbox")) {
|
|
96
141
|
customElements.define("bv-checkbox", BvCheckbox);
|
|
@@ -177,6 +222,7 @@ var BvFilterPanel = class extends HTMLElement {
|
|
|
177
222
|
}
|
|
178
223
|
_buildGroups() {
|
|
179
224
|
if (!this._groupsEl) return;
|
|
225
|
+
const focused = this._focusedOption();
|
|
180
226
|
this._groupsEl.innerHTML = "";
|
|
181
227
|
let rendered = 0;
|
|
182
228
|
for (const group of this._groups) {
|
|
@@ -203,6 +249,8 @@ var BvFilterPanel = class extends HTMLElement {
|
|
|
203
249
|
const bvCheckbox = document.createElement("bv-checkbox");
|
|
204
250
|
bvCheckbox.setAttribute("label", opt.label);
|
|
205
251
|
bvCheckbox.setAttribute("size", "sm");
|
|
252
|
+
bvCheckbox.setAttribute("data-group", group.key);
|
|
253
|
+
bvCheckbox.setAttribute("data-value", opt.value);
|
|
206
254
|
if (opt.checked) bvCheckbox.setAttribute("checked", "");
|
|
207
255
|
bvCheckbox.addEventListener("bv-change", (e) => {
|
|
208
256
|
opt.checked = e.detail.checked;
|
|
@@ -237,6 +285,39 @@ var BvFilterPanel = class extends HTMLElement {
|
|
|
237
285
|
}
|
|
238
286
|
if (rendered === 0) this.setAttribute("empty", "");
|
|
239
287
|
else this.removeAttribute("empty");
|
|
288
|
+
if (focused) this._restoreFocus(focused.group, focused.value);
|
|
289
|
+
}
|
|
290
|
+
/** `data-group` / `data-value` of the checkbox currently holding focus, if any. */
|
|
291
|
+
_focusedOption() {
|
|
292
|
+
var _a;
|
|
293
|
+
const active = (_a = this.shadowRoot) == null ? void 0 : _a.activeElement;
|
|
294
|
+
if (!active || active.tagName !== "BV-CHECKBOX") return null;
|
|
295
|
+
const group = active.getAttribute("data-group");
|
|
296
|
+
const value = active.getAttribute("data-value");
|
|
297
|
+
if (group === null || value === null) return null;
|
|
298
|
+
return { group, value };
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Put focus back on the rebuilt checkbox for the same option. Matched by
|
|
302
|
+
* iterating rather than with an attribute selector: group keys and option
|
|
303
|
+
* values come from consumer JSON and can contain quotes or brackets that
|
|
304
|
+
* would break — or inject into — a selector string.
|
|
305
|
+
*
|
|
306
|
+
* If the option is gone from the new groups (filtered out by a search, say),
|
|
307
|
+
* focus is deliberately left wherever the browser put it rather than moved to
|
|
308
|
+
* a neighbour. Silently focusing a different filter than the one the user was
|
|
309
|
+
* on is worse than dropping out of the list.
|
|
310
|
+
*/
|
|
311
|
+
_restoreFocus(group, value) {
|
|
312
|
+
var _a;
|
|
313
|
+
const boxes = (_a = this.shadowRoot) == null ? void 0 : _a.querySelectorAll("bv-checkbox");
|
|
314
|
+
if (!boxes) return;
|
|
315
|
+
for (const box of Array.from(boxes)) {
|
|
316
|
+
if (box.getAttribute("data-group") === group && box.getAttribute("data-value") === value) {
|
|
317
|
+
box.focus();
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
240
321
|
}
|
|
241
322
|
};
|
|
242
323
|
if (!customElements.get("bv-filter-panel")) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// css-inline:/home/runner/work/BV_lumen/BV_lumen/components/bv-icon/bv-icon.css
|
|
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";
|
|
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:host([hidden]) {\n display: none;\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
4
|
// components/_shared/adopt-styles.ts
|
|
5
5
|
var _sheetCache = /* @__PURE__ */ new Map();
|
|
@@ -20,7 +20,7 @@ function adoptStyles(shadow, css) {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
// components/bv-icon/icons.ts
|
|
23
|
-
var icons = {
|
|
23
|
+
var icons = Object.assign(/* @__PURE__ */ Object.create(null), {
|
|
24
24
|
// Navigation
|
|
25
25
|
"chevron-up": `<path d="M18 15l-6-6-6 6"/>`,
|
|
26
26
|
"chevron-down": `<path d="M6 9l6 6 6-6"/>`,
|
|
@@ -71,16 +71,16 @@ var icons = {
|
|
|
71
71
|
bell: `<path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/>`,
|
|
72
72
|
mail: `<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><polyline points="22,6 12,13 2,6"/>`,
|
|
73
73
|
link: `<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>`
|
|
74
|
-
};
|
|
74
|
+
});
|
|
75
75
|
function getIconSvg(name, size = 16) {
|
|
76
|
-
const raw =
|
|
76
|
+
const raw = RAW_ICON_MAP.get(name);
|
|
77
77
|
if (raw)
|
|
78
78
|
return raw.replace(/width="[^"]*"/, `width="${size}"`).replace(/height="[^"]*"/, `height="${size}"`);
|
|
79
|
-
const paths =
|
|
79
|
+
const paths = ICON_MAP.get(name);
|
|
80
80
|
if (!paths) return "";
|
|
81
81
|
return `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${paths}</svg>`;
|
|
82
82
|
}
|
|
83
|
-
var rawIcons = {
|
|
83
|
+
var rawIcons = Object.assign(/* @__PURE__ */ Object.create(null), {
|
|
84
84
|
// Module type (small, ~18px)
|
|
85
85
|
"module-scorm": `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 15.03 16.28" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M13.9014 4.60034L7.51368 8.14201M7.51368 8.14201L1.126 4.60034M7.51368 8.14201L7.5137 15.267M14.2771 11.1859V5.09812C14.2771 4.84113 14.2771 4.71264 14.2392 4.59804C14.2056 4.49666 14.1508 4.4036 14.0783 4.32508C13.9963 4.23633 13.8838 4.17393 13.6587 4.04913L8.09763 0.965793C7.88451 0.847624 7.77794 0.78854 7.66509 0.765376C7.56521 0.744875 7.46219 0.744875 7.36231 0.765376C7.24946 0.78854 7.1429 0.847624 6.92977 0.965793L1.36873 4.04913C1.14364 4.17393 1.0311 4.23633 0.949147 4.32508C0.876647 4.4036 0.82178 4.49666 0.788217 4.59804C0.750278 4.71264 0.750278 4.84113 0.750278 5.09812V11.1859C0.750278 11.4429 0.750278 11.5714 0.788217 11.686C0.82178 11.7874 0.876647 11.8805 0.949147 11.959C1.0311 12.0477 1.14364 12.1101 1.36873 12.2349L6.92977 15.3183C7.1429 15.4364 7.24946 15.4955 7.36231 15.5187C7.46219 15.5392 7.56521 15.5392 7.66509 15.5187C7.77794 15.4955 7.88451 15.4364 8.09763 15.3183L13.6587 12.2349C13.8838 12.1101 13.9963 12.0477 14.0783 11.959C14.1508 11.8805 14.2056 11.7874 14.2392 11.686C14.2771 11.5714 14.2771 11.4429 14.2771 11.1859Z"/></svg>`,
|
|
86
86
|
"module-assessment": `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 13.72 16.13" fill="none" stroke="currentColor" stroke-width="1.125" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12.507 6.1875V4.1625C12.507 2.90238 12.507 2.27232 12.2629 1.79102C12.0482 1.36766 11.7056 1.02345 11.2841 0.807736C10.8051 0.5625 10.1779 0.5625 8.92364 0.5625H4.14585C2.89156 0.5625 2.26441 0.5625 1.78534 0.807736C1.36393 1.02345 1.02132 1.36766 0.806601 1.79102C0.5625 2.27232 0.5625 2.90238 0.5625 4.1625V11.9625C0.5625 13.2226 0.5625 13.8527 0.806601 14.334C1.02132 14.7573 1.36393 15.1015 1.78534 15.3173C2.26441 15.5625 2.89156 15.5625 4.14585 15.5625H8.0278M8.0278 7.3125H3.54862M5.04168 10.3125H3.54862M9.52086 4.3125H3.54862M9.89413 10.3142C10.0257 9.93852 10.2853 9.62175 10.627 9.41998C10.9688 9.21821 11.3705 9.14445 11.7612 9.21178C12.1519 9.2791 12.5062 9.48315 12.7615 9.7878C13.0168 10.0925 13.1565 10.478 13.1559 10.8763C13.1559 12.0004 11.4775 12.5625 11.4775 12.5625M11.4991 14.8125H11.5066"/></svg>`,
|
|
@@ -90,7 +90,9 @@ var rawIcons = {
|
|
|
90
90
|
"module-adobe-connect": `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 16.06 14.63" fill="none" stroke="currentColor" stroke-width="1.125" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M11.7605 0.56252L8.0278 3.56252L4.29515 0.56252M4.14585 14.0625H11.9098C13.164 14.0625 13.7912 14.0625 14.2703 13.8173C14.6917 13.6016 15.0343 13.2574 15.249 12.834C15.4931 12.3527 15.4931 11.7226 15.4931 10.4625V7.16252C15.4931 5.9024 15.4931 5.27234 15.249 4.79104C15.0343 4.36768 14.6917 4.02347 14.2703 3.80776C13.7912 3.56252 13.164 3.56252 11.9098 3.56252H4.14585C2.89156 3.56252 2.26441 3.56252 1.78534 3.80776C1.36393 4.02347 1.02132 4.36768 0.806601 4.79104C0.5625 5.27234 0.5625 5.9024 0.5625 7.16252V10.4625C0.5625 11.7226 0.5625 12.3527 0.806601 12.834C1.02132 13.2574 1.36393 13.6016 1.78534 13.8173C2.26441 14.0625 2.89156 14.0625 4.14585 14.0625Z"/></svg>`,
|
|
91
91
|
"module-video": `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 16.06 11.63" fill="none" stroke="currentColor" stroke-width="1.125" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15.4931 3.51103C15.4931 3.05667 15.4931 2.82949 15.4037 2.72429C15.3261 2.63301 15.2097 2.58457 15.0906 2.59399C14.9533 2.60484 14.7934 2.76548 14.4736 3.08676L11.7605 5.8125L14.4736 8.53824C14.7934 8.85952 14.9533 9.02016 15.0906 9.03101C15.2097 9.04043 15.3261 8.99199 15.4037 8.90071C15.4931 8.79552 15.4931 8.56833 15.4931 8.11397V3.51103ZM0.5625 4.1625C0.5625 2.90238 0.5625 2.27232 0.806601 1.79102C1.02132 1.36766 1.36393 1.02345 1.78534 0.807736C2.26441 0.5625 2.89156 0.5625 4.14585 0.5625H8.17711C9.4314 0.5625 10.0585 0.5625 10.5376 0.807736C10.959 1.02345 11.3016 1.36766 11.5164 1.79102C11.7605 2.27232 11.7605 2.90238 11.7605 4.1625V7.4625C11.7605 8.72262 11.7605 9.35268 11.5164 9.83398C11.3016 10.2573 10.959 10.6015 10.5376 10.8173C10.0585 11.0625 9.4314 11.0625 8.17711 11.0625H4.14584C2.89156 11.0625 2.26441 11.0625 1.78534 10.8173C1.36393 10.6015 1.02132 10.2573 0.806601 9.83398C0.5625 9.35268 0.5625 8.72262 0.5625 7.4625V4.1625Z"/></svg>`,
|
|
92
92
|
"module-upload": `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 14.75 16.13" fill="none" stroke="currentColor" stroke-width="1.125" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M13.39 4.3125V4.1625C13.39 2.90238 13.39 2.27232 13.1278 1.79102C12.8972 1.36766 12.5293 1.02345 12.0767 0.807736C11.5622 0.5625 10.8887 0.5625 9.54172 0.5625H4.41074C3.06373 0.5625 2.39022 0.5625 1.87573 0.807736C1.42318 1.02345 1.05524 1.36766 0.824646 1.79102C0.5625 2.27232 0.5625 2.90238 0.5625 4.1625V11.9625C0.5625 13.2226 0.5625 13.8527 0.824646 14.334C1.05524 14.7573 1.42318 15.1015 1.87573 15.3173C2.39022 15.5625 3.06373 15.5625 4.41074 15.5625H7.37709M7.37709 7.3125H3.76936M6.57537 10.3125H3.76936M10.1831 4.3125H3.76936M11.7865 12.5625V8.4375C11.7865 7.81618 12.3249 7.3125 12.9891 7.3125C13.6533 7.3125 14.1917 7.81618 14.1917 8.4375V12.5625C14.1917 13.8051 13.1149 14.8125 11.7865 14.8125C10.4582 14.8125 9.38138 13.8051 9.38138 12.5625V9.5625"/></svg>`
|
|
93
|
-
};
|
|
93
|
+
});
|
|
94
|
+
var RAW_ICON_MAP = new Map(Object.entries(rawIcons));
|
|
95
|
+
var ICON_MAP = new Map(Object.entries(icons));
|
|
94
96
|
|
|
95
97
|
// components/bv-icon/bv-icon.ts
|
|
96
98
|
var BvIcon = class extends HTMLElement {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// css-inline:/home/runner/work/BV_lumen/BV_lumen/components/bv-input/bv-input.css
|
|
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";
|
|
2
|
+
var bv_input_default = ":host {\n display: block;\n font-family: var(--bv-font-family-base);\n}\n\n:host([hidden]) {\n display: none;\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/* Author `display: block` above beats the user-agent `[hidden] { display:\n none }`, so `_syncLabel()` setting `.hidden` did nothing on screen. With no\n label text the element collapses to 0px on its own, which is why this went\n unnoticed - but `required` appends an asterisk after the text is cleared, so\n a required field with no label rendered a stray \"*\" above the control\n (BTN-11521). */\n.field-label[hidden] {\n display: none;\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\n/* These elements have an author `display`, which beats the user-agent\n `[hidden] { display: none }` regardless of specificity. The component\n toggles their `hidden`, so without this the property changes nothing on\n screen (BTN-11521). */\n.field-error[hidden] {\n display: none;\n}\n";
|
|
3
3
|
|
|
4
4
|
// components/_shared/adopt-styles.ts
|
|
5
5
|
var _sheetCache = /* @__PURE__ */ new Map();
|
|
@@ -11,8 +11,24 @@ export interface InputDropdownSelectAllDetail {
|
|
|
11
11
|
export interface InputDropdownToggleDetail {
|
|
12
12
|
checked: boolean;
|
|
13
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* BTN-11485 — emitted once per click while `tree` is set, in place of the
|
|
16
|
+
* slotted row's own `bv-change` (which the component stops at its boundary so
|
|
17
|
+
* a consumer cannot end up handling both).
|
|
18
|
+
*
|
|
19
|
+
* `affected` is every value the click changes — the clicked node first, then
|
|
20
|
+
* its descendants in row order — and `checked` is the state to apply to all
|
|
21
|
+
* of them. One event, not one per node: the CET Report resets its Courses
|
|
22
|
+
* cascade on every Categories change, and twenty-three events would reset it
|
|
23
|
+
* twenty-three times.
|
|
24
|
+
*/
|
|
25
|
+
export interface InputDropdownTreeSelectDetail {
|
|
26
|
+
value: string;
|
|
27
|
+
checked: boolean;
|
|
28
|
+
affected: string[];
|
|
29
|
+
}
|
|
14
30
|
export declare class BvInputDropdown extends HTMLElement {
|
|
15
|
-
static readonly observedAttributes: readonly ["label", "value", "placeholder", "required", "disabled", "error", "search", "select-all", "select-all-state", "toggle-label", "toggle-checked", "open"];
|
|
31
|
+
static readonly observedAttributes: readonly ["label", "value", "placeholder", "required", "disabled", "error", "search", "select-all", "select-all-state", "tree", "toggle-label", "toggle-checked", "label-no-results", "label-no-results-hint", "label-empty", "label-empty-hint", "open"];
|
|
16
32
|
private _rendered;
|
|
17
33
|
private _labelEl;
|
|
18
34
|
private _triggerLabelEl;
|
|
@@ -22,7 +38,16 @@ export declare class BvInputDropdown extends HTMLElement {
|
|
|
22
38
|
private _selectAllEl;
|
|
23
39
|
private _toggleEl;
|
|
24
40
|
private _errorEl;
|
|
41
|
+
private _slotEl;
|
|
42
|
+
private _optionsEl;
|
|
43
|
+
private _emptyEl;
|
|
44
|
+
private _emptyTitleEl;
|
|
45
|
+
private _emptyHintEl;
|
|
25
46
|
private _dropdown;
|
|
47
|
+
private _rowObserver;
|
|
48
|
+
/** Last query seen from the internal search box. Drives the copy choice. */
|
|
49
|
+
private _query;
|
|
50
|
+
private _emptyState;
|
|
26
51
|
constructor();
|
|
27
52
|
get value(): string;
|
|
28
53
|
set value(v: string);
|
|
@@ -32,12 +57,109 @@ export declare class BvInputDropdown extends HTMLElement {
|
|
|
32
57
|
set required(v: boolean);
|
|
33
58
|
connectedCallback(): void;
|
|
34
59
|
disconnectedCallback(): void;
|
|
60
|
+
/**
|
|
61
|
+
* Everything that has to be torn down on detach and stood back up on
|
|
62
|
+
* attach, as opposed to the DOM, which is built once.
|
|
63
|
+
*
|
|
64
|
+
* `_render` returns early on its `_rendered` guard, so anything bound inside
|
|
65
|
+
* it is bound exactly once in the element's lifetime — which is correct for
|
|
66
|
+
* the DOM and wrong for a listener that `disconnectedCallback` just removed.
|
|
67
|
+
* A detached and re-attached dropdown came back with no row observer and a
|
|
68
|
+
* dropdown controller whose `cleanup()` had already run: the dashes stopped
|
|
69
|
+
* repainting and Escape and outside-click stopped closing the panel.
|
|
70
|
+
*
|
|
71
|
+
* The controller half predates BTN-11485 — the null check did not catch it
|
|
72
|
+
* because the object was still there, emptied out. Raised by Copilot on
|
|
73
|
+
* PR #49 against the observer; the controller came out with it.
|
|
74
|
+
*
|
|
75
|
+
* Idempotent, because `connectedCallback` can fire more than once and this
|
|
76
|
+
* must not stack listeners.
|
|
77
|
+
*/
|
|
78
|
+
private _bindLiveWiring;
|
|
79
|
+
/**
|
|
80
|
+
* The row observer runs only while tree mode does.
|
|
81
|
+
*
|
|
82
|
+
* It exists to repaint the dash when a consumer rewrites `checked` on rows
|
|
83
|
+
* already in the slot — which no other consumer of this component needs.
|
|
84
|
+
* Binding it unconditionally made every ordinary checkbox toggle, in every
|
|
85
|
+
* dropdown in the app, pay for a feature it does not use. Raised by Copilot
|
|
86
|
+
* on PR #49.
|
|
87
|
+
*
|
|
88
|
+
* `attributeFilter: ['checked']` is load-bearing, not tidiness: the handler
|
|
89
|
+
* writes `indeterminate`, and watching all attributes would feed those
|
|
90
|
+
* writes straight back in — BTN-11850 with different attributes. Filtering
|
|
91
|
+
* to the one attribute we never write makes the feedback edge unreachable
|
|
92
|
+
* rather than merely unlikely, and `npm run test:observers` holds it shut.
|
|
93
|
+
*/
|
|
94
|
+
private _syncRowObserver;
|
|
35
95
|
attributeChangedCallback(name: string, _old: string | null, _val: string | null): void;
|
|
36
96
|
private _render;
|
|
97
|
+
/** Whether hierarchical selection is on. */
|
|
98
|
+
private get _isTree();
|
|
99
|
+
/**
|
|
100
|
+
* Every slotted element carrying `data-value`, in document order.
|
|
101
|
+
*
|
|
102
|
+
* Descendants count, not just direct slot children. Consumers disagree about
|
|
103
|
+
* markup — the CET Report renders one flat `*ngFor` and expresses depth as
|
|
104
|
+
* padding, while this component's own Tree view story nests rows in wrapper
|
|
105
|
+
* divs — and both are legitimate. That disagreement is the whole reason the
|
|
106
|
+
* hierarchy travels in `data-parent` rather than in the DOM shape: read the
|
|
107
|
+
* relationships from the attributes and the markup stops mattering.
|
|
108
|
+
*/
|
|
109
|
+
private _treeElements;
|
|
110
|
+
/**
|
|
111
|
+
* The slotted rows, as the pure helper wants them.
|
|
112
|
+
*
|
|
113
|
+
* Only elements carrying `data-value` take part; anything else a consumer
|
|
114
|
+
* slots in (a separator, a heading) is ignored rather than treated as a
|
|
115
|
+
* root. `data-parent` empty or absent means root.
|
|
116
|
+
*
|
|
117
|
+
* A branch reaches only what the consumer rendered, and that is the intended
|
|
118
|
+
* rule rather than a side effect of reading the DOM. A row the consumer
|
|
119
|
+
* withheld — a group hidden behind Show Inactive, say — is withheld on
|
|
120
|
+
* purpose, and a click has no business reaching past that decision into
|
|
121
|
+
* something the user has asked not to see. Confirmed as correct with the
|
|
122
|
+
* team on 2026-09-18 and pinned by a test, because it currently *follows*
|
|
123
|
+
* from reading rendered rows: give this component the whole tree some other
|
|
124
|
+
* way and the behaviour would reverse with nothing to catch it.
|
|
125
|
+
*/
|
|
126
|
+
private _treeRows;
|
|
127
|
+
/**
|
|
128
|
+
* Paint the dash on every partially selected node.
|
|
129
|
+
*
|
|
130
|
+
* `indeterminate` is the one piece of row state the component owns.
|
|
131
|
+
* `checked` belongs to the consumer — in Angular it is an `[attr.checked]`
|
|
132
|
+
* binding, so anything written here would be overwritten on the next change
|
|
133
|
+
* detection pass. Nothing binds `indeterminate`, so this is ours to keep
|
|
134
|
+
* correct, and it is what makes a check become a dash without the consumer
|
|
135
|
+
* computing anything.
|
|
136
|
+
*/
|
|
137
|
+
private _syncTreeStates;
|
|
138
|
+
/**
|
|
139
|
+
* A slotted row reported a change.
|
|
140
|
+
*
|
|
141
|
+
* The row has already flipped its own `checked` by the time this runs, and
|
|
142
|
+
* that value is deliberately ignored: a partially selected parent must FILL
|
|
143
|
+
* its branch, and its own checkbox may have been sitting either way. The
|
|
144
|
+
* answer comes from the tree instead — see `resolveClick`.
|
|
145
|
+
*/
|
|
146
|
+
private _onRowChange;
|
|
37
147
|
private _syncLabel;
|
|
38
148
|
private _syncTriggerLabel;
|
|
39
149
|
private _syncError;
|
|
40
150
|
private _syncSearch;
|
|
151
|
+
private _resolveEmptyState;
|
|
152
|
+
/**
|
|
153
|
+
* Hot path: CET Report rebuilds the whole option list on every checkbox
|
|
154
|
+
* toggle (the same behavior that forced `composedPath()` outside-click
|
|
155
|
+
* detection in BTN-10274), so this runs on every tick, not only when the
|
|
156
|
+
* list genuinely empties. It stays a length check plus a comparison and
|
|
157
|
+
* returns before touching the DOM when the state has not flipped — the
|
|
158
|
+
* toolbar and header are never re-rendered under the user's focus for a
|
|
159
|
+
* change that did not happen.
|
|
160
|
+
*/
|
|
161
|
+
private _syncEmptyState;
|
|
162
|
+
private _paintEmptyState;
|
|
41
163
|
private _syncToolbar;
|
|
42
164
|
private _updateHeaderVisibility;
|
|
43
165
|
}
|