@deadragdoll/reactnu 0.1.73 → 0.1.74
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/components/TreeListView/TreeListView.d.ts +7 -1
- package/dist/index.cjs +68 -4
- package/dist/index.js +67 -4
- package/docs/API_REFERENCE.md +2 -2
- package/docs/COMPONENT_INDEX.md +1 -0
- package/docs/TreeListView.md +5 -0
- package/docs/TreeTable.md +21 -0
- package/package.json +1 -1
|
@@ -16,6 +16,8 @@ export type TreeListViewProps<T extends TreeListItemBase<T>> = Omit<HTMLAttribut
|
|
|
16
16
|
acceptsDrop?: (item: NuDragDropItem) => boolean;
|
|
17
17
|
activeItemId?: string;
|
|
18
18
|
checkedIds?: string[];
|
|
19
|
+
/** Persists user-resized column widths in `localStorage` under `reactnu.<key>`. */
|
|
20
|
+
columnStoreKey?: string;
|
|
19
21
|
onPopupMenu?: (event: MouseEvent<HTMLDivElement>, item: T, context: TreeListCellContext<T>) => void;
|
|
20
22
|
columns: TreeListColumn<T>[];
|
|
21
23
|
data: T[];
|
|
@@ -39,5 +41,9 @@ export type TreeListViewProps<T extends TreeListItemBase<T>> = Omit<HTMLAttribut
|
|
|
39
41
|
selectedId?: string;
|
|
40
42
|
uncheckedShape?: "box" | "none";
|
|
41
43
|
};
|
|
42
|
-
declare function TreeListViewInner<T extends TreeListItemBase<T>>({ acceptsDrop, activeItemId: activeItemIdProp, checkedIds, className, columns, onPopupMenu, data, dataVersion, defaultActiveItemId, defaultExpandedIds, emptyText, expandedIds, getDragItem, getCellContent, onActiveItemChange, onExpandedIdsChange, onItemCheckChange, onItemDoubleClick, onItemDragOut, onItemSelect, onDrop, selectedId, uncheckedShape, ...props }: TreeListViewProps<T>, ref: ForwardedRef<TreeListViewHandle>): import("react/jsx-runtime").JSX.Element;
|
|
44
|
+
declare function TreeListViewInner<T extends TreeListItemBase<T>>({ acceptsDrop, activeItemId: activeItemIdProp, checkedIds, className, columnStoreKey, columns, onPopupMenu, data, dataVersion, defaultActiveItemId, defaultExpandedIds, emptyText, expandedIds, getDragItem, getCellContent, onActiveItemChange, onExpandedIdsChange, onItemCheckChange, onItemDoubleClick, onItemDragOut, onItemSelect, onDrop, selectedId, uncheckedShape, ...props }: TreeListViewProps<T>, ref: ForwardedRef<TreeListViewHandle>): import("react/jsx-runtime").JSX.Element;
|
|
43
45
|
export declare const TreeListView: <T extends TreeListItemBase<T>>(props: TreeListViewProps<T> & RefAttributes<TreeListViewHandle>) => ReturnType<typeof TreeListViewInner>;
|
|
46
|
+
/** Semantic alias for `TreeListView` when used as a hierarchical data table. */
|
|
47
|
+
export declare const TreeTable: <T extends TreeListItemBase<T>>(props: TreeListViewProps<T> & RefAttributes<TreeListViewHandle>) => ReturnType<typeof TreeListViewInner>;
|
|
48
|
+
export type TreeTableHandle = TreeListViewHandle;
|
|
49
|
+
export type TreeTableProps<T extends TreeListItemBase<T>> = TreeListViewProps<T>;
|
package/dist/index.cjs
CHANGED
|
@@ -71,6 +71,7 @@ __export(index_exports, {
|
|
|
71
71
|
ToolDropButton: () => ToolDropButton,
|
|
72
72
|
ToolSeparator: () => ToolSeparator,
|
|
73
73
|
TreeListView: () => TreeListView,
|
|
74
|
+
TreeTable: () => TreeTable,
|
|
74
75
|
TreeView: () => TreeView,
|
|
75
76
|
Window: () => Window,
|
|
76
77
|
WindowBar: () => WindowBar,
|
|
@@ -9803,11 +9804,42 @@ var TreeListViewRow = (0, import_react46.memo)(
|
|
|
9803
9804
|
|
|
9804
9805
|
// src/components/TreeListView/TreeListView.tsx
|
|
9805
9806
|
var import_jsx_runtime63 = require("react/jsx-runtime");
|
|
9807
|
+
function getColumnStorageKey(columnStoreKey) {
|
|
9808
|
+
const normalizedKey = columnStoreKey?.trim();
|
|
9809
|
+
return normalizedKey ? `reactnu.${normalizedKey}` : null;
|
|
9810
|
+
}
|
|
9811
|
+
function readStoredColumnWidths(storageKey, columns) {
|
|
9812
|
+
if (!storageKey || typeof window === "undefined") {
|
|
9813
|
+
return {};
|
|
9814
|
+
}
|
|
9815
|
+
try {
|
|
9816
|
+
const rawValue = window.localStorage.getItem(storageKey);
|
|
9817
|
+
if (!rawValue) {
|
|
9818
|
+
return {};
|
|
9819
|
+
}
|
|
9820
|
+
const parsedValue = JSON.parse(rawValue);
|
|
9821
|
+
if (!parsedValue || typeof parsedValue !== "object") {
|
|
9822
|
+
return {};
|
|
9823
|
+
}
|
|
9824
|
+
return Object.fromEntries(
|
|
9825
|
+
columns.flatMap((column) => {
|
|
9826
|
+
const width = parsedValue[column.id];
|
|
9827
|
+
if (typeof width !== "number" || !Number.isFinite(width)) {
|
|
9828
|
+
return [];
|
|
9829
|
+
}
|
|
9830
|
+
return [[column.id, Math.max(width, column.minWidth ?? 0)]];
|
|
9831
|
+
})
|
|
9832
|
+
);
|
|
9833
|
+
} catch {
|
|
9834
|
+
return {};
|
|
9835
|
+
}
|
|
9836
|
+
}
|
|
9806
9837
|
function TreeListViewInner({
|
|
9807
9838
|
acceptsDrop,
|
|
9808
9839
|
activeItemId: activeItemIdProp,
|
|
9809
9840
|
checkedIds,
|
|
9810
9841
|
className,
|
|
9842
|
+
columnStoreKey,
|
|
9811
9843
|
columns,
|
|
9812
9844
|
onPopupMenu,
|
|
9813
9845
|
data,
|
|
@@ -9832,6 +9864,9 @@ function TreeListViewInner({
|
|
|
9832
9864
|
const rootRef = (0, import_react47.useRef)(null);
|
|
9833
9865
|
const [rootElement, setRootElement] = (0, import_react47.useState)(null);
|
|
9834
9866
|
const treeId = (0, import_react47.useId)();
|
|
9867
|
+
const storageKey = getColumnStorageKey(columnStoreKey);
|
|
9868
|
+
const loadedStorageKeyRef = (0, import_react47.useRef)(storageKey);
|
|
9869
|
+
const shouldPersistColumnWidthsRef = (0, import_react47.useRef)(false);
|
|
9835
9870
|
const itemRefs = (0, import_react47.useRef)({});
|
|
9836
9871
|
const resizeFrameRef = (0, import_react47.useRef)(null);
|
|
9837
9872
|
const resizeStateRef = (0, import_react47.useRef)(null);
|
|
@@ -9845,7 +9880,7 @@ function TreeListViewInner({
|
|
|
9845
9880
|
});
|
|
9846
9881
|
const [uncontrolledSelectedId, setUncontrolledSelectedId] = (0, import_react47.useState)(null);
|
|
9847
9882
|
const [autoColumnWidths, setAutoColumnWidths] = (0, import_react47.useState)({});
|
|
9848
|
-
const [userColumnWidths, setUserColumnWidths] = (0, import_react47.useState)(
|
|
9883
|
+
const [userColumnWidths, setUserColumnWidths] = (0, import_react47.useState)(() => readStoredColumnWidths(storageKey, columns));
|
|
9849
9884
|
const isActiveControlled = activeItemIdProp !== void 0;
|
|
9850
9885
|
const resolvedExpandedIds = isExpandedControlled ? expandedIds : uncontrolledExpandedIds;
|
|
9851
9886
|
const expandedIdSet = (0, import_react47.useMemo)(
|
|
@@ -9907,6 +9942,27 @@ function TreeListViewInner({
|
|
|
9907
9942
|
block: "nearest"
|
|
9908
9943
|
});
|
|
9909
9944
|
}, [resolvedActiveItemId]);
|
|
9945
|
+
(0, import_react47.useEffect)(() => {
|
|
9946
|
+
if (loadedStorageKeyRef.current === storageKey) {
|
|
9947
|
+
return;
|
|
9948
|
+
}
|
|
9949
|
+
loadedStorageKeyRef.current = storageKey;
|
|
9950
|
+
shouldPersistColumnWidthsRef.current = false;
|
|
9951
|
+
setUserColumnWidths(readStoredColumnWidths(storageKey, columns));
|
|
9952
|
+
}, [columns, storageKey]);
|
|
9953
|
+
(0, import_react47.useEffect)(() => {
|
|
9954
|
+
if (!shouldPersistColumnWidthsRef.current) {
|
|
9955
|
+
return;
|
|
9956
|
+
}
|
|
9957
|
+
shouldPersistColumnWidthsRef.current = false;
|
|
9958
|
+
if (!storageKey || typeof window === "undefined") {
|
|
9959
|
+
return;
|
|
9960
|
+
}
|
|
9961
|
+
try {
|
|
9962
|
+
window.localStorage.setItem(storageKey, JSON.stringify(userColumnWidths));
|
|
9963
|
+
} catch {
|
|
9964
|
+
}
|
|
9965
|
+
}, [storageKey, userColumnWidths]);
|
|
9910
9966
|
const registerItemRef = (0, import_react47.useCallback)(
|
|
9911
9967
|
(itemId, node) => {
|
|
9912
9968
|
itemRefs.current[itemId] = node;
|
|
@@ -10197,9 +10253,15 @@ function TreeListViewInner({
|
|
|
10197
10253
|
return;
|
|
10198
10254
|
}
|
|
10199
10255
|
setUserColumnWidths(
|
|
10200
|
-
(currentWidths) =>
|
|
10201
|
-
|
|
10202
|
-
|
|
10256
|
+
(currentWidths) => {
|
|
10257
|
+
if (currentWidths[resizeState.columnId] === resizeState.nextWidth) {
|
|
10258
|
+
return currentWidths;
|
|
10259
|
+
}
|
|
10260
|
+
shouldPersistColumnWidthsRef.current = true;
|
|
10261
|
+
return {
|
|
10262
|
+
...currentWidths,
|
|
10263
|
+
[resizeState.columnId]: resizeState.nextWidth
|
|
10264
|
+
};
|
|
10203
10265
|
}
|
|
10204
10266
|
);
|
|
10205
10267
|
}
|
|
@@ -10330,6 +10392,7 @@ function TreeListViewInner({
|
|
|
10330
10392
|
);
|
|
10331
10393
|
}
|
|
10332
10394
|
var TreeListView = (0, import_react47.forwardRef)(TreeListViewInner);
|
|
10395
|
+
var TreeTable = TreeListView;
|
|
10333
10396
|
|
|
10334
10397
|
// src/theme/NuThemeProvider.tsx
|
|
10335
10398
|
var import_react49 = require("react");
|
|
@@ -10789,6 +10852,7 @@ function NuThemeProvider({
|
|
|
10789
10852
|
ToolDropButton,
|
|
10790
10853
|
ToolSeparator,
|
|
10791
10854
|
TreeListView,
|
|
10855
|
+
TreeTable,
|
|
10792
10856
|
TreeView,
|
|
10793
10857
|
Window,
|
|
10794
10858
|
WindowBar,
|
package/dist/index.js
CHANGED
|
@@ -9841,11 +9841,42 @@ var TreeListViewRow = memo5(
|
|
|
9841
9841
|
|
|
9842
9842
|
// src/components/TreeListView/TreeListView.tsx
|
|
9843
9843
|
import { jsx as jsx63, jsxs as jsxs41 } from "react/jsx-runtime";
|
|
9844
|
+
function getColumnStorageKey(columnStoreKey) {
|
|
9845
|
+
const normalizedKey = columnStoreKey?.trim();
|
|
9846
|
+
return normalizedKey ? `reactnu.${normalizedKey}` : null;
|
|
9847
|
+
}
|
|
9848
|
+
function readStoredColumnWidths(storageKey, columns) {
|
|
9849
|
+
if (!storageKey || typeof window === "undefined") {
|
|
9850
|
+
return {};
|
|
9851
|
+
}
|
|
9852
|
+
try {
|
|
9853
|
+
const rawValue = window.localStorage.getItem(storageKey);
|
|
9854
|
+
if (!rawValue) {
|
|
9855
|
+
return {};
|
|
9856
|
+
}
|
|
9857
|
+
const parsedValue = JSON.parse(rawValue);
|
|
9858
|
+
if (!parsedValue || typeof parsedValue !== "object") {
|
|
9859
|
+
return {};
|
|
9860
|
+
}
|
|
9861
|
+
return Object.fromEntries(
|
|
9862
|
+
columns.flatMap((column) => {
|
|
9863
|
+
const width = parsedValue[column.id];
|
|
9864
|
+
if (typeof width !== "number" || !Number.isFinite(width)) {
|
|
9865
|
+
return [];
|
|
9866
|
+
}
|
|
9867
|
+
return [[column.id, Math.max(width, column.minWidth ?? 0)]];
|
|
9868
|
+
})
|
|
9869
|
+
);
|
|
9870
|
+
} catch {
|
|
9871
|
+
return {};
|
|
9872
|
+
}
|
|
9873
|
+
}
|
|
9844
9874
|
function TreeListViewInner({
|
|
9845
9875
|
acceptsDrop,
|
|
9846
9876
|
activeItemId: activeItemIdProp,
|
|
9847
9877
|
checkedIds,
|
|
9848
9878
|
className,
|
|
9879
|
+
columnStoreKey,
|
|
9849
9880
|
columns,
|
|
9850
9881
|
onPopupMenu,
|
|
9851
9882
|
data,
|
|
@@ -9870,6 +9901,9 @@ function TreeListViewInner({
|
|
|
9870
9901
|
const rootRef = useRef23(null);
|
|
9871
9902
|
const [rootElement, setRootElement] = useState31(null);
|
|
9872
9903
|
const treeId = useId17();
|
|
9904
|
+
const storageKey = getColumnStorageKey(columnStoreKey);
|
|
9905
|
+
const loadedStorageKeyRef = useRef23(storageKey);
|
|
9906
|
+
const shouldPersistColumnWidthsRef = useRef23(false);
|
|
9873
9907
|
const itemRefs = useRef23({});
|
|
9874
9908
|
const resizeFrameRef = useRef23(null);
|
|
9875
9909
|
const resizeStateRef = useRef23(null);
|
|
@@ -9883,7 +9917,7 @@ function TreeListViewInner({
|
|
|
9883
9917
|
});
|
|
9884
9918
|
const [uncontrolledSelectedId, setUncontrolledSelectedId] = useState31(null);
|
|
9885
9919
|
const [autoColumnWidths, setAutoColumnWidths] = useState31({});
|
|
9886
|
-
const [userColumnWidths, setUserColumnWidths] = useState31(
|
|
9920
|
+
const [userColumnWidths, setUserColumnWidths] = useState31(() => readStoredColumnWidths(storageKey, columns));
|
|
9887
9921
|
const isActiveControlled = activeItemIdProp !== void 0;
|
|
9888
9922
|
const resolvedExpandedIds = isExpandedControlled ? expandedIds : uncontrolledExpandedIds;
|
|
9889
9923
|
const expandedIdSet = useMemo20(
|
|
@@ -9945,6 +9979,27 @@ function TreeListViewInner({
|
|
|
9945
9979
|
block: "nearest"
|
|
9946
9980
|
});
|
|
9947
9981
|
}, [resolvedActiveItemId]);
|
|
9982
|
+
useEffect17(() => {
|
|
9983
|
+
if (loadedStorageKeyRef.current === storageKey) {
|
|
9984
|
+
return;
|
|
9985
|
+
}
|
|
9986
|
+
loadedStorageKeyRef.current = storageKey;
|
|
9987
|
+
shouldPersistColumnWidthsRef.current = false;
|
|
9988
|
+
setUserColumnWidths(readStoredColumnWidths(storageKey, columns));
|
|
9989
|
+
}, [columns, storageKey]);
|
|
9990
|
+
useEffect17(() => {
|
|
9991
|
+
if (!shouldPersistColumnWidthsRef.current) {
|
|
9992
|
+
return;
|
|
9993
|
+
}
|
|
9994
|
+
shouldPersistColumnWidthsRef.current = false;
|
|
9995
|
+
if (!storageKey || typeof window === "undefined") {
|
|
9996
|
+
return;
|
|
9997
|
+
}
|
|
9998
|
+
try {
|
|
9999
|
+
window.localStorage.setItem(storageKey, JSON.stringify(userColumnWidths));
|
|
10000
|
+
} catch {
|
|
10001
|
+
}
|
|
10002
|
+
}, [storageKey, userColumnWidths]);
|
|
9948
10003
|
const registerItemRef = useCallback8(
|
|
9949
10004
|
(itemId, node) => {
|
|
9950
10005
|
itemRefs.current[itemId] = node;
|
|
@@ -10235,9 +10290,15 @@ function TreeListViewInner({
|
|
|
10235
10290
|
return;
|
|
10236
10291
|
}
|
|
10237
10292
|
setUserColumnWidths(
|
|
10238
|
-
(currentWidths) =>
|
|
10239
|
-
|
|
10240
|
-
|
|
10293
|
+
(currentWidths) => {
|
|
10294
|
+
if (currentWidths[resizeState.columnId] === resizeState.nextWidth) {
|
|
10295
|
+
return currentWidths;
|
|
10296
|
+
}
|
|
10297
|
+
shouldPersistColumnWidthsRef.current = true;
|
|
10298
|
+
return {
|
|
10299
|
+
...currentWidths,
|
|
10300
|
+
[resizeState.columnId]: resizeState.nextWidth
|
|
10301
|
+
};
|
|
10241
10302
|
}
|
|
10242
10303
|
);
|
|
10243
10304
|
}
|
|
@@ -10368,6 +10429,7 @@ function TreeListViewInner({
|
|
|
10368
10429
|
);
|
|
10369
10430
|
}
|
|
10370
10431
|
var TreeListView = forwardRef4(TreeListViewInner);
|
|
10432
|
+
var TreeTable = TreeListView;
|
|
10371
10433
|
|
|
10372
10434
|
// src/theme/NuThemeProvider.tsx
|
|
10373
10435
|
import {
|
|
@@ -10831,6 +10893,7 @@ export {
|
|
|
10831
10893
|
ToolDropButton,
|
|
10832
10894
|
ToolSeparator,
|
|
10833
10895
|
TreeListView,
|
|
10896
|
+
TreeTable,
|
|
10834
10897
|
TreeView,
|
|
10835
10898
|
Window,
|
|
10836
10899
|
WindowBar,
|
package/docs/API_REFERENCE.md
CHANGED
|
@@ -96,8 +96,8 @@ See: [Slot Customization](./SLOT_CUSTOMIZATION.md)
|
|
|
96
96
|
docs: [ListView](./ListView.md)
|
|
97
97
|
- `TreeView`
|
|
98
98
|
docs: [TreeView](./TreeView.md)
|
|
99
|
-
- `TreeListView`
|
|
100
|
-
docs: [TreeListView](./TreeListView.md)
|
|
99
|
+
- `TreeListView`, `TreeTable`
|
|
100
|
+
docs: [TreeListView](./TreeListView.md), [TreeTable](./TreeTable.md)
|
|
101
101
|
- Shared drag-and-drop contract
|
|
102
102
|
docs: [NuDragDropProvider](./NuDragDropProvider.md)
|
|
103
103
|
|
package/docs/COMPONENT_INDEX.md
CHANGED
package/docs/TreeListView.md
CHANGED
|
@@ -44,6 +44,8 @@ const columns: TreeListColumn<Node>[] = [
|
|
|
44
44
|
## Key Props
|
|
45
45
|
|
|
46
46
|
- `columns`
|
|
47
|
+
- `columnStoreKey` — stores user-resized widths under `reactnu.<key>` in
|
|
48
|
+
`localStorage`
|
|
47
49
|
- `data`
|
|
48
50
|
- `getCellContent`
|
|
49
51
|
- `dataVersion`
|
|
@@ -87,6 +89,9 @@ const columns: TreeListColumn<Node>[] = [
|
|
|
87
89
|
- Columns auto-size from visible content by default.
|
|
88
90
|
- `minWidth` sets a lower bound for auto-sized and resized columns.
|
|
89
91
|
- Columns are resizable unless `resizable={false}` is set on a column.
|
|
92
|
+
- Give `columnStoreKey` a stable, application-owned name to restore a user's
|
|
93
|
+
resized widths on the next mount. Missing, malformed, or unavailable browser
|
|
94
|
+
storage falls back to the column definitions without throwing.
|
|
90
95
|
- Right-clicking an enabled row activates it and calls
|
|
91
96
|
`onPopupMenu(event, item, context)`. `context` has the same `depth`, `isLeaf`,
|
|
92
97
|
`item`, and `rowIndex` fields as `getCellContent`; the host owns rendering the
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# TreeTable
|
|
2
|
+
|
|
3
|
+
`TreeTable` is the semantic name for `TreeListView` when it is used as a
|
|
4
|
+
hierarchical report table. It is the same component and accepts the same props,
|
|
5
|
+
including tree navigation, report cells, drag-and-drop, and column resizing.
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
<TreeTable
|
|
11
|
+
columnStoreKey="workspace-files"
|
|
12
|
+
columns={columns}
|
|
13
|
+
data={nodes}
|
|
14
|
+
/>
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
`columnStoreKey="workspace-files"` persists user-resized widths as JSON in
|
|
18
|
+
`localStorage` under `reactnu.workspace-files`. Only widths changed by the user
|
|
19
|
+
are stored. Invalid or unavailable storage is ignored safely.
|
|
20
|
+
|
|
21
|
+
For the full API, see [TreeListView](./TreeListView.md).
|