@djangocfg/widget-data 0.1.7 → 0.1.9
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@djangocfg/widget-data",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "Data surfaces: file tree, JSON viewer, data grid and table, kanban, listbox, masonry and timeline",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"tree",
|
|
@@ -90,21 +90,21 @@
|
|
|
90
90
|
"test:watch": "vitest"
|
|
91
91
|
},
|
|
92
92
|
"dependencies": {
|
|
93
|
-
"@djangocfg/widget-kit": "^0.1.
|
|
93
|
+
"@djangocfg/widget-kit": "^0.1.9",
|
|
94
94
|
"@dnd-kit/core": "^6.3.1",
|
|
95
95
|
"@radix-ui/react-direction": "^1.1.2",
|
|
96
96
|
"@radix-ui/react-slot": "^1.3.0",
|
|
97
97
|
"class-variance-authority": "^0.7.1"
|
|
98
98
|
},
|
|
99
99
|
"peerDependencies": {
|
|
100
|
-
"@djangocfg/ui-core": "^2.1.
|
|
100
|
+
"@djangocfg/ui-core": "^2.1.550",
|
|
101
101
|
"lucide-react": "^0.545.0",
|
|
102
102
|
"react": "^19.0.0",
|
|
103
103
|
"react-dom": "^19.0.0"
|
|
104
104
|
},
|
|
105
105
|
"devDependencies": {
|
|
106
|
-
"@djangocfg/typescript-config": "^2.1.
|
|
107
|
-
"@djangocfg/ui-core": "^2.1.
|
|
106
|
+
"@djangocfg/typescript-config": "^2.1.550",
|
|
107
|
+
"@djangocfg/ui-core": "^2.1.550",
|
|
108
108
|
"@storybook/react-vite": "^10.5.0",
|
|
109
109
|
"@types/node": "^25.9.5",
|
|
110
110
|
"@types/react": "19.2.15",
|
|
@@ -262,7 +262,10 @@ export function DataGridProvider<T>(props: DataGridProviderProps<T>) {
|
|
|
262
262
|
// Pagination
|
|
263
263
|
const totalRows = filteredData.length;
|
|
264
264
|
const pageCount = Math.max(1, Math.ceil(totalRows / effectivePagination.pageSize));
|
|
265
|
-
|
|
265
|
+
// Clamped at both ends, like `setPage`. A controlled host passing a
|
|
266
|
+
// 0-indexed page makes `start` negative, and `slice(-n, 0)` renders an
|
|
267
|
+
// empty grid while the page count still claims there are rows.
|
|
268
|
+
const safePage = Math.max(1, Math.min(effectivePagination.page, pageCount));
|
|
266
269
|
|
|
267
270
|
const paginatedData = useMemo(() => {
|
|
268
271
|
const start = (safePage - 1) * effectivePagination.pageSize;
|
|
@@ -256,7 +256,10 @@ export function DataTableProvider<T>(props: DataTableProviderProps<T>) {
|
|
|
256
256
|
// Pagination
|
|
257
257
|
const totalRows = filteredData.length;
|
|
258
258
|
const pageCount = Math.max(1, Math.ceil(totalRows / effectivePagination.pageSize));
|
|
259
|
-
|
|
259
|
+
// Clamped at both ends, like `setPage`. A controlled host passing a
|
|
260
|
+
// 0-indexed page makes `start` negative, and `slice(-n, 0)` renders an
|
|
261
|
+
// empty grid while the page count still claims there are rows.
|
|
262
|
+
const safePage = Math.max(1, Math.min(effectivePagination.page, pageCount));
|
|
260
263
|
|
|
261
264
|
const paginatedData = useMemo(() => {
|
|
262
265
|
const start = (safePage - 1) * effectivePagination.pageSize;
|
|
@@ -597,8 +597,13 @@ export const JsonTree = memo(function JsonTree({
|
|
|
597
597
|
const a = document.createElement('a');
|
|
598
598
|
a.href = url;
|
|
599
599
|
a.download = downloadFilename;
|
|
600
|
+
// Appended, and revoked a tick later: the click is queued, so revoking in
|
|
601
|
+
// the next statement can pull the blob out from under a download that has
|
|
602
|
+
// not started reading it yet — a silent zero-byte file.
|
|
603
|
+
document.body.appendChild(a);
|
|
600
604
|
a.click();
|
|
601
|
-
|
|
605
|
+
a.remove();
|
|
606
|
+
setTimeout(() => URL.revokeObjectURL(url), 0);
|
|
602
607
|
}, [jsonString, downloadFilename]);
|
|
603
608
|
|
|
604
609
|
const toggleSearch = useCallback(() => {
|
|
@@ -645,12 +645,7 @@ function useResizeObserver(positioner: Positioner) {
|
|
|
645
645
|
return () => ({ disconnect: () => {}, observe: () => {}, unobserve: () => {} });
|
|
646
646
|
}
|
|
647
647
|
|
|
648
|
-
const cache = new WeakMap<object, ResizeObserver>();
|
|
649
|
-
|
|
650
648
|
return (positioner: Positioner, onUpdate: () => void) => {
|
|
651
|
-
const key = { positioner, onUpdate };
|
|
652
|
-
if (cache.has(key)) return cache.get(key)!;
|
|
653
|
-
|
|
654
649
|
const updates: number[] = [];
|
|
655
650
|
const itemMap = new WeakMap<Element, number>();
|
|
656
651
|
|
|
@@ -700,13 +695,18 @@ function useResizeObserver(positioner: Positioner) {
|
|
|
700
695
|
}
|
|
701
696
|
};
|
|
702
697
|
|
|
703
|
-
cache.set(key, observer);
|
|
704
698
|
return observer;
|
|
705
699
|
};
|
|
706
700
|
}, []);
|
|
707
701
|
|
|
708
|
-
|
|
709
|
-
|
|
702
|
+
// Memoized on `positioner`. Calling the factory during render built a new
|
|
703
|
+
// ResizeObserver every time — the WeakMap that was meant to prevent it keyed
|
|
704
|
+
// on a fresh object literal, so it never hit — and each new identity made the
|
|
705
|
+
// effect below disconnect and rebuild the observer for the whole grid, on
|
|
706
|
+
// every throttled scroll tick.
|
|
707
|
+
const resizeObserver = React.useMemo(
|
|
708
|
+
() => createResizeObserver(positioner, () => setLayoutVersion((prev) => prev + 1)),
|
|
709
|
+
[createResizeObserver, positioner],
|
|
710
710
|
);
|
|
711
711
|
|
|
712
712
|
React.useEffect(() => () => resizeObserver.disconnect(), [resizeObserver]);
|