treege 3.0.0-beta.9 → 3.0.0-beta.91
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/LICENSE +18 -12
- package/README.md +598 -79
- package/dist/DefaultSubmitButton-NeSDqyzv.js +1909 -0
- package/dist/ThemeContext-CPsC8QIP.js +1008 -0
- package/dist/editor/components/input/ComboboxWithCreate.d.ts +2 -1
- package/dist/editor/components/styles/EditorStyles.d.ts +2 -0
- package/dist/editor/constants/defaultNode.d.ts +1 -1
- package/dist/editor/constants/edgeTypes.d.ts +3 -2
- package/dist/editor/constants/inputTypeIcons.d.ts +3 -0
- package/dist/editor/constants/nodeSpacing.d.ts +25 -0
- package/dist/editor/constants/nodeTypes.d.ts +4 -5
- package/dist/editor/context/OpenApiContext.d.ts +79 -0
- package/dist/editor/context/TreegeEditorRuntimeProvider.d.ts +78 -0
- package/dist/editor/features/TreegeEditor/TreegeEditor.d.ts +1 -1
- package/dist/editor/features/TreegeEditor/controls/MiniMapControl.d.ts +6 -0
- package/dist/editor/features/TreegeEditor/dialogs/AuthorizeDialog.d.ts +20 -0
- package/dist/editor/features/TreegeEditor/dialogs/ChangeNodeTypeDialog.d.ts +2 -0
- package/dist/editor/features/TreegeEditor/dialogs/DeleteNodeDialog.d.ts +2 -0
- package/dist/editor/features/TreegeEditor/dialogs/HeadersDialog.d.ts +19 -0
- package/dist/editor/features/TreegeEditor/dialogs/OpenApiDialog.d.ts +6 -0
- package/dist/editor/features/TreegeEditor/edges/ConditionalEdge.d.ts +2 -2
- package/dist/editor/features/TreegeEditor/edges/DefaultEdge.d.ts +3 -0
- package/dist/editor/features/TreegeEditor/forms/HttpConfigForm.d.ts +4 -1
- package/dist/editor/features/TreegeEditor/forms/JsonTemplateEditor.d.ts +13 -0
- package/dist/editor/features/TreegeEditor/forms/OptionsMappingFields.d.ts +34 -0
- package/dist/editor/features/TreegeEditor/forms/OptionsSourceForm.d.ts +7 -0
- package/dist/editor/features/TreegeEditor/forms/SensitiveHeaderWarning.d.ts +13 -0
- package/dist/editor/features/TreegeEditor/forms/SubmitConfigForm.d.ts +7 -0
- package/dist/editor/features/TreegeEditor/inputs/ApiUrlCombobox.d.ts +20 -0
- package/dist/editor/features/TreegeEditor/inputs/ComboboxPattern.d.ts +2 -1
- package/dist/editor/features/TreegeEditor/inputs/DefaultFileValueField.d.ts +14 -0
- package/dist/editor/features/TreegeEditor/inputs/OptionImageField.d.ts +6 -0
- package/dist/editor/features/TreegeEditor/inputs/SelectNodeGroup.d.ts +22 -1
- package/dist/editor/features/TreegeEditor/inputs/TranslatableInput.d.ts +20 -0
- package/dist/editor/features/TreegeEditor/layout/AutoLayout.d.ts +15 -0
- package/dist/editor/features/TreegeEditor/listeners/FlowChangeEmitter.d.ts +19 -0
- package/dist/editor/features/TreegeEditor/nodes/TreegeNode.d.ts +5 -0
- package/dist/editor/features/TreegeEditor/nodes/components/BottomHandleDropdown.d.ts +25 -0
- package/dist/editor/features/TreegeEditor/nodes/components/NodeGroupBadge.d.ts +6 -0
- package/dist/editor/features/TreegeEditor/nodes/components/NodeImage.d.ts +5 -0
- package/dist/editor/features/TreegeEditor/nodes/components/NodeImageButton.d.ts +6 -0
- package/dist/editor/features/TreegeEditor/nodes/components/NodeInputPreview.d.ts +12 -0
- package/dist/editor/features/TreegeEditor/nodes/components/NodeLabelInput.d.ts +10 -0
- package/dist/editor/features/TreegeEditor/nodes/components/NodeMoreMenu.d.ts +6 -0
- package/dist/editor/features/TreegeEditor/nodes/components/NodeRequiredButton.d.ts +6 -0
- package/dist/editor/features/TreegeEditor/nodes/components/NodeStackOrderButtons.d.ts +6 -0
- package/dist/editor/features/TreegeEditor/nodes/components/NodeTypeBadge.d.ts +7 -0
- package/dist/editor/features/TreegeEditor/nodes/components/NodeTypePickerMenuContent.d.ts +12 -0
- package/dist/editor/features/TreegeEditor/nodes/layout/NodeWrapper.d.ts +4 -2
- package/dist/editor/features/TreegeEditor/panel/AIGeneratorDialog.d.ts +16 -0
- package/dist/editor/features/TreegeEditor/panel/ActionsPanel.d.ts +7 -2
- package/dist/editor/features/TreegeEditor/panel/MultiSelectionPanel.d.ts +7 -0
- package/dist/editor/hooks/useAvailableParentFields.d.ts +13 -0
- package/dist/editor/hooks/useFlowActions.d.ts +6 -2
- package/dist/editor/hooks/useFlowConnections.d.ts +14 -0
- package/dist/editor/hooks/useFlowContent.d.ts +16 -0
- package/dist/editor/hooks/useHistoryStore.d.ts +26 -0
- package/dist/editor/hooks/useIsStackedEdge.d.ts +8 -0
- package/dist/editor/hooks/useKeyValueRows.d.ts +15 -0
- package/dist/editor/hooks/useNodesSelection.d.ts +5 -5
- package/dist/editor/hooks/useStackPosition.d.ts +14 -0
- package/dist/editor/hooks/useTranslate.d.ts +1 -1
- package/dist/editor/hooks/useUndoRedo.d.ts +31 -0
- package/dist/editor/types/ai.d.ts +65 -0
- package/dist/editor/types/editor.d.ts +106 -10
- package/dist/editor/types/openapi.d.ts +106 -0
- package/dist/editor/utils/aiFlowGenerator.d.ts +5 -0
- package/dist/editor/utils/cleanEmptyData.d.ts +18 -0
- package/dist/editor/utils/cleanNodeConfig.d.ts +5 -0
- package/dist/editor/utils/dagreLayout.d.ts +8 -0
- package/dist/editor/utils/edge.d.ts +50 -0
- package/dist/editor/utils/groupColor.d.ts +14 -0
- package/dist/editor/utils/image.d.ts +7 -0
- package/dist/editor/utils/inputTypeIcon.d.ts +6 -0
- package/dist/editor/utils/jsonBindTarget.d.ts +15 -0
- package/dist/editor/utils/openApiPayload.d.ts +12 -0
- package/dist/editor/utils/openapi.d.ts +35 -0
- package/dist/editor/utils/sensitiveHeaders.d.ts +20 -0
- package/dist/editor/utils/stackPositionIndex.d.ts +9 -0
- package/dist/editor-DJbNgLSF.js +6485 -0
- package/dist/editor.js +3 -7
- package/dist/main.js +6 -52
- package/dist/renderer/context/TreegeRenderRuntimeProvider.d.ts +135 -0
- package/dist/renderer/context/TreegeRendererProvider.d.ts +15 -0
- package/dist/renderer/context/TreegeViewerProvider.d.ts +28 -0
- package/dist/renderer/features/TreegeRenderer/native/TreegeRenderer.d.ts +19 -11
- package/dist/renderer/features/TreegeRenderer/native/components/DefaultFormWrapper.d.ts +7 -7
- package/dist/renderer/features/TreegeRenderer/native/components/DefaultInputLabel.d.ts +10 -0
- package/dist/renderer/features/TreegeRenderer/native/components/DefaultInputWrapper.d.ts +9 -0
- package/dist/renderer/features/TreegeRenderer/native/components/DefaultInputs.d.ts +20 -15
- package/dist/renderer/features/TreegeRenderer/native/components/DefaultLoadingSkeleton.d.ts +8 -0
- package/dist/renderer/features/TreegeRenderer/native/components/DefaultStep.d.ts +3 -0
- package/dist/renderer/features/TreegeRenderer/native/components/DefaultSubmitButton.d.ts +9 -7
- package/dist/renderer/features/TreegeRenderer/native/components/DefaultSubmitButtonWrapper.d.ts +11 -0
- package/dist/renderer/features/TreegeRenderer/native/components/DefaultUI.d.ts +8 -7
- package/dist/renderer/features/TreegeRenderer/native/components/DependencyHint.d.ts +15 -0
- package/dist/renderer/features/TreegeRenderer/native/components/OptionItemContent.d.ts +17 -0
- package/dist/renderer/features/TreegeRenderer/native/components/inputs/DefaultAddressInput.d.ts +3 -0
- package/dist/renderer/features/TreegeRenderer/native/components/inputs/DefaultAutocompleteInput.d.ts +3 -0
- package/dist/renderer/features/TreegeRenderer/native/components/inputs/DefaultCheckboxInput.d.ts +3 -0
- package/dist/renderer/features/TreegeRenderer/native/components/inputs/DefaultDateInput.d.ts +3 -0
- package/dist/renderer/features/TreegeRenderer/native/components/inputs/DefaultDateRangeInput.d.ts +3 -0
- package/dist/renderer/features/TreegeRenderer/native/components/inputs/DefaultFileInput.d.ts +3 -0
- package/dist/renderer/features/TreegeRenderer/native/components/inputs/DefaultHiddenInput.d.ts +3 -0
- package/dist/renderer/features/TreegeRenderer/native/components/inputs/DefaultHttpInput.d.ts +3 -0
- package/dist/renderer/features/TreegeRenderer/native/components/inputs/DefaultNumberInput.d.ts +3 -0
- package/dist/renderer/features/TreegeRenderer/native/components/inputs/DefaultPasswordInput.d.ts +3 -0
- package/dist/renderer/features/TreegeRenderer/native/components/inputs/DefaultRadioInput.d.ts +3 -0
- package/dist/renderer/features/TreegeRenderer/native/components/inputs/DefaultSelectInput.d.ts +3 -0
- package/dist/renderer/features/TreegeRenderer/native/components/inputs/DefaultSubmitInput.d.ts +11 -0
- package/dist/renderer/features/TreegeRenderer/native/components/inputs/DefaultSwitchInput.d.ts +3 -0
- package/dist/renderer/features/TreegeRenderer/native/components/inputs/DefaultTextInput.d.ts +3 -0
- package/dist/renderer/features/TreegeRenderer/native/components/inputs/DefaultTextareaInput.d.ts +3 -0
- package/dist/renderer/features/TreegeRenderer/native/components/inputs/DefaultTimeInput.d.ts +3 -0
- package/dist/renderer/features/TreegeRenderer/native/components/inputs/DefaultTimeRangeInput.d.ts +3 -0
- package/dist/renderer/features/TreegeRenderer/useTreegeRenderer.d.ts +97 -24
- package/dist/renderer/features/TreegeRenderer/web/TreegeRenderer.d.ts +1 -1
- package/dist/renderer/features/TreegeRenderer/web/components/DefaultFormWrapper.d.ts +3 -2
- package/dist/renderer/features/TreegeRenderer/web/components/DefaultInputLabel.d.ts +9 -0
- package/dist/renderer/features/TreegeRenderer/web/components/DefaultInputWrapper.d.ts +9 -0
- package/dist/renderer/features/TreegeRenderer/web/components/DefaultLoadingSkeleton.d.ts +7 -0
- package/dist/renderer/features/TreegeRenderer/web/components/DefaultStep.d.ts +3 -0
- package/dist/renderer/features/TreegeRenderer/web/components/DefaultSubmitButton.d.ts +5 -1
- package/dist/renderer/features/TreegeRenderer/web/components/DependencyHint.d.ts +22 -0
- package/dist/renderer/features/TreegeRenderer/web/components/OptionItemContent.d.ts +17 -0
- package/dist/renderer/features/TreegeRenderer/web/components/inputs/DefaultAddressInput.d.ts +1 -1
- package/dist/renderer/features/TreegeRenderer/web/components/inputs/DefaultAutocompleteInput.d.ts +1 -1
- package/dist/renderer/features/TreegeRenderer/web/components/inputs/DefaultCheckboxInput.d.ts +1 -1
- package/dist/renderer/features/TreegeRenderer/web/components/inputs/DefaultDateInput.d.ts +1 -1
- package/dist/renderer/features/TreegeRenderer/web/components/inputs/DefaultDateRangeInput.d.ts +1 -1
- package/dist/renderer/features/TreegeRenderer/web/components/inputs/DefaultFileInput.d.ts +1 -1
- package/dist/renderer/features/TreegeRenderer/web/components/inputs/DefaultHiddenInput.d.ts +1 -1
- package/dist/renderer/features/TreegeRenderer/web/components/inputs/DefaultHttpInput.d.ts +1 -1
- package/dist/renderer/features/TreegeRenderer/web/components/inputs/DefaultNumberInput.d.ts +1 -1
- package/dist/renderer/features/TreegeRenderer/web/components/inputs/DefaultPasswordInput.d.ts +1 -1
- package/dist/renderer/features/TreegeRenderer/web/components/inputs/DefaultRadioInput.d.ts +1 -1
- package/dist/renderer/features/TreegeRenderer/web/components/inputs/DefaultSelectInput.d.ts +1 -1
- package/dist/renderer/features/TreegeRenderer/web/components/inputs/DefaultSubmitInput.d.ts +11 -0
- package/dist/renderer/features/TreegeRenderer/web/components/inputs/DefaultSwitchInput.d.ts +1 -1
- package/dist/renderer/features/TreegeRenderer/web/components/inputs/DefaultTextAreaInput.d.ts +1 -1
- package/dist/renderer/features/TreegeRenderer/web/components/inputs/DefaultTextInput.d.ts +1 -1
- package/dist/renderer/features/TreegeRenderer/web/components/inputs/DefaultTimeInput.d.ts +1 -1
- package/dist/renderer/features/TreegeRenderer/web/components/inputs/DefaultTimeRangeInput.d.ts +1 -1
- package/dist/renderer/features/TreegeRenderer/web/components/styles/RendererStyles.d.ts +2 -0
- package/dist/renderer/features/TreegeViewer/utils/viewerFields.d.ts +102 -0
- package/dist/renderer/features/TreegeViewer/web/TreegeViewer.d.ts +94 -0
- package/dist/renderer/hooks/useInputOptions.d.ts +28 -0
- package/dist/renderer/hooks/useRenderNode.d.ts +62 -0
- package/dist/renderer/hooks/useSubmitHandler.d.ts +37 -0
- package/dist/renderer/hooks/useTranslate.d.ts +7 -5
- package/dist/renderer/index.d.ts +10 -2
- package/dist/renderer/index.native.d.ts +20 -0
- package/dist/renderer/types/renderer.d.ts +332 -49
- package/dist/renderer/utils/extraPayload.d.ts +21 -0
- package/dist/renderer/utils/file.d.ts +24 -10
- package/dist/renderer/utils/flow.d.ts +1 -18
- package/dist/renderer/utils/form.d.ts +54 -2
- package/dist/renderer/utils/http.d.ts +177 -0
- package/dist/renderer/utils/jsonTemplate.d.ts +30 -0
- package/dist/renderer/utils/node.d.ts +29 -1
- package/dist/renderer/utils/sanitize.d.ts +85 -0
- package/dist/renderer/utils/sanitize.native.d.ts +69 -0
- package/dist/renderer/utils/step.d.ts +27 -0
- package/dist/renderer/utils/submit.d.ts +50 -0
- package/dist/renderer/utils/templateDependencies.d.ts +17 -0
- package/dist/renderer-CNbSt_QW.js +446 -0
- package/dist/renderer-native.d.ts +2 -0
- package/dist/renderer-native.js +3696 -0
- package/dist/renderer.js +5 -45
- package/dist/shared/components/ui/badge.d.ts +2 -2
- package/dist/shared/components/ui/button.d.ts +3 -3
- package/dist/shared/components/ui/collapsible.d.ts +1 -1
- package/dist/shared/components/ui/command.d.ts +1 -1
- package/dist/shared/components/ui/dropdown-menu.d.ts +1 -1
- package/dist/shared/components/ui/field.d.ts +24 -0
- package/dist/shared/components/ui/form.d.ts +1 -1
- package/dist/shared/components/ui/item.d.ts +23 -0
- package/dist/shared/components/ui/popover.d.ts +10 -2
- package/dist/shared/components/ui/select.d.ts +3 -1
- package/dist/shared/components/ui/sheet.d.ts +1 -1
- package/dist/shared/components/ui/skeleton.d.ts +3 -0
- package/dist/shared/components/ui/toggle-group.d.ts +7 -0
- package/dist/shared/components/ui/toggle.d.ts +9 -0
- package/dist/shared/components/ui/tooltip.d.ts +1 -1
- package/dist/shared/constants/colors.d.ts +45 -0
- package/dist/shared/constants/inputType.d.ts +6 -0
- package/dist/shared/constants/node.d.ts +0 -1
- package/dist/shared/context/PortalContainerContext.d.ts +5 -0
- package/dist/shared/context/ThemeContext.d.ts +2 -0
- package/dist/shared/context/ThemeContext.native.d.ts +22 -0
- package/dist/shared/hooks/useMediaQuery.d.ts +12 -0
- package/dist/shared/hooks/useThemeColors.d.ts +37 -0
- package/dist/shared/locales/ar.json.d.ts +259 -19
- package/dist/shared/locales/de.json.d.ts +260 -20
- package/dist/shared/locales/en.json.d.ts +261 -21
- package/dist/shared/locales/es.json.d.ts +260 -20
- package/dist/shared/locales/fr.json.d.ts +260 -20
- package/dist/shared/locales/it.json.d.ts +260 -20
- package/dist/shared/locales/pt.json.d.ts +260 -20
- package/dist/shared/types/edge.d.ts +6 -0
- package/dist/shared/types/file.d.ts +14 -0
- package/dist/shared/types/node.d.ts +155 -19
- package/dist/shared/utils/httpRecord.d.ts +20 -0
- package/dist/shared/utils/inputTypeGuards.d.ts +7 -0
- package/dist/shared/utils/nodeTypeGuards.d.ts +1 -6
- package/dist/shared/utils/normalizeLabel.d.ts +22 -0
- package/dist/shared/utils/translations.d.ts +21 -1
- package/dist/useRenderNode-CG466pNk.js +538 -0
- package/package.json +54 -22
- package/dist/ThemeContext-BIvs8Kw-.js +0 -758
- package/dist/TreegeEditor-Lv5Tn9_F.js +0 -2152
- package/dist/TreegeRenderer-BVaqgInZ.js +0 -1405
- package/dist/editor/context/TreegeEditorContext.d.ts +0 -12
- package/dist/editor/features/TreegeEditor/forms/FlowNodeForm.d.ts +0 -2
- package/dist/editor/features/TreegeEditor/inputs/SelectInputType.d.ts +0 -7
- package/dist/editor/features/TreegeEditor/nodes/FlowNode.d.ts +0 -6
- package/dist/editor/features/TreegeEditor/nodes/GroupNode.d.ts +0 -6
- package/dist/editor/features/TreegeEditor/nodes/InputNode.d.ts +0 -6
- package/dist/editor/features/TreegeEditor/nodes/UINode.d.ts +0 -6
- package/dist/editor/hooks/useEdgesSelection.d.ts +0 -11
- package/dist/renderer/context/TreegeConfigContext.d.ts +0 -39
- package/dist/renderer/context/TreegeRendererContext.d.ts +0 -25
- package/dist/renderer/features/TreegeRenderer/native/components/DefaultGroup.d.ts +0 -7
- package/dist/renderer/features/TreegeRenderer/web/components/DefaultGroup.d.ts +0 -6
- /package/dist/editor/components/{data-display/logo.d.ts → branding/Logo.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
<img alt="Treege" src="https://user-images.githubusercontent.com/108873902/189673125-5d1fdaf3-82d1-486f-bb16-01b0554bd4f1.png" style="padding: 20px;" width="auto" height="100" />
|
|
3
3
|
|
|
4
4
|
<h1>Treege</h1>
|
|
5
|
-
<p><strong>
|
|
5
|
+
<p><strong>Building complex, dynamic forms has never been this simple</strong></p>
|
|
6
6
|
|
|
7
7
|
[](https://badge.fury.io/js/treege)
|
|
8
|
-
[](https://opensource.org/licenses/MIT)
|
|
9
9
|
|
|
10
10
|
<p>
|
|
11
11
|
<a href="https://treege.io/">🌐 Website</a> •
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
<a href="#features">Features</a> •
|
|
14
14
|
<a href="#installation">Installation</a> •
|
|
15
15
|
<a href="#quick-start">Quick Start</a> •
|
|
16
|
-
<a href="#examples">Examples</a>
|
|
16
|
+
<a href="#examples">Examples</a> •
|
|
17
|
+
<a href="./AI_GENERATION.md">🪄 AI Generation</a>
|
|
17
18
|
</p>
|
|
18
19
|
</div>
|
|
19
20
|
|
|
@@ -21,14 +22,15 @@
|
|
|
21
22
|
|
|
22
23
|
## Overview
|
|
23
24
|
|
|
24
|
-
Treege is a modern React library for creating and rendering interactive decision trees. Built on top of ReactFlow, it provides a complete solution for building complex form
|
|
25
|
+
Treege is a modern React library for creating and rendering interactive decision trees. Built on top of ReactFlow, it provides a complete solution for building complex form flow, decision logic, and conditional workflows with an intuitive visual editor.
|
|
25
26
|
|
|
26
27
|
## Features
|
|
27
28
|
|
|
28
29
|
### Visual Editor (`treege/editor`)
|
|
29
30
|
- **Node-based Interface**: Drag-and-drop editor powered by ReactFlow
|
|
30
|
-
- **
|
|
31
|
+
- **3 Node Types**: Input, UI, and Group nodes
|
|
31
32
|
- **Conditional Edges**: Advanced logic with AND/OR operators (`===`, `!==`, `>`, `<`, `>=`, `<=`)
|
|
33
|
+
- **AI-Powered Generation**: Generate decision trees from natural language descriptions using Gemini, OpenAI, DeepSeek, or Claude ([Learn more](./AI_GENERATION.md))
|
|
32
34
|
- **Multi-language Support**: Built-in translation system for all labels
|
|
33
35
|
- **Type-safe**: Full TypeScript support
|
|
34
36
|
- **Mini-map & Controls**: Navigation tools for complex trees
|
|
@@ -37,13 +39,21 @@ Treege is a modern React library for creating and rendering interactive decision
|
|
|
37
39
|
### Runtime Renderer (`treege/renderer`)
|
|
38
40
|
- **Production Ready**: Full-featured form generation and validation system
|
|
39
41
|
- **16 Input Types**: text, number, select, checkbox, radio, date, daterange, time, timerange, file, address, http, textarea, password, switch, autocomplete, and hidden
|
|
42
|
+
- **Cross-Platform**: Full support for both React Web and React Native with dedicated implementations
|
|
40
43
|
- **HTTP Integration**: Built-in API integration with response mapping and search functionality
|
|
41
44
|
- **Advanced Validation**: Required fields, pattern matching, custom validation functions
|
|
45
|
+
- **Security**: Built-in input sanitization to prevent XSS attacks
|
|
46
|
+
- **Enhanced Error Messages**: Clear, user-friendly error messages for HTTP inputs and validation
|
|
42
47
|
- **Conditional Logic**: Dynamic field visibility based on user input and conditional edges
|
|
43
|
-
- **
|
|
44
|
-
- **
|
|
48
|
+
- **Multi-Step Forms**: Group nodes are automatically turned into navigable steps with Back/Continue controls, an `onBack` bridge to outer flows, and external-button submission via `formId`
|
|
49
|
+
- **Edit Mode**: Pre-fill with `initialValues` (accepts name keys, reactive) to round-trip and edit previously submitted records
|
|
50
|
+
- **Host Data Injection**: Attach app-owned fields (e.g. a user id) to every submission with `extraPayload` — merged into both the `onSubmit` payload and the HTTP submit body
|
|
51
|
+
- **Loading State**: Built-in `isLoading` prop renders a customizable skeleton while the flow is being fetched, plus `isSubmitting` to drive the button's loading state from async submits
|
|
52
|
+
- **Fully Customizable**: Override any component (form, inputs, inputLabel, ui, step, submitButton, submitButtonWrapper, loadingSkeleton)
|
|
53
|
+
- **Optional Dependencies**: Graceful degradation when optional packages like `react-native-document-picker` aren't installed
|
|
45
54
|
- **Theme Support**: Dark/light mode out of the box
|
|
46
55
|
- **Google API Integration**: Address autocomplete support
|
|
56
|
+
- **Read-Only Viewer**: `TreegeViewer` renders a submitted flow as a label/value recap — same branch-visibility and formatting as the form, works with or without a flow (self-describing values), supports collapse, with a headless `getViewerFields` core for custom layouts
|
|
47
57
|
|
|
48
58
|
### Developer Experience
|
|
49
59
|
- **Modular**: Import only what you need (editor, renderer, or both)
|
|
@@ -54,6 +64,9 @@ Treege is a modern React library for creating and rendering interactive decision
|
|
|
54
64
|
## Installation
|
|
55
65
|
|
|
56
66
|
```bash
|
|
67
|
+
# bun
|
|
68
|
+
bun add treege
|
|
69
|
+
|
|
57
70
|
# npm
|
|
58
71
|
npm install treege
|
|
59
72
|
|
|
@@ -62,9 +75,6 @@ pnpm add treege
|
|
|
62
75
|
|
|
63
76
|
# yarn
|
|
64
77
|
yarn add treege
|
|
65
|
-
|
|
66
|
-
# bun
|
|
67
|
-
bun add treege
|
|
68
78
|
```
|
|
69
79
|
|
|
70
80
|
## Quick Start
|
|
@@ -125,7 +135,7 @@ function App() {
|
|
|
125
135
|
|
|
126
136
|
return (
|
|
127
137
|
<TreegeRenderer
|
|
128
|
-
|
|
138
|
+
flow={flow}
|
|
129
139
|
onSubmit={handleSubmit}
|
|
130
140
|
/>
|
|
131
141
|
);
|
|
@@ -152,16 +162,136 @@ function App() {
|
|
|
152
162
|
{mode === "edit" ? (
|
|
153
163
|
<TreegeEditor flow={flow} onSave={setFlow} />
|
|
154
164
|
) : (
|
|
155
|
-
<TreegeRenderer
|
|
165
|
+
<TreegeRenderer flow={flow} onSubmit={console.log} />
|
|
156
166
|
)}
|
|
157
167
|
</div>
|
|
158
168
|
);
|
|
159
169
|
}
|
|
160
170
|
```
|
|
161
171
|
|
|
172
|
+
### Live Preview (Editor → Renderer)
|
|
173
|
+
|
|
174
|
+
Use the editor's `onChange` (debounced) to render the form **live** next to the editor — no Save click needed. Because `onChange` isn't gated on having input nodes, the preview also reflects an emptied canvas after Clear. Omit `onSave` to hide the Save button entirely when you rely solely on live updates:
|
|
175
|
+
|
|
176
|
+
```tsx
|
|
177
|
+
import { TreegeEditor } from "treege/editor";
|
|
178
|
+
import { TreegeRenderer } from "treege/renderer";
|
|
179
|
+
import { useState } from "react";
|
|
180
|
+
import type { Flow } from "treege";
|
|
181
|
+
|
|
182
|
+
function App() {
|
|
183
|
+
const [flow, setFlow] = useState<Flow | null>(null);
|
|
184
|
+
|
|
185
|
+
return (
|
|
186
|
+
<div style={{ display: "flex" }}>
|
|
187
|
+
<TreegeEditor onChange={setFlow} /> {/* live, no Save button */}
|
|
188
|
+
<TreegeRenderer flow={flow} onSubmit={console.log} />
|
|
189
|
+
</div>
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Read-Only Viewer (`TreegeViewer`)
|
|
195
|
+
|
|
196
|
+
Once a form has been submitted, `TreegeViewer` renders the result as a read-only **label / value recap** — no inputs, no validation. With a `flow` it replays the submitted `flowResponse` through the renderer's branch-visibility logic, so only the fields that were actually reachable for those values are shown. Option values resolve to their labels, dates/ranges and i18n labels are formatted exactly like the form, and `hidden`/`submit` fields are excluded.
|
|
197
|
+
|
|
198
|
+
```tsx
|
|
199
|
+
import { TreegeRenderer, TreegeViewer } from "treege/renderer";
|
|
200
|
+
import { useState } from "react";
|
|
201
|
+
import type { Flow, FormValues } from "treege";
|
|
202
|
+
|
|
203
|
+
function App({ flow }: { flow: Flow }) {
|
|
204
|
+
const [submitted, setSubmitted] = useState<FormValues | null>(null);
|
|
205
|
+
|
|
206
|
+
if (submitted) {
|
|
207
|
+
return <TreegeViewer flow={flow} flowResponse={submitted} language="en" />;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return <TreegeRenderer flow={flow} onSubmit={setSubmitted} />;
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Without a flow
|
|
215
|
+
|
|
216
|
+
When you only have stored, self-describing values (e.g. a persisted `WorkflowValue[]`) and no flow definition, omit `flow` and pass them as `flowResponse`. Each entry carries its own `{ name, type, value, label }`, so values are still formatted by type. `flowResponse` is **typed conditionally on `flow`**: with a flow it's `FormValues`, without a flow it's `FlowResponseEntry[]`.
|
|
217
|
+
|
|
218
|
+
```tsx
|
|
219
|
+
<TreegeViewer
|
|
220
|
+
flowResponse={[
|
|
221
|
+
{ name: "city", type: "text", value: "Paris", label: { en: "City" } },
|
|
222
|
+
{ name: "dates", type: "daterange", value: "2026-06-01,2026-07-15", label: { en: "Dates" } },
|
|
223
|
+
]}
|
|
224
|
+
/>
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Props
|
|
228
|
+
|
|
229
|
+
| Prop | Type | Default | Description |
|
|
230
|
+
|-------------------------|------------------------------------------------------------------|-------------------------|---------------------------------------------------------------------------------------------------|
|
|
231
|
+
| `flow` | `Flow` | - | The flow the values were submitted against (omit for flow-less mode) |
|
|
232
|
+
| `flowResponse` | `FormValues` *(with `flow`)* / `FlowResponseEntry[]` *(without)* | - | The submitted values — type is conditional on `flow` |
|
|
233
|
+
| `language` | `string` | provider, then `"en"` | Language used to resolve translatable labels/options |
|
|
234
|
+
| `theme` | `"light" \| "dark"` | provider, then `"dark"` | Light/dark theme (falls back to the `TreegeRendererProvider` config) |
|
|
235
|
+
| `baseUrl` | `string` | - | Resolves relative file paths into absolute URLs; `data:`/`blob:`/absolute URLs are left untouched |
|
|
236
|
+
| `excludedFields` | `string[]` | - | Field names (or ids) to hide from the view |
|
|
237
|
+
| `excludeEmptyFields` | `boolean` | `false` | Hide fields that have no submitted value (instead of showing `emptyText`) |
|
|
238
|
+
| `collapsed` | `boolean` | `false` | When `true`, only the first `collapsedVisibleCount` fields are rendered |
|
|
239
|
+
| `collapsedVisibleCount` | `number` | - | Number of fields kept visible while `collapsed` (defaults to all) |
|
|
240
|
+
| `emptyText` | `string` | `"—"` | Text shown when a field has no submitted value |
|
|
241
|
+
| `className` | `string` | - | Extra class names on the root element |
|
|
242
|
+
| `renderField` | `Partial<Record<InputType, (field) => ReactNode>>` | - | Per-type rendering overrides for the value cell (typically `file`) |
|
|
243
|
+
| `renderRow` | `(field, defaultRow) => ReactNode` | - | Wrap or replace a whole field row (label + value) |
|
|
244
|
+
|
|
245
|
+
### Collapse
|
|
246
|
+
|
|
247
|
+
`collapsed` + `collapsedVisibleCount` are controlled — you render the toggle and own the state. While collapsed, only the first N fields show:
|
|
248
|
+
|
|
249
|
+
```tsx
|
|
250
|
+
const [collapsed, setCollapsed] = useState(true);
|
|
251
|
+
|
|
252
|
+
<>
|
|
253
|
+
<button onClick={() => setCollapsed((c) => !c)}>{collapsed ? "Show all" : "Show less"}</button>
|
|
254
|
+
<TreegeViewer flow={flow} flowResponse={submitted} collapsed={collapsed} collapsedVisibleCount={3} />
|
|
255
|
+
</>
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Customizing rendering
|
|
259
|
+
|
|
260
|
+
Use `renderField` to override the value cell for a specific input type — most often `file`, to render thumbnails from your own storage — while every other type keeps its built-in rendering. Use `renderRow` to control the whole row layout (label + value):
|
|
261
|
+
|
|
262
|
+
```tsx
|
|
263
|
+
<TreegeViewer
|
|
264
|
+
flow={flow}
|
|
265
|
+
flowResponse={submitted}
|
|
266
|
+
language="fr"
|
|
267
|
+
excludedFields={["internalNote"]}
|
|
268
|
+
renderField={{ file: ({ rawValue }) => <Thumbnails files={rawValue} /> }}
|
|
269
|
+
/>
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Headless usage
|
|
273
|
+
|
|
274
|
+
`TreegeViewer` is a thin layer over two field builders that return the ordered, display-ready fields — use them directly for a fully custom layout (a table, a PDF, columns…):
|
|
275
|
+
|
|
276
|
+
- `getViewerFields(flow, values, { language, baseUrl })` — flow-based resolution.
|
|
277
|
+
- `viewerFieldsFromResponse(response, { language })` — flow-less, from self-describing entries.
|
|
278
|
+
|
|
279
|
+
```tsx
|
|
280
|
+
import { getViewerFields } from "treege/renderer";
|
|
281
|
+
|
|
282
|
+
const fields = getViewerFields(flow, values, { language: "en", baseUrl });
|
|
283
|
+
|
|
284
|
+
fields.forEach((field) => {
|
|
285
|
+
// field.label, field.type, field.rawValue
|
|
286
|
+
// field.display — normalized, render-ready value:
|
|
287
|
+
// { kind: "text", text } | { kind: "boolean", checked }
|
|
288
|
+
// { kind: "tags", tags } | { kind: "files", files } | { kind: "empty" }
|
|
289
|
+
});
|
|
290
|
+
```
|
|
291
|
+
|
|
162
292
|
## Module Structure
|
|
163
293
|
|
|
164
|
-
Treege provides
|
|
294
|
+
Treege provides multiple import paths for optimal bundle size:
|
|
165
295
|
|
|
166
296
|
```tsx
|
|
167
297
|
// Import everything (editor + renderer + types)
|
|
@@ -170,25 +300,188 @@ import { TreegeEditor, TreegeRenderer } from "treege";
|
|
|
170
300
|
// Import only the editor
|
|
171
301
|
import { TreegeEditor } from "treege/editor";
|
|
172
302
|
|
|
173
|
-
// Import only the renderer
|
|
303
|
+
// Import only the web renderer
|
|
174
304
|
import { TreegeRenderer } from "treege/renderer";
|
|
305
|
+
|
|
306
|
+
// Import only the React Native renderer
|
|
307
|
+
import { TreegeRenderer } from "treege/renderer-native";
|
|
175
308
|
```
|
|
176
309
|
|
|
177
|
-
##
|
|
310
|
+
## React Native Support
|
|
311
|
+
|
|
312
|
+
Treege 3.0 includes full React Native support with a dedicated renderer implementation.
|
|
313
|
+
|
|
314
|
+
### Installation for React Native
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
# Install Treege
|
|
318
|
+
npm install treege
|
|
319
|
+
|
|
320
|
+
# Install peer dependencies
|
|
321
|
+
npm install react-native
|
|
322
|
+
|
|
323
|
+
# Optional: Install for file input support
|
|
324
|
+
npm install react-native-document-picker
|
|
325
|
+
```
|
|
178
326
|
|
|
179
|
-
###
|
|
180
|
-
Navigation node that controls the flow between different parts of the tree.
|
|
327
|
+
### Basic Usage
|
|
181
328
|
|
|
182
329
|
```tsx
|
|
183
|
-
{
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
330
|
+
import { TreegeRenderer } from "treege/renderer-native";
|
|
331
|
+
import type { Flow, FormValues } from "treege";
|
|
332
|
+
|
|
333
|
+
function App() {
|
|
334
|
+
const flow: Flow = {
|
|
335
|
+
id: "flow-1",
|
|
336
|
+
nodes: [
|
|
337
|
+
{
|
|
338
|
+
id: "name",
|
|
339
|
+
type: "input",
|
|
340
|
+
data: {
|
|
341
|
+
type: "text",
|
|
342
|
+
name: "fullName",
|
|
343
|
+
label: "Full Name",
|
|
344
|
+
required: true
|
|
345
|
+
}
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
id: "email",
|
|
349
|
+
type: "input",
|
|
350
|
+
data: {
|
|
351
|
+
type: "text",
|
|
352
|
+
name: "email",
|
|
353
|
+
label: "Email",
|
|
354
|
+
required: true,
|
|
355
|
+
pattern: "^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}$"
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
],
|
|
359
|
+
edges: []
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
const handleSubmit = (values: FormValues) => {
|
|
363
|
+
console.log("Form submitted:", values);
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
return (
|
|
367
|
+
<TreegeRenderer
|
|
368
|
+
flow={flow}
|
|
369
|
+
onSubmit={handleSubmit}
|
|
370
|
+
/>
|
|
371
|
+
);
|
|
189
372
|
}
|
|
190
373
|
```
|
|
191
374
|
|
|
375
|
+
### Custom Styling
|
|
376
|
+
|
|
377
|
+
You can customize the appearance using the `style` and `contentContainerStyle` props:
|
|
378
|
+
|
|
379
|
+
```tsx
|
|
380
|
+
<TreegeRenderer
|
|
381
|
+
flow={flow}
|
|
382
|
+
onSubmit={handleSubmit}
|
|
383
|
+
style={{ flex: 1, backgroundColor: "#f5f5f5" }}
|
|
384
|
+
contentContainerStyle={{ padding: 20 }}
|
|
385
|
+
/>
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### Custom Components
|
|
389
|
+
|
|
390
|
+
Override default components with your own React Native components.
|
|
391
|
+
|
|
392
|
+
Each input renderer is a **React component** receiving a single props object with two keys:
|
|
393
|
+
|
|
394
|
+
1. `field` — DOM-safe props (`id`, `name`, `value`, `placeholder`, `required`, `aria-invalid`). On the web you can spread them onto an element (`<input {...field} />`); on React Native pick the ones you need.
|
|
395
|
+
2. `extra` — Treege-specific props: `setValue`, `error`, `label`, `helperText`, `node`, `InputLabel` (the resolved, overridable label component), and `missingDependencies` (the unfilled fields this input's dynamic options depend on).
|
|
396
|
+
|
|
397
|
+
```tsx
|
|
398
|
+
import { Text, TextInput, View } from "react-native";
|
|
399
|
+
import { TreegeRenderer } from "treege/renderer-native";
|
|
400
|
+
|
|
401
|
+
const CustomTextInput = ({ field, extra }) => {
|
|
402
|
+
return (
|
|
403
|
+
<View style={{ marginBottom: 16 }}>
|
|
404
|
+
<Text style={{ fontSize: 14, marginBottom: 4 }}>{extra.label}</Text>
|
|
405
|
+
<TextInput
|
|
406
|
+
value={field.value}
|
|
407
|
+
placeholder={field.placeholder}
|
|
408
|
+
onChangeText={extra.setValue}
|
|
409
|
+
style={{
|
|
410
|
+
borderWidth: 1,
|
|
411
|
+
borderColor: extra.error ? "red" : "#ccc",
|
|
412
|
+
padding: 10,
|
|
413
|
+
borderRadius: 8
|
|
414
|
+
}}
|
|
415
|
+
/>
|
|
416
|
+
{extra.error && <Text style={{ color: "red", fontSize: 12 }}>{extra.error}</Text>}
|
|
417
|
+
{extra.missingDependencies.length > 0 && (
|
|
418
|
+
<Text style={{ color: "#b45309", fontSize: 12 }}>
|
|
419
|
+
Please fill in first: {extra.missingDependencies.map((d) => d.label).join(", ")}
|
|
420
|
+
</Text>
|
|
421
|
+
)}
|
|
422
|
+
</View>
|
|
423
|
+
);
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
<TreegeRenderer
|
|
427
|
+
flow={flow}
|
|
428
|
+
components={{
|
|
429
|
+
inputs: {
|
|
430
|
+
text: CustomTextInput
|
|
431
|
+
}
|
|
432
|
+
}}
|
|
433
|
+
/>
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
### Supported Input Types
|
|
437
|
+
|
|
438
|
+
The React Native renderer includes default implementations for all input types:
|
|
439
|
+
|
|
440
|
+
**Fully Implemented (Vanilla React Native)**:
|
|
441
|
+
- `text`, `number`, `textarea`, `password`
|
|
442
|
+
- `checkbox`, `switch`, `hidden`
|
|
443
|
+
|
|
444
|
+
**With Optional Dependencies** (gracefully degrades if not installed):
|
|
445
|
+
- `file` - Requires [react-native-document-picker](https://github.com/rnmods/react-native-document-picker) (optional)
|
|
446
|
+
|
|
447
|
+
**Requires Custom Implementation** (placeholder provided):
|
|
448
|
+
- `select`, `radio`, `autocomplete`
|
|
449
|
+
- `date`, `daterange`, `time`, `timerange`
|
|
450
|
+
- `address`, `http`
|
|
451
|
+
|
|
452
|
+
You can implement these inputs using popular React Native libraries:
|
|
453
|
+
- [@react-native-picker/picker](https://github.com/react-native-picker/picker) for `select` and `radio`
|
|
454
|
+
- [react-native-date-picker](https://github.com/henninghall/react-native-date-picker) for `date` and `time` inputs
|
|
455
|
+
- [@react-native-community/google-places-autocomplete](https://github.com/FaridSafi/react-native-google-places-autocomplete) for `address`
|
|
456
|
+
|
|
457
|
+
### API Reference
|
|
458
|
+
|
|
459
|
+
The React Native renderer shares the same API as the web renderer, with some platform-specific props:
|
|
460
|
+
|
|
461
|
+
| Prop | Type | Default | Description |
|
|
462
|
+
|-------------------------|-------------------------------------------------|--------------|------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
463
|
+
| `flow` | `Flow \| null` | - | Decision tree to render |
|
|
464
|
+
| `onSubmit` | `(values: FormValues, meta?: Meta) => void` | - | Form submission handler (meta includes HTTP response data) |
|
|
465
|
+
| `extraPayload` | `Record<string, unknown> \| (values) => Record` | - | Host-owned fields merged into every submission — the `onSubmit` payload **and** the HTTP submit body. Object or function of the current values (see below) |
|
|
466
|
+
| `onChange` | `(values: FormValues) => void` | - | Form change handler |
|
|
467
|
+
| `validate` | `(values, nodes) => Record<string, string>` | - | Custom validation function |
|
|
468
|
+
| `initialValues` | `FormValues` | `{}` | Pre-fill values to edit a record. Accepts `node.id` or name keys; reactive (re-seeds if it changes after mount) |
|
|
469
|
+
| `components` | `TreegeRendererComponents` | - | Custom component overrides |
|
|
470
|
+
| `language` | `string` | `"en"` | UI language |
|
|
471
|
+
| `validationMode` | `"onSubmit" \| "onChange"` | `"onSubmit"` | When to validate |
|
|
472
|
+
| `theme` | `"light" \| "dark"` | `"dark"` | Renderer theme |
|
|
473
|
+
| `googleApiKey` | `string` | - | API key for address input |
|
|
474
|
+
| `headers` | `HttpHeaders` | - | HTTP headers as `{ name: value }`, applied to every request (field-level wins) |
|
|
475
|
+
| `isLoading` | `boolean` | `false` | Render a loading skeleton instead of the form |
|
|
476
|
+
| `isSubmitting` | `boolean` | `false` | Force the submit/continue button into its loading state (OR-ed with internal state) |
|
|
477
|
+
| `onBack` | `() => void` | - | Called when Back is clicked on the first step; bridges to an outer flow |
|
|
478
|
+
| `style` | `ViewStyle` | - | ScrollView style (RN only) |
|
|
479
|
+
| `contentContainerStyle` | `ViewStyle` | - | Content container style (RN) |
|
|
480
|
+
|
|
481
|
+
## Node Types
|
|
482
|
+
|
|
483
|
+
Treege has three node types: `input`, `ui`, and `group`. Navigation is automatic — group nodes drive step navigation and conditional edges drive branching.
|
|
484
|
+
|
|
192
485
|
### Input Node
|
|
193
486
|
Form input with validation, patterns, and conditional logic.
|
|
194
487
|
|
|
@@ -209,7 +502,7 @@ Form input with validation, patterns, and conditional logic.
|
|
|
209
502
|
Supported input types: `text`, `number`, `textarea`, `password`, `select`, `radio`, `checkbox`, `switch`, `autocomplete`, `date`, `daterange`, `time`, `timerange`, `file`, `address`, `http`, `hidden`
|
|
210
503
|
|
|
211
504
|
### Group Node
|
|
212
|
-
Container for organizing multiple nodes together.
|
|
505
|
+
Container for organizing multiple nodes together. Groups also drive **multi-step forms**: at runtime each group of visible nodes becomes a navigable step (Back/Continue). Child nodes belong to a group via their `parentId`.
|
|
213
506
|
|
|
214
507
|
```tsx
|
|
215
508
|
{
|
|
@@ -239,7 +532,7 @@ Supported UI types:
|
|
|
239
532
|
|
|
240
533
|
## Conditional Edges
|
|
241
534
|
|
|
242
|
-
Create dynamic
|
|
535
|
+
Create dynamic flow with conditional logic:
|
|
243
536
|
|
|
244
537
|
```tsx
|
|
245
538
|
{
|
|
@@ -285,17 +578,30 @@ Treege supports multiple languages out of the box:
|
|
|
285
578
|
|
|
286
579
|
### Custom Input Components
|
|
287
580
|
|
|
288
|
-
Override default input renderers with your own
|
|
581
|
+
Override default input renderers with your own. A renderer is a React component
|
|
582
|
+
receiving a single props object: `field` (DOM-safe props, spreadable onto an
|
|
583
|
+
element) and `extra` (`setValue`, `error`, `label`, `helperText`, `node`,
|
|
584
|
+
`InputLabel`, `missingDependencies`).
|
|
289
585
|
|
|
290
586
|
```tsx
|
|
291
587
|
import { TreegeRenderer } from "treege/renderer";
|
|
292
588
|
|
|
293
|
-
const CustomTextInput = ({
|
|
294
|
-
return
|
|
589
|
+
const CustomTextInput = ({ field, extra }) => {
|
|
590
|
+
return (
|
|
591
|
+
<label>
|
|
592
|
+
{extra.label}
|
|
593
|
+
<input
|
|
594
|
+
{...field}
|
|
595
|
+
className="my-custom-input"
|
|
596
|
+
onChange={(e) => extra.setValue(e.target.value)}
|
|
597
|
+
/>
|
|
598
|
+
{extra.error && <span className="error">{extra.error}</span>}
|
|
599
|
+
</label>
|
|
600
|
+
);
|
|
295
601
|
};
|
|
296
602
|
|
|
297
603
|
<TreegeRenderer
|
|
298
|
-
|
|
604
|
+
flow={flow}
|
|
299
605
|
components={{
|
|
300
606
|
inputs: {
|
|
301
607
|
text: CustomTextInput
|
|
@@ -304,13 +610,34 @@ const CustomTextInput = ({ node }) => {
|
|
|
304
610
|
/>
|
|
305
611
|
```
|
|
306
612
|
|
|
613
|
+
### Custom Input Label
|
|
614
|
+
|
|
615
|
+
All default inputs render their label through a single shared component, `DefaultInputLabel`. Override it once via `components.inputLabel` to restyle every field label at once. It receives `{ label, required, htmlFor }` (web) and **renders nothing when the field has no label** — so the technical `name` key never leaks into the form. Each input also exposes the resolved label as `extra.InputLabel`, so custom inputs can reuse it:
|
|
616
|
+
|
|
617
|
+
```tsx
|
|
618
|
+
<TreegeRenderer
|
|
619
|
+
flow={flow}
|
|
620
|
+
components={{
|
|
621
|
+
inputLabel: ({ label, required, htmlFor }) =>
|
|
622
|
+
label ? (
|
|
623
|
+
<label htmlFor={htmlFor} className="my-label">
|
|
624
|
+
{label}
|
|
625
|
+
{required && <span className="text-red-500"> *</span>}
|
|
626
|
+
</label>
|
|
627
|
+
) : null,
|
|
628
|
+
}}
|
|
629
|
+
/>
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
Accessibility is preserved even without a visible label: the default inputs fall back to `aria-label={label || node.data.name}` on the control itself.
|
|
633
|
+
|
|
307
634
|
### Custom Validation
|
|
308
635
|
|
|
309
636
|
Add custom validation logic:
|
|
310
637
|
|
|
311
638
|
```tsx
|
|
312
639
|
<TreegeRenderer
|
|
313
|
-
|
|
640
|
+
flow={flow}
|
|
314
641
|
validate={(values, visibleNodes) => {
|
|
315
642
|
const errors = {};
|
|
316
643
|
|
|
@@ -363,112 +690,304 @@ Use the HTTP input type to fetch and map data from APIs:
|
|
|
363
690
|
|
|
364
691
|
### Global Configuration
|
|
365
692
|
|
|
366
|
-
Configure the renderer globally using the
|
|
693
|
+
Configure the renderer globally using the TreegeRendererProvider:
|
|
367
694
|
|
|
368
695
|
```tsx
|
|
369
|
-
import {
|
|
696
|
+
import { TreegeRendererProvider } from "treege/renderer";
|
|
370
697
|
|
|
371
698
|
function App() {
|
|
372
699
|
return (
|
|
373
|
-
<
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
components
|
|
378
|
-
// Your custom components
|
|
379
|
-
}
|
|
700
|
+
<TreegeRendererProvider
|
|
701
|
+
language="fr"
|
|
702
|
+
googleApiKey="your-google-api-key"
|
|
703
|
+
components={{
|
|
704
|
+
// Your custom components
|
|
380
705
|
}}
|
|
381
706
|
>
|
|
382
|
-
<TreegeRenderer
|
|
383
|
-
</
|
|
707
|
+
<TreegeRenderer flow={flow} />
|
|
708
|
+
</TreegeRendererProvider>
|
|
384
709
|
);
|
|
385
710
|
}
|
|
386
711
|
```
|
|
387
712
|
|
|
388
|
-
###
|
|
713
|
+
### Loading State
|
|
389
714
|
|
|
390
|
-
|
|
715
|
+
When the flow is being fetched asynchronously, pass `isLoading` to render a skeleton in place of the form:
|
|
716
|
+
|
|
717
|
+
```tsx
|
|
718
|
+
function App() {
|
|
719
|
+
const { data: flow, isPending } = useQuery(/* ... */);
|
|
720
|
+
|
|
721
|
+
return <TreegeRenderer flow={flow ?? null} isLoading={isPending} onSubmit={console.log} />;
|
|
722
|
+
}
|
|
723
|
+
```
|
|
724
|
+
|
|
725
|
+
Customize the skeleton via `components.loadingSkeleton`:
|
|
726
|
+
|
|
727
|
+
```tsx
|
|
728
|
+
<TreegeRenderer
|
|
729
|
+
flow={flow}
|
|
730
|
+
isLoading={isPending}
|
|
731
|
+
components={{
|
|
732
|
+
loadingSkeleton: () => <MyCustomSkeleton />,
|
|
733
|
+
}}
|
|
734
|
+
/>
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
### Editing an Existing Submission
|
|
738
|
+
|
|
739
|
+
To edit a record that was already filled in, pass it to `initialValues`. The keys can be either `node.id` **or** the same name-based keys you receive from `onSubmit`/`onChange`, so you can round-trip the submitted object directly — no remapping needed:
|
|
740
|
+
|
|
741
|
+
```tsx
|
|
742
|
+
const handleSubmit = (values) => save(values); // e.g. { firstName: "Alice", email: "a@b.com" }
|
|
743
|
+
|
|
744
|
+
// later, to edit the saved record:
|
|
745
|
+
<TreegeRenderer flow={flow} initialValues={savedRecord} onSubmit={handleSubmit} />
|
|
746
|
+
```
|
|
747
|
+
|
|
748
|
+
`initialValues` is **reactive**: if it changes after mount (e.g. an async-fetched record resolves later), the form is re-seeded automatically — no `key` prop or `isLoading` gate required. Passing a new object of identical content does not reset the form, so in-progress edits are preserved.
|
|
749
|
+
|
|
750
|
+
```tsx
|
|
751
|
+
const { data } = useQuery(/* ... */);
|
|
752
|
+
<TreegeRenderer flow={flow} initialValues={data ?? {}} onSubmit={handleSubmit} />
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
#### Pre-filling file fields
|
|
756
|
+
|
|
757
|
+
A `file` field's value is a serializable object (never a DOM `File`, so it round-trips through JSON):
|
|
758
|
+
|
|
759
|
+
```ts
|
|
760
|
+
type SerializableFile = {
|
|
761
|
+
name: string;
|
|
762
|
+
size: number;
|
|
763
|
+
type: string;
|
|
764
|
+
lastModified: number;
|
|
765
|
+
data: string; // base64 data-URL (web) or file URI (native)
|
|
766
|
+
};
|
|
767
|
+
```
|
|
768
|
+
|
|
769
|
+
The stored value is a single `SerializableFile` (or an array when the field is `multiple`, or `null`). Pass the same shape in `initialValues` to pre-fill a file field when editing — the renderer lists the files and lets the user remove them or add more. Only `name`/`size` are needed for display, so `data` can hold a server URL for already-uploaded files:
|
|
770
|
+
|
|
771
|
+
```tsx
|
|
772
|
+
<TreegeRenderer
|
|
773
|
+
flow={flow}
|
|
774
|
+
initialValues={{
|
|
775
|
+
attachment: { name: "contract.pdf", size: 24576, type: "application/pdf", lastModified: 0, data: "https://cdn.example.com/contract.pdf" },
|
|
776
|
+
}}
|
|
777
|
+
onSubmit={handleSubmit}
|
|
778
|
+
/>
|
|
779
|
+
```
|
|
780
|
+
|
|
781
|
+
### Injecting Host Data (`extraPayload`)
|
|
782
|
+
|
|
783
|
+
Use `extraPayload` to attach data owned by the host app — not by the form itself — to every submission (e.g. the logged-in user id, a tenant id). The fields are merged at the **top level** of both the `onSubmit` payload and the built-in HTTP submit body, so they ride along wherever the form data goes:
|
|
784
|
+
|
|
785
|
+
```tsx
|
|
786
|
+
<TreegeRenderer flow={flow} extraPayload={{ userId }} onSubmit={handleSubmit} />
|
|
787
|
+
// onSubmit receives → { ...formValues, userId }
|
|
788
|
+
```
|
|
789
|
+
|
|
790
|
+
Pass a **function** when the value must be read at submit time rather than captured at render — a rotating auth token, a timestamp, or a value derived from the current answers (it receives the same name-keyed values you get in `onSubmit`):
|
|
791
|
+
|
|
792
|
+
```tsx
|
|
793
|
+
<TreegeRenderer flow={flow} extraPayload={() => ({ token: auth.getToken() })} />
|
|
794
|
+
<TreegeRenderer flow={flow} extraPayload={(values) => ({ fullName: `${values.firstName} ${values.lastName}` })} />
|
|
795
|
+
```
|
|
796
|
+
|
|
797
|
+
Notes:
|
|
798
|
+
|
|
799
|
+
- The extra fields are spread **last**, so a key here intentionally overrides a same-named form field.
|
|
800
|
+
- It also applies to the built-in HTTP submit (`submitConfig`): the fields are merged into the request body, respecting any `payloadTemplate` shape. If the config would otherwise send no body, the extra is sent on its own — your data is never silently dropped.
|
|
801
|
+
- A function that returns a non-object (array / primitive) is ignored.
|
|
802
|
+
|
|
803
|
+
### Submitting State
|
|
804
|
+
|
|
805
|
+
Pass `isSubmitting` to keep the submit/continue button in its loading state (spinner + disabled) while an async `onSubmit` resolves on your side. It's OR-ed with the renderer's own internal submitting state (e.g. during an HTTP `submitConfig` call):
|
|
806
|
+
|
|
807
|
+
```tsx
|
|
808
|
+
<TreegeRenderer flow={flow} isSubmitting={mutation.isPending} onSubmit={handleSubmit} />
|
|
809
|
+
```
|
|
810
|
+
|
|
811
|
+
### Multi-Step Forms
|
|
812
|
+
|
|
813
|
+
When a flow contains **Group** nodes, the renderer automatically splits the form into navigable steps — each contiguous slice of visible nodes sharing the same group becomes one step, with built-in Back/Continue controls (Continue turns into Submit on the last step). Branching via conditional edges recomputes the steps on the fly.
|
|
814
|
+
|
|
815
|
+
Override the default step layout via `components.step`:
|
|
816
|
+
|
|
817
|
+
```tsx
|
|
818
|
+
<TreegeRenderer
|
|
819
|
+
flow={flow}
|
|
820
|
+
components={{
|
|
821
|
+
step: ({ label, children, canGoBack, isLastStep, canContinue, isSubmitting, onBack, onContinue }) => (
|
|
822
|
+
<section>
|
|
823
|
+
<h2>{label}</h2>
|
|
824
|
+
{children}
|
|
825
|
+
{canGoBack && <button onClick={onBack}>Back</button>}
|
|
826
|
+
<button disabled={!canContinue || isSubmitting} onClick={onContinue}>
|
|
827
|
+
{isSubmitting ? "Submitting…" : isLastStep ? "Submit" : "Continue"}
|
|
828
|
+
</button>
|
|
829
|
+
</section>
|
|
830
|
+
),
|
|
831
|
+
}}
|
|
832
|
+
/>
|
|
833
|
+
```
|
|
834
|
+
|
|
835
|
+
Use **`canGoBack`** (not `!isFirstStep`) to decide whether to show the Back control: it's `true` on any step past the first, and also on the first step when an `onBack` prop is provided.
|
|
836
|
+
|
|
837
|
+
#### Bridging navigation to an outer flow
|
|
838
|
+
|
|
839
|
+
When the renderer is embedded in a surrounding wizard (e.g. a modal with its own steps), use `onBack` to step back out of the renderer's first step, and `formId` to drive submission from an external button:
|
|
840
|
+
|
|
841
|
+
```tsx
|
|
842
|
+
<TreegeRenderer
|
|
843
|
+
flow={flow}
|
|
844
|
+
formId="treege-form"
|
|
845
|
+
onBack={() => modal.goToPreviousStep()} // Back on step 0 → previous modal step
|
|
846
|
+
onSubmit={handleSubmit}
|
|
847
|
+
/>
|
|
848
|
+
|
|
849
|
+
// A submit button living outside the renderer (web): only submits on the last
|
|
850
|
+
// step — on earlier steps it advances, like the built-in Continue button.
|
|
851
|
+
<button type="submit" form="treege-form">Save</button>
|
|
852
|
+
```
|
|
853
|
+
|
|
854
|
+
### Headless / Programmatic Control
|
|
855
|
+
|
|
856
|
+
Use the `useTreegeRenderer` hook to drive the form yourself (headless mode). It takes the same configuration as `TreegeRenderer` and returns the full form state and control methods:
|
|
391
857
|
|
|
392
858
|
```tsx
|
|
393
859
|
import { useTreegeRenderer } from "treege/renderer";
|
|
394
860
|
|
|
395
|
-
function CustomForm() {
|
|
396
|
-
const {
|
|
861
|
+
function CustomForm({ flow }) {
|
|
862
|
+
const {
|
|
863
|
+
formValues,
|
|
864
|
+
setFieldValue,
|
|
865
|
+
handleSubmit,
|
|
866
|
+
formErrors,
|
|
867
|
+
visibleNodes,
|
|
868
|
+
isSubmitting,
|
|
869
|
+
currentStep,
|
|
870
|
+
goToNextStep,
|
|
871
|
+
goToPreviousStep,
|
|
872
|
+
} = useTreegeRenderer({
|
|
873
|
+
flow,
|
|
874
|
+
onSubmit: (values) => console.log("Submitted:", values),
|
|
875
|
+
});
|
|
397
876
|
|
|
398
877
|
return (
|
|
399
878
|
<div>
|
|
400
879
|
<button onClick={() => setFieldValue("email", "test@example.com")}>
|
|
401
880
|
Prefill Email
|
|
402
881
|
</button>
|
|
403
|
-
<button onClick={
|
|
404
|
-
|
|
882
|
+
<button onClick={handleSubmit} disabled={isSubmitting}>
|
|
883
|
+
Submit
|
|
884
|
+
</button>
|
|
405
885
|
</div>
|
|
406
886
|
);
|
|
407
887
|
}
|
|
408
888
|
```
|
|
409
889
|
|
|
890
|
+
> The `useTreegeRenderer` return type is exported as `UseTreegeRendererReturn` for TypeScript consumers building custom components.
|
|
891
|
+
|
|
410
892
|
## Examples
|
|
411
893
|
|
|
412
894
|
Check out the `/example` directory for complete examples:
|
|
413
895
|
|
|
414
896
|
```bash
|
|
415
|
-
|
|
416
|
-
|
|
897
|
+
# Run the web example app (Vite, opens /example)
|
|
898
|
+
bun run example
|
|
899
|
+
|
|
900
|
+
# Run the React Native example app (Expo)
|
|
901
|
+
bun run example:native
|
|
417
902
|
```
|
|
418
903
|
|
|
904
|
+
### Available Example URLs
|
|
905
|
+
|
|
906
|
+
Once the development server is running, you can access these examples:
|
|
907
|
+
|
|
908
|
+
- **Default Example**: [http://localhost:5173/](http://localhost:5173/)
|
|
909
|
+
- Basic demonstration of Treege functionality
|
|
910
|
+
|
|
911
|
+
- **Demo Example**: [http://localhost:5173/example](http://localhost:5173/example)
|
|
912
|
+
- Full featured demo showcasing the library capabilities
|
|
913
|
+
|
|
914
|
+
- **All Inputs Example**: [http://localhost:5173/example-all-inputs](http://localhost:5173/example-all-inputs)
|
|
915
|
+
- Comprehensive showcase of all 16 input types
|
|
916
|
+
|
|
917
|
+
- **Custom Input Example**: [http://localhost:5173/example-custom-input](http://localhost:5173/example-custom-input)
|
|
918
|
+
- Demonstrates how to create and integrate custom input components
|
|
919
|
+
|
|
920
|
+
- **TreegeRendererProvider Example**: [http://localhost:5173/example-treege-renderer-provider](http://localhost:5173/example-treege-renderer-provider)
|
|
921
|
+
- Shows global configuration with TreegeRendererProvider
|
|
922
|
+
|
|
419
923
|
## API Reference
|
|
420
924
|
|
|
421
925
|
### TreegeEditor Props
|
|
422
926
|
|
|
423
|
-
| Prop
|
|
424
|
-
|
|
425
|
-
| `flow`
|
|
426
|
-
| `onSave`
|
|
427
|
-
| `
|
|
428
|
-
| `
|
|
927
|
+
| Prop | Type | Default | Description |
|
|
928
|
+
|-------------------|------------------------------------------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
929
|
+
| `flow` | `Flow \| null` | `null` | Initial decision tree |
|
|
930
|
+
| `onSave` | `(flow: Flow) => void` | - | Callback when the user saves the tree. The **Save button is only rendered when this prop is provided**, and is no longer disabled on an empty canvas (so a cleared flow can be saved) |
|
|
931
|
+
| `onChange` | `(flow: Flow) => void` | - | Called (debounced ~150 ms) on every canvas change with the current flow. Use it for **live preview / autosave**. Unlike `onSave` it isn't gated on having input nodes, so it also reports an emptied canvas after Clear, and it does **not** strip sensitive headers (live consumers need the real flow) |
|
|
932
|
+
| `onExportJson` | `() => { nodes: Node[]; edges: Edge[] }` | - | Callback for exporting JSON data |
|
|
933
|
+
| `language` | `string` | `"en"` | UI language |
|
|
934
|
+
| `theme` | `"light" \| "dark"` | `"dark"` | Editor theme |
|
|
935
|
+
| `aiConfig` | `AIConfig` | - | AI configuration for tree generation (see [AI Generation](./AI_GENERATION.md)) |
|
|
936
|
+
| `className` | `string` | - | Additional CSS class names for custom styling |
|
|
937
|
+
| `extraMenuItems` | `ExtraMenuItem[]` | - | Extra entries appended to the actions panel "more" dropdown |
|
|
938
|
+
| `openApi` | `OpenApiDocument \| string` | - | OpenAPI 3.x source used to power URL/route suggestions and the Authorize flow. Accepts a pre-parsed document or a URL string (the editor fetches it on mount and toasts on failure) |
|
|
939
|
+
| `baseUrl` | `string` | - | Base URL the tree runs against. HTTP/options-source urls are stored relative to it, shown as a read-only prefix, and used to resolve the "Detect fields" probe. Pass the same value as `TreegeRenderer`'s `baseUrl` |
|
|
940
|
+
| `headers` | `HttpHeaders` | - | Global HTTP headers applied to in-editor requests (e.g. the "Detect fields" button). Pass the same value you give to `TreegeRenderer` so editor previews use the same auth/headers as runtime |
|
|
941
|
+
| `onAuthorize` | `(headers: HttpHeaders) => void` | - | Called when the user submits the Authorize dialog. Forward the resulting headers to `TreegeRenderer` (or `TreegeRendererProvider`) so every form request is authenticated |
|
|
942
|
+
| `onHeadersChange` | `(headers: HttpHeaders) => void` | - | Called when the user edits headers in the built-in "Global headers" dialog. The component is controlled — update your `headers` state in response and pass the new object back via the `headers` prop |
|
|
429
943
|
|
|
430
944
|
### TreegeRenderer Props
|
|
431
945
|
|
|
432
|
-
| Prop | Type
|
|
433
|
-
|
|
434
|
-
| `
|
|
435
|
-
| `onSubmit` | `(values: FormValues) => void`
|
|
436
|
-
| `
|
|
437
|
-
| `
|
|
438
|
-
| `
|
|
439
|
-
| `
|
|
440
|
-
| `
|
|
441
|
-
| `
|
|
442
|
-
| `
|
|
443
|
-
| `
|
|
946
|
+
| Prop | Type | Default | Description |
|
|
947
|
+
|------------------|-------------------------------------------------|--------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
948
|
+
| `flow` | `Flow \| null` | - | Decision tree to render |
|
|
949
|
+
| `onSubmit` | `(values: FormValues, meta?: Meta) => void` | - | Form submission handler (meta includes HTTP response data) |
|
|
950
|
+
| `extraPayload` | `Record<string, unknown> \| (values) => Record` | - | Host-owned fields merged into every submission — the `onSubmit` payload **and** the HTTP submit body. Object or function of the current values (see below) |
|
|
951
|
+
| `onChange` | `(values: FormValues) => void` | - | Form change handler |
|
|
952
|
+
| `validate` | `(values, nodes) => Record<string, string>` | - | Custom validation function |
|
|
953
|
+
| `initialValues` | `FormValues` | `{}` | Pre-fill values to edit a submitted record. Accepts `node.id` **or** name keys (same shape as `onSubmit`); reactive — re-seeds if it changes after mount (see below) |
|
|
954
|
+
| `components` | `TreegeRendererComponents` | - | Custom component overrides |
|
|
955
|
+
| `language` | `string` | `"en"` | UI language |
|
|
956
|
+
| `validationMode` | `"onSubmit" \| "onChange"` | `"onSubmit"` | When to validate |
|
|
957
|
+
| `theme` | `"light" \| "dark"` | `"dark"` | Renderer theme |
|
|
958
|
+
| `googleApiKey` | `string` | - | API key for address input |
|
|
959
|
+
| `headers` | `HttpHeaders` | - | HTTP headers as `{ name: value }`, applied to every request (field-level wins) |
|
|
960
|
+
| `isLoading` | `boolean` | `false` | Render a loading skeleton instead of the form (see below) |
|
|
961
|
+
| `isSubmitting` | `boolean` | `false` | Force the submit/continue button into its loading state (spinner + disabled). OR-ed with the internal submitting state — useful with an async `onSubmit` |
|
|
962
|
+
| `onBack` | `() => void` | - | Called when Back is clicked on the **first step**; bridges back-navigation to an outer flow (e.g. a parent modal). Shows a Back button on step 0 when provided |
|
|
963
|
+
| `formId` | `string` | - | Sets the `<form>` `id` so a submit button outside the renderer can target it via the native `form` attribute. Web only; submits only on the last step in multi-step flows |
|
|
964
|
+
| `className` | `string` | - | Additional CSS class names for custom styling |
|
|
444
965
|
|
|
445
966
|
## Development
|
|
446
967
|
|
|
447
968
|
```bash
|
|
448
969
|
# Install dependencies
|
|
449
|
-
|
|
970
|
+
bun install
|
|
450
971
|
|
|
451
972
|
# Start dev server
|
|
452
|
-
|
|
973
|
+
bun run dev
|
|
453
974
|
|
|
454
975
|
# Build library
|
|
455
|
-
|
|
976
|
+
bun run build
|
|
456
977
|
|
|
457
978
|
# Run linter and type check
|
|
458
|
-
|
|
979
|
+
bun run lint
|
|
459
980
|
|
|
460
981
|
# Preview build
|
|
461
|
-
|
|
982
|
+
bun run preview
|
|
462
983
|
```
|
|
463
984
|
|
|
464
985
|
## Tech Stack
|
|
465
986
|
|
|
466
|
-
- **React**
|
|
987
|
+
- **React** - UI library
|
|
467
988
|
- **TypeScript** - Type safety
|
|
468
989
|
- **TailwindCSS** 4 - Styling
|
|
469
990
|
- **ReactFlow** - Node-based UI
|
|
470
|
-
- **Radix UI** - Accessible components
|
|
471
|
-
- **Zustand** - State management
|
|
472
991
|
- **Vite** - Build tool
|
|
473
992
|
|
|
474
993
|
## Contributing
|
|
@@ -477,13 +996,13 @@ Contributions are welcome! Please feel free to submit a Pull Request.
|
|
|
477
996
|
|
|
478
997
|
## License
|
|
479
998
|
|
|
480
|
-
|
|
999
|
+
MIT
|
|
481
1000
|
|
|
482
1001
|
## Credits
|
|
483
1002
|
|
|
484
|
-
Created and maintained by [Mickaël Austoni](https://github.com/
|
|
1003
|
+
Created and maintained by [Mickaël Austoni](https://github.com/MickaelAustoni)
|
|
485
1004
|
|
|
486
1005
|
## Support
|
|
487
1006
|
|
|
488
|
-
- [GitHub Issues](https://github.com/
|
|
489
|
-
- [Repository](https://github.com/
|
|
1007
|
+
- [GitHub Issues](https://github.com/MickaelAustoni/treege/issues)
|
|
1008
|
+
- [Repository](https://github.com/MickaelAustoni/treege)
|