@object-ui/fields 17.5.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.
Files changed (249) hide show
  1. package/CHANGELOG.md +6150 -0
  2. package/README.md +108 -8
  3. package/dist/FieldEditWidget.d.ts +70 -8
  4. package/dist/coerceToSafeValue.d.ts +54 -0
  5. package/dist/currency.d.ts +1 -1
  6. package/dist/field-type-alias.d.ts +16 -0
  7. package/dist/index.cjs +5 -5
  8. package/dist/index.css +53 -11
  9. package/dist/index.d.ts +653 -128
  10. package/dist/index.js +4275 -3171
  11. package/dist/widgets/AddressField.d.ts +3 -3
  12. package/dist/widgets/AutoNumberField.d.ts +1 -1
  13. package/dist/widgets/AvatarField.d.ts +20 -4
  14. package/dist/widgets/BooleanField.d.ts +2 -2
  15. package/dist/widgets/CapabilityMultiSelectField.d.ts +1 -1
  16. package/dist/widgets/CheckboxesField.d.ts +1 -1
  17. package/dist/widgets/CodeField.d.ts +1 -1
  18. package/dist/widgets/ColorField.d.ts +1 -1
  19. package/dist/widgets/CurrencyField.d.ts +1 -1
  20. package/dist/widgets/DateField.d.ts +2 -2
  21. package/dist/widgets/DateTimeField.d.ts +2 -2
  22. package/dist/widgets/EmailField.d.ts +1 -1
  23. package/dist/widgets/FileField.d.ts +18 -2
  24. package/dist/widgets/FilterConditionField.d.ts +43 -2
  25. package/dist/widgets/FormulaField.d.ts +1 -1
  26. package/dist/widgets/FullscreenFieldEditor.d.ts +9 -2
  27. package/dist/widgets/GeolocationField.d.ts +10 -4
  28. package/dist/widgets/GridField.d.ts +102 -86
  29. package/dist/widgets/ImageField.d.ts +1 -1
  30. package/dist/widgets/LocationField.d.ts +31 -4
  31. package/dist/widgets/LookupField.d.ts +9 -1
  32. package/dist/widgets/MasterDetailField.d.ts +1 -1
  33. package/dist/widgets/MultiSelectField.d.ts +1 -1
  34. package/dist/widgets/NumberField.d.ts +2 -2
  35. package/dist/widgets/ObjectField.d.ts +10 -3
  36. package/dist/widgets/ObjectRefField.d.ts +1 -1
  37. package/dist/widgets/OptionsEmptyState.d.ts +38 -8
  38. package/dist/widgets/PasswordField.d.ts +15 -1
  39. package/dist/widgets/PeoplePicker.d.ts +17 -2
  40. package/dist/widgets/PercentField.d.ts +3 -2
  41. package/dist/widgets/PersonRow.d.ts +13 -2
  42. package/dist/widgets/PhoneField.d.ts +1 -1
  43. package/dist/widgets/QRCodeField.d.ts +1 -1
  44. package/dist/widgets/RadioField.d.ts +1 -1
  45. package/dist/widgets/RatingField.d.ts +1 -1
  46. package/dist/widgets/RecipientPickerField.d.ts +44 -1
  47. package/dist/widgets/RecordPickerDialog.d.ts +33 -16
  48. package/dist/widgets/RichTextField.d.ts +37 -1
  49. package/dist/widgets/SelectField.d.ts +1 -1
  50. package/dist/widgets/SelectionTray.d.ts +13 -2
  51. package/dist/widgets/SignatureField.d.ts +32 -2
  52. package/dist/widgets/SliderField.d.ts +37 -2
  53. package/dist/widgets/SummaryField.d.ts +1 -1
  54. package/dist/widgets/TagsField.d.ts +1 -1
  55. package/dist/widgets/TextAreaField.d.ts +6 -2
  56. package/dist/widgets/TextField.d.ts +2 -2
  57. package/dist/widgets/TimeField.d.ts +2 -2
  58. package/dist/widgets/UrlField.d.ts +1 -1
  59. package/dist/widgets/UserField.d.ts +1 -1
  60. package/dist/widgets/VectorField.d.ts +1 -1
  61. package/dist/widgets/_cell-renderer-bridge.d.ts +1 -1
  62. package/dist/widgets/address-format.d.ts +27 -7
  63. package/dist/widgets/file-affordance.d.ts +33 -0
  64. package/dist/widgets/file-size-guard.d.ts +5 -23
  65. package/dist/widgets/file-value.d.ts +38 -9
  66. package/dist/widgets/lookupColumnDisplay.d.ts +110 -0
  67. package/dist/widgets/nativeDateValue.d.ts +9 -27
  68. package/dist/widgets/number-format.d.ts +137 -0
  69. package/dist/widgets/numberBadInput.d.ts +135 -0
  70. package/dist/widgets/personDisplay.d.ts +22 -4
  71. package/dist/widgets/richTextDisplay.d.ts +116 -0
  72. package/dist/widgets/toDomProps.d.ts +10 -1
  73. package/dist/widgets/toHostGroupProps.d.ts +172 -21
  74. package/dist/widgets/toHostProps.d.ts +105 -0
  75. package/dist/widgets/types.d.ts +19 -6
  76. package/dist/widgets/upload-error-message.d.ts +6 -0
  77. package/dist/widgets/uploadingScope.d.ts +142 -0
  78. package/dist/widgets/useCascadingOptions.d.ts +3 -2
  79. package/dist/widgets/useRecordQuery.d.ts +4 -2
  80. package/dist/widgets/useUploadingSignal.d.ts +8 -0
  81. package/package.json +11 -13
  82. package/dist/widgets/CharacterCount.d.ts +0 -56
  83. package/src/FieldEditWidget.test.ts +0 -133
  84. package/src/FieldEditWidget.tsx +0 -207
  85. package/src/__tests__/AddressCellRenderer.test.tsx +0 -166
  86. package/src/__tests__/CurrencyField.minorUnits.test.tsx +0 -191
  87. package/src/__tests__/CurrencyField.symbol.test.tsx +0 -198
  88. package/src/__tests__/DateCellRenderer.test.tsx +0 -82
  89. package/src/__tests__/NumberCellRenderer.grouping.test.tsx +0 -146
  90. package/src/__tests__/NumberCellRenderer.test.tsx +0 -60
  91. package/src/__tests__/PercentCellRenderer.locale.test.tsx +0 -152
  92. package/src/__tests__/PercentCellRenderer.test.tsx +0 -115
  93. package/src/__tests__/boolean-label-association-e2e.test.tsx +0 -298
  94. package/src/__tests__/capability-multiselect-retired.test.ts +0 -109
  95. package/src/__tests__/cell-truncation.test.tsx +0 -96
  96. package/src/__tests__/composite-group-label-e2e.test.tsx +0 -436
  97. package/src/__tests__/composite-group-label-readonly-e2e.test.tsx +0 -403
  98. package/src/__tests__/date-formatter-residue-4272.test.ts +0 -120
  99. package/src/__tests__/date-locale-channel.test.tsx +0 -305
  100. package/src/__tests__/field-carrier-sdui.test.tsx +0 -169
  101. package/src/__tests__/formatCurrency.centsDigit.test.tsx +0 -158
  102. package/src/__tests__/formatCurrency.minorUnits.test.tsx +0 -221
  103. package/src/__tests__/group-labelling-declaration.test.ts +0 -148
  104. package/src/__tests__/lookupCellDisplayField.test.tsx +0 -107
  105. package/src/__tests__/lookupCellDisplayName.test.tsx +0 -119
  106. package/src/__tests__/lookupCellRecordLink.test.tsx +0 -171
  107. package/src/__tests__/lookupCellReferenceKey.test.tsx +0 -57
  108. package/src/__tests__/percent-cell-vs-measure-4576.test.ts +0 -115
  109. package/src/__tests__/percent-formatter-locale-4553.test.ts +0 -147
  110. package/src/__tests__/percent-tie-halfup-4590.test.ts +0 -224
  111. package/src/__tests__/registry-collision.test.ts +0 -91
  112. package/src/__tests__/resolveFieldCurrency.test.ts +0 -20
  113. package/src/__tests__/select-label-association-e2e.test.tsx +0 -199
  114. package/src/__tests__/spec-symbol-batch7.test.ts +0 -126
  115. package/src/__tests__/validation-feedback.test.tsx +0 -361
  116. package/src/__tests__/widget-aria-invalid-e2e.test.tsx +0 -265
  117. package/src/__tests__/widget-aria-invalid-registry-e2e.test.tsx +0 -338
  118. package/src/__tests__/widget-dom-leak-e2e.test.tsx +0 -357
  119. package/src/__tests__/widget-props-contract.test.tsx +0 -142
  120. package/src/coerce-safe-value.test.ts +0 -34
  121. package/src/complex-widgets.test.tsx +0 -924
  122. package/src/currency.ts +0 -144
  123. package/src/datetime-widgets.test.tsx +0 -185
  124. package/src/field-type-alias.multiple.test.ts +0 -81
  125. package/src/field-type-alias.ts +0 -156
  126. package/src/field-type-coverage.test.ts +0 -67
  127. package/src/index.css +0 -44
  128. package/src/index.tsx +0 -2745
  129. package/src/standard-widgets.test.tsx +0 -364
  130. package/src/widgets/AddressField.postalCode.test.tsx +0 -257
  131. package/src/widgets/AddressField.tsx +0 -182
  132. package/src/widgets/AddressField.uniqueIds.test.tsx +0 -93
  133. package/src/widgets/AutoNumberField.tsx +0 -18
  134. package/src/widgets/AvatarField.tsx +0 -117
  135. package/src/widgets/BooleanField.tsx +0 -86
  136. package/src/widgets/CapabilityMultiSelectField.test.tsx +0 -168
  137. package/src/widgets/CapabilityMultiSelectField.tsx +0 -241
  138. package/src/widgets/CharacterCount.tsx +0 -263
  139. package/src/widgets/CheckboxesField.cascade.test.tsx +0 -143
  140. package/src/widgets/CheckboxesField.tsx +0 -169
  141. package/src/widgets/CodeField.tsx +0 -41
  142. package/src/widgets/ColorField.tsx +0 -53
  143. package/src/widgets/CurrencyField.tsx +0 -135
  144. package/src/widgets/DateField.tsx +0 -40
  145. package/src/widgets/DateTimeField.tsx +0 -46
  146. package/src/widgets/EmailField.tsx +0 -37
  147. package/src/widgets/FileField.tsx +0 -512
  148. package/src/widgets/FilterConditionField.tsx +0 -454
  149. package/src/widgets/FormulaField.tsx +0 -38
  150. package/src/widgets/FullscreenFieldEditor.tsx +0 -60
  151. package/src/widgets/GeolocationField.tsx +0 -193
  152. package/src/widgets/GeolocationField.uniqueIds.test.tsx +0 -88
  153. package/src/widgets/GridField.test.tsx +0 -632
  154. package/src/widgets/GridField.tsx +0 -1070
  155. package/src/widgets/ImageCropperDialog.tsx +0 -245
  156. package/src/widgets/ImageField.maxSize.test.tsx +0 -154
  157. package/src/widgets/ImageField.tsx +0 -305
  158. package/src/widgets/ImageLightbox.test.tsx +0 -52
  159. package/src/widgets/ImageLightbox.tsx +0 -108
  160. package/src/widgets/LocationField.tsx +0 -57
  161. package/src/widgets/LookupField.dependsOn.test.tsx +0 -233
  162. package/src/widgets/LookupField.gateHintLabel.test.tsx +0 -135
  163. package/src/widgets/LookupField.hydration.test.tsx +0 -136
  164. package/src/widgets/LookupField.idField.test.tsx +0 -61
  165. package/src/widgets/LookupField.tsx +0 -1295
  166. package/src/widgets/MarkdownContent.tsx +0 -19
  167. package/src/widgets/MasterDetailField.tsx +0 -131
  168. package/src/widgets/MultiSelectField.cascade.test.tsx +0 -143
  169. package/src/widgets/MultiSelectField.tsx +0 -196
  170. package/src/widgets/NumberField.tsx +0 -49
  171. package/src/widgets/ObjectField.tsx +0 -94
  172. package/src/widgets/ObjectRefField.tsx +0 -121
  173. package/src/widgets/OptionsEmptyState.no-provider.test.tsx +0 -88
  174. package/src/widgets/OptionsEmptyState.test.tsx +0 -169
  175. package/src/widgets/OptionsEmptyState.tsx +0 -99
  176. package/src/widgets/PasswordField.tsx +0 -49
  177. package/src/widgets/PeoplePicker.test.tsx +0 -360
  178. package/src/widgets/PeoplePicker.tsx +0 -579
  179. package/src/widgets/PeoplePickerComponents.test.tsx +0 -104
  180. package/src/widgets/PercentField.tsx +0 -95
  181. package/src/widgets/PersonRow.tsx +0 -117
  182. package/src/widgets/PhoneField.tsx +0 -37
  183. package/src/widgets/QRCodeField.tsx +0 -103
  184. package/src/widgets/RadioField.cascade.test.tsx +0 -141
  185. package/src/widgets/RadioField.tsx +0 -143
  186. package/src/widgets/RatingField.tsx +0 -94
  187. package/src/widgets/RecipientPickerField.test.tsx +0 -157
  188. package/src/widgets/RecipientPickerField.tsx +0 -188
  189. package/src/widgets/RecordPickerDialog.baseFilterShapes.test.tsx +0 -191
  190. package/src/widgets/RecordPickerDialog.dateLocale.test.tsx +0 -124
  191. package/src/widgets/RecordPickerDialog.filterOptions.test.tsx +0 -611
  192. package/src/widgets/RecordPickerDialog.selectLabel.test.tsx +0 -112
  193. package/src/widgets/RecordPickerDialog.tsx +0 -1365
  194. package/src/widgets/RichTextField.tsx +0 -176
  195. package/src/widgets/SelectField.cascade.test.tsx +0 -138
  196. package/src/widgets/SelectField.tsx +0 -193
  197. package/src/widgets/SelectionTray.tsx +0 -110
  198. package/src/widgets/SignatureField.tsx +0 -140
  199. package/src/widgets/SliderField.tsx +0 -39
  200. package/src/widgets/SummaryField.tsx +0 -31
  201. package/src/widgets/TagsField.placeholder.no-provider.test.tsx +0 -68
  202. package/src/widgets/TagsField.placeholder.test.tsx +0 -95
  203. package/src/widgets/TagsField.tsx +0 -88
  204. package/src/widgets/TextAreaField.tsx +0 -213
  205. package/src/widgets/TextField.tsx +0 -45
  206. package/src/widgets/TimeField.tsx +0 -31
  207. package/src/widgets/UrlField.tsx +0 -46
  208. package/src/widgets/UserField.tsx +0 -59
  209. package/src/widgets/UserFieldPicker.test.tsx +0 -78
  210. package/src/widgets/VectorField.tsx +0 -29
  211. package/src/widgets/__tests__/FilterConditionField.matchAll.test.ts +0 -66
  212. package/src/widgets/__tests__/FilterConditionField.operators.test.ts +0 -166
  213. package/src/widgets/__tests__/FullscreenFieldEditor.i18n.test.tsx +0 -248
  214. package/src/widgets/__tests__/FullscreenFieldEditor.no-provider.test.tsx +0 -116
  215. package/src/widgets/__tests__/RichTextField.fullscreenDisabled.test.tsx +0 -244
  216. package/src/widgets/__tests__/RichTextField.mobileFullscreen.test.tsx +0 -195
  217. package/src/widgets/__tests__/TextAreaField.characterCount.announcements.test.tsx +0 -417
  218. package/src/widgets/__tests__/TextAreaField.characterCount.i18n.test.tsx +0 -287
  219. package/src/widgets/__tests__/TextAreaField.characterCount.no-provider.test.tsx +0 -160
  220. package/src/widgets/__tests__/TextAreaField.fullscreenCharacterCount.i18n.test.tsx +0 -161
  221. package/src/widgets/__tests__/TextAreaField.fullscreenCharacterCount.test.tsx +0 -346
  222. package/src/widgets/__tests__/TextAreaField.fullscreenDisabled.test.tsx +0 -246
  223. package/src/widgets/__tests__/TextAreaField.mobileFullscreen.test.tsx +0 -175
  224. package/src/widgets/_cell-renderer-bridge.ts +0 -19
  225. package/src/widgets/address-format.ts +0 -120
  226. package/src/widgets/deriveLookupColumns.test.ts +0 -112
  227. package/src/widgets/deriveLookupColumns.ts +0 -108
  228. package/src/widgets/file-size-guard.ts +0 -55
  229. package/src/widgets/file-value.test.ts +0 -230
  230. package/src/widgets/file-value.ts +0 -246
  231. package/src/widgets/nativeDateValue.test.ts +0 -115
  232. package/src/widgets/nativeDateValue.ts +0 -112
  233. package/src/widgets/openNativePicker.ts +0 -18
  234. package/src/widgets/optionWidgets.gatedOptions.test.tsx +0 -267
  235. package/src/widgets/optionWidgets.unconfiguredOptions.test.tsx +0 -150
  236. package/src/widgets/personDisplay.test.ts +0 -113
  237. package/src/widgets/personDisplay.ts +0 -92
  238. package/src/widgets/recentLookups.test.ts +0 -45
  239. package/src/widgets/recentLookups.ts +0 -47
  240. package/src/widgets/toDomProps.ts +0 -204
  241. package/src/widgets/toHostGroupProps.ts +0 -102
  242. package/src/widgets/types.ts +0 -242
  243. package/src/widgets/useCascadingOptions.ts +0 -46
  244. package/src/widgets/useFieldTranslation.ts +0 -132
  245. package/src/widgets/useRecordQuery.test.ts +0 -174
  246. package/src/widgets/useRecordQuery.ts +0 -291
  247. package/src/widgets/useUploadingSignal.test.tsx +0 -62
  248. package/src/widgets/useUploadingSignal.ts +0 -20
  249. package/src/withFieldCarrier.tsx +0 -75
package/dist/index.d.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  import { default as React } from 'react';
2
2
  import { FieldMetadata } from '@object-ui/types';
3
- import { resolveFieldCurrency } from './currency';
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';
6
+ import { resolveFieldCurrency } from './currency.js';
4
7
  /**
5
8
  * Pick the most reasonable display name from an arbitrary record object.
6
9
  * Tries common name-like keys in priority order, then falls back to undefined.
@@ -8,8 +11,18 @@ import { resolveFieldCurrency } from './currency';
8
11
  export declare function pickRecordDisplayName(record: Record<string, unknown> | null | undefined, preferredField?: string): string | undefined;
9
12
  /**
10
13
  * Heuristic: detect strings that look like opaque foreign-key IDs (e.g. nanoid
11
- * or BSON ObjectId). Used so we don't display random gibberish to users when
12
- * a lookup wasn't expanded.
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.
13
26
  */
14
27
  export declare function isLikelyOpaqueId(v: unknown): boolean;
15
28
  /**
@@ -21,15 +34,18 @@ export interface CellRendererProps {
21
34
  isEditing?: boolean;
22
35
  onChange?: (value: any) => void;
23
36
  }
37
+ export { coerceToSafeValue };
38
+ export { resolveFieldCurrency };
24
39
  /**
25
- * Coerce a value to a safe primitive for rendering.
26
- * Handles MongoDB wrapper types ($numberDecimal, $oid, $date), expanded
27
- * reference objects, and arrays so that no raw object is ever passed as
28
- * a React child — preventing React error #310.
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.
29
47
  */
30
- export declare function coerceToSafeValue(value: unknown): string | number | boolean | null | undefined;
31
- export { resolveFieldCurrency };
32
- export declare function formatCurrency(value: number, currency?: string, locale?: string): string;
48
+ export { formatCurrency };
33
49
  /**
34
50
  * Format currency value in compact form for mobile display.
35
51
  * E.g., $150,000 → $150K, $1,200,000 → $1.2M
@@ -37,18 +53,36 @@ export declare function formatCurrency(value: number, currency?: string, locale?
37
53
  */
38
54
  export declare function formatCompactCurrency(value: number, currency?: string, locale?: string): string;
39
55
  /**
40
- * Format a plain number with thousands separators, no currency symbol.
41
- * Used as a safe fallback when a currency-typed field has no `currency`
42
- * configured — we'd rather render `1,234.50` than silently assume USD.
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.
43
60
  */
44
61
  export declare function formatNumber(value: number, decimals?: number, locale?: string): string;
45
62
  /**
46
- * Format percent value.
47
- * Handles both decimal (0.8 = 80%) and whole number (80 = 80%) inputs.
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.
48
71
  *
49
- * `locale` is the third positional parameter, matching {@link formatNumber} and
50
- * {@link formatCurrency} — the shape the sibling formatters already use.
51
- * Callers should pass the tag from `useDisplayLocale()`.
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()`.
52
86
  *
53
87
  * Before objectui#4553 this function took no locale and never touched `Intl`:
54
88
  * its whole body was `${percentDisplayValue(value).toFixed(precision)}%`, so it
@@ -58,52 +92,37 @@ export declare function formatNumber(value: number, decimals?: number, locale?:
58
92
  * so the grouping and the locale are fixed together: en output MOVES from
59
93
  * `1235%` to `1,235%` at four digits and up, and that move is the fix.
60
94
  */
61
- 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;
62
96
  /**
63
- * Humanize a snake_case or kebab-case string into Title Case.
64
- * Used as fallback label when no explicit option.label exists.
97
+ * Humanize a snake_case or kebab-case string into Title Case — the fallback
98
+ * label when no explicit `option.label` exists.
65
99
  *
66
- * Examples:
67
- * "in_progress" → "In Progress"
68
- * "high-priority" → "High Priority"
69
- * "active" → "Active"
70
- */
71
- export declare function humanizeLabel(value: string): string;
72
- /** Options shared by {@link formatDate} / {@link formatRelativeDate}. */
73
- export interface DateDisplayOptions {
74
- dueLike?: boolean;
75
- /** BCP-47 display locale (ADR-0053 tenant default); falls back to the runtime locale. */
76
- locale?: string;
77
- /** i18n translate fn for phrases `Intl` can't produce (the "Overdue Nd" wording). */
78
- t?: (key: string, params?: Record<string, unknown>) => string;
79
- }
80
- /**
81
- * Format date as relative time (e.g., "3 days ago", "Today", "Overdue 3d"),
82
- * localized via `Intl.RelativeTimeFormat` (objectstack-ai/objectstack#3040).
83
- *
84
- * `dueLike` gates the "Overdue" wording — a past `start_date`/`created_at`
85
- * isn't overdue, only a past due/deadline-semantic field is. Non-due-like
86
- * past dates render as plain "N days ago" instead. The overdue phrase has no
87
- * `Intl` equivalent, so it resolves through `options.t` (key
88
- * `fields.relativeDate.overdue`) with an English fallback.
89
- */
90
- export declare function formatRelativeDate(value: string | Date | number, options?: DateDisplayOptions): string;
91
- /**
92
- * Format date value
93
- */
94
- export declare function formatDate(value: string | Date | number, style?: string, options?: DateDisplayOptions): string;
95
- /**
96
- * Format datetime value.
100
+ * Defined in `@object-ui/core` (`utils/humanize-label.ts`) and re-exported here
101
+ * because this package is one of its two doorways: `plugin-grid`,
102
+ * `plugin-gantt` and `plugin-detail` read it from `@object-ui/fields`, while
103
+ * `plugin-charts` reads the same function straight from core. Until
104
+ * objectui#5444 this file and `plugin-charts`' `ObjectChart.tsx` each held a
105
+ * byte-identical private copy; core is the shared ancestor both packages
106
+ * already depend on, so the convention has one home and no new dependency edge
107
+ * (objectui#4389: core-canonical logic, plugins consume). The core docstring
108
+ * carries the convention itself, and the reason it stays distinct from
109
+ * `humanizeFieldKey`'s camelCase-splitting KEY convention.
110
+ */
111
+ export { humanizeLabel };
112
+ /**
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.
97
116
  *
98
- * `options` mirrors {@link formatDate}'s and is optional, so an existing
99
- * caller that passes nothing keeps the exact runtime-default behavior it had.
100
- * Before objectui#4272 the parameter did not exist at all, which meant no
101
- * caller could localize this function however hard it tried — it always handed
102
- * `Intl` an `undefined` tag, i.e. the MACHINE's locale, which is neither of
103
- * the repo's two locale channels. Callers should pass the tag from
104
- * `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.
105
123
  */
106
- export declare function formatDateTime(value: string | Date | number, options?: DateDisplayOptions): string;
124
+ export { formatDate, formatDateTime, formatDateTimeCompactParts, formatRelativeDate };
125
+ export type { DateDisplayOptions };
107
126
  /**
108
127
  * Text field cell renderer
109
128
  */
@@ -133,7 +152,44 @@ export declare function DateCellRenderer({ value, field }: CellRendererProps): R
133
152
  /**
134
153
  * DateTime field cell renderer (Airtable-style with date and time visually separated)
135
154
  */
136
- export declare function DateTimeCellRenderer({ value }: CellRendererProps): React.ReactElement;
155
+ export declare function DateTimeCellRenderer({ value, field }: CellRendererProps): React.ReactElement;
156
+ /** The six pill colors plus the two dot colors derived from one declared hex. */
157
+ export interface HexBadgePalette {
158
+ bg: string;
159
+ fg: string;
160
+ border: string;
161
+ bgDark: string;
162
+ fgDark: string;
163
+ borderDark: string;
164
+ dot: string;
165
+ dotDark: string;
166
+ }
167
+ /**
168
+ * Derive a full soft-pill palette from an author-declared hex.
169
+ *
170
+ * The declared LIGHTNESS is what separates two same-hue tiers (`#2ecc71` is
171
+ * l=0.49, `#1e8449` is l=0.32 — their hues differ by 0.1°), so it has to
172
+ * survive into the *surface*. A fixed pale tint — the obvious reading of
173
+ * "compute a soft pill from the hex" — does not carry it: measured, that
174
+ * leaves the reported pair ΔE 2.3 apart in Lab, at the ~2.3 just-noticeable
175
+ * threshold, which would close this issue on paper while the user still cannot
176
+ * tell the two badges apart. Letting the tint depth track the declared
177
+ * lightness puts them ΔE 8.0 apart instead.
178
+ */
179
+ export declare function deriveHexBadgePalette(color: string): HexBadgePalette | undefined;
180
+ /** A className plus the custom properties it reads. */
181
+ export interface HexColorAppearance {
182
+ className: string;
183
+ style: React.CSSProperties;
184
+ }
185
+ /**
186
+ * Soft-pill appearance for an explicitly declared hex, or `undefined` for
187
+ * every other kind of declaration (family name, no colour at all) so the
188
+ * caller falls back to `getBadgeColorClasses`.
189
+ */
190
+ export declare function getBadgeHexAppearance(color?: string): HexColorAppearance | undefined;
191
+ /** Dot appearance for an explicitly declared hex (see `getBadgeHexAppearance`). */
192
+ export declare function getDotHexAppearance(color?: string): HexColorAppearance | undefined;
137
193
  export declare function getBadgeColorClasses(color?: string, val?: unknown): string;
138
194
  /**
139
195
  * Resolve a semantic color name (e.g. "red", "green") for a value, suitable
@@ -201,14 +257,19 @@ export declare function ImageCellRenderer({ value }: CellRendererProps): React.R
201
257
  * Display order:
202
258
  * 1. Embedded record object (`{ id, name, ... }` from `$expand`) → use its name
203
259
  * 2. Static `field.options[]` (e.g. when the lookup is a closed enum) → look up label
204
- * 3. Fetch-on-demand: when the value is a primitive ID and `field.reference_to`
260
+ * 3. Fetch-on-demand: when the value is a primitive ID and `field.reference`
205
261
  * is known, resolve via dataSource and show the related record's display name.
206
- * Falls back to a muted placeholder while pending and on failure.
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.
207
266
  *
208
267
  * Record → name resolution (1 and 3) goes through the referenced object's
209
268
  * schema when the data source exposes it (`displayField` → nameField/titleFormat
210
269
  * → derivation, see {@link resolveLookupRecordName}), so the chip and the
211
- * 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).
212
273
  */
213
274
  export declare function LookupCellRenderer({ value, field }: CellRendererProps): React.ReactElement;
214
275
  /**
@@ -217,8 +278,16 @@ export declare function LookupCellRenderer({ value, field }: CellRendererProps):
217
278
  export declare function FormulaCellRenderer({ value }: CellRendererProps): React.ReactElement;
218
279
  /**
219
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.
220
289
  */
221
- export declare function UserCellRenderer({ value }: CellRendererProps): React.ReactElement;
290
+ export declare function UserCellRenderer({ value, field }: CellRendererProps): React.ReactElement;
222
291
  /**
223
292
  * Register a custom field renderer
224
293
  * @param type Field type (e.g. 'text', 'location', 'my-custom-type')
@@ -246,14 +315,16 @@ export declare function JsonCellRenderer({ value }: CellRendererProps): React.Re
246
315
  */
247
316
  export declare function ColorSwatchCellRenderer({ value }: CellRendererProps): React.ReactElement;
248
317
  /**
249
- * Renders `markdown` / `richtext` values as formatted GFM markdown (lazy-loaded,
250
- * sanitized) instead of the raw markup string.
251
- */
252
- export declare function MarkdownCellRenderer({ value }: CellRendererProps): React.ReactElement;
253
- /**
254
- * Renders an `html` value as sanitized, formatted HTML instead of raw markup.
318
+ * The rich-content display pipelines — `markdown` through the GFM renderer,
319
+ * `html`/`richtext` through the sanitizing HTML renderer — live in
320
+ * `./widgets/richTextDisplay.js` rather than here, so `RichTextField` can
321
+ * import them without importing this barrel back (`4bb940b6e`). Re-exported
322
+ * unchanged: they are part of this package's published surface, and
323
+ * `RICH_TEXT_CELL_RENDERERS` below is the one table both the cell resolver and
324
+ * the widget's readonly branch read.
255
325
  */
256
- export declare function HtmlCellRenderer({ value }: CellRendererProps): React.ReactElement;
326
+ export { MarkdownCellRenderer, HtmlCellRenderer } from './widgets/richTextDisplay.js';
327
+ export { RICH_TEXT_FIELD_TYPES, type RichTextFieldType } from './widgets/richTextDisplay.js';
257
328
  /**
258
329
  * Renders a `location`/`geolocation` value as readable coordinates with a pin.
259
330
  * Accepts `{ lat, lng }` / `{ latitude, longitude }`, a `"lat,lng"` string,
@@ -280,11 +351,142 @@ export declare function LocationCellRenderer({ value }: CellRendererProps): Reac
280
351
  * is never silently swallowed by the fix.
281
352
  */
282
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[];
283
484
  /**
284
485
  * Get the appropriate cell renderer for a field type
285
486
  */
286
487
  export declare function getCellRenderer(fieldType: string): React.FC<CellRendererProps>;
287
- export { mapFieldTypeToFormType } from './field-type-alias';
488
+ export { mapFieldTypeToFormType } from './field-type-alias.js';
489
+ export { RETIRED_FIELD_TYPES, isRetiredFieldType, reportRetiredFieldType, resetRetiredFieldTypeReports, } from './field-type-alias.js';
288
490
  /**
289
491
  * Formats file size in bytes to human-readable string
290
492
  * @param bytes - File size in bytes (must be non-negative)
@@ -304,6 +506,235 @@ export declare function buildValidationRules(field: any): any;
304
506
  * @returns Whether the condition is met
305
507
  */
306
508
  export declare function evaluateCondition(condition: any, formData: any): boolean;
509
+ declare const fieldWidgetMap: {
510
+ text: () => Promise<{
511
+ default: React.ComponentType<any>;
512
+ } | {
513
+ default: typeof import('./widgets/TextField.js').TextField;
514
+ }>;
515
+ textarea: () => Promise<{
516
+ default: React.ComponentType<any>;
517
+ } | {
518
+ default: typeof import('./widgets/TextAreaField.js').TextAreaField;
519
+ }>;
520
+ number: () => Promise<{
521
+ default: React.ComponentType<any>;
522
+ } | {
523
+ default: typeof import('./widgets/NumberField.js').NumberField;
524
+ }>;
525
+ boolean: () => Promise<{
526
+ default: React.ComponentType<any>;
527
+ } | {
528
+ default: typeof import('./widgets/BooleanField.js').BooleanField;
529
+ }>;
530
+ select: () => Promise<{
531
+ default: React.ComponentType<any>;
532
+ } | {
533
+ default: typeof import('./widgets/SelectField.js').SelectField;
534
+ }>;
535
+ date: () => Promise<{
536
+ default: React.ComponentType<any>;
537
+ } | {
538
+ default: typeof import('./widgets/DateField.js').DateField;
539
+ }>;
540
+ datetime: () => Promise<{
541
+ default: React.ComponentType<any>;
542
+ } | {
543
+ default: typeof import('./widgets/DateTimeField.js').DateTimeField;
544
+ }>;
545
+ time: () => Promise<{
546
+ default: React.ComponentType<any>;
547
+ } | {
548
+ default: typeof import('./widgets/TimeField.js').TimeField;
549
+ }>;
550
+ email: () => Promise<{
551
+ default: React.ComponentType<any>;
552
+ } | {
553
+ default: typeof import('./widgets/EmailField.js').EmailField;
554
+ }>;
555
+ phone: () => Promise<{
556
+ default: React.ComponentType<any>;
557
+ } | {
558
+ default: typeof import('./widgets/PhoneField.js').PhoneField;
559
+ }>;
560
+ url: () => Promise<{
561
+ default: React.ComponentType<any>;
562
+ } | {
563
+ default: typeof import('./widgets/UrlField.js').UrlField;
564
+ }>;
565
+ multiselect: () => Promise<{
566
+ default: React.ComponentType<any>;
567
+ } | {
568
+ default: typeof import('./widgets/MultiSelectField.js').MultiSelectField;
569
+ }>;
570
+ radio: () => Promise<{
571
+ default: React.ComponentType<any>;
572
+ } | {
573
+ default: typeof import('./widgets/RadioField.js').RadioField;
574
+ }>;
575
+ checkboxes: () => Promise<{
576
+ default: React.ComponentType<any>;
577
+ } | {
578
+ default: typeof import('./widgets/CheckboxesField.js').CheckboxesField;
579
+ }>;
580
+ tags: () => Promise<{
581
+ default: React.ComponentType<any>;
582
+ } | {
583
+ default: typeof import('./widgets/TagsField.js').TagsField;
584
+ }>;
585
+ currency: () => Promise<{
586
+ default: React.ComponentType<any>;
587
+ } | {
588
+ default: typeof import('./widgets/CurrencyField.js').CurrencyField;
589
+ }>;
590
+ percent: () => Promise<{
591
+ default: React.ComponentType<any>;
592
+ } | {
593
+ default: typeof import('./widgets/PercentField.js').PercentField;
594
+ }>;
595
+ password: () => Promise<{
596
+ default: React.ComponentType<any>;
597
+ } | {
598
+ default: typeof import('./widgets/PasswordField.js').PasswordField;
599
+ }>;
600
+ markdown: () => Promise<{
601
+ default: React.ComponentType<any>;
602
+ } | {
603
+ default: typeof import('./widgets/RichTextField.js').RichTextField;
604
+ }>;
605
+ html: () => Promise<{
606
+ default: React.ComponentType<any>;
607
+ } | {
608
+ default: typeof import('./widgets/RichTextField.js').RichTextField;
609
+ }>;
610
+ richtext: () => Promise<{
611
+ default: React.ComponentType<any>;
612
+ } | {
613
+ default: typeof import('./widgets/RichTextField.js').RichTextField;
614
+ }>;
615
+ lookup: () => Promise<{
616
+ default: React.ComponentType<any>;
617
+ } | {
618
+ default: typeof import('./widgets/LookupField.js').LookupField;
619
+ }>;
620
+ master_detail: () => Promise<{
621
+ default: React.ComponentType<any>;
622
+ } | {
623
+ default: typeof import('./widgets/LookupField.js').LookupField;
624
+ }>;
625
+ file: () => Promise<{
626
+ default: React.ComponentType<any>;
627
+ } | {
628
+ default: typeof import('./widgets/FileField.js').FileField;
629
+ }>;
630
+ image: () => Promise<{
631
+ default: React.ComponentType<any>;
632
+ } | {
633
+ default: typeof import('./widgets/ImageField.js').ImageField;
634
+ }>;
635
+ location: () => Promise<{
636
+ default: React.ComponentType<any>;
637
+ } | {
638
+ default: typeof import('./widgets/LocationField.js').LocationField;
639
+ }>;
640
+ formula: () => Promise<{
641
+ default: React.ComponentType<any>;
642
+ } | {
643
+ default: typeof import('./widgets/FormulaField.js').FormulaField;
644
+ }>;
645
+ summary: () => Promise<{
646
+ default: React.ComponentType<any>;
647
+ } | {
648
+ default: typeof import('./widgets/SummaryField.js').SummaryField;
649
+ }>;
650
+ auto_number: () => Promise<{
651
+ default: React.ComponentType<any>;
652
+ } | {
653
+ default: typeof import('./widgets/AutoNumberField.js').AutoNumberField;
654
+ }>;
655
+ user: () => Promise<{
656
+ default: React.ComponentType<any>;
657
+ } | {
658
+ default: typeof import('./widgets/UserField.js').UserField;
659
+ }>;
660
+ object: () => Promise<{
661
+ default: React.ComponentType<any>;
662
+ } | {
663
+ default: typeof import('./widgets/ObjectField.js').ObjectField;
664
+ }>;
665
+ vector: () => Promise<{
666
+ default: React.ComponentType<any>;
667
+ } | {
668
+ default: typeof import('./widgets/VectorField.js').VectorField;
669
+ }>;
670
+ grid: () => Promise<{
671
+ default: React.ComponentType<any>;
672
+ } | {
673
+ default: typeof import('./widgets/GridField.js').GridField;
674
+ }>;
675
+ color: () => Promise<{
676
+ default: React.ComponentType<any>;
677
+ } | {
678
+ default: typeof import('./widgets/ColorField.js').ColorField;
679
+ }>;
680
+ slider: () => Promise<{
681
+ default: React.ComponentType<any>;
682
+ } | {
683
+ default: typeof import('./widgets/SliderField.js').SliderField;
684
+ }>;
685
+ rating: () => Promise<{
686
+ default: React.ComponentType<any>;
687
+ } | {
688
+ default: typeof import('./widgets/RatingField.js').RatingField;
689
+ }>;
690
+ code: () => Promise<{
691
+ default: React.ComponentType<any>;
692
+ } | {
693
+ default: typeof import('./widgets/CodeField.js').CodeField;
694
+ }>;
695
+ avatar: () => Promise<{
696
+ default: React.ComponentType<any>;
697
+ } | {
698
+ default: typeof import('./widgets/AvatarField.js').AvatarField;
699
+ }>;
700
+ address: () => Promise<{
701
+ default: React.ComponentType<any>;
702
+ } | {
703
+ default: typeof import('./widgets/AddressField.js').AddressField;
704
+ }>;
705
+ geolocation: () => Promise<{
706
+ default: React.ComponentType<any>;
707
+ } | {
708
+ default: typeof import('./widgets/GeolocationField.js').GeolocationField;
709
+ }>;
710
+ signature: () => Promise<{
711
+ default: React.ComponentType<any>;
712
+ } | {
713
+ default: typeof import('./widgets/SignatureField.js').SignatureField;
714
+ }>;
715
+ qrcode: () => Promise<{
716
+ default: React.ComponentType<any>;
717
+ } | {
718
+ default: typeof import('./widgets/QRCodeField.js').QRCodeField;
719
+ }>;
720
+ 'object-ref': () => Promise<{
721
+ default: React.ComponentType<any>;
722
+ } | {
723
+ default: typeof import('./widgets/ObjectRefField.js').ObjectRefField;
724
+ }>;
725
+ 'filter-condition': () => Promise<{
726
+ default: React.ComponentType<any>;
727
+ } | {
728
+ default: typeof import('./widgets/FilterConditionField.js').FilterConditionField;
729
+ }>;
730
+ 'recipient-picker': () => Promise<{
731
+ default: React.ComponentType<any>;
732
+ } | {
733
+ default: typeof import('./widgets/RecipientPickerField.js').RecipientPickerField;
734
+ }>;
735
+ };
736
+ /** The registered field widget keys, as a literal union (objectui#4857). */
737
+ export type RegisteredFieldWidgetType = keyof typeof fieldWidgetMap;
307
738
  /**
308
739
  * Every field type the form can render (the canonical list of supported types).
309
740
  * Exported so inline editing can be checked against it — a form type must
@@ -323,6 +754,18 @@ export declare const FORM_FIELD_TYPES: readonly string[];
323
754
  * support can never drift behind the form surface (ADR-0059).
324
755
  */
325
756
  export declare function resolveFormWidgetType(fieldType: string): string;
757
+ /**
758
+ * The widget keys that must be fed the live record (`dependentValues`) so their
759
+ * offered option set can be re-resolved per option `visibleWhen` / `dependsOn`.
760
+ *
761
+ * Defined in `@object-ui/core`, next to `resolveCascadingOptions` — the
762
+ * evaluator that reads the record — and re-exported here because this is the
763
+ * package whose {@link resolveFormWidgetType} produces the keys the set is
764
+ * keyed on: a consumer resolving a widget key finds the allow-table in the
765
+ * same place. One definition, two doorways; never a second copy (objectui#4770,
766
+ * which converged the three private copies that preceded it).
767
+ */
768
+ export { CASCADE_OPTION_WIDGET_TYPES } from '@object-ui/core';
326
769
  /**
327
770
  * Lazily-loaded form field widget for a field type. Shares the exact loaders
328
771
  * of {@link fieldWidgetMap} (the same components `registerField` registers for
@@ -332,6 +775,59 @@ export declare function resolveFormWidgetType(fieldType: string): string;
332
775
  * widget via {@link resolveFormWidgetType}.
333
776
  */
334
777
  export declare function getLazyFieldWidget(fieldType: string): React.ComponentType<any>;
778
+ /**
779
+ * The labelling declaration of EVERY registered field widget
780
+ * (`ComponentMeta.labelling` — the closed `'control' | 'group' | 'display'`
781
+ * vocabulary, objectui#3961 extended by objectui#4857). This `Record` is keyed
782
+ * by the widget map's own literal key union, so it is exhaustive BY
783
+ * CONSTRUCTION: registering a widget without deciding how a host's label
784
+ * reaches it is a COMPILE error here, not a silent fall-through to the
785
+ * `'control'` path — the omitted-declaration degradation is exactly the trap
786
+ * the #4857 ruling named, and it is what turned the display-only four into
787
+ * fields with no accessible name.
788
+ *
789
+ * ## `'group'` — a surface no `<label for>` can reach; the WIDGET consumes the IDREF
790
+ *
791
+ * Two shapes, one declaration:
792
+ *
793
+ * - real composites — `address` / `geolocation` render several inputs under one
794
+ * container, `checkboxes` / `radio` / `rating` / `multiselect` a set of
795
+ * choice controls, and `grid` a whole table of cell inputs plus row actions;
796
+ * the host's label names the GROUP, each sub-control keeps its own name (a
797
+ * sub-label, the chip's text content, or a cell's own `aria-label`).
798
+ * - single non-labelable controls — `file`'s one control is a
799
+ * `div[role="button"]` dropzone, `slider`'s is Radix's `span[role="slider"]`
800
+ * thumb (objectui#3318), `signature`'s drawing surface is a `<canvas>`
801
+ * (objectui#3318). A `div`/`span`/`canvas` cannot be `for`-labelled, so the
802
+ * name goes by IDREF to the control (or, for `signature`, its container).
803
+ *
804
+ * Measured, not assumed: every `'group'` entry was verified in a real form —
805
+ * the #3961/#3975 probes for the first seven, the #3318 delivery for
806
+ * `slider`/`signature`, and the #4857 re-measurement for `grid` (bare config:
807
+ * one focusable, the auxiliary "Add line" BUTTON — routing `for` there would
808
+ * have label clicks INSERT A ROW; realistic config: 8 focusables across cell
809
+ * inputs and row actions — a composite, not a single control).
810
+ *
811
+ * ## `'display'` — a pure display in EVERY state; the HOST wraps (objectui#4857)
812
+ *
813
+ * `formula` / `summary` / `auto_number` / `vector` have no editable branch at
814
+ * all: the whole widget is a replacement display with no focusable control, in
815
+ * the editable state as much as the readonly one (on the real object-form path
816
+ * they arrive `disabled`, never `readonly`, so the #4788 readonly gate could
817
+ * not cover them). The form renderer answers the declaration with its own
818
+ * wrapper — id + `aria-labelledby` + `aria-describedby` + `role="group"`, the
819
+ * #4788 container — and the label emits no `for`. The widgets spread nothing,
820
+ * by design; the host is the named surface.
821
+ *
822
+ * ## `'control'` — everything else
823
+ *
824
+ * The host's `<label for>` reaches a real labelable element. At registration
825
+ * this is deliberately spelled as ABSENCE of the meta key (one spelling of the
826
+ * default, objectui#3961), so hosts keep one rule for these and for
827
+ * out-of-registry widgets alike; the entry here is still mandatory, because
828
+ * "defaulted by omission" and "decided to be the default" are different facts.
829
+ */
830
+ export declare const FIELD_WIDGET_LABELLING: Record<RegisteredFieldWidgetType, NonNullable<ComponentMeta['labelling']>>;
335
831
  export declare function registerField(fieldType: string): void;
336
832
  /**
337
833
  * Register all field types (for backward compatibility)
@@ -343,59 +839,88 @@ export declare function registerField(fieldType: string): void;
343
839
  * // Register all fields at once
344
840
  * registerAllFields();
345
841
  */
842
+ /**
843
+ * The widget a RETIRED field-type spelling renders (objectui#4814).
844
+ *
845
+ * Shape borrowed from the form renderer's spec-vocabulary boundary (#3090),
846
+ * which is this repo's settled answer to "an authored entry this renderer
847
+ * cannot honour": an inline alert that NAMES the offending entry, plus a
848
+ * `console.error` whose text doubles as the fix instruction. Nothing is thrown
849
+ * — one retired field must not take down the rest of a record form — but
850
+ * nothing is silently substituted either, which is the whole point: the author
851
+ * sees a refusal where they expected an input, not a text box that looks like
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.
864
+ */
865
+ export declare const RetiredFieldTombstone: React.FC<Record<string, any>>;
346
866
  export declare function registerAllFields(): void;
347
- export * from './widgets/types';
348
- export * from './widgets/file-value';
349
- export * from './FieldEditWidget';
350
- export * from './widgets/TextField';
351
- export * from './widgets/NumberField';
352
- export * from './widgets/BooleanField';
353
- export * from './widgets/SelectField';
354
- export * from './widgets/DateField';
355
- export * from './widgets/DateTimeField';
356
- export * from './widgets/TimeField';
357
- export * from './widgets/EmailField';
358
- export * from './widgets/PhoneField';
359
- export * from './widgets/UrlField';
360
- export * from './widgets/CurrencyField';
361
- export * from './widgets/PercentField';
362
- export * from './widgets/PasswordField';
363
- export * from './widgets/TextAreaField';
364
- export * from './widgets/RichTextField';
365
- export * from './widgets/LookupField';
366
- export * from './widgets/CapabilityMultiSelectField';
367
- export * from './widgets/ObjectRefField';
368
- export * from './widgets/FilterConditionField';
369
- export * from './widgets/RecipientPickerField';
370
- export * from './widgets/RecordPickerDialog';
371
- export * from './widgets/deriveLookupColumns';
372
- export * from './widgets/FileField';
373
- export * from './widgets/ImageField';
374
- export { ImageCropperDialog } from './widgets/ImageCropperDialog';
375
- export type { ImageCropperDialogProps } from './widgets/ImageCropperDialog';
376
- export * from './widgets/LocationField';
377
- export * from './widgets/FormulaField';
378
- export * from './widgets/SummaryField';
379
- export * from './widgets/AutoNumberField';
380
- export * from './widgets/UserField';
381
- export * from './widgets/ObjectField';
382
- export * from './widgets/VectorField';
383
- export * from './widgets/GridField';
384
- export * from './widgets/ColorField';
385
- export * from './widgets/SliderField';
386
- export * from './widgets/RatingField';
387
- export * from './widgets/CodeField';
388
- export * from './widgets/AvatarField';
389
- export * from './widgets/AddressField';
390
- export * from './widgets/GeolocationField';
391
- export * from './widgets/SignatureField';
392
- export * from './widgets/QRCodeField';
393
- export * from './widgets/MasterDetailField';
394
- export * from './widgets/MultiSelectField';
395
- export * from './widgets/RadioField';
396
- export * from './widgets/CheckboxesField';
397
- export * from './widgets/TagsField';
398
- export { withFieldCarrier } from './withFieldCarrier';
399
- export { toDomProps } from './widgets/toDomProps';
400
- export type { DomProps } from './widgets/toDomProps';
401
- export { toDateInputValue, toDateTimeInputValue, fromDateTimeInputValue, } from './widgets/nativeDateValue';
867
+ export * from './widgets/types.js';
868
+ export * from './widgets/file-value.js';
869
+ export * from './FieldEditWidget.js';
870
+ export * from './widgets/TextField.js';
871
+ export * from './widgets/NumberField.js';
872
+ export * from './widgets/BooleanField.js';
873
+ export * from './widgets/SelectField.js';
874
+ export * from './widgets/DateField.js';
875
+ export * from './widgets/DateTimeField.js';
876
+ export * from './widgets/TimeField.js';
877
+ export * from './widgets/EmailField.js';
878
+ export * from './widgets/PhoneField.js';
879
+ export * from './widgets/UrlField.js';
880
+ export * from './widgets/CurrencyField.js';
881
+ export * from './widgets/PercentField.js';
882
+ export * from './widgets/PasswordField.js';
883
+ export * from './widgets/TextAreaField.js';
884
+ export * from './widgets/RichTextField.js';
885
+ export * from './widgets/LookupField.js';
886
+ export * from './widgets/CapabilityMultiSelectField.js';
887
+ export * from './widgets/ObjectRefField.js';
888
+ export * from './widgets/FilterConditionField.js';
889
+ export * from './widgets/RecipientPickerField.js';
890
+ export * from './widgets/RecordPickerDialog.js';
891
+ export * from './widgets/deriveLookupColumns.js';
892
+ export * from './widgets/FileField.js';
893
+ export * from './widgets/ImageField.js';
894
+ export { ImageCropperDialog } from './widgets/ImageCropperDialog.js';
895
+ export type { ImageCropperDialogProps } from './widgets/ImageCropperDialog.js';
896
+ export * from './widgets/LocationField.js';
897
+ export * from './widgets/FormulaField.js';
898
+ export * from './widgets/SummaryField.js';
899
+ export * from './widgets/AutoNumberField.js';
900
+ export * from './widgets/UserField.js';
901
+ export * from './widgets/ObjectField.js';
902
+ export * from './widgets/VectorField.js';
903
+ export * from './widgets/GridField.js';
904
+ export * from './widgets/ColorField.js';
905
+ export * from './widgets/SliderField.js';
906
+ export * from './widgets/RatingField.js';
907
+ export * from './widgets/CodeField.js';
908
+ export * from './widgets/AvatarField.js';
909
+ export * from './widgets/AddressField.js';
910
+ export * from './widgets/GeolocationField.js';
911
+ export * from './widgets/SignatureField.js';
912
+ export * from './widgets/QRCodeField.js';
913
+ export * from './widgets/MasterDetailField.js';
914
+ export * from './widgets/MultiSelectField.js';
915
+ export * from './widgets/RadioField.js';
916
+ export * from './widgets/CheckboxesField.js';
917
+ export * from './widgets/TagsField.js';
918
+ export { withFieldCarrier } from './withFieldCarrier.js';
919
+ export { toDomProps } from './widgets/toDomProps.js';
920
+ export type { DomProps } from './widgets/toDomProps.js';
921
+ export { toHostProps } from './widgets/toHostProps.js';
922
+ export type { HostProps } from './widgets/toHostProps.js';
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';