@object-ui/plugin-form 11.3.0 → 11.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/CHANGELOG.md +92 -0
- package/dist/autoLayout.d.ts +67 -8
- package/dist/deriveMasterDetail.d.ts +12 -0
- package/dist/fieldGroups.d.ts +11 -17
- package/dist/index.js +971 -836
- package/dist/index.umd.cjs +1 -1
- package/dist/masterDetailTx.d.ts +11 -0
- package/package.json +10 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,97 @@
|
|
|
1
1
|
# @object-ui/plugin-form
|
|
2
2
|
|
|
3
|
+
## 11.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 8bf6295: feat: adaptive record surface + semantic field span + responsive columns (framework#2578)
|
|
8
|
+
|
|
9
|
+
Field-heavy objects (all metadata is AI-authored) now present themselves without
|
|
10
|
+
any authored presentation config:
|
|
11
|
+
|
|
12
|
+
- **Adaptive surface** — a record's create/edit/detail opens as a full page when
|
|
13
|
+
the object is field-heavy, or a drawer when it is light. Derived from field
|
|
14
|
+
count (`deriveRecordSurface`), not authored; mobile always pages. Wired into the
|
|
15
|
+
app-shell ObjectView detail navigation (an authored view/object `navigation`
|
|
16
|
+
still wins).
|
|
17
|
+
- **Semantic field span** — `FormField.span` (`auto`/`full`) is a width primitive
|
|
18
|
+
decoupled from the (per-surface derived) column count; legacy `colSpan` is
|
|
19
|
+
clamped so it never overflows. `ObjectForm` now honours per-section `columns`
|
|
20
|
+
and carries `span`/`colSpan` from section defs — fixes the bug where
|
|
21
|
+
`type:'simple'` ignored `section.columns` and grouped fields rendered single
|
|
22
|
+
column.
|
|
23
|
+
- **Responsive columns** — `inferColumns` scales the column CAP with field count
|
|
24
|
+
(≤3→1, ≤8→2, ≤15→3, 16+→4); the ACTUAL column count follows the form's real
|
|
25
|
+
width via CSS container queries, so the same form goes 1→2→3→4 columns as a
|
|
26
|
+
drawer widens or becomes a page.
|
|
27
|
+
- **Runtime overlay width** — `NavigationConfig.size` bucket is resolved to a
|
|
28
|
+
viewport-clamped width at runtime (`overlayWidthFor`); a pixel width is never
|
|
29
|
+
authored (the author cannot know the client viewport).
|
|
30
|
+
|
|
31
|
+
- 144ab55: Consume the ADR-0085 object semantic roles from `@objectstack/spec@11.7.0`, retiring the per-surface hint dialects:
|
|
32
|
+
|
|
33
|
+
- **Single-source fieldGroups derivation**: `plugin-form`'s `deriveFieldGroupSections` and `plugin-detail`'s `deriveFieldGroupDetailSections` are now thin adapters over the spec's `deriveFieldGroupLayout` (ADR-0085 §5) — forms, modals and detail pages render the SAME grouping from one implementation. The canonical `collapse: 'none' | 'expanded' | 'collapsed'` enum is honoured everywhere (deprecated `collapsible`/`collapsed` and `defaultExpanded` spellings still read for pre-11.7 metadata).
|
|
34
|
+
- **`stageField` semantic role**: the detail stepper reads the top-level `stageField`; `stageField: false` now actually suppresses stage detection (previously the `false` handling was wired to the removed `detail.stageField` key, so spec-authored `false` fell through to the name heuristic).
|
|
35
|
+
- **`highlightFields` rename**: default grid columns, card compact views, the detail highlight strip, child-record preview fields and interface-page default columns read the object's `highlightFields` (deprecated `compactLayout` spelling read as fallback for pre-11.7 metadata).
|
|
36
|
+
- **Removed dead reads**: the never-spec-writable `objectDef.views.*` UI hints and the ADR-0085-removed `detail.*` block (`sections`, `sectionGroups`, `highlightFields`, `stageField`, `useFieldGroups`, `showReferenceRail`, `hideReferenceRail`, `hideRelatedTab`, `relatedLayout`) are no longer consulted. Per-page customization goes through an assigned Page schema (`record:reference_rail` remains available there as a renderer capability). `detail.renderViaSchema` survives only as the legacy-renderer kill-switch and is removed together with that path.
|
|
37
|
+
|
|
38
|
+
### Patch Changes
|
|
39
|
+
|
|
40
|
+
- c38d107: Fix view-level `FormField.visibleOn` (CEL) never taking effect (#2212).
|
|
41
|
+
|
|
42
|
+
The spec ships `visibleOn` as an Expression object `{ dialect: 'cel', source }`
|
|
43
|
+
(what the `P` template emits) or a bare string, but the whole chain dropped it:
|
|
44
|
+
|
|
45
|
+
- `sectionFields.ts` / `ObjectForm.tsx` only accepted the bare-string shape and
|
|
46
|
+
attached a dead `visible()` closure no renderer ever called — the Expression
|
|
47
|
+
object shape was silently discarded.
|
|
48
|
+
- The form renderer destructured `visibleOn` out of the field config and never
|
|
49
|
+
evaluated it.
|
|
50
|
+
- `RecordFormPage` dropped a `simple` form view's `sections` entirely, so
|
|
51
|
+
page-mode create/edit fell back to the raw schema (every field, no authored
|
|
52
|
+
selection/grouping) while the modal path honored the same view.
|
|
53
|
+
- `ObjectForm`'s grouped-sections path matched section fields by name only,
|
|
54
|
+
dropping per-field `visibleOn` overrides.
|
|
55
|
+
|
|
56
|
+
`visibleOn` now flows through normalization verbatim (both wire shapes) and is
|
|
57
|
+
evaluated reactively by the form renderer with the canonical expression engine
|
|
58
|
+
(`evalFieldPredicate` — same engine, record scope, and fail-open semantics as
|
|
59
|
+
field-level `visibleWhen`; both predicates must allow a field for it to show).
|
|
60
|
+
Sectioned/flat normalization also copies field-level `visibleWhen` /
|
|
61
|
+
`readonlyWhen` / `requiredWhen` rules it previously lost.
|
|
62
|
+
|
|
63
|
+
- 1e9145d: Hydrate widget types on hand-authored master-detail subform columns. A view can
|
|
64
|
+
list a child grid's columns as bare `{ field, label }` (the common authoring
|
|
65
|
+
form); previously such untyped columns were passed straight to the grid, so a
|
|
66
|
+
`select` / `lookup` / `date` / `number` field silently rendered as a plain text
|
|
67
|
+
cell. `MasterDetailForm` (and `deriveDetail`) now resolve each untyped column's
|
|
68
|
+
`type` (plus `options` / `reference` / computed `expr`) from the child object's
|
|
69
|
+
schema via the new `hydrateColumns` helper — a picklist becomes a dropdown, a
|
|
70
|
+
lookup a record picker, a date a date input — while preserving the author's
|
|
71
|
+
exact column set, order and labels. Columns that already declare a `type` are
|
|
72
|
+
left untouched (the author's explicit choice still wins).
|
|
73
|
+
- Updated dependencies [8bf6295]
|
|
74
|
+
- Updated dependencies [1948c5b]
|
|
75
|
+
- Updated dependencies [bce581a]
|
|
76
|
+
- Updated dependencies [9cd9be1]
|
|
77
|
+
- Updated dependencies [5160832]
|
|
78
|
+
- Updated dependencies [69d6b94]
|
|
79
|
+
- Updated dependencies [c38d107]
|
|
80
|
+
- Updated dependencies [243a9ba]
|
|
81
|
+
- Updated dependencies [289be5b]
|
|
82
|
+
- Updated dependencies [7782698]
|
|
83
|
+
- Updated dependencies [19f2533]
|
|
84
|
+
- Updated dependencies [790558b]
|
|
85
|
+
- Updated dependencies [09e1b26]
|
|
86
|
+
- Updated dependencies [e84d64d]
|
|
87
|
+
- @object-ui/types@11.4.0
|
|
88
|
+
- @object-ui/components@11.4.0
|
|
89
|
+
- @object-ui/fields@11.4.0
|
|
90
|
+
- @object-ui/i18n@11.4.0
|
|
91
|
+
- @object-ui/core@11.4.0
|
|
92
|
+
- @object-ui/permissions@11.4.0
|
|
93
|
+
- @object-ui/react@11.4.0
|
|
94
|
+
|
|
3
95
|
## 11.3.0
|
|
4
96
|
|
|
5
97
|
### Patch Changes
|
package/dist/autoLayout.d.ts
CHANGED
|
@@ -8,21 +8,49 @@ export declare function isWideFieldType(type: string): boolean;
|
|
|
8
8
|
*/
|
|
9
9
|
export declare function isAutoGeneratedFieldType(type: string): boolean;
|
|
10
10
|
/**
|
|
11
|
-
* Infer
|
|
12
|
-
*
|
|
11
|
+
* Infer the MAX column count from the field count (#2578). This is an UPPER
|
|
12
|
+
* BOUND — the actual column count at render time is decided by the CSS
|
|
13
|
+
* container queries in {@link CONTAINER_GRID_COLS} against the form's REAL
|
|
14
|
+
* width, so a narrow drawer stays 1–2 columns while the SAME form on a wide
|
|
15
|
+
* page spreads out to this cap. The cap scales with field count so a light
|
|
16
|
+
* form is never thinned across too many columns, while a field-heavy record
|
|
17
|
+
* can use the full width.
|
|
13
18
|
*
|
|
14
|
-
* Rules:
|
|
15
|
-
* - 0
|
|
16
|
-
* - 4
|
|
19
|
+
* Rules (upper bound; container queries clamp to the actual width):
|
|
20
|
+
* - 0–3 fields → 1 column
|
|
21
|
+
* - 4–8 fields → 2 columns
|
|
22
|
+
* - 9–15 fields → 3 columns
|
|
23
|
+
* - 16+ fields → 4 columns
|
|
17
24
|
*/
|
|
18
25
|
export declare function inferColumns(fieldCount: number): number;
|
|
19
26
|
/**
|
|
20
|
-
*
|
|
21
|
-
*
|
|
27
|
+
* Resolve the effective colSpan (grid cells) a field occupies, given the form's
|
|
28
|
+
* grid width and the section's desired column count (#2578).
|
|
22
29
|
*
|
|
30
|
+
* The column count is derived per surface (mobile 1 / modal 2 / page 3-4), so
|
|
31
|
+
* the robust field-width primitive is the relative `span`, NOT an absolute
|
|
32
|
+
* colSpan. Precedence:
|
|
33
|
+
* 1. `span: 'full'` → whole row (grid cells).
|
|
34
|
+
* 2. legacy `colSpan` → honoured but CLAMPED to the grid (never overflows).
|
|
35
|
+
* 3. wide widget type → whole row (textarea/markdown/… — the `span:'auto'` default).
|
|
36
|
+
* 4. section density → grid / sectionColumns, so `sectionColumns` fields fill a row.
|
|
37
|
+
*
|
|
38
|
+
* `sectionColumns` defaults to the grid width, i.e. one field per cell (the flat
|
|
39
|
+
* form's historical behaviour) when there is no narrower section.
|
|
40
|
+
*/
|
|
41
|
+
export declare function resolveColSpan(field: FormField, gridColumns: number, sectionColumns?: number): number;
|
|
42
|
+
/**
|
|
43
|
+
* Apply the resolved colSpan to each field so the form's CSS grid lays them out
|
|
44
|
+
* at the intended density. Span-aware and clamping (#2578); wide fields still
|
|
45
|
+
* span the full row (the `span: 'auto'` default). `section-divider` rows are
|
|
46
|
+
* left untouched (they carry their own full-row span).
|
|
47
|
+
*
|
|
48
|
+
* @param gridColumns The form's grid column count (1-4).
|
|
49
|
+
* @param sectionColumns The desired columns for THIS group of fields (defaults
|
|
50
|
+
* to the grid width = one field per cell).
|
|
23
51
|
* @returns A new array of fields with colSpan applied where needed.
|
|
24
52
|
*/
|
|
25
|
-
export declare function applyAutoColSpan(fields: FormField[],
|
|
53
|
+
export declare function applyAutoColSpan(fields: FormField[], gridColumns: number, sectionColumns?: number): FormField[];
|
|
26
54
|
/**
|
|
27
55
|
* Filter out auto-managed system fields (id, audit timestamps, tenant/owner ids).
|
|
28
56
|
* Applied in BOTH create and edit modes, because these fields are always
|
|
@@ -54,6 +82,37 @@ export declare function filterCreateModeFields(fields: FormField[], objectSchema
|
|
|
54
82
|
* their current computed values rendered as readonly.
|
|
55
83
|
*/
|
|
56
84
|
export declare function filterAutoGeneratedFields(fields: FormField[], objectSchema?: any): FormField[];
|
|
85
|
+
/**
|
|
86
|
+
* Container-query-based grid classes for laying out form FIELDS inside a
|
|
87
|
+
* section. Uses `@container` / `@md:` / `@2xl:` / `@4xl:` variants so the grid
|
|
88
|
+
* responds to the form's actual width (modal / drawer / split panel) instead of
|
|
89
|
+
* the viewport — a narrow modal stays single-column regardless of viewport size.
|
|
90
|
+
*
|
|
91
|
+
* `1` maps to `undefined` so the caller falls back to the form renderer's
|
|
92
|
+
* default single-column stack (`space-y-4`).
|
|
93
|
+
*/
|
|
94
|
+
export declare const CONTAINER_GRID_COLS: Record<number, string | undefined>;
|
|
95
|
+
/** Clamp an arbitrary column count into the 1–4 keys of {@link CONTAINER_GRID_COLS}. */
|
|
96
|
+
export declare function containerGridColsFor(columns: number | undefined): string | undefined;
|
|
97
|
+
/**
|
|
98
|
+
* Build the layout-related props for a *section's* inner form (`SchemaRenderer`).
|
|
99
|
+
*
|
|
100
|
+
* A section groups its fields and lays them out in `columns` columns. That grid
|
|
101
|
+
* must be applied to the FIELD container INSIDE the form — not wrapped around
|
|
102
|
+
* the whole form element. Wrapping the single `<form>` in a multi-column grid
|
|
103
|
+
* (as the section variants used to) puts the entire form in the first grid cell
|
|
104
|
+
* and leaves every other column permanently empty. Here we instead thread
|
|
105
|
+
* `columns` + `fieldContainerClass` into the form so its own field container
|
|
106
|
+
* becomes the multi-column grid — mirroring the flat-fields layout path.
|
|
107
|
+
*
|
|
108
|
+
* @param fields Already-built (and permission-filtered) section fields.
|
|
109
|
+
* @param columns Section column count (1–4).
|
|
110
|
+
*/
|
|
111
|
+
export declare function sectionFormLayout(fields: FormField[], columns: number | undefined): {
|
|
112
|
+
fields: FormField[];
|
|
113
|
+
columns: number;
|
|
114
|
+
fieldContainerClass?: string;
|
|
115
|
+
};
|
|
57
116
|
/**
|
|
58
117
|
* Infer an appropriate modal size based on the number of layout columns.
|
|
59
118
|
* Used to auto-upgrade the modal width when auto-layout detects multi-column forms.
|
|
@@ -34,6 +34,18 @@ export declare function deriveColumns(childSchema: ObjectSchemaLike | undefined,
|
|
|
34
34
|
exclude?: string[];
|
|
35
35
|
maxColumns?: number;
|
|
36
36
|
}): GridColumn[];
|
|
37
|
+
/**
|
|
38
|
+
* Fill in missing widget metadata on author-supplied grid columns from the
|
|
39
|
+
* child object's field definitions. A view often lists columns as bare
|
|
40
|
+
* `{ field, label }` (the common, ergonomic authoring form) — without a `type`
|
|
41
|
+
* those cells fall back to a plain text `<Input>`, so a lookup, date, number or
|
|
42
|
+
* picklist field silently renders as free text. This resolves each such
|
|
43
|
+
* column's `type` (plus `options` / `reference` / computed `expr`) from the
|
|
44
|
+
* schema, exactly as {@link deriveColumns} would, while preserving the author's
|
|
45
|
+
* column set, order and labels. A column that already declares a `type` is left
|
|
46
|
+
* untouched — the author's explicit choice always wins.
|
|
47
|
+
*/
|
|
48
|
+
export declare function hydrateColumns(columns: GridColumn[] | undefined, childSchema: ObjectSchemaLike | undefined): GridColumn[];
|
|
37
49
|
/**
|
|
38
50
|
* Field names for a child's full "row form" (the per-row expand editor) — every
|
|
39
51
|
* editable business field, skipping system/audit fields, the back-reference FK,
|
package/dist/fieldGroups.d.ts
CHANGED
|
@@ -1,27 +1,21 @@
|
|
|
1
1
|
import { FormField, ObjectFormSection } from '@object-ui/types';
|
|
2
|
-
/** A declared field group on the object metadata. */
|
|
3
|
-
export interface DeclaredFieldGroup {
|
|
4
|
-
key: string;
|
|
5
|
-
label?: string;
|
|
6
|
-
/** Render the group's section header with a collapse toggle. */
|
|
7
|
-
collapsible?: boolean;
|
|
8
|
-
/** Start the (collapsible) group collapsed. */
|
|
9
|
-
collapsed?: boolean;
|
|
10
|
-
}
|
|
11
|
-
/** Read an object's `fieldGroups` into a normalized, well-typed list. */
|
|
12
|
-
export declare function readObjectFieldGroups(input: unknown): DeclaredFieldGroup[];
|
|
13
2
|
/**
|
|
14
3
|
* Derive form sections from an object's declared `fieldGroups` and each
|
|
15
4
|
* rendered field's `group`.
|
|
16
5
|
*
|
|
17
6
|
* Returns `null` when grouping does not apply — no declared groups, or no
|
|
18
7
|
* rendered field opts into a declared group — so callers fall back to a flat
|
|
19
|
-
* form.
|
|
20
|
-
* collect into a trailing untitled section (no `name`/`label`) so they render
|
|
21
|
-
* as a plain block rather than a card.
|
|
8
|
+
* form.
|
|
22
9
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
10
|
+
* The derivation runs against the RENDERED field list (post permission /
|
|
11
|
+
* visibility filtering), not the raw object def, so a section never names a
|
|
12
|
+
* field the form isn't showing. Any rendered field the shared derivation
|
|
13
|
+
* excludes from its default buckets (audit/system fields) is re-appended to
|
|
14
|
+
* the trailing bucket: the form was already told to render it, and a layout
|
|
15
|
+
* helper silently dropping a rendered input is exactly the failure mode
|
|
16
|
+
* ADR-0085 exists to kill.
|
|
17
|
+
*
|
|
18
|
+
* Section `fields` are field *names* (strings) so the result plugs straight
|
|
19
|
+
* into ObjectForm's existing section-render path.
|
|
26
20
|
*/
|
|
27
21
|
export declare function deriveFieldGroupSections(fields: FormField[], fieldGroups: unknown): ObjectFormSection[] | null;
|