flexdesk 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -0
- package/css/base.css +2 -2
- package/css/flexdesk.css +78 -2
- package/css/tokens.css +4 -0
- package/dist/charts.js +2 -2
- package/dist/{chunk-EHHTKD7B.js → chunk-2LEJQD4H.js} +2 -2
- package/dist/{chunk-6CGH73BC.js → chunk-M2L4XW2U.js} +224 -31
- package/dist/chunk-M2L4XW2U.js.map +7 -0
- package/dist/flexdesk.css +78 -2
- package/dist/flow.js +1 -1
- package/dist/tiles.js +2 -2
- package/dist/tokens.css +4 -0
- package/dist/widgets.js +1 -1
- package/package.json +1 -1
- package/src/ui/components/data_table.js +266 -31
- package/dist/chunk-6CGH73BC.js.map +0 -7
- /package/dist/{chunk-EHHTKD7B.js.map → chunk-2LEJQD4H.js.map} +0 -0
package/README.md
CHANGED
|
@@ -885,6 +885,39 @@ list.setColumnVisible(3, true);
|
|
|
885
885
|
A column sorted on and then hidden keeps the order; its arrow comes back with
|
|
886
886
|
the column.
|
|
887
887
|
|
|
888
|
+
### DataTable: a select mode (0.12.0)
|
|
889
|
+
|
|
890
|
+
A list whose click opens a row can still let people pick many rows: a toggle
|
|
891
|
+
in the table's own header turns on a select mode, with a checkbox per row and
|
|
892
|
+
a click that ticks instead of opening. A table that sets none of these options
|
|
893
|
+
draws and behaves as in 0.11.
|
|
894
|
+
|
|
895
|
+
```js
|
|
896
|
+
const list = DataTable.mount(host, {
|
|
897
|
+
headers, rows,
|
|
898
|
+
getRowKey: (row) => row[0], // keeps the ticks across new rows
|
|
899
|
+
onRowActivate: (i, row) => open(row), // not called while selecting
|
|
900
|
+
selectToggle: true,
|
|
901
|
+
onSelectModeChange: (on) => bar.hidden = !on,
|
|
902
|
+
onSelectionChange: (ticked) => bar.count = ticked.length,
|
|
903
|
+
});
|
|
904
|
+
list.setSelectMode(true);
|
|
905
|
+
```
|
|
906
|
+
|
|
907
|
+
| Option | What it does |
|
|
908
|
+
|---|---|
|
|
909
|
+
| `selectToggle: true` | Draws a narrow leading column whose header holds a toggle button. While the mode is on, every row shows a checkbox and the header a select-all box. Needs a multi-row `selectable` (on `false` or `'single'` it is ignored, with a console warning). |
|
|
910
|
+
| `selectMode: true` | Starts in the mode. Draws the column even without `selectToggle`; the consumer then leaves the mode with `setSelectMode(false)`. |
|
|
911
|
+
| `setSelectMode(on)` / `isSelectMode()` | Turns the mode on or off from code (returns whether it changed), and says whether it is on. The selection is kept either way. |
|
|
912
|
+
| `onSelectModeChange(on)` | Called after every change of the mode: the toggle, Escape, `setSelectMode`. |
|
|
913
|
+
| In the mode | A plain click or Space ticks or unticks one row; Shift-click adds the range from the last row ticked. The arrows move a cursor without changing the ticks (Shift ticks the rows passed). A right-click keeps the ticks. Escape clears them, and a second Escape leaves the mode. Nothing opens a row: `onRowActivate` is not called (`onRowClick` still is, so a consumer that opens rows from it checks `isSelectMode()`). New rows (`setData`) keep the ticks by `getRowKey`. |
|
|
914
|
+
| Select-all | Ticks every row the filters let through, on every page; when all are ticked it clears them. It shows checked, mixed or clear. |
|
|
915
|
+
|
|
916
|
+
The select column is not a data column: it is not in a copy, a CSV,
|
|
917
|
+
`ctx.colIdx` or `hiddenColumns`, and it cannot be resized. It is drawn for the
|
|
918
|
+
table's whole life, so remembered widths stay on their columns when the mode
|
|
919
|
+
flips, and widths saved by a table without it land on the same columns.
|
|
920
|
+
|
|
888
921
|
### Scrollbars
|
|
889
922
|
|
|
890
923
|
`installAutoScrollbars(root)` (from `@flexdesk/widgets`) replaces the browser's
|
package/css/base.css
CHANGED
|
@@ -6001,7 +6001,7 @@ button.twm-about-dialog__btn--close:focus {
|
|
|
6001
6001
|
/* ── the popover both pickers are drawn in ──────────────────────────── */
|
|
6002
6002
|
.twm-flow-popover {
|
|
6003
6003
|
position: fixed;
|
|
6004
|
-
z-index: var(--z-
|
|
6004
|
+
z-index: var(--z-over-windows, 7100); /* over the managed window it opened from */
|
|
6005
6005
|
display: flex;
|
|
6006
6006
|
flex-direction: column;
|
|
6007
6007
|
box-sizing: border-box;
|
|
@@ -7328,7 +7328,7 @@ button.twm-about-dialog__btn--close:focus {
|
|
|
7328
7328
|
/* the grip drag: a ghost under the pointer, and a drop line naming the place */
|
|
7329
7329
|
.twm-flow-outline__ghost {
|
|
7330
7330
|
position: fixed;
|
|
7331
|
-
z-index: var(--z-
|
|
7331
|
+
z-index: var(--z-over-windows, 7100); /* over the managed window it opened from */
|
|
7332
7332
|
box-sizing: border-box;
|
|
7333
7333
|
display: flex;
|
|
7334
7334
|
align-items: center;
|
package/css/flexdesk.css
CHANGED
|
@@ -706,6 +706,82 @@ body.twm-dt-col-resizing {
|
|
|
706
706
|
.twm-preview-table tbody tr.twm-dt-row--active > td:first-child {
|
|
707
707
|
box-shadow: inset 2px 0 0 0 var(--accent-bright, #007acc);
|
|
708
708
|
}
|
|
709
|
+
/* STORY-0016 `selectToggle` / `selectMode` — the select column. Narrow, never
|
|
710
|
+
* the time column (it is the first child, so the time rules reach it: (0,3,2)
|
|
711
|
+
* here beats them), and the time styling moves to the first column after it,
|
|
712
|
+
* so a table looks as it did before the column was added. Its boxes show only
|
|
713
|
+
* in select mode; the header's toggle always. */
|
|
714
|
+
.twm-preview-table.twm-dt--select tr > .twm-dt-select-cell {
|
|
715
|
+
width: 32px;
|
|
716
|
+
min-width: 0;
|
|
717
|
+
max-width: none;
|
|
718
|
+
padding-left: 6px;
|
|
719
|
+
padding-right: 2px;
|
|
720
|
+
text-align: left;
|
|
721
|
+
color: inherit;
|
|
722
|
+
font-weight: inherit;
|
|
723
|
+
white-space: nowrap;
|
|
724
|
+
}
|
|
725
|
+
.twm-preview-table.twm-dt--select:not(.twm-dt--first-plain) tr > .twm-dt-select-cell + th,
|
|
726
|
+
.twm-preview-table.twm-dt--select:not(.twm-dt--first-plain) tr > .twm-dt-select-cell + td {
|
|
727
|
+
width: 120px;
|
|
728
|
+
min-width: 100px;
|
|
729
|
+
font-weight: 500;
|
|
730
|
+
color: #bbb;
|
|
731
|
+
}
|
|
732
|
+
.twm-preview-table.twm-dt--select:not(.twm-dt--first-plain) tr > th.twm-dt-select-cell + th {
|
|
733
|
+
font-weight: 600;
|
|
734
|
+
color: #aaa;
|
|
735
|
+
}
|
|
736
|
+
.twm-preview-table.twm-dt--select td.twm-dt-select-cell .twm-dt-select-box {
|
|
737
|
+
display: none;
|
|
738
|
+
margin: 0;
|
|
739
|
+
vertical-align: middle;
|
|
740
|
+
cursor: pointer;
|
|
741
|
+
}
|
|
742
|
+
.twm-preview-table.twm-dt--selecting td.twm-dt-select-cell .twm-dt-select-box {
|
|
743
|
+
display: inline-block;
|
|
744
|
+
}
|
|
745
|
+
.twm-preview-table.twm-dt--select th.twm-dt-select-cell .twm-dt-select-all {
|
|
746
|
+
margin: 0 4px 0 0;
|
|
747
|
+
vertical-align: middle;
|
|
748
|
+
cursor: pointer;
|
|
749
|
+
}
|
|
750
|
+
.twm-preview-table.twm-dt--select th.twm-dt-select-cell .twm-dt-select-toggle {
|
|
751
|
+
display: inline-flex;
|
|
752
|
+
align-items: center;
|
|
753
|
+
justify-content: center;
|
|
754
|
+
width: 20px;
|
|
755
|
+
height: 20px;
|
|
756
|
+
margin: -3px 0;
|
|
757
|
+
padding: 0;
|
|
758
|
+
border: 0;
|
|
759
|
+
border-radius: 3px;
|
|
760
|
+
background: transparent;
|
|
761
|
+
color: inherit;
|
|
762
|
+
font-size: 16px;
|
|
763
|
+
line-height: 1;
|
|
764
|
+
vertical-align: middle;
|
|
765
|
+
cursor: pointer;
|
|
766
|
+
opacity: 0.7;
|
|
767
|
+
}
|
|
768
|
+
.twm-preview-table.twm-dt--select th.twm-dt-select-cell .twm-dt-select-toggle:hover,
|
|
769
|
+
.twm-preview-table.twm-dt--select th.twm-dt-select-cell .twm-dt-select-toggle[aria-pressed="true"] {
|
|
770
|
+
opacity: 1;
|
|
771
|
+
background: rgba(255, 255, 255, 0.08);
|
|
772
|
+
}
|
|
773
|
+
.twm-preview-table.twm-dt--select th.twm-dt-select-cell .twm-dt-select-toggle:focus-visible {
|
|
774
|
+
opacity: 1;
|
|
775
|
+
outline: 1px solid var(--accent-bright, #007acc);
|
|
776
|
+
}
|
|
777
|
+
/* In the mode a click ticks: a pointer on every row, and the keyboard's row
|
|
778
|
+
* (the arrows move it, Space ticks it) drawn as an outline. */
|
|
779
|
+
.twm-preview-table.twm-dt--selecting tbody tr:not(.twm-dt-spacer):not(.data-table__empty-row) {
|
|
780
|
+
cursor: pointer;
|
|
781
|
+
}
|
|
782
|
+
.twm-preview-table.twm-dt--selecting tbody tr.twm-dt-row--cursor > td {
|
|
783
|
+
box-shadow: inset 0 1px 0 0 var(--accent-bright, #007acc), inset 0 -1px 0 0 var(--accent-bright, #007acc);
|
|
784
|
+
}
|
|
709
785
|
/* `rowIcon` — drawn from `data-twm-icon` so the icon's NAME is not cell
|
|
710
786
|
* text (not in a copy, not in the clipped-cell tooltip). The span carries the
|
|
711
787
|
* icon font's class; the pseudo-element inherits its font and ligatures. Top
|
|
@@ -8536,7 +8612,7 @@ tr:hover .twm-row-action { opacity: 1; }
|
|
|
8536
8612
|
/* ── the popover both pickers are drawn in ──────────────────────────── */
|
|
8537
8613
|
.twm-flow-popover {
|
|
8538
8614
|
position: fixed;
|
|
8539
|
-
z-index: var(--z-
|
|
8615
|
+
z-index: var(--z-over-windows, 7100); /* over the managed window it opened from */
|
|
8540
8616
|
display: flex;
|
|
8541
8617
|
flex-direction: column;
|
|
8542
8618
|
box-sizing: border-box;
|
|
@@ -9863,7 +9939,7 @@ tr:hover .twm-row-action { opacity: 1; }
|
|
|
9863
9939
|
/* the grip drag: a ghost under the pointer, and a drop line naming the place */
|
|
9864
9940
|
.twm-flow-outline__ghost {
|
|
9865
9941
|
position: fixed;
|
|
9866
|
-
z-index: var(--z-
|
|
9942
|
+
z-index: var(--z-over-windows, 7100); /* over the managed window it opened from */
|
|
9867
9943
|
box-sizing: border-box;
|
|
9868
9944
|
display: flex;
|
|
9869
9945
|
align-items: center;
|
package/css/tokens.css
CHANGED
|
@@ -115,6 +115,10 @@
|
|
|
115
115
|
--z-popover: 200;
|
|
116
116
|
--z-modal: 1000;
|
|
117
117
|
--z-toast: 10000;
|
|
118
|
+
/* What opens FROM a managed window and must draw over it: managed windows
|
|
119
|
+
stack from 6000 to 6999 (managed_window.js), so a popover at
|
|
120
|
+
--z-popover would open behind the window that opened it. */
|
|
121
|
+
--z-over-windows: 7100;
|
|
118
122
|
|
|
119
123
|
/* ── Transitions ──────────────────────────────────────────── */
|
|
120
124
|
--transition-fast: 120ms ease;
|
package/dist/charts.js
CHANGED
|
@@ -39,10 +39,10 @@ import {
|
|
|
39
39
|
setPlotlySource,
|
|
40
40
|
uid,
|
|
41
41
|
updateChart
|
|
42
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-2LEJQD4H.js";
|
|
43
43
|
import {
|
|
44
44
|
createRafResizeObserver
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-M2L4XW2U.js";
|
|
46
46
|
import {
|
|
47
47
|
ManagedWindow
|
|
48
48
|
} from "./chunk-6JSOVNID.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DataTable,
|
|
3
3
|
createRafResizeObserver
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-M2L4XW2U.js";
|
|
5
5
|
import {
|
|
6
6
|
ManagedWindow
|
|
7
7
|
} from "./chunk-6JSOVNID.js";
|
|
@@ -2370,4 +2370,4 @@ export {
|
|
|
2370
2370
|
openPlotPopoutWindow,
|
|
2371
2371
|
openRawTracesWindow
|
|
2372
2372
|
};
|
|
2373
|
-
//# sourceMappingURL=chunk-
|
|
2373
|
+
//# sourceMappingURL=chunk-2LEJQD4H.js.map
|
|
@@ -763,8 +763,21 @@ var DataTable = class {
|
|
|
763
763
|
hiddenColumns: null,
|
|
764
764
|
columnChooser: false,
|
|
765
765
|
onColumnsChange: null,
|
|
766
|
+
// STORY-0016. Off — no select column, as in 0.11 — until set.
|
|
767
|
+
selectToggle: false,
|
|
768
|
+
selectMode: false,
|
|
769
|
+
onSelectModeChange: null,
|
|
766
770
|
...config
|
|
767
771
|
};
|
|
772
|
+
{
|
|
773
|
+
const sel = this.config.selectable;
|
|
774
|
+
const asked = !!this.config.selectToggle || !!this.config.selectMode;
|
|
775
|
+
this._gutter = asked && !!sel && sel !== "single";
|
|
776
|
+
if (asked && !this._gutter) {
|
|
777
|
+
console.warn("[DataTable] selectToggle/selectMode need a multi-row `selectable`; ignored.");
|
|
778
|
+
}
|
|
779
|
+
this._selecting = this._gutter && !!this.config.selectMode;
|
|
780
|
+
}
|
|
768
781
|
this._expanded = new Set((this.config.expandedRows || []).map((k) => String(k)));
|
|
769
782
|
this._detailHeights = /* @__PURE__ */ new Map();
|
|
770
783
|
this._source = null;
|
|
@@ -879,8 +892,10 @@ var DataTable = class {
|
|
|
879
892
|
}
|
|
880
893
|
if (blob.colWidths && typeof blob.colWidths === "object") {
|
|
881
894
|
this._colWidths = {};
|
|
895
|
+
const shift = this._lead().select - (Number(blob.colWidthsLead) || 0);
|
|
882
896
|
for (const [k, v] of Object.entries(blob.colWidths)) {
|
|
883
|
-
|
|
897
|
+
const i = Number(k) + shift;
|
|
898
|
+
if (i >= this._lead().select) this._colWidths[i] = v;
|
|
884
899
|
}
|
|
885
900
|
this._colWidthsSig = this._colSig();
|
|
886
901
|
applied = true;
|
|
@@ -906,6 +921,9 @@ var DataTable = class {
|
|
|
906
921
|
sortAscending: this._state.sortAscending,
|
|
907
922
|
filters: [...this._state.filters.entries()],
|
|
908
923
|
colWidths: { ...this._colWidths },
|
|
924
|
+
// STORY-0016. Where the widths start, so a blob read by a table
|
|
925
|
+
// with or without the select column lands on the same columns.
|
|
926
|
+
...this._gutter ? { colWidthsLead: 1 } : {},
|
|
909
927
|
// STORY-0010. Only for a table that asked: one that did not writes
|
|
910
928
|
// the 0.9.1 blob, key for key.
|
|
911
929
|
...this.config.persistPage ? { offset: this._state.offset } : {},
|
|
@@ -935,18 +953,24 @@ var DataTable = class {
|
|
|
935
953
|
/** The cells a drawn row has: the shown columns, and the row number. */
|
|
936
954
|
_domColCount() {
|
|
937
955
|
const n = Math.max(0, (this.config.headers?.length || 0) - this._hidden.size);
|
|
938
|
-
return n +
|
|
956
|
+
return n + this._lead().all;
|
|
957
|
+
}
|
|
958
|
+
/** STORY-0016. The drawn columns in front of the data: the select column
|
|
959
|
+
* (`select`, 0 or 1, always first) and the row number. */
|
|
960
|
+
_lead() {
|
|
961
|
+
const select = this._gutter ? 1 : 0;
|
|
962
|
+
return { select, all: select + (this.config.showRowNumbers ? 1 : 0) };
|
|
939
963
|
}
|
|
940
964
|
/** A data column's drawn index (row number included), or -1 when hidden. */
|
|
941
965
|
_domIdxOf(colIdx) {
|
|
942
966
|
if (this._isHidden(colIdx)) return -1;
|
|
943
|
-
let dom = this.
|
|
967
|
+
let dom = this._lead().all;
|
|
944
968
|
for (const h of this._hidden) if (h < colIdx) dom--;
|
|
945
969
|
return dom + colIdx;
|
|
946
970
|
}
|
|
947
971
|
/** A drawn cell's data column, or null for the row number. */
|
|
948
972
|
_dataIdxOfDom(domIdx) {
|
|
949
|
-
let i = domIdx -
|
|
973
|
+
let i = domIdx - this._lead().all;
|
|
950
974
|
if (i < 0) return null;
|
|
951
975
|
const n = this.config.headers?.length || 0;
|
|
952
976
|
for (let c = 0; c < n; c++) {
|
|
@@ -993,7 +1017,7 @@ var DataTable = class {
|
|
|
993
1017
|
this._setHidden([...next]);
|
|
994
1018
|
if (kept) {
|
|
995
1019
|
const widths = {};
|
|
996
|
-
|
|
1020
|
+
for (let i = 0; i < this._lead().all; i++) if (old[i] != null) widths[i] = old[i];
|
|
997
1021
|
for (let c = 0; c < n; c++) {
|
|
998
1022
|
const from = domBefore[c];
|
|
999
1023
|
const to = this._domIdxOf(c);
|
|
@@ -1039,6 +1063,7 @@ var DataTable = class {
|
|
|
1039
1063
|
* @param {Object} updates - Partial config updates (headers, rows, etc.)
|
|
1040
1064
|
*/
|
|
1041
1065
|
setData(updates) {
|
|
1066
|
+
const keepTicks = updates.rows && this._selecting && typeof this.config.getRowKey === "function" && this._state.selected.size ? new Set(this.getSelection().map((i) => this._rowKey(this.config.rows[i], i)).filter((k) => k !== null)) : null;
|
|
1042
1067
|
if (updates.headers && this._state.filters.size > 0) {
|
|
1043
1068
|
const oldHeaders = this.config.headers;
|
|
1044
1069
|
const newHeaders = updates.headers;
|
|
@@ -1087,9 +1112,15 @@ var DataTable = class {
|
|
|
1087
1112
|
if (Object.prototype.hasOwnProperty.call(updates, "columnTypes") && !updates.rows) {
|
|
1088
1113
|
this._columnTypes = this._detectColumnTypes();
|
|
1089
1114
|
}
|
|
1115
|
+
if (keepTicks) {
|
|
1116
|
+
(this.config.rows || []).forEach((r, i) => {
|
|
1117
|
+
if (keepTicks.has(this._rowKey(r, i))) this._state.selected.add(i);
|
|
1118
|
+
});
|
|
1119
|
+
}
|
|
1090
1120
|
this._processedRows = null;
|
|
1091
1121
|
this._processedIndexMap = null;
|
|
1092
1122
|
this.render();
|
|
1123
|
+
if (keepTicks) this._notifySelectionChange();
|
|
1093
1124
|
}
|
|
1094
1125
|
/**
|
|
1095
1126
|
* Show / hide a translucent loading overlay over the table body.
|
|
@@ -1414,6 +1445,7 @@ var DataTable = class {
|
|
|
1414
1445
|
headerTable.className = this._tableClassName();
|
|
1415
1446
|
const thead = document.createElement("thead");
|
|
1416
1447
|
const tr = document.createElement("tr");
|
|
1448
|
+
if (this._gutter) tr.appendChild(this._buildSelectHead());
|
|
1417
1449
|
if (showRowNumbers) {
|
|
1418
1450
|
const th = document.createElement("th");
|
|
1419
1451
|
th.className = "num";
|
|
@@ -1922,6 +1954,11 @@ var DataTable = class {
|
|
|
1922
1954
|
const { showRowNumbers } = this.config;
|
|
1923
1955
|
const tr = document.createElement("tr");
|
|
1924
1956
|
tr.className = "twm-data-table__filter-row";
|
|
1957
|
+
if (this._gutter) {
|
|
1958
|
+
const th = document.createElement("th");
|
|
1959
|
+
th.className = "data-table__filter-cell data-table__filter-cell--empty twm-dt-select-cell";
|
|
1960
|
+
tr.appendChild(th);
|
|
1961
|
+
}
|
|
1925
1962
|
if (showRowNumbers) {
|
|
1926
1963
|
const th = document.createElement("th");
|
|
1927
1964
|
th.className = "data-table__filter-cell data-table__filter-cell--empty";
|
|
@@ -2268,7 +2305,7 @@ var DataTable = class {
|
|
|
2268
2305
|
if (!row) return null;
|
|
2269
2306
|
const cells = Array.from(row.children);
|
|
2270
2307
|
const idx = cells.indexOf(cell);
|
|
2271
|
-
return this.
|
|
2308
|
+
return this._dataIdxOfDom(idx);
|
|
2272
2309
|
}
|
|
2273
2310
|
_restoreFilterFocus(colIdx) {
|
|
2274
2311
|
const filterRow = this._wrapperEl?.querySelector(".twm-data-table__filter-row");
|
|
@@ -2740,6 +2777,7 @@ var DataTable = class {
|
|
|
2740
2777
|
table.tabIndex = 0;
|
|
2741
2778
|
const thead = document.createElement("thead");
|
|
2742
2779
|
const headerRow = document.createElement("tr");
|
|
2780
|
+
if (this._gutter) headerRow.appendChild(this._buildSelectHead());
|
|
2743
2781
|
if (showRowNumbers) {
|
|
2744
2782
|
const th = document.createElement("th");
|
|
2745
2783
|
th.className = "num";
|
|
@@ -2898,7 +2936,7 @@ var DataTable = class {
|
|
|
2898
2936
|
const colgroup = document.createElement("colgroup");
|
|
2899
2937
|
for (let i = 0; i < n; i++) {
|
|
2900
2938
|
const col = document.createElement("col");
|
|
2901
|
-
const w = this._colWidths?.[i];
|
|
2939
|
+
const w = i < this._lead().select ? this._selectColWidth() : this._colWidths?.[i];
|
|
2902
2940
|
if (w != null && this._colWidthsSig === this._colSig()) col.style.width = `${w}px`;
|
|
2903
2941
|
colgroup.appendChild(col);
|
|
2904
2942
|
}
|
|
@@ -3306,6 +3344,18 @@ var DataTable = class {
|
|
|
3306
3344
|
* update than it did on load. */
|
|
3307
3345
|
_fillRowCells(tr, row, globalIdx, showRowNumbers) {
|
|
3308
3346
|
tr.replaceChildren();
|
|
3347
|
+
if (this._gutter) {
|
|
3348
|
+
const td = document.createElement("td");
|
|
3349
|
+
td.className = "twm-dt-select-cell";
|
|
3350
|
+
const box = document.createElement("input");
|
|
3351
|
+
box.type = "checkbox";
|
|
3352
|
+
box.className = "twm-dt-select-box";
|
|
3353
|
+
box.tabIndex = -1;
|
|
3354
|
+
box.checked = this._state.selected.has(globalIdx);
|
|
3355
|
+
box.setAttribute("aria-label", "Select row");
|
|
3356
|
+
td.appendChild(box);
|
|
3357
|
+
tr.appendChild(td);
|
|
3358
|
+
}
|
|
3309
3359
|
if (showRowNumbers) {
|
|
3310
3360
|
const td = document.createElement("td");
|
|
3311
3361
|
td.className = "num";
|
|
@@ -3418,7 +3468,7 @@ var DataTable = class {
|
|
|
3418
3468
|
minWidth: td.style.minWidth,
|
|
3419
3469
|
maxWidth: td.style.maxWidth
|
|
3420
3470
|
})) : null;
|
|
3421
|
-
const showRowNumbers = this.config.showRowNumbers !== false && tr.
|
|
3471
|
+
const showRowNumbers = this.config.showRowNumbers !== false && !!tr.querySelector(":scope > td.num");
|
|
3422
3472
|
this._fillRowCells(tr, row, index, showRowNumbers);
|
|
3423
3473
|
if (widths) {
|
|
3424
3474
|
widths.forEach((saved, i) => {
|
|
@@ -4575,6 +4625,8 @@ var DataTable = class {
|
|
|
4575
4625
|
const names = this.config.readonly ? ["twm-preview-table", "twm-preview-table--readonly"] : ["twm-preview-table"];
|
|
4576
4626
|
if (this.config.firstColumn === "plain") names.push("twm-dt--first-plain");
|
|
4577
4627
|
if (this._isClickable()) names.push("twm-dt--clickable");
|
|
4628
|
+
if (this._gutter) names.push("twm-dt--select");
|
|
4629
|
+
if (this._selecting) names.push("twm-dt--selecting");
|
|
4578
4630
|
return names.join(" ");
|
|
4579
4631
|
}
|
|
4580
4632
|
/** `clickable` when it is said; otherwise exactly when rows open. */
|
|
@@ -4658,6 +4710,7 @@ var DataTable = class {
|
|
|
4658
4710
|
const multi = !!sel && sel !== "single";
|
|
4659
4711
|
const fire = (tr, ev) => {
|
|
4660
4712
|
if (!this._wrapperEl || typeof this.config.onRowActivate !== "function") return;
|
|
4713
|
+
if (this._selecting) return;
|
|
4661
4714
|
try {
|
|
4662
4715
|
this.config.onRowActivate(tr.__rowIndex, tr.__row, ev);
|
|
4663
4716
|
} catch (err) {
|
|
@@ -5018,7 +5071,7 @@ var DataTable = class {
|
|
|
5018
5071
|
*/
|
|
5019
5072
|
autoSizeColumn(domIdx, opts = {}) {
|
|
5020
5073
|
const natural = this._measureNaturalWidths({ sample: true });
|
|
5021
|
-
if (!natural || domIdx <
|
|
5074
|
+
if (!natural || domIdx < this._lead().select || domIdx >= natural.length) return false;
|
|
5022
5075
|
this._colWidths[domIdx] = this._autoWidth(natural[domIdx], opts);
|
|
5023
5076
|
this._colWidthsSig = this._colSig();
|
|
5024
5077
|
this._savePersisted();
|
|
@@ -5044,7 +5097,7 @@ var DataTable = class {
|
|
|
5044
5097
|
const natural = this._measureNaturalWidths({ sample: true });
|
|
5045
5098
|
if (!natural) return false;
|
|
5046
5099
|
this._colWidths = {};
|
|
5047
|
-
for (let i =
|
|
5100
|
+
for (let i = this._lead().select; i < natural.length; i++) {
|
|
5048
5101
|
this._colWidths[i] = this._autoWidth(natural[i], opts);
|
|
5049
5102
|
}
|
|
5050
5103
|
this._colWidthsSig = this._colSig();
|
|
@@ -5076,7 +5129,7 @@ var DataTable = class {
|
|
|
5076
5129
|
*/
|
|
5077
5130
|
_allColumnsPinned(n) {
|
|
5078
5131
|
if (!n || this._colWidthsSig !== this._colSig()) return false;
|
|
5079
|
-
for (let i =
|
|
5132
|
+
for (let i = this._lead().select; i < n; i++) {
|
|
5080
5133
|
if (this._colWidths[i] == null) return false;
|
|
5081
5134
|
}
|
|
5082
5135
|
return true;
|
|
@@ -5101,10 +5154,12 @@ var DataTable = class {
|
|
|
5101
5154
|
const wrap = this._tableWrapEl;
|
|
5102
5155
|
const headerWrap = this._headerWrapEl;
|
|
5103
5156
|
const avail = wrap ? wrap.clientWidth : 0;
|
|
5104
|
-
const
|
|
5157
|
+
const lead = this._lead().all;
|
|
5158
|
+
const firstIdx = lead && n > lead ? lead : 0;
|
|
5105
5159
|
const widths = this._fitColumnWidths(natural, avail, {
|
|
5106
5160
|
firstIdx,
|
|
5107
|
-
|
|
5161
|
+
// STORY-0016. The select column is as wide as its controls, always.
|
|
5162
|
+
overrides: this._gutter ? { ...this._colWidths, 0: this._selectColWidth() } : this._colWidths,
|
|
5108
5163
|
fit: this.config.columnFit,
|
|
5109
5164
|
floors: this._filterFloors
|
|
5110
5165
|
});
|
|
@@ -5336,6 +5391,7 @@ var DataTable = class {
|
|
|
5336
5391
|
if (!headRow) return;
|
|
5337
5392
|
[...headRow.children].forEach((th, domIdx) => {
|
|
5338
5393
|
if (th.querySelector(".twm-dt-col-resizer")) return;
|
|
5394
|
+
if (th.classList.contains("twm-dt-select-cell")) return;
|
|
5339
5395
|
th.classList.add("twm-dt-col");
|
|
5340
5396
|
const grip = document.createElement("div");
|
|
5341
5397
|
grip.className = "twm-dt-col-resizer";
|
|
@@ -5508,6 +5564,19 @@ var DataTable = class {
|
|
|
5508
5564
|
if (!(was && (event.metaKey || event.ctrlKey))) selected.add(idx);
|
|
5509
5565
|
else DESELECTING_CLICKS.add(event);
|
|
5510
5566
|
this._state.anchorIndex = selected.size ? idx : null;
|
|
5567
|
+
} else if (this._selecting) {
|
|
5568
|
+
if (event.shiftKey && this._state.anchorIndex != null) {
|
|
5569
|
+
const order = this._processedIndexMap || this.config.rows.map((_, i) => i);
|
|
5570
|
+
const a = order.indexOf(this._state.anchorIndex);
|
|
5571
|
+
const b = order.indexOf(idx);
|
|
5572
|
+
if (a >= 0 && b >= 0) {
|
|
5573
|
+
for (let i = Math.min(a, b); i <= Math.max(a, b); i++) selected.add(order[i]);
|
|
5574
|
+
} else selected.add(idx);
|
|
5575
|
+
} else if (selected.has(idx)) selected.delete(idx);
|
|
5576
|
+
else selected.add(idx);
|
|
5577
|
+
this._state.anchorIndex = idx;
|
|
5578
|
+
this._navCursor = idx;
|
|
5579
|
+
this._markCursor();
|
|
5511
5580
|
} else if (event.shiftKey && this._state.anchorIndex != null) {
|
|
5512
5581
|
const start = Math.min(this._state.anchorIndex, idx);
|
|
5513
5582
|
const end = Math.max(this._state.anchorIndex, idx);
|
|
@@ -5559,7 +5628,7 @@ var DataTable = class {
|
|
|
5559
5628
|
if (!order.length) return;
|
|
5560
5629
|
ev.preventDefault();
|
|
5561
5630
|
const selected = this._state.selected;
|
|
5562
|
-
const cur = this._navCursor != null && selected.has(this._navCursor) ? this._navCursor : this._state.anchorIndex;
|
|
5631
|
+
const cur = this._navCursor != null && (this._selecting || selected.has(this._navCursor)) ? this._navCursor : this._state.anchorIndex;
|
|
5563
5632
|
let pos = order.indexOf(cur);
|
|
5564
5633
|
if (ev.key === "Home") pos = 0;
|
|
5565
5634
|
else if (ev.key === "End") pos = order.length - 1;
|
|
@@ -5568,6 +5637,20 @@ var DataTable = class {
|
|
|
5568
5637
|
const idx = order[pos];
|
|
5569
5638
|
this._navCursor = idx;
|
|
5570
5639
|
const anchorPos = order.indexOf(this._state.anchorIndex);
|
|
5640
|
+
if (this._selecting) {
|
|
5641
|
+
if (ev.shiftKey) {
|
|
5642
|
+
const from = order.indexOf(cur);
|
|
5643
|
+
if (from >= 0) {
|
|
5644
|
+
for (let i = Math.min(from, pos); i <= Math.max(from, pos); i++) selected.add(order[i]);
|
|
5645
|
+
} else selected.add(idx);
|
|
5646
|
+
this._updateRowSelection();
|
|
5647
|
+
this._notifySelectionChange();
|
|
5648
|
+
}
|
|
5649
|
+
this._state.anchorIndex = idx;
|
|
5650
|
+
this._markCursor();
|
|
5651
|
+
this.scrollToRow(idx);
|
|
5652
|
+
return;
|
|
5653
|
+
}
|
|
5571
5654
|
if (ev.shiftKey && selectable !== "single" && anchorPos !== -1) {
|
|
5572
5655
|
const [a, b] = anchorPos <= pos ? [anchorPos, pos] : [pos, anchorPos];
|
|
5573
5656
|
selected.clear();
|
|
@@ -5584,6 +5667,25 @@ var DataTable = class {
|
|
|
5584
5667
|
table.addEventListener("keydown", onNavKey);
|
|
5585
5668
|
this._disposers.push(() => table.removeEventListener("keydown", onNavKey));
|
|
5586
5669
|
}
|
|
5670
|
+
if (this._gutter) {
|
|
5671
|
+
const onSpace = (ev) => {
|
|
5672
|
+
if (!this._selecting || ev.key !== " " || ev.ctrlKey || ev.metaKey || ev.altKey) return;
|
|
5673
|
+
if (isRowControl(ev.target, table)) return;
|
|
5674
|
+
const idx = this._navCursor ?? this._state.anchorIndex;
|
|
5675
|
+
if (idx == null || !this.config.rows[idx]) return;
|
|
5676
|
+
ev.preventDefault();
|
|
5677
|
+
const selected = this._state.selected;
|
|
5678
|
+
if (selected.has(idx)) selected.delete(idx);
|
|
5679
|
+
else selected.add(idx);
|
|
5680
|
+
this._state.anchorIndex = idx;
|
|
5681
|
+
this._updateRowSelection();
|
|
5682
|
+
this._notifySelectionChange();
|
|
5683
|
+
};
|
|
5684
|
+
table.addEventListener("keydown", onSpace);
|
|
5685
|
+
this._disposers.push(() => table.removeEventListener("keydown", onSpace));
|
|
5686
|
+
this._paintSelectHead();
|
|
5687
|
+
this._markCursor();
|
|
5688
|
+
}
|
|
5587
5689
|
if (typeof this.config.onRowActivate === "function") {
|
|
5588
5690
|
this._installActivation(tbody, table);
|
|
5589
5691
|
}
|
|
@@ -5625,7 +5727,7 @@ var DataTable = class {
|
|
|
5625
5727
|
}
|
|
5626
5728
|
event.preventDefault();
|
|
5627
5729
|
event.stopPropagation();
|
|
5628
|
-
if (idx !== void 0 && !this._state.selected.has(idx)) {
|
|
5730
|
+
if (idx !== void 0 && !this._state.selected.has(idx) && !this._selecting) {
|
|
5629
5731
|
this._state.selected.clear();
|
|
5630
5732
|
this._state.selected.add(idx);
|
|
5631
5733
|
this._state.anchorIndex = idx;
|
|
@@ -5650,20 +5752,7 @@ var DataTable = class {
|
|
|
5650
5752
|
event.preventDefault();
|
|
5651
5753
|
} else if (key === "a" && selectable) {
|
|
5652
5754
|
event.preventDefault();
|
|
5653
|
-
this.
|
|
5654
|
-
const indexMap = this._processedIndexMap;
|
|
5655
|
-
if (indexMap) {
|
|
5656
|
-
for (const originalIdx of indexMap) {
|
|
5657
|
-
this._state.selected.add(originalIdx);
|
|
5658
|
-
}
|
|
5659
|
-
} else {
|
|
5660
|
-
for (let i = 0; i < this.config.rows.length; i++) {
|
|
5661
|
-
this._state.selected.add(i);
|
|
5662
|
-
}
|
|
5663
|
-
}
|
|
5664
|
-
this._state.anchorIndex = this.config.rows.length - 1;
|
|
5665
|
-
this._updateRowSelection();
|
|
5666
|
-
this._notifySelectionChange();
|
|
5755
|
+
this._selectAllShown();
|
|
5667
5756
|
} else if (key === "c") {
|
|
5668
5757
|
event.preventDefault();
|
|
5669
5758
|
this.copyToClipboard(event.shiftKey ? "csv" : "tsv");
|
|
@@ -5671,6 +5760,8 @@ var DataTable = class {
|
|
|
5671
5760
|
} else if (event.key === "Escape") {
|
|
5672
5761
|
if (this._state.selected.size) {
|
|
5673
5762
|
this.clearSelection();
|
|
5763
|
+
} else if (this._selecting && this.config.selectToggle) {
|
|
5764
|
+
this.setSelectMode(false);
|
|
5674
5765
|
}
|
|
5675
5766
|
this._hideContextMenu();
|
|
5676
5767
|
}
|
|
@@ -5684,9 +5775,111 @@ var DataTable = class {
|
|
|
5684
5775
|
this._tbodyEl.querySelectorAll("tr").forEach((tr) => {
|
|
5685
5776
|
const idx = tr.__rowIndex;
|
|
5686
5777
|
if (idx !== void 0) {
|
|
5687
|
-
|
|
5778
|
+
const on = this._state.selected.has(idx);
|
|
5779
|
+
tr.classList.toggle("selected", on);
|
|
5780
|
+
const box = this._gutter ? tr.querySelector(":scope > td.twm-dt-select-cell > input") : null;
|
|
5781
|
+
if (box) box.checked = on;
|
|
5688
5782
|
}
|
|
5689
5783
|
});
|
|
5784
|
+
this._paintSelectHead();
|
|
5785
|
+
}
|
|
5786
|
+
/* ── STORY-0016: select mode ─────────────────────────────────────── */
|
|
5787
|
+
/** Whether the table is in select mode. */
|
|
5788
|
+
isSelectMode() {
|
|
5789
|
+
return !!this._selecting;
|
|
5790
|
+
}
|
|
5791
|
+
/**
|
|
5792
|
+
* Turn select mode on or off. The ticks are kept either way (a selection
|
|
5793
|
+
* is a selection); the consumer clears it if leaving means "never mind".
|
|
5794
|
+
* Does nothing on a table without the select column.
|
|
5795
|
+
*
|
|
5796
|
+
* @param {boolean} on
|
|
5797
|
+
* @returns {boolean} whether the mode changed
|
|
5798
|
+
*/
|
|
5799
|
+
setSelectMode(on) {
|
|
5800
|
+
if (!this._gutter || !!on === this._selecting) return false;
|
|
5801
|
+
this._selecting = !!on;
|
|
5802
|
+
this._navCursor = this._selecting ? this._state.anchorIndex : null;
|
|
5803
|
+
if (this._wrapperEl) this.render();
|
|
5804
|
+
try {
|
|
5805
|
+
this.config.onSelectModeChange?.(this._selecting);
|
|
5806
|
+
} catch (err) {
|
|
5807
|
+
console.error("[DataTable] onSelectModeChange threw", err);
|
|
5808
|
+
}
|
|
5809
|
+
return true;
|
|
5810
|
+
}
|
|
5811
|
+
/** The rows the filters let through, on every page, by original index. */
|
|
5812
|
+
_shownIndices() {
|
|
5813
|
+
if (this._isServerSide()) return this.config.rows.map((_, i) => i);
|
|
5814
|
+
this._getProcessedRows();
|
|
5815
|
+
return this._processedIndexMap ? [...this._processedIndexMap] : this.config.rows.map((_, i) => i);
|
|
5816
|
+
}
|
|
5817
|
+
/** Ctrl+A and the select-all box: every row the filters let through. */
|
|
5818
|
+
_selectAllShown() {
|
|
5819
|
+
this._state.selected.clear();
|
|
5820
|
+
for (const i of this._shownIndices()) this._state.selected.add(i);
|
|
5821
|
+
this._state.anchorIndex = this.config.rows.length - 1;
|
|
5822
|
+
this._updateRowSelection();
|
|
5823
|
+
this._notifySelectionChange();
|
|
5824
|
+
}
|
|
5825
|
+
/** The select column's width: its controls, never a drag. */
|
|
5826
|
+
_selectColWidth() {
|
|
5827
|
+
return this._selecting ? this.config.selectToggle ? 56 : 32 : 32;
|
|
5828
|
+
}
|
|
5829
|
+
/** The select column's header: the toggle and, in the mode, select-all. */
|
|
5830
|
+
_buildSelectHead() {
|
|
5831
|
+
const th = document.createElement("th");
|
|
5832
|
+
th.className = "twm-dt-select-cell twm-dt-select-head";
|
|
5833
|
+
if (this._selecting) {
|
|
5834
|
+
const all = document.createElement("input");
|
|
5835
|
+
all.type = "checkbox";
|
|
5836
|
+
all.className = "twm-dt-select-all";
|
|
5837
|
+
all.setAttribute("aria-label", "Select all rows");
|
|
5838
|
+
all.title = "Select all rows";
|
|
5839
|
+
all.addEventListener("click", (ev) => {
|
|
5840
|
+
ev.stopPropagation();
|
|
5841
|
+
const shown = this._shownIndices();
|
|
5842
|
+
const every = shown.length > 0 && shown.every((i) => this._state.selected.has(i));
|
|
5843
|
+
if (every) this.clearSelection();
|
|
5844
|
+
else this._selectAllShown();
|
|
5845
|
+
});
|
|
5846
|
+
th.appendChild(all);
|
|
5847
|
+
}
|
|
5848
|
+
if (this.config.selectToggle) {
|
|
5849
|
+
const btn = document.createElement("button");
|
|
5850
|
+
btn.type = "button";
|
|
5851
|
+
btn.className = "material-symbols-outlined twm-dt-select-toggle";
|
|
5852
|
+
btn.textContent = this._selecting ? "close" : "checklist";
|
|
5853
|
+
btn.setAttribute("aria-pressed", this._selecting ? "true" : "false");
|
|
5854
|
+
const label = this._selecting ? "Stop selecting" : "Select multiple";
|
|
5855
|
+
btn.setAttribute("aria-label", label);
|
|
5856
|
+
btn.title = label;
|
|
5857
|
+
btn.addEventListener("click", (ev) => {
|
|
5858
|
+
ev.stopPropagation();
|
|
5859
|
+
this.setSelectMode(!this._selecting);
|
|
5860
|
+
});
|
|
5861
|
+
th.appendChild(btn);
|
|
5862
|
+
}
|
|
5863
|
+
th.classList.toggle("twm-dt-select-head--on", this._selecting);
|
|
5864
|
+
return th;
|
|
5865
|
+
}
|
|
5866
|
+
/** The select-all box: checked, mixed or clear, as the ticks are. */
|
|
5867
|
+
_paintSelectHead() {
|
|
5868
|
+
if (!this._gutter || !this._wrapperEl) return;
|
|
5869
|
+
const all = this._wrapperEl.querySelector(".twm-dt-select-all");
|
|
5870
|
+
if (!all) return;
|
|
5871
|
+
const shown = this._shownIndices();
|
|
5872
|
+
const n = shown.filter((i) => this._state.selected.has(i)).length;
|
|
5873
|
+
all.checked = n > 0 && n === shown.length;
|
|
5874
|
+
all.indeterminate = n > 0 && n < shown.length;
|
|
5875
|
+
}
|
|
5876
|
+
/** The keyboard's row in select mode, marked so it can be seen. */
|
|
5877
|
+
_markCursor() {
|
|
5878
|
+
if (!this._tbodyEl) return;
|
|
5879
|
+
for (const tr of this._tbodyEl.children) {
|
|
5880
|
+
if (tr.__rowIndex === void 0) continue;
|
|
5881
|
+
tr.classList.toggle("twm-dt-row--cursor", this._selecting && tr.__rowIndex === this._navCursor);
|
|
5882
|
+
}
|
|
5690
5883
|
}
|
|
5691
5884
|
_notifySelectionChange() {
|
|
5692
5885
|
this.config.onSelectionChange?.(this.getSelection());
|
|
@@ -5975,4 +6168,4 @@ export {
|
|
|
5975
6168
|
resolvePaging,
|
|
5976
6169
|
DataTable
|
|
5977
6170
|
};
|
|
5978
|
-
//# sourceMappingURL=chunk-
|
|
6171
|
+
//# sourceMappingURL=chunk-M2L4XW2U.js.map
|