@object-ui/fields 17.5.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 +714 -0
- package/dist/FieldEditWidget.d.ts +16 -2
- package/dist/field-type-alias.d.ts +16 -0
- package/dist/index.cjs +4 -4
- package/dist/index.css +27 -9
- package/dist/index.d.ts +425 -72
- package/dist/index.js +2530 -2228
- package/dist/widgets/AddressField.d.ts +3 -3
- 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 +9 -2
- package/dist/widgets/GeolocationField.d.ts +1 -1
- package/dist/widgets/GridField.d.ts +56 -4
- 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 +13 -7
- 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 +2 -4
- package/dist/widgets/RichTextField.d.ts +37 -1
- package/dist/widgets/SelectField.d.ts +1 -1
- 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 +27 -7
- package/dist/widgets/lookupColumnDisplay.d.ts +93 -0
- package/dist/widgets/richTextDisplay.d.ts +80 -0
- package/dist/widgets/toHostGroupProps.d.ts +119 -21
- package/dist/widgets/types.d.ts +8 -3
- package/package.json +9 -10
- package/dist/widgets/CharacterCount.d.ts +0 -56
- package/src/FieldEditWidget.test.ts +0 -133
- package/src/FieldEditWidget.tsx +0 -207
- package/src/__tests__/AddressCellRenderer.test.tsx +0 -166
- package/src/__tests__/CurrencyField.minorUnits.test.tsx +0 -191
- package/src/__tests__/CurrencyField.symbol.test.tsx +0 -198
- package/src/__tests__/DateCellRenderer.test.tsx +0 -82
- package/src/__tests__/NumberCellRenderer.grouping.test.tsx +0 -146
- package/src/__tests__/NumberCellRenderer.test.tsx +0 -60
- package/src/__tests__/PercentCellRenderer.locale.test.tsx +0 -152
- package/src/__tests__/PercentCellRenderer.test.tsx +0 -115
- package/src/__tests__/boolean-label-association-e2e.test.tsx +0 -298
- package/src/__tests__/capability-multiselect-retired.test.ts +0 -109
- package/src/__tests__/cell-truncation.test.tsx +0 -96
- package/src/__tests__/composite-group-label-e2e.test.tsx +0 -436
- package/src/__tests__/composite-group-label-readonly-e2e.test.tsx +0 -403
- package/src/__tests__/date-formatter-residue-4272.test.ts +0 -120
- package/src/__tests__/date-locale-channel.test.tsx +0 -305
- package/src/__tests__/field-carrier-sdui.test.tsx +0 -169
- package/src/__tests__/formatCurrency.centsDigit.test.tsx +0 -158
- package/src/__tests__/formatCurrency.minorUnits.test.tsx +0 -221
- package/src/__tests__/group-labelling-declaration.test.ts +0 -148
- package/src/__tests__/lookupCellDisplayField.test.tsx +0 -107
- package/src/__tests__/lookupCellDisplayName.test.tsx +0 -119
- package/src/__tests__/lookupCellRecordLink.test.tsx +0 -171
- package/src/__tests__/lookupCellReferenceKey.test.tsx +0 -57
- package/src/__tests__/percent-cell-vs-measure-4576.test.ts +0 -115
- package/src/__tests__/percent-formatter-locale-4553.test.ts +0 -147
- package/src/__tests__/percent-tie-halfup-4590.test.ts +0 -224
- package/src/__tests__/registry-collision.test.ts +0 -91
- package/src/__tests__/resolveFieldCurrency.test.ts +0 -20
- package/src/__tests__/select-label-association-e2e.test.tsx +0 -199
- 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 -357
- 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 -924
- package/src/currency.ts +0 -144
- package/src/datetime-widgets.test.tsx +0 -185
- package/src/field-type-alias.multiple.test.ts +0 -81
- package/src/field-type-alias.ts +0 -156
- package/src/field-type-coverage.test.ts +0 -67
- package/src/index.css +0 -44
- package/src/index.tsx +0 -2745
- package/src/standard-widgets.test.tsx +0 -364
- package/src/widgets/AddressField.postalCode.test.tsx +0 -257
- package/src/widgets/AddressField.tsx +0 -182
- package/src/widgets/AddressField.uniqueIds.test.tsx +0 -93
- package/src/widgets/AutoNumberField.tsx +0 -18
- package/src/widgets/AvatarField.tsx +0 -117
- package/src/widgets/BooleanField.tsx +0 -86
- package/src/widgets/CapabilityMultiSelectField.test.tsx +0 -168
- package/src/widgets/CapabilityMultiSelectField.tsx +0 -241
- package/src/widgets/CharacterCount.tsx +0 -263
- package/src/widgets/CheckboxesField.cascade.test.tsx +0 -143
- package/src/widgets/CheckboxesField.tsx +0 -169
- package/src/widgets/CodeField.tsx +0 -41
- package/src/widgets/ColorField.tsx +0 -53
- package/src/widgets/CurrencyField.tsx +0 -135
- package/src/widgets/DateField.tsx +0 -40
- package/src/widgets/DateTimeField.tsx +0 -46
- package/src/widgets/EmailField.tsx +0 -37
- package/src/widgets/FileField.tsx +0 -512
- package/src/widgets/FilterConditionField.tsx +0 -454
- package/src/widgets/FormulaField.tsx +0 -38
- package/src/widgets/FullscreenFieldEditor.tsx +0 -60
- package/src/widgets/GeolocationField.tsx +0 -193
- package/src/widgets/GeolocationField.uniqueIds.test.tsx +0 -88
- package/src/widgets/GridField.test.tsx +0 -632
- package/src/widgets/GridField.tsx +0 -1070
- package/src/widgets/ImageCropperDialog.tsx +0 -245
- package/src/widgets/ImageField.maxSize.test.tsx +0 -154
- package/src/widgets/ImageField.tsx +0 -305
- 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 -1295
- 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 -196
- 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 -99
- 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 -143
- package/src/widgets/RatingField.tsx +0 -94
- package/src/widgets/RecipientPickerField.test.tsx +0 -157
- package/src/widgets/RecipientPickerField.tsx +0 -188
- package/src/widgets/RecordPickerDialog.baseFilterShapes.test.tsx +0 -191
- package/src/widgets/RecordPickerDialog.dateLocale.test.tsx +0 -124
- package/src/widgets/RecordPickerDialog.filterOptions.test.tsx +0 -611
- package/src/widgets/RecordPickerDialog.selectLabel.test.tsx +0 -112
- package/src/widgets/RecordPickerDialog.tsx +0 -1365
- package/src/widgets/RichTextField.tsx +0 -176
- package/src/widgets/SelectField.cascade.test.tsx +0 -138
- package/src/widgets/SelectField.tsx +0 -193
- 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 -59
- 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 -166
- 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/address-format.ts +0 -120
- package/src/widgets/deriveLookupColumns.test.ts +0 -112
- package/src/widgets/deriveLookupColumns.ts +0 -108
- package/src/widgets/file-size-guard.ts +0 -55
- package/src/widgets/file-value.test.ts +0 -230
- package/src/widgets/file-value.ts +0 -246
- package/src/widgets/nativeDateValue.test.ts +0 -115
- package/src/widgets/nativeDateValue.ts +0 -112
- package/src/widgets/openNativePicker.ts +0 -18
- package/src/widgets/optionWidgets.gatedOptions.test.tsx +0 -267
- package/src/widgets/optionWidgets.unconfiguredOptions.test.tsx +0 -150
- 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 -204
- package/src/widgets/toHostGroupProps.ts +0 -102
- package/src/widgets/types.ts +0 -242
- package/src/widgets/useCascadingOptions.ts +0 -46
- package/src/widgets/useFieldTranslation.ts +0 -132
- package/src/widgets/useRecordQuery.test.ts +0 -174
- package/src/widgets/useRecordQuery.ts +0 -291
- 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
|
* 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;
|
|
@@ -52,17 +52,37 @@ export type LegacyAddressValue = AddressValue & {
|
|
|
52
52
|
/** Postal code of a stored address, preferring the canonical key. */
|
|
53
53
|
export declare function readPostalCode(addr: AddressValue): string | undefined;
|
|
54
54
|
/**
|
|
55
|
-
* Formats a stored address as a single line
|
|
55
|
+
* Formats a stored address as a single line, in the part order the reader's
|
|
56
|
+
* locale writes addresses in.
|
|
56
57
|
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
* `
|
|
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 `", , ,"`.
|
|
62
78
|
*
|
|
63
79
|
* Returns `''` when no part is usable — callers decide what an empty address
|
|
64
80
|
* looks like (an `EmptyValue` placeholder for the cell renderer), and a value
|
|
65
81
|
* carrying no recognized part at all is NOT silently blanked: see
|
|
66
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.
|
|
67
87
|
*/
|
|
68
|
-
export declare function formatAddress(addr: AddressValue): string;
|
|
88
|
+
export declare function formatAddress(addr: AddressValue, locale?: string): string;
|
|
@@ -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,80 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { CellRendererProps } from '../index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Renders `markdown` values as formatted GFM markdown (lazy-loaded, sanitized)
|
|
5
|
+
* instead of the raw markup string.
|
|
6
|
+
*
|
|
7
|
+
* Markdown ONLY. `MarkdownContent` runs react-markdown with no `rehype-raw`, so
|
|
8
|
+
* raw HTML in the string is not parsed and never reaches the DOM — that is this
|
|
9
|
+
* renderer's trust boundary, not an oversight, and it must stay that way
|
|
10
|
+
* (objectui#5452). `richtext` used to be routed here too and rendered as a
|
|
11
|
+
* COMPLETELY EMPTY cell, because a richtext value is entirely HTML and this
|
|
12
|
+
* pipeline drops all of it; see {@link HtmlCellRenderer}, which is where that
|
|
13
|
+
* type belongs. Loosening this pipeline to pass raw HTML through would have
|
|
14
|
+
* "fixed" one type by moving every `markdown` cell's trust boundary.
|
|
15
|
+
*/
|
|
16
|
+
export declare function MarkdownCellRenderer({ value }: CellRendererProps): React.ReactElement;
|
|
17
|
+
/**
|
|
18
|
+
* Renders an `html` value as sanitized, formatted HTML instead of raw markup.
|
|
19
|
+
*
|
|
20
|
+
* Also the renderer for `richtext` (objectui#5452). Both types store an HTML
|
|
21
|
+
* string: the spec's `Field.richtext` is documented as "Formatted content with
|
|
22
|
+
* HTML/WYSIWYG", the showcase seed's own specimen is
|
|
23
|
+
* `<p>Rich <strong>text</strong></p>`, and this repo's designer bridge already
|
|
24
|
+
* maps `richtext` onto its `html` type. {@link sanitizeHtml} above removes
|
|
25
|
+
* script/style/iframe/object/embed blocks, inline event handlers and
|
|
26
|
+
* `javascript:` URLs, and touches nothing a rich-text editor legitimately
|
|
27
|
+
* emits — headings, paragraphs, emphasis, lists, links, quotes all survive, so
|
|
28
|
+
* routing `richtext` here restores the content rather than trading a blank cell
|
|
29
|
+
* for a mangled one.
|
|
30
|
+
*/
|
|
31
|
+
export declare function HtmlCellRenderer({ value }: CellRendererProps): React.ReactElement;
|
|
32
|
+
/**
|
|
33
|
+
* Field type → display pipeline, for the three types `RichTextField` serves.
|
|
34
|
+
*
|
|
35
|
+
* THE table, singular. `getCellRenderer`'s standard map spreads it (so the
|
|
36
|
+
* grid, kanban, gallery, related list, dashboard panel and detail read mode
|
|
37
|
+
* resolve through these entries) and `RichTextField`'s readonly branch indexes
|
|
38
|
+
* it (so a readonly form field renders through the very same component). A
|
|
39
|
+
* change here moves every read surface at once; there is no second copy left
|
|
40
|
+
* to forget.
|
|
41
|
+
*
|
|
42
|
+
* `richtext` reads through the HTML renderer — NOT the markdown one, which
|
|
43
|
+
* drops raw HTML and therefore rendered every populated richtext value as a
|
|
44
|
+
* blank cell (objectui#5452).
|
|
45
|
+
*/
|
|
46
|
+
export declare const RICH_TEXT_CELL_RENDERERS: {
|
|
47
|
+
readonly markdown: typeof MarkdownCellRenderer;
|
|
48
|
+
readonly html: typeof HtmlCellRenderer;
|
|
49
|
+
readonly richtext: typeof HtmlCellRenderer;
|
|
50
|
+
};
|
|
51
|
+
/** The rich-content field types, i.e. the keys of {@link RICH_TEXT_CELL_RENDERERS}. */
|
|
52
|
+
export type RichTextFieldType = keyof typeof RICH_TEXT_CELL_RENDERERS;
|
|
53
|
+
/**
|
|
54
|
+
* The SYNTAX a rich-content type stores, derived from the renderer that type
|
|
55
|
+
* resolves to rather than declared a second time.
|
|
56
|
+
*
|
|
57
|
+
* This is what `RichTextField`'s editor header names ("Format: markdown"), and
|
|
58
|
+
* deriving it from {@link RICH_TEXT_CELL_RENDERERS} is the point: the header
|
|
59
|
+
* used to be computed as `field.format || 'markdown'`, and since `format` is
|
|
60
|
+
* declared on no rich-content field type (only on `date`/`datetime`/`time`/
|
|
61
|
+
* `phone`/`auto_number`), it read `undefined` for every real field and labelled
|
|
62
|
+
* an `html` field "Format: markdown" — a label pointing at a pipeline the value
|
|
63
|
+
* does not go through. Derived, the label cannot disagree with the renderer.
|
|
64
|
+
*
|
|
65
|
+
* `undefined` for a type with no pipeline, rather than a guessed default: the
|
|
66
|
+
* caller has to say what it does with "not a rich-content type" instead of
|
|
67
|
+
* silently getting the markdown answer, which is the bug this replaces.
|
|
68
|
+
*/
|
|
69
|
+
export declare function richTextSyntax(fieldType: string): 'markdown' | 'html' | undefined;
|
|
70
|
+
/**
|
|
71
|
+
* The display pipeline a field type reads through, or `undefined` when the
|
|
72
|
+
* type is not one of the three rich-content types.
|
|
73
|
+
*
|
|
74
|
+
* The lookup is a function rather than a raw index so the "not a rich-content
|
|
75
|
+
* type" answer is in the RETURN TYPE. Indexing {@link RICH_TEXT_CELL_RENDERERS}
|
|
76
|
+
* directly hands back a non-optional component for any key the caller casts,
|
|
77
|
+
* so the miss becomes a runtime `undefined` the compiler has been told cannot
|
|
78
|
+
* happen — and a caller that checks for it reads as dead code.
|
|
79
|
+
*/
|
|
80
|
+
export declare function richTextCellRenderer(fieldType: string): React.FC<CellRendererProps> | undefined;
|
|
@@ -7,19 +7,21 @@
|
|
|
7
7
|
*/
|
|
8
8
|
/**
|
|
9
9
|
* The props that make a group-labelled widget's rendered surface the thing its
|
|
10
|
-
* host label actually NAMES,
|
|
11
|
-
* (objectui#3990).
|
|
10
|
+
* host label actually NAMES — and, where nothing else can carry it, DESCRIBES
|
|
11
|
+
* (objectui#3990, objectui#4005).
|
|
12
12
|
*
|
|
13
13
|
* ## What it is for
|
|
14
14
|
*
|
|
15
15
|
* A widget declared `labelling: 'group'` (objectui#3961) is told by the form
|
|
16
16
|
* renderer: your label publishes an `id` and drops its `for`, so name yourself
|
|
17
|
-
* by IDREF. The renderer hands down
|
|
18
|
-
* a WHOLE:
|
|
17
|
+
* by IDREF. The renderer hands down facts that address the field as a WHOLE:
|
|
19
18
|
*
|
|
20
19
|
* - `id` — the host's control id (`…-form-item`), the id the label's `for`
|
|
21
20
|
* used to point at;
|
|
22
|
-
* - `aria-labelledby` — the IDREF of that visible label
|
|
21
|
+
* - `aria-labelledby` — the IDREF of that visible label;
|
|
22
|
+
* - `aria-describedby` — the IDREF of `<FormDescription>`, the field's visible
|
|
23
|
+
* help text. Which surface may consume it is the one thing that is NOT
|
|
24
|
+
* uniform, so it is decided per call site — see {@link HostGroupSurface}.
|
|
23
25
|
*
|
|
24
26
|
* Every editable branch already consumes them inside its wider `toDomProps`
|
|
25
27
|
* spread. The branches that returned EARLY did not — a field-level
|
|
@@ -39,19 +41,66 @@
|
|
|
39
41
|
* to nothing can at least be swept for, while "a label published an id and
|
|
40
42
|
* nobody consumed it" looks like healthy markup.
|
|
41
43
|
*
|
|
42
|
-
* ##
|
|
44
|
+
* ## The description was the other half of the same defect (objectui#4005)
|
|
43
45
|
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
46
|
+
* #3990 landed the `id` + `aria-labelledby` pair above and deliberately stopped
|
|
47
|
+
* there. The reasoning it recorded — a readonly display has no focusable
|
|
48
|
+
* control, and `aria-describedby` is announced when focus lands on something
|
|
49
|
+
* focusable — was the right call for the surface as it stood THEN: before this
|
|
50
|
+
* helper existed, a readonly branch had no role at all, and on a role-less
|
|
51
|
+
* `div` / `span` an `aria-describedby` is as inert as the `aria-labelledby`
|
|
52
|
+
* was. That premise expired the moment #3990 gave those surfaces
|
|
53
|
+
* `role="group"`. A group IS a description carrier under ARIA 1.2: assistive
|
|
54
|
+
* technology announces a group's name and description on entering it, with no
|
|
55
|
+
* focusable control required. So the help text stayed measurably unreachable
|
|
56
|
+
* for exactly as long as it took to have somewhere to put it. Measured on
|
|
57
|
+
* `origin/main` at `c25222758`, a real form, one field per row, counting the
|
|
58
|
+
* elements whose `aria-describedby` names the rendered `<FormDescription>`:
|
|
53
59
|
*
|
|
54
|
-
*
|
|
60
|
+
* ```
|
|
61
|
+
* descEl consumers consumerTags
|
|
62
|
+
* address editable desc=YES SET 1 [input]
|
|
63
|
+
* address readonly desc=YES SET 0 []
|
|
64
|
+
* geolocation editable desc=YES SET 1 [input]
|
|
65
|
+
* geolocation readonly desc=YES SET 0 []
|
|
66
|
+
* checkboxes editable desc=YES SET 1 [div[group]]
|
|
67
|
+
* checkboxes readonly desc=YES SET 0 []
|
|
68
|
+
* radio editable desc=YES SET 1 [div[radiogroup]]
|
|
69
|
+
* radio readonly desc=YES SET 0 []
|
|
70
|
+
* rating editable desc=YES SET 1 [div[group]]
|
|
71
|
+
* rating readonly desc=YES SET 0 []
|
|
72
|
+
* file editable desc=YES SET 1 [div[button]]
|
|
73
|
+
* file readonly desc=YES SET 0 []
|
|
74
|
+
* multiselect editable desc=YES SET 1 [div[group]]
|
|
75
|
+
* multiselect readonly desc=YES SET 0 []
|
|
76
|
+
* ```
|
|
77
|
+
*
|
|
78
|
+
* All seven render the `<FormDescription>` in the readonly state — none is
|
|
79
|
+
* exempt for want of one — and all seven left it referenced by nothing.
|
|
80
|
+
*
|
|
81
|
+
* ## What still does NOT come along, and why that is a boundary and not an oversight
|
|
82
|
+
*
|
|
83
|
+
* `aria-invalid` and `aria-required` are CONTROL-channel state: they report
|
|
84
|
+
* what a user's own editing may do wrong, to the element they would edit. A
|
|
85
|
+
* readonly display cannot be edited and cannot be made invalid by the person
|
|
86
|
+
* reading it, so putting either on it announces a state that has no action
|
|
87
|
+
* behind it. Spreading the whole `toDomProps` result would drag both back —
|
|
88
|
+
* along with `disabled` / `tabIndex` / the focus handlers, which only mean
|
|
89
|
+
* something on an interactive element, and `name`, which is DOM-legal on form
|
|
90
|
+
* controls only and on a `div` is exactly the leak objectui#3291 sweeps for.
|
|
91
|
+
* That is what objectui#3291 and objectui#3318 drew the line against, and
|
|
92
|
+
* adding the description does not move it: the description is what the FIELD
|
|
93
|
+
* is, the other two are what the CONTROL is doing. The line is pinned from both
|
|
94
|
+
* sides in `composite-group-label-readonly-e2e.test.tsx` — the description must
|
|
95
|
+
* be there, `aria-invalid` / `aria-required` must not — so neither a later
|
|
96
|
+
* "spread it all" nor a later "take it all back out" can pass quietly.
|
|
97
|
+
*
|
|
98
|
+
* Spreading the full result would also put the host's `className` on top of the
|
|
99
|
+
* widget's own, because the widgets whose readonly surface is a placeholder or
|
|
100
|
+
* a plain container (`EmptyValue`, `FileField`, `AddressField`) keep
|
|
101
|
+
* `className` inside `props`.
|
|
102
|
+
*
|
|
103
|
+
* ## Why `role` travels with the keys
|
|
55
104
|
*
|
|
56
105
|
* `aria-labelledby` on a role-less `div` / `span` names NOTHING — `generic`
|
|
57
106
|
* prohibits an author name — so the pair is inert without a role that supports
|
|
@@ -73,19 +122,68 @@ export interface HostGroupProps {
|
|
|
73
122
|
id?: string;
|
|
74
123
|
/** IDREF of the host's visible label. */
|
|
75
124
|
'aria-labelledby'?: string;
|
|
125
|
+
/**
|
|
126
|
+
* IDREF of the host's visible help text — present only on a surface that
|
|
127
|
+
* renders no input of the field's own. See {@link HostGroupSurface}.
|
|
128
|
+
*/
|
|
129
|
+
'aria-describedby'?: string;
|
|
76
130
|
/** `'group'` when — and only when — a host named this surface. */
|
|
77
131
|
role?: 'group';
|
|
78
132
|
}
|
|
79
133
|
/**
|
|
80
|
-
*
|
|
81
|
-
*
|
|
134
|
+
* WHERE the surface being named sits relative to the field's own inputs. The
|
|
135
|
+
* name is uniform; the DESCRIPTION is not, so every call site has to say which
|
|
136
|
+
* of the two shapes it is, and the compiler makes the next widget author say it
|
|
137
|
+
* too rather than inherit whichever default happened to be there.
|
|
138
|
+
*
|
|
139
|
+
* - `'above-the-inputs'` — a composite's EDITABLE container (`address`,
|
|
140
|
+
* `geolocation`): the field's real inputs are inside it and each already
|
|
141
|
+
* receives `aria-describedby` in its own `toDomProps` spread, straight from
|
|
142
|
+
* `<FormControl>`'s Slot. This surface therefore takes the NAME only.
|
|
143
|
+
* objectui#3318 chose that split deliberately and
|
|
144
|
+
* `composite-group-label-e2e.test.tsx` pins it: the help text is announced
|
|
145
|
+
* when focus reaches the box the user types into, and announcing it a second
|
|
146
|
+
* time on the container that merely wraps those boxes is a double channel of
|
|
147
|
+
* exactly the kind objectui#3290 removed from the required marker.
|
|
148
|
+
*
|
|
149
|
+
* - `'instead-of-the-inputs'` — every readonly branch, and the zero-option box
|
|
150
|
+
* (`OptionsEmptyState`). The field renders no input at all here, so no
|
|
151
|
+
* element inside can carry the description and this surface is the only
|
|
152
|
+
* candidate there is. It takes the name AND the description.
|
|
153
|
+
*
|
|
154
|
+
* Note what the discriminator is NOT about: whether the surface contains
|
|
155
|
+
* anything focusable. `geolocation`'s readonly row holds a "View on map" link
|
|
156
|
+
* — focusable, and correctly announced as itself. It is not an input OF THE
|
|
157
|
+
* FIELD and never receives the field's `aria-describedby`, so that row is still
|
|
158
|
+
* `'instead-of-the-inputs'`.
|
|
159
|
+
*/
|
|
160
|
+
export type HostGroupSurface = 'above-the-inputs' | 'instead-of-the-inputs';
|
|
161
|
+
/**
|
|
162
|
+
* Read the whole-field keys out of a widget's leftover props, plus the role
|
|
163
|
+
* that makes them mean something. See {@link HostGroupProps} and
|
|
164
|
+
* {@link HostGroupSurface}.
|
|
82
165
|
*
|
|
83
166
|
* Routed through {@link toDomProps} rather than reading `props` directly so the
|
|
84
|
-
*
|
|
85
|
-
* whitelist still forwards them, and its
|
|
167
|
+
* keys keep ONE gate: they reach an element only if the DOM pass-through
|
|
168
|
+
* whitelist still forwards them, and its compile-time assertions bind that
|
|
86
169
|
* whitelist to the props contract in both directions.
|
|
170
|
+
*
|
|
171
|
+
* `aria-describedby` is forwarded exactly as the host handed it down, with no
|
|
172
|
+
* check that it resolves — a widget cannot see whether `<FormDescription>`
|
|
173
|
+
* rendered, and a DOM probe for it would be a layout-effect hack around the
|
|
174
|
+
* renderer's own knowledge. That is not a new gap: `<FormControl>`'s Slot emits
|
|
175
|
+
* the IDREF unconditionally, so a field with NO description already hands every
|
|
176
|
+
* editable control an `aria-describedby` pointing at an element that does not
|
|
177
|
+
* exist. Measured on `origin/main` at `c25222758`, `desc=NO`: all seven
|
|
178
|
+
* group-labelled widgets plus the builtin `input` and the single-control
|
|
179
|
+
* `email` carry exactly one such reference, on the same element that would
|
|
180
|
+
* carry a resolving one. A readonly surface answering identically is parity
|
|
181
|
+
* with the editable branch, not a class of its own — and an IDREF that resolves
|
|
182
|
+
* to nothing is inert for assistive technology, where an unconsumed
|
|
183
|
+
* description is simply lost.
|
|
87
184
|
*/
|
|
88
185
|
export declare function toHostGroupProps(props: {
|
|
89
186
|
id?: string;
|
|
90
187
|
'aria-labelledby'?: string;
|
|
91
|
-
|
|
188
|
+
'aria-describedby'?: string;
|
|
189
|
+
}, surface: HostGroupSurface): HostGroupProps;
|
package/dist/widgets/types.d.ts
CHANGED
|
@@ -157,9 +157,14 @@ export type FieldWidgetComponentProps<T = any> = {
|
|
|
157
157
|
onUploadingChange?: (uploading: boolean) => void;
|
|
158
158
|
/**
|
|
159
159
|
* DataSource for widgets that query records (lookup / user / object-ref /
|
|
160
|
-
* recipient-picker
|
|
161
|
-
*
|
|
162
|
-
*
|
|
160
|
+
* recipient-picker). Injected by the form renderer for the field types that
|
|
161
|
+
* need it, and passed directly by inline-edit hosts. Option widgets
|
|
162
|
+
* destructure it purely to keep it off their DOM spread.
|
|
163
|
+
*
|
|
164
|
+
* `grid` was listed here with zero consumers (objectui#4814): `GridField.tsx`
|
|
165
|
+
* never reads `dataSource`, and no data-source table has ever contained the
|
|
166
|
+
* key, so the claim described a wiring that did not exist. `owner` is absent
|
|
167
|
+
* for a different reason — the spelling itself is retired (same card).
|
|
163
168
|
*
|
|
164
169
|
* Left structural (`unknown`): `@object-ui/fields` must not depend on a
|
|
165
170
|
* concrete adapter — every consumer narrows it itself.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@object-ui/fields",
|
|
3
|
-
"version": "17.
|
|
3
|
+
"version": "17.6.0",
|
|
4
4
|
"description": "Field renderers and registry for Object UI",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -18,25 +18,24 @@
|
|
|
18
18
|
},
|
|
19
19
|
"files": [
|
|
20
20
|
"dist",
|
|
21
|
-
"src",
|
|
22
21
|
"README.md",
|
|
23
22
|
"CHANGELOG.md",
|
|
24
23
|
"LICENSE"
|
|
25
24
|
],
|
|
26
25
|
"dependencies": {
|
|
27
|
-
"@objectstack/spec": "^17.0.0
|
|
26
|
+
"@objectstack/spec": "^17.0.0",
|
|
28
27
|
"clsx": "^2.1.1",
|
|
29
|
-
"lucide-react": "^1.
|
|
28
|
+
"lucide-react": "^1.31.0",
|
|
30
29
|
"react-markdown": "^10.1.0",
|
|
31
30
|
"rehype-sanitize": "^6.0.0",
|
|
32
31
|
"remark-gfm": "^4.0.1",
|
|
33
32
|
"tailwind-merge": "^3.6.0",
|
|
34
|
-
"@object-ui/components": "17.
|
|
35
|
-
"@object-ui/core": "17.
|
|
36
|
-
"@object-ui/i18n": "17.
|
|
37
|
-
"@object-ui/providers": "17.
|
|
38
|
-
"@object-ui/react": "17.
|
|
39
|
-
"@object-ui/types": "17.
|
|
33
|
+
"@object-ui/components": "17.6.0",
|
|
34
|
+
"@object-ui/core": "17.6.0",
|
|
35
|
+
"@object-ui/i18n": "17.6.0",
|
|
36
|
+
"@object-ui/providers": "17.6.0",
|
|
37
|
+
"@object-ui/react": "17.6.0",
|
|
38
|
+
"@object-ui/types": "17.6.0"
|
|
40
39
|
},
|
|
41
40
|
"peerDependencies": {
|
|
42
41
|
"react": "^18.0.0 || ^19.0.0",
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { default as React } from 'react';
|
|
2
|
-
export interface CharacterCountProps {
|
|
3
|
-
/**
|
|
4
|
-
* Length of the text this surface is counting. The inline surface passes the
|
|
5
|
-
* committed value's length; the fullscreen dialog passes the DRAFT's, which
|
|
6
|
-
* is the number that is true of what the user is looking at.
|
|
7
|
-
*/
|
|
8
|
-
length: number;
|
|
9
|
-
/**
|
|
10
|
-
* The declared cap. Callers render this component only when the field
|
|
11
|
-
* declares one, so it is non-optional here — a counter with no cap to count
|
|
12
|
-
* against has nothing to say and must not be mounted at all (an unconditional
|
|
13
|
-
* live region in every long-text field is the objectui#3408 defect back
|
|
14
|
-
* again).
|
|
15
|
-
*/
|
|
16
|
-
maxLength: number;
|
|
17
|
-
/**
|
|
18
|
-
* The description node's `id`, minted by the host from `useId()`.
|
|
19
|
-
*
|
|
20
|
-
* The host MUST also name it in the edited control's `aria-describedby` —
|
|
21
|
-
* this component renders the sentence, only the host knows which element is
|
|
22
|
-
* being described, and a description nothing references is a node no screen
|
|
23
|
-
* reader will ever reach. That association is asserted from the OUTSIDE (the
|
|
24
|
-
* tests resolve `aria-describedby` and concatenate the referenced nodes' text,
|
|
25
|
-
* exactly as an assistive technology does) rather than trusted here.
|
|
26
|
-
*
|
|
27
|
-
* Two surfaces of one widget therefore need two ids: the dialog's draft and
|
|
28
|
-
* the inline value diverge the moment the user types in the dialog, so one
|
|
29
|
-
* shared id would point both controls at whichever sentence rendered last.
|
|
30
|
-
*/
|
|
31
|
-
descriptionId: string;
|
|
32
|
-
/**
|
|
33
|
-
* Render node 3, the threshold-gated debounced `aria-live` status region.
|
|
34
|
-
*
|
|
35
|
-
* Required on purpose — see the component doc above. `false` removes the
|
|
36
|
-
* region from the DOM entirely (not merely empties it), which is the only
|
|
37
|
-
* form of "no live region" a test can tell apart from "a live region that
|
|
38
|
-
* happens to be silent right now".
|
|
39
|
-
*/
|
|
40
|
-
announceNearLimit: boolean;
|
|
41
|
-
/**
|
|
42
|
-
* Classes for the visible digits. Required because placement is entirely the
|
|
43
|
-
* surface's business — inline pins them to the textarea's bottom-right
|
|
44
|
-
* corner, the dialog lays them out as a footer item — and a default borrowed
|
|
45
|
-
* from either one would position the other wrongly while looking deliberate.
|
|
46
|
-
*/
|
|
47
|
-
className: string;
|
|
48
|
-
/**
|
|
49
|
-
* `data-testid` for the visible digits, namespaced per surface
|
|
50
|
-
* (`textarea-character-count`, `textarea-fullscreen-character-count`) so a
|
|
51
|
-
* test that finds digits can say WHICH surface it found them on. Same
|
|
52
|
-
* convention, same reason, as `FullscreenFieldEditor`'s `testIdPrefix`.
|
|
53
|
-
*/
|
|
54
|
-
testId: string;
|
|
55
|
-
}
|
|
56
|
-
export declare function CharacterCount({ length, maxLength, descriptionId, announceNearLimit, className, testId, }: CharacterCountProps): React.JSX.Element;
|