@rozie-ui/data-table-solid 0.8.1 → 0.9.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/dist/index.mjs CHANGED
@@ -290,6 +290,28 @@ const tileIndex = (i, lo, hi) => {
290
290
  return lo + k;
291
291
  };
292
292
  //#endregion
293
+ //#region src/helpers/rangeFill.ts
294
+ const rangeFillTargets = (range, activeRow, activeCol) => {
295
+ const single = {
296
+ top: activeRow,
297
+ bottom: activeRow,
298
+ col: activeCol,
299
+ size: 1
300
+ };
301
+ if (!range) return single;
302
+ const top = Math.min(range.r0, range.r1);
303
+ const bottom = Math.max(range.r0, range.r1);
304
+ const left = Math.min(range.c0, range.c1);
305
+ const right = Math.max(range.c0, range.c1);
306
+ if (activeCol < left || activeCol > right || activeRow < top || activeRow > bottom) return single;
307
+ return {
308
+ top,
309
+ bottom,
310
+ col: activeCol,
311
+ size: bottom - top + 1
312
+ };
313
+ };
314
+ //#endregion
293
315
  //#region src/helpers/rowValueUtils.ts
294
316
  const replaceRowValue = (rows, rowIndex, field, value) => {
295
317
  const src = rows || [];
@@ -475,6 +497,8 @@ var _tmpl$$11 = /* @__PURE__ */ template(`<div class=rozie-data-table-wrap data-
475
497
  --rdt-border: 1px solid var(--rozie-data-table-border-color, var(--rdt-ds-border-color));
476
498
  --rdt-filter-border: 1px solid var(--rozie-data-table-control-border-color, var(--rdt-ds-control-border-color));
477
499
  --rdt-filter-radius: var(--rozie-data-table-radius, var(--rdt-ds-radius));
500
+ --rdt-column-border: 1px solid var(--rozie-data-table-column-border-color, var(--rozie-data-table-border-color, var(--rdt-ds-column-border-color)));
501
+ --rdt-pinned-bg: var(--rozie-data-table-pinned-bg, var(--rdt-ds-pinned-bg));
478
502
  --rdt-font: var(--rozie-data-table-font, var(--rdt-ds-font));
479
503
  --rdt-cell-padding: var(--rozie-data-table-cell-padding, var(--rdt-ds-cell-padding));
480
504
  --rdt-header-bg: var(--rozie-data-table-header-bg, var(--rdt-ds-header-bg));
@@ -496,7 +520,12 @@ var _tmpl$$11 = /* @__PURE__ */ template(`<div class=rozie-data-table-wrap data-
496
520
  --rdt-page-size-radius: var(--rozie-data-table-radius, var(--rdt-ds-radius));
497
521
  }
498
522
  .rozie-data-table[data-rozie-s-d5dcab4c] {
499
- border-collapse: collapse;
523
+ /* SEPARATE, not collapse. With collapsed borders the browser keeps a sticky cell's shared
524
+ border in the scrolling grid, so a 1px line of scrolled content shows beside pinned
525
+ columns and above the sticky header. Separate borders travel with their cell; zero
526
+ spacing keeps lines 1px because each cell draws only its own sides (see the cell rule). */
527
+ border-collapse: separate;
528
+ border-spacing: 0;
500
529
  width: 100%;
501
530
  font: var(--rdt-font, 14px system-ui, sans-serif);
502
531
  color: var(--rdt-color, inherit);
@@ -555,8 +584,28 @@ var _tmpl$$11 = /* @__PURE__ */ template(`<div class=rozie-data-table-wrap data-
555
584
  .rozie-data-table[data-rozie-s-d5dcab4c] .rdt-td[data-rozie-s-d5dcab4c] {
556
585
  padding: var(--rdt-cell-padding, 0.5rem 0.75rem);
557
586
  text-align: left;
587
+ /* Reset every side, then draw only the row line. Under separate borders each cell owns its
588
+ lines, and the reset keeps a host's plain \`table td { border }\` rule from drawing a second
589
+ set inside the table (this class-scoped rule outranks it). */
590
+ border: 0;
558
591
  border-bottom: var(--rdt-border, 1px solid rgba(0, 0, 0, 0.08));
559
592
  }
593
+ .rozie-data-table[data-rozie-s-d5dcab4c] .rdt-detail-cell[data-rozie-s-d5dcab4c] {
594
+ border: 0;
595
+ }
596
+ .rozie-data-table.rdt-column-lines[data-rozie-s-d5dcab4c] .rdt-th[data-rozie-s-d5dcab4c],
597
+ .rozie-data-table.rdt-column-lines[data-rozie-s-d5dcab4c] .rdt-td[data-rozie-s-d5dcab4c],
598
+ .rozie-data-table.rdt-column-lines[data-rozie-s-d5dcab4c] .rdt-filter-cell[data-rozie-s-d5dcab4c],
599
+ .rozie-data-table.rdt-column-lines[data-rozie-s-d5dcab4c] .rdt-detail-cell[data-rozie-s-d5dcab4c] {
600
+ border-inline-end: var(--rdt-column-border, 1px solid rgba(0, 0, 0, 0.08));
601
+ }
602
+ .rozie-data-table.rdt-column-lines[data-rozie-s-d5dcab4c] tr[data-rozie-s-d5dcab4c] > [data-rozie-s-d5dcab4c]:first-child:not(.rdt-col-spacer[data-rozie-s-d5dcab4c]),
603
+ .rozie-data-table.rdt-column-lines[data-rozie-s-d5dcab4c] tr[data-rozie-s-d5dcab4c] > .rdt-col-spacer[data-rozie-s-d5dcab4c]:first-child + *[data-rozie-s-d5dcab4c] {
604
+ border-inline-start: var(--rdt-column-border, 1px solid rgba(0, 0, 0, 0.08));
605
+ }
606
+ .rozie-data-table.rdt-column-lines[data-rozie-s-d5dcab4c] .rdt-thead[data-rozie-s-d5dcab4c] > tr[data-rozie-s-d5dcab4c]:first-child > .rdt-th[data-rozie-s-d5dcab4c] {
607
+ border-top: var(--rdt-column-border, 1px solid rgba(0, 0, 0, 0.08));
608
+ }
560
609
  .rozie-data-table[data-rozie-s-d5dcab4c] .rdt-thead[data-rozie-s-d5dcab4c] .rdt-th[data-rozie-s-d5dcab4c] {
561
610
  font-weight: var(--rdt-header-weight, 600);
562
611
  /* OPAQUE default (was rgba(0,0,0,0.03)): a translucent header lets the scrolling body
@@ -659,8 +708,21 @@ var _tmpl$$11 = /* @__PURE__ */ template(`<div class=rozie-data-table-wrap data-
659
708
  .rozie-data-table[data-rozie-s-d5dcab4c] .rdt-pinned[data-rozie-s-d5dcab4c] {
660
709
  box-sizing: border-box;
661
710
  }
711
+ .rozie-data-table[data-rozie-s-d5dcab4c] .rdt-td.rdt-pinned[data-rozie-s-d5dcab4c] {
712
+ background-color: var(--rdt-pinned-bg, #fff);
713
+ }
714
+ .rozie-data-table[data-rozie-s-d5dcab4c] .rdt-group-header[data-rozie-s-d5dcab4c] > .rdt-td.rdt-pinned[data-rozie-s-d5dcab4c] {
715
+ background: linear-gradient(var(--rdt-group-header-bg, rgba(0, 0, 0, 0.025)), var(--rdt-group-header-bg, rgba(0, 0, 0, 0.025))), var(--rdt-pinned-bg, #fff);
716
+ }
717
+ .rozie-data-table[data-rozie-s-d5dcab4c] .rdt-filter-cell.rdt-pinned[data-rozie-s-d5dcab4c] {
718
+ background: linear-gradient(var(--rdt-filter-row-bg, rgba(0, 0, 0, 0.015)), var(--rdt-filter-row-bg, rgba(0, 0, 0, 0.015))), var(--rdt-pinned-bg, #fff);
719
+ }
720
+ .rozie-data-table[data-rozie-s-d5dcab4c] .rdt-td.rdt-pinned.rdt-in-range[data-rozie-s-d5dcab4c] {
721
+ background: linear-gradient(var(--rdt-range-bg, rgba(37, 99, 235, 0.12)), var(--rdt-range-bg, rgba(37, 99, 235, 0.12))), var(--rdt-pinned-bg, #fff);
722
+ }
662
723
  .rozie-data-table[data-rozie-s-d5dcab4c] .rdt-filter-cell[data-rozie-s-d5dcab4c] {
663
724
  padding: var(--rdt-filter-cell-padding, 0.35rem 0.75rem);
725
+ border: 0;
664
726
  border-bottom: var(--rdt-border, 1px solid rgba(0, 0, 0, 0.08));
665
727
  }
666
728
  .rozie-data-table-wrap[data-rozie-s-d5dcab4c] .rdt-filter-row[data-rozie-s-d5dcab4c] .rdt-col-filter {
@@ -881,6 +943,7 @@ function DataTable(_props) {
881
943
  getSubRows: null,
882
944
  groupable: false,
883
945
  stickyHeader: false,
946
+ columnLines: false,
884
947
  interactionMode: "table",
885
948
  singleClickEdit: false,
886
949
  undoable: false,
@@ -913,6 +976,7 @@ function DataTable(_props) {
913
976
  "columnOrder",
914
977
  "columnPinning",
915
978
  "stickyHeader",
979
+ "columnLines",
916
980
  "interactionMode",
917
981
  "singleClickEdit",
918
982
  "undoable",
@@ -1224,6 +1288,7 @@ function DataTable(_props) {
1224
1288
  };
1225
1289
  document.addEventListener("pointerdown", docPointerDown, true);
1226
1290
  }
1291
+ if (gridRoot) gridRoot.addEventListener("keydown", onEditorDropinKeyDownCapture, true);
1227
1292
  if (isWindowed()) gridScrollEl = __rozieRootRef ? __rozieRootRef.querySelector(".rdt-scroll") : null;
1228
1293
  if (rowsWindowed()) {
1229
1294
  virtualizer = new Virtualizer(virtualizerOptions());
@@ -1260,6 +1325,7 @@ function DataTable(_props) {
1260
1325
  document.removeEventListener("pointerdown", docPointerDown, true);
1261
1326
  docPointerDown = null;
1262
1327
  }
1328
+ if (gridRoot) gridRoot.removeEventListener("keydown", onEditorDropinKeyDownCapture, true);
1263
1329
  if (virtualizerCleanup) virtualizerCleanup();
1264
1330
  if (colVirtualizerCleanup) colVirtualizerCleanup();
1265
1331
  teardownColRtlWatch();
@@ -3350,7 +3416,7 @@ function DataTable(_props) {
3350
3416
  setActiveColIndex(col);
3351
3417
  if (isHeader !== prevIsHeader || col !== prevCol || (isHeader ? movedLevel !== prevLevel : movedRow !== prevRow)) focusIntentEpoch = focusIntentEpoch + 1;
3352
3418
  if (rangeTransition) rangeTransition = false;
3353
- else if (rangeClickPending && rangeClickPending.isHeader === isHeader && rangeClickPending.r === movedRow && rangeClickPending.c === col) rangeClickPending = null;
3419
+ else if (!isHeader && tgt !== cellEl && editingRow() === movedRow && editingCol() === col) {} else if (rangeClickPending && rangeClickPending.isHeader === isHeader && rangeClickPending.r === movedRow && rangeClickPending.c === col) rangeClickPending = null;
3354
3420
  else {
3355
3421
  rangeClickPending = null;
3356
3422
  clearRange();
@@ -4098,6 +4164,18 @@ function DataTable(_props) {
4098
4164
  }
4099
4165
  applyGridToRange(grid, box.r0, box.c0, "filled");
4100
4166
  }
4167
+ function fillTargets() {
4168
+ return rangeFillTargets(normalizedRange(), activeRow(), activeColIndex());
4169
+ }
4170
+ function rangeSize() {
4171
+ return activeIsHeader() ? 1 : fillTargets().size;
4172
+ }
4173
+ function fillActiveColumn(value) {
4174
+ const t = fillTargets();
4175
+ const grid = [];
4176
+ for (let i = 0; i < t.size; i++) grid.push([value]);
4177
+ return applyGridToRange(grid, t.top, t.col, "updated");
4178
+ }
4101
4179
  let fillDragging = false;
4102
4180
  let fillDragMove = null;
4103
4181
  let fillDragUp = null;
@@ -4520,6 +4598,44 @@ function DataTable(_props) {
4520
4598
  } else if (skipFocusReturn !== true) focusCellWhenReady(focusRow, focusCol);
4521
4599
  return true;
4522
4600
  }
4601
+ function commitEditToRange(overrideValue = void 0) {
4602
+ if (editingRow() < 0) return false;
4603
+ if (committedThisSession) return false;
4604
+ const colId = editingColumnId();
4605
+ if (colId == null) {
4606
+ endEdit();
4607
+ return false;
4608
+ }
4609
+ const rawValue = overrideValue !== void 0 ? overrideValue : draftValue();
4610
+ const err = runValidator(colId, coerceCellValue(colId, rawValue), editingRowOriginal());
4611
+ if (err !== true) {
4612
+ setInvalid(err);
4613
+ focusEditorWhenReady(editingRow(), editingCol());
4614
+ return false;
4615
+ }
4616
+ setInvalid("");
4617
+ const focusRow = editingRow();
4618
+ const focusCol = editingCol();
4619
+ const rowOriginal = editingRowOriginal();
4620
+ const rowId = editingRowId();
4621
+ editTransition = true;
4622
+ committedThisSession = true;
4623
+ const result = fillActiveColumn(rawValue);
4624
+ endEdit();
4625
+ editTransition = false;
4626
+ rangeClickPending = {
4627
+ isHeader: false,
4628
+ r: focusRow,
4629
+ c: focusCol
4630
+ };
4631
+ if (result && result.changed > 0) pendingEditFollow = {
4632
+ rowOriginal,
4633
+ rowId,
4634
+ col: focusCol
4635
+ };
4636
+ else focusCellWhenReady(focusRow, focusCol);
4637
+ return true;
4638
+ }
4523
4639
  function toggleActiveBooleanCell() {
4524
4640
  if (rowIndexIsGrouped(activeRow())) return;
4525
4641
  const row = (rows() || [])[activeRow()];
@@ -4531,6 +4647,11 @@ function DataTable(_props) {
4531
4647
  const rowId = row.id;
4532
4648
  const oldValue = cellValueAt(activeRow(), activeColIndex());
4533
4649
  const newValue = !oldValue;
4650
+ if (rangeSize() > 1) {
4651
+ setInvalid("");
4652
+ fillActiveColumn(newValue);
4653
+ return;
4654
+ }
4534
4655
  const err = runValidator(colId, newValue, rowOriginal);
4535
4656
  if (err !== true) {
4536
4657
  setInvalid(err);
@@ -4752,6 +4873,7 @@ function DataTable(_props) {
4752
4873
  let committedThisSession = false;
4753
4874
  let rowDraftSync = {};
4754
4875
  let dropinTabFlush = null;
4876
+ let rangeCommitIntent = false;
4755
4877
  function inRowEdit() {
4756
4878
  return editingRowIndex() != null;
4757
4879
  }
@@ -4762,11 +4884,17 @@ function DataTable(_props) {
4762
4884
  return !!(inRowEdit() ? rowDraft() ? rowDraft()[colId] : null : draftValue());
4763
4885
  }
4764
4886
  function editorCommitFor(colId) {
4765
- return (value) => {
4887
+ return (value, options) => {
4766
4888
  if (inRowEdit()) {
4767
4889
  setRowDraft$local(colId, value);
4768
4890
  return;
4769
4891
  }
4892
+ const wantsRange = options != null && options.toRange === true || rangeCommitIntent;
4893
+ rangeCommitIntent = false;
4894
+ if (wantsRange && !dropinTabFlush && rangeSize() > 1) {
4895
+ commitEditToRange(value);
4896
+ return;
4897
+ }
4770
4898
  if (dropinTabFlush) {
4771
4899
  dropinTabFlush.called = true;
4772
4900
  if (commitEdit(value, true)) dropinTabFlush.committed = true;
@@ -4841,7 +4969,10 @@ function DataTable(_props) {
4841
4969
  }
4842
4970
  return;
4843
4971
  }
4844
- if (key === "Enter") {
4972
+ if (key === "Enter" && (e.ctrlKey || e.metaKey) && rangeSize() > 1) {
4973
+ e.preventDefault();
4974
+ commitEditToRange(void 0);
4975
+ } else if (key === "Enter") {
4845
4976
  e.preventDefault();
4846
4977
  commitEdit(void 0);
4847
4978
  } else if (key === "Tab") {
@@ -4862,8 +4993,18 @@ function DataTable(_props) {
4862
4993
  cancelEdit();
4863
4994
  }
4864
4995
  }
4996
+ function onEditorDropinKeyDownCapture(e) {
4997
+ if (!e) return;
4998
+ if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
4999
+ rangeCommitIntent = true;
5000
+ setTimeout(() => {
5001
+ rangeCommitIntent = false;
5002
+ }, 0);
5003
+ }
5004
+ }
4865
5005
  function onEditorDropinKeyDown(e) {
4866
5006
  if (!e) return;
5007
+ rangeCommitIntent = false;
4867
5008
  const key = e.key;
4868
5009
  if (inRowEdit()) {
4869
5010
  if (key === "Enter") {
@@ -5725,6 +5866,9 @@ function DataTable(_props) {
5725
5866
  },
5726
5867
  get autofocus() {
5727
5868
  return editorAutofocusFor(cell().column.id, rowIndexOf(row()));
5869
+ },
5870
+ get rangeSize() {
5871
+ return inRowEdit() ? 1 : rangeSize();
5728
5872
  }
5729
5873
  }) ?? (_props.editorSlot ?? _props.slots?.["editor"])?.({
5730
5874
  get columnId() {
@@ -5750,6 +5894,9 @@ function DataTable(_props) {
5750
5894
  },
5751
5895
  get autofocus() {
5752
5896
  return editorAutofocusFor(cell().column.id, rowIndexOf(row()));
5897
+ },
5898
+ get rangeSize() {
5899
+ return inRowEdit() ? 1 : rangeSize();
5753
5900
  }
5754
5901
  }) ?? (() => {
5755
5902
  var _el$68 = _tmpl$29();
@@ -6032,7 +6179,10 @@ function DataTable(_props) {
6032
6179
  }))]
6033
6180
  }));
6034
6181
  effect((_p$) => {
6035
- var _v$0 = rozieAttr(gridAriaRowCount()), _v$1 = rozieAttr(gridAriaColCount()), _v$10 = "rozie-data-table " + rozieClass({ "rdt-sticky": local.stickyHeader }), _v$11 = rozieAttr(tableRole());
6182
+ var _v$0 = rozieAttr(gridAriaRowCount()), _v$1 = rozieAttr(gridAriaColCount()), _v$10 = "rozie-data-table " + rozieClass({
6183
+ "rdt-sticky": local.stickyHeader,
6184
+ "rdt-column-lines": local.columnLines
6185
+ }), _v$11 = rozieAttr(tableRole());
6036
6186
  _v$0 !== _p$.e && setAttribute(_el$23, "aria-rowcount", _p$.e = _v$0);
6037
6187
  _v$1 !== _p$.t && setAttribute(_el$23, "aria-colcount", _p$.t = _v$1);
6038
6188
  _v$10 !== _p$.a && className(_el$23, _p$.a = _v$10);
@@ -6608,6 +6758,9 @@ function DataTable(_props) {
6608
6758
  },
6609
6759
  get autofocus() {
6610
6760
  return editorAutofocusFor(cell().column.id, wr().vi.index);
6761
+ },
6762
+ get rangeSize() {
6763
+ return inRowEdit() ? 1 : rangeSize();
6611
6764
  }
6612
6765
  }) ?? (_props.editorSlot ?? _props.slots?.["editor"])?.({
6613
6766
  get columnId() {
@@ -6633,6 +6786,9 @@ function DataTable(_props) {
6633
6786
  },
6634
6787
  get autofocus() {
6635
6788
  return editorAutofocusFor(cell().column.id, wr().vi.index);
6789
+ },
6790
+ get rangeSize() {
6791
+ return inRowEdit() ? 1 : rangeSize();
6636
6792
  }
6637
6793
  }) ?? (() => {
6638
6794
  var _el$126 = _tmpl$29();
@@ -6970,7 +7126,8 @@ function DataTable(_props) {
6970
7126
  effect((_p$) => {
6971
7127
  var _v$ = parseInlineStyle(rowsWindowed() && local.maxHeight ? "max-height:" + local.maxHeight + ";overflow:auto;--rozie-data-table-max-height:" + local.maxHeight : "overflow:auto"), _v$2 = rozieAttr(gridAriaRowCount()), _v$3 = rozieAttr(gridAriaColCount()), _v$4 = "rozie-data-table " + rozieClass({
6972
7128
  "rdt-sticky": local.stickyHeader,
6973
- "rdt-col-windowed": colsWindowed()
7129
+ "rdt-col-windowed": colsWindowed(),
7130
+ "rdt-column-lines": local.columnLines
6974
7131
  }), _v$5 = rozieAttr(tableRole()), _v$6 = rozieAttr(windowedColSpan()), _v$7 = parseInlineStyle("height:" + padTop() + "px;padding:0;border:0"), _v$8 = rozieAttr(windowedColSpan()), _v$9 = parseInlineStyle("height:" + padBottom() + "px;padding:0;border:0");
6975
7132
  _p$.e = style(_el$15, _v$, _p$.e);
6976
7133
  _v$2 !== _p$.t && setAttribute(_el$16, "aria-rowcount", _p$.t = _v$2);
@@ -289,6 +289,28 @@ const tileIndex = (i, lo, hi) => {
289
289
  return lo + k;
290
290
  };
291
291
  //#endregion
292
+ //#region src/helpers/rangeFill.ts
293
+ const rangeFillTargets = (range, activeRow, activeCol) => {
294
+ const single = {
295
+ top: activeRow,
296
+ bottom: activeRow,
297
+ col: activeCol,
298
+ size: 1
299
+ };
300
+ if (!range) return single;
301
+ const top = Math.min(range.r0, range.r1);
302
+ const bottom = Math.max(range.r0, range.r1);
303
+ const left = Math.min(range.c0, range.c1);
304
+ const right = Math.max(range.c0, range.c1);
305
+ if (activeCol < left || activeCol > right || activeRow < top || activeRow > bottom) return single;
306
+ return {
307
+ top,
308
+ bottom,
309
+ col: activeCol,
310
+ size: bottom - top + 1
311
+ };
312
+ };
313
+ //#endregion
292
314
  //#region src/helpers/rowValueUtils.ts
293
315
  const replaceRowValue = (rows, rowIndex, field, value) => {
294
316
  const src = rows || [];
@@ -473,6 +495,8 @@ __rozieInjectStyle("DataTable-d5dcab4c", `[data-rozie-s-d5dcab4c]:host {
473
495
  --rdt-border: 1px solid var(--rozie-data-table-border-color, var(--rdt-ds-border-color));
474
496
  --rdt-filter-border: 1px solid var(--rozie-data-table-control-border-color, var(--rdt-ds-control-border-color));
475
497
  --rdt-filter-radius: var(--rozie-data-table-radius, var(--rdt-ds-radius));
498
+ --rdt-column-border: 1px solid var(--rozie-data-table-column-border-color, var(--rozie-data-table-border-color, var(--rdt-ds-column-border-color)));
499
+ --rdt-pinned-bg: var(--rozie-data-table-pinned-bg, var(--rdt-ds-pinned-bg));
476
500
  --rdt-font: var(--rozie-data-table-font, var(--rdt-ds-font));
477
501
  --rdt-cell-padding: var(--rozie-data-table-cell-padding, var(--rdt-ds-cell-padding));
478
502
  --rdt-header-bg: var(--rozie-data-table-header-bg, var(--rdt-ds-header-bg));
@@ -494,7 +518,12 @@ __rozieInjectStyle("DataTable-d5dcab4c", `[data-rozie-s-d5dcab4c]:host {
494
518
  --rdt-page-size-radius: var(--rozie-data-table-radius, var(--rdt-ds-radius));
495
519
  }
496
520
  .rozie-data-table[data-rozie-s-d5dcab4c] {
497
- border-collapse: collapse;
521
+ /* SEPARATE, not collapse. With collapsed borders the browser keeps a sticky cell's shared
522
+ border in the scrolling grid, so a 1px line of scrolled content shows beside pinned
523
+ columns and above the sticky header. Separate borders travel with their cell; zero
524
+ spacing keeps lines 1px because each cell draws only its own sides (see the cell rule). */
525
+ border-collapse: separate;
526
+ border-spacing: 0;
498
527
  width: 100%;
499
528
  font: var(--rdt-font, 14px system-ui, sans-serif);
500
529
  color: var(--rdt-color, inherit);
@@ -553,8 +582,28 @@ __rozieInjectStyle("DataTable-d5dcab4c", `[data-rozie-s-d5dcab4c]:host {
553
582
  .rozie-data-table[data-rozie-s-d5dcab4c] .rdt-td[data-rozie-s-d5dcab4c] {
554
583
  padding: var(--rdt-cell-padding, 0.5rem 0.75rem);
555
584
  text-align: left;
585
+ /* Reset every side, then draw only the row line. Under separate borders each cell owns its
586
+ lines, and the reset keeps a host's plain \`table td { border }\` rule from drawing a second
587
+ set inside the table (this class-scoped rule outranks it). */
588
+ border: 0;
556
589
  border-bottom: var(--rdt-border, 1px solid rgba(0, 0, 0, 0.08));
557
590
  }
591
+ .rozie-data-table[data-rozie-s-d5dcab4c] .rdt-detail-cell[data-rozie-s-d5dcab4c] {
592
+ border: 0;
593
+ }
594
+ .rozie-data-table.rdt-column-lines[data-rozie-s-d5dcab4c] .rdt-th[data-rozie-s-d5dcab4c],
595
+ .rozie-data-table.rdt-column-lines[data-rozie-s-d5dcab4c] .rdt-td[data-rozie-s-d5dcab4c],
596
+ .rozie-data-table.rdt-column-lines[data-rozie-s-d5dcab4c] .rdt-filter-cell[data-rozie-s-d5dcab4c],
597
+ .rozie-data-table.rdt-column-lines[data-rozie-s-d5dcab4c] .rdt-detail-cell[data-rozie-s-d5dcab4c] {
598
+ border-inline-end: var(--rdt-column-border, 1px solid rgba(0, 0, 0, 0.08));
599
+ }
600
+ .rozie-data-table.rdt-column-lines[data-rozie-s-d5dcab4c] tr[data-rozie-s-d5dcab4c] > [data-rozie-s-d5dcab4c]:first-child:not(.rdt-col-spacer[data-rozie-s-d5dcab4c]),
601
+ .rozie-data-table.rdt-column-lines[data-rozie-s-d5dcab4c] tr[data-rozie-s-d5dcab4c] > .rdt-col-spacer[data-rozie-s-d5dcab4c]:first-child + *[data-rozie-s-d5dcab4c] {
602
+ border-inline-start: var(--rdt-column-border, 1px solid rgba(0, 0, 0, 0.08));
603
+ }
604
+ .rozie-data-table.rdt-column-lines[data-rozie-s-d5dcab4c] .rdt-thead[data-rozie-s-d5dcab4c] > tr[data-rozie-s-d5dcab4c]:first-child > .rdt-th[data-rozie-s-d5dcab4c] {
605
+ border-top: var(--rdt-column-border, 1px solid rgba(0, 0, 0, 0.08));
606
+ }
558
607
  .rozie-data-table[data-rozie-s-d5dcab4c] .rdt-thead[data-rozie-s-d5dcab4c] .rdt-th[data-rozie-s-d5dcab4c] {
559
608
  font-weight: var(--rdt-header-weight, 600);
560
609
  /* OPAQUE default (was rgba(0,0,0,0.03)): a translucent header lets the scrolling body
@@ -657,8 +706,21 @@ __rozieInjectStyle("DataTable-d5dcab4c", `[data-rozie-s-d5dcab4c]:host {
657
706
  .rozie-data-table[data-rozie-s-d5dcab4c] .rdt-pinned[data-rozie-s-d5dcab4c] {
658
707
  box-sizing: border-box;
659
708
  }
709
+ .rozie-data-table[data-rozie-s-d5dcab4c] .rdt-td.rdt-pinned[data-rozie-s-d5dcab4c] {
710
+ background-color: var(--rdt-pinned-bg, #fff);
711
+ }
712
+ .rozie-data-table[data-rozie-s-d5dcab4c] .rdt-group-header[data-rozie-s-d5dcab4c] > .rdt-td.rdt-pinned[data-rozie-s-d5dcab4c] {
713
+ background: linear-gradient(var(--rdt-group-header-bg, rgba(0, 0, 0, 0.025)), var(--rdt-group-header-bg, rgba(0, 0, 0, 0.025))), var(--rdt-pinned-bg, #fff);
714
+ }
715
+ .rozie-data-table[data-rozie-s-d5dcab4c] .rdt-filter-cell.rdt-pinned[data-rozie-s-d5dcab4c] {
716
+ background: linear-gradient(var(--rdt-filter-row-bg, rgba(0, 0, 0, 0.015)), var(--rdt-filter-row-bg, rgba(0, 0, 0, 0.015))), var(--rdt-pinned-bg, #fff);
717
+ }
718
+ .rozie-data-table[data-rozie-s-d5dcab4c] .rdt-td.rdt-pinned.rdt-in-range[data-rozie-s-d5dcab4c] {
719
+ background: linear-gradient(var(--rdt-range-bg, rgba(37, 99, 235, 0.12)), var(--rdt-range-bg, rgba(37, 99, 235, 0.12))), var(--rdt-pinned-bg, #fff);
720
+ }
660
721
  .rozie-data-table[data-rozie-s-d5dcab4c] .rdt-filter-cell[data-rozie-s-d5dcab4c] {
661
722
  padding: var(--rdt-filter-cell-padding, 0.35rem 0.75rem);
723
+ border: 0;
662
724
  border-bottom: var(--rdt-border, 1px solid rgba(0, 0, 0, 0.08));
663
725
  }
664
726
  .rozie-data-table-wrap[data-rozie-s-d5dcab4c] .rdt-filter-row[data-rozie-s-d5dcab4c] .rdt-col-filter {
@@ -879,6 +941,7 @@ function DataTable(_props) {
879
941
  getSubRows: null,
880
942
  groupable: false,
881
943
  stickyHeader: false,
944
+ columnLines: false,
882
945
  interactionMode: "table",
883
946
  singleClickEdit: false,
884
947
  undoable: false,
@@ -911,6 +974,7 @@ function DataTable(_props) {
911
974
  "columnOrder",
912
975
  "columnPinning",
913
976
  "stickyHeader",
977
+ "columnLines",
914
978
  "interactionMode",
915
979
  "singleClickEdit",
916
980
  "undoable",
@@ -1222,6 +1286,7 @@ function DataTable(_props) {
1222
1286
  };
1223
1287
  document.addEventListener("pointerdown", docPointerDown, true);
1224
1288
  }
1289
+ if (gridRoot) gridRoot.addEventListener("keydown", onEditorDropinKeyDownCapture, true);
1225
1290
  if (isWindowed()) gridScrollEl = __rozieRootRef ? __rozieRootRef.querySelector(".rdt-scroll") : null;
1226
1291
  if (rowsWindowed()) {
1227
1292
  virtualizer = new Virtualizer(virtualizerOptions());
@@ -1258,6 +1323,7 @@ function DataTable(_props) {
1258
1323
  document.removeEventListener("pointerdown", docPointerDown, true);
1259
1324
  docPointerDown = null;
1260
1325
  }
1326
+ if (gridRoot) gridRoot.removeEventListener("keydown", onEditorDropinKeyDownCapture, true);
1261
1327
  if (virtualizerCleanup) virtualizerCleanup();
1262
1328
  if (colVirtualizerCleanup) colVirtualizerCleanup();
1263
1329
  teardownColRtlWatch();
@@ -3349,7 +3415,7 @@ function DataTable(_props) {
3349
3415
  setActiveColIndex(col);
3350
3416
  if (isHeader !== prevIsHeader || col !== prevCol || (isHeader ? movedLevel !== prevLevel : movedRow !== prevRow)) focusIntentEpoch = focusIntentEpoch + 1;
3351
3417
  if (rangeTransition) rangeTransition = false;
3352
- else if (rangeClickPending && rangeClickPending.isHeader === isHeader && rangeClickPending.r === movedRow && rangeClickPending.c === col) rangeClickPending = null;
3418
+ else if (!isHeader && tgt !== cellEl && editingRow() === movedRow && editingCol() === col) {} else if (rangeClickPending && rangeClickPending.isHeader === isHeader && rangeClickPending.r === movedRow && rangeClickPending.c === col) rangeClickPending = null;
3353
3419
  else {
3354
3420
  rangeClickPending = null;
3355
3421
  clearRange();
@@ -4097,6 +4163,18 @@ function DataTable(_props) {
4097
4163
  }
4098
4164
  applyGridToRange(grid, box.r0, box.c0, "filled");
4099
4165
  }
4166
+ function fillTargets() {
4167
+ return rangeFillTargets(normalizedRange(), activeRow(), activeColIndex());
4168
+ }
4169
+ function rangeSize() {
4170
+ return activeIsHeader() ? 1 : fillTargets().size;
4171
+ }
4172
+ function fillActiveColumn(value) {
4173
+ const t = fillTargets();
4174
+ const grid = [];
4175
+ for (let i = 0; i < t.size; i++) grid.push([value]);
4176
+ return applyGridToRange(grid, t.top, t.col, "updated");
4177
+ }
4100
4178
  let fillDragging = false;
4101
4179
  let fillDragMove = null;
4102
4180
  let fillDragUp = null;
@@ -4519,6 +4597,44 @@ function DataTable(_props) {
4519
4597
  } else if (skipFocusReturn !== true) focusCellWhenReady(focusRow, focusCol);
4520
4598
  return true;
4521
4599
  }
4600
+ function commitEditToRange(overrideValue = void 0) {
4601
+ if (editingRow() < 0) return false;
4602
+ if (committedThisSession) return false;
4603
+ const colId = editingColumnId();
4604
+ if (colId == null) {
4605
+ endEdit();
4606
+ return false;
4607
+ }
4608
+ const rawValue = overrideValue !== void 0 ? overrideValue : draftValue();
4609
+ const err = runValidator(colId, coerceCellValue(colId, rawValue), editingRowOriginal());
4610
+ if (err !== true) {
4611
+ setInvalid(err);
4612
+ focusEditorWhenReady(editingRow(), editingCol());
4613
+ return false;
4614
+ }
4615
+ setInvalid("");
4616
+ const focusRow = editingRow();
4617
+ const focusCol = editingCol();
4618
+ const rowOriginal = editingRowOriginal();
4619
+ const rowId = editingRowId();
4620
+ editTransition = true;
4621
+ committedThisSession = true;
4622
+ const result = fillActiveColumn(rawValue);
4623
+ endEdit();
4624
+ editTransition = false;
4625
+ rangeClickPending = {
4626
+ isHeader: false,
4627
+ r: focusRow,
4628
+ c: focusCol
4629
+ };
4630
+ if (result && result.changed > 0) pendingEditFollow = {
4631
+ rowOriginal,
4632
+ rowId,
4633
+ col: focusCol
4634
+ };
4635
+ else focusCellWhenReady(focusRow, focusCol);
4636
+ return true;
4637
+ }
4522
4638
  function toggleActiveBooleanCell() {
4523
4639
  if (rowIndexIsGrouped(activeRow())) return;
4524
4640
  const row = (rows() || [])[activeRow()];
@@ -4530,6 +4646,11 @@ function DataTable(_props) {
4530
4646
  const rowId = row.id;
4531
4647
  const oldValue = cellValueAt(activeRow(), activeColIndex());
4532
4648
  const newValue = !oldValue;
4649
+ if (rangeSize() > 1) {
4650
+ setInvalid("");
4651
+ fillActiveColumn(newValue);
4652
+ return;
4653
+ }
4533
4654
  const err = runValidator(colId, newValue, rowOriginal);
4534
4655
  if (err !== true) {
4535
4656
  setInvalid(err);
@@ -4751,6 +4872,7 @@ function DataTable(_props) {
4751
4872
  let committedThisSession = false;
4752
4873
  let rowDraftSync = {};
4753
4874
  let dropinTabFlush = null;
4875
+ let rangeCommitIntent = false;
4754
4876
  function inRowEdit() {
4755
4877
  return editingRowIndex() != null;
4756
4878
  }
@@ -4761,11 +4883,17 @@ function DataTable(_props) {
4761
4883
  return !!(inRowEdit() ? rowDraft() ? rowDraft()[colId] : null : draftValue());
4762
4884
  }
4763
4885
  function editorCommitFor(colId) {
4764
- return (value) => {
4886
+ return (value, options) => {
4765
4887
  if (inRowEdit()) {
4766
4888
  setRowDraft$local(colId, value);
4767
4889
  return;
4768
4890
  }
4891
+ const wantsRange = options != null && options.toRange === true || rangeCommitIntent;
4892
+ rangeCommitIntent = false;
4893
+ if (wantsRange && !dropinTabFlush && rangeSize() > 1) {
4894
+ commitEditToRange(value);
4895
+ return;
4896
+ }
4769
4897
  if (dropinTabFlush) {
4770
4898
  dropinTabFlush.called = true;
4771
4899
  if (commitEdit(value, true)) dropinTabFlush.committed = true;
@@ -4840,7 +4968,10 @@ function DataTable(_props) {
4840
4968
  }
4841
4969
  return;
4842
4970
  }
4843
- if (key === "Enter") {
4971
+ if (key === "Enter" && (e.ctrlKey || e.metaKey) && rangeSize() > 1) {
4972
+ e.preventDefault();
4973
+ commitEditToRange(void 0);
4974
+ } else if (key === "Enter") {
4844
4975
  e.preventDefault();
4845
4976
  commitEdit(void 0);
4846
4977
  } else if (key === "Tab") {
@@ -4861,8 +4992,18 @@ function DataTable(_props) {
4861
4992
  cancelEdit();
4862
4993
  }
4863
4994
  }
4995
+ function onEditorDropinKeyDownCapture(e) {
4996
+ if (!e) return;
4997
+ if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
4998
+ rangeCommitIntent = true;
4999
+ setTimeout(() => {
5000
+ rangeCommitIntent = false;
5001
+ }, 0);
5002
+ }
5003
+ }
4864
5004
  function onEditorDropinKeyDown(e) {
4865
5005
  if (!e) return;
5006
+ rangeCommitIntent = false;
4866
5007
  const key = e.key;
4867
5008
  if (inRowEdit()) {
4868
5009
  if (key === "Enter") {
@@ -5158,7 +5299,10 @@ function DataTable(_props) {
5158
5299
  applyGrouping,
5159
5300
  clearGrouping
5160
5301
  }) ?? <Key each={groupingKeys()} by={(gk) => gk}>{(gk) => <span class={"rdt-group-token"} data-group-token="" data-rozie-s-d5dcab4c="">{rozieDisplay(gk())}</span>}</Key>}
5161
- </div></Show>}{<Show when={isWindowed()} fallback={<table aria-rowcount={rozieAttr(gridAriaRowCount())} aria-colcount={rozieAttr(gridAriaColCount())} class={"rozie-data-table " + rozieClass({ "rdt-sticky": local.stickyHeader })} role={rozieAttr(tableRole())} onKeyDown={($event) => {
5302
+ </div></Show>}{<Show when={isWindowed()} fallback={<table aria-rowcount={rozieAttr(gridAriaRowCount())} aria-colcount={rozieAttr(gridAriaColCount())} class={"rozie-data-table " + rozieClass({
5303
+ "rdt-sticky": local.stickyHeader,
5304
+ "rdt-column-lines": local.columnLines
5305
+ })} role={rozieAttr(tableRole())} onKeyDown={($event) => {
5162
5306
  onGridKeyDown($event);
5163
5307
  }} onFocusIn={($event) => {
5164
5308
  syncActiveFromEvent($event);
@@ -5400,6 +5544,9 @@ function DataTable(_props) {
5400
5544
  },
5401
5545
  get autofocus() {
5402
5546
  return editorAutofocusFor(cell().column.id, rowIndexOf(row()));
5547
+ },
5548
+ get rangeSize() {
5549
+ return inRowEdit() ? 1 : rangeSize();
5403
5550
  }
5404
5551
  }) ?? (_props.editorSlot ?? _props.slots?.["editor"])?.({
5405
5552
  get columnId() {
@@ -5425,6 +5572,9 @@ function DataTable(_props) {
5425
5572
  },
5426
5573
  get autofocus() {
5427
5574
  return editorAutofocusFor(cell().column.id, rowIndexOf(row()));
5575
+ },
5576
+ get rangeSize() {
5577
+ return inRowEdit() ? 1 : rangeSize();
5428
5578
  }
5429
5579
  }) ?? <input type="text" data-editing-cell="" data-builtin-editor="" aria-invalid={rozieAttr(invalidMsg() ? "true" : null)} class={"rdt-cell-editor"} value={editorValueFor(cell().column.id)} onInput={($event) => {
5430
5580
  onCellEditorInput(cell().column.id, $event);
@@ -5520,7 +5670,8 @@ function DataTable(_props) {
5520
5670
  </table>}><div class={"rdt-scroll"} style={parseInlineStyle(rowsWindowed() && local.maxHeight ? "max-height:" + local.maxHeight + ";overflow:auto;--rozie-data-table-max-height:" + local.maxHeight : "overflow:auto")} data-rozie-s-d5dcab4c="">
5521
5671
  <table aria-rowcount={rozieAttr(gridAriaRowCount())} aria-colcount={rozieAttr(gridAriaColCount())} class={"rozie-data-table " + rozieClass({
5522
5672
  "rdt-sticky": local.stickyHeader,
5523
- "rdt-col-windowed": colsWindowed()
5673
+ "rdt-col-windowed": colsWindowed(),
5674
+ "rdt-column-lines": local.columnLines
5524
5675
  })} role={rozieAttr(tableRole())} onKeyDown={($event) => {
5525
5676
  onGridKeyDown($event);
5526
5677
  }} onFocusIn={($event) => {
@@ -5770,6 +5921,9 @@ function DataTable(_props) {
5770
5921
  },
5771
5922
  get autofocus() {
5772
5923
  return editorAutofocusFor(cell().column.id, wr().vi.index);
5924
+ },
5925
+ get rangeSize() {
5926
+ return inRowEdit() ? 1 : rangeSize();
5773
5927
  }
5774
5928
  }) ?? (_props.editorSlot ?? _props.slots?.["editor"])?.({
5775
5929
  get columnId() {
@@ -5795,6 +5949,9 @@ function DataTable(_props) {
5795
5949
  },
5796
5950
  get autofocus() {
5797
5951
  return editorAutofocusFor(cell().column.id, wr().vi.index);
5952
+ },
5953
+ get rangeSize() {
5954
+ return inRowEdit() ? 1 : rangeSize();
5798
5955
  }
5799
5956
  }) ?? <input type="text" data-editing-cell="" data-builtin-editor="" aria-invalid={rozieAttr(invalidMsg() ? "true" : null)} class={"rdt-cell-editor"} value={editorValueFor(cell().column.id)} onInput={($event) => {
5800
5957
  onCellEditorInput(cell().column.id, $event);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rozie-ui/data-table-solid",
3
- "version": "0.8.1",
3
+ "version": "0.9.1",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "license": "MIT",
@@ -48,7 +48,7 @@
48
48
  ],
49
49
  "dependencies": {
50
50
  "@solid-primitives/keyed": "^1.5.3",
51
- "@rozie/runtime-solid": "^0.10.1"
51
+ "@rozie/runtime-solid": "^0.10.2"
52
52
  },
53
53
  "peerDependencies": {
54
54
  "solid-js": "^1.8",