@sonata-innovations/fiber-fbre 3.2.1 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +58 -0
- package/CHANGELOG.md +129 -0
- package/README.md +61 -365
- package/dist/fiber-fbre.cjs +1 -1
- package/dist/fiber-fbre.css +1 -1
- package/dist/fiber-fbre.js +1555 -1496
- package/dist/index.d.ts +27 -3
- package/docs/features/confirmation-screen.md +125 -0
- package/docs/features/fbre-theming.md +264 -0
- package/docs/fiber-concepts.md +461 -0
- package/docs/integration/fbre.md +387 -0
- package/package.json +19 -10
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Fiber Concepts
|
|
3
|
+
applies-to:
|
|
4
|
+
- "@sonata-innovations/fiber-types@^2.2"
|
|
5
|
+
- "@sonata-innovations/fiber-fbre@^3.3"
|
|
6
|
+
- "@sonata-innovations/fiber-fbt@^2.2"
|
|
7
|
+
- "@sonata-innovations/fiber-fbtl@^2.2"
|
|
8
|
+
read-when: "First contact with Fiber: the Flow/Screen/Component model, FlowData, builders vs render engine, conditions/validation/calculations concepts."
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
<!-- Generated from the Fiber repo's docs/ tree by project/scripts/sync-package-docs.mjs. Do not edit here. -->
|
|
12
|
+
# Fiber Concepts
|
|
13
|
+
|
|
14
|
+
> A high-level conceptual overview of Fiber for AI assistants and newcomers.
|
|
15
|
+
> For integration code and API reference, see the integration guides.
|
|
16
|
+
> For the JSON schema specification, see [`flow-schema.md`](@sonata-innovations/fiber-types/docs/schema/flow-schema.md).
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 1. What is Fiber?
|
|
21
|
+
|
|
22
|
+
Fiber is a system for building and rendering data-collection forms. It splits authoring from rendering and offers two authoring surfaces targeted at different audiences:
|
|
23
|
+
|
|
24
|
+
- **FBT (Fiber Tool)** — A visual drag-and-drop builder for power users / form designers. Full feature surface: screens, multi-rule conditions, validation, calculations, reference markup, the complete 30-type component palette. See the [FBT integration guide](@sonata-innovations/fiber-fbt/docs/integration/fbt.md).
|
|
25
|
+
- **FBTL (Fiber Tool Lite)** — A stripped-down, end-user-friendly builder designed to be embedded in parent apps so non-technical end users (clinicians, teachers, etc.) can author their own forms. Five question types + Information Screens + single-rule conditions. Preserves advanced properties from loaded flows without editing them. See the [FBTL integration guide](@sonata-innovations/fiber-fbtl/docs/integration/fbtl.md).
|
|
26
|
+
- **FBRE (Fiber Render Engine)** — A render engine that consumes Flow JSON, renders the interactive form for end users, and outputs collected data ("FlowData") back to the parent application. See the [FBRE integration guide](integration/fbre.md).
|
|
27
|
+
|
|
28
|
+
A fourth library, the **Theme Editor**, is a plug-and-play widget that lets end users visually customize a flow's theme (color scheme, style, palette knobs) and emits the resulting `ThemeConfig`. See the [Theme Editor integration guide](@sonata-innovations/fiber-theme-editor/docs/integration/theme-editor.md).
|
|
29
|
+
|
|
30
|
+
**The problem it solves:** Both form designers and parent-app end users need to create multi-step forms without writing code. Developers need to embed those forms into their applications without building form infrastructure from scratch.
|
|
31
|
+
|
|
32
|
+
The libraries are standard React components — not iframes, not external services. They embed directly into a parent React application with full control over styling, data flow, and lifecycle. **FBT and FBTL produce the same Flow JSON schema**, so any Flow is portable between them (with FBTL preserving — but not editing — power-user features).
|
|
33
|
+
|
|
34
|
+
### Packages
|
|
35
|
+
|
|
36
|
+
| Package | What it is |
|
|
37
|
+
|---------|-----------|
|
|
38
|
+
| `@sonata-innovations/fiber-types` | Shared TypeScript types — the Flow/FlowData schema as code |
|
|
39
|
+
| `@sonata-innovations/fiber-shared` | Engine layer: condition evaluation, validation, markup conversion, formula evaluation. Used client-side (FBRE, FBT) **and** server-side, so the same rules evaluate identically anywhere |
|
|
40
|
+
| `@sonata-innovations/fiber-fbre` | The render engine |
|
|
41
|
+
| `@sonata-innovations/fiber-fbt` | The full builder |
|
|
42
|
+
| `@sonata-innovations/fiber-fbtl` | The lite builder |
|
|
43
|
+
| `@sonata-innovations/fiber-theme-editor` | The theming widget |
|
|
44
|
+
|
|
45
|
+
Three private (unpublished) packages — a Fastify **server**, an admin **portal**, and a **hosted** form-filling app — make up the hosted platform built on top of the libraries (see Section 13).
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## 2. Core Data Model
|
|
50
|
+
|
|
51
|
+
### The Flow JSON
|
|
52
|
+
|
|
53
|
+
The Flow is the interchange format between the builders and the render engine. FBT and FBTL both produce it; FBRE consumes it. It is a plain JSON document that can be stored, transmitted, versioned, and inspected.
|
|
54
|
+
|
|
55
|
+
### Hierarchy
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
Flow
|
|
59
|
+
├── uuid — Unique identifier for the entire flow
|
|
60
|
+
├── metadata — Name, description, and arbitrary key-value pairs
|
|
61
|
+
├── config — Runtime settings (mode, theme, navigation, controls, confirmation, summary)
|
|
62
|
+
├── calculations[] — Optional: named formulas computed over component values
|
|
63
|
+
└── screens[] — Ordered list of screens (pages)
|
|
64
|
+
├── uuid
|
|
65
|
+
├── label
|
|
66
|
+
├── conditions — Optional: show/hide this screen based on rules
|
|
67
|
+
└── components[] — Ordered list of components on this screen
|
|
68
|
+
├── uuid
|
|
69
|
+
├── type — One of 30 component types
|
|
70
|
+
├── properties — Configuration (label, placeholder, options, validation, width, etc.)
|
|
71
|
+
├── conditions — Optional: show/hide this component based on rules
|
|
72
|
+
└── components[] — Optional: child components (group and repeater types)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Identity
|
|
76
|
+
|
|
77
|
+
Every entity (flow, screen, component, calculation) has a UUID. These UUIDs are the stable identity used for:
|
|
78
|
+
- Referencing components in conditions ("show this if *that component* equals X")
|
|
79
|
+
- Cross-field validation ("this field must match *that field*")
|
|
80
|
+
- Reference markup (`${uuid}` tokens resolving to live values)
|
|
81
|
+
- Pre-populating data (matching FlowData entries to their components)
|
|
82
|
+
- Tracking changes in the builder
|
|
83
|
+
|
|
84
|
+
### Flow Configuration
|
|
85
|
+
|
|
86
|
+
The optional `config` object controls runtime behavior, organized into semantic groups:
|
|
87
|
+
|
|
88
|
+
| Group | Setting | Purpose |
|
|
89
|
+
|-------|---------|---------|
|
|
90
|
+
| _(flat)_ | `mode` | Presentation mode: `"standard"` (default) or `"conversational"` (one question at a time) |
|
|
91
|
+
| `theme` | `color` | Primary accent color (CSS value) |
|
|
92
|
+
| `theme` | `colorScheme` | Built-in palette preset: `"light"` (default) or `"dark"` (replaces the former `darkMode` boolean) |
|
|
93
|
+
| `theme` | `style` | Visual style (`"clean"`, `"outlined"`, …) |
|
|
94
|
+
| `theme` | `background` / `surface` / `text` / `border` | Palette knobs overriding the preset tokens |
|
|
95
|
+
| `theme` | `radius` / `fontFamily` | Corner radius and font family knobs |
|
|
96
|
+
| `theme` | `error` / `success` / `warning` | Semantic state color knobs |
|
|
97
|
+
| `navigation` | `transition` | Screen transition animation type |
|
|
98
|
+
| `navigation` | `allowInvalidTransition` | Allow navigating past screens with validation errors |
|
|
99
|
+
| `controls` | `show` | Show/hide built-in next/back buttons |
|
|
100
|
+
| `controls` | `layout` | Controls layout (`"default"`, `"centered"`, `"inline-full"`, or `"stacked"`) |
|
|
101
|
+
| `controls` | `showStepper` | Show/hide the step indicator |
|
|
102
|
+
| `controls` | `stepperStyle` | Stepper variant (`"default"`, `"dots"`, `"pill"`, `"glow"`, `"bar"`, `"text"`) |
|
|
103
|
+
| `confirmation` | `show` / `title` / `body` | Terminal "thank you" screen shown after submission (see Section 13) |
|
|
104
|
+
| _(flat)_ | `summary` | Show a review screen before final submission |
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## 3. Screens
|
|
109
|
+
|
|
110
|
+
Screens are the pages of a multi-step form. Users see one screen at a time and navigate between them with next/back buttons.
|
|
111
|
+
|
|
112
|
+
**Key behaviors:**
|
|
113
|
+
- Screens render in array order (first screen in the array is shown first)
|
|
114
|
+
- Navigation is linear by default — next goes forward, back goes backward
|
|
115
|
+
- Screens can be conditionally shown or hidden (see Conditions below) — hidden screens are automatically skipped during navigation
|
|
116
|
+
- Each screen can customize its next and back button labels
|
|
117
|
+
- Screen transitions can be animated (slide, fade, rise, etc.)
|
|
118
|
+
|
|
119
|
+
**Summary screen:** When enabled via `config.summary`, a review screen appears after the last screen showing all collected data before the user confirms submission.
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## 4. Components
|
|
124
|
+
|
|
125
|
+
Components are the individual form elements within a screen. Fiber has **30 component types** across six categories. This section summarizes each category; the exhaustive per-type property reference lives in [`flow-schema.md`](@sonata-innovations/fiber-types/docs/schema/flow-schema.md).
|
|
126
|
+
|
|
127
|
+
| Category | Types | Purpose |
|
|
128
|
+
|----------|-------|---------|
|
|
129
|
+
| Display (6) | `header`, `text`, `divider`, `callout`, `table`, `computed` | Presentational content: headings, body text (with inline markup), separators, highlighted callouts, static tables, and calculated-value display |
|
|
130
|
+
| Text & Number (3) | `inputText`, `inputTextArea`, `inputNumber` | Free-form text and numeric entry |
|
|
131
|
+
| Selection (8) | `dropDown`, `dropDownMulti`, `checkbox`, `radio`, `toggleSwitch`, `yesNo`, `confirm`, `cardSelect` | Choosing from predefined options — single-select, multi-select, boolean toggles, an acknowledgment checkbox, and rich card-based selection |
|
|
132
|
+
| Date & Time (6) | `date`, `time`, `dateTime`, `dateRange`, `timeRange`, `dateTimeRange` | Point-in-time and range pickers; ranges produce `{ start, end }` values |
|
|
133
|
+
| Interactive (5) | `fileUpload`, `rating`, `slider`, `colorPicker`, `signature` | Richer input widgets: drag-and-drop file upload, star rating, numeric slider, color selection, and signature capture |
|
|
134
|
+
| Containers (2) | `group`, `repeater` | Hold child components (see below) |
|
|
135
|
+
|
|
136
|
+
**Display components** are presentational and are excluded from FlowData — with one exception: `computed` lives in the display category but *does* emit a value (the result of the calculation it displays).
|
|
137
|
+
|
|
138
|
+
**Options:** Selection components that use options store them as `OptionItem` objects: `{ label, value }` where `label` is what the user sees and `value` (a `string` or `number`) is what gets stored in FlowData. Each option may also carry `metadata` — an arbitrary `Record<string, string | number | boolean>` — for machine-readable data (scores, codes, flags) that calculations and parent applications can use.
|
|
139
|
+
|
|
140
|
+
### Group
|
|
141
|
+
|
|
142
|
+
The `group` type contains its own `components[]` array (containers are recursive — groups can nest). A group is a visual grouping with an optional label; it can be **collapsible** (expand/collapse by the user) and can force its border on or off (`showBorder`).
|
|
143
|
+
|
|
144
|
+
### Repeater
|
|
145
|
+
|
|
146
|
+
The `repeater` type is the repeatable container: the user can add, fill in, and remove multiple iterations of the repeater's child components (e.g., "Add another phone number"). Its properties include `minIterations` (the minimum number of iterations) and `initialData` (pre-populated iteration values). Groups and repeaters can nest inside each other, but repeaters cannot nest inside repeaters.
|
|
147
|
+
|
|
148
|
+
### Component Properties
|
|
149
|
+
|
|
150
|
+
Every component has a `properties` object. Some properties are common across types (like `label`, `width`, `validation`), while others are type-specific (like `options` for selection components, `min`/`max` for sliders, `dateFormat` for date pickers). The full per-type property tables are in [`flow-schema.md`](@sonata-innovations/fiber-types/docs/schema/flow-schema.md).
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## 5. Layout System
|
|
155
|
+
|
|
156
|
+
Each component has an optional `width` property that controls how much horizontal space it occupies:
|
|
157
|
+
|
|
158
|
+
| Width | CSS | Visual |
|
|
159
|
+
|-------|-----|--------|
|
|
160
|
+
| `full` (default) | 100% | Entire row |
|
|
161
|
+
| `half` | 50% | Half row |
|
|
162
|
+
| `third` | 33.33% | One-third |
|
|
163
|
+
| `two-thirds` | 66.67% | Two-thirds |
|
|
164
|
+
| `quarter` | 25% | One-quarter |
|
|
165
|
+
| `three-quarters` | 75% | Three-quarters |
|
|
166
|
+
|
|
167
|
+
**Wrapping behavior:** Components flow left-to-right like text. When components don't fill a row (e.g., two `half` components), they sit side by side. When they exceed a row's width, they wrap to the next line.
|
|
168
|
+
|
|
169
|
+
**Responsive:** Fractional widths are gap-adjusted `calc()` values (e.g. half is `calc(50% - gap/2)`). There is no global full-width collapse breakpoint; a few individual controls (buttons, stepper, yes/no) compact themselves at narrow container widths via CSS container queries — responding to the FBRE container's size, not the viewport.
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## 6. Condition System
|
|
174
|
+
|
|
175
|
+
Conditions control the visibility of components and screens based on the current values of other components in the flow — or on external **context** values supplied by the parent application.
|
|
176
|
+
|
|
177
|
+
### Structure
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
conditions: {
|
|
181
|
+
action: "show" | "hide",
|
|
182
|
+
when: {
|
|
183
|
+
logic: "and" | "or",
|
|
184
|
+
rules: [
|
|
185
|
+
{
|
|
186
|
+
source: "<component-uuid or context key>",
|
|
187
|
+
sourceType: "component" | "context", // optional, defaults to "component"
|
|
188
|
+
operator: "<operator>",
|
|
189
|
+
value: "<test-value>"
|
|
190
|
+
}
|
|
191
|
+
]
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
- **`action`** — What to do when the rules evaluate to true: `show` the target or `hide` it
|
|
197
|
+
- **`logic`** — How to combine multiple rules: `and` (all must match) or `or` (any must match)
|
|
198
|
+
- **`source`** — UUID of the component whose value is being tested, or (with `sourceType: "context"`) the key of an external context value
|
|
199
|
+
- **`sourceType`** — Where the source value comes from: `"component"` (default) tests another component's live value; `"context"` tests a value from FBRE's `context` prop, letting parent-supplied data (user role, tenant flags, etc.) drive visibility
|
|
200
|
+
- **`operator`** — One of 19 comparison operators
|
|
201
|
+
- **`value`** — The value to compare against (omitted for operators that don't need it)
|
|
202
|
+
|
|
203
|
+
### Operators (19)
|
|
204
|
+
|
|
205
|
+
| Category | Operators |
|
|
206
|
+
|----------|-----------|
|
|
207
|
+
| Equality | `equals`, `notEquals` |
|
|
208
|
+
| String | `contains`, `notContains`, `startsWith`, `endsWith` |
|
|
209
|
+
| Empty | `isEmpty`, `isNotEmpty` |
|
|
210
|
+
| Numeric | `greaterThan`, `greaterThanOrEqual`, `lessThan`, `lessThanOrEqual` |
|
|
211
|
+
| Set membership | `isOneOf`, `isNotOneOf` |
|
|
212
|
+
| Array | `includesAny`, `includesAll`, `includesNone` |
|
|
213
|
+
| Boolean | `isTrue`, `isFalse` |
|
|
214
|
+
|
|
215
|
+
### Runtime Effects
|
|
216
|
+
|
|
217
|
+
When a component or screen is hidden by a condition:
|
|
218
|
+
- It is **not rendered** in the UI
|
|
219
|
+
- Its value is **excluded from FlowData** output
|
|
220
|
+
- Its validation rules are **not enforced** (won't block form submission)
|
|
221
|
+
- If it's a screen, navigation automatically skips it
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## 7. Validation System
|
|
226
|
+
|
|
227
|
+
Validation enforces rules on component values before the user can proceed to the next screen or submit the form.
|
|
228
|
+
|
|
229
|
+
### Structure
|
|
230
|
+
|
|
231
|
+
```
|
|
232
|
+
properties: {
|
|
233
|
+
validation: {
|
|
234
|
+
rules: [
|
|
235
|
+
{ type: "<validator>", params: { ... }, message: "Optional custom error" }
|
|
236
|
+
]
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Each rule has a `type` (the validator name), optional `params` (validator-specific configuration), and an optional `message` (custom error text that overrides the default).
|
|
242
|
+
|
|
243
|
+
### Validators (17)
|
|
244
|
+
|
|
245
|
+
| Validator | Params | Purpose |
|
|
246
|
+
|-----------|--------|---------|
|
|
247
|
+
| `required` | — | Field must have a non-empty value |
|
|
248
|
+
| `email` | — | Valid email format |
|
|
249
|
+
| `phone` | — | Valid phone format |
|
|
250
|
+
| `url` | — | Valid URL format |
|
|
251
|
+
| `minLength` | `{ min }` | Minimum character count |
|
|
252
|
+
| `maxLength` | `{ max }` | Maximum character count |
|
|
253
|
+
| `exactLength` | `{ length }` | Exact character count |
|
|
254
|
+
| `minValue` | `{ min }` | Minimum numeric value |
|
|
255
|
+
| `maxValue` | `{ max }` | Maximum numeric value |
|
|
256
|
+
| `pattern` | `{ pattern }` | Regex pattern match |
|
|
257
|
+
| `minSelected` | `{ min }` | Minimum selected options (checkbox/multi-select) |
|
|
258
|
+
| `maxSelected` | `{ max }` | Maximum selected options |
|
|
259
|
+
| `fileType` | `{ types[] }` | Allowed MIME types |
|
|
260
|
+
| `fileSize` | `{ max }` | Maximum file size in bytes |
|
|
261
|
+
| `contains` | `{ text }` | Must contain substring |
|
|
262
|
+
| `excludes` | `{ text }` | Must not contain substring |
|
|
263
|
+
| `matchesField` | `{ field }` | Must match another component's value (by UUID) |
|
|
264
|
+
|
|
265
|
+
### Validation Timing
|
|
266
|
+
|
|
267
|
+
- Validation runs when the user attempts to navigate forward (next button or submission)
|
|
268
|
+
- If `config.navigation.allowInvalidTransition` is false (default), the user cannot proceed past an invalid screen
|
|
269
|
+
- Components hidden by conditions are not validated
|
|
270
|
+
- `matchesField` enables cross-field validation (e.g., "confirm email must match email")
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## 8. Calculations
|
|
275
|
+
|
|
276
|
+
Calculations are named formulas defined at the flow level (`Flow.calculations[]`) that compute numeric results from component values as the user fills in the form.
|
|
277
|
+
|
|
278
|
+
- Each calculation has a `uuid`, `label`, and a `formula` — an expression over component values referenced by UUID, supporting arithmetic and aggregate functions
|
|
279
|
+
- Optional formatting: `format` (`"number"`, `"currency"`, `"percentage"`), `decimalPlaces`, `currencySymbol`
|
|
280
|
+
- Results update live as the user types
|
|
281
|
+
- The `computed` display component shows a calculation's result inline in the form
|
|
282
|
+
- `${uuid}` reference markup (see Section 10) can interpolate calculation results into text
|
|
283
|
+
- Results are emitted in FlowData under a top-level `calculations[]` array (see Section 9)
|
|
284
|
+
|
|
285
|
+
The formula engine lives in `@sonata-innovations/fiber-shared`, so calculations evaluate identically in FBRE, in FBT's preview, and on the server.
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## 9. Data Flow: End to End
|
|
290
|
+
|
|
291
|
+
### Authoring Phase (FBT or FBTL)
|
|
292
|
+
|
|
293
|
+
1. A form author opens **FBT** (power users) or **FBTL** (non-technical end users) in a parent application
|
|
294
|
+
2. They assemble the flow — FBT via multi-screen drag-and-drop with the full component palette; FBTL via a flat, one-question-per-screen list limited to five question types plus Information Screens
|
|
295
|
+
3. The builder produces a Flow JSON object via the `onFlowChange` callback (FBT also exposes `exportFlow()` on the store)
|
|
296
|
+
4. The parent application saves the Flow JSON (to a database, file, API, etc.)
|
|
297
|
+
|
|
298
|
+
FBTL emits a flow with one component per screen (conversational mode) and promotes component-level conditions to screen-level conditions on emit. Loading a multi-screen flow into FBTL flattens it into the one-per-screen shape on the next save, while preserving all advanced properties (calculations, reference markup, multi-rule conditions, etc.) that FBTL itself cannot edit. The resulting JSON remains fully interoperable with FBT.
|
|
299
|
+
|
|
300
|
+
### Rendering Phase (FBRE)
|
|
301
|
+
|
|
302
|
+
1. The parent application loads the saved Flow JSON and passes it to FBRE (as a prop, or via one of the remote modes — see Section 13)
|
|
303
|
+
2. FBRE renders the form screen by screen
|
|
304
|
+
3. The end user fills in the form, navigating between screens
|
|
305
|
+
4. On the final screen, the user submits the form
|
|
306
|
+
5. FBRE calls `onFlowComplete` with the collected FlowData
|
|
307
|
+
|
|
308
|
+
### FlowData Structure
|
|
309
|
+
|
|
310
|
+
FlowData mirrors the Flow hierarchy but contains only collected values:
|
|
311
|
+
|
|
312
|
+
```
|
|
313
|
+
FlowData
|
|
314
|
+
├── uuid — Same as the flow's UUID
|
|
315
|
+
├── metadata — Same as the flow's metadata
|
|
316
|
+
├── calculations[] — Present when the flow defines calculations
|
|
317
|
+
│ ├── uuid — Calculation UUID
|
|
318
|
+
│ ├── label — Calculation label
|
|
319
|
+
│ ├── value — Computed numeric result (or null)
|
|
320
|
+
│ └── formattedValue — Formatted string (e.g., "$1,250.00"), when computed
|
|
321
|
+
└── screens[]
|
|
322
|
+
├── uuid — Screen UUID
|
|
323
|
+
├── label — Screen label
|
|
324
|
+
└── components[]
|
|
325
|
+
├── uuid — Component UUID
|
|
326
|
+
├── type — Component type
|
|
327
|
+
├── label — Component label
|
|
328
|
+
├── value — The collected value (type varies by component)
|
|
329
|
+
└── components[][] — Containers only: child data, one inner array per iteration
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
**Containers in FlowData:** `group` and `repeater` components appear as their own entries carrying a nested `components` field typed `ComponentData[][]` — an array of iterations, each an array of child component data. A group always has exactly one iteration; a repeater has one inner array per iteration the user filled in.
|
|
333
|
+
|
|
334
|
+
**What's excluded from FlowData:**
|
|
335
|
+
- Display components (`header`, `text`, `divider`, `callout`, `table`) — they don't collect data (`computed` *is* included, with its calculated value)
|
|
336
|
+
- Components hidden by conditions — their values are not relevant
|
|
337
|
+
- Screens hidden by conditions — all their components are excluded
|
|
338
|
+
|
|
339
|
+
The full output schema is documented in [`flow-data-schema.md`](@sonata-innovations/fiber-types/docs/schema/flow-data-schema.md).
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
## 10. Theming and Presentation
|
|
344
|
+
|
|
345
|
+
### CSS Custom Properties
|
|
346
|
+
|
|
347
|
+
FBRE uses CSS custom properties for theming. Parent applications can override these on the `.fbre-container` element:
|
|
348
|
+
|
|
349
|
+
- **Colors:** `--fbre-theme-color`, `--fbre-error`, `--fbre-text`, `--fbre-border`, `--fbre-bg`, `--fbre-surface` (and light/dark/secondary variants)
|
|
350
|
+
- **Sizing:** `--fbre-radius` (border radius)
|
|
351
|
+
- **Typography:** `--fbre-font` (font family)
|
|
352
|
+
- **Animation:** `--fbre-transition-duration`, `--fbre-transition-easing`
|
|
353
|
+
|
|
354
|
+
### Color Scheme
|
|
355
|
+
|
|
356
|
+
Selected via the `theme` prop on FBRE (`{ colorScheme: "dark" }`) or `config.theme.colorScheme` in the Flow JSON (default `"light"`). The prop takes precedence. The scheme seeds a built-in palette preset (all `--fbre-*` tokens shift to light- or dark-appropriate values); palette knobs and raw CSS-variable overrides then layer on top. Replaces the former `darkMode` boolean.
|
|
357
|
+
|
|
358
|
+
For the full theming model — palette knobs, the override precedence, and the complete `--fbre-*` token catalog — see the [FBRE Theming Guide](features/fbre-theming.md).
|
|
359
|
+
|
|
360
|
+
### Screen Transitions
|
|
361
|
+
|
|
362
|
+
Six animation types for transitions between screens:
|
|
363
|
+
|
|
364
|
+
| Type | Effect |
|
|
365
|
+
|------|--------|
|
|
366
|
+
| `none` | Instant switch (default) |
|
|
367
|
+
| `slide` | Horizontal slide left/right |
|
|
368
|
+
| `fade` | Cross-fade |
|
|
369
|
+
| `slideFade` | Slide combined with fade |
|
|
370
|
+
| `rise` | Vertical rise with fade |
|
|
371
|
+
| `scaleFade` | Scale up/down with fade |
|
|
372
|
+
|
|
373
|
+
Set via `config.navigation.transition` in the Flow JSON.
|
|
374
|
+
|
|
375
|
+
### Inline Markup
|
|
376
|
+
|
|
377
|
+
`text` components and `detail` property fields support lightweight inline formatting:
|
|
378
|
+
- `[b]bold[/b]` renders as **bold**
|
|
379
|
+
- `[i]italic[/i]` renders as *italic*
|
|
380
|
+
- `[s size="sm|lg|xl"]sized text[/s]` renders at a preset font size
|
|
381
|
+
- `[l href="url"]link text[/l]` renders as a hyperlink
|
|
382
|
+
|
|
383
|
+
The markup → HTML converter lives in `@sonata-innovations/fiber-shared`, shared by FBRE (render), FBT (preview), and the server.
|
|
384
|
+
|
|
385
|
+
### Reference Markup
|
|
386
|
+
|
|
387
|
+
`${...}` tokens interpolate live values into text. A token is resolved in order against: **calculations** (by UUID) → **component values** (by UUID) → **context** (by key, from FBRE's `context` prop). Unresolvable references render as empty. This powers dynamic text like "Your total is ${calc-uuid}" or "Welcome back, ${userName}".
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
391
|
+
## 11. Extension Points
|
|
392
|
+
|
|
393
|
+
### Custom Presets
|
|
394
|
+
|
|
395
|
+
Presets are pre-configured component templates that appear in FBT's component palette. They let teams create reusable field patterns (e.g., "Phone Number" = inputText with phone validation and placeholder).
|
|
396
|
+
|
|
397
|
+
A preset is **serializable data** — a `PresetData` object (`{ type, label, icon, components }`) where `components` is a plain array of `Component` JSON. Because presets are data, they can be stored anywhere JSON can: in code, in a file, or in a database. When a preset is dropped onto the stage, FBT regenerates every UUID in the copy, so the same preset can be used many times without ID collisions.
|
|
398
|
+
|
|
399
|
+
### Custom Templates
|
|
400
|
+
|
|
401
|
+
Templates are complete pre-built flows (multiple screens with components). They let teams provide starting points for common form patterns (e.g., "Employee Onboarding", "Patient Intake").
|
|
402
|
+
|
|
403
|
+
A template is likewise data — a `TemplateData` object (`{ type, label, icon, flow }`) holding a complete `Flow`. Loading a template replaces the current flow in FBT, with all UUIDs regenerated.
|
|
404
|
+
|
|
405
|
+
### Data-First Design
|
|
406
|
+
|
|
407
|
+
Presets and templates being plain data (rather than code) is what enables server-side storage: the hosted platform stores tenant-scoped custom presets and templates in the database and serves them to FBT at load time. Older factory-function definitions (functions returning fresh `Component`/`Flow` objects) are still accepted for back-compat, but data-based definitions are the current model.
|
|
408
|
+
|
|
409
|
+
See [`custom-presets-and-templates.md`](@sonata-innovations/fiber-fbt/docs/features/custom-presets-and-templates.md) for the full authoring guide.
|
|
410
|
+
|
|
411
|
+
---
|
|
412
|
+
|
|
413
|
+
## 12. Key Architectural Decisions
|
|
414
|
+
|
|
415
|
+
### Zustand Stores
|
|
416
|
+
|
|
417
|
+
FBT, FBTL, and FBRE all use Zustand for state management. Each component instance creates its own isolated store, so multiple instances on the same page don't conflict.
|
|
418
|
+
|
|
419
|
+
### Shared Engine Layer
|
|
420
|
+
|
|
421
|
+
Condition evaluation, validation, markup conversion, and formula evaluation live in `@sonata-innovations/fiber-shared` — a dependency of both the client libraries and the server. This is the key to the "same rules evaluate anywhere" mental model: a condition behaves identically in FBRE running in a browser and in the server evaluating a session screen-by-screen.
|
|
422
|
+
|
|
423
|
+
### Component Registry
|
|
424
|
+
|
|
425
|
+
FBRE uses a registry pattern to map component types to their React renderers. Each component type registers itself, and a dispatcher looks up the correct renderer at runtime. This makes the system extensible — adding a new component type means registering a new entry.
|
|
426
|
+
|
|
427
|
+
### Flattened Store Architecture
|
|
428
|
+
|
|
429
|
+
Components are stored in a flat `Record<string, Component>` map (keyed by UUID), not nested inside screens. Separate index maps (`screenComponents`, `groupComponents`) track parent-child relationships. This makes lookups O(1) and avoids deep cloning when updating nested structures.
|
|
430
|
+
|
|
431
|
+
### No Runtime Auto-Migration
|
|
432
|
+
|
|
433
|
+
There is no runtime auto-migration: legacy (pre-v2) flows — old condition/validation formats, group `layout` strings, deprecated component types — must be migrated to the current schema before being loaded.
|
|
434
|
+
|
|
435
|
+
### Container Queries
|
|
436
|
+
|
|
437
|
+
Where components adapt to narrow spaces (compact button/stepper sizing, yes/no stacking), they use CSS container queries rather than media queries. The layout responds to the FBRE container's width, not the browser viewport — critical for embedded use cases where the form may occupy a sidebar or modal.
|
|
438
|
+
|
|
439
|
+
---
|
|
440
|
+
|
|
441
|
+
## 13. Integration Modes and Platform
|
|
442
|
+
|
|
443
|
+
### FBRE's Three Integration Modes
|
|
444
|
+
|
|
445
|
+
FBRE accepts a flow through one of three mutually exclusive prop shapes:
|
|
446
|
+
|
|
447
|
+
1. **Local flow** — `<FBRE flow={flowJson} />`. The parent owns storage and passes the Flow JSON directly. The simplest and most common mode.
|
|
448
|
+
2. **Remote flow** — `<FBRE flowId="..." apiEndpoint="..." />`. FBRE fetches a published flow from a Fiber server and renders it client-side. All evaluation (conditions, validation, calculations) still happens in the browser.
|
|
449
|
+
3. **Server-driven** — `<FBRE flowId="..." sessionEndpoint="..." />`. FBRE starts a session and receives one screen at a time; the server evaluates conditions and validation between screens (using the same `fiber-shared` engines) and assembles the final FlowData. The full flow definition never reaches the client — useful for sensitive branching logic and server-side integrations between screens.
|
|
450
|
+
|
|
451
|
+
### Conversational Mode
|
|
452
|
+
|
|
453
|
+
Setting `config.mode: "conversational"` (or the FBRE `mode` prop) renders the flow one question at a time in a chat-like presentation instead of the standard screen-per-page layout. Same Flow JSON, same condition/validation/FlowData behavior — only the presentation changes. FBTL authors flows in this shape by default.
|
|
454
|
+
|
|
455
|
+
### Confirmation Screen
|
|
456
|
+
|
|
457
|
+
`config.confirmation` (`{ show, title, body }`) defines a terminal "thank you" screen shown after submission. Title and body support inline and reference markup, resolved against collected values and context. The parent can also drive it dynamically: `onFlowComplete` may return nothing (`void`), a `Promise` (the submit button stays in-flight until it settles), or a `ConfirmationResult` (directly or via the Promise) that overrides the configured message — e.g., to show a server-generated reference number. A rejected Promise surfaces as a completion error and the confirmation is not shown.
|
|
458
|
+
|
|
459
|
+
### Hosted Platform
|
|
460
|
+
|
|
461
|
+
The private packages (**server**, **portal**, **hosted**) form a hosted form service built on the public libraries: tenant-scoped flow storage and publishing, custom preset/template storage, file upload hosting, submission management, session-based server-driven rendering, and a hosted form-filling app. The libraries remain free and self-sufficient; the platform is the product layered on top.
|