@akcelik/strct 5.30.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.
@@ -15243,6 +15243,21 @@ const DG_LABELS = {
15243
15243
  pageOf: (page, pages) => `Page ${page} of ${pages}`,
15244
15244
  rowsMatch: (shown, total) => `${shown} of ${total} rows match`,
15245
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
+ */
15246
15261
  /** Flat inputs already named in a deprecation warning, per app run. */
15247
15262
  const warnedFlatInputs = new Set();
15248
15263
  const pendingFlatInputWarnings = new Set();
@@ -17803,796 +17818,7 @@ class StrctDatagrid {
17803
17818
  return String(a ?? '').localeCompare(String(b ?? ''), undefined, { numeric: true });
17804
17819
  }
17805
17820
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctDatagrid, deps: [], target: i0.ɵɵFactoryTarget.Component });
17806
- 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: `
17807
- <!-- One polite region for everything the grid does to itself: sorting,
17808
- paging and filtering all change the rows without saying so. -->
17809
- <span class="strct-dg__announcer" role="status" aria-live="polite">{{ announcement() }}</span>
17810
- @if (actionBarDef() || quickFilterable() || actionBarCaptionDef()) {
17811
- <div class="strct-dg__toolbar">
17812
- @if (quickFilterable()) {
17813
- <strct-searchbox
17814
- class="strct-dg__quickfilter"
17815
- [class.strct-dg__quickfilter--end]="quickFilterAlign() === 'end'"
17816
- [placeholder]="L().quickFilter"
17817
- [ariaLabel]="L().quickFilter"
17818
- [value]="quickFilter()"
17819
- (valueChange)="quickFilter.set($event)"
17820
- />
17821
- @if (filterNote(); as note) {
17822
- <span
17823
- class="strct-dg__filternote"
17824
- [class.strct-dg__filternote--end]="quickFilterAlign() === 'end'"
17825
- >{{ note }}</span
17826
- >
17827
- }
17828
- }
17829
- <span class="strct-dg__actioncaption">
17830
- <ng-content select="[strctDatagridActionBarCaption]" />
17831
- </span>
17832
- <ng-content select="[strctDatagridActionBar]" />
17833
- </div>
17834
- }
17835
-
17836
- @if (hasEditableColumn()) {
17837
- <!-- What the editable cells point at with aria-describedby: a keyboard
17838
- user is told the cell can be edited, and how. -->
17839
- <!-- In flow, not absolutely positioned: an out-of-flow box whose
17840
- containing block is the page extends the document's scrollable area
17841
- from wherever the grid happens to sit. 1x1 and clipped is enough. -->
17842
- <span
17843
- class="strct-sr-only"
17844
- style="display: inline-block; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap"
17845
- [id]="editHintId"
17846
- >{{ L().editCellInstructions }}</span
17847
- >
17848
- }
17849
-
17850
- @if (bulkHint(); as hint) {
17851
- <!-- Selecting the page is not selecting the set. Say which one happened,
17852
- and offer the other. -->
17853
- <div class="strct-dg__bulk" role="status">
17854
- <span>{{ hint.text }}</span>
17855
- <button strct-button variant="flat" size="sm" (click)="hint.run()">
17856
- {{ hint.action }}
17857
- </button>
17858
- </div>
17859
- }
17860
- <div
17861
- class="strct-dg__layout"
17862
- [class.strct-dg__layout--paned]="paneOpen()"
17863
- [class.strct-dg__layout--panetakeover]="paneOpen() && narrowPane()"
17864
- [style.--strct-dg-pane-list-w]="paneListWidth()"
17865
- >
17866
- <div
17867
- class="strct-dg__scroll"
17868
- tabindex="0"
17869
- role="region"
17870
- [attr.aria-label]="L().rows"
17871
- [style.max-height.px]="virtual() ? viewportHeight() : maxHeight()"
17872
- (scroll)="virtual() && onScroll($event)"
17873
- >
17874
- <table
17875
- class="strct-dg"
17876
- [attr.role]="childrenKey() ? 'treegrid' : gridMode() ? 'grid' : null"
17877
- [attr.aria-rowcount]="ariaRowCount()"
17878
- [attr.aria-labelledby]="caption() ? captionId : null"
17879
- >
17880
- @if (caption()) {
17881
- <caption class="strct-dg__caption" [id]="captionId">
17882
- {{
17883
- caption()
17884
- }}
17885
- </caption>
17886
- }
17887
- <thead>
17888
- <tr>
17889
- <!-- A utility column is still a column: axe reports every empty
17890
- header, and a screen-reader user hears nothing where the
17891
- detail, expand and select controls are. The name is hidden,
17892
- not absent. -->
17893
- @if (canDetail()) {
17894
- <th
17895
- class="strct-dg__expandcol"
17896
- scope="col"
17897
- [class.strct-dg__cell--sticky]="stickyActive()"
17898
- [style.insetInlineStart.px]="utilLeft('detail')"
17899
- >
17900
- <span class="strct-sr-only">{{ L().detailColumn }}</span>
17901
- </th>
17902
- }
17903
- @if (canExpand()) {
17904
- <th
17905
- class="strct-dg__expandcol"
17906
- scope="col"
17907
- [class.strct-dg__cell--sticky]="stickyActive()"
17908
- [style.insetInlineStart.px]="utilLeft('expand')"
17909
- >
17910
- <span class="strct-sr-only">{{ L().expandColumn }}</span>
17911
- </th>
17912
- }
17913
- @if (hasSelectionColumn()) {
17914
- <th
17915
- class="strct-dg__sel"
17916
- scope="col"
17917
- [class.strct-dg__cell--sticky]="stickyActive()"
17918
- [style.insetInlineStart.px]="utilLeft('sel')"
17919
- >
17920
- @if (mode() === 'multiple') {
17921
- <strct-checkbox
17922
- [ariaLabel]="L().selectAll"
17923
- [checked]="allPageSelected()"
17924
- [indeterminate]="somePageSelected()"
17925
- (checkedChange)="toggleAll()"
17926
- />
17927
- } @else {
17928
- <span class="strct-sr-only">{{ L().selectColumn }}</span>
17929
- }
17930
- </th>
17931
- }
17932
- @for (col of visibleColumns(); track col.key) {
17933
- <th
17934
- scope="col"
17935
- [style.text-align]="col.align ?? (col.numeric ? 'end' : 'start')"
17936
- [style.width]="colWidth(col.key) ?? col.width ?? null"
17937
- [class.strct-dg__th--sortable]="col.sortable"
17938
- [class.strct-dg__th--drop]="col.key === dropKey()"
17939
- [class.strct-dg__cell--sticky]="isSticky(col)"
17940
- [class.strct-dg__cell--sticky-last]="col.key === lastStickyKey()"
17941
- [style.insetInlineStart.px]="stickyLeft(col.key)"
17942
- [attr.data-col]="col.key"
17943
- [attr.aria-sort]="col.sortable ? ariaSort(col.key) : null"
17944
- [attr.draggable]="reorderable() ? true : null"
17945
- (dragstart)="onColDragStart(col.key, $event)"
17946
- (dragover)="onColDragOver(col.key, $event)"
17947
- (drop)="onColDrop(col.key)"
17948
- (dragend)="onColDragEnd()"
17949
- >
17950
- <span class="strct-dg__hd">
17951
- <!-- A header that sorts is a button: a th with tabindex is
17952
- read as "column header, focusable" and never says it
17953
- can be activated. aria-sort stays on the th, which is
17954
- what carries the column's sorted state. -->
17955
- @if (col.sortable) {
17956
- <!-- The button covers most of the header, so it carries
17957
- the drag source too: a reorderable column has to be
17958
- grabbable where the pointer actually lands. The
17959
- event bubbles to the th's own handlers. -->
17960
- <button
17961
- type="button"
17962
- class="strct-dg__sortbtn"
17963
- [attr.draggable]="reorderable() ? true : null"
17964
- (click)="sortBy(col.key)"
17965
- >
17966
- {{ col.label }}
17967
- <strct-icon
17968
- class="strct-dg__sorticon"
17969
- [name]="sortIcon(col.key)"
17970
- [size]="13"
17971
- />
17972
- </button>
17973
- } @else {
17974
- {{ col.label }}
17975
- }
17976
- @if (col.filterable || col.filterOptions) {
17977
- <button
17978
- #fbtn
17979
- type="button"
17980
- class="strct-dg__filterbtn"
17981
- [class.strct-dg__filterbtn--active]="hasFilter(col.key)"
17982
- [attr.aria-expanded]="filterOpenKey() === col.key"
17983
- [attr.aria-label]="L().filterColumn + ': ' + col.label"
17984
- (click)="toggleFilterPanel(col.key, $event)"
17985
- (keydown.enter)="$event.stopPropagation()"
17986
- (keydown.space)="$event.stopPropagation()"
17987
- >
17988
- <strct-icon name="filter" [size]="12" />
17989
- </button>
17990
- @if (filterOpenKey() === col.key) {
17991
- <div
17992
- class="strct-dg__filterpanel"
17993
- role="dialog"
17994
- [attr.aria-label]="L().filterColumn + ': ' + col.label"
17995
- [strctOverlay]="fbtn"
17996
- strctOverlayPlacement="bottom-start"
17997
- (click)="$event.stopPropagation()"
17998
- (keydown.enter)="$event.stopPropagation()"
17999
- (keydown.space)="$event.stopPropagation()"
18000
- >
18001
- @if (col.filterOptions; as opts) {
18002
- @for (opt of opts; track $index) {
18003
- <label class="strct-dg__filteropt">
18004
- <input
18005
- type="checkbox"
18006
- [checked]="optionChecked(col.key, opt)"
18007
- (change)="toggleFilterOption(col.key, opt)"
18008
- />
18009
- <span>{{ opt }}</span>
18010
- </label>
18011
- }
18012
- } @else {
18013
- <input
18014
- class="strct-dg__filterinput"
18015
- type="text"
18016
- [attr.placeholder]="L().filterPlaceholder"
18017
- [attr.aria-label]="L().filterColumn + ': ' + col.label"
18018
- [value]="textFilter(col.key)"
18019
- (input)="setTextFilter(col.key, $any($event.target).value)"
18020
- />
18021
- }
18022
- <button
18023
- type="button"
18024
- class="strct-dg__filterclear"
18025
- [disabled]="!hasFilter(col.key)"
18026
- (click)="clearFilter(col.key)"
18027
- >
18028
- {{ L().clearFilter }}
18029
- </button>
18030
- </div>
18031
- }
18032
- }
18033
- </span>
18034
- @if (resizable() && col.resizable !== false) {
18035
- <!-- A separator, not a bare div: a column could only be
18036
- resized with a mouse, which is the one input a
18037
- console cannot assume. -->
18038
- <div
18039
- class="strct-dg__resize"
18040
- role="separator"
18041
- aria-orientation="vertical"
18042
- tabindex="0"
18043
- [attr.aria-label]="L().resizeColumn(col.label)"
18044
- [attr.aria-valuenow]="separatorValue(col.key)"
18045
- [attr.aria-valuemin]="40"
18046
- (mousedown)="onResizeStart($event, col.key)"
18047
- (keydown)="onResizeKey($event, col.key)"
18048
- (dblclick)="resetWidth(col.key)"
18049
- ></div>
18050
- }
18051
- </th>
18052
- }
18053
- @if (canActions()) {
18054
- <th class="strct-dg__actioncol" scope="col" [attr.aria-label]="L().actions"></th>
18055
- }
18056
- </tr>
18057
- </thead>
18058
- <!--
18059
- focusin is the real keyboard path (focus does not bubble from cells);
18060
- the plain focus binding exists to satisfy mouse-events-have-key-events.
18061
- -->
18062
- <tbody
18063
- (mouseover)="revealIfClipped($event)"
18064
- (focusin)="revealIfClipped($event)"
18065
- (focus)="revealIfClipped($event)"
18066
- >
18067
- @if (loading()) {
18068
- @for (_ of [1, 2, 3, 4, 5]; track $index) {
18069
- <tr class="strct-dg__skeleton-row">
18070
- @if (canDetail()) {
18071
- <td class="strct-dg__expandcell"></td>
18072
- }
18073
- @if (canExpand()) {
18074
- <td class="strct-dg__expandcell"></td>
18075
- }
18076
- @if (hasSelectionColumn()) {
18077
- <td class="strct-dg__sel"></td>
18078
- }
18079
- @for (col of visibleColumns(); track col.key) {
18080
- <td [style.text-align]="col.align ?? 'start'">
18081
- <div class="strct-dg__skeleton-block"></div>
18082
- </td>
18083
- }
18084
- @if (canActions()) {
18085
- <td class="strct-dg__actioncell"></td>
18086
- }
18087
- </tr>
18088
- }
18089
- } @else {
18090
- @if (virtual() && topPad() > 0) {
18091
- <tr class="strct-dg__vspacer" aria-hidden="true">
18092
- <td [attr.colspan]="colspan()" [style.height.px]="topPad()"></td>
18093
- </tr>
18094
- }
18095
- @for (it of displayItems(); track itemKey(it)) {
18096
- @if (it.group; as grp) {
18097
- <!-- Group header: distinct value + count, collapsible. -->
18098
- <tr class="strct-dg__grouprow">
18099
- @if (groupSelect() && mode() === 'multiple') {
18100
- <td class="strct-dg__sel">
18101
- <strct-checkbox
18102
- [ariaLabel]="L().selectAllInGroup(grp.label)"
18103
- [checked]="groupAllSelected(grp.key)"
18104
- [indeterminate]="groupSomeSelected(grp.key)"
18105
- (checkedChange)="toggleGroupSelection(grp.key)"
18106
- />
18107
- </td>
18108
- }
18109
- <td
18110
- [attr.colspan]="
18111
- groupSelect() && mode() === 'multiple' ? colspan() - 1 : colspan()
18112
- "
18113
- >
18114
- <button
18115
- type="button"
18116
- class="strct-dg__groupbtn"
18117
- [attr.aria-expanded]="!grp.collapsed"
18118
- (click)="toggleGroup(grp.key)"
18119
- >
18120
- <span
18121
- class="strct-dg__groupchev"
18122
- [class.strct-dg__groupchev--open]="!grp.collapsed"
18123
- >
18124
- <strct-icon name="chevronRight" [size]="12" [strokeWidth]="1.7" />
18125
- </span>
18126
- @if (groupHeaderDef(); as tpl) {
18127
- <!-- The consumer draws the row; the button, its
18128
- aria-expanded and the keyboard stay ours. -->
18129
- <ng-container
18130
- [ngTemplateOutlet]="tpl.template"
18131
- [ngTemplateOutletContext]="{
18132
- $implicit: grp,
18133
- group: grp,
18134
- count: grp.count,
18135
- }"
18136
- />
18137
- } @else {
18138
- <span
18139
- class="strct-dg__grouplabel strct-dg__grouplabel--{{
18140
- grp.status ?? 'none'
18141
- }}"
18142
- >{{ grp.label }}</span
18143
- >
18144
- <!-- The three spans run together in the button's
18145
- name ("Needs your decision1Blocks the join…");
18146
- the separators are read, not seen. -->
18147
- <span class="strct-dg__announcer">, </span>
18148
- <span
18149
- class="strct-dg__groupcount strct-dg__groupcount--{{
18150
- grp.status ?? 'none'
18151
- }}"
18152
- >{{ grp.count }}</span
18153
- >
18154
- <!-- Seen: the chip's number. Heard: the number with
18155
- the grid's noun, because "Inconclusive, 3" does
18156
- not say three of what. -->
18157
- <span class="strct-dg__announcer"> {{ countNoun(grp.count) }}</span>
18158
- @if (grp.note) {
18159
- <span class="strct-dg__announcer">. </span>
18160
- <span class="strct-dg__groupnote">{{ grp.note }}</span>
18161
- }
18162
- }
18163
- </button>
18164
- </td>
18165
- </tr>
18166
- } @else {
18167
- @let row = it.row!;
18168
- <tr
18169
- [attr.aria-rowindex]="ariaRowIndex(row)"
18170
- [class.strct-dg__row--selected]="isSelected(row)"
18171
- [class.strct-dg__row--locked]="lockedReason(row) !== null"
18172
- [attr.aria-selected]="mode() === 'none' ? null : isSelected(row)"
18173
- [attr.aria-disabled]="lockedReason(row) !== null ? 'true' : null"
18174
- [attr.title]="lockedReason(row) || null"
18175
- (click)="onRowPick(row)"
18176
- [class.strct-dg__row--active]="paneOpen() && row === activeRow()"
18177
- [attr.aria-level]="childrenKey() ? treeDepth(row) + 1 : null"
18178
- [attr.aria-expanded]="
18179
- childrenKey() && treeHasChildren(row) ? treeExpanded(row) : null
18180
- "
18181
- [attr.tabindex]="
18182
- childrenKey()
18183
- ? treeRowTabindex(row)
18184
- : gridMode()
18185
- ? gridRowTabindex(row)
18186
- : canDetail()
18187
- ? paneRowTabindex(row)
18188
- : null
18189
- "
18190
- (keydown)="
18191
- childrenKey()
18192
- ? onTreeRowKeydown(row, $event)
18193
- : gridMode()
18194
- ? onGridRowKeydown(row, $event)
18195
- : onPaneRowKeydown(row, $event)
18196
- "
18197
- (dblclick)="onRowActivate(row)"
18198
- >
18199
- @if (canDetail()) {
18200
- <td
18201
- class="strct-dg__expandcell"
18202
- [class.strct-dg__cell--sticky]="stickyActive()"
18203
- [style.insetInlineStart.px]="utilLeft('detail')"
18204
- >
18205
- <button
18206
- type="button"
18207
- [attr.tabindex]="ctlTabindex()"
18208
- class="strct-dg__detailbtn"
18209
- [class.strct-dg__detailbtn--active]="row === activeRow()"
18210
- [attr.aria-expanded]="row === activeRow()"
18211
- [attr.aria-label]="L().openDetail"
18212
- (click)="openDetail(row)"
18213
- >
18214
- <strct-icon name="chevronDoubleRight" [size]="13" [strokeWidth]="1.6" />
18215
- </button>
18216
- </td>
18217
- }
18218
- @if (canExpand()) {
18219
- <td
18220
- class="strct-dg__expandcell"
18221
- [class.strct-dg__cell--sticky]="stickyActive()"
18222
- [style.insetInlineStart.px]="utilLeft('expand')"
18223
- >
18224
- <button
18225
- type="button"
18226
- [attr.tabindex]="ctlTabindex()"
18227
- class="strct-dg__expandbtn"
18228
- [class.strct-dg__expandbtn--open]="isExpanded(row)"
18229
- [attr.aria-expanded]="isExpanded(row)"
18230
- [attr.aria-label]="L().toggleDetail"
18231
- (click)="toggleExpand(row)"
18232
- >
18233
- <strct-icon name="chevronRight" [size]="12" [strokeWidth]="1.7" />
18234
- </button>
18235
- </td>
18236
- }
18237
- @if (hasSelectionColumn()) {
18238
- <td
18239
- class="strct-dg__sel"
18240
- [class.strct-dg__cell--sticky]="stickyActive()"
18241
- [style.insetInlineStart.px]="utilLeft('sel')"
18242
- >
18243
- @if (mode() === 'single') {
18244
- <!-- A native radio group: one name per grid, so the
18245
- arrow keys move between rows and Space picks,
18246
- without the grid inventing its own keyboarding. -->
18247
- <input
18248
- type="radio"
18249
- class="strct-dg__radio"
18250
- [name]="radioName"
18251
- [attr.aria-label]="selectRowLabel(row)"
18252
- [attr.aria-description]="lockedReason(row) || null"
18253
- [checked]="isSelected(row)"
18254
- [disabled]="lockedReason(row) !== null"
18255
- [attr.tabindex]="ctlTabindex()"
18256
- (change)="selectSingle(row)"
18257
- (click)="$event.stopPropagation()"
18258
- />
18259
- } @else {
18260
- <!-- click fires (and bubbles) before the input's change,
18261
- so the modifier is recorded by the time toggleRow runs. -->
18262
- <strct-checkbox
18263
- [ariaLabel]="selectRowLabel(row)"
18264
- [attr.aria-description]="lockedReason(row) || null"
18265
- [checked]="isSelected(row)"
18266
- [disabled]="lockedReason(row) !== null"
18267
- [tabIndex]="ctlTabindex()"
18268
- (click)="noteRangeIntent($event); $event.stopPropagation()"
18269
- (checkedChange)="toggleRow(row)"
18270
- />
18271
- }
18272
- </td>
18273
- }
18274
- @for (col of visibleColumns(); track col.key; let colIdx = $index) {
18275
- <td
18276
- [style.text-align]="col.align ?? (col.numeric ? 'end' : 'start')"
18277
- [class.strct-dg__cell--mono]="col.mono"
18278
- [class.strct-dg__cell--muted]="col.muted"
18279
- [class.strct-dg__cell--numeric]="col.numeric"
18280
- [class.strct-dg__cell--sticky]="isSticky(col)"
18281
- [class.strct-dg__cell--sticky-last]="col.key === lastStickyKey()"
18282
- [class.strct-dg__cell--editable]="col.editable"
18283
- [style.insetInlineStart.px]="stickyLeft(col.key)"
18284
- [attr.data-edit]="col.editable ? '' : null"
18285
- [attr.tabindex]="col.editable ? editCellTabindex(row, col) : null"
18286
- [attr.aria-describedby]="col.editable ? editHintId : null"
18287
- (dblclick)="col.editable && startEdit(row, col)"
18288
- (focus)="col.editable && onEditCellFocus(row, col)"
18289
- (keydown)="col.editable && onEditCellKeydown(row, col, $event)"
18290
- >
18291
- @if (childrenKey() && colIdx === 0) {
18292
- <span
18293
- class="strct-dg__treepad"
18294
- [style.width.px]="treeDepth(row) * 18"
18295
- aria-hidden="true"
18296
- ></span>
18297
- @if (treeHasChildren(row)) {
18298
- <button
18299
- type="button"
18300
- class="strct-dg__treebtn"
18301
- [class.strct-dg__treebtn--open]="treeExpanded(row)"
18302
- [attr.aria-expanded]="treeExpanded(row)"
18303
- [attr.aria-label]="L().toggleChildren"
18304
- (click)="toggleTreeRow(row)"
18305
- >
18306
- <strct-icon name="chevronRight" [size]="12" [strokeWidth]="1.7" />
18307
- </button>
18308
- } @else {
18309
- <span
18310
- class="strct-dg__treebtn strct-dg__treebtn--leaf"
18311
- aria-hidden="true"
18312
- ></span>
18313
- }
18314
- }
18315
- @if (isEditingCell(row, col)) {
18316
- @switch (col.editor ?? 'text') {
18317
- @case ('select') {
18318
- <!-- Choosing is the commit: there is nothing to
18319
- confirm with Enter once an option is picked. -->
18320
- <strct-select
18321
- class="strct-dg__editselect"
18322
- [options]="editorOptionsFor(row, col)"
18323
- [listLabel]="L().editCell + ': ' + col.label"
18324
- [ngModel]="row[col.key]"
18325
- (ngModelChange)="commitValue(row, col, $event)"
18326
- (keydown.escape)="cancelEdit($event)"
18327
- (click)="$event.stopPropagation()"
18328
- />
18329
- }
18330
- @case ('number') {
18331
- <strct-number
18332
- class="strct-dg__editnumber"
18333
- [ariaLabel]="L().editCell + ': ' + col.label"
18334
- [min]="col.editorMin ?? null"
18335
- [max]="col.editorMax ?? null"
18336
- [step]="col.editorStep ?? 1"
18337
- [ngModel]="row[col.key]"
18338
- (ngModelChange)="editDraft.set($event)"
18339
- (keydown.enter)="commitDraft(row, col, $event)"
18340
- (keydown.escape)="cancelEdit($event)"
18341
- (focusout)="commitOnLeave(row, col, $event)"
18342
- (click)="$event.stopPropagation()"
18343
- />
18344
- }
18345
- @default {
18346
- <input
18347
- class="strct-dg__editinput"
18348
- type="text"
18349
- [value]="row[col.key] ?? ''"
18350
- [attr.aria-label]="L().editCell + ': ' + col.label"
18351
- (keydown.enter)="commitEdit(row, col, $event)"
18352
- (keydown.escape)="cancelEdit($event)"
18353
- (blur)="commitEdit(row, col, $event)"
18354
- (click)="$event.stopPropagation()"
18355
- />
18356
- }
18357
- }
18358
- } @else if (cellTemplate(col.key); as tpl) {
18359
- <ng-container
18360
- [ngTemplateOutlet]="tpl"
18361
- [ngTemplateOutletContext]="{
18362
- $implicit: row,
18363
- row,
18364
- value: row[col.key],
18365
- column: col,
18366
- }"
18367
- />
18368
- } @else if (isBlank(row, col)) {
18369
- <span
18370
- class="strct-dg__empty"
18371
- [attr.aria-label]="col.emptyLabel || null"
18372
- >{{ col.emptyText }}</span
18373
- >
18374
- } @else {
18375
- {{ displayValue(row, col) }}
18376
- @if (col.descriptionKey && row[col.descriptionKey]) {
18377
- <span class="strct-dg__celldesc">{{ row[col.descriptionKey] }}</span>
18378
- }
18379
- }
18380
- <!-- The affordance a mouse never needed: a cell that
18381
- can be edited says so on hover and on focus. -->
18382
- @if (col.editable && editHint() && !isEditingCell(row, col)) {
18383
- <strct-icon
18384
- class="strct-dg__editpencil"
18385
- name="pencil"
18386
- [size]="12"
18387
- [strokeWidth]="1.6"
18388
- aria-hidden="true"
18389
- />
18390
- }
18391
- </td>
18392
- }
18393
- @if (canActions()) {
18394
- <td class="strct-dg__actioncell">
18395
- <button
18396
- type="button"
18397
- [attr.tabindex]="ctlTabindex()"
18398
- class="strct-dg__kebab"
18399
- [attr.aria-label]="L().rowActions"
18400
- (click)="openRowMenu(row, $event)"
18401
- >
18402
- <strct-icon name="dots" [size]="16" />
18403
- </button>
18404
- </td>
18405
- }
18406
- </tr>
18407
- @if (canExpand() && isExpanded(row)) {
18408
- <tr class="strct-dg__detailrow">
18409
- <td [attr.colspan]="colspan()">
18410
- <div class="strct-dg__detail">
18411
- <ng-container
18412
- [ngTemplateOutlet]="detailDef()!.template"
18413
- [ngTemplateOutletContext]="{ $implicit: row, row }"
18414
- />
18415
- </div>
18416
- </td>
18417
- </tr>
18418
- }
18419
- }
18420
- } @empty {
18421
- <!-- "Nothing here" and "nothing matches what you typed" are
18422
- different states: the second one can be undone, and
18423
- saying so is the whole point. -->
18424
- <tr>
18425
- <td class="strct-dg__emptyrow" [attr.colspan]="colspan()">
18426
- @if (filteredAway()) {
18427
- <strct-empty-state
18428
- size="sm"
18429
- [titleLevel]="null"
18430
- [title]="L().noMatches"
18431
- [description]="noMatchesDescription()"
18432
- >
18433
- <button strct-button variant="flat" size="sm" (click)="clearAllFilters()">
18434
- {{ L().clearFilters }}
18435
- </button>
18436
- </strct-empty-state>
18437
- } @else {
18438
- <!-- Not a heading: a grid is a region of a page, and an
18439
- empty one used to put an <h3> in its outline. -->
18440
- <strct-empty-state size="sm" [titleLevel]="null" [title]="emptyText()" />
18441
- }
18442
- </td>
18443
- </tr>
18444
- }
18445
- @if (virtual() && bottomPad() > 0) {
18446
- <tr class="strct-dg__vspacer" aria-hidden="true">
18447
- <td [attr.colspan]="colspan()" [style.height.px]="bottomPad()"></td>
18448
- </tr>
18449
- }
18450
- }
18451
- </tbody>
18452
- </table>
18453
- </div>
18454
-
18455
- @if (paneOpen()) {
18456
- <aside class="strct-dg__pane">
18457
- <div class="strct-dg__pane-head">
18458
- @if (narrowPane()) {
18459
- <!-- The pane has taken the list's place, so there is a way back. -->
18460
- <button
18461
- type="button"
18462
- class="strct-dg__pane-back"
18463
- [attr.aria-label]="L().backToList"
18464
- (click)="closePane()"
18465
- >
18466
- <strct-icon name="chevronLeft" [size]="13" />
18467
- </button>
18468
- }
18469
- <span class="strct-dg__pane-title">
18470
- <ng-content select="[strctDetailPaneTitle]" />
18471
- @if (!paneTitleDef()) {
18472
- {{ activeRow()![columns()[0].key] }}
18473
- }
18474
- </span>
18475
- <span class="strct-dg__pane-meta">
18476
- <ng-content select="[strctDetailPaneMeta]" />
18477
- </span>
18478
- <span class="strct-dg__pane-actions">
18479
- <ng-content select="[strctDetailPaneActions]" />
18480
- </span>
18481
- <button
18482
- type="button"
18483
- class="strct-dg__pane-close"
18484
- [attr.aria-label]="L().closeDetail"
18485
- (click)="closePane()"
18486
- >
18487
- <strct-icon name="close" [size]="13" />
18488
- </button>
18489
- </div>
18490
- <div class="strct-dg__pane-body">
18491
- <ng-container
18492
- [ngTemplateOutlet]="detailDef()!.template"
18493
- [ngTemplateOutletContext]="{ $implicit: activeRow(), row: activeRow() }"
18494
- />
18495
- </div>
18496
- </aside>
18497
- }
18498
- </div>
18499
-
18500
- @if (showFooter()) {
18501
- <div class="strct-dg__foot">
18502
- <div class="strct-dg__foot-left">
18503
- @if (columnChooser() || sync()) {
18504
- <div class="strct-dg__actions">
18505
- <strct-button-group>
18506
- @if (columnChooser()) {
18507
- <button
18508
- strct-button
18509
- size="sm"
18510
- [class.is-open]="chooserOpen()"
18511
- [disabled]="footerActionsDisabled()"
18512
- [attr.aria-label]="L().chooseColumns"
18513
- (click)="toggleChooser($event)"
18514
- >
18515
- <strct-icon name="settings" [size]="16" />
18516
- </button>
18517
- }
18518
- @if (sync()) {
18519
- <button
18520
- strct-button
18521
- size="sm"
18522
- [disabled]="footerActionsDisabled()"
18523
- [attr.aria-label]="L().refresh"
18524
- (click)="syncChange.emit()"
18525
- >
18526
- <strct-icon name="refresh" [size]="16" />
18527
- </button>
18528
- }
18529
- </strct-button-group>
18530
- @if (columnChooser() && chooserOpen()) {
18531
- <div class="strct-dg__chooser-menu">
18532
- @for (col of columns(); track col.key) {
18533
- <!-- The whole row toggles; the checkbox's own click must not
18534
- reach the row or the column would flip twice. -->
18535
- <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->
18536
- <div
18537
- class="strct-dg__chooser-item"
18538
- (click)="toggleColumn(col.key, hiddenColumns().has(col.key))"
18539
- >
18540
- <strct-checkbox
18541
- [checked]="!hiddenColumns().has(col.key)"
18542
- (checkedChange)="toggleColumn(col.key, $event)"
18543
- (click)="$event.stopPropagation()"
18544
- />
18545
- <span>{{ col.label }}</span>
18546
- </div>
18547
- }
18548
- </div>
18549
- }
18550
- </div>
18551
- }
18552
- <span class="strct-dg__count">
18553
- @if (paging() === 'more') {
18554
- {{ L().showing(rows().length, moreTotal() ?? undefined) }}
18555
- } @else {
18556
- {{ totalCount() }} {{ totalCount() === 1 ? L().row : L().rows }}
18557
- }
18558
- @if (selectedCount() && mode() !== 'single') {
18559
- <span class="strct-dg__count-sep">|</span>
18560
- <span class="strct-dg__count-sel">{{ selectedCount() }} {{ L().selected }}</span>
18561
- }
18562
- </span>
18563
- </div>
18564
- <div class="strct-dg__foot-right">
18565
- <!-- A feed that pages by cursor loads more at the end: page numbers
18566
- are something a cursor API cannot answer. It takes the pager's
18567
- place — the column chooser, the sync button and the count are
18568
- the footer's, not the pager's. -->
18569
- @if (paging() === 'more') {
18570
- @if (hasMore()) {
18571
- <button
18572
- strct-button
18573
- size="sm"
18574
- class="strct-dg__more"
18575
- [disabled]="loadingMore()"
18576
- (click)="loadMore.emit()"
18577
- >
18578
- @if (loadingMore()) {
18579
- <strct-spinner size="sm" />
18580
- }
18581
- {{ L().loadMore }}
18582
- </button>
18583
- }
18584
- } @else if (pageSize() > 0 && !groupBy()) {
18585
- <strct-pagination
18586
- [total]="totalCount()"
18587
- [pageSize]="pageSize()"
18588
- [page]="page()"
18589
- (pageChange)="goToPage($event)"
18590
- />
18591
- }
18592
- </div>
18593
- </div>
18594
- }
18595
- `, 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 });
18596
17822
  }
18597
17823
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctDatagrid, decorators: [{
18598
17824
  type: Component,
@@ -18610,796 +17836,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
18610
17836
  StrctSpinner,
18611
17837
  StrctEmptyState,
18612
17838
  FormsModule,
18613
- ], template: `
18614
- <!-- One polite region for everything the grid does to itself: sorting,
18615
- paging and filtering all change the rows without saying so. -->
18616
- <span class="strct-dg__announcer" role="status" aria-live="polite">{{ announcement() }}</span>
18617
- @if (actionBarDef() || quickFilterable() || actionBarCaptionDef()) {
18618
- <div class="strct-dg__toolbar">
18619
- @if (quickFilterable()) {
18620
- <strct-searchbox
18621
- class="strct-dg__quickfilter"
18622
- [class.strct-dg__quickfilter--end]="quickFilterAlign() === 'end'"
18623
- [placeholder]="L().quickFilter"
18624
- [ariaLabel]="L().quickFilter"
18625
- [value]="quickFilter()"
18626
- (valueChange)="quickFilter.set($event)"
18627
- />
18628
- @if (filterNote(); as note) {
18629
- <span
18630
- class="strct-dg__filternote"
18631
- [class.strct-dg__filternote--end]="quickFilterAlign() === 'end'"
18632
- >{{ note }}</span
18633
- >
18634
- }
18635
- }
18636
- <span class="strct-dg__actioncaption">
18637
- <ng-content select="[strctDatagridActionBarCaption]" />
18638
- </span>
18639
- <ng-content select="[strctDatagridActionBar]" />
18640
- </div>
18641
- }
18642
-
18643
- @if (hasEditableColumn()) {
18644
- <!-- What the editable cells point at with aria-describedby: a keyboard
18645
- user is told the cell can be edited, and how. -->
18646
- <!-- In flow, not absolutely positioned: an out-of-flow box whose
18647
- containing block is the page extends the document's scrollable area
18648
- from wherever the grid happens to sit. 1x1 and clipped is enough. -->
18649
- <span
18650
- class="strct-sr-only"
18651
- style="display: inline-block; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap"
18652
- [id]="editHintId"
18653
- >{{ L().editCellInstructions }}</span
18654
- >
18655
- }
18656
-
18657
- @if (bulkHint(); as hint) {
18658
- <!-- Selecting the page is not selecting the set. Say which one happened,
18659
- and offer the other. -->
18660
- <div class="strct-dg__bulk" role="status">
18661
- <span>{{ hint.text }}</span>
18662
- <button strct-button variant="flat" size="sm" (click)="hint.run()">
18663
- {{ hint.action }}
18664
- </button>
18665
- </div>
18666
- }
18667
- <div
18668
- class="strct-dg__layout"
18669
- [class.strct-dg__layout--paned]="paneOpen()"
18670
- [class.strct-dg__layout--panetakeover]="paneOpen() && narrowPane()"
18671
- [style.--strct-dg-pane-list-w]="paneListWidth()"
18672
- >
18673
- <div
18674
- class="strct-dg__scroll"
18675
- tabindex="0"
18676
- role="region"
18677
- [attr.aria-label]="L().rows"
18678
- [style.max-height.px]="virtual() ? viewportHeight() : maxHeight()"
18679
- (scroll)="virtual() && onScroll($event)"
18680
- >
18681
- <table
18682
- class="strct-dg"
18683
- [attr.role]="childrenKey() ? 'treegrid' : gridMode() ? 'grid' : null"
18684
- [attr.aria-rowcount]="ariaRowCount()"
18685
- [attr.aria-labelledby]="caption() ? captionId : null"
18686
- >
18687
- @if (caption()) {
18688
- <caption class="strct-dg__caption" [id]="captionId">
18689
- {{
18690
- caption()
18691
- }}
18692
- </caption>
18693
- }
18694
- <thead>
18695
- <tr>
18696
- <!-- A utility column is still a column: axe reports every empty
18697
- header, and a screen-reader user hears nothing where the
18698
- detail, expand and select controls are. The name is hidden,
18699
- not absent. -->
18700
- @if (canDetail()) {
18701
- <th
18702
- class="strct-dg__expandcol"
18703
- scope="col"
18704
- [class.strct-dg__cell--sticky]="stickyActive()"
18705
- [style.insetInlineStart.px]="utilLeft('detail')"
18706
- >
18707
- <span class="strct-sr-only">{{ L().detailColumn }}</span>
18708
- </th>
18709
- }
18710
- @if (canExpand()) {
18711
- <th
18712
- class="strct-dg__expandcol"
18713
- scope="col"
18714
- [class.strct-dg__cell--sticky]="stickyActive()"
18715
- [style.insetInlineStart.px]="utilLeft('expand')"
18716
- >
18717
- <span class="strct-sr-only">{{ L().expandColumn }}</span>
18718
- </th>
18719
- }
18720
- @if (hasSelectionColumn()) {
18721
- <th
18722
- class="strct-dg__sel"
18723
- scope="col"
18724
- [class.strct-dg__cell--sticky]="stickyActive()"
18725
- [style.insetInlineStart.px]="utilLeft('sel')"
18726
- >
18727
- @if (mode() === 'multiple') {
18728
- <strct-checkbox
18729
- [ariaLabel]="L().selectAll"
18730
- [checked]="allPageSelected()"
18731
- [indeterminate]="somePageSelected()"
18732
- (checkedChange)="toggleAll()"
18733
- />
18734
- } @else {
18735
- <span class="strct-sr-only">{{ L().selectColumn }}</span>
18736
- }
18737
- </th>
18738
- }
18739
- @for (col of visibleColumns(); track col.key) {
18740
- <th
18741
- scope="col"
18742
- [style.text-align]="col.align ?? (col.numeric ? 'end' : 'start')"
18743
- [style.width]="colWidth(col.key) ?? col.width ?? null"
18744
- [class.strct-dg__th--sortable]="col.sortable"
18745
- [class.strct-dg__th--drop]="col.key === dropKey()"
18746
- [class.strct-dg__cell--sticky]="isSticky(col)"
18747
- [class.strct-dg__cell--sticky-last]="col.key === lastStickyKey()"
18748
- [style.insetInlineStart.px]="stickyLeft(col.key)"
18749
- [attr.data-col]="col.key"
18750
- [attr.aria-sort]="col.sortable ? ariaSort(col.key) : null"
18751
- [attr.draggable]="reorderable() ? true : null"
18752
- (dragstart)="onColDragStart(col.key, $event)"
18753
- (dragover)="onColDragOver(col.key, $event)"
18754
- (drop)="onColDrop(col.key)"
18755
- (dragend)="onColDragEnd()"
18756
- >
18757
- <span class="strct-dg__hd">
18758
- <!-- A header that sorts is a button: a th with tabindex is
18759
- read as "column header, focusable" and never says it
18760
- can be activated. aria-sort stays on the th, which is
18761
- what carries the column's sorted state. -->
18762
- @if (col.sortable) {
18763
- <!-- The button covers most of the header, so it carries
18764
- the drag source too: a reorderable column has to be
18765
- grabbable where the pointer actually lands. The
18766
- event bubbles to the th's own handlers. -->
18767
- <button
18768
- type="button"
18769
- class="strct-dg__sortbtn"
18770
- [attr.draggable]="reorderable() ? true : null"
18771
- (click)="sortBy(col.key)"
18772
- >
18773
- {{ col.label }}
18774
- <strct-icon
18775
- class="strct-dg__sorticon"
18776
- [name]="sortIcon(col.key)"
18777
- [size]="13"
18778
- />
18779
- </button>
18780
- } @else {
18781
- {{ col.label }}
18782
- }
18783
- @if (col.filterable || col.filterOptions) {
18784
- <button
18785
- #fbtn
18786
- type="button"
18787
- class="strct-dg__filterbtn"
18788
- [class.strct-dg__filterbtn--active]="hasFilter(col.key)"
18789
- [attr.aria-expanded]="filterOpenKey() === col.key"
18790
- [attr.aria-label]="L().filterColumn + ': ' + col.label"
18791
- (click)="toggleFilterPanel(col.key, $event)"
18792
- (keydown.enter)="$event.stopPropagation()"
18793
- (keydown.space)="$event.stopPropagation()"
18794
- >
18795
- <strct-icon name="filter" [size]="12" />
18796
- </button>
18797
- @if (filterOpenKey() === col.key) {
18798
- <div
18799
- class="strct-dg__filterpanel"
18800
- role="dialog"
18801
- [attr.aria-label]="L().filterColumn + ': ' + col.label"
18802
- [strctOverlay]="fbtn"
18803
- strctOverlayPlacement="bottom-start"
18804
- (click)="$event.stopPropagation()"
18805
- (keydown.enter)="$event.stopPropagation()"
18806
- (keydown.space)="$event.stopPropagation()"
18807
- >
18808
- @if (col.filterOptions; as opts) {
18809
- @for (opt of opts; track $index) {
18810
- <label class="strct-dg__filteropt">
18811
- <input
18812
- type="checkbox"
18813
- [checked]="optionChecked(col.key, opt)"
18814
- (change)="toggleFilterOption(col.key, opt)"
18815
- />
18816
- <span>{{ opt }}</span>
18817
- </label>
18818
- }
18819
- } @else {
18820
- <input
18821
- class="strct-dg__filterinput"
18822
- type="text"
18823
- [attr.placeholder]="L().filterPlaceholder"
18824
- [attr.aria-label]="L().filterColumn + ': ' + col.label"
18825
- [value]="textFilter(col.key)"
18826
- (input)="setTextFilter(col.key, $any($event.target).value)"
18827
- />
18828
- }
18829
- <button
18830
- type="button"
18831
- class="strct-dg__filterclear"
18832
- [disabled]="!hasFilter(col.key)"
18833
- (click)="clearFilter(col.key)"
18834
- >
18835
- {{ L().clearFilter }}
18836
- </button>
18837
- </div>
18838
- }
18839
- }
18840
- </span>
18841
- @if (resizable() && col.resizable !== false) {
18842
- <!-- A separator, not a bare div: a column could only be
18843
- resized with a mouse, which is the one input a
18844
- console cannot assume. -->
18845
- <div
18846
- class="strct-dg__resize"
18847
- role="separator"
18848
- aria-orientation="vertical"
18849
- tabindex="0"
18850
- [attr.aria-label]="L().resizeColumn(col.label)"
18851
- [attr.aria-valuenow]="separatorValue(col.key)"
18852
- [attr.aria-valuemin]="40"
18853
- (mousedown)="onResizeStart($event, col.key)"
18854
- (keydown)="onResizeKey($event, col.key)"
18855
- (dblclick)="resetWidth(col.key)"
18856
- ></div>
18857
- }
18858
- </th>
18859
- }
18860
- @if (canActions()) {
18861
- <th class="strct-dg__actioncol" scope="col" [attr.aria-label]="L().actions"></th>
18862
- }
18863
- </tr>
18864
- </thead>
18865
- <!--
18866
- focusin is the real keyboard path (focus does not bubble from cells);
18867
- the plain focus binding exists to satisfy mouse-events-have-key-events.
18868
- -->
18869
- <tbody
18870
- (mouseover)="revealIfClipped($event)"
18871
- (focusin)="revealIfClipped($event)"
18872
- (focus)="revealIfClipped($event)"
18873
- >
18874
- @if (loading()) {
18875
- @for (_ of [1, 2, 3, 4, 5]; track $index) {
18876
- <tr class="strct-dg__skeleton-row">
18877
- @if (canDetail()) {
18878
- <td class="strct-dg__expandcell"></td>
18879
- }
18880
- @if (canExpand()) {
18881
- <td class="strct-dg__expandcell"></td>
18882
- }
18883
- @if (hasSelectionColumn()) {
18884
- <td class="strct-dg__sel"></td>
18885
- }
18886
- @for (col of visibleColumns(); track col.key) {
18887
- <td [style.text-align]="col.align ?? 'start'">
18888
- <div class="strct-dg__skeleton-block"></div>
18889
- </td>
18890
- }
18891
- @if (canActions()) {
18892
- <td class="strct-dg__actioncell"></td>
18893
- }
18894
- </tr>
18895
- }
18896
- } @else {
18897
- @if (virtual() && topPad() > 0) {
18898
- <tr class="strct-dg__vspacer" aria-hidden="true">
18899
- <td [attr.colspan]="colspan()" [style.height.px]="topPad()"></td>
18900
- </tr>
18901
- }
18902
- @for (it of displayItems(); track itemKey(it)) {
18903
- @if (it.group; as grp) {
18904
- <!-- Group header: distinct value + count, collapsible. -->
18905
- <tr class="strct-dg__grouprow">
18906
- @if (groupSelect() && mode() === 'multiple') {
18907
- <td class="strct-dg__sel">
18908
- <strct-checkbox
18909
- [ariaLabel]="L().selectAllInGroup(grp.label)"
18910
- [checked]="groupAllSelected(grp.key)"
18911
- [indeterminate]="groupSomeSelected(grp.key)"
18912
- (checkedChange)="toggleGroupSelection(grp.key)"
18913
- />
18914
- </td>
18915
- }
18916
- <td
18917
- [attr.colspan]="
18918
- groupSelect() && mode() === 'multiple' ? colspan() - 1 : colspan()
18919
- "
18920
- >
18921
- <button
18922
- type="button"
18923
- class="strct-dg__groupbtn"
18924
- [attr.aria-expanded]="!grp.collapsed"
18925
- (click)="toggleGroup(grp.key)"
18926
- >
18927
- <span
18928
- class="strct-dg__groupchev"
18929
- [class.strct-dg__groupchev--open]="!grp.collapsed"
18930
- >
18931
- <strct-icon name="chevronRight" [size]="12" [strokeWidth]="1.7" />
18932
- </span>
18933
- @if (groupHeaderDef(); as tpl) {
18934
- <!-- The consumer draws the row; the button, its
18935
- aria-expanded and the keyboard stay ours. -->
18936
- <ng-container
18937
- [ngTemplateOutlet]="tpl.template"
18938
- [ngTemplateOutletContext]="{
18939
- $implicit: grp,
18940
- group: grp,
18941
- count: grp.count,
18942
- }"
18943
- />
18944
- } @else {
18945
- <span
18946
- class="strct-dg__grouplabel strct-dg__grouplabel--{{
18947
- grp.status ?? 'none'
18948
- }}"
18949
- >{{ grp.label }}</span
18950
- >
18951
- <!-- The three spans run together in the button's
18952
- name ("Needs your decision1Blocks the join…");
18953
- the separators are read, not seen. -->
18954
- <span class="strct-dg__announcer">, </span>
18955
- <span
18956
- class="strct-dg__groupcount strct-dg__groupcount--{{
18957
- grp.status ?? 'none'
18958
- }}"
18959
- >{{ grp.count }}</span
18960
- >
18961
- <!-- Seen: the chip's number. Heard: the number with
18962
- the grid's noun, because "Inconclusive, 3" does
18963
- not say three of what. -->
18964
- <span class="strct-dg__announcer"> {{ countNoun(grp.count) }}</span>
18965
- @if (grp.note) {
18966
- <span class="strct-dg__announcer">. </span>
18967
- <span class="strct-dg__groupnote">{{ grp.note }}</span>
18968
- }
18969
- }
18970
- </button>
18971
- </td>
18972
- </tr>
18973
- } @else {
18974
- @let row = it.row!;
18975
- <tr
18976
- [attr.aria-rowindex]="ariaRowIndex(row)"
18977
- [class.strct-dg__row--selected]="isSelected(row)"
18978
- [class.strct-dg__row--locked]="lockedReason(row) !== null"
18979
- [attr.aria-selected]="mode() === 'none' ? null : isSelected(row)"
18980
- [attr.aria-disabled]="lockedReason(row) !== null ? 'true' : null"
18981
- [attr.title]="lockedReason(row) || null"
18982
- (click)="onRowPick(row)"
18983
- [class.strct-dg__row--active]="paneOpen() && row === activeRow()"
18984
- [attr.aria-level]="childrenKey() ? treeDepth(row) + 1 : null"
18985
- [attr.aria-expanded]="
18986
- childrenKey() && treeHasChildren(row) ? treeExpanded(row) : null
18987
- "
18988
- [attr.tabindex]="
18989
- childrenKey()
18990
- ? treeRowTabindex(row)
18991
- : gridMode()
18992
- ? gridRowTabindex(row)
18993
- : canDetail()
18994
- ? paneRowTabindex(row)
18995
- : null
18996
- "
18997
- (keydown)="
18998
- childrenKey()
18999
- ? onTreeRowKeydown(row, $event)
19000
- : gridMode()
19001
- ? onGridRowKeydown(row, $event)
19002
- : onPaneRowKeydown(row, $event)
19003
- "
19004
- (dblclick)="onRowActivate(row)"
19005
- >
19006
- @if (canDetail()) {
19007
- <td
19008
- class="strct-dg__expandcell"
19009
- [class.strct-dg__cell--sticky]="stickyActive()"
19010
- [style.insetInlineStart.px]="utilLeft('detail')"
19011
- >
19012
- <button
19013
- type="button"
19014
- [attr.tabindex]="ctlTabindex()"
19015
- class="strct-dg__detailbtn"
19016
- [class.strct-dg__detailbtn--active]="row === activeRow()"
19017
- [attr.aria-expanded]="row === activeRow()"
19018
- [attr.aria-label]="L().openDetail"
19019
- (click)="openDetail(row)"
19020
- >
19021
- <strct-icon name="chevronDoubleRight" [size]="13" [strokeWidth]="1.6" />
19022
- </button>
19023
- </td>
19024
- }
19025
- @if (canExpand()) {
19026
- <td
19027
- class="strct-dg__expandcell"
19028
- [class.strct-dg__cell--sticky]="stickyActive()"
19029
- [style.insetInlineStart.px]="utilLeft('expand')"
19030
- >
19031
- <button
19032
- type="button"
19033
- [attr.tabindex]="ctlTabindex()"
19034
- class="strct-dg__expandbtn"
19035
- [class.strct-dg__expandbtn--open]="isExpanded(row)"
19036
- [attr.aria-expanded]="isExpanded(row)"
19037
- [attr.aria-label]="L().toggleDetail"
19038
- (click)="toggleExpand(row)"
19039
- >
19040
- <strct-icon name="chevronRight" [size]="12" [strokeWidth]="1.7" />
19041
- </button>
19042
- </td>
19043
- }
19044
- @if (hasSelectionColumn()) {
19045
- <td
19046
- class="strct-dg__sel"
19047
- [class.strct-dg__cell--sticky]="stickyActive()"
19048
- [style.insetInlineStart.px]="utilLeft('sel')"
19049
- >
19050
- @if (mode() === 'single') {
19051
- <!-- A native radio group: one name per grid, so the
19052
- arrow keys move between rows and Space picks,
19053
- without the grid inventing its own keyboarding. -->
19054
- <input
19055
- type="radio"
19056
- class="strct-dg__radio"
19057
- [name]="radioName"
19058
- [attr.aria-label]="selectRowLabel(row)"
19059
- [attr.aria-description]="lockedReason(row) || null"
19060
- [checked]="isSelected(row)"
19061
- [disabled]="lockedReason(row) !== null"
19062
- [attr.tabindex]="ctlTabindex()"
19063
- (change)="selectSingle(row)"
19064
- (click)="$event.stopPropagation()"
19065
- />
19066
- } @else {
19067
- <!-- click fires (and bubbles) before the input's change,
19068
- so the modifier is recorded by the time toggleRow runs. -->
19069
- <strct-checkbox
19070
- [ariaLabel]="selectRowLabel(row)"
19071
- [attr.aria-description]="lockedReason(row) || null"
19072
- [checked]="isSelected(row)"
19073
- [disabled]="lockedReason(row) !== null"
19074
- [tabIndex]="ctlTabindex()"
19075
- (click)="noteRangeIntent($event); $event.stopPropagation()"
19076
- (checkedChange)="toggleRow(row)"
19077
- />
19078
- }
19079
- </td>
19080
- }
19081
- @for (col of visibleColumns(); track col.key; let colIdx = $index) {
19082
- <td
19083
- [style.text-align]="col.align ?? (col.numeric ? 'end' : 'start')"
19084
- [class.strct-dg__cell--mono]="col.mono"
19085
- [class.strct-dg__cell--muted]="col.muted"
19086
- [class.strct-dg__cell--numeric]="col.numeric"
19087
- [class.strct-dg__cell--sticky]="isSticky(col)"
19088
- [class.strct-dg__cell--sticky-last]="col.key === lastStickyKey()"
19089
- [class.strct-dg__cell--editable]="col.editable"
19090
- [style.insetInlineStart.px]="stickyLeft(col.key)"
19091
- [attr.data-edit]="col.editable ? '' : null"
19092
- [attr.tabindex]="col.editable ? editCellTabindex(row, col) : null"
19093
- [attr.aria-describedby]="col.editable ? editHintId : null"
19094
- (dblclick)="col.editable && startEdit(row, col)"
19095
- (focus)="col.editable && onEditCellFocus(row, col)"
19096
- (keydown)="col.editable && onEditCellKeydown(row, col, $event)"
19097
- >
19098
- @if (childrenKey() && colIdx === 0) {
19099
- <span
19100
- class="strct-dg__treepad"
19101
- [style.width.px]="treeDepth(row) * 18"
19102
- aria-hidden="true"
19103
- ></span>
19104
- @if (treeHasChildren(row)) {
19105
- <button
19106
- type="button"
19107
- class="strct-dg__treebtn"
19108
- [class.strct-dg__treebtn--open]="treeExpanded(row)"
19109
- [attr.aria-expanded]="treeExpanded(row)"
19110
- [attr.aria-label]="L().toggleChildren"
19111
- (click)="toggleTreeRow(row)"
19112
- >
19113
- <strct-icon name="chevronRight" [size]="12" [strokeWidth]="1.7" />
19114
- </button>
19115
- } @else {
19116
- <span
19117
- class="strct-dg__treebtn strct-dg__treebtn--leaf"
19118
- aria-hidden="true"
19119
- ></span>
19120
- }
19121
- }
19122
- @if (isEditingCell(row, col)) {
19123
- @switch (col.editor ?? 'text') {
19124
- @case ('select') {
19125
- <!-- Choosing is the commit: there is nothing to
19126
- confirm with Enter once an option is picked. -->
19127
- <strct-select
19128
- class="strct-dg__editselect"
19129
- [options]="editorOptionsFor(row, col)"
19130
- [listLabel]="L().editCell + ': ' + col.label"
19131
- [ngModel]="row[col.key]"
19132
- (ngModelChange)="commitValue(row, col, $event)"
19133
- (keydown.escape)="cancelEdit($event)"
19134
- (click)="$event.stopPropagation()"
19135
- />
19136
- }
19137
- @case ('number') {
19138
- <strct-number
19139
- class="strct-dg__editnumber"
19140
- [ariaLabel]="L().editCell + ': ' + col.label"
19141
- [min]="col.editorMin ?? null"
19142
- [max]="col.editorMax ?? null"
19143
- [step]="col.editorStep ?? 1"
19144
- [ngModel]="row[col.key]"
19145
- (ngModelChange)="editDraft.set($event)"
19146
- (keydown.enter)="commitDraft(row, col, $event)"
19147
- (keydown.escape)="cancelEdit($event)"
19148
- (focusout)="commitOnLeave(row, col, $event)"
19149
- (click)="$event.stopPropagation()"
19150
- />
19151
- }
19152
- @default {
19153
- <input
19154
- class="strct-dg__editinput"
19155
- type="text"
19156
- [value]="row[col.key] ?? ''"
19157
- [attr.aria-label]="L().editCell + ': ' + col.label"
19158
- (keydown.enter)="commitEdit(row, col, $event)"
19159
- (keydown.escape)="cancelEdit($event)"
19160
- (blur)="commitEdit(row, col, $event)"
19161
- (click)="$event.stopPropagation()"
19162
- />
19163
- }
19164
- }
19165
- } @else if (cellTemplate(col.key); as tpl) {
19166
- <ng-container
19167
- [ngTemplateOutlet]="tpl"
19168
- [ngTemplateOutletContext]="{
19169
- $implicit: row,
19170
- row,
19171
- value: row[col.key],
19172
- column: col,
19173
- }"
19174
- />
19175
- } @else if (isBlank(row, col)) {
19176
- <span
19177
- class="strct-dg__empty"
19178
- [attr.aria-label]="col.emptyLabel || null"
19179
- >{{ col.emptyText }}</span
19180
- >
19181
- } @else {
19182
- {{ displayValue(row, col) }}
19183
- @if (col.descriptionKey && row[col.descriptionKey]) {
19184
- <span class="strct-dg__celldesc">{{ row[col.descriptionKey] }}</span>
19185
- }
19186
- }
19187
- <!-- The affordance a mouse never needed: a cell that
19188
- can be edited says so on hover and on focus. -->
19189
- @if (col.editable && editHint() && !isEditingCell(row, col)) {
19190
- <strct-icon
19191
- class="strct-dg__editpencil"
19192
- name="pencil"
19193
- [size]="12"
19194
- [strokeWidth]="1.6"
19195
- aria-hidden="true"
19196
- />
19197
- }
19198
- </td>
19199
- }
19200
- @if (canActions()) {
19201
- <td class="strct-dg__actioncell">
19202
- <button
19203
- type="button"
19204
- [attr.tabindex]="ctlTabindex()"
19205
- class="strct-dg__kebab"
19206
- [attr.aria-label]="L().rowActions"
19207
- (click)="openRowMenu(row, $event)"
19208
- >
19209
- <strct-icon name="dots" [size]="16" />
19210
- </button>
19211
- </td>
19212
- }
19213
- </tr>
19214
- @if (canExpand() && isExpanded(row)) {
19215
- <tr class="strct-dg__detailrow">
19216
- <td [attr.colspan]="colspan()">
19217
- <div class="strct-dg__detail">
19218
- <ng-container
19219
- [ngTemplateOutlet]="detailDef()!.template"
19220
- [ngTemplateOutletContext]="{ $implicit: row, row }"
19221
- />
19222
- </div>
19223
- </td>
19224
- </tr>
19225
- }
19226
- }
19227
- } @empty {
19228
- <!-- "Nothing here" and "nothing matches what you typed" are
19229
- different states: the second one can be undone, and
19230
- saying so is the whole point. -->
19231
- <tr>
19232
- <td class="strct-dg__emptyrow" [attr.colspan]="colspan()">
19233
- @if (filteredAway()) {
19234
- <strct-empty-state
19235
- size="sm"
19236
- [titleLevel]="null"
19237
- [title]="L().noMatches"
19238
- [description]="noMatchesDescription()"
19239
- >
19240
- <button strct-button variant="flat" size="sm" (click)="clearAllFilters()">
19241
- {{ L().clearFilters }}
19242
- </button>
19243
- </strct-empty-state>
19244
- } @else {
19245
- <!-- Not a heading: a grid is a region of a page, and an
19246
- empty one used to put an <h3> in its outline. -->
19247
- <strct-empty-state size="sm" [titleLevel]="null" [title]="emptyText()" />
19248
- }
19249
- </td>
19250
- </tr>
19251
- }
19252
- @if (virtual() && bottomPad() > 0) {
19253
- <tr class="strct-dg__vspacer" aria-hidden="true">
19254
- <td [attr.colspan]="colspan()" [style.height.px]="bottomPad()"></td>
19255
- </tr>
19256
- }
19257
- }
19258
- </tbody>
19259
- </table>
19260
- </div>
19261
-
19262
- @if (paneOpen()) {
19263
- <aside class="strct-dg__pane">
19264
- <div class="strct-dg__pane-head">
19265
- @if (narrowPane()) {
19266
- <!-- The pane has taken the list's place, so there is a way back. -->
19267
- <button
19268
- type="button"
19269
- class="strct-dg__pane-back"
19270
- [attr.aria-label]="L().backToList"
19271
- (click)="closePane()"
19272
- >
19273
- <strct-icon name="chevronLeft" [size]="13" />
19274
- </button>
19275
- }
19276
- <span class="strct-dg__pane-title">
19277
- <ng-content select="[strctDetailPaneTitle]" />
19278
- @if (!paneTitleDef()) {
19279
- {{ activeRow()![columns()[0].key] }}
19280
- }
19281
- </span>
19282
- <span class="strct-dg__pane-meta">
19283
- <ng-content select="[strctDetailPaneMeta]" />
19284
- </span>
19285
- <span class="strct-dg__pane-actions">
19286
- <ng-content select="[strctDetailPaneActions]" />
19287
- </span>
19288
- <button
19289
- type="button"
19290
- class="strct-dg__pane-close"
19291
- [attr.aria-label]="L().closeDetail"
19292
- (click)="closePane()"
19293
- >
19294
- <strct-icon name="close" [size]="13" />
19295
- </button>
19296
- </div>
19297
- <div class="strct-dg__pane-body">
19298
- <ng-container
19299
- [ngTemplateOutlet]="detailDef()!.template"
19300
- [ngTemplateOutletContext]="{ $implicit: activeRow(), row: activeRow() }"
19301
- />
19302
- </div>
19303
- </aside>
19304
- }
19305
- </div>
19306
-
19307
- @if (showFooter()) {
19308
- <div class="strct-dg__foot">
19309
- <div class="strct-dg__foot-left">
19310
- @if (columnChooser() || sync()) {
19311
- <div class="strct-dg__actions">
19312
- <strct-button-group>
19313
- @if (columnChooser()) {
19314
- <button
19315
- strct-button
19316
- size="sm"
19317
- [class.is-open]="chooserOpen()"
19318
- [disabled]="footerActionsDisabled()"
19319
- [attr.aria-label]="L().chooseColumns"
19320
- (click)="toggleChooser($event)"
19321
- >
19322
- <strct-icon name="settings" [size]="16" />
19323
- </button>
19324
- }
19325
- @if (sync()) {
19326
- <button
19327
- strct-button
19328
- size="sm"
19329
- [disabled]="footerActionsDisabled()"
19330
- [attr.aria-label]="L().refresh"
19331
- (click)="syncChange.emit()"
19332
- >
19333
- <strct-icon name="refresh" [size]="16" />
19334
- </button>
19335
- }
19336
- </strct-button-group>
19337
- @if (columnChooser() && chooserOpen()) {
19338
- <div class="strct-dg__chooser-menu">
19339
- @for (col of columns(); track col.key) {
19340
- <!-- The whole row toggles; the checkbox's own click must not
19341
- reach the row or the column would flip twice. -->
19342
- <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->
19343
- <div
19344
- class="strct-dg__chooser-item"
19345
- (click)="toggleColumn(col.key, hiddenColumns().has(col.key))"
19346
- >
19347
- <strct-checkbox
19348
- [checked]="!hiddenColumns().has(col.key)"
19349
- (checkedChange)="toggleColumn(col.key, $event)"
19350
- (click)="$event.stopPropagation()"
19351
- />
19352
- <span>{{ col.label }}</span>
19353
- </div>
19354
- }
19355
- </div>
19356
- }
19357
- </div>
19358
- }
19359
- <span class="strct-dg__count">
19360
- @if (paging() === 'more') {
19361
- {{ L().showing(rows().length, moreTotal() ?? undefined) }}
19362
- } @else {
19363
- {{ totalCount() }} {{ totalCount() === 1 ? L().row : L().rows }}
19364
- }
19365
- @if (selectedCount() && mode() !== 'single') {
19366
- <span class="strct-dg__count-sep">|</span>
19367
- <span class="strct-dg__count-sel">{{ selectedCount() }} {{ L().selected }}</span>
19368
- }
19369
- </span>
19370
- </div>
19371
- <div class="strct-dg__foot-right">
19372
- <!-- A feed that pages by cursor loads more at the end: page numbers
19373
- are something a cursor API cannot answer. It takes the pager's
19374
- place — the column chooser, the sync button and the count are
19375
- the footer's, not the pager's. -->
19376
- @if (paging() === 'more') {
19377
- @if (hasMore()) {
19378
- <button
19379
- strct-button
19380
- size="sm"
19381
- class="strct-dg__more"
19382
- [disabled]="loadingMore()"
19383
- (click)="loadMore.emit()"
19384
- >
19385
- @if (loadingMore()) {
19386
- <strct-spinner size="sm" />
19387
- }
19388
- {{ L().loadMore }}
19389
- </button>
19390
- }
19391
- } @else if (pageSize() > 0 && !groupBy()) {
19392
- <strct-pagination
19393
- [total]="totalCount()"
19394
- [pageSize]="pageSize()"
19395
- [page]="page()"
19396
- (pageChange)="goToPage($event)"
19397
- />
19398
- }
19399
- </div>
19400
- </div>
19401
- }
19402
- `, host: {
17839
+ ], host: {
19403
17840
  class: 'strct-dg-host',
19404
17841
  // The skeleton rows say "updating" to the eye; this says it to everyone else.
19405
17842
  '[attr.aria-busy]': 'loading() || loadingMore() ? "true" : null',
@@ -19409,7 +17846,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
19409
17846
  '[class.strct-dg-host--bounded]': '!virtual() && maxHeight() !== null',
19410
17847
  '[class.strct-dg-host--sticky]': 'stickyActive()',
19411
17848
  '[class.strct-dg-host--flush]': 'flush()',
19412
- }, 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"] }]
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"] }]
19413
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: [{
19414
17851
  type: HostListener,
19415
17852
  args: ['document:click', ['$event']]
@@ -32185,5 +30622,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
32185
30622
  * Generated bundle index. Do not edit.
32186
30623
  */
32187
30624
 
32188
- 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 };
32189
30626
  //# sourceMappingURL=akcelik-strct.mjs.map