@ahrowe/ui 0.27.0 → 0.28.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/esm/common/accordion/accordion.mjs +1 -1
- package/dist/esm/common/accordion/accordion.mjs.map +1 -1
- package/dist/esm/common/colorPicker/colorPicker.mjs +1 -1
- package/dist/esm/common/colorPicker/colorPicker.mjs.map +1 -1
- package/dist/esm/common/confirmModal/confirmModal.mjs +1 -1
- package/dist/esm/common/confirmModal/confirmModal.mjs.map +1 -1
- package/dist/esm/common/dropZone/dropZone.mjs +1 -1
- package/dist/esm/common/dropZone/dropZone.mjs.map +1 -1
- package/dist/esm/common/floatingMenu/useFloatingPosition.mjs +1 -1
- package/dist/esm/common/floatingMenu/useFloatingPosition.mjs.map +1 -1
- package/dist/esm/common/hooks/useAnchorTracking.mjs +2 -0
- package/dist/esm/common/hooks/useAnchorTracking.mjs.map +1 -0
- package/dist/esm/common/idleManager/idleManager.mjs +1 -1
- package/dist/esm/common/idleManager/idleManager.mjs.map +1 -1
- package/dist/esm/common/input/input.mjs +1 -1
- package/dist/esm/common/input/input.mjs.map +1 -1
- package/dist/esm/common/inputDropdown/inputDropdown.mjs +1 -1
- package/dist/esm/common/inputDropdown/inputDropdown.mjs.map +1 -1
- package/dist/esm/common/klipyPicker/components/gifView/gifView.mjs +1 -1
- package/dist/esm/common/klipyPicker/components/gifView/gifView.mjs.map +1 -1
- package/dist/esm/common/multiSelect/multiSelect.mjs +2 -0
- package/dist/esm/common/multiSelect/multiSelect.mjs.map +1 -0
- package/dist/esm/common/multiSelect/multiSelect.module.mjs +2 -0
- package/dist/esm/common/multiSelect/multiSelect.module.mjs.map +1 -0
- package/dist/esm/common/overscroll/overscroll.mjs +1 -1
- package/dist/esm/common/overscroll/overscroll.mjs.map +1 -1
- package/dist/esm/common/pagination/pagination.mjs +2 -0
- package/dist/esm/common/pagination/pagination.mjs.map +1 -0
- package/dist/esm/common/pagination/pagination.module.mjs +2 -0
- package/dist/esm/common/pagination/pagination.module.mjs.map +1 -0
- package/dist/esm/common/popover/usePopoverPosition.mjs +1 -1
- package/dist/esm/common/popover/usePopoverPosition.mjs.map +1 -1
- package/dist/esm/common/timer/timer.mjs.map +1 -1
- package/dist/esm/common/tree/flattenTree.mjs +2 -0
- package/dist/esm/common/tree/flattenTree.mjs.map +1 -0
- package/dist/esm/common/tree/tree.mjs +2 -0
- package/dist/esm/common/tree/tree.mjs.map +1 -0
- package/dist/esm/common/tree/tree.module.mjs +2 -0
- package/dist/esm/common/tree/tree.module.mjs.map +1 -0
- package/dist/esm/common/virtualList/virtualList.mjs +1 -1
- package/dist/esm/common/virtualList/virtualList.mjs.map +1 -1
- package/dist/esm/common/virtualList/virtualRow.mjs.map +1 -1
- package/dist/esm/index.mjs +1 -1
- package/dist/esm/services/formValidation/validatableComponent.mjs.map +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.cjs.map +1 -1
- package/dist/style.css +1 -1
- package/dist/types/package/common/configProvider/configProvider.types.d.ts +6 -0
- package/dist/types/package/common/floatingMenu/useFloatingPosition.d.ts +4 -6
- package/dist/types/package/common/hooks/useAnchorTracking.d.ts +40 -0
- package/dist/types/package/common/inputDropdown/inputDropdown.types.d.ts +6 -0
- package/dist/types/package/common/multiSelect/index.d.ts +2 -0
- package/dist/types/package/common/multiSelect/multiSelect.d.ts +4 -0
- package/dist/types/package/common/multiSelect/multiSelect.types.d.ts +62 -0
- package/dist/types/package/common/pagination/index.d.ts +2 -0
- package/dist/types/package/common/pagination/pagination.d.ts +4 -0
- package/dist/types/package/common/pagination/pagination.types.d.ts +30 -0
- package/dist/types/package/common/popover/usePopoverPosition.d.ts +4 -2
- package/dist/types/package/common/tree/flattenTree.d.ts +3 -0
- package/dist/types/package/common/tree/index.d.ts +3 -0
- package/dist/types/package/common/tree/tree.d.ts +4 -0
- package/dist/types/package/common/tree/tree.types.d.ts +62 -0
- package/dist/types/package/common/virtualList/virtualList.types.d.ts +8 -0
- package/dist/types/package/common/virtualList/virtualRow.d.ts +1 -1
- package/dist/types/package/index.d.ts +6 -0
- package/docs/CLAUDE.md +3 -0
- package/docs/InputDropdown.md +3 -0
- package/docs/MultiSelect.md +100 -0
- package/docs/Pagination.md +72 -0
- package/docs/Tree.md +95 -0
- package/docs/VirtualList.md +1 -0
- package/package.json +2 -2
package/docs/Tree.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Tree
|
|
2
|
+
|
|
3
|
+
**When to use:** A hierarchical list the user can expand, collapse and pick from: categories, nested locations, folder structures, org charts. For a flat list of thousands of rows use [VirtualList](VirtualList.md); for picking several unrelated values use [MultiSelect](MultiSelect.md).
|
|
4
|
+
|
|
5
|
+
**Keywords:** hierarchy, directory, expand collapse, parent child, drilldown, navigation sidebar, outline, subfolder
|
|
6
|
+
|
|
7
|
+
**Import:** `import { Tree, flattenTree } from '@ahrowe/ui'`
|
|
8
|
+
**Types:** `import type { TreeProps, TreeNode, TreeValue, FlatTreeNode } from '@ahrowe/ui'`
|
|
9
|
+
|
|
10
|
+
```tsx
|
|
11
|
+
import { useState } from 'react';
|
|
12
|
+
import { Tree } from '@ahrowe/ui';
|
|
13
|
+
import type { TreeNode, TreeValue } from '@ahrowe/ui';
|
|
14
|
+
|
|
15
|
+
const nodes: TreeNode[] = [
|
|
16
|
+
{
|
|
17
|
+
key: 'hall-1',
|
|
18
|
+
label: 'Hall 1',
|
|
19
|
+
children: [
|
|
20
|
+
{ key: 'bay-a', label: 'Bay A' },
|
|
21
|
+
{ key: 'bay-b', label: 'Bay B' },
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
{ key: 'archive', label: 'Archive', disabled: true },
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
// Controlled selection
|
|
28
|
+
const [selected, setSelected] = useState<TreeValue | null>(null);
|
|
29
|
+
<Tree nodes={nodes} selectedKey={selected} onSelect={setSelected} aria-label="Locations" />
|
|
30
|
+
|
|
31
|
+
// Uncontrolled, with some branches open to begin with
|
|
32
|
+
<Tree nodes={nodes} defaultExpandedKeys={['hall-1']} defaultSelectedKey="bay-a" />
|
|
33
|
+
|
|
34
|
+
// Controlled expansion, e.g. to persist it
|
|
35
|
+
<Tree nodes={nodes} expandedKeys={open} onExpandedChange={setOpen} />
|
|
36
|
+
|
|
37
|
+
// Clicking a branch selects it without opening it
|
|
38
|
+
<Tree nodes={nodes} expandOnSelect={false} />
|
|
39
|
+
|
|
40
|
+
// Icons per node, and a wider indent
|
|
41
|
+
import { faWarehouse } from '@fortawesome/free-solid-svg-icons';
|
|
42
|
+
<Tree nodes={nodes.map((n) => ({ ...n, icon: faWarehouse }))} indent={40} />
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Branch or leaf:** a node is a branch when it has a `children` array, even an empty one. `children: []` renders a toggle with nothing behind it yet, which is what you want while a branch's contents are still loading; omit `children` entirely for a true leaf.
|
|
46
|
+
|
|
47
|
+
**Selection is single.** `onSelect` fires with the key and the node itself, so you do not have to look it up again. There is no multi-select or checkbox mode.
|
|
48
|
+
|
|
49
|
+
**Key props:**
|
|
50
|
+
|
|
51
|
+
| Prop | Type | Description |
|
|
52
|
+
|------|------|-------------|
|
|
53
|
+
| `nodes` | `TreeNode[]` | The tree: `{ key, label, icon?, children?, disabled? }` |
|
|
54
|
+
| `expandedKeys` | `TreeValue[]` | Controlled open branches (omit for uncontrolled) |
|
|
55
|
+
| `defaultExpandedKeys` | `TreeValue[]` | Branches open initially when uncontrolled (default `[]`) |
|
|
56
|
+
| `onExpandedChange` | `(keys: TreeValue[]) => void` | Fires with the full new set of open branches |
|
|
57
|
+
| `selectedKey` | `TreeValue \| null` | Controlled selection (omit for uncontrolled) |
|
|
58
|
+
| `defaultSelectedKey` | `TreeValue` | Selection when uncontrolled |
|
|
59
|
+
| `onSelect` | `(key: TreeValue, node: TreeNode) => void` | Fires with the picked key and node |
|
|
60
|
+
| `expandOnSelect` | `boolean` | Clicking a branch's row also toggles it (default `true`) |
|
|
61
|
+
| `indent` | `number` | Pixels per level (default `20`) |
|
|
62
|
+
| `toggleIcon` | `IconDefinition \| ReactElement` | Toggle icon, rotated 90° when open (default a right chevron) |
|
|
63
|
+
| `height` | `number \| string` | Windows the rows through `VirtualList` at this viewport height |
|
|
64
|
+
| `estimatedRowHeight` | `number` | Row height for the windowed renderer (default `32`) |
|
|
65
|
+
| `emptyLabel` | `string` | Shown when `nodes` is empty (default `'Nothing here'`) |
|
|
66
|
+
| `disabled` | `boolean` | Dims the tree and blocks interaction |
|
|
67
|
+
| `aria-label` | `string` | Accessible name for the tree (default `'Tree'`) |
|
|
68
|
+
|
|
69
|
+
**Keyboard:** `↑`/`↓` move between visible rows. `→` opens a closed branch, then steps into its first child. `←` closes an open branch, then steps out to its parent. `Home`/`End` jump to the ends. `Enter` or `Space` selects.
|
|
70
|
+
|
|
71
|
+
**Accessibility:** `role="tree"` containing `role="treeitem"` rows. Because the rows render flat rather than nested, each carries `aria-level`, `aria-posinset` and `aria-setsize`; branches also carry `aria-expanded`. Focus uses a roving tabindex, so one row at a time is reachable by Tab, and it is the selected one (or the first, before anything is selected). The toggle is `aria-hidden`, since `aria-expanded` on the row already reports the state.
|
|
72
|
+
|
|
73
|
+
**Why flat:** the rows are a flattened list, not nested `<div>`s. Keyboard movement becomes a step along one array instead of a tree walk, and a node's accessible name stays its own label rather than absorbing its descendants'.
|
|
74
|
+
|
|
75
|
+
**Very large trees:** set `height`. `Tree` then windows its rows through [VirtualList](VirtualList.md), so only the ones in view are in the DOM, and it keeps everything else: the ARIA, the expansion, the selection and the keyboard.
|
|
76
|
+
|
|
77
|
+
```tsx
|
|
78
|
+
<Tree nodes={nodes} height={300} expandedKeys={open} onExpandedChange={setOpen} />
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Two things change in that mode. Rows must be a uniform height, so size them with `--tree-node-height` rather than per row. And the tab stop moves from the selected row to the tree itself, because a roving tabindex on a row that is scrolled out of the window would leave the tree with no tab stop at all; tabbing in still lands on the selected row, which is scrolled into view first.
|
|
82
|
+
|
|
83
|
+
`flattenTree` is exported separately if you want the rows without the component: it returns `FlatTreeNode`s carrying `node`, `level`, `parentKey`, `isBranch`, `isExpanded`, `setSize` and `posInSet`, ready for `VirtualList`'s `items` and `getItemDepth` (which also feeds its `treeReorder` drag-and-drop). You then write the row markup, ARIA and keyboard handling yourself.
|
|
84
|
+
|
|
85
|
+
**Theming:** override these CSS variables theme-wide via `ThemeProvider` or per instance via `style`; each falls back to a built-in default:
|
|
86
|
+
|
|
87
|
+
| Variable | Falls back to |
|
|
88
|
+
|----------|---------------|
|
|
89
|
+
| `--tree-node-height` | `32px` |
|
|
90
|
+
| `--tree-selected-background` | `var(--primary-color)` |
|
|
91
|
+
| `--tree-selected-color` | `var(--text-on-primary)` |
|
|
92
|
+
|
|
93
|
+
**Global defaults:** adopts `ConfigProvider`, e.g. `defaultProps={{ Tree: { indent: 30 } }}`. See [ConfigProvider.md](ConfigProvider.md).
|
|
94
|
+
|
|
95
|
+
**Slots:** `root` `node` `toggle` `icon` `label` `empty`
|
package/docs/VirtualList.md
CHANGED
|
@@ -139,6 +139,7 @@ const columns: VirtualListColumn<User>[] = [
|
|
|
139
139
|
| `onLoadMore` | `() => Promise<void>` | Triggered near the bottom, and repeatedly while the rows don't fill the viewport — append items in the handler |
|
|
140
140
|
| `loadMoreThreshold` | `number` | Distance from bottom that triggers `onLoadMore` (default `100`) |
|
|
141
141
|
| `isLoading` | `boolean` | Replaces list body with a full-height spinner |
|
|
142
|
+
| `ariaRoles` | `{ container: string; row: string }` | Replaces the roles put on the container and rows (default `list`/`listitem`, or `grid`/`row` with columns). Pass `'none'` for both when the rows carry their own semantics, as [Tree](Tree.md) does when windowing `treeitem` rows |
|
|
142
143
|
|
|
143
144
|
Drag-and-drop reordering adds `reorderable`, `treeReorder`, `dragHandle`, and their callbacks — see **Row reordering** below.
|
|
144
145
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ahrowe/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.28.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"build:mcp": "vite build --config vite.mcp.config.ts",
|
|
56
56
|
"preview": "vite preview",
|
|
57
57
|
"gen-barrel": "tsx scripts/gen-barrel.ts",
|
|
58
|
-
"gc": "
|
|
58
|
+
"gc": "tsx scripts/generate-component.ts",
|
|
59
59
|
"changeset": "changeset",
|
|
60
60
|
"lint": "eslint .",
|
|
61
61
|
"lint:fix": "eslint . --fix",
|