@object-ui/fields 17.1.0 → 17.2.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 +194 -0
- package/dist/FieldEditWidget.d.ts +2 -2
- package/dist/__tests__/spec-symbol-batch7.test.d.ts +8 -0
- package/dist/__tests__/widget-props-contract.test.d.ts +8 -0
- package/dist/index.cjs +3 -3
- package/dist/index.js +290 -292
- package/dist/widgets/AddressField.d.ts +2 -2
- package/dist/widgets/AutoNumberField.d.ts +2 -2
- package/dist/widgets/AvatarField.d.ts +2 -2
- package/dist/widgets/BooleanField.d.ts +2 -2
- package/dist/widgets/CapabilityMultiSelectField.d.ts +2 -2
- package/dist/widgets/CheckboxesField.d.ts +2 -2
- package/dist/widgets/CodeField.d.ts +2 -2
- package/dist/widgets/ColorField.d.ts +2 -2
- package/dist/widgets/CurrencyField.d.ts +2 -2
- package/dist/widgets/DateField.d.ts +2 -2
- package/dist/widgets/DateTimeField.d.ts +2 -2
- package/dist/widgets/EmailField.d.ts +2 -2
- package/dist/widgets/FileField.d.ts +2 -2
- package/dist/widgets/FilterConditionField.d.ts +2 -2
- package/dist/widgets/FormulaField.d.ts +2 -2
- package/dist/widgets/GeolocationField.d.ts +2 -2
- package/dist/widgets/GridField.d.ts +2 -2
- package/dist/widgets/ImageField.d.ts +2 -2
- package/dist/widgets/LocationField.d.ts +2 -2
- package/dist/widgets/LookupField.d.ts +2 -2
- package/dist/widgets/MasterDetailField.d.ts +2 -2
- package/dist/widgets/MultiSelectField.d.ts +2 -2
- package/dist/widgets/NumberField.d.ts +2 -2
- package/dist/widgets/ObjectField.d.ts +2 -2
- package/dist/widgets/ObjectRefField.d.ts +2 -2
- package/dist/widgets/PasswordField.d.ts +2 -2
- package/dist/widgets/PercentField.d.ts +2 -2
- package/dist/widgets/PhoneField.d.ts +2 -2
- package/dist/widgets/QRCodeField.d.ts +2 -2
- package/dist/widgets/RadioField.d.ts +2 -2
- package/dist/widgets/RatingField.d.ts +2 -2
- package/dist/widgets/RecipientPickerField.d.ts +2 -2
- package/dist/widgets/RichTextField.d.ts +2 -2
- package/dist/widgets/SelectField.d.ts +2 -2
- package/dist/widgets/SignatureField.d.ts +2 -2
- package/dist/widgets/SliderField.d.ts +2 -2
- package/dist/widgets/SummaryField.d.ts +2 -2
- package/dist/widgets/TagsField.d.ts +2 -2
- package/dist/widgets/TextAreaField.d.ts +2 -2
- package/dist/widgets/TextField.d.ts +2 -2
- package/dist/widgets/TimeField.d.ts +2 -2
- package/dist/widgets/UrlField.d.ts +2 -2
- package/dist/widgets/UserField.d.ts +2 -2
- package/dist/widgets/VectorField.d.ts +2 -2
- package/dist/widgets/file-value.d.ts +20 -33
- package/dist/widgets/types.d.ts +119 -3
- package/package.json +8 -8
- package/src/FieldEditWidget.tsx +6 -4
- package/src/__tests__/spec-symbol-batch7.test.ts +112 -0
- package/src/__tests__/widget-props-contract.test.tsx +129 -0
- package/src/complex-widgets.test.tsx +3 -3
- package/src/datetime-widgets.test.tsx +2 -2
- package/src/index.tsx +3 -1
- package/src/widgets/AddressField.tsx +2 -2
- package/src/widgets/AutoNumberField.tsx +2 -2
- package/src/widgets/AvatarField.tsx +2 -2
- package/src/widgets/BooleanField.tsx +2 -2
- package/src/widgets/CapabilityMultiSelectField.tsx +4 -4
- package/src/widgets/CheckboxesField.tsx +4 -4
- package/src/widgets/CodeField.tsx +2 -2
- package/src/widgets/ColorField.tsx +2 -2
- package/src/widgets/CurrencyField.tsx +2 -2
- package/src/widgets/DateField.tsx +2 -2
- package/src/widgets/DateTimeField.tsx +2 -2
- package/src/widgets/EmailField.tsx +2 -2
- package/src/widgets/FileField.tsx +2 -2
- package/src/widgets/FilterConditionField.tsx +3 -3
- package/src/widgets/FormulaField.tsx +2 -2
- package/src/widgets/GeolocationField.tsx +2 -2
- package/src/widgets/GridField.tsx +3 -3
- package/src/widgets/ImageField.tsx +2 -2
- package/src/widgets/LocationField.tsx +2 -2
- package/src/widgets/LookupField.tsx +10 -10
- package/src/widgets/MasterDetailField.tsx +2 -2
- package/src/widgets/MultiSelectField.tsx +4 -4
- package/src/widgets/NumberField.tsx +2 -2
- package/src/widgets/ObjectField.tsx +2 -2
- package/src/widgets/ObjectRefField.tsx +4 -4
- package/src/widgets/PasswordField.tsx +2 -2
- package/src/widgets/PercentField.tsx +2 -2
- package/src/widgets/PhoneField.tsx +2 -2
- package/src/widgets/QRCodeField.tsx +2 -2
- package/src/widgets/RadioField.tsx +4 -4
- package/src/widgets/RatingField.tsx +2 -2
- package/src/widgets/RecipientPickerField.tsx +4 -4
- package/src/widgets/RichTextField.tsx +2 -2
- package/src/widgets/SelectField.tsx +5 -5
- package/src/widgets/SignatureField.tsx +2 -2
- package/src/widgets/SliderField.tsx +2 -2
- package/src/widgets/SummaryField.tsx +2 -2
- package/src/widgets/TagsField.tsx +3 -3
- package/src/widgets/TextAreaField.tsx +2 -2
- package/src/widgets/TextField.tsx +2 -2
- package/src/widgets/TimeField.tsx +2 -2
- package/src/widgets/UrlField.tsx +2 -2
- package/src/widgets/UserField.tsx +2 -2
- package/src/widgets/VectorField.tsx +2 -2
- package/src/widgets/file-value.ts +21 -5
- package/src/widgets/types.ts +129 -6
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Slider } from '@object-ui/components';
|
|
3
|
-
import {
|
|
3
|
+
import { FieldWidgetComponentProps } from './types';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Slider field widget - provides a range slider input
|
|
7
7
|
* Supports numeric values with configurable min, max, and step
|
|
8
8
|
*/
|
|
9
|
-
export function SliderField({ value, onChange, field, readonly, ...props }:
|
|
9
|
+
export function SliderField({ value, onChange, field, readonly, ...props }: FieldWidgetComponentProps<number>) {
|
|
10
10
|
// Get slider-specific configuration from field metadata
|
|
11
11
|
const sliderField = (field || (props as any).schema) as any;
|
|
12
12
|
const min = sliderField?.min ?? 0;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { EmptyValue } from '@object-ui/components';
|
|
3
|
-
import {
|
|
3
|
+
import { FieldWidgetComponentProps } from './types';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* SummaryField - Read-only aggregation field
|
|
7
7
|
* Values are aggregated from related records and cannot be edited
|
|
8
8
|
*/
|
|
9
|
-
export function SummaryField({ value, field, ...props }:
|
|
9
|
+
export function SummaryField({ value, field, ...props }: FieldWidgetComponentProps<any>) {
|
|
10
10
|
const summaryField = (field || (props as any).schema) as any;
|
|
11
11
|
const summaryType = summaryField?.summary_type || 'count';
|
|
12
12
|
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Badge, Input, EmptyValue, cn } from '@object-ui/components';
|
|
3
|
-
import {
|
|
3
|
+
import { FieldWidgetComponentProps } from './types';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* TagsField - free-form list of string tags. Type a value and press Enter (or
|
|
7
7
|
* comma) to add it; click a tag's × to remove it. The stored value is a
|
|
8
8
|
* string[]. Used for the `tags` field type.
|
|
9
9
|
*/
|
|
10
|
-
export function TagsField({ value, onChange, field, readonly, className, ...props }:
|
|
10
|
+
export function TagsField({ value, onChange, field, readonly, className, ...props }: FieldWidgetComponentProps<string[]>) {
|
|
11
11
|
const tags: string[] = Array.isArray(value) ? value : value == null ? [] : [value as unknown as string];
|
|
12
12
|
const [draft, setDraft] = React.useState('');
|
|
13
13
|
|
|
@@ -58,7 +58,7 @@ export function TagsField({ value, onChange, field, readonly, className, ...prop
|
|
|
58
58
|
onChange={(e) => setDraft(e.target.value)}
|
|
59
59
|
onKeyDown={onKeyDown}
|
|
60
60
|
onBlur={() => addTag(draft)}
|
|
61
|
-
disabled={
|
|
61
|
+
disabled={props.disabled}
|
|
62
62
|
placeholder={tags.length === 0 ? '输入后回车添加…' : ''}
|
|
63
63
|
className="h-7 flex-1 border-0 bg-transparent p-0 px-1 shadow-none focus-visible:ring-0 min-w-[8ch]"
|
|
64
64
|
/>
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
Button,
|
|
11
11
|
} from '@object-ui/components';
|
|
12
12
|
import { Maximize2, Check, X } from 'lucide-react';
|
|
13
|
-
import {
|
|
13
|
+
import { FieldWidgetComponentProps } from './types';
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* TextAreaField - Multi-line text input widget
|
|
@@ -21,7 +21,7 @@ import { FieldWidgetProps } from './types';
|
|
|
21
21
|
* a fullscreen edit dialog — much easier on phones than tapping a 4-row
|
|
22
22
|
* textarea trapped between other fields.
|
|
23
23
|
*/
|
|
24
|
-
export function TextAreaField({ value, onChange, field, readonly, errorMessage, ...props }:
|
|
24
|
+
export function TextAreaField({ value, onChange, field, readonly, errorMessage, ...props }: FieldWidgetComponentProps<string>) {
|
|
25
25
|
// Hooks must run before any early return (readonly) to keep hook order stable.
|
|
26
26
|
const [fullscreenOpen, setFullscreenOpen] = useState(false);
|
|
27
27
|
const [draft, setDraft] = useState(value ?? '');
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Input, Textarea, EmptyValue } from '@object-ui/components';
|
|
3
3
|
import { TextareaFieldMetadata } from '@object-ui/types';
|
|
4
|
-
import {
|
|
4
|
+
import { FieldWidgetComponentProps } from './types';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* TextField - Standard single-line or multi-line text input
|
|
8
8
|
* Automatically renders as a textarea when rows are configured in field metadata
|
|
9
9
|
*/
|
|
10
|
-
export function TextField({ value, onChange, field, readonly, ...props }:
|
|
10
|
+
export function TextField({ value, onChange, field, readonly, ...props }: FieldWidgetComponentProps<string>) {
|
|
11
11
|
const fieldData = field || (props as any).schema;
|
|
12
12
|
|
|
13
13
|
if (readonly) {
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Input, EmptyValue } from '@object-ui/components';
|
|
3
|
-
import {
|
|
3
|
+
import { FieldWidgetComponentProps } from './types';
|
|
4
4
|
import { openNativePicker } from './openNativePicker';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* TimeField - Time picker input widget
|
|
8
8
|
* Uses native time input for hour and minute selection
|
|
9
9
|
*/
|
|
10
|
-
export function TimeField({ value, onChange, field, readonly, ...props }:
|
|
10
|
+
export function TimeField({ value, onChange, field, readonly, ...props }: FieldWidgetComponentProps<string>) {
|
|
11
11
|
if (readonly) {
|
|
12
12
|
return <span className="text-sm">{value || <EmptyValue />}</span>;
|
|
13
13
|
}
|
package/src/widgets/UrlField.tsx
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Input, EmptyValue } from '@object-ui/components';
|
|
3
|
-
import {
|
|
3
|
+
import { FieldWidgetComponentProps } from './types';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* UrlField - URL input with clickable link in readonly mode
|
|
7
7
|
* Validates URLs to only render http/https links for security
|
|
8
8
|
*/
|
|
9
|
-
export function UrlField({ value, onChange, field, readonly, errorMessage, ...props }:
|
|
9
|
+
export function UrlField({ value, onChange, field, readonly, errorMessage, ...props }: FieldWidgetComponentProps<string>) {
|
|
10
10
|
const config = field || (props as any).schema;
|
|
11
11
|
if (readonly) {
|
|
12
12
|
if (!value) return <EmptyValue />;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { FieldWidgetComponentProps } from './types';
|
|
3
3
|
import { LookupField } from './LookupField';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -29,7 +29,7 @@ function withBannedFilter(filters?: any[]): any[] {
|
|
|
29
29
|
: [...base, { field: 'banned', operator: 'ne', value: true }];
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
export function UserField(props:
|
|
32
|
+
export function UserField(props: FieldWidgetComponentProps<any>) {
|
|
33
33
|
const raw = (props.field || (props as any).schema) as any;
|
|
34
34
|
|
|
35
35
|
// The objectSchema field metadata may live directly on `field`, or nested at
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { EmptyValue } from '@object-ui/components';
|
|
3
|
-
import {
|
|
3
|
+
import { FieldWidgetComponentProps } from './types';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* VectorField - Vector/embedding data display
|
|
7
7
|
* Shows vector embeddings in a read-only format
|
|
8
8
|
*/
|
|
9
|
-
export function VectorField({ value, field, ...props }:
|
|
9
|
+
export function VectorField({ value, field, ...props }: FieldWidgetComponentProps<number[]>) {
|
|
10
10
|
const vectorField = (field || (props as any).schema) as any;
|
|
11
11
|
const dimensions = vectorField?.dimensions || (Array.isArray(value) ? value.length : 0);
|
|
12
12
|
|
|
@@ -29,6 +29,8 @@
|
|
|
29
29
|
* onto the same contract.
|
|
30
30
|
*/
|
|
31
31
|
|
|
32
|
+
import { isFileIdToken } from '@objectstack/spec/data';
|
|
33
|
+
|
|
32
34
|
/** A file value normalised for rendering, whatever form it arrived in. */
|
|
33
35
|
export interface FileValueView {
|
|
34
36
|
/** `sys_file` id, when the value carries one. */
|
|
@@ -45,12 +47,26 @@ export interface FileValueView {
|
|
|
45
47
|
|
|
46
48
|
/**
|
|
47
49
|
* A minted file id: uuid/nanoid-shaped, and crucially not a URL — a URL always
|
|
48
|
-
* carries `:`, `/` or `.`, so it can never match.
|
|
49
|
-
*
|
|
50
|
+
* carries `:`, `/` or `.`, so it can never match.
|
|
51
|
+
*
|
|
52
|
+
* This IS the platform's arbiter now, not a mirror of it (objectui#3161,
|
|
53
|
+
* objectstack#4115 ledger batch 7). The declaration that stood here said it
|
|
54
|
+
* "mirrors the platform's `isFileIdToken`" while being a character-for-character
|
|
55
|
+
* copy of that function's body under that function's own name — the shape
|
|
56
|
+
* objectui#3003 argued about and objectui#3169 caught again in
|
|
57
|
+
* `isAggregatedViewContainer`: every value test and every behaviour test passes
|
|
58
|
+
* against a faithful copy, so reference identity is the only check that can tell
|
|
59
|
+
* a re-export from a fork. It is asserted in
|
|
60
|
+
* `__tests__/spec-symbol-batch7.test.ts`.
|
|
61
|
+
*
|
|
62
|
+
* Why it matters that this one is shared rather than duplicated: the regex is a
|
|
63
|
+
* WIRE decision. Widening it server-side (say, ids grow past 64 chars) while a
|
|
64
|
+
* copy here keeps the old bound turns every new id into "not a reference", and
|
|
65
|
+
* the widget then submits the legacy inline blob against a backend that expects
|
|
66
|
+
* a reference. That failure surfaces as a broken thumbnail, nowhere near a
|
|
67
|
+
* regex.
|
|
50
68
|
*/
|
|
51
|
-
export
|
|
52
|
-
return typeof value === 'string' && /^[A-Za-z0-9_-]{1,64}$/.test(value);
|
|
53
|
-
}
|
|
69
|
+
export { isFileIdToken };
|
|
54
70
|
|
|
55
71
|
/**
|
|
56
72
|
* The `sys_file` id a value refers to, or `undefined`.
|
package/src/widgets/types.ts
CHANGED
|
@@ -1,10 +1,57 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { AriaAttributes, FocusEventHandler, MouseEventHandler } from 'react';
|
|
2
|
+
import type { DependsOnInput, FieldMetadata } from '@object-ui/types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Props every field widget in this package receives at RUNTIME.
|
|
6
|
+
*
|
|
7
|
+
* Named `FieldWidgetComponentProps`, not `FieldWidgetProps` (objectui#3161,
|
|
8
|
+
* objectstack#4115 ledger batch 7), adopting the name `@object-ui/app-shell`
|
|
9
|
+
* settled on for the same split in objectui#3169: `@objectstack/spec/ui` owns
|
|
10
|
+
* `FieldWidgetProps` for the DECLARED widget-plugin contract — a zod object
|
|
11
|
+
* (`FieldWidgetPropsSchema`) a plugin manifest is validated against, with
|
|
12
|
+
* `field` narrowed to `{ name?, label?, type: <the FieldType enum> }` and
|
|
13
|
+
* `readonly` / `required` carrying `.default()`s. This is the React interface
|
|
14
|
+
* the widgets in this directory actually implement, against
|
|
15
|
+
* `@object-ui/types`'s much richer `FieldMetadata`.
|
|
16
|
+
*
|
|
17
|
+
* The two are NOT interchangeable, and the divergence is not cosmetic: the
|
|
18
|
+
* spec's contract names the error slot `error`, this one names it
|
|
19
|
+
* `errorMessage`, so a widget written to the spec's declared props renders no
|
|
20
|
+
* validation message here. That divergence is tracked in objectui#3222 and is
|
|
21
|
+
* deliberately NOT resolved here — but it is now *visible*: reading
|
|
22
|
+
* `props.error` or `props.required` off this type is a compile error rather
|
|
23
|
+
* than a silent `any`.
|
|
24
|
+
*
|
|
25
|
+
* ## Why there is no `[key: string]: any` (objectui#3221)
|
|
26
|
+
*
|
|
27
|
+
* This type used to end in an index signature, "load-bearing" for the widgets'
|
|
28
|
+
* `...props` spreads. It was also why every drift above was invisible: **a type
|
|
29
|
+
* that claims to have every key can never be reported as missing one** (the
|
|
30
|
+
* objectstack#4075 mechanism). `props.required` and `props.error` were legal
|
|
31
|
+
* reads typed `any` and always `undefined` at runtime; a misspelled prop
|
|
32
|
+
* (`readOnly` for `readonly`, `onchange` for `onChange`) compiled; and any
|
|
33
|
+
* structural/parity comparison against the type was useless *in principle*,
|
|
34
|
+
* which is why the batch-7 symbol guard was the only detector that could see
|
|
35
|
+
* the collision at all.
|
|
36
|
+
*
|
|
37
|
+
* It is replaced by the CLOSED set below: the controlled-input contract, the
|
|
38
|
+
* host plumbing the form renderer genuinely forwards, and a DOM pass-through
|
|
39
|
+
* allowance. `data-*` is an open family by design (it is open in HTML too) and
|
|
40
|
+
* is expressed as a template-literal index signature, which — unlike
|
|
41
|
+
* `[key: string]` — leaves `keyof` finite, so an undeclared prop still fails.
|
|
42
|
+
*
|
|
43
|
+
* Adding a key here is a contract change: say who produces it and who reads it.
|
|
44
|
+
*/
|
|
45
|
+
export type FieldWidgetComponentProps<T = any> = {
|
|
46
|
+
/* ── The controlled-input contract every widget implements ─────────────── */
|
|
2
47
|
|
|
3
|
-
export type FieldWidgetProps<T = any> = {
|
|
4
48
|
value: T;
|
|
5
49
|
onChange: (val: T) => void;
|
|
6
|
-
|
|
7
|
-
|
|
50
|
+
/**
|
|
51
|
+
* The field's metadata. Deliberately the looser `@object-ui/types` shape
|
|
52
|
+
* rather than the spec's, to avoid a circular dependency for now.
|
|
53
|
+
*/
|
|
54
|
+
field: FieldMetadata;
|
|
8
55
|
readonly?: boolean;
|
|
9
56
|
disabled?: boolean;
|
|
10
57
|
className?: string;
|
|
@@ -15,5 +62,81 @@ export type FieldWidgetProps<T = any> = {
|
|
|
15
62
|
* widgets ignore it.
|
|
16
63
|
*/
|
|
17
64
|
onUploadingChange?: (uploading: boolean) => void;
|
|
18
|
-
|
|
19
|
-
|
|
65
|
+
|
|
66
|
+
/* ── Host plumbing: what a rendering host actually forwards ─────────────── */
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* The raw authored node the widget was rendered from. Two hosts supply it:
|
|
70
|
+
* `SchemaRenderer` (`<Component schema={schema} {...schema} />`) and the
|
|
71
|
+
* form renderer's `renderFieldComponent` (`schema={props.field || ...}`),
|
|
72
|
+
* which is why ~25 widgets read `field || schema` for their config.
|
|
73
|
+
*
|
|
74
|
+
* This is a second carrier for what `field` already means, i.e. a de-facto
|
|
75
|
+
* second contract (AGENTS.md #0.1) — declared here so it is at least
|
|
76
|
+
* visible; converging the two is tracked separately.
|
|
77
|
+
*/
|
|
78
|
+
schema?: FieldMetadata | Record<string, unknown>;
|
|
79
|
+
/**
|
|
80
|
+
* DataSource for widgets that query records (lookup / user / object-ref /
|
|
81
|
+
* recipient-picker / grid). Injected by the form renderer for the field
|
|
82
|
+
* types that need it, and passed directly by inline-edit hosts. Option
|
|
83
|
+
* widgets destructure it purely to keep it off their DOM spread.
|
|
84
|
+
*
|
|
85
|
+
* Left structural (`unknown`): `@object-ui/fields` must not depend on a
|
|
86
|
+
* concrete adapter — every consumer narrows it itself.
|
|
87
|
+
*/
|
|
88
|
+
dataSource?: unknown;
|
|
89
|
+
/**
|
|
90
|
+
* Live sibling-field values driving cascading / role-gated options and
|
|
91
|
+
* dependent lookups (ADR-0058, #2215/#2284). The form renderer passes the
|
|
92
|
+
* in-progress record; widgets fall back to `SchemaRendererContext`.
|
|
93
|
+
*/
|
|
94
|
+
dependentValues?: Record<string, unknown>;
|
|
95
|
+
/**
|
|
96
|
+
* Controlling field(s) that gate this field's option list. Normally declared
|
|
97
|
+
* on the field metadata; accepted as a prop so a host can drive the gate for
|
|
98
|
+
* a field it synthesised. Field metadata wins when both are present.
|
|
99
|
+
*/
|
|
100
|
+
dependsOn?: DependsOnInput;
|
|
101
|
+
/**
|
|
102
|
+
* Hint shown when a dependency-gated option list is still waiting on its
|
|
103
|
+
* controlling field. Forwarded by the form renderer; the option widgets in
|
|
104
|
+
* this package currently discard it and render their own message instead.
|
|
105
|
+
*/
|
|
106
|
+
emptyHint?: string;
|
|
107
|
+
/**
|
|
108
|
+
* Render as a single-line, borderless control for a grid cell (the inline
|
|
109
|
+
* editor and the line-item grid set it) instead of the full form layout.
|
|
110
|
+
*/
|
|
111
|
+
compact?: boolean;
|
|
112
|
+
/**
|
|
113
|
+
* Receive the FULL selected record rather than just its id, so a host can
|
|
114
|
+
* auto-fill sibling fields from it (a line-item grid copying a product's
|
|
115
|
+
* price). When provided, the host owns the resulting value change.
|
|
116
|
+
*/
|
|
117
|
+
onSelectRecord?: (record: Record<string, any>) => void;
|
|
118
|
+
/**
|
|
119
|
+
* Offer a "create new" affordance in a record picker, carrying whatever the
|
|
120
|
+
* user had typed. Also declarable on the field metadata.
|
|
121
|
+
*/
|
|
122
|
+
onCreateNew?: (searchQuery: string) => void;
|
|
123
|
+
|
|
124
|
+
/* ── DOM pass-through: what `...props` may legitimately reach an input ──── */
|
|
125
|
+
|
|
126
|
+
id?: string;
|
|
127
|
+
/** react-hook-form's field name, spread in by the form renderer. */
|
|
128
|
+
name?: string;
|
|
129
|
+
autoFocus?: boolean;
|
|
130
|
+
tabIndex?: number;
|
|
131
|
+
onBlur?: FocusEventHandler<HTMLElement>;
|
|
132
|
+
onFocus?: FocusEventHandler<HTMLElement>;
|
|
133
|
+
onClick?: MouseEventHandler<HTMLElement>;
|
|
134
|
+
} & AriaAttributes & {
|
|
135
|
+
/**
|
|
136
|
+
* Arbitrary `data-*` attributes (test ids, analytics hooks). Open by design,
|
|
137
|
+
* but a template-literal key — `keyof` stays finite, so this does NOT
|
|
138
|
+
* reintroduce the index signature objectui#3221 removed: `props.required`
|
|
139
|
+
* is still an error, `props['data-testid']` is still fine.
|
|
140
|
+
*/
|
|
141
|
+
[dataAttribute: `data-${string}`]: string | number | boolean | undefined;
|
|
142
|
+
};
|