@cxtms/cx-schema 1.9.67 → 1.9.242
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +43 -9
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/schemas/actions/all.json +5 -1
- package/schemas/actions/reload.json +17 -0
- package/schemas/actions/setSessionStorage.json +38 -0
- package/schemas/actions/sound.json +39 -0
- package/schemas/actions/vibrate.json +48 -0
- package/schemas/components/avatar.json +1 -0
- package/schemas/components/badge.json +79 -0
- package/schemas/components/barcodeScanner.json +28 -0
- package/schemas/components/camera.json +177 -0
- package/schemas/components/card.json +78 -0
- package/schemas/components/dashboard-widget.json +39 -0
- package/schemas/components/dashboard.json +46 -0
- package/schemas/components/dataGrid.json +15 -0
- package/schemas/components/field-collection.json +86 -2
- package/schemas/components/field.json +39 -4
- package/schemas/components/form.json +4 -0
- package/schemas/components/index.json +17 -1
- package/schemas/components/infoLine.json +1 -0
- package/schemas/components/map.json +167 -0
- package/schemas/components/module.json +32 -0
- package/schemas/components/planner.json +1 -0
- package/schemas/components/progressBar.json +1 -0
- package/schemas/components/timeline.json +216 -74
- package/schemas/components/timelineGrid.json +5 -1
- package/schemas/fields/autocomplete-googleplaces.json +2 -2
- package/schemas/fields/datetime.json +2 -2
- package/schemas/fields/index.json +4 -0
- package/schemas/fields/number-select.json +88 -0
- package/schemas/fields/rangedatetime.json +10 -2
- package/schemas/fields/select-async.json +2 -2
- package/schemas/fields/toggle.json +91 -0
- package/schemas/schema.graphql +11016 -12171
- package/schemas/schemas.json +131 -4
- package/schemas/workflows/flow/entity.json +3 -1
- package/schemas/workflows/input.json +1 -1
- package/schemas/workflows/output.json +1 -1
- package/schemas/workflows/tasks/all.json +9 -0
- package/schemas/workflows/tasks/commodity.json +8 -0
- package/schemas/workflows/tasks/contact-address.json +25 -0
- package/schemas/workflows/tasks/dispatch-routes.json +64 -0
- package/schemas/workflows/tasks/edi.json +15 -0
- package/schemas/workflows/tasks/export.json +21 -0
- package/schemas/workflows/tasks/httpRequest.json +4 -0
- package/schemas/workflows/tasks/import.json +5 -0
- package/schemas/workflows/tasks/order-move.json +38 -0
- package/schemas/workflows/tasks/order.json +6 -0
- package/schemas/workflows/tasks/organization-config.json +101 -0
- package/schemas/workflows/tasks/tracking-event.json +11 -3
- package/schemas/workflows/tasks/workflow-execute.json +4 -0
- package/schemas/workflows/variable.json +2 -2
- package/schemas/workflows/workflow.json +39 -2
- package/skills/cxtms-developer/SKILL.md +5 -2
- package/skills/cxtms-developer/ref-cli-auth.md +2 -0
- package/skills/cxtms-developer/ref-entity-commodity.md +41 -5
- package/skills/cxtms-developer/ref-entity-contact.md +46 -0
- package/skills/cxtms-developer/ref-entity-dispatch-routing.md +195 -0
- package/skills/cxtms-developer/ref-entity-geography.md +26 -1
- package/skills/cxtms-developer/ref-entity-job.md +6 -2
- package/skills/cxtms-developer/ref-entity-order-sub.md +1 -1
- package/skills/cxtms-developer/ref-entity-order.md +38 -3
- package/skills/cxtms-developer/ref-entity-organization.md +4 -2
- package/skills/cxtms-developer/ref-entity-shared.md +79 -3
- package/skills/cxtms-developer/ref-graphql-query.md +246 -4
- package/skills/cxtms-module-builder/SKILL.md +33 -6
- package/skills/cxtms-module-builder/ref-components-data.md +85 -0
- package/skills/cxtms-module-builder/ref-components-display.md +282 -8
- package/skills/cxtms-module-builder/ref-components-forms.md +386 -21
- package/skills/cxtms-module-builder/ref-components-interactive.md +2 -0
- package/skills/cxtms-module-builder/ref-components-layout.md +288 -29
- package/skills/cxtms-module-builder/ref-components-specialized.md +168 -20
- package/skills/cxtms-workflow-builder/SKILL.md +45 -6
- package/skills/cxtms-workflow-builder/ref-entity.md +100 -4
- package/skills/cxtms-workflow-builder/ref-expressions-ncalc.md +35 -2
- package/skills/cxtms-workflow-builder/ref-expressions-template.md +15 -1
- package/skills/cxtms-workflow-builder/ref-flow.md +6 -1
- package/skills/cxtms-workflow-builder/ref-query.md +16 -0
- package/skills/cxtms-workflow-builder/ref-utilities.md +32 -2
- package/templates/workflow-public-api.yaml +1 -0
|
@@ -1,11 +1,217 @@
|
|
|
1
1
|
# Form & Input Components
|
|
2
2
|
|
|
3
3
|
## Contents
|
|
4
|
+
- Mobile-friendly form layout (adaptive design)
|
|
4
5
|
- Form component
|
|
5
6
|
- Field component
|
|
6
7
|
- FieldCollection component
|
|
7
8
|
- BarcodeScanner component
|
|
8
9
|
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Mobile-Friendly Form Layout
|
|
13
|
+
|
|
14
|
+
> See **`ref-components-layout.md` → Adaptive / Responsive Design** for breakpoint definitions and the full responsive prop reference. This section covers form-specific patterns.
|
|
15
|
+
|
|
16
|
+
`form` itself is a flexbox column — children stack top-to-bottom with no horizontal flow. To create responsive multi-column forms (one column on mobile, two on tablet, etc.), wrap fields in a `layout` child and use **modern MUI Grid v2 spacing** (`columnSpacing` + `rowSpacing`, both responsive) plus `itemDefaults.size`.
|
|
17
|
+
|
|
18
|
+
> **Do NOT** use `cols: N`, the `row` component, or CSS `className`s for form layout. Use `layout` + `size` + `columnSpacing`/`rowSpacing` + `sx` only.
|
|
19
|
+
|
|
20
|
+
### Pattern 1 — Responsive 2-column form (1 column on mobile)
|
|
21
|
+
|
|
22
|
+
```yaml
|
|
23
|
+
component: form
|
|
24
|
+
name: contactForm
|
|
25
|
+
props:
|
|
26
|
+
validationSchema:
|
|
27
|
+
firstName: { type: string, required: true }
|
|
28
|
+
lastName: { type: string, required: true }
|
|
29
|
+
email: { type: string, required: true }
|
|
30
|
+
children:
|
|
31
|
+
- component: layout
|
|
32
|
+
name: contactFields
|
|
33
|
+
props:
|
|
34
|
+
columnSpacing: { xs: 1, md: 2 } # tighter horizontal gap on mobile
|
|
35
|
+
rowSpacing: { xs: 2, md: 3 } # comfortable vertical breathing room
|
|
36
|
+
itemDefaults:
|
|
37
|
+
size: { xs: 12, md: 6 } # 1 col mobile, 2 col tablet+
|
|
38
|
+
children:
|
|
39
|
+
- component: field
|
|
40
|
+
name: firstName
|
|
41
|
+
props: { type: text, label: { en-US: "First Name" } }
|
|
42
|
+
- component: field
|
|
43
|
+
name: lastName
|
|
44
|
+
props: { type: text, label: { en-US: "Last Name" } }
|
|
45
|
+
- component: field
|
|
46
|
+
name: email
|
|
47
|
+
props:
|
|
48
|
+
type: email
|
|
49
|
+
label: { en-US: "Email" }
|
|
50
|
+
size: { xs: 12 } # always full width
|
|
51
|
+
- component: field
|
|
52
|
+
name: notes
|
|
53
|
+
props:
|
|
54
|
+
type: textarea
|
|
55
|
+
label: { en-US: "Notes" }
|
|
56
|
+
rows: 4
|
|
57
|
+
size: { xs: 12 } # textareas always full width
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Pattern 2 — Three-tier form (1 / 2 / 3 columns)
|
|
61
|
+
|
|
62
|
+
```yaml
|
|
63
|
+
component: form
|
|
64
|
+
name: productForm
|
|
65
|
+
props:
|
|
66
|
+
validationSchema:
|
|
67
|
+
sku: { type: string, required: true }
|
|
68
|
+
children:
|
|
69
|
+
- component: layout
|
|
70
|
+
props:
|
|
71
|
+
columnSpacing: { xs: 1, sm: 2, md: 3 }
|
|
72
|
+
rowSpacing: { xs: 2, md: 3 }
|
|
73
|
+
itemDefaults:
|
|
74
|
+
size: { xs: 12, sm: 6, lg: 4 } # phone: 1 col, tablet: 2 col, desktop: 3 col
|
|
75
|
+
children:
|
|
76
|
+
- component: field
|
|
77
|
+
name: sku
|
|
78
|
+
props: { type: text, label: { en-US: "SKU" } }
|
|
79
|
+
- component: field
|
|
80
|
+
name: name
|
|
81
|
+
props: { type: text, label: { en-US: "Name" } }
|
|
82
|
+
- component: field
|
|
83
|
+
name: price
|
|
84
|
+
props: { type: number, label: { en-US: "Price" } }
|
|
85
|
+
- component: field
|
|
86
|
+
name: weight
|
|
87
|
+
props: { type: number, label: { en-US: "Weight" } }
|
|
88
|
+
- component: field
|
|
89
|
+
name: status
|
|
90
|
+
props: { type: select, label: { en-US: "Status" } }
|
|
91
|
+
- component: field
|
|
92
|
+
name: category
|
|
93
|
+
props: { type: select, label: { en-US: "Category" } }
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Pattern 3 — Section cards that reflow
|
|
97
|
+
|
|
98
|
+
Group related fields into cards. The cards stack on mobile and sit side-by-side on desktop.
|
|
99
|
+
|
|
100
|
+
```yaml
|
|
101
|
+
component: form
|
|
102
|
+
name: orderForm
|
|
103
|
+
props:
|
|
104
|
+
validationSchema: { orderNumber: { type: string, required: true } }
|
|
105
|
+
children:
|
|
106
|
+
- component: layout
|
|
107
|
+
props:
|
|
108
|
+
spacing: { xs: 2, md: 3 } # uniform gap between cards
|
|
109
|
+
itemDefaults:
|
|
110
|
+
size: { xs: 12, lg: 6 } # cards stack on phone/tablet, split on desktop
|
|
111
|
+
children:
|
|
112
|
+
- component: card
|
|
113
|
+
name: customerCard
|
|
114
|
+
props:
|
|
115
|
+
options:
|
|
116
|
+
variant: outlined
|
|
117
|
+
header: { title: "Customer" }
|
|
118
|
+
children:
|
|
119
|
+
- component: layout
|
|
120
|
+
props:
|
|
121
|
+
columnSpacing: { xs: 1, md: 2 }
|
|
122
|
+
rowSpacing: 2
|
|
123
|
+
itemDefaults:
|
|
124
|
+
size: { xs: 12, sm: 6 }
|
|
125
|
+
children:
|
|
126
|
+
- component: field
|
|
127
|
+
name: customerId
|
|
128
|
+
props: { type: select-async, label: { en-US: "Customer" } }
|
|
129
|
+
- component: field
|
|
130
|
+
name: poNumber
|
|
131
|
+
props: { type: text, label: { en-US: "PO #" } }
|
|
132
|
+
- component: card
|
|
133
|
+
name: shippingCard
|
|
134
|
+
props:
|
|
135
|
+
options:
|
|
136
|
+
variant: outlined
|
|
137
|
+
header: { title: "Shipping" }
|
|
138
|
+
children:
|
|
139
|
+
- component: layout
|
|
140
|
+
props:
|
|
141
|
+
columnSpacing: { xs: 1, md: 2 }
|
|
142
|
+
rowSpacing: 2
|
|
143
|
+
itemDefaults:
|
|
144
|
+
size: { xs: 12, sm: 6 }
|
|
145
|
+
children:
|
|
146
|
+
- component: field
|
|
147
|
+
name: shipDate
|
|
148
|
+
props: { type: date, label: { en-US: "Ship Date" } }
|
|
149
|
+
- component: field
|
|
150
|
+
name: carrier
|
|
151
|
+
props: { type: select, label: { en-US: "Carrier" } }
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Pattern 4 — Paired fields that wrap together
|
|
155
|
+
|
|
156
|
+
Fields that belong together (qty + uom, from + to dates, address city/state/zip) should share breakpoints so they always wrap as a unit. Use a responsive `columns` total to pack 3 short fields into a single mobile row.
|
|
157
|
+
|
|
158
|
+
```yaml
|
|
159
|
+
- component: layout
|
|
160
|
+
props:
|
|
161
|
+
columns: { xs: 12, md: 12 }
|
|
162
|
+
columnSpacing: { xs: 1, md: 2 }
|
|
163
|
+
rowSpacing: 2
|
|
164
|
+
children:
|
|
165
|
+
- component: field
|
|
166
|
+
name: quantity
|
|
167
|
+
props: { type: number, label: { en-US: "Qty" }, size: { xs: 4 } }
|
|
168
|
+
- component: field
|
|
169
|
+
name: uom
|
|
170
|
+
props: { type: select, label: { en-US: "UOM" }, size: { xs: 4 } }
|
|
171
|
+
- component: field
|
|
172
|
+
name: weight
|
|
173
|
+
props: { type: number, label: { en-US: "Weight" }, size: { xs: 4 } }
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Pattern 5 — Toolbar that adapts
|
|
177
|
+
|
|
178
|
+
```yaml
|
|
179
|
+
- component: layout
|
|
180
|
+
name: formActions
|
|
181
|
+
props:
|
|
182
|
+
columnSpacing: { xs: 1, md: 2 }
|
|
183
|
+
sx: { justifyContent: { xs: 'space-between', md: 'flex-end' } }
|
|
184
|
+
children:
|
|
185
|
+
- component: button
|
|
186
|
+
name: cancel
|
|
187
|
+
props: { label: { en-US: "Cancel" }, variant: outlined }
|
|
188
|
+
- component: button
|
|
189
|
+
name: save
|
|
190
|
+
props: { label: { en-US: "Save" }, options: { type: submit, variant: primary } }
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Form mobile checklist
|
|
194
|
+
|
|
195
|
+
- **Default to 1 column on `xs`** — never assume horizontal space. Use `itemDefaults.size: { xs: 12, ... }`.
|
|
196
|
+
- **2 columns on `md+`** for paired short fields (firstName/lastName, qty/uom, from/to).
|
|
197
|
+
- **Long fields full-width**: `textarea`, `quill`, `attachment`, `notes`, multi-line inputs → `size: { xs: 12 }`.
|
|
198
|
+
- **Cap visible columns**: max 2 on `sm`, max 3 on `md`, max 4 on `lg`. More than that overcrowds.
|
|
199
|
+
- **Group with cards** when a form has 3+ logical sections — gives clear visual breaks on mobile and reflow targets on desktop.
|
|
200
|
+
- **Use the modern Grid spacing pattern**: `columnSpacing` + `rowSpacing` (responsive maps) over the legacy single-number `spacing`. Tighter columns on phones, comfortable rows always.
|
|
201
|
+
- **Toolbar on phones**: prefer `space-between` (cancel left, save right) so primary action stays in the thumb zone. Switch to `flex-end` on `md+`.
|
|
202
|
+
- **Validation messages** appear under the field — make sure `helperText` length doesn't break tight 2-col `sm` layouts.
|
|
203
|
+
- **Tap targets ≥ 44px**: don't set `size: small` on primary buttons / interactive fields on `xs`.
|
|
204
|
+
|
|
205
|
+
### What NOT to do in form layouts
|
|
206
|
+
|
|
207
|
+
- ❌ `cols: N` on `form` (or anywhere) — non-responsive, ignored on mobile.
|
|
208
|
+
- ❌ `row` component for new layouts — use `layout`.
|
|
209
|
+
- ❌ `className: "row"` / `className: "col-md-6"` / any Bootstrap-style class — these don't affect MUI Grid sizing. Use `size` + `columns` instead.
|
|
210
|
+
- ❌ Custom CSS classes on `layout` / `row` / `col` for sizing or spacing — those props belong on `size`, `spacing`, `rowSpacing`, `columnSpacing`, `sx`, or `containerSx`.
|
|
211
|
+
- ❌ Mixing `spacing` with explicit `rowSpacing` AND `columnSpacing` (the explicit ones override).
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
9
215
|
## form
|
|
10
216
|
|
|
11
217
|
Data entry form with validation, queries, and submission. Wraps React Hook Form's FormProvider.
|
|
@@ -21,6 +227,7 @@ Data entry form with validation, queries, and submission. Wraps React Hook Form'
|
|
|
21
227
|
| `queries` | `QueryDef[]` | GraphQL queries for data loading |
|
|
22
228
|
| `prefix` | `string` | Field name namespace prefix |
|
|
23
229
|
| `refreshHandler` | `string` | Remount on refresh event |
|
|
230
|
+
| `reloadHandler` | `string` | Refetch target; falls back to `refreshHandler`, then form name |
|
|
24
231
|
| `dirtyGuard` | `DirtyGuardProps` | Unsaved changes protection |
|
|
25
232
|
| `dirtyGuard.enabled` | `boolean` | Enable guard |
|
|
26
233
|
| `dirtyGuard.title` | `ILocalizeString` | Dialog title |
|
|
@@ -31,7 +238,7 @@ Data entry form with validation, queries, and submission. Wraps React Hook Form'
|
|
|
31
238
|
| `resetOnSubmit` | `boolean` | Reset form after submit |
|
|
32
239
|
| `preventDefault` | `boolean` | Prevent default form submit |
|
|
33
240
|
| `toolbar` | `component[]` | Toolbar components |
|
|
34
|
-
|
|
|
241
|
+
| ~~`cols: N`~~ | _legacy_ | **Do not use.** Non-responsive. Wrap children in a `layout` with `itemDefaults.size: { xs: 12, md: 6 }` instead. See "Mobile-Friendly Form Layout" above. |
|
|
35
242
|
| `orientation` | `string` | Layout orientation |
|
|
36
243
|
|
|
37
244
|
**Events:**
|
|
@@ -46,6 +253,10 @@ Data entry form with validation, queries, and submission. Wraps React Hook Form'
|
|
|
46
253
|
|
|
47
254
|
**Children:** Yes — typically `field` components. Provides `formName` and `createMode` in variables.
|
|
48
255
|
|
|
256
|
+
Named forms expose `{{<formName>.dirty}}` in action templates. The value compares current fields with the last loaded `initialValues`, treats `null`, `undefined`, and `''` as equivalent empty values, and resets after reload. It is not available to component visibility or disabled templates.
|
|
257
|
+
|
|
258
|
+
Use `- reload: orderForm` to refetch and replace a mounted form's `initialValues` without remounting its children. Reload discards unsaved edits; `refresh` keeps current values and only recomputes the component. Multiple reload targets are supported as an array. Dialog `onClose` actions can read values written inside the dialog as well as the caller store, allowing reloads to be conditional.
|
|
259
|
+
|
|
49
260
|
```yaml
|
|
50
261
|
component: form
|
|
51
262
|
name: orderForm
|
|
@@ -98,17 +309,25 @@ props:
|
|
|
98
309
|
- notification: { message: { en-US: "Saved!" }, type: success }
|
|
99
310
|
- navigateBack: { fallback: "/orders" }
|
|
100
311
|
children:
|
|
101
|
-
- component:
|
|
102
|
-
name:
|
|
103
|
-
props: { type: text, label: { en-US: "Order Number" }, required: true }
|
|
104
|
-
- component: field
|
|
105
|
-
name: status
|
|
312
|
+
- component: layout
|
|
313
|
+
name: orderFormFields
|
|
106
314
|
props:
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
315
|
+
columnSpacing: { xs: 1, md: 2 } # tighter on mobile, breathing room on desktop
|
|
316
|
+
rowSpacing: { xs: 2, md: 3 }
|
|
317
|
+
itemDefaults:
|
|
318
|
+
size: { xs: 12, md: 6 } # 1 col on phone, 2 col on tablet+
|
|
319
|
+
children:
|
|
320
|
+
- component: field
|
|
321
|
+
name: orderNumber
|
|
322
|
+
props: { type: text, label: { en-US: "Order Number" }, required: true }
|
|
323
|
+
- component: field
|
|
324
|
+
name: status
|
|
325
|
+
props:
|
|
326
|
+
type: select
|
|
327
|
+
label: { en-US: "Status" }
|
|
328
|
+
items:
|
|
329
|
+
- { label: "Draft", value: "Draft" }
|
|
330
|
+
- { label: "Active", value: "Active" }
|
|
112
331
|
```
|
|
113
332
|
|
|
114
333
|
---
|
|
@@ -134,22 +353,33 @@ Polymorphic form field — renders different input types based on `type` prop.
|
|
|
134
353
|
| `defaultCountry` | `string` | Default country for phone type |
|
|
135
354
|
| `isClearable` | `boolean` | Allow clearing the value |
|
|
136
355
|
| `InputProps` | `object` | Passed to underlying MUI TextField |
|
|
356
|
+
| `size` | `number \| {xs,sm,md,lg,xl}` | When the field is a child of a `layout`, controls the Grid item width per breakpoint. Use `{ xs: 12, md: 6 }` for 1-col mobile / 2-col tablet+. Omit to inherit `itemDefaults.size` from parent layout. |
|
|
357
|
+
| `offset` | `number \| {xs,sm,md,lg,xl}` | Leading offset (push field right) when inside a `layout` |
|
|
358
|
+
| `order` | `number \| {xs,sm,md,lg,xl}` | Visual order per breakpoint when inside a `layout` |
|
|
359
|
+
|
|
360
|
+
Password fields receive a stable input id from the field name unless an explicit `id` is provided. This keeps multiple password fields in the same form isolated for browser autocomplete. Use `autoComplete` when a form needs a specific password-manager hint.
|
|
137
361
|
|
|
138
362
|
**Field Types:**
|
|
139
363
|
| Type | Description |
|
|
140
364
|
|------|-------------|
|
|
141
365
|
| `text` | Standard text input. `multiple: true` → multi-value tags |
|
|
142
366
|
| `number` | Numeric input |
|
|
367
|
+
| `number-select` | Numeric input with up/down controls and long-press repeat; supports `min`, `max`, `step`, and `options.decimalScale` / `fixedDecimalScale` / `allowNegative` |
|
|
143
368
|
| `email` | Email input |
|
|
144
369
|
| `password` | Password input |
|
|
145
370
|
| `tel` / `phone` | Phone number with country selector |
|
|
146
371
|
| `textarea` | Multi-line text with `rows` prop |
|
|
147
372
|
| `checkbox` | Boolean checkbox |
|
|
148
373
|
| `radio` | Radio button (use `value` prop) |
|
|
374
|
+
| `toggle` | Segmented toggle button group. `allowMultiple: true` gives array values; MUI props (size, color, orientation) live under `options`. Supports icons, disabled items, `enforceValue`, and `defaultValue`. |
|
|
149
375
|
| `date` | Date picker |
|
|
150
376
|
| `datetime` | Date + time picker |
|
|
151
377
|
| `rangedatetime` | Date range picker |
|
|
152
378
|
| `enhanced-rangedatetime` | Enhanced date range picker |
|
|
379
|
+
|
|
380
|
+
**Timezone-aware datetime fields:** For appointment or terminal times that must be stored as UTC but displayed as a fixed local wall clock, set `options.useTimezone: true`, `options.storeAsUTC: true`, and an IANA `options.timezone` such as `America/New_York`. The picker treats the selected time as being in that configured timezone, not the user's browser timezone, so saving `11:00 PM` in New York stores the matching UTC instant and reads back as `11:00 PM` on machines in any timezone.
|
|
381
|
+
|
|
382
|
+
**Enhanced rangedatetime filter behavior:** `more_than` emits bracketed Lucene ranges such as `field:[* TO NOW-7DAYS]`; boolean/number falsy values (`false`, `0`) are preserved as real filter values; and switching away from Empty/Not Empty clears the previous `NULL` term instead of latching it.
|
|
153
383
|
| `time` | Time picker |
|
|
154
384
|
| `select` | Dropdown select from `items[]` |
|
|
155
385
|
| `select-async` | Async search select (GraphQL-backed) |
|
|
@@ -162,7 +392,7 @@ Polymorphic form field — renders different input types based on `type` prop.
|
|
|
162
392
|
| `quill` | Rich text editor (Quill) |
|
|
163
393
|
| `object` | JSON object editor |
|
|
164
394
|
| `yaml` | YAML editor |
|
|
165
|
-
| `secret` | Encrypted secret input — stores `${secret:qualifiedName}` reference. Requires `secretPath` prop for naming. |
|
|
395
|
+
| `secret` | Encrypted secret input — stores `${secret:qualifiedName}` reference. Requires `secretPath` prop for naming and sends `setSecret(input: { organizationId, secretName, secretValue })` / `deleteSecret(input: { organizationId, secretName })` using the current organization. |
|
|
166
396
|
|
|
167
397
|
**Select/Async options (under `options`):**
|
|
168
398
|
| Prop | Type | Description |
|
|
@@ -179,6 +409,43 @@ Polymorphic form field — renders different input types based on `type` prop.
|
|
|
179
409
|
| `valueQuery` | `{name, path, params}` | Single-value lookup query ref |
|
|
180
410
|
| `variant` | `string` | Select variant |
|
|
181
411
|
|
|
412
|
+
For an inline-create-only `select-async`, omit `valueQuery` and enable
|
|
413
|
+
`allowCreate`. Existing primitive values are rendered directly (as chips when
|
|
414
|
+
`allowMultiple` is true), so this pattern works for free-form arrays without a
|
|
415
|
+
backing entity lookup. Optional `itemLabelTemplate` and `itemValueTemplate`
|
|
416
|
+
still control the displayed label and stored value.
|
|
417
|
+
|
|
418
|
+
```yaml
|
|
419
|
+
- component: field
|
|
420
|
+
name: aliasScacCodes
|
|
421
|
+
props:
|
|
422
|
+
type: select-async
|
|
423
|
+
label: { en-US: "Alias SCAC codes" }
|
|
424
|
+
options:
|
|
425
|
+
allowCreate: true
|
|
426
|
+
allowMultiple: true
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
**Google Places autocomplete:** `autocomplete-googleplaces` uses the organization-level Google Maps API key from `apps.google.googleMapsApiKey`. Do not put API keys in module YAML. Configure `searchQuery.params` and `valueQuery.params` only:
|
|
430
|
+
|
|
431
|
+
```yaml
|
|
432
|
+
- component: field
|
|
433
|
+
name: pickupAddress
|
|
434
|
+
props:
|
|
435
|
+
type: autocomplete-googleplaces
|
|
436
|
+
label: { en-US: "Pickup address" }
|
|
437
|
+
options:
|
|
438
|
+
itemLabelTemplate: "{{ description }}"
|
|
439
|
+
searchQuery:
|
|
440
|
+
params:
|
|
441
|
+
input: "{{ search }}"
|
|
442
|
+
types: ["address"]
|
|
443
|
+
language: "en-US"
|
|
444
|
+
valueQuery:
|
|
445
|
+
params:
|
|
446
|
+
fields: ["name", "address_components", "formatted_address", "geometry", "place_id"]
|
|
447
|
+
```
|
|
448
|
+
|
|
182
449
|
**Events:**
|
|
183
450
|
| Event | Description |
|
|
184
451
|
|-------|-------------|
|
|
@@ -188,7 +455,7 @@ Polymorphic form field — renders different input types based on `type` prop.
|
|
|
188
455
|
| `onFocus` | Fires on focus |
|
|
189
456
|
| `onKeyPress` | Fires on keypress (data: `key`, `keyCode`) |
|
|
190
457
|
| `onSelectValue` | Fires on select-async value selection |
|
|
191
|
-
| `onEditClick` | Fires when edit icon clicked. Supported on text and
|
|
458
|
+
| `onEditClick` | Fires when edit icon clicked. Supported on `text`, `select-async`, and `autocomplete-async` fields when a single value is set. Passes current form values (with optional `valueFieldName`) to the action context |
|
|
192
459
|
|
|
193
460
|
```yaml
|
|
194
461
|
# Text field
|
|
@@ -200,6 +467,19 @@ Polymorphic form field — renders different input types based on `type` prop.
|
|
|
200
467
|
required: true
|
|
201
468
|
placeholder: "Enter company name"
|
|
202
469
|
|
|
470
|
+
|
|
471
|
+
# Number select with arrow controls
|
|
472
|
+
- component: field
|
|
473
|
+
name: pieces
|
|
474
|
+
props:
|
|
475
|
+
type: number-select
|
|
476
|
+
label: { en-US: "Pieces" }
|
|
477
|
+
min: 0
|
|
478
|
+
max: 999
|
|
479
|
+
step: 1
|
|
480
|
+
options:
|
|
481
|
+
decimalScale: 0
|
|
482
|
+
|
|
203
483
|
# Select field
|
|
204
484
|
- component: field
|
|
205
485
|
name: status
|
|
@@ -210,6 +490,23 @@ Polymorphic form field — renders different input types based on `type` prop.
|
|
|
210
490
|
- { label: "Active", value: "active" }
|
|
211
491
|
- { label: "Inactive", value: "inactive" }
|
|
212
492
|
|
|
493
|
+
# Toggle field
|
|
494
|
+
- component: field
|
|
495
|
+
name: priority
|
|
496
|
+
props:
|
|
497
|
+
type: toggle
|
|
498
|
+
label: { en-US: "Priority" }
|
|
499
|
+
allowMultiple: false
|
|
500
|
+
enforceValue: true
|
|
501
|
+
defaultValue: normal
|
|
502
|
+
options:
|
|
503
|
+
size: small
|
|
504
|
+
color: primary
|
|
505
|
+
orientation: horizontal
|
|
506
|
+
items:
|
|
507
|
+
- { label: "Normal", value: normal }
|
|
508
|
+
- { label: "High", value: high }
|
|
509
|
+
|
|
213
510
|
# Async select with search
|
|
214
511
|
- component: field
|
|
215
512
|
name: customerId
|
|
@@ -275,7 +572,9 @@ Polymorphic form field — renders different input types based on `type` prop.
|
|
|
275
572
|
|
|
276
573
|
## field-collection
|
|
277
574
|
|
|
278
|
-
Dynamic array/list editor for repeating field groups. Supports add/remove/reorder with drag-and-drop.
|
|
575
|
+
Dynamic array/list editor for repeating field groups. Supports add/remove/reorder with drag-and-drop and optional up/down move buttons. Reorder UI adds stable internal `_uuid` keys to object rows only when drag handles or move buttons are shown, so non-reorder payloads stay untouched.
|
|
576
|
+
|
|
577
|
+
When `options.allowRemove` is enabled and the item count is above `minItems`, removal is exposed through a theme-colored three-dots menu with a **Delete** action. The same menu is used for list/grid items and accordion headers; selecting it still follows `options.removeType` (`soft` or `hard`).
|
|
279
578
|
|
|
280
579
|
**Props:**
|
|
281
580
|
| Prop | Type | Default | Description |
|
|
@@ -289,20 +588,41 @@ Dynamic array/list editor for repeating field groups. Supports add/remove/reorde
|
|
|
289
588
|
| `options.allowReorder` | `boolean` | `true` | Enable drag-and-drop |
|
|
290
589
|
| `options.minItems` | `number` | `0` | Minimum items (auto-created) |
|
|
291
590
|
| `options.maxItems` | `number` | `∞` | Maximum items |
|
|
591
|
+
| `options.removeType` | `soft \| hard` | `soft` | Individual remove behavior. `soft` marks object rows with `isDeleted: true`; `hard` splices the row from the array |
|
|
292
592
|
| `addButton.label` | `ILocalizeString` | `Add Item` | Add button label |
|
|
293
593
|
| `addButton.icon` | `string` | `plus` | Add button icon |
|
|
294
594
|
| `addButton.position` | `top \| bottom \| both` | `bottom` | Add button placement |
|
|
295
595
|
| `defaultItem` | `any` | — | Template for new items |
|
|
296
596
|
| `layout` | `list \| grid \| accordion` | `list` | Layout mode |
|
|
297
|
-
| `cols` | `number` | `1` | Grid columns |
|
|
597
|
+
| `cols` | `number` | `1` | Grid columns (non-responsive). For adaptive item layouts, set `cols: 1` and use a `layout` inside `itemTemplate` with `itemDefaults.size: { xs, md }`. |
|
|
598
|
+
| `groupCols` | `number \| {xs,sm,md,lg,xl}` | `1` | Group columns when `groupMode` is true |
|
|
599
|
+
| `groupSpacing` | `number` | `0` | Spacing between group columns |
|
|
298
600
|
| `groupMode` | `boolean` | `false` | Enable grouping |
|
|
299
601
|
| `groupBy` | `string` | — | Field path to group by |
|
|
300
602
|
| `groups` | `{key, label, icon?}[]` | — | Group definitions |
|
|
301
603
|
| `showIndex` | `boolean` | `false` | Show item index |
|
|
302
604
|
| `showDragHandle` | `boolean` | `false` | Show drag handles |
|
|
605
|
+
| `showMoveButtons` | `boolean` | `false` | Show up/down move buttons for accessible reordering; requires `options.allowReorder` |
|
|
606
|
+
| `label` | `ILocalizeString` | — | Enables a collection header; nested collections use a compact section header |
|
|
607
|
+
| `itemTitle` | `string` | derived | Field path or template for the accordion row title |
|
|
608
|
+
| `itemIcon` | `string` | — | Icon name or per-item template rendered before the row title |
|
|
609
|
+
| `itemSubtitle` | `string` | — | Per-item template for muted row metadata |
|
|
610
|
+
| `itemBadges` | `{label,color?,when?}[]` | — | Inline semantic badges; colors: `danger`, `warning`, `info`, `success`, `primary`, `neutral` |
|
|
611
|
+
| `itemNestedCount` | `string` | — | Template resolving to a nested-record count on collapsed rows |
|
|
612
|
+
| `summaryTemplate` | `string` | item count | Header summary template with `count` and `items` variables |
|
|
613
|
+
| `showCount` | `boolean` | `true` | Show the header count chip |
|
|
614
|
+
| `showExpandAll` | `boolean` | `true` | Show bulk expansion controls for multi-row accordions |
|
|
615
|
+
| `collapseNested` | `boolean` | `true` | Render nested collections as collapsed accordion rows unless `layout` is explicit |
|
|
616
|
+
| `autoItemTitle` | `boolean` | `true` | Derive missing titles from label-like scalar record fields |
|
|
617
|
+
| `density` | `compact \| comfortable` | `compact` | Accordion row padding preset |
|
|
303
618
|
|
|
304
619
|
**Children:** Uses `itemTemplate` (not `children`). Each item gets `item`, `index`, `collection` variables.
|
|
305
620
|
|
|
621
|
+
For compact record lists, use `layout: accordion`. If `label` is set, the add action moves into
|
|
622
|
+
the header unless its position is explicit. Nested collections collapse by default; blank new
|
|
623
|
+
records expand automatically. `itemIcon`, `itemSubtitle`, and badge/count templates receive the
|
|
624
|
+
parent variables plus `item`, `index`, and the item's own fields.
|
|
625
|
+
|
|
306
626
|
```yaml
|
|
307
627
|
component: field-collection
|
|
308
628
|
name: lineItems
|
|
@@ -312,6 +632,7 @@ props:
|
|
|
312
632
|
allowAdd: true
|
|
313
633
|
allowRemove: true
|
|
314
634
|
allowReorder: true
|
|
635
|
+
removeType: soft
|
|
315
636
|
minItems: 1
|
|
316
637
|
maxItems: 50
|
|
317
638
|
addButton:
|
|
@@ -324,19 +645,57 @@ props:
|
|
|
324
645
|
unitPrice: 0
|
|
325
646
|
layout: list
|
|
326
647
|
itemTemplate:
|
|
327
|
-
component:
|
|
648
|
+
component: layout
|
|
328
649
|
name: lineItemRow
|
|
329
|
-
props:
|
|
650
|
+
props:
|
|
651
|
+
columnSpacing: { xs: 1, md: 2 }
|
|
652
|
+
rowSpacing: 2
|
|
330
653
|
children:
|
|
331
654
|
- component: field
|
|
332
655
|
name: description
|
|
333
|
-
props:
|
|
656
|
+
props:
|
|
657
|
+
type: text
|
|
658
|
+
label: { en-US: "Description" }
|
|
659
|
+
size: { xs: 12, md: 6 }
|
|
334
660
|
- component: field
|
|
335
661
|
name: quantity
|
|
336
|
-
props:
|
|
662
|
+
props:
|
|
663
|
+
type: number
|
|
664
|
+
label: { en-US: "Qty" }
|
|
665
|
+
size: { xs: 6, md: 3 }
|
|
337
666
|
- component: field
|
|
338
667
|
name: unitPrice
|
|
339
|
-
props:
|
|
668
|
+
props:
|
|
669
|
+
type: number
|
|
670
|
+
label: { en-US: "Unit Price" }
|
|
671
|
+
size: { xs: 6, md: 3 }
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
Grouped collections can render groups in multiple columns. Use a fixed `groupCols` count or responsive breakpoint counts; each count is converted to Material UI's 12-column grid.
|
|
675
|
+
|
|
676
|
+
```yaml
|
|
677
|
+
component: field-collection
|
|
678
|
+
name: businessHours
|
|
679
|
+
props:
|
|
680
|
+
fieldName: businessHours
|
|
681
|
+
groupMode: true
|
|
682
|
+
groupBy: dayOfWeek
|
|
683
|
+
groupCols: { xs: 1, md: 2, lg: 4 }
|
|
684
|
+
groupSpacing: 2
|
|
685
|
+
groups:
|
|
686
|
+
- { key: 1, label: { en-US: Monday } }
|
|
687
|
+
- { key: 2, label: { en-US: Tuesday } }
|
|
688
|
+
layout: accordion
|
|
689
|
+
itemTemplate:
|
|
690
|
+
component: layout
|
|
691
|
+
props: { cols: 2 }
|
|
692
|
+
children:
|
|
693
|
+
- component: field
|
|
694
|
+
name: startTime
|
|
695
|
+
props: { type: time, label: { en-US: Start } }
|
|
696
|
+
- component: field
|
|
697
|
+
name: endTime
|
|
698
|
+
props: { type: time, label: { en-US: End } }
|
|
340
699
|
```
|
|
341
700
|
|
|
342
701
|
---
|
|
@@ -349,9 +708,15 @@ Headless barcode/keyboard scanner listener. Captures rapid keystrokes and fires
|
|
|
349
708
|
| Prop | Type | Default | Description |
|
|
350
709
|
|------|------|---------|-------------|
|
|
351
710
|
| `minBarcodeLength` | `number` | `4` | Min chars to qualify as scan |
|
|
711
|
+
| `deduplicate` | `boolean` | `true` | Mobile: suppress repeat reads per barcode |
|
|
712
|
+
| `scanDelayMs` | `number` | `1000` | Mobile: per-code dedup window in milliseconds |
|
|
713
|
+
| `minScanIntervalMs` | `number` | `0` | Mobile: minimum time between accepted scans; `0` disables |
|
|
714
|
+
| `continuous` | `boolean` | `true` | Mobile: accept more than one scan |
|
|
715
|
+
| `maxBarcodes` | `number` | — | Mobile: maximum accepted scans in continuous mode |
|
|
352
716
|
| `onScan` | `action[]` | — | **Required.** Action on scan detection |
|
|
353
717
|
|
|
354
|
-
**Renders:** Nothing (empty fragment).
|
|
718
|
+
**Renders:** Nothing (empty fragment). Web listens on `document` keypress. Mobile supports
|
|
719
|
+
native HID scanners with a hidden-input fallback and shares camera-scanner deduplication rules.
|
|
355
720
|
|
|
356
721
|
**Scan data:** `result: { data: string, format: 'input' }`
|
|
357
722
|
|
|
@@ -43,6 +43,8 @@ MUI Button with icon, label, loading state, and action dispatch.
|
|
|
43
43
|
|
|
44
44
|
**Events:** `onClick` — dispatches action chain with loading spinner while executing.
|
|
45
45
|
|
|
46
|
+
**Theme note:** MUI toggle button groups use the primary color by default, and medium toggle buttons are fixed at 39px height to align segmented controls with neighboring inputs.
|
|
47
|
+
|
|
46
48
|
```yaml
|
|
47
49
|
# Primary submit button
|
|
48
50
|
- component: button
|