@object-ui/fields 17.6.0 → 17.7.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.
Files changed (50) hide show
  1. package/CHANGELOG.md +5436 -0
  2. package/README.md +108 -8
  3. package/dist/FieldEditWidget.d.ts +54 -6
  4. package/dist/coerceToSafeValue.d.ts +54 -0
  5. package/dist/currency.d.ts +1 -1
  6. package/dist/index.cjs +5 -5
  7. package/dist/index.css +26 -2
  8. package/dist/index.d.ts +229 -57
  9. package/dist/index.js +3811 -3009
  10. package/dist/widgets/AvatarField.d.ts +19 -3
  11. package/dist/widgets/BooleanField.d.ts +1 -1
  12. package/dist/widgets/DateField.d.ts +1 -1
  13. package/dist/widgets/DateTimeField.d.ts +1 -1
  14. package/dist/widgets/FilterConditionField.d.ts +21 -7
  15. package/dist/widgets/GeolocationField.d.ts +9 -3
  16. package/dist/widgets/GridField.d.ts +63 -99
  17. package/dist/widgets/LocationField.d.ts +30 -3
  18. package/dist/widgets/LookupField.d.ts +8 -0
  19. package/dist/widgets/NumberField.d.ts +1 -1
  20. package/dist/widgets/ObjectField.d.ts +9 -2
  21. package/dist/widgets/OptionsEmptyState.d.ts +29 -5
  22. package/dist/widgets/PasswordField.d.ts +14 -0
  23. package/dist/widgets/PeoplePicker.d.ts +17 -2
  24. package/dist/widgets/PercentField.d.ts +2 -1
  25. package/dist/widgets/PersonRow.d.ts +13 -2
  26. package/dist/widgets/RecipientPickerField.d.ts +43 -0
  27. package/dist/widgets/RecordPickerDialog.d.ts +31 -12
  28. package/dist/widgets/RichTextField.d.ts +1 -1
  29. package/dist/widgets/SelectionTray.d.ts +13 -2
  30. package/dist/widgets/TextField.d.ts +1 -1
  31. package/dist/widgets/TimeField.d.ts +1 -1
  32. package/dist/widgets/file-affordance.d.ts +33 -0
  33. package/dist/widgets/file-size-guard.d.ts +5 -23
  34. package/dist/widgets/file-value.d.ts +38 -9
  35. package/dist/widgets/lookupColumnDisplay.d.ts +24 -7
  36. package/dist/widgets/nativeDateValue.d.ts +9 -27
  37. package/dist/widgets/number-format.d.ts +137 -0
  38. package/dist/widgets/numberBadInput.d.ts +135 -0
  39. package/dist/widgets/personDisplay.d.ts +22 -4
  40. package/dist/widgets/richTextDisplay.d.ts +36 -0
  41. package/dist/widgets/toDomProps.d.ts +10 -1
  42. package/dist/widgets/toHostGroupProps.d.ts +53 -0
  43. package/dist/widgets/toHostProps.d.ts +105 -0
  44. package/dist/widgets/types.d.ts +11 -3
  45. package/dist/widgets/upload-error-message.d.ts +6 -0
  46. package/dist/widgets/uploadingScope.d.ts +142 -0
  47. package/dist/widgets/useCascadingOptions.d.ts +3 -2
  48. package/dist/widgets/useRecordQuery.d.ts +4 -2
  49. package/dist/widgets/useUploadingSignal.d.ts +8 -0
  50. package/package.json +11 -12
@@ -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
- * Supports image URLs or file uploads
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#4023,
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.
@@ -4,9 +4,15 @@ import { FieldWidgetComponentProps } from './types.js';
4
4
  * Geolocation data structure
5
5
  */
6
6
  export interface GeolocationValue {
7
- latitude?: number;
8
- longitude?: number;
9
- accuracy?: number;
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,64 @@ 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 (a subset of `GridColumnDefinition`):
50
- * { name, label?, type?, options?, width?, required?, prefix?, step? }
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 (from `GridFieldMetadata`):
55
- * columns, min_rows, max_rows, allow_add, allow_delete, total_field
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: `sort_field`, the last key read before any face declared it,
56
+ * is declared there too (objectui#11070 round 9).
56
57
  */
57
- export interface GridColumn {
58
- /**
59
- * The column's field name — the key it reads and writes on each row object.
60
- *
61
- * Spelled `name`, exactly as the declared `GridColumnDefinition`
62
- * (`@object-ui/types`) and the grid docs page say (objectui#3951). This
63
- * widget used to read a divergent `field` key, so metadata authored against
64
- * the published type rendered every cell empty plus a React key warning.
65
- * There is deliberately no tolerant alias bridging the retired spelling to
66
- * this one: a single spelling, enforced at the producer — AGENTS.md #0.1.
67
- *
68
- * (Wording note: do not restate that rule as an alternation expression over
69
- * the two key names. `column-identity.ratchet.test.ts` (objectui#3104) scans
70
- * these files line by line and cannot tell prose from code, so spelling the
71
- * shape out here registers as a new dual read and fails the gate.)
72
- */
73
- name: string;
74
- label?: string;
75
- /**
76
- * Cell control + read/write adapter for the column.
77
- *
78
- * `date` / `datetime` / `time` are three DISTINCT controls, not one
79
- * (objectui#3569). Collapsing `datetime` onto the `date` control did not
80
- * merely under-render it — `<input type="date">` hands back a bare
81
- * `YYYY-MM-DD` on change, so touching the day of a `datetime` cell silently
82
- * DELETED its time component from the record.
83
- */
84
- type?: 'text' | 'number' | 'currency' | 'date' | 'datetime' | 'time' | 'select' | 'lookup' | 'file';
85
- options?: Array<{
86
- label: string;
87
- value: string;
88
- }>;
89
- width?: number;
90
- required?: boolean;
91
- prefix?: string;
92
- step?: number;
93
- /** For `type: 'lookup'` — the referenced object and label/id fields. */
94
- reference?: string;
95
- displayField?: string;
96
- idField?: string;
97
- /** Multi-value column: multi-record lookup, or multi-file upload cell. */
98
- multiple?: boolean;
99
- /** For `type: 'file'` — accepted MIME types / extensions for the picker
100
- * (e.g. `['image/*', '.pdf']`). Omit to accept anything. */
101
- accept?: string[];
102
- /**
103
- * Hidden from the grid by default but revealable via the column chooser.
104
- * Set by `deriveColumns` for fields beyond the default-visible budget — the
105
- * data is NOT dropped (it's just collapsed, like Odoo's `optional` columns /
106
- * Salesforce column personalization), so business-critical fields stay
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
- }
58
+ /**
59
+ * One grid column — `@objectstack/spec`'s inline grid column
60
+ * (`InlineGridColumn`, the element of `FieldSchema.inlineColumns`), BY
61
+ * REFERENCE (objectui#11070). The spec declares that shape as the strict
62
+ * mirror of this widget's column, so the widget's type IS the spec's: one
63
+ * declaration, the same one `GridFieldMetadata.columns` and
64
+ * `FormField.columns` (`@object-ui/types`) carry. This widget reads each
65
+ * column by exactly the spec's keys — every key below is one the spec
66
+ * declares, and there is no second spelling of any of them.
67
+ *
68
+ * How the widget reads the keys (the spec's own descriptions say what each
69
+ * MEANS; these are the renderer's notes):
70
+ *
71
+ * - `name` — the key a column reads and writes on each row object. There is
72
+ * deliberately no tolerant alias bridging the spelling objectui#3951
73
+ * retired to this one: a single spelling, enforced at the producer —
74
+ * AGENTS.md #0.1 (the spec refuses the retired spelling by name).
75
+ * (Wording note: do not restate that rule as an alternation expression over
76
+ * the two key names. `column-identity.ratchet.test.ts` (objectui#3104) scans
77
+ * these files line by line and cannot tell prose from code, so spelling the
78
+ * shape out here registers as a new dual read and fails the gate.)
79
+ * - `type` — the cell control and its read/write adapter. `date` /
80
+ * `datetime` / `time` are three DISTINCT controls, not one
81
+ * (objectui#3569): `<input type="date">` hands back a bare `YYYY-MM-DD` on
82
+ * change, so collapsing `datetime` onto it silently DELETED the time
83
+ * component from the record.
84
+ * - `prefix` — a symbol shown in a `currency` cell IN PLACE OF the resolved
85
+ * currency's own symbol. When absent, the cell shows the symbol of the
86
+ * currency it resolves (objectui#10355); there is no default symbol.
87
+ * - `defaultHidden` — collapsed into the column chooser, not dropped
88
+ * (`deriveColumns` sets it beyond the default-visible budget). Required
89
+ * columns are never default-hidden.
90
+ * - `computed` + `expr` — a read-only column recomputed live from sibling
91
+ * cells by this file's own safe arithmetic evaluator (`+ - * / %`,
92
+ * parentheses, numeric literals, `record.qty` or bare `qty`), and written
93
+ * back into the row so it persists and any running total reflects it.
94
+ * - `scale` — decimal places for a computed `number` result. ⛔ Not read on
95
+ * a `currency` column (objectui#10783): the resolved currency's ISO 4217
96
+ * minor unit decides both the stored and the shown width
97
+ * (`currencyWidth`), and the spec refuses `scale` on a column declaring
98
+ * `type: 'currency'`. A column that takes `currency` from its child field
99
+ * at render time is reported by `hydrateColumns` in
100
+ * `@object-ui/plugin-form` instead of being read in silence.
101
+ * - `autofill` — for a `lookup` column: picking a record copies its fields
102
+ * into sibling columns of the same name. On unless set `false`.
103
+ * - `readonlyWhen` / `requiredWhen` — CEL predicates evaluated per row
104
+ * against the row as `record` plus the header as `parent`. Client-side UX;
105
+ * a predicate that faults fails open.
106
+ */
107
+ export type GridColumn = InlineGridColumn;
149
108
  type Row = Record<string, any>;
150
109
  /** Evaluate an arithmetic `expr` against `row`. null when blank/unparseable. */
151
110
  export declare function evalArith(expr: string, row: Row): number | null;
@@ -163,7 +122,12 @@ export declare function evalArith(expr: string, row: Row): number | null;
163
122
  * it is unit-testable independent of the picker UI.
164
123
  */
165
124
  export declare function lookupAutofillPatch(columns: GridColumn[], col: GridColumn, record: any): Row;
166
- export declare function computeRow(columns: GridColumn[], row: Row): Row;
125
+ /**
126
+ * @param tenantCurrency the tenant's default currency (`useLocalization()`),
127
+ * the resolver's last step for a `currency` column — see
128
+ * {@link storedFractionScale}.
129
+ */
130
+ export declare function computeRow(columns: GridColumn[], row: Row, tenantCurrency?: string): Row;
167
131
  /** Sum a numeric column across rows (ignoring blanks/NaN). */
168
132
  export declare function sumColumn(rows: Row[], field: string): number;
169
133
  export declare function GridField({ value, onChange, field, readonly, disabled, className, error, onRowExpand, displayMode, onAdd, ...props }: FieldWidgetComponentProps<Row[]> & {
@@ -1,7 +1,34 @@
1
1
  import { default as React } from 'react';
2
+ import { LocationValue } from '@objectstack/spec/data';
2
3
  import { FieldWidgetComponentProps } from './types.js';
3
4
  /**
4
- * LocationField - Geographic coordinate input for latitude and longitude
5
- * Stores location as { latitude, longitude } object and displays as comma-separated pair
5
+ * The stored shape of a `type: 'location'` value — RE-EXPORTED from
6
+ * `@objectstack/spec/data`, never re-declared here (objectui#6272).
7
+ *
8
+ * `LocationValue` is `z.input` of the spec's `LocationValueSchema`
9
+ * (`{ lat, lng, altitude?, accuracy? }`), which is what `valueSchemaFor({ type:
10
+ * 'location' })` validates a stored location against. A second local
11
+ * declaration under the spec's own name is objectstack#4115's failure class and
12
+ * is refused by `scripts/check-spec-symbol-derivation.mjs` — it was refused on
13
+ * the closed PR #6418, which is why this is a bare re-export.
6
14
  */
7
- export declare function LocationField({ value, onChange, field, readonly, error, ...props }: FieldWidgetComponentProps<any>): React.JSX.Element;
15
+ export type { LocationValue } from '@objectstack/spec/data';
16
+ /**
17
+ * LocationField - Geographic coordinate input for a `type: 'location'` value.
18
+ *
19
+ * Reads and writes `@objectstack/spec`'s `LocationValue` (`{ lat, lng }`) and
20
+ * displays it as the comma-separated pair a user types. The coordinates are
21
+ * still called latitude and longitude to a human — only the STORED key names
22
+ * are the spec's (objectui#6272), which is why the placeholder names the two
23
+ * coordinates rather than the `lat`/`lng` keys. That is a statement about KEY
24
+ * NAMES, not about language: the placeholder's words are the reader's, from
25
+ * the locale packs (objectui#8149, {@link placeholderPair}).
26
+ *
27
+ * ⚠️ BREAKING (objectui#6272): a record stored in the deprecated
28
+ * `{ latitude, longitude }` spelling — including one this widget itself wrote
29
+ * before the flip — now renders EMPTY here until it is re-saved or fixed at the
30
+ * data layer. It keeps rendering correctly in detail views and on the map,
31
+ * which read the spec spelling first. That cost was presented and accepted as
32
+ * part of the A1 ruling; it is not an oversight to route around with a shim.
33
+ */
34
+ export declare function LocationField({ value, onChange, field, readonly, error, ...props }: FieldWidgetComponentProps<LocationValue | null>): React.JSX.Element;
@@ -3,6 +3,14 @@ import { FieldWidgetComponentProps } from './types.js';
3
3
  export interface LookupOption {
4
4
  value: string | number;
5
5
  label: string;
6
+ /**
7
+ * Secondary text: searched by the popover typeahead alongside the label, and
8
+ * rendered as supporting text. For AUTHORED static options this is the
9
+ * declared `SelectOptionMetadata.description` (objectui#6153 — declared
10
+ * there, and on `@objectstack/spec`'s `SelectOptionSchema`, precisely
11
+ * because this widget consumes it); for fetched records `recordToOption`
12
+ * derives it from `descriptionField`.
13
+ */
6
14
  description?: string;
7
15
  [key: string]: any;
8
16
  }
@@ -4,4 +4,4 @@ import { FieldWidgetComponentProps } from './types.js';
4
4
  * NumberField - Numeric input with optional decimal precision
5
5
  * Supports min/max/step constraints and configurable decimal precision
6
6
  */
7
- export declare function NumberField({ value, onChange, field, readonly, ...props }: FieldWidgetComponentProps<number>): React.JSX.Element;
7
+ export declare function NumberField({ value, onChange, field, readonly, error, ...props }: FieldWidgetComponentProps<number>): React.JSX.Element;
@@ -1,7 +1,14 @@
1
1
  import { default as React } from 'react';
2
2
  import { FieldWidgetComponentProps } from './types.js';
3
3
  /**
4
- * ObjectField - JSON object editor
5
- * Allows editing structured JSON data
4
+ * ObjectField - JSON editor for a structured value.
5
+ *
6
+ * The form face of the free-form JSON types: `object`, `composite`, `record`, and
7
+ * since objectui#11448 `json`, which used to alias the raw-text code editor and
8
+ * so showed a stored object as `[object Object]` and saved an edit as a string.
9
+ * A json value need not be an object — an array, a number, a string, a boolean
10
+ * and `null` are all JSON — and this editor shows and parses each of them as
11
+ * itself: the box holds `JSON.stringify(value, null, 2)` and an edit emits
12
+ * `JSON.parse(text)`.
6
13
  */
7
14
  export declare function ObjectField({ value, onChange, field, readonly, error, ...props }: FieldWidgetComponentProps<any>): React.JSX.Element;
@@ -1,5 +1,5 @@
1
1
  import { default as React } from 'react';
2
- import { HostGroupProps } from './toHostGroupProps.js';
2
+ import { HostControlProps, HostGroupProps } from './toHostGroupProps.js';
3
3
  /**
4
4
  * The "this option list cannot be filled" state shared by every fixed-option
5
5
  * widget (`SelectField` single, `MultiSelectField`, `RadioField`,
@@ -56,10 +56,34 @@ export interface OptionsEmptyStateProps {
56
56
  * `aria-describedby` and the `role` that makes them meaningful may reach this
57
57
  * element, and reopening a spread is what objectui#3291 exists to prevent —
58
58
  * `aria-invalid` / `aria-required` are control-channel state and stay off this
59
- * surface. Absent for the single `SelectField` — it is not group-labelled, its
60
- * label still uses a plain `for`, and it must keep emitting no such
61
- * attributes.
59
+ * surface. Absent for the single `SelectField`, which is not group-labelled
60
+ * and fills {@link OptionsEmptyStateProps.hostControlProps} instead.
62
61
  */
63
62
  hostGroupProps?: HostGroupProps;
63
+ /**
64
+ * The host label's PLAIN-`for` plumbing, for the one caller that is NOT
65
+ * group-labelled — the single `SelectField` (objectui#8803).
66
+ *
67
+ * Supplying this switches the rendered element from a `div` to an `<output>`,
68
+ * and that is the entire repair. `select` declares `labelling: 'control'`,
69
+ * which the registry defines as "the component's outermost rendered element
70
+ * is a LABELABLE HTML element" — true of the Radix
71
+ * `button[role="combobox"]` it renders with options, and FALSE of the `div`
72
+ * this box used to be. So the host's `for` pointed at an id no element
73
+ * carried, and `HTMLLabelElement.control` was null. Landing the id on the
74
+ * `div` instead was measured and rejected: `for` may only reference a
75
+ * labelable element, so it stayed null and the label stayed unusable.
76
+ *
77
+ * `<output>` is labelable, and its implicit `status` role claims no
78
+ * interactivity — it is the result of a computation, which is what this box
79
+ * reports. Declaring `select` as `'group'` was the alternative and it
80
+ * measurably moved the LIVE path: a select WITH options lost the working
81
+ * `<label for>` to its combobox (objectui#3306).
82
+ *
83
+ * Mutually exclusive with `hostGroupProps` — one host, one naming channel
84
+ * (objectui#3978). A caller that supplies neither renders the box with no
85
+ * host plumbing at all, which is what standalone rendering has always done.
86
+ */
87
+ hostControlProps?: HostControlProps;
64
88
  }
65
- export declare function OptionsEmptyState({ emptyHint, gated, dependsOnFields, testId, className, hostGroupProps, }: OptionsEmptyStateProps): React.JSX.Element;
89
+ export declare function OptionsEmptyState({ emptyHint, gated, dependsOnFields, testId, className, hostGroupProps, hostControlProps, }: OptionsEmptyStateProps): React.JSX.Element;
@@ -3,5 +3,19 @@ import { FieldWidgetComponentProps } from './types.js';
3
3
  /**
4
4
  * PasswordField - Secure password input with visibility toggle
5
5
  * Includes show/hide toggle button and masks value in readonly mode
6
+ *
7
+ * Readonly draws the mask for a credential that is SET, and the shared
8
+ * `EmptyValue` affordance for one that is NOT (objectui#10639). The platform's
9
+ * read contract is presence-preserving: `@objectstack/spec`'s `SECRET_MASK`
10
+ * docblock says an unset credential "reads back `null` instead, never this
11
+ * mask", which is what lets a reader tell "configured" from "not configured".
12
+ *
13
+ * "Empty" is the password CELL's predicate (`MaskedCellRenderer` in this
14
+ * package's barrel, objectui#8678), called on the same two helpers, so `{}`
15
+ * and a whitespace-only string stay values and keep the mask. The helpers are
16
+ * imported from their own modules, never from the barrel, which lazy-loads
17
+ * this widget. ⛔ The value is never printed, and a set value keeps exactly
18
+ * the mask it drew before. `__tests__/PasswordField.readonlyEmpty-10639`
19
+ * pins the widget's "empty" to the cell's.
6
20
  */
7
21
  export declare function PasswordField({ value, onChange, field, readonly, className, ...props }: FieldWidgetComponentProps<string>): React.JSX.Element;
@@ -27,12 +27,27 @@ export interface PeoplePickerProps {
27
27
  dataSource: DataSource;
28
28
  /** Object to query — `sys_user` for user fields. */
29
29
  objectName: string;
30
+ /**
31
+ * The person's name field (default `name`), read first of the name ladder
32
+ * (then `name`, `username`, `label`). Once the permission policy has loaded,
33
+ * a rung the user may not read on `objectName` is skipped.
34
+ */
30
35
  displayField?: string;
31
36
  idField?: string;
32
- /** Dotted field paths for the row subtitle, e.g. `['primary_business_unit_id.name','email']`. */
37
+ /**
38
+ * Dotted field paths for the row subtitle, e.g. `['primary_business_unit_id.name','email']`.
39
+ * Once the permission policy has loaded, a path whose field on `objectName`
40
+ * the user may not read is not drawn.
41
+ */
33
42
  subtitleFields?: string[];
43
+ /** Avatar image field; not drawn once the loaded policy denies it on `objectName`. */
34
44
  avatarField?: string;
35
- /** Related entities to expand (e.g. `['primary_business_unit_id']` for the department name). */
45
+ /**
46
+ * Related entities to expand (e.g. `['primary_business_unit_id']` for the
47
+ * department name). Once the permission policy has loaded, a relation the
48
+ * user may not read on `objectName` is left out, as it is from the list
49
+ * derived from `subtitleFields` when this is not passed.
50
+ */
36
51
  expand?: string[];
37
52
  /** Narrow the server searchable set (ADR-0061). */
38
53
  searchFields?: string[];
@@ -1,7 +1,8 @@
1
1
  import { default as React } from 'react';
2
2
  import { FieldWidgetComponentProps } from './types.js';
3
3
  /**
4
- * PercentField - Percentage input with configurable decimal precision
4
+ * PercentField - Percentage input whose decimal places follow the field's
5
+ * `scale` as the protocol resolves it (see the read below)
5
6
  * Stores values as decimals (0-1) and displays as percentages (0-100%)
6
7
  * Includes a slider for interactive control.
7
8
  */
@@ -10,8 +10,19 @@ import { default as React } from 'react';
10
10
  export interface PersonRowProps {
11
11
  record: any;
12
12
  displayField?: string;
13
+ /**
14
+ * The fields the name is read from, in order; defaults to the ladder of
15
+ * `displayField` (`getPersonNameFields`). PeoplePicker passes the fields of
16
+ * that ladder the loaded policy lets the viewer read (objectui#10535).
17
+ */
18
+ nameFields?: string[];
13
19
  subtitleFields?: string[];
14
- avatarField?: string;
20
+ /**
21
+ * Avatar image field (default `image`). `null` draws no image, only the
22
+ * initials: what PeoplePicker passes when field-level security withholds the
23
+ * field (objectui#10433).
24
+ */
25
+ avatarField?: string | null;
15
26
  selected?: boolean;
16
27
  /** Keyboard cursor is on this row — highlight + scroll into view. */
17
28
  active?: boolean;
@@ -20,4 +31,4 @@ export interface PersonRowProps {
20
31
  onSelect?: (record: any) => void;
21
32
  className?: string;
22
33
  }
23
- export declare function PersonRow({ record, displayField, subtitleFields, avatarField, selected, active, highlightQuery, onSelect, className, }: PersonRowProps): React.JSX.Element;
34
+ export declare function PersonRow({ record, displayField, nameFields, subtitleFields, avatarField, selected, active, highlightQuery, onSelect, className, }: PersonRowProps): React.JSX.Element;
@@ -1,4 +1,47 @@
1
1
  import { default as React } from 'react';
2
2
  import { FieldWidgetComponentProps } from './types.js';
3
+ /** A user-valued column offered by the `field` recipient mode. */
4
+ interface UserFieldDef {
5
+ /** The machine name — this is what gets stored in `recipient_id`. */
6
+ name: string;
7
+ label: string;
8
+ }
9
+ /**
10
+ * Does this declared field hold USERS?
11
+ *
12
+ * ⭐ This predicate is the picker's half of a two-sided agreement with the
13
+ * sharing evaluator, which asks the same question of the same two spellings:
14
+ * the `user` type (whose target is fixed to `sys_user` by the type itself —
15
+ * `Field.user()` takes no target), and a `lookup` / `master_detail` whose
16
+ * `reference` is `sys_user`.
17
+ *
18
+ * ⛔ The two must not drift apart. The evaluator treats a column that is not
19
+ * user-typed as "grants nobody" and warns once per rule, so a picker that
20
+ * OFFERED a wider set would let an admin save a rule that looks configured and
21
+ * authorises nobody — worse than the hand-typed name this mode replaces,
22
+ * because it has a credible appearance.
23
+ *
24
+ * `reference` is the only spelling the protocol declares (objectui#6837):
25
+ * `FieldSchema` refuses `reference_to` by name, and the evaluator reads
26
+ * `reference` as well.
27
+ *
28
+ * @internal exported for tests
29
+ */
30
+ export declare function fieldHoldsUsers(def: unknown): boolean;
31
+ /**
32
+ * The user-valued columns of an object schema, in declaration order.
33
+ *
34
+ * Accepts both shapes an object schema spells `fields` in — a name-keyed map
35
+ * and an array of definitions carrying their own `name`.
36
+ *
37
+ * ⛔ `hidden` is deliberately NOT filtered here, unlike the filter builder's
38
+ * own field derivation: the evaluator honours a hidden user column exactly
39
+ * like a visible one, and withholding it would break the agreement above in
40
+ * the other direction — an authorable, working configuration the picker
41
+ * refuses to offer.
42
+ *
43
+ * @internal exported for tests
44
+ */
45
+ export declare function deriveUserFields(schema: any): UserFieldDef[];
3
46
  export declare function RecipientPickerField({ value, onChange, readonly, className, error, ...props }: FieldWidgetComponentProps<string>): React.JSX.Element;
4
47
  export default RecipientPickerField;