@rozie-ui/data-table-lit 0.6.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -501,6 +501,8 @@ Beyond props, the component exposes imperative methods (declared once in the Roz
501
501
  | `focusCell` | Move + focus the active cell (grid interaction mode) — `focusCell(rowIndex, colIndex)`. `rowIndex` is the ABSOLUTE display-order position in `getPrePaginationRowModel().rows` (filter+sort+expand applied, BEFORE pagination/windowing), in BOTH paginated and virtual modes: a paginated `focusCell(abs)` switches to `Math.floor(abs/pageSize)` then focuses; a virtual `focusCell(abs)` scrolls-then-focuses. Args coerced to integers + clamped to bounds. Fires `activecell-change` with the absolute `rowIndex`. (Named `focusCell`, not `focus`: a bare `focus` verb shadows the inherited `HTMLElement.focus` on Lit — ROZ137.) |
502
502
  | `getActiveCell` | Return the current active-cell position — `getActiveCell()` → `{ rowIndex, colIndex, isHeader }`. For a body cell `rowIndex` is the ABSOLUTE display-order index (matching `focusCell` / `activecell-change`) and `isHeader` is `false`; for a header-active cell `rowIndex` is `null` and `isHeader` is `true` (integers only — no row data, no DOM node). |
503
503
  | `clearActiveCell` | Reset the roving active-cell position to the entry cell and exit interaction mode — `clearActiveCell()`. The next Tab-in re-enters at the entry cell. (Named `clearActiveCell`, not `clear`: distinct from the listbox `clear` selection verb.) |
504
+ | `scrollToRow` | Scroll a row into view on a `virtual` table — `scrollToRow(index, options?)` where `options` mirrors TanStack virtual-core's own `ScrollToOptions` (`{ align?: 'start'|'center'|'end'|'auto', behavior?: 'auto'|'smooth'|'instant' }`) and is forwarded UNCHANGED to `virtualizer.scrollToIndex`. INDEPENDENT of grid-mode focus: never moves the roving active cell and never fires `activecell-change`, callable in either `interactionMode`. `index` is coerced to an integer (never range-clamped here — virtual-core's own `scrollToIndex` already clamps to `[0, options.count-1]`). A no-op when rows are not windowed (`virtual` off, or `'columns'`-only). |
505
+ | `getScrollElement` | Return the scroll-container DOM node the row and column virtualizer(s) observe — `getScrollElement()` → `HTMLElement | null`. The supported replacement for reaching into the internal `.rdt-scroll` class selector. Returns `null` when nothing is windowed. |
504
506
  | `getRowIndexRelativeToPage` | Convert an ABSOLUTE display-order row index (the `focusCell` / `getActiveCell` / `activecell-change` space) to the PAGE-RELATIVE index — `getRowIndexRelativeToPage(absRow?)` → `number`. With no argument it converts the current active cell (`abs - pageIndex*pageSize`). In virtual mode (no pagination) it returns the absolute index unchanged. Mirrors MUI `getRowIndexRelativeToVisibleRows`. (Named `getRowIndexRelativeToPage`: collision-clean against the verb/event/prop and Lit ROZ137 reserved sets.) |
505
507
  | `editCell` | Programmatically open the editor on a cell — `editCell(rowIndex, colIndex)`, addressed by index over the visible model (args coerced to integers + clamped). No-op on a non-editable cell. (Named `editCell`, not `edit`: collision-clean against the verb/event/prop and Lit ROZ137 reserved sets.) |
506
508
  | `commitEditing` | Programmatically commit the open editor — `commitEditing()`. Runs the column validator; on success writes the two-way `data` model and fires one `cell-edit-commit`; on a validation failure keeps the editor open. No-op when no cell is editing. (Named `commitEditing`, not `commit`.) |
package/dist/index.cjs CHANGED
@@ -1146,6 +1146,11 @@ let DataTable = class DataTable extends (0, _lit_labs_preact_signals.SignalWatch
1146
1146
  composed: true
1147
1147
  }));
1148
1148
  };
1149
+ this.scrollToRow = (index, options) => {
1150
+ if (!this.rowsWindowed() || !this.virtualizer) return;
1151
+ this.virtualizer.scrollToIndex(Math.trunc(Number(index)) || 0, options || void 0);
1152
+ };
1153
+ this.getScrollElement = () => this.gridScrollEl;
1149
1154
  this.virtualItemKey = (i) => {
1150
1155
  const src = this.windowSource();
1151
1156
  return src && src[i] ? src[i].id : void 0;
@@ -4843,6 +4848,18 @@ let DataTable = class DataTable extends (0, _lit_labs_preact_signals.SignalWatch
4843
4848
  queueMicrotask(() => {
4844
4849
  if (this.isConnected || this._rozieTornDown) return;
4845
4850
  this._rozieTornDown = true;
4851
+ (() => {
4852
+ if (this.docPointerDown && typeof document !== "undefined") {
4853
+ document.removeEventListener("pointerdown", this.docPointerDown, true);
4854
+ this.docPointerDown = null;
4855
+ }
4856
+ if (this.virtualizerCleanup) this.virtualizerCleanup();
4857
+ if (this.colVirtualizerCleanup) this.colVirtualizerCleanup();
4858
+ this.teardownColRtlWatch();
4859
+ this.teardownRemeasure();
4860
+ this.teardownFillDrag();
4861
+ this.teardownRangeDrag();
4862
+ })();
4846
4863
  for (const fn of this._disconnectCleanups) fn();
4847
4864
  this._disconnectCleanups = [];
4848
4865
  });
@@ -5885,7 +5902,8 @@ __decorate([(0, lit_decorators_js.property)({
5885
5902
  __decorate([(0, lit_decorators_js.property)({ type: Array })], DataTable.prototype, "columns", void 0);
5886
5903
  __decorate([(0, lit_decorators_js.property)({
5887
5904
  type: String,
5888
- reflect: true
5905
+ reflect: true,
5906
+ attribute: "selection-mode"
5889
5907
  })], DataTable.prototype, "selectionMode", void 0);
5890
5908
  __decorate([(0, lit_decorators_js.property)({
5891
5909
  type: Array,
@@ -5909,11 +5927,13 @@ __decorate([(0, lit_decorators_js.property)({
5909
5927
  })], DataTable.prototype, "manual", void 0);
5910
5928
  __decorate([(0, lit_decorators_js.property)({
5911
5929
  type: Number,
5912
- reflect: true
5930
+ reflect: true,
5931
+ attribute: "row-count"
5913
5932
  })], DataTable.prototype, "rowCount", void 0);
5914
5933
  __decorate([(0, lit_decorators_js.property)({
5915
5934
  type: Number,
5916
- reflect: true
5935
+ reflect: true,
5936
+ attribute: "page-count"
5917
5937
  })], DataTable.prototype, "pageCount", void 0);
5918
5938
  __decorate([(0, lit_decorators_js.property)({
5919
5939
  type: Boolean,
@@ -5923,8 +5943,14 @@ __decorate([(0, lit_decorators_js.property)({
5923
5943
  type: Object,
5924
5944
  attribute: "expanded"
5925
5945
  })], DataTable.prototype, "_expanded_attr", void 0);
5926
- __decorate([(0, lit_decorators_js.property)({ type: Function })], DataTable.prototype, "getRowId", void 0);
5927
- __decorate([(0, lit_decorators_js.property)({ type: Function })], DataTable.prototype, "getSubRows", void 0);
5946
+ __decorate([(0, lit_decorators_js.property)({
5947
+ type: Function,
5948
+ attribute: "get-row-id"
5949
+ })], DataTable.prototype, "getRowId", void 0);
5950
+ __decorate([(0, lit_decorators_js.property)({
5951
+ type: Function,
5952
+ attribute: "get-sub-rows"
5953
+ })], DataTable.prototype, "getSubRows", void 0);
5928
5954
  __decorate([(0, lit_decorators_js.property)({
5929
5955
  type: Boolean,
5930
5956
  reflect: true
@@ -5955,15 +5981,18 @@ __decorate([(0, lit_decorators_js.property)({
5955
5981
  })], DataTable.prototype, "_columnPinning_attr", void 0);
5956
5982
  __decorate([(0, lit_decorators_js.property)({
5957
5983
  type: Boolean,
5958
- reflect: true
5984
+ reflect: true,
5985
+ attribute: "sticky-header"
5959
5986
  })], DataTable.prototype, "stickyHeader", void 0);
5960
5987
  __decorate([(0, lit_decorators_js.property)({
5961
5988
  type: String,
5962
- reflect: true
5989
+ reflect: true,
5990
+ attribute: "interaction-mode"
5963
5991
  })], DataTable.prototype, "interactionMode", void 0);
5964
5992
  __decorate([(0, lit_decorators_js.property)({
5965
5993
  type: Boolean,
5966
- reflect: true
5994
+ reflect: true,
5995
+ attribute: "single-click-edit"
5967
5996
  })], DataTable.prototype, "singleClickEdit", void 0);
5968
5997
  __decorate([(0, lit_decorators_js.property)({
5969
5998
  type: Boolean,
@@ -5971,20 +6000,24 @@ __decorate([(0, lit_decorators_js.property)({
5971
6000
  })], DataTable.prototype, "undoable", void 0);
5972
6001
  __decorate([(0, lit_decorators_js.property)({
5973
6002
  type: Number,
5974
- reflect: true
6003
+ reflect: true,
6004
+ attribute: "undo-limit"
5975
6005
  })], DataTable.prototype, "undoLimit", void 0);
5976
6006
  __decorate([(0, lit_decorators_js.property)({ converter: { fromAttribute: (v) => v === null ? false : v === "true" ? true : v === "false" ? false : v === "" ? true : v } })], DataTable.prototype, "virtual", void 0);
5977
6007
  __decorate([(0, lit_decorators_js.property)({
5978
6008
  type: Number,
5979
- reflect: true
6009
+ reflect: true,
6010
+ attribute: "estimate-row-height"
5980
6011
  })], DataTable.prototype, "estimateRowHeight", void 0);
5981
6012
  __decorate([(0, lit_decorators_js.property)({
5982
6013
  type: Boolean,
5983
- reflect: true
6014
+ reflect: true,
6015
+ attribute: "auto-measure"
5984
6016
  })], DataTable.prototype, "autoMeasure", void 0);
5985
6017
  __decorate([(0, lit_decorators_js.property)({
5986
6018
  type: String,
5987
- reflect: true
6019
+ reflect: true,
6020
+ attribute: "max-height"
5988
6021
  })], DataTable.prototype, "maxHeight", void 0);
5989
6022
  __decorate([(0, lit_decorators_js.query)("[data-rozie-ref=\"__rozieRoot\"]")], DataTable.prototype, "_ref__rozieRoot", void 0);
5990
6023
  __decorate([(0, lit_decorators_js.state)()], DataTable.prototype, "_hasSlotDefault", void 0);
@@ -6174,7 +6207,7 @@ __decorate([(0, lit_decorators_js.property)({
6174
6207
  type: String,
6175
6208
  reflect: true
6176
6209
  })], Column.prototype, "pinned", void 0);
6177
- __decorate([(0, lit_decorators_js.property)({ type: String })], Column.prototype, "width", void 0);
6210
+ __decorate([(0, lit_decorators_js.property)({ converter: { fromAttribute: _rozie_runtime_lit.rozieNumberOrStringAttr } })], Column.prototype, "width", void 0);
6178
6211
  __decorate([(0, lit_decorators_js.property)({
6179
6212
  type: Boolean,
6180
6213
  reflect: true
@@ -6183,7 +6216,10 @@ __decorate([(0, lit_decorators_js.property)({
6183
6216
  type: Boolean,
6184
6217
  reflect: true
6185
6218
  })], Column.prototype, "groupable", void 0);
6186
- __decorate([(0, lit_decorators_js.property)({ type: String })], Column.prototype, "aggregationFn", void 0);
6219
+ __decorate([(0, lit_decorators_js.property)({
6220
+ type: String,
6221
+ attribute: "aggregation-fn"
6222
+ })], Column.prototype, "aggregationFn", void 0);
6187
6223
  __decorate([(0, lit_decorators_js.property)({
6188
6224
  type: Boolean,
6189
6225
  reflect: true
@@ -6192,7 +6228,10 @@ __decorate([(0, lit_decorators_js.property)({
6192
6228
  type: String,
6193
6229
  reflect: true
6194
6230
  })], Column.prototype, "editor", void 0);
6195
- __decorate([(0, lit_decorators_js.property)({ type: Array })], Column.prototype, "editorOptions", void 0);
6231
+ __decorate([(0, lit_decorators_js.property)({
6232
+ type: Array,
6233
+ attribute: "editor-options"
6234
+ })], Column.prototype, "editorOptions", void 0);
6196
6235
  __decorate([(0, lit_decorators_js.property)({ type: Function })], Column.prototype, "validate", void 0);
6197
6236
  Column = __decorate([(0, lit_decorators_js.customElement)("rozie-column")], Column);
6198
6237
  var Column_default = Column;
@@ -6279,7 +6318,8 @@ let EditorText = class EditorText extends (0, _lit_labs_preact_signals.SignalWat
6279
6318
  };
6280
6319
  __decorate([(0, lit_decorators_js.property)({
6281
6320
  type: String,
6282
- reflect: true
6321
+ reflect: true,
6322
+ attribute: "column-id"
6283
6323
  })], EditorText.prototype, "columnId", void 0);
6284
6324
  __decorate([(0, lit_decorators_js.property)({ type: Object })], EditorText.prototype, "column", void 0);
6285
6325
  __decorate([(0, lit_decorators_js.property)({ type: Object })], EditorText.prototype, "row", void 0);
@@ -6292,7 +6332,8 @@ __decorate([(0, lit_decorators_js.property)({
6292
6332
  })], EditorText.prototype, "autofocus", void 0);
6293
6333
  __decorate([(0, lit_decorators_js.property)({
6294
6334
  type: String,
6295
- reflect: true
6335
+ reflect: true,
6336
+ attribute: "column-label"
6296
6337
  })], EditorText.prototype, "columnLabel", void 0);
6297
6338
  __decorate([(0, lit_decorators_js.query)("[data-rozie-ref=\"inputEl\"]")], EditorText.prototype, "_refInputEl", void 0);
6298
6339
  EditorText = __decorate([(0, lit_decorators_js.customElement)("rozie-editor-text")], EditorText);
@@ -6387,7 +6428,8 @@ let EditorNumber = class EditorNumber extends (0, _lit_labs_preact_signals.Signa
6387
6428
  };
6388
6429
  __decorate([(0, lit_decorators_js.property)({
6389
6430
  type: String,
6390
- reflect: true
6431
+ reflect: true,
6432
+ attribute: "column-id"
6391
6433
  })], EditorNumber.prototype, "columnId", void 0);
6392
6434
  __decorate([(0, lit_decorators_js.property)({ type: Object })], EditorNumber.prototype, "column", void 0);
6393
6435
  __decorate([(0, lit_decorators_js.property)({ type: Object })], EditorNumber.prototype, "row", void 0);
@@ -6400,7 +6442,8 @@ __decorate([(0, lit_decorators_js.property)({
6400
6442
  })], EditorNumber.prototype, "autofocus", void 0);
6401
6443
  __decorate([(0, lit_decorators_js.property)({
6402
6444
  type: String,
6403
- reflect: true
6445
+ reflect: true,
6446
+ attribute: "column-label"
6404
6447
  })], EditorNumber.prototype, "columnLabel", void 0);
6405
6448
  __decorate([(0, lit_decorators_js.query)("[data-rozie-ref=\"inputEl\"]")], EditorNumber.prototype, "_refInputEl", void 0);
6406
6449
  EditorNumber = __decorate([(0, lit_decorators_js.customElement)("rozie-editor-number")], EditorNumber);
@@ -6491,7 +6534,8 @@ let EditorSelect = class EditorSelect extends (0, _lit_labs_preact_signals.Signa
6491
6534
  };
6492
6535
  __decorate([(0, lit_decorators_js.property)({
6493
6536
  type: String,
6494
- reflect: true
6537
+ reflect: true,
6538
+ attribute: "column-id"
6495
6539
  })], EditorSelect.prototype, "columnId", void 0);
6496
6540
  __decorate([(0, lit_decorators_js.property)({ type: Object })], EditorSelect.prototype, "column", void 0);
6497
6541
  __decorate([(0, lit_decorators_js.property)({ type: Object })], EditorSelect.prototype, "row", void 0);
@@ -6505,7 +6549,8 @@ __decorate([(0, lit_decorators_js.property)({
6505
6549
  })], EditorSelect.prototype, "autofocus", void 0);
6506
6550
  __decorate([(0, lit_decorators_js.property)({
6507
6551
  type: String,
6508
- reflect: true
6552
+ reflect: true,
6553
+ attribute: "column-label"
6509
6554
  })], EditorSelect.prototype, "columnLabel", void 0);
6510
6555
  __decorate([(0, lit_decorators_js.query)("[data-rozie-ref=\"selectEl\"]")], EditorSelect.prototype, "_refSelectEl", void 0);
6511
6556
  EditorSelect = __decorate([(0, lit_decorators_js.customElement)("rozie-editor-select")], EditorSelect);
@@ -6575,7 +6620,8 @@ let EditorCheckbox = class EditorCheckbox extends (0, _lit_labs_preact_signals.S
6575
6620
  };
6576
6621
  __decorate([(0, lit_decorators_js.property)({
6577
6622
  type: String,
6578
- reflect: true
6623
+ reflect: true,
6624
+ attribute: "column-id"
6579
6625
  })], EditorCheckbox.prototype, "columnId", void 0);
6580
6626
  __decorate([(0, lit_decorators_js.property)({ type: Object })], EditorCheckbox.prototype, "column", void 0);
6581
6627
  __decorate([(0, lit_decorators_js.property)({ type: Object })], EditorCheckbox.prototype, "row", void 0);
@@ -6588,7 +6634,8 @@ __decorate([(0, lit_decorators_js.property)({
6588
6634
  })], EditorCheckbox.prototype, "autofocus", void 0);
6589
6635
  __decorate([(0, lit_decorators_js.property)({
6590
6636
  type: String,
6591
- reflect: true
6637
+ reflect: true,
6638
+ attribute: "column-label"
6592
6639
  })], EditorCheckbox.prototype, "columnLabel", void 0);
6593
6640
  __decorate([(0, lit_decorators_js.query)("[data-rozie-ref=\"inputEl\"]")], EditorCheckbox.prototype, "_refInputEl", void 0);
6594
6641
  EditorCheckbox = __decorate([(0, lit_decorators_js.customElement)("rozie-editor-checkbox")], EditorCheckbox);
@@ -6715,7 +6762,8 @@ let EditorDate = class EditorDate extends (0, _lit_labs_preact_signals.SignalWat
6715
6762
  };
6716
6763
  __decorate([(0, lit_decorators_js.property)({
6717
6764
  type: String,
6718
- reflect: true
6765
+ reflect: true,
6766
+ attribute: "column-id"
6719
6767
  })], EditorDate.prototype, "columnId", void 0);
6720
6768
  __decorate([(0, lit_decorators_js.property)({ type: Object })], EditorDate.prototype, "column", void 0);
6721
6769
  __decorate([(0, lit_decorators_js.property)({ type: Object })], EditorDate.prototype, "row", void 0);
@@ -6728,7 +6776,8 @@ __decorate([(0, lit_decorators_js.property)({
6728
6776
  })], EditorDate.prototype, "autofocus", void 0);
6729
6777
  __decorate([(0, lit_decorators_js.property)({
6730
6778
  type: String,
6731
- reflect: true
6779
+ reflect: true,
6780
+ attribute: "column-label"
6732
6781
  })], EditorDate.prototype, "columnLabel", void 0);
6733
6782
  __decorate([(0, lit_decorators_js.query)("[data-rozie-ref=\"inputEl\"]")], EditorDate.prototype, "_refInputEl", void 0);
6734
6783
  EditorDate = __decorate([(0, lit_decorators_js.customElement)("rozie-editor-date")], EditorDate);
@@ -6813,14 +6862,19 @@ let FilterText = class FilterText extends (0, _lit_labs_preact_signals.SignalWat
6813
6862
  };
6814
6863
  __decorate([(0, lit_decorators_js.property)({
6815
6864
  type: String,
6816
- reflect: true
6865
+ reflect: true,
6866
+ attribute: "column-id"
6817
6867
  })], FilterText.prototype, "columnId", void 0);
6818
6868
  __decorate([(0, lit_decorators_js.property)({ type: Object })], FilterText.prototype, "column", void 0);
6819
6869
  __decorate([(0, lit_decorators_js.property)({ type: Object })], FilterText.prototype, "value", void 0);
6820
- __decorate([(0, lit_decorators_js.property)({ type: Function })], FilterText.prototype, "setFilter", void 0);
6870
+ __decorate([(0, lit_decorators_js.property)({
6871
+ type: Function,
6872
+ attribute: "set-filter"
6873
+ })], FilterText.prototype, "setFilter", void 0);
6821
6874
  __decorate([(0, lit_decorators_js.property)({
6822
6875
  type: String,
6823
- reflect: true
6876
+ reflect: true,
6877
+ attribute: "column-label"
6824
6878
  })], FilterText.prototype, "columnLabel", void 0);
6825
6879
  FilterText = __decorate([(0, lit_decorators_js.customElement)("rozie-filter-text")], FilterText);
6826
6880
  var FilterText_default = FilterText;
@@ -6920,15 +6974,23 @@ let FilterNumberRange = class FilterNumberRange extends (0, _lit_labs_preact_sig
6920
6974
  };
6921
6975
  __decorate([(0, lit_decorators_js.property)({
6922
6976
  type: String,
6923
- reflect: true
6977
+ reflect: true,
6978
+ attribute: "column-id"
6924
6979
  })], FilterNumberRange.prototype, "columnId", void 0);
6925
6980
  __decorate([(0, lit_decorators_js.property)({ type: Object })], FilterNumberRange.prototype, "column", void 0);
6926
6981
  __decorate([(0, lit_decorators_js.property)({ type: Object })], FilterNumberRange.prototype, "value", void 0);
6927
- __decorate([(0, lit_decorators_js.property)({ type: Function })], FilterNumberRange.prototype, "setFilter", void 0);
6928
- __decorate([(0, lit_decorators_js.property)({ type: Object })], FilterNumberRange.prototype, "minMax", void 0);
6982
+ __decorate([(0, lit_decorators_js.property)({
6983
+ type: Function,
6984
+ attribute: "set-filter"
6985
+ })], FilterNumberRange.prototype, "setFilter", void 0);
6986
+ __decorate([(0, lit_decorators_js.property)({
6987
+ type: Object,
6988
+ attribute: "min-max"
6989
+ })], FilterNumberRange.prototype, "minMax", void 0);
6929
6990
  __decorate([(0, lit_decorators_js.property)({
6930
6991
  type: String,
6931
- reflect: true
6992
+ reflect: true,
6993
+ attribute: "column-label"
6932
6994
  })], FilterNumberRange.prototype, "columnLabel", void 0);
6933
6995
  FilterNumberRange = __decorate([(0, lit_decorators_js.customElement)("rozie-filter-number-range")], FilterNumberRange);
6934
6996
  var FilterNumberRange_default = FilterNumberRange;
@@ -6983,15 +7045,23 @@ let FilterSelect = class FilterSelect extends (0, _lit_labs_preact_signals.Signa
6983
7045
  };
6984
7046
  __decorate([(0, lit_decorators_js.property)({
6985
7047
  type: String,
6986
- reflect: true
7048
+ reflect: true,
7049
+ attribute: "column-id"
6987
7050
  })], FilterSelect.prototype, "columnId", void 0);
6988
7051
  __decorate([(0, lit_decorators_js.property)({ type: Object })], FilterSelect.prototype, "column", void 0);
6989
7052
  __decorate([(0, lit_decorators_js.property)({ type: Object })], FilterSelect.prototype, "value", void 0);
6990
- __decorate([(0, lit_decorators_js.property)({ type: Function })], FilterSelect.prototype, "setFilter", void 0);
6991
- __decorate([(0, lit_decorators_js.property)({ type: Array })], FilterSelect.prototype, "uniqueValues", void 0);
7053
+ __decorate([(0, lit_decorators_js.property)({
7054
+ type: Function,
7055
+ attribute: "set-filter"
7056
+ })], FilterSelect.prototype, "setFilter", void 0);
7057
+ __decorate([(0, lit_decorators_js.property)({
7058
+ type: Array,
7059
+ attribute: "unique-values"
7060
+ })], FilterSelect.prototype, "uniqueValues", void 0);
6992
7061
  __decorate([(0, lit_decorators_js.property)({
6993
7062
  type: String,
6994
- reflect: true
7063
+ reflect: true,
7064
+ attribute: "column-label"
6995
7065
  })], FilterSelect.prototype, "columnLabel", void 0);
6996
7066
  FilterSelect = __decorate([(0, lit_decorators_js.customElement)("rozie-filter-select")], FilterSelect);
6997
7067
  var FilterSelect_default = FilterSelect;
@@ -7246,9 +7316,18 @@ let GroupBar = class GroupBar extends (0, _lit_labs_preact_signals.SignalWatcher
7246
7316
  }
7247
7317
  };
7248
7318
  __decorate([(0, lit_decorators_js.property)({ type: Array })], GroupBar.prototype, "grouping", void 0);
7249
- __decorate([(0, lit_decorators_js.property)({ type: Array })], GroupBar.prototype, "groupableColumns", void 0);
7250
- __decorate([(0, lit_decorators_js.property)({ type: Function })], GroupBar.prototype, "applyGrouping", void 0);
7251
- __decorate([(0, lit_decorators_js.property)({ type: Function })], GroupBar.prototype, "clearGrouping", void 0);
7319
+ __decorate([(0, lit_decorators_js.property)({
7320
+ type: Array,
7321
+ attribute: "groupable-columns"
7322
+ })], GroupBar.prototype, "groupableColumns", void 0);
7323
+ __decorate([(0, lit_decorators_js.property)({
7324
+ type: Function,
7325
+ attribute: "apply-grouping"
7326
+ })], GroupBar.prototype, "applyGrouping", void 0);
7327
+ __decorate([(0, lit_decorators_js.property)({
7328
+ type: Function,
7329
+ attribute: "clear-grouping"
7330
+ })], GroupBar.prototype, "clearGrouping", void 0);
7252
7331
  GroupBar = __decorate([(0, lit_decorators_js.customElement)("rozie-group-bar")], GroupBar);
7253
7332
  var GroupBar_default = GroupBar;
7254
7333
  //#endregion
package/dist/index.d.cts CHANGED
@@ -447,6 +447,11 @@ declare class DataTable extends DataTable_base {
447
447
  lastRangeStart: number;
448
448
  lastRangeEnd: number;
449
449
  emitVisibleRangeIfChanged: () => void;
450
+ scrollToRow: (index: any, options?: {
451
+ align?: "start" | "center" | "end" | "auto";
452
+ behavior?: "auto" | "smooth" | "instant";
453
+ }) => void;
454
+ getScrollElement: () => any;
450
455
  virtualItemKey: (i: any) => any;
451
456
  COL_OVERSCAN: number;
452
457
  colRtlObserver: any;
package/dist/index.d.mts CHANGED
@@ -447,6 +447,11 @@ declare class DataTable extends DataTable_base {
447
447
  lastRangeStart: number;
448
448
  lastRangeEnd: number;
449
449
  emitVisibleRangeIfChanged: () => void;
450
+ scrollToRow: (index: any, options?: {
451
+ align?: "start" | "center" | "end" | "auto";
452
+ behavior?: "auto" | "smooth" | "instant";
453
+ }) => void;
454
+ getScrollElement: () => any;
450
455
  virtualItemKey: (i: any) => any;
451
456
  COL_OVERSCAN: number;
452
457
  colRtlObserver: any;
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { LitElement, css, html, nothing } from "lit";
2
2
  import { customElement, property, query, queryAssignedElements, state } from "lit/decorators.js";
3
3
  import { SignalWatcher, effect, signal, untracked } from "@lit-labs/preact-signals";
4
- import { RozieSlotDistributor, createLitControllableProperty, rozieAttr, rozieDisplay, rozieStyle } from "@rozie/runtime-lit";
4
+ import { RozieSlotDistributor, createLitControllableProperty, rozieAttr, rozieDisplay, rozieNumberOrStringAttr, rozieStyle } from "@rozie/runtime-lit";
5
5
  import { ContextConsumer, ContextProvider, createContext } from "@lit/context";
6
6
  import { repeat } from "lit/directives/repeat.js";
7
7
  import "@rozie-ui/popover-lit";
@@ -1142,6 +1142,11 @@ let DataTable = class DataTable extends SignalWatcher(LitElement) {
1142
1142
  composed: true
1143
1143
  }));
1144
1144
  };
1145
+ this.scrollToRow = (index, options) => {
1146
+ if (!this.rowsWindowed() || !this.virtualizer) return;
1147
+ this.virtualizer.scrollToIndex(Math.trunc(Number(index)) || 0, options || void 0);
1148
+ };
1149
+ this.getScrollElement = () => this.gridScrollEl;
1145
1150
  this.virtualItemKey = (i) => {
1146
1151
  const src = this.windowSource();
1147
1152
  return src && src[i] ? src[i].id : void 0;
@@ -4839,6 +4844,18 @@ let DataTable = class DataTable extends SignalWatcher(LitElement) {
4839
4844
  queueMicrotask(() => {
4840
4845
  if (this.isConnected || this._rozieTornDown) return;
4841
4846
  this._rozieTornDown = true;
4847
+ (() => {
4848
+ if (this.docPointerDown && typeof document !== "undefined") {
4849
+ document.removeEventListener("pointerdown", this.docPointerDown, true);
4850
+ this.docPointerDown = null;
4851
+ }
4852
+ if (this.virtualizerCleanup) this.virtualizerCleanup();
4853
+ if (this.colVirtualizerCleanup) this.colVirtualizerCleanup();
4854
+ this.teardownColRtlWatch();
4855
+ this.teardownRemeasure();
4856
+ this.teardownFillDrag();
4857
+ this.teardownRangeDrag();
4858
+ })();
4842
4859
  for (const fn of this._disconnectCleanups) fn();
4843
4860
  this._disconnectCleanups = [];
4844
4861
  });
@@ -5881,7 +5898,8 @@ __decorate([property({
5881
5898
  __decorate([property({ type: Array })], DataTable.prototype, "columns", void 0);
5882
5899
  __decorate([property({
5883
5900
  type: String,
5884
- reflect: true
5901
+ reflect: true,
5902
+ attribute: "selection-mode"
5885
5903
  })], DataTable.prototype, "selectionMode", void 0);
5886
5904
  __decorate([property({
5887
5905
  type: Array,
@@ -5905,11 +5923,13 @@ __decorate([property({
5905
5923
  })], DataTable.prototype, "manual", void 0);
5906
5924
  __decorate([property({
5907
5925
  type: Number,
5908
- reflect: true
5926
+ reflect: true,
5927
+ attribute: "row-count"
5909
5928
  })], DataTable.prototype, "rowCount", void 0);
5910
5929
  __decorate([property({
5911
5930
  type: Number,
5912
- reflect: true
5931
+ reflect: true,
5932
+ attribute: "page-count"
5913
5933
  })], DataTable.prototype, "pageCount", void 0);
5914
5934
  __decorate([property({
5915
5935
  type: Boolean,
@@ -5919,8 +5939,14 @@ __decorate([property({
5919
5939
  type: Object,
5920
5940
  attribute: "expanded"
5921
5941
  })], DataTable.prototype, "_expanded_attr", void 0);
5922
- __decorate([property({ type: Function })], DataTable.prototype, "getRowId", void 0);
5923
- __decorate([property({ type: Function })], DataTable.prototype, "getSubRows", void 0);
5942
+ __decorate([property({
5943
+ type: Function,
5944
+ attribute: "get-row-id"
5945
+ })], DataTable.prototype, "getRowId", void 0);
5946
+ __decorate([property({
5947
+ type: Function,
5948
+ attribute: "get-sub-rows"
5949
+ })], DataTable.prototype, "getSubRows", void 0);
5924
5950
  __decorate([property({
5925
5951
  type: Boolean,
5926
5952
  reflect: true
@@ -5951,15 +5977,18 @@ __decorate([property({
5951
5977
  })], DataTable.prototype, "_columnPinning_attr", void 0);
5952
5978
  __decorate([property({
5953
5979
  type: Boolean,
5954
- reflect: true
5980
+ reflect: true,
5981
+ attribute: "sticky-header"
5955
5982
  })], DataTable.prototype, "stickyHeader", void 0);
5956
5983
  __decorate([property({
5957
5984
  type: String,
5958
- reflect: true
5985
+ reflect: true,
5986
+ attribute: "interaction-mode"
5959
5987
  })], DataTable.prototype, "interactionMode", void 0);
5960
5988
  __decorate([property({
5961
5989
  type: Boolean,
5962
- reflect: true
5990
+ reflect: true,
5991
+ attribute: "single-click-edit"
5963
5992
  })], DataTable.prototype, "singleClickEdit", void 0);
5964
5993
  __decorate([property({
5965
5994
  type: Boolean,
@@ -5967,20 +5996,24 @@ __decorate([property({
5967
5996
  })], DataTable.prototype, "undoable", void 0);
5968
5997
  __decorate([property({
5969
5998
  type: Number,
5970
- reflect: true
5999
+ reflect: true,
6000
+ attribute: "undo-limit"
5971
6001
  })], DataTable.prototype, "undoLimit", void 0);
5972
6002
  __decorate([property({ converter: { fromAttribute: (v) => v === null ? false : v === "true" ? true : v === "false" ? false : v === "" ? true : v } })], DataTable.prototype, "virtual", void 0);
5973
6003
  __decorate([property({
5974
6004
  type: Number,
5975
- reflect: true
6005
+ reflect: true,
6006
+ attribute: "estimate-row-height"
5976
6007
  })], DataTable.prototype, "estimateRowHeight", void 0);
5977
6008
  __decorate([property({
5978
6009
  type: Boolean,
5979
- reflect: true
6010
+ reflect: true,
6011
+ attribute: "auto-measure"
5980
6012
  })], DataTable.prototype, "autoMeasure", void 0);
5981
6013
  __decorate([property({
5982
6014
  type: String,
5983
- reflect: true
6015
+ reflect: true,
6016
+ attribute: "max-height"
5984
6017
  })], DataTable.prototype, "maxHeight", void 0);
5985
6018
  __decorate([query("[data-rozie-ref=\"__rozieRoot\"]")], DataTable.prototype, "_ref__rozieRoot", void 0);
5986
6019
  __decorate([state()], DataTable.prototype, "_hasSlotDefault", void 0);
@@ -6170,7 +6203,7 @@ __decorate([property({
6170
6203
  type: String,
6171
6204
  reflect: true
6172
6205
  })], Column.prototype, "pinned", void 0);
6173
- __decorate([property({ type: String })], Column.prototype, "width", void 0);
6206
+ __decorate([property({ converter: { fromAttribute: rozieNumberOrStringAttr } })], Column.prototype, "width", void 0);
6174
6207
  __decorate([property({
6175
6208
  type: Boolean,
6176
6209
  reflect: true
@@ -6179,7 +6212,10 @@ __decorate([property({
6179
6212
  type: Boolean,
6180
6213
  reflect: true
6181
6214
  })], Column.prototype, "groupable", void 0);
6182
- __decorate([property({ type: String })], Column.prototype, "aggregationFn", void 0);
6215
+ __decorate([property({
6216
+ type: String,
6217
+ attribute: "aggregation-fn"
6218
+ })], Column.prototype, "aggregationFn", void 0);
6183
6219
  __decorate([property({
6184
6220
  type: Boolean,
6185
6221
  reflect: true
@@ -6188,7 +6224,10 @@ __decorate([property({
6188
6224
  type: String,
6189
6225
  reflect: true
6190
6226
  })], Column.prototype, "editor", void 0);
6191
- __decorate([property({ type: Array })], Column.prototype, "editorOptions", void 0);
6227
+ __decorate([property({
6228
+ type: Array,
6229
+ attribute: "editor-options"
6230
+ })], Column.prototype, "editorOptions", void 0);
6192
6231
  __decorate([property({ type: Function })], Column.prototype, "validate", void 0);
6193
6232
  Column = __decorate([customElement("rozie-column")], Column);
6194
6233
  var Column_default = Column;
@@ -6275,7 +6314,8 @@ let EditorText = class EditorText extends SignalWatcher(LitElement) {
6275
6314
  };
6276
6315
  __decorate([property({
6277
6316
  type: String,
6278
- reflect: true
6317
+ reflect: true,
6318
+ attribute: "column-id"
6279
6319
  })], EditorText.prototype, "columnId", void 0);
6280
6320
  __decorate([property({ type: Object })], EditorText.prototype, "column", void 0);
6281
6321
  __decorate([property({ type: Object })], EditorText.prototype, "row", void 0);
@@ -6288,7 +6328,8 @@ __decorate([property({
6288
6328
  })], EditorText.prototype, "autofocus", void 0);
6289
6329
  __decorate([property({
6290
6330
  type: String,
6291
- reflect: true
6331
+ reflect: true,
6332
+ attribute: "column-label"
6292
6333
  })], EditorText.prototype, "columnLabel", void 0);
6293
6334
  __decorate([query("[data-rozie-ref=\"inputEl\"]")], EditorText.prototype, "_refInputEl", void 0);
6294
6335
  EditorText = __decorate([customElement("rozie-editor-text")], EditorText);
@@ -6383,7 +6424,8 @@ let EditorNumber = class EditorNumber extends SignalWatcher(LitElement) {
6383
6424
  };
6384
6425
  __decorate([property({
6385
6426
  type: String,
6386
- reflect: true
6427
+ reflect: true,
6428
+ attribute: "column-id"
6387
6429
  })], EditorNumber.prototype, "columnId", void 0);
6388
6430
  __decorate([property({ type: Object })], EditorNumber.prototype, "column", void 0);
6389
6431
  __decorate([property({ type: Object })], EditorNumber.prototype, "row", void 0);
@@ -6396,7 +6438,8 @@ __decorate([property({
6396
6438
  })], EditorNumber.prototype, "autofocus", void 0);
6397
6439
  __decorate([property({
6398
6440
  type: String,
6399
- reflect: true
6441
+ reflect: true,
6442
+ attribute: "column-label"
6400
6443
  })], EditorNumber.prototype, "columnLabel", void 0);
6401
6444
  __decorate([query("[data-rozie-ref=\"inputEl\"]")], EditorNumber.prototype, "_refInputEl", void 0);
6402
6445
  EditorNumber = __decorate([customElement("rozie-editor-number")], EditorNumber);
@@ -6487,7 +6530,8 @@ let EditorSelect = class EditorSelect extends SignalWatcher(LitElement) {
6487
6530
  };
6488
6531
  __decorate([property({
6489
6532
  type: String,
6490
- reflect: true
6533
+ reflect: true,
6534
+ attribute: "column-id"
6491
6535
  })], EditorSelect.prototype, "columnId", void 0);
6492
6536
  __decorate([property({ type: Object })], EditorSelect.prototype, "column", void 0);
6493
6537
  __decorate([property({ type: Object })], EditorSelect.prototype, "row", void 0);
@@ -6501,7 +6545,8 @@ __decorate([property({
6501
6545
  })], EditorSelect.prototype, "autofocus", void 0);
6502
6546
  __decorate([property({
6503
6547
  type: String,
6504
- reflect: true
6548
+ reflect: true,
6549
+ attribute: "column-label"
6505
6550
  })], EditorSelect.prototype, "columnLabel", void 0);
6506
6551
  __decorate([query("[data-rozie-ref=\"selectEl\"]")], EditorSelect.prototype, "_refSelectEl", void 0);
6507
6552
  EditorSelect = __decorate([customElement("rozie-editor-select")], EditorSelect);
@@ -6571,7 +6616,8 @@ let EditorCheckbox = class EditorCheckbox extends SignalWatcher(LitElement) {
6571
6616
  };
6572
6617
  __decorate([property({
6573
6618
  type: String,
6574
- reflect: true
6619
+ reflect: true,
6620
+ attribute: "column-id"
6575
6621
  })], EditorCheckbox.prototype, "columnId", void 0);
6576
6622
  __decorate([property({ type: Object })], EditorCheckbox.prototype, "column", void 0);
6577
6623
  __decorate([property({ type: Object })], EditorCheckbox.prototype, "row", void 0);
@@ -6584,7 +6630,8 @@ __decorate([property({
6584
6630
  })], EditorCheckbox.prototype, "autofocus", void 0);
6585
6631
  __decorate([property({
6586
6632
  type: String,
6587
- reflect: true
6633
+ reflect: true,
6634
+ attribute: "column-label"
6588
6635
  })], EditorCheckbox.prototype, "columnLabel", void 0);
6589
6636
  __decorate([query("[data-rozie-ref=\"inputEl\"]")], EditorCheckbox.prototype, "_refInputEl", void 0);
6590
6637
  EditorCheckbox = __decorate([customElement("rozie-editor-checkbox")], EditorCheckbox);
@@ -6711,7 +6758,8 @@ let EditorDate = class EditorDate extends SignalWatcher(LitElement) {
6711
6758
  };
6712
6759
  __decorate([property({
6713
6760
  type: String,
6714
- reflect: true
6761
+ reflect: true,
6762
+ attribute: "column-id"
6715
6763
  })], EditorDate.prototype, "columnId", void 0);
6716
6764
  __decorate([property({ type: Object })], EditorDate.prototype, "column", void 0);
6717
6765
  __decorate([property({ type: Object })], EditorDate.prototype, "row", void 0);
@@ -6724,7 +6772,8 @@ __decorate([property({
6724
6772
  })], EditorDate.prototype, "autofocus", void 0);
6725
6773
  __decorate([property({
6726
6774
  type: String,
6727
- reflect: true
6775
+ reflect: true,
6776
+ attribute: "column-label"
6728
6777
  })], EditorDate.prototype, "columnLabel", void 0);
6729
6778
  __decorate([query("[data-rozie-ref=\"inputEl\"]")], EditorDate.prototype, "_refInputEl", void 0);
6730
6779
  EditorDate = __decorate([customElement("rozie-editor-date")], EditorDate);
@@ -6809,14 +6858,19 @@ let FilterText = class FilterText extends SignalWatcher(LitElement) {
6809
6858
  };
6810
6859
  __decorate([property({
6811
6860
  type: String,
6812
- reflect: true
6861
+ reflect: true,
6862
+ attribute: "column-id"
6813
6863
  })], FilterText.prototype, "columnId", void 0);
6814
6864
  __decorate([property({ type: Object })], FilterText.prototype, "column", void 0);
6815
6865
  __decorate([property({ type: Object })], FilterText.prototype, "value", void 0);
6816
- __decorate([property({ type: Function })], FilterText.prototype, "setFilter", void 0);
6866
+ __decorate([property({
6867
+ type: Function,
6868
+ attribute: "set-filter"
6869
+ })], FilterText.prototype, "setFilter", void 0);
6817
6870
  __decorate([property({
6818
6871
  type: String,
6819
- reflect: true
6872
+ reflect: true,
6873
+ attribute: "column-label"
6820
6874
  })], FilterText.prototype, "columnLabel", void 0);
6821
6875
  FilterText = __decorate([customElement("rozie-filter-text")], FilterText);
6822
6876
  var FilterText_default = FilterText;
@@ -6916,15 +6970,23 @@ let FilterNumberRange = class FilterNumberRange extends SignalWatcher(LitElement
6916
6970
  };
6917
6971
  __decorate([property({
6918
6972
  type: String,
6919
- reflect: true
6973
+ reflect: true,
6974
+ attribute: "column-id"
6920
6975
  })], FilterNumberRange.prototype, "columnId", void 0);
6921
6976
  __decorate([property({ type: Object })], FilterNumberRange.prototype, "column", void 0);
6922
6977
  __decorate([property({ type: Object })], FilterNumberRange.prototype, "value", void 0);
6923
- __decorate([property({ type: Function })], FilterNumberRange.prototype, "setFilter", void 0);
6924
- __decorate([property({ type: Object })], FilterNumberRange.prototype, "minMax", void 0);
6978
+ __decorate([property({
6979
+ type: Function,
6980
+ attribute: "set-filter"
6981
+ })], FilterNumberRange.prototype, "setFilter", void 0);
6982
+ __decorate([property({
6983
+ type: Object,
6984
+ attribute: "min-max"
6985
+ })], FilterNumberRange.prototype, "minMax", void 0);
6925
6986
  __decorate([property({
6926
6987
  type: String,
6927
- reflect: true
6988
+ reflect: true,
6989
+ attribute: "column-label"
6928
6990
  })], FilterNumberRange.prototype, "columnLabel", void 0);
6929
6991
  FilterNumberRange = __decorate([customElement("rozie-filter-number-range")], FilterNumberRange);
6930
6992
  var FilterNumberRange_default = FilterNumberRange;
@@ -6979,15 +7041,23 @@ let FilterSelect = class FilterSelect extends SignalWatcher(LitElement) {
6979
7041
  };
6980
7042
  __decorate([property({
6981
7043
  type: String,
6982
- reflect: true
7044
+ reflect: true,
7045
+ attribute: "column-id"
6983
7046
  })], FilterSelect.prototype, "columnId", void 0);
6984
7047
  __decorate([property({ type: Object })], FilterSelect.prototype, "column", void 0);
6985
7048
  __decorate([property({ type: Object })], FilterSelect.prototype, "value", void 0);
6986
- __decorate([property({ type: Function })], FilterSelect.prototype, "setFilter", void 0);
6987
- __decorate([property({ type: Array })], FilterSelect.prototype, "uniqueValues", void 0);
7049
+ __decorate([property({
7050
+ type: Function,
7051
+ attribute: "set-filter"
7052
+ })], FilterSelect.prototype, "setFilter", void 0);
7053
+ __decorate([property({
7054
+ type: Array,
7055
+ attribute: "unique-values"
7056
+ })], FilterSelect.prototype, "uniqueValues", void 0);
6988
7057
  __decorate([property({
6989
7058
  type: String,
6990
- reflect: true
7059
+ reflect: true,
7060
+ attribute: "column-label"
6991
7061
  })], FilterSelect.prototype, "columnLabel", void 0);
6992
7062
  FilterSelect = __decorate([customElement("rozie-filter-select")], FilterSelect);
6993
7063
  var FilterSelect_default = FilterSelect;
@@ -7242,9 +7312,18 @@ let GroupBar = class GroupBar extends SignalWatcher(LitElement) {
7242
7312
  }
7243
7313
  };
7244
7314
  __decorate([property({ type: Array })], GroupBar.prototype, "grouping", void 0);
7245
- __decorate([property({ type: Array })], GroupBar.prototype, "groupableColumns", void 0);
7246
- __decorate([property({ type: Function })], GroupBar.prototype, "applyGrouping", void 0);
7247
- __decorate([property({ type: Function })], GroupBar.prototype, "clearGrouping", void 0);
7315
+ __decorate([property({
7316
+ type: Array,
7317
+ attribute: "groupable-columns"
7318
+ })], GroupBar.prototype, "groupableColumns", void 0);
7319
+ __decorate([property({
7320
+ type: Function,
7321
+ attribute: "apply-grouping"
7322
+ })], GroupBar.prototype, "applyGrouping", void 0);
7323
+ __decorate([property({
7324
+ type: Function,
7325
+ attribute: "clear-grouping"
7326
+ })], GroupBar.prototype, "clearGrouping", void 0);
7248
7327
  GroupBar = __decorate([customElement("rozie-group-bar")], GroupBar);
7249
7328
  var GroupBar_default = GroupBar;
7250
7329
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rozie-ui/data-table-lit",
3
- "version": "0.6.0",
3
+ "version": "0.7.1",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "license": "MIT",
@@ -45,7 +45,7 @@
45
45
  "src"
46
46
  ],
47
47
  "dependencies": {
48
- "@rozie/runtime-lit": "^0.7.5"
48
+ "@rozie/runtime-lit": "^0.8.0"
49
49
  },
50
50
  "peerDependencies": {
51
51
  "lit": "^3.2",
@@ -54,7 +54,7 @@
54
54
  "@preact/signals-core": "^1.3.0",
55
55
  "@tanstack/table-core": "^8.21",
56
56
  "@tanstack/virtual-core": "^3",
57
- "@rozie-ui/popover-lit": "^0.1.0 || ^0.2.0"
57
+ "@rozie-ui/popover-lit": "^0.1.0 || ^0.2.0 || ^0.3.0"
58
58
  },
59
59
  "peerDependenciesMeta": {
60
60
  "lit": {
package/src/Column.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { LitElement, css, html } from 'lit';
2
2
  import { customElement, property } from 'lit/decorators.js';
3
3
  import { SignalWatcher } from '@lit-labs/preact-signals';
4
+ import { rozieNumberOrStringAttr } from '@rozie/runtime-lit';
4
5
  import { ContextConsumer, createContext } from '@lit/context';
5
6
 
6
7
  const __rozieCtx_data_table_columns = createContext(Symbol.for("rozie:data-table:columns"));
@@ -40,7 +41,7 @@ export default class Column extends SignalWatcher(LitElement) {
40
41
  /**
41
42
  * Optional fixed/initial column width, applied as the column's starting size — a px number (`120`) or a px string (`'120px'`). Column sizing is numeric px, so other CSS lengths (`'12rem'`, `'20%'`, `'auto'`) have no px value to apply and are ignored; the column keeps the default width. An interactive resize overrides this.
42
43
  */
43
- @property({ type: String }) width: string | number = '';
44
+ @property({ converter: { fromAttribute: rozieNumberOrStringAttr } }) width: string | number = '';
44
45
  /**
45
46
  * Reserved per-column metadata flagging participation in the expand affordance. The expander chevron is its own auto-injected leading column on `<DataTable expandable>`, so this is forward-compat metadata, not the toggle host. Default `false`.
46
47
  */
@@ -52,7 +53,7 @@ export default class Column extends SignalWatcher(LitElement) {
52
53
  /**
53
54
  * The table-core aggregation for this column inside a group-header cell. Either a built-in name string — `'sum'` | `'min'` | `'max'` | `'extent'` | `'mean'` | `'median'` | `'unique'` | `'uniqueCount'` | `'count'` — or a custom function `(columnId, leafRows, childRows) => any` (defensively wrapped by the parent so a throw cannot crash grouping). Null → no aggregation (the group-header cell renders as a placeholder).
54
55
  */
55
- @property({ type: String }) aggregationFn: string | (((...args: any[]) => any) | null) = null;
56
+ @property({ type: String, attribute: 'aggregation-fn' }) aggregationFn: string | (((...args: any[]) => any) | null) = null;
56
57
  /**
57
58
  * Whether this column's cells are editable (opt-in). Default `false` → the column is read-only and the display↔editor branch never mounts an editor. Bind `:editable="true"` (a bare attr only coerces on Vue+Lit).
58
59
  */
@@ -64,7 +65,7 @@ export default class Column extends SignalWatcher(LitElement) {
64
65
  /**
65
66
  * Options for `editor: 'select'` — `[{ value, label }]`. Empty for other editor types.
66
67
  */
67
- @property({ type: Array }) editorOptions: any[] = [];
68
+ @property({ type: Array, attribute: 'editor-options' }) editorOptions: any[] = [];
68
69
  /**
69
70
  * Synchronous per-column validator `(value, row) => true | string`. A string return is the error message (the editor stays open and the aria-live region announces it). Null → no validation. The parent wraps it defensively against a thrown/non-bool/non-string return.
70
71
  */
package/src/DataTable.ts CHANGED
@@ -585,7 +585,7 @@ export default class DataTable extends SignalWatcher(LitElement) {
585
585
  /**
586
586
  * Row-selection mode: `'none'` | `'single'` | `'multiple'`. `'multiple'` auto-injects a leading checkbox column with a select-all header.
587
587
  */
588
- @property({ type: String, reflect: true }) selectionMode: string = 'none';
588
+ @property({ type: String, reflect: true, attribute: 'selection-mode' }) selectionMode: string = 'none';
589
589
  /**
590
590
  * `SortingState` — `[{ id, desc }]`. Uncontrolled fallback when unbound. Two-way: writes funnel a fresh value through the `sort-change` event regardless of binding.
591
591
  */
@@ -619,11 +619,11 @@ export default class DataTable extends SignalWatcher(LitElement) {
619
619
  /**
620
620
  * Total server-side row count for `manual` pagination; lets the table compute page count when it doesn't hold the full dataset.
621
621
  */
622
- @property({ type: Number, reflect: true }) rowCount: number | null = null;
622
+ @property({ type: Number, reflect: true, attribute: 'row-count' }) rowCount: number | null = null;
623
623
  /**
624
624
  * Explicit total page count for `manual` pagination; overrides rowCount-derived count.
625
625
  */
626
- @property({ type: Number, reflect: true }) pageCount: number | null = null;
626
+ @property({ type: Number, reflect: true, attribute: 'page-count' }) pageCount: number | null = null;
627
627
  /**
628
628
  * Opt-in **expandable rows**. When `true`, a leading chevron expander column auto-injects (after the select column) and `getExpandedRowModel` activates; default `false` is byte-identical-off. Every row can expand to reveal a `#detail` panel unless `getSubRows` is supplied (then only rows with children expand). Pass `expandable` as a real boolean — a valueless attribute only coerces to `true` on Vue and Lit.
629
629
  */
@@ -636,11 +636,11 @@ export default class DataTable extends SignalWatcher(LitElement) {
636
636
  /**
637
637
  * Row identity `(originalRow, index, parentRow?) => string | number` — the key `rowSelection`, `expanded` and the per-row caches use. Default null → table-core keys rows by position (`"0"`, `"1"`, … and `"0.1"` for sub-rows), so inserting or removing rows above a selected or expanded row moves that state onto whatever row now sits at its index. Supply it whenever rows can be added or removed while state is held (server push, live lists); the result is coerced to a string.
638
638
  */
639
- @property({ type: Function }) getRowId: ((...args: any[]) => any) | null = null;
639
+ @property({ type: Function, attribute: 'get-row-id' }) getRowId: ((...args: any[]) => any) | null = null;
640
640
  /**
641
641
  * Table-level child-row accessor `(originalRow, index) => TData[] | undefined` that drives nested sub-rows. When supplied (with `expandable`), table-core flattens the hierarchy and the expand seam reveals depth-indented child rows. Null → the `#detail` scoped slot is the expand mode.
642
642
  */
643
- @property({ type: Function }) getSubRows: ((...args: any[]) => any) | null = null;
643
+ @property({ type: Function, attribute: 'get-sub-rows' }) getSubRows: ((...args: any[]) => any) | null = null;
644
644
  /**
645
645
  * Opt-in gate for the **headless `#groupBar`** host region. Default `false` is byte-identical-off. `getGroupedRowModel` is wired unconditionally (inert when `grouping` is empty), so grouping is driven by the `grouping` model; this flag only gates the consumer-facing group-bar surface (the component ships **no** built-in drag UI).
646
646
  */
@@ -684,15 +684,15 @@ export default class DataTable extends SignalWatcher(LitElement) {
684
684
  /**
685
685
  * Pure-CSS sticky header: the `<thead>` sticks to the top of the scroll container.
686
686
  */
687
- @property({ type: Boolean, reflect: true }) stickyHeader: boolean = false;
687
+ @property({ type: Boolean, reflect: true, attribute: 'sticky-header' }) stickyHeader: boolean = false;
688
688
  /**
689
689
  * `'table'` (default, row-oriented, byte-behaviorally identical to a plain accessible table) | `'grid'` — lights up the full WAI-ARIA **[grid interaction mode](/components/data-table-grid-mode)**: `role="grid"`, a roving single tab-stop, 2-D APG arrow-key cell navigation, range selection, and clipboard support.
690
690
  */
691
- @property({ type: String, reflect: true }) interactionMode: string = 'table';
691
+ @property({ type: String, reflect: true, attribute: 'interaction-mode' }) interactionMode: string = 'table';
692
692
  /**
693
693
  * Grid mode only. When `true`, a plain click on an **editable** cell opens its editor immediately (single-click-to-edit) instead of just activating the cell. Default `false` keeps click-to-activate (double-click opens the editor). Shift+click (range selection) and clicks on non-editable cells are unaffected.
694
694
  */
695
- @property({ type: Boolean, reflect: true }) singleClickEdit: boolean = false;
695
+ @property({ type: Boolean, reflect: true, attribute: 'single-click-edit' }) singleClickEdit: boolean = false;
696
696
  /**
697
697
  * Grid mode. When `true`, every committed data mutation (cell/row edit, paste, fill, cut, clear) becomes one undo step: Ctrl/Cmd+Z undoes, Ctrl/Cmd+Y or Ctrl/Cmd+Shift+Z redoes. Default `false` records no history and Ctrl+Z/Y are inert.
698
698
  */
@@ -700,7 +700,7 @@ export default class DataTable extends SignalWatcher(LitElement) {
700
700
  /**
701
701
  * The maximum number of undo steps retained (oldest evicted past this depth). Only consulted when `undoable` is `true`.
702
702
  */
703
- @property({ type: Number, reflect: true }) undoLimit: number = 100;
703
+ @property({ type: Number, reflect: true, attribute: 'undo-limit' }) undoLimit: number = 100;
704
704
  /**
705
705
  * Opt-in windowing grammar: `false` (default, off — byte-identical to a non-virtual table) | `true` or `'rows'` (vertical row windowing; `true` is byte-behavior-identical to every existing consumer, zero churn) | `'columns'` (horizontal column windowing) | `'both'` (both axes windowed). Row windowing renders only the visible slice of rows inside a bounded `rdt-scroll` container (with leading/trailing spacer rows preserving total scroll height), windowing over the full filtered + sorted (pre-pagination) model and suppressing the client pagination chrome. Column windowing renders only the visible slice of leaf columns inside the same `rdt-scroll` container. An unrecognised string behaves as `false`.
706
706
  */
@@ -708,15 +708,15 @@ export default class DataTable extends SignalWatcher(LitElement) {
708
708
  /**
709
709
  * Estimated row height (px) — the first-paint seed for the windowing engine before any row has been measured. Only consulted when rows are windowed. When `autoMeasure` is `true`, later renders progressively refine the estimate from measured content; when `autoMeasure` is `false` this remains the explicit override for every render.
710
710
  */
711
- @property({ type: Number, reflect: true }) estimateRowHeight: number = 40;
711
+ @property({ type: Number, reflect: true, attribute: 'estimate-row-height' }) estimateRowHeight: number = 40;
712
712
  /**
713
713
  * Opt-in content-driven row-size estimation. When `true`, the windowing engine feeds `estimateSize()` a running mean of measured row heights instead of the fixed `estimateRowHeight` seed, so `getTotalSize()` converges to the true content total on a large table with variable-height rows. Falls back to `estimateRowHeight` before any row has been measured. Default `false` keeps the estimate fixed at `estimateRowHeight` for every render (today's behavior).
714
714
  */
715
- @property({ type: Boolean, reflect: true }) autoMeasure: boolean = false;
715
+ @property({ type: Boolean, reflect: true, attribute: 'auto-measure' }) autoMeasure: boolean = false;
716
716
  /**
717
717
  * A CSS length string bounding the `rdt-scroll` container when `virtual` is on (e.g. `'400px'`). Mirrored to the `--rozie-data-table-max-height` custom property; the prop wins, the token is the fallback.
718
718
  */
719
- @property({ type: String, reflect: true }) maxHeight: string = '';
719
+ @property({ type: String, reflect: true, attribute: 'max-height' }) maxHeight: string = '';
720
720
  private _dataDefault = signal<any[]>([]);
721
721
  private _sortingDefault = signal<any[]>([]);
722
722
  private _globalFilterDefault = signal('');
@@ -1542,7 +1542,7 @@ private __rozieCtxProvider_data_table_columns = new ContextProvider(this, { cont
1542
1542
  queueMicrotask(() => {
1543
1543
  if (this.isConnected || this._rozieTornDown) return;
1544
1544
  this._rozieTornDown = true;
1545
- () => {
1545
+ (() => {
1546
1546
  // B-02: drop the document click-away listener (it is attached for the instance's lifetime,
1547
1547
  // not per edit session — attaching it per session would freeze a stale closure on React).
1548
1548
  if (this.docPointerDown && typeof document !== 'undefined') {
@@ -1565,7 +1565,7 @@ private __rozieCtxProvider_data_table_columns = new ContextProvider(this, { cont
1565
1565
  this.teardownFillDrag();
1566
1566
  // §6 (260709-3qt): remove any live drag-select document listeners on a mid-drag unmount.
1567
1567
  this.teardownRangeDrag();
1568
- };
1568
+ })();
1569
1569
  for (const fn of this._disconnectCleanups) fn();
1570
1570
  this._disconnectCleanups = [];
1571
1571
  });
@@ -3420,6 +3420,35 @@ ${this.groupable ? html`<div class="rdt-group-bar-host" data-rozie-s-d5dcab4c>
3420
3420
  }));
3421
3421
  };
3422
3422
 
3423
+ // scrollToRow(index, options?) — quick 260927-a2r (oinbox dogfooding): plain scroll-into-view
3424
+ // for a windowed row, forwarding TanStack virtual-core's own ScrollToOptions ({ align?,
3425
+ // behavior? }) UNCHANGED to virtualizer.scrollToIndex — the SAME call focusActiveCell's D-12
3426
+ // off-window scroll-then-focus path (gridFocusNav.rzts) already drives, exposed here as a
3427
+ // standalone public verb rather than invented plumbing. INDEPENDENT of grid-mode focus
3428
+ // (feedback_no_false_equivalent_options / the todo's own open question): never reads or
3429
+ // writes $data.activeRow/activeColIndex, never emits activecell-change, and is callable in
3430
+ // EITHER interactionMode ('table' or 'grid') — a scroll, not a focus move. No-op when rows
3431
+ // are not windowed or the row virtualizer has not been constructed yet — mirrors the
3432
+ // isGrid()-gated no-op precedent on focusCell/clearActiveCell (gridActiveCellVerbs.rzts) for
3433
+ // the identical reason: the capability this verb drives isn't active. `index` is coerced
3434
+ // (T-260927A2R-01) — never range-clamped here: virtual-core's own scrollToIndex already
3435
+ // clamps to [0, options.count-1] internally (verified in @tanstack/virtual-core source).
3436
+ scrollToRow = (index: any, options?: {
3437
+ align?: 'start' | 'center' | 'end' | 'auto';
3438
+ behavior?: 'auto' | 'smooth' | 'instant';
3439
+ }): void => {
3440
+ if (!this.rowsWindowed() || !this.virtualizer) return;
3441
+ this.virtualizer.scrollToIndex(Math.trunc(Number(index)) || 0, options || undefined);
3442
+ };
3443
+
3444
+ // getScrollElement() — quick 260927-a2r: returns the DOM node the row AND column
3445
+ // virtualizer(s) observe/scroll (the `.rdt-scroll` div captured post-mount in
3446
+ // DataTable.rozie's own $onMount, D-03) — the supported replacement for a consumer reaching
3447
+ // into the internal `.rdt-scroll` class selector. Returns null when nothing is windowed:
3448
+ // gridScrollEl is only ever assigned inside the isWindowed() guard, so no extra gate is
3449
+ // needed here beyond that natural null.
3450
+ getScrollElement = (): any => this.gridScrollEl;
3451
+
3423
3452
  // ══ Generic vertical windowing math (Phase 64, D-04) — the target-agnostic virtual-core bridge ══
3424
3453
  // Lifted verbatim from the DataTable virtualization.rzts (the Phase 53/63 B13 baseline). This partial
3425
3454
  // holds ONLY the PURE windowing math; every DOM/refs/virtualizer-instance impurity stays per-consumer
@@ -12,7 +12,7 @@ export default class EditorCheckbox extends SignalWatcher(LitElement) {
12
12
  /**
13
13
  * The column id (mirrors the `#editor` slot scope). Used as the input `aria-label`.
14
14
  */
15
- @property({ type: String, reflect: true }) columnId: string = '';
15
+ @property({ type: String, reflect: true, attribute: 'column-id' }) columnId: string = '';
16
16
  /**
17
17
  * The table-core column object (opaque passthrough from the `#editor` slot scope).
18
18
  */
@@ -40,7 +40,7 @@ export default class EditorCheckbox extends SignalWatcher(LitElement) {
40
40
  /**
41
41
  * The column's human header, forwarded by the slot scope — used as the control's accessible name in place of the internal column id.
42
42
  */
43
- @property({ type: String, reflect: true }) columnLabel: string = '';
43
+ @property({ type: String, reflect: true, attribute: 'column-label' }) columnLabel: string = '';
44
44
  @query('[data-rozie-ref="inputEl"]') private _refInputEl!: HTMLElement;
45
45
  private __rozieFirstUpdateDone = false;
46
46
 
package/src/EditorDate.ts CHANGED
@@ -33,7 +33,7 @@ export default class EditorDate extends SignalWatcher(LitElement) {
33
33
  /**
34
34
  * The column id (mirrors the `#editor` slot scope). Used as the input `aria-label`.
35
35
  */
36
- @property({ type: String, reflect: true }) columnId: string = '';
36
+ @property({ type: String, reflect: true, attribute: 'column-id' }) columnId: string = '';
37
37
  /**
38
38
  * The table-core column object (opaque passthrough from the `#editor` slot scope).
39
39
  */
@@ -61,7 +61,7 @@ export default class EditorDate extends SignalWatcher(LitElement) {
61
61
  /**
62
62
  * The column's human header, forwarded by the slot scope — used as the control's accessible name in place of the internal column id.
63
63
  */
64
- @property({ type: String, reflect: true }) columnLabel: string = '';
64
+ @property({ type: String, reflect: true, attribute: 'column-label' }) columnLabel: string = '';
65
65
  private _draft = signal('');
66
66
  private _touched = signal(false);
67
67
  @query('[data-rozie-ref="inputEl"]') private _refInputEl!: HTMLElement;
@@ -12,7 +12,7 @@ export default class EditorNumber extends SignalWatcher(LitElement) {
12
12
  /**
13
13
  * The column id (mirrors the `#editor` slot scope). Used as the input `aria-label`.
14
14
  */
15
- @property({ type: String, reflect: true }) columnId: string = '';
15
+ @property({ type: String, reflect: true, attribute: 'column-id' }) columnId: string = '';
16
16
  /**
17
17
  * The table-core column object (opaque passthrough from the `#editor` slot scope).
18
18
  */
@@ -40,7 +40,7 @@ export default class EditorNumber extends SignalWatcher(LitElement) {
40
40
  /**
41
41
  * The column's human header, forwarded by the slot scope — used as the control's accessible name in place of the internal column id.
42
42
  */
43
- @property({ type: String, reflect: true }) columnLabel: string = '';
43
+ @property({ type: String, reflect: true, attribute: 'column-label' }) columnLabel: string = '';
44
44
  private _draft = signal('');
45
45
  private _touched = signal(false);
46
46
  @query('[data-rozie-ref="inputEl"]') private _refInputEl!: HTMLElement;
@@ -13,7 +13,7 @@ export default class EditorSelect extends SignalWatcher(LitElement) {
13
13
  /**
14
14
  * The column id (mirrors the `#editor` slot scope). Used as the select `aria-label`.
15
15
  */
16
- @property({ type: String, reflect: true }) columnId: string = '';
16
+ @property({ type: String, reflect: true, attribute: 'column-id' }) columnId: string = '';
17
17
  /**
18
18
  * The table-core column object (opaque passthrough from the `#editor` slot scope).
19
19
  */
@@ -45,7 +45,7 @@ export default class EditorSelect extends SignalWatcher(LitElement) {
45
45
  /**
46
46
  * The column's human header, forwarded by the slot scope — used as the control's accessible name in place of the internal column id.
47
47
  */
48
- @property({ type: String, reflect: true }) columnLabel: string = '';
48
+ @property({ type: String, reflect: true, attribute: 'column-label' }) columnLabel: string = '';
49
49
  private _draft = signal('');
50
50
  private _touched = signal(false);
51
51
  @query('[data-rozie-ref="selectEl"]') private _refSelectEl!: HTMLElement;
package/src/EditorText.ts CHANGED
@@ -12,7 +12,7 @@ export default class EditorText extends SignalWatcher(LitElement) {
12
12
  /**
13
13
  * The column id (mirrors the `#editor` slot scope). Used as the input `aria-label` fallback.
14
14
  */
15
- @property({ type: String, reflect: true }) columnId: string = '';
15
+ @property({ type: String, reflect: true, attribute: 'column-id' }) columnId: string = '';
16
16
  /**
17
17
  * The table-core column object (opaque passthrough from the `#editor` slot scope).
18
18
  */
@@ -40,7 +40,7 @@ export default class EditorText extends SignalWatcher(LitElement) {
40
40
  /**
41
41
  * The column's human header, forwarded by the slot scope — used as the control's accessible name in place of the internal column id.
42
42
  */
43
- @property({ type: String, reflect: true }) columnLabel: string = '';
43
+ @property({ type: String, reflect: true, attribute: 'column-label' }) columnLabel: string = '';
44
44
  private _draft = signal('');
45
45
  private _touched = signal(false);
46
46
  @query('[data-rozie-ref="inputEl"]') private _refInputEl!: HTMLElement;
@@ -12,7 +12,7 @@ export default class FilterNumberRange extends SignalWatcher(LitElement) {
12
12
  /**
13
13
  * The column id (mirrors the `#filter` slot scope) — used as the filter key and the input `aria-label` base.
14
14
  */
15
- @property({ type: String, reflect: true }) columnId: string = '';
15
+ @property({ type: String, reflect: true, attribute: 'column-id' }) columnId: string = '';
16
16
  /**
17
17
  * The table-core column object (opaque passthrough from the `#filter` slot scope).
18
18
  */
@@ -24,15 +24,15 @@ export default class FilterNumberRange extends SignalWatcher(LitElement) {
24
24
  /**
25
25
  * `(columnId, value) => void` — apply the column filter as a `[min, max]` tuple (each side coerced to a Number or `undefined`, so a one-sided range works); both empty clears the filter. Null-guarded at call sites.
26
26
  */
27
- @property({ type: Function }) setFilter: ((...args: any[]) => any) | null = null;
27
+ @property({ type: Function, attribute: 'set-filter' }) setFilter: ((...args: any[]) => any) | null = null;
28
28
  /**
29
29
  * The faceted `[min, max]` bounds for this column (`[number, number]` or null) — drives the input placeholders only.
30
30
  */
31
- @property({ type: Object }) minMax: unknown = null;
31
+ @property({ type: Object, attribute: 'min-max' }) minMax: unknown = null;
32
32
  /**
33
33
  * The column's human header, forwarded by the `#filter` slot scope — used as the control's accessible name in place of the internal column id.
34
34
  */
35
- @property({ type: String, reflect: true }) columnLabel: string = '';
35
+ @property({ type: String, reflect: true, attribute: 'column-label' }) columnLabel: string = '';
36
36
  private _minDraft = signal('');
37
37
  private _maxDraft = signal('');
38
38
  private _touched = signal(false);
@@ -13,7 +13,7 @@ export default class FilterSelect extends SignalWatcher(LitElement) {
13
13
  /**
14
14
  * The column id (mirrors the `#filter` slot scope) — used as the filter key and the select `aria-label`.
15
15
  */
16
- @property({ type: String, reflect: true }) columnId: string = '';
16
+ @property({ type: String, reflect: true, attribute: 'column-id' }) columnId: string = '';
17
17
  /**
18
18
  * The table-core column object (opaque passthrough from the `#filter` slot scope).
19
19
  */
@@ -25,15 +25,15 @@ export default class FilterSelect extends SignalWatcher(LitElement) {
25
25
  /**
26
26
  * `(columnId, value) => void` — apply the column filter on change; the leading empty "All" option clears it. Null-guarded at call sites.
27
27
  */
28
- @property({ type: Function }) setFilter: ((...args: any[]) => any) | null = null;
28
+ @property({ type: Function, attribute: 'set-filter' }) setFilter: ((...args: any[]) => any) | null = null;
29
29
  /**
30
30
  * The faceted distinct keys for this column (cross-filtered, keys only — no occurrence counts) used to build the `<option>` list.
31
31
  */
32
- @property({ type: Array }) uniqueValues: any[] = [];
32
+ @property({ type: Array, attribute: 'unique-values' }) uniqueValues: any[] = [];
33
33
  /**
34
34
  * The column's human header, forwarded by the `#filter` slot scope — used as the control's accessible name in place of the internal column id.
35
35
  */
36
- @property({ type: String, reflect: true }) columnLabel: string = '';
36
+ @property({ type: String, reflect: true, attribute: 'column-label' }) columnLabel: string = '';
37
37
 
38
38
  private _disconnectCleanups: Array<() => void> = [];
39
39
  // Re-parenting guard: set true once the deferred teardown has actually
package/src/FilterText.ts CHANGED
@@ -12,7 +12,7 @@ export default class FilterText extends SignalWatcher(LitElement) {
12
12
  /**
13
13
  * The column id (mirrors the `#filter` slot scope) — used as the filter key and the input `aria-label`.
14
14
  */
15
- @property({ type: String, reflect: true }) columnId: string = '';
15
+ @property({ type: String, reflect: true, attribute: 'column-id' }) columnId: string = '';
16
16
  /**
17
17
  * The table-core column object (opaque passthrough from the `#filter` slot scope).
18
18
  */
@@ -24,11 +24,11 @@ export default class FilterText extends SignalWatcher(LitElement) {
24
24
  /**
25
25
  * `(columnId, value) => void` — apply the column filter (Enter / blur applies, Escape clears). Null-guarded at call sites.
26
26
  */
27
- @property({ type: Function }) setFilter: ((...args: any[]) => any) | null = null;
27
+ @property({ type: Function, attribute: 'set-filter' }) setFilter: ((...args: any[]) => any) | null = null;
28
28
  /**
29
29
  * The column's human header, forwarded by the `#filter` slot scope — used as the control's accessible name in place of the internal column id.
30
30
  */
31
- @property({ type: String, reflect: true }) columnLabel: string = '';
31
+ @property({ type: String, reflect: true, attribute: 'column-label' }) columnLabel: string = '';
32
32
  private _draft = signal('');
33
33
  private _touched = signal(false);
34
34
  private __rozieFirstUpdateDone = false;
package/src/GroupBar.ts CHANGED
@@ -86,15 +86,15 @@ export default class GroupBar extends SignalWatcher(LitElement) {
86
86
  /**
87
87
  * The columns offered as grouping targets — `[{ id, label }]` — rendered as draggable chips.
88
88
  */
89
- @property({ type: Array }) groupableColumns: any[] = [];
89
+ @property({ type: Array, attribute: 'groupable-columns' }) groupableColumns: any[] = [];
90
90
  /**
91
91
  * `(cols: string[]) => void` — the only add/reorder writer for the grouping order. Null-guarded at call sites.
92
92
  */
93
- @property({ type: Function }) applyGrouping: ((...args: any[]) => any) | null = null;
93
+ @property({ type: Function, attribute: 'apply-grouping' }) applyGrouping: ((...args: any[]) => any) | null = null;
94
94
  /**
95
95
  * `() => void` — the only clear writer; resets grouping to empty. Null-guarded at call sites.
96
96
  */
97
- @property({ type: Function }) clearGrouping: ((...args: any[]) => any) | null = null;
97
+ @property({ type: Function, attribute: 'clear-grouping' }) clearGrouping: ((...args: any[]) => any) | null = null;
98
98
  private _draggingId = signal('');
99
99
  private _isOver = signal(false);
100
100
  private _dragKind = signal('');