@rozie-ui/data-table-lit 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/DataTable.ts CHANGED
@@ -52,13 +52,13 @@ interface RozieSelectAllSlotCtx {
52
52
  toggle: any;
53
53
  }
54
54
 
55
- interface RozieColHeaderSlotCtx {
55
+ interface RozieDynamicColHeaderSlotCtx {
56
56
  columnId: any;
57
57
  column: any;
58
58
  label: any;
59
59
  }
60
60
 
61
- interface RozieFilterSlotCtx {
61
+ interface RozieDynamicFilterSlotCtx {
62
62
  columnId: any;
63
63
  value: any;
64
64
  uniqueValues: any;
@@ -72,14 +72,14 @@ interface RozieSelectCellSlotCtx {
72
72
  toggle: any;
73
73
  }
74
74
 
75
- interface RozieCellSlotCtx {
75
+ interface RozieDynamicCellSlotCtx {
76
76
  columnId: any;
77
77
  column: any;
78
78
  row: any;
79
79
  value: any;
80
80
  }
81
81
 
82
- interface RozieEditorSlotCtx {
82
+ interface RozieDynamicEditorSlotCtx {
83
83
  columnId: any;
84
84
  column: any;
85
85
  row: any;
@@ -93,6 +93,37 @@ interface RozieDetailSlotCtx {
93
93
  row: any;
94
94
  }
95
95
 
96
+ interface RozieColHeaderSlotCtx {
97
+ columnId: any;
98
+ column: any;
99
+ label: any;
100
+ }
101
+
102
+ interface RozieFilterSlotCtx {
103
+ columnId: any;
104
+ value: any;
105
+ uniqueValues: any;
106
+ minMax: any;
107
+ setFilter: any;
108
+ }
109
+
110
+ interface RozieCellSlotCtx {
111
+ columnId: any;
112
+ column: any;
113
+ row: any;
114
+ value: any;
115
+ }
116
+
117
+ interface RozieEditorSlotCtx {
118
+ columnId: any;
119
+ column: any;
120
+ row: any;
121
+ value: any;
122
+ commit: any;
123
+ cancel: any;
124
+ autofocus: any;
125
+ }
126
+
96
127
  @customElement('rozie-data-table')
97
128
  export default class DataTable extends SignalWatcher(LitElement) {
98
129
  static shadowRootOptions: ShadowRootInit = { ...LitElement.shadowRootOptions, slotAssignment: 'manual' };
@@ -658,24 +689,32 @@ private __rozieCtxProvider_data_table_columns = new ContextProvider(this, { cont
658
689
  @state() private _hasSlotSelectAll = false;
659
690
  @queryAssignedElements({ slot: 'selectAll', flatten: true }) private _slotSelectAllElements!: Element[];
660
691
  @property({ attribute: false }) selectAll?: (scope: { checked: any; indeterminate: any; toggle: any }) => unknown;
692
+ @state() private _hasSlotDynamicColHeader = false;
693
+ @queryAssignedElements({ flatten: true }) private _slotDynamicColHeaderElements!: Element[];
694
+ @state() private _hasSlotDynamicFilter = false;
695
+ @queryAssignedElements({ flatten: true }) private _slotDynamicFilterElements!: Element[];
696
+ @state() private _hasSlotSelectCell = false;
697
+ @queryAssignedElements({ slot: 'selectCell', flatten: true }) private _slotSelectCellElements!: Element[];
698
+ @property({ attribute: false }) selectCell?: (scope: { row: any; checked: any; toggle: any }) => unknown;
699
+ @state() private _hasSlotDynamicCell = false;
700
+ @queryAssignedElements({ flatten: true }) private _slotDynamicCellElements!: Element[];
701
+ @state() private _hasSlotDynamicEditor = false;
702
+ @queryAssignedElements({ flatten: true }) private _slotDynamicEditorElements!: Element[];
703
+ @state() private _hasSlotDetail = false;
704
+ @queryAssignedElements({ slot: 'detail', flatten: true }) private _slotDetailElements!: Element[];
705
+ @property({ attribute: false }) detail?: (scope: { row: any }) => unknown;
661
706
  @state() private _hasSlotColHeader = false;
662
707
  @queryAssignedElements({ slot: 'colHeader', flatten: true }) private _slotColHeaderElements!: Element[];
663
708
  @property({ attribute: false }) colHeader?: (scope: { columnId: any; column: any; label: any }) => unknown;
664
709
  @state() private _hasSlotFilter = false;
665
710
  @queryAssignedElements({ slot: 'filter', flatten: true }) private _slotFilterElements!: Element[];
666
711
  @property({ attribute: false }) filter?: (scope: { columnId: any; value: any; uniqueValues: any; minMax: any; setFilter: any }) => unknown;
667
- @state() private _hasSlotSelectCell = false;
668
- @queryAssignedElements({ slot: 'selectCell', flatten: true }) private _slotSelectCellElements!: Element[];
669
- @property({ attribute: false }) selectCell?: (scope: { row: any; checked: any; toggle: any }) => unknown;
670
712
  @state() private _hasSlotCell = false;
671
713
  @queryAssignedElements({ slot: 'cell', flatten: true }) private _slotCellElements!: Element[];
672
714
  @property({ attribute: false }) cell?: (scope: { columnId: any; column: any; row: any; value: any }) => unknown;
673
715
  @state() private _hasSlotEditor = false;
674
716
  @queryAssignedElements({ slot: 'editor', flatten: true }) private _slotEditorElements!: Element[];
675
717
  @property({ attribute: false }) editor?: (scope: { columnId: any; column: any; row: any; value: any; commit: any; cancel: any; autofocus: any }) => unknown;
676
- @state() private _hasSlotDetail = false;
677
- @queryAssignedElements({ slot: 'detail', flatten: true }) private _slotDetailElements!: Element[];
678
- @property({ attribute: false }) detail?: (scope: { row: any }) => unknown;
679
718
  // Phase 79 Plan 08 (R4) contract for 79-09: the record intake for
680
719
  // record-routed slot fills. 79-09's consumer-side emitSlotFiller
681
720
  // accumulates an object literal onto the SAME `.rozieSlots=${{ ... }}`
@@ -685,7 +724,7 @@ private __rozieCtxProvider_data_table_columns = new ContextProvider(this, { cont
685
724
  // named function-prop / <slot> fallback (AC-9). Attribute
686
725
  // deserialization is disabled — this is a function-valued record,
687
726
  // never reflected to/from an HTML attribute.
688
- @property({ attribute: false }) rozieSlots?: Record<string, (scope: any) => unknown>;
727
+ @property({ attribute: false }) rozieSlots?: { [key: `colHeader-${string}`]: (scope: { columnId: any; column: any; label: any }) => unknown; [key: `filter-${string}`]: (scope: { columnId: any; value: any; uniqueValues: any; minMax: any; setFilter: any }) => unknown; [key: `cell-${string}`]: (scope: { columnId: any; column: any; row: any; value: any }) => unknown; [key: `editor-${string}`]: (scope: { columnId: any; column: any; row: any; value: any; commit: any; cancel: any; autofocus: any }) => unknown; } & Record<string, (scope: any) => unknown>;
689
728
 
690
729
  private _disconnectCleanups: Array<() => void> = [];
691
730
  // Re-parenting guard: set true once the deferred teardown has actually
@@ -727,9 +766,9 @@ private __rozieCtxProvider_data_table_columns = new ContextProvider(this, { cont
727
766
  }
728
767
 
729
768
  {
730
- const slotEl = this.shadowRoot?.querySelector('slot[name="colHeader"]');
769
+ const slotEl = this.shadowRoot?.querySelector('slot:not([name])');
731
770
  if (slotEl !== null && slotEl !== undefined) {
732
- const update = () => { this._hasSlotColHeader = this._slotColHeaderElements.length > 0; };
771
+ const update = () => { this._hasSlotDynamicColHeader = this._slotDynamicColHeaderElements.length > 0; };
733
772
  slotEl.addEventListener('slotchange', update);
734
773
  // CR-05 fix: push cleanup so the listener is removed on disconnectedCallback.
735
774
  this._disconnectCleanups.push(() => slotEl.removeEventListener('slotchange', update));
@@ -738,9 +777,9 @@ private __rozieCtxProvider_data_table_columns = new ContextProvider(this, { cont
738
777
  }
739
778
 
740
779
  {
741
- const slotEl = this.shadowRoot?.querySelector('slot[name="filter"]');
780
+ const slotEl = this.shadowRoot?.querySelector('slot:not([name])');
742
781
  if (slotEl !== null && slotEl !== undefined) {
743
- const update = () => { this._hasSlotFilter = this._slotFilterElements.length > 0; };
782
+ const update = () => { this._hasSlotDynamicFilter = this._slotDynamicFilterElements.length > 0; };
744
783
  slotEl.addEventListener('slotchange', update);
745
784
  // CR-05 fix: push cleanup so the listener is removed on disconnectedCallback.
746
785
  this._disconnectCleanups.push(() => slotEl.removeEventListener('slotchange', update));
@@ -760,9 +799,9 @@ private __rozieCtxProvider_data_table_columns = new ContextProvider(this, { cont
760
799
  }
761
800
 
762
801
  {
763
- const slotEl = this.shadowRoot?.querySelector('slot[name="cell"]');
802
+ const slotEl = this.shadowRoot?.querySelector('slot:not([name])');
764
803
  if (slotEl !== null && slotEl !== undefined) {
765
- const update = () => { this._hasSlotCell = this._slotCellElements.length > 0; };
804
+ const update = () => { this._hasSlotDynamicCell = this._slotDynamicCellElements.length > 0; };
766
805
  slotEl.addEventListener('slotchange', update);
767
806
  // CR-05 fix: push cleanup so the listener is removed on disconnectedCallback.
768
807
  this._disconnectCleanups.push(() => slotEl.removeEventListener('slotchange', update));
@@ -771,9 +810,9 @@ private __rozieCtxProvider_data_table_columns = new ContextProvider(this, { cont
771
810
  }
772
811
 
773
812
  {
774
- const slotEl = this.shadowRoot?.querySelector('slot[name="editor"]');
813
+ const slotEl = this.shadowRoot?.querySelector('slot:not([name])');
775
814
  if (slotEl !== null && slotEl !== undefined) {
776
- const update = () => { this._hasSlotEditor = this._slotEditorElements.length > 0; };
815
+ const update = () => { this._hasSlotDynamicEditor = this._slotDynamicEditorElements.length > 0; };
777
816
  slotEl.addEventListener('slotchange', update);
778
817
  // CR-05 fix: push cleanup so the listener is removed on disconnectedCallback.
779
818
  this._disconnectCleanups.push(() => slotEl.removeEventListener('slotchange', update));
@@ -791,6 +830,50 @@ private __rozieCtxProvider_data_table_columns = new ContextProvider(this, { cont
791
830
  update();
792
831
  }
793
832
  }
833
+
834
+ {
835
+ const slotEl = this.shadowRoot?.querySelector('slot[name="colHeader"]');
836
+ if (slotEl !== null && slotEl !== undefined) {
837
+ const update = () => { this._hasSlotColHeader = this._slotColHeaderElements.length > 0; };
838
+ slotEl.addEventListener('slotchange', update);
839
+ // CR-05 fix: push cleanup so the listener is removed on disconnectedCallback.
840
+ this._disconnectCleanups.push(() => slotEl.removeEventListener('slotchange', update));
841
+ update();
842
+ }
843
+ }
844
+
845
+ {
846
+ const slotEl = this.shadowRoot?.querySelector('slot[name="filter"]');
847
+ if (slotEl !== null && slotEl !== undefined) {
848
+ const update = () => { this._hasSlotFilter = this._slotFilterElements.length > 0; };
849
+ slotEl.addEventListener('slotchange', update);
850
+ // CR-05 fix: push cleanup so the listener is removed on disconnectedCallback.
851
+ this._disconnectCleanups.push(() => slotEl.removeEventListener('slotchange', update));
852
+ update();
853
+ }
854
+ }
855
+
856
+ {
857
+ const slotEl = this.shadowRoot?.querySelector('slot[name="cell"]');
858
+ if (slotEl !== null && slotEl !== undefined) {
859
+ const update = () => { this._hasSlotCell = this._slotCellElements.length > 0; };
860
+ slotEl.addEventListener('slotchange', update);
861
+ // CR-05 fix: push cleanup so the listener is removed on disconnectedCallback.
862
+ this._disconnectCleanups.push(() => slotEl.removeEventListener('slotchange', update));
863
+ update();
864
+ }
865
+ }
866
+
867
+ {
868
+ const slotEl = this.shadowRoot?.querySelector('slot[name="editor"]');
869
+ if (slotEl !== null && slotEl !== undefined) {
870
+ const update = () => { this._hasSlotEditor = this._slotEditorElements.length > 0; };
871
+ slotEl.addEventListener('slotchange', update);
872
+ // CR-05 fix: push cleanup so the listener is removed on disconnectedCallback.
873
+ this._disconnectCleanups.push(() => slotEl.removeEventListener('slotchange', update));
874
+ update();
875
+ }
876
+ }
794
877
  }
795
878
 
796
879
  connectedCallback(): void {
@@ -798,12 +881,16 @@ private __rozieCtxProvider_data_table_columns = new ContextProvider(this, { cont
798
881
  this._hasSlotDefault = Array.from(this.children).some((el) => !el.hasAttribute('slot') && (el.nodeType !== 3 || (el.textContent?.trim().length ?? 0) > 0));
799
882
  this._hasSlotGroupBar = Array.from(this.children).some((el) => el.getAttribute('slot') === 'groupBar');
800
883
  this._hasSlotSelectAll = Array.from(this.children).some((el) => el.getAttribute('slot') === 'selectAll');
884
+ this._hasSlotDynamicColHeader = Array.from(this.children).some((el) => !el.hasAttribute('slot') && (el.nodeType !== 3 || (el.textContent?.trim().length ?? 0) > 0));
885
+ this._hasSlotDynamicFilter = Array.from(this.children).some((el) => !el.hasAttribute('slot') && (el.nodeType !== 3 || (el.textContent?.trim().length ?? 0) > 0));
886
+ this._hasSlotSelectCell = Array.from(this.children).some((el) => el.getAttribute('slot') === 'selectCell');
887
+ this._hasSlotDynamicCell = Array.from(this.children).some((el) => !el.hasAttribute('slot') && (el.nodeType !== 3 || (el.textContent?.trim().length ?? 0) > 0));
888
+ this._hasSlotDynamicEditor = Array.from(this.children).some((el) => !el.hasAttribute('slot') && (el.nodeType !== 3 || (el.textContent?.trim().length ?? 0) > 0));
889
+ this._hasSlotDetail = Array.from(this.children).some((el) => el.getAttribute('slot') === 'detail');
801
890
  this._hasSlotColHeader = Array.from(this.children).some((el) => el.getAttribute('slot') === 'colHeader');
802
891
  this._hasSlotFilter = Array.from(this.children).some((el) => el.getAttribute('slot') === 'filter');
803
- this._hasSlotSelectCell = Array.from(this.children).some((el) => el.getAttribute('slot') === 'selectCell');
804
892
  this._hasSlotCell = Array.from(this.children).some((el) => el.getAttribute('slot') === 'cell');
805
893
  this._hasSlotEditor = Array.from(this.children).some((el) => el.getAttribute('slot') === 'editor');
806
- this._hasSlotDetail = Array.from(this.children).some((el) => el.getAttribute('slot') === 'detail');
807
894
  super.connectedCallback();
808
895
  if (this.hasUpdated && this._rozieTornDown) { this._rozieTornDown = false; this._armListeners(); }
809
896
  }
@@ -1288,19 +1375,23 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
1288
1375
  <thead class="rdt-thead" role="rowgroup" data-rozie-s-d5dcab4c>
1289
1376
  ${repeat<any>(this._headerGroups.value, (hg, hgLevel) => hg.id, (hg, hgLevel) => html`<tr class="rdt-tr" role="row" aria-rowindex=${rozieAttr(hgLevel + 1)} data-rozie-s-d5dcab4c>
1290
1377
 
1291
- ${this.colsWindowed() ? html`<th class="rdt-col-spacer" aria-hidden="true" style=${rozieStyle('width:' + this.colPadLeft() + 'px;padding:0;border:0')} data-rozie-s-d5dcab4c></th>` : nothing}${repeat<any>(this.windowedHeadersFor(hg, hgLevel), (wh, _idx) => wh.header.id, (wh, _idx) => html`<th class="${Object.entries({ "rdt-th": true, 'rdt-select-th': this.isSelectColumn(wh.header.column.id), 'rdt-expander-th': this.isExpanderColumn(wh.header.column.id), 'rdt-th-resizing': this.columnIsResizing(wh.header.column.id), 'rdt-cell-active': this.isActiveCell('__header', this.headerColIndexOf(hg, wh.header), hgLevel) }).filter(([, v]) => v).map(([k]) => k).join(' ')}" role="columnheader" data-col=${rozieAttr(wh.header.column.id)} data-grid-cell="" data-row="__header" data-header-level=${rozieAttr(hgLevel)} colspan=${rozieAttr(wh.span > 1 ? wh.span : null)} data-col-index=${rozieAttr(this.headerColIndexOf(hg, wh.header))} tabindex=${rozieAttr(this.cellTabindex('__header', this.headerColIndexOf(hg, wh.header), hgLevel))} aria-sort=${rozieAttr(this.ariaSortFor(wh.header.column.id))} style=${rozieStyle(this.thStyle(wh.header.column.id))} data-rozie-s-d5dcab4c>
1378
+ ${this.colsWindowed() ? html`<th class="rdt-col-spacer" aria-hidden="true" style=${rozieStyle('width:' + this.colPadLeft() + 'px;padding:0;border:0')} data-rozie-s-d5dcab4c></th>` : nothing}${repeat<any>(this.windowedHeadersFor(hg, hgLevel), (wh, _idx) => wh.header.id, (wh, _idx) => html`<th class="${Object.entries({ "rdt-th": true, 'rdt-select-th': this.isSelectColumn(wh.header.column.id), 'rdt-expander-th': this.isExpanderColumn(wh.header.column.id), 'rdt-th-resizing': this.columnIsResizing(wh.header.column.id), 'rdt-cell-active': this.isActiveCell('__header', this.headerColIndexOf(hg, wh.header), hgLevel) }).filter(([, v]) => v).map(([k]) => k).join(' ')}" role="columnheader" data-col=${rozieAttr(wh.header.column.id)} data-grid-cell="" data-row="__header" data-header-level=${rozieAttr(hgLevel)} colspan=${rozieAttr(wh.span > 1 ? wh.span : null)} data-col-index=${rozieAttr(this.headerColIndexOf(hg, wh.header))} tabindex=${rozieAttr(this.cellTabindex('__header', this.headerColIndexOf(hg, wh.header), hgLevel))} aria-sort=${rozieAttr(this.ariaSortFor(wh.header.column.id))} style=${rozieStyle(this.thStyle(wh.header))} data-rozie-s-d5dcab4c>
1292
1379
  ${this.isSelectColumn(wh.header.column.id) ? html`<span style="display:contents" data-rozie-s-d5dcab4c>
1293
1380
  ${this.selectAll !== undefined ? this.selectAll({checked: this.isAllRowsSelected(), indeterminate: this.isSomeRowsSelected(), toggle: this.onToggleAllRows}) : html`<slot name="selectAll" data-rozie-params=${(() => { try { return JSON.stringify({checked: this.isAllRowsSelected(), indeterminate: this.isSomeRowsSelected()}); } catch { return '{}'; } })()} @rozie-select-all-toggle=${($event: CustomEvent) => ((this.onToggleAllRows) as (...args: any[]) => any)($event.detail)}>
1294
1381
  ${this.selectionMode === 'multiple' ? html`<input class="rdt-select-all" type="checkbox" aria-label="Select all rows" ?checked=${this.isAllRowsSelected()} @change=${($event: Event & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onToggleAllRows($event); }} data-rozie-s-d5dcab4c />` : nothing}</slot>`}
1295
1382
  </span>` : this.isExpanderColumn(wh.header.column.id) ? html`<span style="display:contents" data-rozie-s-d5dcab4c></span>` : html`<span style="display:contents" data-rozie-s-d5dcab4c>
1296
1383
  ${wh.header.column.getCanSort && wh.header.column.getCanSort() ? html`<button class="rdt-sort-btn" type="button" @click=${($event: MouseEvent & { currentTarget: HTMLButtonElement; target: HTMLButtonElement }) => { this.onHeaderSort(wh.header.column.id, $event); }} data-rozie-s-d5dcab4c>
1297
1384
  <span class="rdt-header-label" data-rozie-s-d5dcab4c>
1298
- ${this.colHeader !== undefined ? this.colHeader({columnId: wh.header.column.id, column: wh.header.column, label: this.headerLabel(wh.header.column.id)}) : html`<slot name="colHeader" data-rozie-params=${(() => { try { return JSON.stringify({columnId: wh.header.column.id, column: wh.header.column, label: this.headerLabel(wh.header.column.id)}); } catch { return '{}'; } })()}>${rozieDisplay(this.headerLabel(wh.header.column.id))}</slot>`}
1385
+ ${this.rozieSlots?.[`colHeader-${wh.header.column.id}`] !== undefined ? this.rozieSlots?.[`colHeader-${wh.header.column.id}`]!({columnId: wh.header.column.id, column: wh.header.column, label: this.headerLabel(wh.header.column.id)}) : html`<slot name="${`colHeader-${wh.header.column.id}`}" data-rozie-params=${(() => { try { return JSON.stringify({columnId: wh.header.column.id, column: wh.header.column, label: this.headerLabel(wh.header.column.id)}); } catch { return '{}'; } })()}>
1386
+ ${this.colHeader !== undefined ? this.colHeader({columnId: wh.header.column.id, column: wh.header.column, label: this.headerLabel(wh.header.column.id)}) : html`<slot name="colHeader" data-rozie-params=${(() => { try { return JSON.stringify({columnId: wh.header.column.id, column: wh.header.column, label: this.headerLabel(wh.header.column.id)}); } catch { return '{}'; } })()}>${rozieDisplay(this.headerLabel(wh.header.column.id))}</slot>`}
1387
+ </slot>`}
1299
1388
  </span>
1300
1389
  <span class="rdt-sort-ind" aria-hidden="true" data-rozie-s-d5dcab4c>${rozieDisplay(this.sortIndicator(wh.header.column.id))}</span>
1301
1390
  </button>` : html`<span style="display:contents" data-rozie-s-d5dcab4c>
1302
1391
  <span class="rdt-header-label" data-rozie-s-d5dcab4c>
1303
- ${this.colHeader !== undefined ? this.colHeader({columnId: wh.header.column.id, column: wh.header.column, label: this.headerLabel(wh.header.column.id)}) : html`<slot name="colHeader" data-rozie-params=${(() => { try { return JSON.stringify({columnId: wh.header.column.id, column: wh.header.column, label: this.headerLabel(wh.header.column.id)}); } catch { return '{}'; } })()}>${rozieDisplay(this.headerLabel(wh.header.column.id))}</slot>`}
1392
+ ${this.rozieSlots?.[`colHeader-${wh.header.column.id}`] !== undefined ? this.rozieSlots?.[`colHeader-${wh.header.column.id}`]!({columnId: wh.header.column.id, column: wh.header.column, label: this.headerLabel(wh.header.column.id)}) : html`<slot name="${`colHeader-${wh.header.column.id}`}" data-rozie-params=${(() => { try { return JSON.stringify({columnId: wh.header.column.id, column: wh.header.column, label: this.headerLabel(wh.header.column.id)}); } catch { return '{}'; } })()}>
1393
+ ${this.colHeader !== undefined ? this.colHeader({columnId: wh.header.column.id, column: wh.header.column, label: this.headerLabel(wh.header.column.id)}) : html`<slot name="colHeader" data-rozie-params=${(() => { try { return JSON.stringify({columnId: wh.header.column.id, column: wh.header.column, label: this.headerLabel(wh.header.column.id)}); } catch { return '{}'; } })()}>${rozieDisplay(this.headerLabel(wh.header.column.id))}</slot>`}
1394
+ </slot>`}
1304
1395
  </span>
1305
1396
  </span>`}<rozie-popover trigger="click" placement="bottom-end" strategy="fixed" .offset=${4} data-rozie-s-d5dcab4c><button class="rdt-col-menu-trigger" type="button" aria-label=${rozieAttr('Column options for ' + this.headerLabel(wh.header.column.id))} data-rozie-s-d5dcab4c slot="anchor">⋯</button><div class="rdt-col-menu" role="menu" data-rozie-s-d5dcab4c>
1306
1397
  <button class="rdt-col-menu-item" type="button" role="menuitem" aria-pressed=${this.columnPinSide(wh.header.column.id) === 'left'} @click=${($event: MouseEvent & { currentTarget: HTMLButtonElement; target: HTMLButtonElement }) => { this.onPinColumn(wh.header.column.id, 'left', $event); }} data-rozie-s-d5dcab4c>Pin left</button>
@@ -1317,8 +1408,12 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
1317
1408
  ${this.hasAnyFilterableColumn() ? html`<tr class="rdt-filter-row" data-rozie-s-d5dcab4c>
1318
1409
  ${this.colsWindowed() ? html`<th class="rdt-col-spacer" aria-hidden="true" style=${rozieStyle('width:' + this.colPadLeft() + 'px;padding:0;border:0')} data-rozie-s-d5dcab4c></th>` : nothing}${repeat<any>(this.windowedHeadersFor(this._headerGroups.value[this._headerGroups.value.length - 1], this._headerGroups.value.length - 1), (wh, _idx) => wh.header.id, (wh, _idx) => html`<th class="rdt-filter-cell" role="presentation" data-col=${rozieAttr(wh.header.column.id)} style=${rozieStyle(this.pinStyle(wh.header.column.id))} data-rozie-s-d5dcab4c>
1319
1410
  ${this.isSelectColumn(wh.header.column.id) ? html`<span style="display:contents" data-rozie-s-d5dcab4c></span>` : this.isExpanderColumn(wh.header.column.id) ? html`<span style="display:contents" data-rozie-s-d5dcab4c></span>` : html`<span style="display:contents" data-rozie-s-d5dcab4c>
1320
- ${this.columnIsFilterable(wh.header.column.id) && !this.hasFilterSlot() ? html`<input class="rdt-col-filter" type="text" aria-label=${rozieAttr('Filter ' + this.headerLabel(wh.header.column.id))} .value=${this.columnFilterValue(wh.header.column.id)} @input=${($event: InputEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onColumnFilterInput(wh.header.column.id, $event); }} @click=${($event: MouseEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.stopEvent($event); }} data-rozie-s-d5dcab4c />` : nothing}${this.columnIsFilterable(wh.header.column.id) ? html`<span style="display:contents" data-rozie-s-d5dcab4c>
1321
- ${this.filter !== undefined ? this.filter({columnId: wh.header.column.id, value: this.columnFilterValue(wh.header.column.id), uniqueValues: this.getFacetedUniqueValues(wh.header.column.id), minMax: this.getFacetedMinMaxValues(wh.header.column.id), setFilter: this.setColumnFilter}) : html`<slot name="filter" data-rozie-params=${(() => { try { return JSON.stringify({columnId: wh.header.column.id, value: this.columnFilterValue(wh.header.column.id), uniqueValues: this.getFacetedUniqueValues(wh.header.column.id), minMax: this.getFacetedMinMaxValues(wh.header.column.id)}); } catch { return '{}'; } })()} @rozie-filter-set-filter=${($event: CustomEvent) => ((this.setColumnFilter) as (...args: any[]) => any)($event.detail)}></slot>`}
1411
+ ${this.columnIsFilterable(wh.header.column.id) ? html`<span style="display:contents" data-rozie-s-d5dcab4c>
1412
+ ${this.rozieSlots?.[`filter-${wh.header.column.id}`] !== undefined ? this.rozieSlots?.[`filter-${wh.header.column.id}`]!({columnId: wh.header.column.id, value: this.columnFilterValue(wh.header.column.id), uniqueValues: this.getFacetedUniqueValues(wh.header.column.id), minMax: this.getFacetedMinMaxValues(wh.header.column.id), setFilter: this.setColumnFilter}) : html`<slot name="${`filter-${wh.header.column.id}`}" data-rozie-params=${(() => { try { return JSON.stringify({columnId: wh.header.column.id, value: this.columnFilterValue(wh.header.column.id), uniqueValues: this.getFacetedUniqueValues(wh.header.column.id), minMax: this.getFacetedMinMaxValues(wh.header.column.id)}); } catch { return '{}'; } })()} @rozie-default-set-filter=${($event: CustomEvent) => ((this.setColumnFilter) as (...args: any[]) => any)($event.detail)}>
1413
+ ${this.filter !== undefined ? this.filter({columnId: wh.header.column.id, value: this.columnFilterValue(wh.header.column.id), uniqueValues: this.getFacetedUniqueValues(wh.header.column.id), minMax: this.getFacetedMinMaxValues(wh.header.column.id), setFilter: this.setColumnFilter}) : html`<slot name="filter" data-rozie-params=${(() => { try { return JSON.stringify({columnId: wh.header.column.id, value: this.columnFilterValue(wh.header.column.id), uniqueValues: this.getFacetedUniqueValues(wh.header.column.id), minMax: this.getFacetedMinMaxValues(wh.header.column.id)}); } catch { return '{}'; } })()} @rozie-filter-set-filter=${($event: CustomEvent) => ((this.setColumnFilter) as (...args: any[]) => any)($event.detail)}>
1414
+ <input class="rdt-col-filter" type="text" aria-label=${rozieAttr('Filter ' + this.headerLabel(wh.header.column.id))} .value=${this.columnFilterValue(wh.header.column.id)} @input=${($event: InputEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onColumnFilterInput(wh.header.column.id, $event); }} @click=${($event: MouseEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.stopEvent($event); }} data-rozie-s-d5dcab4c />
1415
+ </slot>`}
1416
+ </slot>`}
1322
1417
  </span>` : nothing}</span>`}</th>`)}
1323
1418
  ${this.colsWindowed() ? html`<th class="rdt-col-spacer" aria-hidden="true" style=${rozieStyle('width:' + this.colPadRight() + 'px;padding:0;border:0')} data-rozie-s-d5dcab4c></th>` : nothing}</tr>` : nothing}</thead>
1324
1419
 
@@ -1341,16 +1436,24 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
1341
1436
  </span>` : this.cellIsGrouped(cell) ? html`<span style="display:contents" data-rozie-s-d5dcab4c>
1342
1437
  <button class="rdt-expander rdt-group-toggle" type="button" data-expander="" aria-expanded=${!!this.rowIsExpanded(wr.row)} aria-label=${rozieAttr(this.rowIsExpanded(wr.row) ? 'Collapse group' : 'Expand group')} @click=${($event: MouseEvent & { currentTarget: HTMLButtonElement; target: HTMLButtonElement }) => { this.onToggleExpand(wr.row, $event); }} data-rozie-s-d5dcab4c>${rozieDisplay(this.rowIsExpanded(wr.row) ? '▾' : '▸')}</button>
1343
1438
  <span class="rdt-group-value" data-rozie-s-d5dcab4c>
1344
- ${this.cell !== undefined ? this.cell({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(wr.row), value: cell.getValue()}) : html`<slot name="cell" data-rozie-params=${(() => { try { return JSON.stringify({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(wr.row), value: cell.getValue()}); } catch { return '{}'; } })()}>${rozieDisplay(cell.getValue())}</slot>`}
1439
+ ${this.rozieSlots?.[`cell-${cell.column.id}`] !== undefined ? this.rozieSlots?.[`cell-${cell.column.id}`]!({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(wr.row), value: cell.getValue()}) : html`<slot name="${`cell-${cell.column.id}`}" data-rozie-params=${(() => { try { return JSON.stringify({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(wr.row), value: cell.getValue()}); } catch { return '{}'; } })()}>
1440
+ ${this.cell !== undefined ? this.cell({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(wr.row), value: cell.getValue()}) : html`<slot name="cell" data-rozie-params=${(() => { try { return JSON.stringify({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(wr.row), value: cell.getValue()}); } catch { return '{}'; } })()}>${rozieDisplay(cell.getValue())}</slot>`}
1441
+ </slot>`}
1345
1442
  </span>
1346
1443
  <span class="rdt-group-count" data-rozie-s-d5dcab4c>${rozieDisplay('(' + this.groupSubRowCount(wr.row) + ')')}</span>
1347
1444
  </span>` : this.isEditing(wr.vi.index, this.colIndexOf(wr.row, cell)) ? html`<span style="display:contents" data-rozie-s-d5dcab4c>
1348
- ${this.hasEditorSlot(cell.column.id) ? html`<span style="display:contents" data-rozie-s-d5dcab4c>
1349
- ${this.editor !== undefined ? this.editor({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(wr.row), value: this.editorValueFor(cell.column.id), commit: this.editorCommitFor(cell.column.id), cancel: this.editorCancelFor(), autofocus: this.editorAutofocusFor(cell.column.id, wr.vi.index)}) : html`<slot name="editor" data-rozie-params=${(() => { try { return JSON.stringify({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(wr.row), value: this.editorValueFor(cell.column.id), commit: this.editorCommitFor(cell.column.id), cancel: this.editorCancelFor(), autofocus: this.editorAutofocusFor(cell.column.id, wr.vi.index)}); } catch { return '{}'; } })()}></slot>`}
1350
- </span>` : this.editorTypeOf(cell.column.id) === 'number' ? html`<input class="rdt-cell-editor" type="number" data-editing-cell="" .value=${this.editorValueFor(cell.column.id)} @input=${($event: InputEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onCellEditorInput(cell.column.id, $event); }} @keydown=${($event: KeyboardEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorKeyDown($event); }} @blur=${($event: FocusEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorBlur($event); }} data-rozie-s-d5dcab4c />` : this.editorTypeOf(cell.column.id) === 'select' ? html`<select class="rdt-cell-editor" data-editing-cell="" .value=${this.editorValueFor(cell.column.id)} @change=${($event: Event & { currentTarget: HTMLSelectElement; target: HTMLSelectElement }) => { this.onCellEditorInput(cell.column.id, $event); }} @keydown=${($event: KeyboardEvent & { currentTarget: HTMLSelectElement; target: HTMLSelectElement }) => { this.onEditorKeyDown($event); }} @blur=${($event: FocusEvent & { currentTarget: HTMLSelectElement; target: HTMLSelectElement }) => { this.onEditorBlur($event); }} data-rozie-s-d5dcab4c>
1445
+ ${this.editorTypeOf(cell.column.id) === 'number' ? html`<input class="rdt-cell-editor" type="number" data-editing-cell="" data-builtin-editor="" .value=${this.editorValueFor(cell.column.id)} @input=${($event: InputEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onCellEditorInput(cell.column.id, $event); }} @keydown=${($event: KeyboardEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorKeyDown($event); }} @blur=${($event: FocusEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorBlur($event); }} data-rozie-s-d5dcab4c />` : this.editorTypeOf(cell.column.id) === 'select' ? html`<select class="rdt-cell-editor" data-editing-cell="" data-builtin-editor="" .value=${this.editorValueFor(cell.column.id)} @change=${($event: Event & { currentTarget: HTMLSelectElement; target: HTMLSelectElement }) => { this.onCellEditorInput(cell.column.id, $event); }} @keydown=${($event: KeyboardEvent & { currentTarget: HTMLSelectElement; target: HTMLSelectElement }) => { this.onEditorKeyDown($event); }} @blur=${($event: FocusEvent & { currentTarget: HTMLSelectElement; target: HTMLSelectElement }) => { this.onEditorBlur($event); }} data-rozie-s-d5dcab4c>
1351
1446
  ${repeat<any>(this.editorOptionsOf(cell.column.id), (opt, _idx) => opt.value, (opt, _idx) => html`<option value=${rozieAttr(opt.value)} data-rozie-s-d5dcab4c>${rozieDisplay(opt.label)}</option>`)}
1352
- </select>` : this.editorTypeOf(cell.column.id) === 'checkbox' ? html`<input class="rdt-cell-editor" type="checkbox" data-editing-cell="" ?checked=${this.editorCheckedFor(cell.column.id)} @change=${($event: Event & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onCellEditorCheckbox(cell.column.id, $event); }} @keydown=${($event: KeyboardEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorKeyDown($event); }} @blur=${($event: FocusEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorBlur($event); }} data-rozie-s-d5dcab4c />` : html`<input class="rdt-cell-editor" type="text" data-editing-cell="" .value=${this.editorValueFor(cell.column.id)} @input=${($event: InputEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onCellEditorInput(cell.column.id, $event); }} @keydown=${($event: KeyboardEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorKeyDown($event); }} @blur=${($event: FocusEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorBlur($event); }} data-rozie-s-d5dcab4c />`}</span>` : this.cellIsPlaceholder(cell) ? html`<span style="display:contents" data-rozie-s-d5dcab4c></span>` : html`<span class="rdt-cell-value" data-rozie-s-d5dcab4c>
1353
- ${this.cell !== undefined ? this.cell({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(wr.row), value: cell.getValue()}) : html`<slot name="cell" data-rozie-params=${(() => { try { return JSON.stringify({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(wr.row), value: cell.getValue()}); } catch { return '{}'; } })()}>${rozieDisplay(cell.getValue())}</slot>`}
1447
+ </select>` : this.editorTypeOf(cell.column.id) === 'checkbox' ? html`<input class="rdt-cell-editor" type="checkbox" data-editing-cell="" data-builtin-editor="" ?checked=${this.editorCheckedFor(cell.column.id)} @change=${($event: Event & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onCellEditorCheckbox(cell.column.id, $event); }} @keydown=${($event: KeyboardEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorKeyDown($event); }} @blur=${($event: FocusEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorBlur($event); }} data-rozie-s-d5dcab4c />` : this.editorTypeOf(cell.column.id) === 'custom' ? html`<span style="display:contents" data-rozie-s-d5dcab4c>
1448
+ ${this.rozieSlots?.[`editor-${cell.column.id}`] !== undefined ? this.rozieSlots?.[`editor-${cell.column.id}`]!({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(wr.row), value: this.editorValueFor(cell.column.id), commit: this.editorCommitFor(cell.column.id), cancel: this.editorCancelFor(), autofocus: this.editorAutofocusFor(cell.column.id, wr.vi.index)}) : html`<slot name="${`editor-${cell.column.id}`}" data-rozie-params=${(() => { try { return JSON.stringify({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(wr.row), value: this.editorValueFor(cell.column.id), commit: this.editorCommitFor(cell.column.id), cancel: this.editorCancelFor(), autofocus: this.editorAutofocusFor(cell.column.id, wr.vi.index)}); } catch { return '{}'; } })()}>
1449
+ ${this.editor !== undefined ? this.editor({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(wr.row), value: this.editorValueFor(cell.column.id), commit: this.editorCommitFor(cell.column.id), cancel: this.editorCancelFor(), autofocus: this.editorAutofocusFor(cell.column.id, wr.vi.index)}) : html`<slot name="editor" data-rozie-params=${(() => { try { return JSON.stringify({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(wr.row), value: this.editorValueFor(cell.column.id), commit: this.editorCommitFor(cell.column.id), cancel: this.editorCancelFor(), autofocus: this.editorAutofocusFor(cell.column.id, wr.vi.index)}); } catch { return '{}'; } })()}>
1450
+ <input class="rdt-cell-editor" type="text" data-editing-cell="" data-builtin-editor="" .value=${this.editorValueFor(cell.column.id)} @input=${($event: InputEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onCellEditorInput(cell.column.id, $event); }} @keydown=${($event: KeyboardEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorKeyDown($event); }} @blur=${($event: FocusEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorBlur($event); }} data-rozie-s-d5dcab4c />
1451
+ </slot>`}
1452
+ </slot>`}
1453
+ </span>` : html`<input class="rdt-cell-editor" type="text" data-editing-cell="" data-builtin-editor="" .value=${this.editorValueFor(cell.column.id)} @input=${($event: InputEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onCellEditorInput(cell.column.id, $event); }} @keydown=${($event: KeyboardEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorKeyDown($event); }} @blur=${($event: FocusEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorBlur($event); }} data-rozie-s-d5dcab4c />`}</span>` : this.cellIsPlaceholder(cell) ? html`<span style="display:contents" data-rozie-s-d5dcab4c></span>` : html`<span class="rdt-cell-value" data-rozie-s-d5dcab4c>
1454
+ ${this.rozieSlots?.[`cell-${cell.column.id}`] !== undefined ? this.rozieSlots?.[`cell-${cell.column.id}`]!({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(wr.row), value: cell.getValue()}) : html`<slot name="${`cell-${cell.column.id}`}" data-rozie-params=${(() => { try { return JSON.stringify({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(wr.row), value: cell.getValue()}); } catch { return '{}'; } })()}>
1455
+ ${this.cell !== undefined ? this.cell({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(wr.row), value: cell.getValue()}) : html`<slot name="cell" data-rozie-params=${(() => { try { return JSON.stringify({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(wr.row), value: cell.getValue()}); } catch { return '{}'; } })()}>${rozieDisplay(cell.getValue())}</slot>`}
1456
+ </slot>`}
1354
1457
  </span>`}${this.isFillHandleCell(wr.vi.index, this.colIndexOf(wr.row, cell)) ? html`<span class="rdt-fill-handle" data-fill-handle="" data-testid="fill-handle" aria-hidden="true" @pointerdown=${($event: PointerEvent & { currentTarget: HTMLSpanElement; target: HTMLSpanElement }) => { this.onFillHandlePointerDown($event); }} data-rozie-s-d5dcab4c></span>` : nothing}</td>`)}
1355
1458
 
1356
1459
  ${this.colsWindowed() ? html`<td class="rdt-col-spacer" aria-hidden="true" style=${rozieStyle('width:' + this.colPadRight() + 'px;padding:0;border:0')} data-rozie-s-d5dcab4c></td>` : nothing}</tr>
@@ -1369,7 +1472,7 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
1369
1472
  </div>` : html`<table class="${Object.entries({ "rozie-data-table": true, 'rdt-sticky': this.stickyHeader }).filter(([, v]) => v).map(([k]) => k).join(' ')}" role=${rozieAttr(this.tableRole())} aria-rowcount=${rozieAttr(this.gridAriaRowCount())} @keydown=${($event: KeyboardEvent & { currentTarget: HTMLTableElement; target: HTMLTableElement }) => { this.onGridKeyDown($event); }} @focusin=${($event: Event & { currentTarget: HTMLTableElement; target: HTMLTableElement }) => { this.syncActiveFromEvent($event); }} @focusout=${($event: Event & { currentTarget: HTMLTableElement; target: HTMLTableElement }) => { this.onGridFocusOut($event); }} @mousedown=${($event: MouseEvent & { currentTarget: HTMLTableElement; target: HTMLTableElement }) => { this.onGridMouseDown($event); }} @dblclick=${($event: Event & { currentTarget: HTMLTableElement; target: HTMLTableElement }) => { this.onGridDblClick($event); }} @click=${($event: MouseEvent & { currentTarget: HTMLTableElement; target: HTMLTableElement }) => { this.onGridClick($event); }} data-rozie-s-d5dcab4c>
1370
1473
  <thead class="rdt-thead" role="rowgroup" data-rozie-s-d5dcab4c>
1371
1474
  ${repeat<any>(this._headerGroups.value, (hg, hgLevel) => hg.id, (hg, hgLevel) => html`<tr class="rdt-tr" role="row" aria-rowindex=${rozieAttr(hgLevel + 1)} data-rozie-s-d5dcab4c>
1372
- ${repeat<any>(hg.headers, (header, _idx) => header.id, (header, _idx) => html`<th class="${Object.entries({ "rdt-th": true, 'rdt-select-th': this.isSelectColumn(header.column.id), 'rdt-expander-th': this.isExpanderColumn(header.column.id), 'rdt-th-resizing': this.columnIsResizing(header.column.id), 'rdt-cell-active': this.isActiveCell('__header', this.headerColIndexOf(hg, header), hgLevel) }).filter(([, v]) => v).map(([k]) => k).join(' ')}" role="columnheader" data-col=${rozieAttr(header.column.id)} data-grid-cell="" data-row="__header" data-header-level=${rozieAttr(hgLevel)} colspan=${rozieAttr(header.colSpan > 1 ? header.colSpan : null)} data-col-index=${rozieAttr(this.headerColIndexOf(hg, header))} tabindex=${rozieAttr(this.cellTabindex('__header', this.headerColIndexOf(hg, header), hgLevel))} aria-sort=${rozieAttr(this.ariaSortFor(header.column.id))} style=${rozieStyle(this.thStyle(header.column.id))} data-rozie-s-d5dcab4c>
1475
+ ${repeat<any>(hg.headers, (header, _idx) => header.id, (header, _idx) => html`<th class="${Object.entries({ "rdt-th": true, 'rdt-select-th': this.isSelectColumn(header.column.id), 'rdt-expander-th': this.isExpanderColumn(header.column.id), 'rdt-th-resizing': this.columnIsResizing(header.column.id), 'rdt-cell-active': this.isActiveCell('__header', this.headerColIndexOf(hg, header), hgLevel) }).filter(([, v]) => v).map(([k]) => k).join(' ')}" role="columnheader" data-col=${rozieAttr(header.column.id)} data-grid-cell="" data-row="__header" data-header-level=${rozieAttr(hgLevel)} colspan=${rozieAttr(header.colSpan > 1 ? header.colSpan : null)} data-col-index=${rozieAttr(this.headerColIndexOf(hg, header))} tabindex=${rozieAttr(this.cellTabindex('__header', this.headerColIndexOf(hg, header), hgLevel))} aria-sort=${rozieAttr(this.ariaSortFor(header.column.id))} style=${rozieStyle(this.thStyle(header))} data-rozie-s-d5dcab4c>
1373
1476
 
1374
1477
 
1375
1478
  ${this.isSelectColumn(header.column.id) ? html`<span style="display:contents" data-rozie-s-d5dcab4c>
@@ -1381,12 +1484,16 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
1381
1484
  ${header.column.getCanSort && header.column.getCanSort() ? html`<button class="rdt-sort-btn" type="button" @click=${($event: MouseEvent & { currentTarget: HTMLButtonElement; target: HTMLButtonElement }) => { this.onHeaderSort(header.column.id, $event); }} data-rozie-s-d5dcab4c>
1382
1485
 
1383
1486
  <span class="rdt-header-label" data-rozie-s-d5dcab4c>
1384
- ${this.colHeader !== undefined ? this.colHeader({columnId: header.column.id, column: header.column, label: this.headerLabel(header.column.id)}) : html`<slot name="colHeader" data-rozie-params=${(() => { try { return JSON.stringify({columnId: header.column.id, column: header.column, label: this.headerLabel(header.column.id)}); } catch { return '{}'; } })()}>${rozieDisplay(this.headerLabel(header.column.id))}</slot>`}
1487
+ ${this.rozieSlots?.[`colHeader-${header.column.id}`] !== undefined ? this.rozieSlots?.[`colHeader-${header.column.id}`]!({columnId: header.column.id, column: header.column, label: this.headerLabel(header.column.id)}) : html`<slot name="${`colHeader-${header.column.id}`}" data-rozie-params=${(() => { try { return JSON.stringify({columnId: header.column.id, column: header.column, label: this.headerLabel(header.column.id)}); } catch { return '{}'; } })()}>
1488
+ ${this.colHeader !== undefined ? this.colHeader({columnId: header.column.id, column: header.column, label: this.headerLabel(header.column.id)}) : html`<slot name="colHeader" data-rozie-params=${(() => { try { return JSON.stringify({columnId: header.column.id, column: header.column, label: this.headerLabel(header.column.id)}); } catch { return '{}'; } })()}>${rozieDisplay(this.headerLabel(header.column.id))}</slot>`}
1489
+ </slot>`}
1385
1490
  </span>
1386
1491
  <span class="rdt-sort-ind" aria-hidden="true" data-rozie-s-d5dcab4c>${rozieDisplay(this.sortIndicator(header.column.id))}</span>
1387
1492
  </button>` : html`<span style="display:contents" data-rozie-s-d5dcab4c>
1388
1493
  <span class="rdt-header-label" data-rozie-s-d5dcab4c>
1389
- ${this.colHeader !== undefined ? this.colHeader({columnId: header.column.id, column: header.column, label: this.headerLabel(header.column.id)}) : html`<slot name="colHeader" data-rozie-params=${(() => { try { return JSON.stringify({columnId: header.column.id, column: header.column, label: this.headerLabel(header.column.id)}); } catch { return '{}'; } })()}>${rozieDisplay(this.headerLabel(header.column.id))}</slot>`}
1494
+ ${this.rozieSlots?.[`colHeader-${header.column.id}`] !== undefined ? this.rozieSlots?.[`colHeader-${header.column.id}`]!({columnId: header.column.id, column: header.column, label: this.headerLabel(header.column.id)}) : html`<slot name="${`colHeader-${header.column.id}`}" data-rozie-params=${(() => { try { return JSON.stringify({columnId: header.column.id, column: header.column, label: this.headerLabel(header.column.id)}); } catch { return '{}'; } })()}>
1495
+ ${this.colHeader !== undefined ? this.colHeader({columnId: header.column.id, column: header.column, label: this.headerLabel(header.column.id)}) : html`<slot name="colHeader" data-rozie-params=${(() => { try { return JSON.stringify({columnId: header.column.id, column: header.column, label: this.headerLabel(header.column.id)}); } catch { return '{}'; } })()}>${rozieDisplay(this.headerLabel(header.column.id))}</slot>`}
1496
+ </slot>`}
1390
1497
  </span>
1391
1498
  </span>`}<rozie-popover trigger="click" placement="bottom-end" strategy="fixed" .offset=${4} data-rozie-s-d5dcab4c><button class="rdt-col-menu-trigger" type="button" aria-label=${rozieAttr('Column options for ' + this.headerLabel(header.column.id))} data-rozie-s-d5dcab4c slot="anchor">⋯</button><div class="rdt-col-menu" role="menu" data-rozie-s-d5dcab4c>
1392
1499
  <button class="rdt-col-menu-item" type="button" role="menuitem" aria-pressed=${this.columnPinSide(header.column.id) === 'left'} @click=${($event: MouseEvent & { currentTarget: HTMLButtonElement; target: HTMLButtonElement }) => { this.onPinColumn(header.column.id, 'left', $event); }} data-rozie-s-d5dcab4c>Pin left</button>
@@ -1403,8 +1510,12 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
1403
1510
  ${this.hasAnyFilterableColumn() ? html`<tr class="rdt-filter-row" data-rozie-s-d5dcab4c>
1404
1511
  ${repeat<any>(this._headerGroups.value[this._headerGroups.value.length - 1].headers, (header, _idx) => header.id, (header, _idx) => html`<th class="rdt-filter-cell" role="presentation" style=${rozieStyle(this.pinStyle(header.column.id))} data-rozie-s-d5dcab4c>
1405
1512
  ${this.isSelectColumn(header.column.id) ? html`<span style="display:contents" data-rozie-s-d5dcab4c></span>` : this.isExpanderColumn(header.column.id) ? html`<span style="display:contents" data-rozie-s-d5dcab4c></span>` : html`<span style="display:contents" data-rozie-s-d5dcab4c>
1406
- ${this.columnIsFilterable(header.column.id) && !this.hasFilterSlot() ? html`<input class="rdt-col-filter" type="text" aria-label=${rozieAttr('Filter ' + this.headerLabel(header.column.id))} .value=${this.columnFilterValue(header.column.id)} @input=${($event: InputEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onColumnFilterInput(header.column.id, $event); }} @click=${($event: MouseEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.stopEvent($event); }} data-rozie-s-d5dcab4c />` : nothing}${this.columnIsFilterable(header.column.id) ? html`<span style="display:contents" data-rozie-s-d5dcab4c>
1407
- ${this.filter !== undefined ? this.filter({columnId: header.column.id, value: this.columnFilterValue(header.column.id), uniqueValues: this.getFacetedUniqueValues(header.column.id), minMax: this.getFacetedMinMaxValues(header.column.id), setFilter: this.setColumnFilter}) : html`<slot name="filter" data-rozie-params=${(() => { try { return JSON.stringify({columnId: header.column.id, value: this.columnFilterValue(header.column.id), uniqueValues: this.getFacetedUniqueValues(header.column.id), minMax: this.getFacetedMinMaxValues(header.column.id)}); } catch { return '{}'; } })()} @rozie-filter-set-filter=${($event: CustomEvent) => ((this.setColumnFilter) as (...args: any[]) => any)($event.detail)}></slot>`}
1513
+ ${this.columnIsFilterable(header.column.id) ? html`<span style="display:contents" data-rozie-s-d5dcab4c>
1514
+ ${this.rozieSlots?.[`filter-${header.column.id}`] !== undefined ? this.rozieSlots?.[`filter-${header.column.id}`]!({columnId: header.column.id, value: this.columnFilterValue(header.column.id), uniqueValues: this.getFacetedUniqueValues(header.column.id), minMax: this.getFacetedMinMaxValues(header.column.id), setFilter: this.setColumnFilter}) : html`<slot name="${`filter-${header.column.id}`}" data-rozie-params=${(() => { try { return JSON.stringify({columnId: header.column.id, value: this.columnFilterValue(header.column.id), uniqueValues: this.getFacetedUniqueValues(header.column.id), minMax: this.getFacetedMinMaxValues(header.column.id)}); } catch { return '{}'; } })()} @rozie-default-set-filter=${($event: CustomEvent) => ((this.setColumnFilter) as (...args: any[]) => any)($event.detail)}>
1515
+ ${this.filter !== undefined ? this.filter({columnId: header.column.id, value: this.columnFilterValue(header.column.id), uniqueValues: this.getFacetedUniqueValues(header.column.id), minMax: this.getFacetedMinMaxValues(header.column.id), setFilter: this.setColumnFilter}) : html`<slot name="filter" data-rozie-params=${(() => { try { return JSON.stringify({columnId: header.column.id, value: this.columnFilterValue(header.column.id), uniqueValues: this.getFacetedUniqueValues(header.column.id), minMax: this.getFacetedMinMaxValues(header.column.id)}); } catch { return '{}'; } })()} @rozie-filter-set-filter=${($event: CustomEvent) => ((this.setColumnFilter) as (...args: any[]) => any)($event.detail)}>
1516
+ <input class="rdt-col-filter" type="text" aria-label=${rozieAttr('Filter ' + this.headerLabel(header.column.id))} .value=${this.columnFilterValue(header.column.id)} @input=${($event: InputEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onColumnFilterInput(header.column.id, $event); }} @click=${($event: MouseEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.stopEvent($event); }} data-rozie-s-d5dcab4c />
1517
+ </slot>`}
1518
+ </slot>`}
1408
1519
  </span>` : nothing}</span>`}</th>`)}
1409
1520
  </tr>` : nothing}</thead>
1410
1521
 
@@ -1422,16 +1533,24 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
1422
1533
  </span>` : this.cellIsGrouped(cell) ? html`<span style="display:contents" data-rozie-s-d5dcab4c>
1423
1534
  <button class="rdt-expander rdt-group-toggle" type="button" data-expander="" aria-expanded=${!!this.rowIsExpanded(row)} aria-label=${rozieAttr(this.rowIsExpanded(row) ? 'Collapse group' : 'Expand group')} @click=${($event: MouseEvent & { currentTarget: HTMLButtonElement; target: HTMLButtonElement }) => { this.onToggleExpand(row, $event); }} data-rozie-s-d5dcab4c>${rozieDisplay(this.rowIsExpanded(row) ? '▾' : '▸')}</button>
1424
1535
  <span class="rdt-group-value" data-rozie-s-d5dcab4c>
1425
- ${this.cell !== undefined ? this.cell({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(row), value: cell.getValue()}) : html`<slot name="cell" data-rozie-params=${(() => { try { return JSON.stringify({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(row), value: cell.getValue()}); } catch { return '{}'; } })()}>${rozieDisplay(cell.getValue())}</slot>`}
1536
+ ${this.rozieSlots?.[`cell-${cell.column.id}`] !== undefined ? this.rozieSlots?.[`cell-${cell.column.id}`]!({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(row), value: cell.getValue()}) : html`<slot name="${`cell-${cell.column.id}`}" data-rozie-params=${(() => { try { return JSON.stringify({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(row), value: cell.getValue()}); } catch { return '{}'; } })()}>
1537
+ ${this.cell !== undefined ? this.cell({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(row), value: cell.getValue()}) : html`<slot name="cell" data-rozie-params=${(() => { try { return JSON.stringify({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(row), value: cell.getValue()}); } catch { return '{}'; } })()}>${rozieDisplay(cell.getValue())}</slot>`}
1538
+ </slot>`}
1426
1539
  </span>
1427
1540
  <span class="rdt-group-count" data-rozie-s-d5dcab4c>${rozieDisplay('(' + this.groupSubRowCount(row) + ')')}</span>
1428
1541
  </span>` : this.isEditing(this.rowIndexOf(row), this.colIndexOf(row, cell)) ? html`<span style="display:contents" data-rozie-s-d5dcab4c>
1429
- ${this.hasEditorSlot(cell.column.id) ? html`<span style="display:contents" data-rozie-s-d5dcab4c>
1430
- ${this.editor !== undefined ? this.editor({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(row), value: this.editorValueFor(cell.column.id), commit: this.editorCommitFor(cell.column.id), cancel: this.editorCancelFor(), autofocus: this.editorAutofocusFor(cell.column.id, this.rowIndexOf(row))}) : html`<slot name="editor" data-rozie-params=${(() => { try { return JSON.stringify({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(row), value: this.editorValueFor(cell.column.id), commit: this.editorCommitFor(cell.column.id), cancel: this.editorCancelFor(), autofocus: this.editorAutofocusFor(cell.column.id, this.rowIndexOf(row))}); } catch { return '{}'; } })()}></slot>`}
1431
- </span>` : this.editorTypeOf(cell.column.id) === 'number' ? html`<input class="rdt-cell-editor" type="number" data-editing-cell="" .value=${this.editorValueFor(cell.column.id)} @input=${($event: InputEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onCellEditorInput(cell.column.id, $event); }} @keydown=${($event: KeyboardEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorKeyDown($event); }} @blur=${($event: FocusEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorBlur($event); }} data-rozie-s-d5dcab4c />` : this.editorTypeOf(cell.column.id) === 'select' ? html`<select class="rdt-cell-editor" data-editing-cell="" .value=${this.editorValueFor(cell.column.id)} @change=${($event: Event & { currentTarget: HTMLSelectElement; target: HTMLSelectElement }) => { this.onCellEditorInput(cell.column.id, $event); }} @keydown=${($event: KeyboardEvent & { currentTarget: HTMLSelectElement; target: HTMLSelectElement }) => { this.onEditorKeyDown($event); }} @blur=${($event: FocusEvent & { currentTarget: HTMLSelectElement; target: HTMLSelectElement }) => { this.onEditorBlur($event); }} data-rozie-s-d5dcab4c>
1542
+ ${this.editorTypeOf(cell.column.id) === 'number' ? html`<input class="rdt-cell-editor" type="number" data-editing-cell="" data-builtin-editor="" .value=${this.editorValueFor(cell.column.id)} @input=${($event: InputEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onCellEditorInput(cell.column.id, $event); }} @keydown=${($event: KeyboardEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorKeyDown($event); }} @blur=${($event: FocusEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorBlur($event); }} data-rozie-s-d5dcab4c />` : this.editorTypeOf(cell.column.id) === 'select' ? html`<select class="rdt-cell-editor" data-editing-cell="" data-builtin-editor="" .value=${this.editorValueFor(cell.column.id)} @change=${($event: Event & { currentTarget: HTMLSelectElement; target: HTMLSelectElement }) => { this.onCellEditorInput(cell.column.id, $event); }} @keydown=${($event: KeyboardEvent & { currentTarget: HTMLSelectElement; target: HTMLSelectElement }) => { this.onEditorKeyDown($event); }} @blur=${($event: FocusEvent & { currentTarget: HTMLSelectElement; target: HTMLSelectElement }) => { this.onEditorBlur($event); }} data-rozie-s-d5dcab4c>
1432
1543
  ${repeat<any>(this.editorOptionsOf(cell.column.id), (opt, _idx) => opt.value, (opt, _idx) => html`<option value=${rozieAttr(opt.value)} data-rozie-s-d5dcab4c>${rozieDisplay(opt.label)}</option>`)}
1433
- </select>` : this.editorTypeOf(cell.column.id) === 'checkbox' ? html`<input class="rdt-cell-editor" type="checkbox" data-editing-cell="" ?checked=${this.editorCheckedFor(cell.column.id)} @change=${($event: Event & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onCellEditorCheckbox(cell.column.id, $event); }} @keydown=${($event: KeyboardEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorKeyDown($event); }} @blur=${($event: FocusEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorBlur($event); }} data-rozie-s-d5dcab4c />` : html`<input class="rdt-cell-editor" type="text" data-editing-cell="" .value=${this.editorValueFor(cell.column.id)} @input=${($event: InputEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onCellEditorInput(cell.column.id, $event); }} @keydown=${($event: KeyboardEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorKeyDown($event); }} @blur=${($event: FocusEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorBlur($event); }} data-rozie-s-d5dcab4c />`}</span>` : this.cellIsPlaceholder(cell) ? html`<span style="display:contents" data-rozie-s-d5dcab4c></span>` : html`<span class="rdt-cell-value" data-rozie-s-d5dcab4c>
1434
- ${this.cell !== undefined ? this.cell({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(row), value: cell.getValue()}) : html`<slot name="cell" data-rozie-params=${(() => { try { return JSON.stringify({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(row), value: cell.getValue()}); } catch { return '{}'; } })()}>${rozieDisplay(cell.getValue())}</slot>`}
1544
+ </select>` : this.editorTypeOf(cell.column.id) === 'checkbox' ? html`<input class="rdt-cell-editor" type="checkbox" data-editing-cell="" data-builtin-editor="" ?checked=${this.editorCheckedFor(cell.column.id)} @change=${($event: Event & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onCellEditorCheckbox(cell.column.id, $event); }} @keydown=${($event: KeyboardEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorKeyDown($event); }} @blur=${($event: FocusEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorBlur($event); }} data-rozie-s-d5dcab4c />` : this.editorTypeOf(cell.column.id) === 'custom' ? html`<span style="display:contents" data-rozie-s-d5dcab4c>
1545
+ ${this.rozieSlots?.[`editor-${cell.column.id}`] !== undefined ? this.rozieSlots?.[`editor-${cell.column.id}`]!({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(row), value: this.editorValueFor(cell.column.id), commit: this.editorCommitFor(cell.column.id), cancel: this.editorCancelFor(), autofocus: this.editorAutofocusFor(cell.column.id, this.rowIndexOf(row))}) : html`<slot name="${`editor-${cell.column.id}`}" data-rozie-params=${(() => { try { return JSON.stringify({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(row), value: this.editorValueFor(cell.column.id), commit: this.editorCommitFor(cell.column.id), cancel: this.editorCancelFor(), autofocus: this.editorAutofocusFor(cell.column.id, this.rowIndexOf(row))}); } catch { return '{}'; } })()}>
1546
+ ${this.editor !== undefined ? this.editor({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(row), value: this.editorValueFor(cell.column.id), commit: this.editorCommitFor(cell.column.id), cancel: this.editorCancelFor(), autofocus: this.editorAutofocusFor(cell.column.id, this.rowIndexOf(row))}) : html`<slot name="editor" data-rozie-params=${(() => { try { return JSON.stringify({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(row), value: this.editorValueFor(cell.column.id), commit: this.editorCommitFor(cell.column.id), cancel: this.editorCancelFor(), autofocus: this.editorAutofocusFor(cell.column.id, this.rowIndexOf(row))}); } catch { return '{}'; } })()}>
1547
+ <input class="rdt-cell-editor" type="text" data-editing-cell="" data-builtin-editor="" .value=${this.editorValueFor(cell.column.id)} @input=${($event: InputEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onCellEditorInput(cell.column.id, $event); }} @keydown=${($event: KeyboardEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorKeyDown($event); }} @blur=${($event: FocusEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorBlur($event); }} data-rozie-s-d5dcab4c />
1548
+ </slot>`}
1549
+ </slot>`}
1550
+ </span>` : html`<input class="rdt-cell-editor" type="text" data-editing-cell="" data-builtin-editor="" .value=${this.editorValueFor(cell.column.id)} @input=${($event: InputEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onCellEditorInput(cell.column.id, $event); }} @keydown=${($event: KeyboardEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorKeyDown($event); }} @blur=${($event: FocusEvent & { currentTarget: HTMLInputElement; target: HTMLInputElement }) => { this.onEditorBlur($event); }} data-rozie-s-d5dcab4c />`}</span>` : this.cellIsPlaceholder(cell) ? html`<span style="display:contents" data-rozie-s-d5dcab4c></span>` : html`<span class="rdt-cell-value" data-rozie-s-d5dcab4c>
1551
+ ${this.rozieSlots?.[`cell-${cell.column.id}`] !== undefined ? this.rozieSlots?.[`cell-${cell.column.id}`]!({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(row), value: cell.getValue()}) : html`<slot name="${`cell-${cell.column.id}`}" data-rozie-params=${(() => { try { return JSON.stringify({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(row), value: cell.getValue()}); } catch { return '{}'; } })()}>
1552
+ ${this.cell !== undefined ? this.cell({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(row), value: cell.getValue()}) : html`<slot name="cell" data-rozie-params=${(() => { try { return JSON.stringify({columnId: cell.column.id, column: cell.column, row: this.cellSlotRow(row), value: cell.getValue()}); } catch { return '{}'; } })()}>${rozieDisplay(cell.getValue())}</slot>`}
1553
+ </slot>`}
1435
1554
  </span>`}${this.isFillHandleCell(this.rowIndexOf(row), this.colIndexOf(row, cell)) ? html`<span class="rdt-fill-handle" data-fill-handle="" data-testid="fill-handle" aria-hidden="true" @pointerdown=${($event: PointerEvent & { currentTarget: HTMLSpanElement; target: HTMLSpanElement }) => { this.onFillHandlePointerDown($event); }} data-rozie-s-d5dcab4c></span>` : nothing}</td>`)}
1436
1555
  </tr>
1437
1556
 
@@ -3632,17 +3751,6 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
3632
3751
  return m && m.editorOptions != null ? m.editorOptions : [];
3633
3752
  };
3634
3753
 
3635
- // hasEditorSlot: this column routes through the consumer's #editor scoped slot (req-2)
3636
- // — true only when the column declared editor='custom' AND the consumer actually
3637
- // provided an #editor slot. Falls through to the built-in editor otherwise (e.g. a
3638
- // column marked 'custom' with no slot supplied degrades to the text editor, never blank).
3639
- hasEditorSlot = (colId: any) => this.editorTypeOf(colId) === 'custom' && !!(this._hasSlotEditor || this.editor !== undefined);
3640
-
3641
- // hasFilterSlot: the consumer supplied a #filter scoped slot, so it OWNS the per-column
3642
- // filter UI (re-added in 72-05 alongside the dedicated filter row's `<slot name="filter">`
3643
- // host — see the 72-03 removal note in that plan's SUMMARY for why this was briefly gone).
3644
- hasFilterSlot = () => !!(this._hasSlotFilter || this.filter !== undefined);
3645
-
3646
3754
  columnIsFilterable = (colId: any) => {
3647
3755
  const d = this.defFor(colId);
3648
3756
  return !!(d && d.filterable);
@@ -3654,13 +3762,27 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
3654
3762
  };
3655
3763
 
3656
3764
  // ── Column-management chrome (req-8/9/10/11) ────────────────────────────────────────
3657
- // Live header width (px) for a column — drives the <th> :style width binding. Reads the
3658
- // table-core column size (post-mount) with a fallback to undefined (auto width).
3659
- headerWidth = (colId: any) => {
3660
- if (this.tick() < 0 || !this.table) return null;
3661
- const col = this.table.getColumn(colId);
3662
- if (!col) return null;
3663
- const w = col.getSize();
3765
+ // Live header width (px) for a <th> — drives the :style width binding. Takes the table-core
3766
+ // HEADER object (not a column id / Column lookup) and reads header.getSize() — deliberately,
3767
+ // NOT column.getSize(). table-core's own ColumnSizing feature (createHeader, always present —
3768
+ // it is in table-core's builtInFeatures, never opt-in) gives Header.getSize() a recursive
3769
+ // implementation: a LEAF header returns its own column's getSize() (identical to the old
3770
+ // column.getSize() path — byte-identical output there), but a GROUP header (one with
3771
+ // subHeaders, e.g. a multi-level `columns:` entry from buildConfigDef) SUMS every descendant
3772
+ // leaf column's getSize() instead of returning the group's own meaningless single-column
3773
+ // default (150px, table-core's defaultColumnSizing.size — group ColumnDefs never set `size`).
3774
+ // Before this fix, a colspan-N grouped <th> asked the browser for ONE column's worth of width
3775
+ // (150px) while spanning N columns; under `table-layout:fixed` the browser then divides that
3776
+ // single declared width ACROSS all N spanned <th>s (150/5 = 30px for this codebase's 5-column
3777
+ // "Group A" fixture) — a 5x collapse of the actual rendered column width, independent of (and
3778
+ // invisible to) columnSize()/the column virtualizer's windowing math, which reads
3779
+ // table.getVisibleLeafColumns()[i].getSize() directly and was never affected. Root cause +
3780
+ // fix confirmed via .planning/debug/datatable-d13-column-axis-all-targets.md and previously
3781
+ // documented as "Gap 1" in .planning/phases/87-.../deferred-items.md (the identical grouped-
3782
+ // header/colspan mismatch, found independently during 87-05/87-06 authoring and deferred).
3783
+ headerWidth = (header: any) => {
3784
+ if (this.tick() < 0 || !header || typeof header.getSize !== 'function') return null;
3785
+ const w = header.getSize();
3664
3786
  return w != null && w > 0 ? w + 'px' : null;
3665
3787
  };
3666
3788
 
@@ -3784,15 +3906,18 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
3784
3906
  return '';
3785
3907
  };
3786
3908
 
3787
- // Combined inline style for a <th> (width + pin) and a <td> (pin). Plain string concat —
3788
- // uniform on all 6, no bound-object trap. zIndex=2 (see pinStyle) so a pinned header cell
3789
- // — which hosts the ⋯ menu's floating content — always stacks above the pinned filter-row
3790
- // cell for the same column (zIndex=1, its own default).
3791
- thStyle = (colId: any) => {
3909
+ // Combined inline style for a <th> (width + pin). Plain string concat — uniform on all 6, no
3910
+ // bound-object trap. zIndex=2 (see pinStyle) so a pinned header cell — which hosts the ⋯ menu's
3911
+ // floating content — always stacks above the pinned filter-row cell for the same column
3912
+ // (zIndex=1, its own default). Takes the HEADER object (not a bare colId) so headerWidth() can
3913
+ // read header.getSize() — the group-aware size (see headerWidth's own comment). pinStyle still
3914
+ // keys off the plain column id (pinning is a leaf-column-only concern; a grouped header never
3915
+ // pins as a unit in this codebase's model).
3916
+ thStyle = (header: any) => {
3792
3917
  let s = '';
3793
- const w = this.headerWidth(colId);
3918
+ const w = this.headerWidth(header);
3794
3919
  if (w) s += 'width:' + w + ';';
3795
- s += this.pinStyle(colId, 2);
3920
+ s += this.pinStyle(header && header.column ? header.column.id : null, 2);
3796
3921
  return s;
3797
3922
  };
3798
3923
 
@@ -6268,8 +6393,26 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
6268
6393
  }
6269
6394
  };
6270
6395
 
6271
- cellIndexFromPoint = (clientX: any, clientY: any) => {
6272
- if (typeof document === 'undefined' || !document.elementFromPoint) return null;
6396
+ // FILL_HITTEST_PROBE_RADIUS_PX / FILL_HITTEST_PROBE_STEP_PX (hardening, authorized alongside the
6397
+ // D-13 grouped-header width fix — .planning/debug/datatable-d13-column-axis-all-targets.md):
6398
+ // resolveCellAt() below hit-tests document.elementFromPoint at ONE exact pixel — structurally
6399
+ // fragile against a scrolling DOM by construction: any narrow column transiting past that fixed
6400
+ // screen point (the edge-auto-scroll rAF loop in fillDrag re-probes the SAME fixed point every
6401
+ // frame while gridScrollEl's content slides underneath it) has only a single-frame-scale window
6402
+ // to be caught, and a probe pixel landing exactly on a border/rounding edge between two adjacent
6403
+ // `<td>`/`<th>`s can miss both. cellIndexFromPoint widens the miss case ONLY: it tries the exact
6404
+ // point first (byte-identical to the pre-hardening behavior on a hit — this is not a behavior
6405
+ // change to the common case) and, only if that misses, fans out a small nearest-first horizontal
6406
+ // search before giving up. Vertical-only misses are not probed (rows are >=24px tall by design —
6407
+ // FILL_EDGE_SCROLL_PX itself — so a row is never narrower than a single scroll step; only COLUMN
6408
+ // width has no such floor, hence a horizontal-only widening).
6409
+ FILL_HITTEST_PROBE_RADIUS_PX = 8;
6410
+
6411
+ FILL_HITTEST_PROBE_STEP_PX = 2;
6412
+
6413
+ // resolveCellAt: the exact-point hit-test (identical logic to the pre-hardening
6414
+ // cellIndexFromPoint body) extracted so it can be re-tried at nearby x-offsets below.
6415
+ resolveCellAt = (clientX: any, clientY: any) => {
6273
6416
  let el = document.elementFromPoint(clientX, clientY);
6274
6417
  // Pierce OPEN shadow roots (Lit): document.elementFromPoint retargets to the shadow HOST, so
6275
6418
  // a drag over the Lit data-table's shadow content would otherwise resolve the host (no cell)
@@ -6295,6 +6438,23 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
6295
6438
  };
6296
6439
  };
6297
6440
 
6441
+ cellIndexFromPoint = (clientX: any, clientY: any) => {
6442
+ if (typeof document === 'undefined' || !document.elementFromPoint) return null;
6443
+ const direct = this.resolveCellAt(clientX, clientY);
6444
+ if (direct) return direct;
6445
+ // Widened nearest-cell search: only reached when the exact point misses. Fans outward
6446
+ // (nearest-first, alternating +/-x) up to FILL_HITTEST_PROBE_RADIUS_PX before giving up —
6447
+ // catches a narrow column that transited past the fixed probe point on this exact frame
6448
+ // without changing which cell wins on an ordinary (non-edge-case) hit.
6449
+ for (let d = this.FILL_HITTEST_PROBE_STEP_PX; d <= this.FILL_HITTEST_PROBE_RADIUS_PX; d += this.FILL_HITTEST_PROBE_STEP_PX) {
6450
+ const right = this.resolveCellAt(clientX + d, clientY);
6451
+ if (right) return right;
6452
+ const left = this.resolveCellAt(clientX - d, clientY);
6453
+ if (left) return left;
6454
+ }
6455
+ return null;
6456
+ };
6457
+
6298
6458
  onFillHandlePointerDown = (e: any) => {
6299
6459
  if (!e) return;
6300
6460
  if (e.preventDefault) e.preventDefault();
@@ -6624,39 +6784,73 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
6624
6784
  return row ? row.id : null;
6625
6785
  };
6626
6786
 
6787
+ // resolveEditFocusCellEl(rowIndex, colIndex): the DOM cell element for an edit-focus
6788
+ // target, given an EXPLICIT index pair — NEVER a $data re-read inside this function or its
6789
+ // caller's poll closure. Every call site already knows this pair SYNCHRONOUSLY at the
6790
+ // moment it calls (beginEdit's own rowIndex/colIndex params; commitEdit's stable, already-
6791
+ // settled $data.editingRow/editingCol; beginRowEdit's rowIndex + the target column's
6792
+ // editable[].colIndex from editableColumnsForRow) — threading them through as PARAMETERS,
6793
+ // mirroring focusRowEditorAt's already-proven resolveCellEl(String(rowIndex), colIndex)
6794
+ // shape, closes the React batched-setState staleness class 88-05-SUMMARY.md documented
6795
+ // (REACT_STALE_GATE_SINGLE_CELL_BUG): the OLD gate read $data.editFocusColId SYNCHRONOUSLY,
6796
+ // in the SAME tick beginEdit's own setState call set it, and React's batching meant that
6797
+ // read saw the PRE-edit (null) value. A plain function argument threaded through — never a
6798
+ // reactive re-read — is not subject to that race, uniformly on all 6 targets.
6799
+ resolveEditFocusCellEl = (rowIndex: any, colIndex: any) => {
6800
+ if (rowIndex == null || colIndex == null || rowIndex < 0 || colIndex < 0) return null;
6801
+ return this.resolveCellEl(String(rowIndex), colIndex);
6802
+ };
6803
+
6627
6804
  // Focus the freshly-mounted editor (Pitfall 1, ROZ123): after beginEdit flips the editing
6628
6805
  // state, the editor <input> does not exist until the framework commits the r-if branch
6629
- // (React setState async; Solid/Lit/Svelte next reactive tick). Poll for the
6630
- // [data-editing-cell] element off gridRoot for ~30 frames — the five fast targets resolve
6631
- // on attempt 1, React retries across its async commit. NEVER read $refs eagerly.
6806
+ // (React setState async; Solid/Lit/Svelte next reactive tick). Poll for the target CELL's
6807
+ // marked built-in editor for ~30 frames — the five fast targets resolve on attempt 1, React
6808
+ // retries across its async commit. NEVER read $refs eagerly.
6632
6809
  // B2: selectAll gates the post-focus el.select(). Select-all is right when entering
6633
6810
  // edit IN PLACE (F2/Enter/click/row-edit/validation-reject — no seeded char, the user
6634
6811
  // retypes), but WRONG on a type-to-edit entry where a printable key already seeded the
6635
6812
  // draft (selecting the seeded char makes the next keystroke replace it: Zeta → eta).
6636
6813
  // beginEdit threads `seed == null` so a seeded entry skips the select and the caret sits
6637
6814
  // AFTER the seeded char; every other caller keeps the default select-all.
6638
- // Editor-owns-focus contract (quick 260711-i5m): REVERTS the g52 shadow-piercing helper
6639
- // (commit 5fa30045) that recursed into descendant shadow roots. Built-in editors are
6640
- // host-DOM — the plain direct query resolves them on all 6 targets (no shadow to cross). A
6641
- // #editor DROP-IN now owns its OWN focus via the reactive `autofocus` prop (EditorText's
6642
- // $onMount + lazy $watch), so the host never needs to reach across a Lit drop-in's nested
6643
- // shadow root at all — see the !hasEditorSlot gate below, which skips the host focus call
6644
- // entirely for a drop-in target.
6645
- focusEditorWhenReady = (selectAll = true) => {
6815
+ // D-01/D-02 (88-07): REPLACES the deleted presence-check early-return gate AND the
6816
+ // gridRoot-wide `[data-editing-cell]` first-match query with a column-scoped, marker-driven
6817
+ // poll. Resolves the TARGET cell first (resolveEditFocusCellEl, mirroring
6818
+ // focusRowEditorAt's already-shipped two-step resolve), then queries for an editor carrying
6819
+ // BOTH `data-editing-cell` and the host-owned `data-builtin-editor` marker WITHIN that one
6820
+ // cell — "no marker found" (a drop-in target, D-01) bails immediately rather than reaching
6821
+ // into DOM the host does not own; "no editor at all yet" keeps polling (the framework hasn't
6822
+ // committed the r-if branch). This closes the D-02 wrong-column hole the old grid-wide query
6823
+ // left open (every editable cell mounts an editor at once in row-edit mode) AND fixes the
6824
+ // React staleness race documented above, as a side effect of no longer reading
6825
+ // $data.editFocusColId anywhere in this function.
6826
+ focusEditorWhenReady = (rowIndex: any, colIndex: any, selectAll = true) => {
6646
6827
  if (!this.gridRoot) return;
6647
- // Editor-owns-focus contract: when the CURRENT focus target is a #editor drop-in, the host
6648
- // does NOT reach into its DOM — the drop-in self-focuses via its own autofocus prop.
6649
- if (this._editFocusColId.value != null && this.hasEditorSlot(this._editFocusColId.value)) return;
6650
6828
  let attempts = 0;
6651
6829
  const tryFocus = () => {
6652
- const el = this.gridRoot ? this.gridRoot.querySelector('[data-editing-cell]') : null;
6830
+ const cellEl = this.resolveEditFocusCellEl(rowIndex, colIndex);
6831
+ const el = cellEl && cellEl.querySelector ? cellEl.querySelector('[data-editing-cell][data-builtin-editor]') : null;
6832
+ if (!el) {
6833
+ // Editor-owns-focus contract (quick 260711-i5m, D-01): if the cell ALREADY holds an
6834
+ // editor that carries only the base marker, it's a consumer drop-in — it owns its own
6835
+ // focus (EditorText's own $onMount + reactive `autofocus`). Bail immediately, zero
6836
+ // wasted frames, rather than burning the retry ceiling on DOM the host does not own.
6837
+ const anyEditor = cellEl && cellEl.querySelector ? cellEl.querySelector('[data-editing-cell]') : null;
6838
+ if (anyEditor) return;
6839
+ attempts = attempts + 1;
6840
+ if (attempts >= 30) return;
6841
+ if (typeof requestAnimationFrame === 'function') requestAnimationFrame(tryFocus);else setTimeout(tryFocus, 16);
6842
+ return;
6843
+ }
6653
6844
  // Do NOT stomp focus a later interaction already placed in a DIFFERENT column's editor of
6654
6845
  // this row: focusEditorWhenReady only needs to get focus INTO the (first) freshly-mounted
6655
6846
  // editor; if focus already sits in another editable cell, a late rAF re-focus would steal it
6656
6847
  // back to the first editor and break row-mode Tab containment (the non-deterministic B21
6657
6848
  // focus-theft). Compare the OWNING cell's data-col-index (NOT node identity) so a stale
6658
6849
  // SAME-column editor node on Solid's node-replacing re-render still resolves as the target —
6659
- // a genuinely dropped focus is still recovered.
6850
+ // a genuinely dropped focus is still recovered. Stays BROAD on `data-editing-cell` (NOT
6851
+ // narrowed to the builtin marker, D-02): focus validly placed inside a drop-in must still
6852
+ // count as "already placed" — narrowing this check would let a late rAF poll steal focus
6853
+ // back from a drop-in that legitimately holds it.
6660
6854
  const ae = this.gridRoot && this.gridRoot.getRootNode ? this.gridRoot.getRootNode().activeElement : null;
6661
6855
  if (ae && el && ae !== el && ae.closest && this.gridRoot.contains(ae) && ae.hasAttribute && ae.hasAttribute('data-editing-cell')) {
6662
6856
  const aeCell = ae.closest('[data-grid-cell]');
@@ -6665,18 +6859,12 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
6665
6859
  const elCol = elCell ? elCell.getAttribute('data-col-index') : null;
6666
6860
  if (aeCol != null && aeCol !== elCol) return;
6667
6861
  }
6668
- if (el) {
6669
- el.focus();
6670
- if (selectAll && el.select) {
6671
- try {
6672
- el.select();
6673
- } catch (e: any) {}
6674
- }
6675
- return;
6862
+ el.focus();
6863
+ if (selectAll && el.select) {
6864
+ try {
6865
+ el.select();
6866
+ } catch (e: any) {}
6676
6867
  }
6677
- attempts = attempts + 1;
6678
- if (attempts >= 30) return;
6679
- if (typeof requestAnimationFrame === 'function') requestAnimationFrame(tryFocus);else setTimeout(tryFocus, 16);
6680
6868
  };
6681
6869
  if (typeof requestAnimationFrame === 'function') requestAnimationFrame(tryFocus);else setTimeout(tryFocus, 0);
6682
6870
  };
@@ -6732,8 +6920,10 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
6732
6920
  // from it. Cleared on endEdit.
6733
6921
  this._editFocusColId.value = colId;
6734
6922
  // B2: a seeded (type-to-edit) entry must NOT select-all — keep the caret after the
6735
- // seeded char so subsequent typing appends instead of replacing it.
6736
- this.focusEditorWhenReady(seed == null);
6923
+ // seeded char so subsequent typing appends instead of replacing it. rowIndex/colIndex
6924
+ // are THIS call's own params — passed through directly (D-02), never re-read off
6925
+ // $data.editingRow/editingCol inside the poll.
6926
+ this.focusEditorWhenReady(rowIndex, colIndex, seed == null);
6737
6927
  };
6738
6928
 
6739
6929
  // Return focus to a body cell AFTER the editor unmounts (commit/cancel). The display↔
@@ -6847,8 +7037,10 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
6847
7037
  const err = this.runValidator(colId, newValue, rowOriginal);
6848
7038
  if (err !== true) {
6849
7039
  // D-01: reject — keep the editor open, announce, re-trap focus, NEVER write the model.
7040
+ // $data.editingRow/editingCol are STABLE here (set by a prior beginEdit call, not this
7041
+ // same tick) — safe to read directly, unlike the deleted $data.editFocusColId gate.
6850
7042
  this.setInvalid(err);
6851
- this.focusEditorWhenReady();
7043
+ this.focusEditorWhenReady(this._editingRow.value, this._editingCol.value);
6852
7044
  return false;
6853
7045
  }
6854
7046
  this.setInvalid('');
@@ -7017,22 +7209,22 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
7017
7209
 
7018
7210
  // B21/B22: focus the row-mode editor at a given VISIBLE col index. In full-row edit every
7019
7211
  // editable cell is already mounted as an editor, so this resolves the cell off gridRoot and
7020
- // focuses its [data-editing-cell] control. Bounded rAF-poll (mirrors focusEditorWhenReady)
7021
- // so a React re-render that recreates the input across the focus call still lands it. select-
7022
- // all on text/number editors (a no-op try/catch on select/checkbox).
7023
- // Editor-owns-focus contract (quick 260711-i5m): when the TARGET column is a #editor
7024
- // drop-in, the host does NOT reach into its DOM (early return, before starting the rAF poll
7025
- // at all) — the drop-in self-focuses via its own reactive `autofocus` prop, which the caller
7026
- // (commitRow's B22 reject path / rowEditTab) already flips via $data.editFocusColId. Built-in
7027
- // columns are unaffected (hasEditorSlot is false for them) — unchanged host direct-focus.
7212
+ // focuses its [data-editing-cell][data-builtin-editor] control. Bounded rAF-poll (mirrors
7213
+ // focusEditorWhenReady) so a React re-render that recreates the input across the focus call
7214
+ // still lands it. select-all on text/number editors (a no-op try/catch on select/checkbox).
7215
+ // D-01/D-02 (88-07): the old columnIdAt + presence-check early-return gate is DELETED — the
7216
+ // host-owned data-builtin-editor marker replaces it. If the resolved cell already holds an
7217
+ // editor carrying ONLY the base data-editing-cell marker (no builtin marker), that's a
7218
+ // consumer drop-in — bail immediately, it owns its own focus (EditorText's own $onMount +
7219
+ // reactive `autofocus`, which the caller already flips via $data.editFocusColId). This
7220
+ // two-step resolve (resolveCellEl THEN a scoped query within that one cell) was ALREADY
7221
+ // column-scoped and correct — it is the shape focusEditorWhenReady's D-02 rework adopts.
7028
7222
  focusRowEditorAt = (rowIndex: any, colIndex: any) => {
7029
7223
  if (!this.gridRoot) return;
7030
- const colId = this.columnIdAt(rowIndex, colIndex);
7031
- if (colId != null && this.hasEditorSlot(colId)) return;
7032
7224
  let attempts = 0;
7033
7225
  const tryFocus = () => {
7034
7226
  const cellEl = this.resolveCellEl(String(rowIndex), colIndex);
7035
- const ed = cellEl && cellEl.querySelector ? cellEl.querySelector('[data-editing-cell]') : null;
7227
+ const ed = cellEl && cellEl.querySelector ? cellEl.querySelector('[data-editing-cell][data-builtin-editor]') : null;
7036
7228
  if (ed) {
7037
7229
  ed.focus();
7038
7230
  if (ed.select) {
@@ -7042,6 +7234,11 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
7042
7234
  }
7043
7235
  return;
7044
7236
  }
7237
+ // No marked built-in editor yet in this cell: a drop-in mounted there owns its own
7238
+ // focus — bail immediately (D-02) rather than burning the retry ceiling on DOM the
7239
+ // host does not own. No editor at all yet just means "keep polling."
7240
+ const any = cellEl && cellEl.querySelector ? cellEl.querySelector('[data-editing-cell]') : null;
7241
+ if (any) return;
7045
7242
  attempts = attempts + 1;
7046
7243
  if (attempts >= 30) return;
7047
7244
  if (typeof requestAnimationFrame === 'function') requestAnimationFrame(tryFocus);else setTimeout(tryFocus, 16);
@@ -7088,9 +7285,11 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
7088
7285
  // Editor-owns-focus contract (quick 260711-i5m): the row's FIRST editable column is the
7089
7286
  // initial focus target — editorAutofocusFor derives the reactive `autofocus` #editor scope
7090
7287
  // prop from it (a built-in column is also host-focused below via focusEditorWhenReady; a
7091
- // drop-in column self-focuses via its own $onMount, gated off the host reach-in in Task 3).
7288
+ // drop-in column self-focuses via its own $onMount, gated off the host reach-in via D-01's
7289
+ // marker). editable[0].colIndex is THIS call's own already-resolved value (D-02) — passed
7290
+ // through directly, never re-read off $data.editFocusColId inside the poll.
7092
7291
  this._editFocusColId.value = editable[0].colId;
7093
- this.focusEditorWhenReady();
7292
+ this.focusEditorWhenReady(rowIndex, editable[0].colIndex);
7094
7293
  };
7095
7294
 
7096
7295
  // commitRow(): validate EVERY edited column (D-01 — keep the row open if ANY fails: set