@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
|
@@ -22,6 +22,21 @@ export declare class BvTable extends HTMLElement {
|
|
|
22
22
|
private _mutationObserver;
|
|
23
23
|
private _bodyObserver;
|
|
24
24
|
private _headerObserver;
|
|
25
|
+
/**
|
|
26
|
+
* BTN-11914 — the `<thead>` the header observer currently watches for
|
|
27
|
+
* `characterData`. Held so the re-attach below can tell "already watching
|
|
28
|
+
* this one" from "the consumer swapped the header out", and so
|
|
29
|
+
* `disconnectedCallback` can drop it: `disconnect()` clears the
|
|
30
|
+
* registration, and a stale ref would make the re-attach skip itself.
|
|
31
|
+
*/
|
|
32
|
+
private _observedThead;
|
|
33
|
+
/**
|
|
34
|
+
* BTN-11914 — dedicated to the `<thead>` `characterData` watch. Separate from
|
|
35
|
+
* `_headerObserver` so a replaced header can be dropped with `disconnect()`
|
|
36
|
+
* without discarding the host observer's queued childList records. See
|
|
37
|
+
* `_observeTheadCharacterData`.
|
|
38
|
+
*/
|
|
39
|
+
private _theadObserver;
|
|
25
40
|
get loading(): boolean;
|
|
26
41
|
set loading(v: boolean);
|
|
27
42
|
get fitViewport(): boolean;
|
|
@@ -31,6 +46,7 @@ export declare class BvTable extends HTMLElement {
|
|
|
31
46
|
attributeChangedCallback(name: string, _old: string | null, val: string | null): void;
|
|
32
47
|
private _renderSkeleton;
|
|
33
48
|
private _removeSkeleton;
|
|
49
|
+
private _syncSkeletonLabel;
|
|
34
50
|
private _setupDrag;
|
|
35
51
|
private _teardownDrag;
|
|
36
52
|
private _setupStickyColumns;
|
|
@@ -46,8 +62,42 @@ export declare class BvTable extends HTMLElement {
|
|
|
46
62
|
private _isOverText;
|
|
47
63
|
private _enhanceHeaders;
|
|
48
64
|
private _enhanceOneHeader;
|
|
65
|
+
private _renderTooltipOnlyTh;
|
|
66
|
+
private _buildThContent;
|
|
49
67
|
private _extractHeaderLabel;
|
|
50
68
|
private _syncSortableTh;
|
|
51
69
|
private _cycleSort;
|
|
52
70
|
private _observeHeaderMutations;
|
|
71
|
+
/**
|
|
72
|
+
* The header observer's record handling, shared by both observers that feed
|
|
73
|
+
* it: the host-wide one above (childList + attributes) and the `<thead>`
|
|
74
|
+
* characterData one below. One body so a branch added to either cannot drift
|
|
75
|
+
* from the other.
|
|
76
|
+
*/
|
|
77
|
+
private _handleHeaderMutations;
|
|
78
|
+
/**
|
|
79
|
+
* BTN-11914 — watches `characterData` on the current `<thead>`, and nothing
|
|
80
|
+
* else. Cheap to call repeatedly: it returns immediately while the same
|
|
81
|
+
* element is already being watched.
|
|
82
|
+
*
|
|
83
|
+
* `characterData` must keep reaching the header (BTN-11247): Angular's Ivy
|
|
84
|
+
* creates the header's text node empty and fills it on the update pass, which
|
|
85
|
+
* arrives as a characterData mutation, not a childList one.
|
|
86
|
+
*
|
|
87
|
+
* **Why its own MutationObserver instead of a second `observe()` on the
|
|
88
|
+
* header one.** A replaced `<thead>` has to stop being watched, or a consumer
|
|
89
|
+
* that keeps and mutates the detached subtree still reaches
|
|
90
|
+
* `_enhanceFilledHeader` — records for stale DOM, which is the narrow scope
|
|
91
|
+
* leaking back open (raised by Copilot on PR #50). There is no
|
|
92
|
+
* `unobserve(node)`, so the only way to drop one registration is
|
|
93
|
+
* `disconnect()`, and that also **discards records already queued and not yet
|
|
94
|
+
* delivered**. On the shared observer that would throw away pending childList
|
|
95
|
+
* and attribute records mid-batch — the first version of this fix accepted the
|
|
96
|
+
* stale registration for exactly that reason. A dedicated observer removes the
|
|
97
|
+
* trade entirely: the records it discards are the old `<thead>`'s, which are
|
|
98
|
+
* the ones being dropped on purpose.
|
|
99
|
+
*/
|
|
100
|
+
private _observeTheadCharacterData;
|
|
101
|
+
private _enhanceFilledHeader;
|
|
102
|
+
private _enhanceAddedHeaders;
|
|
53
103
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// css-inline:/home/runner/work/BV_lumen/BV_lumen/components/bv-table/bv-table.css
|
|
2
|
-
var bv_table_default = "bv-table {\n display: block;\n width: 100%;\n box-sizing: border-box;\n overflow-x: auto;\n border: 1px solid var(--bv-color-neutral-200);\n font-family: var(--bv-font-family-base);\n cursor: grab;\n}\n\n/* \u2500\u2500 fit-viewport (BTN-10755) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 * Consumer wraps the table in a flex container that fills the viewport bottom\n * (e.g. `.wrap { display: flex; flex-direction: column; height: 100vh }` +\n * `bv-table { flex: 1 }`). Then this attribute:\n * 1. Adds vertical scrolling on the host (in addition to the horizontal one\n * that already exists), so the body scrolls without pushing page layout.\n * 2. Pins the header row(s) via `position: sticky; top: 0` inside the\n * scrolling viewport, so column labels stay visible while the user\n * pages through rows.\n * The horizontal scrollbar stays at the bottom of the host \u2014 always visible,\n * per the CET spec.\n */\nbv-table[fit-viewport] {\n overflow: auto;\n height: 100%;\n min-height: 0;\n}\n\nbv-table[fit-viewport] thead th {\n position: sticky;\n top: 0;\n z-index: 2;\n}\n\n/* Header row 2 (subheaders) sits below row 1 in the sticky stack \u2014 offset by\n * the height of row 1 so both rows pin. Split down the middle so the visual\n * height of a 2-row header still equals a single-row header. */\nbv-table[fit-viewport] thead tr:nth-child(2) th {\n top: calc(var(--bv-sticky-head-row1-height, 24px));\n}\n\n/* During drag: override cursor for the entire table and all children */\nbv-table[data-dragging],\nbv-table[data-dragging] * {\n cursor: grabbing !important;\n user-select: none !important;\n}\n\nbv-table tbody td {\n cursor: grab;\n}\n\n/* Only the rendered glyphs are text-selectable \u2014 see _enhanceBodyCells in bv-table.ts */\nbv-table tbody td .bv-cell-text {\n cursor: text;\n}\n\nbv-table table {\n width: 100%;\n border-collapse: collapse;\n min-width: 0;\n}\n\n/* \u2500\u2500 Header \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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\nbv-table thead th {\n /* Own background per <th> (was on <tr>) \u2014 under `fit-viewport` every\n * header cell becomes `position: sticky` and the sticky cell floats at\n * top:0 while its parent <tr> scrolls off-screen. A <tr>-level bg would\n * scroll away with the row and leave the pinned header transparent\n * (BTN-10755 followup). */\n background: var(--bv-color-neutral-100);\n padding: 12px 16px;\n text-align: left;\n font-size: var(--bv-font-size-xs);\n font-weight: var(--bv-font-weight-semibold);\n color: var(--bv-color-neutral-800);\n border-bottom: 1px solid var(--bv-color-neutral-200);\n white-space: nowrap;\n user-select: none;\n vertical-align: middle;\n}\n\nbv-table thead th[data-sortable] {\n cursor: pointer;\n}\n\nbv-table thead th[data-sortable]:hover {\n color: var(--bv-color-neutral-700);\n}\n\nbv-table thead th[data-sort='asc'] .bv-sort-icon,\nbv-table thead th[data-sort='desc'] .bv-sort-icon {\n color: var(--bv-color-primary);\n}\n\n.bv-th-content {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n.bv-sort-icon {\n width: 14px;\n height: 14px;\n flex-shrink: 0;\n}\n\n/* \u2500\u2500 Body \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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\nbv-table tbody td {\n padding: 12px 16px;\n font-size: var(--bv-font-size-sm);\n color: var(--bv-color-neutral-700);\n border-bottom: 1px solid var(--bv-color-neutral-100);\n vertical-align: middle;\n white-space: nowrap;\n}\n\nbv-table tbody tr:last-child td {\n border-bottom: none;\n}\n\nbv-table tbody tr:hover td {\n background: var(--bv-color-neutral-100);\n}\n\n/* \u2500\u2500 Column alignment \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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\nbv-table thead th[data-align='right'],\nbv-table tbody td[data-align='right'] {\n text-align: right;\n}\n\nbv-table thead th[data-align='center'],\nbv-table tbody td[data-align='center'] {\n text-align: center;\n}\n\n/* \u2500\u2500 Cell modifier classes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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/* Muted: em dash or empty placeholder */\nbv-table td.bv-cell-muted {\n color: var(--bv-color-neutral-400);\n}\n\n/* Hidden: redacted identity for external users */\nbv-table td.bv-cell-hidden {\n color: var(--bv-color-neutral-400);\n font-style: italic;\n}\n\n/* Colored text for numeric highlight states */\nbv-table td.bv-cell-success {\n color: var(--bv-color-success);\n font-weight: var(--bv-font-weight-medium);\n}\n\nbv-table td.bv-cell-warning {\n color: var(--bv-color-warning);\n font-weight: var(--bv-font-weight-medium);\n}\n\nbv-table td.bv-cell-danger {\n color: var(--bv-color-danger);\n font-weight: var(--bv-font-weight-medium);\n}\n\nbv-table td.bv-cell-info {\n color: var(--bv-color-primary);\n font-weight: var(--bv-font-weight-medium);\n}\n\n/* \u2500\u2500 Modifiers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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\nbv-table[striped] tbody tr:nth-child(even) td {\n background: var(--bv-color-neutral-100);\n}\n\nbv-table[bordered] thead th,\nbv-table[bordered] tbody td {\n border-right: 1px solid var(--bv-color-neutral-100);\n}\n\nbv-table[bordered] thead th:last-child,\nbv-table[bordered] tbody td:last-child {\n border-right: none;\n}\n\n/* \u2500\u2500 Column divider \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500*/\n\nbv-table thead th[data-divider],\nbv-table tbody td[data-divider] {\n border-left: 1px solid var(--bv-color-neutral-200);\n}\n\n/* \u2500\u2500 Grouped header (BTN-10755) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 * 2-row header pattern: consumer writes a first-row <th colspan=\"N\">\n * spanning the group cells, then a second <tr> in <thead> with N\n * sub-header <th>s below it. Cells outside the group use rowspan=\"2\".\n *\n * Sub-headers are visually lighter than main headers and get their own\n * divider from the group cell above. The group cell centers its label\n * horizontally over the axis of the sub-columns (data-align=\"center\"\n * on the group th, per convention).\n */\nbv-table thead tr + tr th {\n font-size: var(--bv-font-size-xs);\n font-weight: var(--bv-font-weight-medium);\n color: var(--bv-color-neutral-600);\n /* Half of the base 8px 16px so the two-row header packs tighter \u2014 the\n * rowspan=2 cells still control the row-1 height, so this only affects\n * how much air sits around the group label and sub-headers. */\n padding: 4px 16px;\n}\n\nbv-table thead th[data-group] {\n text-align: center;\n /* Same halving as the sub-header row \u2014 matches the visual density of the\n * grouped-header stack (label + 3 subs) with the surrounding row-1 cells. */\n padding: 6px 16px;\n /* The base `thead th { border-bottom }` rule paints the divider between\n * the header and tbody. On a group cell that divider would appear\n * *inside* the header block (between the group label and its sub-headers)\n * \u2014 the sub-header row's own border-bottom already covers the header/body\n * boundary. */\n border-bottom: none;\n}\n\n/* \u2500\u2500 Sticky columns (BTN-10755) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 * Consumers opt in per cell with `data-sticky` on the th/td of the\n * columns they want to freeze during horizontal scroll. The component\n * computes cumulative `left` offsets from the natural widths of the\n * sticky <th>s and writes them as a `--bv-sticky-left` inline style\n * on every sticky cell (see _updateStickyColumnOffsets in bv-table.ts).\n *\n * The last sticky cell in each row is marked with `data-sticky-last`\n * so CSS can hang the scroll shadow gradient on its trailing edge \u2014\n * only visible when the host has scrolled off `scrollLeft: 0` (that\n * toggles `data-scrolled-x` on the host from bv-table.ts).\n */\nbv-table td[data-sticky],\nbv-table th[data-sticky] {\n position: sticky;\n left: var(--bv-sticky-left, 0);\n /* --bv-sticky-bg is the sole knob for state-dependent sticky background\n * (default / header / striped / hover). The gap-fill box-shadow below\n * reads the same variable, so the two always stay in sync. */\n --bv-sticky-bg: var(--bv-color-neutral-0);\n background: var(--bv-sticky-bg);\n z-index: 1;\n}\n\n/* Sub-pixel gap guard (BTN-10755 followup) \u2014 the computed sticky `left`\n * offset comes from `offsetWidth`, which rounds to the nearest integer\n * pixel while the browser renders the column widths as fractional pixels.\n * That mismatch leaves a hairline gap between adjacent sticky cells,\n * through which the scrolling columns behind bleed visible text. Extend\n * each non-last sticky cell 1px to the right with a box-shadow in the\n * cell's own background color to close the gap. The last sticky cell has\n * the scroll-shadow gradient (::after below) doing the same visual job. */\nbv-table td[data-sticky]:not([data-sticky-last]),\nbv-table th[data-sticky]:not([data-sticky-last]) {\n box-shadow: 1px 0 0 0 var(--bv-sticky-bg);\n}\n\n/* Header sticky cells stack above body sticky cells during vertical\n * scroll (relevant only under [fit-viewport]) and above the row\n * hovering neighbors that also carry sticky. */\nbv-table thead th[data-sticky] {\n --bv-sticky-bg: var(--bv-color-neutral-100);\n z-index: 3;\n}\n\n/* Under fit-viewport, header sticky cells sit above the horizontal\n * sticky \"corner\" area \u2014 their z stacking must beat both. */\nbv-table[fit-viewport] thead th[data-sticky] {\n z-index: 4;\n}\n\n/* Striped rows: sticky cells match the row's background so the frozen\n * column doesn't visually break the alternating band. */\nbv-table[striped] tbody tr:nth-child(even) td[data-sticky] {\n --bv-sticky-bg: var(--bv-color-neutral-100);\n}\n\n/* Hover: same override \u2014 sticky cell background must track the row's\n * hover background or the frozen cells look \"unclickable\". */\nbv-table tbody tr:hover td[data-sticky] {\n --bv-sticky-bg: var(--bv-color-neutral-100);\n}\n\n/* Scroll shadow \u2014 spec gradient from the ticket:\n * linear-gradient(to right, rgba(15,23,42,.10), rgba(15,23,42,0))\n * Painted as an absolutely-positioned ::after so it extends outside the\n * sticky cell without affecting its own width. Only paints when the\n * host has scrolled off the initial x-position (data-scrolled-x set\n * by _onScroll in bv-table.ts).\n */\nbv-table[data-scrolled-x] td[data-sticky-last]::after,\nbv-table[data-scrolled-x] th[data-sticky-last]::after {\n content: '';\n position: absolute;\n top: 0;\n right: -12px;\n bottom: 0;\n width: 12px;\n /* Ticket spec was `linear-gradient(to right, rgba(15,23,42,.10), rgba(15,23,42,0))`.\n * `rgba(15, 23, 42, ...)` is `--bv-color-neutral-900` (#0f172a) \u2014 drive it\n * through the token so a future dark theme automatically rethemes the\n * shadow and CLAUDE.md's \"no hardcoded colors\" rule holds. `color-mix`\n * has been baseline-supported since Chrome 111 / Firefox 113 / Safari 16.2. */\n background: linear-gradient(\n to right,\n color-mix(in srgb, var(--bv-color-neutral-900) 10%, transparent),\n transparent\n );\n pointer-events: none;\n}\n\n/* \u2500\u2500 Checkbox column \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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\nbv-table thead th.bv-col-check,\nbv-table tbody td.bv-col-check {\n width: 48px;\n padding: 12px 16px;\n}\n\n/* \u2500\u2500 BTN-10191 \xB7 loading skeleton \u2500\u2500\u2500\u2500\u2500\u2500\u2500\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/* Hide the real table while the skeleton is showing. Consumers keep\n their <thead>/<tbody> markup in place so no re-hydration is needed\n when data lands \u2014 only display switches. */\nbv-table[loading] > table {\n display: none;\n}\n\n.bv-table-skeleton {\n display: flex;\n flex-direction: column;\n gap: var(--bv-spacing-md-minus);\n padding: var(--bv-spacing-md);\n}\n\n.bv-table-skeleton-row {\n display: flex;\n gap: var(--bv-spacing-lg);\n}\n\n.bv-table-skeleton-bar {\n flex: 1;\n height: 14px;\n border-radius: var(--bv-radius-sm);\n background: var(--bv-color-neutral-200);\n animation: bv-table-skeleton-shimmer 1.5s ease-in-out infinite;\n}\n\n/* Slight offset per row so the shimmer isn't in lockstep \u2014 reads more\n like real content loading than a pulsing wall. */\n.bv-table-skeleton-row:nth-child(even) .bv-table-skeleton-bar {\n animation-delay: 0.2s;\n}\n\n@keyframes bv-table-skeleton-shimmer {\n 0%,\n 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0.5;\n }\n}\n";
|
|
2
|
+
var bv_table_default = "bv-table {\n display: block;\n width: 100%;\n box-sizing: border-box;\n overflow-x: auto;\n border: 1px solid var(--bv-color-neutral-200);\n font-family: var(--bv-font-family-base);\n cursor: grab;\n}\n\n/* \u2500\u2500 fit-viewport (BTN-10755) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 * Consumer wraps the table in a flex container that fills the viewport bottom\n * (e.g. `.wrap { display: flex; flex-direction: column; height: 100vh }` +\n * `bv-table { flex: 1 }`). Then this attribute:\n * 1. Adds vertical scrolling on the host (in addition to the horizontal one\n * that already exists), so the body scrolls without pushing page layout.\n * 2. Pins the header row(s) via `position: sticky; top: 0` inside the\n * scrolling viewport, so column labels stay visible while the user\n * pages through rows.\n * The horizontal scrollbar stays at the bottom of the host \u2014 always visible,\n * per the CET spec.\n */\nbv-table[fit-viewport] {\n overflow: auto;\n height: 100%;\n min-height: 0;\n}\n\nbv-table[fit-viewport] thead th {\n position: sticky;\n top: 0;\n z-index: 2;\n}\n\n/* Header row 2 (subheaders) sits below row 1 in the sticky stack \u2014 offset by\n * the height of row 1 so both rows pin. Split down the middle so the visual\n * height of a 2-row header still equals a single-row header. */\nbv-table[fit-viewport] thead tr:nth-child(2) th {\n top: calc(var(--bv-sticky-head-row1-height, 24px));\n}\n\n/* During drag: override cursor for the entire table and all children */\nbv-table[data-dragging],\nbv-table[data-dragging] * {\n cursor: grabbing !important;\n user-select: none !important;\n}\n\nbv-table tbody td {\n cursor: grab;\n}\n\n/* Only the rendered glyphs are text-selectable \u2014 see _enhanceBodyCells in bv-table.ts */\nbv-table tbody td .bv-cell-text {\n cursor: text;\n}\n\nbv-table table {\n width: 100%;\n border-collapse: collapse;\n min-width: 0;\n}\n\n/* \u2500\u2500 Header \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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\nbv-table thead th {\n /* Own background per <th> (was on <tr>) \u2014 under `fit-viewport` every\n * header cell becomes `position: sticky` and the sticky cell floats at\n * top:0 while its parent <tr> scrolls off-screen. A <tr>-level bg would\n * scroll away with the row and leave the pinned header transparent\n * (BTN-10755 followup). */\n background: var(--bv-color-neutral-100);\n padding: 12px 16px;\n text-align: left;\n font-size: var(--bv-font-size-xs);\n font-weight: var(--bv-font-weight-semibold);\n color: var(--bv-color-neutral-800);\n border-bottom: 1px solid var(--bv-color-neutral-200);\n white-space: nowrap;\n user-select: none;\n vertical-align: middle;\n}\n\nbv-table thead th[data-sortable] {\n cursor: pointer;\n}\n\nbv-table thead th[data-sortable]:hover {\n color: var(--bv-color-neutral-700);\n}\n\nbv-table thead th[data-sort='asc'] .bv-sort-icon,\nbv-table thead th[data-sort='desc'] .bv-sort-icon {\n color: var(--bv-color-primary);\n}\n\n.bv-th-content {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n.bv-sort-icon {\n width: 14px;\n height: 14px;\n flex-shrink: 0;\n}\n\n/* \u2500\u2500 Body \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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\nbv-table tbody td {\n padding: 12px 16px;\n font-size: var(--bv-font-size-sm);\n color: var(--bv-color-neutral-700);\n border-bottom: 1px solid var(--bv-color-neutral-100);\n vertical-align: middle;\n white-space: nowrap;\n}\n\nbv-table tbody tr:last-child td {\n border-bottom: none;\n}\n\nbv-table tbody tr:hover td {\n background: var(--bv-color-neutral-100);\n}\n\n/* \u2500\u2500 Column alignment \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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\nbv-table thead th[data-align='right'],\nbv-table tbody td[data-align='right'] {\n text-align: right;\n}\n\nbv-table thead th[data-align='center'],\nbv-table tbody td[data-align='center'] {\n text-align: center;\n}\n\n/* \u2500\u2500 Cell modifier classes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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/* Muted: em dash or empty placeholder */\nbv-table td.bv-cell-muted {\n color: var(--bv-color-neutral-400);\n}\n\n/* Hidden: redacted identity for external users */\nbv-table td.bv-cell-hidden {\n color: var(--bv-color-neutral-400);\n font-style: italic;\n}\n\n/* Colored text for numeric highlight states */\nbv-table td.bv-cell-success {\n color: var(--bv-color-success);\n font-weight: var(--bv-font-weight-medium);\n}\n\nbv-table td.bv-cell-warning {\n color: var(--bv-color-warning);\n font-weight: var(--bv-font-weight-medium);\n}\n\nbv-table td.bv-cell-danger {\n color: var(--bv-color-danger);\n font-weight: var(--bv-font-weight-medium);\n}\n\nbv-table td.bv-cell-info {\n color: var(--bv-color-primary);\n font-weight: var(--bv-font-weight-medium);\n}\n\n/* \u2500\u2500 Modifiers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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\nbv-table[striped] tbody tr:nth-child(even) td {\n background: var(--bv-color-neutral-100);\n}\n\nbv-table[bordered] thead th,\nbv-table[bordered] tbody td {\n border-right: 1px solid var(--bv-color-neutral-100);\n}\n\nbv-table[bordered] thead th:last-child,\nbv-table[bordered] tbody td:last-child {\n border-right: none;\n}\n\n/* \u2500\u2500 Column divider \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500*/\n\nbv-table thead th[data-divider],\nbv-table tbody td[data-divider] {\n border-left: 1px solid var(--bv-color-neutral-200);\n}\n\n/* \u2500\u2500 Grouped header (BTN-10755) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 * 2-row header pattern: consumer writes a first-row <th colspan=\"N\">\n * spanning the group cells, then a second <tr> in <thead> with N\n * sub-header <th>s below it. Cells outside the group use rowspan=\"2\".\n *\n * Sub-headers are visually lighter than main headers and get their own\n * divider from the group cell above. The group cell centers its label\n * horizontally over the axis of the sub-columns (data-align=\"center\"\n * on the group th, per convention).\n */\nbv-table thead tr + tr th {\n font-size: var(--bv-font-size-xs);\n font-weight: var(--bv-font-weight-medium);\n color: var(--bv-color-neutral-600);\n /* Half of the base 8px 16px so the two-row header packs tighter \u2014 the\n * rowspan=2 cells still control the row-1 height, so this only affects\n * how much air sits around the group label and sub-headers. */\n padding: 4px 16px;\n}\n\nbv-table thead th[data-group] {\n text-align: center;\n /* Same halving as the sub-header row \u2014 matches the visual density of the\n * grouped-header stack (label + 3 subs) with the surrounding row-1 cells. */\n padding: 6px 16px;\n /* The base `thead th { border-bottom }` rule paints the divider between\n * the header and tbody. On a group cell that divider would appear\n * *inside* the header block (between the group label and its sub-headers)\n * \u2014 the sub-header row's own border-bottom already covers the header/body\n * boundary. */\n border-bottom: none;\n}\n\n/* \u2500\u2500 Sticky columns (BTN-10755) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 * Consumers opt in per cell with `data-sticky` on the th/td of the\n * columns they want to freeze during horizontal scroll. The component\n * computes cumulative `left` offsets from the natural widths of the\n * sticky <th>s and writes them as a `--bv-sticky-left` inline style\n * on every sticky cell (see _updateStickyColumnOffsets in bv-table.ts).\n *\n * The last sticky cell in each row is marked with `data-sticky-last`\n * so CSS can hang the scroll shadow gradient on its trailing edge \u2014\n * only visible when the host has scrolled off `scrollLeft: 0` (that\n * toggles `data-scrolled-x` on the host from bv-table.ts).\n */\nbv-table td[data-sticky],\nbv-table th[data-sticky] {\n position: sticky;\n left: var(--bv-sticky-left, 0);\n /* --bv-sticky-bg is the sole knob for state-dependent sticky background\n * (default / header / striped / hover). The gap-fill box-shadow below\n * reads the same variable, so the two always stay in sync. */\n --bv-sticky-bg: var(--bv-color-neutral-0);\n background: var(--bv-sticky-bg);\n z-index: 1;\n}\n\n/* Sub-pixel gap guard (BTN-10755 followup) \u2014 the computed sticky `left`\n * offset comes from `offsetWidth`, which rounds to the nearest integer\n * pixel while the browser renders the column widths as fractional pixels.\n * That mismatch leaves a hairline gap between adjacent sticky cells,\n * through which the scrolling columns behind bleed visible text. Extend\n * each non-last sticky cell 1px to the right with a box-shadow in the\n * cell's own background color to close the gap. The last sticky cell has\n * the scroll-shadow gradient (::after below) doing the same visual job. */\nbv-table td[data-sticky]:not([data-sticky-last]),\nbv-table th[data-sticky]:not([data-sticky-last]) {\n box-shadow: 1px 0 0 0 var(--bv-sticky-bg);\n}\n\n/* Header sticky cells stack above body sticky cells during vertical\n * scroll (relevant only under [fit-viewport]) and above the row\n * hovering neighbors that also carry sticky. */\nbv-table thead th[data-sticky] {\n --bv-sticky-bg: var(--bv-color-neutral-100);\n z-index: 3;\n}\n\n/* Under fit-viewport, header sticky cells sit above the horizontal\n * sticky \"corner\" area \u2014 their z stacking must beat both. */\nbv-table[fit-viewport] thead th[data-sticky] {\n z-index: 4;\n}\n\n/* Striped rows: sticky cells match the row's background so the frozen\n * column doesn't visually break the alternating band. */\nbv-table[striped] tbody tr:nth-child(even) td[data-sticky] {\n --bv-sticky-bg: var(--bv-color-neutral-100);\n}\n\n/* Hover: same override \u2014 sticky cell background must track the row's\n * hover background or the frozen cells look \"unclickable\". */\nbv-table tbody tr:hover td[data-sticky] {\n --bv-sticky-bg: var(--bv-color-neutral-100);\n}\n\n/* Scroll shadow \u2014 spec gradient from the ticket:\n * linear-gradient(to right, rgba(15,23,42,.10), rgba(15,23,42,0))\n * Painted as an absolutely-positioned ::after so it extends outside the\n * sticky cell without affecting its own width. Only paints when the\n * host has scrolled off the initial x-position (data-scrolled-x set\n * by _onScroll in bv-table.ts).\n */\nbv-table[data-scrolled-x] td[data-sticky-last]::after,\nbv-table[data-scrolled-x] th[data-sticky-last]::after {\n content: '';\n position: absolute;\n top: 0;\n right: -12px;\n bottom: 0;\n width: 12px;\n /* Ticket spec was `linear-gradient(to right, rgba(15,23,42,.10), rgba(15,23,42,0))`.\n * `rgba(15, 23, 42, ...)` is `--bv-color-neutral-900` (#0f172a) \u2014 drive it\n * through the token so a future dark theme automatically rethemes the\n * shadow and CLAUDE.md's \"no hardcoded colors\" rule holds. `color-mix`\n * has been baseline-supported since Chrome 111 / Firefox 113 / Safari 16.2. */\n background: linear-gradient(\n to right,\n color-mix(in srgb, var(--bv-color-neutral-900) 10%, transparent),\n transparent\n );\n pointer-events: none;\n}\n\n/* \u2500\u2500 Checkbox column \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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\nbv-table thead th.bv-col-check,\nbv-table tbody td.bv-col-check {\n width: 48px;\n padding: 12px 16px;\n}\n\n/* \u2500\u2500 BTN-10191 \xB7 loading skeleton \u2500\u2500\u2500\u2500\u2500\u2500\u2500\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/* Hide the real table while the skeleton is showing. Consumers keep\n their <thead>/<tbody> markup in place so no re-hydration is needed\n when data lands \u2014 only display switches. */\nbv-table[loading] > table {\n display: none;\n}\n\n.bv-table-skeleton {\n display: flex;\n flex-direction: column;\n gap: var(--bv-spacing-md-minus);\n padding: var(--bv-spacing-md);\n}\n\n.bv-table-skeleton-row {\n display: flex;\n gap: var(--bv-spacing-lg);\n}\n\n.bv-table-skeleton-bar {\n flex: 1;\n height: 14px;\n border-radius: var(--bv-radius-sm);\n background: var(--bv-color-neutral-200);\n animation: bv-table-skeleton-shimmer 1.5s ease-in-out infinite;\n}\n\n/* Slight offset per row so the shimmer isn't in lockstep \u2014 reads more\n like real content loading than a pulsing wall. */\n.bv-table-skeleton-row:nth-child(even) .bv-table-skeleton-bar {\n animation-delay: 0.2s;\n}\n\n@keyframes bv-table-skeleton-shimmer {\n 0%,\n 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0.5;\n }\n}\n\n/* Light DOM by design (the CSS is injected into document.head so it can reach\n nested th/td), so this is the element selector, not `:host`. The rule above\n sets `display: block` from the author origin, which beats the user agent's\n `[hidden] { display: none }` regardless of specificity. */\nbv-table[hidden] {\n display: none;\n}\n";
|
|
3
3
|
|
|
4
4
|
// css-inline:/home/runner/work/BV_lumen/BV_lumen/components/bv-tooltip/bv-tooltip.css
|
|
5
5
|
var bv_tooltip_default = ":host {\n display: inline-flex;\n align-items: center;\n position: relative;\n font-family: var(--bv-font-family-base);\n}\n\n:host([hidden]) {\n display: none;\n}\n\n.wrap {\n display: inline-flex;\n align-items: center;\n position: relative;\n}\n\n.trigger {\n display: inline-flex;\n align-items: center;\n cursor: help;\n color: var(--bv-color-neutral-400);\n outline: none;\n border: none;\n background: none;\n padding: 0;\n line-height: 0;\n}\n\n.trigger:hover,\n.trigger:focus {\n color: var(--bv-color-neutral-600);\n}\n\n.trigger svg {\n display: block;\n width: 14px;\n height: 14px;\n}\n\n/* \u2500\u2500 Popup \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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.popup {\n /* Shown/positioned entirely via JS \u2014 display starts as none */\n display: none;\n position: absolute;\n z-index: 500;\n min-width: 200px;\n max-width: 300px;\n background: var(--bv-color-neutral-900);\n color: var(--bv-color-neutral-0);\n border-radius: var(--bv-radius-md);\n padding: 10px 12px;\n font-size: var(--bv-font-size-xs);\n font-weight: var(--bv-font-weight-regular);\n line-height: 1.6;\n box-shadow: var(--bv-shadow-lg);\n pointer-events: none;\n white-space: normal;\n}\n\n/* \u2500\u2500 Content \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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.text-content {\n display: none;\n}\n\n:host([text]) .text-content {\n display: block;\n}\n\n:host([text]) slot {\n display: none;\n}\n\n::slotted(p) {\n margin: 0 0 4px;\n}\n\n::slotted(p:last-child) {\n margin-bottom: 0;\n}\n";
|
|
@@ -156,8 +156,8 @@ var SORT_ASC = `<svg class="bv-sort-icon" viewBox="0 0 16 16" fill="none" xmlns=
|
|
|
156
156
|
var SORT_DESC = `<svg class="bv-sort-icon" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
157
157
|
<path d="M8 3v10M5 10l3 3 3-3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
158
158
|
</svg>`;
|
|
159
|
-
function
|
|
160
|
-
return
|
|
159
|
+
function normalizeLoadingLabel(label) {
|
|
160
|
+
return (label == null ? void 0 : label.trim()) || "Loading";
|
|
161
161
|
}
|
|
162
162
|
function injectTableStyles() {
|
|
163
163
|
if (document.getElementById("bv-table-styles")) return;
|
|
@@ -172,6 +172,7 @@ var BvTable = class extends HTMLElement {
|
|
|
172
172
|
"bordered",
|
|
173
173
|
"loading",
|
|
174
174
|
"loading-rows",
|
|
175
|
+
"loading-label",
|
|
175
176
|
"fit-viewport"
|
|
176
177
|
];
|
|
177
178
|
_isDragging = false;
|
|
@@ -185,6 +186,21 @@ var BvTable = class extends HTMLElement {
|
|
|
185
186
|
_mutationObserver = null;
|
|
186
187
|
_bodyObserver = null;
|
|
187
188
|
_headerObserver = null;
|
|
189
|
+
/**
|
|
190
|
+
* BTN-11914 — the `<thead>` the header observer currently watches for
|
|
191
|
+
* `characterData`. Held so the re-attach below can tell "already watching
|
|
192
|
+
* this one" from "the consumer swapped the header out", and so
|
|
193
|
+
* `disconnectedCallback` can drop it: `disconnect()` clears the
|
|
194
|
+
* registration, and a stale ref would make the re-attach skip itself.
|
|
195
|
+
*/
|
|
196
|
+
_observedThead = null;
|
|
197
|
+
/**
|
|
198
|
+
* BTN-11914 — dedicated to the `<thead>` `characterData` watch. Separate from
|
|
199
|
+
* `_headerObserver` so a replaced header can be dropped with `disconnect()`
|
|
200
|
+
* without discarding the host observer's queued childList records. See
|
|
201
|
+
* `_observeTheadCharacterData`.
|
|
202
|
+
*/
|
|
203
|
+
_theadObserver = null;
|
|
188
204
|
get loading() {
|
|
189
205
|
return this.hasAttribute("loading");
|
|
190
206
|
}
|
|
@@ -210,13 +226,16 @@ var BvTable = class extends HTMLElement {
|
|
|
210
226
|
if (this.hasAttribute("loading")) this._renderSkeleton();
|
|
211
227
|
}
|
|
212
228
|
disconnectedCallback() {
|
|
213
|
-
var _a, _b;
|
|
229
|
+
var _a, _b, _c;
|
|
214
230
|
this._teardownDrag();
|
|
215
231
|
this._teardownStickyColumns();
|
|
216
232
|
(_a = this._bodyObserver) == null ? void 0 : _a.disconnect();
|
|
217
233
|
this._bodyObserver = null;
|
|
218
234
|
(_b = this._headerObserver) == null ? void 0 : _b.disconnect();
|
|
219
235
|
this._headerObserver = null;
|
|
236
|
+
(_c = this._theadObserver) == null ? void 0 : _c.disconnect();
|
|
237
|
+
this._theadObserver = null;
|
|
238
|
+
this._observedThead = null;
|
|
220
239
|
}
|
|
221
240
|
attributeChangedCallback(name, _old, val) {
|
|
222
241
|
if (!this.isConnected) return;
|
|
@@ -228,6 +247,7 @@ var BvTable = class extends HTMLElement {
|
|
|
228
247
|
this._removeSkeleton();
|
|
229
248
|
this._renderSkeleton();
|
|
230
249
|
}
|
|
250
|
+
if (name === "loading-label") this._syncSkeletonLabel(val);
|
|
231
251
|
if (name === "fit-viewport") {
|
|
232
252
|
this._teardownStickyColumns();
|
|
233
253
|
this._setupStickyColumns();
|
|
@@ -245,7 +265,7 @@ var BvTable = class extends HTMLElement {
|
|
|
245
265
|
skeleton.className = "bv-table-skeleton";
|
|
246
266
|
skeleton.setAttribute("role", "status");
|
|
247
267
|
skeleton.setAttribute("aria-live", "polite");
|
|
248
|
-
skeleton.setAttribute("aria-label", this.getAttribute("loading-label")
|
|
268
|
+
skeleton.setAttribute("aria-label", normalizeLoadingLabel(this.getAttribute("loading-label")));
|
|
249
269
|
for (let r = 0; r < rows; r++) {
|
|
250
270
|
const row = document.createElement("div");
|
|
251
271
|
row.className = "bv-table-skeleton-row";
|
|
@@ -262,6 +282,19 @@ var BvTable = class extends HTMLElement {
|
|
|
262
282
|
var _a;
|
|
263
283
|
(_a = this.querySelector(":scope > .bv-table-skeleton")) == null ? void 0 : _a.remove();
|
|
264
284
|
}
|
|
285
|
+
// BTN-11343 — patches the skeleton's accessible name in place. Extracted
|
|
286
|
+
// rather than inlined in `attributeChangedCallback` for the same reason
|
|
287
|
+
// `_renderSkeleton` and `_removeSkeleton` are: `wc/no-child-traversal-in-
|
|
288
|
+
// attributechangedcallback` rejects traversing children from there, and the
|
|
289
|
+
// rule is right — the skeleton only exists while loading, so the caller
|
|
290
|
+
// cannot assume it is there. No-op when it is absent.
|
|
291
|
+
_syncSkeletonLabel(label) {
|
|
292
|
+
var _a;
|
|
293
|
+
(_a = this.querySelector(":scope > .bv-table-skeleton")) == null ? void 0 : _a.setAttribute(
|
|
294
|
+
"aria-label",
|
|
295
|
+
normalizeLoadingLabel(label)
|
|
296
|
+
);
|
|
297
|
+
}
|
|
265
298
|
_setupDrag() {
|
|
266
299
|
this.addEventListener("mousedown", this._boundMouseDown);
|
|
267
300
|
window.addEventListener("mousemove", this._boundMouseMove);
|
|
@@ -367,10 +400,22 @@ var BvTable = class extends HTMLElement {
|
|
|
367
400
|
if (td.children.length > 0) return;
|
|
368
401
|
const text = td.textContent;
|
|
369
402
|
if (!text || !text.trim()) return;
|
|
370
|
-
const
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
403
|
+
const children = Array.from(td.childNodes);
|
|
404
|
+
let run = [];
|
|
405
|
+
const wrapRun = () => {
|
|
406
|
+
if (run.length === 0) return;
|
|
407
|
+
const span = document.createElement("span");
|
|
408
|
+
span.className = "bv-cell-text";
|
|
409
|
+
span.textContent = run.map((n) => n.textContent ?? "").join("");
|
|
410
|
+
td.insertBefore(span, run[0] ?? null);
|
|
411
|
+
for (const n of run) td.removeChild(n);
|
|
412
|
+
run = [];
|
|
413
|
+
};
|
|
414
|
+
for (const node of children) {
|
|
415
|
+
if (node.nodeType === Node.TEXT_NODE) run.push(node);
|
|
416
|
+
else wrapRun();
|
|
417
|
+
}
|
|
418
|
+
wrapRun();
|
|
374
419
|
}
|
|
375
420
|
// Watches the host for TDs materialized after the initial `_enhanceBodyCells`
|
|
376
421
|
// pass — Angular *ngFor, React lists, or any consumer that mounts <bv-table>
|
|
@@ -436,14 +481,15 @@ var BvTable = class extends HTMLElement {
|
|
|
436
481
|
const hasTooltip = th.hasAttribute("data-tooltip");
|
|
437
482
|
if (!hasSortable && !hasTooltip) return;
|
|
438
483
|
if (hasSortable && !th.hasAttribute("data-column")) {
|
|
439
|
-
|
|
440
|
-
"
|
|
441
|
-
|
|
442
|
-
|
|
484
|
+
if (!th.dataset["bvColumnWarned"]) {
|
|
485
|
+
th.dataset["bvColumnWarned"] = "true";
|
|
486
|
+
console.warn(
|
|
487
|
+
"[bv-table] <th data-sortable> requires data-column; skipping sort enhancement for:",
|
|
488
|
+
th
|
|
489
|
+
);
|
|
490
|
+
}
|
|
443
491
|
if (!hasTooltip) return;
|
|
444
|
-
|
|
445
|
-
const tip = escapeAttr(th.getAttribute("data-tooltip") ?? "");
|
|
446
|
-
th.innerHTML = `<span class="bv-th-content">${label}<bv-tooltip text="${tip}" position="bottom"></bv-tooltip></span>`;
|
|
492
|
+
this._renderTooltipOnlyTh(th);
|
|
447
493
|
return;
|
|
448
494
|
}
|
|
449
495
|
if (hasSortable) {
|
|
@@ -464,10 +510,57 @@ var BvTable = class extends HTMLElement {
|
|
|
464
510
|
th.setAttribute("tabindex", "0");
|
|
465
511
|
this._syncSortableTh(th);
|
|
466
512
|
} else {
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
513
|
+
this._renderTooltipOnlyTh(th);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
// BTN-11212 — tooltip-only header render. Extracted from `_enhanceOneHeader`
|
|
517
|
+
// because two call sites need it and both are now re-entrant: the header
|
|
518
|
+
// observer watches childList, so this runs again every time the consumer's
|
|
519
|
+
// framework mutates the header's children.
|
|
520
|
+
//
|
|
521
|
+
// Two guards keep the re-entry harmless:
|
|
522
|
+
// 1. An already-enhanced th short-circuits on the bv-tooltip probe, which
|
|
523
|
+
// preserves the single-shot property the previous inline version had.
|
|
524
|
+
// 2. An empty label means the framework has created the th but has not
|
|
525
|
+
// written its text yet — rewriting now would delete the text node it
|
|
526
|
+
// is about to fill. Skip; the childList branch of the observer calls
|
|
527
|
+
// back once the text lands.
|
|
528
|
+
_renderTooltipOnlyTh(th) {
|
|
529
|
+
if (th.querySelector("bv-tooltip")) return;
|
|
530
|
+
const label = this._extractHeaderLabel(th);
|
|
531
|
+
if (!label) return;
|
|
532
|
+
this._buildThContent(th, label);
|
|
533
|
+
}
|
|
534
|
+
// Builds the `.bv-th-content` wrapper without ever interpolating consumer
|
|
535
|
+
// text into markup (Copilot review). The label arrives from
|
|
536
|
+
// `_extractHeaderLabel`, i.e. from `textContent` — decoded text, not
|
|
537
|
+
// markup — so interpolating it into `innerHTML` re-parsed it: a header
|
|
538
|
+
// whose label was the plain string "<img src=x onerror=…>" became a real
|
|
539
|
+
// <img> element. Reachable in practice, because a header label is routinely
|
|
540
|
+
// data (a category name, an admin-configured column title) rendered through
|
|
541
|
+
// a framework binding.
|
|
542
|
+
//
|
|
543
|
+
// The label goes in as a text node and the tooltip text through
|
|
544
|
+
// `setAttribute`, so neither can be parsed as HTML and neither needs
|
|
545
|
+
// escaping. `icon` is the only raw markup and it is always one of the three
|
|
546
|
+
// module-level SVG constants — never anything a consumer supplies.
|
|
547
|
+
//
|
|
548
|
+
// `replaceChildren` reports the wrapper as the single added node, same as
|
|
549
|
+
// the `innerHTML` write it replaces, so the observer's re-entry guard is
|
|
550
|
+
// unaffected.
|
|
551
|
+
_buildThContent(th, label, icon) {
|
|
552
|
+
const content = document.createElement("span");
|
|
553
|
+
content.className = "bv-th-content";
|
|
554
|
+
content.appendChild(document.createTextNode(label));
|
|
555
|
+
const tip = th.getAttribute("data-tooltip");
|
|
556
|
+
if (tip !== null) {
|
|
557
|
+
const tooltip = document.createElement("bv-tooltip");
|
|
558
|
+
tooltip.setAttribute("text", tip);
|
|
559
|
+
tooltip.setAttribute("position", "bottom");
|
|
560
|
+
content.appendChild(tooltip);
|
|
470
561
|
}
|
|
562
|
+
if (icon) content.insertAdjacentHTML("beforeend", icon);
|
|
563
|
+
th.replaceChildren(content);
|
|
471
564
|
}
|
|
472
565
|
// Reads the plain-text label from a th, whether it's still raw markup
|
|
473
566
|
// (initial enhance pass) or has already been wrapped in `.bv-th-content`
|
|
@@ -489,14 +582,14 @@ var BvTable = class extends HTMLElement {
|
|
|
489
582
|
// `_headerObserver` (to reflect a consumer's external data-sort write).
|
|
490
583
|
_syncSortableTh(th) {
|
|
491
584
|
const sortDir = th.getAttribute("data-sort") ?? "none";
|
|
492
|
-
const label = this._extractHeaderLabel(th);
|
|
493
|
-
const tooltip = th.hasAttribute("data-tooltip") ? `<bv-tooltip text="${escapeAttr(th.getAttribute("data-tooltip") ?? "")}" position="bottom"></bv-tooltip>` : "";
|
|
494
|
-
const icon = sortDir === "asc" ? SORT_ASC : sortDir === "desc" ? SORT_DESC : SORT_NONE;
|
|
495
|
-
th.innerHTML = `<span class="bv-th-content">${label}${tooltip}${icon}</span>`;
|
|
496
585
|
th.setAttribute(
|
|
497
586
|
"aria-sort",
|
|
498
587
|
sortDir === "asc" ? "ascending" : sortDir === "desc" ? "descending" : "none"
|
|
499
588
|
);
|
|
589
|
+
const label = this._extractHeaderLabel(th);
|
|
590
|
+
if (!label) return;
|
|
591
|
+
const icon = sortDir === "asc" ? SORT_ASC : sortDir === "desc" ? SORT_DESC : SORT_NONE;
|
|
592
|
+
this._buildThContent(th, label, icon);
|
|
500
593
|
}
|
|
501
594
|
// BTN-10755 — click and Enter/Space both route through here. Cycles the
|
|
502
595
|
// tri-state, clears sibling sortable ths (UX for user interaction — the
|
|
@@ -537,25 +630,173 @@ var BvTable = class extends HTMLElement {
|
|
|
537
630
|
// runs the initial enhance for that th.
|
|
538
631
|
// The observer never clears siblings — sibling sanitation is UX for the
|
|
539
632
|
// user-driven click / keydown paths.
|
|
633
|
+
//
|
|
634
|
+
// BTN-11212 — the observer also watches `childList`. Before that, headers
|
|
635
|
+
// were enhanced from `connectedCallback` and nowhere else, which never runs
|
|
636
|
+
// against real headers for a framework that appends <bv-table> before
|
|
637
|
+
// creating its children (Angular does). The initial pass saw an empty
|
|
638
|
+
// <thead>, and a <th> appended afterwards — already carrying data-sortable
|
|
639
|
+
// or data-tooltip — is a childList mutation the attribute filter cannot
|
|
640
|
+
// see. Tooltips therefore never rendered at all, and sortable headers were
|
|
641
|
+
// enhanced only by the accident of a later `data-sort` write, at a moment
|
|
642
|
+
// when their text had not been written yet. `_bodyObserver` has had the
|
|
643
|
+
// equivalent childList branch for <td> all along; this is the same thing
|
|
644
|
+
// for <th>.
|
|
540
645
|
_observeHeaderMutations() {
|
|
541
646
|
this._headerObserver = new MutationObserver((mutations) => {
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
const target = m.target;
|
|
545
|
-
if (!(target instanceof HTMLElement)) continue;
|
|
546
|
-
if (target.tagName !== "TH" || !target.closest("thead")) continue;
|
|
547
|
-
if (m.attributeName === "data-sort") {
|
|
548
|
-
if (target.hasAttribute("data-sortable")) this._syncSortableTh(target);
|
|
549
|
-
} else if (m.attributeName === "data-sortable") {
|
|
550
|
-
if (target.hasAttribute("data-sortable")) this._enhanceOneHeader(target);
|
|
551
|
-
}
|
|
552
|
-
}
|
|
647
|
+
this._observeTheadCharacterData();
|
|
648
|
+
this._handleHeaderMutations(mutations);
|
|
553
649
|
});
|
|
554
650
|
this._headerObserver.observe(this, {
|
|
555
651
|
attributes: true,
|
|
652
|
+
childList: true,
|
|
556
653
|
subtree: true,
|
|
557
654
|
attributeFilter: ["data-sort", "data-sortable"]
|
|
558
655
|
});
|
|
656
|
+
this._observeTheadCharacterData();
|
|
657
|
+
}
|
|
658
|
+
/**
|
|
659
|
+
* The header observer's record handling, shared by both observers that feed
|
|
660
|
+
* it: the host-wide one above (childList + attributes) and the `<thead>`
|
|
661
|
+
* characterData one below. One body so a branch added to either cannot drift
|
|
662
|
+
* from the other.
|
|
663
|
+
*/
|
|
664
|
+
_handleHeaderMutations(mutations) {
|
|
665
|
+
for (const m of mutations) {
|
|
666
|
+
if (m.target.nodeType === Node.COMMENT_NODE) continue;
|
|
667
|
+
if (m.type === "childList") {
|
|
668
|
+
this._enhanceAddedHeaders(m);
|
|
669
|
+
continue;
|
|
670
|
+
}
|
|
671
|
+
if (m.type === "characterData") {
|
|
672
|
+
this._enhanceFilledHeader(m);
|
|
673
|
+
continue;
|
|
674
|
+
}
|
|
675
|
+
if (m.type !== "attributes") continue;
|
|
676
|
+
const target = m.target;
|
|
677
|
+
if (!(target instanceof HTMLElement)) continue;
|
|
678
|
+
if (target.tagName !== "TH" || !target.closest("thead")) continue;
|
|
679
|
+
if (m.attributeName === "data-sort") {
|
|
680
|
+
if (target.hasAttribute("data-sortable")) this._syncSortableTh(target);
|
|
681
|
+
} else if (m.attributeName === "data-sortable") {
|
|
682
|
+
if (target.hasAttribute("data-sortable")) this._enhanceOneHeader(target);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
/**
|
|
687
|
+
* BTN-11914 — watches `characterData` on the current `<thead>`, and nothing
|
|
688
|
+
* else. Cheap to call repeatedly: it returns immediately while the same
|
|
689
|
+
* element is already being watched.
|
|
690
|
+
*
|
|
691
|
+
* `characterData` must keep reaching the header (BTN-11247): Angular's Ivy
|
|
692
|
+
* creates the header's text node empty and fills it on the update pass, which
|
|
693
|
+
* arrives as a characterData mutation, not a childList one.
|
|
694
|
+
*
|
|
695
|
+
* **Why its own MutationObserver instead of a second `observe()` on the
|
|
696
|
+
* header one.** A replaced `<thead>` has to stop being watched, or a consumer
|
|
697
|
+
* that keeps and mutates the detached subtree still reaches
|
|
698
|
+
* `_enhanceFilledHeader` — records for stale DOM, which is the narrow scope
|
|
699
|
+
* leaking back open (raised by Copilot on PR #50). There is no
|
|
700
|
+
* `unobserve(node)`, so the only way to drop one registration is
|
|
701
|
+
* `disconnect()`, and that also **discards records already queued and not yet
|
|
702
|
+
* delivered**. On the shared observer that would throw away pending childList
|
|
703
|
+
* and attribute records mid-batch — the first version of this fix accepted the
|
|
704
|
+
* stale registration for exactly that reason. A dedicated observer removes the
|
|
705
|
+
* trade entirely: the records it discards are the old `<thead>`'s, which are
|
|
706
|
+
* the ones being dropped on purpose.
|
|
707
|
+
*/
|
|
708
|
+
_observeTheadCharacterData() {
|
|
709
|
+
const thead = this.querySelector("thead");
|
|
710
|
+
if (thead === this._observedThead) return;
|
|
711
|
+
this._observedThead = thead;
|
|
712
|
+
if (!this._theadObserver) {
|
|
713
|
+
this._theadObserver = new MutationObserver(
|
|
714
|
+
(mutations) => this._handleHeaderMutations(mutations)
|
|
715
|
+
);
|
|
716
|
+
}
|
|
717
|
+
this._theadObserver.disconnect();
|
|
718
|
+
if (thead) this._theadObserver.observe(thead, { characterData: true, subtree: true });
|
|
719
|
+
}
|
|
720
|
+
// BTN-11247 — characterData half of the header observer. BTN-11212 covered
|
|
721
|
+
// the two childList shapes (a <th> appended, and a text node appended into
|
|
722
|
+
// a <th>) and assumed those were all the ways a label can arrive late.
|
|
723
|
+
// They are not: Angular's Ivy creates the header's text node **empty**
|
|
724
|
+
// during the creation pass and fills it during the update pass. Filling an
|
|
725
|
+
// existing text node is neither of those shapes — it is a characterData
|
|
726
|
+
// mutation, and nothing was listening.
|
|
727
|
+
//
|
|
728
|
+
// The consequence was not a missing observer callback but a half-rendered
|
|
729
|
+
// header, which is why it read as working: `_enhanceOneHeader` did run off
|
|
730
|
+
// the empty-text-node append, wired the listeners and set tabindex /
|
|
731
|
+
// aria-sort, then returned on the empty-label guard exactly as intended.
|
|
732
|
+
// Nothing called it back, so sorting ended up fully accessible and
|
|
733
|
+
// completely invisible, and tooltip-only headers rendered nothing at all.
|
|
734
|
+
//
|
|
735
|
+
// Re-entry is safe for the same two reasons the childList branch documents
|
|
736
|
+
// above, and the second one holds here specifically: `_buildThContent`
|
|
737
|
+
// writes a **new** text node via `replaceChildren`, which the observer
|
|
738
|
+
// reports as a childList mutation on the wrapper — never characterData on
|
|
739
|
+
// a <th>'s own child. So our own writes cannot reach this branch at all.
|
|
740
|
+
//
|
|
741
|
+
// BTN-11850 — that last sentence is true and was not enough, which is the
|
|
742
|
+
// part worth carrying forward. It reasons about the nodes *we* write, and
|
|
743
|
+
// the loop that shipped came from nodes we do not write: a framework's own
|
|
744
|
+
// children living inside the same <th>, mutated by that framework, landing
|
|
745
|
+
// here, and being destroyed by the rebuild this function triggers — so the
|
|
746
|
+
// framework wrote them again. The feedback edge does not need our writes to
|
|
747
|
+
// reach this branch; it only needs our writes to disturb something whose
|
|
748
|
+
// owner will restore it.
|
|
749
|
+
//
|
|
750
|
+
// The guard for that specific shape is in `_observeHeaderMutations`, which
|
|
751
|
+
// drops comment targets before this function is reached. The general rule
|
|
752
|
+
// it stands for: an enhancer that rebuilds a subtree it does not fully own
|
|
753
|
+
// must be judged on what else lives in that subtree, not only on what it
|
|
754
|
+
// writes into it.
|
|
755
|
+
_enhanceFilledHeader(m) {
|
|
756
|
+
var _a;
|
|
757
|
+
const el = (_a = m.target.parentElement) == null ? void 0 : _a.closest("th, tbody");
|
|
758
|
+
if (!(el instanceof HTMLElement) || el.tagName !== "TH") return;
|
|
759
|
+
if (el.closest("thead")) this._enhanceOneHeader(el);
|
|
760
|
+
}
|
|
761
|
+
// BTN-11212 — childList half of the header observer. Covers the two ways a
|
|
762
|
+
// header can materialize as a *structural* change: the <th> itself being
|
|
763
|
+
// appended (directly, or as part of a <thead> / <table> subtree), and the
|
|
764
|
+
// label text landing in a <th> that was appended empty. The third way — an
|
|
765
|
+
// already-appended empty text node being filled in place — is not a
|
|
766
|
+
// childList mutation at all; see `_enhanceFilledHeader` (BTN-11247).
|
|
767
|
+
//
|
|
768
|
+
// This runs inside the subtree the enhancers rewrite, so re-entry matters.
|
|
769
|
+
// Two independent things make it safe, in order of strength:
|
|
770
|
+
//
|
|
771
|
+
// 1. Both render paths are idempotent. `_syncSortableTh` re-reads the
|
|
772
|
+
// label out of the `.bv-th-content` it wrote and produces the same
|
|
773
|
+
// markup; `_renderTooltipOnlyTh` short-circuits on the bv-tooltip
|
|
774
|
+
// probe. So the worst case of an unexpected re-entry is one redundant
|
|
775
|
+
// rewrite that converges — not a loop. This is the guarantee to
|
|
776
|
+
// preserve if the rewrite below is ever changed, and it is pinned by
|
|
777
|
+
// the "stray text appended to an already-enhanced th" test.
|
|
778
|
+
// 2. In practice re-entry does not happen for our own writes at all:
|
|
779
|
+
// `_buildThContent`'s `replaceChildren` reports the `.bv-th-content`
|
|
780
|
+
// wrapper as the added node, never a bare text node with a <th> parent
|
|
781
|
+
// and never a <th>, so both branches below skip it.
|
|
782
|
+
//
|
|
783
|
+
// Point 2 is an observation about what MutationObserver reports; point 1 is
|
|
784
|
+
// structural. Do not let a future rewrite rely on point 2 alone.
|
|
785
|
+
_enhanceAddedHeaders(m) {
|
|
786
|
+
m.addedNodes.forEach((node) => {
|
|
787
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
788
|
+
const parent = node.parentElement;
|
|
789
|
+
if ((parent == null ? void 0 : parent.tagName) === "TH" && parent.closest("thead")) this._enhanceOneHeader(parent);
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
792
|
+
if (!(node instanceof HTMLElement)) return;
|
|
793
|
+
if (node.classList.contains("bv-th-content")) return;
|
|
794
|
+
if (node.closest("tbody")) return;
|
|
795
|
+
if (node.matches("th") && node.closest("thead")) this._enhanceOneHeader(node);
|
|
796
|
+
node.querySelectorAll("th").forEach((th) => {
|
|
797
|
+
if (th.closest("thead")) this._enhanceOneHeader(th);
|
|
798
|
+
});
|
|
799
|
+
});
|
|
559
800
|
}
|
|
560
801
|
};
|
|
561
802
|
if (!customElements.get("bv-table")) {
|
|
@@ -2,11 +2,26 @@ export type ToggleSize = 'sm' | 'md';
|
|
|
2
2
|
export declare class BvToggle extends HTMLElement {
|
|
3
3
|
static readonly observedAttributes: readonly ["checked", "disabled", "label", "size"];
|
|
4
4
|
private _rendered;
|
|
5
|
+
private _wrapEl;
|
|
5
6
|
private _labelEl;
|
|
6
7
|
constructor();
|
|
7
8
|
connectedCallback(): void;
|
|
8
9
|
attributeChangedCallback(name: string, _old: string | null, val: string | null): void;
|
|
9
10
|
get checked(): boolean;
|
|
10
11
|
set checked(v: boolean);
|
|
12
|
+
/**
|
|
13
|
+
* Focus the toggle. The focusable element is the internal `.wrap`, not the
|
|
14
|
+
* host, so `hostEl.focus()` would otherwise be a silent no-op. Consumers that
|
|
15
|
+
* rebuild the panel a toggle lives in (bv-input-dropdown's `toggle-label`,
|
|
16
|
+
* bv-search-picker's `inactive-toggle-label`) need this to restore focus
|
|
17
|
+
* after the rebuild without reaching into this component's shadow root.
|
|
18
|
+
*
|
|
19
|
+
* No-op before the first render, and when disabled — `tabindex="-1"` only
|
|
20
|
+
* removes the element from Tab order, it does not block programmatic focus,
|
|
21
|
+
* so a restore pass could otherwise land focus on a control that was
|
|
22
|
+
* disabled mid-rebuild.
|
|
23
|
+
*/
|
|
24
|
+
focus(options?: FocusOptions): void;
|
|
11
25
|
private _render;
|
|
26
|
+
private _syncAria;
|
|
12
27
|
}
|