@object-ui/fields 17.1.0 → 17.3.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 +786 -0
- package/dist/FieldEditWidget.d.ts +2 -2
- package/dist/__tests__/cell-truncation.test.d.ts +0 -0
- package/dist/__tests__/field-carrier-sdui.test.d.ts +0 -0
- package/dist/__tests__/spec-symbol-batch7.test.d.ts +8 -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 +8 -0
- package/dist/index.cjs +5 -5
- package/dist/index.d.ts +4 -0
- package/dist/index.js +2882 -2569
- package/dist/widgets/AddressField.d.ts +2 -2
- package/dist/widgets/AddressField.uniqueIds.test.d.ts +0 -0
- 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/CharacterCount.d.ts +56 -0
- 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/FullscreenFieldEditor.d.ts +155 -0
- package/dist/widgets/GeolocationField.d.ts +2 -2
- package/dist/widgets/GeolocationField.uniqueIds.test.d.ts +0 -0
- 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/LookupField.gateHintLabel.test.d.ts +8 -0
- 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/OptionsEmptyState.d.ts +45 -0
- package/dist/widgets/OptionsEmptyState.no-provider.test.d.ts +0 -0
- package/dist/widgets/OptionsEmptyState.test.d.ts +0 -0
- 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/RecordPickerDialog.d.ts +17 -1
- package/dist/widgets/RecordPickerDialog.filterOptions.test.d.ts +8 -0
- package/dist/widgets/RecordPickerDialog.selectLabel.test.d.ts +8 -0
- package/dist/widgets/RichTextField.d.ts +20 -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/TagsField.placeholder.no-provider.test.d.ts +0 -0
- package/dist/widgets/TagsField.placeholder.test.d.ts +0 -0
- package/dist/widgets/TextAreaField.d.ts +45 -6
- 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/__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/file-value.d.ts +20 -33
- package/dist/widgets/toDomProps.d.ts +91 -0
- package/dist/widgets/types.d.ts +215 -4
- package/dist/withFieldCarrier.d.ts +56 -0
- package/package.json +13 -13
- package/src/FieldEditWidget.tsx +6 -4
- package/src/__tests__/cell-truncation.test.tsx +96 -0
- package/src/__tests__/field-carrier-sdui.test.tsx +169 -0
- package/src/__tests__/spec-symbol-batch7.test.ts +126 -0
- package/src/__tests__/validation-feedback.test.tsx +22 -13
- package/src/__tests__/widget-aria-invalid-e2e.test.tsx +265 -0
- package/src/__tests__/widget-aria-invalid-registry-e2e.test.tsx +338 -0
- package/src/__tests__/widget-dom-leak-e2e.test.tsx +598 -0
- package/src/__tests__/widget-props-contract.test.tsx +142 -0
- package/src/complex-widgets.test.tsx +3 -3
- package/src/datetime-widgets.test.tsx +2 -2
- package/src/index.tsx +77 -27
- package/src/widgets/AddressField.tsx +32 -13
- package/src/widgets/AddressField.uniqueIds.test.tsx +92 -0
- package/src/widgets/AutoNumberField.tsx +2 -2
- package/src/widgets/AvatarField.tsx +10 -3
- package/src/widgets/BooleanField.tsx +5 -5
- package/src/widgets/CapabilityMultiSelectField.tsx +4 -4
- package/src/widgets/CharacterCount.tsx +263 -0
- package/src/widgets/CheckboxesField.tsx +35 -18
- package/src/widgets/CodeField.tsx +10 -3
- package/src/widgets/ColorField.tsx +12 -3
- package/src/widgets/CurrencyField.tsx +6 -5
- package/src/widgets/DateField.tsx +4 -4
- package/src/widgets/DateTimeField.tsx +4 -4
- package/src/widgets/EmailField.tsx +6 -6
- package/src/widgets/FileField.tsx +14 -4
- package/src/widgets/FilterConditionField.tsx +14 -3
- package/src/widgets/FormulaField.tsx +3 -3
- package/src/widgets/FullscreenFieldEditor.tsx +271 -0
- package/src/widgets/GeolocationField.tsx +22 -7
- package/src/widgets/GeolocationField.uniqueIds.test.tsx +88 -0
- package/src/widgets/GridField.tsx +4 -4
- package/src/widgets/ImageField.tsx +10 -3
- package/src/widgets/LocationField.tsx +10 -3
- package/src/widgets/LookupField.gateHintLabel.test.tsx +135 -0
- package/src/widgets/LookupField.tsx +50 -15
- package/src/widgets/MasterDetailField.tsx +3 -3
- package/src/widgets/MultiSelectField.tsx +34 -18
- package/src/widgets/NumberField.tsx +5 -5
- package/src/widgets/ObjectField.tsx +18 -9
- package/src/widgets/ObjectRefField.tsx +14 -4
- package/src/widgets/OptionsEmptyState.no-provider.test.tsx +88 -0
- package/src/widgets/OptionsEmptyState.test.tsx +169 -0
- package/src/widgets/OptionsEmptyState.tsx +83 -0
- package/src/widgets/PasswordField.tsx +5 -5
- package/src/widgets/PeoplePicker.tsx +7 -1
- package/src/widgets/PercentField.tsx +6 -5
- package/src/widgets/PhoneField.tsx +6 -6
- package/src/widgets/QRCodeField.tsx +10 -3
- package/src/widgets/RadioField.tsx +28 -18
- package/src/widgets/RatingField.tsx +19 -4
- package/src/widgets/RecipientPickerField.tsx +22 -4
- package/src/widgets/RecordPickerDialog.filterOptions.test.tsx +611 -0
- package/src/widgets/RecordPickerDialog.selectLabel.test.tsx +112 -0
- package/src/widgets/RecordPickerDialog.tsx +173 -8
- package/src/widgets/RichTextField.tsx +152 -25
- package/src/widgets/SelectField.tsx +53 -22
- package/src/widgets/SignatureField.tsx +2 -2
- package/src/widgets/SliderField.tsx +3 -3
- package/src/widgets/SummaryField.tsx +3 -3
- package/src/widgets/TagsField.placeholder.no-provider.test.tsx +68 -0
- package/src/widgets/TagsField.placeholder.test.tsx +95 -0
- package/src/widgets/TagsField.tsx +25 -4
- package/src/widgets/TextAreaField.tsx +172 -94
- package/src/widgets/TextField.tsx +5 -5
- package/src/widgets/TimeField.tsx +4 -4
- package/src/widgets/UrlField.tsx +6 -6
- package/src/widgets/UserField.tsx +3 -3
- package/src/widgets/VectorField.tsx +3 -3
- package/src/widgets/__tests__/FullscreenFieldEditor.i18n.test.tsx +248 -0
- package/src/widgets/__tests__/FullscreenFieldEditor.no-provider.test.tsx +116 -0
- package/src/widgets/__tests__/RichTextField.fullscreenDisabled.test.tsx +244 -0
- package/src/widgets/__tests__/RichTextField.mobileFullscreen.test.tsx +195 -0
- package/src/widgets/__tests__/TextAreaField.characterCount.announcements.test.tsx +417 -0
- package/src/widgets/__tests__/TextAreaField.characterCount.i18n.test.tsx +287 -0
- package/src/widgets/__tests__/TextAreaField.characterCount.no-provider.test.tsx +160 -0
- package/src/widgets/__tests__/TextAreaField.fullscreenCharacterCount.i18n.test.tsx +161 -0
- package/src/widgets/__tests__/TextAreaField.fullscreenCharacterCount.test.tsx +346 -0
- package/src/widgets/__tests__/TextAreaField.fullscreenDisabled.test.tsx +246 -0
- package/src/widgets/__tests__/TextAreaField.mobileFullscreen.test.tsx +175 -0
- package/src/widgets/file-value.ts +21 -5
- package/src/widgets/toDomProps.ts +175 -0
- package/src/widgets/types.ts +230 -7
- package/src/widgets/useFieldTranslation.ts +60 -0
- package/src/withFieldCarrier.tsx +75 -0
|
@@ -39,6 +39,12 @@ const FIELD_DEFAULTS: Record<string, string> = {
|
|
|
39
39
|
'lookup.nextPage': 'Next page',
|
|
40
40
|
'lookup.jumpToPage': 'Jump to page',
|
|
41
41
|
'lookup.retry': 'Retry',
|
|
42
|
+
// objectui#3231 — the empty / dependency-gated state of the fixed-option
|
|
43
|
+
// widgets (select, multiselect, radio, checkboxes). Only used when the host
|
|
44
|
+
// supplies no `emptyHint`; the gate sentence shares its key with the form
|
|
45
|
+
// renderer so both cannot drift apart in a locale.
|
|
46
|
+
'fields.options.empty': 'No options available',
|
|
47
|
+
'fields.options.selectFirst': 'Select {{fields}} first',
|
|
42
48
|
// objectstack#3821 — sharing-rule authoring widgets (object-ref /
|
|
43
49
|
// recipient-picker / filter-condition). The recipient placeholder is keyed
|
|
44
50
|
// PER TYPE rather than interpolating the enum value into an English
|
|
@@ -69,6 +75,60 @@ const FIELD_DEFAULTS: Record<string, string> = {
|
|
|
69
75
|
'fields.filterCondition.jsonOnly': 'This criteria can only be edited as JSON',
|
|
70
76
|
'fields.filterCondition.editAsJson': 'Edit as JSON',
|
|
71
77
|
'fields.filterCondition.useVisualBuilder': 'Use visual builder',
|
|
78
|
+
// objectui#3342 — the tags widget's input hint. Used only when the field
|
|
79
|
+
// author declared no `placeholder` of their own (author declaration wins).
|
|
80
|
+
'fields.tags.placeholder': 'Type and press Enter to add…',
|
|
81
|
+
// objectui#3406 — the accessible name of `TextAreaField`'s character
|
|
82
|
+
// counter, rendered only when the field declares `maxLength`. The visible
|
|
83
|
+
// `{n}/{max}` is digits; this sentence is what a screen reader speaks, and
|
|
84
|
+
// the element is `aria-live`, so before the key existed a non-English
|
|
85
|
+
// session heard English on every keystroke. Byte-identical to the literal
|
|
86
|
+
// it replaces, so a no-provider render is unchanged.
|
|
87
|
+
'fields.textarea.characterCount': 'Character count: {{count}} of {{max}}',
|
|
88
|
+
// objectui#3408 — the NEAR-LIMIT warning, spoken by the counter's status
|
|
89
|
+
// region after the typist pauses and only once they are inside the last 10%
|
|
90
|
+
// (or last 20 characters) of the cap. The sentence above became the field's
|
|
91
|
+
// `aria-describedby` description in the same change; this one is the only
|
|
92
|
+
// thing that is ever announced mid-typing, which is why it says what is
|
|
93
|
+
// LEFT rather than repeating the whole count.
|
|
94
|
+
//
|
|
95
|
+
// Colon form, not "You have {{count}} characters remaining": `count` makes
|
|
96
|
+
// i18next attempt plural lookup (`_one` / `_few` / …) before the base key,
|
|
97
|
+
// and these packs declare the base key only — the same base-key fallback
|
|
98
|
+
// `characterCount` already relies on. A sentence whose grammar does not
|
|
99
|
+
// depend on the number stays correct at 1 without ten plural entries per
|
|
100
|
+
// pack, and matches the sibling key's shape.
|
|
101
|
+
'fields.textarea.charactersRemaining': 'Characters remaining: {{count}}',
|
|
102
|
+
// objectui#3404 — the shared fullscreen long-text dialog
|
|
103
|
+
// (`FullscreenFieldEditor`, reached from `TextAreaField` and
|
|
104
|
+
// `RichTextField` when `mobile_fullscreen` is set).
|
|
105
|
+
//
|
|
106
|
+
// Deliberately the SAME `form.fullscreen.*` / `common.cancel` keys the
|
|
107
|
+
// built-in branch consumes (`FullscreenTextarea` in
|
|
108
|
+
// `components/src/renderers/form/form.tsx`, objectui#3272) rather than
|
|
109
|
+
// `fields.fullscreen.*` twins. One form-level setting
|
|
110
|
+
// (`ObjectFormSchema.mobile.fullscreenLongText`) projects onto BOTH render
|
|
111
|
+
// paths inside a single form, so a second copy of this copy is guaranteed
|
|
112
|
+
// drift — the shape #3231/#3263 had to undo — and would mean editing ten
|
|
113
|
+
// locale packs to say what they already say. `common.cancel` is already
|
|
114
|
+
// declared above and is reused here for exactly that reason.
|
|
115
|
+
//
|
|
116
|
+
// The values are byte-identical to the English literals they replaced, so
|
|
117
|
+
// a widget rendered with no I18nProvider (standalone/embedded hosts, and
|
|
118
|
+
// every bare-render test in this package) shows what it always did instead
|
|
119
|
+
// of a raw key. Measured before the change: with no provider mounted, bare
|
|
120
|
+
// `useObjectTranslation().t` returns the key itself
|
|
121
|
+
// (`common.cancel` → "common.cancel"), which is why this goes through
|
|
122
|
+
// `createSafeTranslation` like the built-in branch does.
|
|
123
|
+
'form.fullscreen.title': 'Edit text',
|
|
124
|
+
'form.fullscreen.description': 'Edit the full text value, then save or cancel your changes.',
|
|
125
|
+
'form.fullscreen.done': 'Done',
|
|
126
|
+
// Kept as ONE interpolated sentence with a translated generic noun standing
|
|
127
|
+
// in for a missing label — the literal's own shape
|
|
128
|
+
// (`Edit ${label ?? 'text'} fullscreen`). A second, label-less sentence key
|
|
129
|
+
// would need ten new pack entries to say the same thing.
|
|
130
|
+
'form.fullscreen.toggle': 'Edit {{label}} fullscreen',
|
|
131
|
+
'form.fullscreen.textFallback': 'text',
|
|
72
132
|
// objectui#2600 B5 — capability picker scope group headers.
|
|
73
133
|
'capability.group.platform': 'Platform',
|
|
74
134
|
'capability.group.org': 'Organization',
|
|
@@ -0,0 +1,75 @@
|
|
|
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
|
+
import React from 'react';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Adapt `SchemaRenderer`'s SDUI carrier onto the field-widget contract —
|
|
13
|
+
* objectui#3233, the producer-side half of retiring `schema` from
|
|
14
|
+
* {@link import('./widgets/types').FieldWidgetComponentProps}.
|
|
15
|
+
*
|
|
16
|
+
* ## Why this exists
|
|
17
|
+
*
|
|
18
|
+
* Two kinds of host render a registered field widget, and they name the
|
|
19
|
+
* metadata differently *for good reason*:
|
|
20
|
+
*
|
|
21
|
+
* - the **form renderer** (`renderFieldComponent` in
|
|
22
|
+
* `@object-ui/components`), the inline-edit hosts (`FieldEditWidget`) and
|
|
23
|
+
* the action dialogs pass **`field`** — the field metadata they already
|
|
24
|
+
* hold;
|
|
25
|
+
* - **`SchemaRenderer`** (`@object-ui/react`) passes **`schema`** — the
|
|
26
|
+
* authored node. That key is the UNIVERSAL SDUI contract *every* registered
|
|
27
|
+
* component receives (`element:*`, `page:*`, `object-grid`,
|
|
28
|
+
* `ReportRenderer` …). It is not being retired and must not be: it is what
|
|
29
|
+
* the renderer means by "the node you were rendered from".
|
|
30
|
+
*
|
|
31
|
+
* What WAS wrong is that both keys reached the widget, so ~30 widgets resolved
|
|
32
|
+
* their config as `field || schema` — one concept under two spellings, a second
|
|
33
|
+
* de-facto contract on the widget side (AGENTS.md #0.1) and precisely the shape
|
|
34
|
+
* that lets an AI-written widget pick one spelling and appear to work under one
|
|
35
|
+
* host while reading `undefined` under the other.
|
|
36
|
+
*
|
|
37
|
+
* The translation belongs at the seam, exactly once: here. Downstream `field`
|
|
38
|
+
* is the only carrier, and a widget reading `props.schema` no longer compiles.
|
|
39
|
+
*
|
|
40
|
+
* ## Guarantee
|
|
41
|
+
*
|
|
42
|
+
* Payload-preserving by construction: the node is forwarded **by reference**,
|
|
43
|
+
* so a widget's `field` is the very object it used to read through `schema`.
|
|
44
|
+
* `field` wins when a host supplies both (the form path always does, and it
|
|
45
|
+
* holds the resolved metadata rather than the raw node).
|
|
46
|
+
*
|
|
47
|
+
* `schema` is *consumed* here rather than forwarded — with the key gone from
|
|
48
|
+
* the contract, passing it on would only reach the DOM as a stray attribute
|
|
49
|
+
* through a widget's `...props` spread.
|
|
50
|
+
*
|
|
51
|
+
* ## For widget authors outside this repo
|
|
52
|
+
*
|
|
53
|
+
* Registering a widget raw means `SchemaRenderer` hands it `schema` and no
|
|
54
|
+
* `field`. Wrap it once at registration and the widget only ever implements
|
|
55
|
+
* `FieldWidgetComponentProps`:
|
|
56
|
+
*
|
|
57
|
+
* ```tsx
|
|
58
|
+
* import { withFieldCarrier } from '@object-ui/fields';
|
|
59
|
+
*
|
|
60
|
+
* ComponentRegistry.register('color', withFieldCarrier(ColorPickerField), {
|
|
61
|
+
* namespace: 'field',
|
|
62
|
+
* });
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export function withFieldCarrier<P extends object>(
|
|
66
|
+
FieldWidget: React.ComponentType<P>,
|
|
67
|
+
): React.FC<Record<string, any>> {
|
|
68
|
+
const FieldCarrierAdapter: React.FC<Record<string, any>> = ({ schema, field, ...props }) => (
|
|
69
|
+
<FieldWidget {...(props as unknown as P)} field={field ?? schema} />
|
|
70
|
+
);
|
|
71
|
+
FieldCarrierAdapter.displayName = `FieldCarrier(${
|
|
72
|
+
(FieldWidget as any).displayName || (FieldWidget as any).name || 'Component'
|
|
73
|
+
})`;
|
|
74
|
+
return FieldCarrierAdapter;
|
|
75
|
+
}
|