@object-ui/plugin-form 17.5.0 → 17.6.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/README.md CHANGED
@@ -35,53 +35,222 @@ const schema = {
35
35
  };
36
36
  ```
37
37
 
38
- ### Manual Registration
38
+ ### What the side-effect import registers
39
+
40
+ There is no component map to iterate: registration is a side effect of importing
41
+ the package entry, which makes six `ComponentRegistry.register(...)` calls. These
42
+ are the schema types those calls claim, read off the calls themselves in
43
+ `src/index.tsx`:
44
+
45
+ | Namespaced type | Bare-name fallback | Component behind it |
46
+ |---|---|---|
47
+ | `plugin-form:object-form` | `object-form` | `ObjectForm` — metadata-driven form over one record |
48
+ | `view:form` | none | the same renderer under the view protocol |
49
+ | `plugin-form:embeddable-form` | `embeddable-form` | `EmbeddableForm` — standalone public form |
50
+ | `plugin-form:form-analytics` | `form-analytics` | `FormAnalytics` — submission dashboard |
51
+ | `plugin-form:object-master-detail-form` | `object-master-detail-form` | `MasterDetailForm` — parent + child line items in one submit |
52
+ | `record:line_items` | none | `LineItemsPanel` — child grid bound to the record on the page |
53
+
54
+ `ComponentRegistry.register` also registers a namespaced type under its bare name
55
+ for backwards compatibility, unless the call passes `skipFallback: true`
56
+ (`@object-ui/core`, `src/registry/Registry.ts`). Two calls here do: bare `form`
57
+ stays the basic `@object-ui/components` form, and bare `line_items` is left to
58
+ whoever else claims it.
59
+
60
+ ### Public exports
61
+
62
+ The package entry exports these — components, their prop/schema types, and the
63
+ layout helpers. There is no aggregate map among them:
64
+
65
+ ```typescript
66
+ import {
67
+ ObjectForm,
68
+ TabbedForm,
69
+ WizardForm,
70
+ SplitForm,
71
+ DrawerForm,
72
+ ModalForm,
73
+ EmbeddableForm,
74
+ MasterDetailForm,
75
+ LineItemsPanel,
76
+ FormAnalytics,
77
+ FormSectionContainer,
78
+ applyAutoLayout,
79
+ applyAutoColSpan,
80
+ inferColumns,
81
+ inferModalSize,
82
+ isWideFieldType,
83
+ isAutoGeneratedFieldType,
84
+ containerGridColsFor,
85
+ filterCreateModeFields,
86
+ filterSystemFields,
87
+ filterAutoGeneratedFields,
88
+ deriveDetail,
89
+ deriveColumns,
90
+ deriveFormFields,
91
+ findRelationshipField,
92
+ resolveInlineMode,
93
+ } from '@object-ui/plugin-form';
94
+
95
+ import type {
96
+ ObjectFormComponentProps,
97
+ ObjectFormProps, // deprecated alias of ObjectFormComponentProps
98
+ FormSectionContainerProps,
99
+ TabbedFormProps,
100
+ TabbedFormSchema,
101
+ FormSectionConfig,
102
+ WizardFormProps,
103
+ WizardFormSchema,
104
+ SplitFormProps,
105
+ SplitFormSchema,
106
+ DrawerFormProps,
107
+ DrawerFormSchema,
108
+ ModalFormProps,
109
+ ModalFormSchema,
110
+ EmbeddableFormProps,
111
+ EmbeddableFormConfig,
112
+ EmbeddableFormTexts,
113
+ FormAnalyticsProps,
114
+ FormSubmissionMetric,
115
+ MasterDetailFormProps,
116
+ MasterDetailFormSchema,
117
+ MasterDetailDetailConfig,
118
+ LineItemsPanelSchema,
119
+ DerivedDetail,
120
+ InlineMode,
121
+ } from '@object-ui/plugin-form';
122
+ ```
123
+
124
+ ### Registering a component under your own key
125
+
126
+ To put one of these components on a schema type of your own, register the
127
+ exported component:
39
128
 
40
129
  ```typescript
41
- import { formComponents } from '@object-ui/plugin-form';
42
130
  import { ComponentRegistry } from '@object-ui/core';
131
+ import { ObjectForm } from '@object-ui/plugin-form';
43
132
 
44
- // Register form components
45
- Object.entries(formComponents).forEach(([type, component]) => {
46
- ComponentRegistry.register(type, component);
47
- });
133
+ ComponentRegistry.register('my-form', ObjectForm, { namespace: 'my-app' });
48
134
  ```
49
135
 
136
+ The renderers this package registers for itself are internal wrappers rather
137
+ than these exported components. `SchemaRenderer` hands a registered component its
138
+ `schema` (plus the schema's own props), but never a `dataSource` — that travels
139
+ on `SchemaRendererContext` — so each wrapper reads it off the context first.
140
+ `ObjectForm` takes `dataSource` as a prop, optional because inline `customFields`
141
+ need no adapter, so a custom-key registration either supplies one or wraps the
142
+ component the same way.
143
+
50
144
  ## Schema API
51
145
 
52
- ### Form
146
+ Two form schemas reach a renderer, and **both are declared in
147
+ `@object-ui/types`** — this package imports them and declares neither. The
148
+ tables below name the keys and point at the declaration; the declaration is the
149
+ contract. (Restating an interface inside this README is what let this section
150
+ drift away from the code in the first place — objectui#5075.)
53
151
 
54
- Complete form with fields and validation:
152
+ | Schema | `type` | Declared in | Rendered by |
153
+ |---|---|---|---|
154
+ | `FormSchema` | `'form'` | `packages/types/src/form.ts` | the basic form in `@object-ui/components` — bare `form` is deliberately **not** claimed by this plugin (`skipFallback: true`, see the table above) |
155
+ | `ObjectFormSchema` | `'object-form'` | `packages/types/src/objectql.ts` | `ObjectForm` here, through `plugin-form:object-form` / `object-form` |
55
156
 
56
- ```typescript
57
- {
58
- type: 'form',
59
- fields: FormField[],
60
- submitLabel?: string,
61
- cancelLabel?: string,
62
- onSubmit?: (data) => void,
63
- onCancel?: () => void,
64
- className?: string
65
- }
66
- ```
157
+ Both `type` slots are string **literals**. A schema whose `type` names something
158
+ no registration claims does not fall back to a form — it renders the
159
+ unknown-component placeholder.
160
+
161
+ ### Form (`type: 'form'`)
162
+
163
+ | Key | Type | Notes |
164
+ |---|---|---|
165
+ | `type` | `'form'` | literal, not a free string |
166
+ | `fields` | `FormField[]` | **optional** — a form may render `children` instead |
167
+ | `defaultValues` | `Record<string, any>` | form-level initial values. There is no field-level `defaultValue` |
168
+ | `submitLabel` / `cancelLabel` | `string` | button text |
169
+ | `showCancel` / `showActions` | `boolean` | action-row composition |
170
+ | `mobileStickyActions` | `boolean` | pin the action row on small viewports |
171
+ | `layout` | `'vertical' \| 'horizontal'` | label placement |
172
+ | `columns` | `number` | grid width (1–4) |
173
+ | `validationMode` | `'onSubmit' \| 'onBlur' \| 'onChange' \| 'onTouched' \| 'all'` | when the rules run |
174
+ | `resetOnSubmit` / `disabled` | `boolean` | |
175
+ | `mode` | `'edit' \| 'read' \| 'disabled'` | whole-form mode |
176
+ | `objectName` | `string` | enables metadata field locators `data-testid="field:{objectName}.{field}"` (ADR-0054 C4) |
177
+ | `previousValues` | `Record<string, any>` | edit-mode hosts only — the persisted record, as evaluation context for `previous` / `readonlyWhen`. Never sent anywhere |
178
+ | `fieldContainerClass` | `string` | class for the field grid inside the `<form>` |
179
+ | `fieldTabs` / `defaultFieldTab` / `fieldTabsPosition` | see [Tabbed field layout](#tabbed-field-layout-fieldtabs) | |
180
+ | `fieldPanes` / `fieldPanesOrientation` / `fieldPanesResizable` | see [Split field layout](#split-field-layout-fieldpanes) | |
181
+ | `actions` | `SchemaNode[]` | extra nodes in the action row |
182
+ | `children` | `SchemaNode \| SchemaNode[]` | custom body instead of `fields` |
183
+ | `onSubmit` / `onChange` / `onDirtyChange` / `onCancel` | callbacks | **TypeScript-authored schemas only** — a JSON metadata document cannot carry a function. Metadata pages go through the object-form route instead |
184
+ | `className`, `id`, `hidden`, … | — | inherited from `BaseSchema` |
185
+
186
+ ⚠️ `FormSchema` extends `BaseSchema`, which declares `[key: string]: any`
187
+ (`packages/types/src/base.ts`), so an invented or misspelled key on a form schema
188
+ is **not** a compile error — it is simply never read. That is why every example
189
+ below is annotated with its real type *and* checked against these key tables:
190
+ an un-annotated `const schema = { … }` type-checks whatever is written in it.
67
191
 
68
192
  ### Form Field
69
193
 
70
- Individual form field configuration:
194
+ `FormField` (`packages/types/src/form.ts`) declares 23 keys, and `name` is the
195
+ only **required** one:
71
196
 
72
- ```typescript
73
- interface FormField {
74
- name: string;
75
- type: string; // 'input', 'select', 'checkbox', etc.
76
- label: string;
77
- placeholder?: string;
78
- required?: boolean;
79
- validation?: ValidationRule[];
80
- defaultValue?: any;
81
- disabled?: boolean;
82
- className?: string;
83
- }
84
- ```
197
+ | Key | Type | What it does |
198
+ |---|---|---|
199
+ | `name` | `string` | **required** — the submit key |
200
+ | `id` | `string` | stable render key; falls back to `name` |
201
+ | `label` | `string` | optional — with none, no label element is rendered at all (validation messages fall back to `name`). The object-bound paths always fill it from the object field |
202
+ | `description` | `string` | help text under the control |
203
+ | `type` | `string` | optional, defaults to `'input'`. Built-ins: `input`, `textarea`, `checkbox`, `switch`, `select`; any other value resolves through the registry (`field:<type>` first, then the bare name) |
204
+ | `inputType` | `string` | HTML input type for `type: 'input'` — `'email'`, `'password'`, `'tel'`, … |
205
+ | `widget` | `string` | widget override; wins over `type` (spec `FormField.widget`) |
206
+ | `placeholder` | `string` | |
207
+ | `required` | `boolean` | the presence rule. `validation.required` does **not** make a field required — see below |
208
+ | `disabled` | `boolean` | not interactive, muted |
209
+ | `readonly` | `boolean` | shown plainly, not editable — deliberately distinct from `disabled` |
210
+ | `hidden` | `boolean` | field is not rendered at all |
211
+ | `options` | `SelectOption[] \| RadioOption[]` | for `select` / radio fields |
212
+ | `validation` | `FieldValidationRules` | **an object keyed by rule name** — see below |
213
+ | `condition` | `FieldCondition` | legacy `{ field, equals, notEquals, in, custom }` matcher |
214
+ | `visibleWhen` / `readonlyWhen` / `requiredWhen` | `string \| { dialect?, source }` | CEL predicates over the live record, evaluated by `@objectstack/formula` — the same engine and dialect the server uses. Fail open |
215
+ | `visibleOn` | `string \| { dialect?, source }` | view-level visibility predicate (spec `FormField.visibleOn`) |
216
+ | `dependsOn` | `DependsOnInput` | cascading parent(s): a bare name, a list of names, or `{ field, param }` entries |
217
+ | `span` | `'auto' \| 'full'` | relative width, independent of the column count (preferred) |
218
+ | `colSpan` | `number` | legacy column span (1–4), clamped to the current column count |
219
+ | `field` | `Record<string, any>` | the resolved object-field **metadata object**, stashed by the object-bound paths so widgets can read `precision`, `currency`, `reference_to`, … In the *spec* form-view vocabulary `field` is a string (the referenced field name); that shape ends at `normalizeSectionField` and never reaches a runtime `FormField` |
220
+
221
+ `FormField` also declares `[key: string]: any`, so an invented key type-checks
222
+ here too. Two that a reader might expect, and that are **not** declared:
223
+
224
+ | Not a `FormField` key | Write this instead |
225
+ |---|---|
226
+ | `defaultValue` | `FormSchema.defaultValues` at form level. An object-bound form seeds from the object field's own declared `defaultValue` — see [What a create form opens with](#what-a-create-form-opens-with) |
227
+ | `className` | `span` / `colSpan` for width, `FormSchema.fieldContainerClass` for the grid. (An undeclared key still rides the props spread down to whichever component the field resolves to, so a field-level `className` can visibly land on a built-in control — but nothing in the contract promises that, and a registered widget honours it only if it happens to spread its leftover props. The renderer reads it *explicitly* on exactly one pseudo-field, `type: 'section-divider'`, where it styles the inline section header.) |
228
+
229
+ There is no `ValidationRule` type in this repo, under any spelling.
230
+
231
+ #### `validation` is an object keyed by rule name
232
+
233
+ `FieldValidationRules` (`packages/types/src/form.ts`) is **not** an array of
234
+ `{ type, value, message }` entries:
235
+
236
+ | Rule | Type | Notes |
237
+ |---|---|---|
238
+ | `required` | `string \| boolean` | supplies the required **message** only. Whether the field is required is decided by `required` / `requiredWhen` **on the field** |
239
+ | `minLength` / `maxLength` | `{ value: number; message: string }` | `message` is not optional when you author the rule by hand |
240
+ | `min` / `max` | `{ value: number; message: string }` | numeric range |
241
+ | `pattern` | `{ value: string \| RegExp; message: string }` | pass a **RegExp** in a hand-authored schema: react-hook-form only applies a pattern whose value `instanceof RegExp`, and it is the object-metadata path (`buildValidationRules` in `@object-ui/fields`) that compiles a declared string into one |
242
+ | `validate` | `(value) => boolean \| string \| Promise<boolean \| string>` | custom check; TypeScript-authored schemas only |
243
+
244
+ There is no `email` rule name — an email check is a `pattern`, which is exactly
245
+ what `buildValidationRules` emits for an object field of type `email`.
246
+
247
+ **Why the array spelling fails silently.** The only reader of this key is the
248
+ basic form renderer, which spreads it into the rule object handed to
249
+ react-hook-form — `const rules: any = { ...validation }`
250
+ (`packages/components/src/renderers/form/form.tsx:1652`). Spreading an **array**
251
+ into an object literal produces numeric keys (`{ '0': …, '1': … }`), which
252
+ react-hook-form does not recognise: every rule is dropped, nothing throws, and
253
+ the form looks validated while validating nothing.
85
254
 
86
255
  ### What a create form opens with
87
256
 
@@ -115,7 +284,7 @@ it; folding a default in over a column the record leaves unset would arm a
115
284
  silent write of a value the user never chose, on the next save of any other
116
285
  field.
117
286
 
118
- #### `required` + a runtime default
287
+ #### `required` (or `requiredWhen`) + a runtime default
119
288
 
120
289
  A field may declare both, and it is coherent authoring — storage-level required,
121
290
  with the value guaranteed by the producer:
@@ -131,22 +300,37 @@ rule, and the field is **omitted from the payload** — omitted, not sent empty,
131
300
  because `applyFieldDefaults` resolves the declaration only for a field that
132
301
  arrives absent or null, and a blank string is neither.
133
302
 
303
+ The **conditional** spelling reaches the same verdict. A `requiredWhen`
304
+ predicate says "required in this state", but `NOW()` / `current_user` resolve
305
+ at insert regardless of state, so the producer's guarantee covers the
306
+ conditional claim exactly as it covers the unconditional one:
307
+
308
+ ```ts
309
+ remind_at: Field.datetime({ requiredWhen: 'record.status == "scheduled"', defaultValue: 'NOW()' }),
310
+ ```
311
+
134
312
  | Mode | Declared | Left empty | Effect |
135
313
  |---|---|---|---|
136
- | create | `required` + a runtime default | yes | submits; the key is absent, and the server resolves it |
137
- | create | `required` + a runtime default | no (user typed) | submits the typed value — it outranks the default |
138
- | create | `required` + a static literal | user cleared the seeded control | refused: they removed a value that was really there |
139
- | edit | `required`, anything | user blanked it | refused: the token was resolved at insert, so this is a real removal |
314
+ | create | `required` / `requiredWhen` TRUE + a runtime default | yes | submits; the key is absent, and the server resolves it |
315
+ | create | `required` / `requiredWhen` TRUE + a runtime default | no (user typed) | submits the typed value — it outranks the default |
316
+ | create | `required` / `requiredWhen` TRUE + a static literal | user cleared the seeded control | refused: they removed a value that was really there |
317
+ | create | `requiredWhen` TRUE, no default | yes | refused: nobody else supplies this value |
318
+ | edit | `required` / `requiredWhen` TRUE, anything | user blanked it | refused: the token was resolved at insert, so this is a real removal |
140
319
 
141
320
  The required marker and `aria-required` go with the rule in the create case,
142
- since one boolean drives all three — in that mode the user genuinely is not
321
+ since one verdict drives all three — in that mode the user genuinely is not
143
322
  required to provide the value. Showing what the server *will* supply, as a
144
323
  non-authoritative preview, is a separate follow-up.
145
324
 
146
- Both halves read one predicate (`isRuntimeDefault` in `schemaDefaults`), which
147
- is what keeps a form from seeding a field it also refuses to submit. Not
148
- extended to `requiredWhen`, the conditional-required CEL rule, which the form
149
- renderer resolves against the live record.
325
+ Every consumer reads one predicate, `isRuntimeDefault` in `@object-ui/core`
326
+ (re-exported for this package's own use by `src/schemaDefaults.ts`, not from the
327
+ package entry listed above) — which is what keeps a form from seeding a field it
328
+ also refuses to submit. The static half is decided at the producer, in
329
+ `isRequiredInForm`; the conditional half cannot be, because `requiredWhen` is
330
+ resolved downstream against the live record, so it is suppressed inside the one
331
+ evaluator that resolves it — `resolveFieldRuleState`, reading
332
+ `isServerOwnedValue`. Display and validation share that single verdict, so a
333
+ field can never lose its asterisk while still refusing the submit.
150
334
 
151
335
  ### Column width of a sectioned form
152
336
 
@@ -259,7 +443,9 @@ primary pane, the rest stack in the secondary one behind inline section headers.
259
443
  ### Basic Form
260
444
 
261
445
  ```typescript
262
- const schema = {
446
+ import type { FormSchema } from '@object-ui/types';
447
+
448
+ const schema: FormSchema = {
263
449
  type: 'form',
264
450
  fields: [
265
451
  {
@@ -275,9 +461,15 @@ const schema = {
275
461
  inputType: 'email',
276
462
  label: 'Email Address',
277
463
  required: true,
278
- validation: [
279
- { type: 'email', message: 'Invalid email format' }
280
- ]
464
+ // Rule name → rule. Not an array (see Schema API above), and there is no
465
+ // 'email' rule: the email check is the pattern the metadata path builds
466
+ // for a field of type `email`.
467
+ validation: {
468
+ pattern: {
469
+ value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
470
+ message: 'Invalid email format'
471
+ }
472
+ }
281
473
  },
282
474
  {
283
475
  name: 'country',
@@ -304,51 +496,111 @@ const schema = {
304
496
 
305
497
  ### Multi-Step Form
306
498
 
499
+ A multi-step form is an **`object-form` with `formType: 'wizard'`**, and its
500
+ steps are its `sections` — one step per section. There is no
501
+ `multi-step-form` schema type (no registration anywhere claims that name) and no
502
+ `steps` key on any form schema, so a schema written that way renders the
503
+ unknown-component placeholder and the fields inside `steps` are never read.
504
+
307
505
  ```typescript
308
- const schema = {
309
- type: 'multi-step-form',
310
- steps: [
506
+ import type { ObjectFormSchema } from '@object-ui/types';
507
+
508
+ const schema: ObjectFormSchema = {
509
+ type: 'object-form',
510
+ objectName: 'contacts', // required
511
+ mode: 'create', // required
512
+ formType: 'wizard', // routes to WizardForm — needs at least one section
513
+ sections: [
514
+ {
515
+ name: 'personal',
516
+ label: 'Personal Info',
517
+ fields: ['first_name', 'last_name'] // field NAMES, resolved from the object schema
518
+ },
311
519
  {
312
- title: 'Personal Info',
520
+ name: 'contact',
521
+ label: 'Contact Info',
522
+ fields: ['email', 'phone']
523
+ }
524
+ ],
525
+ allowSkip: false, // see "Wizard steps and allowSkip" above
526
+ showStepIndicator: true
527
+ };
528
+ ```
529
+
530
+ A section's `fields` accepts three shapes — a field **name**, a spec
531
+ `FormFieldSchema` object (whose identity key is `field`), or an inline runtime
532
+ `FormField` object. The inline shape is what lets a wizard run with no data
533
+ source at all, which is the closest equivalent of the old snippet; note that
534
+ `WizardForm` reports a data-source-less submit through `onSuccess` (there is no
535
+ `onSubmit` on this schema):
536
+
537
+ ```tsx
538
+ import { WizardForm } from '@object-ui/plugin-form';
539
+ import type { WizardFormSchema } from '@object-ui/plugin-form';
540
+
541
+ const wizard: WizardFormSchema = {
542
+ type: 'object-form',
543
+ formType: 'wizard',
544
+ objectName: 'contacts',
545
+ mode: 'create',
546
+ sections: [
547
+ {
548
+ name: 'personal',
549
+ label: 'Personal Info',
313
550
  fields: [
314
551
  { name: 'firstName', type: 'input', label: 'First Name', required: true },
315
552
  { name: 'lastName', type: 'input', label: 'Last Name', required: true }
316
553
  ]
317
554
  },
318
555
  {
319
- title: 'Contact Info',
556
+ name: 'contact',
557
+ label: 'Contact Info',
320
558
  fields: [
321
559
  { name: 'email', type: 'input', inputType: 'email', label: 'Email', required: true },
322
560
  { name: 'phone', type: 'input', inputType: 'tel', label: 'Phone' }
323
561
  ]
324
- },
325
- {
326
- title: 'Review',
327
- fields: []
328
562
  }
329
563
  ],
330
- onSubmit: (data) => {
564
+ onSuccess: (data) => {
331
565
  console.log('Multi-step form completed:', data);
332
566
  }
333
567
  };
568
+
569
+ <WizardForm schema={wizard} /> // dataSource omitted: every step lists inline fields
334
570
  ```
335
571
 
572
+ `WizardFormSchema` declares no index signature, so an invented key on *this*
573
+ type is a real compile error — unlike `ObjectFormSchema`, which inherits
574
+ `BaseSchema`'s `[key: string]: any`.
575
+
576
+ One more route exists and is worth knowing about rather than reinventing: a flat
577
+ `object-form` can be turned into a stepper on small viewports with
578
+ `mobile: { stepper: true | 'auto', stepperFieldsPerStep, stepperMinFields }`,
579
+ which feeds the same `WizardForm`.
580
+
336
581
  ### Form with Validation
337
582
 
338
583
  ```typescript
339
- const schema = {
584
+ import type { FormSchema } from '@object-ui/types';
585
+
586
+ const schema: FormSchema = {
340
587
  type: 'form',
588
+ validationMode: 'onBlur',
341
589
  fields: [
342
590
  {
343
591
  name: 'username',
344
592
  type: 'input',
345
593
  label: 'Username',
346
- required: true,
347
- validation: [
348
- { type: 'minLength', value: 3, message: 'Username must be at least 3 characters' },
349
- { type: 'maxLength', value: 20, message: 'Username must be less than 20 characters' },
350
- { type: 'pattern', value: '^[a-zA-Z0-9_]+$', message: 'Only letters, numbers, and underscores' }
351
- ]
594
+ required: true, // presence: this is the key that decides it
595
+ validation: {
596
+ required: 'Pick a username', // the MESSAGE for the rule above, nothing more
597
+ minLength: { value: 3, message: 'Username must be at least 3 characters' },
598
+ maxLength: { value: 20, message: 'Username must be less than 20 characters' },
599
+ pattern: {
600
+ value: /^[a-zA-Z0-9_]+$/, // a RegExp, not a string
601
+ message: 'Only letters, numbers, and underscores'
602
+ }
603
+ }
352
604
  },
353
605
  {
354
606
  name: 'password',
@@ -356,42 +608,153 @@ const schema = {
356
608
  inputType: 'password',
357
609
  label: 'Password',
358
610
  required: true,
359
- validation: [
360
- { type: 'minLength', value: 8, message: 'Password must be at least 8 characters' },
361
- { type: 'pattern', value: '(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])', message: 'Must contain uppercase, lowercase, and number' }
362
- ]
611
+ validation: {
612
+ minLength: { value: 8, message: 'Password must be at least 8 characters' },
613
+ pattern: {
614
+ value: /(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])/,
615
+ message: 'Must contain uppercase, lowercase, and number'
616
+ },
617
+ validate: (value) =>
618
+ String(value).toLowerCase() !== 'password' || 'Pick something less guessable'
619
+ }
363
620
  }
364
621
  ]
365
622
  };
366
623
  ```
367
624
 
625
+ Each rule appears **once**, under its own name — an object, not a list. A second
626
+ `minLength` cannot exist, which is the point: the shape the renderer hands
627
+ react-hook-form is one rule per kind.
628
+
368
629
  ## Integration with Data Sources
369
630
 
370
- Connect forms to backend APIs:
631
+ **The adapter is not a schema key.** A schema is a serialisable document; a live
632
+ adapter is an object with methods, so it cannot travel in one. Both form routes
633
+ read the adapter from React context, which the host installs once above the whole
634
+ tree — the same rule [Registering a component under your own
635
+ key](#registering-a-component-under-your-own-key) states for custom
636
+ registrations.
371
637
 
372
- ```typescript
638
+ ### The metadata route — `object-form`
639
+
640
+ This is the route that actually reads and writes a record. `ObjectFormSchema`
641
+ names its object with **`objectName`** and its intent with **`mode`**, and both
642
+ are **required** (`packages/types/src/objectql.ts`); the adapter arrives on the
643
+ context, which `ObjectFormRenderer` reads at `src/index.tsx` before handing
644
+ `ObjectForm` its `dataSource` prop.
645
+
646
+ ```tsx
647
+ import { SchemaRendererProvider, SchemaRenderer } from '@object-ui/react';
373
648
  import { createObjectStackAdapter } from '@object-ui/data-objectstack';
649
+ import '@object-ui/plugin-form';
650
+ import type { ObjectFormSchema } from '@object-ui/types';
374
651
 
375
652
  const dataSource = createObjectStackAdapter({
376
653
  baseUrl: 'https://api.example.com',
377
- token: 'your-auth-token'
654
+ token: 'your-auth-token',
378
655
  });
379
656
 
380
- const schema = {
657
+ const schema: ObjectFormSchema = {
658
+ type: 'object-form',
659
+ objectName: 'users',
660
+ mode: 'create',
661
+ fields: ['name', 'email'],
662
+ submitText: 'Create user',
663
+ };
664
+
665
+ export const App = () => (
666
+ <SchemaRendererProvider dataSource={dataSource}>
667
+ <SchemaRenderer schema={schema} />
668
+ </SchemaRendererProvider>
669
+ );
670
+ ```
671
+
672
+ The object comes from `objectName`; there is no `resource` key. For `mode: 'edit'`
673
+ or `'view'`, add the `recordId` of the record being opened. Note that this
674
+ `mode` vocabulary is `'create' | 'edit' | 'view'` — the basic form's `mode` is a
675
+ different key with a different vocabulary (`'edit' | 'read' | 'disabled'`, see
676
+ [Schema API](#schema-api)).
677
+
678
+ ### The TypeScript route — basic `form`
679
+
680
+ A bare `form` never fetches or saves by itself: it has no object name and no
681
+ query, so there is nothing for it to call an adapter *with*. It collects values
682
+ and hands them to your `onSubmit`, which the renderer awaits
683
+ (`packages/components/src/renderers/form/form.tsx:1428`). Any persistence is
684
+ whatever that function does:
685
+
686
+ ```typescript
687
+ import type { FormSchema } from '@object-ui/types';
688
+
689
+ const dataSource = createObjectStackAdapter({
690
+ baseUrl: 'https://api.example.com',
691
+ token: 'your-auth-token',
692
+ });
693
+
694
+ const schema: FormSchema = {
381
695
  type: 'form',
382
- dataSource,
383
- resource: 'users',
384
- fields: [/* fields */],
696
+ fields: [
697
+ { name: 'name', type: 'input', label: 'Full Name', required: true },
698
+ { name: 'email', type: 'input', inputType: 'email', label: 'Email', required: true },
699
+ ],
700
+ submitLabel: 'Create user',
701
+ // The adapter reaches this call through the CLOSURE, not through the schema.
385
702
  onSubmit: async (data) => {
386
703
  await dataSource.create('users', data);
387
- }
704
+ },
388
705
  };
389
706
  ```
390
707
 
708
+ `onSubmit` is a function, so this route is **TypeScript-authored schemas only** —
709
+ a JSON metadata document cannot carry one. Metadata pages take the `object-form`
710
+ route above.
711
+
712
+ What the adapter on the context still does for a bare `form` is supply the
713
+ **field widgets**: the renderer reads it at `form.tsx:1004`
714
+ (`const contextDataSource = schemaCtx?.dataSource ?? null`) and passes it down
715
+ per field at `:2061`, which is how a lookup or cascading select loads its
716
+ options. Nothing else about the form is wired to it.
717
+
718
+ ### Keys that look like wiring but are not
719
+
720
+ Neither of these is a key of either form schema, and writing them changes
721
+ nothing:
722
+
723
+ | Written on a form schema | What actually happens |
724
+ |---|---|
725
+ | `dataSource` | **Discarded.** The basic form strips it in both directions — `dataSource: _dataSource` at `form.tsx:304` (`stripRendererOnlyProps`) and `:2168` — so it never reaches a widget and never reaches the DOM. The adapter the fields receive is the context one |
726
+ | `resource` | **Never read.** It is not declared on `FormSchema` or `ObjectFormSchema` at all. The key exists elsewhere in the protocol — on **`CRUDSchema`** (`packages/types/src/crud.ts`, `type: 'crud'`), where `CRUDBuilder` in `@object-ui/core` sets it — but no form renderer reads it under any spelling. On a form it names nothing |
727
+
728
+ Both survive compilation for the reason [Schema API](#schema-api) gives: `FormSchema`
729
+ and `ObjectFormSchema` extend `BaseSchema`, which declares `[key: string]: any`, so an
730
+ invented key is not a type error — it is simply never read. That is also why the
731
+ older version of this section looked like it worked: its `onSubmit` genuinely ran
732
+ and genuinely saved, but through the adapter its closure captured. The `dataSource`
733
+ and `resource` keys sitting beside it in the same object were inert. Delete them and
734
+ that example behaves identically — which is the test for whether a key is doing
735
+ anything.
736
+
737
+ > A top-level `dataSource` **does** mean something on a schema node, but it is not
738
+ > an adapter: it is the spec's element **binding** (`PageComponentSchema.dataSource`,
739
+ > objectstack#6953) — a descriptor such as `{ object: 'users' }` — resolved by
740
+ > `useElementDataSource` (`packages/react/src/hooks/useElementDataSource.ts:139`).
741
+ > `object-form` passes through that gate, and honours the binding's `object` key
742
+ > only. Handing that slot a live adapter is rejected on purpose: the predicate
743
+ > refuses any value carrying a `find` method
744
+ > (`packages/core/src/data-scope/element-data-source.ts:131`), so an adapter written
745
+ > there is ignored rather than mistaken for a binding. Pass adapters through the
746
+ > provider above.
747
+
391
748
  ## TypeScript Support
392
749
 
750
+ `FormSchema` and `FormField` are protocol types, so they live in
751
+ `@object-ui/types` alongside the rest of the JSON contract. This package imports
752
+ them and does not re-export them — the form types on its own entry are the
753
+ per-container ones (`TabbedFormSchema`, `WizardFormSchema`, `ModalFormSchema`, …)
754
+ listed under [Public exports](#public-exports).
755
+
393
756
  ```typescript
394
- import type { FormSchema, FormField } from '@object-ui/plugin-form';
757
+ import type { FormSchema, FormField } from '@object-ui/types';
395
758
 
396
759
  const emailField: FormField = {
397
760
  name: 'email',
@@ -1 +1 @@
1
- {"version":3,"file":"DrawerForm.d.ts","sourceRoot":"","sources":["../src/DrawerForm.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"DrawerForm.d.ts","sourceRoot":"","sources":["../src/DrawerForm.tsx"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"EmbeddableForm.d.ts","sourceRoot":"","sources":["../src/EmbeddableForm.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"EmbeddableForm.d.ts","sourceRoot":"","sources":["../src/EmbeddableForm.tsx"],"names":[],"mappings":"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"}