@astryxdesign/core 0.1.7-canary.fb9c68c → 0.1.7
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/README.md +15 -24
- package/dist/Collapsible/Collapsible.d.ts +1 -11
- package/dist/Collapsible/Collapsible.d.ts.map +1 -1
- package/dist/Collapsible/Collapsible.js +4 -36
- package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
- package/dist/ContextMenu/ContextMenu.js +3 -4
- package/dist/ContextMenu/index.d.ts +0 -3
- package/dist/ContextMenu/index.d.ts.map +1 -1
- package/dist/ContextMenu/index.js +1 -7
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +4 -8
- package/dist/DropdownMenu/DropdownMenuContext.d.ts +1 -17
- package/dist/DropdownMenu/DropdownMenuContext.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuContext.js +0 -18
- package/dist/DropdownMenu/index.d.ts +1 -5
- package/dist/DropdownMenu/index.d.ts.map +1 -1
- package/dist/DropdownMenu/index.js +1 -10
- package/dist/Icon/Icon.d.ts +12 -17
- package/dist/Icon/Icon.d.ts.map +1 -1
- package/dist/Icon/Icon.js +20 -28
- package/dist/Outline/Outline.d.ts +3 -69
- package/dist/Outline/Outline.d.ts.map +1 -1
- package/dist/Outline/Outline.js +26 -129
- package/dist/Outline/useScrollSpy.d.ts +7 -27
- package/dist/Outline/useScrollSpy.d.ts.map +1 -1
- package/dist/Outline/useScrollSpy.js +70 -202
- package/dist/TabList/Tab.d.ts.map +1 -1
- package/dist/TabList/Tab.js +2 -2
- package/dist/TabList/TabList.d.ts.map +1 -1
- package/dist/TabList/TabList.js +0 -2
- package/dist/TabList/TabMenu.d.ts.map +1 -1
- package/dist/TabList/TabMenu.js +1 -1
- package/dist/Table/index.d.ts +0 -2
- package/dist/Table/index.d.ts.map +1 -1
- package/dist/Table/index.js +0 -1
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +2 -24
- package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
- package/dist/Table/plugins/sortable/useTableSortable.js +7 -18
- package/dist/Table/useBaseTablePlugins.d.ts.map +1 -1
- package/dist/Table/useBaseTablePlugins.js +3 -6
- package/dist/Toolbar/Toolbar.d.ts.map +1 -1
- package/dist/Toolbar/Toolbar.js +1 -8
- package/dist/astryx.css +2 -18
- package/dist/astryx.umd.js +48 -48
- package/dist/astryx.umd.js.map +4 -4
- package/dist/theme/Theme.js +1 -1
- package/dist/theme/defineTheme.d.ts +1 -1
- package/dist/theme/defineTheme.js +1 -1
- package/dist/theme/hct.d.ts +1 -0
- package/dist/theme/hct.d.ts.map +1 -1
- package/dist/theme/hct.js +3 -0
- package/locales/en.json +0 -28
- package/locales/pseudo.json +0 -21
- package/package.json +1 -3
- package/src/CheckboxInput/CheckboxInput.doc.mjs +1 -1
- package/src/Collapsible/Collapsible.doc.mjs +0 -7
- package/src/Collapsible/Collapsible.test.tsx +0 -80
- package/src/Collapsible/Collapsible.tsx +5 -58
- package/src/ContextMenu/ContextMenu.test.tsx +1 -75
- package/src/ContextMenu/ContextMenu.tsx +5 -10
- package/src/ContextMenu/index.ts +0 -15
- package/src/DropdownMenu/DropdownMenu.doc.mjs +0 -23
- package/src/DropdownMenu/DropdownMenu.tsx +6 -11
- package/src/DropdownMenu/DropdownMenuContext.tsx +1 -29
- package/src/DropdownMenu/DropdownMenuItem.doc.mjs +1 -7
- package/src/DropdownMenu/index.ts +3 -23
- package/src/Field/Field.doc.mjs +1 -1
- package/src/Field/FieldLabel.doc.mjs +1 -1
- package/src/Icon/Icon.test.tsx +0 -46
- package/src/Icon/Icon.tsx +24 -37
- package/src/NumberInput/NumberInput.doc.mjs +2 -2
- package/src/Outline/Outline.doc.mjs +3 -123
- package/src/Outline/Outline.test.tsx +0 -735
- package/src/Outline/Outline.tsx +33 -184
- package/src/Outline/useScrollSpy.ts +72 -248
- package/src/Selector/SelectorOption.doc.mjs +1 -1
- package/src/SideNav/SideNavItem.doc.mjs +2 -2
- package/src/Switch/Switch.doc.mjs +1 -1
- package/src/TabList/Tab.tsx +1 -5
- package/src/TabList/TabList.doc.mjs +3 -3
- package/src/TabList/TabList.test.tsx +0 -66
- package/src/TabList/TabList.tsx +0 -8
- package/src/TabList/TabMenu.tsx +1 -4
- package/src/Table/Table.doc.mjs +0 -2
- package/src/Table/index.ts +0 -7
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.test.tsx +1 -90
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +5 -37
- package/src/Table/plugins/sortable/useTableSortable.test.tsx +9 -95
- package/src/Table/plugins/sortable/useTableSortable.tsx +7 -23
- package/src/Table/useBaseTablePlugins.ts +2 -6
- package/src/TextArea/TextArea.doc.mjs +1 -1
- package/src/TextInput/TextInput.doc.mjs +1 -1
- package/src/Toolbar/Toolbar.tsx +3 -10
- package/src/theme/Theme.doc.mjs +4 -4
- package/src/theme/Theme.tsx +1 -1
- package/src/theme/defineTheme.ts +1 -1
- package/src/theme/hct.ts +4 -0
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +0 -89
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +0 -1
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +0 -170
- package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts +0 -69
- package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts.map +0 -1
- package/dist/DropdownMenu/DropdownMenuRadioGroup.js +0 -70
- package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts +0 -69
- package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +0 -1
- package/dist/DropdownMenu/DropdownMenuRadioItem.js +0 -178
- package/dist/DropdownMenu/menuItemRoles.d.ts +0 -13
- package/dist/DropdownMenu/menuItemRoles.d.ts.map +0 -1
- package/dist/DropdownMenu/menuItemRoles.js +0 -15
- package/dist/Table/plugins/tree/index.d.ts +0 -5
- package/dist/Table/plugins/tree/index.d.ts.map +0 -1
- package/dist/Table/plugins/tree/index.js +0 -4
- package/dist/Table/plugins/tree/useTableTreeData.d.ts +0 -38
- package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +0 -1
- package/dist/Table/plugins/tree/useTableTreeData.js +0 -358
- package/dist/Table/plugins/tree/useTableTreeState.d.ts +0 -51
- package/dist/Table/plugins/tree/useTableTreeState.d.ts.map +0 -1
- package/dist/Table/plugins/tree/useTableTreeState.js +0 -175
- package/scripts/postinstall.mjs +0 -93
- package/src/DropdownMenu/DropdownMenuCheckboxItem.doc.mjs +0 -95
- package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +0 -237
- package/src/DropdownMenu/DropdownMenuRadioGroup.doc.mjs +0 -80
- package/src/DropdownMenu/DropdownMenuRadioGroup.tsx +0 -119
- package/src/DropdownMenu/DropdownMenuRadioItem.doc.mjs +0 -80
- package/src/DropdownMenu/DropdownMenuRadioItem.tsx +0 -232
- package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +0 -163
- package/src/DropdownMenu/menuItemRoles.ts +0 -22
- package/src/Table/plugins/tree/index.ts +0 -12
- package/src/Table/plugins/tree/useTableTreeData-perf.test.tsx +0 -163
- package/src/Table/plugins/tree/useTableTreeData.test.tsx +0 -594
- package/src/Table/plugins/tree/useTableTreeData.tsx +0 -495
- package/src/Table/plugins/tree/useTableTreeState.test.tsx +0 -636
- package/src/Table/plugins/tree/useTableTreeState.tsx +0 -253
- package/src/Table/useTableTreeData.doc.mjs +0 -75
- package/src/Table/useTableTreeState.doc.mjs +0 -98
- package/src/postinstall.test.mjs +0 -71
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
'use client';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @file useTableTreeState.tsx
|
|
7
|
-
* @input React
|
|
8
|
-
* @output Exports useTableTreeState hook and config/result types
|
|
9
|
-
* @position Tree state helper; owns the expanded set + flattens nested data.
|
|
10
|
-
* Pairs with useTableTreeData (the headless tree plugin).
|
|
11
|
-
*
|
|
12
|
-
* Modeled after useTableSortableState — a convenience layer that owns state
|
|
13
|
-
* (controlled or uncontrolled) and produces both the visible flattened rows
|
|
14
|
-
* and a ready-to-use config for the headless plugin. Data shaping stays
|
|
15
|
-
* outside the render pipeline: Table always receives exactly the rows it
|
|
16
|
-
* renders, so collapsed subtrees are unmounted, not hidden.
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
import {useCallback, useMemo, useRef, useState} from 'react';
|
|
20
|
-
import type {
|
|
21
|
-
TableTreeRowMeta,
|
|
22
|
-
UseTableTreeDataConfig,
|
|
23
|
-
} from './useTableTreeData';
|
|
24
|
-
|
|
25
|
-
// =============================================================================
|
|
26
|
-
// Config
|
|
27
|
-
// =============================================================================
|
|
28
|
-
|
|
29
|
-
export interface UseTableTreeStateConfig<T extends Record<string, unknown>> {
|
|
30
|
-
/** Nested data: rows may carry child rows under `childrenKey`. */
|
|
31
|
-
data: T[];
|
|
32
|
-
/** Row ID accessor: property name, or a function returning a unique id. */
|
|
33
|
-
idKey: (keyof T & string) | ((item: T) => string | number);
|
|
34
|
-
/**
|
|
35
|
-
* Property holding each row's children array.
|
|
36
|
-
* @default 'children'
|
|
37
|
-
*/
|
|
38
|
-
childrenKey?: string;
|
|
39
|
-
/** Initial expanded row ids for uncontrolled mode. Ignored when `expandedIds` is provided. */
|
|
40
|
-
defaultExpandedIds?: Iterable<string>;
|
|
41
|
-
/**
|
|
42
|
-
* Controlled set of expanded row ids. When provided, the hook uses this
|
|
43
|
-
* instead of internal state. Pair with `onExpandedIdsChange`.
|
|
44
|
-
*/
|
|
45
|
-
expandedIds?: ReadonlySet<string>;
|
|
46
|
-
/** Called with the next expanded set whenever expansion changes. */
|
|
47
|
-
onExpandedIdsChange?: (ids: ReadonlySet<string>) => void;
|
|
48
|
-
/**
|
|
49
|
-
* Should this row show an expander? Overrides the default
|
|
50
|
-
* "has a non-empty children array" check — use for lazy loading, where a
|
|
51
|
-
* row is expandable before its children have been fetched.
|
|
52
|
-
*/
|
|
53
|
-
isItemExpandable?: (item: T) => boolean;
|
|
54
|
-
/**
|
|
55
|
-
* Sort each sibling group independently during flattening. Children always
|
|
56
|
-
* stay directly under their parent — sorting never crosses levels. Pass
|
|
57
|
-
* `applySort` from `useTableSortableState` to compose with column sorting.
|
|
58
|
-
*/
|
|
59
|
-
sortSiblings?: (siblings: T[]) => T[];
|
|
60
|
-
/** Indent step per level, forwarded to useTableTreeData. */
|
|
61
|
-
indent?: 'sm' | 'md' | 'lg';
|
|
62
|
-
/** Column that carries the tree affordance, forwarded to useTableTreeData. */
|
|
63
|
-
treeColumnKey?: string;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// =============================================================================
|
|
67
|
-
// Result
|
|
68
|
-
// =============================================================================
|
|
69
|
-
|
|
70
|
-
export interface UseTableTreeStateResult<T extends Record<string, unknown>> {
|
|
71
|
-
/** The flattened, currently-visible rows. Pass to `<Table data>`. */
|
|
72
|
-
visibleData: T[];
|
|
73
|
-
/** Ready-to-use config for useTableTreeData. */
|
|
74
|
-
treeConfig: UseTableTreeDataConfig<T>;
|
|
75
|
-
/** The current expanded row ids. */
|
|
76
|
-
expandedIds: ReadonlySet<string>;
|
|
77
|
-
/** Expand every expandable row in the tree. */
|
|
78
|
-
expandAll: () => void;
|
|
79
|
-
/** Collapse every row. */
|
|
80
|
-
collapseAll: () => void;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// =============================================================================
|
|
84
|
-
// Hook
|
|
85
|
-
// =============================================================================
|
|
86
|
-
|
|
87
|
-
export function useTableTreeState<T extends Record<string, unknown>>(
|
|
88
|
-
config: UseTableTreeStateConfig<T>,
|
|
89
|
-
): UseTableTreeStateResult<T> {
|
|
90
|
-
const {
|
|
91
|
-
data,
|
|
92
|
-
idKey,
|
|
93
|
-
childrenKey = 'children',
|
|
94
|
-
defaultExpandedIds,
|
|
95
|
-
expandedIds: controlledExpandedIds,
|
|
96
|
-
onExpandedIdsChange,
|
|
97
|
-
isItemExpandable,
|
|
98
|
-
sortSiblings,
|
|
99
|
-
indent,
|
|
100
|
-
treeColumnKey,
|
|
101
|
-
} = config;
|
|
102
|
-
|
|
103
|
-
const getId = useCallback(
|
|
104
|
-
(item: T): string =>
|
|
105
|
-
typeof idKey === 'function' ? String(idKey(item)) : String(item[idKey]),
|
|
106
|
-
[idKey],
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
const getChildren = useCallback(
|
|
110
|
-
(item: T): T[] => {
|
|
111
|
-
const children = item[childrenKey];
|
|
112
|
-
return Array.isArray(children) ? (children as T[]) : [];
|
|
113
|
-
},
|
|
114
|
-
[childrenKey],
|
|
115
|
-
);
|
|
116
|
-
|
|
117
|
-
const getIsExpandable = useCallback(
|
|
118
|
-
(item: T): boolean =>
|
|
119
|
-
isItemExpandable ? isItemExpandable(item) : getChildren(item).length > 0,
|
|
120
|
-
[isItemExpandable, getChildren],
|
|
121
|
-
);
|
|
122
|
-
|
|
123
|
-
// Internal state (used in uncontrolled mode)
|
|
124
|
-
const [internalExpandedIds, setInternalExpandedIds] = useState<
|
|
125
|
-
ReadonlySet<string>
|
|
126
|
-
>(() => new Set(defaultExpandedIds));
|
|
127
|
-
|
|
128
|
-
// Resolve controlled vs uncontrolled
|
|
129
|
-
const isControlled = controlledExpandedIds !== undefined;
|
|
130
|
-
const expandedIds = isControlled
|
|
131
|
-
? controlledExpandedIds
|
|
132
|
-
: internalExpandedIds;
|
|
133
|
-
|
|
134
|
-
// Stable refs so callbacks don't churn on inline-prop identity changes
|
|
135
|
-
const expandedIdsRef = useRef(expandedIds);
|
|
136
|
-
expandedIdsRef.current = expandedIds;
|
|
137
|
-
const onExpandedIdsChangeRef = useRef(onExpandedIdsChange);
|
|
138
|
-
onExpandedIdsChangeRef.current = onExpandedIdsChange;
|
|
139
|
-
|
|
140
|
-
const commitExpandedIds = useCallback(
|
|
141
|
-
(next: ReadonlySet<string>) => {
|
|
142
|
-
// Advance the ref immediately so a second commit in the same React
|
|
143
|
-
// batch (e.g. two onToggleItem calls in one event handler) builds
|
|
144
|
-
// on this one instead of the pre-batch set. The ref re-syncs from
|
|
145
|
-
// the resolved state on the next render either way.
|
|
146
|
-
expandedIdsRef.current = next;
|
|
147
|
-
if (!isControlled) {
|
|
148
|
-
setInternalExpandedIds(next);
|
|
149
|
-
}
|
|
150
|
-
onExpandedIdsChangeRef.current?.(next);
|
|
151
|
-
},
|
|
152
|
-
[isControlled],
|
|
153
|
-
);
|
|
154
|
-
|
|
155
|
-
// Flatten: depth-first walk emitting only visible rows, collecting per-row
|
|
156
|
-
// meta ({level, hasChildren, isExpanded}) in the same pass. Children mount
|
|
157
|
-
// only when their parent is expanded, so collapsed subtrees stay unmounted.
|
|
158
|
-
// `path` holds the ids on the current ancestor chain: an edge pointing back
|
|
159
|
-
// at an ancestor is skipped instead of recursing forever. Sibling arrays
|
|
160
|
-
// are copied before sortSiblings so an in-place sorter can't reorder the
|
|
161
|
-
// consumer's data.
|
|
162
|
-
const {visibleData, metaMap} = useMemo(() => {
|
|
163
|
-
const rows: T[] = [];
|
|
164
|
-
const meta = new Map<string, TableTreeRowMeta>();
|
|
165
|
-
const path = new Set<string>();
|
|
166
|
-
const walk = (items: T[], level: number) => {
|
|
167
|
-
const siblings = sortSiblings ? sortSiblings([...items]) : items;
|
|
168
|
-
for (const item of siblings) {
|
|
169
|
-
const id = getId(item);
|
|
170
|
-
if (path.has(id)) {
|
|
171
|
-
continue; // cyclic edge — this row is its own ancestor
|
|
172
|
-
}
|
|
173
|
-
const hasChildren = getIsExpandable(item);
|
|
174
|
-
const isExpanded = hasChildren && expandedIds.has(id);
|
|
175
|
-
rows.push(item);
|
|
176
|
-
meta.set(id, {id, level, hasChildren, isExpanded});
|
|
177
|
-
if (isExpanded) {
|
|
178
|
-
path.add(id);
|
|
179
|
-
walk(getChildren(item), level + 1);
|
|
180
|
-
path.delete(id);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
};
|
|
184
|
-
walk(data, 0);
|
|
185
|
-
return {visibleData: rows, metaMap: meta};
|
|
186
|
-
}, [data, expandedIds, getId, getChildren, getIsExpandable, sortSiblings]);
|
|
187
|
-
|
|
188
|
-
// Every expandable row id across the whole tree, including collapsed
|
|
189
|
-
// subtrees (drives expandAll and the migration no-op flag). Same
|
|
190
|
-
// ancestor-chain guard as the flatten walk.
|
|
191
|
-
const allExpandableIds = useMemo(() => {
|
|
192
|
-
const idsAcc: string[] = [];
|
|
193
|
-
const path = new Set<string>();
|
|
194
|
-
const walk = (items: T[]) => {
|
|
195
|
-
for (const item of items) {
|
|
196
|
-
const id = getId(item);
|
|
197
|
-
if (path.has(id)) {
|
|
198
|
-
continue;
|
|
199
|
-
}
|
|
200
|
-
if (getIsExpandable(item)) {
|
|
201
|
-
idsAcc.push(id);
|
|
202
|
-
}
|
|
203
|
-
path.add(id);
|
|
204
|
-
walk(getChildren(item));
|
|
205
|
-
path.delete(id);
|
|
206
|
-
}
|
|
207
|
-
};
|
|
208
|
-
walk(data);
|
|
209
|
-
return idsAcc;
|
|
210
|
-
}, [data, getId, getChildren, getIsExpandable]);
|
|
211
|
-
|
|
212
|
-
const hasExpandableRows = allExpandableIds.length > 0;
|
|
213
|
-
|
|
214
|
-
const onToggleItem = useCallback(
|
|
215
|
-
(item: T) => {
|
|
216
|
-
const id = getId(item);
|
|
217
|
-
const next = new Set(expandedIdsRef.current);
|
|
218
|
-
if (next.has(id)) {
|
|
219
|
-
next.delete(id);
|
|
220
|
-
} else {
|
|
221
|
-
next.add(id);
|
|
222
|
-
}
|
|
223
|
-
commitExpandedIds(next);
|
|
224
|
-
},
|
|
225
|
-
[getId, commitExpandedIds],
|
|
226
|
-
);
|
|
227
|
-
|
|
228
|
-
const expandAll = useCallback(() => {
|
|
229
|
-
commitExpandedIds(new Set(allExpandableIds));
|
|
230
|
-
}, [commitExpandedIds, allExpandableIds]);
|
|
231
|
-
|
|
232
|
-
const collapseAll = useCallback(() => {
|
|
233
|
-
commitExpandedIds(new Set());
|
|
234
|
-
}, [commitExpandedIds]);
|
|
235
|
-
|
|
236
|
-
const getRowMeta = useCallback(
|
|
237
|
-
(item: T): TableTreeRowMeta | undefined => metaMap.get(getId(item)),
|
|
238
|
-
[metaMap, getId],
|
|
239
|
-
);
|
|
240
|
-
|
|
241
|
-
const treeConfig = useMemo(
|
|
242
|
-
(): UseTableTreeDataConfig<T> => ({
|
|
243
|
-
getRowMeta,
|
|
244
|
-
onToggleItem,
|
|
245
|
-
hasExpandableRows,
|
|
246
|
-
indent,
|
|
247
|
-
treeColumnKey,
|
|
248
|
-
}),
|
|
249
|
-
[getRowMeta, onToggleItem, hasExpandableRows, indent, treeColumnKey],
|
|
250
|
-
);
|
|
251
|
-
|
|
252
|
-
return {visibleData, treeConfig, expandedIds, expandAll, collapseAll};
|
|
253
|
-
}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
/** @type {import('../docs-types').ComponentDoc} */
|
|
4
|
-
|
|
5
|
-
export const docs = {
|
|
6
|
-
name: 'useTableTreeData',
|
|
7
|
-
subComponentOf: 'Table',
|
|
8
|
-
displayName: 'useTableTreeData',
|
|
9
|
-
description:
|
|
10
|
-
'Headless tree plugin for Table: renders nested rows with per-level indentation and expand/collapse chevrons in the tree column (the first column by default), and reflects hierarchy on body rows via aria-level and aria-expanded. Composable with the other Table plugins: the canonical plugin order places tree before selection, so the checkbox column lands left of the indented tree column. Feed it the treeConfig from useTableTreeState, or construct the config directly for server-driven or pre-flattened trees. When no row is expandable (flat data), every transform is a pass-through and the table renders identically to one without the plugin. Known limitation: the tree column wraps its cell content, so textOverflow="truncate" tooltips do not apply within the tree column.',
|
|
11
|
-
props: [
|
|
12
|
-
{
|
|
13
|
-
name: 'getRowMeta',
|
|
14
|
-
type: '(item: T) => TableTreeRowMeta | undefined',
|
|
15
|
-
description:
|
|
16
|
-
'Structural meta for a visible row: {id, level (0-based), hasChildren, isExpanded}.',
|
|
17
|
-
required: true,
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
name: 'onToggleItem',
|
|
21
|
-
type: '(item: T) => void',
|
|
22
|
-
description: 'Toggle a row’s expansion.',
|
|
23
|
-
required: true,
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
name: 'hasExpandableRows',
|
|
27
|
-
type: 'boolean',
|
|
28
|
-
description:
|
|
29
|
-
'Whether any row in the dataset is expandable. When false the plugin is a no-op: no expanders, no indent, no tree ARIA.',
|
|
30
|
-
required: true,
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
name: 'indent',
|
|
34
|
-
type: "'sm' | 'md' | 'lg'",
|
|
35
|
-
description:
|
|
36
|
-
'Indent step per level, mapped to the spacing-3 / spacing-4 / spacing-6 tokens.',
|
|
37
|
-
default: "'md'",
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
name: 'treeColumnKey',
|
|
41
|
-
type: 'string',
|
|
42
|
-
description:
|
|
43
|
-
'Column that carries the indent + expander. Defaults to the first column.',
|
|
44
|
-
},
|
|
45
|
-
],
|
|
46
|
-
examples: [
|
|
47
|
-
{
|
|
48
|
-
label: 'File tree with expandable folders',
|
|
49
|
-
code: `const {visibleData, treeConfig} = useTableTreeState({
|
|
50
|
-
data: files, // rows may nest under 'children'
|
|
51
|
-
idKey: 'id',
|
|
52
|
-
defaultExpandedIds: ['src'],
|
|
53
|
-
});
|
|
54
|
-
const tree = useTableTreeData(treeConfig);
|
|
55
|
-
|
|
56
|
-
<Table data={visibleData} columns={columns} idKey="id" plugins={{tree}} />;`,
|
|
57
|
-
},
|
|
58
|
-
],
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
export const docsDense = {
|
|
62
|
-
name: 'useTableTreeData',
|
|
63
|
-
displayName: 'useTableTreeData',
|
|
64
|
-
description:
|
|
65
|
-
'Headless tree plugin: indent + expander chevron on the tree column (first column by default), aria-level/aria-expanded on body rows. Canonical plugin order puts tree before selection (checkbox column lands left of tree column). Consume treeConfig from useTableTreeState, or construct directly for server-driven trees. hasExpandableRows=false => full no-op (flat-data migration).',
|
|
66
|
-
propDescriptions: {
|
|
67
|
-
getRowMeta:
|
|
68
|
-
'structural meta per visible row: {id, level (0-based), hasChildren, isExpanded}',
|
|
69
|
-
onToggleItem: 'toggle row expansion',
|
|
70
|
-
hasExpandableRows: 'false => plugin is a no-op (no expanders/indent/ARIA)',
|
|
71
|
-
indent:
|
|
72
|
-
"indent step per level: 'sm' | 'md' | 'lg' (spacing-3/4/6). Defaults to 'md'.",
|
|
73
|
-
treeColumnKey: 'column carrying indent + expander. Defaults to first column.',
|
|
74
|
-
},
|
|
75
|
-
};
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
/** @type {import('../docs-types').ComponentDoc} */
|
|
4
|
-
|
|
5
|
-
export const docs = {
|
|
6
|
-
name: 'useTableTreeState',
|
|
7
|
-
subComponentOf: 'Table',
|
|
8
|
-
displayName: 'useTableTreeState',
|
|
9
|
-
description:
|
|
10
|
-
'State management companion for useTableTreeData. Owns the expanded set (controlled or uncontrolled) and flattens nested data into the visible row array — collapsed subtrees are unmounted, not hidden, so the table body contains exactly the visible rows. Returns expandAll/collapseAll helpers and a ready-to-use config for the tree plugin. Note: because collapsed rows unmount, cell-local React state inside collapsed subtrees is lost on collapse; lift state that must survive.',
|
|
11
|
-
props: [
|
|
12
|
-
{
|
|
13
|
-
name: 'data',
|
|
14
|
-
type: 'T[]',
|
|
15
|
-
description:
|
|
16
|
-
'Nested data: rows may carry child rows under childrenKey. Flat data (no children anywhere) makes the plugin a no-op, so it can be adopted before the data becomes hierarchical.',
|
|
17
|
-
required: true,
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
name: 'idKey',
|
|
21
|
-
type: '(keyof T & string) | ((item: T) => string | number)',
|
|
22
|
-
description:
|
|
23
|
-
'Row ID accessor: property name or function returning a unique id.',
|
|
24
|
-
required: true,
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
name: 'childrenKey',
|
|
28
|
-
type: 'string',
|
|
29
|
-
description: 'Property holding each row’s children array.',
|
|
30
|
-
default: "'children'",
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
name: 'defaultExpandedIds',
|
|
34
|
-
type: 'Iterable<string>',
|
|
35
|
-
description:
|
|
36
|
-
'Initial expanded row ids for uncontrolled mode. Ignored when expandedIds is provided.',
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
name: 'expandedIds',
|
|
40
|
-
type: 'ReadonlySet<string>',
|
|
41
|
-
description:
|
|
42
|
-
'Controlled set of expanded row ids. Pair with onExpandedIdsChange.',
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
name: 'onExpandedIdsChange',
|
|
46
|
-
type: '(ids: ReadonlySet<string>) => void',
|
|
47
|
-
description:
|
|
48
|
-
'Called with the next expanded set whenever expansion changes (both modes). In lazy-loading setups, trigger the children fetch here.',
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
name: 'isItemExpandable',
|
|
52
|
-
type: '(item: T) => boolean',
|
|
53
|
-
description:
|
|
54
|
-
'Should this row show an expander? Overrides the default non-empty-children check — use for lazy loading, where a row is expandable before its children have been fetched.',
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
name: 'sortSiblings',
|
|
58
|
-
type: '(siblings: T[]) => T[]',
|
|
59
|
-
description:
|
|
60
|
-
'Sort each sibling group independently during flattening; children always stay directly under their parent. Pass applySort from useTableSortableState to compose with column sorting.',
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
name: 'indent',
|
|
64
|
-
type: "'sm' | 'md' | 'lg'",
|
|
65
|
-
description:
|
|
66
|
-
'Indent step per level (spacing-3 / spacing-4 / spacing-6), forwarded to useTableTreeData.',
|
|
67
|
-
default: "'md'",
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
name: 'treeColumnKey',
|
|
71
|
-
type: 'string',
|
|
72
|
-
description:
|
|
73
|
-
'Column that carries the indent + expander, forwarded to useTableTreeData. Defaults to the first column.',
|
|
74
|
-
},
|
|
75
|
-
],
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
export const docsDense = {
|
|
79
|
-
name: 'useTableTreeState',
|
|
80
|
-
displayName: 'useTableTreeState',
|
|
81
|
-
description:
|
|
82
|
-
'State companion for useTableTreeData. Owns expanded set (controlled or uncontrolled), flattens nested data to visible rows (collapsed subtrees unmounted, not hidden). Returns {visibleData, treeConfig, expandedIds, expandAll, collapseAll}. Cell-local state in collapsed subtrees is lost on collapse; lift state that must survive.',
|
|
83
|
-
propDescriptions: {
|
|
84
|
-
data: 'nested data; rows carry child rows under childrenKey. Flat data => plugin is a no-op.',
|
|
85
|
-
idKey: 'row ID accessor: property name or fn returning unique id',
|
|
86
|
-
childrenKey: "property holding children array. Defaults to 'children'.",
|
|
87
|
-
defaultExpandedIds: 'initial expanded ids (uncontrolled)',
|
|
88
|
-
expandedIds: 'controlled expanded set; pair with onExpandedIdsChange',
|
|
89
|
-
onExpandedIdsChange:
|
|
90
|
-
'called with next expanded set on change (both modes); trigger lazy children fetch here',
|
|
91
|
-
isItemExpandable:
|
|
92
|
-
'overrides non-empty-children expandability check (lazy loading)',
|
|
93
|
-
sortSiblings:
|
|
94
|
-
'sorts each sibling group during flattening; pass applySort from useTableSortableState',
|
|
95
|
-
indent: "indent step per level: 'sm' | 'md' | 'lg'. Defaults to 'md'.",
|
|
96
|
-
treeColumnKey: 'column carrying indent + expander. Defaults to first column.',
|
|
97
|
-
},
|
|
98
|
-
};
|
package/src/postinstall.test.mjs
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @file Guardrail tests for the @astryxdesign/core postinstall nudge (layer 1).
|
|
5
|
-
*
|
|
6
|
-
* The marker check mirrors the CLI's single source of truth (core can't import
|
|
7
|
-
* the CLI). Tests that it detects the marker across EVERY agent-doc location
|
|
8
|
-
* (incl. Hermes) + legacy markers, and that the nudge decision matrix is correct.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import {describe, it, expect, beforeEach, afterEach} from 'vitest';
|
|
12
|
-
import * as fs from 'node:fs';
|
|
13
|
-
import * as os from 'node:os';
|
|
14
|
-
import * as path from 'node:path';
|
|
15
|
-
import {isAstryxInitialized, shouldNudge} from '../scripts/postinstall.mjs';
|
|
16
|
-
|
|
17
|
-
const MARKER = '<!-- ASTRYX:START -->';
|
|
18
|
-
|
|
19
|
-
let tmp;
|
|
20
|
-
beforeEach(() => {
|
|
21
|
-
tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-core-postinstall-'));
|
|
22
|
-
});
|
|
23
|
-
afterEach(() => {
|
|
24
|
-
fs.rmSync(tmp, {recursive: true, force: true});
|
|
25
|
-
});
|
|
26
|
-
function write(rel, body) {
|
|
27
|
-
const p = path.join(tmp, rel);
|
|
28
|
-
fs.mkdirSync(path.dirname(p), {recursive: true});
|
|
29
|
-
fs.writeFileSync(p, body);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
describe('core postinstall — isAstryxInitialized (mirrors CLI contract)', () => {
|
|
33
|
-
it('is false in an empty project', () => {
|
|
34
|
-
expect(isAstryxInitialized(tmp)).toBe(false);
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it.each(['AGENTS.md', 'CLAUDE.md', '.claude/CLAUDE.md', '.cursorrules', '.hermes.md', 'HERMES.md'])(
|
|
38
|
-
'detects the marker in %s',
|
|
39
|
-
file => {
|
|
40
|
-
write(file, `# doc\n${MARKER}\nbody`);
|
|
41
|
-
expect(isAstryxInitialized(tmp)).toBe(true);
|
|
42
|
-
},
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
it('detects the legacy XDS marker', () => {
|
|
46
|
-
write('AGENTS.md', '<!-- XDS:START -->');
|
|
47
|
-
expect(isAstryxInitialized(tmp)).toBe(true);
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
describe('core postinstall — shouldNudge', () => {
|
|
52
|
-
const DEP = '/proj/node_modules/@astryxdesign/core/scripts/postinstall.mjs';
|
|
53
|
-
const NPX = '/Users/x/.npm/_npx/a1/node_modules/@astryxdesign/core/scripts/postinstall.mjs';
|
|
54
|
-
const REPO = '/repo/packages/core/scripts/postinstall.mjs';
|
|
55
|
-
|
|
56
|
-
it('nudges for a real dependency install when not set up', () => {
|
|
57
|
-
expect(shouldNudge({scriptPath: DEP, npmCommand: 'install', isSetUp: false})).toBe(true);
|
|
58
|
-
});
|
|
59
|
-
it('quiet in the monorepo/source', () => {
|
|
60
|
-
expect(shouldNudge({scriptPath: REPO, npmCommand: 'install', isSetUp: false})).toBe(false);
|
|
61
|
-
});
|
|
62
|
-
it('quiet during npx transient install (_npx path)', () => {
|
|
63
|
-
expect(shouldNudge({scriptPath: NPX, npmCommand: 'install', isSetUp: false})).toBe(false);
|
|
64
|
-
});
|
|
65
|
-
it('quiet during npx (npm_command=exec)', () => {
|
|
66
|
-
expect(shouldNudge({scriptPath: DEP, npmCommand: 'exec', isSetUp: false})).toBe(false);
|
|
67
|
-
});
|
|
68
|
-
it('quiet once set up', () => {
|
|
69
|
-
expect(shouldNudge({scriptPath: DEP, npmCommand: 'install', isSetUp: true})).toBe(false);
|
|
70
|
-
});
|
|
71
|
-
});
|