torch-glare 2.4.0 → 2.4.1
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 +8 -0
- package/apps/lib/components/ActionButton.tsx +7 -12
- package/apps/lib/components/ActionsGroup.tsx +4 -15
- package/apps/lib/components/AlertDialog.tsx +173 -191
- package/apps/lib/components/Avatar.tsx +13 -16
- package/apps/lib/components/Badge.tsx +1 -3
- package/apps/lib/components/BadgeField.tsx +76 -71
- package/apps/lib/components/Breadcrumb.tsx +49 -85
- package/apps/lib/components/Button.tsx +20 -19
- package/apps/lib/components/ButtonGroup.tsx +31 -41
- package/apps/lib/components/Calendar.tsx +51 -29
- package/apps/lib/components/Card.tsx +2 -13
- package/apps/lib/components/ChartBlockTool.ts +17 -52
- package/apps/lib/components/Checkbox.tsx +9 -16
- package/apps/lib/components/ContextMenu.tsx +97 -96
- package/apps/lib/components/CountBadge.tsx +4 -6
- package/apps/lib/components/DataTable.tsx +196 -216
- package/apps/lib/components/DataViews/DataViewRadio.tsx +1 -6
- package/apps/lib/components/DataViews/DataViewsConfigPanel.tsx +13 -47
- package/apps/lib/components/DataViews/DataViewsHeader.tsx +1 -3
- package/apps/lib/components/DataViews/DataViewsLayout.tsx +5 -12
- package/apps/lib/components/DataViews/FilterPanel.tsx +155 -149
- package/apps/lib/components/DataViews/HeaderSearch.tsx +1 -5
- package/apps/lib/components/DataViews/InboxView.tsx +22 -68
- package/apps/lib/components/DataViews/InboxViewCard.tsx +68 -77
- package/apps/lib/components/DataViews/KanbanView.tsx +8 -25
- package/apps/lib/components/DataViews/PanelControls.tsx +3 -13
- package/apps/lib/components/DataViews/SettingsPanel.tsx +83 -89
- package/apps/lib/components/DataViews/TableView.tsx +8 -28
- package/apps/lib/components/DataViews/TreeView.tsx +12 -40
- package/apps/lib/components/DataViews/badgeAdapter.ts +32 -28
- package/apps/lib/components/DataViews/fieldRenderers.tsx +106 -141
- package/apps/lib/components/DataViews/filters/DatePickerRangeFilter.tsx +30 -23
- package/apps/lib/components/DataViews/filters/DateRangePopover.tsx +39 -32
- package/apps/lib/components/DataViews/filters/PresetChips.tsx +15 -15
- package/apps/lib/components/DataViews/filters/RangeSliderWithInputs.tsx +69 -58
- package/apps/lib/components/DataViews/index.ts +26 -26
- package/apps/lib/components/DataViews/tree/TreeDrawer.tsx +12 -16
- package/apps/lib/components/DataViews/tree/TreeSidebar.tsx +28 -31
- package/apps/lib/components/DataViews/types.ts +104 -115
- package/apps/lib/components/DatePicker.tsx +198 -196
- package/apps/lib/components/Dialog.tsx +92 -105
- package/apps/lib/components/Divider.tsx +21 -24
- package/apps/lib/components/Drawer.tsx +79 -139
- package/apps/lib/components/DropdownMenu.tsx +131 -171
- package/apps/lib/components/FieldHint.tsx +4 -11
- package/apps/lib/components/Form.tsx +146 -155
- package/apps/lib/components/FormStepper.tsx +9 -39
- package/apps/lib/components/HeaderBar.tsx +1 -9
- package/apps/lib/components/ImageAttachment.tsx +111 -73
- package/apps/lib/components/InnerLabelField.tsx +20 -16
- package/apps/lib/components/Input.tsx +171 -172
- package/apps/lib/components/InputField.tsx +44 -45
- package/apps/lib/components/InputOTP.tsx +68 -69
- package/apps/lib/components/Label.tsx +31 -35
- package/apps/lib/components/LabelField.tsx +4 -5
- package/apps/lib/components/LabeledCheckBox.tsx +8 -12
- package/apps/lib/components/LabeledRadio.tsx +7 -5
- package/apps/lib/components/LinkButton.tsx +2 -9
- package/apps/lib/components/LoginButton.tsx +4 -9
- package/apps/lib/components/PasswordLevel.tsx +5 -5
- package/apps/lib/components/Popover.tsx +15 -33
- package/apps/lib/components/ProfileMenu.tsx +67 -72
- package/apps/lib/components/Radio.tsx +1 -5
- package/apps/lib/components/RadioCard.tsx +9 -28
- package/apps/lib/components/ScrollArea.tsx +45 -43
- package/apps/lib/components/SearchField.tsx +49 -39
- package/apps/lib/components/SearchableSelect.tsx +8 -14
- package/apps/lib/components/SearchableTable.tsx +108 -118
- package/apps/lib/components/SearchableTree.tsx +469 -0
- package/apps/lib/components/SearchableTreeDialog.tsx +493 -0
- package/apps/lib/components/SectionBlock.tsx +4 -16
- package/apps/lib/components/Select.tsx +53 -80
- package/apps/lib/components/SimpleSelect.tsx +196 -187
- package/apps/lib/components/Skeleton.tsx +9 -12
- package/apps/lib/components/SlideDatePicker.tsx +215 -166
- package/apps/lib/components/SpinLoading.tsx +33 -49
- package/apps/lib/components/Stepper.tsx +13 -56
- package/apps/lib/components/Switch.tsx +8 -10
- package/apps/lib/components/TabFormItem.tsx +3 -12
- package/apps/lib/components/TabSwitch.tsx +7 -34
- package/apps/lib/components/Table.tsx +60 -75
- package/apps/lib/components/TableDnDWrapper.ts +15 -48
- package/apps/lib/components/TextEditor.tsx +93 -104
- package/apps/lib/components/Textarea.tsx +8 -12
- package/apps/lib/components/Timeline.tsx +21 -41
- package/apps/lib/components/Toast.tsx +83 -83
- package/apps/lib/components/Toggle.tsx +112 -114
- package/apps/lib/components/ToggleButton.tsx +1 -1
- package/apps/lib/components/Tooltip.tsx +24 -19
- package/apps/lib/components/TransparentLabel.tsx +61 -62
- package/apps/lib/components/TreeDropDown.tsx +86 -52
- package/apps/lib/components/TreeFolder/TreeFolder.tsx +15 -48
- package/apps/lib/components/TreeFolder/TreeFolderBreadcrumb.tsx +16 -21
- package/apps/lib/components/TreeFolder/TreeFolderRow.tsx +9 -20
- package/apps/lib/components/TreeFolder/TreeFolderStyles.tsx +3 -3
- package/apps/lib/components/TreeFolder/icons.tsx +14 -17
- package/apps/lib/components/TreeFolder/index.ts +15 -8
- package/apps/lib/components/TreeFolder/treeFolderUtils.ts +47 -52
- package/apps/lib/components/TreeFolder/types.ts +32 -32
- package/apps/lib/components/TreeFolder/useTreeFolderDnD.ts +117 -123
- package/apps/lib/hooks/useActiveTreeItem.ts +52 -55
- package/apps/lib/hooks/useClickOutside.ts +21 -20
- package/apps/lib/hooks/useDataViewsState.ts +86 -80
- package/apps/lib/hooks/useIsMobile.ts +12 -12
- package/apps/lib/hooks/useResize.ts +54 -65
- package/apps/lib/hooks/useTagSelection.ts +201 -201
- package/apps/lib/layouts/CNLayout.tsx +181 -140
- package/apps/lib/layouts/DataViewCard.tsx +4 -18
- package/apps/lib/layouts/FieldSection.tsx +2 -6
- package/apps/lib/layouts/TreeSubLayout.tsx +24 -38
- package/apps/lib/providers/ThemeProvider.tsx +8 -23
- package/apps/lib/registry.json +1004 -0
- package/apps/lib/tsconfig.json +9 -0
- package/apps/lib/utils/cn.ts +1 -1
- package/apps/lib/utils/dataViews/columnUtils.ts +46 -44
- package/apps/lib/utils/dataViews/fieldUtils.ts +70 -71
- package/apps/lib/utils/dataViews/nestedDataUtils.tsx +129 -122
- package/apps/lib/utils/dataViews/pathUtils.ts +74 -67
- package/apps/lib/utils/dataViews/rangeUtils.ts +121 -112
- package/apps/lib/utils/dataViews/treeUtils.ts +204 -211
- package/apps/lib/utils/dateFormat.ts +64 -54
- package/apps/lib/utils/markdownParser.ts +2 -7
- package/apps/lib/utils/resize.ts +21 -25
- package/apps/lib/utils/types.ts +13 -13
- package/dist/bin/index.js +8 -2
- package/dist/bin/index.js.map +1 -1
- package/dist/src/shared/getAvailableFiles.d.ts.map +1 -1
- package/dist/src/shared/getAvailableFiles.js +6 -1
- package/dist/src/shared/getAvailableFiles.js.map +1 -1
- package/dist/src/shared/loadRegistry.d.ts +7 -0
- package/dist/src/shared/loadRegistry.d.ts.map +1 -0
- package/dist/src/shared/loadRegistry.js +31 -0
- package/dist/src/shared/loadRegistry.js.map +1 -0
- package/dist/src/shared/resolveInstallPlan.d.ts +12 -0
- package/dist/src/shared/resolveInstallPlan.d.ts.map +1 -0
- package/dist/src/shared/resolveInstallPlan.js +39 -0
- package/dist/src/shared/resolveInstallPlan.js.map +1 -0
- package/dist/src/types/main.d.ts +24 -0
- package/dist/src/types/main.d.ts.map +1 -1
- package/docs/README.md +10 -2
- package/docs/components/action-button.md +30 -24
- package/docs/components/actions-group.md +26 -20
- package/docs/components/alert-dialog.md +45 -45
- package/docs/components/avatar.md +6 -2
- package/docs/components/badge-field.md +6 -2
- package/docs/components/badge.md +7 -1
- package/docs/components/breadcrumb.md +15 -40
- package/docs/components/button-group.md +13 -10
- package/docs/components/button.md +58 -33
- package/docs/components/calendar.md +26 -19
- package/docs/components/card.md +19 -16
- package/docs/components/chart-block-tool.md +128 -0
- package/docs/components/checkbox.md +16 -8
- package/docs/components/cn-layout.md +7 -1
- package/docs/components/context-menu.md +18 -25
- package/docs/components/count-badge.md +7 -1
- package/docs/components/data-table.md +45 -33
- package/docs/components/data-views-config-panel.md +15 -11
- package/docs/components/data-views-layout.md +13 -16
- package/docs/components/date-picker.md +30 -23
- package/docs/components/dialog.md +43 -42
- package/docs/components/divider.md +10 -4
- package/docs/components/drawer.md +8 -33
- package/docs/components/dropdown-menu.md +25 -34
- package/docs/components/field-hint.md +37 -25
- package/docs/components/field-section.md +9 -3
- package/docs/components/form-stepper.md +6 -0
- package/docs/components/form.md +17 -20
- package/docs/components/header-bar.md +6 -0
- package/docs/components/image-attachment.md +33 -41
- package/docs/components/inbox-view.md +16 -5
- package/docs/components/inner-label-field.md +34 -24
- package/docs/components/input-field.md +18 -10
- package/docs/components/input-otp.md +14 -11
- package/docs/components/input.md +22 -16
- package/docs/components/kanban-view.md +15 -5
- package/docs/components/label-field.md +32 -22
- package/docs/components/label.md +43 -32
- package/docs/components/labeled-check-box.md +16 -8
- package/docs/components/labeled-radio.md +18 -11
- package/docs/components/link-button.md +7 -1
- package/docs/components/login-button.md +8 -2
- package/docs/components/password-level.md +37 -24
- package/docs/components/popover.md +26 -23
- package/docs/components/profile-menu.md +38 -27
- package/docs/components/radio-card.md +16 -9
- package/docs/components/radio.md +16 -8
- package/docs/components/scroll-area.md +6 -2
- package/docs/components/search-field.md +14 -6
- package/docs/components/searchable-select.md +19 -14
- package/docs/components/searchable-table.md +18 -13
- package/docs/components/searchable-tree-dialog.md +190 -0
- package/docs/components/searchable-tree.md +200 -0
- package/docs/components/section-block.md +12 -4
- package/docs/components/select.md +23 -18
- package/docs/components/simple-select.md +14 -10
- package/docs/components/skeleton.md +43 -33
- package/docs/components/slide-date-picker.md +37 -29
- package/docs/components/spin-loading.md +32 -23
- package/docs/components/stepper.md +6 -0
- package/docs/components/switch.md +14 -6
- package/docs/components/tab-form-item.md +7 -1
- package/docs/components/tab-switch.md +13 -6
- package/docs/components/table-dnd-wrapper.md +105 -0
- package/docs/components/table-view.md +15 -5
- package/docs/components/table.md +28 -28
- package/docs/components/text-editor.md +19 -13
- package/docs/components/textarea.md +15 -7
- package/docs/components/timeline.md +6 -0
- package/docs/components/toast.md +35 -26
- package/docs/components/toggle-button.md +24 -21
- package/docs/components/toggle.md +23 -15
- package/docs/components/tooltip.md +42 -30
- package/docs/components/transparent-label.md +29 -20
- package/docs/components/tree-drop-down.md +31 -23
- package/docs/components/tree-sub-layout.md +6 -2
- package/docs/components/tree-view.md +16 -5
- package/docs/explanation/architecture.md +54 -0
- package/docs/explanation/design-system.md +52 -0
- package/docs/how-to/data-views-from-backend-response.md +6 -4
- package/docs/how-to/guides.md +24 -18
- package/docs/migration/changelog.md +38 -0
- package/docs/reference/cli.md +87 -0
- package/docs/reference/components.md +11 -12
- package/docs/reference/hooks.md +8 -8
- package/docs/reference/providers.md +22 -22
- package/docs/reference/tailwind-plugins.md +2 -2
- package/docs/reference/theme.md +85 -0
- package/docs/reference/types.md +4 -4
- package/docs/reference/utilities.md +19 -26
- package/docs/tutorials/building-first-form.md +20 -13
- package/docs/tutorials/component-composition.md +34 -50
- package/docs/tutorials/getting-started.md +2 -2
- package/docs/tutorials/theming-basics.md +13 -10
- package/package.json +31 -3
- package/dist/src/commands/block.d.ts +0 -5
- package/dist/src/commands/block.d.ts.map +0 -1
- package/dist/src/commands/block.js +0 -255
- package/dist/src/commands/block.js.map +0 -1
- package/dist/src/shared/configureFonts.d.ts +0 -6
- package/dist/src/shared/configureFonts.d.ts.map +0 -1
- package/dist/src/shared/configureFonts.js +0 -106
- package/dist/src/shared/configureFonts.js.map +0 -1
- package/dist/src/shared/configureGlobalCss.d.ts +0 -6
- package/dist/src/shared/configureGlobalCss.d.ts.map +0 -1
- package/dist/src/shared/configureGlobalCss.js +0 -154
- package/dist/src/shared/configureGlobalCss.js.map +0 -1
- package/dist/src/shared/configureTailwind.d.ts +0 -7
- package/dist/src/shared/configureTailwind.d.ts.map +0 -1
- package/dist/src/shared/configureTailwind.js +0 -163
- package/dist/src/shared/configureTailwind.js.map +0 -1
- package/dist/src/shared/detectFramework.d.ts +0 -23
- package/dist/src/shared/detectFramework.d.ts.map +0 -1
- package/dist/src/shared/detectFramework.js +0 -119
- package/dist/src/shared/detectFramework.js.map +0 -1
- package/dist/src/shared/installBaseUtils.d.ts +0 -5
- package/dist/src/shared/installBaseUtils.d.ts.map +0 -1
- package/dist/src/shared/installBaseUtils.js +0 -79
- package/dist/src/shared/installBaseUtils.js.map +0 -1
- package/dist/src/shared/resolveAliases.d.ts +0 -24
- package/dist/src/shared/resolveAliases.d.ts.map +0 -1
- package/dist/src/shared/resolveAliases.js +0 -98
- package/dist/src/shared/resolveAliases.js.map +0 -1
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: SearchableTreeDialog
|
|
3
|
+
description: Searchable tree-select presented in a modal dialog — a trigger opens a dialog containing a searchable hierarchical tree, with client or server-side search
|
|
4
|
+
group: Inputs
|
|
5
|
+
keywords: [searchable-tree-dialog, tree, tree-select, dialog, modal, hierarchy, search, async]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# SearchableTreeDialog
|
|
9
|
+
|
|
10
|
+
> A searchable tree-select that opens in a modal **Dialog** instead of a popover. A trigger
|
|
11
|
+
> field opens a dialog containing a search input and a hierarchical tree of nodes, filtered as
|
|
12
|
+
> you type. Accepts nested data (via `getNodeChildren`) or a flat list it nests for you (via
|
|
13
|
+
> `parentIdKey`). Supports local filtering or debounced server-side search, optional folder
|
|
14
|
+
> selection, and controlled selection. Use it instead of [SearchableTree](./searchable-tree.md)
|
|
15
|
+
> when the tree is large or you want a focused, full-screen-friendly selection surface.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
TORCH Glare is a copy-in library: the CLI copies this component's source into your project
|
|
20
|
+
(you do **not** install it from the npm package). Run `init` once, then `add`:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx torch-glare@latest init
|
|
24
|
+
npx torch-glare@latest add SearchableTreeDialog
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The CLI also copies its internal dependencies: `Button`, `Dialog`, `Input`, and the
|
|
28
|
+
`cn`/`types` utils.
|
|
29
|
+
|
|
30
|
+
## Import
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { SearchableTreeDialog } from "@/components/SearchableTreeDialog";
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Quick Examples
|
|
37
|
+
|
|
38
|
+
### Basic Usage (nested data)
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
import { SearchableTreeDialog } from "@/components/SearchableTreeDialog";
|
|
42
|
+
|
|
43
|
+
type Node = { id: string; name: string; children?: Node[] };
|
|
44
|
+
|
|
45
|
+
const data: Node[] = [
|
|
46
|
+
{
|
|
47
|
+
id: "eng",
|
|
48
|
+
name: "Engineering",
|
|
49
|
+
children: [
|
|
50
|
+
{ id: "fe", name: "Frontend" },
|
|
51
|
+
{ id: "be", name: "Backend" },
|
|
52
|
+
],
|
|
53
|
+
},
|
|
54
|
+
{ id: "design", name: "Design" },
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
export function DepartmentPicker() {
|
|
58
|
+
const [value, setValue] = useState<Node | null>(null);
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<SearchableTreeDialog
|
|
62
|
+
nodes={data}
|
|
63
|
+
getNodeId={(n) => n.id}
|
|
64
|
+
getNodeLabel={(n) => n.name}
|
|
65
|
+
getNodeChildren={(n) => n.children}
|
|
66
|
+
value={value}
|
|
67
|
+
onSelect={setValue}
|
|
68
|
+
placeholder="Select a department"
|
|
69
|
+
searchPlaceholder="Search departments…"
|
|
70
|
+
title="Departments"
|
|
71
|
+
size="M"
|
|
72
|
+
/>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Flat data (built from a parent id)
|
|
78
|
+
|
|
79
|
+
```tsx
|
|
80
|
+
type Row = { id: string; label: string; parentId: string | null };
|
|
81
|
+
|
|
82
|
+
const rows: Row[] = [
|
|
83
|
+
{ id: "1", label: "Company", parentId: null },
|
|
84
|
+
{ id: "2", label: "Sales", parentId: "1" },
|
|
85
|
+
{ id: "3", label: "EMEA", parentId: "2" },
|
|
86
|
+
];
|
|
87
|
+
|
|
88
|
+
<SearchableTreeDialog
|
|
89
|
+
nodes={rows}
|
|
90
|
+
parentIdKey="parentId"
|
|
91
|
+
getNodeId={(r) => r.id}
|
|
92
|
+
getNodeLabel={(r) => r.label}
|
|
93
|
+
onSelect={(r) => console.log(r.id)}
|
|
94
|
+
/>;
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Server-side search
|
|
98
|
+
|
|
99
|
+
```tsx
|
|
100
|
+
<SearchableTreeDialog
|
|
101
|
+
nodes={results}
|
|
102
|
+
getNodeId={(n) => n.id}
|
|
103
|
+
getNodeLabel={(n) => n.name}
|
|
104
|
+
getNodeChildren={(n) => n.children}
|
|
105
|
+
filterClientSide={false}
|
|
106
|
+
onSearchChange={(query) => fetchNodes(query)}
|
|
107
|
+
loading={isFetching}
|
|
108
|
+
searchDebounceMs={300}
|
|
109
|
+
/>
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## API Reference
|
|
113
|
+
|
|
114
|
+
### Props
|
|
115
|
+
|
|
116
|
+
| Prop | Type | Default | Description |
|
|
117
|
+
|------|------|---------|-------------|
|
|
118
|
+
| `nodes` | `T[]` | — | Tree data. Nested by default; treated as a flat list when `parentIdKey` is set. |
|
|
119
|
+
| `getNodeId` | `(node: T) => string` | — | Returns a stable unique id for a node. |
|
|
120
|
+
| `getNodeLabel` | `(node: T) => ReactNode` | — | Returns a node's display label. |
|
|
121
|
+
| `getNodeChildren` | `(node: T) => T[] \| undefined` | — | Returns a node's children (nested mode). Ignored when `parentIdKey` is set. |
|
|
122
|
+
| `parentIdKey` | `keyof T & string` | — | When set, `nodes` is a FLAT list and the tree is built from this parent-id key. |
|
|
123
|
+
| `value` | `T \| null` | — | Controlled selected node. |
|
|
124
|
+
| `onSelect` | `(node: T) => void` | — | Called when a node is selected. |
|
|
125
|
+
| `getSearchText` | `(node: T) => string` | `String(getNodeLabel(node))` | Plain text used for search matching. |
|
|
126
|
+
| `placeholder` | `string` | — | Trigger placeholder shown until a node is selected. |
|
|
127
|
+
| `searchPlaceholder` | `string` | — | Placeholder for the search input inside the dialog. |
|
|
128
|
+
| `title` | `string` | — | Label shown on the dialog's search field. |
|
|
129
|
+
| `size` | `"XS" \| "S" \| "M"` | `"M"` | Trigger size. |
|
|
130
|
+
| `variant` | `"SystemStyle" \| "PresentationStyle"` | `"PresentationStyle"` | Visual style. `SystemStyle` is reserved for internal library system surfaces. |
|
|
131
|
+
| `icon` | `ReactNode` | — | Leading icon in the trigger. |
|
|
132
|
+
| `theme` | `Themes` | — | `"dark" \| "light" \| "default"`. |
|
|
133
|
+
| `dir` | `string` | — | Text direction. |
|
|
134
|
+
| `className` | `string` | — | Extra classes for the trigger. |
|
|
135
|
+
| `defaultExpanded` | `boolean` | `true` | Expand every node when the dialog opens. |
|
|
136
|
+
| `selectableFolders` | `boolean` | `false` | When true, folder nodes are selectable too; otherwise folders only expand/collapse. |
|
|
137
|
+
| `filterClientSide` | `boolean` | `true` | Filter locally. Set `false` for server-side search. |
|
|
138
|
+
| `onSearchChange` | `(query: string) => void` | — | Debounced as the user types — refetch your data here (server search). |
|
|
139
|
+
| `searchDebounceMs` | `number` | `300` | Debounce for `onSearchChange`. |
|
|
140
|
+
| `loading` | `boolean` | `false` | Whether a fetch is in flight; shows a loading indicator. |
|
|
141
|
+
|
|
142
|
+
### TypeScript
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
import { ReactNode } from "react";
|
|
146
|
+
import { Themes } from "@/utils/types";
|
|
147
|
+
|
|
148
|
+
interface SearchableTreeDialogProps<T> {
|
|
149
|
+
nodes: T[];
|
|
150
|
+
getNodeId: (node: T) => string;
|
|
151
|
+
getNodeLabel: (node: T) => ReactNode;
|
|
152
|
+
getNodeChildren?: (node: T) => T[] | undefined;
|
|
153
|
+
parentIdKey?: keyof T & string;
|
|
154
|
+
value?: T | null;
|
|
155
|
+
onSelect?: (node: T) => void;
|
|
156
|
+
getSearchText?: (node: T) => string;
|
|
157
|
+
placeholder?: string;
|
|
158
|
+
searchPlaceholder?: string;
|
|
159
|
+
title?: string;
|
|
160
|
+
size?: "XS" | "S" | "M";
|
|
161
|
+
variant?: "SystemStyle" | "PresentationStyle";
|
|
162
|
+
icon?: ReactNode;
|
|
163
|
+
theme?: Themes;
|
|
164
|
+
dir?: string;
|
|
165
|
+
className?: string;
|
|
166
|
+
defaultExpanded?: boolean;
|
|
167
|
+
selectableFolders?: boolean;
|
|
168
|
+
filterClientSide?: boolean;
|
|
169
|
+
onSearchChange?: (query: string) => void;
|
|
170
|
+
searchDebounceMs?: number;
|
|
171
|
+
loading?: boolean;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export function SearchableTreeDialog<T>(props: SearchableTreeDialogProps<T>): JSX.Element;
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Common Patterns
|
|
178
|
+
|
|
179
|
+
- **Dialog vs popover:** use `SearchableTreeDialog` for large trees or a focused modal
|
|
180
|
+
selection; use [SearchableTree](./searchable-tree.md) for an inline popover field.
|
|
181
|
+
- **Nested vs flat data:** provide `getNodeChildren` for nested data, or `parentIdKey` to nest
|
|
182
|
+
a flat list. Do not use both.
|
|
183
|
+
- **Async search:** set `filterClientSide={false}`, handle `onSearchChange` to fetch, and pass
|
|
184
|
+
`loading` while the request is in flight.
|
|
185
|
+
|
|
186
|
+
## Related Components
|
|
187
|
+
|
|
188
|
+
- [SearchableTree](./searchable-tree.md) — the same tree-select on an inline Popover.
|
|
189
|
+
- [SearchableSelect](./searchable-select.md) — flat searchable single-select combobox.
|
|
190
|
+
- [Dialog](./dialog.md) — the modal surface this component builds on.
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: SearchableTree
|
|
3
|
+
description: Searchable tree-select that opens on focus and filters hierarchical nodes as you type, on a Popover surface, with client or server-side search
|
|
4
|
+
group: Inputs
|
|
5
|
+
keywords: [searchable-tree, tree, tree-select, hierarchy, search, combobox, async, popover]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# SearchableTree
|
|
9
|
+
|
|
10
|
+
> A searchable tree-select. It renders a field that opens a Popover containing a hierarchical
|
|
11
|
+
> tree of nodes and filters them as you type. Accepts either nested data (via `getNodeChildren`)
|
|
12
|
+
> or a flat list that it nests for you (via `parentIdKey`). Supports local filtering or
|
|
13
|
+
> debounced server-side search, optional folder selection, and controlled selection.
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
TORCH Glare is a copy-in library: the CLI copies this component's source into your project
|
|
18
|
+
(you do **not** install it from the npm package). Run `init` once, then `add`:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx torch-glare@latest init
|
|
22
|
+
npx torch-glare@latest add SearchableTree
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The CLI also copies its internal dependencies: `Button`, `Input`, `Popover`, the
|
|
26
|
+
`useClickOutside` hook, and the `cn`/`types` utils.
|
|
27
|
+
|
|
28
|
+
## Import
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import { SearchableTree } from "@/components/SearchableTree";
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Quick Examples
|
|
35
|
+
|
|
36
|
+
### Basic Usage (nested data)
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
import { SearchableTree } from "@/components/SearchableTree";
|
|
40
|
+
|
|
41
|
+
type Node = { id: string; name: string; children?: Node[] };
|
|
42
|
+
|
|
43
|
+
const data: Node[] = [
|
|
44
|
+
{
|
|
45
|
+
id: "eng",
|
|
46
|
+
name: "Engineering",
|
|
47
|
+
children: [
|
|
48
|
+
{ id: "fe", name: "Frontend" },
|
|
49
|
+
{ id: "be", name: "Backend" },
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
{ id: "design", name: "Design" },
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
export function DepartmentPicker() {
|
|
56
|
+
const [value, setValue] = useState<Node | null>(null);
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<SearchableTree
|
|
60
|
+
nodes={data}
|
|
61
|
+
getNodeId={(n) => n.id}
|
|
62
|
+
getNodeLabel={(n) => n.name}
|
|
63
|
+
getNodeChildren={(n) => n.children}
|
|
64
|
+
value={value}
|
|
65
|
+
onSelect={setValue}
|
|
66
|
+
placeholder="Select a department"
|
|
67
|
+
title="Departments"
|
|
68
|
+
size="M"
|
|
69
|
+
/>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Flat data (built from a parent id)
|
|
75
|
+
|
|
76
|
+
```tsx
|
|
77
|
+
type Row = { id: string; label: string; parentId: string | null };
|
|
78
|
+
|
|
79
|
+
const rows: Row[] = [
|
|
80
|
+
{ id: "1", label: "Company", parentId: null },
|
|
81
|
+
{ id: "2", label: "Sales", parentId: "1" },
|
|
82
|
+
{ id: "3", label: "EMEA", parentId: "2" },
|
|
83
|
+
];
|
|
84
|
+
|
|
85
|
+
<SearchableTree
|
|
86
|
+
nodes={rows}
|
|
87
|
+
parentIdKey="parentId"
|
|
88
|
+
getNodeId={(r) => r.id}
|
|
89
|
+
getNodeLabel={(r) => r.label}
|
|
90
|
+
onSelect={(r) => console.log(r.id)}
|
|
91
|
+
/>;
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Server-side search
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
<SearchableTree
|
|
98
|
+
nodes={results}
|
|
99
|
+
getNodeId={(n) => n.id}
|
|
100
|
+
getNodeLabel={(n) => n.name}
|
|
101
|
+
getNodeChildren={(n) => n.children}
|
|
102
|
+
filterClientSide={false}
|
|
103
|
+
onSearchChange={(query) => fetchNodes(query)}
|
|
104
|
+
loading={isFetching}
|
|
105
|
+
searchDebounceMs={300}
|
|
106
|
+
/>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Selectable folders
|
|
110
|
+
|
|
111
|
+
```tsx
|
|
112
|
+
<SearchableTree
|
|
113
|
+
nodes={data}
|
|
114
|
+
getNodeId={(n) => n.id}
|
|
115
|
+
getNodeLabel={(n) => n.name}
|
|
116
|
+
getNodeChildren={(n) => n.children}
|
|
117
|
+
selectableFolders
|
|
118
|
+
onSelect={(n) => console.log(n.id)}
|
|
119
|
+
/>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## API Reference
|
|
123
|
+
|
|
124
|
+
### Props
|
|
125
|
+
|
|
126
|
+
| Prop | Type | Default | Description |
|
|
127
|
+
|------|------|---------|-------------|
|
|
128
|
+
| `nodes` | `T[]` | — | Tree data. Nested by default; treated as a flat list when `parentIdKey` is set. |
|
|
129
|
+
| `getNodeId` | `(node: T) => string` | — | Returns a stable unique id for a node. |
|
|
130
|
+
| `getNodeLabel` | `(node: T) => ReactNode` | — | Returns a node's display label. |
|
|
131
|
+
| `getNodeChildren` | `(node: T) => T[] \| undefined` | — | Returns a node's children (nested mode). Ignored when `parentIdKey` is set. |
|
|
132
|
+
| `parentIdKey` | `keyof T & string` | — | When set, `nodes` is a FLAT list and the tree is built from this parent-id key. |
|
|
133
|
+
| `value` | `T \| null` | — | Controlled selected node. |
|
|
134
|
+
| `onSelect` | `(node: T) => void` | — | Called when a node is selected. |
|
|
135
|
+
| `getSearchText` | `(node: T) => string` | `String(getNodeLabel(node))` | Plain text used for search matching. |
|
|
136
|
+
| `placeholder` | `string` | `"Select…"` | Field placeholder shown when nothing is selected. |
|
|
137
|
+
| `title` | `string` | `"Select an item"` | Section heading above the tree rows in the dropdown. |
|
|
138
|
+
| `size` | `"XS" \| "S" \| "M"` | `"M"` | Field size. |
|
|
139
|
+
| `variant` | `"SystemStyle" \| "PresentationStyle"` | `"PresentationStyle"` | Visual style. `SystemStyle` is reserved for internal library system surfaces. |
|
|
140
|
+
| `icon` | `ReactNode` | — | Leading icon in the field. |
|
|
141
|
+
| `theme` | `Themes` | — | `"dark" \| "light" \| "default"`. |
|
|
142
|
+
| `dir` | `string` | — | Text direction. |
|
|
143
|
+
| `className` | `string` | — | Extra classes for the field. |
|
|
144
|
+
| `defaultExpanded` | `boolean` | `true` | Expand every node when the dropdown opens. |
|
|
145
|
+
| `selectableFolders` | `boolean` | `false` | When true, folder nodes are selectable too; otherwise folders only expand/collapse. |
|
|
146
|
+
| `maxBodyHeight` | `number` | `320` | Max height (px) of the scrollable tree body before it scrolls. |
|
|
147
|
+
| `filterClientSide` | `boolean` | `true` | Filter locally. Set `false` for server-side search. |
|
|
148
|
+
| `onSearchChange` | `(query: string) => void` | — | Debounced as the user types — refetch your data here (server search). |
|
|
149
|
+
| `searchDebounceMs` | `number` | `300` | Debounce for `onSearchChange`. |
|
|
150
|
+
| `loading` | `boolean` | `false` | Whether a fetch is in flight; shows a loading indicator. |
|
|
151
|
+
|
|
152
|
+
### TypeScript
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
import { ReactNode } from "react";
|
|
156
|
+
import { Themes } from "@/utils/types";
|
|
157
|
+
|
|
158
|
+
interface SearchableTreeProps<T> {
|
|
159
|
+
nodes: T[];
|
|
160
|
+
getNodeId: (node: T) => string;
|
|
161
|
+
getNodeLabel: (node: T) => ReactNode;
|
|
162
|
+
getNodeChildren?: (node: T) => T[] | undefined;
|
|
163
|
+
parentIdKey?: keyof T & string;
|
|
164
|
+
value?: T | null;
|
|
165
|
+
onSelect?: (node: T) => void;
|
|
166
|
+
getSearchText?: (node: T) => string;
|
|
167
|
+
placeholder?: string;
|
|
168
|
+
title?: string;
|
|
169
|
+
size?: "XS" | "S" | "M";
|
|
170
|
+
variant?: "SystemStyle" | "PresentationStyle";
|
|
171
|
+
icon?: ReactNode;
|
|
172
|
+
theme?: Themes;
|
|
173
|
+
dir?: string;
|
|
174
|
+
className?: string;
|
|
175
|
+
defaultExpanded?: boolean;
|
|
176
|
+
selectableFolders?: boolean;
|
|
177
|
+
maxBodyHeight?: number;
|
|
178
|
+
filterClientSide?: boolean;
|
|
179
|
+
onSearchChange?: (query: string) => void;
|
|
180
|
+
searchDebounceMs?: number;
|
|
181
|
+
loading?: boolean;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export function SearchableTree<T>(props: SearchableTreeProps<T>): JSX.Element;
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Common Patterns
|
|
188
|
+
|
|
189
|
+
- **Nested vs flat data:** provide `getNodeChildren` for already-nested data, or `parentIdKey`
|
|
190
|
+
to let the component nest a flat list for you. Do not use both.
|
|
191
|
+
- **Async search:** set `filterClientSide={false}` and handle `onSearchChange` to fetch from a
|
|
192
|
+
backend; pass `loading` while the request is in flight.
|
|
193
|
+
- **Folder selection:** by default only leaf nodes are selectable. Set `selectableFolders` to
|
|
194
|
+
allow selecting a folder node (clicking any node selects it and closes the dropdown).
|
|
195
|
+
|
|
196
|
+
## Related Components
|
|
197
|
+
|
|
198
|
+
- [SearchableTreeDialog](./searchable-tree-dialog.md) — the same tree-select in a modal dialog.
|
|
199
|
+
- [SearchableSelect](./searchable-select.md) — flat searchable single-select combobox.
|
|
200
|
+
- [TreeDropDown](./tree-drop-down.md) — dropdown tree without search.
|
|
@@ -6,7 +6,7 @@ category: layout
|
|
|
6
6
|
group: Layout & Containers
|
|
7
7
|
tags: [layout, card, section, container, form, group]
|
|
8
8
|
status: stable
|
|
9
|
-
version:
|
|
9
|
+
version: 2.4.0
|
|
10
10
|
dependencies:
|
|
11
11
|
- "class-variance-authority": "^0.7.0"
|
|
12
12
|
---
|
|
@@ -17,14 +17,22 @@ dependencies:
|
|
|
17
17
|
|
|
18
18
|
## Installation
|
|
19
19
|
|
|
20
|
+
TORCH Glare is a copy-in library: the CLI copies this component's source into your project
|
|
21
|
+
(you do **not** install it from the npm package). Run `init` once, then `add`:
|
|
22
|
+
|
|
20
23
|
```bash
|
|
21
|
-
npx torch-glare
|
|
24
|
+
npx torch-glare@latest init
|
|
25
|
+
npx torch-glare@latest add SectionBlock
|
|
22
26
|
```
|
|
23
27
|
|
|
28
|
+
`add` also copies any components, hooks, and utilities that `SectionBlock` depends on.
|
|
29
|
+
|
|
24
30
|
## Import
|
|
25
31
|
|
|
26
|
-
|
|
27
|
-
|
|
32
|
+
Import from your project's local path — the alias configured in `glare.json` (e.g. `@/*`):
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
import { SectionBlock } from "@/components/SectionBlock";
|
|
28
36
|
```
|
|
29
37
|
|
|
30
38
|
## Basic Usage
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: Select
|
|
3
|
-
version:
|
|
3
|
+
version: 2.4.0
|
|
4
4
|
status: stable
|
|
5
5
|
category: components/forms
|
|
6
6
|
tags: [form, select, dropdown, accessible, radix-ui]
|
|
@@ -17,23 +17,22 @@ dependencies:
|
|
|
17
17
|
|
|
18
18
|
## Installation
|
|
19
19
|
|
|
20
|
+
TORCH Glare is a copy-in library: the CLI copies this component's source into your project
|
|
21
|
+
(you do **not** install it from the npm package). Run `init` once, then `add`:
|
|
22
|
+
|
|
20
23
|
```bash
|
|
21
|
-
|
|
24
|
+
npx torch-glare@latest init
|
|
25
|
+
npx torch-glare@latest add Select
|
|
22
26
|
```
|
|
23
27
|
|
|
28
|
+
`add` also copies any components, hooks, and utilities that `Select` depends on.
|
|
29
|
+
|
|
24
30
|
## Import
|
|
25
31
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
SelectContent,
|
|
31
|
-
SelectItem,
|
|
32
|
-
SelectValue,
|
|
33
|
-
SelectGroup,
|
|
34
|
-
SelectLabel,
|
|
35
|
-
SelectSeparator
|
|
36
|
-
} from 'torch-glare/lib/components/Select'
|
|
32
|
+
Import from your project's local path — the alias configured in `glare.json` (e.g. `@/*`):
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
import { Select } from "@/components/Select";
|
|
37
36
|
```
|
|
38
37
|
|
|
39
38
|
## Quick Examples
|
|
@@ -47,7 +46,7 @@ import {
|
|
|
47
46
|
SelectContent,
|
|
48
47
|
SelectItem,
|
|
49
48
|
SelectValue
|
|
50
|
-
} from '
|
|
49
|
+
} from '@/components/Select'
|
|
51
50
|
|
|
52
51
|
function Example() {
|
|
53
52
|
const [value, setValue] = useState('')
|
|
@@ -265,6 +264,9 @@ function Uncontrolled() {
|
|
|
265
264
|
| Prop | Type | Default | Description |
|
|
266
265
|
|------|------|---------|-------------|
|
|
267
266
|
| `value` | `string` | - | Item value (required) |
|
|
267
|
+
| `variant` | `'Default' \| 'Warning' \| 'Negative' \| 'SystemStyle'` | `'Default'` | Visual variant |
|
|
268
|
+
| `size` | `'S' \| 'M'` | `'M'` | Item size |
|
|
269
|
+
| `active` | `boolean` | `false` | Renders the item in its selected/active style |
|
|
268
270
|
| `disabled` | `boolean` | `false` | Disable item |
|
|
269
271
|
| `className` | `string` | - | Additional CSS classes |
|
|
270
272
|
| `children` | `React.ReactNode` | - | Item content |
|
|
@@ -272,7 +274,7 @@ function Uncontrolled() {
|
|
|
272
274
|
### TypeScript
|
|
273
275
|
|
|
274
276
|
```typescript
|
|
275
|
-
import type { Themes } from '
|
|
277
|
+
import type { Themes } from '@/utils/types'
|
|
276
278
|
|
|
277
279
|
// Select component types
|
|
278
280
|
interface SelectProps {
|
|
@@ -316,6 +318,9 @@ interface SelectContentProps {
|
|
|
316
318
|
// Item types
|
|
317
319
|
interface SelectItemProps {
|
|
318
320
|
value: string
|
|
321
|
+
variant?: 'Default' | 'Warning' | 'Negative' | 'SystemStyle'
|
|
322
|
+
size?: 'S' | 'M'
|
|
323
|
+
active?: boolean
|
|
319
324
|
disabled?: boolean
|
|
320
325
|
className?: string
|
|
321
326
|
children: React.ReactNode
|
|
@@ -363,8 +368,8 @@ function CountrySelect() {
|
|
|
363
368
|
### Form Integration
|
|
364
369
|
|
|
365
370
|
```typescript
|
|
366
|
-
import { Form } from '
|
|
367
|
-
import { Label } from '
|
|
371
|
+
import { Form } from '@/components/Form'
|
|
372
|
+
import { Label } from '@/components/Label'
|
|
368
373
|
|
|
369
374
|
function FormSelect() {
|
|
370
375
|
const [formData, setFormData] = useState({
|
|
@@ -464,7 +469,7 @@ function DynamicSelect() {
|
|
|
464
469
|
|
|
465
470
|
```typescript
|
|
466
471
|
import { render, screen, fireEvent } from '@testing-library/react'
|
|
467
|
-
import { Select, SelectTrigger, SelectContent, SelectItem, SelectValue } from '
|
|
472
|
+
import { Select, SelectTrigger, SelectContent, SelectItem, SelectValue } from '@/components/Select'
|
|
468
473
|
|
|
469
474
|
describe('Select', () => {
|
|
470
475
|
it('opens dropdown on trigger click', () => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: SimpleSelect
|
|
3
|
-
version:
|
|
3
|
+
version: 2.4.0
|
|
4
4
|
status: stable
|
|
5
5
|
category: components/forms
|
|
6
6
|
tags: [form, select, dropdown, custom, system-style, accessible]
|
|
@@ -17,18 +17,22 @@ dependencies:
|
|
|
17
17
|
|
|
18
18
|
## Installation
|
|
19
19
|
|
|
20
|
+
TORCH Glare is a copy-in library: the CLI copies this component's source into your project
|
|
21
|
+
(you do **not** install it from the npm package). Run `init` once, then `add`:
|
|
22
|
+
|
|
20
23
|
```bash
|
|
21
|
-
|
|
24
|
+
npx torch-glare@latest init
|
|
25
|
+
npx torch-glare@latest add SimpleSelect
|
|
22
26
|
```
|
|
23
27
|
|
|
28
|
+
`add` also copies any components, hooks, and utilities that `SimpleSelect` depends on.
|
|
29
|
+
|
|
24
30
|
## Import
|
|
25
31
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
SimpleSelectDropDown
|
|
31
|
-
} from 'torch-glare/lib/components/SimpleSelect'
|
|
32
|
+
Import from your project's local path — the alias configured in `glare.json` (e.g. `@/*`):
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
import { SimpleSelect } from "@/components/SimpleSelect";
|
|
32
36
|
```
|
|
33
37
|
|
|
34
38
|
## Quick Examples
|
|
@@ -36,7 +40,7 @@ import {
|
|
|
36
40
|
### Basic Usage
|
|
37
41
|
|
|
38
42
|
```typescript
|
|
39
|
-
import { SimpleSelectValue, SimpleSelectItem } from '
|
|
43
|
+
import { SimpleSelectValue, SimpleSelectItem } from '@/components/SimpleSelect'
|
|
40
44
|
|
|
41
45
|
function Example() {
|
|
42
46
|
const [value, setValue] = useState('option1')
|
|
@@ -470,7 +474,7 @@ function DynamicSelect() {
|
|
|
470
474
|
|
|
471
475
|
```typescript
|
|
472
476
|
import { render, screen, fireEvent } from '@testing-library/react'
|
|
473
|
-
import { SimpleSelectValue, SimpleSelectItem } from '
|
|
477
|
+
import { SimpleSelectValue, SimpleSelectItem } from '@/components/SimpleSelect'
|
|
474
478
|
|
|
475
479
|
describe('SimpleSelect', () => {
|
|
476
480
|
it('opens dropdown on click', () => {
|