@object-ui/fields 17.3.0 → 17.6.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 +1655 -0
- package/README.md +1 -12
- package/dist/FieldEditWidget.d.ts +23 -3
- package/dist/currency.d.ts +46 -0
- package/dist/field-type-alias.d.ts +35 -1
- package/dist/index.cjs +4 -4
- package/dist/index.css +651 -0
- package/dist/index.d.ts +474 -85
- package/dist/index.js +5418 -5023
- package/dist/widgets/AddressField.d.ts +4 -12
- package/dist/widgets/AutoNumberField.d.ts +1 -1
- package/dist/widgets/AvatarField.d.ts +1 -1
- package/dist/widgets/BooleanField.d.ts +1 -1
- package/dist/widgets/CapabilityMultiSelectField.d.ts +1 -1
- package/dist/widgets/CheckboxesField.d.ts +1 -1
- package/dist/widgets/CodeField.d.ts +1 -1
- package/dist/widgets/ColorField.d.ts +1 -1
- package/dist/widgets/CurrencyField.d.ts +1 -1
- package/dist/widgets/DateField.d.ts +1 -1
- package/dist/widgets/DateTimeField.d.ts +1 -1
- package/dist/widgets/EmailField.d.ts +1 -1
- package/dist/widgets/FileField.d.ts +18 -2
- package/dist/widgets/FilterConditionField.d.ts +28 -1
- package/dist/widgets/FormulaField.d.ts +1 -1
- package/dist/widgets/FullscreenFieldEditor.d.ts +49 -152
- package/dist/widgets/GeolocationField.d.ts +1 -1
- package/dist/widgets/GridField.d.ts +68 -6
- package/dist/widgets/ImageField.d.ts +1 -1
- package/dist/widgets/LocationField.d.ts +1 -1
- package/dist/widgets/LookupField.d.ts +1 -1
- package/dist/widgets/MasterDetailField.d.ts +1 -1
- package/dist/widgets/MultiSelectField.d.ts +1 -1
- package/dist/widgets/NumberField.d.ts +1 -1
- package/dist/widgets/ObjectField.d.ts +1 -1
- package/dist/widgets/ObjectRefField.d.ts +1 -1
- package/dist/widgets/OptionsEmptyState.d.ts +21 -1
- package/dist/widgets/PasswordField.d.ts +1 -1
- package/dist/widgets/PercentField.d.ts +1 -1
- package/dist/widgets/PhoneField.d.ts +1 -1
- package/dist/widgets/QRCodeField.d.ts +1 -1
- package/dist/widgets/RadioField.d.ts +1 -1
- package/dist/widgets/RatingField.d.ts +1 -1
- package/dist/widgets/RecipientPickerField.d.ts +1 -1
- package/dist/widgets/RecordPickerDialog.d.ts +34 -10
- package/dist/widgets/RichTextField.d.ts +37 -1
- package/dist/widgets/SelectField.d.ts +26 -6
- package/dist/widgets/SignatureField.d.ts +32 -2
- package/dist/widgets/SliderField.d.ts +37 -2
- package/dist/widgets/SummaryField.d.ts +1 -1
- package/dist/widgets/TagsField.d.ts +1 -1
- package/dist/widgets/TextAreaField.d.ts +6 -2
- package/dist/widgets/TextField.d.ts +1 -1
- package/dist/widgets/TimeField.d.ts +1 -1
- package/dist/widgets/UrlField.d.ts +1 -1
- package/dist/widgets/UserField.d.ts +1 -1
- package/dist/widgets/VectorField.d.ts +1 -1
- package/dist/widgets/_cell-renderer-bridge.d.ts +1 -1
- package/dist/widgets/address-format.d.ts +88 -0
- package/dist/widgets/file-size-guard.d.ts +41 -0
- package/dist/widgets/lookupColumnDisplay.d.ts +93 -0
- package/dist/widgets/nativeDateValue.d.ts +37 -0
- package/dist/widgets/richTextDisplay.d.ts +80 -0
- package/dist/widgets/toDomProps.d.ts +30 -10
- package/dist/widgets/toHostGroupProps.d.ts +189 -0
- package/dist/widgets/types.d.ts +8 -3
- package/dist/widgets/useRecordQuery.d.ts +7 -1
- package/package.json +17 -14
- package/dist/FieldEditWidget.test.d.ts +0 -8
- package/dist/__tests__/DateCellRenderer.test.d.ts +0 -0
- package/dist/__tests__/NumberCellRenderer.test.d.ts +0 -0
- package/dist/__tests__/cell-truncation.test.d.ts +0 -0
- package/dist/__tests__/field-carrier-sdui.test.d.ts +0 -0
- package/dist/__tests__/lookupCellDisplayField.test.d.ts +0 -0
- package/dist/__tests__/lookupCellDisplayName.test.d.ts +0 -0
- package/dist/__tests__/lookupCellReferenceKey.test.d.ts +0 -0
- package/dist/__tests__/registry-collision.test.d.ts +0 -0
- package/dist/__tests__/resolveFieldCurrency.test.d.ts +0 -1
- package/dist/__tests__/spec-symbol-batch7.test.d.ts +0 -8
- package/dist/__tests__/validation-feedback.test.d.ts +0 -0
- package/dist/__tests__/widget-aria-invalid-e2e.test.d.ts +0 -0
- package/dist/__tests__/widget-aria-invalid-registry-e2e.test.d.ts +0 -0
- package/dist/__tests__/widget-dom-leak-e2e.test.d.ts +0 -0
- package/dist/__tests__/widget-props-contract.test.d.ts +0 -8
- package/dist/coerce-safe-value.test.d.ts +0 -1
- package/dist/complex-widgets.test.d.ts +0 -1
- package/dist/datetime-widgets.test.d.ts +0 -1
- package/dist/field-type-coverage.test.d.ts +0 -1
- package/dist/standard-widgets.test.d.ts +0 -0
- package/dist/widgets/AddressField.uniqueIds.test.d.ts +0 -0
- package/dist/widgets/CapabilityMultiSelectField.test.d.ts +0 -0
- package/dist/widgets/CharacterCount.d.ts +0 -56
- package/dist/widgets/CheckboxesField.cascade.test.d.ts +0 -0
- package/dist/widgets/GeolocationField.uniqueIds.test.d.ts +0 -0
- package/dist/widgets/GridField.test.d.ts +0 -1
- package/dist/widgets/ImageLightbox.test.d.ts +0 -1
- package/dist/widgets/LookupField.dependsOn.test.d.ts +0 -8
- package/dist/widgets/LookupField.gateHintLabel.test.d.ts +0 -8
- package/dist/widgets/LookupField.hydration.test.d.ts +0 -1
- package/dist/widgets/LookupField.idField.test.d.ts +0 -1
- package/dist/widgets/MultiSelectField.cascade.test.d.ts +0 -0
- package/dist/widgets/OptionsEmptyState.no-provider.test.d.ts +0 -0
- package/dist/widgets/OptionsEmptyState.test.d.ts +0 -0
- package/dist/widgets/PeoplePicker.test.d.ts +0 -8
- package/dist/widgets/PeoplePickerComponents.test.d.ts +0 -8
- package/dist/widgets/RadioField.cascade.test.d.ts +0 -0
- package/dist/widgets/RecipientPickerField.test.d.ts +0 -0
- package/dist/widgets/RecordPickerDialog.filterOptions.test.d.ts +0 -8
- package/dist/widgets/RecordPickerDialog.selectLabel.test.d.ts +0 -8
- package/dist/widgets/SelectField.cascade.test.d.ts +0 -0
- package/dist/widgets/TagsField.placeholder.no-provider.test.d.ts +0 -0
- package/dist/widgets/TagsField.placeholder.test.d.ts +0 -0
- package/dist/widgets/UserFieldPicker.test.d.ts +0 -8
- package/dist/widgets/__tests__/FilterConditionField.matchAll.test.d.ts +0 -8
- package/dist/widgets/__tests__/FilterConditionField.operators.test.d.ts +0 -8
- package/dist/widgets/__tests__/FullscreenFieldEditor.i18n.test.d.ts +0 -0
- package/dist/widgets/__tests__/FullscreenFieldEditor.no-provider.test.d.ts +0 -0
- package/dist/widgets/__tests__/RichTextField.fullscreenDisabled.test.d.ts +0 -0
- package/dist/widgets/__tests__/RichTextField.mobileFullscreen.test.d.ts +0 -0
- package/dist/widgets/__tests__/TextAreaField.characterCount.announcements.test.d.ts +0 -0
- package/dist/widgets/__tests__/TextAreaField.characterCount.i18n.test.d.ts +0 -0
- package/dist/widgets/__tests__/TextAreaField.characterCount.no-provider.test.d.ts +0 -0
- package/dist/widgets/__tests__/TextAreaField.fullscreenCharacterCount.i18n.test.d.ts +0 -0
- package/dist/widgets/__tests__/TextAreaField.fullscreenCharacterCount.test.d.ts +0 -0
- package/dist/widgets/__tests__/TextAreaField.fullscreenDisabled.test.d.ts +0 -0
- package/dist/widgets/__tests__/TextAreaField.mobileFullscreen.test.d.ts +0 -0
- package/dist/widgets/deriveLookupColumns.test.d.ts +0 -1
- package/dist/widgets/file-value.test.d.ts +0 -1
- package/dist/widgets/personDisplay.test.d.ts +0 -8
- package/dist/widgets/recentLookups.test.d.ts +0 -1
- package/dist/widgets/useRecordQuery.test.d.ts +0 -8
- package/dist/widgets/useUploadingSignal.test.d.ts +0 -1
- package/src/FieldEditWidget.test.ts +0 -133
- package/src/FieldEditWidget.tsx +0 -191
- package/src/__tests__/DateCellRenderer.test.tsx +0 -73
- package/src/__tests__/NumberCellRenderer.test.tsx +0 -60
- package/src/__tests__/cell-truncation.test.tsx +0 -96
- package/src/__tests__/field-carrier-sdui.test.tsx +0 -169
- package/src/__tests__/lookupCellDisplayField.test.tsx +0 -107
- package/src/__tests__/lookupCellDisplayName.test.tsx +0 -119
- package/src/__tests__/lookupCellReferenceKey.test.tsx +0 -57
- package/src/__tests__/registry-collision.test.ts +0 -91
- package/src/__tests__/resolveFieldCurrency.test.ts +0 -20
- package/src/__tests__/spec-symbol-batch7.test.ts +0 -126
- package/src/__tests__/validation-feedback.test.tsx +0 -361
- package/src/__tests__/widget-aria-invalid-e2e.test.tsx +0 -265
- package/src/__tests__/widget-aria-invalid-registry-e2e.test.tsx +0 -338
- package/src/__tests__/widget-dom-leak-e2e.test.tsx +0 -598
- package/src/__tests__/widget-props-contract.test.tsx +0 -142
- package/src/coerce-safe-value.test.ts +0 -34
- package/src/complex-widgets.test.tsx +0 -908
- package/src/currency.ts +0 -14
- package/src/datetime-widgets.test.tsx +0 -93
- package/src/field-type-alias.ts +0 -100
- package/src/field-type-coverage.test.ts +0 -67
- package/src/index.tsx +0 -2503
- package/src/standard-widgets.test.tsx +0 -357
- package/src/widgets/AddressField.tsx +0 -132
- package/src/widgets/AddressField.uniqueIds.test.tsx +0 -92
- package/src/widgets/AutoNumberField.tsx +0 -18
- package/src/widgets/AvatarField.tsx +0 -117
- package/src/widgets/BooleanField.tsx +0 -52
- package/src/widgets/CapabilityMultiSelectField.test.tsx +0 -168
- package/src/widgets/CapabilityMultiSelectField.tsx +0 -229
- package/src/widgets/CharacterCount.tsx +0 -263
- package/src/widgets/CheckboxesField.cascade.test.tsx +0 -143
- package/src/widgets/CheckboxesField.tsx +0 -136
- package/src/widgets/CodeField.tsx +0 -41
- package/src/widgets/ColorField.tsx +0 -53
- package/src/widgets/CurrencyField.tsx +0 -95
- package/src/widgets/DateField.tsx +0 -31
- package/src/widgets/DateTimeField.tsx +0 -37
- package/src/widgets/EmailField.tsx +0 -37
- package/src/widgets/FileField.tsx +0 -494
- package/src/widgets/FilterConditionField.tsx +0 -454
- package/src/widgets/FormulaField.tsx +0 -33
- package/src/widgets/FullscreenFieldEditor.tsx +0 -271
- package/src/widgets/GeolocationField.tsx +0 -167
- package/src/widgets/GeolocationField.uniqueIds.test.tsx +0 -88
- package/src/widgets/GridField.test.tsx +0 -406
- package/src/widgets/GridField.tsx +0 -966
- package/src/widgets/ImageCropperDialog.tsx +0 -245
- package/src/widgets/ImageField.tsx +0 -255
- package/src/widgets/ImageLightbox.test.tsx +0 -52
- package/src/widgets/ImageLightbox.tsx +0 -108
- package/src/widgets/LocationField.tsx +0 -57
- package/src/widgets/LookupField.dependsOn.test.tsx +0 -233
- package/src/widgets/LookupField.gateHintLabel.test.tsx +0 -135
- package/src/widgets/LookupField.hydration.test.tsx +0 -136
- package/src/widgets/LookupField.idField.test.tsx +0 -61
- package/src/widgets/LookupField.tsx +0 -1291
- package/src/widgets/MarkdownContent.tsx +0 -19
- package/src/widgets/MasterDetailField.tsx +0 -131
- package/src/widgets/MultiSelectField.cascade.test.tsx +0 -143
- package/src/widgets/MultiSelectField.tsx +0 -142
- package/src/widgets/NumberField.tsx +0 -49
- package/src/widgets/ObjectField.tsx +0 -94
- package/src/widgets/ObjectRefField.tsx +0 -121
- package/src/widgets/OptionsEmptyState.no-provider.test.tsx +0 -88
- package/src/widgets/OptionsEmptyState.test.tsx +0 -169
- package/src/widgets/OptionsEmptyState.tsx +0 -83
- package/src/widgets/PasswordField.tsx +0 -49
- package/src/widgets/PeoplePicker.test.tsx +0 -360
- package/src/widgets/PeoplePicker.tsx +0 -579
- package/src/widgets/PeoplePickerComponents.test.tsx +0 -104
- package/src/widgets/PercentField.tsx +0 -95
- package/src/widgets/PersonRow.tsx +0 -117
- package/src/widgets/PhoneField.tsx +0 -37
- package/src/widgets/QRCodeField.tsx +0 -103
- package/src/widgets/RadioField.cascade.test.tsx +0 -141
- package/src/widgets/RadioField.tsx +0 -111
- package/src/widgets/RatingField.tsx +0 -81
- package/src/widgets/RecipientPickerField.test.tsx +0 -157
- package/src/widgets/RecipientPickerField.tsx +0 -188
- package/src/widgets/RecordPickerDialog.filterOptions.test.tsx +0 -611
- package/src/widgets/RecordPickerDialog.selectLabel.test.tsx +0 -112
- package/src/widgets/RecordPickerDialog.tsx +0 -1316
- package/src/widgets/RichTextField.tsx +0 -176
- package/src/widgets/SelectField.cascade.test.tsx +0 -138
- package/src/widgets/SelectField.tsx +0 -162
- package/src/widgets/SelectionTray.tsx +0 -110
- package/src/widgets/SignatureField.tsx +0 -140
- package/src/widgets/SliderField.tsx +0 -39
- package/src/widgets/SummaryField.tsx +0 -31
- package/src/widgets/TagsField.placeholder.no-provider.test.tsx +0 -68
- package/src/widgets/TagsField.placeholder.test.tsx +0 -95
- package/src/widgets/TagsField.tsx +0 -88
- package/src/widgets/TextAreaField.tsx +0 -213
- package/src/widgets/TextField.tsx +0 -45
- package/src/widgets/TimeField.tsx +0 -31
- package/src/widgets/UrlField.tsx +0 -46
- package/src/widgets/UserField.tsx +0 -58
- package/src/widgets/UserFieldPicker.test.tsx +0 -78
- package/src/widgets/VectorField.tsx +0 -29
- package/src/widgets/__tests__/FilterConditionField.matchAll.test.ts +0 -66
- package/src/widgets/__tests__/FilterConditionField.operators.test.ts +0 -142
- package/src/widgets/__tests__/FullscreenFieldEditor.i18n.test.tsx +0 -248
- package/src/widgets/__tests__/FullscreenFieldEditor.no-provider.test.tsx +0 -116
- package/src/widgets/__tests__/RichTextField.fullscreenDisabled.test.tsx +0 -244
- package/src/widgets/__tests__/RichTextField.mobileFullscreen.test.tsx +0 -195
- package/src/widgets/__tests__/TextAreaField.characterCount.announcements.test.tsx +0 -417
- package/src/widgets/__tests__/TextAreaField.characterCount.i18n.test.tsx +0 -287
- package/src/widgets/__tests__/TextAreaField.characterCount.no-provider.test.tsx +0 -160
- package/src/widgets/__tests__/TextAreaField.fullscreenCharacterCount.i18n.test.tsx +0 -161
- package/src/widgets/__tests__/TextAreaField.fullscreenCharacterCount.test.tsx +0 -346
- package/src/widgets/__tests__/TextAreaField.fullscreenDisabled.test.tsx +0 -246
- package/src/widgets/__tests__/TextAreaField.mobileFullscreen.test.tsx +0 -175
- package/src/widgets/_cell-renderer-bridge.ts +0 -19
- package/src/widgets/deriveLookupColumns.test.ts +0 -112
- package/src/widgets/deriveLookupColumns.ts +0 -108
- package/src/widgets/file-value.test.ts +0 -230
- package/src/widgets/file-value.ts +0 -246
- package/src/widgets/openNativePicker.ts +0 -18
- package/src/widgets/personDisplay.test.ts +0 -113
- package/src/widgets/personDisplay.ts +0 -92
- package/src/widgets/recentLookups.test.ts +0 -45
- package/src/widgets/recentLookups.ts +0 -47
- package/src/widgets/toDomProps.ts +0 -175
- package/src/widgets/types.ts +0 -242
- package/src/widgets/useCascadingOptions.ts +0 -46
- package/src/widgets/useFieldTranslation.ts +0 -150
- package/src/widgets/useRecordQuery.test.ts +0 -174
- package/src/widgets/useRecordQuery.ts +0 -264
- package/src/widgets/useUploadingSignal.test.tsx +0 -62
- package/src/widgets/useUploadingSignal.ts +0 -20
- package/src/withFieldCarrier.tsx +0 -75
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
import { FieldWidgetComponentProps } from './types';
|
|
2
|
+
import { FieldWidgetComponentProps } from './types.js';
|
|
3
3
|
/**
|
|
4
4
|
* PercentField - Percentage input with configurable decimal precision
|
|
5
5
|
* Stores values as decimals (0-1) and displays as percentages (0-100%)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
import { FieldWidgetComponentProps } from './types';
|
|
2
|
+
import { FieldWidgetComponentProps } from './types.js';
|
|
3
3
|
/**
|
|
4
4
|
* PhoneField - Telephone number input with tel link in readonly mode
|
|
5
5
|
* Renders as a clickable tel link when readonly, standard phone input otherwise
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
import { FieldWidgetComponentProps } from './types';
|
|
2
|
+
import { FieldWidgetComponentProps } from './types.js';
|
|
3
3
|
/**
|
|
4
4
|
* RadioField - choose exactly one value from a fixed option set, rendered as a
|
|
5
5
|
* radio group. The stored value is the selected option value (string). Used for
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
import { FieldWidgetComponentProps } from './types';
|
|
2
|
+
import { FieldWidgetComponentProps } from './types.js';
|
|
3
3
|
export declare function RecipientPickerField({ value, onChange, readonly, className, error, ...props }: FieldWidgetComponentProps<string>): React.JSX.Element;
|
|
4
4
|
export default RecipientPickerField;
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
2
|
import { DataSource, LookupColumnDef, LookupFilterDef } from '@object-ui/types';
|
|
3
|
+
import { LookupCellRendererResolver } from './lookupColumnDisplay.js';
|
|
3
4
|
/**
|
|
4
5
|
* Cell renderer function signature — matches getCellRenderer from @object-ui/fields.
|
|
5
6
|
* Accepts a field type and returns a React component that renders a formatted cell.
|
|
6
7
|
*/
|
|
7
|
-
export type CellRendererResolver =
|
|
8
|
-
value: any;
|
|
9
|
-
field: any;
|
|
10
|
-
}>;
|
|
8
|
+
export type CellRendererResolver = LookupCellRendererResolver;
|
|
11
9
|
/**
|
|
12
10
|
* Filter column definition used by the inline filter bar.
|
|
13
11
|
* A subset of LookupColumnDef enriched with filter-specific metadata.
|
|
@@ -126,13 +124,39 @@ export interface RecordPickerDialogProps {
|
|
|
126
124
|
*/
|
|
127
125
|
lookupFilters?: LookupFilterDef[];
|
|
128
126
|
/**
|
|
129
|
-
* Hard filter
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
127
|
+
* Hard filter constraint applied to every query. Unlike `lookupFilters`,
|
|
128
|
+
* entries here never surface in the filter bar and cannot be overridden by
|
|
129
|
+
* user filter input.
|
|
130
|
+
*
|
|
131
|
+
* Two shapes, discriminated STRUCTURALLY (`Array.isArray`), because the two
|
|
132
|
+
* callers speak two legitimate vocabularies and neither should be bent into
|
|
133
|
+
* the other:
|
|
134
|
+
*
|
|
135
|
+
* - **`QueryParams.$filter` record form** (`{ account: 'a1' }`) — the
|
|
136
|
+
* dependent (cascading) lookup chain, where the parent field's value MUST
|
|
137
|
+
* scope the candidate set (#2215). Merged by KEY OVERWRITE, so a cascaded
|
|
138
|
+
* value REPLACES a stale `lookupFilters` entry on the same field instead of
|
|
139
|
+
* intersecting with it. That precedence is load-bearing: an `and` of both
|
|
140
|
+
* would ask for `account = 'stale' AND account = 'a1'` and return nothing.
|
|
141
|
+
* - **A spec `ViewFilterRule[]`** (`[{ field, operator, value? }]`) — an
|
|
142
|
+
* author's `record:related_list.add.picker.filter`, handed over VERBATIM
|
|
143
|
+
* (#3831). Lowered by `mergeFilterNodes`, the repo's single filter sink, so
|
|
144
|
+
* all 19 `VIEW_FILTER_OPERATORS` reach the wire — including the four
|
|
145
|
+
* (`before`, `after`, `is_empty`, `is_not_empty`) the record form has no
|
|
146
|
+
* `$op` for. No second operator vocabulary is introduced here: two already
|
|
147
|
+
* exist (the spec's `AST_OPERATOR_MAP`, data-objectstack's
|
|
148
|
+
* `FILTER_OPERATOR_ALIASES`) and #3948 is what a third costs.
|
|
149
|
+
*
|
|
150
|
+
* The discriminator is exact rather than heuristic — every AST node is an
|
|
151
|
+
* ARRAY and a rule is a plain OBJECT, the same predicate `toFilterNode` uses.
|
|
152
|
+
*
|
|
153
|
+
* Typed `unknown` rather than `Record< string, any >` on purpose: that type
|
|
154
|
+
* ACCEPTED a rule array (TypeScript lets an array satisfy a string index of
|
|
155
|
+
* `any`), the old object-spread merge then flattened it to
|
|
156
|
+
* `{"0": {...}, "1": {...}}`, and the query filtered on columns literally
|
|
157
|
+
* named `0`/`1` — type-check green, wrong query, no diagnostic anywhere.
|
|
134
158
|
*/
|
|
135
|
-
baseFilter?:
|
|
159
|
+
baseFilter?: unknown;
|
|
136
160
|
/**
|
|
137
161
|
* Cell renderer resolver function.
|
|
138
162
|
* When provided, columns with a `type` property will be rendered using the
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
import { FieldWidgetComponentProps } from './types';
|
|
2
|
+
import { FieldWidgetComponentProps } from './types.js';
|
|
3
3
|
/**
|
|
4
4
|
* Rich text field with markdown/HTML support
|
|
5
5
|
* For now, this is a simple textarea. A full implementation would use
|
|
@@ -22,5 +22,41 @@ import { FieldWidgetComponentProps } from './types';
|
|
|
22
22
|
* tolerant fallback in one of them. The affordance and dialog themselves come
|
|
23
23
|
* from the shared `FullscreenFieldEditor`, so one form-level setting keeps
|
|
24
24
|
* producing one behaviour across both widgets.
|
|
25
|
+
*
|
|
26
|
+
* ## Readonly display (objectui#5498)
|
|
27
|
+
*
|
|
28
|
+
* The readonly early return used to render `{value}` as a React TEXT CHILD,
|
|
29
|
+
* so a readonly field of any of the three types showed the user the markup
|
|
30
|
+
* SOURCE of their own content — a `markdown` field's asterisks and hashes, a
|
|
31
|
+
* `richtext` field's tags. The `prose` classes on that wrapper were the tell:
|
|
32
|
+
* they exist to style RENDERED rich content and there was none to style. Every
|
|
33
|
+
* other read surface — grid, kanban card, gallery, related list, dashboard
|
|
34
|
+
* record panel, record detail read mode — dispatches through `getCellRenderer`
|
|
35
|
+
* and renders the same stored bytes FORMATTED, so one field disagreed with
|
|
36
|
+
* itself depending on which surface it was read on, and this branch was the
|
|
37
|
+
* one disagreeing with the platform.
|
|
38
|
+
*
|
|
39
|
+
* It now renders through {@link richTextCellRenderer} — literally the same
|
|
40
|
+
* components `getCellRenderer` resolves, one table shared by both (see
|
|
41
|
+
* `./richTextDisplay.tsx`), so the html/richtext path carries that renderer's
|
|
42
|
+
* `sanitizeHtml` trust boundary rather than a second hand-rolled escape, and a
|
|
43
|
+
* future change to either pipeline moves both surfaces at once.
|
|
44
|
+
*
|
|
45
|
+
* ## Host plumbing (objectui#4810)
|
|
46
|
+
*
|
|
47
|
+
* The editable branch had no `toDomProps` at all, so everything
|
|
48
|
+
* `<FormControl>`'s Radix `Slot` hands down — the field's `id`, the
|
|
49
|
+
* `aria-describedby` naming its `<FormDescription>` and `<FormMessage>` —
|
|
50
|
+
* arrived as props and landed on no element. Measured on a real form: the
|
|
51
|
+
* visible label's `for` pointed at an id nothing carried (`for=DANGLING`) and
|
|
52
|
+
* the rendered description had zero consumers, for all three registry keys
|
|
53
|
+
* (`markdown` / `html` / `richtext`) since they are this one widget.
|
|
54
|
+
*
|
|
55
|
+
* The fix is objectui#3318's standing recipe — `toDomProps(props)` spread onto
|
|
56
|
+
* the REAL focusable control, which here is the `<Textarea>` inside
|
|
57
|
+
* `RichTextEditorSurface`, never the wrapper `<div>`s (a non-focusable wrapper
|
|
58
|
+
* carrying the id would satisfy `document.getElementById` and still leave the
|
|
59
|
+
* label inert). Only the inline surface receives it; see `domProps` there for
|
|
60
|
+
* why the dialog's copy must not.
|
|
25
61
|
*/
|
|
26
62
|
export declare function RichTextField({ value, onChange, field, readonly, error, ...props }: FieldWidgetComponentProps<string>): React.JSX.Element;
|
|
@@ -1,15 +1,35 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
import { FieldWidgetComponentProps } from './types';
|
|
2
|
+
import { FieldWidgetComponentProps } from './types.js';
|
|
3
3
|
/**
|
|
4
4
|
* SelectField - dropdown selection widget.
|
|
5
5
|
*
|
|
6
6
|
* A field declared `multiple: true` selects zero-or-more values (spec:
|
|
7
7
|
* `multiple` is valid on `select`), so it renders the multi-value chip picker
|
|
8
|
-
* — the same widget the `multiselect` type uses.
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
8
|
+
* — the same widget the `multiselect` type uses. Single-value selects keep the
|
|
9
|
+
* cascading dropdown below.
|
|
10
|
+
*
|
|
11
|
+
* The FORM no longer arrives here with `multiple` (objectui#3986):
|
|
12
|
+
* `mapFieldTypeToFormType` now resolves a `select` + `multiple: true` field to
|
|
13
|
+
* `field:multiselect`, so the object-form path renders `MultiSelectField`
|
|
14
|
+
* directly under its own registry id — which is what carries the
|
|
15
|
+
* `labelling: 'group'` declaration the host label needs. Deciding the widget at
|
|
16
|
+
* the type-resolution layer is what keeps the declaration and the render from
|
|
17
|
+
* disagreeing; a delegation invisible to the resolver could not.
|
|
18
|
+
*
|
|
19
|
+
* The branch below stays because it is NOT dead — measured entrances that reach
|
|
20
|
+
* it with `multiple` set, none of which consult that resolver:
|
|
21
|
+
*
|
|
22
|
+
* - **the inline grid editor** — `FieldEditWidget` looks `select` up in its own
|
|
23
|
+
* `EDIT_WIDGETS` table, which SHORT-CIRCUITS before the alias map is
|
|
24
|
+
* consulted, and forwards the whole metadata object as `field`;
|
|
25
|
+
* - **`ActionParamDialog`** — `paramToField` resolves through
|
|
26
|
+
* `resolveFormWidgetType`, which likewise returns `select` from
|
|
27
|
+
* `fieldWidgetMap` before reaching the alias map, and carries
|
|
28
|
+
* `multiple: param.multiple` on the field it builds;
|
|
29
|
+
* - **hand-written SDUI** — a `{ type: 'field:select' }` node whose metadata
|
|
30
|
+
* declares `multiple`, which addresses this widget by name.
|
|
31
|
+
*
|
|
32
|
+
* All three then inherit multi-select from here identically, with no drift.
|
|
13
33
|
*
|
|
14
34
|
* Both branches resolve per-option `visibleWhen` cascading / role-gating through
|
|
15
35
|
* the shared {@link useCascadingOptions} hook (#2715), so single and multi stay
|
|
@@ -1,7 +1,37 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
import { FieldWidgetComponentProps } from './types';
|
|
2
|
+
import { FieldWidgetComponentProps } from './types.js';
|
|
3
3
|
/**
|
|
4
4
|
* Signature field widget - provides a signature pad for capturing signatures
|
|
5
5
|
* Outputs signature as a base64 PNG image
|
|
6
|
+
*
|
|
7
|
+
* ## Naming, and the half that is deliberately absent (objectui#3318)
|
|
8
|
+
*
|
|
9
|
+
* This widget forwarded nothing a host handed it — every branch below wrote its
|
|
10
|
+
* attributes by hand — so its visible label pointed `for` at an id no element
|
|
11
|
+
* in the row carried, and the rendered help text had zero consumers. Measured
|
|
12
|
+
* on `origin/main`, a real form, this field required and freshly failed:
|
|
13
|
+
*
|
|
14
|
+
* ```
|
|
15
|
+
* signature labelFor=…-form-item -> DANGLING descConsumers=0 ids=[]
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* The name and the description arrive here, on the container, through
|
|
19
|
+
* {@link toHostGroupProps} — the objectui#3961 route for a widget whose surface
|
|
20
|
+
* no `<label for>` can reach (`<canvas>` is not a labelable element), and which
|
|
21
|
+
* therefore declares `labelling: 'group'` in `FIELD_WIDGET_LABELLING`.
|
|
22
|
+
* `'instead-of-the-inputs'` because this field renders no input of its own for
|
|
23
|
+
* the description to land on: the Clear button is auxiliary — it acts on the
|
|
24
|
+
* value, it is not the value's control — the same reading that put
|
|
25
|
+
* `geolocation`'s focusable "View on map" link on that side of the split.
|
|
26
|
+
*
|
|
27
|
+
* `aria-invalid` and `aria-required` are NOT here, and their absence is a
|
|
28
|
+
* verdict rather than an omission. The drawing surface has no keyboard path at
|
|
29
|
+
* all (measured: this row offers zero focusable elements while empty — the only
|
|
30
|
+
* candidate, Clear, is `disabled` until something has been drawn), so there is
|
|
31
|
+
* no element assistive technology would read a control state from. Marking the
|
|
32
|
+
* container instead would announce a state with no control behind it — the
|
|
33
|
+
* non-focusable-wrapper move objectui#3291 and #3318 both draw the line
|
|
34
|
+
* against. The type is recorded in that sweep's NOT_APPLICABLE ledger with a
|
|
35
|
+
* guard that turns red the day a real control appears here.
|
|
6
36
|
*/
|
|
7
|
-
export declare function SignatureField({ value, onChange, readonly }: FieldWidgetComponentProps<string>): React.JSX.Element;
|
|
37
|
+
export declare function SignatureField({ value, onChange, readonly, ...props }: FieldWidgetComponentProps<string>): React.JSX.Element;
|
|
@@ -1,7 +1,42 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
import { FieldWidgetComponentProps } from './types';
|
|
2
|
+
import { FieldWidgetComponentProps } from './types.js';
|
|
3
3
|
/**
|
|
4
4
|
* Slider field widget - provides a range slider input
|
|
5
5
|
* Supports numeric values with configurable min, max, and step
|
|
6
|
+
*
|
|
7
|
+
* ## Where the host's facts go, and why (objectui#3318)
|
|
8
|
+
*
|
|
9
|
+
* This widget used to read exactly two keys off its props (`disabled`,
|
|
10
|
+
* `className`) and forward nothing else, so everything `<FormControl>`'s Slot
|
|
11
|
+
* delivered was dropped on the floor. Measured on `origin/main`, a real form
|
|
12
|
+
* with a required slider that had just failed validation:
|
|
13
|
+
*
|
|
14
|
+
* ```
|
|
15
|
+
* ariaInvalidTrue=[] labelFor=…-form-item -> DANGLING
|
|
16
|
+
* descConsumers=0 ids=[] <- no element of the row carried an id at all
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* Three channels, one cause. The DOM pass-through now goes to the THUMB — the
|
|
20
|
+
* `span[role="slider"]` a keyboard user lands on, which is where ARIA state
|
|
21
|
+
* belongs — through the `thumbProps` the primitive grew for this
|
|
22
|
+
* (`lib/slider-thumb.ts`; the shadcn `ui/slider.tsx` renders its thumb
|
|
23
|
+
* internally and exports only `Slider`, so it cannot be addressed from here
|
|
24
|
+
* the way objectui#3306 addressed `SelectTrigger`).
|
|
25
|
+
*
|
|
26
|
+
* The split of which keys stay on Root is `SelectField`'s, key for key:
|
|
27
|
+
*
|
|
28
|
+
* - `name`: Root owns the hidden input that takes part in form submission; on
|
|
29
|
+
* a `span` it is not even DOM-legal, and is exactly the leak objectui#3291
|
|
30
|
+
* sweeps for.
|
|
31
|
+
* - `disabled`: Root is the single authority (it disables the thumb and the
|
|
32
|
+
* hidden input together); forwarding the raw prop to the thumb as well would
|
|
33
|
+
* give the state a second, OR-merged author.
|
|
34
|
+
*
|
|
35
|
+
* The visible label reaches the thumb by IDREF, not by `for`: a
|
|
36
|
+
* `span[role="slider"]` is not one of HTML's labelable elements, so this widget
|
|
37
|
+
* is declared `labelling: 'group'` for the same reason `file` is — see
|
|
38
|
+
* `FIELD_WIDGET_LABELLING` in `../index` and objectui#3961. No extra
|
|
39
|
+
* `role="group"` wrapper: there is one control here, and `slider` is a role
|
|
40
|
+
* that carries a name perfectly well on its own.
|
|
6
41
|
*/
|
|
7
|
-
export declare function SliderField({ value, onChange, field, readonly, ...props }: FieldWidgetComponentProps<number>): React.JSX.Element;
|
|
42
|
+
export declare function SliderField({ value, onChange, field, readonly, error, ...props }: FieldWidgetComponentProps<number>): React.JSX.Element;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
import { FieldWidgetComponentProps } from './types';
|
|
2
|
+
import { FieldWidgetComponentProps } from './types.js';
|
|
3
3
|
/**
|
|
4
4
|
* SummaryField - Read-only aggregation field
|
|
5
5
|
* Values are aggregated from related records and cannot be edited
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
import { FieldWidgetComponentProps } from './types';
|
|
2
|
+
import { FieldWidgetComponentProps } from './types.js';
|
|
3
3
|
/**
|
|
4
4
|
* TagsField - free-form list of string tags. Type a value and press Enter (or
|
|
5
5
|
* comma) to add it; click a tag's × to remove it. The stored value is a
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
import { FieldWidgetComponentProps } from './types';
|
|
2
|
+
import { FieldWidgetComponentProps } from './types.js';
|
|
3
3
|
/**
|
|
4
4
|
* TextAreaField - Multi-line text input widget
|
|
5
5
|
* Supports configurable row count and preserves whitespace in readonly mode.
|
|
@@ -35,7 +35,11 @@ import { FieldWidgetComponentProps } from './types';
|
|
|
35
35
|
* ## The character counter (objectui#3408, shared across surfaces in #3417)
|
|
36
36
|
*
|
|
37
37
|
* Both editing surfaces below — the inline `<Textarea>` and the fullscreen
|
|
38
|
-
* dialog's — render the SAME `CharacterCount
|
|
38
|
+
* dialog's — render the SAME `CharacterCount`. It lives in
|
|
39
|
+
* `@object-ui/components` since objectui#3439, hoisted there so the form
|
|
40
|
+
* renderer's built-in `textarea` branch renders that very component too rather
|
|
41
|
+
* than growing a third copy; this widget's use of it is unchanged. It owns the
|
|
42
|
+
* three-node
|
|
39
43
|
* GOV.UK shape (decorative digits / accessible description / gated status
|
|
40
44
|
* region) and the debounce and threshold behind it. Until #3417 the fullscreen
|
|
41
45
|
* footer had its own hand-written copy that was digits and nothing else, which
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
import { FieldWidgetComponentProps } from './types';
|
|
2
|
+
import { FieldWidgetComponentProps } from './types.js';
|
|
3
3
|
/**
|
|
4
4
|
* TextField - Standard single-line or multi-line text input
|
|
5
5
|
* Automatically renders as a textarea when rows are configured in field metadata
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
import { FieldWidgetComponentProps } from './types';
|
|
2
|
+
import { FieldWidgetComponentProps } from './types.js';
|
|
3
3
|
/**
|
|
4
4
|
* UrlField - URL input with clickable link in readonly mode
|
|
5
5
|
* Validates URLs to only render http/https links for security
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { CellRendererResolver } from './RecordPickerDialog';
|
|
1
|
+
import { CellRendererResolver } from './RecordPickerDialog.js';
|
|
2
2
|
export declare function setCellRendererResolver(resolver: CellRendererResolver): void;
|
|
3
3
|
export declare function getCellRendererResolver(): CellRendererResolver | undefined;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { AddressValue } from '@objectstack/spec/data';
|
|
2
|
+
/**
|
|
3
|
+
* Address data structure — `z.input` of `@objectstack/spec`'s
|
|
4
|
+
* `AddressValueSchema`, which is what the platform stores and what
|
|
5
|
+
* `/api/v1/data/**` serves back.
|
|
6
|
+
*
|
|
7
|
+
* The postal code is spelled `postalCode` (objectstack#5143). `AddressField`
|
|
8
|
+
* used to read and write `zipCode`, a key that appears nowhere in the spec, so
|
|
9
|
+
* the stored postal code never reached the input — and whatever the user then
|
|
10
|
+
* typed into that apparently-empty box was written under a key
|
|
11
|
+
* `AddressValueSchema` strips: lost outright on a new record, and on an
|
|
12
|
+
* existing one silently discarded while the stale stored value survived. (A
|
|
13
|
+
* postal code nobody touched did survive an unrelated edit, because the write
|
|
14
|
+
* spread the whole stored object through; the issue's account of that half is
|
|
15
|
+
* corrected in `AddressField.postalCode.test.tsx`.) One name, on both sides:
|
|
16
|
+
* the contract's.
|
|
17
|
+
*
|
|
18
|
+
* IMPORTED rather than declared since objectui#4167. rc.6 publishes
|
|
19
|
+
* `AddressValue` under this exact name, and the local copy — whose own comment
|
|
20
|
+
* already claimed to be "the part names of `AddressSchema`" — declared five of
|
|
21
|
+
* the seven parts. `countryCode` and `formatted` were missing, which is
|
|
22
|
+
* objectstack#4115's failure class precisely: a canonical CLAIM over a narrower
|
|
23
|
+
* shape, believed by the next reader. The claim is now the code.
|
|
24
|
+
*
|
|
25
|
+
* `AddressField` still renders five inputs and {@link formatAddress} still
|
|
26
|
+
* composes five parts, and that is a deliberate split rather than an omission:
|
|
27
|
+
* `formatted` is a derived one-line rendering of the parts (what this module
|
|
28
|
+
* computes) and `countryCode` is the ISO pair for `country`, neither of which a
|
|
29
|
+
* human types into a part box. Binding the type does not publish them as
|
|
30
|
+
* inputs — it stops the type from asserting the platform cannot store them, and
|
|
31
|
+
* it means a write from the widget no longer looks type-clean while dropping a
|
|
32
|
+
* key the contract carries: the `{ ...address }` spread in `handleFieldChange`
|
|
33
|
+
* preserves both, and now says so.
|
|
34
|
+
*
|
|
35
|
+
* The declaration moved here (objectui#4037) so the display cell renderer and
|
|
36
|
+
* the widget share one definition; the SOURCE of that definition is the spec.
|
|
37
|
+
*/
|
|
38
|
+
export type { AddressValue };
|
|
39
|
+
/**
|
|
40
|
+
* The shape written by builds up to and including 17.0.0-rc.1, whose postal
|
|
41
|
+
* code landed under `zipCode` (objectstack#5143). Read-time compatibility ONLY,
|
|
42
|
+
* and deliberately not part of {@link AddressValue}: authoring code must not be
|
|
43
|
+
* able to spell `zipCode`, and nothing here ever writes it back — the first
|
|
44
|
+
* edit of any part normalizes the record onto `postalCode` (see
|
|
45
|
+
* `AddressField`'s `handleFieldChange`). This is not a producer alias to be
|
|
46
|
+
* honoured forever; it exists to carry data THIS widget mis-wrote, and can go
|
|
47
|
+
* once no such data remains.
|
|
48
|
+
*/
|
|
49
|
+
export type LegacyAddressValue = AddressValue & {
|
|
50
|
+
zipCode?: string;
|
|
51
|
+
};
|
|
52
|
+
/** Postal code of a stored address, preferring the canonical key. */
|
|
53
|
+
export declare function readPostalCode(addr: AddressValue): string | undefined;
|
|
54
|
+
/**
|
|
55
|
+
* Formats a stored address as a single line, in the part order the reader's
|
|
56
|
+
* locale writes addresses in.
|
|
57
|
+
*
|
|
58
|
+
* Two orders, and the second is exactly the first reversed:
|
|
59
|
+
*
|
|
60
|
+
* - **small-to-large** (default; `en` and every Latin/Cyrillic/Arabic locale
|
|
61
|
+
* this repo ships) — `Street, City, State ZIP, Country`. Unchanged from
|
|
62
|
+
* what `AddressField`'s readonly branch has always produced, so English and
|
|
63
|
+
* provider-less rendering are byte-identical to before.
|
|
64
|
+
* - **large-to-small** ({@link LARGE_TO_SMALL_LANGUAGES}) — `Country, ZIP
|
|
65
|
+
* State, City, Street`. A `zh` console rendering a Chinese address
|
|
66
|
+
* largest-first is the whole point of objectui#4028: `中国, 310000 浙江,
|
|
67
|
+
* 杭州, 中策路 1 号` rather than the US-ordered line it produced before.
|
|
68
|
+
*
|
|
69
|
+
* Only the ORDER varies. The separator stays `', '` in both, because that is
|
|
70
|
+
* not what the issue reports and because these lines carry mixed-script data —
|
|
71
|
+
* a US address read on a `zh` console would look stranger under fullwidth
|
|
72
|
+
* punctuation than under the comma it already has.
|
|
73
|
+
*
|
|
74
|
+
* The state/postal-code pair keeps its one comma-delimited group in both
|
|
75
|
+
* orders, space-separated inside it ("CA 94102" / "310000 浙江"); either part
|
|
76
|
+
* alone occupies the group by itself. Missing parts are dropped rather than
|
|
77
|
+
* spaced over, so a street-only address is `"中策路 1 号"` and never `", , ,"`.
|
|
78
|
+
*
|
|
79
|
+
* Returns `''` when no part is usable — callers decide what an empty address
|
|
80
|
+
* looks like (an `EmptyValue` placeholder for the cell renderer), and a value
|
|
81
|
+
* carrying no recognized part at all is NOT silently blanked: see
|
|
82
|
+
* `AddressCellRenderer`, which falls back to JSON so unknown data stays visible.
|
|
83
|
+
*
|
|
84
|
+
* @param locale - BCP-47 tag from `useDisplayLocale()`. Omitted (tests, and any
|
|
85
|
+
* caller with no React context) means the small-to-large default, which is
|
|
86
|
+
* what this function did unconditionally before objectui#4028.
|
|
87
|
+
*/
|
|
88
|
+
export declare function formatAddress(addr: AddressValue, locale?: string): string;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The client-side `maxSize` guard shared by the file and image widgets
|
|
3
|
+
* (objectui#4141).
|
|
4
|
+
*
|
|
5
|
+
* Why this is shared rather than mirrored per widget: the guard is the only
|
|
6
|
+
* thing standing between a declared `maxSize` and a real `presigned → PUT →
|
|
7
|
+
* complete` round trip, and `paramToField` copies `maxSize` onto the field
|
|
8
|
+
* config for **every** param type regardless of which widget ends up rendering
|
|
9
|
+
* it. So a widget that re-derives the check drifts silently — the image param
|
|
10
|
+
* shipped receiving the constraint and never reading it, while the file param
|
|
11
|
+
* rejected the identical pick, and nothing failed until QA drove the two side by
|
|
12
|
+
* side. One exported function makes the difference visible: a widget either
|
|
13
|
+
* calls it or conspicuously does not.
|
|
14
|
+
*
|
|
15
|
+
* Both widgets deliberately share the `fields.file.exceedsMaxSize` key too. The
|
|
16
|
+
* sentence names a file and a limit and says nothing file-widget-specific, it is
|
|
17
|
+
* already translated in all 11 built-in locales, and a parallel `fields.image.*`
|
|
18
|
+
* twin would be the same sentence maintained twice — drifting the moment one
|
|
19
|
+
* translator rewords one of them.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Minimal shape of the i18next `t` this module needs, matching the established
|
|
23
|
+
* `TranslateFn` pattern in `app-shell/src/providers/writeWarningToast`.
|
|
24
|
+
*/
|
|
25
|
+
export type TranslateFn = (key: string, options?: Record<string, unknown>) => string;
|
|
26
|
+
/**
|
|
27
|
+
* The rejection message for a pick that exceeds `maxSize`, or `null` when the
|
|
28
|
+
* pick is within the limit — so a caller reads it as `if (err) reject`.
|
|
29
|
+
*
|
|
30
|
+
* A falsy `maxSize` (undeclared, or an explicit `0`) means **unrestricted**,
|
|
31
|
+
* preserving the `if (maxSize && …)` semantics the file widget has always
|
|
32
|
+
* applied: an undeclared limit must never turn into a 0-byte one.
|
|
33
|
+
*
|
|
34
|
+
* Takes `name` and `size` separately instead of a `File` because the image
|
|
35
|
+
* widget's crop path validates a re-encoded `Blob`, which carries no name of its
|
|
36
|
+
* own — that name comes from the cropper's output.
|
|
37
|
+
*/
|
|
38
|
+
export declare function maxSizeError(t: TranslateFn, pick: {
|
|
39
|
+
name: string;
|
|
40
|
+
size: number;
|
|
41
|
+
}, maxSize: number | undefined): string | null;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { LookupColumnDef } from '@object-ui/types';
|
|
3
|
+
/**
|
|
4
|
+
* Cell renderer function signature — matches `getCellRenderer` from
|
|
5
|
+
* `@object-ui/fields`. Re-declared here (rather than imported from
|
|
6
|
+
* RecordPickerDialog) so this module sits BELOW both consumers in the import
|
|
7
|
+
* graph and neither surface can pull the other in.
|
|
8
|
+
*/
|
|
9
|
+
export type LookupCellRendererResolver = (fieldType: string) => React.FC<{
|
|
10
|
+
value: any;
|
|
11
|
+
field: any;
|
|
12
|
+
}>;
|
|
13
|
+
/**
|
|
14
|
+
* A select option as the object schema declares it — `{ value, label }` plus
|
|
15
|
+
* whatever the renderer also reads (`color`, …), which the i18n translation
|
|
16
|
+
* carries through untouched.
|
|
17
|
+
*/
|
|
18
|
+
export type SchemaOption = {
|
|
19
|
+
value: any;
|
|
20
|
+
label: string;
|
|
21
|
+
[key: string]: any;
|
|
22
|
+
};
|
|
23
|
+
/** Translate a schema field's options through the shared i18n option path. */
|
|
24
|
+
export type OptionTranslator = (objectName: string, fieldName: string, options: SchemaOption[]) => SchemaOption[];
|
|
25
|
+
/**
|
|
26
|
+
* Normalise a lookup_columns entry (string | LookupColumnDef) into a
|
|
27
|
+
* concrete LookupColumnDef object.
|
|
28
|
+
*/
|
|
29
|
+
export declare function normalizeColumn(col: string | LookupColumnDef): LookupColumnDef;
|
|
30
|
+
/**
|
|
31
|
+
* Pretty-print a field name as a column header label.
|
|
32
|
+
* Converts snake_case / camelCase to Title Case.
|
|
33
|
+
*/
|
|
34
|
+
export declare function fieldToLabel(field: string): string;
|
|
35
|
+
/**
|
|
36
|
+
* Resolve a field's select options from the referenced object's schema field
|
|
37
|
+
* definition (`fieldsMeta[field]`), translated through the shared i18n option
|
|
38
|
+
* path.
|
|
39
|
+
*
|
|
40
|
+
* This is the SINGLE source for every surface that needs option labels: the
|
|
41
|
+
* picker table cells (#3333), the picker's filter panel select inputs (#3336)
|
|
42
|
+
* and the inline dropdown's option preview (#5492) — so a picker column, the
|
|
43
|
+
* filter input for that same column and the dropdown row can never disagree
|
|
44
|
+
* about what an option is called.
|
|
45
|
+
*
|
|
46
|
+
* Returns `undefined` when the schema field declares no options: a select
|
|
47
|
+
* field with no authored options genuinely has nothing to offer, and
|
|
48
|
+
* synthesising entries from the loaded page's raw stored values would paper
|
|
49
|
+
* over the metadata gap with a list that changes per page.
|
|
50
|
+
*/
|
|
51
|
+
export declare function resolveSchemaOptions(meta: {
|
|
52
|
+
options?: unknown;
|
|
53
|
+
} | undefined, objectName: string, fieldName: string, translateOptions: OptionTranslator): SchemaOption[] | undefined;
|
|
54
|
+
/**
|
|
55
|
+
* Field descriptors handed to the type-aware cell renderers, enriched from the
|
|
56
|
+
* referenced object's schema (`fieldsMeta`) the same way the list view enriches
|
|
57
|
+
* its columns. This is what lets a `select` column resolve its option label
|
|
58
|
+
* (options + i18n) instead of title-casing the raw value (#3333), and what
|
|
59
|
+
* carries `reference` / `reference_to` through to the lookup cell renderer so
|
|
60
|
+
* an unresolved foreign-key id resolves to a name (#5492).
|
|
61
|
+
*
|
|
62
|
+
* Columns whose def carries no `type` inherit the schema field's type, so
|
|
63
|
+
* string-authored `lookup_columns` format identically to object-authored ones.
|
|
64
|
+
*/
|
|
65
|
+
export declare function buildLookupColumnDescriptors(columns: LookupColumnDef[], fieldsMeta: Record<string, any> | undefined, objectName: string, translateOptions: OptionTranslator): Record<string, any>;
|
|
66
|
+
export interface LookupColumnRenderContext {
|
|
67
|
+
/** Field descriptors from {@link buildLookupColumnDescriptors}. */
|
|
68
|
+
descriptors: Record<string, any>;
|
|
69
|
+
/** Type-aware renderer resolver; when absent every cell degrades to text. */
|
|
70
|
+
cellRenderer?: LookupCellRendererResolver;
|
|
71
|
+
/** The referenced object's `titleFormat`, applied to the display column. */
|
|
72
|
+
titleFormat?: string | null;
|
|
73
|
+
/** The lookup's display field — the column the title template stands in for. */
|
|
74
|
+
displayField?: string;
|
|
75
|
+
/** Locale for the plain-text `$date` fallback. */
|
|
76
|
+
displayLocale?: string;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Render one column of one candidate record.
|
|
80
|
+
*
|
|
81
|
+
* Order:
|
|
82
|
+
* 1. `titleFormat` template, for the display column only — so users see a
|
|
83
|
+
* human-readable name instead of a raw id when the display field
|
|
84
|
+
* (commonly defaulted to `name`) does not exist on the record.
|
|
85
|
+
* 2. the type-aware cell renderer for the column's field descriptor.
|
|
86
|
+
* 3. a plain-text fallback for columns with no descriptor / no resolver.
|
|
87
|
+
*
|
|
88
|
+
* Step 3 never blanks a populated value: an object with no recognised shape
|
|
89
|
+
* keeps its JSON and a primitive keeps its `String()` form. That floor is
|
|
90
|
+
* deliberate — an unresolved reference showing its bare id is strictly better
|
|
91
|
+
* than a silently empty column (objectui#5492).
|
|
92
|
+
*/
|
|
93
|
+
export declare function renderLookupColumnValue(record: any, col: LookupColumnDef, ctx: LookupColumnRenderContext): React.ReactNode;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Stored value → `<input type="date">` value (`YYYY-MM-DD`).
|
|
10
|
+
*
|
|
11
|
+
* A leading `YYYY-MM-DD` is passed through VERBATIM rather than re-parsed: a
|
|
12
|
+
* date-only string is parsed as UTC midnight by `new Date()`, so reading local
|
|
13
|
+
* calendar components back out of it shifts the day by one everywhere west of
|
|
14
|
+
* Greenwich. `2026-06-17` must stay June 17th in every zone.
|
|
15
|
+
*/
|
|
16
|
+
export declare function toDateInputValue(value: unknown): string;
|
|
17
|
+
/**
|
|
18
|
+
* Stored value → `<input type="datetime-local">` value (`YYYY-MM-DDTHH:mm`),
|
|
19
|
+
* expressed in the viewer's local wall clock — the same instant the detail
|
|
20
|
+
* page shows, so opening the editor never appears to move the time.
|
|
21
|
+
*
|
|
22
|
+
* A value that is ALREADY a zone-less local datetime is truncated to minutes
|
|
23
|
+
* in place instead of being round-tripped through `Date`, which would
|
|
24
|
+
* reinterpret it and then re-render it, twice risking an off-by-a-zone shift.
|
|
25
|
+
*/
|
|
26
|
+
export declare function toDateTimeInputValue(value: unknown): string;
|
|
27
|
+
/**
|
|
28
|
+
* `<input type="datetime-local">` value → stored value (ISO-8601, UTC).
|
|
29
|
+
*
|
|
30
|
+
* The control hands us a zone-less local wall clock; `new Date()` reads that
|
|
31
|
+
* form as local time, which is the inverse of what `toDateTimeInputValue`
|
|
32
|
+
* wrote — the pair is what keeps read and write on one basis.
|
|
33
|
+
*
|
|
34
|
+
* An unparseable string is returned untouched rather than blanked: dropping a
|
|
35
|
+
* value the user can see in the box would be a data loss dressed up as a fix.
|
|
36
|
+
*/
|
|
37
|
+
export declare function fromDateTimeInputValue(value: string): string;
|