@object-ui/fields 17.7.0 → 18.0.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 +792 -0
- package/README.md +146 -4
- package/dist/fieldHelpText.d.ts +41 -0
- package/dist/index.cjs +4 -4
- package/dist/index.css +42 -3
- package/dist/index.d.ts +219 -14
- package/dist/index.js +4090 -3009
- package/dist/resolveActionParams.d.ts +259 -0
- package/dist/widgets/FormulaField.d.ts +41 -0
- package/dist/widgets/GridField.d.ts +12 -4
- package/dist/widgets/RecipientPickerField.d.ts +32 -0
- package/dist/widgets/RegistryRefField.d.ts +77 -0
- package/dist/widgets/SummaryField.d.ts +30 -0
- package/dist/widgets/booleanValueLabel.d.ts +18 -0
- package/dist/widgets/date-picker/DatePickerField.d.ts +40 -0
- package/dist/widgets/date-picker/localeDateText.d.ts +39 -0
- package/dist/widgets/deriveLookupColumns.d.ts +1 -1
- package/dist/widgets/file-affordance.d.ts +30 -0
- package/dist/widgets/file-refused.d.ts +17 -0
- package/dist/widgets/file-value.d.ts +11 -0
- package/dist/widgets/longTextCarrierHandoff.d.ts +35 -0
- package/dist/widgets/lookupColumnDisplay.d.ts +2 -2
- package/dist/widgets/objectRefLabel.d.ts +16 -0
- package/dist/widgets/recipientKinds.d.ts +85 -0
- package/dist/widgets/richTextDisplay.d.ts +0 -17
- package/dist/widgets/searchOffer.d.ts +8 -0
- package/dist/widgets/toDomProps.d.ts +16 -3
- package/dist/widgets/useRecordQuery.d.ts +13 -0
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -42,18 +42,31 @@ View components use `getCellRenderer` to resolve the correct component for a fie
|
|
|
42
42
|
```tsx
|
|
43
43
|
import { getCellRenderer, resolveCellRendererType, type CellRendererProps } from '@object-ui/fields';
|
|
44
44
|
|
|
45
|
-
const MyGridCell = ({ field, value }: CellRendererProps) => {
|
|
45
|
+
const MyGridCell = ({ field, value, row }: CellRendererProps & { row: Record<string, unknown> }) => {
|
|
46
46
|
// Resolve the renderer KEY first, then the renderer. A field's declared
|
|
47
47
|
// `type` is not always the renderer's key: a textual field carrying a
|
|
48
48
|
// format hint (`Field.text({ format: 'phone' })`) resolves to the richer
|
|
49
|
-
// renderer
|
|
49
|
+
// renderer, and one declaring a widget with a read cell of its own
|
|
50
|
+
// (`widget: 'object-ref'`, `widget: 'recipient-picker'`) resolves to that
|
|
51
|
+
// cell. Passing `field.type` raw skips that mapping and draws such a
|
|
50
52
|
// column as bare text, silently. Resolving first is never worse: with no
|
|
51
|
-
//
|
|
53
|
+
// hint the resolver returns the declared `type` unchanged.
|
|
52
54
|
const Renderer = getCellRenderer(resolveCellRendererType(field));
|
|
53
|
-
|
|
55
|
+
// `dependentValues` is the row, for a cell whose value only means something
|
|
56
|
+
// beside a sibling column: a `recipient-picker` face reads the row's
|
|
57
|
+
// `recipient_type` from it. Without it, that face draws the stored text.
|
|
58
|
+
return <Renderer field={field} value={value} dependentValues={row} />;
|
|
54
59
|
};
|
|
55
60
|
```
|
|
56
61
|
|
|
62
|
+
This package registers the `object-ref` and `recipient-picker` keys with the stored
|
|
63
|
+
text as their default face. A host that can read the referenced lists registers faces
|
|
64
|
+
that name the value under the same keys (`registerFieldRenderer`); the console's live in
|
|
65
|
+
`@object-ui/app-shell`. They name a value as the edit widgets do, through the kind table
|
|
66
|
+
and the spellings this package publishes for it: `RECIPIENT_RECORD_KINDS`,
|
|
67
|
+
`RECIPIENT_REGISTRY_KINDS`, `FIELD_RECIPIENT_TYPE`, `recipientCandidateLabel`,
|
|
68
|
+
`objectRefOptionLabel` and the shared `UnresolvedReferenceMark` drawing.
|
|
69
|
+
|
|
57
70
|
## Standard Field Types
|
|
58
71
|
|
|
59
72
|
Supported types out of the box:
|
|
@@ -110,6 +123,80 @@ The app-shell `ActionParamDialog` uses these to render declared action params
|
|
|
110
123
|
through the exact same widgets as the object form — with a drift test pinning
|
|
111
124
|
param support ⊇ form support.
|
|
112
125
|
|
|
126
|
+
### Resolving declared action params
|
|
127
|
+
|
|
128
|
+
An action param is declared either inline (`name` + `type`) or field-backed
|
|
129
|
+
(`field`, plus `objectOverride` when the field lives on another object). Before
|
|
130
|
+
a dialog can render one, it has to be resolved against the object's field
|
|
131
|
+
definitions. This package holds the one resolver for that, shared by the
|
|
132
|
+
record page's action dialog (`@object-ui/app-shell`) and the selection bar's
|
|
133
|
+
bulk dialog (`@object-ui/plugin-grid`):
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
import {
|
|
137
|
+
resolveActionParams,
|
|
138
|
+
withKnownObjects,
|
|
139
|
+
type RawActionParam,
|
|
140
|
+
type ResolveActionParamsContext,
|
|
141
|
+
} from '@object-ui/fields';
|
|
142
|
+
|
|
143
|
+
type KnownObject = ResolveActionParamsContext['objects'][number];
|
|
144
|
+
|
|
145
|
+
// The object definitions the caller renders, and the ones the session's
|
|
146
|
+
// metadata store holds (`useMetadata().objects` from `@object-ui/react`).
|
|
147
|
+
declare const callerObjects: KnownObject[];
|
|
148
|
+
declare const storeObjects: KnownObject[];
|
|
149
|
+
|
|
150
|
+
const params: RawActionParam[] = [
|
|
151
|
+
{ field: 'crm_campaign', objectOverride: 'crm_campaign_member' }, // field-backed
|
|
152
|
+
{ name: 'note', type: 'textarea', label: 'Note' }, // inline
|
|
153
|
+
];
|
|
154
|
+
|
|
155
|
+
const resolved = resolveActionParams(params, {
|
|
156
|
+
objectName: 'crm_lead', // the owner when a param names no objectOverride
|
|
157
|
+
objects: withKnownObjects(callerObjects, storeObjects), // the caller's defs win by name
|
|
158
|
+
fieldLabel: (_objectName, _fieldName, fallback) => fallback,
|
|
159
|
+
locale: 'en',
|
|
160
|
+
});
|
|
161
|
+
// resolved[0] takes its type, label and `referenceTo` from the
|
|
162
|
+
// `crm_campaign_member.crm_campaign` field definition; resolved[1] is as declared.
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
- `resolveActionParam(param, ctx)` / `resolveActionParams(params, ctx)` — a
|
|
166
|
+
field-backed param inherits the field's type, label, options, placeholder,
|
|
167
|
+
help text, default and picker config. Inline keys on the param override the
|
|
168
|
+
field. A param whose field is not in `ctx.objects` comes back with
|
|
169
|
+
`unresolvedField: '<object>.<field>'`, and both dialogs refuse it rather than
|
|
170
|
+
drawing an input.
|
|
171
|
+
- `withKnownObjects(supplied, stored)` — unions two object lists by `name`,
|
|
172
|
+
the caller's first.
|
|
173
|
+
- `resolveParamWidgetType(type)` — the param-type fold (`checkbox`,
|
|
174
|
+
`reference`, `datetime-local` aliases) onto `resolveFormWidgetType`.
|
|
175
|
+
- `RESOLVED_ONLY_PARAM_KEYS` — keys of the resolved shape an author may not
|
|
176
|
+
write on a param (`referenceTo`, `displayField`, …), each with the fix the
|
|
177
|
+
resolver's dev warning prints.
|
|
178
|
+
- Types: `RawActionParam`, `RawActionParamOption`, `ResolveActionParamsContext`.
|
|
179
|
+
|
|
180
|
+
### A field's help line
|
|
181
|
+
|
|
182
|
+
`fieldHelpText(field)` is the one read of the help line a field draws under its
|
|
183
|
+
control. The record form (`@object-ui/plugin-form`) and a field-backed action
|
|
184
|
+
param both use it, so the two cannot disagree:
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
import { fieldHelpText } from '@object-ui/fields';
|
|
188
|
+
|
|
189
|
+
fieldHelpText({ inlineHelpText: 'Shown under the control', description: 'About the field' });
|
|
190
|
+
// → 'Shown under the control'
|
|
191
|
+
fieldHelpText({ inlineHelpText: '', description: 'About the field' });
|
|
192
|
+
// → 'About the field' (an empty string reads as absent)
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
It reads `@objectstack/spec`'s `inlineHelpText`, then `description`. It does
|
|
196
|
+
not read `help`: the spec refuses that key on a field, and an objectstack
|
|
197
|
+
server on spec 17.7.0 or later serves a field's translated help text on
|
|
198
|
+
`description`.
|
|
199
|
+
|
|
113
200
|
### Enumerating the CELL renderer registry
|
|
114
201
|
|
|
115
202
|
`listCellRendererTypes()` is the read-side twin of `FORM_FIELD_TYPES`: every
|
|
@@ -168,6 +255,46 @@ import { MaskedCellRenderer } from '@object-ui/fields';
|
|
|
168
255
|
const withheldCell = (value: unknown) => <MaskedCellRenderer value={value} />;
|
|
169
256
|
```
|
|
170
257
|
|
|
258
|
+
### Polymorphic pointer pairs (`referenceVia`)
|
|
259
|
+
|
|
260
|
+
A `text` field that declares `@objectstack/spec`'s `referenceVia` is the id half
|
|
261
|
+
of a two-column pointer pair: its value is a record id of the object that the
|
|
262
|
+
sibling column it names holds, on the same row (`sys_approval_request.record_id`
|
|
263
|
+
with `referenceVia: 'object_name'`, or `sys_activity.source_id` with
|
|
264
|
+
`referenceVia: 'source_object'`). The target changes per row, and a cell
|
|
265
|
+
renderer gets one value and no row, so the pair is resolved by the caller that
|
|
266
|
+
holds the row (objectui#12045):
|
|
267
|
+
|
|
268
|
+
- `resolveRecordPointer(field, row, optionsOf?)` is the one place the rule
|
|
269
|
+
lives. It returns `{ objectName, recordId }` (a `RecordPointer`) for a `text`
|
|
270
|
+
field with a non-empty `referenceVia` whose row fills both halves, and `null`
|
|
271
|
+
otherwise.
|
|
272
|
+
- When the field also declares `referenceDeletedWhen: { field, value }` (the
|
|
273
|
+
platform's assertion that it deleted the target, objectui#12489) and the row's
|
|
274
|
+
sibling `field` holds `value`, the pair carries `deletedLabel`: that option's
|
|
275
|
+
label from `optionsOf(field)`, the options the caller draws `select` cells
|
|
276
|
+
with. A face draws it as a tombstone and reads and links nothing; the default
|
|
277
|
+
face draws it in place of the record id.
|
|
278
|
+
- `RECORD_POINTER_CARD_TYPE` is the registry key a resolved pair is drawn with,
|
|
279
|
+
the pair as the renderer's `value`. This package registers a default under it
|
|
280
|
+
that draws the record id as text, so nothing changes for a host that does not
|
|
281
|
+
register a face. `@object-ui/app-shell` registers its record preview card
|
|
282
|
+
there.
|
|
283
|
+
|
|
284
|
+
The record details grid in `@object-ui/plugin-detail` is the call site today;
|
|
285
|
+
list cells are not one yet.
|
|
286
|
+
|
|
287
|
+
```tsx
|
|
288
|
+
import { getCellRenderer, resolveRecordPointer, RECORD_POINTER_CARD_TYPE } from '@object-ui/fields';
|
|
289
|
+
|
|
290
|
+
function PointerValue({ field, row }: { field: { name: string; type: string; referenceVia?: string }; row: Record<string, unknown> }) {
|
|
291
|
+
const pointer = resolveRecordPointer(field, row);
|
|
292
|
+
if (!pointer) return <>{String(row[field.name] ?? '')}</>;
|
|
293
|
+
const Face = getCellRenderer(RECORD_POINTER_CARD_TYPE);
|
|
294
|
+
return <Face value={pointer} field={{ name: field.name, type: 'text' }} />;
|
|
295
|
+
}
|
|
296
|
+
```
|
|
297
|
+
|
|
171
298
|
### File uploads in line-item grids
|
|
172
299
|
|
|
173
300
|
`GridField` (the master-detail line-items grid) supports `type: 'file'` columns:
|
|
@@ -179,6 +306,21 @@ or photo per row without opening the row form (objectui#2360). Columns accept
|
|
|
179
306
|
exported as `FileCell`). Auto-derived subform columns map `file`/`image`/
|
|
180
307
|
`avatar` fields to file columns instead of dropping them.
|
|
181
308
|
|
|
309
|
+
### Registry-name pickers (`position-ref`, `permission-ref`)
|
|
310
|
+
|
|
311
|
+
A `text` field that stores the machine name of one registry item declares
|
|
312
|
+
`widget: 'position-ref'` or `widget: 'permission-ref'` (resolved as
|
|
313
|
+
`field:<widget>`). The widget lists that registry through the data source's
|
|
314
|
+
`listMetadataItems(type)`, shows each item's label beside its name, and writes
|
|
315
|
+
the name only. A stored name the loaded registry lacks stays, flagged *not
|
|
316
|
+
found*. `position-ref` leaves out the audience anchors (the spec's
|
|
317
|
+
`AUDIENCE_ANCHOR_POSITIONS`: `everyone`, `guest`), because the server refuses
|
|
318
|
+
an anchor as a grant target; a stored anchor still shows as its own option.
|
|
319
|
+
When the adapter cannot list a registry, the list is empty, or the
|
|
320
|
+
load fails, it is a text box that takes the typed name (a failure is shown with
|
|
321
|
+
its cause). See
|
|
322
|
+
[`content/docs/guide/fields.md`](../../content/docs/guide/fields.md).
|
|
323
|
+
|
|
182
324
|
### Multi-value selects
|
|
183
325
|
|
|
184
326
|
A `select` field declared `multiple: true` selects zero-or-more values (spec
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { BaseFieldMetadata } from '@object-ui/types';
|
|
2
|
+
/**
|
|
3
|
+
* The help line a field draws under its control: the ONE read of a field
|
|
4
|
+
* definition's help text (objectui#12213). The order lives here and nowhere
|
|
5
|
+
* else, and both of its readers call this function:
|
|
6
|
+
*
|
|
7
|
+
* - `@object-ui/plugin-form`, for the record form's help line. `ObjectForm`'s
|
|
8
|
+
* field builder and `fromObjectSchema` both call it, so the flat, sectioned
|
|
9
|
+
* and tabbed forms cannot drift apart.
|
|
10
|
+
* - `resolveActionParam` in this package, for a field-backed action param
|
|
11
|
+
* that declares no `helpText` of its own.
|
|
12
|
+
*
|
|
13
|
+
* First non-empty value wins:
|
|
14
|
+
*
|
|
15
|
+
* 1. `inlineHelpText`, `@objectstack/spec`'s `FieldSchema.inlineHelpText`
|
|
16
|
+
* ("Help text displayed below the field in forms"). Studio's object field
|
|
17
|
+
* inspector writes it, and flow screens draw it in the same place.
|
|
18
|
+
* 2. `description`, the fallback the form always had. An objectstack server
|
|
19
|
+
* on `@objectstack/spec` 17.7.0 or later serves a field's translated help
|
|
20
|
+
* text here.
|
|
21
|
+
*
|
|
22
|
+
* ## `||`, not `??`
|
|
23
|
+
*
|
|
24
|
+
* An empty string reads as absent, so `inlineHelpText: ''` falls back to the
|
|
25
|
+
* description instead of hiding it. The spec declares no setting that hides
|
|
26
|
+
* the help line, and Studio's inspector stores a cleared box as no key at all
|
|
27
|
+
* (`inlineHelpText: v || undefined`). With `??`, an empty string would become
|
|
28
|
+
* a second, undeclared way to suppress the description.
|
|
29
|
+
*
|
|
30
|
+
* ## `help` is not read
|
|
31
|
+
*
|
|
32
|
+
* `FieldSchema` refuses `help` by name and suggests `inlineHelpText`, so no
|
|
33
|
+
* document that passes the write door carries it. Its one producer was an
|
|
34
|
+
* objectstack server older than `@objectstack/spec` 17.7.0, whose translator
|
|
35
|
+
* put a field's translated description on the served field's `help` key;
|
|
36
|
+
* 17.7.0 serves that text on `description`. The read of that served leg is
|
|
37
|
+
* retired (the ruling on objectui#12213): translated field help needs an
|
|
38
|
+
* objectstack server on spec 17.7.0 or later. A definition that still carries
|
|
39
|
+
* `help` draws its `inlineHelpText`, else its `description`, else nothing.
|
|
40
|
+
*/
|
|
41
|
+
export declare function fieldHelpText(field: Pick<BaseFieldMetadata, 'inlineHelpText' | 'description'>): string | undefined;
|