@akcelik/strct 5.29.0 → 5.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/akcelik-strct.mjs +269 -1641
- package/fesm2022/akcelik-strct.mjs.map +1 -1
- package/package.json +1 -1
- package/types/akcelik-strct.d.ts +218 -54
|
@@ -1098,9 +1098,20 @@ function strctDevWarn(key, message) {
|
|
|
1098
1098
|
warned.add(key);
|
|
1099
1099
|
console.warn(message);
|
|
1100
1100
|
}
|
|
1101
|
+
/**
|
|
1102
|
+
* A diagnostic that keeps its own state (one that collects names and reports
|
|
1103
|
+
* them together, say) registers how to forget it, so the test hook below
|
|
1104
|
+
* stays the one way to reset dev-mode diagnostics.
|
|
1105
|
+
*/
|
|
1106
|
+
const resetters = new Set();
|
|
1107
|
+
function strctOnDevWarnReset(forget) {
|
|
1108
|
+
resetters.add(forget);
|
|
1109
|
+
}
|
|
1101
1110
|
/** Test hook: forget which warnings have fired. Not part of the public API. */
|
|
1102
1111
|
function resetStrctDevWarnings() {
|
|
1103
1112
|
warned.clear();
|
|
1113
|
+
for (const forget of resetters)
|
|
1114
|
+
forget();
|
|
1104
1115
|
}
|
|
1105
1116
|
|
|
1106
1117
|
/**
|
|
@@ -15232,6 +15243,37 @@ const DG_LABELS = {
|
|
|
15232
15243
|
pageOf: (page, pages) => `Page ${page} of ${pages}`,
|
|
15233
15244
|
rowsMatch: (shown, total) => `${shown} of ${total} rows match`,
|
|
15234
15245
|
};
|
|
15246
|
+
|
|
15247
|
+
/*
|
|
15248
|
+
* ── The grid's features, as objects (5.30.0) ──────────────────────────────
|
|
15249
|
+
*
|
|
15250
|
+
* The component grew to 54 inputs, which is more than a template can read.
|
|
15251
|
+
* Each cluster of them becomes one object; the flat inputs keep working
|
|
15252
|
+
* through 5.x and dev mode says which object each has moved into, so a
|
|
15253
|
+
* consumer upgrades a screen at a time. They are removed in 6.0.
|
|
15254
|
+
*
|
|
15255
|
+
* What stays flat on purpose: the two-way state (`selectedIds`, `filters`,
|
|
15256
|
+
* `columnState`, `collapsedGroups`, `quickFilter`, `activeRowId`,
|
|
15257
|
+
* `selectedId`), because `[(…)]` cannot bind through a property of an
|
|
15258
|
+
* object; and the grid's core (`columns`, `rows`, `rowId`, `labels`) with the
|
|
15259
|
+
* handful of look flags.
|
|
15260
|
+
*/
|
|
15261
|
+
/** Flat inputs already named in a deprecation warning, per app run. */
|
|
15262
|
+
const warnedFlatInputs = new Set();
|
|
15263
|
+
const pendingFlatInputWarnings = new Set();
|
|
15264
|
+
let flatInputWarningQueued = false;
|
|
15265
|
+
strctOnDevWarnReset(() => {
|
|
15266
|
+
warnedFlatInputs.clear();
|
|
15267
|
+
pendingFlatInputWarnings.clear();
|
|
15268
|
+
});
|
|
15269
|
+
/**
|
|
15270
|
+
* `virtual` and `pane` take the flag they always took — including the bare
|
|
15271
|
+
* attribute, which arrives as `''` — or the object that replaced their
|
|
15272
|
+
* satellite inputs.
|
|
15273
|
+
*/
|
|
15274
|
+
function objectOrBoolean(value) {
|
|
15275
|
+
return typeof value === 'object' && value !== null ? value : booleanAttribute(value);
|
|
15276
|
+
}
|
|
15235
15277
|
/**
|
|
15236
15278
|
* A fully custom group header row:
|
|
15237
15279
|
*
|
|
@@ -15328,28 +15370,25 @@ class StrctDatagrid {
|
|
|
15328
15370
|
rows = input.required(/* @ts-ignore */
|
|
15329
15371
|
...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
|
|
15330
15372
|
/** Rows per page (0 disables paging). */
|
|
15331
|
-
|
|
15332
|
-
...(ngDevMode ? [{ debugName: "pageSize" }] : /* istanbul ignore next */ []));
|
|
15373
|
+
pageSizeFlat = input(0, { ...(ngDevMode ? { debugName: "pageSizeFlat" } : /* istanbul ignore next */ {}), alias: 'pageSize' });
|
|
15333
15374
|
/** Enable row selection. */
|
|
15334
|
-
|
|
15375
|
+
selectableFlat = input(false, { ...(ngDevMode ? { debugName: "selectableFlat" } : /* istanbul ignore next */ {}), alias: 'selectable', transform: booleanAttribute });
|
|
15335
15376
|
/** Expand a row in place to reveal its detail template below it. */
|
|
15336
15377
|
expandable = input(false, { ...(ngDevMode ? { debugName: "expandable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
15337
15378
|
/** Collapse the grid to a single column and open a side detail pane for the
|
|
15338
15379
|
* clicked row (distinct from {@link expandable}). */
|
|
15339
|
-
|
|
15380
|
+
detailPaneFlat = input(false, { ...(ngDevMode ? { debugName: "detailPaneFlat" } : /* istanbul ignore next */ {}), alias: 'detailPane', transform: booleanAttribute });
|
|
15340
15381
|
/**
|
|
15341
15382
|
* How wide the list column is while the pane is open — px or any CSS width.
|
|
15342
15383
|
* 260px cuts a test name like "Validate Switch Enabled Teaming
|
|
15343
15384
|
* Configurations" in half and hides its status.
|
|
15344
15385
|
*/
|
|
15345
|
-
|
|
15346
|
-
...(ngDevMode ? [{ debugName: "paneListWidth" }] : /* istanbul ignore next */ []));
|
|
15386
|
+
paneListWidthFlat = input('260px', { ...(ngDevMode ? { debugName: "paneListWidthFlat" } : /* istanbul ignore next */ {}), alias: 'paneListWidth' });
|
|
15347
15387
|
/**
|
|
15348
15388
|
* Below this container width (px) the pane takes the list's place, with a
|
|
15349
15389
|
* way back in its header, rather than squeezing both into a phone.
|
|
15350
15390
|
*/
|
|
15351
|
-
|
|
15352
|
-
...(ngDevMode ? [{ debugName: "paneTakeoverWidth" }] : /* istanbul ignore next */ []));
|
|
15391
|
+
paneTakeoverWidthFlat = input(900, { ...(ngDevMode ? { debugName: "paneTakeoverWidthFlat" } : /* istanbul ignore next */ {}), alias: 'paneTakeoverWidth' });
|
|
15353
15392
|
/**
|
|
15354
15393
|
* The row whose pane is open, two-way: a "what to do next" chip opens the
|
|
15355
15394
|
* finding it settles, a URL fragment deep-links to a test, `null` closes it.
|
|
@@ -15373,7 +15412,7 @@ class StrctDatagrid {
|
|
|
15373
15412
|
/** Show a column-chooser dropdown in the footer. */
|
|
15374
15413
|
columnChooser = input(false, { ...(ngDevMode ? { debugName: "columnChooser" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
15375
15414
|
/** Show a refresh button in the footer. */
|
|
15376
|
-
|
|
15415
|
+
syncFlat = input(false, { ...(ngDevMode ? { debugName: "syncFlat" } : /* istanbul ignore next */ {}), alias: 'sync', transform: booleanAttribute });
|
|
15377
15416
|
/** Disable all footer action buttons (sync, column chooser, etc.). */
|
|
15378
15417
|
footerActionsDisabled = input(false, { ...(ngDevMode ? { debugName: "footerActionsDisabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
15379
15418
|
/**
|
|
@@ -15389,8 +15428,7 @@ class StrctDatagrid {
|
|
|
15389
15428
|
* exactly one row is grid behaviour rather than a column of radios the
|
|
15390
15429
|
* consumer builds and wires by hand.
|
|
15391
15430
|
*/
|
|
15392
|
-
|
|
15393
|
-
...(ngDevMode ? [{ debugName: "selectionMode" }] : /* istanbul ignore next */ []));
|
|
15431
|
+
selectionModeFlat = input('none', { ...(ngDevMode ? { debugName: "selectionModeFlat" } : /* istanbul ignore next */ {}), alias: 'selectionMode' });
|
|
15394
15432
|
/** Two-way single selection: the row id (per `rowId`), or null. */
|
|
15395
15433
|
selectedId = model(null, /* @ts-ignore */
|
|
15396
15434
|
...(ngDevMode ? [{ debugName: "selectedId" }] : /* istanbul ignore next */ []));
|
|
@@ -15399,30 +15437,22 @@ class StrctDatagrid {
|
|
|
15399
15437
|
* it AND say why — shown as the row's tooltip and given to assistive tech as
|
|
15400
15438
|
* the control's description, following the `hint` convention.
|
|
15401
15439
|
*/
|
|
15402
|
-
|
|
15403
|
-
...(ngDevMode ? [{ debugName: "rowSelectable" }] : /* istanbul ignore next */ []));
|
|
15440
|
+
rowSelectableFlat = input(null, { ...(ngDevMode ? { debugName: "rowSelectableFlat" } : /* istanbul ignore next */ {}), alias: 'rowSelectable' });
|
|
15404
15441
|
/** No outer border, radius or shadow — for a grid inside a bordered panel. */
|
|
15405
15442
|
flush = input(false, { ...(ngDevMode ? { debugName: "flush" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
15406
15443
|
/** The grid's title, rendered above the header and used as its accessible name. */
|
|
15407
15444
|
caption = input('', /* @ts-ignore */
|
|
15408
15445
|
...(ngDevMode ? [{ debugName: "caption" }] : /* istanbul ignore next */ []));
|
|
15409
|
-
/**
|
|
15410
|
-
* `'more'` swaps the pager for a count and a Load more button — the shape a
|
|
15411
|
-
* cursor API can answer. The consumer appends rows; the grid does not page.
|
|
15412
|
-
*/
|
|
15413
|
-
paging = input('pages', /* @ts-ignore */
|
|
15414
|
-
...(ngDevMode ? [{ debugName: "paging" }] : /* istanbul ignore next */ []));
|
|
15415
15446
|
/** Whether there is another slice to ask for. */
|
|
15416
|
-
|
|
15447
|
+
hasMoreFlat = input(false, { ...(ngDevMode ? { debugName: "hasMoreFlat" } : /* istanbul ignore next */ {}), alias: 'hasMore', transform: booleanAttribute });
|
|
15417
15448
|
/** A slice is on its way: the button waits with a spinner. */
|
|
15418
|
-
|
|
15449
|
+
loadingMoreFlat = input(false, { ...(ngDevMode ? { debugName: "loadingMoreFlat" } : /* istanbul ignore next */ {}), alias: 'loadingMore', transform: booleanAttribute });
|
|
15419
15450
|
/** The grand total, when the API knows it — "Showing the latest 50 of 812". */
|
|
15420
|
-
|
|
15421
|
-
...(ngDevMode ? [{ debugName: "moreTotal" }] : /* istanbul ignore next */ []));
|
|
15451
|
+
moreTotalFlat = input(null, { ...(ngDevMode ? { debugName: "moreTotalFlat" } : /* istanbul ignore next */ {}), alias: 'moreTotal' });
|
|
15422
15452
|
/** The user asked for the next slice. */
|
|
15423
15453
|
loadMore = output();
|
|
15424
15454
|
/** With `groupBy` and multiple selection: a tri-state checkbox per group. */
|
|
15425
|
-
|
|
15455
|
+
groupSelectFlat = input(false, { ...(ngDevMode ? { debugName: "groupSelectFlat" } : /* istanbul ignore next */ {}), alias: 'groupSelect', transform: booleanAttribute });
|
|
15426
15456
|
/**
|
|
15427
15457
|
* Per-row action menu resolver. When set, each row gets a trailing actions
|
|
15428
15458
|
* column with a vertical-dots (kebab) button that opens this row's menu.
|
|
@@ -15436,8 +15466,7 @@ class StrctDatagrid {
|
|
|
15436
15466
|
* `selectable`. Assigning a new array (e.g. when opening a dialog) re-seeds the
|
|
15437
15467
|
* selection; the user's subsequent toggles are preserved until the next change.
|
|
15438
15468
|
*/
|
|
15439
|
-
|
|
15440
|
-
...(ngDevMode ? [{ debugName: "initialSelection" }] : /* istanbul ignore next */ []));
|
|
15469
|
+
initialSelectionFlat = input(null, { ...(ngDevMode ? { debugName: "initialSelectionFlat" } : /* istanbul ignore next */ {}), alias: 'initialSelection' });
|
|
15441
15470
|
/**
|
|
15442
15471
|
* The selection itself, two-way, for `selectionMode="multiple"` — what
|
|
15443
15472
|
* `selectedId` is for single mode. Write it and the grid checks those rows
|
|
@@ -15453,48 +15482,36 @@ class StrctDatagrid {
|
|
|
15453
15482
|
/** Effective labels (defaults + overrides). */
|
|
15454
15483
|
L = computed(() => ({ ...DG_LABELS, ...this.labels() }), /* @ts-ignore */
|
|
15455
15484
|
...(ngDevMode ? [{ debugName: "L" }] : /* istanbul ignore next */ []));
|
|
15456
|
-
/**
|
|
15457
|
-
* Virtual scrolling for large data sets: only the rows inside the viewport
|
|
15458
|
-
* (plus a small overscan) are in the DOM — 20k+ rows stay smooth. The scroll
|
|
15459
|
-
* area gets `viewportHeight` and a sticky header. Assumes uniform
|
|
15460
|
-
* `rowHeight`; combine with `expandable` is unsupported.
|
|
15461
|
-
*/
|
|
15462
|
-
virtual = input(false, { ...(ngDevMode ? { debugName: "virtual" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
15463
15485
|
/** Scroll viewport height in px (virtual mode). */
|
|
15464
|
-
|
|
15465
|
-
...(ngDevMode ? [{ debugName: "viewportHeight" }] : /* istanbul ignore next */ []));
|
|
15486
|
+
viewportHeightFlat = input(360, { ...(ngDevMode ? { debugName: "viewportHeightFlat" } : /* istanbul ignore next */ {}), alias: 'viewportHeight' });
|
|
15466
15487
|
/**
|
|
15467
15488
|
* Bound the grid's own scroll box (px), with a sticky header — what
|
|
15468
15489
|
* `viewportHeight` does for `virtual`, for every other grid: a grouped
|
|
15469
15490
|
* picker inside a dialog scrolls instead of growing the page.
|
|
15470
15491
|
*/
|
|
15471
|
-
|
|
15472
|
-
...(ngDevMode ? [{ debugName: "maxHeight" }] : /* istanbul ignore next */ []));
|
|
15492
|
+
maxHeightFlat = input(null, { ...(ngDevMode ? { debugName: "maxHeightFlat" } : /* istanbul ignore next */ {}), alias: 'maxHeight' });
|
|
15473
15493
|
/**
|
|
15474
15494
|
* Show a pencil on an editable cell when it is hovered or focused. A mouse
|
|
15475
15495
|
* user finds an editable cell by double-clicking one; nothing said so.
|
|
15476
15496
|
*/
|
|
15477
15497
|
editHint = input(false, { ...(ngDevMode ? { debugName: "editHint" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
15478
15498
|
/** Uniform row height in px (virtual mode; tune when `compact`). */
|
|
15479
|
-
|
|
15480
|
-
...(ngDevMode ? [{ debugName: "rowHeight" }] : /* istanbul ignore next */ []));
|
|
15499
|
+
rowHeightFlat = input(38, { ...(ngDevMode ? { debugName: "rowHeightFlat" } : /* istanbul ignore next */ {}), alias: 'rowHeight' });
|
|
15481
15500
|
/**
|
|
15482
15501
|
* Server-side mode: the grid never sorts or slices `rows` itself — it shows
|
|
15483
15502
|
* them as given and emits `(lazyLoad)` with `{ page, pageSize, sortKey,
|
|
15484
15503
|
* sortDir }` whenever the user pages or sorts (and once on init). Provide
|
|
15485
15504
|
* `total` so the pager and count reflect the full server-side set.
|
|
15486
15505
|
*/
|
|
15487
|
-
|
|
15506
|
+
lazyFlat = input(false, { ...(ngDevMode ? { debugName: "lazyFlat" } : /* istanbul ignore next */ {}), alias: 'lazy', transform: booleanAttribute });
|
|
15488
15507
|
/** Total row count on the server (lazy mode). */
|
|
15489
|
-
|
|
15490
|
-
...(ngDevMode ? [{ debugName: "total" }] : /* istanbul ignore next */ []));
|
|
15508
|
+
totalFlat = input(null, { ...(ngDevMode ? { debugName: "totalFlat" } : /* istanbul ignore next */ {}), alias: 'total' });
|
|
15491
15509
|
/**
|
|
15492
15510
|
* Persist the user's column widths + hidden columns under this key in
|
|
15493
15511
|
* localStorage (`strct-dg:<key>`), restoring them on init. For full control
|
|
15494
15512
|
* use the two-way `columnState` instead (both may be combined).
|
|
15495
15513
|
*/
|
|
15496
|
-
|
|
15497
|
-
...(ngDevMode ? [{ debugName: "stateKey" }] : /* istanbul ignore next */ []));
|
|
15514
|
+
stateKeyFlat = input(null, { ...(ngDevMode ? { debugName: "stateKeyFlat" } : /* istanbul ignore next */ {}), alias: 'stateKey' });
|
|
15498
15515
|
/** User column preferences (two-way): widths from resize, hidden from the chooser. */
|
|
15499
15516
|
columnState = model(null, /* @ts-ignore */
|
|
15500
15517
|
...(ngDevMode ? [{ debugName: "columnState" }] : /* istanbul ignore next */ []));
|
|
@@ -15505,17 +15522,16 @@ class StrctDatagrid {
|
|
|
15505
15522
|
* per distinct value (with a count), respecting the current sort within
|
|
15506
15523
|
* groups. Paging is bypassed while grouped; not combinable with `virtual`.
|
|
15507
15524
|
*/
|
|
15508
|
-
|
|
15509
|
-
...(ngDevMode ? [{ debugName: "groupBy" }] : /* istanbul ignore next */ []));
|
|
15525
|
+
groupByFlat = input(null, { ...(ngDevMode ? { debugName: "groupByFlat" } : /* istanbul ignore next */ {}), alias: 'groupBy' });
|
|
15510
15526
|
/**
|
|
15511
15527
|
* The groups themselves, beside `groupBy`: their order, their labels, a
|
|
15512
15528
|
* tone, a note, whether they start folded and a count of the consumer's
|
|
15513
15529
|
* own. Values no group mentions follow, in the order the rows arrived.
|
|
15514
15530
|
*/
|
|
15515
|
-
|
|
15516
|
-
...(ngDevMode ? [{ debugName: "groups" }] : /* istanbul ignore next */ []));
|
|
15531
|
+
groupsFlat = input(null, { ...(ngDevMode ? { debugName: "groupsFlat" } : /* istanbul ignore next */ {}), alias: 'groups' });
|
|
15517
15532
|
/** Keep a declared group that holds no rows, rather than dropping it. */
|
|
15518
|
-
|
|
15533
|
+
showEmptyGroupsFlat = input(false, { ...(ngDevMode ? { debugName: "showEmptyGroupsFlat" } : /* istanbul ignore next */ {}), alias: 'showEmptyGroups',
|
|
15534
|
+
transform: booleanAttribute });
|
|
15519
15535
|
/**
|
|
15520
15536
|
* Which groups are folded, two-way — so a summary counter elsewhere on the
|
|
15521
15537
|
* page can open the group it counts.
|
|
@@ -15538,18 +15554,17 @@ class StrctDatagrid {
|
|
|
15538
15554
|
quickFilter = model('', /* @ts-ignore */
|
|
15539
15555
|
...(ngDevMode ? [{ debugName: "quickFilter" }] : /* istanbul ignore next */ []));
|
|
15540
15556
|
/** Columns the quick term scans. Defaults to every column's `key`. */
|
|
15541
|
-
|
|
15542
|
-
...(ngDevMode ? [{ debugName: "quickFilterFields" }] : /* istanbul ignore next */ []));
|
|
15557
|
+
quickFilterFieldsFlat = input(null, { ...(ngDevMode ? { debugName: "quickFilterFieldsFlat" } : /* istanbul ignore next */ {}), alias: 'quickFilterFields' });
|
|
15543
15558
|
/** Render the built-in quick-filter searchbox in the toolbar. */
|
|
15544
|
-
|
|
15559
|
+
quickFilterableFlat = input(false, { ...(ngDevMode ? { debugName: "quickFilterableFlat" } : /* istanbul ignore next */ {}), alias: 'quickFilterable',
|
|
15560
|
+
transform: booleanAttribute });
|
|
15545
15561
|
/**
|
|
15546
15562
|
* Where the built-in box sits in the toolbar. `'end'` (default) follows the
|
|
15547
15563
|
* console convention: action verbs lead on the left, view controls sit at
|
|
15548
15564
|
* the far right — and the box keeps a stable position across grids whose
|
|
15549
15565
|
* button sets differ.
|
|
15550
15566
|
*/
|
|
15551
|
-
|
|
15552
|
-
...(ngDevMode ? [{ debugName: "quickFilterAlign" }] : /* istanbul ignore next */ []));
|
|
15567
|
+
quickFilterAlignFlat = input('end', { ...(ngDevMode ? { debugName: "quickFilterAlignFlat" } : /* istanbul ignore next */ {}), alias: 'quickFilterAlign' });
|
|
15553
15568
|
/**
|
|
15554
15569
|
* Tree-grid: the row property holding a row's children array. Rows render
|
|
15555
15570
|
* hierarchically with indent + carets; sorting applies per sibling level;
|
|
@@ -15562,8 +15577,7 @@ class StrctDatagrid {
|
|
|
15562
15577
|
* ArrowLeft collapses an expanded one. There is no cell-level navigation —
|
|
15563
15578
|
* Tab walks the interactive elements inside each row as usual.
|
|
15564
15579
|
*/
|
|
15565
|
-
|
|
15566
|
-
...(ngDevMode ? [{ debugName: "childrenKey" }] : /* istanbul ignore next */ []));
|
|
15580
|
+
childrenKeyFlat = input(null, { ...(ngDevMode ? { debugName: "childrenKeyFlat" } : /* istanbul ignore next */ {}), alias: 'childrenKey' });
|
|
15567
15581
|
/**
|
|
15568
15582
|
* `'table'` (the default) is what the grid has always been: a table whose
|
|
15569
15583
|
* controls each take a tab stop. `'grid'` is the APG grid: the table claims
|
|
@@ -15582,8 +15596,7 @@ class StrctDatagrid {
|
|
|
15582
15596
|
* file list selects by clicking the row, not a control in it. The row is
|
|
15583
15597
|
* then the control, so pair it with `interactionMode="grid"`.
|
|
15584
15598
|
*/
|
|
15585
|
-
|
|
15586
|
-
...(ngDevMode ? [{ debugName: "selectionColumn" }] : /* istanbul ignore next */ []));
|
|
15599
|
+
selectionColumnFlat = input('auto', { ...(ngDevMode ? { debugName: "selectionColumnFlat" } : /* istanbul ignore next */ {}), alias: 'selectionColumn' });
|
|
15587
15600
|
/**
|
|
15588
15601
|
* The row was opened: a double-click, or Enter on the focused row in grid
|
|
15589
15602
|
* mode. Selection is "which rows do I mean"; activation is "go".
|
|
@@ -15601,6 +15614,193 @@ class StrctDatagrid {
|
|
|
15601
15614
|
* editor). The grid does not mutate rows — apply the value to your data and
|
|
15602
15615
|
* pass the updated array back in. */
|
|
15603
15616
|
cellEdit = output();
|
|
15617
|
+
// ── The feature objects, and the flat inputs they replace ───────────────
|
|
15618
|
+
// Each resolved signal below keeps the name the rest of the component (and
|
|
15619
|
+
// the template) already uses, so the object is read where the flat input
|
|
15620
|
+
// was. The object wins when it carries the property; otherwise the flat
|
|
15621
|
+
// input answers, as it did before 5.30.0.
|
|
15622
|
+
/** How rows are picked — replaces six flat inputs. */
|
|
15623
|
+
selectionCfg = input({}, { ...(ngDevMode ? { debugName: "selectionCfg" } : /* istanbul ignore next */ {}), alias: 'selection' });
|
|
15624
|
+
/** The detail pane — replaces three. `[pane]` on its own turns it on. */
|
|
15625
|
+
paneFlat = input(false, { ...(ngDevMode ? { debugName: "paneFlat" } : /* istanbul ignore next */ {}), alias: 'pane',
|
|
15626
|
+
transform: objectOrBoolean });
|
|
15627
|
+
paneCfg = computed(() => {
|
|
15628
|
+
const v = this.paneFlat();
|
|
15629
|
+
return typeof v === 'boolean' ? (v ? { enabled: true } : {}) : { enabled: true, ...v };
|
|
15630
|
+
}, /* @ts-ignore */
|
|
15631
|
+
...(ngDevMode ? [{ debugName: "paneCfg" }] : /* istanbul ignore next */ []));
|
|
15632
|
+
/** How rows are paged. Takes the mode on its own, as before, or the object. */
|
|
15633
|
+
pagingFlat = input('pages', { ...(ngDevMode ? { debugName: "pagingFlat" } : /* istanbul ignore next */ {}), alias: 'paging' });
|
|
15634
|
+
pagingCfg = computed(() => {
|
|
15635
|
+
const v = this.pagingFlat();
|
|
15636
|
+
return typeof v === 'string' ? { mode: v } : v;
|
|
15637
|
+
}, /* @ts-ignore */
|
|
15638
|
+
...(ngDevMode ? [{ debugName: "pagingCfg" }] : /* istanbul ignore next */ []));
|
|
15639
|
+
/** Numbered pages or a "load more" footer. */
|
|
15640
|
+
paging = computed(() => this.pagingCfg().mode ?? 'pages', /* @ts-ignore */
|
|
15641
|
+
...(ngDevMode ? [{ debugName: "paging" }] : /* istanbul ignore next */ []));
|
|
15642
|
+
/** Virtual scrolling. Takes the flag on its own, as before, or the object. */
|
|
15643
|
+
virtualFlat = input(false, { ...(ngDevMode ? { debugName: "virtualFlat" } : /* istanbul ignore next */ {}), alias: 'virtual', transform: objectOrBoolean });
|
|
15644
|
+
virtualCfg = computed(() => {
|
|
15645
|
+
const v = this.virtualFlat();
|
|
15646
|
+
return typeof v === 'boolean' ? (v ? { enabled: true } : {}) : { enabled: true, ...v };
|
|
15647
|
+
}, /* @ts-ignore */
|
|
15648
|
+
...(ngDevMode ? [{ debugName: "virtualCfg" }] : /* istanbul ignore next */ []));
|
|
15649
|
+
/** Whether the grid renders only the rows in view. */
|
|
15650
|
+
virtual = computed(() => this.virtualCfg().enabled ?? false, /* @ts-ignore */
|
|
15651
|
+
...(ngDevMode ? [{ debugName: "virtual" }] : /* istanbul ignore next */ []));
|
|
15652
|
+
/** How rows are grouped — replaces four flat inputs. */
|
|
15653
|
+
groupingCfg = input({}, { ...(ngDevMode ? { debugName: "groupingCfg" } : /* istanbul ignore next */ {}), alias: 'grouping' });
|
|
15654
|
+
/** The quick filter — replaces three flat inputs. */
|
|
15655
|
+
filteringCfg = input({}, { ...(ngDevMode ? { debugName: "filteringCfg" } : /* istanbul ignore next */ {}), alias: 'filtering' });
|
|
15656
|
+
/** Remembered state — replaces `stateKey` and `sync`. */
|
|
15657
|
+
stateCfg = input({}, { ...(ngDevMode ? { debugName: "stateCfg" } : /* istanbul ignore next */ {}), alias: 'state' });
|
|
15658
|
+
/**
|
|
15659
|
+
* The flat inputs this grid is actually given, with the object each has
|
|
15660
|
+
* moved into. "Given" is read as "not its default", which is what a
|
|
15661
|
+
* template can be checked against from inside the component.
|
|
15662
|
+
*/
|
|
15663
|
+
flatInputsInUse = [
|
|
15664
|
+
['pageSize', () => this.pageSizeFlat() !== 0, '[paging].pageSize'],
|
|
15665
|
+
['selectable', () => this.selectableFlat(), '[selection].enabled'],
|
|
15666
|
+
['detailPane', () => this.detailPaneFlat(), '[pane].enabled'],
|
|
15667
|
+
['paneListWidth', () => this.paneListWidthFlat() !== '260px', '[pane].listWidth'],
|
|
15668
|
+
['paneTakeoverWidth', () => this.paneTakeoverWidthFlat() !== 900, '[pane].takeoverWidth'],
|
|
15669
|
+
['sync', () => this.syncFlat(), '[state].sync'],
|
|
15670
|
+
['selectionMode', () => this.selectionModeFlat() !== 'none', '[selection].mode'],
|
|
15671
|
+
['rowSelectable', () => this.rowSelectableFlat() !== null, '[selection].rowSelectable'],
|
|
15672
|
+
['hasMore', () => this.hasMoreFlat(), '[paging].hasMore'],
|
|
15673
|
+
['loadingMore', () => this.loadingMoreFlat(), '[paging].loadingMore'],
|
|
15674
|
+
['moreTotal', () => this.moreTotalFlat() !== null, '[paging].moreTotal'],
|
|
15675
|
+
['groupSelect', () => this.groupSelectFlat(), '[selection].groupSelect'],
|
|
15676
|
+
['initialSelection', () => this.initialSelectionFlat() !== null, '[selection].initial'],
|
|
15677
|
+
['viewportHeight', () => this.viewportHeightFlat() !== 360, '[virtual].viewportHeight'],
|
|
15678
|
+
['maxHeight', () => this.maxHeightFlat() !== null, '[virtual].maxHeight'],
|
|
15679
|
+
['rowHeight', () => this.rowHeightFlat() !== 38, '[virtual].rowHeight'],
|
|
15680
|
+
['lazy', () => this.lazyFlat(), '[paging].lazy'],
|
|
15681
|
+
['total', () => this.totalFlat() !== null, '[paging].total'],
|
|
15682
|
+
['stateKey', () => this.stateKeyFlat() !== null, '[state].key'],
|
|
15683
|
+
['groupBy', () => this.groupByFlat() !== null, '[grouping].by'],
|
|
15684
|
+
['groups', () => this.groupsFlat() !== null, '[grouping].groups'],
|
|
15685
|
+
['showEmptyGroups', () => this.showEmptyGroupsFlat(), '[grouping].showEmpty'],
|
|
15686
|
+
['quickFilterFields', () => this.quickFilterFieldsFlat() !== null, '[filtering].fields'],
|
|
15687
|
+
['quickFilterable', () => this.quickFilterableFlat(), '[filtering].quick'],
|
|
15688
|
+
['quickFilterAlign', () => this.quickFilterAlignFlat() !== 'end', '[filtering].align'],
|
|
15689
|
+
['childrenKey', () => this.childrenKeyFlat() !== null, '[grouping].childrenKey'],
|
|
15690
|
+
['selectionColumn', () => this.selectionColumnFlat() !== 'auto', '[selection].column'],
|
|
15691
|
+
];
|
|
15692
|
+
/**
|
|
15693
|
+
* Dev mode says, once per app run, which flat inputs have moved — a
|
|
15694
|
+
* console line per name would be a wall in a screen with four grids, so
|
|
15695
|
+
* the names are collected and reported together.
|
|
15696
|
+
*/
|
|
15697
|
+
reportFlatInputs() {
|
|
15698
|
+
const fresh = this.flatInputsInUse
|
|
15699
|
+
.filter(([name, given]) => given() && !warnedFlatInputs.has(name))
|
|
15700
|
+
.map(([name, , to]) => {
|
|
15701
|
+
warnedFlatInputs.add(name);
|
|
15702
|
+
return ` ${name} → ${to}`;
|
|
15703
|
+
});
|
|
15704
|
+
if (!fresh.length)
|
|
15705
|
+
return;
|
|
15706
|
+
for (const line of fresh)
|
|
15707
|
+
pendingFlatInputWarnings.add(line);
|
|
15708
|
+
if (flatInputWarningQueued)
|
|
15709
|
+
return;
|
|
15710
|
+
flatInputWarningQueued = true;
|
|
15711
|
+
setTimeout(() => {
|
|
15712
|
+
flatInputWarningQueued = false;
|
|
15713
|
+
const lines = [...pendingFlatInputWarnings].sort();
|
|
15714
|
+
pendingFlatInputWarnings.clear();
|
|
15715
|
+
console.warn(`[strct-datagrid] ${lines.length} input(s) have moved into a feature ` +
|
|
15716
|
+
`object and are removed in 6.0. They keep working through 5.x:\n` +
|
|
15717
|
+
lines.join('\n') +
|
|
15718
|
+
`\nThe objects are [selection], [paging], [pane], [virtual], ` +
|
|
15719
|
+
`[grouping], [filtering] and [state]; two-way state ` +
|
|
15720
|
+
`(selectedIds, filters, columnState, …) stays where it is.`);
|
|
15721
|
+
});
|
|
15722
|
+
}
|
|
15723
|
+
/** `[paging].pageSize` when it is set, else the flat `pageSize` (deprecated). */
|
|
15724
|
+
pageSize = computed(() => this.pagingCfg().pageSize ?? this.pageSizeFlat(), /* @ts-ignore */
|
|
15725
|
+
...(ngDevMode ? [{ debugName: "pageSize" }] : /* istanbul ignore next */ []));
|
|
15726
|
+
/** `[selection].enabled` when it is set, else the flat `selectable` (deprecated). */
|
|
15727
|
+
selectable = computed(() => this.selectionCfg().enabled ?? this.selectableFlat(), /* @ts-ignore */
|
|
15728
|
+
...(ngDevMode ? [{ debugName: "selectable" }] : /* istanbul ignore next */ []));
|
|
15729
|
+
/** `[pane].enabled` when it is set, else the flat `detailPane` (deprecated). */
|
|
15730
|
+
detailPane = computed(() => this.paneCfg().enabled ?? this.detailPaneFlat(), /* @ts-ignore */
|
|
15731
|
+
...(ngDevMode ? [{ debugName: "detailPane" }] : /* istanbul ignore next */ []));
|
|
15732
|
+
/** `[pane].listWidth` when it is set, else the flat `paneListWidth` (deprecated). */
|
|
15733
|
+
paneListWidth = computed(() => this.paneCfg().listWidth ?? this.paneListWidthFlat(), /* @ts-ignore */
|
|
15734
|
+
...(ngDevMode ? [{ debugName: "paneListWidth" }] : /* istanbul ignore next */ []));
|
|
15735
|
+
/** `[pane].takeoverWidth` when it is set, else the flat `paneTakeoverWidth` (deprecated). */
|
|
15736
|
+
paneTakeoverWidth = computed(() => this.paneCfg().takeoverWidth ?? this.paneTakeoverWidthFlat(), /* @ts-ignore */
|
|
15737
|
+
...(ngDevMode ? [{ debugName: "paneTakeoverWidth" }] : /* istanbul ignore next */ []));
|
|
15738
|
+
/** `[state].sync` when it is set, else the flat `sync` (deprecated). */
|
|
15739
|
+
sync = computed(() => this.stateCfg().sync ?? this.syncFlat(), /* @ts-ignore */
|
|
15740
|
+
...(ngDevMode ? [{ debugName: "sync" }] : /* istanbul ignore next */ []));
|
|
15741
|
+
/** `[selection].mode` when it is set, else the flat `selectionMode` (deprecated). */
|
|
15742
|
+
selectionMode = computed(() => this.selectionCfg().mode ?? this.selectionModeFlat(), /* @ts-ignore */
|
|
15743
|
+
...(ngDevMode ? [{ debugName: "selectionMode" }] : /* istanbul ignore next */ []));
|
|
15744
|
+
/** `[selection].rowSelectable` when it is set, else the flat `rowSelectable` (deprecated). */
|
|
15745
|
+
rowSelectable = computed(() => this.selectionCfg().rowSelectable ?? this.rowSelectableFlat(), /* @ts-ignore */
|
|
15746
|
+
...(ngDevMode ? [{ debugName: "rowSelectable" }] : /* istanbul ignore next */ []));
|
|
15747
|
+
/** `[paging].hasMore` when it is set, else the flat `hasMore` (deprecated). */
|
|
15748
|
+
hasMore = computed(() => this.pagingCfg().hasMore ?? this.hasMoreFlat(), /* @ts-ignore */
|
|
15749
|
+
...(ngDevMode ? [{ debugName: "hasMore" }] : /* istanbul ignore next */ []));
|
|
15750
|
+
/** `[paging].loadingMore` when it is set, else the flat `loadingMore` (deprecated). */
|
|
15751
|
+
loadingMore = computed(() => this.pagingCfg().loadingMore ?? this.loadingMoreFlat(), /* @ts-ignore */
|
|
15752
|
+
...(ngDevMode ? [{ debugName: "loadingMore" }] : /* istanbul ignore next */ []));
|
|
15753
|
+
/** `[paging].moreTotal` when it is set, else the flat `moreTotal` (deprecated). */
|
|
15754
|
+
moreTotal = computed(() => this.pagingCfg().moreTotal ?? this.moreTotalFlat(), /* @ts-ignore */
|
|
15755
|
+
...(ngDevMode ? [{ debugName: "moreTotal" }] : /* istanbul ignore next */ []));
|
|
15756
|
+
/** `[selection].groupSelect` when it is set, else the flat `groupSelect` (deprecated). */
|
|
15757
|
+
groupSelect = computed(() => this.selectionCfg().groupSelect ?? this.groupSelectFlat(), /* @ts-ignore */
|
|
15758
|
+
...(ngDevMode ? [{ debugName: "groupSelect" }] : /* istanbul ignore next */ []));
|
|
15759
|
+
/** `[selection].initial` when it is set, else the flat `initialSelection` (deprecated). */
|
|
15760
|
+
initialSelection = computed(() => this.selectionCfg().initial ?? this.initialSelectionFlat(), /* @ts-ignore */
|
|
15761
|
+
...(ngDevMode ? [{ debugName: "initialSelection" }] : /* istanbul ignore next */ []));
|
|
15762
|
+
/** `[virtual].viewportHeight` when it is set, else the flat `viewportHeight` (deprecated). */
|
|
15763
|
+
viewportHeight = computed(() => this.virtualCfg().viewportHeight ?? this.viewportHeightFlat(), /* @ts-ignore */
|
|
15764
|
+
...(ngDevMode ? [{ debugName: "viewportHeight" }] : /* istanbul ignore next */ []));
|
|
15765
|
+
/** `[virtual].maxHeight` when it is set, else the flat `maxHeight` (deprecated). */
|
|
15766
|
+
maxHeight = computed(() => this.virtualCfg().maxHeight ?? this.maxHeightFlat(), /* @ts-ignore */
|
|
15767
|
+
...(ngDevMode ? [{ debugName: "maxHeight" }] : /* istanbul ignore next */ []));
|
|
15768
|
+
/** `[virtual].rowHeight` when it is set, else the flat `rowHeight` (deprecated). */
|
|
15769
|
+
rowHeight = computed(() => this.virtualCfg().rowHeight ?? this.rowHeightFlat(), /* @ts-ignore */
|
|
15770
|
+
...(ngDevMode ? [{ debugName: "rowHeight" }] : /* istanbul ignore next */ []));
|
|
15771
|
+
/** `[paging].lazy` when it is set, else the flat `lazy` (deprecated). */
|
|
15772
|
+
lazy = computed(() => this.pagingCfg().lazy ?? this.lazyFlat(), /* @ts-ignore */
|
|
15773
|
+
...(ngDevMode ? [{ debugName: "lazy" }] : /* istanbul ignore next */ []));
|
|
15774
|
+
/** `[paging].total` when it is set, else the flat `total` (deprecated). */
|
|
15775
|
+
total = computed(() => this.pagingCfg().total ?? this.totalFlat(), /* @ts-ignore */
|
|
15776
|
+
...(ngDevMode ? [{ debugName: "total" }] : /* istanbul ignore next */ []));
|
|
15777
|
+
/** `[state].key` when it is set, else the flat `stateKey` (deprecated). */
|
|
15778
|
+
stateKey = computed(() => this.stateCfg().key ?? this.stateKeyFlat(), /* @ts-ignore */
|
|
15779
|
+
...(ngDevMode ? [{ debugName: "stateKey" }] : /* istanbul ignore next */ []));
|
|
15780
|
+
/** `[grouping].by` when it is set, else the flat `groupBy` (deprecated). */
|
|
15781
|
+
groupBy = computed(() => this.groupingCfg().by ?? this.groupByFlat(), /* @ts-ignore */
|
|
15782
|
+
...(ngDevMode ? [{ debugName: "groupBy" }] : /* istanbul ignore next */ []));
|
|
15783
|
+
/** `[grouping].groups` when it is set, else the flat `groups` (deprecated). */
|
|
15784
|
+
groups = computed(() => this.groupingCfg().groups ?? this.groupsFlat(), /* @ts-ignore */
|
|
15785
|
+
...(ngDevMode ? [{ debugName: "groups" }] : /* istanbul ignore next */ []));
|
|
15786
|
+
/** `[grouping].showEmpty` when it is set, else the flat `showEmptyGroups` (deprecated). */
|
|
15787
|
+
showEmptyGroups = computed(() => this.groupingCfg().showEmpty ?? this.showEmptyGroupsFlat(), /* @ts-ignore */
|
|
15788
|
+
...(ngDevMode ? [{ debugName: "showEmptyGroups" }] : /* istanbul ignore next */ []));
|
|
15789
|
+
/** `[filtering].fields` when it is set, else the flat `quickFilterFields` (deprecated). */
|
|
15790
|
+
quickFilterFields = computed(() => this.filteringCfg().fields ?? this.quickFilterFieldsFlat(), /* @ts-ignore */
|
|
15791
|
+
...(ngDevMode ? [{ debugName: "quickFilterFields" }] : /* istanbul ignore next */ []));
|
|
15792
|
+
/** `[filtering].quick` when it is set, else the flat `quickFilterable` (deprecated). */
|
|
15793
|
+
quickFilterable = computed(() => this.filteringCfg().quick ?? this.quickFilterableFlat(), /* @ts-ignore */
|
|
15794
|
+
...(ngDevMode ? [{ debugName: "quickFilterable" }] : /* istanbul ignore next */ []));
|
|
15795
|
+
/** `[filtering].align` when it is set, else the flat `quickFilterAlign` (deprecated). */
|
|
15796
|
+
quickFilterAlign = computed(() => this.filteringCfg().align ?? this.quickFilterAlignFlat(), /* @ts-ignore */
|
|
15797
|
+
...(ngDevMode ? [{ debugName: "quickFilterAlign" }] : /* istanbul ignore next */ []));
|
|
15798
|
+
/** `[grouping].childrenKey` when it is set, else the flat `childrenKey` (deprecated). */
|
|
15799
|
+
childrenKey = computed(() => this.groupingCfg().childrenKey ?? this.childrenKeyFlat(), /* @ts-ignore */
|
|
15800
|
+
...(ngDevMode ? [{ debugName: "childrenKey" }] : /* istanbul ignore next */ []));
|
|
15801
|
+
/** `[selection].column` when it is set, else the flat `selectionColumn` (deprecated). */
|
|
15802
|
+
selectionColumn = computed(() => this.selectionCfg().column ?? this.selectionColumnFlat(), /* @ts-ignore */
|
|
15803
|
+
...(ngDevMode ? [{ debugName: "selectionColumn" }] : /* istanbul ignore next */ []));
|
|
15604
15804
|
menu = inject(StrctMenuService);
|
|
15605
15805
|
detailDef = contentChild(StrctRowDetailDef, /* @ts-ignore */
|
|
15606
15806
|
...(ngDevMode ? [{ debugName: "detailDef" }] : /* istanbul ignore next */ []));
|
|
@@ -17108,6 +17308,12 @@ class StrctDatagrid {
|
|
|
17108
17308
|
this.lazyLoad.emit(state);
|
|
17109
17309
|
});
|
|
17110
17310
|
});
|
|
17311
|
+
// The inputs are bound by the first render, so this is where they can be
|
|
17312
|
+
// read and reported.
|
|
17313
|
+
afterNextRender(() => {
|
|
17314
|
+
if (typeof ngDevMode !== 'undefined' && ngDevMode)
|
|
17315
|
+
this.reportFlatInputs();
|
|
17316
|
+
});
|
|
17111
17317
|
// Below `paneTakeoverWidth` the pane replaces the list. The grid's own
|
|
17112
17318
|
// width decides, not the viewport: the same grid is wide in a page and
|
|
17113
17319
|
// narrow in a drawer.
|
|
@@ -17612,796 +17818,7 @@ class StrctDatagrid {
|
|
|
17612
17818
|
return String(a ?? '').localeCompare(String(b ?? ''), undefined, { numeric: true });
|
|
17613
17819
|
}
|
|
17614
17820
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctDatagrid, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
17615
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.4", type: StrctDatagrid, isStandalone: true, selector: "strct-datagrid", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: true, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, selectable: { classPropertyName: "selectable", publicName: "selectable", isSignal: true, isRequired: false, transformFunction: null }, expandable: { classPropertyName: "expandable", publicName: "expandable", isSignal: true, isRequired: false, transformFunction: null }, detailPane: { classPropertyName: "detailPane", publicName: "detailPane", isSignal: true, isRequired: false, transformFunction: null }, paneListWidth: { classPropertyName: "paneListWidth", publicName: "paneListWidth", isSignal: true, isRequired: false, transformFunction: null }, paneTakeoverWidth: { classPropertyName: "paneTakeoverWidth", publicName: "paneTakeoverWidth", isSignal: true, isRequired: false, transformFunction: null }, activeRowId: { classPropertyName: "activeRowId", publicName: "activeRowId", isSignal: true, isRequired: false, transformFunction: null }, compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null }, singleLine: { classPropertyName: "singleLine", publicName: "singleLine", isSignal: true, isRequired: false, transformFunction: null }, emptyText: { classPropertyName: "emptyText", publicName: "emptyText", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, resizable: { classPropertyName: "resizable", publicName: "resizable", isSignal: true, isRequired: false, transformFunction: null }, columnChooser: { classPropertyName: "columnChooser", publicName: "columnChooser", isSignal: true, isRequired: false, transformFunction: null }, sync: { classPropertyName: "sync", publicName: "sync", isSignal: true, isRequired: false, transformFunction: null }, footerActionsDisabled: { classPropertyName: "footerActionsDisabled", publicName: "footerActionsDisabled", isSignal: true, isRequired: false, transformFunction: null }, rowId: { classPropertyName: "rowId", publicName: "rowId", isSignal: true, isRequired: false, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, selectedId: { classPropertyName: "selectedId", publicName: "selectedId", isSignal: true, isRequired: false, transformFunction: null }, rowSelectable: { classPropertyName: "rowSelectable", publicName: "rowSelectable", isSignal: true, isRequired: false, transformFunction: null }, flush: { classPropertyName: "flush", publicName: "flush", isSignal: true, isRequired: false, transformFunction: null }, caption: { classPropertyName: "caption", publicName: "caption", isSignal: true, isRequired: false, transformFunction: null }, paging: { classPropertyName: "paging", publicName: "paging", isSignal: true, isRequired: false, transformFunction: null }, hasMore: { classPropertyName: "hasMore", publicName: "hasMore", isSignal: true, isRequired: false, transformFunction: null }, loadingMore: { classPropertyName: "loadingMore", publicName: "loadingMore", isSignal: true, isRequired: false, transformFunction: null }, moreTotal: { classPropertyName: "moreTotal", publicName: "moreTotal", isSignal: true, isRequired: false, transformFunction: null }, groupSelect: { classPropertyName: "groupSelect", publicName: "groupSelect", isSignal: true, isRequired: false, transformFunction: null }, rowActions: { classPropertyName: "rowActions", publicName: "rowActions", isSignal: true, isRequired: false, transformFunction: null }, initialSelection: { classPropertyName: "initialSelection", publicName: "initialSelection", isSignal: true, isRequired: false, transformFunction: null }, selectedIds: { classPropertyName: "selectedIds", publicName: "selectedIds", isSignal: true, isRequired: false, transformFunction: null }, labels: { classPropertyName: "labels", publicName: "labels", isSignal: true, isRequired: false, transformFunction: null }, virtual: { classPropertyName: "virtual", publicName: "virtual", isSignal: true, isRequired: false, transformFunction: null }, viewportHeight: { classPropertyName: "viewportHeight", publicName: "viewportHeight", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, editHint: { classPropertyName: "editHint", publicName: "editHint", isSignal: true, isRequired: false, transformFunction: null }, rowHeight: { classPropertyName: "rowHeight", publicName: "rowHeight", isSignal: true, isRequired: false, transformFunction: null }, lazy: { classPropertyName: "lazy", publicName: "lazy", isSignal: true, isRequired: false, transformFunction: null }, total: { classPropertyName: "total", publicName: "total", isSignal: true, isRequired: false, transformFunction: null }, stateKey: { classPropertyName: "stateKey", publicName: "stateKey", isSignal: true, isRequired: false, transformFunction: null }, columnState: { classPropertyName: "columnState", publicName: "columnState", isSignal: true, isRequired: false, transformFunction: null }, reorderable: { classPropertyName: "reorderable", publicName: "reorderable", isSignal: true, isRequired: false, transformFunction: null }, groupBy: { classPropertyName: "groupBy", publicName: "groupBy", isSignal: true, isRequired: false, transformFunction: null }, groups: { classPropertyName: "groups", publicName: "groups", isSignal: true, isRequired: false, transformFunction: null }, showEmptyGroups: { classPropertyName: "showEmptyGroups", publicName: "showEmptyGroups", isSignal: true, isRequired: false, transformFunction: null }, collapsedGroups: { classPropertyName: "collapsedGroups", publicName: "collapsedGroups", isSignal: true, isRequired: false, transformFunction: null }, filters: { classPropertyName: "filters", publicName: "filters", isSignal: true, isRequired: false, transformFunction: null }, quickFilter: { classPropertyName: "quickFilter", publicName: "quickFilter", isSignal: true, isRequired: false, transformFunction: null }, quickFilterFields: { classPropertyName: "quickFilterFields", publicName: "quickFilterFields", isSignal: true, isRequired: false, transformFunction: null }, quickFilterable: { classPropertyName: "quickFilterable", publicName: "quickFilterable", isSignal: true, isRequired: false, transformFunction: null }, quickFilterAlign: { classPropertyName: "quickFilterAlign", publicName: "quickFilterAlign", isSignal: true, isRequired: false, transformFunction: null }, childrenKey: { classPropertyName: "childrenKey", publicName: "childrenKey", isSignal: true, isRequired: false, transformFunction: null }, interactionMode: { classPropertyName: "interactionMode", publicName: "interactionMode", isSignal: true, isRequired: false, transformFunction: null }, selectionColumn: { classPropertyName: "selectionColumn", publicName: "selectionColumn", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeRowId: "activeRowIdChange", selectedId: "selectedIdChange", loadMore: "loadMore", selectedIds: "selectedIdsChange", columnState: "columnStateChange", collapsedGroups: "collapsedGroupsChange", filters: "filtersChange", quickFilter: "quickFilterChange", rowActivate: "rowActivate", selectionChange: "selectionChange", syncChange: "syncChange", rowAction: "rowAction", lazyLoad: "lazyLoad", cellEdit: "cellEdit" }, host: { listeners: { "document:click": "onDocClickOverlays($event)", "document:keydown.escape": "onEscapeOverlays($event)" }, properties: { "attr.aria-busy": "loading() || loadingMore() ? \"true\" : null", "class.strct-dg-host--compact": "compact()", "class.strct-dg-host--singleline": "singleLine()", "class.strct-dg-host--virtual": "virtual()", "class.strct-dg-host--bounded": "!virtual() && maxHeight() !== null", "class.strct-dg-host--sticky": "stickyActive()", "class.strct-dg-host--flush": "flush()" }, classAttribute: "strct-dg-host" }, queries: [{ propertyName: "detailDef", first: true, predicate: StrctRowDetailDef, descendants: true, isSignal: true }, { propertyName: "groupHeaderDef", first: true, predicate: StrctGroupHeaderDef, descendants: true, isSignal: true }, { propertyName: "paneTitleDef", first: true, predicate: StrctDetailPaneTitle, descendants: true, isSignal: true }, { propertyName: "actionBarDef", first: true, predicate: StrctDatagridActionBar, descendants: true, isSignal: true }, { propertyName: "actionBarCaptionDef", first: true, predicate: StrctDatagridActionBarCaption, descendants: true, isSignal: true }, { propertyName: "cellDefs", predicate: StrctCellDef, isSignal: true }], ngImport: i0, template: `
|
|
17616
|
-
<!-- One polite region for everything the grid does to itself: sorting,
|
|
17617
|
-
paging and filtering all change the rows without saying so. -->
|
|
17618
|
-
<span class="strct-dg__announcer" role="status" aria-live="polite">{{ announcement() }}</span>
|
|
17619
|
-
@if (actionBarDef() || quickFilterable() || actionBarCaptionDef()) {
|
|
17620
|
-
<div class="strct-dg__toolbar">
|
|
17621
|
-
@if (quickFilterable()) {
|
|
17622
|
-
<strct-searchbox
|
|
17623
|
-
class="strct-dg__quickfilter"
|
|
17624
|
-
[class.strct-dg__quickfilter--end]="quickFilterAlign() === 'end'"
|
|
17625
|
-
[placeholder]="L().quickFilter"
|
|
17626
|
-
[ariaLabel]="L().quickFilter"
|
|
17627
|
-
[value]="quickFilter()"
|
|
17628
|
-
(valueChange)="quickFilter.set($event)"
|
|
17629
|
-
/>
|
|
17630
|
-
@if (filterNote(); as note) {
|
|
17631
|
-
<span
|
|
17632
|
-
class="strct-dg__filternote"
|
|
17633
|
-
[class.strct-dg__filternote--end]="quickFilterAlign() === 'end'"
|
|
17634
|
-
>{{ note }}</span
|
|
17635
|
-
>
|
|
17636
|
-
}
|
|
17637
|
-
}
|
|
17638
|
-
<span class="strct-dg__actioncaption">
|
|
17639
|
-
<ng-content select="[strctDatagridActionBarCaption]" />
|
|
17640
|
-
</span>
|
|
17641
|
-
<ng-content select="[strctDatagridActionBar]" />
|
|
17642
|
-
</div>
|
|
17643
|
-
}
|
|
17644
|
-
|
|
17645
|
-
@if (hasEditableColumn()) {
|
|
17646
|
-
<!-- What the editable cells point at with aria-describedby: a keyboard
|
|
17647
|
-
user is told the cell can be edited, and how. -->
|
|
17648
|
-
<!-- In flow, not absolutely positioned: an out-of-flow box whose
|
|
17649
|
-
containing block is the page extends the document's scrollable area
|
|
17650
|
-
from wherever the grid happens to sit. 1x1 and clipped is enough. -->
|
|
17651
|
-
<span
|
|
17652
|
-
class="strct-sr-only"
|
|
17653
|
-
style="display: inline-block; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap"
|
|
17654
|
-
[id]="editHintId"
|
|
17655
|
-
>{{ L().editCellInstructions }}</span
|
|
17656
|
-
>
|
|
17657
|
-
}
|
|
17658
|
-
|
|
17659
|
-
@if (bulkHint(); as hint) {
|
|
17660
|
-
<!-- Selecting the page is not selecting the set. Say which one happened,
|
|
17661
|
-
and offer the other. -->
|
|
17662
|
-
<div class="strct-dg__bulk" role="status">
|
|
17663
|
-
<span>{{ hint.text }}</span>
|
|
17664
|
-
<button strct-button variant="flat" size="sm" (click)="hint.run()">
|
|
17665
|
-
{{ hint.action }}
|
|
17666
|
-
</button>
|
|
17667
|
-
</div>
|
|
17668
|
-
}
|
|
17669
|
-
<div
|
|
17670
|
-
class="strct-dg__layout"
|
|
17671
|
-
[class.strct-dg__layout--paned]="paneOpen()"
|
|
17672
|
-
[class.strct-dg__layout--panetakeover]="paneOpen() && narrowPane()"
|
|
17673
|
-
[style.--strct-dg-pane-list-w]="paneListWidth()"
|
|
17674
|
-
>
|
|
17675
|
-
<div
|
|
17676
|
-
class="strct-dg__scroll"
|
|
17677
|
-
tabindex="0"
|
|
17678
|
-
role="region"
|
|
17679
|
-
[attr.aria-label]="L().rows"
|
|
17680
|
-
[style.max-height.px]="virtual() ? viewportHeight() : maxHeight()"
|
|
17681
|
-
(scroll)="virtual() && onScroll($event)"
|
|
17682
|
-
>
|
|
17683
|
-
<table
|
|
17684
|
-
class="strct-dg"
|
|
17685
|
-
[attr.role]="childrenKey() ? 'treegrid' : gridMode() ? 'grid' : null"
|
|
17686
|
-
[attr.aria-rowcount]="ariaRowCount()"
|
|
17687
|
-
[attr.aria-labelledby]="caption() ? captionId : null"
|
|
17688
|
-
>
|
|
17689
|
-
@if (caption()) {
|
|
17690
|
-
<caption class="strct-dg__caption" [id]="captionId">
|
|
17691
|
-
{{
|
|
17692
|
-
caption()
|
|
17693
|
-
}}
|
|
17694
|
-
</caption>
|
|
17695
|
-
}
|
|
17696
|
-
<thead>
|
|
17697
|
-
<tr>
|
|
17698
|
-
<!-- A utility column is still a column: axe reports every empty
|
|
17699
|
-
header, and a screen-reader user hears nothing where the
|
|
17700
|
-
detail, expand and select controls are. The name is hidden,
|
|
17701
|
-
not absent. -->
|
|
17702
|
-
@if (canDetail()) {
|
|
17703
|
-
<th
|
|
17704
|
-
class="strct-dg__expandcol"
|
|
17705
|
-
scope="col"
|
|
17706
|
-
[class.strct-dg__cell--sticky]="stickyActive()"
|
|
17707
|
-
[style.insetInlineStart.px]="utilLeft('detail')"
|
|
17708
|
-
>
|
|
17709
|
-
<span class="strct-sr-only">{{ L().detailColumn }}</span>
|
|
17710
|
-
</th>
|
|
17711
|
-
}
|
|
17712
|
-
@if (canExpand()) {
|
|
17713
|
-
<th
|
|
17714
|
-
class="strct-dg__expandcol"
|
|
17715
|
-
scope="col"
|
|
17716
|
-
[class.strct-dg__cell--sticky]="stickyActive()"
|
|
17717
|
-
[style.insetInlineStart.px]="utilLeft('expand')"
|
|
17718
|
-
>
|
|
17719
|
-
<span class="strct-sr-only">{{ L().expandColumn }}</span>
|
|
17720
|
-
</th>
|
|
17721
|
-
}
|
|
17722
|
-
@if (hasSelectionColumn()) {
|
|
17723
|
-
<th
|
|
17724
|
-
class="strct-dg__sel"
|
|
17725
|
-
scope="col"
|
|
17726
|
-
[class.strct-dg__cell--sticky]="stickyActive()"
|
|
17727
|
-
[style.insetInlineStart.px]="utilLeft('sel')"
|
|
17728
|
-
>
|
|
17729
|
-
@if (mode() === 'multiple') {
|
|
17730
|
-
<strct-checkbox
|
|
17731
|
-
[ariaLabel]="L().selectAll"
|
|
17732
|
-
[checked]="allPageSelected()"
|
|
17733
|
-
[indeterminate]="somePageSelected()"
|
|
17734
|
-
(checkedChange)="toggleAll()"
|
|
17735
|
-
/>
|
|
17736
|
-
} @else {
|
|
17737
|
-
<span class="strct-sr-only">{{ L().selectColumn }}</span>
|
|
17738
|
-
}
|
|
17739
|
-
</th>
|
|
17740
|
-
}
|
|
17741
|
-
@for (col of visibleColumns(); track col.key) {
|
|
17742
|
-
<th
|
|
17743
|
-
scope="col"
|
|
17744
|
-
[style.text-align]="col.align ?? (col.numeric ? 'end' : 'start')"
|
|
17745
|
-
[style.width]="colWidth(col.key) ?? col.width ?? null"
|
|
17746
|
-
[class.strct-dg__th--sortable]="col.sortable"
|
|
17747
|
-
[class.strct-dg__th--drop]="col.key === dropKey()"
|
|
17748
|
-
[class.strct-dg__cell--sticky]="isSticky(col)"
|
|
17749
|
-
[class.strct-dg__cell--sticky-last]="col.key === lastStickyKey()"
|
|
17750
|
-
[style.insetInlineStart.px]="stickyLeft(col.key)"
|
|
17751
|
-
[attr.data-col]="col.key"
|
|
17752
|
-
[attr.aria-sort]="col.sortable ? ariaSort(col.key) : null"
|
|
17753
|
-
[attr.draggable]="reorderable() ? true : null"
|
|
17754
|
-
(dragstart)="onColDragStart(col.key, $event)"
|
|
17755
|
-
(dragover)="onColDragOver(col.key, $event)"
|
|
17756
|
-
(drop)="onColDrop(col.key)"
|
|
17757
|
-
(dragend)="onColDragEnd()"
|
|
17758
|
-
>
|
|
17759
|
-
<span class="strct-dg__hd">
|
|
17760
|
-
<!-- A header that sorts is a button: a th with tabindex is
|
|
17761
|
-
read as "column header, focusable" and never says it
|
|
17762
|
-
can be activated. aria-sort stays on the th, which is
|
|
17763
|
-
what carries the column's sorted state. -->
|
|
17764
|
-
@if (col.sortable) {
|
|
17765
|
-
<!-- The button covers most of the header, so it carries
|
|
17766
|
-
the drag source too: a reorderable column has to be
|
|
17767
|
-
grabbable where the pointer actually lands. The
|
|
17768
|
-
event bubbles to the th's own handlers. -->
|
|
17769
|
-
<button
|
|
17770
|
-
type="button"
|
|
17771
|
-
class="strct-dg__sortbtn"
|
|
17772
|
-
[attr.draggable]="reorderable() ? true : null"
|
|
17773
|
-
(click)="sortBy(col.key)"
|
|
17774
|
-
>
|
|
17775
|
-
{{ col.label }}
|
|
17776
|
-
<strct-icon
|
|
17777
|
-
class="strct-dg__sorticon"
|
|
17778
|
-
[name]="sortIcon(col.key)"
|
|
17779
|
-
[size]="13"
|
|
17780
|
-
/>
|
|
17781
|
-
</button>
|
|
17782
|
-
} @else {
|
|
17783
|
-
{{ col.label }}
|
|
17784
|
-
}
|
|
17785
|
-
@if (col.filterable || col.filterOptions) {
|
|
17786
|
-
<button
|
|
17787
|
-
#fbtn
|
|
17788
|
-
type="button"
|
|
17789
|
-
class="strct-dg__filterbtn"
|
|
17790
|
-
[class.strct-dg__filterbtn--active]="hasFilter(col.key)"
|
|
17791
|
-
[attr.aria-expanded]="filterOpenKey() === col.key"
|
|
17792
|
-
[attr.aria-label]="L().filterColumn + ': ' + col.label"
|
|
17793
|
-
(click)="toggleFilterPanel(col.key, $event)"
|
|
17794
|
-
(keydown.enter)="$event.stopPropagation()"
|
|
17795
|
-
(keydown.space)="$event.stopPropagation()"
|
|
17796
|
-
>
|
|
17797
|
-
<strct-icon name="filter" [size]="12" />
|
|
17798
|
-
</button>
|
|
17799
|
-
@if (filterOpenKey() === col.key) {
|
|
17800
|
-
<div
|
|
17801
|
-
class="strct-dg__filterpanel"
|
|
17802
|
-
role="dialog"
|
|
17803
|
-
[attr.aria-label]="L().filterColumn + ': ' + col.label"
|
|
17804
|
-
[strctOverlay]="fbtn"
|
|
17805
|
-
strctOverlayPlacement="bottom-start"
|
|
17806
|
-
(click)="$event.stopPropagation()"
|
|
17807
|
-
(keydown.enter)="$event.stopPropagation()"
|
|
17808
|
-
(keydown.space)="$event.stopPropagation()"
|
|
17809
|
-
>
|
|
17810
|
-
@if (col.filterOptions; as opts) {
|
|
17811
|
-
@for (opt of opts; track $index) {
|
|
17812
|
-
<label class="strct-dg__filteropt">
|
|
17813
|
-
<input
|
|
17814
|
-
type="checkbox"
|
|
17815
|
-
[checked]="optionChecked(col.key, opt)"
|
|
17816
|
-
(change)="toggleFilterOption(col.key, opt)"
|
|
17817
|
-
/>
|
|
17818
|
-
<span>{{ opt }}</span>
|
|
17819
|
-
</label>
|
|
17820
|
-
}
|
|
17821
|
-
} @else {
|
|
17822
|
-
<input
|
|
17823
|
-
class="strct-dg__filterinput"
|
|
17824
|
-
type="text"
|
|
17825
|
-
[attr.placeholder]="L().filterPlaceholder"
|
|
17826
|
-
[attr.aria-label]="L().filterColumn + ': ' + col.label"
|
|
17827
|
-
[value]="textFilter(col.key)"
|
|
17828
|
-
(input)="setTextFilter(col.key, $any($event.target).value)"
|
|
17829
|
-
/>
|
|
17830
|
-
}
|
|
17831
|
-
<button
|
|
17832
|
-
type="button"
|
|
17833
|
-
class="strct-dg__filterclear"
|
|
17834
|
-
[disabled]="!hasFilter(col.key)"
|
|
17835
|
-
(click)="clearFilter(col.key)"
|
|
17836
|
-
>
|
|
17837
|
-
{{ L().clearFilter }}
|
|
17838
|
-
</button>
|
|
17839
|
-
</div>
|
|
17840
|
-
}
|
|
17841
|
-
}
|
|
17842
|
-
</span>
|
|
17843
|
-
@if (resizable() && col.resizable !== false) {
|
|
17844
|
-
<!-- A separator, not a bare div: a column could only be
|
|
17845
|
-
resized with a mouse, which is the one input a
|
|
17846
|
-
console cannot assume. -->
|
|
17847
|
-
<div
|
|
17848
|
-
class="strct-dg__resize"
|
|
17849
|
-
role="separator"
|
|
17850
|
-
aria-orientation="vertical"
|
|
17851
|
-
tabindex="0"
|
|
17852
|
-
[attr.aria-label]="L().resizeColumn(col.label)"
|
|
17853
|
-
[attr.aria-valuenow]="separatorValue(col.key)"
|
|
17854
|
-
[attr.aria-valuemin]="40"
|
|
17855
|
-
(mousedown)="onResizeStart($event, col.key)"
|
|
17856
|
-
(keydown)="onResizeKey($event, col.key)"
|
|
17857
|
-
(dblclick)="resetWidth(col.key)"
|
|
17858
|
-
></div>
|
|
17859
|
-
}
|
|
17860
|
-
</th>
|
|
17861
|
-
}
|
|
17862
|
-
@if (canActions()) {
|
|
17863
|
-
<th class="strct-dg__actioncol" scope="col" [attr.aria-label]="L().actions"></th>
|
|
17864
|
-
}
|
|
17865
|
-
</tr>
|
|
17866
|
-
</thead>
|
|
17867
|
-
<!--
|
|
17868
|
-
focusin is the real keyboard path (focus does not bubble from cells);
|
|
17869
|
-
the plain focus binding exists to satisfy mouse-events-have-key-events.
|
|
17870
|
-
-->
|
|
17871
|
-
<tbody
|
|
17872
|
-
(mouseover)="revealIfClipped($event)"
|
|
17873
|
-
(focusin)="revealIfClipped($event)"
|
|
17874
|
-
(focus)="revealIfClipped($event)"
|
|
17875
|
-
>
|
|
17876
|
-
@if (loading()) {
|
|
17877
|
-
@for (_ of [1, 2, 3, 4, 5]; track $index) {
|
|
17878
|
-
<tr class="strct-dg__skeleton-row">
|
|
17879
|
-
@if (canDetail()) {
|
|
17880
|
-
<td class="strct-dg__expandcell"></td>
|
|
17881
|
-
}
|
|
17882
|
-
@if (canExpand()) {
|
|
17883
|
-
<td class="strct-dg__expandcell"></td>
|
|
17884
|
-
}
|
|
17885
|
-
@if (hasSelectionColumn()) {
|
|
17886
|
-
<td class="strct-dg__sel"></td>
|
|
17887
|
-
}
|
|
17888
|
-
@for (col of visibleColumns(); track col.key) {
|
|
17889
|
-
<td [style.text-align]="col.align ?? 'start'">
|
|
17890
|
-
<div class="strct-dg__skeleton-block"></div>
|
|
17891
|
-
</td>
|
|
17892
|
-
}
|
|
17893
|
-
@if (canActions()) {
|
|
17894
|
-
<td class="strct-dg__actioncell"></td>
|
|
17895
|
-
}
|
|
17896
|
-
</tr>
|
|
17897
|
-
}
|
|
17898
|
-
} @else {
|
|
17899
|
-
@if (virtual() && topPad() > 0) {
|
|
17900
|
-
<tr class="strct-dg__vspacer" aria-hidden="true">
|
|
17901
|
-
<td [attr.colspan]="colspan()" [style.height.px]="topPad()"></td>
|
|
17902
|
-
</tr>
|
|
17903
|
-
}
|
|
17904
|
-
@for (it of displayItems(); track itemKey(it)) {
|
|
17905
|
-
@if (it.group; as grp) {
|
|
17906
|
-
<!-- Group header: distinct value + count, collapsible. -->
|
|
17907
|
-
<tr class="strct-dg__grouprow">
|
|
17908
|
-
@if (groupSelect() && mode() === 'multiple') {
|
|
17909
|
-
<td class="strct-dg__sel">
|
|
17910
|
-
<strct-checkbox
|
|
17911
|
-
[ariaLabel]="L().selectAllInGroup(grp.label)"
|
|
17912
|
-
[checked]="groupAllSelected(grp.key)"
|
|
17913
|
-
[indeterminate]="groupSomeSelected(grp.key)"
|
|
17914
|
-
(checkedChange)="toggleGroupSelection(grp.key)"
|
|
17915
|
-
/>
|
|
17916
|
-
</td>
|
|
17917
|
-
}
|
|
17918
|
-
<td
|
|
17919
|
-
[attr.colspan]="
|
|
17920
|
-
groupSelect() && mode() === 'multiple' ? colspan() - 1 : colspan()
|
|
17921
|
-
"
|
|
17922
|
-
>
|
|
17923
|
-
<button
|
|
17924
|
-
type="button"
|
|
17925
|
-
class="strct-dg__groupbtn"
|
|
17926
|
-
[attr.aria-expanded]="!grp.collapsed"
|
|
17927
|
-
(click)="toggleGroup(grp.key)"
|
|
17928
|
-
>
|
|
17929
|
-
<span
|
|
17930
|
-
class="strct-dg__groupchev"
|
|
17931
|
-
[class.strct-dg__groupchev--open]="!grp.collapsed"
|
|
17932
|
-
>
|
|
17933
|
-
<strct-icon name="chevronRight" [size]="12" [strokeWidth]="1.7" />
|
|
17934
|
-
</span>
|
|
17935
|
-
@if (groupHeaderDef(); as tpl) {
|
|
17936
|
-
<!-- The consumer draws the row; the button, its
|
|
17937
|
-
aria-expanded and the keyboard stay ours. -->
|
|
17938
|
-
<ng-container
|
|
17939
|
-
[ngTemplateOutlet]="tpl.template"
|
|
17940
|
-
[ngTemplateOutletContext]="{
|
|
17941
|
-
$implicit: grp,
|
|
17942
|
-
group: grp,
|
|
17943
|
-
count: grp.count,
|
|
17944
|
-
}"
|
|
17945
|
-
/>
|
|
17946
|
-
} @else {
|
|
17947
|
-
<span
|
|
17948
|
-
class="strct-dg__grouplabel strct-dg__grouplabel--{{
|
|
17949
|
-
grp.status ?? 'none'
|
|
17950
|
-
}}"
|
|
17951
|
-
>{{ grp.label }}</span
|
|
17952
|
-
>
|
|
17953
|
-
<!-- The three spans run together in the button's
|
|
17954
|
-
name ("Needs your decision1Blocks the join…");
|
|
17955
|
-
the separators are read, not seen. -->
|
|
17956
|
-
<span class="strct-dg__announcer">, </span>
|
|
17957
|
-
<span
|
|
17958
|
-
class="strct-dg__groupcount strct-dg__groupcount--{{
|
|
17959
|
-
grp.status ?? 'none'
|
|
17960
|
-
}}"
|
|
17961
|
-
>{{ grp.count }}</span
|
|
17962
|
-
>
|
|
17963
|
-
<!-- Seen: the chip's number. Heard: the number with
|
|
17964
|
-
the grid's noun, because "Inconclusive, 3" does
|
|
17965
|
-
not say three of what. -->
|
|
17966
|
-
<span class="strct-dg__announcer"> {{ countNoun(grp.count) }}</span>
|
|
17967
|
-
@if (grp.note) {
|
|
17968
|
-
<span class="strct-dg__announcer">. </span>
|
|
17969
|
-
<span class="strct-dg__groupnote">{{ grp.note }}</span>
|
|
17970
|
-
}
|
|
17971
|
-
}
|
|
17972
|
-
</button>
|
|
17973
|
-
</td>
|
|
17974
|
-
</tr>
|
|
17975
|
-
} @else {
|
|
17976
|
-
@let row = it.row!;
|
|
17977
|
-
<tr
|
|
17978
|
-
[attr.aria-rowindex]="ariaRowIndex(row)"
|
|
17979
|
-
[class.strct-dg__row--selected]="isSelected(row)"
|
|
17980
|
-
[class.strct-dg__row--locked]="lockedReason(row) !== null"
|
|
17981
|
-
[attr.aria-selected]="mode() === 'none' ? null : isSelected(row)"
|
|
17982
|
-
[attr.aria-disabled]="lockedReason(row) !== null ? 'true' : null"
|
|
17983
|
-
[attr.title]="lockedReason(row) || null"
|
|
17984
|
-
(click)="onRowPick(row)"
|
|
17985
|
-
[class.strct-dg__row--active]="paneOpen() && row === activeRow()"
|
|
17986
|
-
[attr.aria-level]="childrenKey() ? treeDepth(row) + 1 : null"
|
|
17987
|
-
[attr.aria-expanded]="
|
|
17988
|
-
childrenKey() && treeHasChildren(row) ? treeExpanded(row) : null
|
|
17989
|
-
"
|
|
17990
|
-
[attr.tabindex]="
|
|
17991
|
-
childrenKey()
|
|
17992
|
-
? treeRowTabindex(row)
|
|
17993
|
-
: gridMode()
|
|
17994
|
-
? gridRowTabindex(row)
|
|
17995
|
-
: canDetail()
|
|
17996
|
-
? paneRowTabindex(row)
|
|
17997
|
-
: null
|
|
17998
|
-
"
|
|
17999
|
-
(keydown)="
|
|
18000
|
-
childrenKey()
|
|
18001
|
-
? onTreeRowKeydown(row, $event)
|
|
18002
|
-
: gridMode()
|
|
18003
|
-
? onGridRowKeydown(row, $event)
|
|
18004
|
-
: onPaneRowKeydown(row, $event)
|
|
18005
|
-
"
|
|
18006
|
-
(dblclick)="onRowActivate(row)"
|
|
18007
|
-
>
|
|
18008
|
-
@if (canDetail()) {
|
|
18009
|
-
<td
|
|
18010
|
-
class="strct-dg__expandcell"
|
|
18011
|
-
[class.strct-dg__cell--sticky]="stickyActive()"
|
|
18012
|
-
[style.insetInlineStart.px]="utilLeft('detail')"
|
|
18013
|
-
>
|
|
18014
|
-
<button
|
|
18015
|
-
type="button"
|
|
18016
|
-
[attr.tabindex]="ctlTabindex()"
|
|
18017
|
-
class="strct-dg__detailbtn"
|
|
18018
|
-
[class.strct-dg__detailbtn--active]="row === activeRow()"
|
|
18019
|
-
[attr.aria-expanded]="row === activeRow()"
|
|
18020
|
-
[attr.aria-label]="L().openDetail"
|
|
18021
|
-
(click)="openDetail(row)"
|
|
18022
|
-
>
|
|
18023
|
-
<strct-icon name="chevronDoubleRight" [size]="13" [strokeWidth]="1.6" />
|
|
18024
|
-
</button>
|
|
18025
|
-
</td>
|
|
18026
|
-
}
|
|
18027
|
-
@if (canExpand()) {
|
|
18028
|
-
<td
|
|
18029
|
-
class="strct-dg__expandcell"
|
|
18030
|
-
[class.strct-dg__cell--sticky]="stickyActive()"
|
|
18031
|
-
[style.insetInlineStart.px]="utilLeft('expand')"
|
|
18032
|
-
>
|
|
18033
|
-
<button
|
|
18034
|
-
type="button"
|
|
18035
|
-
[attr.tabindex]="ctlTabindex()"
|
|
18036
|
-
class="strct-dg__expandbtn"
|
|
18037
|
-
[class.strct-dg__expandbtn--open]="isExpanded(row)"
|
|
18038
|
-
[attr.aria-expanded]="isExpanded(row)"
|
|
18039
|
-
[attr.aria-label]="L().toggleDetail"
|
|
18040
|
-
(click)="toggleExpand(row)"
|
|
18041
|
-
>
|
|
18042
|
-
<strct-icon name="chevronRight" [size]="12" [strokeWidth]="1.7" />
|
|
18043
|
-
</button>
|
|
18044
|
-
</td>
|
|
18045
|
-
}
|
|
18046
|
-
@if (hasSelectionColumn()) {
|
|
18047
|
-
<td
|
|
18048
|
-
class="strct-dg__sel"
|
|
18049
|
-
[class.strct-dg__cell--sticky]="stickyActive()"
|
|
18050
|
-
[style.insetInlineStart.px]="utilLeft('sel')"
|
|
18051
|
-
>
|
|
18052
|
-
@if (mode() === 'single') {
|
|
18053
|
-
<!-- A native radio group: one name per grid, so the
|
|
18054
|
-
arrow keys move between rows and Space picks,
|
|
18055
|
-
without the grid inventing its own keyboarding. -->
|
|
18056
|
-
<input
|
|
18057
|
-
type="radio"
|
|
18058
|
-
class="strct-dg__radio"
|
|
18059
|
-
[name]="radioName"
|
|
18060
|
-
[attr.aria-label]="selectRowLabel(row)"
|
|
18061
|
-
[attr.aria-description]="lockedReason(row) || null"
|
|
18062
|
-
[checked]="isSelected(row)"
|
|
18063
|
-
[disabled]="lockedReason(row) !== null"
|
|
18064
|
-
[attr.tabindex]="ctlTabindex()"
|
|
18065
|
-
(change)="selectSingle(row)"
|
|
18066
|
-
(click)="$event.stopPropagation()"
|
|
18067
|
-
/>
|
|
18068
|
-
} @else {
|
|
18069
|
-
<!-- click fires (and bubbles) before the input's change,
|
|
18070
|
-
so the modifier is recorded by the time toggleRow runs. -->
|
|
18071
|
-
<strct-checkbox
|
|
18072
|
-
[ariaLabel]="selectRowLabel(row)"
|
|
18073
|
-
[attr.aria-description]="lockedReason(row) || null"
|
|
18074
|
-
[checked]="isSelected(row)"
|
|
18075
|
-
[disabled]="lockedReason(row) !== null"
|
|
18076
|
-
[tabIndex]="ctlTabindex()"
|
|
18077
|
-
(click)="noteRangeIntent($event); $event.stopPropagation()"
|
|
18078
|
-
(checkedChange)="toggleRow(row)"
|
|
18079
|
-
/>
|
|
18080
|
-
}
|
|
18081
|
-
</td>
|
|
18082
|
-
}
|
|
18083
|
-
@for (col of visibleColumns(); track col.key; let colIdx = $index) {
|
|
18084
|
-
<td
|
|
18085
|
-
[style.text-align]="col.align ?? (col.numeric ? 'end' : 'start')"
|
|
18086
|
-
[class.strct-dg__cell--mono]="col.mono"
|
|
18087
|
-
[class.strct-dg__cell--muted]="col.muted"
|
|
18088
|
-
[class.strct-dg__cell--numeric]="col.numeric"
|
|
18089
|
-
[class.strct-dg__cell--sticky]="isSticky(col)"
|
|
18090
|
-
[class.strct-dg__cell--sticky-last]="col.key === lastStickyKey()"
|
|
18091
|
-
[class.strct-dg__cell--editable]="col.editable"
|
|
18092
|
-
[style.insetInlineStart.px]="stickyLeft(col.key)"
|
|
18093
|
-
[attr.data-edit]="col.editable ? '' : null"
|
|
18094
|
-
[attr.tabindex]="col.editable ? editCellTabindex(row, col) : null"
|
|
18095
|
-
[attr.aria-describedby]="col.editable ? editHintId : null"
|
|
18096
|
-
(dblclick)="col.editable && startEdit(row, col)"
|
|
18097
|
-
(focus)="col.editable && onEditCellFocus(row, col)"
|
|
18098
|
-
(keydown)="col.editable && onEditCellKeydown(row, col, $event)"
|
|
18099
|
-
>
|
|
18100
|
-
@if (childrenKey() && colIdx === 0) {
|
|
18101
|
-
<span
|
|
18102
|
-
class="strct-dg__treepad"
|
|
18103
|
-
[style.width.px]="treeDepth(row) * 18"
|
|
18104
|
-
aria-hidden="true"
|
|
18105
|
-
></span>
|
|
18106
|
-
@if (treeHasChildren(row)) {
|
|
18107
|
-
<button
|
|
18108
|
-
type="button"
|
|
18109
|
-
class="strct-dg__treebtn"
|
|
18110
|
-
[class.strct-dg__treebtn--open]="treeExpanded(row)"
|
|
18111
|
-
[attr.aria-expanded]="treeExpanded(row)"
|
|
18112
|
-
[attr.aria-label]="L().toggleChildren"
|
|
18113
|
-
(click)="toggleTreeRow(row)"
|
|
18114
|
-
>
|
|
18115
|
-
<strct-icon name="chevronRight" [size]="12" [strokeWidth]="1.7" />
|
|
18116
|
-
</button>
|
|
18117
|
-
} @else {
|
|
18118
|
-
<span
|
|
18119
|
-
class="strct-dg__treebtn strct-dg__treebtn--leaf"
|
|
18120
|
-
aria-hidden="true"
|
|
18121
|
-
></span>
|
|
18122
|
-
}
|
|
18123
|
-
}
|
|
18124
|
-
@if (isEditingCell(row, col)) {
|
|
18125
|
-
@switch (col.editor ?? 'text') {
|
|
18126
|
-
@case ('select') {
|
|
18127
|
-
<!-- Choosing is the commit: there is nothing to
|
|
18128
|
-
confirm with Enter once an option is picked. -->
|
|
18129
|
-
<strct-select
|
|
18130
|
-
class="strct-dg__editselect"
|
|
18131
|
-
[options]="editorOptionsFor(row, col)"
|
|
18132
|
-
[listLabel]="L().editCell + ': ' + col.label"
|
|
18133
|
-
[ngModel]="row[col.key]"
|
|
18134
|
-
(ngModelChange)="commitValue(row, col, $event)"
|
|
18135
|
-
(keydown.escape)="cancelEdit($event)"
|
|
18136
|
-
(click)="$event.stopPropagation()"
|
|
18137
|
-
/>
|
|
18138
|
-
}
|
|
18139
|
-
@case ('number') {
|
|
18140
|
-
<strct-number
|
|
18141
|
-
class="strct-dg__editnumber"
|
|
18142
|
-
[ariaLabel]="L().editCell + ': ' + col.label"
|
|
18143
|
-
[min]="col.editorMin ?? null"
|
|
18144
|
-
[max]="col.editorMax ?? null"
|
|
18145
|
-
[step]="col.editorStep ?? 1"
|
|
18146
|
-
[ngModel]="row[col.key]"
|
|
18147
|
-
(ngModelChange)="editDraft.set($event)"
|
|
18148
|
-
(keydown.enter)="commitDraft(row, col, $event)"
|
|
18149
|
-
(keydown.escape)="cancelEdit($event)"
|
|
18150
|
-
(focusout)="commitOnLeave(row, col, $event)"
|
|
18151
|
-
(click)="$event.stopPropagation()"
|
|
18152
|
-
/>
|
|
18153
|
-
}
|
|
18154
|
-
@default {
|
|
18155
|
-
<input
|
|
18156
|
-
class="strct-dg__editinput"
|
|
18157
|
-
type="text"
|
|
18158
|
-
[value]="row[col.key] ?? ''"
|
|
18159
|
-
[attr.aria-label]="L().editCell + ': ' + col.label"
|
|
18160
|
-
(keydown.enter)="commitEdit(row, col, $event)"
|
|
18161
|
-
(keydown.escape)="cancelEdit($event)"
|
|
18162
|
-
(blur)="commitEdit(row, col, $event)"
|
|
18163
|
-
(click)="$event.stopPropagation()"
|
|
18164
|
-
/>
|
|
18165
|
-
}
|
|
18166
|
-
}
|
|
18167
|
-
} @else if (cellTemplate(col.key); as tpl) {
|
|
18168
|
-
<ng-container
|
|
18169
|
-
[ngTemplateOutlet]="tpl"
|
|
18170
|
-
[ngTemplateOutletContext]="{
|
|
18171
|
-
$implicit: row,
|
|
18172
|
-
row,
|
|
18173
|
-
value: row[col.key],
|
|
18174
|
-
column: col,
|
|
18175
|
-
}"
|
|
18176
|
-
/>
|
|
18177
|
-
} @else if (isBlank(row, col)) {
|
|
18178
|
-
<span
|
|
18179
|
-
class="strct-dg__empty"
|
|
18180
|
-
[attr.aria-label]="col.emptyLabel || null"
|
|
18181
|
-
>{{ col.emptyText }}</span
|
|
18182
|
-
>
|
|
18183
|
-
} @else {
|
|
18184
|
-
{{ displayValue(row, col) }}
|
|
18185
|
-
@if (col.descriptionKey && row[col.descriptionKey]) {
|
|
18186
|
-
<span class="strct-dg__celldesc">{{ row[col.descriptionKey] }}</span>
|
|
18187
|
-
}
|
|
18188
|
-
}
|
|
18189
|
-
<!-- The affordance a mouse never needed: a cell that
|
|
18190
|
-
can be edited says so on hover and on focus. -->
|
|
18191
|
-
@if (col.editable && editHint() && !isEditingCell(row, col)) {
|
|
18192
|
-
<strct-icon
|
|
18193
|
-
class="strct-dg__editpencil"
|
|
18194
|
-
name="pencil"
|
|
18195
|
-
[size]="12"
|
|
18196
|
-
[strokeWidth]="1.6"
|
|
18197
|
-
aria-hidden="true"
|
|
18198
|
-
/>
|
|
18199
|
-
}
|
|
18200
|
-
</td>
|
|
18201
|
-
}
|
|
18202
|
-
@if (canActions()) {
|
|
18203
|
-
<td class="strct-dg__actioncell">
|
|
18204
|
-
<button
|
|
18205
|
-
type="button"
|
|
18206
|
-
[attr.tabindex]="ctlTabindex()"
|
|
18207
|
-
class="strct-dg__kebab"
|
|
18208
|
-
[attr.aria-label]="L().rowActions"
|
|
18209
|
-
(click)="openRowMenu(row, $event)"
|
|
18210
|
-
>
|
|
18211
|
-
<strct-icon name="dots" [size]="16" />
|
|
18212
|
-
</button>
|
|
18213
|
-
</td>
|
|
18214
|
-
}
|
|
18215
|
-
</tr>
|
|
18216
|
-
@if (canExpand() && isExpanded(row)) {
|
|
18217
|
-
<tr class="strct-dg__detailrow">
|
|
18218
|
-
<td [attr.colspan]="colspan()">
|
|
18219
|
-
<div class="strct-dg__detail">
|
|
18220
|
-
<ng-container
|
|
18221
|
-
[ngTemplateOutlet]="detailDef()!.template"
|
|
18222
|
-
[ngTemplateOutletContext]="{ $implicit: row, row }"
|
|
18223
|
-
/>
|
|
18224
|
-
</div>
|
|
18225
|
-
</td>
|
|
18226
|
-
</tr>
|
|
18227
|
-
}
|
|
18228
|
-
}
|
|
18229
|
-
} @empty {
|
|
18230
|
-
<!-- "Nothing here" and "nothing matches what you typed" are
|
|
18231
|
-
different states: the second one can be undone, and
|
|
18232
|
-
saying so is the whole point. -->
|
|
18233
|
-
<tr>
|
|
18234
|
-
<td class="strct-dg__emptyrow" [attr.colspan]="colspan()">
|
|
18235
|
-
@if (filteredAway()) {
|
|
18236
|
-
<strct-empty-state
|
|
18237
|
-
size="sm"
|
|
18238
|
-
[titleLevel]="null"
|
|
18239
|
-
[title]="L().noMatches"
|
|
18240
|
-
[description]="noMatchesDescription()"
|
|
18241
|
-
>
|
|
18242
|
-
<button strct-button variant="flat" size="sm" (click)="clearAllFilters()">
|
|
18243
|
-
{{ L().clearFilters }}
|
|
18244
|
-
</button>
|
|
18245
|
-
</strct-empty-state>
|
|
18246
|
-
} @else {
|
|
18247
|
-
<!-- Not a heading: a grid is a region of a page, and an
|
|
18248
|
-
empty one used to put an <h3> in its outline. -->
|
|
18249
|
-
<strct-empty-state size="sm" [titleLevel]="null" [title]="emptyText()" />
|
|
18250
|
-
}
|
|
18251
|
-
</td>
|
|
18252
|
-
</tr>
|
|
18253
|
-
}
|
|
18254
|
-
@if (virtual() && bottomPad() > 0) {
|
|
18255
|
-
<tr class="strct-dg__vspacer" aria-hidden="true">
|
|
18256
|
-
<td [attr.colspan]="colspan()" [style.height.px]="bottomPad()"></td>
|
|
18257
|
-
</tr>
|
|
18258
|
-
}
|
|
18259
|
-
}
|
|
18260
|
-
</tbody>
|
|
18261
|
-
</table>
|
|
18262
|
-
</div>
|
|
18263
|
-
|
|
18264
|
-
@if (paneOpen()) {
|
|
18265
|
-
<aside class="strct-dg__pane">
|
|
18266
|
-
<div class="strct-dg__pane-head">
|
|
18267
|
-
@if (narrowPane()) {
|
|
18268
|
-
<!-- The pane has taken the list's place, so there is a way back. -->
|
|
18269
|
-
<button
|
|
18270
|
-
type="button"
|
|
18271
|
-
class="strct-dg__pane-back"
|
|
18272
|
-
[attr.aria-label]="L().backToList"
|
|
18273
|
-
(click)="closePane()"
|
|
18274
|
-
>
|
|
18275
|
-
<strct-icon name="chevronLeft" [size]="13" />
|
|
18276
|
-
</button>
|
|
18277
|
-
}
|
|
18278
|
-
<span class="strct-dg__pane-title">
|
|
18279
|
-
<ng-content select="[strctDetailPaneTitle]" />
|
|
18280
|
-
@if (!paneTitleDef()) {
|
|
18281
|
-
{{ activeRow()![columns()[0].key] }}
|
|
18282
|
-
}
|
|
18283
|
-
</span>
|
|
18284
|
-
<span class="strct-dg__pane-meta">
|
|
18285
|
-
<ng-content select="[strctDetailPaneMeta]" />
|
|
18286
|
-
</span>
|
|
18287
|
-
<span class="strct-dg__pane-actions">
|
|
18288
|
-
<ng-content select="[strctDetailPaneActions]" />
|
|
18289
|
-
</span>
|
|
18290
|
-
<button
|
|
18291
|
-
type="button"
|
|
18292
|
-
class="strct-dg__pane-close"
|
|
18293
|
-
[attr.aria-label]="L().closeDetail"
|
|
18294
|
-
(click)="closePane()"
|
|
18295
|
-
>
|
|
18296
|
-
<strct-icon name="close" [size]="13" />
|
|
18297
|
-
</button>
|
|
18298
|
-
</div>
|
|
18299
|
-
<div class="strct-dg__pane-body">
|
|
18300
|
-
<ng-container
|
|
18301
|
-
[ngTemplateOutlet]="detailDef()!.template"
|
|
18302
|
-
[ngTemplateOutletContext]="{ $implicit: activeRow(), row: activeRow() }"
|
|
18303
|
-
/>
|
|
18304
|
-
</div>
|
|
18305
|
-
</aside>
|
|
18306
|
-
}
|
|
18307
|
-
</div>
|
|
18308
|
-
|
|
18309
|
-
@if (showFooter()) {
|
|
18310
|
-
<div class="strct-dg__foot">
|
|
18311
|
-
<div class="strct-dg__foot-left">
|
|
18312
|
-
@if (columnChooser() || sync()) {
|
|
18313
|
-
<div class="strct-dg__actions">
|
|
18314
|
-
<strct-button-group>
|
|
18315
|
-
@if (columnChooser()) {
|
|
18316
|
-
<button
|
|
18317
|
-
strct-button
|
|
18318
|
-
size="sm"
|
|
18319
|
-
[class.is-open]="chooserOpen()"
|
|
18320
|
-
[disabled]="footerActionsDisabled()"
|
|
18321
|
-
[attr.aria-label]="L().chooseColumns"
|
|
18322
|
-
(click)="toggleChooser($event)"
|
|
18323
|
-
>
|
|
18324
|
-
<strct-icon name="settings" [size]="16" />
|
|
18325
|
-
</button>
|
|
18326
|
-
}
|
|
18327
|
-
@if (sync()) {
|
|
18328
|
-
<button
|
|
18329
|
-
strct-button
|
|
18330
|
-
size="sm"
|
|
18331
|
-
[disabled]="footerActionsDisabled()"
|
|
18332
|
-
[attr.aria-label]="L().refresh"
|
|
18333
|
-
(click)="syncChange.emit()"
|
|
18334
|
-
>
|
|
18335
|
-
<strct-icon name="refresh" [size]="16" />
|
|
18336
|
-
</button>
|
|
18337
|
-
}
|
|
18338
|
-
</strct-button-group>
|
|
18339
|
-
@if (columnChooser() && chooserOpen()) {
|
|
18340
|
-
<div class="strct-dg__chooser-menu">
|
|
18341
|
-
@for (col of columns(); track col.key) {
|
|
18342
|
-
<!-- The whole row toggles; the checkbox's own click must not
|
|
18343
|
-
reach the row or the column would flip twice. -->
|
|
18344
|
-
<!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->
|
|
18345
|
-
<div
|
|
18346
|
-
class="strct-dg__chooser-item"
|
|
18347
|
-
(click)="toggleColumn(col.key, hiddenColumns().has(col.key))"
|
|
18348
|
-
>
|
|
18349
|
-
<strct-checkbox
|
|
18350
|
-
[checked]="!hiddenColumns().has(col.key)"
|
|
18351
|
-
(checkedChange)="toggleColumn(col.key, $event)"
|
|
18352
|
-
(click)="$event.stopPropagation()"
|
|
18353
|
-
/>
|
|
18354
|
-
<span>{{ col.label }}</span>
|
|
18355
|
-
</div>
|
|
18356
|
-
}
|
|
18357
|
-
</div>
|
|
18358
|
-
}
|
|
18359
|
-
</div>
|
|
18360
|
-
}
|
|
18361
|
-
<span class="strct-dg__count">
|
|
18362
|
-
@if (paging() === 'more') {
|
|
18363
|
-
{{ L().showing(rows().length, moreTotal() ?? undefined) }}
|
|
18364
|
-
} @else {
|
|
18365
|
-
{{ totalCount() }} {{ totalCount() === 1 ? L().row : L().rows }}
|
|
18366
|
-
}
|
|
18367
|
-
@if (selectedCount() && mode() !== 'single') {
|
|
18368
|
-
<span class="strct-dg__count-sep">|</span>
|
|
18369
|
-
<span class="strct-dg__count-sel">{{ selectedCount() }} {{ L().selected }}</span>
|
|
18370
|
-
}
|
|
18371
|
-
</span>
|
|
18372
|
-
</div>
|
|
18373
|
-
<div class="strct-dg__foot-right">
|
|
18374
|
-
<!-- A feed that pages by cursor loads more at the end: page numbers
|
|
18375
|
-
are something a cursor API cannot answer. It takes the pager's
|
|
18376
|
-
place — the column chooser, the sync button and the count are
|
|
18377
|
-
the footer's, not the pager's. -->
|
|
18378
|
-
@if (paging() === 'more') {
|
|
18379
|
-
@if (hasMore()) {
|
|
18380
|
-
<button
|
|
18381
|
-
strct-button
|
|
18382
|
-
size="sm"
|
|
18383
|
-
class="strct-dg__more"
|
|
18384
|
-
[disabled]="loadingMore()"
|
|
18385
|
-
(click)="loadMore.emit()"
|
|
18386
|
-
>
|
|
18387
|
-
@if (loadingMore()) {
|
|
18388
|
-
<strct-spinner size="sm" />
|
|
18389
|
-
}
|
|
18390
|
-
{{ L().loadMore }}
|
|
18391
|
-
</button>
|
|
18392
|
-
}
|
|
18393
|
-
} @else if (pageSize() > 0 && !groupBy()) {
|
|
18394
|
-
<strct-pagination
|
|
18395
|
-
[total]="totalCount()"
|
|
18396
|
-
[pageSize]="pageSize()"
|
|
18397
|
-
[page]="page()"
|
|
18398
|
-
(pageChange)="goToPage($event)"
|
|
18399
|
-
/>
|
|
18400
|
-
}
|
|
18401
|
-
</div>
|
|
18402
|
-
</div>
|
|
18403
|
-
}
|
|
18404
|
-
`, isInline: true, styles: [".strct-dg__radio{width:15px;height:15px;accent-color:var(--acc);cursor:pointer}.strct-dg__radio:disabled{cursor:not-allowed}.strct-dg__row--locked .strct-dg__sel{opacity:.55}.strct-dg__actioncaption:empty{display:none}.strct-dg__actioncaption{display:inline-flex;align-items:center;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--text-sm);color:var(--t2)}.strct-dg__bulk{display:flex;align-items:center;justify-content:center;flex-wrap:wrap;gap:4px 10px;padding:7px 12px;border-bottom:1px solid var(--b2);background:var(--acc-s);color:var(--t2);font-size:var(--text-md)}.strct-dg__announcer{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}.strct-dg-host{display:block;border:1px solid var(--b2);border-radius:var(--radius-lg);background:var(--bg-2);box-shadow:var(--shadow-rest)}.strct-dg-host--flush{border:0;border-radius:0;background:transparent;box-shadow:none}.strct-dg__more strct-spinner{margin-inline-end:4px}.strct-dg__caption{caption-side:top;text-align:start;padding:var(--space-2) var(--space-3);font-size:var(--text-sm);font-weight:600;color:var(--t2)}.strct-dg td.strct-dg__cell--mono{font-family:var(--mono);font-size:var(--text-sm)}.strct-dg td.strct-dg__cell--muted{color:var(--t2)}.strct-dg td.strct-dg__cell--numeric{font-variant-numeric:tabular-nums}.strct-dg__empty{color:var(--t2)}.strct-dg__celldesc{display:block;font-size:var(--text-sm);color:var(--t2);line-height:1.3}.strct-dg__scroll{flex:1 1 auto;min-width:0;overflow-x:auto;-webkit-overflow-scrolling:touch}.strct-dg-host--virtual .strct-dg__scroll,.strct-dg-host--bounded .strct-dg__scroll{overflow-y:auto}.strct-dg-host--virtual .strct-dg thead th,.strct-dg-host--bounded .strct-dg thead th{position:sticky;top:0;z-index:var(--z-raised)}.strct-dg__vspacer td{padding:0;border:0;background:transparent}.strct-dg th[draggable]{cursor:grab}.strct-dg__th--drop{box-shadow:inset 3px 0 0 var(--acc)}.strct-dg__grouprow td{background:var(--bg-2)!important;padding:0}.strct-dg__groupbtn{display:flex;align-items:center;gap:8px;width:100%;padding:7px 13px;border:0;background:transparent;color:var(--t1);font-family:var(--font);font-size:var(--text-sm);font-weight:600;cursor:pointer;text-align:start}.strct-dg__groupbtn:hover{background:var(--bg-3)}.strct-dg__groupbtn:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-dg__groupchev{display:inline-flex;color:var(--t3);transition:transform .15s ease}.strct-dg__groupchev--open{transform:rotate(90deg)}@media(prefers-reduced-motion:reduce){.strct-dg__groupchev{transition:none}}.strct-dg__grouplabel--critical{color:var(--critical)}.strct-dg__grouplabel--warning{color:var(--warning)}.strct-dg__grouplabel--success{color:var(--success)}.strct-dg__grouplabel--accent{color:var(--acc)}.strct-dg__grouplabel--neutral,.strct-dg__grouplabel--none{color:var(--t1)}.strct-dg__groupnote{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--text-sm);font-weight:400;color:var(--t2)}.strct-dg__groupcount{min-width:18px;height:18px;padding:0 5px;display:inline-flex;align-items:center;justify-content:center;font-size:12px;border-radius:4px;background:var(--acc-m);color:var(--acc);font-variant-numeric:tabular-nums}.strct-dg__groupcount--critical{background:var(--critical-bg);color:var(--critical)}.strct-dg__groupcount--warning{background:var(--warning-bg);color:var(--warning)}.strct-dg__groupcount--success{background:var(--success-bg);color:var(--success)}.strct-dg__groupcount--neutral,.strct-dg__groupcount--none{background:var(--bg-3);color:var(--t2)}.strct-dg-host--singleline .strct-dg{border-collapse:separate;border-spacing:0}.strct-dg-host--sticky .strct-dg,.strct-dg-host--virtual .strct-dg,.strct-dg-host--bounded .strct-dg{border-collapse:separate;border-spacing:0;overflow:visible;border-radius:0}.strct-dg-host--sticky .strct-dg{width:max-content;min-width:100%}.strct-dg .strct-dg__cell--sticky{position:sticky;z-index:calc(var(--z-base) + 2)}.strct-dg thead th.strct-dg__cell--sticky{z-index:calc(var(--z-raised) + 1)}.strct-dg .strct-dg__cell--sticky-last:after{content:\"\";position:absolute;top:0;bottom:0;inset-inline-end:-1px;width:7px;pointer-events:none;background:linear-gradient(to right,rgba(0,0,0,.14),transparent)}[dir=rtl] .strct-dg .strct-dg__cell--sticky-last:after{background:linear-gradient(to left,rgba(0,0,0,.14),transparent)}.strct-dg-host--sticky .strct-dg__expandcol,.strct-dg-host--sticky .strct-dg__expandcell{width:36px;min-width:36px;max-width:36px;box-sizing:border-box}.strct-dg-host--sticky .strct-dg__sel{width:40px;min-width:40px;max-width:40px;box-sizing:border-box}.strct-dg-host--sticky tbody .strct-dg__cell--sticky{background:var(--bg-1)}[data-theme=dark] .strct-dg-host--sticky tbody .strct-dg__cell--sticky{background:var(--bg-3)}.strct-dg-host--sticky tbody tr:hover .strct-dg__cell--sticky{background:linear-gradient(var(--acc-s),var(--acc-s)) var(--bg-1)}[data-theme=dark] .strct-dg-host--sticky tbody tr:hover .strct-dg__cell--sticky{background:linear-gradient(var(--acc-s),var(--acc-s)) var(--bg-3)}.strct-dg-host--sticky tbody .strct-dg__row--selected .strct-dg__cell--sticky{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-1)}[data-theme=dark] .strct-dg-host--sticky tbody .strct-dg__row--selected .strct-dg__cell--sticky{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-3)}.strct-dg{width:100%;border-collapse:collapse;font-size:13px;overflow:hidden;background:var(--bg-2)}.strct-dg-host:not(:has(.strct-dg__toolbar)) .strct-dg{border-start-start-radius:4px;border-start-end-radius:4px}.strct-dg-host:not(:has(.strct-dg__foot)) .strct-dg{border-end-start-radius:4px;border-end-end-radius:4px}.strct-dg th,.strct-dg td{padding:9px 13px;text-align:start;border-bottom:1px solid var(--b1)}.strct-dg tbody td{background:var(--bg-1)}[data-theme=dark] .strct-dg tbody td{background:var(--bg-3)}.strct-dg-host--compact .strct-dg th,.strct-dg-host--compact .strct-dg td{padding:5px 11px}.strct-dg-host--singleline .strct-dg tbody tr:not(.strct-dg__detailrow)>td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:360px}.strct-dg th{position:relative;font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.4px;color:var(--t2);background:var(--bg-2);white-space:nowrap;-webkit-user-select:none;user-select:none}.strct-dg__th--sortable{cursor:pointer}.strct-dg__th--sortable:hover{color:var(--t1)}.strct-dg__sortbtn{display:inline-flex;align-items:center;gap:inherit;padding:0;border:0;background:none;color:inherit;font:inherit;text-transform:inherit;letter-spacing:inherit;text-align:inherit;cursor:pointer}.strct-dg__sortbtn:focus-visible{outline:2px solid var(--acc50);outline-offset:2px;border-radius:var(--radius-sm)}.strct-dg__th--sortable:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-dg__hd{display:inline-flex;align-items:center;gap:5px}.strct-dg__sorticon{color:var(--t3)}.strct-dg__th--sortable:hover .strct-dg__sorticon{color:var(--acc)}.strct-dg__resize{position:absolute;inset-inline-end:0;top:0;bottom:0;width:4px;cursor:col-resize;background:transparent;z-index:calc(var(--z-base) + 1)}.strct-dg__resize:hover{background:var(--acc)}.strct-dg td{color:var(--t1)}.strct-dg tbody tr:last-child td{border-bottom:0}.strct-dg tbody tr:not(.strct-dg__detailrow):hover td{background:linear-gradient(var(--acc-s),var(--acc-s)) var(--bg-1)}[data-theme=dark] .strct-dg tbody tr:not(.strct-dg__detailrow):hover td{background:linear-gradient(var(--acc-s),var(--acc-s)) var(--bg-3)}.strct-dg tbody .strct-dg__row--selected td{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-1)}[data-theme=dark] .strct-dg tbody .strct-dg__row--selected td{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-3)}.strct-dg tbody tr.strct-dg__row--selected:hover td{background:linear-gradient(var(--acc-s),var(--acc-s)),linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-1)}[data-theme=dark] .strct-dg tbody tr.strct-dg__row--selected:hover td{background:linear-gradient(var(--acc-s),var(--acc-s)),linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-3)}.strct-dg__sel{width:1%;white-space:nowrap}.strct-dg__sel .strct-cb,.strct-dg__sel .strct-dg__radio,.strct-dg__expandbtn{position:relative}.strct-dg__sel .strct-cb:after,.strct-dg__sel .strct-dg__radio:after,.strct-dg__expandbtn:after{content:\"\";position:absolute;inset:-11px -13px;min-width:24px;min-height:24px}.strct-dg-host--compact .strct-dg__sel .strct-cb:after,.strct-dg-host--compact .strct-dg__sel .strct-dg__radio:after,.strct-dg-host--compact .strct-dg__expandbtn:after{inset:-7px -11px}.strct-dg__sel input{accent-color:var(--acc);width:15px;height:15px;cursor:pointer}.strct-dg__expandcol,.strct-dg__expandcell{width:1%;white-space:nowrap}.strct-dg__actioncol,.strct-dg__actioncell{width:1%;white-space:nowrap;text-align:end}.strct-dg__kebab{display:inline-flex;padding:4px;border:0;border-radius:2px;background:transparent;color:var(--t3);cursor:pointer;transition:color .14s ease,background .14s ease}.strct-dg__kebab:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__expandbtn{position:relative;display:inline-flex;align-items:center;justify-content:center;padding:3px;border:0;border-radius:2px;background:transparent;color:var(--t3);cursor:pointer;transition:transform .15s ease,color .15s ease}.strct-dg__expandbtn:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__expandbtn--open{transform:rotate(90deg);color:var(--acc)}.strct-dg__detailbtn{display:inline-flex;padding:3px;border:0;border-radius:2px;background:transparent;color:var(--t3);cursor:pointer;transition:color .14s ease,background .14s ease}.strct-dg__detailbtn:hover{color:var(--acc);background:var(--bg-3)}.strct-dg__detailbtn--active{color:var(--acc);background:var(--acc-m)}.strct-dg__detailrow td{background:var(--bg-2);padding:0}.strct-dg__detail{padding:14px 16px;font-size:13px;color:var(--t2)}.strct-dg__layout{display:flex;align-items:flex-start;min-width:0}.strct-dg__layout--paned{gap:0}.strct-dg__layout--paned>.strct-dg__scroll{flex:0 0 auto;width:var(--strct-dg-pane-list-w, 260px);min-width:var(--strct-dg-pane-list-w, 260px);max-width:var(--strct-dg-pane-list-w, 260px)}.strct-dg__layout--paned>.strct-dg__scroll>.strct-dg{width:100%;min-width:0;max-width:none;flex-shrink:0;border-start-end-radius:0;border-end-end-radius:0}.strct-dg__layout--panetakeover>.strct-dg__scroll{display:none}.strct-dg__layout--panetakeover>.strct-dg__pane{flex:1;min-width:0}.strct-dg__pane-meta,.strct-dg__pane-actions{display:inline-flex;align-items:center;gap:var(--space-2)}.strct-dg__pane-meta:empty,.strct-dg__pane-actions:empty{display:none}.strct-dg__pane-actions{margin-inline-start:auto}.strct-dg__pane-back{display:inline-flex;align-items:center;border:0;background:none;color:var(--t2);cursor:pointer;padding:2px;border-radius:var(--radius-sm)}.strct-dg__row--clickable{cursor:pointer}.strct-dg tbody .strct-dg__row--active td{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-1)}[data-theme=dark] .strct-dg tbody .strct-dg__row--active td{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-3)}.strct-dg__layout--paned .strct-dg__row--active td:last-child{position:relative;padding-inline-end:26px}.strct-dg__layout--paned .strct-dg__row--active td:last-child:after{content:\"\";position:absolute;inset-inline-end:11px;top:50%;width:6px;height:6px;border-top:1.6px solid var(--acc);border-inline-end:1.6px solid var(--acc);transform:translateY(-50%) rotate(45deg)}.strct-dg__pane{flex:1;min-width:0;align-self:stretch;background:var(--bg-1);border:1px solid var(--b2);border-inline-start:2px solid var(--acc);border-radius:4px;border-start-start-radius:0;border-end-start-radius:0;overflow:hidden;animation:strct-dg-pane-in .14s ease}.strct-dg__pane-head{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:11px 14px;border-bottom:1px solid var(--b1);font-size:13px;font-weight:600;color:var(--t1)}.strct-dg__pane-close{display:inline-flex;padding:3px;border:0;border-radius:2px;background:transparent;color:var(--t3);cursor:pointer}.strct-dg__pane-close:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__pane-body{padding:14px 16px;font-size:13px;color:var(--t2)}@keyframes strct-dg-pane-in{0%{opacity:0;transform:translate(8px)}}@keyframes strct-skeleton-pulse{0%,to{opacity:.4}50%{opacity:.7}}.strct-dg__skeleton-block{height:12px;border-radius:var(--radius-sm);background:linear-gradient(90deg,var(--bg-3) 25%,var(--skeleton-hi, var(--acc18)) 50%,var(--bg-3) 75%);background-size:200% 100%;animation:strct-dg-skeleton-sweep 1.1s linear infinite}@keyframes strct-dg-skeleton-sweep{0%{background-position:100% 0}to{background-position:-100% 0}}@media(prefers-reduced-motion:reduce){.strct-dg__skeleton-block{animation:none;background:var(--skeleton-hi, var(--acc18))}}.strct-dg__skeleton-row td{border-bottom:1px solid var(--b1)}.strct-dg__empty{text-align:center;color:var(--t2);padding:22px}.strct-dg__quickfilter{min-width:180px;max-width:260px}.strct-dg__quickfilter--end{order:2;margin-inline-start:auto}.strct-dg__filternote--end{order:3}.strct-dg__filternote{font-size:var(--text-sm);color:var(--t2);font-variant-numeric:tabular-nums;white-space:nowrap}.strct-dg__toolbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:9px 14px;border-bottom:1px solid var(--b2)}.strct-dg__foot{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:9px 14px;border-top:1px solid var(--b2);flex-wrap:wrap}.strct-dg__foot-left,.strct-dg__foot-right{display:flex;align-items:center;gap:12px}.strct-dg__actions{position:relative}.strct-dg__chooser-menu{position:absolute;bottom:calc(100% + 6px);inset-inline-start:0;z-index:var(--z-sticky);min-width:180px;background:var(--bg-1);border:1px solid var(--b2);border-radius:4px;box-shadow:var(--shadow-pop);padding:6px;display:flex;flex-direction:column;gap:2px}.strct-dg__chooser-menu--right{inset-inline-start:auto;inset-inline-end:0}.strct-dg__chooser-item{display:flex;align-items:center;gap:8px;padding:5px 8px;border-radius:3px;cursor:pointer;font-size:12px;color:var(--t1);transition:background .1s ease;-webkit-user-select:none;user-select:none}.strct-dg__chooser-item:hover{background:var(--bg-3)}.strct-dg__count{font-size:12px;color:var(--t2)}.strct-dg__count-sep{margin:0 8px;color:var(--b2)}.strct-dg__count-sel{color:var(--acc)}.strct-dg__filterbtn{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;margin-inline-start:2px;padding:0;border:0;border-radius:2px;background:transparent;color:var(--t3);cursor:pointer;vertical-align:middle}.strct-dg__filterbtn:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__filterbtn--active{color:var(--acc)}.strct-dg__filterbtn:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-dg__filterpanel{position:absolute;z-index:calc(var(--z-dropdown) + 10);display:flex;flex-direction:column;gap:6px;min-width:180px;padding:10px;background:var(--bg-1);border:1px solid var(--b2);border-radius:3px;box-shadow:var(--shh);font-weight:400;text-transform:none;letter-spacing:normal;white-space:nowrap}.strct-dg__filterinput{padding:5px 8px;border:1px solid var(--b2);border-radius:var(--radius-sm);background:var(--bg-2);color:var(--t1);font-family:var(--font);font-size:12px}.strct-dg__filterinput:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-dg__filteropt{display:flex;align-items:center;gap:7px;font-size:12.5px;color:var(--t1);cursor:pointer}.strct-dg__filterclear{align-self:flex-start;padding:3px 8px;border:1px solid var(--b2);border-radius:var(--radius-sm);background:transparent;color:var(--t2);font-family:var(--font);font-size:var(--text-sm);cursor:pointer}.strct-dg__filterclear:hover:not(:disabled){color:var(--t1);background:var(--bg-3)}.strct-dg__filterclear:disabled{color:var(--t4);cursor:default}.strct-dg tbody tr[tabindex]:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-dg__treepad{display:inline-block;height:1px;vertical-align:middle}.strct-dg__treebtn{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;margin-inline-end:4px;padding:0;border:0;border-radius:2px;background:transparent;color:var(--t3);cursor:pointer;vertical-align:middle}.strct-dg__treebtn:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__treebtn:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-dg__treebtn strct-icon{transition:transform .15s ease}.strct-dg__treebtn--open strct-icon{transform:rotate(90deg)}.strct-dg__treebtn--leaf{cursor:default;pointer-events:none}@media(prefers-reduced-motion:reduce){.strct-dg__treebtn strct-icon{transition:none}}.strct-dg__cell--editable{cursor:text;position:relative}.strct-dg__cell--editable:hover{box-shadow:inset 0 0 0 1px var(--b2)}.strct-dg__cell--editable:focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--acc50)}.strct-dg__editpencil{position:absolute;top:50%;inset-inline-end:6px;transform:translateY(-50%);color:var(--t3);opacity:0;pointer-events:none}td:hover>.strct-dg__editpencil,td:focus-within>.strct-dg__editpencil{opacity:1}.strct-dg__editinput{width:100%;box-sizing:border-box;padding:3px 6px;border:1px solid var(--acc);border-radius:var(--radius-sm);background:var(--bg-1);color:var(--t1);font:inherit}.strct-dg__editselect,.strct-dg__editnumber{display:block;width:100%}.strct-dg__editinput:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "strictName", "size", "strokeWidth", "badge", "mode", "modeLabel", "ariaLabel", "count", "countMax", "countStatus", "countLabel"] }, { kind: "component", type: StrctPagination, selector: "strct-pagination", inputs: ["prevLabel", "nextLabel", "regionLabel", "pageLabel", "total", "pageSize", "page"], outputs: ["pageChange"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: StrctCheckbox, selector: "strct-checkbox", inputs: ["checked", "disabled", "indeterminate", "ariaLabel", "description", "tabIndex"], outputs: ["checkedChange"] }, { kind: "component", type: StrctButton, selector: "button[strct-button], a[strct-button]", inputs: ["variant", "size", "solid", "block", "iconOnly", "disabled", "disabledReason", "disabledReasonPosition"] }, { kind: "component", type: StrctButtonGroup, selector: "strct-button-group" }, { kind: "directive", type: StrctOverlay, selector: "[strctOverlay]", inputs: ["strctOverlay", "strctOverlayPlacement", "strctOverlayMatchWidth", "strctOverlayGap"] }, { kind: "component", type: StrctSearchbox, selector: "strct-searchbox", inputs: ["placeholder", "hint", "trigger", "clearable", "ariaLabel", "clearLabel", "value"], outputs: ["valueChange", "search", "activated"] }, { kind: "component", type: StrctSelect, selector: "strct-select", inputs: ["options", "placeholder", "ariaLabel", "listLabel", "emptyText", "disabled", "compareWith"] }, { kind: "component", type: StrctNumber, selector: "strct-number", inputs: ["min", "max", "step", "placeholder", "ariaLabel", "incrementLabel", "decrementLabel", "disabled"] }, { kind: "component", type: StrctSpinner, selector: "strct-spinner", inputs: ["size", "label", "caption"] }, { kind: "component", type: StrctEmptyState, selector: "strct-empty-state", inputs: ["variant", "icon", "tone", "title", "titleLevel", "size", "description"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
17821
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.4", type: StrctDatagrid, isStandalone: true, selector: "strct-datagrid", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: true, transformFunction: null }, pageSizeFlat: { classPropertyName: "pageSizeFlat", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, selectableFlat: { classPropertyName: "selectableFlat", publicName: "selectable", isSignal: true, isRequired: false, transformFunction: null }, expandable: { classPropertyName: "expandable", publicName: "expandable", isSignal: true, isRequired: false, transformFunction: null }, detailPaneFlat: { classPropertyName: "detailPaneFlat", publicName: "detailPane", isSignal: true, isRequired: false, transformFunction: null }, paneListWidthFlat: { classPropertyName: "paneListWidthFlat", publicName: "paneListWidth", isSignal: true, isRequired: false, transformFunction: null }, paneTakeoverWidthFlat: { classPropertyName: "paneTakeoverWidthFlat", publicName: "paneTakeoverWidth", isSignal: true, isRequired: false, transformFunction: null }, activeRowId: { classPropertyName: "activeRowId", publicName: "activeRowId", isSignal: true, isRequired: false, transformFunction: null }, compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null }, singleLine: { classPropertyName: "singleLine", publicName: "singleLine", isSignal: true, isRequired: false, transformFunction: null }, emptyText: { classPropertyName: "emptyText", publicName: "emptyText", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, resizable: { classPropertyName: "resizable", publicName: "resizable", isSignal: true, isRequired: false, transformFunction: null }, columnChooser: { classPropertyName: "columnChooser", publicName: "columnChooser", isSignal: true, isRequired: false, transformFunction: null }, syncFlat: { classPropertyName: "syncFlat", publicName: "sync", isSignal: true, isRequired: false, transformFunction: null }, footerActionsDisabled: { classPropertyName: "footerActionsDisabled", publicName: "footerActionsDisabled", isSignal: true, isRequired: false, transformFunction: null }, rowId: { classPropertyName: "rowId", publicName: "rowId", isSignal: true, isRequired: false, transformFunction: null }, selectionModeFlat: { classPropertyName: "selectionModeFlat", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, selectedId: { classPropertyName: "selectedId", publicName: "selectedId", isSignal: true, isRequired: false, transformFunction: null }, rowSelectableFlat: { classPropertyName: "rowSelectableFlat", publicName: "rowSelectable", isSignal: true, isRequired: false, transformFunction: null }, flush: { classPropertyName: "flush", publicName: "flush", isSignal: true, isRequired: false, transformFunction: null }, caption: { classPropertyName: "caption", publicName: "caption", isSignal: true, isRequired: false, transformFunction: null }, hasMoreFlat: { classPropertyName: "hasMoreFlat", publicName: "hasMore", isSignal: true, isRequired: false, transformFunction: null }, loadingMoreFlat: { classPropertyName: "loadingMoreFlat", publicName: "loadingMore", isSignal: true, isRequired: false, transformFunction: null }, moreTotalFlat: { classPropertyName: "moreTotalFlat", publicName: "moreTotal", isSignal: true, isRequired: false, transformFunction: null }, groupSelectFlat: { classPropertyName: "groupSelectFlat", publicName: "groupSelect", isSignal: true, isRequired: false, transformFunction: null }, rowActions: { classPropertyName: "rowActions", publicName: "rowActions", isSignal: true, isRequired: false, transformFunction: null }, initialSelectionFlat: { classPropertyName: "initialSelectionFlat", publicName: "initialSelection", isSignal: true, isRequired: false, transformFunction: null }, selectedIds: { classPropertyName: "selectedIds", publicName: "selectedIds", isSignal: true, isRequired: false, transformFunction: null }, labels: { classPropertyName: "labels", publicName: "labels", isSignal: true, isRequired: false, transformFunction: null }, viewportHeightFlat: { classPropertyName: "viewportHeightFlat", publicName: "viewportHeight", isSignal: true, isRequired: false, transformFunction: null }, maxHeightFlat: { classPropertyName: "maxHeightFlat", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, editHint: { classPropertyName: "editHint", publicName: "editHint", isSignal: true, isRequired: false, transformFunction: null }, rowHeightFlat: { classPropertyName: "rowHeightFlat", publicName: "rowHeight", isSignal: true, isRequired: false, transformFunction: null }, lazyFlat: { classPropertyName: "lazyFlat", publicName: "lazy", isSignal: true, isRequired: false, transformFunction: null }, totalFlat: { classPropertyName: "totalFlat", publicName: "total", isSignal: true, isRequired: false, transformFunction: null }, stateKeyFlat: { classPropertyName: "stateKeyFlat", publicName: "stateKey", isSignal: true, isRequired: false, transformFunction: null }, columnState: { classPropertyName: "columnState", publicName: "columnState", isSignal: true, isRequired: false, transformFunction: null }, reorderable: { classPropertyName: "reorderable", publicName: "reorderable", isSignal: true, isRequired: false, transformFunction: null }, groupByFlat: { classPropertyName: "groupByFlat", publicName: "groupBy", isSignal: true, isRequired: false, transformFunction: null }, groupsFlat: { classPropertyName: "groupsFlat", publicName: "groups", isSignal: true, isRequired: false, transformFunction: null }, showEmptyGroupsFlat: { classPropertyName: "showEmptyGroupsFlat", publicName: "showEmptyGroups", isSignal: true, isRequired: false, transformFunction: null }, collapsedGroups: { classPropertyName: "collapsedGroups", publicName: "collapsedGroups", isSignal: true, isRequired: false, transformFunction: null }, filters: { classPropertyName: "filters", publicName: "filters", isSignal: true, isRequired: false, transformFunction: null }, quickFilter: { classPropertyName: "quickFilter", publicName: "quickFilter", isSignal: true, isRequired: false, transformFunction: null }, quickFilterFieldsFlat: { classPropertyName: "quickFilterFieldsFlat", publicName: "quickFilterFields", isSignal: true, isRequired: false, transformFunction: null }, quickFilterableFlat: { classPropertyName: "quickFilterableFlat", publicName: "quickFilterable", isSignal: true, isRequired: false, transformFunction: null }, quickFilterAlignFlat: { classPropertyName: "quickFilterAlignFlat", publicName: "quickFilterAlign", isSignal: true, isRequired: false, transformFunction: null }, childrenKeyFlat: { classPropertyName: "childrenKeyFlat", publicName: "childrenKey", isSignal: true, isRequired: false, transformFunction: null }, interactionMode: { classPropertyName: "interactionMode", publicName: "interactionMode", isSignal: true, isRequired: false, transformFunction: null }, selectionColumnFlat: { classPropertyName: "selectionColumnFlat", publicName: "selectionColumn", isSignal: true, isRequired: false, transformFunction: null }, selectionCfg: { classPropertyName: "selectionCfg", publicName: "selection", isSignal: true, isRequired: false, transformFunction: null }, paneFlat: { classPropertyName: "paneFlat", publicName: "pane", isSignal: true, isRequired: false, transformFunction: null }, pagingFlat: { classPropertyName: "pagingFlat", publicName: "paging", isSignal: true, isRequired: false, transformFunction: null }, virtualFlat: { classPropertyName: "virtualFlat", publicName: "virtual", isSignal: true, isRequired: false, transformFunction: null }, groupingCfg: { classPropertyName: "groupingCfg", publicName: "grouping", isSignal: true, isRequired: false, transformFunction: null }, filteringCfg: { classPropertyName: "filteringCfg", publicName: "filtering", isSignal: true, isRequired: false, transformFunction: null }, stateCfg: { classPropertyName: "stateCfg", publicName: "state", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeRowId: "activeRowIdChange", selectedId: "selectedIdChange", loadMore: "loadMore", selectedIds: "selectedIdsChange", columnState: "columnStateChange", collapsedGroups: "collapsedGroupsChange", filters: "filtersChange", quickFilter: "quickFilterChange", rowActivate: "rowActivate", selectionChange: "selectionChange", syncChange: "syncChange", rowAction: "rowAction", lazyLoad: "lazyLoad", cellEdit: "cellEdit" }, host: { listeners: { "document:click": "onDocClickOverlays($event)", "document:keydown.escape": "onEscapeOverlays($event)" }, properties: { "attr.aria-busy": "loading() || loadingMore() ? \"true\" : null", "class.strct-dg-host--compact": "compact()", "class.strct-dg-host--singleline": "singleLine()", "class.strct-dg-host--virtual": "virtual()", "class.strct-dg-host--bounded": "!virtual() && maxHeight() !== null", "class.strct-dg-host--sticky": "stickyActive()", "class.strct-dg-host--flush": "flush()" }, classAttribute: "strct-dg-host" }, queries: [{ propertyName: "detailDef", first: true, predicate: StrctRowDetailDef, descendants: true, isSignal: true }, { propertyName: "groupHeaderDef", first: true, predicate: StrctGroupHeaderDef, descendants: true, isSignal: true }, { propertyName: "paneTitleDef", first: true, predicate: StrctDetailPaneTitle, descendants: true, isSignal: true }, { propertyName: "actionBarDef", first: true, predicate: StrctDatagridActionBar, descendants: true, isSignal: true }, { propertyName: "actionBarCaptionDef", first: true, predicate: StrctDatagridActionBarCaption, descendants: true, isSignal: true }, { propertyName: "cellDefs", predicate: StrctCellDef, isSignal: true }], ngImport: i0, template: "<!-- One polite region for everything the grid does to itself: sorting,\n paging and filtering all change the rows without saying so. -->\n<span class=\"strct-dg__announcer\" role=\"status\" aria-live=\"polite\">{{ announcement() }}</span>\n@if (actionBarDef() || quickFilterable() || actionBarCaptionDef()) {\n <div class=\"strct-dg__toolbar\">\n @if (quickFilterable()) {\n <strct-searchbox\n class=\"strct-dg__quickfilter\"\n [class.strct-dg__quickfilter--end]=\"quickFilterAlign() === 'end'\"\n [placeholder]=\"L().quickFilter\"\n [ariaLabel]=\"L().quickFilter\"\n [value]=\"quickFilter()\"\n (valueChange)=\"quickFilter.set($event)\"\n />\n @if (filterNote(); as note) {\n <span\n class=\"strct-dg__filternote\"\n [class.strct-dg__filternote--end]=\"quickFilterAlign() === 'end'\"\n >{{ note }}</span\n >\n }\n }\n <span class=\"strct-dg__actioncaption\">\n <ng-content select=\"[strctDatagridActionBarCaption]\" />\n </span>\n <ng-content select=\"[strctDatagridActionBar]\" />\n </div>\n}\n\n@if (hasEditableColumn()) {\n <!-- What the editable cells point at with aria-describedby: a keyboard\n user is told the cell can be edited, and how. -->\n <!-- In flow, not absolutely positioned: an out-of-flow box whose\n containing block is the page extends the document's scrollable area\n from wherever the grid happens to sit. 1x1 and clipped is enough. -->\n <span\n class=\"strct-sr-only\"\n style=\"\n display: inline-block;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n \"\n [id]=\"editHintId\"\n >{{ L().editCellInstructions }}</span\n >\n}\n\n@if (bulkHint(); as hint) {\n <!-- Selecting the page is not selecting the set. Say which one happened,\n and offer the other. -->\n <div class=\"strct-dg__bulk\" role=\"status\">\n <span>{{ hint.text }}</span>\n <button strct-button variant=\"flat\" size=\"sm\" (click)=\"hint.run()\">\n {{ hint.action }}\n </button>\n </div>\n}\n<div\n class=\"strct-dg__layout\"\n [class.strct-dg__layout--paned]=\"paneOpen()\"\n [class.strct-dg__layout--panetakeover]=\"paneOpen() && narrowPane()\"\n [style.--strct-dg-pane-list-w]=\"paneListWidth()\"\n>\n <div\n class=\"strct-dg__scroll\"\n tabindex=\"0\"\n role=\"region\"\n [attr.aria-label]=\"L().rows\"\n [style.max-height.px]=\"virtual() ? viewportHeight() : maxHeight()\"\n (scroll)=\"virtual() && onScroll($event)\"\n >\n <table\n class=\"strct-dg\"\n [attr.role]=\"childrenKey() ? 'treegrid' : gridMode() ? 'grid' : null\"\n [attr.aria-rowcount]=\"ariaRowCount()\"\n [attr.aria-labelledby]=\"caption() ? captionId : null\"\n >\n @if (caption()) {\n <caption class=\"strct-dg__caption\" [id]=\"captionId\">\n {{\n caption()\n }}\n </caption>\n }\n <thead>\n <tr>\n <!-- A utility column is still a column: axe reports every empty\n header, and a screen-reader user hears nothing where the\n detail, expand and select controls are. The name is hidden,\n not absent. -->\n @if (canDetail()) {\n <th\n class=\"strct-dg__expandcol\"\n scope=\"col\"\n [class.strct-dg__cell--sticky]=\"stickyActive()\"\n [style.insetInlineStart.px]=\"utilLeft('detail')\"\n >\n <span class=\"strct-sr-only\">{{ L().detailColumn }}</span>\n </th>\n }\n @if (canExpand()) {\n <th\n class=\"strct-dg__expandcol\"\n scope=\"col\"\n [class.strct-dg__cell--sticky]=\"stickyActive()\"\n [style.insetInlineStart.px]=\"utilLeft('expand')\"\n >\n <span class=\"strct-sr-only\">{{ L().expandColumn }}</span>\n </th>\n }\n @if (hasSelectionColumn()) {\n <th\n class=\"strct-dg__sel\"\n scope=\"col\"\n [class.strct-dg__cell--sticky]=\"stickyActive()\"\n [style.insetInlineStart.px]=\"utilLeft('sel')\"\n >\n @if (mode() === 'multiple') {\n <strct-checkbox\n [ariaLabel]=\"L().selectAll\"\n [checked]=\"allPageSelected()\"\n [indeterminate]=\"somePageSelected()\"\n (checkedChange)=\"toggleAll()\"\n />\n } @else {\n <span class=\"strct-sr-only\">{{ L().selectColumn }}</span>\n }\n </th>\n }\n @for (col of visibleColumns(); track col.key) {\n <th\n scope=\"col\"\n [style.text-align]=\"col.align ?? (col.numeric ? 'end' : 'start')\"\n [style.width]=\"colWidth(col.key) ?? col.width ?? null\"\n [class.strct-dg__th--sortable]=\"col.sortable\"\n [class.strct-dg__th--drop]=\"col.key === dropKey()\"\n [class.strct-dg__cell--sticky]=\"isSticky(col)\"\n [class.strct-dg__cell--sticky-last]=\"col.key === lastStickyKey()\"\n [style.insetInlineStart.px]=\"stickyLeft(col.key)\"\n [attr.data-col]=\"col.key\"\n [attr.aria-sort]=\"col.sortable ? ariaSort(col.key) : null\"\n [attr.draggable]=\"reorderable() ? true : null\"\n (dragstart)=\"onColDragStart(col.key, $event)\"\n (dragover)=\"onColDragOver(col.key, $event)\"\n (drop)=\"onColDrop(col.key)\"\n (dragend)=\"onColDragEnd()\"\n >\n <span class=\"strct-dg__hd\">\n <!-- A header that sorts is a button: a th with tabindex is\n read as \"column header, focusable\" and never says it\n can be activated. aria-sort stays on the th, which is\n what carries the column's sorted state. -->\n @if (col.sortable) {\n <!-- The button covers most of the header, so it carries\n the drag source too: a reorderable column has to be\n grabbable where the pointer actually lands. The\n event bubbles to the th's own handlers. -->\n <button\n type=\"button\"\n class=\"strct-dg__sortbtn\"\n [attr.draggable]=\"reorderable() ? true : null\"\n (click)=\"sortBy(col.key)\"\n >\n {{ col.label }}\n <strct-icon class=\"strct-dg__sorticon\" [name]=\"sortIcon(col.key)\" [size]=\"13\" />\n </button>\n } @else {\n {{ col.label }}\n }\n @if (col.filterable || col.filterOptions) {\n <button\n #fbtn\n type=\"button\"\n class=\"strct-dg__filterbtn\"\n [class.strct-dg__filterbtn--active]=\"hasFilter(col.key)\"\n [attr.aria-expanded]=\"filterOpenKey() === col.key\"\n [attr.aria-label]=\"L().filterColumn + ': ' + col.label\"\n (click)=\"toggleFilterPanel(col.key, $event)\"\n (keydown.enter)=\"$event.stopPropagation()\"\n (keydown.space)=\"$event.stopPropagation()\"\n >\n <strct-icon name=\"filter\" [size]=\"12\" />\n </button>\n @if (filterOpenKey() === col.key) {\n <div\n class=\"strct-dg__filterpanel\"\n role=\"dialog\"\n [attr.aria-label]=\"L().filterColumn + ': ' + col.label\"\n [strctOverlay]=\"fbtn\"\n strctOverlayPlacement=\"bottom-start\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"$event.stopPropagation()\"\n (keydown.space)=\"$event.stopPropagation()\"\n >\n @if (col.filterOptions; as opts) {\n @for (opt of opts; track $index) {\n <label class=\"strct-dg__filteropt\">\n <input\n type=\"checkbox\"\n [checked]=\"optionChecked(col.key, opt)\"\n (change)=\"toggleFilterOption(col.key, opt)\"\n />\n <span>{{ opt }}</span>\n </label>\n }\n } @else {\n <input\n class=\"strct-dg__filterinput\"\n type=\"text\"\n [attr.placeholder]=\"L().filterPlaceholder\"\n [attr.aria-label]=\"L().filterColumn + ': ' + col.label\"\n [value]=\"textFilter(col.key)\"\n (input)=\"setTextFilter(col.key, $any($event.target).value)\"\n />\n }\n <button\n type=\"button\"\n class=\"strct-dg__filterclear\"\n [disabled]=\"!hasFilter(col.key)\"\n (click)=\"clearFilter(col.key)\"\n >\n {{ L().clearFilter }}\n </button>\n </div>\n }\n }\n </span>\n @if (resizable() && col.resizable !== false) {\n <!-- A separator, not a bare div: a column could only be\n resized with a mouse, which is the one input a\n console cannot assume. -->\n <div\n class=\"strct-dg__resize\"\n role=\"separator\"\n aria-orientation=\"vertical\"\n tabindex=\"0\"\n [attr.aria-label]=\"L().resizeColumn(col.label)\"\n [attr.aria-valuenow]=\"separatorValue(col.key)\"\n [attr.aria-valuemin]=\"40\"\n (mousedown)=\"onResizeStart($event, col.key)\"\n (keydown)=\"onResizeKey($event, col.key)\"\n (dblclick)=\"resetWidth(col.key)\"\n ></div>\n }\n </th>\n }\n @if (canActions()) {\n <th class=\"strct-dg__actioncol\" scope=\"col\" [attr.aria-label]=\"L().actions\"></th>\n }\n </tr>\n </thead>\n <!--\n focusin is the real keyboard path (focus does not bubble from cells);\n the plain focus binding exists to satisfy mouse-events-have-key-events.\n -->\n <tbody\n (mouseover)=\"revealIfClipped($event)\"\n (focusin)=\"revealIfClipped($event)\"\n (focus)=\"revealIfClipped($event)\"\n >\n @if (loading()) {\n @for (_ of [1, 2, 3, 4, 5]; track $index) {\n <tr class=\"strct-dg__skeleton-row\">\n @if (canDetail()) {\n <td class=\"strct-dg__expandcell\"></td>\n }\n @if (canExpand()) {\n <td class=\"strct-dg__expandcell\"></td>\n }\n @if (hasSelectionColumn()) {\n <td class=\"strct-dg__sel\"></td>\n }\n @for (col of visibleColumns(); track col.key) {\n <td [style.text-align]=\"col.align ?? 'start'\">\n <div class=\"strct-dg__skeleton-block\"></div>\n </td>\n }\n @if (canActions()) {\n <td class=\"strct-dg__actioncell\"></td>\n }\n </tr>\n }\n } @else {\n @if (virtual() && topPad() > 0) {\n <tr class=\"strct-dg__vspacer\" aria-hidden=\"true\">\n <td [attr.colspan]=\"colspan()\" [style.height.px]=\"topPad()\"></td>\n </tr>\n }\n @for (it of displayItems(); track itemKey(it)) {\n @if (it.group; as grp) {\n <!-- Group header: distinct value + count, collapsible. -->\n <tr class=\"strct-dg__grouprow\">\n @if (groupSelect() && mode() === 'multiple') {\n <td class=\"strct-dg__sel\">\n <strct-checkbox\n [ariaLabel]=\"L().selectAllInGroup(grp.label)\"\n [checked]=\"groupAllSelected(grp.key)\"\n [indeterminate]=\"groupSomeSelected(grp.key)\"\n (checkedChange)=\"toggleGroupSelection(grp.key)\"\n />\n </td>\n }\n <td\n [attr.colspan]=\"\n groupSelect() && mode() === 'multiple' ? colspan() - 1 : colspan()\n \"\n >\n <button\n type=\"button\"\n class=\"strct-dg__groupbtn\"\n [attr.aria-expanded]=\"!grp.collapsed\"\n (click)=\"toggleGroup(grp.key)\"\n >\n <span\n class=\"strct-dg__groupchev\"\n [class.strct-dg__groupchev--open]=\"!grp.collapsed\"\n >\n <strct-icon name=\"chevronRight\" [size]=\"12\" [strokeWidth]=\"1.7\" />\n </span>\n @if (groupHeaderDef(); as tpl) {\n <!-- The consumer draws the row; the button, its\n aria-expanded and the keyboard stay ours. -->\n <ng-container\n [ngTemplateOutlet]=\"tpl.template\"\n [ngTemplateOutletContext]=\"{\n $implicit: grp,\n group: grp,\n count: grp.count,\n }\"\n />\n } @else {\n <span\n class=\"strct-dg__grouplabel strct-dg__grouplabel--{{\n grp.status ?? 'none'\n }}\"\n >{{ grp.label }}</span\n >\n <!-- The three spans run together in the button's\n name (\"Needs your decision1Blocks the join\u2026\");\n the separators are read, not seen. -->\n <span class=\"strct-dg__announcer\">, </span>\n <span\n class=\"strct-dg__groupcount strct-dg__groupcount--{{\n grp.status ?? 'none'\n }}\"\n >{{ grp.count }}</span\n >\n <!-- Seen: the chip's number. Heard: the number with\n the grid's noun, because \"Inconclusive, 3\" does\n not say three of what. -->\n <span class=\"strct-dg__announcer\"> {{ countNoun(grp.count) }}</span>\n @if (grp.note) {\n <span class=\"strct-dg__announcer\">. </span>\n <span class=\"strct-dg__groupnote\">{{ grp.note }}</span>\n }\n }\n </button>\n </td>\n </tr>\n } @else {\n @let row = it.row!;\n <tr\n [attr.aria-rowindex]=\"ariaRowIndex(row)\"\n [class.strct-dg__row--selected]=\"isSelected(row)\"\n [class.strct-dg__row--locked]=\"lockedReason(row) !== null\"\n [attr.aria-selected]=\"mode() === 'none' ? null : isSelected(row)\"\n [attr.aria-disabled]=\"lockedReason(row) !== null ? 'true' : null\"\n [attr.title]=\"lockedReason(row) || null\"\n (click)=\"onRowPick(row)\"\n [class.strct-dg__row--active]=\"paneOpen() && row === activeRow()\"\n [attr.aria-level]=\"childrenKey() ? treeDepth(row) + 1 : null\"\n [attr.aria-expanded]=\"\n childrenKey() && treeHasChildren(row) ? treeExpanded(row) : null\n \"\n [attr.tabindex]=\"\n childrenKey()\n ? treeRowTabindex(row)\n : gridMode()\n ? gridRowTabindex(row)\n : canDetail()\n ? paneRowTabindex(row)\n : null\n \"\n (keydown)=\"\n childrenKey()\n ? onTreeRowKeydown(row, $event)\n : gridMode()\n ? onGridRowKeydown(row, $event)\n : onPaneRowKeydown(row, $event)\n \"\n (dblclick)=\"onRowActivate(row)\"\n >\n @if (canDetail()) {\n <td\n class=\"strct-dg__expandcell\"\n [class.strct-dg__cell--sticky]=\"stickyActive()\"\n [style.insetInlineStart.px]=\"utilLeft('detail')\"\n >\n <button\n type=\"button\"\n [attr.tabindex]=\"ctlTabindex()\"\n class=\"strct-dg__detailbtn\"\n [class.strct-dg__detailbtn--active]=\"row === activeRow()\"\n [attr.aria-expanded]=\"row === activeRow()\"\n [attr.aria-label]=\"L().openDetail\"\n (click)=\"openDetail(row)\"\n >\n <strct-icon name=\"chevronDoubleRight\" [size]=\"13\" [strokeWidth]=\"1.6\" />\n </button>\n </td>\n }\n @if (canExpand()) {\n <td\n class=\"strct-dg__expandcell\"\n [class.strct-dg__cell--sticky]=\"stickyActive()\"\n [style.insetInlineStart.px]=\"utilLeft('expand')\"\n >\n <button\n type=\"button\"\n [attr.tabindex]=\"ctlTabindex()\"\n class=\"strct-dg__expandbtn\"\n [class.strct-dg__expandbtn--open]=\"isExpanded(row)\"\n [attr.aria-expanded]=\"isExpanded(row)\"\n [attr.aria-label]=\"L().toggleDetail\"\n (click)=\"toggleExpand(row)\"\n >\n <strct-icon name=\"chevronRight\" [size]=\"12\" [strokeWidth]=\"1.7\" />\n </button>\n </td>\n }\n @if (hasSelectionColumn()) {\n <td\n class=\"strct-dg__sel\"\n [class.strct-dg__cell--sticky]=\"stickyActive()\"\n [style.insetInlineStart.px]=\"utilLeft('sel')\"\n >\n @if (mode() === 'single') {\n <!-- A native radio group: one name per grid, so the\n arrow keys move between rows and Space picks,\n without the grid inventing its own keyboarding. -->\n <input\n type=\"radio\"\n class=\"strct-dg__radio\"\n [name]=\"radioName\"\n [attr.aria-label]=\"selectRowLabel(row)\"\n [attr.aria-description]=\"lockedReason(row) || null\"\n [checked]=\"isSelected(row)\"\n [disabled]=\"lockedReason(row) !== null\"\n [attr.tabindex]=\"ctlTabindex()\"\n (change)=\"selectSingle(row)\"\n (click)=\"$event.stopPropagation()\"\n />\n } @else {\n <!-- click fires (and bubbles) before the input's change,\n so the modifier is recorded by the time toggleRow runs. -->\n <strct-checkbox\n [ariaLabel]=\"selectRowLabel(row)\"\n [attr.aria-description]=\"lockedReason(row) || null\"\n [checked]=\"isSelected(row)\"\n [disabled]=\"lockedReason(row) !== null\"\n [tabIndex]=\"ctlTabindex()\"\n (click)=\"noteRangeIntent($event); $event.stopPropagation()\"\n (checkedChange)=\"toggleRow(row)\"\n />\n }\n </td>\n }\n @for (col of visibleColumns(); track col.key; let colIdx = $index) {\n <td\n [style.text-align]=\"col.align ?? (col.numeric ? 'end' : 'start')\"\n [class.strct-dg__cell--mono]=\"col.mono\"\n [class.strct-dg__cell--muted]=\"col.muted\"\n [class.strct-dg__cell--numeric]=\"col.numeric\"\n [class.strct-dg__cell--sticky]=\"isSticky(col)\"\n [class.strct-dg__cell--sticky-last]=\"col.key === lastStickyKey()\"\n [class.strct-dg__cell--editable]=\"col.editable\"\n [style.insetInlineStart.px]=\"stickyLeft(col.key)\"\n [attr.data-edit]=\"col.editable ? '' : null\"\n [attr.tabindex]=\"col.editable ? editCellTabindex(row, col) : null\"\n [attr.aria-describedby]=\"col.editable ? editHintId : null\"\n (dblclick)=\"col.editable && startEdit(row, col)\"\n (focus)=\"col.editable && onEditCellFocus(row, col)\"\n (keydown)=\"col.editable && onEditCellKeydown(row, col, $event)\"\n >\n @if (childrenKey() && colIdx === 0) {\n <span\n class=\"strct-dg__treepad\"\n [style.width.px]=\"treeDepth(row) * 18\"\n aria-hidden=\"true\"\n ></span>\n @if (treeHasChildren(row)) {\n <button\n type=\"button\"\n class=\"strct-dg__treebtn\"\n [class.strct-dg__treebtn--open]=\"treeExpanded(row)\"\n [attr.aria-expanded]=\"treeExpanded(row)\"\n [attr.aria-label]=\"L().toggleChildren\"\n (click)=\"toggleTreeRow(row)\"\n >\n <strct-icon name=\"chevronRight\" [size]=\"12\" [strokeWidth]=\"1.7\" />\n </button>\n } @else {\n <span\n class=\"strct-dg__treebtn strct-dg__treebtn--leaf\"\n aria-hidden=\"true\"\n ></span>\n }\n }\n @if (isEditingCell(row, col)) {\n @switch (col.editor ?? 'text') {\n @case ('select') {\n <!-- Choosing is the commit: there is nothing to\n confirm with Enter once an option is picked. -->\n <strct-select\n class=\"strct-dg__editselect\"\n [options]=\"editorOptionsFor(row, col)\"\n [listLabel]=\"L().editCell + ': ' + col.label\"\n [ngModel]=\"row[col.key]\"\n (ngModelChange)=\"commitValue(row, col, $event)\"\n (keydown.escape)=\"cancelEdit($event)\"\n (click)=\"$event.stopPropagation()\"\n />\n }\n @case ('number') {\n <strct-number\n class=\"strct-dg__editnumber\"\n [ariaLabel]=\"L().editCell + ': ' + col.label\"\n [min]=\"col.editorMin ?? null\"\n [max]=\"col.editorMax ?? null\"\n [step]=\"col.editorStep ?? 1\"\n [ngModel]=\"row[col.key]\"\n (ngModelChange)=\"editDraft.set($event)\"\n (keydown.enter)=\"commitDraft(row, col, $event)\"\n (keydown.escape)=\"cancelEdit($event)\"\n (focusout)=\"commitOnLeave(row, col, $event)\"\n (click)=\"$event.stopPropagation()\"\n />\n }\n @default {\n <input\n class=\"strct-dg__editinput\"\n type=\"text\"\n [value]=\"row[col.key] ?? ''\"\n [attr.aria-label]=\"L().editCell + ': ' + col.label\"\n (keydown.enter)=\"commitEdit(row, col, $event)\"\n (keydown.escape)=\"cancelEdit($event)\"\n (blur)=\"commitEdit(row, col, $event)\"\n (click)=\"$event.stopPropagation()\"\n />\n }\n }\n } @else if (cellTemplate(col.key); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{\n $implicit: row,\n row,\n value: row[col.key],\n column: col,\n }\"\n />\n } @else if (isBlank(row, col)) {\n <span class=\"strct-dg__empty\" [attr.aria-label]=\"col.emptyLabel || null\">{{\n col.emptyText\n }}</span>\n } @else {\n {{ displayValue(row, col) }}\n @if (col.descriptionKey && row[col.descriptionKey]) {\n <span class=\"strct-dg__celldesc\">{{ row[col.descriptionKey] }}</span>\n }\n }\n <!-- The affordance a mouse never needed: a cell that\n can be edited says so on hover and on focus. -->\n @if (col.editable && editHint() && !isEditingCell(row, col)) {\n <strct-icon\n class=\"strct-dg__editpencil\"\n name=\"pencil\"\n [size]=\"12\"\n [strokeWidth]=\"1.6\"\n aria-hidden=\"true\"\n />\n }\n </td>\n }\n @if (canActions()) {\n <td class=\"strct-dg__actioncell\">\n <button\n type=\"button\"\n [attr.tabindex]=\"ctlTabindex()\"\n class=\"strct-dg__kebab\"\n [attr.aria-label]=\"L().rowActions\"\n (click)=\"openRowMenu(row, $event)\"\n >\n <strct-icon name=\"dots\" [size]=\"16\" />\n </button>\n </td>\n }\n </tr>\n @if (canExpand() && isExpanded(row)) {\n <tr class=\"strct-dg__detailrow\">\n <td [attr.colspan]=\"colspan()\">\n <div class=\"strct-dg__detail\">\n <ng-container\n [ngTemplateOutlet]=\"detailDef()!.template\"\n [ngTemplateOutletContext]=\"{ $implicit: row, row }\"\n />\n </div>\n </td>\n </tr>\n }\n }\n } @empty {\n <!-- \"Nothing here\" and \"nothing matches what you typed\" are\n different states: the second one can be undone, and\n saying so is the whole point. -->\n <tr>\n <td class=\"strct-dg__emptyrow\" [attr.colspan]=\"colspan()\">\n @if (filteredAway()) {\n <strct-empty-state\n size=\"sm\"\n [titleLevel]=\"null\"\n [title]=\"L().noMatches\"\n [description]=\"noMatchesDescription()\"\n >\n <button strct-button variant=\"flat\" size=\"sm\" (click)=\"clearAllFilters()\">\n {{ L().clearFilters }}\n </button>\n </strct-empty-state>\n } @else {\n <!-- Not a heading: a grid is a region of a page, and an\n empty one used to put an <h3> in its outline. -->\n <strct-empty-state size=\"sm\" [titleLevel]=\"null\" [title]=\"emptyText()\" />\n }\n </td>\n </tr>\n }\n @if (virtual() && bottomPad() > 0) {\n <tr class=\"strct-dg__vspacer\" aria-hidden=\"true\">\n <td [attr.colspan]=\"colspan()\" [style.height.px]=\"bottomPad()\"></td>\n </tr>\n }\n }\n </tbody>\n </table>\n </div>\n\n @if (paneOpen()) {\n <aside class=\"strct-dg__pane\">\n <div class=\"strct-dg__pane-head\">\n @if (narrowPane()) {\n <!-- The pane has taken the list's place, so there is a way back. -->\n <button\n type=\"button\"\n class=\"strct-dg__pane-back\"\n [attr.aria-label]=\"L().backToList\"\n (click)=\"closePane()\"\n >\n <strct-icon name=\"chevronLeft\" [size]=\"13\" />\n </button>\n }\n <span class=\"strct-dg__pane-title\">\n <ng-content select=\"[strctDetailPaneTitle]\" />\n @if (!paneTitleDef()) {\n {{ activeRow()![columns()[0].key] }}\n }\n </span>\n <span class=\"strct-dg__pane-meta\">\n <ng-content select=\"[strctDetailPaneMeta]\" />\n </span>\n <span class=\"strct-dg__pane-actions\">\n <ng-content select=\"[strctDetailPaneActions]\" />\n </span>\n <button\n type=\"button\"\n class=\"strct-dg__pane-close\"\n [attr.aria-label]=\"L().closeDetail\"\n (click)=\"closePane()\"\n >\n <strct-icon name=\"close\" [size]=\"13\" />\n </button>\n </div>\n <div class=\"strct-dg__pane-body\">\n <ng-container\n [ngTemplateOutlet]=\"detailDef()!.template\"\n [ngTemplateOutletContext]=\"{ $implicit: activeRow(), row: activeRow() }\"\n />\n </div>\n </aside>\n }\n</div>\n\n@if (showFooter()) {\n <div class=\"strct-dg__foot\">\n <div class=\"strct-dg__foot-left\">\n @if (columnChooser() || sync()) {\n <div class=\"strct-dg__actions\">\n <strct-button-group>\n @if (columnChooser()) {\n <button\n strct-button\n size=\"sm\"\n [class.is-open]=\"chooserOpen()\"\n [disabled]=\"footerActionsDisabled()\"\n [attr.aria-label]=\"L().chooseColumns\"\n (click)=\"toggleChooser($event)\"\n >\n <strct-icon name=\"settings\" [size]=\"16\" />\n </button>\n }\n @if (sync()) {\n <button\n strct-button\n size=\"sm\"\n [disabled]=\"footerActionsDisabled()\"\n [attr.aria-label]=\"L().refresh\"\n (click)=\"syncChange.emit()\"\n >\n <strct-icon name=\"refresh\" [size]=\"16\" />\n </button>\n }\n </strct-button-group>\n @if (columnChooser() && chooserOpen()) {\n <div class=\"strct-dg__chooser-menu\">\n @for (col of columns(); track col.key) {\n <!-- The whole row toggles; the checkbox's own click must not\n reach the row or the column would flip twice. -->\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <div\n class=\"strct-dg__chooser-item\"\n (click)=\"toggleColumn(col.key, hiddenColumns().has(col.key))\"\n >\n <strct-checkbox\n [checked]=\"!hiddenColumns().has(col.key)\"\n (checkedChange)=\"toggleColumn(col.key, $event)\"\n (click)=\"$event.stopPropagation()\"\n />\n <span>{{ col.label }}</span>\n </div>\n }\n </div>\n }\n </div>\n }\n <span class=\"strct-dg__count\">\n @if (paging() === 'more') {\n {{ L().showing(rows().length, moreTotal() ?? undefined) }}\n } @else {\n {{ totalCount() }} {{ totalCount() === 1 ? L().row : L().rows }}\n }\n @if (selectedCount() && mode() !== 'single') {\n <span class=\"strct-dg__count-sep\">|</span>\n <span class=\"strct-dg__count-sel\">{{ selectedCount() }} {{ L().selected }}</span>\n }\n </span>\n </div>\n <div class=\"strct-dg__foot-right\">\n <!-- A feed that pages by cursor loads more at the end: page numbers\n are something a cursor API cannot answer. It takes the pager's\n place \u2014 the column chooser, the sync button and the count are\n the footer's, not the pager's. -->\n @if (paging() === 'more') {\n @if (hasMore()) {\n <button\n strct-button\n size=\"sm\"\n class=\"strct-dg__more\"\n [disabled]=\"loadingMore()\"\n (click)=\"loadMore.emit()\"\n >\n @if (loadingMore()) {\n <strct-spinner size=\"sm\" />\n }\n {{ L().loadMore }}\n </button>\n }\n } @else if (pageSize() > 0 && !groupBy()) {\n <strct-pagination\n [total]=\"totalCount()\"\n [pageSize]=\"pageSize()\"\n [page]=\"page()\"\n (pageChange)=\"goToPage($event)\"\n />\n }\n </div>\n </div>\n}\n", styles: [".strct-dg__radio{width:15px;height:15px;accent-color:var(--acc);cursor:pointer}.strct-dg__radio:disabled{cursor:not-allowed}.strct-dg__row--locked .strct-dg__sel{opacity:.55}.strct-dg__actioncaption:empty{display:none}.strct-dg__actioncaption{display:inline-flex;align-items:center;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--text-sm);color:var(--t2)}.strct-dg__bulk{display:flex;align-items:center;justify-content:center;flex-wrap:wrap;gap:4px 10px;padding:7px 12px;border-bottom:1px solid var(--b2);background:var(--acc-s);color:var(--t2);font-size:var(--text-md)}.strct-dg__announcer{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}.strct-dg-host{display:block;border:1px solid var(--b2);border-radius:var(--radius-lg);background:var(--bg-2);box-shadow:var(--shadow-rest)}.strct-dg-host--flush{border:0;border-radius:0;background:transparent;box-shadow:none}.strct-dg__more strct-spinner{margin-inline-end:4px}.strct-dg__caption{caption-side:top;text-align:start;padding:var(--space-2) var(--space-3);font-size:var(--text-sm);font-weight:600;color:var(--t2)}.strct-dg td.strct-dg__cell--mono{font-family:var(--mono);font-size:var(--text-sm)}.strct-dg td.strct-dg__cell--muted{color:var(--t2)}.strct-dg td.strct-dg__cell--numeric{font-variant-numeric:tabular-nums}.strct-dg__empty{color:var(--t2)}.strct-dg__celldesc{display:block;font-size:var(--text-sm);color:var(--t2);line-height:1.3}.strct-dg__scroll{flex:1 1 auto;min-width:0;overflow-x:auto;-webkit-overflow-scrolling:touch}.strct-dg-host--virtual .strct-dg__scroll,.strct-dg-host--bounded .strct-dg__scroll{overflow-y:auto}.strct-dg-host--virtual .strct-dg thead th,.strct-dg-host--bounded .strct-dg thead th{position:sticky;top:0;z-index:var(--z-raised)}.strct-dg__vspacer td{padding:0;border:0;background:transparent}.strct-dg th[draggable]{cursor:grab}.strct-dg__th--drop{box-shadow:inset 3px 0 0 var(--acc)}.strct-dg__grouprow td{background:var(--bg-2)!important;padding:0}.strct-dg__groupbtn{display:flex;align-items:center;gap:8px;width:100%;padding:7px 13px;border:0;background:transparent;color:var(--t1);font-family:var(--font);font-size:var(--text-sm);font-weight:600;cursor:pointer;text-align:start}.strct-dg__groupbtn:hover{background:var(--bg-3)}.strct-dg__groupbtn:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-dg__groupchev{display:inline-flex;color:var(--t3);transition:transform .15s ease}.strct-dg__groupchev--open{transform:rotate(90deg)}@media(prefers-reduced-motion:reduce){.strct-dg__groupchev{transition:none}}.strct-dg__grouplabel--critical{color:var(--critical)}.strct-dg__grouplabel--warning{color:var(--warning)}.strct-dg__grouplabel--success{color:var(--success)}.strct-dg__grouplabel--accent{color:var(--acc)}.strct-dg__grouplabel--neutral,.strct-dg__grouplabel--none{color:var(--t1)}.strct-dg__groupnote{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--text-sm);font-weight:400;color:var(--t2)}.strct-dg__groupcount{min-width:18px;height:18px;padding:0 5px;display:inline-flex;align-items:center;justify-content:center;font-size:12px;border-radius:4px;background:var(--acc-m);color:var(--acc);font-variant-numeric:tabular-nums}.strct-dg__groupcount--critical{background:var(--critical-bg);color:var(--critical)}.strct-dg__groupcount--warning{background:var(--warning-bg);color:var(--warning)}.strct-dg__groupcount--success{background:var(--success-bg);color:var(--success)}.strct-dg__groupcount--neutral,.strct-dg__groupcount--none{background:var(--bg-3);color:var(--t2)}.strct-dg-host--singleline .strct-dg{border-collapse:separate;border-spacing:0}.strct-dg-host--sticky .strct-dg,.strct-dg-host--virtual .strct-dg,.strct-dg-host--bounded .strct-dg{border-collapse:separate;border-spacing:0;overflow:visible;border-radius:0}.strct-dg-host--sticky .strct-dg{width:max-content;min-width:100%}.strct-dg .strct-dg__cell--sticky{position:sticky;z-index:calc(var(--z-base) + 2)}.strct-dg thead th.strct-dg__cell--sticky{z-index:calc(var(--z-raised) + 1)}.strct-dg .strct-dg__cell--sticky-last:after{content:\"\";position:absolute;top:0;bottom:0;inset-inline-end:-1px;width:7px;pointer-events:none;background:linear-gradient(to right,rgba(0,0,0,.14),transparent)}[dir=rtl] .strct-dg .strct-dg__cell--sticky-last:after{background:linear-gradient(to left,rgba(0,0,0,.14),transparent)}.strct-dg-host--sticky .strct-dg__expandcol,.strct-dg-host--sticky .strct-dg__expandcell{width:36px;min-width:36px;max-width:36px;box-sizing:border-box}.strct-dg-host--sticky .strct-dg__sel{width:40px;min-width:40px;max-width:40px;box-sizing:border-box}.strct-dg-host--sticky tbody .strct-dg__cell--sticky{background:var(--bg-1)}[data-theme=dark] .strct-dg-host--sticky tbody .strct-dg__cell--sticky{background:var(--bg-3)}.strct-dg-host--sticky tbody tr:hover .strct-dg__cell--sticky{background:linear-gradient(var(--acc-s),var(--acc-s)) var(--bg-1)}[data-theme=dark] .strct-dg-host--sticky tbody tr:hover .strct-dg__cell--sticky{background:linear-gradient(var(--acc-s),var(--acc-s)) var(--bg-3)}.strct-dg-host--sticky tbody .strct-dg__row--selected .strct-dg__cell--sticky{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-1)}[data-theme=dark] .strct-dg-host--sticky tbody .strct-dg__row--selected .strct-dg__cell--sticky{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-3)}.strct-dg{width:100%;border-collapse:collapse;font-size:13px;overflow:hidden;background:var(--bg-2)}.strct-dg-host:not(:has(.strct-dg__toolbar)) .strct-dg{border-start-start-radius:4px;border-start-end-radius:4px}.strct-dg-host:not(:has(.strct-dg__foot)) .strct-dg{border-end-start-radius:4px;border-end-end-radius:4px}.strct-dg th,.strct-dg td{padding:9px 13px;text-align:start;border-bottom:1px solid var(--b1)}.strct-dg tbody td{background:var(--bg-1)}[data-theme=dark] .strct-dg tbody td{background:var(--bg-3)}.strct-dg-host--compact .strct-dg th,.strct-dg-host--compact .strct-dg td{padding:5px 11px}.strct-dg-host--singleline .strct-dg tbody tr:not(.strct-dg__detailrow)>td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:360px}.strct-dg th{position:relative;font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.4px;color:var(--t2);background:var(--bg-2);white-space:nowrap;-webkit-user-select:none;user-select:none}.strct-dg__th--sortable{cursor:pointer}.strct-dg__th--sortable:hover{color:var(--t1)}.strct-dg__sortbtn{display:inline-flex;align-items:center;gap:inherit;padding:0;border:0;background:none;color:inherit;font:inherit;text-transform:inherit;letter-spacing:inherit;text-align:inherit;cursor:pointer}.strct-dg__sortbtn:focus-visible{outline:2px solid var(--acc50);outline-offset:2px;border-radius:var(--radius-sm)}.strct-dg__th--sortable:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-dg__hd{display:inline-flex;align-items:center;gap:5px}.strct-dg__sorticon{color:var(--t3)}.strct-dg__th--sortable:hover .strct-dg__sorticon{color:var(--acc)}.strct-dg__resize{position:absolute;inset-inline-end:0;top:0;bottom:0;width:4px;cursor:col-resize;background:transparent;z-index:calc(var(--z-base) + 1)}.strct-dg__resize:hover{background:var(--acc)}.strct-dg td{color:var(--t1)}.strct-dg tbody tr:last-child td{border-bottom:0}.strct-dg tbody tr:not(.strct-dg__detailrow):hover td{background:linear-gradient(var(--acc-s),var(--acc-s)) var(--bg-1)}[data-theme=dark] .strct-dg tbody tr:not(.strct-dg__detailrow):hover td{background:linear-gradient(var(--acc-s),var(--acc-s)) var(--bg-3)}.strct-dg tbody .strct-dg__row--selected td{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-1)}[data-theme=dark] .strct-dg tbody .strct-dg__row--selected td{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-3)}.strct-dg tbody tr.strct-dg__row--selected:hover td{background:linear-gradient(var(--acc-s),var(--acc-s)),linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-1)}[data-theme=dark] .strct-dg tbody tr.strct-dg__row--selected:hover td{background:linear-gradient(var(--acc-s),var(--acc-s)),linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-3)}.strct-dg__sel{width:1%;white-space:nowrap}.strct-dg__sel .strct-cb,.strct-dg__sel .strct-dg__radio,.strct-dg__expandbtn{position:relative}.strct-dg__sel .strct-cb:after,.strct-dg__sel .strct-dg__radio:after,.strct-dg__expandbtn:after{content:\"\";position:absolute;inset:-11px -13px;min-width:24px;min-height:24px}.strct-dg-host--compact .strct-dg__sel .strct-cb:after,.strct-dg-host--compact .strct-dg__sel .strct-dg__radio:after,.strct-dg-host--compact .strct-dg__expandbtn:after{inset:-7px -11px}.strct-dg__sel input{accent-color:var(--acc);width:15px;height:15px;cursor:pointer}.strct-dg__expandcol,.strct-dg__expandcell{width:1%;white-space:nowrap}.strct-dg__actioncol,.strct-dg__actioncell{width:1%;white-space:nowrap;text-align:end}.strct-dg__kebab{display:inline-flex;padding:4px;border:0;border-radius:2px;background:transparent;color:var(--t3);cursor:pointer;transition:color .14s ease,background .14s ease}.strct-dg__kebab:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__expandbtn{position:relative;display:inline-flex;align-items:center;justify-content:center;padding:3px;border:0;border-radius:2px;background:transparent;color:var(--t3);cursor:pointer;transition:transform .15s ease,color .15s ease}.strct-dg__expandbtn:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__expandbtn--open{transform:rotate(90deg);color:var(--acc)}.strct-dg__detailbtn{display:inline-flex;padding:3px;border:0;border-radius:2px;background:transparent;color:var(--t3);cursor:pointer;transition:color .14s ease,background .14s ease}.strct-dg__detailbtn:hover{color:var(--acc);background:var(--bg-3)}.strct-dg__detailbtn--active{color:var(--acc);background:var(--acc-m)}.strct-dg__detailrow td{background:var(--bg-2);padding:0}.strct-dg__detail{padding:14px 16px;font-size:13px;color:var(--t2)}.strct-dg__layout{display:flex;align-items:flex-start;min-width:0}.strct-dg__layout--paned{gap:0}.strct-dg__layout--paned>.strct-dg__scroll{flex:0 0 auto;width:var(--strct-dg-pane-list-w, 260px);min-width:var(--strct-dg-pane-list-w, 260px);max-width:var(--strct-dg-pane-list-w, 260px)}.strct-dg__layout--paned>.strct-dg__scroll>.strct-dg{width:100%;min-width:0;max-width:none;flex-shrink:0;border-start-end-radius:0;border-end-end-radius:0}.strct-dg__layout--panetakeover>.strct-dg__scroll{display:none}.strct-dg__layout--panetakeover>.strct-dg__pane{flex:1;min-width:0}.strct-dg__pane-meta,.strct-dg__pane-actions{display:inline-flex;align-items:center;gap:var(--space-2)}.strct-dg__pane-meta:empty,.strct-dg__pane-actions:empty{display:none}.strct-dg__pane-actions{margin-inline-start:auto}.strct-dg__pane-back{display:inline-flex;align-items:center;border:0;background:none;color:var(--t2);cursor:pointer;padding:2px;border-radius:var(--radius-sm)}.strct-dg__row--clickable{cursor:pointer}.strct-dg tbody .strct-dg__row--active td{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-1)}[data-theme=dark] .strct-dg tbody .strct-dg__row--active td{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-3)}.strct-dg__layout--paned .strct-dg__row--active td:last-child{position:relative;padding-inline-end:26px}.strct-dg__layout--paned .strct-dg__row--active td:last-child:after{content:\"\";position:absolute;inset-inline-end:11px;top:50%;width:6px;height:6px;border-top:1.6px solid var(--acc);border-inline-end:1.6px solid var(--acc);transform:translateY(-50%) rotate(45deg)}.strct-dg__pane{flex:1;min-width:0;align-self:stretch;background:var(--bg-1);border:1px solid var(--b2);border-inline-start:2px solid var(--acc);border-radius:4px;border-start-start-radius:0;border-end-start-radius:0;overflow:hidden;animation:strct-dg-pane-in .14s ease}.strct-dg__pane-head{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:11px 14px;border-bottom:1px solid var(--b1);font-size:13px;font-weight:600;color:var(--t1)}.strct-dg__pane-close{display:inline-flex;padding:3px;border:0;border-radius:2px;background:transparent;color:var(--t3);cursor:pointer}.strct-dg__pane-close:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__pane-body{padding:14px 16px;font-size:13px;color:var(--t2)}@keyframes strct-dg-pane-in{0%{opacity:0;transform:translate(8px)}}@keyframes strct-skeleton-pulse{0%,to{opacity:.4}50%{opacity:.7}}.strct-dg__skeleton-block{height:12px;border-radius:var(--radius-sm);background:linear-gradient(90deg,var(--bg-3) 25%,var(--skeleton-hi, var(--acc18)) 50%,var(--bg-3) 75%);background-size:200% 100%;animation:strct-dg-skeleton-sweep 1.1s linear infinite}@keyframes strct-dg-skeleton-sweep{0%{background-position:100% 0}to{background-position:-100% 0}}@media(prefers-reduced-motion:reduce){.strct-dg__skeleton-block{animation:none;background:var(--skeleton-hi, var(--acc18))}}.strct-dg__skeleton-row td{border-bottom:1px solid var(--b1)}.strct-dg__empty{text-align:center;color:var(--t2);padding:22px}.strct-dg__quickfilter{min-width:180px;max-width:260px}.strct-dg__quickfilter--end{order:2;margin-inline-start:auto}.strct-dg__filternote--end{order:3}.strct-dg__filternote{font-size:var(--text-sm);color:var(--t2);font-variant-numeric:tabular-nums;white-space:nowrap}.strct-dg__toolbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:9px 14px;border-bottom:1px solid var(--b2)}.strct-dg__foot{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:9px 14px;border-top:1px solid var(--b2);flex-wrap:wrap}.strct-dg__foot-left,.strct-dg__foot-right{display:flex;align-items:center;gap:12px}.strct-dg__actions{position:relative}.strct-dg__chooser-menu{position:absolute;bottom:calc(100% + 6px);inset-inline-start:0;z-index:var(--z-sticky);min-width:180px;background:var(--bg-1);border:1px solid var(--b2);border-radius:4px;box-shadow:var(--shadow-pop);padding:6px;display:flex;flex-direction:column;gap:2px}.strct-dg__chooser-menu--right{inset-inline-start:auto;inset-inline-end:0}.strct-dg__chooser-item{display:flex;align-items:center;gap:8px;padding:5px 8px;border-radius:3px;cursor:pointer;font-size:12px;color:var(--t1);transition:background .1s ease;-webkit-user-select:none;user-select:none}.strct-dg__chooser-item:hover{background:var(--bg-3)}.strct-dg__count{font-size:12px;color:var(--t2)}.strct-dg__count-sep{margin:0 8px;color:var(--b2)}.strct-dg__count-sel{color:var(--acc)}.strct-dg__filterbtn{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;margin-inline-start:2px;padding:0;border:0;border-radius:2px;background:transparent;color:var(--t3);cursor:pointer;vertical-align:middle}.strct-dg__filterbtn:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__filterbtn--active{color:var(--acc)}.strct-dg__filterbtn:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-dg__filterpanel{position:absolute;z-index:calc(var(--z-dropdown) + 10);display:flex;flex-direction:column;gap:6px;min-width:180px;padding:10px;background:var(--bg-1);border:1px solid var(--b2);border-radius:3px;box-shadow:var(--shh);font-weight:400;text-transform:none;letter-spacing:normal;white-space:nowrap}.strct-dg__filterinput{padding:5px 8px;border:1px solid var(--b2);border-radius:var(--radius-sm);background:var(--bg-2);color:var(--t1);font-family:var(--font);font-size:12px}.strct-dg__filterinput:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-dg__filteropt{display:flex;align-items:center;gap:7px;font-size:12.5px;color:var(--t1);cursor:pointer}.strct-dg__filterclear{align-self:flex-start;padding:3px 8px;border:1px solid var(--b2);border-radius:var(--radius-sm);background:transparent;color:var(--t2);font-family:var(--font);font-size:var(--text-sm);cursor:pointer}.strct-dg__filterclear:hover:not(:disabled){color:var(--t1);background:var(--bg-3)}.strct-dg__filterclear:disabled{color:var(--t4);cursor:default}.strct-dg tbody tr[tabindex]:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-dg__treepad{display:inline-block;height:1px;vertical-align:middle}.strct-dg__treebtn{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;margin-inline-end:4px;padding:0;border:0;border-radius:2px;background:transparent;color:var(--t3);cursor:pointer;vertical-align:middle}.strct-dg__treebtn:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__treebtn:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-dg__treebtn strct-icon{transition:transform .15s ease}.strct-dg__treebtn--open strct-icon{transform:rotate(90deg)}.strct-dg__treebtn--leaf{cursor:default;pointer-events:none}@media(prefers-reduced-motion:reduce){.strct-dg__treebtn strct-icon{transition:none}}.strct-dg__cell--editable{cursor:text;position:relative}.strct-dg__cell--editable:hover{box-shadow:inset 0 0 0 1px var(--b2)}.strct-dg__cell--editable:focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--acc50)}.strct-dg__editpencil{position:absolute;top:50%;inset-inline-end:6px;transform:translateY(-50%);color:var(--t3);opacity:0;pointer-events:none}td:hover>.strct-dg__editpencil,td:focus-within>.strct-dg__editpencil{opacity:1}.strct-dg__editinput{width:100%;box-sizing:border-box;padding:3px 6px;border:1px solid var(--acc);border-radius:var(--radius-sm);background:var(--bg-1);color:var(--t1);font:inherit}.strct-dg__editselect,.strct-dg__editnumber{display:block;width:100%}.strct-dg__editinput:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "strictName", "size", "strokeWidth", "badge", "mode", "modeLabel", "ariaLabel", "count", "countMax", "countStatus", "countLabel"] }, { kind: "component", type: StrctPagination, selector: "strct-pagination", inputs: ["prevLabel", "nextLabel", "regionLabel", "pageLabel", "total", "pageSize", "page"], outputs: ["pageChange"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: StrctCheckbox, selector: "strct-checkbox", inputs: ["checked", "disabled", "indeterminate", "ariaLabel", "description", "tabIndex"], outputs: ["checkedChange"] }, { kind: "component", type: StrctButton, selector: "button[strct-button], a[strct-button]", inputs: ["variant", "size", "solid", "block", "iconOnly", "disabled", "disabledReason", "disabledReasonPosition"] }, { kind: "component", type: StrctButtonGroup, selector: "strct-button-group" }, { kind: "directive", type: StrctOverlay, selector: "[strctOverlay]", inputs: ["strctOverlay", "strctOverlayPlacement", "strctOverlayMatchWidth", "strctOverlayGap"] }, { kind: "component", type: StrctSearchbox, selector: "strct-searchbox", inputs: ["placeholder", "hint", "trigger", "clearable", "ariaLabel", "clearLabel", "value"], outputs: ["valueChange", "search", "activated"] }, { kind: "component", type: StrctSelect, selector: "strct-select", inputs: ["options", "placeholder", "ariaLabel", "listLabel", "emptyText", "disabled", "compareWith"] }, { kind: "component", type: StrctNumber, selector: "strct-number", inputs: ["min", "max", "step", "placeholder", "ariaLabel", "incrementLabel", "decrementLabel", "disabled"] }, { kind: "component", type: StrctSpinner, selector: "strct-spinner", inputs: ["size", "label", "caption"] }, { kind: "component", type: StrctEmptyState, selector: "strct-empty-state", inputs: ["variant", "icon", "tone", "title", "titleLevel", "size", "description"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
18405
17822
|
}
|
|
18406
17823
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctDatagrid, decorators: [{
|
|
18407
17824
|
type: Component,
|
|
@@ -18419,796 +17836,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
|
|
|
18419
17836
|
StrctSpinner,
|
|
18420
17837
|
StrctEmptyState,
|
|
18421
17838
|
FormsModule,
|
|
18422
|
-
],
|
|
18423
|
-
<!-- One polite region for everything the grid does to itself: sorting,
|
|
18424
|
-
paging and filtering all change the rows without saying so. -->
|
|
18425
|
-
<span class="strct-dg__announcer" role="status" aria-live="polite">{{ announcement() }}</span>
|
|
18426
|
-
@if (actionBarDef() || quickFilterable() || actionBarCaptionDef()) {
|
|
18427
|
-
<div class="strct-dg__toolbar">
|
|
18428
|
-
@if (quickFilterable()) {
|
|
18429
|
-
<strct-searchbox
|
|
18430
|
-
class="strct-dg__quickfilter"
|
|
18431
|
-
[class.strct-dg__quickfilter--end]="quickFilterAlign() === 'end'"
|
|
18432
|
-
[placeholder]="L().quickFilter"
|
|
18433
|
-
[ariaLabel]="L().quickFilter"
|
|
18434
|
-
[value]="quickFilter()"
|
|
18435
|
-
(valueChange)="quickFilter.set($event)"
|
|
18436
|
-
/>
|
|
18437
|
-
@if (filterNote(); as note) {
|
|
18438
|
-
<span
|
|
18439
|
-
class="strct-dg__filternote"
|
|
18440
|
-
[class.strct-dg__filternote--end]="quickFilterAlign() === 'end'"
|
|
18441
|
-
>{{ note }}</span
|
|
18442
|
-
>
|
|
18443
|
-
}
|
|
18444
|
-
}
|
|
18445
|
-
<span class="strct-dg__actioncaption">
|
|
18446
|
-
<ng-content select="[strctDatagridActionBarCaption]" />
|
|
18447
|
-
</span>
|
|
18448
|
-
<ng-content select="[strctDatagridActionBar]" />
|
|
18449
|
-
</div>
|
|
18450
|
-
}
|
|
18451
|
-
|
|
18452
|
-
@if (hasEditableColumn()) {
|
|
18453
|
-
<!-- What the editable cells point at with aria-describedby: a keyboard
|
|
18454
|
-
user is told the cell can be edited, and how. -->
|
|
18455
|
-
<!-- In flow, not absolutely positioned: an out-of-flow box whose
|
|
18456
|
-
containing block is the page extends the document's scrollable area
|
|
18457
|
-
from wherever the grid happens to sit. 1x1 and clipped is enough. -->
|
|
18458
|
-
<span
|
|
18459
|
-
class="strct-sr-only"
|
|
18460
|
-
style="display: inline-block; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap"
|
|
18461
|
-
[id]="editHintId"
|
|
18462
|
-
>{{ L().editCellInstructions }}</span
|
|
18463
|
-
>
|
|
18464
|
-
}
|
|
18465
|
-
|
|
18466
|
-
@if (bulkHint(); as hint) {
|
|
18467
|
-
<!-- Selecting the page is not selecting the set. Say which one happened,
|
|
18468
|
-
and offer the other. -->
|
|
18469
|
-
<div class="strct-dg__bulk" role="status">
|
|
18470
|
-
<span>{{ hint.text }}</span>
|
|
18471
|
-
<button strct-button variant="flat" size="sm" (click)="hint.run()">
|
|
18472
|
-
{{ hint.action }}
|
|
18473
|
-
</button>
|
|
18474
|
-
</div>
|
|
18475
|
-
}
|
|
18476
|
-
<div
|
|
18477
|
-
class="strct-dg__layout"
|
|
18478
|
-
[class.strct-dg__layout--paned]="paneOpen()"
|
|
18479
|
-
[class.strct-dg__layout--panetakeover]="paneOpen() && narrowPane()"
|
|
18480
|
-
[style.--strct-dg-pane-list-w]="paneListWidth()"
|
|
18481
|
-
>
|
|
18482
|
-
<div
|
|
18483
|
-
class="strct-dg__scroll"
|
|
18484
|
-
tabindex="0"
|
|
18485
|
-
role="region"
|
|
18486
|
-
[attr.aria-label]="L().rows"
|
|
18487
|
-
[style.max-height.px]="virtual() ? viewportHeight() : maxHeight()"
|
|
18488
|
-
(scroll)="virtual() && onScroll($event)"
|
|
18489
|
-
>
|
|
18490
|
-
<table
|
|
18491
|
-
class="strct-dg"
|
|
18492
|
-
[attr.role]="childrenKey() ? 'treegrid' : gridMode() ? 'grid' : null"
|
|
18493
|
-
[attr.aria-rowcount]="ariaRowCount()"
|
|
18494
|
-
[attr.aria-labelledby]="caption() ? captionId : null"
|
|
18495
|
-
>
|
|
18496
|
-
@if (caption()) {
|
|
18497
|
-
<caption class="strct-dg__caption" [id]="captionId">
|
|
18498
|
-
{{
|
|
18499
|
-
caption()
|
|
18500
|
-
}}
|
|
18501
|
-
</caption>
|
|
18502
|
-
}
|
|
18503
|
-
<thead>
|
|
18504
|
-
<tr>
|
|
18505
|
-
<!-- A utility column is still a column: axe reports every empty
|
|
18506
|
-
header, and a screen-reader user hears nothing where the
|
|
18507
|
-
detail, expand and select controls are. The name is hidden,
|
|
18508
|
-
not absent. -->
|
|
18509
|
-
@if (canDetail()) {
|
|
18510
|
-
<th
|
|
18511
|
-
class="strct-dg__expandcol"
|
|
18512
|
-
scope="col"
|
|
18513
|
-
[class.strct-dg__cell--sticky]="stickyActive()"
|
|
18514
|
-
[style.insetInlineStart.px]="utilLeft('detail')"
|
|
18515
|
-
>
|
|
18516
|
-
<span class="strct-sr-only">{{ L().detailColumn }}</span>
|
|
18517
|
-
</th>
|
|
18518
|
-
}
|
|
18519
|
-
@if (canExpand()) {
|
|
18520
|
-
<th
|
|
18521
|
-
class="strct-dg__expandcol"
|
|
18522
|
-
scope="col"
|
|
18523
|
-
[class.strct-dg__cell--sticky]="stickyActive()"
|
|
18524
|
-
[style.insetInlineStart.px]="utilLeft('expand')"
|
|
18525
|
-
>
|
|
18526
|
-
<span class="strct-sr-only">{{ L().expandColumn }}</span>
|
|
18527
|
-
</th>
|
|
18528
|
-
}
|
|
18529
|
-
@if (hasSelectionColumn()) {
|
|
18530
|
-
<th
|
|
18531
|
-
class="strct-dg__sel"
|
|
18532
|
-
scope="col"
|
|
18533
|
-
[class.strct-dg__cell--sticky]="stickyActive()"
|
|
18534
|
-
[style.insetInlineStart.px]="utilLeft('sel')"
|
|
18535
|
-
>
|
|
18536
|
-
@if (mode() === 'multiple') {
|
|
18537
|
-
<strct-checkbox
|
|
18538
|
-
[ariaLabel]="L().selectAll"
|
|
18539
|
-
[checked]="allPageSelected()"
|
|
18540
|
-
[indeterminate]="somePageSelected()"
|
|
18541
|
-
(checkedChange)="toggleAll()"
|
|
18542
|
-
/>
|
|
18543
|
-
} @else {
|
|
18544
|
-
<span class="strct-sr-only">{{ L().selectColumn }}</span>
|
|
18545
|
-
}
|
|
18546
|
-
</th>
|
|
18547
|
-
}
|
|
18548
|
-
@for (col of visibleColumns(); track col.key) {
|
|
18549
|
-
<th
|
|
18550
|
-
scope="col"
|
|
18551
|
-
[style.text-align]="col.align ?? (col.numeric ? 'end' : 'start')"
|
|
18552
|
-
[style.width]="colWidth(col.key) ?? col.width ?? null"
|
|
18553
|
-
[class.strct-dg__th--sortable]="col.sortable"
|
|
18554
|
-
[class.strct-dg__th--drop]="col.key === dropKey()"
|
|
18555
|
-
[class.strct-dg__cell--sticky]="isSticky(col)"
|
|
18556
|
-
[class.strct-dg__cell--sticky-last]="col.key === lastStickyKey()"
|
|
18557
|
-
[style.insetInlineStart.px]="stickyLeft(col.key)"
|
|
18558
|
-
[attr.data-col]="col.key"
|
|
18559
|
-
[attr.aria-sort]="col.sortable ? ariaSort(col.key) : null"
|
|
18560
|
-
[attr.draggable]="reorderable() ? true : null"
|
|
18561
|
-
(dragstart)="onColDragStart(col.key, $event)"
|
|
18562
|
-
(dragover)="onColDragOver(col.key, $event)"
|
|
18563
|
-
(drop)="onColDrop(col.key)"
|
|
18564
|
-
(dragend)="onColDragEnd()"
|
|
18565
|
-
>
|
|
18566
|
-
<span class="strct-dg__hd">
|
|
18567
|
-
<!-- A header that sorts is a button: a th with tabindex is
|
|
18568
|
-
read as "column header, focusable" and never says it
|
|
18569
|
-
can be activated. aria-sort stays on the th, which is
|
|
18570
|
-
what carries the column's sorted state. -->
|
|
18571
|
-
@if (col.sortable) {
|
|
18572
|
-
<!-- The button covers most of the header, so it carries
|
|
18573
|
-
the drag source too: a reorderable column has to be
|
|
18574
|
-
grabbable where the pointer actually lands. The
|
|
18575
|
-
event bubbles to the th's own handlers. -->
|
|
18576
|
-
<button
|
|
18577
|
-
type="button"
|
|
18578
|
-
class="strct-dg__sortbtn"
|
|
18579
|
-
[attr.draggable]="reorderable() ? true : null"
|
|
18580
|
-
(click)="sortBy(col.key)"
|
|
18581
|
-
>
|
|
18582
|
-
{{ col.label }}
|
|
18583
|
-
<strct-icon
|
|
18584
|
-
class="strct-dg__sorticon"
|
|
18585
|
-
[name]="sortIcon(col.key)"
|
|
18586
|
-
[size]="13"
|
|
18587
|
-
/>
|
|
18588
|
-
</button>
|
|
18589
|
-
} @else {
|
|
18590
|
-
{{ col.label }}
|
|
18591
|
-
}
|
|
18592
|
-
@if (col.filterable || col.filterOptions) {
|
|
18593
|
-
<button
|
|
18594
|
-
#fbtn
|
|
18595
|
-
type="button"
|
|
18596
|
-
class="strct-dg__filterbtn"
|
|
18597
|
-
[class.strct-dg__filterbtn--active]="hasFilter(col.key)"
|
|
18598
|
-
[attr.aria-expanded]="filterOpenKey() === col.key"
|
|
18599
|
-
[attr.aria-label]="L().filterColumn + ': ' + col.label"
|
|
18600
|
-
(click)="toggleFilterPanel(col.key, $event)"
|
|
18601
|
-
(keydown.enter)="$event.stopPropagation()"
|
|
18602
|
-
(keydown.space)="$event.stopPropagation()"
|
|
18603
|
-
>
|
|
18604
|
-
<strct-icon name="filter" [size]="12" />
|
|
18605
|
-
</button>
|
|
18606
|
-
@if (filterOpenKey() === col.key) {
|
|
18607
|
-
<div
|
|
18608
|
-
class="strct-dg__filterpanel"
|
|
18609
|
-
role="dialog"
|
|
18610
|
-
[attr.aria-label]="L().filterColumn + ': ' + col.label"
|
|
18611
|
-
[strctOverlay]="fbtn"
|
|
18612
|
-
strctOverlayPlacement="bottom-start"
|
|
18613
|
-
(click)="$event.stopPropagation()"
|
|
18614
|
-
(keydown.enter)="$event.stopPropagation()"
|
|
18615
|
-
(keydown.space)="$event.stopPropagation()"
|
|
18616
|
-
>
|
|
18617
|
-
@if (col.filterOptions; as opts) {
|
|
18618
|
-
@for (opt of opts; track $index) {
|
|
18619
|
-
<label class="strct-dg__filteropt">
|
|
18620
|
-
<input
|
|
18621
|
-
type="checkbox"
|
|
18622
|
-
[checked]="optionChecked(col.key, opt)"
|
|
18623
|
-
(change)="toggleFilterOption(col.key, opt)"
|
|
18624
|
-
/>
|
|
18625
|
-
<span>{{ opt }}</span>
|
|
18626
|
-
</label>
|
|
18627
|
-
}
|
|
18628
|
-
} @else {
|
|
18629
|
-
<input
|
|
18630
|
-
class="strct-dg__filterinput"
|
|
18631
|
-
type="text"
|
|
18632
|
-
[attr.placeholder]="L().filterPlaceholder"
|
|
18633
|
-
[attr.aria-label]="L().filterColumn + ': ' + col.label"
|
|
18634
|
-
[value]="textFilter(col.key)"
|
|
18635
|
-
(input)="setTextFilter(col.key, $any($event.target).value)"
|
|
18636
|
-
/>
|
|
18637
|
-
}
|
|
18638
|
-
<button
|
|
18639
|
-
type="button"
|
|
18640
|
-
class="strct-dg__filterclear"
|
|
18641
|
-
[disabled]="!hasFilter(col.key)"
|
|
18642
|
-
(click)="clearFilter(col.key)"
|
|
18643
|
-
>
|
|
18644
|
-
{{ L().clearFilter }}
|
|
18645
|
-
</button>
|
|
18646
|
-
</div>
|
|
18647
|
-
}
|
|
18648
|
-
}
|
|
18649
|
-
</span>
|
|
18650
|
-
@if (resizable() && col.resizable !== false) {
|
|
18651
|
-
<!-- A separator, not a bare div: a column could only be
|
|
18652
|
-
resized with a mouse, which is the one input a
|
|
18653
|
-
console cannot assume. -->
|
|
18654
|
-
<div
|
|
18655
|
-
class="strct-dg__resize"
|
|
18656
|
-
role="separator"
|
|
18657
|
-
aria-orientation="vertical"
|
|
18658
|
-
tabindex="0"
|
|
18659
|
-
[attr.aria-label]="L().resizeColumn(col.label)"
|
|
18660
|
-
[attr.aria-valuenow]="separatorValue(col.key)"
|
|
18661
|
-
[attr.aria-valuemin]="40"
|
|
18662
|
-
(mousedown)="onResizeStart($event, col.key)"
|
|
18663
|
-
(keydown)="onResizeKey($event, col.key)"
|
|
18664
|
-
(dblclick)="resetWidth(col.key)"
|
|
18665
|
-
></div>
|
|
18666
|
-
}
|
|
18667
|
-
</th>
|
|
18668
|
-
}
|
|
18669
|
-
@if (canActions()) {
|
|
18670
|
-
<th class="strct-dg__actioncol" scope="col" [attr.aria-label]="L().actions"></th>
|
|
18671
|
-
}
|
|
18672
|
-
</tr>
|
|
18673
|
-
</thead>
|
|
18674
|
-
<!--
|
|
18675
|
-
focusin is the real keyboard path (focus does not bubble from cells);
|
|
18676
|
-
the plain focus binding exists to satisfy mouse-events-have-key-events.
|
|
18677
|
-
-->
|
|
18678
|
-
<tbody
|
|
18679
|
-
(mouseover)="revealIfClipped($event)"
|
|
18680
|
-
(focusin)="revealIfClipped($event)"
|
|
18681
|
-
(focus)="revealIfClipped($event)"
|
|
18682
|
-
>
|
|
18683
|
-
@if (loading()) {
|
|
18684
|
-
@for (_ of [1, 2, 3, 4, 5]; track $index) {
|
|
18685
|
-
<tr class="strct-dg__skeleton-row">
|
|
18686
|
-
@if (canDetail()) {
|
|
18687
|
-
<td class="strct-dg__expandcell"></td>
|
|
18688
|
-
}
|
|
18689
|
-
@if (canExpand()) {
|
|
18690
|
-
<td class="strct-dg__expandcell"></td>
|
|
18691
|
-
}
|
|
18692
|
-
@if (hasSelectionColumn()) {
|
|
18693
|
-
<td class="strct-dg__sel"></td>
|
|
18694
|
-
}
|
|
18695
|
-
@for (col of visibleColumns(); track col.key) {
|
|
18696
|
-
<td [style.text-align]="col.align ?? 'start'">
|
|
18697
|
-
<div class="strct-dg__skeleton-block"></div>
|
|
18698
|
-
</td>
|
|
18699
|
-
}
|
|
18700
|
-
@if (canActions()) {
|
|
18701
|
-
<td class="strct-dg__actioncell"></td>
|
|
18702
|
-
}
|
|
18703
|
-
</tr>
|
|
18704
|
-
}
|
|
18705
|
-
} @else {
|
|
18706
|
-
@if (virtual() && topPad() > 0) {
|
|
18707
|
-
<tr class="strct-dg__vspacer" aria-hidden="true">
|
|
18708
|
-
<td [attr.colspan]="colspan()" [style.height.px]="topPad()"></td>
|
|
18709
|
-
</tr>
|
|
18710
|
-
}
|
|
18711
|
-
@for (it of displayItems(); track itemKey(it)) {
|
|
18712
|
-
@if (it.group; as grp) {
|
|
18713
|
-
<!-- Group header: distinct value + count, collapsible. -->
|
|
18714
|
-
<tr class="strct-dg__grouprow">
|
|
18715
|
-
@if (groupSelect() && mode() === 'multiple') {
|
|
18716
|
-
<td class="strct-dg__sel">
|
|
18717
|
-
<strct-checkbox
|
|
18718
|
-
[ariaLabel]="L().selectAllInGroup(grp.label)"
|
|
18719
|
-
[checked]="groupAllSelected(grp.key)"
|
|
18720
|
-
[indeterminate]="groupSomeSelected(grp.key)"
|
|
18721
|
-
(checkedChange)="toggleGroupSelection(grp.key)"
|
|
18722
|
-
/>
|
|
18723
|
-
</td>
|
|
18724
|
-
}
|
|
18725
|
-
<td
|
|
18726
|
-
[attr.colspan]="
|
|
18727
|
-
groupSelect() && mode() === 'multiple' ? colspan() - 1 : colspan()
|
|
18728
|
-
"
|
|
18729
|
-
>
|
|
18730
|
-
<button
|
|
18731
|
-
type="button"
|
|
18732
|
-
class="strct-dg__groupbtn"
|
|
18733
|
-
[attr.aria-expanded]="!grp.collapsed"
|
|
18734
|
-
(click)="toggleGroup(grp.key)"
|
|
18735
|
-
>
|
|
18736
|
-
<span
|
|
18737
|
-
class="strct-dg__groupchev"
|
|
18738
|
-
[class.strct-dg__groupchev--open]="!grp.collapsed"
|
|
18739
|
-
>
|
|
18740
|
-
<strct-icon name="chevronRight" [size]="12" [strokeWidth]="1.7" />
|
|
18741
|
-
</span>
|
|
18742
|
-
@if (groupHeaderDef(); as tpl) {
|
|
18743
|
-
<!-- The consumer draws the row; the button, its
|
|
18744
|
-
aria-expanded and the keyboard stay ours. -->
|
|
18745
|
-
<ng-container
|
|
18746
|
-
[ngTemplateOutlet]="tpl.template"
|
|
18747
|
-
[ngTemplateOutletContext]="{
|
|
18748
|
-
$implicit: grp,
|
|
18749
|
-
group: grp,
|
|
18750
|
-
count: grp.count,
|
|
18751
|
-
}"
|
|
18752
|
-
/>
|
|
18753
|
-
} @else {
|
|
18754
|
-
<span
|
|
18755
|
-
class="strct-dg__grouplabel strct-dg__grouplabel--{{
|
|
18756
|
-
grp.status ?? 'none'
|
|
18757
|
-
}}"
|
|
18758
|
-
>{{ grp.label }}</span
|
|
18759
|
-
>
|
|
18760
|
-
<!-- The three spans run together in the button's
|
|
18761
|
-
name ("Needs your decision1Blocks the join…");
|
|
18762
|
-
the separators are read, not seen. -->
|
|
18763
|
-
<span class="strct-dg__announcer">, </span>
|
|
18764
|
-
<span
|
|
18765
|
-
class="strct-dg__groupcount strct-dg__groupcount--{{
|
|
18766
|
-
grp.status ?? 'none'
|
|
18767
|
-
}}"
|
|
18768
|
-
>{{ grp.count }}</span
|
|
18769
|
-
>
|
|
18770
|
-
<!-- Seen: the chip's number. Heard: the number with
|
|
18771
|
-
the grid's noun, because "Inconclusive, 3" does
|
|
18772
|
-
not say three of what. -->
|
|
18773
|
-
<span class="strct-dg__announcer"> {{ countNoun(grp.count) }}</span>
|
|
18774
|
-
@if (grp.note) {
|
|
18775
|
-
<span class="strct-dg__announcer">. </span>
|
|
18776
|
-
<span class="strct-dg__groupnote">{{ grp.note }}</span>
|
|
18777
|
-
}
|
|
18778
|
-
}
|
|
18779
|
-
</button>
|
|
18780
|
-
</td>
|
|
18781
|
-
</tr>
|
|
18782
|
-
} @else {
|
|
18783
|
-
@let row = it.row!;
|
|
18784
|
-
<tr
|
|
18785
|
-
[attr.aria-rowindex]="ariaRowIndex(row)"
|
|
18786
|
-
[class.strct-dg__row--selected]="isSelected(row)"
|
|
18787
|
-
[class.strct-dg__row--locked]="lockedReason(row) !== null"
|
|
18788
|
-
[attr.aria-selected]="mode() === 'none' ? null : isSelected(row)"
|
|
18789
|
-
[attr.aria-disabled]="lockedReason(row) !== null ? 'true' : null"
|
|
18790
|
-
[attr.title]="lockedReason(row) || null"
|
|
18791
|
-
(click)="onRowPick(row)"
|
|
18792
|
-
[class.strct-dg__row--active]="paneOpen() && row === activeRow()"
|
|
18793
|
-
[attr.aria-level]="childrenKey() ? treeDepth(row) + 1 : null"
|
|
18794
|
-
[attr.aria-expanded]="
|
|
18795
|
-
childrenKey() && treeHasChildren(row) ? treeExpanded(row) : null
|
|
18796
|
-
"
|
|
18797
|
-
[attr.tabindex]="
|
|
18798
|
-
childrenKey()
|
|
18799
|
-
? treeRowTabindex(row)
|
|
18800
|
-
: gridMode()
|
|
18801
|
-
? gridRowTabindex(row)
|
|
18802
|
-
: canDetail()
|
|
18803
|
-
? paneRowTabindex(row)
|
|
18804
|
-
: null
|
|
18805
|
-
"
|
|
18806
|
-
(keydown)="
|
|
18807
|
-
childrenKey()
|
|
18808
|
-
? onTreeRowKeydown(row, $event)
|
|
18809
|
-
: gridMode()
|
|
18810
|
-
? onGridRowKeydown(row, $event)
|
|
18811
|
-
: onPaneRowKeydown(row, $event)
|
|
18812
|
-
"
|
|
18813
|
-
(dblclick)="onRowActivate(row)"
|
|
18814
|
-
>
|
|
18815
|
-
@if (canDetail()) {
|
|
18816
|
-
<td
|
|
18817
|
-
class="strct-dg__expandcell"
|
|
18818
|
-
[class.strct-dg__cell--sticky]="stickyActive()"
|
|
18819
|
-
[style.insetInlineStart.px]="utilLeft('detail')"
|
|
18820
|
-
>
|
|
18821
|
-
<button
|
|
18822
|
-
type="button"
|
|
18823
|
-
[attr.tabindex]="ctlTabindex()"
|
|
18824
|
-
class="strct-dg__detailbtn"
|
|
18825
|
-
[class.strct-dg__detailbtn--active]="row === activeRow()"
|
|
18826
|
-
[attr.aria-expanded]="row === activeRow()"
|
|
18827
|
-
[attr.aria-label]="L().openDetail"
|
|
18828
|
-
(click)="openDetail(row)"
|
|
18829
|
-
>
|
|
18830
|
-
<strct-icon name="chevronDoubleRight" [size]="13" [strokeWidth]="1.6" />
|
|
18831
|
-
</button>
|
|
18832
|
-
</td>
|
|
18833
|
-
}
|
|
18834
|
-
@if (canExpand()) {
|
|
18835
|
-
<td
|
|
18836
|
-
class="strct-dg__expandcell"
|
|
18837
|
-
[class.strct-dg__cell--sticky]="stickyActive()"
|
|
18838
|
-
[style.insetInlineStart.px]="utilLeft('expand')"
|
|
18839
|
-
>
|
|
18840
|
-
<button
|
|
18841
|
-
type="button"
|
|
18842
|
-
[attr.tabindex]="ctlTabindex()"
|
|
18843
|
-
class="strct-dg__expandbtn"
|
|
18844
|
-
[class.strct-dg__expandbtn--open]="isExpanded(row)"
|
|
18845
|
-
[attr.aria-expanded]="isExpanded(row)"
|
|
18846
|
-
[attr.aria-label]="L().toggleDetail"
|
|
18847
|
-
(click)="toggleExpand(row)"
|
|
18848
|
-
>
|
|
18849
|
-
<strct-icon name="chevronRight" [size]="12" [strokeWidth]="1.7" />
|
|
18850
|
-
</button>
|
|
18851
|
-
</td>
|
|
18852
|
-
}
|
|
18853
|
-
@if (hasSelectionColumn()) {
|
|
18854
|
-
<td
|
|
18855
|
-
class="strct-dg__sel"
|
|
18856
|
-
[class.strct-dg__cell--sticky]="stickyActive()"
|
|
18857
|
-
[style.insetInlineStart.px]="utilLeft('sel')"
|
|
18858
|
-
>
|
|
18859
|
-
@if (mode() === 'single') {
|
|
18860
|
-
<!-- A native radio group: one name per grid, so the
|
|
18861
|
-
arrow keys move between rows and Space picks,
|
|
18862
|
-
without the grid inventing its own keyboarding. -->
|
|
18863
|
-
<input
|
|
18864
|
-
type="radio"
|
|
18865
|
-
class="strct-dg__radio"
|
|
18866
|
-
[name]="radioName"
|
|
18867
|
-
[attr.aria-label]="selectRowLabel(row)"
|
|
18868
|
-
[attr.aria-description]="lockedReason(row) || null"
|
|
18869
|
-
[checked]="isSelected(row)"
|
|
18870
|
-
[disabled]="lockedReason(row) !== null"
|
|
18871
|
-
[attr.tabindex]="ctlTabindex()"
|
|
18872
|
-
(change)="selectSingle(row)"
|
|
18873
|
-
(click)="$event.stopPropagation()"
|
|
18874
|
-
/>
|
|
18875
|
-
} @else {
|
|
18876
|
-
<!-- click fires (and bubbles) before the input's change,
|
|
18877
|
-
so the modifier is recorded by the time toggleRow runs. -->
|
|
18878
|
-
<strct-checkbox
|
|
18879
|
-
[ariaLabel]="selectRowLabel(row)"
|
|
18880
|
-
[attr.aria-description]="lockedReason(row) || null"
|
|
18881
|
-
[checked]="isSelected(row)"
|
|
18882
|
-
[disabled]="lockedReason(row) !== null"
|
|
18883
|
-
[tabIndex]="ctlTabindex()"
|
|
18884
|
-
(click)="noteRangeIntent($event); $event.stopPropagation()"
|
|
18885
|
-
(checkedChange)="toggleRow(row)"
|
|
18886
|
-
/>
|
|
18887
|
-
}
|
|
18888
|
-
</td>
|
|
18889
|
-
}
|
|
18890
|
-
@for (col of visibleColumns(); track col.key; let colIdx = $index) {
|
|
18891
|
-
<td
|
|
18892
|
-
[style.text-align]="col.align ?? (col.numeric ? 'end' : 'start')"
|
|
18893
|
-
[class.strct-dg__cell--mono]="col.mono"
|
|
18894
|
-
[class.strct-dg__cell--muted]="col.muted"
|
|
18895
|
-
[class.strct-dg__cell--numeric]="col.numeric"
|
|
18896
|
-
[class.strct-dg__cell--sticky]="isSticky(col)"
|
|
18897
|
-
[class.strct-dg__cell--sticky-last]="col.key === lastStickyKey()"
|
|
18898
|
-
[class.strct-dg__cell--editable]="col.editable"
|
|
18899
|
-
[style.insetInlineStart.px]="stickyLeft(col.key)"
|
|
18900
|
-
[attr.data-edit]="col.editable ? '' : null"
|
|
18901
|
-
[attr.tabindex]="col.editable ? editCellTabindex(row, col) : null"
|
|
18902
|
-
[attr.aria-describedby]="col.editable ? editHintId : null"
|
|
18903
|
-
(dblclick)="col.editable && startEdit(row, col)"
|
|
18904
|
-
(focus)="col.editable && onEditCellFocus(row, col)"
|
|
18905
|
-
(keydown)="col.editable && onEditCellKeydown(row, col, $event)"
|
|
18906
|
-
>
|
|
18907
|
-
@if (childrenKey() && colIdx === 0) {
|
|
18908
|
-
<span
|
|
18909
|
-
class="strct-dg__treepad"
|
|
18910
|
-
[style.width.px]="treeDepth(row) * 18"
|
|
18911
|
-
aria-hidden="true"
|
|
18912
|
-
></span>
|
|
18913
|
-
@if (treeHasChildren(row)) {
|
|
18914
|
-
<button
|
|
18915
|
-
type="button"
|
|
18916
|
-
class="strct-dg__treebtn"
|
|
18917
|
-
[class.strct-dg__treebtn--open]="treeExpanded(row)"
|
|
18918
|
-
[attr.aria-expanded]="treeExpanded(row)"
|
|
18919
|
-
[attr.aria-label]="L().toggleChildren"
|
|
18920
|
-
(click)="toggleTreeRow(row)"
|
|
18921
|
-
>
|
|
18922
|
-
<strct-icon name="chevronRight" [size]="12" [strokeWidth]="1.7" />
|
|
18923
|
-
</button>
|
|
18924
|
-
} @else {
|
|
18925
|
-
<span
|
|
18926
|
-
class="strct-dg__treebtn strct-dg__treebtn--leaf"
|
|
18927
|
-
aria-hidden="true"
|
|
18928
|
-
></span>
|
|
18929
|
-
}
|
|
18930
|
-
}
|
|
18931
|
-
@if (isEditingCell(row, col)) {
|
|
18932
|
-
@switch (col.editor ?? 'text') {
|
|
18933
|
-
@case ('select') {
|
|
18934
|
-
<!-- Choosing is the commit: there is nothing to
|
|
18935
|
-
confirm with Enter once an option is picked. -->
|
|
18936
|
-
<strct-select
|
|
18937
|
-
class="strct-dg__editselect"
|
|
18938
|
-
[options]="editorOptionsFor(row, col)"
|
|
18939
|
-
[listLabel]="L().editCell + ': ' + col.label"
|
|
18940
|
-
[ngModel]="row[col.key]"
|
|
18941
|
-
(ngModelChange)="commitValue(row, col, $event)"
|
|
18942
|
-
(keydown.escape)="cancelEdit($event)"
|
|
18943
|
-
(click)="$event.stopPropagation()"
|
|
18944
|
-
/>
|
|
18945
|
-
}
|
|
18946
|
-
@case ('number') {
|
|
18947
|
-
<strct-number
|
|
18948
|
-
class="strct-dg__editnumber"
|
|
18949
|
-
[ariaLabel]="L().editCell + ': ' + col.label"
|
|
18950
|
-
[min]="col.editorMin ?? null"
|
|
18951
|
-
[max]="col.editorMax ?? null"
|
|
18952
|
-
[step]="col.editorStep ?? 1"
|
|
18953
|
-
[ngModel]="row[col.key]"
|
|
18954
|
-
(ngModelChange)="editDraft.set($event)"
|
|
18955
|
-
(keydown.enter)="commitDraft(row, col, $event)"
|
|
18956
|
-
(keydown.escape)="cancelEdit($event)"
|
|
18957
|
-
(focusout)="commitOnLeave(row, col, $event)"
|
|
18958
|
-
(click)="$event.stopPropagation()"
|
|
18959
|
-
/>
|
|
18960
|
-
}
|
|
18961
|
-
@default {
|
|
18962
|
-
<input
|
|
18963
|
-
class="strct-dg__editinput"
|
|
18964
|
-
type="text"
|
|
18965
|
-
[value]="row[col.key] ?? ''"
|
|
18966
|
-
[attr.aria-label]="L().editCell + ': ' + col.label"
|
|
18967
|
-
(keydown.enter)="commitEdit(row, col, $event)"
|
|
18968
|
-
(keydown.escape)="cancelEdit($event)"
|
|
18969
|
-
(blur)="commitEdit(row, col, $event)"
|
|
18970
|
-
(click)="$event.stopPropagation()"
|
|
18971
|
-
/>
|
|
18972
|
-
}
|
|
18973
|
-
}
|
|
18974
|
-
} @else if (cellTemplate(col.key); as tpl) {
|
|
18975
|
-
<ng-container
|
|
18976
|
-
[ngTemplateOutlet]="tpl"
|
|
18977
|
-
[ngTemplateOutletContext]="{
|
|
18978
|
-
$implicit: row,
|
|
18979
|
-
row,
|
|
18980
|
-
value: row[col.key],
|
|
18981
|
-
column: col,
|
|
18982
|
-
}"
|
|
18983
|
-
/>
|
|
18984
|
-
} @else if (isBlank(row, col)) {
|
|
18985
|
-
<span
|
|
18986
|
-
class="strct-dg__empty"
|
|
18987
|
-
[attr.aria-label]="col.emptyLabel || null"
|
|
18988
|
-
>{{ col.emptyText }}</span
|
|
18989
|
-
>
|
|
18990
|
-
} @else {
|
|
18991
|
-
{{ displayValue(row, col) }}
|
|
18992
|
-
@if (col.descriptionKey && row[col.descriptionKey]) {
|
|
18993
|
-
<span class="strct-dg__celldesc">{{ row[col.descriptionKey] }}</span>
|
|
18994
|
-
}
|
|
18995
|
-
}
|
|
18996
|
-
<!-- The affordance a mouse never needed: a cell that
|
|
18997
|
-
can be edited says so on hover and on focus. -->
|
|
18998
|
-
@if (col.editable && editHint() && !isEditingCell(row, col)) {
|
|
18999
|
-
<strct-icon
|
|
19000
|
-
class="strct-dg__editpencil"
|
|
19001
|
-
name="pencil"
|
|
19002
|
-
[size]="12"
|
|
19003
|
-
[strokeWidth]="1.6"
|
|
19004
|
-
aria-hidden="true"
|
|
19005
|
-
/>
|
|
19006
|
-
}
|
|
19007
|
-
</td>
|
|
19008
|
-
}
|
|
19009
|
-
@if (canActions()) {
|
|
19010
|
-
<td class="strct-dg__actioncell">
|
|
19011
|
-
<button
|
|
19012
|
-
type="button"
|
|
19013
|
-
[attr.tabindex]="ctlTabindex()"
|
|
19014
|
-
class="strct-dg__kebab"
|
|
19015
|
-
[attr.aria-label]="L().rowActions"
|
|
19016
|
-
(click)="openRowMenu(row, $event)"
|
|
19017
|
-
>
|
|
19018
|
-
<strct-icon name="dots" [size]="16" />
|
|
19019
|
-
</button>
|
|
19020
|
-
</td>
|
|
19021
|
-
}
|
|
19022
|
-
</tr>
|
|
19023
|
-
@if (canExpand() && isExpanded(row)) {
|
|
19024
|
-
<tr class="strct-dg__detailrow">
|
|
19025
|
-
<td [attr.colspan]="colspan()">
|
|
19026
|
-
<div class="strct-dg__detail">
|
|
19027
|
-
<ng-container
|
|
19028
|
-
[ngTemplateOutlet]="detailDef()!.template"
|
|
19029
|
-
[ngTemplateOutletContext]="{ $implicit: row, row }"
|
|
19030
|
-
/>
|
|
19031
|
-
</div>
|
|
19032
|
-
</td>
|
|
19033
|
-
</tr>
|
|
19034
|
-
}
|
|
19035
|
-
}
|
|
19036
|
-
} @empty {
|
|
19037
|
-
<!-- "Nothing here" and "nothing matches what you typed" are
|
|
19038
|
-
different states: the second one can be undone, and
|
|
19039
|
-
saying so is the whole point. -->
|
|
19040
|
-
<tr>
|
|
19041
|
-
<td class="strct-dg__emptyrow" [attr.colspan]="colspan()">
|
|
19042
|
-
@if (filteredAway()) {
|
|
19043
|
-
<strct-empty-state
|
|
19044
|
-
size="sm"
|
|
19045
|
-
[titleLevel]="null"
|
|
19046
|
-
[title]="L().noMatches"
|
|
19047
|
-
[description]="noMatchesDescription()"
|
|
19048
|
-
>
|
|
19049
|
-
<button strct-button variant="flat" size="sm" (click)="clearAllFilters()">
|
|
19050
|
-
{{ L().clearFilters }}
|
|
19051
|
-
</button>
|
|
19052
|
-
</strct-empty-state>
|
|
19053
|
-
} @else {
|
|
19054
|
-
<!-- Not a heading: a grid is a region of a page, and an
|
|
19055
|
-
empty one used to put an <h3> in its outline. -->
|
|
19056
|
-
<strct-empty-state size="sm" [titleLevel]="null" [title]="emptyText()" />
|
|
19057
|
-
}
|
|
19058
|
-
</td>
|
|
19059
|
-
</tr>
|
|
19060
|
-
}
|
|
19061
|
-
@if (virtual() && bottomPad() > 0) {
|
|
19062
|
-
<tr class="strct-dg__vspacer" aria-hidden="true">
|
|
19063
|
-
<td [attr.colspan]="colspan()" [style.height.px]="bottomPad()"></td>
|
|
19064
|
-
</tr>
|
|
19065
|
-
}
|
|
19066
|
-
}
|
|
19067
|
-
</tbody>
|
|
19068
|
-
</table>
|
|
19069
|
-
</div>
|
|
19070
|
-
|
|
19071
|
-
@if (paneOpen()) {
|
|
19072
|
-
<aside class="strct-dg__pane">
|
|
19073
|
-
<div class="strct-dg__pane-head">
|
|
19074
|
-
@if (narrowPane()) {
|
|
19075
|
-
<!-- The pane has taken the list's place, so there is a way back. -->
|
|
19076
|
-
<button
|
|
19077
|
-
type="button"
|
|
19078
|
-
class="strct-dg__pane-back"
|
|
19079
|
-
[attr.aria-label]="L().backToList"
|
|
19080
|
-
(click)="closePane()"
|
|
19081
|
-
>
|
|
19082
|
-
<strct-icon name="chevronLeft" [size]="13" />
|
|
19083
|
-
</button>
|
|
19084
|
-
}
|
|
19085
|
-
<span class="strct-dg__pane-title">
|
|
19086
|
-
<ng-content select="[strctDetailPaneTitle]" />
|
|
19087
|
-
@if (!paneTitleDef()) {
|
|
19088
|
-
{{ activeRow()![columns()[0].key] }}
|
|
19089
|
-
}
|
|
19090
|
-
</span>
|
|
19091
|
-
<span class="strct-dg__pane-meta">
|
|
19092
|
-
<ng-content select="[strctDetailPaneMeta]" />
|
|
19093
|
-
</span>
|
|
19094
|
-
<span class="strct-dg__pane-actions">
|
|
19095
|
-
<ng-content select="[strctDetailPaneActions]" />
|
|
19096
|
-
</span>
|
|
19097
|
-
<button
|
|
19098
|
-
type="button"
|
|
19099
|
-
class="strct-dg__pane-close"
|
|
19100
|
-
[attr.aria-label]="L().closeDetail"
|
|
19101
|
-
(click)="closePane()"
|
|
19102
|
-
>
|
|
19103
|
-
<strct-icon name="close" [size]="13" />
|
|
19104
|
-
</button>
|
|
19105
|
-
</div>
|
|
19106
|
-
<div class="strct-dg__pane-body">
|
|
19107
|
-
<ng-container
|
|
19108
|
-
[ngTemplateOutlet]="detailDef()!.template"
|
|
19109
|
-
[ngTemplateOutletContext]="{ $implicit: activeRow(), row: activeRow() }"
|
|
19110
|
-
/>
|
|
19111
|
-
</div>
|
|
19112
|
-
</aside>
|
|
19113
|
-
}
|
|
19114
|
-
</div>
|
|
19115
|
-
|
|
19116
|
-
@if (showFooter()) {
|
|
19117
|
-
<div class="strct-dg__foot">
|
|
19118
|
-
<div class="strct-dg__foot-left">
|
|
19119
|
-
@if (columnChooser() || sync()) {
|
|
19120
|
-
<div class="strct-dg__actions">
|
|
19121
|
-
<strct-button-group>
|
|
19122
|
-
@if (columnChooser()) {
|
|
19123
|
-
<button
|
|
19124
|
-
strct-button
|
|
19125
|
-
size="sm"
|
|
19126
|
-
[class.is-open]="chooserOpen()"
|
|
19127
|
-
[disabled]="footerActionsDisabled()"
|
|
19128
|
-
[attr.aria-label]="L().chooseColumns"
|
|
19129
|
-
(click)="toggleChooser($event)"
|
|
19130
|
-
>
|
|
19131
|
-
<strct-icon name="settings" [size]="16" />
|
|
19132
|
-
</button>
|
|
19133
|
-
}
|
|
19134
|
-
@if (sync()) {
|
|
19135
|
-
<button
|
|
19136
|
-
strct-button
|
|
19137
|
-
size="sm"
|
|
19138
|
-
[disabled]="footerActionsDisabled()"
|
|
19139
|
-
[attr.aria-label]="L().refresh"
|
|
19140
|
-
(click)="syncChange.emit()"
|
|
19141
|
-
>
|
|
19142
|
-
<strct-icon name="refresh" [size]="16" />
|
|
19143
|
-
</button>
|
|
19144
|
-
}
|
|
19145
|
-
</strct-button-group>
|
|
19146
|
-
@if (columnChooser() && chooserOpen()) {
|
|
19147
|
-
<div class="strct-dg__chooser-menu">
|
|
19148
|
-
@for (col of columns(); track col.key) {
|
|
19149
|
-
<!-- The whole row toggles; the checkbox's own click must not
|
|
19150
|
-
reach the row or the column would flip twice. -->
|
|
19151
|
-
<!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->
|
|
19152
|
-
<div
|
|
19153
|
-
class="strct-dg__chooser-item"
|
|
19154
|
-
(click)="toggleColumn(col.key, hiddenColumns().has(col.key))"
|
|
19155
|
-
>
|
|
19156
|
-
<strct-checkbox
|
|
19157
|
-
[checked]="!hiddenColumns().has(col.key)"
|
|
19158
|
-
(checkedChange)="toggleColumn(col.key, $event)"
|
|
19159
|
-
(click)="$event.stopPropagation()"
|
|
19160
|
-
/>
|
|
19161
|
-
<span>{{ col.label }}</span>
|
|
19162
|
-
</div>
|
|
19163
|
-
}
|
|
19164
|
-
</div>
|
|
19165
|
-
}
|
|
19166
|
-
</div>
|
|
19167
|
-
}
|
|
19168
|
-
<span class="strct-dg__count">
|
|
19169
|
-
@if (paging() === 'more') {
|
|
19170
|
-
{{ L().showing(rows().length, moreTotal() ?? undefined) }}
|
|
19171
|
-
} @else {
|
|
19172
|
-
{{ totalCount() }} {{ totalCount() === 1 ? L().row : L().rows }}
|
|
19173
|
-
}
|
|
19174
|
-
@if (selectedCount() && mode() !== 'single') {
|
|
19175
|
-
<span class="strct-dg__count-sep">|</span>
|
|
19176
|
-
<span class="strct-dg__count-sel">{{ selectedCount() }} {{ L().selected }}</span>
|
|
19177
|
-
}
|
|
19178
|
-
</span>
|
|
19179
|
-
</div>
|
|
19180
|
-
<div class="strct-dg__foot-right">
|
|
19181
|
-
<!-- A feed that pages by cursor loads more at the end: page numbers
|
|
19182
|
-
are something a cursor API cannot answer. It takes the pager's
|
|
19183
|
-
place — the column chooser, the sync button and the count are
|
|
19184
|
-
the footer's, not the pager's. -->
|
|
19185
|
-
@if (paging() === 'more') {
|
|
19186
|
-
@if (hasMore()) {
|
|
19187
|
-
<button
|
|
19188
|
-
strct-button
|
|
19189
|
-
size="sm"
|
|
19190
|
-
class="strct-dg__more"
|
|
19191
|
-
[disabled]="loadingMore()"
|
|
19192
|
-
(click)="loadMore.emit()"
|
|
19193
|
-
>
|
|
19194
|
-
@if (loadingMore()) {
|
|
19195
|
-
<strct-spinner size="sm" />
|
|
19196
|
-
}
|
|
19197
|
-
{{ L().loadMore }}
|
|
19198
|
-
</button>
|
|
19199
|
-
}
|
|
19200
|
-
} @else if (pageSize() > 0 && !groupBy()) {
|
|
19201
|
-
<strct-pagination
|
|
19202
|
-
[total]="totalCount()"
|
|
19203
|
-
[pageSize]="pageSize()"
|
|
19204
|
-
[page]="page()"
|
|
19205
|
-
(pageChange)="goToPage($event)"
|
|
19206
|
-
/>
|
|
19207
|
-
}
|
|
19208
|
-
</div>
|
|
19209
|
-
</div>
|
|
19210
|
-
}
|
|
19211
|
-
`, host: {
|
|
17839
|
+
], host: {
|
|
19212
17840
|
class: 'strct-dg-host',
|
|
19213
17841
|
// The skeleton rows say "updating" to the eye; this says it to everyone else.
|
|
19214
17842
|
'[attr.aria-busy]': 'loading() || loadingMore() ? "true" : null',
|
|
@@ -19218,8 +17846,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
|
|
|
19218
17846
|
'[class.strct-dg-host--bounded]': '!virtual() && maxHeight() !== null',
|
|
19219
17847
|
'[class.strct-dg-host--sticky]': 'stickyActive()',
|
|
19220
17848
|
'[class.strct-dg-host--flush]': 'flush()',
|
|
19221
|
-
}, styles: [".strct-dg__radio{width:15px;height:15px;accent-color:var(--acc);cursor:pointer}.strct-dg__radio:disabled{cursor:not-allowed}.strct-dg__row--locked .strct-dg__sel{opacity:.55}.strct-dg__actioncaption:empty{display:none}.strct-dg__actioncaption{display:inline-flex;align-items:center;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--text-sm);color:var(--t2)}.strct-dg__bulk{display:flex;align-items:center;justify-content:center;flex-wrap:wrap;gap:4px 10px;padding:7px 12px;border-bottom:1px solid var(--b2);background:var(--acc-s);color:var(--t2);font-size:var(--text-md)}.strct-dg__announcer{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}.strct-dg-host{display:block;border:1px solid var(--b2);border-radius:var(--radius-lg);background:var(--bg-2);box-shadow:var(--shadow-rest)}.strct-dg-host--flush{border:0;border-radius:0;background:transparent;box-shadow:none}.strct-dg__more strct-spinner{margin-inline-end:4px}.strct-dg__caption{caption-side:top;text-align:start;padding:var(--space-2) var(--space-3);font-size:var(--text-sm);font-weight:600;color:var(--t2)}.strct-dg td.strct-dg__cell--mono{font-family:var(--mono);font-size:var(--text-sm)}.strct-dg td.strct-dg__cell--muted{color:var(--t2)}.strct-dg td.strct-dg__cell--numeric{font-variant-numeric:tabular-nums}.strct-dg__empty{color:var(--t2)}.strct-dg__celldesc{display:block;font-size:var(--text-sm);color:var(--t2);line-height:1.3}.strct-dg__scroll{flex:1 1 auto;min-width:0;overflow-x:auto;-webkit-overflow-scrolling:touch}.strct-dg-host--virtual .strct-dg__scroll,.strct-dg-host--bounded .strct-dg__scroll{overflow-y:auto}.strct-dg-host--virtual .strct-dg thead th,.strct-dg-host--bounded .strct-dg thead th{position:sticky;top:0;z-index:var(--z-raised)}.strct-dg__vspacer td{padding:0;border:0;background:transparent}.strct-dg th[draggable]{cursor:grab}.strct-dg__th--drop{box-shadow:inset 3px 0 0 var(--acc)}.strct-dg__grouprow td{background:var(--bg-2)!important;padding:0}.strct-dg__groupbtn{display:flex;align-items:center;gap:8px;width:100%;padding:7px 13px;border:0;background:transparent;color:var(--t1);font-family:var(--font);font-size:var(--text-sm);font-weight:600;cursor:pointer;text-align:start}.strct-dg__groupbtn:hover{background:var(--bg-3)}.strct-dg__groupbtn:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-dg__groupchev{display:inline-flex;color:var(--t3);transition:transform .15s ease}.strct-dg__groupchev--open{transform:rotate(90deg)}@media(prefers-reduced-motion:reduce){.strct-dg__groupchev{transition:none}}.strct-dg__grouplabel--critical{color:var(--critical)}.strct-dg__grouplabel--warning{color:var(--warning)}.strct-dg__grouplabel--success{color:var(--success)}.strct-dg__grouplabel--accent{color:var(--acc)}.strct-dg__grouplabel--neutral,.strct-dg__grouplabel--none{color:var(--t1)}.strct-dg__groupnote{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--text-sm);font-weight:400;color:var(--t2)}.strct-dg__groupcount{min-width:18px;height:18px;padding:0 5px;display:inline-flex;align-items:center;justify-content:center;font-size:12px;border-radius:4px;background:var(--acc-m);color:var(--acc);font-variant-numeric:tabular-nums}.strct-dg__groupcount--critical{background:var(--critical-bg);color:var(--critical)}.strct-dg__groupcount--warning{background:var(--warning-bg);color:var(--warning)}.strct-dg__groupcount--success{background:var(--success-bg);color:var(--success)}.strct-dg__groupcount--neutral,.strct-dg__groupcount--none{background:var(--bg-3);color:var(--t2)}.strct-dg-host--singleline .strct-dg{border-collapse:separate;border-spacing:0}.strct-dg-host--sticky .strct-dg,.strct-dg-host--virtual .strct-dg,.strct-dg-host--bounded .strct-dg{border-collapse:separate;border-spacing:0;overflow:visible;border-radius:0}.strct-dg-host--sticky .strct-dg{width:max-content;min-width:100%}.strct-dg .strct-dg__cell--sticky{position:sticky;z-index:calc(var(--z-base) + 2)}.strct-dg thead th.strct-dg__cell--sticky{z-index:calc(var(--z-raised) + 1)}.strct-dg .strct-dg__cell--sticky-last:after{content:\"\";position:absolute;top:0;bottom:0;inset-inline-end:-1px;width:7px;pointer-events:none;background:linear-gradient(to right,rgba(0,0,0,.14),transparent)}[dir=rtl] .strct-dg .strct-dg__cell--sticky-last:after{background:linear-gradient(to left,rgba(0,0,0,.14),transparent)}.strct-dg-host--sticky .strct-dg__expandcol,.strct-dg-host--sticky .strct-dg__expandcell{width:36px;min-width:36px;max-width:36px;box-sizing:border-box}.strct-dg-host--sticky .strct-dg__sel{width:40px;min-width:40px;max-width:40px;box-sizing:border-box}.strct-dg-host--sticky tbody .strct-dg__cell--sticky{background:var(--bg-1)}[data-theme=dark] .strct-dg-host--sticky tbody .strct-dg__cell--sticky{background:var(--bg-3)}.strct-dg-host--sticky tbody tr:hover .strct-dg__cell--sticky{background:linear-gradient(var(--acc-s),var(--acc-s)) var(--bg-1)}[data-theme=dark] .strct-dg-host--sticky tbody tr:hover .strct-dg__cell--sticky{background:linear-gradient(var(--acc-s),var(--acc-s)) var(--bg-3)}.strct-dg-host--sticky tbody .strct-dg__row--selected .strct-dg__cell--sticky{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-1)}[data-theme=dark] .strct-dg-host--sticky tbody .strct-dg__row--selected .strct-dg__cell--sticky{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-3)}.strct-dg{width:100%;border-collapse:collapse;font-size:13px;overflow:hidden;background:var(--bg-2)}.strct-dg-host:not(:has(.strct-dg__toolbar)) .strct-dg{border-start-start-radius:4px;border-start-end-radius:4px}.strct-dg-host:not(:has(.strct-dg__foot)) .strct-dg{border-end-start-radius:4px;border-end-end-radius:4px}.strct-dg th,.strct-dg td{padding:9px 13px;text-align:start;border-bottom:1px solid var(--b1)}.strct-dg tbody td{background:var(--bg-1)}[data-theme=dark] .strct-dg tbody td{background:var(--bg-3)}.strct-dg-host--compact .strct-dg th,.strct-dg-host--compact .strct-dg td{padding:5px 11px}.strct-dg-host--singleline .strct-dg tbody tr:not(.strct-dg__detailrow)>td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:360px}.strct-dg th{position:relative;font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.4px;color:var(--t2);background:var(--bg-2);white-space:nowrap;-webkit-user-select:none;user-select:none}.strct-dg__th--sortable{cursor:pointer}.strct-dg__th--sortable:hover{color:var(--t1)}.strct-dg__sortbtn{display:inline-flex;align-items:center;gap:inherit;padding:0;border:0;background:none;color:inherit;font:inherit;text-transform:inherit;letter-spacing:inherit;text-align:inherit;cursor:pointer}.strct-dg__sortbtn:focus-visible{outline:2px solid var(--acc50);outline-offset:2px;border-radius:var(--radius-sm)}.strct-dg__th--sortable:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-dg__hd{display:inline-flex;align-items:center;gap:5px}.strct-dg__sorticon{color:var(--t3)}.strct-dg__th--sortable:hover .strct-dg__sorticon{color:var(--acc)}.strct-dg__resize{position:absolute;inset-inline-end:0;top:0;bottom:0;width:4px;cursor:col-resize;background:transparent;z-index:calc(var(--z-base) + 1)}.strct-dg__resize:hover{background:var(--acc)}.strct-dg td{color:var(--t1)}.strct-dg tbody tr:last-child td{border-bottom:0}.strct-dg tbody tr:not(.strct-dg__detailrow):hover td{background:linear-gradient(var(--acc-s),var(--acc-s)) var(--bg-1)}[data-theme=dark] .strct-dg tbody tr:not(.strct-dg__detailrow):hover td{background:linear-gradient(var(--acc-s),var(--acc-s)) var(--bg-3)}.strct-dg tbody .strct-dg__row--selected td{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-1)}[data-theme=dark] .strct-dg tbody .strct-dg__row--selected td{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-3)}.strct-dg tbody tr.strct-dg__row--selected:hover td{background:linear-gradient(var(--acc-s),var(--acc-s)),linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-1)}[data-theme=dark] .strct-dg tbody tr.strct-dg__row--selected:hover td{background:linear-gradient(var(--acc-s),var(--acc-s)),linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-3)}.strct-dg__sel{width:1%;white-space:nowrap}.strct-dg__sel .strct-cb,.strct-dg__sel .strct-dg__radio,.strct-dg__expandbtn{position:relative}.strct-dg__sel .strct-cb:after,.strct-dg__sel .strct-dg__radio:after,.strct-dg__expandbtn:after{content:\"\";position:absolute;inset:-11px -13px;min-width:24px;min-height:24px}.strct-dg-host--compact .strct-dg__sel .strct-cb:after,.strct-dg-host--compact .strct-dg__sel .strct-dg__radio:after,.strct-dg-host--compact .strct-dg__expandbtn:after{inset:-7px -11px}.strct-dg__sel input{accent-color:var(--acc);width:15px;height:15px;cursor:pointer}.strct-dg__expandcol,.strct-dg__expandcell{width:1%;white-space:nowrap}.strct-dg__actioncol,.strct-dg__actioncell{width:1%;white-space:nowrap;text-align:end}.strct-dg__kebab{display:inline-flex;padding:4px;border:0;border-radius:2px;background:transparent;color:var(--t3);cursor:pointer;transition:color .14s ease,background .14s ease}.strct-dg__kebab:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__expandbtn{position:relative;display:inline-flex;align-items:center;justify-content:center;padding:3px;border:0;border-radius:2px;background:transparent;color:var(--t3);cursor:pointer;transition:transform .15s ease,color .15s ease}.strct-dg__expandbtn:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__expandbtn--open{transform:rotate(90deg);color:var(--acc)}.strct-dg__detailbtn{display:inline-flex;padding:3px;border:0;border-radius:2px;background:transparent;color:var(--t3);cursor:pointer;transition:color .14s ease,background .14s ease}.strct-dg__detailbtn:hover{color:var(--acc);background:var(--bg-3)}.strct-dg__detailbtn--active{color:var(--acc);background:var(--acc-m)}.strct-dg__detailrow td{background:var(--bg-2);padding:0}.strct-dg__detail{padding:14px 16px;font-size:13px;color:var(--t2)}.strct-dg__layout{display:flex;align-items:flex-start;min-width:0}.strct-dg__layout--paned{gap:0}.strct-dg__layout--paned>.strct-dg__scroll{flex:0 0 auto;width:var(--strct-dg-pane-list-w, 260px);min-width:var(--strct-dg-pane-list-w, 260px);max-width:var(--strct-dg-pane-list-w, 260px)}.strct-dg__layout--paned>.strct-dg__scroll>.strct-dg{width:100%;min-width:0;max-width:none;flex-shrink:0;border-start-end-radius:0;border-end-end-radius:0}.strct-dg__layout--panetakeover>.strct-dg__scroll{display:none}.strct-dg__layout--panetakeover>.strct-dg__pane{flex:1;min-width:0}.strct-dg__pane-meta,.strct-dg__pane-actions{display:inline-flex;align-items:center;gap:var(--space-2)}.strct-dg__pane-meta:empty,.strct-dg__pane-actions:empty{display:none}.strct-dg__pane-actions{margin-inline-start:auto}.strct-dg__pane-back{display:inline-flex;align-items:center;border:0;background:none;color:var(--t2);cursor:pointer;padding:2px;border-radius:var(--radius-sm)}.strct-dg__row--clickable{cursor:pointer}.strct-dg tbody .strct-dg__row--active td{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-1)}[data-theme=dark] .strct-dg tbody .strct-dg__row--active td{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-3)}.strct-dg__layout--paned .strct-dg__row--active td:last-child{position:relative;padding-inline-end:26px}.strct-dg__layout--paned .strct-dg__row--active td:last-child:after{content:\"\";position:absolute;inset-inline-end:11px;top:50%;width:6px;height:6px;border-top:1.6px solid var(--acc);border-inline-end:1.6px solid var(--acc);transform:translateY(-50%) rotate(45deg)}.strct-dg__pane{flex:1;min-width:0;align-self:stretch;background:var(--bg-1);border:1px solid var(--b2);border-inline-start:2px solid var(--acc);border-radius:4px;border-start-start-radius:0;border-end-start-radius:0;overflow:hidden;animation:strct-dg-pane-in .14s ease}.strct-dg__pane-head{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:11px 14px;border-bottom:1px solid var(--b1);font-size:13px;font-weight:600;color:var(--t1)}.strct-dg__pane-close{display:inline-flex;padding:3px;border:0;border-radius:2px;background:transparent;color:var(--t3);cursor:pointer}.strct-dg__pane-close:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__pane-body{padding:14px 16px;font-size:13px;color:var(--t2)}@keyframes strct-dg-pane-in{0%{opacity:0;transform:translate(8px)}}@keyframes strct-skeleton-pulse{0%,to{opacity:.4}50%{opacity:.7}}.strct-dg__skeleton-block{height:12px;border-radius:var(--radius-sm);background:linear-gradient(90deg,var(--bg-3) 25%,var(--skeleton-hi, var(--acc18)) 50%,var(--bg-3) 75%);background-size:200% 100%;animation:strct-dg-skeleton-sweep 1.1s linear infinite}@keyframes strct-dg-skeleton-sweep{0%{background-position:100% 0}to{background-position:-100% 0}}@media(prefers-reduced-motion:reduce){.strct-dg__skeleton-block{animation:none;background:var(--skeleton-hi, var(--acc18))}}.strct-dg__skeleton-row td{border-bottom:1px solid var(--b1)}.strct-dg__empty{text-align:center;color:var(--t2);padding:22px}.strct-dg__quickfilter{min-width:180px;max-width:260px}.strct-dg__quickfilter--end{order:2;margin-inline-start:auto}.strct-dg__filternote--end{order:3}.strct-dg__filternote{font-size:var(--text-sm);color:var(--t2);font-variant-numeric:tabular-nums;white-space:nowrap}.strct-dg__toolbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:9px 14px;border-bottom:1px solid var(--b2)}.strct-dg__foot{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:9px 14px;border-top:1px solid var(--b2);flex-wrap:wrap}.strct-dg__foot-left,.strct-dg__foot-right{display:flex;align-items:center;gap:12px}.strct-dg__actions{position:relative}.strct-dg__chooser-menu{position:absolute;bottom:calc(100% + 6px);inset-inline-start:0;z-index:var(--z-sticky);min-width:180px;background:var(--bg-1);border:1px solid var(--b2);border-radius:4px;box-shadow:var(--shadow-pop);padding:6px;display:flex;flex-direction:column;gap:2px}.strct-dg__chooser-menu--right{inset-inline-start:auto;inset-inline-end:0}.strct-dg__chooser-item{display:flex;align-items:center;gap:8px;padding:5px 8px;border-radius:3px;cursor:pointer;font-size:12px;color:var(--t1);transition:background .1s ease;-webkit-user-select:none;user-select:none}.strct-dg__chooser-item:hover{background:var(--bg-3)}.strct-dg__count{font-size:12px;color:var(--t2)}.strct-dg__count-sep{margin:0 8px;color:var(--b2)}.strct-dg__count-sel{color:var(--acc)}.strct-dg__filterbtn{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;margin-inline-start:2px;padding:0;border:0;border-radius:2px;background:transparent;color:var(--t3);cursor:pointer;vertical-align:middle}.strct-dg__filterbtn:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__filterbtn--active{color:var(--acc)}.strct-dg__filterbtn:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-dg__filterpanel{position:absolute;z-index:calc(var(--z-dropdown) + 10);display:flex;flex-direction:column;gap:6px;min-width:180px;padding:10px;background:var(--bg-1);border:1px solid var(--b2);border-radius:3px;box-shadow:var(--shh);font-weight:400;text-transform:none;letter-spacing:normal;white-space:nowrap}.strct-dg__filterinput{padding:5px 8px;border:1px solid var(--b2);border-radius:var(--radius-sm);background:var(--bg-2);color:var(--t1);font-family:var(--font);font-size:12px}.strct-dg__filterinput:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-dg__filteropt{display:flex;align-items:center;gap:7px;font-size:12.5px;color:var(--t1);cursor:pointer}.strct-dg__filterclear{align-self:flex-start;padding:3px 8px;border:1px solid var(--b2);border-radius:var(--radius-sm);background:transparent;color:var(--t2);font-family:var(--font);font-size:var(--text-sm);cursor:pointer}.strct-dg__filterclear:hover:not(:disabled){color:var(--t1);background:var(--bg-3)}.strct-dg__filterclear:disabled{color:var(--t4);cursor:default}.strct-dg tbody tr[tabindex]:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-dg__treepad{display:inline-block;height:1px;vertical-align:middle}.strct-dg__treebtn{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;margin-inline-end:4px;padding:0;border:0;border-radius:2px;background:transparent;color:var(--t3);cursor:pointer;vertical-align:middle}.strct-dg__treebtn:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__treebtn:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-dg__treebtn strct-icon{transition:transform .15s ease}.strct-dg__treebtn--open strct-icon{transform:rotate(90deg)}.strct-dg__treebtn--leaf{cursor:default;pointer-events:none}@media(prefers-reduced-motion:reduce){.strct-dg__treebtn strct-icon{transition:none}}.strct-dg__cell--editable{cursor:text;position:relative}.strct-dg__cell--editable:hover{box-shadow:inset 0 0 0 1px var(--b2)}.strct-dg__cell--editable:focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--acc50)}.strct-dg__editpencil{position:absolute;top:50%;inset-inline-end:6px;transform:translateY(-50%);color:var(--t3);opacity:0;pointer-events:none}td:hover>.strct-dg__editpencil,td:focus-within>.strct-dg__editpencil{opacity:1}.strct-dg__editinput{width:100%;box-sizing:border-box;padding:3px 6px;border:1px solid var(--acc);border-radius:var(--radius-sm);background:var(--bg-1);color:var(--t1);font:inherit}.strct-dg__editselect,.strct-dg__editnumber{display:block;width:100%}.strct-dg__editinput:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}\n"] }]
|
|
19222
|
-
}], ctorParameters: () => [], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: true }] }],
|
|
17849
|
+
}, template: "<!-- One polite region for everything the grid does to itself: sorting,\n paging and filtering all change the rows without saying so. -->\n<span class=\"strct-dg__announcer\" role=\"status\" aria-live=\"polite\">{{ announcement() }}</span>\n@if (actionBarDef() || quickFilterable() || actionBarCaptionDef()) {\n <div class=\"strct-dg__toolbar\">\n @if (quickFilterable()) {\n <strct-searchbox\n class=\"strct-dg__quickfilter\"\n [class.strct-dg__quickfilter--end]=\"quickFilterAlign() === 'end'\"\n [placeholder]=\"L().quickFilter\"\n [ariaLabel]=\"L().quickFilter\"\n [value]=\"quickFilter()\"\n (valueChange)=\"quickFilter.set($event)\"\n />\n @if (filterNote(); as note) {\n <span\n class=\"strct-dg__filternote\"\n [class.strct-dg__filternote--end]=\"quickFilterAlign() === 'end'\"\n >{{ note }}</span\n >\n }\n }\n <span class=\"strct-dg__actioncaption\">\n <ng-content select=\"[strctDatagridActionBarCaption]\" />\n </span>\n <ng-content select=\"[strctDatagridActionBar]\" />\n </div>\n}\n\n@if (hasEditableColumn()) {\n <!-- What the editable cells point at with aria-describedby: a keyboard\n user is told the cell can be edited, and how. -->\n <!-- In flow, not absolutely positioned: an out-of-flow box whose\n containing block is the page extends the document's scrollable area\n from wherever the grid happens to sit. 1x1 and clipped is enough. -->\n <span\n class=\"strct-sr-only\"\n style=\"\n display: inline-block;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n \"\n [id]=\"editHintId\"\n >{{ L().editCellInstructions }}</span\n >\n}\n\n@if (bulkHint(); as hint) {\n <!-- Selecting the page is not selecting the set. Say which one happened,\n and offer the other. -->\n <div class=\"strct-dg__bulk\" role=\"status\">\n <span>{{ hint.text }}</span>\n <button strct-button variant=\"flat\" size=\"sm\" (click)=\"hint.run()\">\n {{ hint.action }}\n </button>\n </div>\n}\n<div\n class=\"strct-dg__layout\"\n [class.strct-dg__layout--paned]=\"paneOpen()\"\n [class.strct-dg__layout--panetakeover]=\"paneOpen() && narrowPane()\"\n [style.--strct-dg-pane-list-w]=\"paneListWidth()\"\n>\n <div\n class=\"strct-dg__scroll\"\n tabindex=\"0\"\n role=\"region\"\n [attr.aria-label]=\"L().rows\"\n [style.max-height.px]=\"virtual() ? viewportHeight() : maxHeight()\"\n (scroll)=\"virtual() && onScroll($event)\"\n >\n <table\n class=\"strct-dg\"\n [attr.role]=\"childrenKey() ? 'treegrid' : gridMode() ? 'grid' : null\"\n [attr.aria-rowcount]=\"ariaRowCount()\"\n [attr.aria-labelledby]=\"caption() ? captionId : null\"\n >\n @if (caption()) {\n <caption class=\"strct-dg__caption\" [id]=\"captionId\">\n {{\n caption()\n }}\n </caption>\n }\n <thead>\n <tr>\n <!-- A utility column is still a column: axe reports every empty\n header, and a screen-reader user hears nothing where the\n detail, expand and select controls are. The name is hidden,\n not absent. -->\n @if (canDetail()) {\n <th\n class=\"strct-dg__expandcol\"\n scope=\"col\"\n [class.strct-dg__cell--sticky]=\"stickyActive()\"\n [style.insetInlineStart.px]=\"utilLeft('detail')\"\n >\n <span class=\"strct-sr-only\">{{ L().detailColumn }}</span>\n </th>\n }\n @if (canExpand()) {\n <th\n class=\"strct-dg__expandcol\"\n scope=\"col\"\n [class.strct-dg__cell--sticky]=\"stickyActive()\"\n [style.insetInlineStart.px]=\"utilLeft('expand')\"\n >\n <span class=\"strct-sr-only\">{{ L().expandColumn }}</span>\n </th>\n }\n @if (hasSelectionColumn()) {\n <th\n class=\"strct-dg__sel\"\n scope=\"col\"\n [class.strct-dg__cell--sticky]=\"stickyActive()\"\n [style.insetInlineStart.px]=\"utilLeft('sel')\"\n >\n @if (mode() === 'multiple') {\n <strct-checkbox\n [ariaLabel]=\"L().selectAll\"\n [checked]=\"allPageSelected()\"\n [indeterminate]=\"somePageSelected()\"\n (checkedChange)=\"toggleAll()\"\n />\n } @else {\n <span class=\"strct-sr-only\">{{ L().selectColumn }}</span>\n }\n </th>\n }\n @for (col of visibleColumns(); track col.key) {\n <th\n scope=\"col\"\n [style.text-align]=\"col.align ?? (col.numeric ? 'end' : 'start')\"\n [style.width]=\"colWidth(col.key) ?? col.width ?? null\"\n [class.strct-dg__th--sortable]=\"col.sortable\"\n [class.strct-dg__th--drop]=\"col.key === dropKey()\"\n [class.strct-dg__cell--sticky]=\"isSticky(col)\"\n [class.strct-dg__cell--sticky-last]=\"col.key === lastStickyKey()\"\n [style.insetInlineStart.px]=\"stickyLeft(col.key)\"\n [attr.data-col]=\"col.key\"\n [attr.aria-sort]=\"col.sortable ? ariaSort(col.key) : null\"\n [attr.draggable]=\"reorderable() ? true : null\"\n (dragstart)=\"onColDragStart(col.key, $event)\"\n (dragover)=\"onColDragOver(col.key, $event)\"\n (drop)=\"onColDrop(col.key)\"\n (dragend)=\"onColDragEnd()\"\n >\n <span class=\"strct-dg__hd\">\n <!-- A header that sorts is a button: a th with tabindex is\n read as \"column header, focusable\" and never says it\n can be activated. aria-sort stays on the th, which is\n what carries the column's sorted state. -->\n @if (col.sortable) {\n <!-- The button covers most of the header, so it carries\n the drag source too: a reorderable column has to be\n grabbable where the pointer actually lands. The\n event bubbles to the th's own handlers. -->\n <button\n type=\"button\"\n class=\"strct-dg__sortbtn\"\n [attr.draggable]=\"reorderable() ? true : null\"\n (click)=\"sortBy(col.key)\"\n >\n {{ col.label }}\n <strct-icon class=\"strct-dg__sorticon\" [name]=\"sortIcon(col.key)\" [size]=\"13\" />\n </button>\n } @else {\n {{ col.label }}\n }\n @if (col.filterable || col.filterOptions) {\n <button\n #fbtn\n type=\"button\"\n class=\"strct-dg__filterbtn\"\n [class.strct-dg__filterbtn--active]=\"hasFilter(col.key)\"\n [attr.aria-expanded]=\"filterOpenKey() === col.key\"\n [attr.aria-label]=\"L().filterColumn + ': ' + col.label\"\n (click)=\"toggleFilterPanel(col.key, $event)\"\n (keydown.enter)=\"$event.stopPropagation()\"\n (keydown.space)=\"$event.stopPropagation()\"\n >\n <strct-icon name=\"filter\" [size]=\"12\" />\n </button>\n @if (filterOpenKey() === col.key) {\n <div\n class=\"strct-dg__filterpanel\"\n role=\"dialog\"\n [attr.aria-label]=\"L().filterColumn + ': ' + col.label\"\n [strctOverlay]=\"fbtn\"\n strctOverlayPlacement=\"bottom-start\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"$event.stopPropagation()\"\n (keydown.space)=\"$event.stopPropagation()\"\n >\n @if (col.filterOptions; as opts) {\n @for (opt of opts; track $index) {\n <label class=\"strct-dg__filteropt\">\n <input\n type=\"checkbox\"\n [checked]=\"optionChecked(col.key, opt)\"\n (change)=\"toggleFilterOption(col.key, opt)\"\n />\n <span>{{ opt }}</span>\n </label>\n }\n } @else {\n <input\n class=\"strct-dg__filterinput\"\n type=\"text\"\n [attr.placeholder]=\"L().filterPlaceholder\"\n [attr.aria-label]=\"L().filterColumn + ': ' + col.label\"\n [value]=\"textFilter(col.key)\"\n (input)=\"setTextFilter(col.key, $any($event.target).value)\"\n />\n }\n <button\n type=\"button\"\n class=\"strct-dg__filterclear\"\n [disabled]=\"!hasFilter(col.key)\"\n (click)=\"clearFilter(col.key)\"\n >\n {{ L().clearFilter }}\n </button>\n </div>\n }\n }\n </span>\n @if (resizable() && col.resizable !== false) {\n <!-- A separator, not a bare div: a column could only be\n resized with a mouse, which is the one input a\n console cannot assume. -->\n <div\n class=\"strct-dg__resize\"\n role=\"separator\"\n aria-orientation=\"vertical\"\n tabindex=\"0\"\n [attr.aria-label]=\"L().resizeColumn(col.label)\"\n [attr.aria-valuenow]=\"separatorValue(col.key)\"\n [attr.aria-valuemin]=\"40\"\n (mousedown)=\"onResizeStart($event, col.key)\"\n (keydown)=\"onResizeKey($event, col.key)\"\n (dblclick)=\"resetWidth(col.key)\"\n ></div>\n }\n </th>\n }\n @if (canActions()) {\n <th class=\"strct-dg__actioncol\" scope=\"col\" [attr.aria-label]=\"L().actions\"></th>\n }\n </tr>\n </thead>\n <!--\n focusin is the real keyboard path (focus does not bubble from cells);\n the plain focus binding exists to satisfy mouse-events-have-key-events.\n -->\n <tbody\n (mouseover)=\"revealIfClipped($event)\"\n (focusin)=\"revealIfClipped($event)\"\n (focus)=\"revealIfClipped($event)\"\n >\n @if (loading()) {\n @for (_ of [1, 2, 3, 4, 5]; track $index) {\n <tr class=\"strct-dg__skeleton-row\">\n @if (canDetail()) {\n <td class=\"strct-dg__expandcell\"></td>\n }\n @if (canExpand()) {\n <td class=\"strct-dg__expandcell\"></td>\n }\n @if (hasSelectionColumn()) {\n <td class=\"strct-dg__sel\"></td>\n }\n @for (col of visibleColumns(); track col.key) {\n <td [style.text-align]=\"col.align ?? 'start'\">\n <div class=\"strct-dg__skeleton-block\"></div>\n </td>\n }\n @if (canActions()) {\n <td class=\"strct-dg__actioncell\"></td>\n }\n </tr>\n }\n } @else {\n @if (virtual() && topPad() > 0) {\n <tr class=\"strct-dg__vspacer\" aria-hidden=\"true\">\n <td [attr.colspan]=\"colspan()\" [style.height.px]=\"topPad()\"></td>\n </tr>\n }\n @for (it of displayItems(); track itemKey(it)) {\n @if (it.group; as grp) {\n <!-- Group header: distinct value + count, collapsible. -->\n <tr class=\"strct-dg__grouprow\">\n @if (groupSelect() && mode() === 'multiple') {\n <td class=\"strct-dg__sel\">\n <strct-checkbox\n [ariaLabel]=\"L().selectAllInGroup(grp.label)\"\n [checked]=\"groupAllSelected(grp.key)\"\n [indeterminate]=\"groupSomeSelected(grp.key)\"\n (checkedChange)=\"toggleGroupSelection(grp.key)\"\n />\n </td>\n }\n <td\n [attr.colspan]=\"\n groupSelect() && mode() === 'multiple' ? colspan() - 1 : colspan()\n \"\n >\n <button\n type=\"button\"\n class=\"strct-dg__groupbtn\"\n [attr.aria-expanded]=\"!grp.collapsed\"\n (click)=\"toggleGroup(grp.key)\"\n >\n <span\n class=\"strct-dg__groupchev\"\n [class.strct-dg__groupchev--open]=\"!grp.collapsed\"\n >\n <strct-icon name=\"chevronRight\" [size]=\"12\" [strokeWidth]=\"1.7\" />\n </span>\n @if (groupHeaderDef(); as tpl) {\n <!-- The consumer draws the row; the button, its\n aria-expanded and the keyboard stay ours. -->\n <ng-container\n [ngTemplateOutlet]=\"tpl.template\"\n [ngTemplateOutletContext]=\"{\n $implicit: grp,\n group: grp,\n count: grp.count,\n }\"\n />\n } @else {\n <span\n class=\"strct-dg__grouplabel strct-dg__grouplabel--{{\n grp.status ?? 'none'\n }}\"\n >{{ grp.label }}</span\n >\n <!-- The three spans run together in the button's\n name (\"Needs your decision1Blocks the join\u2026\");\n the separators are read, not seen. -->\n <span class=\"strct-dg__announcer\">, </span>\n <span\n class=\"strct-dg__groupcount strct-dg__groupcount--{{\n grp.status ?? 'none'\n }}\"\n >{{ grp.count }}</span\n >\n <!-- Seen: the chip's number. Heard: the number with\n the grid's noun, because \"Inconclusive, 3\" does\n not say three of what. -->\n <span class=\"strct-dg__announcer\"> {{ countNoun(grp.count) }}</span>\n @if (grp.note) {\n <span class=\"strct-dg__announcer\">. </span>\n <span class=\"strct-dg__groupnote\">{{ grp.note }}</span>\n }\n }\n </button>\n </td>\n </tr>\n } @else {\n @let row = it.row!;\n <tr\n [attr.aria-rowindex]=\"ariaRowIndex(row)\"\n [class.strct-dg__row--selected]=\"isSelected(row)\"\n [class.strct-dg__row--locked]=\"lockedReason(row) !== null\"\n [attr.aria-selected]=\"mode() === 'none' ? null : isSelected(row)\"\n [attr.aria-disabled]=\"lockedReason(row) !== null ? 'true' : null\"\n [attr.title]=\"lockedReason(row) || null\"\n (click)=\"onRowPick(row)\"\n [class.strct-dg__row--active]=\"paneOpen() && row === activeRow()\"\n [attr.aria-level]=\"childrenKey() ? treeDepth(row) + 1 : null\"\n [attr.aria-expanded]=\"\n childrenKey() && treeHasChildren(row) ? treeExpanded(row) : null\n \"\n [attr.tabindex]=\"\n childrenKey()\n ? treeRowTabindex(row)\n : gridMode()\n ? gridRowTabindex(row)\n : canDetail()\n ? paneRowTabindex(row)\n : null\n \"\n (keydown)=\"\n childrenKey()\n ? onTreeRowKeydown(row, $event)\n : gridMode()\n ? onGridRowKeydown(row, $event)\n : onPaneRowKeydown(row, $event)\n \"\n (dblclick)=\"onRowActivate(row)\"\n >\n @if (canDetail()) {\n <td\n class=\"strct-dg__expandcell\"\n [class.strct-dg__cell--sticky]=\"stickyActive()\"\n [style.insetInlineStart.px]=\"utilLeft('detail')\"\n >\n <button\n type=\"button\"\n [attr.tabindex]=\"ctlTabindex()\"\n class=\"strct-dg__detailbtn\"\n [class.strct-dg__detailbtn--active]=\"row === activeRow()\"\n [attr.aria-expanded]=\"row === activeRow()\"\n [attr.aria-label]=\"L().openDetail\"\n (click)=\"openDetail(row)\"\n >\n <strct-icon name=\"chevronDoubleRight\" [size]=\"13\" [strokeWidth]=\"1.6\" />\n </button>\n </td>\n }\n @if (canExpand()) {\n <td\n class=\"strct-dg__expandcell\"\n [class.strct-dg__cell--sticky]=\"stickyActive()\"\n [style.insetInlineStart.px]=\"utilLeft('expand')\"\n >\n <button\n type=\"button\"\n [attr.tabindex]=\"ctlTabindex()\"\n class=\"strct-dg__expandbtn\"\n [class.strct-dg__expandbtn--open]=\"isExpanded(row)\"\n [attr.aria-expanded]=\"isExpanded(row)\"\n [attr.aria-label]=\"L().toggleDetail\"\n (click)=\"toggleExpand(row)\"\n >\n <strct-icon name=\"chevronRight\" [size]=\"12\" [strokeWidth]=\"1.7\" />\n </button>\n </td>\n }\n @if (hasSelectionColumn()) {\n <td\n class=\"strct-dg__sel\"\n [class.strct-dg__cell--sticky]=\"stickyActive()\"\n [style.insetInlineStart.px]=\"utilLeft('sel')\"\n >\n @if (mode() === 'single') {\n <!-- A native radio group: one name per grid, so the\n arrow keys move between rows and Space picks,\n without the grid inventing its own keyboarding. -->\n <input\n type=\"radio\"\n class=\"strct-dg__radio\"\n [name]=\"radioName\"\n [attr.aria-label]=\"selectRowLabel(row)\"\n [attr.aria-description]=\"lockedReason(row) || null\"\n [checked]=\"isSelected(row)\"\n [disabled]=\"lockedReason(row) !== null\"\n [attr.tabindex]=\"ctlTabindex()\"\n (change)=\"selectSingle(row)\"\n (click)=\"$event.stopPropagation()\"\n />\n } @else {\n <!-- click fires (and bubbles) before the input's change,\n so the modifier is recorded by the time toggleRow runs. -->\n <strct-checkbox\n [ariaLabel]=\"selectRowLabel(row)\"\n [attr.aria-description]=\"lockedReason(row) || null\"\n [checked]=\"isSelected(row)\"\n [disabled]=\"lockedReason(row) !== null\"\n [tabIndex]=\"ctlTabindex()\"\n (click)=\"noteRangeIntent($event); $event.stopPropagation()\"\n (checkedChange)=\"toggleRow(row)\"\n />\n }\n </td>\n }\n @for (col of visibleColumns(); track col.key; let colIdx = $index) {\n <td\n [style.text-align]=\"col.align ?? (col.numeric ? 'end' : 'start')\"\n [class.strct-dg__cell--mono]=\"col.mono\"\n [class.strct-dg__cell--muted]=\"col.muted\"\n [class.strct-dg__cell--numeric]=\"col.numeric\"\n [class.strct-dg__cell--sticky]=\"isSticky(col)\"\n [class.strct-dg__cell--sticky-last]=\"col.key === lastStickyKey()\"\n [class.strct-dg__cell--editable]=\"col.editable\"\n [style.insetInlineStart.px]=\"stickyLeft(col.key)\"\n [attr.data-edit]=\"col.editable ? '' : null\"\n [attr.tabindex]=\"col.editable ? editCellTabindex(row, col) : null\"\n [attr.aria-describedby]=\"col.editable ? editHintId : null\"\n (dblclick)=\"col.editable && startEdit(row, col)\"\n (focus)=\"col.editable && onEditCellFocus(row, col)\"\n (keydown)=\"col.editable && onEditCellKeydown(row, col, $event)\"\n >\n @if (childrenKey() && colIdx === 0) {\n <span\n class=\"strct-dg__treepad\"\n [style.width.px]=\"treeDepth(row) * 18\"\n aria-hidden=\"true\"\n ></span>\n @if (treeHasChildren(row)) {\n <button\n type=\"button\"\n class=\"strct-dg__treebtn\"\n [class.strct-dg__treebtn--open]=\"treeExpanded(row)\"\n [attr.aria-expanded]=\"treeExpanded(row)\"\n [attr.aria-label]=\"L().toggleChildren\"\n (click)=\"toggleTreeRow(row)\"\n >\n <strct-icon name=\"chevronRight\" [size]=\"12\" [strokeWidth]=\"1.7\" />\n </button>\n } @else {\n <span\n class=\"strct-dg__treebtn strct-dg__treebtn--leaf\"\n aria-hidden=\"true\"\n ></span>\n }\n }\n @if (isEditingCell(row, col)) {\n @switch (col.editor ?? 'text') {\n @case ('select') {\n <!-- Choosing is the commit: there is nothing to\n confirm with Enter once an option is picked. -->\n <strct-select\n class=\"strct-dg__editselect\"\n [options]=\"editorOptionsFor(row, col)\"\n [listLabel]=\"L().editCell + ': ' + col.label\"\n [ngModel]=\"row[col.key]\"\n (ngModelChange)=\"commitValue(row, col, $event)\"\n (keydown.escape)=\"cancelEdit($event)\"\n (click)=\"$event.stopPropagation()\"\n />\n }\n @case ('number') {\n <strct-number\n class=\"strct-dg__editnumber\"\n [ariaLabel]=\"L().editCell + ': ' + col.label\"\n [min]=\"col.editorMin ?? null\"\n [max]=\"col.editorMax ?? null\"\n [step]=\"col.editorStep ?? 1\"\n [ngModel]=\"row[col.key]\"\n (ngModelChange)=\"editDraft.set($event)\"\n (keydown.enter)=\"commitDraft(row, col, $event)\"\n (keydown.escape)=\"cancelEdit($event)\"\n (focusout)=\"commitOnLeave(row, col, $event)\"\n (click)=\"$event.stopPropagation()\"\n />\n }\n @default {\n <input\n class=\"strct-dg__editinput\"\n type=\"text\"\n [value]=\"row[col.key] ?? ''\"\n [attr.aria-label]=\"L().editCell + ': ' + col.label\"\n (keydown.enter)=\"commitEdit(row, col, $event)\"\n (keydown.escape)=\"cancelEdit($event)\"\n (blur)=\"commitEdit(row, col, $event)\"\n (click)=\"$event.stopPropagation()\"\n />\n }\n }\n } @else if (cellTemplate(col.key); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{\n $implicit: row,\n row,\n value: row[col.key],\n column: col,\n }\"\n />\n } @else if (isBlank(row, col)) {\n <span class=\"strct-dg__empty\" [attr.aria-label]=\"col.emptyLabel || null\">{{\n col.emptyText\n }}</span>\n } @else {\n {{ displayValue(row, col) }}\n @if (col.descriptionKey && row[col.descriptionKey]) {\n <span class=\"strct-dg__celldesc\">{{ row[col.descriptionKey] }}</span>\n }\n }\n <!-- The affordance a mouse never needed: a cell that\n can be edited says so on hover and on focus. -->\n @if (col.editable && editHint() && !isEditingCell(row, col)) {\n <strct-icon\n class=\"strct-dg__editpencil\"\n name=\"pencil\"\n [size]=\"12\"\n [strokeWidth]=\"1.6\"\n aria-hidden=\"true\"\n />\n }\n </td>\n }\n @if (canActions()) {\n <td class=\"strct-dg__actioncell\">\n <button\n type=\"button\"\n [attr.tabindex]=\"ctlTabindex()\"\n class=\"strct-dg__kebab\"\n [attr.aria-label]=\"L().rowActions\"\n (click)=\"openRowMenu(row, $event)\"\n >\n <strct-icon name=\"dots\" [size]=\"16\" />\n </button>\n </td>\n }\n </tr>\n @if (canExpand() && isExpanded(row)) {\n <tr class=\"strct-dg__detailrow\">\n <td [attr.colspan]=\"colspan()\">\n <div class=\"strct-dg__detail\">\n <ng-container\n [ngTemplateOutlet]=\"detailDef()!.template\"\n [ngTemplateOutletContext]=\"{ $implicit: row, row }\"\n />\n </div>\n </td>\n </tr>\n }\n }\n } @empty {\n <!-- \"Nothing here\" and \"nothing matches what you typed\" are\n different states: the second one can be undone, and\n saying so is the whole point. -->\n <tr>\n <td class=\"strct-dg__emptyrow\" [attr.colspan]=\"colspan()\">\n @if (filteredAway()) {\n <strct-empty-state\n size=\"sm\"\n [titleLevel]=\"null\"\n [title]=\"L().noMatches\"\n [description]=\"noMatchesDescription()\"\n >\n <button strct-button variant=\"flat\" size=\"sm\" (click)=\"clearAllFilters()\">\n {{ L().clearFilters }}\n </button>\n </strct-empty-state>\n } @else {\n <!-- Not a heading: a grid is a region of a page, and an\n empty one used to put an <h3> in its outline. -->\n <strct-empty-state size=\"sm\" [titleLevel]=\"null\" [title]=\"emptyText()\" />\n }\n </td>\n </tr>\n }\n @if (virtual() && bottomPad() > 0) {\n <tr class=\"strct-dg__vspacer\" aria-hidden=\"true\">\n <td [attr.colspan]=\"colspan()\" [style.height.px]=\"bottomPad()\"></td>\n </tr>\n }\n }\n </tbody>\n </table>\n </div>\n\n @if (paneOpen()) {\n <aside class=\"strct-dg__pane\">\n <div class=\"strct-dg__pane-head\">\n @if (narrowPane()) {\n <!-- The pane has taken the list's place, so there is a way back. -->\n <button\n type=\"button\"\n class=\"strct-dg__pane-back\"\n [attr.aria-label]=\"L().backToList\"\n (click)=\"closePane()\"\n >\n <strct-icon name=\"chevronLeft\" [size]=\"13\" />\n </button>\n }\n <span class=\"strct-dg__pane-title\">\n <ng-content select=\"[strctDetailPaneTitle]\" />\n @if (!paneTitleDef()) {\n {{ activeRow()![columns()[0].key] }}\n }\n </span>\n <span class=\"strct-dg__pane-meta\">\n <ng-content select=\"[strctDetailPaneMeta]\" />\n </span>\n <span class=\"strct-dg__pane-actions\">\n <ng-content select=\"[strctDetailPaneActions]\" />\n </span>\n <button\n type=\"button\"\n class=\"strct-dg__pane-close\"\n [attr.aria-label]=\"L().closeDetail\"\n (click)=\"closePane()\"\n >\n <strct-icon name=\"close\" [size]=\"13\" />\n </button>\n </div>\n <div class=\"strct-dg__pane-body\">\n <ng-container\n [ngTemplateOutlet]=\"detailDef()!.template\"\n [ngTemplateOutletContext]=\"{ $implicit: activeRow(), row: activeRow() }\"\n />\n </div>\n </aside>\n }\n</div>\n\n@if (showFooter()) {\n <div class=\"strct-dg__foot\">\n <div class=\"strct-dg__foot-left\">\n @if (columnChooser() || sync()) {\n <div class=\"strct-dg__actions\">\n <strct-button-group>\n @if (columnChooser()) {\n <button\n strct-button\n size=\"sm\"\n [class.is-open]=\"chooserOpen()\"\n [disabled]=\"footerActionsDisabled()\"\n [attr.aria-label]=\"L().chooseColumns\"\n (click)=\"toggleChooser($event)\"\n >\n <strct-icon name=\"settings\" [size]=\"16\" />\n </button>\n }\n @if (sync()) {\n <button\n strct-button\n size=\"sm\"\n [disabled]=\"footerActionsDisabled()\"\n [attr.aria-label]=\"L().refresh\"\n (click)=\"syncChange.emit()\"\n >\n <strct-icon name=\"refresh\" [size]=\"16\" />\n </button>\n }\n </strct-button-group>\n @if (columnChooser() && chooserOpen()) {\n <div class=\"strct-dg__chooser-menu\">\n @for (col of columns(); track col.key) {\n <!-- The whole row toggles; the checkbox's own click must not\n reach the row or the column would flip twice. -->\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <div\n class=\"strct-dg__chooser-item\"\n (click)=\"toggleColumn(col.key, hiddenColumns().has(col.key))\"\n >\n <strct-checkbox\n [checked]=\"!hiddenColumns().has(col.key)\"\n (checkedChange)=\"toggleColumn(col.key, $event)\"\n (click)=\"$event.stopPropagation()\"\n />\n <span>{{ col.label }}</span>\n </div>\n }\n </div>\n }\n </div>\n }\n <span class=\"strct-dg__count\">\n @if (paging() === 'more') {\n {{ L().showing(rows().length, moreTotal() ?? undefined) }}\n } @else {\n {{ totalCount() }} {{ totalCount() === 1 ? L().row : L().rows }}\n }\n @if (selectedCount() && mode() !== 'single') {\n <span class=\"strct-dg__count-sep\">|</span>\n <span class=\"strct-dg__count-sel\">{{ selectedCount() }} {{ L().selected }}</span>\n }\n </span>\n </div>\n <div class=\"strct-dg__foot-right\">\n <!-- A feed that pages by cursor loads more at the end: page numbers\n are something a cursor API cannot answer. It takes the pager's\n place \u2014 the column chooser, the sync button and the count are\n the footer's, not the pager's. -->\n @if (paging() === 'more') {\n @if (hasMore()) {\n <button\n strct-button\n size=\"sm\"\n class=\"strct-dg__more\"\n [disabled]=\"loadingMore()\"\n (click)=\"loadMore.emit()\"\n >\n @if (loadingMore()) {\n <strct-spinner size=\"sm\" />\n }\n {{ L().loadMore }}\n </button>\n }\n } @else if (pageSize() > 0 && !groupBy()) {\n <strct-pagination\n [total]=\"totalCount()\"\n [pageSize]=\"pageSize()\"\n [page]=\"page()\"\n (pageChange)=\"goToPage($event)\"\n />\n }\n </div>\n </div>\n}\n", styles: [".strct-dg__radio{width:15px;height:15px;accent-color:var(--acc);cursor:pointer}.strct-dg__radio:disabled{cursor:not-allowed}.strct-dg__row--locked .strct-dg__sel{opacity:.55}.strct-dg__actioncaption:empty{display:none}.strct-dg__actioncaption{display:inline-flex;align-items:center;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--text-sm);color:var(--t2)}.strct-dg__bulk{display:flex;align-items:center;justify-content:center;flex-wrap:wrap;gap:4px 10px;padding:7px 12px;border-bottom:1px solid var(--b2);background:var(--acc-s);color:var(--t2);font-size:var(--text-md)}.strct-dg__announcer{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}.strct-dg-host{display:block;border:1px solid var(--b2);border-radius:var(--radius-lg);background:var(--bg-2);box-shadow:var(--shadow-rest)}.strct-dg-host--flush{border:0;border-radius:0;background:transparent;box-shadow:none}.strct-dg__more strct-spinner{margin-inline-end:4px}.strct-dg__caption{caption-side:top;text-align:start;padding:var(--space-2) var(--space-3);font-size:var(--text-sm);font-weight:600;color:var(--t2)}.strct-dg td.strct-dg__cell--mono{font-family:var(--mono);font-size:var(--text-sm)}.strct-dg td.strct-dg__cell--muted{color:var(--t2)}.strct-dg td.strct-dg__cell--numeric{font-variant-numeric:tabular-nums}.strct-dg__empty{color:var(--t2)}.strct-dg__celldesc{display:block;font-size:var(--text-sm);color:var(--t2);line-height:1.3}.strct-dg__scroll{flex:1 1 auto;min-width:0;overflow-x:auto;-webkit-overflow-scrolling:touch}.strct-dg-host--virtual .strct-dg__scroll,.strct-dg-host--bounded .strct-dg__scroll{overflow-y:auto}.strct-dg-host--virtual .strct-dg thead th,.strct-dg-host--bounded .strct-dg thead th{position:sticky;top:0;z-index:var(--z-raised)}.strct-dg__vspacer td{padding:0;border:0;background:transparent}.strct-dg th[draggable]{cursor:grab}.strct-dg__th--drop{box-shadow:inset 3px 0 0 var(--acc)}.strct-dg__grouprow td{background:var(--bg-2)!important;padding:0}.strct-dg__groupbtn{display:flex;align-items:center;gap:8px;width:100%;padding:7px 13px;border:0;background:transparent;color:var(--t1);font-family:var(--font);font-size:var(--text-sm);font-weight:600;cursor:pointer;text-align:start}.strct-dg__groupbtn:hover{background:var(--bg-3)}.strct-dg__groupbtn:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-dg__groupchev{display:inline-flex;color:var(--t3);transition:transform .15s ease}.strct-dg__groupchev--open{transform:rotate(90deg)}@media(prefers-reduced-motion:reduce){.strct-dg__groupchev{transition:none}}.strct-dg__grouplabel--critical{color:var(--critical)}.strct-dg__grouplabel--warning{color:var(--warning)}.strct-dg__grouplabel--success{color:var(--success)}.strct-dg__grouplabel--accent{color:var(--acc)}.strct-dg__grouplabel--neutral,.strct-dg__grouplabel--none{color:var(--t1)}.strct-dg__groupnote{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--text-sm);font-weight:400;color:var(--t2)}.strct-dg__groupcount{min-width:18px;height:18px;padding:0 5px;display:inline-flex;align-items:center;justify-content:center;font-size:12px;border-radius:4px;background:var(--acc-m);color:var(--acc);font-variant-numeric:tabular-nums}.strct-dg__groupcount--critical{background:var(--critical-bg);color:var(--critical)}.strct-dg__groupcount--warning{background:var(--warning-bg);color:var(--warning)}.strct-dg__groupcount--success{background:var(--success-bg);color:var(--success)}.strct-dg__groupcount--neutral,.strct-dg__groupcount--none{background:var(--bg-3);color:var(--t2)}.strct-dg-host--singleline .strct-dg{border-collapse:separate;border-spacing:0}.strct-dg-host--sticky .strct-dg,.strct-dg-host--virtual .strct-dg,.strct-dg-host--bounded .strct-dg{border-collapse:separate;border-spacing:0;overflow:visible;border-radius:0}.strct-dg-host--sticky .strct-dg{width:max-content;min-width:100%}.strct-dg .strct-dg__cell--sticky{position:sticky;z-index:calc(var(--z-base) + 2)}.strct-dg thead th.strct-dg__cell--sticky{z-index:calc(var(--z-raised) + 1)}.strct-dg .strct-dg__cell--sticky-last:after{content:\"\";position:absolute;top:0;bottom:0;inset-inline-end:-1px;width:7px;pointer-events:none;background:linear-gradient(to right,rgba(0,0,0,.14),transparent)}[dir=rtl] .strct-dg .strct-dg__cell--sticky-last:after{background:linear-gradient(to left,rgba(0,0,0,.14),transparent)}.strct-dg-host--sticky .strct-dg__expandcol,.strct-dg-host--sticky .strct-dg__expandcell{width:36px;min-width:36px;max-width:36px;box-sizing:border-box}.strct-dg-host--sticky .strct-dg__sel{width:40px;min-width:40px;max-width:40px;box-sizing:border-box}.strct-dg-host--sticky tbody .strct-dg__cell--sticky{background:var(--bg-1)}[data-theme=dark] .strct-dg-host--sticky tbody .strct-dg__cell--sticky{background:var(--bg-3)}.strct-dg-host--sticky tbody tr:hover .strct-dg__cell--sticky{background:linear-gradient(var(--acc-s),var(--acc-s)) var(--bg-1)}[data-theme=dark] .strct-dg-host--sticky tbody tr:hover .strct-dg__cell--sticky{background:linear-gradient(var(--acc-s),var(--acc-s)) var(--bg-3)}.strct-dg-host--sticky tbody .strct-dg__row--selected .strct-dg__cell--sticky{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-1)}[data-theme=dark] .strct-dg-host--sticky tbody .strct-dg__row--selected .strct-dg__cell--sticky{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-3)}.strct-dg{width:100%;border-collapse:collapse;font-size:13px;overflow:hidden;background:var(--bg-2)}.strct-dg-host:not(:has(.strct-dg__toolbar)) .strct-dg{border-start-start-radius:4px;border-start-end-radius:4px}.strct-dg-host:not(:has(.strct-dg__foot)) .strct-dg{border-end-start-radius:4px;border-end-end-radius:4px}.strct-dg th,.strct-dg td{padding:9px 13px;text-align:start;border-bottom:1px solid var(--b1)}.strct-dg tbody td{background:var(--bg-1)}[data-theme=dark] .strct-dg tbody td{background:var(--bg-3)}.strct-dg-host--compact .strct-dg th,.strct-dg-host--compact .strct-dg td{padding:5px 11px}.strct-dg-host--singleline .strct-dg tbody tr:not(.strct-dg__detailrow)>td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:360px}.strct-dg th{position:relative;font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.4px;color:var(--t2);background:var(--bg-2);white-space:nowrap;-webkit-user-select:none;user-select:none}.strct-dg__th--sortable{cursor:pointer}.strct-dg__th--sortable:hover{color:var(--t1)}.strct-dg__sortbtn{display:inline-flex;align-items:center;gap:inherit;padding:0;border:0;background:none;color:inherit;font:inherit;text-transform:inherit;letter-spacing:inherit;text-align:inherit;cursor:pointer}.strct-dg__sortbtn:focus-visible{outline:2px solid var(--acc50);outline-offset:2px;border-radius:var(--radius-sm)}.strct-dg__th--sortable:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-dg__hd{display:inline-flex;align-items:center;gap:5px}.strct-dg__sorticon{color:var(--t3)}.strct-dg__th--sortable:hover .strct-dg__sorticon{color:var(--acc)}.strct-dg__resize{position:absolute;inset-inline-end:0;top:0;bottom:0;width:4px;cursor:col-resize;background:transparent;z-index:calc(var(--z-base) + 1)}.strct-dg__resize:hover{background:var(--acc)}.strct-dg td{color:var(--t1)}.strct-dg tbody tr:last-child td{border-bottom:0}.strct-dg tbody tr:not(.strct-dg__detailrow):hover td{background:linear-gradient(var(--acc-s),var(--acc-s)) var(--bg-1)}[data-theme=dark] .strct-dg tbody tr:not(.strct-dg__detailrow):hover td{background:linear-gradient(var(--acc-s),var(--acc-s)) var(--bg-3)}.strct-dg tbody .strct-dg__row--selected td{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-1)}[data-theme=dark] .strct-dg tbody .strct-dg__row--selected td{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-3)}.strct-dg tbody tr.strct-dg__row--selected:hover td{background:linear-gradient(var(--acc-s),var(--acc-s)),linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-1)}[data-theme=dark] .strct-dg tbody tr.strct-dg__row--selected:hover td{background:linear-gradient(var(--acc-s),var(--acc-s)),linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-3)}.strct-dg__sel{width:1%;white-space:nowrap}.strct-dg__sel .strct-cb,.strct-dg__sel .strct-dg__radio,.strct-dg__expandbtn{position:relative}.strct-dg__sel .strct-cb:after,.strct-dg__sel .strct-dg__radio:after,.strct-dg__expandbtn:after{content:\"\";position:absolute;inset:-11px -13px;min-width:24px;min-height:24px}.strct-dg-host--compact .strct-dg__sel .strct-cb:after,.strct-dg-host--compact .strct-dg__sel .strct-dg__radio:after,.strct-dg-host--compact .strct-dg__expandbtn:after{inset:-7px -11px}.strct-dg__sel input{accent-color:var(--acc);width:15px;height:15px;cursor:pointer}.strct-dg__expandcol,.strct-dg__expandcell{width:1%;white-space:nowrap}.strct-dg__actioncol,.strct-dg__actioncell{width:1%;white-space:nowrap;text-align:end}.strct-dg__kebab{display:inline-flex;padding:4px;border:0;border-radius:2px;background:transparent;color:var(--t3);cursor:pointer;transition:color .14s ease,background .14s ease}.strct-dg__kebab:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__expandbtn{position:relative;display:inline-flex;align-items:center;justify-content:center;padding:3px;border:0;border-radius:2px;background:transparent;color:var(--t3);cursor:pointer;transition:transform .15s ease,color .15s ease}.strct-dg__expandbtn:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__expandbtn--open{transform:rotate(90deg);color:var(--acc)}.strct-dg__detailbtn{display:inline-flex;padding:3px;border:0;border-radius:2px;background:transparent;color:var(--t3);cursor:pointer;transition:color .14s ease,background .14s ease}.strct-dg__detailbtn:hover{color:var(--acc);background:var(--bg-3)}.strct-dg__detailbtn--active{color:var(--acc);background:var(--acc-m)}.strct-dg__detailrow td{background:var(--bg-2);padding:0}.strct-dg__detail{padding:14px 16px;font-size:13px;color:var(--t2)}.strct-dg__layout{display:flex;align-items:flex-start;min-width:0}.strct-dg__layout--paned{gap:0}.strct-dg__layout--paned>.strct-dg__scroll{flex:0 0 auto;width:var(--strct-dg-pane-list-w, 260px);min-width:var(--strct-dg-pane-list-w, 260px);max-width:var(--strct-dg-pane-list-w, 260px)}.strct-dg__layout--paned>.strct-dg__scroll>.strct-dg{width:100%;min-width:0;max-width:none;flex-shrink:0;border-start-end-radius:0;border-end-end-radius:0}.strct-dg__layout--panetakeover>.strct-dg__scroll{display:none}.strct-dg__layout--panetakeover>.strct-dg__pane{flex:1;min-width:0}.strct-dg__pane-meta,.strct-dg__pane-actions{display:inline-flex;align-items:center;gap:var(--space-2)}.strct-dg__pane-meta:empty,.strct-dg__pane-actions:empty{display:none}.strct-dg__pane-actions{margin-inline-start:auto}.strct-dg__pane-back{display:inline-flex;align-items:center;border:0;background:none;color:var(--t2);cursor:pointer;padding:2px;border-radius:var(--radius-sm)}.strct-dg__row--clickable{cursor:pointer}.strct-dg tbody .strct-dg__row--active td{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-1)}[data-theme=dark] .strct-dg tbody .strct-dg__row--active td{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-3)}.strct-dg__layout--paned .strct-dg__row--active td:last-child{position:relative;padding-inline-end:26px}.strct-dg__layout--paned .strct-dg__row--active td:last-child:after{content:\"\";position:absolute;inset-inline-end:11px;top:50%;width:6px;height:6px;border-top:1.6px solid var(--acc);border-inline-end:1.6px solid var(--acc);transform:translateY(-50%) rotate(45deg)}.strct-dg__pane{flex:1;min-width:0;align-self:stretch;background:var(--bg-1);border:1px solid var(--b2);border-inline-start:2px solid var(--acc);border-radius:4px;border-start-start-radius:0;border-end-start-radius:0;overflow:hidden;animation:strct-dg-pane-in .14s ease}.strct-dg__pane-head{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:11px 14px;border-bottom:1px solid var(--b1);font-size:13px;font-weight:600;color:var(--t1)}.strct-dg__pane-close{display:inline-flex;padding:3px;border:0;border-radius:2px;background:transparent;color:var(--t3);cursor:pointer}.strct-dg__pane-close:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__pane-body{padding:14px 16px;font-size:13px;color:var(--t2)}@keyframes strct-dg-pane-in{0%{opacity:0;transform:translate(8px)}}@keyframes strct-skeleton-pulse{0%,to{opacity:.4}50%{opacity:.7}}.strct-dg__skeleton-block{height:12px;border-radius:var(--radius-sm);background:linear-gradient(90deg,var(--bg-3) 25%,var(--skeleton-hi, var(--acc18)) 50%,var(--bg-3) 75%);background-size:200% 100%;animation:strct-dg-skeleton-sweep 1.1s linear infinite}@keyframes strct-dg-skeleton-sweep{0%{background-position:100% 0}to{background-position:-100% 0}}@media(prefers-reduced-motion:reduce){.strct-dg__skeleton-block{animation:none;background:var(--skeleton-hi, var(--acc18))}}.strct-dg__skeleton-row td{border-bottom:1px solid var(--b1)}.strct-dg__empty{text-align:center;color:var(--t2);padding:22px}.strct-dg__quickfilter{min-width:180px;max-width:260px}.strct-dg__quickfilter--end{order:2;margin-inline-start:auto}.strct-dg__filternote--end{order:3}.strct-dg__filternote{font-size:var(--text-sm);color:var(--t2);font-variant-numeric:tabular-nums;white-space:nowrap}.strct-dg__toolbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:9px 14px;border-bottom:1px solid var(--b2)}.strct-dg__foot{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:9px 14px;border-top:1px solid var(--b2);flex-wrap:wrap}.strct-dg__foot-left,.strct-dg__foot-right{display:flex;align-items:center;gap:12px}.strct-dg__actions{position:relative}.strct-dg__chooser-menu{position:absolute;bottom:calc(100% + 6px);inset-inline-start:0;z-index:var(--z-sticky);min-width:180px;background:var(--bg-1);border:1px solid var(--b2);border-radius:4px;box-shadow:var(--shadow-pop);padding:6px;display:flex;flex-direction:column;gap:2px}.strct-dg__chooser-menu--right{inset-inline-start:auto;inset-inline-end:0}.strct-dg__chooser-item{display:flex;align-items:center;gap:8px;padding:5px 8px;border-radius:3px;cursor:pointer;font-size:12px;color:var(--t1);transition:background .1s ease;-webkit-user-select:none;user-select:none}.strct-dg__chooser-item:hover{background:var(--bg-3)}.strct-dg__count{font-size:12px;color:var(--t2)}.strct-dg__count-sep{margin:0 8px;color:var(--b2)}.strct-dg__count-sel{color:var(--acc)}.strct-dg__filterbtn{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;margin-inline-start:2px;padding:0;border:0;border-radius:2px;background:transparent;color:var(--t3);cursor:pointer;vertical-align:middle}.strct-dg__filterbtn:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__filterbtn--active{color:var(--acc)}.strct-dg__filterbtn:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-dg__filterpanel{position:absolute;z-index:calc(var(--z-dropdown) + 10);display:flex;flex-direction:column;gap:6px;min-width:180px;padding:10px;background:var(--bg-1);border:1px solid var(--b2);border-radius:3px;box-shadow:var(--shh);font-weight:400;text-transform:none;letter-spacing:normal;white-space:nowrap}.strct-dg__filterinput{padding:5px 8px;border:1px solid var(--b2);border-radius:var(--radius-sm);background:var(--bg-2);color:var(--t1);font-family:var(--font);font-size:12px}.strct-dg__filterinput:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-dg__filteropt{display:flex;align-items:center;gap:7px;font-size:12.5px;color:var(--t1);cursor:pointer}.strct-dg__filterclear{align-self:flex-start;padding:3px 8px;border:1px solid var(--b2);border-radius:var(--radius-sm);background:transparent;color:var(--t2);font-family:var(--font);font-size:var(--text-sm);cursor:pointer}.strct-dg__filterclear:hover:not(:disabled){color:var(--t1);background:var(--bg-3)}.strct-dg__filterclear:disabled{color:var(--t4);cursor:default}.strct-dg tbody tr[tabindex]:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-dg__treepad{display:inline-block;height:1px;vertical-align:middle}.strct-dg__treebtn{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;margin-inline-end:4px;padding:0;border:0;border-radius:2px;background:transparent;color:var(--t3);cursor:pointer;vertical-align:middle}.strct-dg__treebtn:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__treebtn:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-dg__treebtn strct-icon{transition:transform .15s ease}.strct-dg__treebtn--open strct-icon{transform:rotate(90deg)}.strct-dg__treebtn--leaf{cursor:default;pointer-events:none}@media(prefers-reduced-motion:reduce){.strct-dg__treebtn strct-icon{transition:none}}.strct-dg__cell--editable{cursor:text;position:relative}.strct-dg__cell--editable:hover{box-shadow:inset 0 0 0 1px var(--b2)}.strct-dg__cell--editable:focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--acc50)}.strct-dg__editpencil{position:absolute;top:50%;inset-inline-end:6px;transform:translateY(-50%);color:var(--t3);opacity:0;pointer-events:none}td:hover>.strct-dg__editpencil,td:focus-within>.strct-dg__editpencil{opacity:1}.strct-dg__editinput{width:100%;box-sizing:border-box;padding:3px 6px;border:1px solid var(--acc);border-radius:var(--radius-sm);background:var(--bg-1);color:var(--t1);font:inherit}.strct-dg__editselect,.strct-dg__editnumber{display:block;width:100%}.strct-dg__editinput:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}\n"] }]
|
|
17850
|
+
}], ctorParameters: () => [], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: true }] }], pageSizeFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }], selectableFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectable", required: false }] }], expandable: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandable", required: false }] }], detailPaneFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "detailPane", required: false }] }], paneListWidthFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "paneListWidth", required: false }] }], paneTakeoverWidthFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "paneTakeoverWidth", required: false }] }], activeRowId: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeRowId", required: false }] }, { type: i0.Output, args: ["activeRowIdChange"] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }], singleLine: [{ type: i0.Input, args: [{ isSignal: true, alias: "singleLine", required: false }] }], emptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyText", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], resizable: [{ type: i0.Input, args: [{ isSignal: true, alias: "resizable", required: false }] }], columnChooser: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnChooser", required: false }] }], syncFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "sync", required: false }] }], footerActionsDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "footerActionsDisabled", required: false }] }], rowId: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowId", required: false }] }], selectionModeFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionMode", required: false }] }], selectedId: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedId", required: false }] }, { type: i0.Output, args: ["selectedIdChange"] }], rowSelectableFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowSelectable", required: false }] }], flush: [{ type: i0.Input, args: [{ isSignal: true, alias: "flush", required: false }] }], caption: [{ type: i0.Input, args: [{ isSignal: true, alias: "caption", required: false }] }], hasMoreFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasMore", required: false }] }], loadingMoreFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingMore", required: false }] }], moreTotalFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "moreTotal", required: false }] }], loadMore: [{ type: i0.Output, args: ["loadMore"] }], groupSelectFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupSelect", required: false }] }], rowActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowActions", required: false }] }], initialSelectionFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialSelection", required: false }] }], selectedIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedIds", required: false }] }, { type: i0.Output, args: ["selectedIdsChange"] }], labels: [{ type: i0.Input, args: [{ isSignal: true, alias: "labels", required: false }] }], viewportHeightFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewportHeight", required: false }] }], maxHeightFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxHeight", required: false }] }], editHint: [{ type: i0.Input, args: [{ isSignal: true, alias: "editHint", required: false }] }], rowHeightFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowHeight", required: false }] }], lazyFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "lazy", required: false }] }], totalFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "total", required: false }] }], stateKeyFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "stateKey", required: false }] }], columnState: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnState", required: false }] }, { type: i0.Output, args: ["columnStateChange"] }], reorderable: [{ type: i0.Input, args: [{ isSignal: true, alias: "reorderable", required: false }] }], groupByFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupBy", required: false }] }], groupsFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "groups", required: false }] }], showEmptyGroupsFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "showEmptyGroups", required: false }] }], collapsedGroups: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsedGroups", required: false }] }, { type: i0.Output, args: ["collapsedGroupsChange"] }], filters: [{ type: i0.Input, args: [{ isSignal: true, alias: "filters", required: false }] }, { type: i0.Output, args: ["filtersChange"] }], quickFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "quickFilter", required: false }] }, { type: i0.Output, args: ["quickFilterChange"] }], quickFilterFieldsFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "quickFilterFields", required: false }] }], quickFilterableFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "quickFilterable", required: false }] }], quickFilterAlignFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "quickFilterAlign", required: false }] }], childrenKeyFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "childrenKey", required: false }] }], interactionMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "interactionMode", required: false }] }], selectionColumnFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionColumn", required: false }] }], rowActivate: [{ type: i0.Output, args: ["rowActivate"] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], syncChange: [{ type: i0.Output, args: ["syncChange"] }], rowAction: [{ type: i0.Output, args: ["rowAction"] }], lazyLoad: [{ type: i0.Output, args: ["lazyLoad"] }], cellEdit: [{ type: i0.Output, args: ["cellEdit"] }], selectionCfg: [{ type: i0.Input, args: [{ isSignal: true, alias: "selection", required: false }] }], paneFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "pane", required: false }] }], pagingFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "paging", required: false }] }], virtualFlat: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtual", required: false }] }], groupingCfg: [{ type: i0.Input, args: [{ isSignal: true, alias: "grouping", required: false }] }], filteringCfg: [{ type: i0.Input, args: [{ isSignal: true, alias: "filtering", required: false }] }], stateCfg: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: false }] }], detailDef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => StrctRowDetailDef), { isSignal: true }] }], groupHeaderDef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => StrctGroupHeaderDef), { isSignal: true }] }], paneTitleDef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => StrctDetailPaneTitle), { isSignal: true }] }], actionBarDef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => StrctDatagridActionBar), { isSignal: true }] }], actionBarCaptionDef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => StrctDatagridActionBarCaption), { isSignal: true }] }], cellDefs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => StrctCellDef), { isSignal: true }] }], onDocClickOverlays: [{
|
|
19223
17851
|
type: HostListener,
|
|
19224
17852
|
args: ['document:click', ['$event']]
|
|
19225
17853
|
}], onEscapeOverlays: [{
|
|
@@ -31994,5 +30622,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
|
|
|
31994
30622
|
* Generated bundle index. Do not edit.
|
|
31995
30623
|
*/
|
|
31996
30624
|
|
|
31997
|
-
export { FOCUSABLE_SELECTOR, STRCT_DP_DOW, STRCT_DP_DOW_FULL, STRCT_DP_MONTHS, STRCT_ICONS, STRCT_ICON_GROUPS, STRCT_ICON_NAMES, STRCT_MASKS, STRCT_MD_LIMITS, STRCT_NOTIFICATION_HISTORY_LIMIT, STRCT_PALETTES, STRCT_RAW_ICONS, STRCT_TIME_RANGE_PRESETS, STRCT_WIZARD_DEFAULTS, StrctAccordion, StrctAccordionPanel, StrctAccordionPanelMeta, StrctAlert, StrctAlertActions, StrctAnnouncer, StrctAvatar, StrctBadge, StrctBreadcrumb, StrctBreadcrumbItem, StrctButton, StrctButtonGroup, StrctBytesPipe, StrctCard, StrctCardBlock, StrctCardFooter, StrctCardHeader, StrctCardHeaderActions, StrctCardHeaderLeading, StrctCardHeaderMeta, StrctCardHeaderNote, StrctCascadeColumn, StrctCascadeHost, StrctCascadeSelect, StrctCellDef, StrctCellStatus, StrctChange, StrctChart, StrctChatAttachment, StrctChatComposer, StrctChatMessage, StrctChatMessageActions, StrctChatThread, StrctCheckbox, StrctChips, StrctCode, StrctCodeInline, StrctColorPicker, StrctCombobox, StrctCommandPalette, StrctConfirmOutlet, StrctConfirmService, StrctContextMenu, StrctContextMenuTrigger, StrctControlDescription, StrctCopy, StrctDatagrid, StrctDatagridActionBar, StrctDatagridActionBarCaption, StrctDatepicker, StrctDatetimePicker, StrctDesc, StrctDescriptionList, StrctDetailPaneActions, StrctDetailPaneMeta, StrctDetailPaneTitle, StrctDiff, StrctDivider, StrctDonut, StrctDrawer, StrctDrawerFooter, StrctDropdown, StrctDropdownDivider, StrctDropdownGroup, StrctDropdownItem, StrctDropdownItemAction, StrctDropdownItemDescription, StrctDropdownItemIcon, StrctDropdownItemLabel, StrctDropdownTrigger, StrctDurationPipe, StrctEmptyState, StrctField, StrctFieldGroup, StrctFieldHint, StrctFieldPrefix, StrctFieldSuffix, StrctFieldValue, StrctFile, StrctFilterBar, StrctFlow, StrctFlowNodeTemplate, StrctFooter, StrctGauge, StrctGroupHeaderDef, StrctHeader, StrctHeaderAction, StrctHeatmap, StrctHero, StrctHotkeysHelp, StrctHotkeysService, StrctIcon, StrctInlineEdit, StrctInput, StrctInputMask, StrctInputOtp, StrctKbd, StrctKnob, StrctLegend, StrctList, StrctListItem, StrctListItemDescription, StrctListItemLeading, StrctListItemMeta, StrctListItemTrailing, StrctLiveIndicator, StrctLogViewer, StrctLogin, StrctMarkdown, StrctMarkdownToken, StrctMediaFrame, StrctMenuPanel, StrctMenuService, StrctMenubar, StrctMetricTile, StrctModal, StrctModalContent, StrctNav, StrctNavItem, StrctNotificationCenter, StrctNumber, StrctOverlay, StrctPageHeader, StrctPageHeaderActions, StrctPageHeaderCrumbs, StrctPageHeaderTitleMeta, StrctPagination, StrctPassword, StrctPopover, StrctPopoverTrigger, StrctProductSwitcher, StrctProgress, StrctQr, StrctRadio, StrctRadioGroup, StrctRail, StrctRange, StrctRatePipe, StrctRating, StrctReorder, StrctReorderGroup, StrctReorderHandle, StrctReorderItem, StrctResizeHandle, StrctRowDetailDef, StrctSearchbox, StrctSectionHeader, StrctSectionHeaderActions, StrctSectionHeaderMeta, StrctSectionMenu, StrctSegmented, StrctSelect, StrctShell, StrctShellService, StrctSiPipe, StrctSignpost, StrctSignpostTrigger, StrctSkeleton, StrctSparkline, StrctSpeedDial, StrctSpinner, StrctSplitButton, StrctSplitter, StrctStack, StrctStackItem, StrctStatusDot, StrctStep, StrctStepAction, StrctSteps, StrctSubmenu, StrctTab, StrctTable, StrctTabs, StrctTag, StrctTagLeading, StrctThemeService, StrctThemeSwitcher, StrctTimeRangePicker, StrctTimeline, StrctTimelineItem, StrctToastOutlet, StrctToastService, StrctToggle, StrctToolbar, StrctToolbarCaption, StrctToolbarSpacer, StrctTooltip, StrctTour, StrctTransfer, StrctTree, StrctTreeNode, StrctTreeSelect, StrctVerticalNav, StrctWatermark, StrctWindow, StrctWindowDock, StrctWindowDockItem, StrctWindowService, StrctWizard, StrctWizardAside, __qrInternals, defaultStateWords, focusFirstIn, keepTabInside, lockBodyScroll, parseAnsi, parseInlines, placeTooltip, provideStrctWizardDefaults, registerStrctIcon, restoreFocus, saveFocusedElement, strctCheckHostDisplay, strctCheckHostInputs, strctClassifyHref, strctComputeDiff, strctDpPad, strctFormatBytes, strctFormatDuration, strctFormatRate, strctFormatSi, strctParseMarkdown, strctQrMatrix, strctShowTooltip, strctValidationIcon, strctValidationTone, unlockBodyScroll };
|
|
30625
|
+
export { DG_LABELS, FOCUSABLE_SELECTOR, STRCT_DP_DOW, STRCT_DP_DOW_FULL, STRCT_DP_MONTHS, STRCT_ICONS, STRCT_ICON_GROUPS, STRCT_ICON_NAMES, STRCT_MASKS, STRCT_MD_LIMITS, STRCT_NOTIFICATION_HISTORY_LIMIT, STRCT_PALETTES, STRCT_RAW_ICONS, STRCT_TIME_RANGE_PRESETS, STRCT_WIZARD_DEFAULTS, StrctAccordion, StrctAccordionPanel, StrctAccordionPanelMeta, StrctAlert, StrctAlertActions, StrctAnnouncer, StrctAvatar, StrctBadge, StrctBreadcrumb, StrctBreadcrumbItem, StrctButton, StrctButtonGroup, StrctBytesPipe, StrctCard, StrctCardBlock, StrctCardFooter, StrctCardHeader, StrctCardHeaderActions, StrctCardHeaderLeading, StrctCardHeaderMeta, StrctCardHeaderNote, StrctCascadeColumn, StrctCascadeHost, StrctCascadeSelect, StrctCellDef, StrctCellStatus, StrctChange, StrctChart, StrctChatAttachment, StrctChatComposer, StrctChatMessage, StrctChatMessageActions, StrctChatThread, StrctCheckbox, StrctChips, StrctCode, StrctCodeInline, StrctColorPicker, StrctCombobox, StrctCommandPalette, StrctConfirmOutlet, StrctConfirmService, StrctContextMenu, StrctContextMenuTrigger, StrctControlDescription, StrctCopy, StrctDatagrid, StrctDatagridActionBar, StrctDatagridActionBarCaption, StrctDatepicker, StrctDatetimePicker, StrctDesc, StrctDescriptionList, StrctDetailPaneActions, StrctDetailPaneMeta, StrctDetailPaneTitle, StrctDiff, StrctDivider, StrctDonut, StrctDrawer, StrctDrawerFooter, StrctDropdown, StrctDropdownDivider, StrctDropdownGroup, StrctDropdownItem, StrctDropdownItemAction, StrctDropdownItemDescription, StrctDropdownItemIcon, StrctDropdownItemLabel, StrctDropdownTrigger, StrctDurationPipe, StrctEmptyState, StrctField, StrctFieldGroup, StrctFieldHint, StrctFieldPrefix, StrctFieldSuffix, StrctFieldValue, StrctFile, StrctFilterBar, StrctFlow, StrctFlowNodeTemplate, StrctFooter, StrctGauge, StrctGroupHeaderDef, StrctHeader, StrctHeaderAction, StrctHeatmap, StrctHero, StrctHotkeysHelp, StrctHotkeysService, StrctIcon, StrctInlineEdit, StrctInput, StrctInputMask, StrctInputOtp, StrctKbd, StrctKnob, StrctLegend, StrctList, StrctListItem, StrctListItemDescription, StrctListItemLeading, StrctListItemMeta, StrctListItemTrailing, StrctLiveIndicator, StrctLogViewer, StrctLogin, StrctMarkdown, StrctMarkdownToken, StrctMediaFrame, StrctMenuPanel, StrctMenuService, StrctMenubar, StrctMetricTile, StrctModal, StrctModalContent, StrctNav, StrctNavItem, StrctNotificationCenter, StrctNumber, StrctOverlay, StrctPageHeader, StrctPageHeaderActions, StrctPageHeaderCrumbs, StrctPageHeaderTitleMeta, StrctPagination, StrctPassword, StrctPopover, StrctPopoverTrigger, StrctProductSwitcher, StrctProgress, StrctQr, StrctRadio, StrctRadioGroup, StrctRail, StrctRange, StrctRatePipe, StrctRating, StrctReorder, StrctReorderGroup, StrctReorderHandle, StrctReorderItem, StrctResizeHandle, StrctRowDetailDef, StrctSearchbox, StrctSectionHeader, StrctSectionHeaderActions, StrctSectionHeaderMeta, StrctSectionMenu, StrctSegmented, StrctSelect, StrctShell, StrctShellService, StrctSiPipe, StrctSignpost, StrctSignpostTrigger, StrctSkeleton, StrctSparkline, StrctSpeedDial, StrctSpinner, StrctSplitButton, StrctSplitter, StrctStack, StrctStackItem, StrctStatusDot, StrctStep, StrctStepAction, StrctSteps, StrctSubmenu, StrctTab, StrctTable, StrctTabs, StrctTag, StrctTagLeading, StrctThemeService, StrctThemeSwitcher, StrctTimeRangePicker, StrctTimeline, StrctTimelineItem, StrctToastOutlet, StrctToastService, StrctToggle, StrctToolbar, StrctToolbarCaption, StrctToolbarSpacer, StrctTooltip, StrctTour, StrctTransfer, StrctTree, StrctTreeNode, StrctTreeSelect, StrctVerticalNav, StrctWatermark, StrctWindow, StrctWindowDock, StrctWindowDockItem, StrctWindowService, StrctWizard, StrctWizardAside, __qrInternals, defaultStateWords, focusFirstIn, keepTabInside, lockBodyScroll, parseAnsi, parseInlines, placeTooltip, provideStrctWizardDefaults, registerStrctIcon, restoreFocus, saveFocusedElement, strctCheckHostDisplay, strctCheckHostInputs, strctClassifyHref, strctComputeDiff, strctDpPad, strctFormatBytes, strctFormatDuration, strctFormatRate, strctFormatSi, strctParseMarkdown, strctQrMatrix, strctShowTooltip, strctValidationIcon, strctValidationTone, unlockBodyScroll };
|
|
31998
30626
|
//# sourceMappingURL=akcelik-strct.mjs.map
|