@object-ui/fields 17.6.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 +6228 -0
- package/README.md +251 -9
- package/dist/FieldEditWidget.d.ts +54 -6
- package/dist/coerceToSafeValue.d.ts +54 -0
- package/dist/currency.d.ts +1 -1
- package/dist/fieldHelpText.d.ts +41 -0
- package/dist/index.cjs +5 -5
- package/dist/index.css +68 -5
- package/dist/index.d.ts +446 -69
- package/dist/index.js +5326 -3443
- package/dist/resolveActionParams.d.ts +259 -0
- package/dist/widgets/AvatarField.d.ts +19 -3
- package/dist/widgets/BooleanField.d.ts +1 -1
- package/dist/widgets/DateField.d.ts +1 -1
- package/dist/widgets/DateTimeField.d.ts +1 -1
- package/dist/widgets/FilterConditionField.d.ts +21 -7
- package/dist/widgets/FormulaField.d.ts +41 -0
- package/dist/widgets/GeolocationField.d.ts +9 -3
- package/dist/widgets/GridField.d.ts +73 -101
- package/dist/widgets/LocationField.d.ts +30 -3
- package/dist/widgets/LookupField.d.ts +8 -0
- package/dist/widgets/NumberField.d.ts +1 -1
- package/dist/widgets/ObjectField.d.ts +9 -2
- package/dist/widgets/OptionsEmptyState.d.ts +29 -5
- package/dist/widgets/PasswordField.d.ts +14 -0
- package/dist/widgets/PeoplePicker.d.ts +17 -2
- package/dist/widgets/PercentField.d.ts +2 -1
- package/dist/widgets/PersonRow.d.ts +13 -2
- package/dist/widgets/RecipientPickerField.d.ts +75 -0
- package/dist/widgets/RecordPickerDialog.d.ts +31 -12
- package/dist/widgets/RegistryRefField.d.ts +77 -0
- package/dist/widgets/RichTextField.d.ts +1 -1
- package/dist/widgets/SelectionTray.d.ts +13 -2
- package/dist/widgets/SummaryField.d.ts +30 -0
- package/dist/widgets/TextField.d.ts +1 -1
- package/dist/widgets/TimeField.d.ts +1 -1
- 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 +63 -0
- package/dist/widgets/file-refused.d.ts +17 -0
- package/dist/widgets/file-size-guard.d.ts +5 -23
- package/dist/widgets/file-value.d.ts +49 -9
- package/dist/widgets/longTextCarrierHandoff.d.ts +35 -0
- package/dist/widgets/lookupColumnDisplay.d.ts +26 -9
- package/dist/widgets/nativeDateValue.d.ts +9 -27
- package/dist/widgets/number-format.d.ts +137 -0
- package/dist/widgets/numberBadInput.d.ts +135 -0
- package/dist/widgets/objectRefLabel.d.ts +16 -0
- package/dist/widgets/personDisplay.d.ts +22 -4
- package/dist/widgets/recipientKinds.d.ts +85 -0
- package/dist/widgets/richTextDisplay.d.ts +32 -13
- package/dist/widgets/searchOffer.d.ts +8 -0
- package/dist/widgets/toDomProps.d.ts +26 -4
- package/dist/widgets/toHostGroupProps.d.ts +53 -0
- package/dist/widgets/toHostProps.d.ts +105 -0
- package/dist/widgets/types.d.ts +11 -3
- package/dist/widgets/upload-error-message.d.ts +6 -0
- package/dist/widgets/uploadingScope.d.ts +142 -0
- package/dist/widgets/useCascadingOptions.d.ts +3 -2
- package/dist/widgets/useRecordQuery.d.ts +17 -2
- package/dist/widgets/useUploadingSignal.d.ts +8 -0
- package/package.json +11 -12
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { ActionParamDef, ActionParamOption } from '@object-ui/core';
|
|
2
|
+
import { I18nLabel } from '@objectstack/spec/ui';
|
|
3
|
+
/**
|
|
4
|
+
* Resolve a param `type` to the form widget key that renders it — the fold from
|
|
5
|
+
* a PARAM type spelling to its widget, the one alias table, read rather than
|
|
6
|
+
* restated (see `isLookupResolvedType` below, and app-shell's `paramToField`,
|
|
7
|
+
* which asks the same question one step later). Any type in `FORM_FIELD_TYPES`
|
|
8
|
+
* resolves to itself (identity — asserted by app-shell's drift test); aliases
|
|
9
|
+
* and unknown types resolve through the same fallback chain the form applies
|
|
10
|
+
* (unknown → `text`).
|
|
11
|
+
*/
|
|
12
|
+
export declare function resolveParamWidgetType(paramType: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Resolved params keep raw `FieldType` values (`text` / `email` / `select` /
|
|
15
|
+
* `file` / …), matching the `FieldType` enum in `@objectstack/spec`. **Do
|
|
16
|
+
* not** translate into the FormField widget vocabulary (`field:select`, …)
|
|
17
|
+
* here — `ActionParamDialog` owns that translation via its `paramToField()`
|
|
18
|
+
* adapter (ADR-0059).
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* One option as AUTHORED on an action param — {@link ActionParamOption} with
|
|
22
|
+
* the label on the authoring side of rc.6's `I18nLabel` widening.
|
|
23
|
+
*
|
|
24
|
+
* The distinction is the whole point of the authored/resolved split: an author
|
|
25
|
+
* may write `{ value: 'high', label: { en: 'High', 'zh-CN': '高' } }`, and
|
|
26
|
+
* `ActionParamDialog` reads `ActionParamOption.label` as a plain `string`. Left
|
|
27
|
+
* un-narrowed, the map would ride an INLINE option list straight through to the
|
|
28
|
+
* select widget (inline options pass through verbatim — see `resolvedOptions`),
|
|
29
|
+
* and render as `[object Object]` with no diagnostic anywhere. So the two types
|
|
30
|
+
* are kept apart and {@link resolveOptionLabels} is the one crossing point.
|
|
31
|
+
*
|
|
32
|
+
* Spelled out rather than `Omit<ActionParamOption, 'label'> & { … }`: `Omit`
|
|
33
|
+
* over a type carrying `[key: string]: unknown` resolves `Exclude<keyof T,
|
|
34
|
+
* 'label'>` back to `string | number`, so it drops `value`'s type AND keeps
|
|
35
|
+
* `label` as `unknown` — the derivation silently erases exactly the two keys it
|
|
36
|
+
* is supposed to be about.
|
|
37
|
+
*/
|
|
38
|
+
export type RawActionParamOption = {
|
|
39
|
+
/** Authored label — a plain string, or rc.6's inline per-locale map. */
|
|
40
|
+
label?: I18nLabel;
|
|
41
|
+
value: string;
|
|
42
|
+
/**
|
|
43
|
+
* Everything else an option declares (`visibleWhen` / `color` / `icon` /
|
|
44
|
+
* `disabled`), preserved verbatim — `fbc23e094`.
|
|
45
|
+
*/
|
|
46
|
+
[key: string]: unknown;
|
|
47
|
+
};
|
|
48
|
+
/** Raw param as authored on a schema action (post-zod). */
|
|
49
|
+
export interface RawActionParam {
|
|
50
|
+
name?: string;
|
|
51
|
+
field?: string;
|
|
52
|
+
objectOverride?: string;
|
|
53
|
+
/**
|
|
54
|
+
* Display label, as authored. `@objectstack/spec` 17.0.0-rc.6 widened
|
|
55
|
+
* `I18nLabel` from `string` to `string | Record<string, string>`, so an
|
|
56
|
+
* author may inline a per-locale map here
|
|
57
|
+
* (`label: { en: 'Reason', 'zh-CN': '原因' }`) — the same widening the spec's
|
|
58
|
+
* `ActionParamSchema.label` carries.
|
|
59
|
+
*
|
|
60
|
+
* This restatement is the load-bearing half (objectui#3174): when it drifts
|
|
61
|
+
* from what `@object-ui/types`' `ActionParam` says an author may write, this
|
|
62
|
+
* resolver stops accepting the public authoring type. That drift is exactly
|
|
63
|
+
* what a widened `I18nLabel` produced, and it is why the fix belongs on this
|
|
64
|
+
* DECLARATION rather than on the test that surfaced it.
|
|
65
|
+
*
|
|
66
|
+
* `resolveActionParams` emits `ActionParamDef.label`, which is a plain
|
|
67
|
+
* `string` — so the map is resolved on the way out (see {@link
|
|
68
|
+
* ResolveActionParamsContext.locale}), never forwarded.
|
|
69
|
+
*/
|
|
70
|
+
label?: I18nLabel;
|
|
71
|
+
type?: string;
|
|
72
|
+
required?: boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Option list authored inline on the param. Speaks the same vocabulary as the
|
|
75
|
+
* resolved side ({@link ActionParamOption}): the two keys this resolver reads
|
|
76
|
+
* plus a catch-all for whatever else an option declares (`visibleWhen`,
|
|
77
|
+
* `color`, `icon`, `disabled`) — `fbc23e094`.
|
|
78
|
+
*
|
|
79
|
+
* One key differs, and it is the same rc.6 widening as {@link
|
|
80
|
+
* RawActionParam.label} one level down: an option's `label` is authored as
|
|
81
|
+
* `I18nLabel` and RESOLVED to a `string` before it reaches
|
|
82
|
+
* `ActionParamOption`. See {@link RawActionParamOption}.
|
|
83
|
+
*/
|
|
84
|
+
options?: RawActionParamOption[];
|
|
85
|
+
placeholder?: string;
|
|
86
|
+
helpText?: string;
|
|
87
|
+
defaultValue?: unknown;
|
|
88
|
+
/** When true, seed defaultValue from the row record using the field name. */
|
|
89
|
+
defaultFromRow?: boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Carry-over declaration — the spec's `ActionParamSchema.carryOver`
|
|
92
|
+
* (objectui#6246): seeded from the row, rendered read-only, submitted
|
|
93
|
+
* verbatim. Copied onto `ActionParamDef.carryOver` unchanged on every branch
|
|
94
|
+
* below; `ActionParamDialog` is what honours it.
|
|
95
|
+
*/
|
|
96
|
+
carryOver?: boolean;
|
|
97
|
+
/** Allow multiple values (file/image/lookup/user params → array value). */
|
|
98
|
+
multiple?: boolean;
|
|
99
|
+
/** Accepted upload types (MIME types / extensions) for `file`/`image` params. */
|
|
100
|
+
accept?: string[];
|
|
101
|
+
/** Max upload size in bytes for `file`/`image` params. */
|
|
102
|
+
maxSize?: number;
|
|
103
|
+
/**
|
|
104
|
+
* Reference target for an INLINE `lookup`/`master_detail` param (objectstack-ai/objectstack#3405) —
|
|
105
|
+
* the object whose records the picker searches. Field-backed params inherit
|
|
106
|
+
* it from the referenced field instead (see `lookupExtras` below). Spelled
|
|
107
|
+
* `reference` to match `FieldSchema.reference` / `ActionParamSchema.reference`.
|
|
108
|
+
*/
|
|
109
|
+
reference?: string;
|
|
110
|
+
/**
|
|
111
|
+
* Visibility predicate (CEL) — mirrors the spec `ActionParamSchema.visible`.
|
|
112
|
+
* The server serialises it through `ExpressionInputSchema` as an
|
|
113
|
+
* `{ dialect, source }` envelope, so accept both the raw string and the
|
|
114
|
+
* envelope. Propagated to `ActionParamDef.visible` so `ActionParamDialog`
|
|
115
|
+
* can gate the param (e.g. hide `phoneNumber` unless `features.phoneNumber`).
|
|
116
|
+
* Absent = always visible.
|
|
117
|
+
*/
|
|
118
|
+
visible?: string | {
|
|
119
|
+
dialect?: string;
|
|
120
|
+
source?: string;
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Keys of the RESOLVED `ActionParamDef` that are not authorable on a raw param,
|
|
125
|
+
* mapped to the prescription an author needs (objectui#3174).
|
|
126
|
+
*
|
|
127
|
+
* They are deliberately ABSENT from `RawActionParam` above rather than declared
|
|
128
|
+
* and ignored: the whole defect this table exists for is that
|
|
129
|
+
* `@object-ui/types`' public `ActionParam` declared them "for parity with the
|
|
130
|
+
* resolved shape", so `{ name: 'account_id', type: 'lookup', referenceTo:
|
|
131
|
+
* 'account' }` type-checked, lost its picker target here, and rendered as a
|
|
132
|
+
* plain record-id text box. `ActionParamSchema` in `@objectstack/spec` is
|
|
133
|
+
* `.strict()` and rejects every one of them at parse time — `referenceTo` by
|
|
134
|
+
* name, with `reference` as the suggestion — so resolving them here would make
|
|
135
|
+
* objectui accept metadata the platform itself refuses to store. That is a
|
|
136
|
+
* second de-facto contract, not a kindness (AGENTS.md "contract-first"): such a
|
|
137
|
+
* param would work in a locally-authored TS action and fail at publish.
|
|
138
|
+
*
|
|
139
|
+
* So the disposition is: recognise, name, and refuse — never silently drop, and
|
|
140
|
+
* never quietly honour.
|
|
141
|
+
*/
|
|
142
|
+
export declare const RESOLVED_ONLY_PARAM_KEYS: Readonly<Record<string, string>>;
|
|
143
|
+
/** Field metadata as exposed by `useMetadata().objects[].fields`. */
|
|
144
|
+
interface RuntimeField {
|
|
145
|
+
type?: string;
|
|
146
|
+
label?: string;
|
|
147
|
+
required?: boolean;
|
|
148
|
+
placeholder?: string;
|
|
149
|
+
/**
|
|
150
|
+
* `@objectstack/spec`'s `FieldSchema.inlineHelpText`, the help line drawn
|
|
151
|
+
* under the field's control (objectui#12213). Read first for a field-backed
|
|
152
|
+
* param's `helpText`, through `fieldHelpText`, the read the record form
|
|
153
|
+
* shares.
|
|
154
|
+
*/
|
|
155
|
+
inlineHelpText?: string;
|
|
156
|
+
/**
|
|
157
|
+
* The help line's fallback, read second through `fieldHelpText`. An
|
|
158
|
+
* objectstack server on `@objectstack/spec` 17.7.0 or later serves a field's
|
|
159
|
+
* translated help text here.
|
|
160
|
+
*/
|
|
161
|
+
description?: string;
|
|
162
|
+
/**
|
|
163
|
+
* The field's own option list — `select` / `radio` / `checkboxes` metadata as
|
|
164
|
+
* `@objectstack/spec`'s `SelectOptionSchema` declares it, so entries may carry
|
|
165
|
+
* `visibleWhen` / `color` / `icon` / `disabled` alongside label and value. A
|
|
166
|
+
* bare string is shorthand for `{ label: s, value: s }`.
|
|
167
|
+
*/
|
|
168
|
+
options?: Array<ActionParamOption | string>;
|
|
169
|
+
multiple?: boolean;
|
|
170
|
+
defaultValue?: unknown;
|
|
171
|
+
accept?: string[];
|
|
172
|
+
maxSize?: number;
|
|
173
|
+
reference?: string;
|
|
174
|
+
displayField?: string;
|
|
175
|
+
reference_field?: string;
|
|
176
|
+
id_field?: string;
|
|
177
|
+
descriptionField?: string;
|
|
178
|
+
description_field?: string;
|
|
179
|
+
title_format?: string;
|
|
180
|
+
lookupColumns?: unknown[];
|
|
181
|
+
lookupFilters?: unknown[];
|
|
182
|
+
lookup_filters?: unknown[];
|
|
183
|
+
lookupPageSize?: number;
|
|
184
|
+
dependsOn?: unknown[];
|
|
185
|
+
}
|
|
186
|
+
interface RuntimeObject {
|
|
187
|
+
name?: string;
|
|
188
|
+
fields?: Record<string, RuntimeField>;
|
|
189
|
+
}
|
|
190
|
+
export interface ResolveActionParamsContext {
|
|
191
|
+
/** Default object name when a param's `objectOverride` is absent. */
|
|
192
|
+
objectName: string;
|
|
193
|
+
/** All known runtime objects (`useMetadata().objects`). */
|
|
194
|
+
objects: RuntimeObject[];
|
|
195
|
+
/** i18n resolver — `useObjectLabel().fieldLabel`. */
|
|
196
|
+
fieldLabel: (objectName: string, fieldName: string, fallback: string) => string;
|
|
197
|
+
/** Optional option-label translator — `useObjectLabel().fieldOptionLabel`. */
|
|
198
|
+
fieldOptionLabel?: (objectName: string, fieldName: string, optionValue: string, fallback: string) => string;
|
|
199
|
+
/**
|
|
200
|
+
* Row record providing default values for params with `defaultFromRow` set.
|
|
201
|
+
* Used by list_item actions (edit/delete dialogs) so the dialog opens with
|
|
202
|
+
* the row's current values pre-filled.
|
|
203
|
+
*/
|
|
204
|
+
row?: Record<string, unknown>;
|
|
205
|
+
/**
|
|
206
|
+
* Active UI language (BCP-47) used to resolve an inline per-locale
|
|
207
|
+
* {@link RawActionParam.label} down to the one string `ActionParamDef.label`
|
|
208
|
+
* can carry. Both callers thread `useObjectTranslation().language`.
|
|
209
|
+
*
|
|
210
|
+
* Optional and nullish-tolerant: omitted means "no locale known", which the
|
|
211
|
+
* spec's resolver documents as resolving to `en`. It is a context field
|
|
212
|
+
* rather than a hook read because this is a pure function — the caller is
|
|
213
|
+
* the component that already knows the language.
|
|
214
|
+
*/
|
|
215
|
+
locale?: string;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Resolve a single raw param against object metadata. Inline params pass
|
|
219
|
+
* through (with safe defaults); field-backed params inherit from the
|
|
220
|
+
* referenced field and accept inline overrides on top.
|
|
221
|
+
*/
|
|
222
|
+
export declare function resolveActionParam(param: RawActionParam, ctx: ResolveActionParamsContext): ActionParamDef;
|
|
223
|
+
/**
|
|
224
|
+
* Union the objects a CALLER holds with the ones the console's metadata store
|
|
225
|
+
* holds, caller first — the object list `resolveActionParams()` should be given.
|
|
226
|
+
*
|
|
227
|
+
* ## Why a union and not simply the store (`6cc910b6d`)
|
|
228
|
+
*
|
|
229
|
+
* The two lists answer different questions and neither contains the other.
|
|
230
|
+
* The caller's list is the world that caller is rendering: `ObjectView` passes
|
|
231
|
+
* the full published set, `DeclaredActionsBar` passes the ONE object it is
|
|
232
|
+
* drawing a toolbar for, `ConsoleShell`'s root runtime passes none, and a
|
|
233
|
+
* preview/draft host passes an overlaid world whose defs deliberately differ
|
|
234
|
+
* from the published ones. The store's list is every object the session has
|
|
235
|
+
* loaded. A caller that carries a def must keep it — replacing it would make a
|
|
236
|
+
* draft overlay render its published twin — so the caller is ranked FIRST and
|
|
237
|
+
* `resolveActionParam`'s `find()` takes the first match by name.
|
|
238
|
+
*
|
|
239
|
+
* What the store adds is the objects the caller never had: the owner of a
|
|
240
|
+
* `{ field }` param dispatched from a surface that is not scoped to that object
|
|
241
|
+
* at all, and the `objectOverride` target of a cross-object param. Before this,
|
|
242
|
+
* such a param resolved against a list that could not contain its owner and
|
|
243
|
+
* degraded — for a field-backed param, which carries no inline `type`, into a
|
|
244
|
+
* bare `text` param: an empty box, no dropdown, no request for the referenced
|
|
245
|
+
* object on the wire, while the identical field rendered a real picker on a
|
|
246
|
+
* record form off this very store.
|
|
247
|
+
*
|
|
248
|
+
* ⛔ Not a lenient fallback in the AGENTS.md #0.1 sense: no dialect is being
|
|
249
|
+
* tolerated and no shape coerced. The metadata is spec-compliant and already in
|
|
250
|
+
* the client; this is the seam that was not handing it over.
|
|
251
|
+
*
|
|
252
|
+
* Pure, and deduplicated by object `name` so a def cannot be resolved twice.
|
|
253
|
+
* Entries with no usable `name` are carried through from the caller's list
|
|
254
|
+
* (they are that caller's business) and skipped from the store's.
|
|
255
|
+
*/
|
|
256
|
+
export declare function withKnownObjects<T>(supplied: readonly T[] | undefined, stored: readonly T[] | undefined): T[];
|
|
257
|
+
/** Resolve an array of raw action params. */
|
|
258
|
+
export declare function resolveActionParams(params: RawActionParam[] | undefined, ctx: ResolveActionParamsContext): ActionParamDef[];
|
|
259
|
+
export {};
|
|
@@ -1,7 +1,23 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
2
|
import { FieldWidgetComponentProps } from './types.js';
|
|
3
3
|
/**
|
|
4
|
-
* Avatar field widget - provides an avatar/profile picture uploader
|
|
5
|
-
*
|
|
4
|
+
* Avatar field widget - provides an avatar/profile picture uploader.
|
|
5
|
+
*
|
|
6
|
+
* `avatar` is a member of the file-reference family, so its stored value is
|
|
7
|
+
* the bare `sys_file` id, exactly as for `file` and `image` (see
|
|
8
|
+
* `file-value`'s "Submitting"). A pick uploads through the ambient
|
|
9
|
+
* `UploadProvider` (`useUpload()`), and the id the adapter surfaced in
|
|
10
|
+
* `meta.fileId` is what `onChange` receives, through `fileValueForSubmit` —
|
|
11
|
+
* the one submit rule the file and image widgets use. A pick whose adapter
|
|
12
|
+
* surfaced no id (the object-URL default `useUpload()` falls back to when no
|
|
13
|
+
* provider is mounted, an S3/Azure-style adapter that mints no `sys_file`
|
|
14
|
+
* row) is refused with the same translated "did not complete" row, and the
|
|
15
|
+
* field is not changed. ⛔ The widget used to read the pick into a `data:` URL
|
|
16
|
+
* and store that string, inlining the whole image into the record row as a
|
|
17
|
+
* value the stored contract refuses (objectui#10785).
|
|
18
|
+
*
|
|
19
|
+
* Reading is `readFileValue`'s: a bare id renders from the storage endpoint,
|
|
20
|
+
* and a legacy `data:` or http(s) URL already on a record still renders as
|
|
21
|
+
* itself — ADR-0104's dual-read window is a read rule.
|
|
6
22
|
*/
|
|
7
|
-
export declare function AvatarField({ value, onChange, field, readonly, error, ...props }: FieldWidgetComponentProps<string>): React.JSX.Element;
|
|
23
|
+
export declare function AvatarField({ value, onChange, field, readonly, onUploadingChange, error, ...props }: FieldWidgetComponentProps<string>): React.JSX.Element;
|
|
@@ -4,4 +4,4 @@ import { FieldWidgetComponentProps } from './types.js';
|
|
|
4
4
|
* BooleanField - Toggle input supporting switch and checkbox variants
|
|
5
5
|
* Renders as Switch or Checkbox based on field widget configuration
|
|
6
6
|
*/
|
|
7
|
-
export declare function BooleanField({ value, onChange, field, readonly, ...props }: FieldWidgetComponentProps<boolean>): React.JSX.Element;
|
|
7
|
+
export declare function BooleanField({ value, onChange, field, readonly, error, ...props }: FieldWidgetComponentProps<boolean>): React.JSX.Element;
|
|
@@ -4,4 +4,4 @@ import { FieldWidgetComponentProps } from './types.js';
|
|
|
4
4
|
* DateField - Date picker input widget
|
|
5
5
|
* Uses native date input and displays locale-formatted date in readonly mode
|
|
6
6
|
*/
|
|
7
|
-
export declare function DateField({ value, onChange, field, readonly, ...props }: FieldWidgetComponentProps<string>): React.JSX.Element;
|
|
7
|
+
export declare function DateField({ value, onChange, field, readonly, error, ...props }: FieldWidgetComponentProps<string>): React.JSX.Element;
|
|
@@ -4,4 +4,4 @@ import { FieldWidgetComponentProps } from './types.js';
|
|
|
4
4
|
* DateTimeField - Combined date and time picker widget
|
|
5
5
|
* Displays both date and time in locale format when readonly
|
|
6
6
|
*/
|
|
7
|
-
export declare function DateTimeField({ value, onChange, field, readonly, ...props }: FieldWidgetComponentProps<string>): React.JSX.Element;
|
|
7
|
+
export declare function DateTimeField({ value, onChange, field, readonly, error, ...props }: FieldWidgetComponentProps<string>): React.JSX.Element;
|
|
@@ -7,8 +7,7 @@ interface BuilderCondition {
|
|
|
7
7
|
value: any;
|
|
8
8
|
}
|
|
9
9
|
/**
|
|
10
|
-
* Opt-in FilterBuilder operators this widget offers (objectui#
|
|
11
|
-
* objectui#4736).
|
|
10
|
+
* Opt-in FilterBuilder operators this widget offers (objectui#4736).
|
|
12
11
|
*
|
|
13
12
|
* The shared dropdown withholds these because two of its three consumers
|
|
14
13
|
* persist into dialects that cannot carry them (see `OPT_IN_OPERATORS` in
|
|
@@ -18,14 +17,19 @@ interface BuilderCondition {
|
|
|
18
17
|
* folded into a `ViewFilterRule` — so the spec's `FILTER_OPERATORS` is the only
|
|
19
18
|
* vocabulary it has to satisfy.
|
|
20
19
|
*
|
|
21
|
-
* - `containsCaseInsensitive` authors `$icontains`, executable on every
|
|
22
|
-
* driver and evaluation face the platform ships (objectstack#5702 +
|
|
23
|
-
* objectstack#6520).
|
|
24
20
|
* - `exists` / `notExists` author `$exists`, which `condToMongo` has emitted
|
|
25
21
|
* and `kvToCondition` has read back since objectui#2942. Naming them here
|
|
26
22
|
* is what KEEPS them reachable now that the shared dropdown no longer
|
|
27
23
|
* offers them to the list and view surfaces, whose dialects have no
|
|
28
|
-
* existence operator at all (objectui#4736).
|
|
24
|
+
* existence operator at all (objectui#4736). They are NOT folded onto
|
|
25
|
+
* `is_not_null` / `is_null` (objectui#9559 ruling B, objectui#9306): on the
|
|
26
|
+
* key-presence drivers that would change which records a stored sharing
|
|
27
|
+
* rule matches.
|
|
28
|
+
*
|
|
29
|
+
* The case-insensitive contains used to be named here too, as
|
|
30
|
+
* `containsCaseInsensitive`. Since objectui#9306 it is the protocol's own
|
|
31
|
+
* `icontains` and an ordinary operator every consumer is offered, so there is
|
|
32
|
+
* nothing to opt into; it still authors `$icontains`, exactly as before.
|
|
29
33
|
*
|
|
30
34
|
* Module scope, not an inline literal: a fresh array each render would reset
|
|
31
35
|
* `FilterBuilder`'s memo inputs on every keystroke.
|
|
@@ -38,12 +42,22 @@ export declare const FILTER_CONDITION_EXTRA_OPERATORS: readonly string[];
|
|
|
38
42
|
* chokepoint where a builder token becomes a spec `FieldOperatorsSchema` key,
|
|
39
43
|
* and a wrong spelling here is rejected downstream by `convertFiltersToAST`
|
|
40
44
|
* rather than at authoring time. @internal
|
|
45
|
+
*
|
|
46
|
+
* ⚠️ The arms are keyed on the builder's PROTOCOL ids (objectui#9306), and the
|
|
47
|
+
* `default` arm stores an EQUALITY. So an operator id with no arm here is not
|
|
48
|
+
* refused — it silently becomes `{ [field]: value }`, which for a
|
|
49
|
+
* `greater_than_or_equal` row would share a different set of records than the
|
|
50
|
+
* one on screen. Every id the dropdown can draw has its own arm, and
|
|
51
|
+
* `filter-builder-protocol-ids-census-9306.test.ts` (app-shell) pins each one's
|
|
52
|
+
* stored predicate, so a missing arm is a red test rather than a quiet `$eq`.
|
|
41
53
|
*/
|
|
42
54
|
export declare function condToMongo(c: BuilderCondition, typeOf: (f: string) => string | undefined): Record<string, any> | null;
|
|
43
55
|
/**
|
|
44
56
|
* Criteria → builder condition (the reverse of {@link condToMongo}). Returning
|
|
45
57
|
* `null` makes the builder refuse to load the rule ("criteria can't be
|
|
46
58
|
* represented"), so this must keep accepting spellings previously written.
|
|
59
|
+
* The rows it produces carry the builder's protocol ids (objectui#9306); the
|
|
60
|
+
* stored criteria are `$`-tokens, which that change did not touch.
|
|
47
61
|
* @internal
|
|
48
62
|
*/
|
|
49
63
|
export declare function kvToCondition(field: string, v: any, idx: number): BuilderCondition | null;
|
|
@@ -51,7 +65,7 @@ export declare function kvToCondition(field: string, v: any, idx: number): Build
|
|
|
51
65
|
* Would this criteria select EVERY record of the object?
|
|
52
66
|
*
|
|
53
67
|
* Mirrors the server's `isMatchAllCriteria` (objectstack `plugin-sharing`,
|
|
54
|
-
* #3896) closely enough to warn before the round-trip: blank, `{}`, `[]`, and
|
|
68
|
+
* objectstack-ai/objectstack#3896) closely enough to warn before the round-trip: blank, `{}`, `[]`, and
|
|
55
69
|
* the vacuous combinators. Deliberately conservative in the same direction —
|
|
56
70
|
* the cost of a false positive is one extra hint, the cost of a false negative
|
|
57
71
|
* is a save that fails with a toast. The server stays authoritative.
|
|
@@ -3,5 +3,46 @@ import { FieldWidgetComponentProps } from './types.js';
|
|
|
3
3
|
/**
|
|
4
4
|
* FormulaField - Read-only computed field
|
|
5
5
|
* Values are computed on the backend and cannot be edited
|
|
6
|
+
*
|
|
7
|
+
* ## One value, one reading (objectui#11748)
|
|
8
|
+
*
|
|
9
|
+
* This is the read-only FORM face of a formula; `FormulaCellRenderer` in this
|
|
10
|
+
* package's barrel is its TABLE face. The two used to format the value each by
|
|
11
|
+
* itself, so one stored value read two ways: a number here was `200000` (no
|
|
12
|
+
* `returnType`) or `200000.00` (a `toFixed(2)`), in monospace, beside the
|
|
13
|
+
* cell's `200,000`; a declared boolean or date read `Yes` / `Jul 4` here and
|
|
14
|
+
* `true` / `2026-07-04` in the cell.
|
|
15
|
+
*
|
|
16
|
+
* Both faces now read the SAME rule and draw each type through the calls the
|
|
17
|
+
* matching field type's faces make, so they agree on every value:
|
|
18
|
+
*
|
|
19
|
+
* - which type: the declared `returnType`; with none, a JS number is a
|
|
20
|
+
* number and anything else is text. ⛔ Nothing is inferred from the
|
|
21
|
+
* expression: the spec's own field form says consumers read `returnType`
|
|
22
|
+
* "instead of re-parsing the expression".
|
|
23
|
+
* - number: `formatNumberFieldValue`, the one call every number face makes
|
|
24
|
+
* (the locale's grouping, the width `resolveFieldScale` answers for a
|
|
25
|
+
* declared `scale`). The value is read the way the formula cell reads it
|
|
26
|
+
* (objectui#11683): blank is empty, and a declared number held as a
|
|
27
|
+
* numeric string is a number.
|
|
28
|
+
* - currency: money, through the currency field's own faces (`CurrencyField`
|
|
29
|
+
* read-only here, `CurrencyCellRenderer` in the cell), reading the
|
|
30
|
+
* formula's own `currencyConfig` as they read a currency field's
|
|
31
|
+
* (objectui#12111).
|
|
32
|
+
* - boolean: the locale's word, as `BooleanField`'s read-only branch draws
|
|
33
|
+
* it; only a JS boolean is a boolean, as there (objectui#8593).
|
|
34
|
+
* - date: `formatDate`'s DEFAULT face, as `DateField`'s read-only branch
|
|
35
|
+
* draws it (objectui#8194).
|
|
36
|
+
* - text: the value as the cell prints it, in the font `TextField`'s
|
|
37
|
+
* read-only branch draws (objectui#12357), declared `text` or not.
|
|
38
|
+
*
|
|
39
|
+
* Both faces also share the emptiness floor (`isEmptyValue` on the coerced
|
|
40
|
+
* value), so an empty value reads the shared affordance in both.
|
|
41
|
+
*
|
|
42
|
+
* The rule is spelled here and in the cell, because the barrel and this lazily
|
|
43
|
+
* loaded widget may not import each other (the reason `number-format.ts`
|
|
44
|
+
* gives). `__tests__/formulaFaces.returnType-11748.test.tsx` draws every
|
|
45
|
+
* declared type in both faces and compares the two texts, so neither can move
|
|
46
|
+
* alone.
|
|
6
47
|
*/
|
|
7
48
|
export declare function FormulaField({ value, field, ...props }: FieldWidgetComponentProps<any>): React.JSX.Element;
|
|
@@ -4,9 +4,15 @@ import { FieldWidgetComponentProps } from './types.js';
|
|
|
4
4
|
* Geolocation data structure
|
|
5
5
|
*/
|
|
6
6
|
export interface GeolocationValue {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
/**
|
|
8
|
+
* `number | null` since objectui#6848. `null` is what an emptied box emits —
|
|
9
|
+
* the spelling `CurrencyField` / `PercentField` / `NumberField` already used
|
|
10
|
+
* for the same user action — so the type has to admit it. `undefined` stays
|
|
11
|
+
* admissible because an untouched coordinate is genuinely absent.
|
|
12
|
+
*/
|
|
13
|
+
latitude?: number | null;
|
|
14
|
+
longitude?: number | null;
|
|
15
|
+
accuracy?: number | null;
|
|
10
16
|
}
|
|
11
17
|
/**
|
|
12
18
|
* Geolocation field widget - provides a location picker with coordinates
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
2
|
import { FieldWidgetComponentProps } from './types.js';
|
|
3
|
+
import { InlineGridColumn } from '@objectstack/spec/data';
|
|
3
4
|
/**
|
|
4
5
|
* GridField / LineItemsField — editable child-grid ("line items") widget.
|
|
5
6
|
*
|
|
@@ -46,106 +47,66 @@ import { FieldWidgetComponentProps } from './types.js';
|
|
|
46
47
|
* column. This is the renderer for the `field:grid` widget and the cell
|
|
47
48
|
* engine behind the master-detail subform (see ADR-0001).
|
|
48
49
|
*
|
|
49
|
-
* Column config
|
|
50
|
-
*
|
|
51
|
-
* type ∈ 'text' | 'number' | 'currency' | 'date' | 'datetime' | 'time'
|
|
52
|
-
* | 'select' | 'lookup' | 'file'
|
|
50
|
+
* Column config: `@objectstack/spec`'s inline grid column, by reference —
|
|
51
|
+
* see {@link GridColumn}.
|
|
53
52
|
*
|
|
54
|
-
* Field-level config
|
|
55
|
-
*
|
|
53
|
+
* Field-level config: the keys `GridFieldMetadata` (`@object-ui/types`)
|
|
54
|
+
* declares, each read under that one spelling (objectui#11070 round 8), and
|
|
55
|
+
* no other key: `sortField`, the last key read before any face declared it,
|
|
56
|
+
* is declared there too (objectui#11070 round 9). objectui#11610 renamed all
|
|
57
|
+
* eight from snake_case to camelCase; a field still carrying a snake_case
|
|
58
|
+
* spelling is refused by name instead of drawn (`RetiredGridFieldKeys`).
|
|
56
59
|
*/
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
name
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
* reachable. Required columns are never default-hidden.
|
|
108
|
-
*/
|
|
109
|
-
defaultHidden?: boolean;
|
|
110
|
-
/**
|
|
111
|
-
* A computed (read-only) column whose value is derived live from sibling
|
|
112
|
-
* cells via {@link expr} — e.g. an invoice line's `amount = quantity *
|
|
113
|
-
* unit_price`. The grid renders it read-only, recomputes it as the row's
|
|
114
|
-
* inputs change, and writes the result back into the row so it persists
|
|
115
|
-
* (and any running total reflects it). The classic spreadsheet pattern used
|
|
116
|
-
* by QuickBooks / Stripe / NetSuite line grids — nobody types the amount.
|
|
117
|
-
*/
|
|
118
|
-
computed?: boolean;
|
|
119
|
-
/** Arithmetic expression for a {@link computed} column. Supports `+ - * / %`,
|
|
120
|
-
* parentheses, numeric literals and field refs (`record.qty` or bare `qty`). */
|
|
121
|
-
expr?: string;
|
|
122
|
-
/** Decimal places to round a computed numeric/currency result to. */
|
|
123
|
-
scale?: number;
|
|
124
|
-
/** For `type: 'lookup'` — when a record is picked, copy its fields into any
|
|
125
|
-
* sibling columns of the same name (e.g. a product's unit_price/description).
|
|
126
|
-
* On by default for lookup columns; set `false` to disable the auto-fill. */
|
|
127
|
-
autofill?: boolean;
|
|
128
|
-
/**
|
|
129
|
-
* CEL predicate: when TRUE for this row, the cell is **read-only** (B2 field
|
|
130
|
-
* rules, generalized to grid cells). Evaluated per row against the row as
|
|
131
|
-
* `record` plus the header as `parent` (so a line locks when
|
|
132
|
-
* `parent.status == 'paid'` *or* on an intra-row condition like
|
|
133
|
-
* `record.kind == 'auto'`). Client-side UX; fails open (stays editable).
|
|
134
|
-
*/
|
|
135
|
-
readonlyWhen?: string | {
|
|
136
|
-
dialect?: string;
|
|
137
|
-
source: string;
|
|
138
|
-
};
|
|
139
|
-
/**
|
|
140
|
-
* CEL predicate: when TRUE for this row, the cell is **required** (flagged
|
|
141
|
-
* inline-invalid while empty). Same `record` + `parent` scope as
|
|
142
|
-
* {@link readonlyWhen}.
|
|
143
|
-
*/
|
|
144
|
-
requiredWhen?: string | {
|
|
145
|
-
dialect?: string;
|
|
146
|
-
source: string;
|
|
147
|
-
};
|
|
148
|
-
}
|
|
60
|
+
/**
|
|
61
|
+
* One grid column — `@objectstack/spec`'s inline grid column
|
|
62
|
+
* (`InlineGridColumn`, the element of `FieldSchema.inlineColumns`), BY
|
|
63
|
+
* REFERENCE (objectui#11070). The spec declares that shape as the strict
|
|
64
|
+
* mirror of this widget's column, so the widget's type IS the spec's: one
|
|
65
|
+
* declaration, the same one `GridFieldMetadata.columns` and
|
|
66
|
+
* `FormField.columns` (`@object-ui/types`) carry. This widget reads each
|
|
67
|
+
* column by exactly the spec's keys — every key below is one the spec
|
|
68
|
+
* declares, and there is no second spelling of any of them.
|
|
69
|
+
*
|
|
70
|
+
* How the widget reads the keys (the spec's own descriptions say what each
|
|
71
|
+
* MEANS; these are the renderer's notes):
|
|
72
|
+
*
|
|
73
|
+
* - `name` — the key a column reads and writes on each row object. There is
|
|
74
|
+
* deliberately no tolerant alias bridging the spelling objectui#3951
|
|
75
|
+
* retired to this one: a single spelling, enforced at the producer —
|
|
76
|
+
* AGENTS.md #0.1 (the spec refuses the retired spelling by name).
|
|
77
|
+
* (Wording note: do not restate that rule as an alternation expression over
|
|
78
|
+
* the two key names. `column-identity.ratchet.test.ts` (objectui#3104) scans
|
|
79
|
+
* these files line by line and cannot tell prose from code, so spelling the
|
|
80
|
+
* shape out here registers as a new dual read and fails the gate.)
|
|
81
|
+
* - `type` — the cell control and its read/write adapter. `date` /
|
|
82
|
+
* `datetime` / `time` are three DISTINCT controls, not one
|
|
83
|
+
* (objectui#3569): `<input type="date">` hands back a bare `YYYY-MM-DD` on
|
|
84
|
+
* change, so collapsing `datetime` onto it silently DELETED the time
|
|
85
|
+
* component from the record.
|
|
86
|
+
* - `prefix` — a symbol shown in a `currency` cell IN PLACE OF the resolved
|
|
87
|
+
* currency's own symbol. When absent, the cell shows the symbol of the
|
|
88
|
+
* currency it resolves (objectui#10355); there is no default symbol.
|
|
89
|
+
* - `defaultHidden` — collapsed into the column chooser, not dropped
|
|
90
|
+
* (`deriveColumns` sets it beyond the default-visible budget). Required
|
|
91
|
+
* columns are never default-hidden.
|
|
92
|
+
* - `computed` + `expr` — a read-only column recomputed live from sibling
|
|
93
|
+
* cells by this file's own safe arithmetic evaluator (`+ - * / %`,
|
|
94
|
+
* parentheses, numeric literals, `record.qty` or bare `qty`), and written
|
|
95
|
+
* back into the row so it persists and any running total reflects it.
|
|
96
|
+
* - `scale` — decimal places for a computed `number` result. ⛔ Not read on
|
|
97
|
+
* a `currency` column (objectui#10783): the resolved currency's ISO 4217
|
|
98
|
+
* minor unit decides both the stored and the shown width
|
|
99
|
+
* (`currencyWidth`), and the spec refuses `scale` on a column declaring
|
|
100
|
+
* `type: 'currency'`. A column that takes `currency` from its child field
|
|
101
|
+
* at render time is reported by `hydrateColumns` in
|
|
102
|
+
* `@object-ui/plugin-form` instead of being read in silence.
|
|
103
|
+
* - `autofill` — for a `lookup` column: picking a record copies its fields
|
|
104
|
+
* into sibling columns of the same name. On unless set `false`.
|
|
105
|
+
* - `readonlyWhen` / `requiredWhen` — CEL predicates evaluated per row
|
|
106
|
+
* against the row as `record` plus the header as `parent`. Client-side UX;
|
|
107
|
+
* a predicate that faults fails open.
|
|
108
|
+
*/
|
|
109
|
+
export type GridColumn = InlineGridColumn;
|
|
149
110
|
type Row = Record<string, any>;
|
|
150
111
|
/** Evaluate an arithmetic `expr` against `row`. null when blank/unparseable. */
|
|
151
112
|
export declare function evalArith(expr: string, row: Row): number | null;
|
|
@@ -163,10 +124,15 @@ export declare function evalArith(expr: string, row: Row): number | null;
|
|
|
163
124
|
* it is unit-testable independent of the picker UI.
|
|
164
125
|
*/
|
|
165
126
|
export declare function lookupAutofillPatch(columns: GridColumn[], col: GridColumn, record: any): Row;
|
|
166
|
-
|
|
127
|
+
/**
|
|
128
|
+
* @param tenantCurrency the tenant's default currency (`useLocalization()`),
|
|
129
|
+
* the resolver's last step for a `currency` column — see
|
|
130
|
+
* {@link storedFractionScale}.
|
|
131
|
+
*/
|
|
132
|
+
export declare function computeRow(columns: GridColumn[], row: Row, tenantCurrency?: string): Row;
|
|
167
133
|
/** Sum a numeric column across rows (ignoring blanks/NaN). */
|
|
168
134
|
export declare function sumColumn(rows: Row[], field: string): number;
|
|
169
|
-
|
|
135
|
+
type GridFieldProps = FieldWidgetComponentProps<Row[]> & {
|
|
170
136
|
/** When provided, each row shows an "expand" button that opens the row in a
|
|
171
137
|
* full form (the host — e.g. MasterDetailForm — renders the drawer/modal and
|
|
172
138
|
* writes the edited values back). Lets a "fat" child be edited in a real form
|
|
@@ -183,7 +149,13 @@ export declare function GridField({ value, onChange, field, readonly, disabled,
|
|
|
183
149
|
* `readonlyWhen` / `requiredWhen` CEL predicate — so a line cell can react to
|
|
184
150
|
* the header (`parent.status == 'paid'`). Supplied by MasterDetailForm. */
|
|
185
151
|
contextRecord?: Record<string, unknown>;
|
|
186
|
-
}
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* The `grid` field widget. A field whose metadata carries one of the retired
|
|
155
|
+
* snake_case keys is refused by name ({@link RetiredGridFieldKeys}); any other
|
|
156
|
+
* field draws the grid.
|
|
157
|
+
*/
|
|
158
|
+
export declare function GridField(props: GridFieldProps): React.JSX.Element;
|
|
187
159
|
/** Semantic alias — the master-detail subform's child grid. */
|
|
188
160
|
export declare const LineItemsField: typeof GridField;
|
|
189
161
|
export {};
|