@12-apps/ui 6.13.1 → 6.13.2
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/_internal/components/data-display/Carousel/Carousel.js +2 -2
- package/dist/_internal/components/data-display/Chart/Chart.js +3 -3
- package/dist/_internal/components/data-display/Chart/SpecChart.js +6 -6
- package/dist/_internal/components/data-display/Chart/chart-renderers.js +2 -2
- package/dist/_internal/components/data-display/Chart/chart-spec.js +2 -2
- package/dist/_internal/components/data-display/DataGrid/DataGrid.js +1 -1
- package/dist/_internal/components/data-display/DataViews/DataViewsGrid.js +13 -12
- package/dist/_internal/components/data-display/DataViews/DataViewsTableBase.js +18 -17
- package/dist/_internal/components/data-display/DataViews/data-views-filter-panel.js +3 -3
- package/dist/_internal/components/data-display/DataViews/data-views-grid-bodies.js +1 -1
- package/dist/_internal/components/data-display/DataViews/data-views-grid-parts.js +9 -9
- package/dist/_internal/components/data-display/DataViews/data-views-inline-bar.js +5 -5
- package/dist/_internal/components/data-display/DataViews/data-views-more-fields.js +3 -3
- package/dist/_internal/components/data-display/DataViews/data-views-more-filters.js +4 -4
- package/dist/_internal/components/data-display/DataViews/data-views-range-pill.js +2 -2
- package/dist/_internal/components/data-display/DataViews/data-views-selection.js +1 -1
- package/dist/_internal/components/data-display/DataViews/data-views-table-parts.js +2 -2
- package/dist/_internal/components/data-display/DataViews/data-views-writers.js +9 -0
- package/dist/_internal/components/data-display/DataViews/data-views-writers.js.map +1 -0
- package/dist/_internal/components/data-display/DataViews/use-data-views-state.js +3 -2
- package/dist/_internal/components/data-display/index.js +14 -14
- package/dist/_internal/components/index.js +14 -14
- package/dist/charts.js +11 -11
- package/dist/{chunk-BV5XTGKB.js → chunk-2UCJJACD.js} +7 -9
- package/dist/chunk-2UCJJACD.js.map +1 -0
- package/dist/{chunk-IN642YHK.js → chunk-4VNUOSTQ.js} +2 -2
- package/dist/{chunk-XPS7FWZS.js → chunk-4ZEU22L2.js} +4 -4
- package/dist/{chunk-NC2AATCC.js → chunk-6PFBYCBU.js} +2 -2
- package/dist/{chunk-CXA6UNFF.js → chunk-AP3PVR3T.js} +5 -5
- package/dist/{chunk-XULTDO56.js → chunk-BVGR7OYA.js} +4 -4
- package/dist/{chunk-JKLWHENB.js → chunk-HNDUCGM3.js} +3 -3
- package/dist/{chunk-NPEKJXVV.js → chunk-HRJ27X5B.js} +4 -4
- package/dist/chunk-LLZWB32X.js +36 -0
- package/dist/chunk-LLZWB32X.js.map +1 -0
- package/dist/{chunk-ZHPKFV7Y.js → chunk-N6JGYVRY.js} +2 -2
- package/dist/{chunk-JPDKRGYI.js → chunk-PDGAFQ6Z.js} +3 -3
- package/dist/{chunk-T4BFDZGU.js → chunk-Q4ITS2EP.js} +6 -6
- package/dist/{chunk-GOWBYHYW.js → chunk-R6SBP5M5.js} +4 -4
- package/dist/{chunk-DEOC5OI7.js → chunk-RRYQG5Y6.js} +3 -3
- package/dist/{chunk-WLCVOQCJ.js → chunk-RUO4D4N6.js} +3 -3
- package/dist/chunk-U5FOJBLG.js +19 -0
- package/dist/chunk-U5FOJBLG.js.map +1 -0
- package/dist/{chunk-BZTFPSWT.js → chunk-XEE7PLDR.js} +4 -4
- package/dist/data-display/CardKit.js +3 -3
- package/dist/data-display/Carousel.js +2 -2
- package/dist/data-display/Chart.js +11 -11
- package/dist/data-display/DataGrid.js +1 -1
- package/dist/data-display/DataViews.js +19 -18
- package/dist/types/components/data-display/DataViews/data-views-selection.d.ts +31 -2
- package/dist/types/components/data-display/DataViews/data-views-selection.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-writers.d.ts +20 -0
- package/dist/types/components/data-display/DataViews/data-views-writers.d.ts.map +1 -0
- package/dist/types/components/data-display/DataViews/use-data-views-state.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/data-display/DataViews/data-views-selection.ts +61 -6
- package/src/components/data-display/DataViews/data-views-writers.ts +45 -0
- package/src/components/data-display/DataViews/use-data-views-state.ts +4 -11
- package/dist/chunk-BV5XTGKB.js.map +0 -1
- package/dist/chunk-WTOTWP6A.js +0 -27
- package/dist/chunk-WTOTWP6A.js.map +0 -1
- /package/dist/{chunk-IN642YHK.js.map → chunk-4VNUOSTQ.js.map} +0 -0
- /package/dist/{chunk-XPS7FWZS.js.map → chunk-4ZEU22L2.js.map} +0 -0
- /package/dist/{chunk-NC2AATCC.js.map → chunk-6PFBYCBU.js.map} +0 -0
- /package/dist/{chunk-CXA6UNFF.js.map → chunk-AP3PVR3T.js.map} +0 -0
- /package/dist/{chunk-XULTDO56.js.map → chunk-BVGR7OYA.js.map} +0 -0
- /package/dist/{chunk-JKLWHENB.js.map → chunk-HNDUCGM3.js.map} +0 -0
- /package/dist/{chunk-NPEKJXVV.js.map → chunk-HRJ27X5B.js.map} +0 -0
- /package/dist/{chunk-ZHPKFV7Y.js.map → chunk-N6JGYVRY.js.map} +0 -0
- /package/dist/{chunk-JPDKRGYI.js.map → chunk-PDGAFQ6Z.js.map} +0 -0
- /package/dist/{chunk-T4BFDZGU.js.map → chunk-Q4ITS2EP.js.map} +0 -0
- /package/dist/{chunk-GOWBYHYW.js.map → chunk-R6SBP5M5.js.map} +0 -0
- /package/dist/{chunk-DEOC5OI7.js.map → chunk-RRYQG5Y6.js.map} +0 -0
- /package/dist/{chunk-WLCVOQCJ.js.map → chunk-RUO4D4N6.js.map} +0 -0
- /package/dist/{chunk-BZTFPSWT.js.map → chunk-XEE7PLDR.js.map} +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DataViewsTableBase
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-RRYQG5Y6.js";
|
|
4
4
|
import "../chunk-LS42VJAI.js";
|
|
5
5
|
import {
|
|
6
6
|
DataViewsGrid
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-HNDUCGM3.js";
|
|
8
8
|
import {
|
|
9
9
|
BaseListCard
|
|
10
10
|
} from "../chunk-RDYBS45D.js";
|
|
@@ -16,31 +16,32 @@ import {
|
|
|
16
16
|
BaseCard
|
|
17
17
|
} from "../chunk-6U7NA74A.js";
|
|
18
18
|
import "../chunk-MQUU2XZB.js";
|
|
19
|
+
import "../chunk-ZOLAYP2D.js";
|
|
19
20
|
import {
|
|
20
21
|
DragContainerProvider,
|
|
21
22
|
DropIndicator,
|
|
22
23
|
useDragItem
|
|
23
24
|
} from "../chunk-JCJGJX7V.js";
|
|
24
|
-
import "../chunk-
|
|
25
|
-
import "../chunk-
|
|
26
|
-
import "../chunk-IN642YHK.js";
|
|
25
|
+
import "../chunk-Q4ITS2EP.js";
|
|
26
|
+
import "../chunk-4VNUOSTQ.js";
|
|
27
27
|
import "../chunk-S7CAXRRP.js";
|
|
28
|
-
import "../chunk-
|
|
28
|
+
import "../chunk-RUO4D4N6.js";
|
|
29
29
|
import "../chunk-5WNQJ5KS.js";
|
|
30
30
|
import "../chunk-ECIGNYSI.js";
|
|
31
|
-
import "../chunk-
|
|
32
|
-
import "../chunk-
|
|
31
|
+
import "../chunk-N6JGYVRY.js";
|
|
32
|
+
import "../chunk-6PFBYCBU.js";
|
|
33
33
|
import "../chunk-QQE2PVLO.js";
|
|
34
34
|
import {
|
|
35
35
|
DataViewsBoard
|
|
36
36
|
} from "../chunk-3DQP6OPC.js";
|
|
37
|
-
import "../chunk-
|
|
37
|
+
import "../chunk-XEE7PLDR.js";
|
|
38
|
+
import "../chunk-FV36LFPX.js";
|
|
38
39
|
import "../chunk-F4RR4666.js";
|
|
39
40
|
import "../chunk-CBOB5AV6.js";
|
|
40
41
|
import "../chunk-VR5HDUBK.js";
|
|
41
42
|
import "../chunk-TQ6FPOPD.js";
|
|
42
43
|
import "../chunk-IAGOUTI6.js";
|
|
43
|
-
import "../chunk-
|
|
44
|
+
import "../chunk-AWTERXCW.js";
|
|
44
45
|
import "../chunk-2I5B5NNT.js";
|
|
45
46
|
import "../chunk-A7Q5AQVD.js";
|
|
46
47
|
import "../chunk-OGGHD64H.js";
|
|
@@ -53,11 +54,6 @@ import {
|
|
|
53
54
|
import {
|
|
54
55
|
DEFAULT_CELL_WIDTH
|
|
55
56
|
} from "../chunk-6VP2L3DJ.js";
|
|
56
|
-
import "../chunk-XPS7FWZS.js";
|
|
57
|
-
import "../chunk-U7SO3N42.js";
|
|
58
|
-
import "../chunk-UHXNEXOC.js";
|
|
59
|
-
import "../chunk-5M4TYFR3.js";
|
|
60
|
-
import "../chunk-AWTERXCW.js";
|
|
61
57
|
import "../chunk-WXBBWSNU.js";
|
|
62
58
|
import "../chunk-NQCYVYP3.js";
|
|
63
59
|
import "../chunk-HGBZZDP6.js";
|
|
@@ -69,18 +65,23 @@ import {
|
|
|
69
65
|
cardScaleForZoom
|
|
70
66
|
} from "../chunk-ZPIMPOHV.js";
|
|
71
67
|
import "../chunk-QTPKACVO.js";
|
|
68
|
+
import "../chunk-4ZEU22L2.js";
|
|
69
|
+
import "../chunk-UHXNEXOC.js";
|
|
70
|
+
import "../chunk-U7SO3N42.js";
|
|
71
|
+
import "../chunk-5M4TYFR3.js";
|
|
72
72
|
import "../chunk-HR7YTBR7.js";
|
|
73
73
|
import "../chunk-DZEC6RFM.js";
|
|
74
|
-
import "../chunk-
|
|
74
|
+
import "../chunk-2UCJJACD.js";
|
|
75
75
|
import "../chunk-4QQVIGRG.js";
|
|
76
76
|
import "../chunk-YGQX7BNI.js";
|
|
77
77
|
import "../chunk-IMLIIW77.js";
|
|
78
|
-
import "../chunk-
|
|
78
|
+
import "../chunk-LLZWB32X.js";
|
|
79
79
|
import {
|
|
80
80
|
DataViewsScopeTabs,
|
|
81
81
|
assertNoScopePillOverlap,
|
|
82
82
|
resolveScope
|
|
83
83
|
} from "../chunk-LYKV3C7B.js";
|
|
84
|
+
import "../chunk-U5FOJBLG.js";
|
|
84
85
|
import "../chunk-5VZPVDUF.js";
|
|
85
86
|
import {
|
|
86
87
|
CARD_ASPECT_RATIOS,
|
|
@@ -169,8 +170,8 @@ import "../chunk-X5MPHXG5.js";
|
|
|
169
170
|
import "../chunk-DLJGBJZW.js";
|
|
170
171
|
import "../chunk-KZLLTOB2.js";
|
|
171
172
|
import "../chunk-E5LWJDI3.js";
|
|
172
|
-
import "../chunk-5E3XZAED.js";
|
|
173
173
|
import "../chunk-G3E66C6J.js";
|
|
174
|
+
import "../chunk-5E3XZAED.js";
|
|
174
175
|
import "../chunk-SNCSGLJ6.js";
|
|
175
176
|
import "../chunk-TCAB2ERD.js";
|
|
176
177
|
import "../chunk-NUGT7LMR.js";
|
|
@@ -4,7 +4,7 @@ interface DataViewsSelection<T> {
|
|
|
4
4
|
setSelectedIds: (ids: Set<string | number>) => void;
|
|
5
5
|
/** Add/remove ONE id — what a card's or board card's checkbox calls. */
|
|
6
6
|
toggleId: (id: string | number) => void;
|
|
7
|
-
/** The selected rows,
|
|
7
|
+
/** The selected rows, INCLUDING ones the current page no longer renders. */
|
|
8
8
|
selectedRows: T[];
|
|
9
9
|
clearSelection: () => void;
|
|
10
10
|
selectAll: () => void;
|
|
@@ -18,7 +18,36 @@ interface DataViewsSelection<T> {
|
|
|
18
18
|
* because `toggleId` needs a functional update: two cards toggled in the same
|
|
19
19
|
* tick would otherwise both read the pre-render set and the second would drop
|
|
20
20
|
* the first's change.
|
|
21
|
+
*
|
|
22
|
+
* ## A selection has to survive PAGING
|
|
23
|
+
*
|
|
24
|
+
* `selectedIds` always did — nothing clears it when the page changes — but
|
|
25
|
+
* `selectedRows` was `matched.filter(...)`, and in SERVER mode `matched` is one
|
|
26
|
+
* page. So ticking three rows, paging, and ticking two more left the checkboxes
|
|
27
|
+
* claiming five and the bulk action receiving two, silently, with the other
|
|
28
|
+
* three still ticked on a page nobody was looking at.
|
|
29
|
+
*
|
|
30
|
+
* That is the worst shape a bug can have here: the UI and the write disagree,
|
|
31
|
+
* neither says so, and the rows that did not move are exactly the ones out of
|
|
32
|
+
* sight. So a row is REMEMBERED for as long as its id is selected, and
|
|
33
|
+
* `selectedRows` answers from that memory for anything the current page does
|
|
34
|
+
* not hold.
|
|
35
|
+
*
|
|
36
|
+
* **Server mode only** ({@link SelectionOptions.rememberOffPage}), and the
|
|
37
|
+
* distinction is not a hedge. In client mode `matched` is the whole filtered
|
|
38
|
+
* result, so nothing is ever off-page and there is nothing to remember — while
|
|
39
|
+
* narrowing the selection as the FILTER narrows is the behaviour a client-mode
|
|
40
|
+
* grid should keep. Remembering there would mean a bulk action reaching rows
|
|
41
|
+
* the operator has just filtered away.
|
|
21
42
|
*/
|
|
22
|
-
export
|
|
43
|
+
export interface SelectionOptions {
|
|
44
|
+
/**
|
|
45
|
+
* Keep rows the current page no longer renders.
|
|
46
|
+
*
|
|
47
|
+
* True in server mode, where `matched` is a page rather than the result.
|
|
48
|
+
*/
|
|
49
|
+
rememberOffPage?: boolean;
|
|
50
|
+
}
|
|
51
|
+
export declare function useSelection<T>(matched: T[], getRowId: (row: T) => string | number, options?: SelectionOptions): DataViewsSelection<T>;
|
|
23
52
|
export {};
|
|
24
53
|
//# sourceMappingURL=data-views-selection.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-views-selection.d.ts","sourceRoot":"","sources":["../../../../../src/components/data-display/DataViews/data-views-selection.ts"],"names":[],"mappings":"AAIA,+EAA+E;AAC/E,UAAU,kBAAkB,CAAC,CAAC;IAC5B,WAAW,EAAE,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;IAClC,cAAc,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,IAAI,CAAC;IACpD,wEAAwE;IACxE,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC;IACxC,
|
|
1
|
+
{"version":3,"file":"data-views-selection.d.ts","sourceRoot":"","sources":["../../../../../src/components/data-display/DataViews/data-views-selection.ts"],"names":[],"mappings":"AAIA,+EAA+E;AAC/E,UAAU,kBAAkB,CAAC,CAAC;IAC5B,WAAW,EAAE,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;IAClC,cAAc,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,IAAI,CAAC;IACpD,wEAAwE;IACxE,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC;IACxC,4EAA4E;IAC5E,YAAY,EAAE,CAAC,EAAE,CAAC;IAClB,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,wBAAgB,YAAY,CAAC,CAAC,EAC5B,OAAO,EAAE,CAAC,EAAE,EACZ,QAAQ,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,MAAM,GAAG,MAAM,EACrC,OAAO,GAAE,gBAAqB,GAC7B,kBAAkB,CAAC,CAAC,CAAC,CA4CvB"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type Dispatch, type SetStateAction } from "react";
|
|
2
|
+
import { type DataViewState, type DataViewStatePatch } from "./data-views-types";
|
|
3
|
+
/**
|
|
4
|
+
* The two ways a DataViews state is WRITTEN, spelled once.
|
|
5
|
+
*
|
|
6
|
+
* Both are `setState` with a shape — a whole-state patch, and the one column
|
|
7
|
+
* toggle that has to merge into a list rather than replace a field. They sat
|
|
8
|
+
* inline in `useDataViewsState`, which is permanently at the size gate's
|
|
9
|
+
* ceiling; here they sit next to each other, where the fact that
|
|
10
|
+
* `toggleColumn` is just a `patch` with a merge rule is visible.
|
|
11
|
+
*
|
|
12
|
+
* Extracted for the same reason `useSelection` was: that hook is a COMPOSITION
|
|
13
|
+
* of the pieces below it, and every piece that can be named on its own leaves
|
|
14
|
+
* it reading as what it assembles rather than as how each part works.
|
|
15
|
+
*/
|
|
16
|
+
export declare function useStateWriters(setState: Dispatch<SetStateAction<DataViewState>>): {
|
|
17
|
+
patch: (next: DataViewStatePatch) => void;
|
|
18
|
+
toggleColumn: (id: string, visible: boolean) => void;
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=data-views-writers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-views-writers.d.ts","sourceRoot":"","sources":["../../../../../src/components/data-display/DataViews/data-views-writers.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,cAAc,EAAE,MAAM,OAAO,CAAC;AAE3D,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAcjF;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,QAAQ,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC,GAAG;IAClF,KAAK,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC1C,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CACtD,CAUA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-data-views-state.d.ts","sourceRoot":"","sources":["../../../../../src/components/data-display/DataViews/use-data-views-state.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAGvE,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAsC,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"use-data-views-state.d.ts","sourceRoot":"","sources":["../../../../../src/components/data-display/DataViews/use-data-views-state.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { useMemo, useState } from "react";
|
|
3
|
+
import { useMemo, useRef, useState } from "react";
|
|
4
4
|
|
|
5
5
|
/** The multi-select model, identical in every layout (table, cards, board). */
|
|
6
6
|
interface DataViewsSelection<T> {
|
|
@@ -8,7 +8,7 @@ interface DataViewsSelection<T> {
|
|
|
8
8
|
setSelectedIds: (ids: Set<string | number>) => void;
|
|
9
9
|
/** Add/remove ONE id — what a card's or board card's checkbox calls. */
|
|
10
10
|
toggleId: (id: string | number) => void;
|
|
11
|
-
/** The selected rows,
|
|
11
|
+
/** The selected rows, INCLUDING ones the current page no longer renders. */
|
|
12
12
|
selectedRows: T[];
|
|
13
13
|
clearSelection: () => void;
|
|
14
14
|
selectAll: () => void;
|
|
@@ -23,16 +23,71 @@ interface DataViewsSelection<T> {
|
|
|
23
23
|
* because `toggleId` needs a functional update: two cards toggled in the same
|
|
24
24
|
* tick would otherwise both read the pre-render set and the second would drop
|
|
25
25
|
* the first's change.
|
|
26
|
+
*
|
|
27
|
+
* ## A selection has to survive PAGING
|
|
28
|
+
*
|
|
29
|
+
* `selectedIds` always did — nothing clears it when the page changes — but
|
|
30
|
+
* `selectedRows` was `matched.filter(...)`, and in SERVER mode `matched` is one
|
|
31
|
+
* page. So ticking three rows, paging, and ticking two more left the checkboxes
|
|
32
|
+
* claiming five and the bulk action receiving two, silently, with the other
|
|
33
|
+
* three still ticked on a page nobody was looking at.
|
|
34
|
+
*
|
|
35
|
+
* That is the worst shape a bug can have here: the UI and the write disagree,
|
|
36
|
+
* neither says so, and the rows that did not move are exactly the ones out of
|
|
37
|
+
* sight. So a row is REMEMBERED for as long as its id is selected, and
|
|
38
|
+
* `selectedRows` answers from that memory for anything the current page does
|
|
39
|
+
* not hold.
|
|
40
|
+
*
|
|
41
|
+
* **Server mode only** ({@link SelectionOptions.rememberOffPage}), and the
|
|
42
|
+
* distinction is not a hedge. In client mode `matched` is the whole filtered
|
|
43
|
+
* result, so nothing is ever off-page and there is nothing to remember — while
|
|
44
|
+
* narrowing the selection as the FILTER narrows is the behaviour a client-mode
|
|
45
|
+
* grid should keep. Remembering there would mean a bulk action reaching rows
|
|
46
|
+
* the operator has just filtered away.
|
|
26
47
|
*/
|
|
48
|
+
export interface SelectionOptions {
|
|
49
|
+
/**
|
|
50
|
+
* Keep rows the current page no longer renders.
|
|
51
|
+
*
|
|
52
|
+
* True in server mode, where `matched` is a page rather than the result.
|
|
53
|
+
*/
|
|
54
|
+
rememberOffPage?: boolean;
|
|
55
|
+
}
|
|
56
|
+
|
|
27
57
|
export function useSelection<T>(
|
|
28
58
|
matched: T[],
|
|
29
59
|
getRowId: (row: T) => string | number,
|
|
60
|
+
options: SelectionOptions = {},
|
|
30
61
|
): DataViewsSelection<T> {
|
|
31
62
|
const [selectedIds, setSelectedIds] = useState<Set<string | number>>(new Set());
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
63
|
+
// Rows seen while selected, so a selection outlives the page that made it.
|
|
64
|
+
// A ref rather than state: it is a CACHE derived from what has been rendered,
|
|
65
|
+
// and holding it in state would re-render on every page load to store rows
|
|
66
|
+
// nothing is waiting for.
|
|
67
|
+
const remembered = useRef(new Map<string | number, T>());
|
|
68
|
+
|
|
69
|
+
const selectedRows = useMemo(() => {
|
|
70
|
+
const onPage = matched.filter((row) => selectedIds.has(getRowId(row)));
|
|
71
|
+
if (!options.rememberOffPage) return onPage;
|
|
72
|
+
|
|
73
|
+
const cache = remembered.current;
|
|
74
|
+
// Refresh from what is on screen NOW: a row edited elsewhere and re-fetched
|
|
75
|
+
// must not be acted on through a stale snapshot from three pages ago.
|
|
76
|
+
for (const row of onPage) cache.set(getRowId(row), row);
|
|
77
|
+
// …and forget anything no longer selected, so the map cannot outgrow the
|
|
78
|
+
// selection it exists to describe.
|
|
79
|
+
for (const id of cache.keys()) if (!selectedIds.has(id)) cache.delete(id);
|
|
80
|
+
|
|
81
|
+
// On-page rows first, in the page's own order — unchanged from before this
|
|
82
|
+
// — then the remembered tail. Appending rather than interleaving keeps the
|
|
83
|
+
// familiar case byte-identical and makes the addition exactly the addition.
|
|
84
|
+
const onPageIds = new Set(onPage.map(getRowId));
|
|
85
|
+
const offPage = [...cache.entries()].flatMap(([id, row]) =>
|
|
86
|
+
onPageIds.has(id) ? [] : [row],
|
|
87
|
+
);
|
|
88
|
+
return [...onPage, ...offPage];
|
|
89
|
+
}, [matched, selectedIds, getRowId, options.rememberOffPage]);
|
|
90
|
+
|
|
36
91
|
return {
|
|
37
92
|
selectedIds,
|
|
38
93
|
setSelectedIds,
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { type Dispatch, type SetStateAction } from "react";
|
|
4
|
+
|
|
5
|
+
import { type DataViewState, type DataViewStatePatch } from "./data-views-types";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Add or remove one column id from the visible-columns list.
|
|
9
|
+
*
|
|
10
|
+
* Moved here with its only caller. A visible column is APPENDED rather than
|
|
11
|
+
* restored to its original index, which is what makes re-showing a column put
|
|
12
|
+
* it last — the behaviour the Exibir panel has always had.
|
|
13
|
+
*/
|
|
14
|
+
function nextVisibleColumns(current: string[], id: string, visible: boolean): string[] {
|
|
15
|
+
const without = current.filter((colId) => colId !== id);
|
|
16
|
+
return visible ? [...without, id] : without;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The two ways a DataViews state is WRITTEN, spelled once.
|
|
21
|
+
*
|
|
22
|
+
* Both are `setState` with a shape — a whole-state patch, and the one column
|
|
23
|
+
* toggle that has to merge into a list rather than replace a field. They sat
|
|
24
|
+
* inline in `useDataViewsState`, which is permanently at the size gate's
|
|
25
|
+
* ceiling; here they sit next to each other, where the fact that
|
|
26
|
+
* `toggleColumn` is just a `patch` with a merge rule is visible.
|
|
27
|
+
*
|
|
28
|
+
* Extracted for the same reason `useSelection` was: that hook is a COMPOSITION
|
|
29
|
+
* of the pieces below it, and every piece that can be named on its own leaves
|
|
30
|
+
* it reading as what it assembles rather than as how each part works.
|
|
31
|
+
*/
|
|
32
|
+
export function useStateWriters(setState: Dispatch<SetStateAction<DataViewState>>): {
|
|
33
|
+
patch: (next: DataViewStatePatch) => void;
|
|
34
|
+
toggleColumn: (id: string, visible: boolean) => void;
|
|
35
|
+
} {
|
|
36
|
+
return {
|
|
37
|
+
patch: (next) =>
|
|
38
|
+
setState((prev) => ({ ...prev, ...(typeof next === "function" ? next(prev) : next) })),
|
|
39
|
+
toggleColumn: (id, visible) =>
|
|
40
|
+
setState((prev) => ({
|
|
41
|
+
...prev,
|
|
42
|
+
visibleColumns: nextVisibleColumns(prev.visibleColumns, id, visible),
|
|
43
|
+
})),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
@@ -15,6 +15,7 @@ import { computeActiveFilterCount, defaultSortFields } from "./data-views-grid-h
|
|
|
15
15
|
import { resolveScope, useScopeConfigChecks, type ScopeConfig } from "./data-views-scopes";
|
|
16
16
|
import { serverDerived, useServerQuery } from "./data-views-server-query";
|
|
17
17
|
import { useSelection } from "./data-views-selection";
|
|
18
|
+
import { useStateWriters } from "./data-views-writers";
|
|
18
19
|
import {
|
|
19
20
|
emptyViewState,
|
|
20
21
|
type DataViewColumn,
|
|
@@ -168,12 +169,6 @@ function useMatchedRows<T extends Record<string, unknown>>(
|
|
|
168
169
|
);
|
|
169
170
|
}
|
|
170
171
|
|
|
171
|
-
/** Add or remove one column id from the visible-columns list. */
|
|
172
|
-
function nextVisibleColumns(current: string[], id: string, visible: boolean): string[] {
|
|
173
|
-
const without = current.filter((colId) => colId !== id);
|
|
174
|
-
return visible ? [...without, id] : without;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
172
|
/**
|
|
178
173
|
* Reconcile external state changes and surface every change to the caller:
|
|
179
174
|
* - `appliedState` (a saved view) fully REPLACES the state — it is columns-
|
|
@@ -336,8 +331,7 @@ export function useDataViewsState<T extends Record<string, unknown>>({
|
|
|
336
331
|
|
|
337
332
|
useStateSyncEffects(appliedState, syncState, state, onStateChange, setState);
|
|
338
333
|
|
|
339
|
-
const patch = (
|
|
340
|
-
setState((prev) => ({ ...prev, ...(typeof next === "function" ? next(prev) : next) }));
|
|
334
|
+
const { patch, toggleColumn } = useStateWriters(setState);
|
|
341
335
|
const matched = useMatchedRows(server, rows, columns, fields, rangeFields, state);
|
|
342
336
|
// Resolved at READ time, every render: a stale deep link or a saved view naming
|
|
343
337
|
// a scope that has since been removed falls back to the first declared scope
|
|
@@ -351,9 +345,8 @@ export function useDataViewsState<T extends Record<string, unknown>>({
|
|
|
351
345
|
onRowClick,
|
|
352
346
|
state.order,
|
|
353
347
|
);
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
const selection = useSelection(matched, getRowId);
|
|
348
|
+
// Server mode is where `matched` is a PAGE — see `useSelection` (FUT-942).
|
|
349
|
+
const selection = useSelection(matched, getRowId, { rememberOffPage: Boolean(server) });
|
|
357
350
|
const resolvedSortFields = sortFields ?? defaultSortFields(columns);
|
|
358
351
|
|
|
359
352
|
return {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/data-display/DataViews/use-data-views-state.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useRef, useState } from \"react\";\n\nimport { type GridColumn } from \"../DataGrid\";\nimport { type SortFieldDefinition } from \"../../layout/ContentToolbar\";\n\nimport { filterRows } from \"./data-views-filter\";\nimport {\n useColumnsWithActions,\n useRenderedColumns,\n type HideableColumn,\n} from \"./data-views-columns\";\nimport { computeActiveFilterCount, defaultSortFields } from \"./data-views-grid-helpers\";\nimport { resolveScope, useScopeConfigChecks, type ScopeConfig } from \"./data-views-scopes\";\nimport { serverDerived, useServerQuery } from \"./data-views-server-query\";\nimport { useSelection } from \"./data-views-selection\";\nimport {\n emptyViewState,\n type DataViewColumn,\n type DataViewServer,\n type DataViewState,\n type DataViewStatePatch,\n type DataViewSyncState,\n type FilterFieldConfig,\n type RangeFieldConfig,\n type DataViewQuery,\n type RangeValue,\n type RowAction,\n} from \"./data-views-types\";\n\nexport type { HideableColumn };\n\n/** Inputs the hook needs to own the view state + derived data. */\ninterface UseDataViewsStateArgs<T extends Record<string, unknown>> {\n rows: T[];\n columns: DataViewColumn<T>[];\n fields: FilterFieldConfig<T>[];\n rangeFields: RangeFieldConfig<T>[];\n getRowId: (row: T) => string | number;\n onRowClick?: (row: T) => void;\n appliedState?: DataViewState;\n /**\n * URL-driven controls (search/pills/ranges/sort) that re-apply on reference\n * change while preserving column visibility — see {@link DataViewSyncState}.\n */\n syncState?: DataViewSyncState;\n onStateChange?: (state: DataViewState) => void;\n testIdPrefix: string;\n sortFields?: SortFieldDefinition[];\n rowActions?: RowAction<T>[];\n rowActionsLeading?: (row: T) => React.ReactNode;\n /** Bespoke per-row menu rendered in the actions column instead of the auto kebab. */\n renderRowMenu?: (row: T) => React.ReactNode;\n /**\n * When present, the table is BACKEND-driven: `rows` is already the current\n * page (no in-browser filter/sort/paginate), and query changes re-fetch via\n * `server.onQueryChange`. Omit for the legacy client-side behaviour.\n */\n server?: DataViewServer;\n /**\n * The page-level partition rendered as tabs under the toolbar. Requires server\n * mode: a scope is applied at the BACKEND, never in the browser.\n */\n scopes?: ScopeConfig[];\n /**\n * The row field the scopes partition by, when the host knows it — used only to\n * reject the pill/scope clash at setup. See `assertNoScopePillOverlap`.\n */\n scopeFieldId?: string;\n}\n\n/** Everything the DataViewsGrid render needs; keeps the component itself thin. */\nexport interface DataViewsController<T extends Record<string, unknown>> {\n state: DataViewState;\n ranges: Record<string, RangeValue>;\n /**\n * Merge a partial into the view state.\n *\n * The UPDATER form is the one to reach for when the patch is derived from\n * state you are also changing — successive calls within one tick each see the\n * previous call's result, where the object form would have every caller build\n * its patch from the same render-scoped snapshot and the last write would win.\n */\n patch: (next: DataViewStatePatch) => void;\n matched: T[];\n gridColumns: GridColumn<T>[];\n /** Columns eligible for the show/hide menu (hideable, with a text header). */\n hideableColumns: HideableColumn[];\n /** Every column id in reading order — what the Colunas tab reorders. */\n columnOrder: string[];\n /** Toggle one column's visibility in the current view state. */\n toggleColumn: (id: string, visible: boolean) => void;\n selectedIds: Set<string | number>;\n setSelectedIds: (ids: Set<string | number>) => void;\n /**\n * Add/remove ONE id from the selection. The card and board bodies both need\n * it, so it lives here rather than being written out twice at the call sites —\n * one selection model, one toggle, identical in every layout.\n */\n toggleId: (id: string | number) => void;\n selectedRows: T[];\n clearSelection: () => void;\n selectAll: () => void;\n filterOpen: boolean;\n setFilterOpen: (open: boolean) => void;\n resolvedSortFields: SortFieldDefinition[];\n activeSortField: string;\n activeSortOrder: \"asc\" | \"desc\";\n activeFilterCount: number;\n /** True when the table is backend-driven (server mode). */\n serverMode: boolean;\n /** Server-mode pagination: 1-based current page (1 when client mode). */\n serverPage: number;\n /** Server-mode pagination: total pages (1 when client mode). */\n serverPageCount: number;\n /** Server-mode: total matched rows across all pages (drives the counter). */\n serverTotalCount: number;\n /** Server-mode: request a specific 1-based page (re-fetches via onQueryChange). */\n changePage: (page: number) => void;\n /**\n * The active scope id, RESOLVED against the declared scopes (see\n * `resolveScope`). `undefined` when the table declares none — which is what\n * keeps `scope` out of the emitted query for every table that never opted in.\n */\n scope: string | undefined;\n /** Select a scope: re-fetches from page 1 and drops the selection. */\n setScope: (id: string) => void;\n /**\n * The query the grid is currently showing. Read by Export, which hands it\n * back to the host UNPAGINATED — so an export follows the filters rather\n * than the 25 rows that happen to be loaded.\n */\n currentQuery: DataViewQuery;\n /**\n * Server-supplied per-scope totals, passed through verbatim, or `undefined`\n * when the server omits them. NEVER falls back to counting `matched`: a count\n * off the loaded page is wrong under pagination, which is the bug scopes fix.\n */\n scopeCounts?: Record<string, number>;\n}\n\n/**\n * The rows to render: in server mode `rows` is already the current page (the\n * backend filtered/sorted/paginated), so it passes through untouched; otherwise\n * the client search/pill/range filter narrows it.\n */\nfunction useMatchedRows<T extends Record<string, unknown>>(\n server: DataViewServer | undefined,\n rows: T[],\n columns: DataViewColumn<T>[],\n fields: FilterFieldConfig<T>[],\n rangeFields: RangeFieldConfig<T>[],\n state: DataViewState,\n): T[] {\n return useMemo(\n () =>\n server\n ? rows\n : filterRows(\n rows,\n columns,\n fields,\n { search: state.search, pills: state.pills, ranges: state.ranges },\n rangeFields,\n ),\n [server, rows, columns, fields, rangeFields, state.search, state.pills, state.ranges],\n );\n}\n\n/** Add or remove one column id from the visible-columns list. */\nfunction nextVisibleColumns(current: string[], id: string, visible: boolean): string[] {\n const without = current.filter((colId) => colId !== id);\n return visible ? [...without, id] : without;\n}\n\n/**\n * Reconcile external state changes and surface every change to the caller:\n * - `appliedState` (a saved view) fully REPLACES the state — it is columns-\n * authoritative, so applying a view restores its filters, sort AND columns.\n * - `syncState` (URL-driven controls) MERGES over the current state, leaving\n * `visibleColumns` untouched — so browser back/forward or a same-route\n * deep-link re-applies search/pills/sort without wiping a user's hidden columns.\n * Each channel only fires when its own reference changes (after the first run).\n */\nfunction useStateSyncEffects(\n appliedState: DataViewState | undefined,\n syncState: DataViewSyncState | undefined,\n state: DataViewState,\n onStateChange: ((state: DataViewState) => void) | undefined,\n setState: React.Dispatch<React.SetStateAction<DataViewState>>,\n): void {\n const firstApplied = useRef(true);\n useEffect(() => {\n if (firstApplied.current) {\n firstApplied.current = false;\n return;\n }\n if (appliedState) setState(appliedState);\n // `setState` is a stable useState setter (passed in), included to satisfy\n // exhaustive-deps; the effect still only re-applies when `appliedState` changes.\n }, [appliedState, setState]);\n const firstSync = useRef(true);\n useEffect(() => {\n if (firstSync.current) {\n firstSync.current = false;\n return;\n }\n // Merge — keep the current `visibleColumns` (never URL-carried); only the\n // URL-driven controls change.\n if (syncState) setState((prev) => ({ ...prev, ...syncState }));\n }, [syncState, setState]);\n useEffect(() => {\n onStateChange?.(state);\n }, [state, onStateChange]);\n}\n\n/**\n * The seed view state: a saved view (`appliedState`) or a pristine all-columns\n * one, with the URL-driven controls (`syncState`) merged over it so a deep-linked\n * filter or scope is reflected on the FIRST render. Column visibility is never\n * URL-carried, so the merge cannot wipe it.\n */\nfunction seedState(\n appliedState: DataViewState | undefined,\n syncState: DataViewSyncState | undefined,\n allColumnIds: string[],\n): DataViewState {\n const seed = appliedState ?? emptyViewState(allColumnIds);\n return syncState ? { ...seed, ...syncState } : seed;\n}\n\n/**\n * Selecting a scope: record it, then DROP the selection.\n *\n * A scope change renders a different result set. A selection that survived it\n * would let a bulk action run against rows the user can no longer see — the\n * same reason changing any other part of the query clears it.\n */\nfunction makeSetScope(\n patch: (next: DataViewStatePatch) => void,\n clearSelection: () => void,\n): (id: string) => void {\n return (id) => {\n patch({ scope: id });\n clearSelection();\n };\n}\n\n/**\n * The declared column ids in the stored reading order — the same tolerance\n * `applyOrder` uses, so the Colunas tab lists exactly what the grid renders.\n */\nfunction orderedColumnIds(allColumnIds: string[], order: string[] | undefined): string[] {\n if (!order || order.length === 0) return allColumnIds;\n const declared = new Set(allColumnIds);\n const kept = order.filter((id) => declared.has(id));\n const seen = new Set(kept);\n return [...kept, ...allColumnIds.filter((id) => !seen.has(id))];\n}\n\n/**\n * The query the grid is currently SHOWING — the same shape `onQueryChange`\n * emits, kept as a value so a host control (Exportar) can re-run it against the\n * backend rather than reading the loaded rows.\n */\nfunction liveQuery(\n state: DataViewState,\n scope: string | undefined,\n server: DataViewServer | undefined,\n matchedCount: number,\n): DataViewQuery {\n return {\n search: state.search,\n pills: state.pills,\n ranges: state.ranges ?? {},\n sortBy: state.sortBy,\n // Absent, not undefined, when the table declares no scopes.\n ...(scope !== undefined ? { scope } : {}),\n page: server?.page ?? 1,\n // Client mode has one page, and it is everything that matched.\n pageSize: server?.pageSize ?? matchedCount,\n };\n}\n\n/** The toolbar's active sort, read off the state's FIRST sort entry. */\nfunction activeSortOf(\n state: DataViewState,\n resolvedSortFields: SortFieldDefinition[],\n): { activeSortField: string; activeSortOrder: \"asc\" | \"desc\" } {\n const active = state.sortBy?.[0];\n return {\n activeSortField: active?.id ?? resolvedSortFields[0]?.value ?? \"\",\n activeSortOrder: active?.dir === \"desc\" ? \"desc\" : \"asc\",\n };\n}\n\n/**\n * Owns the DataViews view state (search/pills/ranges/sort/visibleColumns),\n * multi-select, the filter-panel toggle, and every derived value (filtered rows,\n * grid columns, active sort/filter counts). Extracted from the component so the\n * render stays within the size/complexity budget.\n */\nexport function useDataViewsState<T extends Record<string, unknown>>({\n rows,\n columns,\n fields,\n rangeFields,\n getRowId,\n onRowClick,\n appliedState,\n syncState,\n onStateChange,\n testIdPrefix,\n sortFields,\n rowActions,\n rowActionsLeading,\n renderRowMenu,\n server,\n scopes = [],\n scopeFieldId,\n}: UseDataViewsStateArgs<T>): DataViewsController<T> {\n useScopeConfigChecks(scopes, fields.map((field) => field.id), scopeFieldId, server !== undefined);\n const { columnsWithActions, allColumnIds } = useColumnsWithActions(columns, {\n rowActions,\n rowActionsLeading,\n renderRowMenu,\n testIdPrefix,\n getRowId,\n });\n // Seed once — see {@link seedState}.\n const [state, setState] = useState<DataViewState>(() =>\n seedState(appliedState, syncState, allColumnIds),\n );\n const [filterOpen, setFilterOpen] = useState(false);\n\n useStateSyncEffects(appliedState, syncState, state, onStateChange, setState);\n\n const patch = (next: DataViewStatePatch): void =>\n setState((prev) => ({ ...prev, ...(typeof next === \"function\" ? next(prev) : next) }));\n const matched = useMatchedRows(server, rows, columns, fields, rangeFields, state);\n // Resolved at READ time, every render: a stale deep link or a saved view naming\n // a scope that has since been removed falls back to the first declared scope\n // instead of putting an id the backend rejects on the wire.\n const scope = resolveScope(scopes, state.scope);\n // Server mode: re-fetch on query change (page resets to 1) + drive pagination.\n const { changePage } = useServerQuery(server, state, scope);\n const { gridColumns, hideableColumns } = useRenderedColumns(\n columnsWithActions,\n state.visibleColumns,\n onRowClick,\n state.order,\n );\n const toggleColumn = (id: string, visible: boolean): void =>\n setState((prev) => ({ ...prev, visibleColumns: nextVisibleColumns(prev.visibleColumns, id, visible) }));\n const selection = useSelection(matched, getRowId);\n const resolvedSortFields = sortFields ?? defaultSortFields(columns);\n\n return {\n state,\n ranges: state.ranges ?? {},\n patch,\n matched,\n gridColumns,\n hideableColumns,\n columnOrder: orderedColumnIds(allColumnIds, state.order),\n toggleColumn,\n ...selection,\n filterOpen,\n setFilterOpen,\n resolvedSortFields,\n ...activeSortOf(state, resolvedSortFields),\n activeFilterCount: computeActiveFilterCount(state, fields, rangeFields),\n ...serverDerived(server, matched.length),\n changePage,\n scope,\n setScope: makeSetScope(patch, selection.clearSelection),\n currentQuery: liveQuery(state, scope, server, matched.length),\n // Verbatim, or absent. See DataViewServer.scopeCounts for why there is no\n // client-side fallback.\n scopeCounts: server?.scopeCounts,\n };\n}\n"],"mappings":"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","names":[]}
|
package/dist/chunk-WTOTWP6A.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
// src/components/data-display/DataViews/data-views-selection.ts
|
|
2
|
-
import { useMemo, useState } from "react";
|
|
3
|
-
function useSelection(matched, getRowId) {
|
|
4
|
-
const [selectedIds, setSelectedIds] = useState(/* @__PURE__ */ new Set());
|
|
5
|
-
const selectedRows = useMemo(
|
|
6
|
-
() => matched.filter((row) => selectedIds.has(getRowId(row))),
|
|
7
|
-
[matched, selectedIds, getRowId]
|
|
8
|
-
);
|
|
9
|
-
return {
|
|
10
|
-
selectedIds,
|
|
11
|
-
setSelectedIds,
|
|
12
|
-
toggleId: (id) => setSelectedIds((prev) => {
|
|
13
|
-
const next = new Set(prev);
|
|
14
|
-
if (next.has(id)) next.delete(id);
|
|
15
|
-
else next.add(id);
|
|
16
|
-
return next;
|
|
17
|
-
}),
|
|
18
|
-
selectedRows,
|
|
19
|
-
clearSelection: () => setSelectedIds(/* @__PURE__ */ new Set()),
|
|
20
|
-
selectAll: () => setSelectedIds(new Set(matched.map((row) => getRowId(row))))
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export {
|
|
25
|
-
useSelection
|
|
26
|
-
};
|
|
27
|
-
//# sourceMappingURL=chunk-WTOTWP6A.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/data-display/DataViews/data-views-selection.ts"],"sourcesContent":["\"use client\";\n\nimport { useMemo, useState } from \"react\";\n\n/** The multi-select model, identical in every layout (table, cards, board). */\ninterface DataViewsSelection<T> {\n selectedIds: Set<string | number>;\n setSelectedIds: (ids: Set<string | number>) => void;\n /** Add/remove ONE id — what a card's or board card's checkbox calls. */\n toggleId: (id: string | number) => void;\n /** The selected rows, narrowed to what is currently rendered. */\n selectedRows: T[];\n clearSelection: () => void;\n selectAll: () => void;\n}\n\n/**\n * Owns the DataViews selection. ONE set of ids across every layout, so switching\n * from the board to the table (or to the cards) keeps exactly the same rows\n * selected and offers exactly the same bulk actions.\n *\n * Extracted from {@link useDataViewsState} for that hook's size budget, and\n * because `toggleId` needs a functional update: two cards toggled in the same\n * tick would otherwise both read the pre-render set and the second would drop\n * the first's change.\n */\nexport function useSelection<T>(\n matched: T[],\n getRowId: (row: T) => string | number,\n): DataViewsSelection<T> {\n const [selectedIds, setSelectedIds] = useState<Set<string | number>>(new Set());\n const selectedRows = useMemo(\n () => matched.filter((row) => selectedIds.has(getRowId(row))),\n [matched, selectedIds, getRowId],\n );\n return {\n selectedIds,\n setSelectedIds,\n toggleId: (id) =>\n setSelectedIds((prev) => {\n const next = new Set(prev);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n }),\n selectedRows,\n clearSelection: () => setSelectedIds(new Set()),\n selectAll: () => setSelectedIds(new Set(matched.map((row) => getRowId(row)))),\n };\n}\n"],"mappings":";AAEA,SAAS,SAAS,gBAAgB;AAwB3B,SAAS,aACd,SACA,UACuB;AACvB,QAAM,CAAC,aAAa,cAAc,IAAI,SAA+B,oBAAI,IAAI,CAAC;AAC9E,QAAM,eAAe;AAAA,IACnB,MAAM,QAAQ,OAAO,CAAC,QAAQ,YAAY,IAAI,SAAS,GAAG,CAAC,CAAC;AAAA,IAC5D,CAAC,SAAS,aAAa,QAAQ;AAAA,EACjC;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,UAAU,CAAC,OACT,eAAe,CAAC,SAAS;AACvB,YAAM,OAAO,IAAI,IAAI,IAAI;AACzB,UAAI,KAAK,IAAI,EAAE,EAAG,MAAK,OAAO,EAAE;AAAA,UAC3B,MAAK,IAAI,EAAE;AAChB,aAAO;AAAA,IACT,CAAC;AAAA,IACH;AAAA,IACA,gBAAgB,MAAM,eAAe,oBAAI,IAAI,CAAC;AAAA,IAC9C,WAAW,MAAM,eAAe,IAAI,IAAI,QAAQ,IAAI,CAAC,QAAQ,SAAS,GAAG,CAAC,CAAC,CAAC;AAAA,EAC9E;AACF;","names":[]}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|