treege 3.0.0-beta.86 → 3.0.0-beta.88
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 +112 -56
- package/dist/{editor-BK8Mbi-D.js → editor-BPx-285N.js} +2 -2
- package/dist/editor.js +1 -1
- package/dist/main.js +4 -4
- package/dist/renderer/features/TreegeRenderer/useTreegeRenderer.d.ts +1 -1
- package/dist/renderer/features/TreegeRenderer/web/TreegeRenderer.d.ts +1 -1
- package/dist/renderer/features/TreegeViewer/utils/viewerFields.d.ts +26 -2
- package/dist/renderer/features/TreegeViewer/web/TreegeViewer.d.ts +41 -27
- package/dist/renderer/hooks/useSubmitHandler.d.ts +3 -2
- package/dist/renderer/types/renderer.d.ts +24 -0
- package/dist/renderer/utils/extraPayload.d.ts +21 -0
- package/dist/renderer/utils/submit.d.ts +3 -2
- package/dist/renderer-Bpgwbsub.js +446 -0
- package/dist/renderer-native.js +167 -166
- package/dist/renderer.js +3 -3
- package/dist/{useRenderNode-DQ5lvXuj.js → useRenderNode-CgDdKXTw.js} +203 -192
- package/package.json +1 -1
- package/dist/renderer-8xCEZin9.js +0 -424
package/README.md
CHANGED
|
@@ -47,12 +47,13 @@ Treege is a modern React library for creating and rendering interactive decision
|
|
|
47
47
|
- **Conditional Logic**: Dynamic field visibility based on user input and conditional edges
|
|
48
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
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
|
|
50
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
|
|
51
52
|
- **Fully Customizable**: Override any component (form, inputs, inputLabel, ui, step, submitButton, submitButtonWrapper, loadingSkeleton)
|
|
52
53
|
- **Optional Dependencies**: Graceful degradation when optional packages like `react-native-document-picker` aren't installed
|
|
53
54
|
- **Theme Support**: Dark/light mode out of the box
|
|
54
55
|
- **Google API Integration**: Address autocomplete support
|
|
55
|
-
- **Read-Only Viewer**: `TreegeViewer` renders a submitted flow as a label/value recap — same branch-visibility and formatting as the form, with a headless `getViewerFields` core for custom layouts
|
|
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
|
|
56
57
|
|
|
57
58
|
### Developer Experience
|
|
58
59
|
- **Modular**: Import only what you need (editor, renderer, or both)
|
|
@@ -192,11 +193,10 @@ function App() {
|
|
|
192
193
|
|
|
193
194
|
## Read-Only Viewer (`TreegeViewer`)
|
|
194
195
|
|
|
195
|
-
Once a form has been submitted, `TreegeViewer` renders the result as a read-only **label / value recap** — no inputs, no validation.
|
|
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.
|
|
196
197
|
|
|
197
198
|
```tsx
|
|
198
|
-
import { TreegeRenderer } from "treege/renderer";
|
|
199
|
-
import { TreegeViewer } from "treege/renderer";
|
|
199
|
+
import { TreegeRenderer, TreegeViewer } from "treege/renderer";
|
|
200
200
|
import { useState } from "react";
|
|
201
201
|
import type { Flow, FormValues } from "treege";
|
|
202
202
|
|
|
@@ -204,27 +204,56 @@ function App({ flow }: { flow: Flow }) {
|
|
|
204
204
|
const [submitted, setSubmitted] = useState<FormValues | null>(null);
|
|
205
205
|
|
|
206
206
|
if (submitted) {
|
|
207
|
-
return <TreegeViewer flow={flow}
|
|
207
|
+
return <TreegeViewer flow={flow} flowResponse={submitted} language="en" />;
|
|
208
208
|
}
|
|
209
209
|
|
|
210
210
|
return <TreegeRenderer flow={flow} onSubmit={setSubmitted} />;
|
|
211
211
|
}
|
|
212
212
|
```
|
|
213
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
|
+
|
|
214
227
|
### Props
|
|
215
228
|
|
|
216
|
-
| Prop
|
|
217
|
-
|
|
218
|
-
| `flow`
|
|
219
|
-
| `
|
|
220
|
-
| `language`
|
|
221
|
-
| `
|
|
222
|
-
| `
|
|
223
|
-
| `
|
|
224
|
-
| `
|
|
225
|
-
| `
|
|
226
|
-
| `
|
|
227
|
-
| `
|
|
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
|
+
```
|
|
228
257
|
|
|
229
258
|
### Customizing rendering
|
|
230
259
|
|
|
@@ -233,16 +262,19 @@ Use `renderField` to override the value cell for a specific input type — most
|
|
|
233
262
|
```tsx
|
|
234
263
|
<TreegeViewer
|
|
235
264
|
flow={flow}
|
|
236
|
-
|
|
265
|
+
flowResponse={submitted}
|
|
237
266
|
language="fr"
|
|
238
267
|
excludedFields={["internalNote"]}
|
|
239
268
|
renderField={{ file: ({ rawValue }) => <Thumbnails files={rawValue} /> }}
|
|
240
269
|
/>
|
|
241
270
|
```
|
|
242
271
|
|
|
243
|
-
### Headless usage
|
|
272
|
+
### Headless usage
|
|
244
273
|
|
|
245
|
-
`TreegeViewer` is a thin layer over
|
|
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.
|
|
246
278
|
|
|
247
279
|
```tsx
|
|
248
280
|
import { getViewerFields } from "treege/renderer";
|
|
@@ -426,24 +458,25 @@ You can implement these inputs using popular React Native libraries:
|
|
|
426
458
|
|
|
427
459
|
The React Native renderer shares the same API as the web renderer, with some platform-specific props:
|
|
428
460
|
|
|
429
|
-
| Prop | Type
|
|
430
|
-
|
|
431
|
-
| `flow` | `Flow \| null`
|
|
432
|
-
| `onSubmit` | `(values: FormValues, meta?: Meta) => void`
|
|
433
|
-
| `
|
|
434
|
-
| `
|
|
435
|
-
| `
|
|
436
|
-
| `
|
|
437
|
-
| `
|
|
438
|
-
| `
|
|
439
|
-
| `
|
|
440
|
-
| `
|
|
441
|
-
| `
|
|
442
|
-
| `
|
|
443
|
-
| `
|
|
444
|
-
| `
|
|
445
|
-
| `
|
|
446
|
-
| `
|
|
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) |
|
|
447
480
|
|
|
448
481
|
## Node Types
|
|
449
482
|
|
|
@@ -745,6 +778,28 @@ The stored value is a single `SerializableFile` (or an array when the field is `
|
|
|
745
778
|
/>
|
|
746
779
|
```
|
|
747
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
|
+
|
|
748
803
|
### Submitting State
|
|
749
804
|
|
|
750
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):
|
|
@@ -888,24 +943,25 @@ Once the development server is running, you can access these examples:
|
|
|
888
943
|
|
|
889
944
|
### TreegeRenderer Props
|
|
890
945
|
|
|
891
|
-
| Prop | Type
|
|
892
|
-
|
|
893
|
-
| `flow` | `Flow \| null`
|
|
894
|
-
| `onSubmit` | `(values: FormValues, meta?: Meta) => void`
|
|
895
|
-
| `
|
|
896
|
-
| `
|
|
897
|
-
| `
|
|
898
|
-
| `
|
|
899
|
-
| `
|
|
900
|
-
| `
|
|
901
|
-
| `
|
|
902
|
-
| `
|
|
903
|
-
| `
|
|
904
|
-
| `
|
|
905
|
-
| `
|
|
906
|
-
| `
|
|
907
|
-
| `
|
|
908
|
-
| `
|
|
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 |
|
|
909
965
|
|
|
910
966
|
## Development
|
|
911
967
|
|