@marimo-team/islands 0.23.2-dev14 → 0.23.2-dev16
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/_basePickBy-C-mod5Dp.js +34 -0
- package/dist/{_baseUniq-C87CckHL.js → _baseUniq-Be_p_Ty6.js} +2 -2
- package/dist/{architecture-7HQA4BMR-BHdkAMvZ.js → architecture-7HQA4BMR-kNyKQXbB.js} +2 -2
- package/dist/{architectureDiagram-VXUJARFQ-B3YQo9At.js → architectureDiagram-VXUJARFQ-Dx_Dniiw.js} +11 -11
- package/dist/{blockDiagram-VD42YOAC-CpQ3TKEN.js → blockDiagram-VD42YOAC-D3hGPvEt.js} +4 -4
- package/dist/{c4Diagram-YG6GDRKO-CZSU4uqU.js → c4Diagram-YG6GDRKO-CtY1WMbV.js} +1 -1
- package/dist/{chat-ui-Bi0ioKDx.js → chat-ui-DIVMRPO5.js} +1 -1
- package/dist/{chunk-4F5CHEZ2-D5mClyDv.js → chunk-4F5CHEZ2-oWcaQSBe.js} +1 -1
- package/dist/{chunk-B2363JML-Br0eA2T3.js → chunk-B2363JML-72CRxZbk.js} +1 -1
- package/dist/{chunk-B4BG7PRW-4BjV11Br.js → chunk-B4BG7PRW-ChYfc4rf.js} +2 -2
- package/dist/{chunk-DI55MBZ5-DITY3EyP.js → chunk-DI55MBZ5-CYNE3N2j.js} +2 -2
- package/dist/{chunk-FRFDVMJY-DnEvEFRR.js → chunk-FRFDVMJY-Dgl-7l0K.js} +1 -1
- package/dist/{chunk-JA3XYJ7Z-BcPEfxk_.js → chunk-JA3XYJ7Z-B2BoMdpr.js} +1 -1
- package/dist/{chunk-JZLCHNYA-2bnLL3xL.js → chunk-JZLCHNYA-CkHD9mQU.js} +2 -2
- package/dist/{chunk-N4CR4FBY-CpZSuGSU.js → chunk-N4CR4FBY-DDeXUk3y.js} +4 -4
- package/dist/{chunk-PL6DKKU2-DnId6G-x.js → chunk-PL6DKKU2-CpBHhdj8.js} +1 -1
- package/dist/{chunk-QXUST7PY-Ch6F5Obl.js → chunk-QXUST7PY-BnSZbSK7.js} +3 -3
- package/dist/{chunk-S3R3BYOJ-B0UOFJwq.js → chunk-S3R3BYOJ-DVdRer7T.js} +1 -1
- package/dist/{chunk-SJTYNZTY-BsBZnJUj.js → chunk-SJTYNZTY-DPOwAZc-.js} +1 -1
- package/dist/{chunk-TCCFYFTB-Clbl-fTg.js → chunk-TCCFYFTB-BdE6BTq1.js} +6 -6
- package/dist/{chunk-TQ3KTPDO-CFkSQ30e.js → chunk-TQ3KTPDO-BCXCq8f2.js} +1 -1
- package/dist/{chunk-UMXZTB3W-D-A834Bq.js → chunk-UMXZTB3W-C5Hu2atA.js} +1 -1
- package/dist/{classDiagram-v2-WZHVMYZB-DrmbGANl.js → classDiagram-2ON5EDUG-sUXB0Obe.js} +6 -6
- package/dist/{classDiagram-2ON5EDUG-C8-zE3Zv.js → classDiagram-v2-WZHVMYZB-JeF9-idj.js} +6 -6
- package/dist/{clone-DZFQCtFJ.js → clone-B48LSK6I.js} +1 -1
- package/dist/{dagre-6UL2VRFP-OMItEBnY.js → dagre-6UL2VRFP-Bs_DhCUk.js} +9 -9
- package/dist/{dagre-QVd-lCXU.js → dagre-BLW2E2fh.js} +19 -8
- package/dist/{diagram-PSM6KHXK-CkKbohWI.js → diagram-PSM6KHXK-VB3japmQ.js} +10 -10
- package/dist/{diagram-QEK2KX5R-DjUMpVcx.js → diagram-QEK2KX5R-B8nm2JL9.js} +10 -10
- package/dist/{diagram-S2PKOQOG-b-c0d-wZ.js → diagram-S2PKOQOG-D6PR_2iv.js} +10 -10
- package/dist/{erDiagram-Q2GNP2WA-CDhLaOZ1.js → erDiagram-Q2GNP2WA-gjAse7Jb.js} +5 -5
- package/dist/{flowDiagram-NV44I4VS-BDi4O4CL.js → flowDiagram-NV44I4VS-CQTSZWcI.js} +5 -5
- package/dist/{ganttDiagram-JELNMOA3-BpZE6kVp.js → ganttDiagram-JELNMOA3-aktqk_om.js} +1 -1
- package/dist/{gitGraph-G5XIXVHT-B_c6xFJv.js → gitGraph-G5XIXVHT-Cy06nzLg.js} +2 -2
- package/dist/{gitGraphDiagram-V2S2FVAM-iQnXzbPM.js → gitGraphDiagram-V2S2FVAM-C1ntKO33.js} +10 -10
- package/dist/{graphlib-BV1_gi0C.js → graphlib-Cr691-na.js} +3 -3
- package/dist/{hasIn-DnfJcYpY.js → hasIn-BDDmuo1w.js} +1 -1
- package/dist/{info-VBDWY6EO-BTyzxmhr.js → info-VBDWY6EO-BIO6A8nW.js} +2 -2
- package/dist/{infoDiagram-HS3SLOUP-OYrX6uO3.js → infoDiagram-HS3SLOUP-CtfUf0g_.js} +9 -9
- package/dist/{kanban-definition-3W4ZIXB7-DHEAKdZt.js → kanban-definition-3W4ZIXB7-C5FK4v7x.js} +3 -3
- package/dist/main.js +135 -66
- package/dist/{mermaid-BbhZNQeB.js → mermaid-CcM8GHeT.js} +29 -29
- package/dist/{mermaid-parser.core-ntCgyx0x.js → mermaid-parser.core-fZdPSYor.js} +8 -8
- package/dist/min-DAIOAwWK.js +102 -0
- package/dist/{mindmap-definition-VGOIOE7T-CxEUZZvY.js → mindmap-definition-VGOIOE7T-BvrQf8XZ.js} +5 -5
- package/dist/{packet-DYOGHKS2-BhvnpoGi.js → packet-DYOGHKS2-DDx1z7B-.js} +2 -2
- package/dist/pick-DfX21dj2.js +18 -0
- package/dist/{pie-VRWISCQL-dILuA3iG.js → pie-VRWISCQL-BgRtyDMT.js} +2 -2
- package/dist/{pieDiagram-ADFJNKIX-U3LrUqAS.js → pieDiagram-ADFJNKIX-DAhjFwJD.js} +10 -10
- package/dist/{radar-ZZBFDIW7-DwFrOJDj.js → radar-ZZBFDIW7-xwh47Yzn.js} +2 -2
- package/dist/{requirementDiagram-UZGBJVZJ-D0zpQnKC.js → requirementDiagram-UZGBJVZJ-B3nnp0VG.js} +5 -5
- package/dist/{sequenceDiagram-WL72ISMW-D1BJxLjH.js → sequenceDiagram-WL72ISMW-D2mpRRG2.js} +1 -1
- package/dist/{stateDiagram-FKZM4ZOC-B1S8jGMn.js → stateDiagram-FKZM4ZOC-QD9Wuca0.js} +8 -8
- package/dist/{stateDiagram-v2-4FDKWEC3-BH5ozUbc.js → stateDiagram-v2-4FDKWEC3-DnUhJ525.js} +6 -6
- package/dist/{treemap-GDKQZRPO-bx2ngsgN.js → treemap-GDKQZRPO-5ZsmvXgc.js} +2 -2
- package/dist/{xychartDiagram-PRI3JC2R-CuAZiqHS.js → xychartDiagram-PRI3JC2R-BMsB7VdF.js} +2 -2
- package/package.json +1 -1
- package/src/components/data-table/TableBottomBar.tsx +5 -1
- package/src/components/data-table/__tests__/pagination.test.tsx +46 -132
- package/src/components/data-table/column-explorer-panel/column-explorer.tsx +1 -1
- package/src/components/data-table/pagination.tsx +189 -76
- package/src/components/data-table/types.ts +0 -4
- package/src/components/editor/cell/code/cell-editor.tsx +1 -0
- package/dist/_basePickBy-Sow3pJjS.js +0 -41
- package/dist/min-Ds3gG0Ff.js +0 -96
- package/dist/range-fJeId9Ri.js +0 -30
- /package/dist/{isEmpty-B7FX9wKt.js → isEmpty-D3lf6gH3.js} +0 -0
- /package/dist/{memoize-CSTI9eOX.js → memoize-DEvRzlwP.js} +0 -0
|
@@ -1,144 +1,58 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
3
|
import { expect, test } from "vitest";
|
|
4
|
-
import {
|
|
5
|
-
import type { PageRange } from "../types";
|
|
4
|
+
import { matchingPageRanges } from "../pagination";
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
test("empty prefix returns no ranges", () => {
|
|
7
|
+
expect(matchingPageRanges("", 500)).toEqual([]);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
test("zero prefix returns no ranges", () => {
|
|
11
|
+
expect(matchingPageRanges("0", 500)).toEqual([]);
|
|
12
|
+
});
|
|
13
13
|
|
|
14
|
-
test("
|
|
15
|
-
expect(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"9",
|
|
26
|
-
"10",
|
|
27
|
-
"...",
|
|
28
|
-
"96",
|
|
29
|
-
"97",
|
|
30
|
-
"98",
|
|
31
|
-
"99",
|
|
32
|
-
"100",
|
|
33
|
-
"101",
|
|
34
|
-
"102",
|
|
35
|
-
"103",
|
|
36
|
-
"104",
|
|
37
|
-
"105",
|
|
38
|
-
"...",
|
|
39
|
-
"191",
|
|
40
|
-
"192",
|
|
41
|
-
"193",
|
|
42
|
-
"194",
|
|
43
|
-
"195",
|
|
44
|
-
"196",
|
|
45
|
-
"197",
|
|
46
|
-
"198",
|
|
47
|
-
"199",
|
|
48
|
-
"200",
|
|
49
|
-
]
|
|
50
|
-
`);
|
|
14
|
+
test("leading-zero prefix returns no ranges", () => {
|
|
15
|
+
expect(matchingPageRanges("01", 500)).toEqual([]);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test("single digit prefix", () => {
|
|
19
|
+
expect(matchingPageRanges("5", 500)).toEqual([
|
|
20
|
+
[5, 5],
|
|
21
|
+
[50, 59],
|
|
22
|
+
[500, 500],
|
|
23
|
+
]);
|
|
24
|
+
});
|
|
51
25
|
|
|
52
|
-
|
|
53
|
-
expect(
|
|
54
|
-
|
|
55
|
-
|
|
26
|
+
test("single digit prefix with exact totalPages boundary", () => {
|
|
27
|
+
expect(matchingPageRanges("5", 55)).toEqual([
|
|
28
|
+
[5, 5],
|
|
29
|
+
[50, 55],
|
|
30
|
+
]);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("multi-digit prefix", () => {
|
|
34
|
+
expect(matchingPageRanges("12", 5000)).toEqual([
|
|
35
|
+
[12, 12],
|
|
36
|
+
[120, 129],
|
|
37
|
+
[1200, 1299],
|
|
38
|
+
]);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test("prefix larger than totalPages returns no ranges", () => {
|
|
42
|
+
expect(matchingPageRanges("999", 100)).toEqual([]);
|
|
43
|
+
});
|
|
56
44
|
|
|
57
|
-
|
|
58
|
-
expect(
|
|
59
|
-
expect(getLabels(1)).not.toEqual(getLabels(95));
|
|
60
|
-
expect(getLabels(1)).not.toEqual(getLabels(106));
|
|
61
|
-
expect(getLabels(1)).not.toEqual(getLabels(190));
|
|
45
|
+
test("prefix equal to totalPages", () => {
|
|
46
|
+
expect(matchingPageRanges("100", 100)).toEqual([[100, 100]]);
|
|
62
47
|
});
|
|
63
48
|
|
|
64
|
-
test("
|
|
65
|
-
expect(
|
|
66
|
-
[
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
"3",
|
|
70
|
-
"4",
|
|
71
|
-
"5",
|
|
72
|
-
"6",
|
|
73
|
-
"7",
|
|
74
|
-
"8",
|
|
75
|
-
"9",
|
|
76
|
-
"10",
|
|
77
|
-
"...",
|
|
78
|
-
"50",
|
|
79
|
-
"...",
|
|
80
|
-
"96",
|
|
81
|
-
"97",
|
|
82
|
-
"98",
|
|
83
|
-
"99",
|
|
84
|
-
"100",
|
|
85
|
-
"101",
|
|
86
|
-
"102",
|
|
87
|
-
"103",
|
|
88
|
-
"104",
|
|
89
|
-
"105",
|
|
90
|
-
"...",
|
|
91
|
-
"191",
|
|
92
|
-
"192",
|
|
93
|
-
"193",
|
|
94
|
-
"194",
|
|
95
|
-
"195",
|
|
96
|
-
"196",
|
|
97
|
-
"197",
|
|
98
|
-
"198",
|
|
99
|
-
"199",
|
|
100
|
-
"200",
|
|
101
|
-
]
|
|
102
|
-
`);
|
|
49
|
+
test("prefix 1 with small totalPages", () => {
|
|
50
|
+
expect(matchingPageRanges("1", 10)).toEqual([
|
|
51
|
+
[1, 1],
|
|
52
|
+
[10, 10],
|
|
53
|
+
]);
|
|
103
54
|
});
|
|
104
55
|
|
|
105
|
-
test("
|
|
106
|
-
expect(
|
|
107
|
-
[
|
|
108
|
-
"1",
|
|
109
|
-
"2",
|
|
110
|
-
"3",
|
|
111
|
-
"4",
|
|
112
|
-
"5",
|
|
113
|
-
"6",
|
|
114
|
-
"7",
|
|
115
|
-
"8",
|
|
116
|
-
"9",
|
|
117
|
-
"10",
|
|
118
|
-
"...",
|
|
119
|
-
"96",
|
|
120
|
-
"97",
|
|
121
|
-
"98",
|
|
122
|
-
"99",
|
|
123
|
-
"100",
|
|
124
|
-
"101",
|
|
125
|
-
"102",
|
|
126
|
-
"103",
|
|
127
|
-
"104",
|
|
128
|
-
"105",
|
|
129
|
-
"...",
|
|
130
|
-
"150",
|
|
131
|
-
"...",
|
|
132
|
-
"191",
|
|
133
|
-
"192",
|
|
134
|
-
"193",
|
|
135
|
-
"194",
|
|
136
|
-
"195",
|
|
137
|
-
"196",
|
|
138
|
-
"197",
|
|
139
|
-
"198",
|
|
140
|
-
"199",
|
|
141
|
-
"200",
|
|
142
|
-
]
|
|
143
|
-
`);
|
|
56
|
+
test("prefix 1 with totalPages=1", () => {
|
|
57
|
+
expect(matchingPageRanges("1", 1)).toEqual([[1, 1]]);
|
|
144
58
|
});
|
|
@@ -74,7 +74,7 @@ export const ColumnExplorerPanel = ({
|
|
|
74
74
|
return (
|
|
75
75
|
<div className="mb-3">
|
|
76
76
|
<span className="text-xs font-semibold ml-2 flex">
|
|
77
|
-
{prettifyRowColumnCount(totalRows, totalColumns, locale)}
|
|
77
|
+
{prettifyRowColumnCount({ numRows: totalRows, totalColumns, locale })}
|
|
78
78
|
<CopyClipboardIcon
|
|
79
79
|
tooltip="Copy column names"
|
|
80
80
|
value={columns?.map(([columnName]) => columnName).join(",\n") || ""}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"use no memo";
|
|
3
3
|
|
|
4
4
|
import type { Table } from "@tanstack/react-table";
|
|
5
|
-
import {
|
|
5
|
+
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
6
6
|
import {
|
|
7
7
|
ChevronDown,
|
|
8
8
|
ChevronLeft,
|
|
@@ -37,9 +37,6 @@ import { cn } from "@/utils/cn";
|
|
|
37
37
|
import { Events } from "@/utils/events";
|
|
38
38
|
import { prettyNumber } from "@/utils/numbers";
|
|
39
39
|
import { PluralWord } from "@/utils/pluralize";
|
|
40
|
-
import type { PageRange } from "./types";
|
|
41
|
-
|
|
42
|
-
const MAX_PAGES_BEFORE_CLAMPING = 100;
|
|
43
40
|
|
|
44
41
|
interface DataTablePaginationProps<TData> {
|
|
45
42
|
table: Table<TData>;
|
|
@@ -189,6 +186,81 @@ export const DataTablePagination = <TData,>({
|
|
|
189
186
|
);
|
|
190
187
|
};
|
|
191
188
|
|
|
189
|
+
const PAGE_ITEM_HEIGHT = 32;
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Compute contiguous ranges of page numbers whose string starts with `prefix`,
|
|
193
|
+
* without scanning every page. O(log10(totalPages)).
|
|
194
|
+
*
|
|
195
|
+
* For prefix "5", totalPages=500: [[5,5], [50,59], [500,500]]
|
|
196
|
+
*/
|
|
197
|
+
export function matchingPageRanges(
|
|
198
|
+
prefix: string,
|
|
199
|
+
totalPages: number,
|
|
200
|
+
): [number, number][] {
|
|
201
|
+
const n = Number.parseInt(prefix, 10);
|
|
202
|
+
if (Number.isNaN(n) || n <= 0 || String(n) !== prefix) {
|
|
203
|
+
return [];
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const ranges: [number, number][] = [];
|
|
207
|
+
let power = 1;
|
|
208
|
+
while (n * power <= totalPages) {
|
|
209
|
+
const start = n * power;
|
|
210
|
+
const end = Math.min((n + 1) * power - 1, totalPages);
|
|
211
|
+
ranges.push([start, end]);
|
|
212
|
+
power *= 10;
|
|
213
|
+
}
|
|
214
|
+
return ranges;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
interface PageMapping {
|
|
218
|
+
count: number;
|
|
219
|
+
pageAtIndex: (index: number) => number;
|
|
220
|
+
indexOfPage: (page: number) => number;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function createPageMapping(search: string, totalPages: number): PageMapping {
|
|
224
|
+
if (search === "") {
|
|
225
|
+
return {
|
|
226
|
+
count: totalPages,
|
|
227
|
+
pageAtIndex: (i) => i + 1,
|
|
228
|
+
indexOfPage: (p) => p - 1,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const ranges = matchingPageRanges(search, totalPages);
|
|
233
|
+
let count = 0;
|
|
234
|
+
for (const [s, e] of ranges) {
|
|
235
|
+
count += e - s + 1;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return {
|
|
239
|
+
count,
|
|
240
|
+
pageAtIndex: (i) => {
|
|
241
|
+
let offset = 0;
|
|
242
|
+
for (const [start, end] of ranges) {
|
|
243
|
+
const size = end - start + 1;
|
|
244
|
+
if (i < offset + size) {
|
|
245
|
+
return start + (i - offset);
|
|
246
|
+
}
|
|
247
|
+
offset += size;
|
|
248
|
+
}
|
|
249
|
+
return -1;
|
|
250
|
+
},
|
|
251
|
+
indexOfPage: (p) => {
|
|
252
|
+
let offset = 0;
|
|
253
|
+
for (const [start, end] of ranges) {
|
|
254
|
+
if (p >= start && p <= end) {
|
|
255
|
+
return offset + (p - start);
|
|
256
|
+
}
|
|
257
|
+
offset += end - start + 1;
|
|
258
|
+
}
|
|
259
|
+
return -1;
|
|
260
|
+
},
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
|
|
192
264
|
export const PageSelector = ({
|
|
193
265
|
currentPage,
|
|
194
266
|
totalPages,
|
|
@@ -199,19 +271,31 @@ export const PageSelector = ({
|
|
|
199
271
|
onPageChange: (page: number) => void;
|
|
200
272
|
}) => {
|
|
201
273
|
const [open, setOpen] = React.useState(false);
|
|
274
|
+
const [search, setSearch] = React.useState("");
|
|
202
275
|
|
|
203
|
-
const
|
|
204
|
-
() =>
|
|
205
|
-
[
|
|
276
|
+
const mapping = React.useMemo(
|
|
277
|
+
() => createPageMapping(search, totalPages),
|
|
278
|
+
[search, totalPages],
|
|
206
279
|
);
|
|
207
280
|
|
|
208
281
|
const handleSelect = (page: number) => {
|
|
209
282
|
onPageChange(page - 1);
|
|
283
|
+
setSearch("");
|
|
210
284
|
setOpen(false);
|
|
211
285
|
};
|
|
212
286
|
|
|
287
|
+
const listHeight = Math.min(mapping.count * PAGE_ITEM_HEIGHT, 240);
|
|
288
|
+
|
|
213
289
|
return (
|
|
214
|
-
<Popover
|
|
290
|
+
<Popover
|
|
291
|
+
open={totalPages > 1 ? open : false}
|
|
292
|
+
onOpenChange={(next) => {
|
|
293
|
+
setOpen(next);
|
|
294
|
+
if (!next) {
|
|
295
|
+
setSearch("");
|
|
296
|
+
}
|
|
297
|
+
}}
|
|
298
|
+
>
|
|
215
299
|
<PopoverTrigger asChild={true} disabled={totalPages <= 1}>
|
|
216
300
|
<button
|
|
217
301
|
type="button"
|
|
@@ -229,18 +313,15 @@ export const PageSelector = ({
|
|
|
229
313
|
</button>
|
|
230
314
|
</PopoverTrigger>
|
|
231
315
|
<PopoverContent className="w-36 p-0" align="center" sideOffset={6}>
|
|
232
|
-
<Command
|
|
233
|
-
shouldFilter={true}
|
|
234
|
-
filter={(value, search) => {
|
|
235
|
-
return value.startsWith(search) ? 1 : 0;
|
|
236
|
-
}}
|
|
237
|
-
>
|
|
316
|
+
<Command shouldFilter={false} value={String(currentPage)}>
|
|
238
317
|
<CommandInput
|
|
239
318
|
placeholder={`Page (1–${totalPages})`}
|
|
240
319
|
rootClassName="px-2 h-8"
|
|
241
320
|
className="text-xs h-8"
|
|
242
321
|
autoFocus={true}
|
|
243
322
|
icon={null}
|
|
323
|
+
value={search}
|
|
324
|
+
onValueChange={setSearch}
|
|
244
325
|
onKeyDown={(e) => {
|
|
245
326
|
// Allow navigation/editing keys, block non-numeric input
|
|
246
327
|
const allowed = [
|
|
@@ -248,6 +329,8 @@ export const PageSelector = ({
|
|
|
248
329
|
"Delete",
|
|
249
330
|
"ArrowLeft",
|
|
250
331
|
"ArrowRight",
|
|
332
|
+
"ArrowUp",
|
|
333
|
+
"ArrowDown",
|
|
251
334
|
"Tab",
|
|
252
335
|
"Enter",
|
|
253
336
|
"Escape",
|
|
@@ -257,27 +340,19 @@ export const PageSelector = ({
|
|
|
257
340
|
}
|
|
258
341
|
}}
|
|
259
342
|
/>
|
|
260
|
-
<CommandList className="max-h-60">
|
|
261
|
-
{
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
onMouseDown={Events.preventFocus}
|
|
273
|
-
>
|
|
274
|
-
{item.page}
|
|
275
|
-
</CommandItem>
|
|
276
|
-
),
|
|
343
|
+
<CommandList className="max-h-60 overflow-hidden">
|
|
344
|
+
{mapping.count === 0 ? (
|
|
345
|
+
<CommandEmpty className="py-2 text-center text-xs text-muted-foreground">
|
|
346
|
+
No matching page
|
|
347
|
+
</CommandEmpty>
|
|
348
|
+
) : (
|
|
349
|
+
<VirtualizedPageList
|
|
350
|
+
mapping={mapping}
|
|
351
|
+
currentPage={currentPage}
|
|
352
|
+
listHeight={listHeight}
|
|
353
|
+
onSelect={handleSelect}
|
|
354
|
+
/>
|
|
277
355
|
)}
|
|
278
|
-
<CommandEmpty className="py-2 text-center text-xs text-muted-foreground">
|
|
279
|
-
No matching page
|
|
280
|
-
</CommandEmpty>
|
|
281
356
|
</CommandList>
|
|
282
357
|
</Command>
|
|
283
358
|
</PopoverContent>
|
|
@@ -285,57 +360,95 @@ export const PageSelector = ({
|
|
|
285
360
|
);
|
|
286
361
|
};
|
|
287
362
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
const
|
|
300
|
-
for (let i = 0; i < count; i++) {
|
|
301
|
-
items.push({ type: "page", page: start + i });
|
|
302
|
-
}
|
|
303
|
-
};
|
|
304
|
-
|
|
305
|
-
addPages(1, 10);
|
|
306
|
-
items.push({ type: "ellipsis", key: "e1" });
|
|
307
|
-
|
|
308
|
-
if (currentPage > 10 && currentPage <= middle - 5) {
|
|
309
|
-
items.push(
|
|
310
|
-
{ type: "page", page: currentPage },
|
|
311
|
-
{ type: "ellipsis", key: "e1b" },
|
|
312
|
-
);
|
|
313
|
-
}
|
|
363
|
+
const VirtualizedPageList = ({
|
|
364
|
+
mapping,
|
|
365
|
+
currentPage,
|
|
366
|
+
listHeight,
|
|
367
|
+
onSelect,
|
|
368
|
+
}: {
|
|
369
|
+
mapping: PageMapping;
|
|
370
|
+
currentPage: number;
|
|
371
|
+
listHeight: number;
|
|
372
|
+
onSelect: (page: number) => void;
|
|
373
|
+
}) => {
|
|
374
|
+
const parentRef = React.useRef<HTMLDivElement>(null);
|
|
314
375
|
|
|
315
|
-
|
|
316
|
-
items.push({ type: "ellipsis", key: "e2" });
|
|
376
|
+
const currentIndex = mapping.indexOfPage(currentPage);
|
|
317
377
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
378
|
+
const virtualizer = useVirtualizer({
|
|
379
|
+
count: mapping.count,
|
|
380
|
+
getScrollElement: () => parentRef.current,
|
|
381
|
+
estimateSize: () => PAGE_ITEM_HEIGHT,
|
|
382
|
+
overscan: 10,
|
|
383
|
+
initialOffset:
|
|
384
|
+
currentIndex > 0
|
|
385
|
+
? Math.max(0, currentIndex * PAGE_ITEM_HEIGHT - listHeight / 2)
|
|
386
|
+
: 0,
|
|
387
|
+
});
|
|
324
388
|
|
|
325
|
-
|
|
389
|
+
// Scroll to top when filtered results change (user is searching)
|
|
390
|
+
const prevCount = React.useRef(mapping.count);
|
|
391
|
+
React.useEffect(() => {
|
|
392
|
+
if (mapping.count !== prevCount.current) {
|
|
393
|
+
virtualizer.scrollToIndex(0);
|
|
394
|
+
prevCount.current = mapping.count;
|
|
395
|
+
}
|
|
396
|
+
}, [mapping.count, virtualizer]);
|
|
326
397
|
|
|
327
|
-
return
|
|
328
|
-
}
|
|
398
|
+
return (
|
|
399
|
+
<div ref={parentRef} style={{ height: listHeight, overflow: "auto" }}>
|
|
400
|
+
<div
|
|
401
|
+
style={{
|
|
402
|
+
height: virtualizer.getTotalSize(),
|
|
403
|
+
width: "100%",
|
|
404
|
+
position: "relative",
|
|
405
|
+
}}
|
|
406
|
+
>
|
|
407
|
+
{virtualizer.getVirtualItems().map((virtualItem) => {
|
|
408
|
+
const page = mapping.pageAtIndex(virtualItem.index);
|
|
409
|
+
return (
|
|
410
|
+
<CommandItem
|
|
411
|
+
key={page}
|
|
412
|
+
value={String(page)}
|
|
413
|
+
data-testid="page-option"
|
|
414
|
+
aria-selected={page === currentPage}
|
|
415
|
+
className={cn(
|
|
416
|
+
"text-xs cursor-pointer",
|
|
417
|
+
page === currentPage && "font-semibold bg-accent",
|
|
418
|
+
)}
|
|
419
|
+
style={{
|
|
420
|
+
position: "absolute",
|
|
421
|
+
top: 0,
|
|
422
|
+
left: 0,
|
|
423
|
+
width: "100%",
|
|
424
|
+
height: virtualItem.size,
|
|
425
|
+
transform: `translateY(${virtualItem.start}px)`,
|
|
426
|
+
}}
|
|
427
|
+
onSelect={() => onSelect(page)}
|
|
428
|
+
onMouseDown={Events.preventFocus}
|
|
429
|
+
>
|
|
430
|
+
{page}
|
|
431
|
+
</CommandItem>
|
|
432
|
+
);
|
|
433
|
+
})}
|
|
434
|
+
</div>
|
|
435
|
+
</div>
|
|
436
|
+
);
|
|
437
|
+
};
|
|
329
438
|
|
|
330
439
|
export function prettifyRowCount(rowCount: number, locale: string): string {
|
|
331
440
|
return `${prettyNumber(rowCount, locale)} ${new PluralWord("row").pluralize(rowCount)}`;
|
|
332
441
|
}
|
|
333
442
|
|
|
334
|
-
export const prettifyRowColumnCount = (
|
|
335
|
-
numRows
|
|
336
|
-
totalColumns
|
|
337
|
-
locale
|
|
338
|
-
|
|
443
|
+
export const prettifyRowColumnCount = ({
|
|
444
|
+
numRows,
|
|
445
|
+
totalColumns,
|
|
446
|
+
locale,
|
|
447
|
+
}: {
|
|
448
|
+
numRows: number | "too_many";
|
|
449
|
+
totalColumns: number;
|
|
450
|
+
locale: string;
|
|
451
|
+
}): string => {
|
|
339
452
|
const rowsLabel =
|
|
340
453
|
numRows === "too_many" ? "Unknown" : prettifyRowCount(numRows, locale);
|
|
341
454
|
const columnsLabel = `${prettyNumber(totalColumns, locale)} ${new PluralWord("column").pluralize(totalColumns)}`;
|
|
@@ -105,7 +105,3 @@ export function extractTimezone(dtype: string | undefined): string | undefined {
|
|
|
105
105
|
const match = /^datetime(?:64)?\[[^,]+,([^,]+)]$/.exec(dtype);
|
|
106
106
|
return match?.[1]?.trim();
|
|
107
107
|
}
|
|
108
|
-
|
|
109
|
-
export type PageRange =
|
|
110
|
-
| { type: "page"; page: number }
|
|
111
|
-
| { type: "ellipsis"; key: string };
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { O as _assignValue_default, j as _isIndex_default, z as isObject_default } from "./isArrayLikeObject-LXbTYiBa.js";
|
|
2
|
-
import { c as _castPath_default, o as _baseGet_default, r as _baseFlatten_default, s as _toKey_default } from "./hasIn-DnfJcYpY.js";
|
|
3
|
-
import { t as toNumber_default } from "./toNumber-55tjPCWr.js";
|
|
4
|
-
var INFINITY = Infinity, MAX_INTEGER = 17976931348623157e292;
|
|
5
|
-
function toFinite(e) {
|
|
6
|
-
return e ? (e = toNumber_default(e), e === INFINITY || e === -INFINITY ? (e < 0 ? -1 : 1) * MAX_INTEGER : e === e ? e : 0) : e === 0 ? e : 0;
|
|
7
|
-
}
|
|
8
|
-
var toFinite_default = toFinite;
|
|
9
|
-
function flatten(e) {
|
|
10
|
-
return e != null && e.length ? _baseFlatten_default(e, 1) : [];
|
|
11
|
-
}
|
|
12
|
-
var flatten_default = flatten;
|
|
13
|
-
function baseSet(o, s, l, u) {
|
|
14
|
-
if (!isObject_default(o)) return o;
|
|
15
|
-
s = _castPath_default(s, o);
|
|
16
|
-
for (var d = -1, f = s.length, p = f - 1, m = o; m != null && ++d < f; ) {
|
|
17
|
-
var h = _toKey_default(s[d]), g = l;
|
|
18
|
-
if (h === "__proto__" || h === "constructor" || h === "prototype") return o;
|
|
19
|
-
if (d != p) {
|
|
20
|
-
var _ = m[h];
|
|
21
|
-
g = u ? u(_, h, m) : void 0, g === void 0 && (g = isObject_default(_) ? _ : _isIndex_default(s[d + 1]) ? [] : {});
|
|
22
|
-
}
|
|
23
|
-
_assignValue_default(m, h, g), m = m[h];
|
|
24
|
-
}
|
|
25
|
-
return o;
|
|
26
|
-
}
|
|
27
|
-
var _baseSet_default = baseSet;
|
|
28
|
-
function basePickBy(e, i, a) {
|
|
29
|
-
for (var s = -1, c = i.length, l = {}; ++s < c; ) {
|
|
30
|
-
var u = i[s], d = _baseGet_default(e, u);
|
|
31
|
-
a(d, u) && _baseSet_default(l, _castPath_default(u, e), d);
|
|
32
|
-
}
|
|
33
|
-
return l;
|
|
34
|
-
}
|
|
35
|
-
var _basePickBy_default = basePickBy;
|
|
36
|
-
export {
|
|
37
|
-
toFinite_default as i,
|
|
38
|
-
_baseSet_default as n,
|
|
39
|
-
flatten_default as r,
|
|
40
|
-
_basePickBy_default as t
|
|
41
|
-
};
|