@object-ui/plugin-detail 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 (92) hide show
  1. package/CHANGELOG.md +7216 -0
  2. package/README.md +442 -74
  3. package/dist/ActivityTimeline.d.ts.map +1 -1
  4. package/dist/CommentAttachment.d.ts.map +1 -1
  5. package/dist/ConcurrentUpdateDialog.d.ts +17 -1
  6. package/dist/ConcurrentUpdateDialog.d.ts.map +1 -1
  7. package/dist/DetailSection.d.ts.map +1 -1
  8. package/dist/DetailSectionNode.d.ts +97 -0
  9. package/dist/DetailSectionNode.d.ts.map +1 -0
  10. package/dist/DetailView.d.ts.map +1 -1
  11. package/dist/HeaderHighlight.d.ts.map +1 -1
  12. package/dist/HistoryTimeline.d.ts +8 -1
  13. package/dist/HistoryTimeline.d.ts.map +1 -1
  14. package/dist/InlineEditSaveBar.d.ts +68 -0
  15. package/dist/InlineEditSaveBar.d.ts.map +1 -1
  16. package/dist/InlineFieldInput.d.ts +79 -6
  17. package/dist/InlineFieldInput.d.ts.map +1 -1
  18. package/dist/ReactionPicker.d.ts.map +1 -1
  19. package/dist/RecordActivityTimeline.d.ts +19 -4
  20. package/dist/RecordActivityTimeline.d.ts.map +1 -1
  21. package/dist/RecordChatterPanel.d.ts +6 -1
  22. package/dist/RecordChatterPanel.d.ts.map +1 -1
  23. package/dist/RecordComments.d.ts +1 -0
  24. package/dist/RecordComments.d.ts.map +1 -1
  25. package/dist/RecordDetailDrawer.d.ts +20 -6
  26. package/dist/RecordDetailDrawer.d.ts.map +1 -1
  27. package/dist/RecordDetailPanel.d.ts +101 -0
  28. package/dist/RecordDetailPanel.d.ts.map +1 -0
  29. package/dist/RecordMetaFooter.d.ts +1 -1
  30. package/dist/RecordMetaFooter.d.ts.map +1 -1
  31. package/dist/RelatedList.d.ts +94 -10
  32. package/dist/RelatedList.d.ts.map +1 -1
  33. package/dist/ThreadedReplies.d.ts +1 -1
  34. package/dist/ThreadedReplies.d.ts.map +1 -1
  35. package/dist/emptiness.d.ts +142 -0
  36. package/dist/emptiness.d.ts.map +1 -0
  37. package/dist/fieldEnrichment.d.ts +44 -4
  38. package/dist/fieldEnrichment.d.ts.map +1 -1
  39. package/dist/headerColor.d.ts +20 -0
  40. package/dist/headerColor.d.ts.map +1 -0
  41. package/dist/index.d.ts +181 -76
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +5259 -5567
  44. package/dist/index.umd.cjs +2 -5
  45. package/dist/renderers/record-activity.d.ts.map +1 -1
  46. package/dist/renderers/record-alert.d.ts +83 -13
  47. package/dist/renderers/record-alert.d.ts.map +1 -1
  48. package/dist/renderers/record-alert.readProps.d.ts +40 -0
  49. package/dist/renderers/record-alert.readProps.d.ts.map +1 -0
  50. package/dist/renderers/record-chatter.d.ts.map +1 -1
  51. package/dist/renderers/record-details.d.ts +2 -0
  52. package/dist/renderers/record-details.d.ts.map +1 -1
  53. package/dist/renderers/record-highlights.d.ts.map +1 -1
  54. package/dist/renderers/record-history.d.ts +1 -1
  55. package/dist/renderers/record-history.d.ts.map +1 -1
  56. package/dist/renderers/record-path.d.ts.map +1 -1
  57. package/dist/renderers/record-quick-actions.d.ts +20 -3
  58. package/dist/renderers/record-quick-actions.d.ts.map +1 -1
  59. package/dist/renderers/record-reference-rail.d.ts +42 -17
  60. package/dist/renderers/record-reference-rail.d.ts.map +1 -1
  61. package/dist/renderers/record-related-list.d.ts +37 -3
  62. package/dist/renderers/record-related-list.d.ts.map +1 -1
  63. package/dist/renderers/recordActivityFeed.d.ts +352 -13
  64. package/dist/renderers/recordActivityFeed.d.ts.map +1 -1
  65. package/dist/renderers/recordComponentAria.d.ts +44 -0
  66. package/dist/renderers/recordComponentAria.d.ts.map +1 -0
  67. package/dist/renderers/relatedListActions.d.ts +102 -0
  68. package/dist/renderers/relatedListActions.d.ts.map +1 -0
  69. package/dist/summaryChipPercent.d.ts +83 -0
  70. package/dist/summaryChipPercent.d.ts.map +1 -0
  71. package/dist/summaryChipRenderers.d.ts +83 -0
  72. package/dist/summaryChipRenderers.d.ts.map +1 -0
  73. package/dist/synth/buildDefaultPageSchema.d.ts +98 -17
  74. package/dist/synth/buildDefaultPageSchema.d.ts.map +1 -1
  75. package/dist/useDetailTranslation.d.ts.map +1 -1
  76. package/dist/useRecordEditable.d.ts +1 -1
  77. package/dist/useRecordEditable.d.ts.map +1 -1
  78. package/package.json +20 -18
  79. package/dist/CommentInput.d.ts +0 -24
  80. package/dist/CommentInput.d.ts.map +0 -1
  81. package/dist/DiffView.d.ts +0 -24
  82. package/dist/DiffView.d.ts.map +0 -1
  83. package/dist/InlineCreateRelated.d.ts +0 -32
  84. package/dist/InlineCreateRelated.d.ts.map +0 -1
  85. package/dist/MentionAutocomplete.d.ts +0 -43
  86. package/dist/MentionAutocomplete.d.ts.map +0 -1
  87. package/dist/PointInTimeRestore.d.ts +0 -28
  88. package/dist/PointInTimeRestore.d.ts.map +0 -1
  89. package/dist/RecordNavigationEnhanced.d.ts +0 -18
  90. package/dist/RecordNavigationEnhanced.d.ts.map +0 -1
  91. package/dist/RelationshipGraph.d.ts +0 -23
  92. package/dist/RelationshipGraph.d.ts.map +0 -1
@@ -0,0 +1,101 @@
1
+ import { default as React } from 'react';
2
+ import { DataSource } from '@object-ui/types';
3
+ /**
4
+ * Field names hidden from the quick-look overlay / inline edit form.
5
+ *
6
+ * Scope: this is the OVERLAY allow-list — used to keep the slim panel UI
7
+ * focused on author-defined business fields. The full record detail page
8
+ * (`RecordDetailView`) surfaces audit fields via a compact
9
+ * `<RecordMetaFooter>` (single-line, muted) rather than a heavy panel, so
10
+ * users can still see who/when created or last touched a record.
11
+ *
12
+ * Derived from the shared `SYSTEM_MANAGED_FIELD_NAMES` — the same set the grid's
13
+ * default-column derivation uses — so it stays in lockstep with the fields
14
+ * `applySystemFields` injects (audit `*_at`/`*_by`, the ownership/tenant FKs,
15
+ * soft-delete bookkeeping). Callers can still override via the `systemFields` prop.
16
+ */
17
+ export declare const DEFAULT_SYSTEM_FIELDS: Set<string>;
18
+ export interface RecordDetailPanelProps {
19
+ /** The record being displayed. */
20
+ record: Record<string, any>;
21
+ /** Logical object name used by the data source. */
22
+ objectName: string;
23
+ /** Record id (string-coerced before issuing update/delete). */
24
+ recordId: string | number;
25
+ /** Active data source — used for inline updates and deletion. */
26
+ dataSource?: DataSource;
27
+ /**
28
+ * Optional objectSchema (as returned by `dataSource.getObjectSchema`).
29
+ * When provided the panel infers field types so dates / picklists /
30
+ * currency render with their proper widgets.
31
+ */
32
+ objectSchema?: {
33
+ fields?: Record<string, any>;
34
+ } | null;
35
+ /** Number of columns the field grid should use. Default `2`. */
36
+ columns?: number;
37
+ /**
38
+ * Optional override for the SYSTEM_FIELDS filter. Defaults to a
39
+ * standard set (id, timestamps, audit fields).
40
+ */
41
+ systemFields?: Set<string>;
42
+ /**
43
+ * Persist an inline field edit. Plugins usually update local state
44
+ * here so the panel stays in sync after the network round-trip.
45
+ */
46
+ onFieldSave?: (field: string, value: unknown) => void | Promise<void>;
47
+ /**
48
+ * Persist record deletion. Plugins are expected to remove the record
49
+ * from their local state; the host is asked to close via `onClose`
50
+ * after this resolves.
51
+ */
52
+ onDelete?: () => void | Promise<void>;
53
+ /**
54
+ * Dismiss the overlay. Called after a successful delete. The shell owns
55
+ * every other way of closing.
56
+ */
57
+ onClose?: () => void;
58
+ /**
59
+ * Optional URL to the full record page. When provided, the panel adds an
60
+ * "Open in new tab" entry to `DetailView`'s header overflow menu.
61
+ * Typically `/console/apps/{appName}/{objectName}/record/{recordId}`.
62
+ */
63
+ fullPageHref?: string;
64
+ }
65
+ /**
66
+ * Build `DetailView`'s typed field list from an object schema.
67
+ *
68
+ * Exported because the derivation — not just the JSX — is what the five
69
+ * renderers share; a second hand-written copy is exactly the fork this card
70
+ * exists to remove.
71
+ */
72
+ export declare function buildRecordDetailFields(record: Record<string, any>, objectSchema: {
73
+ fields?: Record<string, any>;
74
+ } | null | undefined, systemFields: Set<string>): Array<Record<string, any>>;
75
+ /**
76
+ * The default overlay width, and the single code home of this literal
77
+ * repo-wide.
78
+ *
79
+ * The gantt, kanban and calendar renderers deliberately spell no `width` of
80
+ * their own and let an unauthored `navigation.width` fall through to this
81
+ * value. Converging it on the `size: 'lg'` bucket (`min(92vw, 960px)` — up to
82
+ * 53% wider below a 1600px viewport) was RULED AGAINST: objectui#6584,
83
+ * 2026-08-27 — stays on the CSS literal; no bucket convergence. The question is
84
+ * CLOSED, not open.
85
+ *
86
+ * ⚠️ It became an EXPORT with objectui#9299. Before that it was
87
+ * `RecordDetailDrawer`'s default parameter, reached by passing `undefined`;
88
+ * the renderers no longer go through that component, so they read the constant
89
+ * instead. ⛔ Do not re-spell the literal at a call site — four copies of a
90
+ * ruled-on number is how the four surfaces drift apart.
91
+ *
92
+ * `NavigationOverlay` treats an authored width as a FLOOR
93
+ * (`max(WIDTH, min(60vw, 880px))`), and for this value that expression reduces
94
+ * to `min(60vw, 960px)` at every viewport — i.e. the same pixels the old
95
+ * inline style set.
96
+ */
97
+ export declare const RECORD_OVERLAY_DEFAULT_WIDTH = "min(960px, 60vw)";
98
+ /** The record overlay payload — shell-free by construction. */
99
+ export declare function RecordDetailPanel({ record, objectName, recordId, dataSource, objectSchema, columns, systemFields, onFieldSave, onDelete, onClose, fullPageHref, }: RecordDetailPanelProps): React.JSX.Element;
100
+ export default RecordDetailPanel;
101
+ //# sourceMappingURL=RecordDetailPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RecordDetailPanel.d.ts","sourceRoot":"","sources":["../src/RecordDetailPanel.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAOnD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,qBAAqB,aAAsC,CAAC;AAEzE,MAAM,WAAW,sBAAsB;IACrC,kCAAkC;IAClC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,mDAAmD;IACnD,UAAU,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,iEAAiE;IACjE,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB;;;;OAIG;IACH,YAAY,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;KAAE,GAAG,IAAI,CAAC;IACvD,gEAAgE;IAChE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,YAAY,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3B;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtE;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,YAAY,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,EACjE,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,GACxB,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CA8F5B;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,4BAA4B,qBAAqB,CAAC;AAE/D,+DAA+D;AAC/D,wBAAgB,iBAAiB,CAAC,EAChC,MAAM,EACN,UAAU,EACV,QAAQ,EACR,UAAU,EACV,YAAY,EACZ,OAAW,EACX,YAAoC,EACpC,WAAW,EACX,QAAQ,EACR,OAAO,EACP,YAAY,GACb,EAAE,sBAAsB,qBAyExB;AAED,eAAe,iBAAiB,CAAC"}
@@ -9,7 +9,7 @@ import * as React from 'react';
9
9
  export interface RecordMetaFooterProps {
10
10
  /** The current record data; expected to contain audit fields when available. */
11
11
  data: Record<string, any> | null | undefined;
12
- /** Resolved object schema (used to read reference_to for created_by/updated_by). */
12
+ /** Resolved object schema (used to read `reference` for created_by/updated_by). */
13
13
  objectSchema?: any;
14
14
  /** Object name for future i18n hooks (currently unused). */
15
15
  objectName?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"RecordMetaFooter.d.ts","sourceRoot":"","sources":["../src/RecordMetaFooter.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAc/B,MAAM,WAAW,qBAAqB;IACpC,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;IAC7C,oFAAoF;IACpF,YAAY,CAAC,EAAE,GAAG,CAAC;IACnB,4DAA4D;IAC5D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA0HD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CA4D5D,CAAC"}
1
+ {"version":3,"file":"RecordMetaFooter.d.ts","sourceRoot":"","sources":["../src/RecordMetaFooter.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAgB/B,MAAM,WAAW,qBAAqB;IACpC,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;IAC7C,mFAAmF;IACnF,YAAY,CAAC,EAAE,GAAG,CAAC;IACnB,4DAA4D;IAC5D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAsKD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAiE5D,CAAC"}
@@ -23,6 +23,17 @@ export interface RelatedListProps {
23
23
  objectName?: string;
24
24
  /** Callback when "New" button is clicked */
25
25
  onNew?: () => void;
26
+ /**
27
+ * [#4646] Render "New" GREYED rather than clickable. Supplied by the host
28
+ * alongside `onNew` when the create affordance exists for this list but its
29
+ * `userActions.create.disabledWhen` predicate answers true for the record in
30
+ * scope (the parent record, on a record page's related list).
31
+ *
32
+ * Deliberately distinct from omitting `onNew` — which HIDES the button. Same
33
+ * hidden-vs-disabled split the row Edit/Delete predicates have had since
34
+ * objectui#2614.
35
+ */
36
+ newDisabled?: boolean;
26
37
  /** Callback when "View All" button is clicked */
27
38
  onViewAll?: () => void;
28
39
  /** Callback when a row Edit action is clicked */
@@ -53,11 +64,27 @@ export interface RelatedListProps {
53
64
  linkField?: string;
54
65
  label?: string;
55
66
  };
56
- /** Callback when a row is clicked (opens record detail) */
57
- onRowClick?: (row: any) => void;
58
67
  /**
59
- * Child-object row actions (`locations: ['list_item']`), already localized
60
- * by the host. Rendered in each row's overflow menu alongside Edit/Delete.
68
+ * Callback when a row is clicked (opens record detail).
69
+ *
70
+ * TWO parameters since objectui#9357, and the second is not decoration: this
71
+ * prop reaches `useNavigationOverlay` as its `onRowClick`, and `handleClick`
72
+ * invokes it as `onRowClick(record, event)` — the modifier payload a host
73
+ * needs to implement Cmd/Ctrl/middle-click for itself. Declaring one
74
+ * parameter hid the second on the ONE line a host reads. Spelled `any` and
75
+ * not `HandleClickModifiers` for the reason objectui#9341 measured on
76
+ * `ObjectKanbanSchema.onCardClick`: that interface lives in
77
+ * `@object-ui/react`, the published twins in `@object-ui/types` may not name
78
+ * it, and a host that discovered the payload from the implementation
79
+ * annotated it `React.MouseEvent` — which a narrower declaration refuses
80
+ * contravariantly. `BaseSchema`'s own `onClick` / `onChange` / `onSubmit`
81
+ * already use this spelling for exactly this situation.
82
+ */
83
+ onRowClick?: (row: any, event?: any) => void;
84
+ /**
85
+ * Child-object row actions (`locations` `list_item`, or `record_related`
86
+ * inside a parent record — objectui#11270), already localized by the host.
87
+ * Rendered in each row's overflow menu alongside Edit/Delete.
61
88
  */
62
89
  rowActions?: RelatedRowActionDef[];
63
90
  /** Execute one of {@link rowActions} against the clicked row. */
@@ -70,6 +97,26 @@ export interface RelatedListProps {
70
97
  toolbarActions?: RelatedRowActionDef[];
71
98
  /** Execute one of {@link toolbarActions} (no row context). */
72
99
  onToolbarAction?: (action: RelatedRowActionDef) => void | Promise<void>;
100
+ /**
101
+ * Field names this list must never show, whatever decided its columns
102
+ * (objectui#9053).
103
+ *
104
+ * The block-level authoring preference `record:related_list` reads as
105
+ * `redactFields`, pushed down to the component that actually decides
106
+ * columns. It used to be applied only where the block could apply it — over
107
+ * the AUTHORED `columns` array — and this component has two more paths that
108
+ * decide columns on their own (`highlightFields` prominence and the
109
+ * heuristic field walk), which that list never reached. Redacting EVERY
110
+ * authored column therefore emptied the array, the empty array read as "no
111
+ * columns were authored", and the derived set brought the redacted field
112
+ * straight back: applying the control maximally switched it off.
113
+ *
114
+ * ⚠️ This is an AUTHORING preference, not the permission boundary. Field
115
+ * security is enforced independently and unconditionally through
116
+ * `perms.checkField(..., 'read')` on every path below; a field that must be
117
+ * unreachable belongs in FLS, not here.
118
+ */
119
+ redactFields?: string[];
73
120
  /** Maximum number of columns to auto-generate. Default 6. */
74
121
  maxColumns?: number;
75
122
  /** Page size for pagination (enables pagination when set) */
@@ -93,6 +140,9 @@ export interface RelatedListProps {
93
140
  * since objectui#3106 they sort the collection rather than the page, so the
94
141
  * button row above them would be a second control over the same order.
95
142
  *
143
+ * A masked column (a `password` / `secret` field, or any column while the
144
+ * object's field types are still unknown) gets no button (objectui#10728).
145
+ *
96
146
  * @default false
97
147
  */
98
148
  sortable?: boolean;
@@ -119,7 +169,12 @@ export interface RelatedListProps {
119
169
  * second conversion dialect appears.
120
170
  */
121
171
  filter?: ViewFilterRule[] | FilterNode;
122
- /** Enable text filtering */
172
+ /**
173
+ * Enable text filtering. The box keeps a row when a column the list shows
174
+ * contains the term; a masked column (a `password` / `secret` field, or any
175
+ * column while the object's field types are still unknown) and a field no
176
+ * column shows are not searched (objectui#10728).
177
+ */
123
178
  filterable?: boolean;
124
179
  /** Whether the card is collapsible */
125
180
  collapsible?: boolean;
@@ -129,15 +184,32 @@ export interface RelatedListProps {
129
184
  * Foreign-key field name on child records pointing back to the parent.
130
185
  * The renderer hides this column from the table and from the schema-derived
131
186
  * column list, since the parent record is already implicit context.
132
- * Used in combination with `parentId` to scope the auto-fetch query.
187
+ * Used in combination with `parentId` to scope the auto-fetch query — its
188
+ * ARITY on the child object decides how that condition is compiled, see
189
+ * `parentId` below.
133
190
  */
134
191
  referenceField?: string;
135
192
  /**
136
193
  * Primary-key value of the parent record. When both `parentId` and
137
- * `referenceField` are set, the auto-fetch query is scoped with
138
- * `$filter: { [referenceField]: parentId }` so only true children
139
- * are returned. Without this scope the list would dump the entire
140
- * target object table.
194
+ * `referenceField` are set, the auto-fetch query is scoped to this parent's
195
+ * children so only true children are returned. Without this scope the list
196
+ * would dump the entire target object table.
197
+ *
198
+ * The condition is compiled to match the relationship field's ARITY on the
199
+ * child object (objectui#7299), because the two arities are two different
200
+ * questions about the stored value:
201
+ *
202
+ * - single-valued → `$filter: { [referenceField]: parentId }` — equality,
203
+ * byte for byte what this component has always sent;
204
+ * - `multiple: true` → `$filter: { [referenceField]: { $contains: parentId } }`
205
+ * — MEMBERSHIP, because the stored value is an ARRAY of ids and equality
206
+ * asks whether the whole array IS one id.
207
+ *
208
+ * The verdict is `@objectstack/spec/data`'s own `isMultiValueField`, not a
209
+ * local rule, and it is reached through `@object-ui/core`'s
210
+ * {@link composeParentScopeFilter} — the ONE compiler of this condition,
211
+ * shared with the tab-badge count probe that used to carry a second one
212
+ * (objectui#8882).
141
213
  */
142
214
  parentId?: string | number;
143
215
  /** Lucide icon name (kebab-case) to render next to the section title. */
@@ -157,6 +229,18 @@ export interface RelatedListProps {
157
229
  * `invite_user` (`visible: "features.organization != false"`) hides when its
158
230
  * predicate is false. `features`/`user` resolve from the ambient
159
231
  * ExpressionProvider scope.
232
+ *
233
+ * The verdict fails CLOSED on a predicate that FAULTS (`throwOnError`), as
234
+ * every action `visible` leg does (objectui#11212, Rider 1 of objectui#4421):
235
+ * a precondition that cannot be evaluated — `current_user.can(…)` before the
236
+ * permissions payload has loaded, an unbound root — hides the button and is
237
+ * reported once, instead of showing an action whose guard is broken. This leg
238
+ * used to fail SOFT to `true`.
239
+ *
240
+ * Whether a gate is DECLARED at all is asked with `hasDeclaredVisibilityGate`,
241
+ * as every other member of the action family asks it (objectui#3812,
242
+ * objectui#11244), never by truthiness: `visible: false` is a declared gate and
243
+ * hides the button, while a blank predicate (`''`, whitespace) is no gate.
160
244
  */
161
245
  export declare const RelatedToolbarButton: React.FC<{
162
246
  action: RelatedRowActionDef;
@@ -1 +1 @@
1
- {"version":3,"file":"RelatedList.d.ts","sourceRoot":"","sources":["../src/RelatedList.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"RelatedList.d.ts","sourceRoot":"","sources":["../src/RelatedList.tsx"],"names":[],"mappings":"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"}
@@ -12,7 +12,7 @@ export interface ThreadedRepliesProps {
12
12
  parentItem: FeedItem;
13
13
  /** Reply feed items (children) */
14
14
  replies: FeedItem[];
15
- /** Called when a reply is submitted */
15
+ /** Called when a reply is submitted. A rejection means it was not written: the draft is kept. */
16
16
  onAddReply?: (parentId: string | number, text: string) => void | Promise<void>;
17
17
  /** Whether to show the reply input */
18
18
  showReplyInput?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"ThreadedReplies.d.ts","sourceRoot":"","sources":["../src/ThreadedReplies.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAGjD,MAAM,WAAW,oBAAoB;IACnC,sCAAsC;IACtC,UAAU,EAAE,QAAQ,CAAC;IACrB,kCAAkC;IAClC,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,uCAAuC;IACvC,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/E,sCAAsC;IACtC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAwBD;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAiH1D,CAAC"}
1
+ {"version":3,"file":"ThreadedReplies.d.ts","sourceRoot":"","sources":["../src/ThreadedReplies.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAIjD,MAAM,WAAW,oBAAoB;IACnC,sCAAsC;IACtC,UAAU,EAAE,QAAQ,CAAC;IACrB,kCAAkC;IAClC,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,iGAAiG;IACjG,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/E,sCAAsC;IACtC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA2BD;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAuH1D,CAAC"}
@@ -0,0 +1,142 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ /**
9
+ * Does this cell have anything to render? **THE** definition of emptiness on
10
+ * the `record:details` page (objectui#8376, widened to the whole package by
11
+ * objectui#8394).
12
+ *
13
+ * ## Readers
14
+ *
15
+ * Every band of the record page that draws a placeholder instead of a value, or
16
+ * omits a slot because there is no value, asks THIS — never its own
17
+ * `null | undefined | ''`:
18
+ *
19
+ * - `DetailSection` — `isEmptyValue` (the row filter behind `emptyCount`, the
20
+ * "Show N empty fields" toggle and the auto-hide heuristic), the `isEmpty`
21
+ * branch of `displayValue` (the muted em-dash + `No value` affordance), and
22
+ * `canCopy` (a row that says `No value` must not offer to copy it);
23
+ * - `HeaderHighlight` — the ADR-0085 highlight strip's `isEmpty`, the same
24
+ * em-dash affordance one band higher on the same screen;
25
+ * - `DetailView` — the `summaryFields` chips beside the page H1, BOTH the
26
+ * auto-detection that picks which field becomes a chip and the render that
27
+ * skips a valueless one. Those two must agree or the derivation spends the
28
+ * one status slot on a field the render then drops, and no chip appears;
29
+ * - `HistoryTimeline` — `formatDiffValue`'s `'—'` placeholder for an audit
30
+ * value;
31
+ * - `RecordMetaFooter` — whether `created_by` / `updated_by` is an actor at
32
+ * all (see the note at its call site: the footer normalizes at the READ,
33
+ * because the label, the `·` separator and the renderer are three consumers
34
+ * of one answer).
35
+ *
36
+ * They MUST agree. Before objectui#8350 / #8376 / #8394 each spelled the test
37
+ * out for itself, none trimmed, and the page contradicted itself in one
38
+ * screenful: the H1 called a whitespace-only field empty, the body grid painted
39
+ * a blank cell, the strip between them painted a blank chip. Raw tests that
40
+ * happen to agree can stop agreeing; one definition cannot.
41
+ *
42
+ * ## Why the scalar half DELEGATES (objectui#8350's authority)
43
+ *
44
+ * None of those tests TRIMMED, so `' '` counted as FILLED while
45
+ * `@object-ui/core`'s `recordDisplayValueAt` — the definition the page H1 and
46
+ * the `record:details` dedupe ladder both read — calls it EMPTY. The
47
+ * consequences were not cosmetic: a row painted a visually blank cell (the exact
48
+ * UI the em-dash exists to prevent), it escaped `emptyCount` so the toggle read
49
+ * one too low, and because `shouldAutoHideEmpty` only needs `filledCount > 0`
50
+ * ONE such value suppressed the all-empty skeleton and hid every genuinely empty
51
+ * row in its section. So the scalar answer is not re-spelled here: it is the
52
+ * authority's, and a `.trim()` written at a call site would be the second
53
+ * implementation that drifts next.
54
+ *
55
+ * ## Why the OBJECT half does NOT delegate — measured, not assumed
56
+ *
57
+ * `recordDisplayValueAt` answers "does this resolve to a NAME", so an object
58
+ * value goes through `displayNameOfEmbeddedObject` and is EMPTY whenever that
59
+ * Salesforce-style chain yields nothing. That is right for a title and WRONG for
60
+ * a cell: here an object value is handed to a TYPE-AWARE renderer that knows how
61
+ * to draw it. `{ latitude, longitude }` renders as coordinates
62
+ * (`LocationCellRenderer`), `{ street, city, … }` as a formatted postal address
63
+ * (`AddressCellRenderer`, objectui#4037), `['alpha','beta']` as select badges,
64
+ * an expanded `{ id, name }` reference through `LookupCellRenderer`'s own
65
+ * display chain, any other object as JSON — none of which carries a name-ish key
66
+ * in the general case, so delegating this half would replace populated cells
67
+ * with `No value`, drop them out of `filledCount`, and let auto-hide bury them.
68
+ * A POPULATED object is therefore a VALUE here.
69
+ *
70
+ * ## The one object shape that is NOT a value: `[]` (objectui#8474)
71
+ *
72
+ * That member now arrives from the SHARED FLOOR rather than from a clause
73
+ * written here — `isEmptyValue` in `@object-ui/core` (objectui#8496). The
74
+ * reasoning below is what MEASURED it, and it is kept because it is the reason
75
+ * the floor may be asked here at all; the four members themselves are no longer
76
+ * this file's to spell.
77
+ *
78
+ * Every example above is a POPULATED object. `typeof [] === 'object'`, so until
79
+ * objectui#8474 an EMPTY array took the same branch and was a value — and there
80
+ * the reasoning stops holding, because the type-aware renderer has nothing to
81
+ * draw. `SelectCellRenderer` tests `value == null || value === ''`, which `[]`
82
+ * passes, and then maps it over zero entries: the cell renders as
83
+ * `<div class="flex flex-wrap gap-1"></div>`, a visually blank cell — the exact
84
+ * UI the em-dash exists to prevent, reached through the function that exists to
85
+ * prevent it. And it brought the whole objectui#8376 triple with it: the row
86
+ * escaped `emptyCount` so the toggle read one too low, `canCopy` offered to copy
87
+ * it, and because `shouldAutoHideEmpty` only needs `filledCount > 0` a section
88
+ * whose one non-null value was `[]` auto-hid every genuinely empty row around it
89
+ * and rendered a lone label over a blank.
90
+ *
91
+ * ⚠️ The declared cost, measured rather than waved past: a `json`-family field
92
+ * holding `[]` used to render the literal two-character text `[]` through
93
+ * `JsonCellRenderer`, and now draws the `No value` placeholder. That is
94
+ * intended — "no items" is what the placeholder says — but it IS a render
95
+ * change, and it is pinned as one.
96
+ *
97
+ * ## Why `{}` is NOT included — measured on this surface, not argued by symmetry
98
+ *
99
+ * `{}` is a VALUE here, and that is a measurement rather than an oversight.
100
+ * Rendered in a real `DetailSection`, `{}` on a `json`, an `object` and a
101
+ * `location` field all draw the literal `{}` through `JsonCellRenderer`
102
+ * (`location` falls back to it when the lat/lng chain yields nothing) — a terse
103
+ * cell, but a DRAWN one. There is no blank cell, so there is no defect of the
104
+ * kind above to fix, and turning a visible `{}` into an em-dash would be a taste
105
+ * change dressed up as a bug fix.
106
+ *
107
+ * ⛔ And the shape that would sweep `{}` in is actively unsafe here:
108
+ * `Object.keys(value).length === 0` is ALSO true of `new Date(0)`, of a
109
+ * populated `Map`, of a populated `Set`, and of any class instance whose state
110
+ * sits behind getters (all four measured). Widening that way would call those
111
+ * EMPTY — a false-empty on values that render, strictly worse than the bug it
112
+ * set out to fix. So this function moves whitespace-only strings and empty
113
+ * arrays, and nothing else.
114
+ *
115
+ * ## Agreement with `RelatedList`'s local predicate (objectui#8459)
116
+ *
117
+ * `RelatedList.isValueEmpty` has drawn this finer line for some time, and
118
+ * objectui#8459 / PR #8476 measured it as the better-shaped answer for a grid,
119
+ * declining to delegate here BECAUSE of this hole. After objectui#8474 the two
120
+ * agree on every probe measured (`[]` empty; `{}`, `[1]`, `{ a: 1 }`, `0` and a
121
+ * `Date` all values). ⛔ Note the DIRECTION: the SHARED authority moved toward
122
+ * the local predicate. `RelatedList.isValueEmpty` is untouched and must stay
123
+ * that way — a grid column and a record row ask this at two granularities, and
124
+ * the local one is pinned in its own file.
125
+ *
126
+ * ## Not every emptiness question on this page is THIS question
127
+ *
128
+ * ⛔ Do not widen the reader list by pattern-matching on the shape of a test.
129
+ * `ConcurrentUpdateDialog`'s `formatValue` deliberately renders `''` as `""`
130
+ * rather than as a placeholder — a conflict dialog is reporting what is STORED,
131
+ * where "empty string" and "absent" are different facts the reader must be able
132
+ * to tell apart. Converging it would delete information rather than add it.
133
+ *
134
+ * Pinned end-to-end (DOM, not predicate) in
135
+ * `__tests__/DetailSection.emptinessAuthority-8376.test.tsx`,
136
+ * `__tests__/detailPage.emptinessAuthority-8394.test.tsx` and
137
+ * `__tests__/DetailSection.emptyArray-8474.test.tsx`, whose NON-REGRESSION
138
+ * cases are red for a wholesale delegation and red for an emptiness test that
139
+ * answers EMPTY for everything.
140
+ */
141
+ export declare function hasCellValue(value: unknown): boolean;
142
+ //# sourceMappingURL=emptiness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emptiness.d.ts","sourceRoot":"","sources":["../src/emptiness.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CA0BpD"}
@@ -7,7 +7,7 @@
7
7
  */
8
8
  /**
9
9
  * Field types the PLATFORM computes — the value is machine-owned and no user
10
- * write is legitimate. They carry a `reference_to` for relational metadata but
10
+ * write is legitimate. They carry a `reference` for relational metadata but
11
11
  * have no editor of their own.
12
12
  *
13
13
  * One set, three readers, so they cannot drift: `InlineFieldInput` renders them
@@ -26,8 +26,8 @@
26
26
  * type: `plugin-form` lists both in each of its non-input sets, and this is the
27
27
  * shape that was missing here. The gap was not academic — the reader that has
28
28
  * no host gate in front of it is `InlineFieldInput`'s reference fallback
29
- * (`!!field.reference_to && !TEXTUAL_REF_FALLBACK_TYPES.has(type)`), on
30
- * exported public API, so a spec-spelled auto-number carrying a `reference_to`
29
+ * (`!!field.reference && !TEXTUAL_REF_FALLBACK_TYPES.has(type)`), on
30
+ * exported public API, so a spec-spelled auto-number carrying a `reference`
31
31
  * resolved into the RECORD PICKER — a list of records offered as replacements
32
32
  * for a machine-generated identity. The editability half of the same report is
33
33
  * held by the alias-aware shared exclusion since #4228; the two gates are a
@@ -73,6 +73,20 @@ export declare function isComputedFieldType(viewFieldType: unknown, objectFieldT
73
73
  * widgets the record form uses, added deliberately so inline edit could preview,
74
74
  * replace and remove files instead of showing a bare storage URL.
75
75
  *
76
+ * `markdown` is exempt on the same footing (objectui#11541). The shared set
77
+ * excludes it among the "Heavy / full editors — better in the record form than
78
+ * a cell", which is again an argument about a CELL. #4228 kept it out of the
79
+ * detail row for the reason it recorded there: "a one-line text box is lossy".
80
+ * That box was the only editor the row then had for it — the terminal text
81
+ * input, which is one line, so the browser strips every line break from the
82
+ * value it is seeded with and the next keystroke writes the flattened text
83
+ * back. A markdown value is a plain string, so a MULTI-line editor loses
84
+ * nothing, and `InlineFieldInput` routes it to `TextAreaField`, the fields
85
+ * package's multi-line widget (the one a `textarea` field edits with in the
86
+ * record form and in a grid cell), never to that terminal input. The grid
87
+ * keeps the exclusion for `markdown`. `html` and
88
+ * `richtext` are not exempt: they stay excluded, unchanged.
89
+ *
76
90
  * The credential and container members are excluded for a VALUE reason — masked
77
91
  * on read, or object-shaped — and that argument transfers to the detail page
78
92
  * verbatim, because the detail fallback is the same plain text input the grid's
@@ -105,6 +119,32 @@ export declare const DETAIL_ROUTED_INLINE_TYPES: Set<string>;
105
119
  * locked: the exemption is consulted per type, before the union.
106
120
  */
107
121
  export declare function isInlineExcludedDetailFieldType(viewFieldType: unknown, objectFieldType: unknown): boolean;
122
+ /**
123
+ * Is this row's cell drawn as a mask, given the type authored on the view entry
124
+ * and the type declared on the object schema?
125
+ *
126
+ * The rule itself is NOT restated here — it is `isMaskedFieldType()` from
127
+ * `@object-ui/fields`, the package that owns the mask registrations
128
+ * (objectui#8686). This file used to keep its own two-member copy of the
129
+ * masked types (objectui#8440), documented as a mirror with two accepted
130
+ * costs: a masked type added to the fields package would render masked and
131
+ * stay copy-interactive here, and `registerFieldRenderer('password', …)`
132
+ * could replace the mask at runtime without this copy seeing it. Reading the
133
+ * authority closes both: a type the fields package masks, declared or
134
+ * registered, refuses the copy here with no edit to this file. The same shape
135
+ * {@link isInlineExcludedDetailFieldType} already has for the write direction.
136
+ *
137
+ * **Narrow-only, like {@link isComputedFieldType} and
138
+ * {@link isInlineExcludedDetailFieldType}** — the answer is the UNION of the
139
+ * two, so an authored display `type` can withdraw the copy affordance but never
140
+ * restore it (objectui#3355). The direction matters here more than anywhere: an
141
+ * object column declared `secret` keeps its refusal even when a view authors
142
+ * `type: 'text'` over it, because a PRESENTATION override has no business
143
+ * widening access to a credential. The declared cost of the union is the mirror
144
+ * case — an object `text` column authored as `password` masks AND refuses the
145
+ * copy, which is the same answer the cell already gives.
146
+ */
147
+ export declare function isMaskedDetailFieldType(viewFieldType: unknown, objectFieldType: unknown): boolean;
108
148
  /**
109
149
  * Object-metadata keys carried onto a detail-view field so the read cell and
110
150
  * the inline editor see the SAME resolved field shape the object form does.
@@ -119,7 +159,7 @@ export declare function isInlineExcludedDetailFieldType(viewFieldType: unknown,
119
159
  *
120
160
  * Ordering is documentation only; the copy is key-by-key.
121
161
  */
122
- export declare const ENRICHED_FIELD_METADATA_KEYS: readonly ["options", "currency", "currencyConfig", "precision", "scale", "min", "max", "step", "format", "widget", "dueLike", "multiple", "reference_field", "display_field", "displayField", "description_field", "descriptionField", "id_field", "allow_create", "allowCreate", "lookup_columns", "lookupColumns", "lookup_page_size", "lookupPageSize", "lookup_filters", "lookupFilters", "picker", "subtitle", "avatar_field", "avatarField", "depends_on", "dependsOn"];
162
+ export declare const ENRICHED_FIELD_METADATA_KEYS: readonly ["options", "currency", "currencyConfig", "precision", "scale", "useGrouping", "min", "max", "step", "format", "widget", "dueLike", "multiple", "reference_field", "displayField", "descriptionField", "idField", "allow_create", "allowCreate", "lookup_columns", "lookupColumns", "lookup_page_size", "lookupPageSize", "lookupFilters", "picker", "subtitle", "avatar_field", "avatarField", "depends_on", "dependsOn"];
123
163
  /**
124
164
  * Merge a detail-view field with its object-schema metadata.
125
165
  *
@@ -1 +1 @@
1
- {"version":3,"file":"fieldEnrichment.d.ts","sourceRoot":"","sources":["../src/fieldEnrichment.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,0BAA0B,aAMrC,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,mBAAmB,CACjC,aAAa,EAAE,OAAO,EACtB,eAAe,EAAE,OAAO,GACvB,OAAO,CAKT;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,0BAA0B,aAOrC,CAAC;AAEH;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,+BAA+B,CAC7C,aAAa,EAAE,OAAO,EACtB,eAAe,EAAE,OAAO,GACvB,OAAO,CAET;AAQD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,4BAA4B,+cA+C/B,CAAC;AAEX;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC9B,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,GAAG,IAAI,GACrD,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAiBrB"}
1
+ {"version":3,"file":"fieldEnrichment.d.ts","sourceRoot":"","sources":["../src/fieldEnrichment.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,0BAA0B,aAMrC,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,mBAAmB,CACjC,aAAa,EAAE,OAAO,EACtB,eAAe,EAAE,OAAO,GACvB,OAAO,CAKT;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,eAAO,MAAM,0BAA0B,aAQrC,CAAC;AAEH;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,+BAA+B,CAC7C,aAAa,EAAE,OAAO,EACtB,eAAe,EAAE,OAAO,GACvB,OAAO,CAET;AAQD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,uBAAuB,CACrC,aAAa,EAAE,OAAO,EACtB,eAAe,EAAE,OAAO,GACvB,OAAO,CAET;AAMD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,4BAA4B,qaAkD/B,CAAC;AAEX;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC9B,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,GAAG,IAAI,GACrD,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CA2BrB"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ /** The declared vocabulary, for tests and for callers that enumerate it. */
9
+ export declare const headerColorVocabulary: Readonly<Record<string, string>>;
10
+ /**
11
+ * Resolve an authored `headerColor` to a class the stylesheet actually
12
+ * carries, or `undefined` when there is none — never a concatenated guess.
13
+ *
14
+ * A value that is already a complete `bg-*` class is handed through
15
+ * untouched, exactly as `useRowColor` does. It then renders on the same terms
16
+ * as any `className` a schema carries: the host app's Tailwind build has to
17
+ * generate it.
18
+ */
19
+ export declare function headerColorClass(headerColor: string | undefined): string | undefined;
20
+ //# sourceMappingURL=headerColor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headerColor.d.ts","sourceRoot":"","sources":["../src/headerColor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA6DH,4EAA4E;AAC5E,eAAO,MAAM,qBAAqB,kCAAuB,CAAC;AAE1D;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAYpF"}