gridsmith-ui 0.21.0 → 0.23.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/dist/chat.js +3 -3
- package/dist/chunk-3BRQRKDO.js +72 -0
- package/dist/chunk-3BRQRKDO.js.map +1 -0
- package/dist/{chunk-GGVASDXT.js → chunk-6PL7FXYH.js} +284 -521
- package/dist/chunk-6PL7FXYH.js.map +1 -0
- package/dist/chunk-7TOJ4G7S.js +197 -0
- package/dist/chunk-7TOJ4G7S.js.map +1 -0
- package/dist/chunk-CKWITUSH.js +40 -0
- package/dist/chunk-CKWITUSH.js.map +1 -0
- package/dist/{chunk-ILIODA7W.js → chunk-CXMV7SXJ.js} +4 -3
- package/dist/chunk-CXMV7SXJ.js.map +1 -0
- package/dist/{chunk-EQDR57AM.js → chunk-EYMGLK4M.js} +3 -3
- package/dist/{chunk-EQDR57AM.js.map → chunk-EYMGLK4M.js.map} +1 -1
- package/dist/chunk-ICNWPNMM.js +1363 -0
- package/dist/chunk-ICNWPNMM.js.map +1 -0
- package/dist/chunk-IVCVNAXG.js +115 -0
- package/dist/chunk-IVCVNAXG.js.map +1 -0
- package/dist/{chunk-XYDIBW3J.js → chunk-SBTBMAIU.js} +4 -3
- package/dist/chunk-SBTBMAIU.js.map +1 -0
- package/dist/data-grid.d.ts +38 -4
- package/dist/data-grid.js +305 -264
- package/dist/data-grid.js.map +1 -1
- package/dist/editor.js +10 -3
- package/dist/editor.js.map +1 -1
- package/dist/index.d.ts +122 -146
- package/dist/index.js +1091 -1885
- package/dist/index.js.map +1 -1
- package/dist/kanban.js +4 -2
- package/dist/kanban.js.map +1 -1
- package/dist/resizable.d.ts +1 -1
- package/dist/resizable.js +26 -14
- package/dist/resizable.js.map +1 -1
- package/dist/roots.css +24 -4
- package/dist/{table-utils-GounRE6s.d.ts → table-utils-BkjNEWts.d.ts} +5 -1
- package/dist/tokens.css +20 -3
- package/dist/use-pagination-DiJo0aW5.d.ts +153 -0
- package/dist/virtualized.d.ts +11 -1
- package/dist/virtualized.js +69 -18
- package/dist/virtualized.js.map +1 -1
- package/dist-static/tokens.css +20 -3
- package/package.json +1 -1
- package/dist/chunk-GGVASDXT.js.map +0 -1
- package/dist/chunk-ILIODA7W.js.map +0 -1
- package/dist/chunk-JN37OVTP.js +0 -67
- package/dist/chunk-JN37OVTP.js.map +0 -1
- package/dist/chunk-TKVTZWBN.js +0 -50
- package/dist/chunk-TKVTZWBN.js.map +0 -1
- package/dist/chunk-XYDIBW3J.js.map +0 -1
|
@@ -31,6 +31,10 @@ declare function BreakpointWidthProvider({ width, children }: {
|
|
|
31
31
|
declare function useBreakpoint(key: BreakpointKey): boolean;
|
|
32
32
|
|
|
33
33
|
/** Shared column-kind inference for Table and DataGrid. */
|
|
34
|
-
|
|
34
|
+
/**
|
|
35
|
+
* What a column holds, which decides how its cells lay out: numbers and dates shrink to their content and stay whole,
|
|
36
|
+
* an identifier (a long run of digits: a barcode, an ID) may wrap anywhere, an email truncates, text wraps at spaces.
|
|
37
|
+
*/
|
|
38
|
+
type ColumnKind = "date" | "number" | "email" | "label" | "text" | "identifier";
|
|
35
39
|
|
|
36
40
|
export { type BreakpointKey as B, type ColumnKind as C, BreakpointWidthProvider as a, useBreakpoint as u };
|
package/dist/tokens.css
CHANGED
|
@@ -168,9 +168,12 @@
|
|
|
168
168
|
--ds-sidebar-active-accent: var(--ds-sidebar-accent);
|
|
169
169
|
--ds-sidebar-active-rail: var(--ds-border-width-thick);
|
|
170
170
|
--ds-sidebar-active-image: none;
|
|
171
|
+
--ds-switch-off-fill: transparent;
|
|
172
|
+
--ds-switch-off-edge: var(--ds-input-border);
|
|
173
|
+
--ds-switch-off-knob: color-mix(in oklab, var(--ds-input-border) var(--ds-switch-knob-share, 100%), var(--ds-bg-surface));
|
|
171
174
|
}
|
|
172
175
|
|
|
173
|
-
/* Navigation active styles — redeclared for nested mode wrappers and overlay portals */
|
|
176
|
+
/* Navigation active styles and the switch's off look — redeclared for nested mode wrappers and overlay portals */
|
|
174
177
|
:root, [data-mode], [data-ds-overlay] {
|
|
175
178
|
--ds-nav-h-active-bg: transparent;
|
|
176
179
|
--ds-nav-h-active-text: var(--ds-text-primary);
|
|
@@ -198,6 +201,9 @@
|
|
|
198
201
|
--ds-sidebar-active-accent: var(--ds-sidebar-accent);
|
|
199
202
|
--ds-sidebar-active-rail: var(--ds-border-width-thick);
|
|
200
203
|
--ds-sidebar-active-image: none;
|
|
204
|
+
--ds-switch-off-fill: transparent;
|
|
205
|
+
--ds-switch-off-edge: var(--ds-input-border);
|
|
206
|
+
--ds-switch-off-knob: color-mix(in oklab, var(--ds-input-border) var(--ds-switch-knob-share, 100%), var(--ds-bg-surface));
|
|
201
207
|
}
|
|
202
208
|
|
|
203
209
|
/* Density — hold the configured value at every viewport */
|
|
@@ -241,6 +247,9 @@
|
|
|
241
247
|
--ds-text-on-primary: oklch(1 0 0);
|
|
242
248
|
--ds-accent-wash: var(--ds-gradient);
|
|
243
249
|
--ds-text-muted-on-tint: var(--ds-neutral-400);
|
|
250
|
+
--ds-check-bg: var(--ds-primary-400);
|
|
251
|
+
--ds-check-fg: var(--ds-neutral-950);
|
|
252
|
+
--ds-check-border: var(--ds-primary-400);
|
|
244
253
|
--ds-palette-1-bold: oklch(0.55 0.1200 48);
|
|
245
254
|
--ds-palette-1-subtle: oklch(0.92 0.0300 48);
|
|
246
255
|
--ds-palette-1-dark: oklch(0.35 0.1000 48);
|
|
@@ -290,6 +299,7 @@
|
|
|
290
299
|
--ds-chart-6-soft: color-mix(in oklch, var(--ds-palette-5-chart) 30%, transparent);
|
|
291
300
|
--ds-chart-fill: var(--ds-chart-1);
|
|
292
301
|
--ds-chart-fill-soft: var(--ds-chart-1-soft);
|
|
302
|
+
--ds-check-gradient: none;
|
|
293
303
|
--ds-status-success: oklch(0.65 0.12 150);
|
|
294
304
|
--ds-status-success-bg: oklch(0.22 0.02 150);
|
|
295
305
|
--ds-status-warning: oklch(0.75 0.12 55);
|
|
@@ -339,8 +349,8 @@
|
|
|
339
349
|
--ds-tab-hover-bg: var(--ds-bg-muted);
|
|
340
350
|
--ds-tab-active-bg: var(--ds-bg-surface);
|
|
341
351
|
--ds-input-bg: var(--ds-neutral-800);
|
|
342
|
-
--ds-input-border: var(--ds-neutral-
|
|
343
|
-
--ds-input-border-hover: var(--ds-neutral-
|
|
352
|
+
--ds-input-border: oklch(0.645 calc(0.008 * var(--ds-sat-neutral)) var(--ds-hue-neutral));
|
|
353
|
+
--ds-input-border-hover: var(--ds-neutral-400);
|
|
344
354
|
--ds-input-focus-ring: var(--ds-ring-active);
|
|
345
355
|
--ds-shadow-focus: 0 0 0 2px var(--ds-primary-500);
|
|
346
356
|
--ds-accent-primary: var(--ds-primary-500);
|
|
@@ -359,6 +369,9 @@
|
|
|
359
369
|
--ds-accent-muted: color-mix(in srgb, var(--ds-accent-primary) 20%, transparent);
|
|
360
370
|
--ds-accent-soft: color-mix(in srgb, var(--ds-accent-primary) 30%, transparent);
|
|
361
371
|
--ds-accent-subtle-text: var(--ds-accent-primary);
|
|
372
|
+
--ds-check-bg: var(--ds-primary-400);
|
|
373
|
+
--ds-check-fg: var(--ds-neutral-950);
|
|
374
|
+
--ds-check-border: var(--ds-primary-400);
|
|
362
375
|
--ds-nav-h-active-bg: transparent;
|
|
363
376
|
--ds-nav-h-active-text: var(--ds-text-primary);
|
|
364
377
|
--ds-nav-h-inactive-text: var(--ds-text-muted);
|
|
@@ -385,4 +398,8 @@
|
|
|
385
398
|
--ds-sidebar-active-accent: var(--ds-sidebar-accent);
|
|
386
399
|
--ds-sidebar-active-rail: var(--ds-border-width-thick);
|
|
387
400
|
--ds-sidebar-active-image: none;
|
|
401
|
+
--ds-switch-off-fill: transparent;
|
|
402
|
+
--ds-switch-off-edge: var(--ds-input-border);
|
|
403
|
+
--ds-switch-off-knob: color-mix(in oklab, var(--ds-input-border) var(--ds-switch-knob-share, 100%), var(--ds-bg-surface));
|
|
404
|
+
--ds-check-gradient: none;
|
|
388
405
|
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
|
|
3
|
+
type PreferenceValidationTiming = "onBlur" | "onSubmit" | "onChange";
|
|
4
|
+
type PreferenceBreakpoint = "sm" | "md" | "lg";
|
|
5
|
+
type PreferenceEmptyStyle = "illustration-cta" | "text-cta" | "redirect";
|
|
6
|
+
type PreferenceLoadingStyle = "skeleton" | "spinner" | "progress-bar";
|
|
7
|
+
type PreferenceDestructiveMode = "dialog" | "undo";
|
|
8
|
+
/** dataDisplay.paginationStyle — how a long list shows more: page numbers, a Load more button, or loading as the user scrolls. */
|
|
9
|
+
type PreferencePaginationStyle = "pagination" | "load-more" | "infinite-scroll";
|
|
10
|
+
interface AppShellPreferences {
|
|
11
|
+
/** forms.validationTiming — when a field first shows its error. */
|
|
12
|
+
validationTiming?: PreferenceValidationTiming;
|
|
13
|
+
/** forms.actions — where a form's buttons sit and how they align. */
|
|
14
|
+
formActions?: {
|
|
15
|
+
align?: "start" | "end";
|
|
16
|
+
placement?: "auto" | "inline";
|
|
17
|
+
};
|
|
18
|
+
/** dataDisplay.itemsPerPage — the page size of a paged or load-more list. */
|
|
19
|
+
itemsPerPage?: number;
|
|
20
|
+
/** dataDisplay.paginationStyle — page numbers, a Load more button, or loading on scroll; usePagination and Pagination follow it (round 22). */
|
|
21
|
+
paginationStyle?: PreferencePaginationStyle;
|
|
22
|
+
/** responsive.tableToCardsBreakpoint — below this width a Table becomes stacked cards. */
|
|
23
|
+
tableToCardsBreakpoint?: PreferenceBreakpoint;
|
|
24
|
+
/** emptyStates.emptyStyle — illustration with an action, text with an action, or redirect to creation. */
|
|
25
|
+
emptyStyle?: PreferenceEmptyStyle;
|
|
26
|
+
/** emptyStates.loadingStyle — what a page shows while data loads. */
|
|
27
|
+
loadingStyle?: PreferenceLoadingStyle;
|
|
28
|
+
/** destructiveActions.mode — confirm in a dialog, or act now with an Undo toast. */
|
|
29
|
+
destructiveMode?: PreferenceDestructiveMode;
|
|
30
|
+
/** destructiveActions.highSeverityActions — always confirm in a dialog, even in undo mode. */
|
|
31
|
+
highSeverityActions?: string[];
|
|
32
|
+
/** destructiveActions.typeToConfirmActions — the user types the name before the confirm enables. */
|
|
33
|
+
typeToConfirmActions?: string[];
|
|
34
|
+
/** destructiveActions.undoWindowSeconds — how long the Undo toast stays. */
|
|
35
|
+
undoWindowSeconds?: number;
|
|
36
|
+
}
|
|
37
|
+
declare const PreferencesContext: react.Context<AppShellPreferences | null>;
|
|
38
|
+
/** Every preference in force, the shell's value or the house default — what app code reads. */
|
|
39
|
+
interface ResolvedPreferences {
|
|
40
|
+
validationTiming: PreferenceValidationTiming;
|
|
41
|
+
formActions: {
|
|
42
|
+
align: "start" | "end";
|
|
43
|
+
placement: "auto" | "inline";
|
|
44
|
+
};
|
|
45
|
+
itemsPerPage: number;
|
|
46
|
+
paginationStyle: PreferencePaginationStyle;
|
|
47
|
+
tableToCardsBreakpoint: PreferenceBreakpoint;
|
|
48
|
+
emptyStyle: PreferenceEmptyStyle;
|
|
49
|
+
loadingStyle: PreferenceLoadingStyle;
|
|
50
|
+
destructiveMode: PreferenceDestructiveMode;
|
|
51
|
+
highSeverityActions: string[];
|
|
52
|
+
typeToConfirmActions: string[];
|
|
53
|
+
undoWindowSeconds: number;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* For app code: every preference in force — the shell's value, else the house default — so a page never writes a
|
|
57
|
+
* fallback of its own. Round 21 (run 58): with every field optional, TypeScript made the builder write
|
|
58
|
+
* `const { itemsPerPage = 20 } = usePreferences()`, a second copy of the preference it then edited by hand when the
|
|
59
|
+
* rule changed. Paged lists use `usePagination`, which reads the page size itself.
|
|
60
|
+
*/
|
|
61
|
+
declare function usePreferences(): ResolvedPreferences;
|
|
62
|
+
/**
|
|
63
|
+
* "Remove range" → "remove_range": the key the high-severity and type-to-confirm lists use. The engine's `actionKey`
|
|
64
|
+
* (platform/src/lib/destructive-mode.ts) is the same rule for compliance; a platform test keeps the two identical.
|
|
65
|
+
*/
|
|
66
|
+
declare function preferenceActionKey(label: string): string;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* A long list in one hook (round 21; all three list styles since round 22). The page size and the list style are the
|
|
70
|
+
* project's `dataDisplay.itemsPerPage` and `dataDisplay.paginationStyle`, read from the shell, so a mid-build
|
|
71
|
+
* `update_rule` on either reaches every list with no page edited. The page gets what to show, the props for
|
|
72
|
+
* `<Pagination>` — page numbers, a Load more button or loading on scroll, whichever the project's style is — and the
|
|
73
|
+
* numbers the count line needs ("Showing 51–100 of 200 events", or "Showing 40 of 120 members" while a list grows).
|
|
74
|
+
*
|
|
75
|
+
* Run 58 hand-wrote the paging; runs 59 and 60 hand-wrote load-more and scroll loading — an IntersectionObserver, a
|
|
76
|
+
* visible count and a page size copied in as a constant, twice in one app — because the library had no way to.
|
|
77
|
+
*
|
|
78
|
+
* const rows = events.map(toRow)
|
|
79
|
+
* const pager = usePagination(rows)
|
|
80
|
+
* <TableToolbar resultCount={rows.length} resultNoun={["event", "events"]} pagination={pager} />
|
|
81
|
+
* <Table columns={columns} data={rows} pager={pager} />
|
|
82
|
+
*
|
|
83
|
+
* The list takes the whole pager (Sprint 25.13 A3): Table, DataGrid, StackedList, Timeline and VirtualizedList draw the
|
|
84
|
+
* pager's part of every row and its control beneath, and a sortable Table sorts every row, not one page. For anything
|
|
85
|
+
* else, draw the page's items and the control yourself: `pager.items.map(…)` then `<Pagination {...pager.props} />`.
|
|
86
|
+
*
|
|
87
|
+
* A long page that must mount only the rows on screen (logs, a feed) still pages: the size the user asked for goes to
|
|
88
|
+
* the hook, with its override note, and the list mounts only what is on screen of each page (A49):
|
|
89
|
+
*
|
|
90
|
+
* // @gridsmith-override dataDisplay.itemsPerPage: <the user's words>
|
|
91
|
+
* const pager = usePagination(entries, { pageSize: 100 })
|
|
92
|
+
* <VirtualizedList items={entries} pager={pager} estimateSize={() => 40} renderItem={(entry) => <LogLine entry={entry} />} />
|
|
93
|
+
*/
|
|
94
|
+
interface Pager<T> {
|
|
95
|
+
/** The list style this list follows: the project's, unless `style` was passed. */
|
|
96
|
+
style: PreferencePaginationStyle;
|
|
97
|
+
/** What to show: the current page's rows, or every row loaded so far on a list that grows. */
|
|
98
|
+
items: T[];
|
|
99
|
+
/** The current page, from 1; on a growing list, how many pages are loaded. */
|
|
100
|
+
page: number;
|
|
101
|
+
pageSize: number;
|
|
102
|
+
totalItems: number;
|
|
103
|
+
totalPages: number;
|
|
104
|
+
/** The first and last row numbers on screen, from 1 ("Showing 51–100"); [0, 0] for an empty list. */
|
|
105
|
+
range: [number, number];
|
|
106
|
+
/** How many rows are on screen. */
|
|
107
|
+
shown: number;
|
|
108
|
+
/** Rows left to show: a next page, or more to load. */
|
|
109
|
+
hasMore: boolean;
|
|
110
|
+
/** The next page, or the next `pageSize` rows on a growing list. */
|
|
111
|
+
loadMore: () => void;
|
|
112
|
+
setPage: (page: number) => void;
|
|
113
|
+
/** A page-size selector's choice; it wins over the project's page size and starts again at page 1. */
|
|
114
|
+
setPageSize: (size: number) => void;
|
|
115
|
+
/**
|
|
116
|
+
* Spread onto <Pagination>: it renders page numbers, a Load more button or the scroll trigger, as `style` says. A list
|
|
117
|
+
* given the whole pager (`<Table pager={pager}>`, Sprint 25.13 A3) draws this control itself.
|
|
118
|
+
*/
|
|
119
|
+
props: {
|
|
120
|
+
currentPage: number;
|
|
121
|
+
totalPages: number;
|
|
122
|
+
onPageChange: (page: number) => void;
|
|
123
|
+
pageSize: number;
|
|
124
|
+
onPageSizeChange: (size: number) => void;
|
|
125
|
+
mode: PreferencePaginationStyle;
|
|
126
|
+
hasMore: boolean;
|
|
127
|
+
onLoadMore: () => void;
|
|
128
|
+
/** The page sizes the user may choose between, when the page offers the choice (`pageSizeOptions` below). */
|
|
129
|
+
pageSizeOptions?: number[];
|
|
130
|
+
/** Which pager the control belongs to, so a second control for the same list is caught in development (A3). */
|
|
131
|
+
pagerToken: object;
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
interface PaginationOptions {
|
|
135
|
+
/** A fixed page size for this list, over the project's. Leave it out: the project's page size is the rule. */
|
|
136
|
+
pageSize?: number;
|
|
137
|
+
/** Values that start the list again at page 1 when they change — the sort column and direction, a search query. */
|
|
138
|
+
resetOn?: unknown;
|
|
139
|
+
/**
|
|
140
|
+
* A list style for this list only, over the project's. Leave it out: the project's style is the rule. Passing one that
|
|
141
|
+
* differs is overriding a rule in force — ask the user first, and put `// @gridsmith-override
|
|
142
|
+
* dataDisplay.paginationStyle: <their reason>` above the call.
|
|
143
|
+
*/
|
|
144
|
+
style?: PreferencePaginationStyle;
|
|
145
|
+
/**
|
|
146
|
+
* The page sizes the user may choose between, beside the page numbers (`[10, 25, 50]`). The choice goes with the
|
|
147
|
+
* control, so a list given the pager (A3) offers it too. Leave it out for the project's page size alone.
|
|
148
|
+
*/
|
|
149
|
+
pageSizeOptions?: number[];
|
|
150
|
+
}
|
|
151
|
+
declare function usePagination<T>(list: readonly T[], options?: PaginationOptions): Pager<T>;
|
|
152
|
+
|
|
153
|
+
export { type AppShellPreferences as A, type Pager as P, type ResolvedPreferences as R, type PaginationOptions as a, PreferencesContext as b, usePreferences as c, preferenceActionKey as p, usePagination as u };
|
package/dist/virtualized.d.ts
CHANGED
|
@@ -1,16 +1,26 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { ReactNode, Ref } from 'react';
|
|
3
3
|
import { VirtualItem } from '@tanstack/react-virtual';
|
|
4
|
+
import { P as Pager } from './use-pagination-DiJo0aW5.js';
|
|
4
5
|
|
|
5
6
|
interface VirtualizedListProps<T> {
|
|
6
7
|
items: T[];
|
|
7
8
|
estimateSize: (index: number) => number;
|
|
9
|
+
/** An item, with its index in `items` (the whole list, when the list is paged). */
|
|
8
10
|
renderItem: (item: T, index: number, virtualItem: VirtualItem) => ReactNode;
|
|
9
11
|
overscan?: number;
|
|
10
12
|
height?: number | string;
|
|
11
13
|
className?: string;
|
|
12
14
|
ref?: Ref<HTMLDivElement>;
|
|
15
|
+
/**
|
|
16
|
+
* The list's pager (Sprint 25.13 A49): paging and drawing only the rows on screen combine. Pass every item and
|
|
17
|
+
* `usePagination(items)`'s pager: the list mounts only the rows on screen of the pager's part, and beneath it draws the
|
|
18
|
+
* control in the project's style. A new page starts at its top; with infinite scroll, scrolling inside the list loads
|
|
19
|
+
* more. For a long page (logs, feeds) the user asked to page differently, pass the size to the hook
|
|
20
|
+
* (`usePagination(rows, { pageSize: 100 })`) with its override note.
|
|
21
|
+
*/
|
|
22
|
+
pager?: Pager<unknown>;
|
|
13
23
|
}
|
|
14
|
-
declare function VirtualizedList<T>({ items, estimateSize, renderItem, overscan, height, className, ref, }: VirtualizedListProps<T>): react_jsx_runtime.JSX.Element;
|
|
24
|
+
declare function VirtualizedList<T>({ items: allItems, estimateSize, renderItem, overscan, height, className, ref, pager, }: VirtualizedListProps<T>): react_jsx_runtime.JSX.Element;
|
|
15
25
|
|
|
16
26
|
export { VirtualizedList };
|
package/dist/virtualized.js
CHANGED
|
@@ -1,25 +1,67 @@
|
|
|
1
|
+
import { useWholeListCheck, pagerPart, Pagination } from './chunk-ICNWPNMM.js';
|
|
2
|
+
import './chunk-7TOJ4G7S.js';
|
|
3
|
+
import './chunk-RT7RYGC3.js';
|
|
4
|
+
import { useScrollsInside } from './chunk-CKWITUSH.js';
|
|
5
|
+
import './chunk-CXMV7SXJ.js';
|
|
6
|
+
import './chunk-7Q46JXSK.js';
|
|
7
|
+
import { useLatest } from './chunk-WH2FUFAC.js';
|
|
8
|
+
import './chunk-4LDYR7QP.js';
|
|
1
9
|
import { cn } from './chunk-M2QRNBDQ.js';
|
|
2
|
-
import { useRef } from 'react';
|
|
10
|
+
import { useRef, useEffect } from 'react';
|
|
3
11
|
import { useVirtualizer } from '@tanstack/react-virtual';
|
|
4
|
-
import { jsx } from 'react/jsx-runtime';
|
|
12
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
5
13
|
|
|
6
14
|
function VirtualizedList({
|
|
7
|
-
items,
|
|
15
|
+
items: allItems,
|
|
8
16
|
estimateSize,
|
|
9
17
|
renderItem,
|
|
10
18
|
overscan = 5,
|
|
11
19
|
height = 400,
|
|
12
20
|
className,
|
|
13
|
-
ref
|
|
21
|
+
ref,
|
|
22
|
+
pager
|
|
14
23
|
}) {
|
|
24
|
+
useScrollsInside();
|
|
15
25
|
const parentRef = useRef(null);
|
|
26
|
+
const endRef = useRef(null);
|
|
27
|
+
useWholeListCheck("VirtualizedList", allItems.length, pager);
|
|
28
|
+
const items = pagerPart(allItems, pager);
|
|
29
|
+
const offset = pager ? Math.max(0, pager.range[0] - 1) : 0;
|
|
16
30
|
const virtualizer = useVirtualizer({
|
|
17
31
|
count: items.length,
|
|
18
32
|
getScrollElement: () => parentRef.current,
|
|
19
|
-
estimateSize,
|
|
33
|
+
estimateSize: (index) => estimateSize(offset + index),
|
|
34
|
+
// a row is known by its place in the whole list, so page 2's third row isn't page 1's (the review of 30 September:
|
|
35
|
+
// an entry opened on page 1 showed opened on page 2, and page 1's heights carried over)
|
|
36
|
+
getItemKey: (index) => offset + index,
|
|
20
37
|
overscan
|
|
21
38
|
});
|
|
22
|
-
|
|
39
|
+
const page = pager ? pager.page : null;
|
|
40
|
+
const pageBefore = useRef(page);
|
|
41
|
+
const numbered = pager?.style === "pagination";
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
const before = pageBefore.current;
|
|
44
|
+
pageBefore.current = page;
|
|
45
|
+
if (page === null || !parentRef.current) return;
|
|
46
|
+
if (numbered ? page !== before : before !== null && page < before) parentRef.current.scrollTop = 0;
|
|
47
|
+
}, [page, numbered]);
|
|
48
|
+
const loadMore = useLatest(pager?.loadMore);
|
|
49
|
+
const growing = pager?.style === "infinite-scroll" && pager.hasMore;
|
|
50
|
+
const loadedAt = useRef(-1);
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
const root = parentRef.current;
|
|
53
|
+
const end = endRef.current;
|
|
54
|
+
if (loadedAt.current !== items.length) loadedAt.current = -1;
|
|
55
|
+
if (!growing || !root || !end || typeof IntersectionObserver === "undefined") return;
|
|
56
|
+
const observer = new IntersectionObserver((entries) => {
|
|
57
|
+
if (!entries.some((e) => e.isIntersecting) || loadedAt.current === items.length) return;
|
|
58
|
+
loadedAt.current = items.length;
|
|
59
|
+
loadMore.current?.();
|
|
60
|
+
}, { root, rootMargin: "200px 0px" });
|
|
61
|
+
observer.observe(end);
|
|
62
|
+
return () => observer.disconnect();
|
|
63
|
+
}, [growing, items.length, loadMore]);
|
|
64
|
+
const list = /* @__PURE__ */ jsxs(
|
|
23
65
|
"div",
|
|
24
66
|
{
|
|
25
67
|
ref: (node) => {
|
|
@@ -27,27 +69,36 @@ function VirtualizedList({
|
|
|
27
69
|
if (typeof ref === "function") ref(node);
|
|
28
70
|
else if (ref) ref.current = node;
|
|
29
71
|
},
|
|
72
|
+
"data-ds-list": pager ? "" : void 0,
|
|
30
73
|
className: cn(
|
|
31
74
|
"overflow-auto",
|
|
32
75
|
"rounded-[var(--ds-radius-md)]",
|
|
33
76
|
"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]",
|
|
34
77
|
"bg-[var(--ds-bg-surface)]",
|
|
35
|
-
className
|
|
78
|
+
!pager && className
|
|
36
79
|
),
|
|
37
80
|
style: { height },
|
|
38
|
-
children:
|
|
39
|
-
"div",
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
81
|
+
children: [
|
|
82
|
+
/* @__PURE__ */ jsx("div", { className: "relative w-full", style: { height: virtualizer.getTotalSize() }, children: virtualizer.getVirtualItems().map((virtualItem) => /* @__PURE__ */ jsx(
|
|
83
|
+
"div",
|
|
84
|
+
{
|
|
85
|
+
"data-index": virtualItem.index,
|
|
86
|
+
ref: virtualizer.measureElement,
|
|
87
|
+
className: "absolute top-0 left-0 w-full",
|
|
88
|
+
style: { transform: `translateY(${virtualItem.start}px)` },
|
|
89
|
+
children: renderItem(items[virtualItem.index], offset + virtualItem.index, virtualItem)
|
|
90
|
+
},
|
|
91
|
+
virtualItem.key
|
|
92
|
+
)) }),
|
|
93
|
+
growing && /* @__PURE__ */ jsx("div", { ref: endRef, "data-load-more-trigger": "", "aria-hidden": "true", className: "h-px w-full" })
|
|
94
|
+
]
|
|
49
95
|
}
|
|
50
96
|
);
|
|
97
|
+
if (!pager) return list;
|
|
98
|
+
return /* @__PURE__ */ jsxs("div", { "data-gs-paged": "", className: cn("flex flex-col min-w-0", className), children: [
|
|
99
|
+
list,
|
|
100
|
+
allItems.length > 0 && /* @__PURE__ */ jsx(Pagination, { ...pager.props, mode: pager.style === "infinite-scroll" ? "load-more" : pager.props.mode })
|
|
101
|
+
] });
|
|
51
102
|
}
|
|
52
103
|
|
|
53
104
|
export { VirtualizedList };
|
package/dist/virtualized.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../showcase/src/components/VirtualizedList.tsx"],"names":[],"mappings":";;;;;AAcO,SAAS,eAAA,CAAmB;AAAA,EACjC,KAAA;AAAA,EACA,YAAA;AAAA,EACA,UAAA;AAAA,EACA,QAAA,GAAW,CAAA;AAAA,EACX,MAAA,GAAS,GAAA;AAAA,EACT,SAAA;AAAA,EACA;AACF,CAAA,EAA4B;AAC1B,EAAA,MAAM,SAAA,GAAY,OAAuB,IAAI,CAAA;AAG7C,EAAA,MAAM,cAAc,cAAA,CAAe;AAAA,IACjC,OAAO,KAAA,CAAM,MAAA;AAAA,IACb,gBAAA,EAAkB,MAAM,SAAA,CAAU,OAAA;AAAA,IAClC,YAAA;AAAA,IACA;AAAA,GACD,CAAA;AAED,EAAA,uBACE,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,GAAA,EAAK,CAAC,IAAA,KAAS;AACb,QAAC,UAA4D,OAAA,GAAU,IAAA;AACvE,QAAA,IAAI,OAAO,GAAA,KAAQ,UAAA,EAAY,GAAA,CAAI,IAAI,CAAA;AAAA,aAAA,IAC9B,GAAA,EAAM,GAAA,CAAsD,OAAA,GAAU,IAAA;AAAA,MACjF,CAAA;AAAA,MACA,SAAA,EAAW,EAAA;AAAA,QACT,eAAA;AAAA,QACA,+BAAA;AAAA,QACA,yEAAA;AAAA,QACA,2BAAA;AAAA,QACA;AAAA,OACF;AAAA,MACA,KAAA,EAAO,EAAE,MAAA,EAAO;AAAA,MAEhB,8BAAC,KAAA,EAAA,EAAI,SAAA,EAAU,iBAAA,EAAkB,KAAA,EAAO,EAAE,MAAA,EAAQ,WAAA,CAAY,YAAA,EAAa,IACxE,QAAA,EAAA,WAAA,CAAY,eAAA,EAAgB,CAAE,GAAA,CAAI,CAAC,WAAA,qBAClC,GAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UAEC,cAAY,WAAA,CAAY,KAAA;AAAA,UACxB,KAAK,WAAA,CAAY,cAAA;AAAA,UACjB,SAAA,EAAU,8BAAA;AAAA,UACV,OAAO,EAAE,SAAA,EAAW,CAAA,WAAA,EAAc,WAAA,CAAY,KAAK,CAAA,GAAA,CAAA,EAAM;AAAA,UAExD,qBAAW,KAAA,CAAM,WAAA,CAAY,KAAK,CAAA,EAAG,WAAA,CAAY,OAAO,WAAW;AAAA,SAAA;AAAA,QAN/D,WAAA,CAAY;AAAA,OAQpB,CAAA,EACH;AAAA;AAAA,GACF;AAEJ","file":"virtualized.js","sourcesContent":["import { useRef, type ReactNode, type Ref } from \"react\";\nimport { useVirtualizer, type VirtualItem } from \"@tanstack/react-virtual\";\nimport { cn } from \"../lib/utils\";\n\nexport interface VirtualizedListProps<T> {\n items: T[];\n estimateSize: (index: number) => number;\n renderItem: (item: T, index: number, virtualItem: VirtualItem) => ReactNode;\n overscan?: number;\n height?: number | string;\n className?: string;\n ref?: Ref<HTMLDivElement>;\n}\n\nexport function VirtualizedList<T>({\n items,\n estimateSize,\n renderItem,\n overscan = 5,\n height = 400,\n className,\n ref,\n}: VirtualizedListProps<T>) {\n const parentRef = useRef<HTMLDivElement>(null);\n\n // eslint-disable-next-line react-hooks/incompatible-library -- TanStack Virtual is not compiler-compatible (informational; the project does not use the React Compiler)\n const virtualizer = useVirtualizer({\n count: items.length,\n getScrollElement: () => parentRef.current,\n estimateSize,\n overscan,\n });\n\n return (\n <div\n ref={(node) => {\n (parentRef as React.MutableRefObject<HTMLDivElement | null>).current = node;\n if (typeof ref === \"function\") ref(node);\n else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node;\n }}\n className={cn(\n \"overflow-auto\",\n \"rounded-[var(--ds-radius-md)]\",\n \"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\",\n \"bg-[var(--ds-bg-surface)]\",\n className,\n )}\n style={{ height }}\n >\n <div className=\"relative w-full\" style={{ height: virtualizer.getTotalSize() }}>\n {virtualizer.getVirtualItems().map((virtualItem) => (\n <div\n key={virtualItem.key}\n data-index={virtualItem.index}\n ref={virtualizer.measureElement}\n className=\"absolute top-0 left-0 w-full\"\n style={{ transform: `translateY(${virtualItem.start}px)` }}\n >\n {renderItem(items[virtualItem.index], virtualItem.index, virtualItem)}\n </div>\n ))}\n </div>\n </div>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../showcase/src/components/VirtualizedList.tsx"],"names":[],"mappings":"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","file":"virtualized.js","sourcesContent":["import { useEffect, useRef, type ReactNode, type Ref } from \"react\";\nimport { useVirtualizer, type VirtualItem } from \"@tanstack/react-virtual\";\nimport { cn } from \"../lib/utils\";\nimport { useLatest } from \"../lib/use-latest\";\nimport { Pagination } from \"./Pagination\";\nimport { pagerPart, useWholeListCheck, type Pager } from \"../lib/use-pagination\";\nimport { useScrollsInside } from \"../lib/surface-context\";\n\nexport interface VirtualizedListProps<T> {\n items: T[];\n estimateSize: (index: number) => number;\n /** An item, with its index in `items` (the whole list, when the list is paged). */\n renderItem: (item: T, index: number, virtualItem: VirtualItem) => ReactNode;\n overscan?: number;\n height?: number | string;\n className?: string;\n ref?: Ref<HTMLDivElement>;\n /**\n * The list's pager (Sprint 25.13 A49): paging and drawing only the rows on screen combine. Pass every item and\n * `usePagination(items)`'s pager: the list mounts only the rows on screen of the pager's part, and beneath it draws the\n * control in the project's style. A new page starts at its top; with infinite scroll, scrolling inside the list loads\n * more. For a long page (logs, feeds) the user asked to page differently, pass the size to the hook\n * (`usePagination(rows, { pageSize: 100 })`) with its override note.\n */\n pager?: Pager<unknown>;\n}\n\nexport function VirtualizedList<T>({\n items: allItems,\n estimateSize,\n renderItem,\n overscan = 5,\n height = 400,\n className,\n ref,\n pager,\n}: VirtualizedListProps<T>) {\n // Sprint 25.14 A44: a list with no frame of its own: a SplitView's list pane keeps its hairline around it\n useScrollsInside();\n const parentRef = useRef<HTMLDivElement>(null);\n const endRef = useRef<HTMLDivElement>(null);\n useWholeListCheck(\"VirtualizedList\", allItems.length, pager);\n const items = pagerPart(allItems, pager);\n const offset = pager ? Math.max(0, pager.range[0] - 1) : 0;\n\n // eslint-disable-next-line react-hooks/incompatible-library -- TanStack Virtual is not compiler-compatible (informational; the project does not use the React Compiler)\n const virtualizer = useVirtualizer({\n count: items.length,\n getScrollElement: () => parentRef.current,\n estimateSize: (index) => estimateSize(offset + index),\n // a row is known by its place in the whole list, so page 2's third row isn't page 1's (the review of 30 September:\n // an entry opened on page 1 showed opened on page 2, and page 1's heights carried over)\n getItemKey: (index) => offset + index,\n overscan,\n });\n\n // A49: a new page starts at its top, and so does a growing list that starts again at its first page (a new order, a\n // search): left scrolled to its end, it loaded the next page at once (the review of 30 September)\n const page = pager ? pager.page : null;\n const pageBefore = useRef(page);\n const numbered = pager?.style === \"pagination\";\n useEffect(() => {\n const before = pageBefore.current;\n pageBefore.current = page;\n if (page === null || !parentRef.current) return;\n if (numbered ? page !== before : before !== null && page < before) parentRef.current.scrollTop = 0;\n }, [page, numbered]);\n\n // A49: with infinite scroll, the trigger sits at the end of the list's own content and watches the list's scroller\n // (it watched the viewport, so scrolling inside the list never loaded more); it loads once per growth of the list\n const loadMore = useLatest(pager?.loadMore);\n const growing = pager?.style === \"infinite-scroll\" && pager.hasMore;\n const loadedAt = useRef(-1);\n useEffect(() => {\n const root = parentRef.current;\n const end = endRef.current;\n // the list's length changed since the last load (it grew, or started again at page 1): it may load again (the\n // review of 30 September: after a reset to the first page it never loaded again)\n if (loadedAt.current !== items.length) loadedAt.current = -1;\n if (!growing || !root || !end || typeof IntersectionObserver === \"undefined\") return;\n const observer = new IntersectionObserver((entries) => {\n if (!entries.some((e) => e.isIntersecting) || loadedAt.current === items.length) return;\n loadedAt.current = items.length;\n loadMore.current?.();\n }, { root, rootMargin: \"200px 0px\" });\n observer.observe(end);\n return () => observer.disconnect();\n }, [growing, items.length, loadMore]);\n\n const list = (\n <div\n ref={(node) => {\n (parentRef as React.MutableRefObject<HTMLDivElement | null>).current = node;\n if (typeof ref === \"function\") ref(node);\n else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node;\n }}\n data-ds-list={pager ? \"\" : undefined}\n className={cn(\n \"overflow-auto\",\n \"rounded-[var(--ds-radius-md)]\",\n \"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\",\n \"bg-[var(--ds-bg-surface)]\",\n !pager && className,\n )}\n style={{ height }}\n >\n <div className=\"relative w-full\" style={{ height: virtualizer.getTotalSize() }}>\n {virtualizer.getVirtualItems().map((virtualItem) => (\n <div\n key={virtualItem.key}\n data-index={virtualItem.index}\n ref={virtualizer.measureElement}\n className=\"absolute top-0 left-0 w-full\"\n style={{ transform: `translateY(${virtualItem.start}px)` }}\n >\n {renderItem(items[virtualItem.index], offset + virtualItem.index, virtualItem)}\n </div>\n ))}\n </div>\n {growing && <div ref={endRef} data-load-more-trigger=\"\" aria-hidden=\"true\" className=\"h-px w-full\" />}\n </div>\n );\n // A3: the pager's control is the list's next sibling, as <Pagination {...pager.props} /> would be. With infinite\n // scroll it is the Load more button alone, for keyboard users: the list's own trigger loads as it scrolls (A49). The\n // two are one element, which takes the className, so in a grid or a flex row they stay one item, and the list keeps\n // its element while its items come and go (the review of 30 September).\n if (!pager) return list;\n return (\n <div data-gs-paged=\"\" className={cn(\"flex flex-col min-w-0\", className)}>\n {list}\n {allItems.length > 0 && <Pagination {...pager.props} mode={pager.style === \"infinite-scroll\" ? \"load-more\" : pager.props.mode} />}\n </div>\n );\n}\n"]}
|
package/dist-static/tokens.css
CHANGED
|
@@ -168,9 +168,12 @@
|
|
|
168
168
|
--ds-sidebar-active-accent: var(--ds-sidebar-accent);
|
|
169
169
|
--ds-sidebar-active-rail: var(--ds-border-width-thick);
|
|
170
170
|
--ds-sidebar-active-image: none;
|
|
171
|
+
--ds-switch-off-fill: transparent;
|
|
172
|
+
--ds-switch-off-edge: var(--ds-input-border);
|
|
173
|
+
--ds-switch-off-knob: color-mix(in oklab, var(--ds-input-border) var(--ds-switch-knob-share, 100%), var(--ds-bg-surface));
|
|
171
174
|
}
|
|
172
175
|
|
|
173
|
-
/* Navigation active styles — redeclared for nested mode wrappers and overlay portals */
|
|
176
|
+
/* Navigation active styles and the switch's off look — redeclared for nested mode wrappers and overlay portals */
|
|
174
177
|
:root, [data-mode], [data-ds-overlay] {
|
|
175
178
|
--ds-nav-h-active-bg: transparent;
|
|
176
179
|
--ds-nav-h-active-text: var(--ds-text-primary);
|
|
@@ -198,6 +201,9 @@
|
|
|
198
201
|
--ds-sidebar-active-accent: var(--ds-sidebar-accent);
|
|
199
202
|
--ds-sidebar-active-rail: var(--ds-border-width-thick);
|
|
200
203
|
--ds-sidebar-active-image: none;
|
|
204
|
+
--ds-switch-off-fill: transparent;
|
|
205
|
+
--ds-switch-off-edge: var(--ds-input-border);
|
|
206
|
+
--ds-switch-off-knob: color-mix(in oklab, var(--ds-input-border) var(--ds-switch-knob-share, 100%), var(--ds-bg-surface));
|
|
201
207
|
}
|
|
202
208
|
|
|
203
209
|
/* Density — hold the configured value at every viewport */
|
|
@@ -241,6 +247,9 @@
|
|
|
241
247
|
--ds-text-on-primary: oklch(1 0 0);
|
|
242
248
|
--ds-accent-wash: var(--ds-gradient);
|
|
243
249
|
--ds-text-muted-on-tint: var(--ds-neutral-400);
|
|
250
|
+
--ds-check-bg: var(--ds-primary-400);
|
|
251
|
+
--ds-check-fg: var(--ds-neutral-950);
|
|
252
|
+
--ds-check-border: var(--ds-primary-400);
|
|
244
253
|
--ds-palette-1-bold: oklch(0.55 0.1200 48);
|
|
245
254
|
--ds-palette-1-subtle: oklch(0.92 0.0300 48);
|
|
246
255
|
--ds-palette-1-dark: oklch(0.35 0.1000 48);
|
|
@@ -290,6 +299,7 @@
|
|
|
290
299
|
--ds-chart-6-soft: color-mix(in oklch, var(--ds-palette-5-chart) 30%, transparent);
|
|
291
300
|
--ds-chart-fill: var(--ds-chart-1);
|
|
292
301
|
--ds-chart-fill-soft: var(--ds-chart-1-soft);
|
|
302
|
+
--ds-check-gradient: none;
|
|
293
303
|
--ds-status-success: oklch(0.65 0.12 150);
|
|
294
304
|
--ds-status-success-bg: oklch(0.22 0.02 150);
|
|
295
305
|
--ds-status-warning: oklch(0.75 0.12 55);
|
|
@@ -339,8 +349,8 @@
|
|
|
339
349
|
--ds-tab-hover-bg: var(--ds-bg-muted);
|
|
340
350
|
--ds-tab-active-bg: var(--ds-bg-surface);
|
|
341
351
|
--ds-input-bg: var(--ds-neutral-800);
|
|
342
|
-
--ds-input-border: var(--ds-neutral-
|
|
343
|
-
--ds-input-border-hover: var(--ds-neutral-
|
|
352
|
+
--ds-input-border: oklch(0.645 calc(0.008 * var(--ds-sat-neutral)) var(--ds-hue-neutral));
|
|
353
|
+
--ds-input-border-hover: var(--ds-neutral-400);
|
|
344
354
|
--ds-input-focus-ring: var(--ds-ring-active);
|
|
345
355
|
--ds-shadow-focus: 0 0 0 2px var(--ds-primary-500);
|
|
346
356
|
--ds-accent-primary: var(--ds-primary-500);
|
|
@@ -359,6 +369,9 @@
|
|
|
359
369
|
--ds-accent-muted: color-mix(in srgb, var(--ds-accent-primary) 20%, transparent);
|
|
360
370
|
--ds-accent-soft: color-mix(in srgb, var(--ds-accent-primary) 30%, transparent);
|
|
361
371
|
--ds-accent-subtle-text: var(--ds-accent-primary);
|
|
372
|
+
--ds-check-bg: var(--ds-primary-400);
|
|
373
|
+
--ds-check-fg: var(--ds-neutral-950);
|
|
374
|
+
--ds-check-border: var(--ds-primary-400);
|
|
362
375
|
--ds-nav-h-active-bg: transparent;
|
|
363
376
|
--ds-nav-h-active-text: var(--ds-text-primary);
|
|
364
377
|
--ds-nav-h-inactive-text: var(--ds-text-muted);
|
|
@@ -385,4 +398,8 @@
|
|
|
385
398
|
--ds-sidebar-active-accent: var(--ds-sidebar-accent);
|
|
386
399
|
--ds-sidebar-active-rail: var(--ds-border-width-thick);
|
|
387
400
|
--ds-sidebar-active-image: none;
|
|
401
|
+
--ds-switch-off-fill: transparent;
|
|
402
|
+
--ds-switch-off-edge: var(--ds-input-border);
|
|
403
|
+
--ds-switch-off-knob: color-mix(in oklab, var(--ds-input-border) var(--ds-switch-knob-share, 100%), var(--ds-bg-surface));
|
|
404
|
+
--ds-check-gradient: none;
|
|
388
405
|
}
|
package/package.json
CHANGED