@object-ui/fields 17.6.0 → 17.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5436 -0
- package/README.md +108 -8
- package/dist/FieldEditWidget.d.ts +54 -6
- package/dist/coerceToSafeValue.d.ts +54 -0
- package/dist/currency.d.ts +1 -1
- package/dist/index.cjs +5 -5
- package/dist/index.css +26 -2
- package/dist/index.d.ts +229 -57
- package/dist/index.js +3811 -3009
- package/dist/widgets/AvatarField.d.ts +19 -3
- package/dist/widgets/BooleanField.d.ts +1 -1
- package/dist/widgets/DateField.d.ts +1 -1
- package/dist/widgets/DateTimeField.d.ts +1 -1
- package/dist/widgets/FilterConditionField.d.ts +21 -7
- package/dist/widgets/GeolocationField.d.ts +9 -3
- package/dist/widgets/GridField.d.ts +63 -99
- package/dist/widgets/LocationField.d.ts +30 -3
- package/dist/widgets/LookupField.d.ts +8 -0
- package/dist/widgets/NumberField.d.ts +1 -1
- package/dist/widgets/ObjectField.d.ts +9 -2
- package/dist/widgets/OptionsEmptyState.d.ts +29 -5
- package/dist/widgets/PasswordField.d.ts +14 -0
- package/dist/widgets/PeoplePicker.d.ts +17 -2
- package/dist/widgets/PercentField.d.ts +2 -1
- package/dist/widgets/PersonRow.d.ts +13 -2
- package/dist/widgets/RecipientPickerField.d.ts +43 -0
- package/dist/widgets/RecordPickerDialog.d.ts +31 -12
- package/dist/widgets/RichTextField.d.ts +1 -1
- package/dist/widgets/SelectionTray.d.ts +13 -2
- package/dist/widgets/TextField.d.ts +1 -1
- package/dist/widgets/TimeField.d.ts +1 -1
- package/dist/widgets/file-affordance.d.ts +33 -0
- package/dist/widgets/file-size-guard.d.ts +5 -23
- package/dist/widgets/file-value.d.ts +38 -9
- package/dist/widgets/lookupColumnDisplay.d.ts +24 -7
- package/dist/widgets/nativeDateValue.d.ts +9 -27
- package/dist/widgets/number-format.d.ts +137 -0
- package/dist/widgets/numberBadInput.d.ts +135 -0
- package/dist/widgets/personDisplay.d.ts +22 -4
- package/dist/widgets/richTextDisplay.d.ts +36 -0
- package/dist/widgets/toDomProps.d.ts +10 -1
- package/dist/widgets/toHostGroupProps.d.ts +53 -0
- package/dist/widgets/toHostProps.d.ts +105 -0
- package/dist/widgets/types.d.ts +11 -3
- package/dist/widgets/upload-error-message.d.ts +6 -0
- package/dist/widgets/uploadingScope.d.ts +142 -0
- package/dist/widgets/useCascadingOptions.d.ts +3 -2
- package/dist/widgets/useRecordQuery.d.ts +4 -2
- package/dist/widgets/useUploadingSignal.d.ts +8 -0
- package/package.json +11 -12
package/dist/index.css
CHANGED
|
@@ -104,6 +104,9 @@
|
|
|
104
104
|
.min-w-\[20px\] {
|
|
105
105
|
min-width: 20px;
|
|
106
106
|
}
|
|
107
|
+
.shrink {
|
|
108
|
+
flex-shrink: 1;
|
|
109
|
+
}
|
|
107
110
|
.basis-\[9rem\] {
|
|
108
111
|
flex-basis: 9rem;
|
|
109
112
|
}
|
|
@@ -127,6 +130,9 @@
|
|
|
127
130
|
.gap-y-1 {
|
|
128
131
|
row-gap: var(--spacing, 0.25rem);
|
|
129
132
|
}
|
|
133
|
+
.rounded-\[2px\] {
|
|
134
|
+
border-radius: 2px;
|
|
135
|
+
}
|
|
130
136
|
.border-\[color\:var\(--os-badge-border\)\] {
|
|
131
137
|
border-color: var(--os-badge-border);
|
|
132
138
|
}
|
|
@@ -178,6 +184,9 @@
|
|
|
178
184
|
.border-purple-200 {
|
|
179
185
|
border-color: var(--color-purple-200, oklch(90.2% 0.063 306.703));
|
|
180
186
|
}
|
|
187
|
+
.border-red-200 {
|
|
188
|
+
border-color: var(--color-red-200, oklch(88.5% 0.062 18.334));
|
|
189
|
+
}
|
|
181
190
|
.border-red-500 {
|
|
182
191
|
border-color: var(--color-red-500, oklch(63.7% 0.237 25.331));
|
|
183
192
|
}
|
|
@@ -214,12 +223,21 @@
|
|
|
214
223
|
background-color: color-mix(in oklab, var(--color-black, #000) 50%, transparent);
|
|
215
224
|
}
|
|
216
225
|
}
|
|
226
|
+
.bg-blue-50 {
|
|
227
|
+
background-color: var(--color-blue-50, oklch(97% 0.014 254.604));
|
|
228
|
+
}
|
|
229
|
+
.bg-blue-500 {
|
|
230
|
+
background-color: var(--color-blue-500, oklch(62.3% 0.214 259.815));
|
|
231
|
+
}
|
|
217
232
|
.bg-destructive\/5 {
|
|
218
233
|
background-color: color-mix(in srgb, hsl(var(--destructive)) 5%, transparent);
|
|
219
234
|
@supports (color: color-mix(in lab, red, red)) {
|
|
220
235
|
background-color: color-mix(in oklab, var(--color-destructive, hsl(var(--destructive))) 5%, transparent);
|
|
221
236
|
}
|
|
222
237
|
}
|
|
238
|
+
.bg-gray-50 {
|
|
239
|
+
background-color: var(--color-gray-50, oklch(98.5% 0.002 247.839));
|
|
240
|
+
}
|
|
223
241
|
.bg-gray-200 {
|
|
224
242
|
background-color: var(--color-gray-200, oklch(92.8% 0.006 264.531));
|
|
225
243
|
}
|
|
@@ -280,12 +298,15 @@
|
|
|
280
298
|
.px-px {
|
|
281
299
|
padding-inline: 1px;
|
|
282
300
|
}
|
|
283
|
-
.
|
|
284
|
-
padding-
|
|
301
|
+
.pt-3 {
|
|
302
|
+
padding-top: calc(var(--spacing, 0.25rem) * 3);
|
|
285
303
|
}
|
|
286
304
|
.pr-1\.5 {
|
|
287
305
|
padding-right: calc(var(--spacing, 0.25rem) * 1.5);
|
|
288
306
|
}
|
|
307
|
+
.pr-8 {
|
|
308
|
+
padding-right: calc(var(--spacing, 0.25rem) * 8);
|
|
309
|
+
}
|
|
289
310
|
.pl-0\.5 {
|
|
290
311
|
padding-left: calc(var(--spacing, 0.25rem) * 0.5);
|
|
291
312
|
}
|
|
@@ -331,6 +352,9 @@
|
|
|
331
352
|
.text-red-600 {
|
|
332
353
|
color: var(--color-red-600, oklch(57.7% 0.245 27.325));
|
|
333
354
|
}
|
|
355
|
+
.text-white {
|
|
356
|
+
color: var(--color-white, #fff);
|
|
357
|
+
}
|
|
334
358
|
.text-yellow-800 {
|
|
335
359
|
color: var(--color-yellow-800, oklch(47.6% 0.114 61.907));
|
|
336
360
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
2
|
import { FieldMetadata } from '@object-ui/types';
|
|
3
|
-
import { humanizeLabel, ComponentMeta } from '@object-ui/core';
|
|
3
|
+
import { PercentScale, humanizeLabel, formatDate, formatDateTime, formatDateTimeCompactParts, formatRelativeDate, ComponentMeta, DateDisplayOptions } from '@object-ui/core';
|
|
4
|
+
import { formatCurrency, percentCellScale } from './widgets/number-format.js';
|
|
5
|
+
import { coerceToSafeValue } from './coerceToSafeValue.js';
|
|
4
6
|
import { resolveFieldCurrency } from './currency.js';
|
|
5
7
|
/**
|
|
6
8
|
* Pick the most reasonable display name from an arbitrary record object.
|
|
@@ -9,8 +11,18 @@ import { resolveFieldCurrency } from './currency.js';
|
|
|
9
11
|
export declare function pickRecordDisplayName(record: Record<string, unknown> | null | undefined, preferredField?: string): string | undefined;
|
|
10
12
|
/**
|
|
11
13
|
* Heuristic: detect strings that look like opaque foreign-key IDs (e.g. nanoid
|
|
12
|
-
* or BSON ObjectId).
|
|
13
|
-
*
|
|
14
|
+
* or BSON ObjectId).
|
|
15
|
+
*
|
|
16
|
+
* ⛔ Nothing in this repo calls it any more, and re-introducing a caller that
|
|
17
|
+
* decides PRESENTATION from it would re-open objectui#8695. It used to gate
|
|
18
|
+
* `LookupCellRenderer`'s muted `—`, i.e. it decided how an unresolved
|
|
19
|
+
* reference was drawn from the SHAPE of the string rather than from whether
|
|
20
|
+
* anything resolved — so `'Ada Lovelace'` printed as a confident name and an
|
|
21
|
+
* opaque id lost its value, two opposite answers to one epistemic state. The
|
|
22
|
+
* export is kept because it is part of this package's published surface and
|
|
23
|
+
* retiring it is a breaking change no display card is entitled to make; the
|
|
24
|
+
* shape question itself is legitimate (a picker filter, an id-vs-name guess),
|
|
25
|
+
* it is only an answer to "what did this screen resolve?" that it can never be.
|
|
14
26
|
*/
|
|
15
27
|
export declare function isLikelyOpaqueId(v: unknown): boolean;
|
|
16
28
|
/**
|
|
@@ -22,15 +34,18 @@ export interface CellRendererProps {
|
|
|
22
34
|
isEditing?: boolean;
|
|
23
35
|
onChange?: (value: any) => void;
|
|
24
36
|
}
|
|
37
|
+
export { coerceToSafeValue };
|
|
38
|
+
export { resolveFieldCurrency };
|
|
25
39
|
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
40
|
+
* `formatCurrency` lives beside `formatNumberFieldValue` in
|
|
41
|
+
* `./widgets/number-format.ts`, re-exported here under its long-standing
|
|
42
|
+
* `@object-ui/fields` name: `CurrencyField`'s read-only branch calls the same
|
|
43
|
+
* function `CurrencyCellRenderer` below calls, and the lazily loaded widget
|
|
44
|
+
* cannot import this barrel (objectui#11444). The width (the currency's ISO
|
|
45
|
+
* 4217 minor-unit count, every amount, no whole-amount trimming) and its
|
|
46
|
+
* history are documented there.
|
|
30
47
|
*/
|
|
31
|
-
export
|
|
32
|
-
export { resolveFieldCurrency };
|
|
33
|
-
export declare function formatCurrency(value: number, currency?: string, locale?: string): string;
|
|
48
|
+
export { formatCurrency };
|
|
34
49
|
/**
|
|
35
50
|
* Format currency value in compact form for mobile display.
|
|
36
51
|
* E.g., $150,000 → $150K, $1,200,000 → $1.2M
|
|
@@ -38,18 +53,36 @@ export declare function formatCurrency(value: number, currency?: string, locale?
|
|
|
38
53
|
*/
|
|
39
54
|
export declare function formatCompactCurrency(value: number, currency?: string, locale?: string): string;
|
|
40
55
|
/**
|
|
41
|
-
* Format a plain number with thousands separators, no
|
|
42
|
-
*
|
|
43
|
-
*
|
|
56
|
+
* Format a plain number with thousands separators at a fixed display width, no
|
|
57
|
+
* currency symbol. `formatCurrency` renders an amount with no currency resolved
|
|
58
|
+
* through the same call shape (`./widgets/number-format.ts`): we'd rather
|
|
59
|
+
* render `1,234.50` than silently assume USD.
|
|
44
60
|
*/
|
|
45
61
|
export declare function formatNumber(value: number, decimals?: number, locale?: string): string;
|
|
46
62
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
63
|
+
* `percentCellScale` lives beside `formatPercentPoints` in
|
|
64
|
+
* `./widgets/number-format.ts` and is re-exported here: the storage scale the
|
|
65
|
+
* percent cell reads a field at, so every face rendering the cell's number for
|
|
66
|
+
* the same field reads the same answer by reference (objectui#11475).
|
|
67
|
+
*/
|
|
68
|
+
export { percentCellScale };
|
|
69
|
+
/**
|
|
70
|
+
* Format a stored percentage at the storage the caller STATES.
|
|
49
71
|
*
|
|
50
|
-
* `
|
|
51
|
-
*
|
|
52
|
-
*
|
|
72
|
+
* `percentScale` is REQUIRED (objectui#11475): `'fraction'` (0.8 means 80%) or
|
|
73
|
+
* `'whole'` (80 means 80%), the spec's `PercentScale`. A face holding a field
|
|
74
|
+
* reads it with {@link percentCellScale} (the spec's `percentScaleOf`, a
|
|
75
|
+
* fraction unless the field declares a `max` above 1); a face without one
|
|
76
|
+
* states what it knows. A value outside the union throws. This used to guess
|
|
77
|
+
* from the value's magnitude (`percentDisplayValue`'s old body), so a
|
|
78
|
+
* fraction-stored `1` read `1%` here and `100%` in the read-only form.
|
|
79
|
+
*
|
|
80
|
+
* FROM `formatPercent(value, precision, locale)` TO
|
|
81
|
+
* `formatPercent(value, percentScale, precision, locale)`.
|
|
82
|
+
*
|
|
83
|
+
* `locale` is the last positional parameter, matching {@link formatNumber} and
|
|
84
|
+
* {@link formatCurrency}. Callers should pass the tag from
|
|
85
|
+
* `useDisplayLocale()`.
|
|
53
86
|
*
|
|
54
87
|
* Before objectui#4553 this function took no locale and never touched `Intl`:
|
|
55
88
|
* its whole body was `${percentDisplayValue(value).toFixed(precision)}%`, so it
|
|
@@ -59,7 +92,7 @@ export declare function formatNumber(value: number, decimals?: number, locale?:
|
|
|
59
92
|
* so the grouping and the locale are fixed together: en output MOVES from
|
|
60
93
|
* `1235%` to `1,235%` at four digits and up, and that move is the fix.
|
|
61
94
|
*/
|
|
62
|
-
export declare function formatPercent(value: number, precision?: number, locale?: string): string;
|
|
95
|
+
export declare function formatPercent(value: number, percentScale: PercentScale, precision?: number, locale?: string): string;
|
|
63
96
|
/**
|
|
64
97
|
* Humanize a snake_case or kebab-case string into Title Case — the fallback
|
|
65
98
|
* label when no explicit `option.label` exists.
|
|
@@ -76,41 +109,20 @@ export declare function formatPercent(value: number, precision?: number, locale?
|
|
|
76
109
|
* `humanizeFieldKey`'s camelCase-splitting KEY convention.
|
|
77
110
|
*/
|
|
78
111
|
export { humanizeLabel };
|
|
79
|
-
/** Options shared by {@link formatDate} / {@link formatRelativeDate}. */
|
|
80
|
-
export interface DateDisplayOptions {
|
|
81
|
-
dueLike?: boolean;
|
|
82
|
-
/** BCP-47 display locale (ADR-0053 tenant default); falls back to the runtime locale. */
|
|
83
|
-
locale?: string;
|
|
84
|
-
/** i18n translate fn for phrases `Intl` can't produce (the "Overdue Nd" wording). */
|
|
85
|
-
t?: (key: string, params?: Record<string, unknown>) => string;
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Format date as relative time (e.g., "3 days ago", "Today", "Overdue 3d"),
|
|
89
|
-
* localized via `Intl.RelativeTimeFormat` (objectstack-ai/objectstack#3040).
|
|
90
|
-
*
|
|
91
|
-
* `dueLike` gates the "Overdue" wording — a past `start_date`/`created_at`
|
|
92
|
-
* isn't overdue, only a past due/deadline-semantic field is. Non-due-like
|
|
93
|
-
* past dates render as plain "N days ago" instead. The overdue phrase has no
|
|
94
|
-
* `Intl` equivalent, so it resolves through `options.t` (key
|
|
95
|
-
* `fields.relativeDate.overdue`) with an English fallback.
|
|
96
|
-
*/
|
|
97
|
-
export declare function formatRelativeDate(value: string | Date | number, options?: DateDisplayOptions): string;
|
|
98
112
|
/**
|
|
99
|
-
*
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Format datetime value.
|
|
113
|
+
* The date/datetime display path - `@object-ui/core`'s `utils/date-display.ts`
|
|
114
|
+
* (objectui#7178), re-exported here under its original names so every existing
|
|
115
|
+
* consumer of `@object-ui/fields` is unchanged.
|
|
104
116
|
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
* `useDisplayLocale()`.
|
|
117
|
+
* It moved for the reason `formatDisplayNumber` moved in objectui#4576: this
|
|
118
|
+
* barrel is a React package, and the React-free engine could not import from
|
|
119
|
+
* it. `core`'s `formatMeasure` needed this exact path - a dataset measure over
|
|
120
|
+
* a date field was rendering its raw ISO string - and the alternative to
|
|
121
|
+
* moving was a second date convention in `dataset-format.ts`, which is the
|
|
122
|
+
* drift #4576 already paid for once with percent.
|
|
112
123
|
*/
|
|
113
|
-
export
|
|
124
|
+
export { formatDate, formatDateTime, formatDateTimeCompactParts, formatRelativeDate };
|
|
125
|
+
export type { DateDisplayOptions };
|
|
114
126
|
/**
|
|
115
127
|
* Text field cell renderer
|
|
116
128
|
*/
|
|
@@ -140,7 +152,7 @@ export declare function DateCellRenderer({ value, field }: CellRendererProps): R
|
|
|
140
152
|
/**
|
|
141
153
|
* DateTime field cell renderer (Airtable-style with date and time visually separated)
|
|
142
154
|
*/
|
|
143
|
-
export declare function DateTimeCellRenderer({ value }: CellRendererProps): React.ReactElement;
|
|
155
|
+
export declare function DateTimeCellRenderer({ value, field }: CellRendererProps): React.ReactElement;
|
|
144
156
|
/** The six pill colors plus the two dot colors derived from one declared hex. */
|
|
145
157
|
export interface HexBadgePalette {
|
|
146
158
|
bg: string;
|
|
@@ -245,14 +257,19 @@ export declare function ImageCellRenderer({ value }: CellRendererProps): React.R
|
|
|
245
257
|
* Display order:
|
|
246
258
|
* 1. Embedded record object (`{ id, name, ... }` from `$expand`) → use its name
|
|
247
259
|
* 2. Static `field.options[]` (e.g. when the lookup is a closed enum) → look up label
|
|
248
|
-
* 3. Fetch-on-demand: when the value is a primitive ID and `field.
|
|
260
|
+
* 3. Fetch-on-demand: when the value is a primitive ID and `field.reference`
|
|
249
261
|
* is known, resolve via dataSource and show the related record's display name.
|
|
250
|
-
*
|
|
262
|
+
* 4. Nothing named it → the unresolved-reference affordance (objectui#8695):
|
|
263
|
+
* the raw value, kept visible, beside a stated epistemic marker. This arm
|
|
264
|
+
* used to be two — a muted `—` for opaque-LOOKING strings and confident
|
|
265
|
+
* bare text for everything else — which answered one state two ways.
|
|
251
266
|
*
|
|
252
267
|
* Record → name resolution (1 and 3) goes through the referenced object's
|
|
253
268
|
* schema when the data source exposes it (`displayField` → nameField/titleFormat
|
|
254
269
|
* → derivation, see {@link resolveLookupRecordName}), so the chip and the
|
|
255
|
-
* picker agree (issue #2357)
|
|
270
|
+
* picker agree (issue #2357) — and, like the picker's option label, it reads
|
|
271
|
+
* only the fields the viewer may read on the referenced object
|
|
272
|
+
* (objectui#10501).
|
|
256
273
|
*/
|
|
257
274
|
export declare function LookupCellRenderer({ value, field }: CellRendererProps): React.ReactElement;
|
|
258
275
|
/**
|
|
@@ -261,8 +278,16 @@ export declare function LookupCellRenderer({ value, field }: CellRendererProps):
|
|
|
261
278
|
export declare function FormulaCellRenderer({ value }: CellRendererProps): React.ReactElement;
|
|
262
279
|
/**
|
|
263
280
|
* User/Owner field cell renderer (with avatars)
|
|
281
|
+
*
|
|
282
|
+
* The name and the avatar are DISPLAY values, so each person row is drawn as
|
|
283
|
+
* the viewer may read it (objectui#10535): with a loaded policy, the fields it
|
|
284
|
+
* denies on the person's object are removed first ({@link withoutDeniedFields},
|
|
285
|
+
* `id` kept), and everything below reads that row — exactly as it reads the
|
|
286
|
+
* row a stripping backend serves. The person's object is the field's
|
|
287
|
+
* `reference`, and `sys_user` when it names none: the object `UserField`
|
|
288
|
+
* points the picker at.
|
|
264
289
|
*/
|
|
265
|
-
export declare function UserCellRenderer({ value }: CellRendererProps): React.ReactElement;
|
|
290
|
+
export declare function UserCellRenderer({ value, field }: CellRendererProps): React.ReactElement;
|
|
266
291
|
/**
|
|
267
292
|
* Register a custom field renderer
|
|
268
293
|
* @param type Field type (e.g. 'text', 'location', 'my-custom-type')
|
|
@@ -293,12 +318,13 @@ export declare function ColorSwatchCellRenderer({ value }: CellRendererProps): R
|
|
|
293
318
|
* The rich-content display pipelines — `markdown` through the GFM renderer,
|
|
294
319
|
* `html`/`richtext` through the sanitizing HTML renderer — live in
|
|
295
320
|
* `./widgets/richTextDisplay.js` rather than here, so `RichTextField` can
|
|
296
|
-
* import them without importing this barrel back (
|
|
321
|
+
* import them without importing this barrel back (`4bb940b6e`). Re-exported
|
|
297
322
|
* unchanged: they are part of this package's published surface, and
|
|
298
323
|
* `RICH_TEXT_CELL_RENDERERS` below is the one table both the cell resolver and
|
|
299
324
|
* the widget's readonly branch read.
|
|
300
325
|
*/
|
|
301
326
|
export { MarkdownCellRenderer, HtmlCellRenderer } from './widgets/richTextDisplay.js';
|
|
327
|
+
export { RICH_TEXT_FIELD_TYPES, type RichTextFieldType } from './widgets/richTextDisplay.js';
|
|
302
328
|
/**
|
|
303
329
|
* Renders a `location`/`geolocation` value as readable coordinates with a pin.
|
|
304
330
|
* Accepts `{ lat, lng }` / `{ latitude, longitude }`, a `"lat,lng"` string,
|
|
@@ -325,6 +351,136 @@ export declare function LocationCellRenderer({ value }: CellRendererProps): Reac
|
|
|
325
351
|
* is never silently swallowed by the fix.
|
|
326
352
|
*/
|
|
327
353
|
export declare function AddressCellRenderer({ value }: CellRendererProps): React.ReactElement;
|
|
354
|
+
/**
|
|
355
|
+
* `password` / `secret` cell renderer: the mask for a credential that is SET,
|
|
356
|
+
* and the shared affordance for one that is NOT (objectui#8678).
|
|
357
|
+
*
|
|
358
|
+
* The entry this replaces was an argument-less arrow that drew the mask for
|
|
359
|
+
* every input, `null` included. On screen, a credential that was never set was
|
|
360
|
+
* then drawn exactly like one that is set. The platform's read contract is
|
|
361
|
+
* presence-preserving on purpose: `@objectstack/spec`'s `SECRET_MASK` docblock
|
|
362
|
+
* says an unset credential "reads back `null` instead, never this mask", which
|
|
363
|
+
* is what lets a console render "configured" vs "not configured" at all. This
|
|
364
|
+
* cell threw that distinction away one step before the reader saw it.
|
|
365
|
+
*
|
|
366
|
+
* ⛔ The value is NEVER printed and never reaches the DOM. Only its presence is
|
|
367
|
+
* read. A populated value keeps the exact mask it drew before this card, and
|
|
368
|
+
* nothing here is a weaker mask.
|
|
369
|
+
*
|
|
370
|
+
* "Empty" is the string class's answer, since both types are
|
|
371
|
+
* `STRING_VALUE_TYPES` members in the spec: `TextCellRenderer`'s predicate
|
|
372
|
+
* exactly, the floor on the coerced text. `{}` therefore stays a VALUE and
|
|
373
|
+
* keeps the mask, per objectui#8596's string-class ruling ("the record IS
|
|
374
|
+
* storing something"). A whitespace-only string also keeps it, because `text`
|
|
375
|
+
* keeps its spaces and a blank credential is still a set one.
|
|
376
|
+
* `cellRenderers.valueIndependent-8678` pins this byte-equal to `text` for
|
|
377
|
+
* every empty input.
|
|
378
|
+
*
|
|
379
|
+
* ⭐ A NAMED module-level component, for the reason {@link RepeaterCellRenderer}
|
|
380
|
+
* states: `EmptyValue` holds a hook, and an inline arrow in the table below
|
|
381
|
+
* is a new component type on every resolution, so it would tear that hook down
|
|
382
|
+
* per render.
|
|
383
|
+
*
|
|
384
|
+
* Exported (objectui#10657) for the cell a producer cannot type yet. While an
|
|
385
|
+
* object-bound table is still waiting for its object's field types, or after
|
|
386
|
+
* that read failed, a column with no type of its own could be a credential,
|
|
387
|
+
* so `ObjectGrid`, `RelatedList` and `ObjectDataTable` draw it WITHHELD: as
|
|
388
|
+
* this mask, never as text. It is this component and not the live registry
|
|
389
|
+
* entry for `password`, so a host override of a masked type cannot change what
|
|
390
|
+
* a withheld cell draws. Registering it for a type
|
|
391
|
+
* (`registerFieldRenderer('api_token', MaskedCellRenderer)`) masks that type,
|
|
392
|
+
* as {@link isMaskedFieldType} describes. `field` is optional: the mask reads
|
|
393
|
+
* only whether the value is present, so a withheld cell has no field metadata
|
|
394
|
+
* to invent.
|
|
395
|
+
*/
|
|
396
|
+
export declare function MaskedCellRenderer({ value, }: Omit<CellRendererProps, 'field'> & {
|
|
397
|
+
field?: CellRendererProps['field'];
|
|
398
|
+
}): React.ReactElement;
|
|
399
|
+
/**
|
|
400
|
+
* The field types this package DECLARES masked: their standard cell is
|
|
401
|
+
* {@link MaskedCellRenderer}, which draws `••••••` in place of the value
|
|
402
|
+
* (objectui#8686). The read-side twin of the credential entry in
|
|
403
|
+
* `INLINE_EXCLUDED_FIELD_TYPES`, which lives in `FieldEditWidget`.
|
|
404
|
+
*
|
|
405
|
+
* ⭐ This set BUILDS the table's masked entries — `buildStandardCellRendererMap`
|
|
406
|
+
* spreads one {@link MaskedCellRenderer} entry per member — so adding a type
|
|
407
|
+
* here masks its cell AND makes {@link isMaskedFieldType} answer `true` for it,
|
|
408
|
+
* in one edit. There is no second list to keep in step.
|
|
409
|
+
*
|
|
410
|
+
* ⚠️ Membership answers "what ships masked", ⛔ not "what is masked right now":
|
|
411
|
+
* `registerFieldRenderer` can add or replace a masked type at runtime, and a
|
|
412
|
+
* set cannot see that. Consumers deciding what to do with a cell's value ask
|
|
413
|
+
* {@link isMaskedFieldType}.
|
|
414
|
+
*
|
|
415
|
+
* RAW spellings, deliberately: the cell path does not resolve form aliases
|
|
416
|
+
* (`getCellRenderer` is an exact-key lookup), so `field:password` renders in
|
|
417
|
+
* the clear and is not a member.
|
|
418
|
+
*
|
|
419
|
+
* Owned here for now. The objectui#8686 ruling made the protocol the first
|
|
420
|
+
* place to look: if `@objectstack/spec` comes to declare which field types are
|
|
421
|
+
* credentials, this set derives from that declaration instead of listing types.
|
|
422
|
+
*/
|
|
423
|
+
export declare const MASKED_FIELD_TYPES: ReadonlySet<string>;
|
|
424
|
+
/**
|
|
425
|
+
* Is a cell of this field type drawn as a mask instead of as its value? The
|
|
426
|
+
* one authority for that question (objectui#8686): ask it rather than keep a
|
|
427
|
+
* list of types. The read-side twin of `isInlineExcludedFieldType()`.
|
|
428
|
+
*
|
|
429
|
+
* A LIVE reading of the cell registry, taken at call time, in the order
|
|
430
|
+
* {@link getCellRenderer} resolves: the runtime registry first, then the
|
|
431
|
+
* standard table.
|
|
432
|
+
*
|
|
433
|
+
* 1. The type resolves to THE mask ({@link MaskedCellRenderer}) → `true`,
|
|
434
|
+
* declared or not. That is how a host adds a masked type:
|
|
435
|
+
* `registerFieldRenderer('api_token', getCellRenderer('password'))`.
|
|
436
|
+
* 2. Otherwise, a type outside {@link MASKED_FIELD_TYPES} → `false`.
|
|
437
|
+
* 3. A declared type whose mask a host REPLACED at runtime
|
|
438
|
+
* (`registerFieldRenderer('password', X)`) → the override is read:
|
|
439
|
+
* - X is one of this package's own cell renderers → `false`. None of them
|
|
440
|
+
* is the mask, so the predicate answers `false` and the cell draws what
|
|
441
|
+
* X draws (for `TextCellRenderer`, the value).
|
|
442
|
+
* - X is the host's own component → `true`, the declared answer. Nothing
|
|
443
|
+
* here can tell whether an opaque component masks. Answering `false`
|
|
444
|
+
* would offer a credential to anything that trusts this predicate
|
|
445
|
+
* (the detail page's copy affordance, objectui#8440) while a custom mask
|
|
446
|
+
* hides it on screen. So an unreadable override falls back to the
|
|
447
|
+
* declared set, on the side that withholds.
|
|
448
|
+
*
|
|
449
|
+
* RAW spelling, no alias resolution, for the reason {@link MASKED_FIELD_TYPES}
|
|
450
|
+
* states. Side-effect free, like `isInlineExcludedFieldType()`: unlike
|
|
451
|
+
* {@link getCellRenderer}, it never reports a retired spelling.
|
|
452
|
+
*/
|
|
453
|
+
export declare function isMaskedFieldType(fieldType: string | undefined): boolean;
|
|
454
|
+
/**
|
|
455
|
+
* Every field type that resolves to a cell renderer OF ITS OWN — a LIVE
|
|
456
|
+
* reading of the registry, taken when you call it (objectui#8734).
|
|
457
|
+
*
|
|
458
|
+
* ## Why this exists
|
|
459
|
+
*
|
|
460
|
+
* Two censuses — `cellRenderers.objectLiteral-8596` in this package and
|
|
461
|
+
* `summaryChip.badgeFitCensus-8464` in `@object-ui/plugin-detail` — declare in
|
|
462
|
+
* prose that they measure "every type `getCellRenderer` resolves to a renderer
|
|
463
|
+
* of its own", and each enforced that declaration with a hard-coded population
|
|
464
|
+
* size. A newly registered type is absent from such a table, so every row in it
|
|
465
|
+
* still passes: the census goes on measuring a snapshot while claiming to
|
|
466
|
+
* measure the registry. This function is what those censuses reconcile against,
|
|
467
|
+
* so a new type turns a silent pass into a red row that NAMES the type.
|
|
468
|
+
*
|
|
469
|
+
* ## ⭐ A function, ⛔ not a frozen constant
|
|
470
|
+
*
|
|
471
|
+
* `FORM_FIELD_TYPES` next door may be `Object.freeze(Object.keys(...))` because
|
|
472
|
+
* `fieldWidgetMap` is a module literal that never changes. This registry DOES
|
|
473
|
+
* change: {@link registerFieldRenderer} is published, and a host may add or
|
|
474
|
+
* override a type after this module is evaluated. A frozen constant here would
|
|
475
|
+
* be a snapshot taken at import time — the very defect the censuses are being
|
|
476
|
+
* repaired for, one level down. Every call re-reads.
|
|
477
|
+
*
|
|
478
|
+
* The answer is the UNION of the runtime registry and the standard table,
|
|
479
|
+
* because {@link getCellRenderer} dispatches on both; it is sorted so callers
|
|
480
|
+
* get a stable order, and `TextCellRenderer` is the TOTAL fallback for
|
|
481
|
+
* everything else, which is exactly why "everything else" is not listed here.
|
|
482
|
+
*/
|
|
483
|
+
export declare function listCellRendererTypes(): readonly string[];
|
|
328
484
|
/**
|
|
329
485
|
* Get the appropriate cell renderer for a field type
|
|
330
486
|
*/
|
|
@@ -694,6 +850,17 @@ export declare function registerField(fieldType: string): void;
|
|
|
694
850
|
* nothing is silently substituted either, which is the whole point: the author
|
|
695
851
|
* sees a refusal where they expected an input, not a text box that looks like
|
|
696
852
|
* it worked.
|
|
853
|
+
*
|
|
854
|
+
* The spelling it names is `retiredFieldType` — the key the RESOLVER answered
|
|
855
|
+
* with this tombstone — and is re-derived from the field only when a host
|
|
856
|
+
* renders the tombstone directly without one (objectui#10471). The field is
|
|
857
|
+
* the wrong witness whenever the retired spelling arrived through a different
|
|
858
|
+
* key than `field.type`: an authored `widget` wins over `type` in both form
|
|
859
|
+
* hosts, so `{ type: 'user', widget: 'owner' }` reaches the `owner` tombstone
|
|
860
|
+
* carrying a `user` field, and deriving from it named the LIVE type as
|
|
861
|
+
* retired, lost the prescription, and logged nothing. The two resolvers fill
|
|
862
|
+
* the prop by binding it ({@link retiredFieldTombstoneFor}); a host whose key
|
|
863
|
+
* IS `field.type` (plugin-detail's inline editor) may keep omitting it.
|
|
697
864
|
*/
|
|
698
865
|
export declare const RetiredFieldTombstone: React.FC<Record<string, any>>;
|
|
699
866
|
export declare function registerAllFields(): void;
|
|
@@ -751,4 +918,9 @@ export * from './widgets/TagsField.js';
|
|
|
751
918
|
export { withFieldCarrier } from './withFieldCarrier.js';
|
|
752
919
|
export { toDomProps } from './widgets/toDomProps.js';
|
|
753
920
|
export type { DomProps } from './widgets/toDomProps.js';
|
|
921
|
+
export { toHostProps } from './widgets/toHostProps.js';
|
|
922
|
+
export type { HostProps } from './widgets/toHostProps.js';
|
|
754
923
|
export { toDateInputValue, toDateTimeInputValue, fromDateTimeInputValue, } from './widgets/nativeDateValue.js';
|
|
924
|
+
export { useUploadingScope, UploadingScopeProvider } from './widgets/uploadingScope.js';
|
|
925
|
+
export { useUploadingSignal } from './widgets/useUploadingSignal.js';
|
|
926
|
+
export type { UploadingScope } from './widgets/uploadingScope.js';
|