@object-ui/plugin-detail 17.6.0 → 18.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7755 -0
- package/README.md +557 -71
- package/dist/ActivityTimeline.d.ts.map +1 -1
- package/dist/CommentAttachment.d.ts.map +1 -1
- package/dist/CommentAuthorControls.d.ts +40 -0
- package/dist/CommentAuthorControls.d.ts.map +1 -0
- package/dist/ConcurrentUpdateDialog.d.ts +16 -1
- package/dist/ConcurrentUpdateDialog.d.ts.map +1 -1
- package/dist/DetailSection.d.ts.map +1 -1
- package/dist/DetailSectionNode.d.ts +97 -0
- package/dist/DetailSectionNode.d.ts.map +1 -0
- package/dist/DetailView.d.ts +13 -0
- package/dist/DetailView.d.ts.map +1 -1
- package/dist/HeaderHighlight.d.ts.map +1 -1
- package/dist/HistoryTimeline.d.ts +21 -4
- package/dist/HistoryTimeline.d.ts.map +1 -1
- package/dist/InlineEditSaveBar.d.ts +68 -0
- package/dist/InlineEditSaveBar.d.ts.map +1 -1
- package/dist/InlineFieldInput.d.ts +80 -7
- package/dist/InlineFieldInput.d.ts.map +1 -1
- package/dist/ReactionPicker.d.ts.map +1 -1
- package/dist/RecordActivityTimeline.d.ts +32 -4
- package/dist/RecordActivityTimeline.d.ts.map +1 -1
- package/dist/RecordChatterPanel.d.ts +10 -1
- package/dist/RecordChatterPanel.d.ts.map +1 -1
- package/dist/RecordComments.d.ts +1 -0
- package/dist/RecordComments.d.ts.map +1 -1
- package/dist/RecordDetailDrawer.d.ts +20 -6
- package/dist/RecordDetailDrawer.d.ts.map +1 -1
- package/dist/RecordDetailPanel.d.ts +101 -0
- package/dist/RecordDetailPanel.d.ts.map +1 -0
- package/dist/RecordMetaFooter.d.ts +1 -1
- package/dist/RecordMetaFooter.d.ts.map +1 -1
- package/dist/RelatedList.d.ts +83 -10
- package/dist/RelatedList.d.ts.map +1 -1
- package/dist/ThreadedReplies.d.ts +9 -1
- package/dist/ThreadedReplies.d.ts.map +1 -1
- package/dist/emptiness.d.ts +142 -0
- package/dist/emptiness.d.ts.map +1 -0
- package/dist/fieldEnrichment.d.ts +46 -5
- package/dist/fieldEnrichment.d.ts.map +1 -1
- package/dist/headerColor.d.ts +20 -0
- package/dist/headerColor.d.ts.map +1 -0
- package/dist/index.d.ts +94 -77
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5693 -5487
- package/dist/index.umd.cjs +2 -5
- package/dist/recordPageProvenance.d.ts +39 -0
- package/dist/recordPageProvenance.d.ts.map +1 -0
- package/dist/renderers/record-activity.d.ts.map +1 -1
- package/dist/renderers/record-alert.d.ts +23 -3
- package/dist/renderers/record-alert.d.ts.map +1 -1
- package/dist/renderers/record-alert.readProps.d.ts +40 -0
- package/dist/renderers/record-alert.readProps.d.ts.map +1 -0
- package/dist/renderers/record-chatter.d.ts.map +1 -1
- package/dist/renderers/record-details.d.ts +12 -0
- package/dist/renderers/record-details.d.ts.map +1 -1
- package/dist/renderers/record-highlights.d.ts +10 -0
- package/dist/renderers/record-highlights.d.ts.map +1 -1
- package/dist/renderers/record-history.d.ts +1 -1
- package/dist/renderers/record-history.d.ts.map +1 -1
- package/dist/renderers/record-path.d.ts.map +1 -1
- package/dist/renderers/record-quick-actions.d.ts +26 -6
- package/dist/renderers/record-quick-actions.d.ts.map +1 -1
- package/dist/renderers/record-reference-rail.d.ts +40 -0
- package/dist/renderers/record-reference-rail.d.ts.map +1 -1
- package/dist/renderers/record-related-list.d.ts +51 -7
- package/dist/renderers/record-related-list.d.ts.map +1 -1
- package/dist/renderers/recordActivityFeed.d.ts +343 -33
- package/dist/renderers/recordActivityFeed.d.ts.map +1 -1
- package/dist/renderers/recordBinding.d.ts +180 -0
- package/dist/renderers/recordBinding.d.ts.map +1 -0
- package/dist/renderers/recordComponentAria.d.ts +44 -0
- package/dist/renderers/recordComponentAria.d.ts.map +1 -0
- package/dist/renderers/relatedListActions.d.ts +102 -0
- package/dist/renderers/relatedListActions.d.ts.map +1 -0
- package/dist/summaryChipPercent.d.ts +83 -0
- package/dist/summaryChipPercent.d.ts.map +1 -0
- package/dist/summaryChipRenderers.d.ts +83 -0
- package/dist/summaryChipRenderers.d.ts.map +1 -0
- package/dist/synth/buildDefaultPageSchema.d.ts +188 -21
- package/dist/synth/buildDefaultPageSchema.d.ts.map +1 -1
- package/dist/useDetailTranslation.d.ts.map +1 -1
- package/dist/useRecordEditable.d.ts +4 -1
- package/dist/useRecordEditable.d.ts.map +1 -1
- package/package.json +19 -18
- package/dist/CommentInput.d.ts +0 -24
- package/dist/CommentInput.d.ts.map +0 -1
- package/dist/DiffView.d.ts +0 -24
- package/dist/DiffView.d.ts.map +0 -1
- package/dist/InlineCreateRelated.d.ts +0 -32
- package/dist/InlineCreateRelated.d.ts.map +0 -1
- package/dist/MentionAutocomplete.d.ts +0 -43
- package/dist/MentionAutocomplete.d.ts.map +0 -1
- package/dist/PointInTimeRestore.d.ts +0 -28
- package/dist/PointInTimeRestore.d.ts.map +0 -1
- package/dist/RecordNavigationEnhanced.d.ts +0 -18
- package/dist/RecordNavigationEnhanced.d.ts.map +0 -1
- package/dist/RelationshipGraph.d.ts +0 -23
- package/dist/RelationshipGraph.d.ts.map +0 -1
- package/dist/renderers/PermissionFacetLink.d.ts +0 -38
- package/dist/renderers/PermissionFacetLink.d.ts.map +0 -1
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { RecordComponentAriaProps } from '@object-ui/types';
|
|
2
|
+
/**
|
|
3
|
+
* The authored `aria` bag as a renderer actually receives it: the declared
|
|
4
|
+
* face, plus the undeclared `label` spelling a stored document may still carry.
|
|
5
|
+
*/
|
|
6
|
+
export type AuthoredRecordAria = RecordComponentAriaProps & {
|
|
7
|
+
/**
|
|
8
|
+
* ⛔ Not a member of the contract. It is the shared ARIA shape's alias entry
|
|
9
|
+
* and is refused on parse. Declared on this type ONLY so the diagnostic can
|
|
10
|
+
* see it without an `as any` cast (a cast is how `record:path` once came to
|
|
11
|
+
* read this spelling and no other).
|
|
12
|
+
*
|
|
13
|
+
* ⚠️ It is never read as a name. objectui#9945 retired the fold that did;
|
|
14
|
+
* a served value is reported, and only for a caller that names its `block`.
|
|
15
|
+
* See this module's header.
|
|
16
|
+
*/
|
|
17
|
+
label?: string;
|
|
18
|
+
};
|
|
19
|
+
/** What {@link useRecordAriaProps} spreads onto a block's container element. */
|
|
20
|
+
export interface RecordAriaDomProps {
|
|
21
|
+
'aria-label'?: string;
|
|
22
|
+
'aria-describedby'?: string;
|
|
23
|
+
role?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The ARIA DOM props for a `record:*` block's own container.
|
|
27
|
+
*
|
|
28
|
+
* @param aria - the authored bag, straight off the node's `aria` key.
|
|
29
|
+
* @param defaultRole - the role this block renders when the author declares
|
|
30
|
+
* none. Omit it and the container stays role-less until an author declares a
|
|
31
|
+
* name, a description or a role — at which point `'region'` carries the name,
|
|
32
|
+
* because an attribute on a `generic` element carries nothing.
|
|
33
|
+
* @param defaultLabel - the block's built-in accessible name, used when the
|
|
34
|
+
* author declared none (or declared an empty one).
|
|
35
|
+
* @param block - the block's registered type (`record:path`), named in the
|
|
36
|
+
* report of a served `aria.label`. Omit it and that spelling is still not
|
|
37
|
+
* read, just not reported. See this module's header for which blocks pass it.
|
|
38
|
+
*/
|
|
39
|
+
export declare function useRecordAriaProps(aria: AuthoredRecordAria | undefined, { defaultRole, defaultLabel, block, }?: {
|
|
40
|
+
defaultRole?: string;
|
|
41
|
+
defaultLabel?: string;
|
|
42
|
+
block?: string;
|
|
43
|
+
}): RecordAriaDomProps;
|
|
44
|
+
//# sourceMappingURL=recordComponentAria.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recordComponentAria.d.ts","sourceRoot":"","sources":["../../src/renderers/recordComponentAria.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmGG;AAKH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AAEjE;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG,wBAAwB,GAAG;IAC1D;;;;;;;;;OASG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,gFAAgF;AAChF,MAAM,WAAW,kBAAkB;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAwCD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,kBAAkB,GAAG,SAAS,EACpC,EACE,WAAW,EACX,YAAY,EACZ,KAAK,GACN,GAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GACtE,kBAAkB,CAapB"}
|
|
@@ -0,0 +1,102 @@
|
|
|
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
|
+
* `record:related_list.actions` — where an authored action id lands on the list,
|
|
9
|
+
* or why it is refused (objectui#11163; the maintainer's ENFORCE ruling on
|
|
10
|
+
* objectstack-ai/objectstack#20665).
|
|
11
|
+
*
|
|
12
|
+
* The contract declares the key as `z.array(z.string())`, "Action IDs available
|
|
13
|
+
* for related records". This module is the whole of its meaning, kept apart
|
|
14
|
+
* from the renderer so the file that draws the block keeps exporting
|
|
15
|
+
* components only:
|
|
16
|
+
*
|
|
17
|
+
* - RESOLUTION is `resolveDeclaredActionIds` — the one function
|
|
18
|
+
* `page:header`, `record:quick_actions` and `record:alert` resolve an
|
|
19
|
+
* authored action id through (objectui#7182, objectui#7382) — against the
|
|
20
|
+
* RELATED object's registered `actions`. ⛔ No second lookup: the caller
|
|
21
|
+
* reads that registry through `useMetadataItem('object', …)`, the same
|
|
22
|
+
* entry `record:quick_actions.actionNames` uses.
|
|
23
|
+
* - Only the IDS arm is this key's. The inline-object arm of the shared
|
|
24
|
+
* rule is `page:header`'s transition tolerance (objectstack#11592) and is
|
|
25
|
+
* not inherited here, the choice `record:alert` made for its CTA: an
|
|
26
|
+
* object in this array would widen what a related list can run past what
|
|
27
|
+
* the object declares.
|
|
28
|
+
* - PLACEMENT is each action's own `locations`, read by `actionRendersAt`
|
|
29
|
+
* — the platform's one placement rule, and the rule the host bridge
|
|
30
|
+
* (`RelatedRecordActionsBridge.deriveActions`) already applies to this
|
|
31
|
+
* list: `list_toolbar` draws a header button; `list_item` and
|
|
32
|
+
* `record_related` draw a row-menu item (objectui#11270). This block only
|
|
33
|
+
* ever renders inside a parent record, which is the scope `record_related`
|
|
34
|
+
* names (objectstack-ai/objectstack#20937, triage `5919625056`: row
|
|
35
|
+
* placement, inside a record only). Naming an action here does not bypass
|
|
36
|
+
* location filtering (only a list view's selection bar is placed by
|
|
37
|
+
* naming), so an id whose action declares none of the three is REFUSED
|
|
38
|
+
* rather than drawn somewhere or dropped.
|
|
39
|
+
* - ORDER is the author's, within each surface.
|
|
40
|
+
*/
|
|
41
|
+
/**
|
|
42
|
+
* An action definition as the registry holds it — the two members read here,
|
|
43
|
+
* typed `unknown` because the definitions arrive straight off the metadata
|
|
44
|
+
* wire (the reason `actionRendersAt` gives for its own parameter).
|
|
45
|
+
*/
|
|
46
|
+
export interface RegisteredRelatedAction {
|
|
47
|
+
readonly name?: unknown;
|
|
48
|
+
readonly locations?: unknown;
|
|
49
|
+
}
|
|
50
|
+
/** One reason an authored entry does not render, stated for the author. */
|
|
51
|
+
export type RelatedListActionRefusal =
|
|
52
|
+
/** The array itself is refused: not an array, or not all action ids. */
|
|
53
|
+
{
|
|
54
|
+
readonly kind: 'array';
|
|
55
|
+
readonly message: string;
|
|
56
|
+
}
|
|
57
|
+
/** An id that names no registered action of the related object. */
|
|
58
|
+
| {
|
|
59
|
+
readonly kind: 'unresolved';
|
|
60
|
+
readonly id: string;
|
|
61
|
+
}
|
|
62
|
+
/** An id that resolves, to an action declaring no location this list renders. */
|
|
63
|
+
| {
|
|
64
|
+
readonly kind: 'unplaced';
|
|
65
|
+
readonly id: string;
|
|
66
|
+
};
|
|
67
|
+
export interface PlacedRelatedListActions<T> {
|
|
68
|
+
/** `list_toolbar` actions, in authored order — the list's header buttons. */
|
|
69
|
+
readonly toolbar: T[];
|
|
70
|
+
/** `list_item` and `record_related` actions, in authored order — each row's menu. */
|
|
71
|
+
readonly row: T[];
|
|
72
|
+
/** Every authored entry that renders nowhere, and why. */
|
|
73
|
+
readonly refused: RelatedListActionRefusal[];
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Whether an authored value has any id to look up — the registry-independent
|
|
77
|
+
* half of the shared rule, so the caller requests the metadata read only when
|
|
78
|
+
* it can change the answer (a `[]`, an object array or a refused array is
|
|
79
|
+
* decided without it).
|
|
80
|
+
*/
|
|
81
|
+
export declare function relatedListActionsNeedLookup(authored: unknown): boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Resolve and place an authored `record:related_list.actions` value.
|
|
84
|
+
*
|
|
85
|
+
* `registered` is the related object's `actions` once the metadata lookup has
|
|
86
|
+
* ANSWERED. The caller does not call this while the lookup is in flight: every
|
|
87
|
+
* id would come back unresolved and the list would refuse an id it is about to
|
|
88
|
+
* resolve.
|
|
89
|
+
*
|
|
90
|
+
* An id authored twice renders once, at its first position — it is drawn, so
|
|
91
|
+
* nothing the author asked for is dropped.
|
|
92
|
+
*/
|
|
93
|
+
export declare function placeAuthoredRelatedListActions<T extends RegisteredRelatedAction>(authored: unknown, registered: readonly T[] | null | undefined): PlacedRelatedListActions<T>;
|
|
94
|
+
/**
|
|
95
|
+
* The refusal notice's text — one sentence per refused entry, naming it and
|
|
96
|
+
* the related object, so the fix is a one-entry edit.
|
|
97
|
+
*
|
|
98
|
+
* `objectKnown` is whether the lookup found the related object at all: an id
|
|
99
|
+
* cannot be "not an action of" an object whose metadata never arrived.
|
|
100
|
+
*/
|
|
101
|
+
export declare function describeRelatedListActionRefusals(refused: readonly RelatedListActionRefusal[], objectName: string, objectKnown: boolean): string;
|
|
102
|
+
//# sourceMappingURL=relatedListActions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relatedListActions.d.ts","sourceRoot":"","sources":["../../src/renderers/relatedListActions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAIH;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,2EAA2E;AAC3E,MAAM,MAAM,wBAAwB;AAClC,wEAAwE;AACtE;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE;AACtD,mEAAmE;GACjE;IAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE;AACtD,iFAAiF;GAC/E;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvD,MAAM,WAAW,wBAAwB,CAAC,CAAC;IACzC,6EAA6E;IAC7E,QAAQ,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;IACtB,qFAAqF;IACrF,QAAQ,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC;IAClB,0DAA0D;IAC1D,QAAQ,CAAC,OAAO,EAAE,wBAAwB,EAAE,CAAC;CAC9C;AAQD;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAIvE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,+BAA+B,CAAC,CAAC,SAAS,uBAAuB,EAC/E,QAAQ,EAAE,OAAO,EACjB,UAAU,EAAE,SAAS,CAAC,EAAE,GAAG,IAAI,GAAG,SAAS,GAC1C,wBAAwB,CAAC,CAAC,CAAC,CA6C7B;AAED;;;;;;GAMG;AACH,wBAAgB,iCAAiC,CAC/C,OAAO,EAAE,SAAS,wBAAwB,EAAE,EAC5C,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,OAAO,GACnB,MAAM,CAeR"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { PercentScale } from '@object-ui/core';
|
|
2
|
+
/**
|
|
3
|
+
* The ONE rule the `summaryFields` chip scales a stored `percent` by — and it
|
|
4
|
+
* is the repo's, not this file's (objectui#9071).
|
|
5
|
+
*
|
|
6
|
+
* ⭐ Since objectui#9167 this is the chip's BAR path only. The chip's TEXT goes
|
|
7
|
+
* straight to `formatPercent` in `@object-ui/fields` — the list cell's own
|
|
8
|
+
* body, which applies {@link percentDisplayValue} itself and then the locale's
|
|
9
|
+
* percent affix at the field's precision. See "The half objectui#9071 did NOT
|
|
10
|
+
* take" below, which objectui#9167 closed.
|
|
11
|
+
*
|
|
12
|
+
* ## Why this function exists at all (objectui#8728)
|
|
13
|
+
*
|
|
14
|
+
* The chip beside the record H1 draws a percent TWICE — as its text and as a
|
|
15
|
+
* small bar — and the two halves scaled the same stored number by two
|
|
16
|
+
* different rules:
|
|
17
|
+
*
|
|
18
|
+
* display = `${num}%`; // the text: no scaling
|
|
19
|
+
* const normalized = num <= 1 ? num * 100 : num; // the bar: ratio, scaled
|
|
20
|
+
*
|
|
21
|
+
* so a stored `0.123` labelled itself `0.123%` beside a bar filled to 12.3%.
|
|
22
|
+
* One control, two percentages, and neither half told the reader which one was
|
|
23
|
+
* right. Both halves read this function — which is why it is a named function
|
|
24
|
+
* and not the same ternary written twice. The next reader cannot
|
|
25
|
+
* re-desynchronise them without deleting a call site.
|
|
26
|
+
*
|
|
27
|
+
* ## What objectui#9071 DELETED, and why aligning it would not have done
|
|
28
|
+
*
|
|
29
|
+
* objectui#8728 converged the chip's two halves onto the BAR's rule and
|
|
30
|
+
* recorded, rather than decided, that the rule was the chip's own. The census
|
|
31
|
+
* it asked for answered the question: the predicate that stood here —
|
|
32
|
+
* a pass-through spelled `if (raw > 1) return raw;`, i.e. the bar's original
|
|
33
|
+
* `num <= 1` written the other way round — was the only spelling of its kind on
|
|
34
|
+
* this side of the tree, and it disagreed with the declared single source of
|
|
35
|
+
* truth at EXACTLY 1 and at every value AT OR BELOW -1:
|
|
36
|
+
*
|
|
37
|
+
* | stored | the deleted local rule | `percentDisplayValue`, and every other band |
|
|
38
|
+
* |--------|------------------------|---------------------------------------------|
|
|
39
|
+
* | `0.25` | `25%` | `25%` (the band they always agreed on) |
|
|
40
|
+
* | `1` | `100%` | `1%` |
|
|
41
|
+
* | `-1` | `-100%` | `-1%` |
|
|
42
|
+
* | `-5` | `-500%` | `-5%` |
|
|
43
|
+
*
|
|
44
|
+
* ⛔ The repair is NOT to move the local predicate's boundary onto the shared
|
|
45
|
+
* one. That would leave two rules agreeing by coincidence — the same shape
|
|
46
|
+
* objectui#5607 removed one package over, and the shape that produced this
|
|
47
|
+
* drift in the first place. The predicate is gone; the authority is
|
|
48
|
+
* {@link percentDisplayValue} in `@object-ui/core`, whose own doc comment
|
|
49
|
+
* requires exactly this of a third surface, and which the list cell
|
|
50
|
+
* (`formatPercent` / `PercentCellRenderer`), the dashboard measure
|
|
51
|
+
* (`formatMeasure`) and the grid column summary already read.
|
|
52
|
+
*
|
|
53
|
+
* ## The half objectui#9071 did NOT take — closed by objectui#9167
|
|
54
|
+
*
|
|
55
|
+
* That doc comment asks a third surface for BOTH halves — the scaling AND the
|
|
56
|
+
* convention. objectui#9071 moved the SCALING only: the chip stated the full
|
|
57
|
+
* JavaScript number with a bare `%` while the list cell rendered through the
|
|
58
|
+
* locale's percent affix at the field's precision (`0` by default), so a stored
|
|
59
|
+
* `12.3` read `12.3%` beside the H1 and `12%` in the list — two spellings of
|
|
60
|
+
* one magnitude, with the two bars proving the magnitude was one. That card
|
|
61
|
+
* stopped because its acceptance forbade moving values the chip rendered
|
|
62
|
+
* correctly today, and the convention half moves several.
|
|
63
|
+
*
|
|
64
|
+
* objectui#9167 took it, value by value rather than by inspection: both
|
|
65
|
+
* surfaces were driven in the same run, on the same field, for every stored
|
|
66
|
+
* value below, and every row that MOVED moved onto the reading the list cell
|
|
67
|
+
* was already giving. The chip's text is now the cell's own `formatPercent`
|
|
68
|
+
* call, byte for byte, and this function is left
|
|
69
|
+
* holding the BAR alone. The table and its `de-DE` leg are pinned in
|
|
70
|
+
* `__tests__/summaryChip.percentConvention-9167.test.tsx`.
|
|
71
|
+
*
|
|
72
|
+
* ## The storage is the field's, stated by the caller (objectui#11475)
|
|
73
|
+
*
|
|
74
|
+
* `percentScale` is the storage the chip's field declares, which `DetailView`
|
|
75
|
+
* reads with `percentCellScale` (`@object-ui/fields`): the spec's
|
|
76
|
+
* `percentScaleOf`, the answer the list cell reads too. Until objectui#11475
|
|
77
|
+
* the shared source guessed the storage from the value's magnitude, so the
|
|
78
|
+
* table above, whose every row is that guess, no longer describes this
|
|
79
|
+
* function: a fraction-stored `1` now fills the bar to 100%, and a
|
|
80
|
+
* whole-stored `0.5` to half a percent.
|
|
81
|
+
*/
|
|
82
|
+
export declare function summaryChipPercentPoints(raw: number, percentScale: PercentScale): number;
|
|
83
|
+
//# sourceMappingURL=summaryChipPercent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summaryChipPercent.d.ts","sourceRoot":"","sources":["../src/summaryChipPercent.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEzE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+EG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,YAAY,GAAG,MAAM,CAyBxF"}
|
|
@@ -0,0 +1,83 @@
|
|
|
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
|
+
* Which field kinds the `summaryFields` chip beside the record H1 may draw
|
|
10
|
+
* with the field's OWN cell renderer, and which it may not (objectui#8464).
|
|
11
|
+
*
|
|
12
|
+
* ## Why this set exists at all
|
|
13
|
+
*
|
|
14
|
+
* The chip's display was `String(val)` with four families special-cased, so an
|
|
15
|
+
* object-valued summary field printed the literal `[object Object]` beside the
|
|
16
|
+
* H1 — and, because the chip's accessible name is built from that same string,
|
|
17
|
+
* in its accessible name too. The fix routes such a value through
|
|
18
|
+
* `getCellRenderer`, the way `HeaderHighlight` one band below already does.
|
|
19
|
+
*
|
|
20
|
+
* ⚠️ That route is NOT free, and this set is the measurement that says so. A
|
|
21
|
+
* Badge is a `whitespace-nowrap rounded-full` pill — a much smaller surface
|
|
22
|
+
* than a cell — and some registered types draw something a pill cannot host.
|
|
23
|
+
* Measured, not assumed: every registered type was rendered through
|
|
24
|
+
* `getCellRenderer` INSIDE the real chip Badge against the object value
|
|
25
|
+
* `{ id: 'acct-1', name: 'Acme Corp' }`, and the DOM inside the pill counted.
|
|
26
|
+
* The instrument is `__tests__/summaryChip.badgeFitCensus-8464.test.tsx`,
|
|
27
|
+
* which re-derives the whole table and fails if this set stops matching it.
|
|
28
|
+
*
|
|
29
|
+
* ⛔ The size of that population is deliberately NOT written down here
|
|
30
|
+
* (objectui#8734, AGENTS.md #9). It used to read "18 of the 53 registered
|
|
31
|
+
* types" — a figure derived once, re-derived never, and still true on the day
|
|
32
|
+
* it went stale. The census now takes its population from
|
|
33
|
+
* `listCellRendererTypes()`, `@object-ui/fields`' live reading of the registry,
|
|
34
|
+
* so the count lives in the instrument that re-derives it and nowhere else.
|
|
35
|
+
*
|
|
36
|
+
* ## The five measured refusals
|
|
37
|
+
*
|
|
38
|
+
* | class | types | what the pill got |
|
|
39
|
+
* |-------------------------------|--------------------------------------------------------|-------------------------------------------------------|
|
|
40
|
+
* | a pill inside a pill | `select` `status` `multiselect` `radio` `checkboxes` `tags` | `SelectCellRenderer`'s own `Badge` — one `rounded-full` node nested in the chip's own |
|
|
41
|
+
* | an avatar composite | `user` | TWO `rounded-full` nodes (Radix `Avatar.Root` + `AvatarFallback`) and the initials glued onto the name: `ACAcme Corp` |
|
|
42
|
+
* | an image and no text | `image` `avatar` `signature` | an `<img>` and `textContent === ''` — a pill with nothing to say, and nothing for the accessible name |
|
|
43
|
+
* | a "No value" face | `boolean` `toggle` `datetime` `repeater` (`EmptyValue`), `date` (`formatDate`'s own em-dash, objectui#8581) | the chip is drawn only AFTER `hasCellValue` called the value FILLED; a renderer answering "empty" one band later re-opens exactly the cross-band contradiction objectui#8394 closed |
|
|
44
|
+
* | an interactive control | `file` `video` `audio` (objectui#9161) | an `<a href>` view/download link per file — a control, and the page-title row hosts text |
|
|
45
|
+
*
|
|
46
|
+
* Every other registered type draws plain inline text inside the pill —
|
|
47
|
+
* `Acme Corp` for
|
|
48
|
+
* the nameable families, the JSON literal for `location` / `geolocation` /
|
|
49
|
+
* `address` / `json` / `object` / `composite` / `record` behind objectui#8481's
|
|
50
|
+
* declared json-literal fence, and the value-independent faces (`password`,
|
|
51
|
+
* `secret`, `vector`, `grid`).
|
|
52
|
+
*
|
|
53
|
+
* ## What the refused kinds get instead — NOT a stringifier written here
|
|
54
|
+
*
|
|
55
|
+
* They fall to `coerceToSafeValue`, `@object-ui/fields`' single documented
|
|
56
|
+
* answer to "what text does a cell draw for a value that is not a string".
|
|
57
|
+
* objectui#8596 ruled `select` / `status` / `multiselect` / `radio` /
|
|
58
|
+
* `checkboxes` / `tags` / `user` onto exactly that text for an object value, so
|
|
59
|
+
* for 7 of these 18 the chip is BYTE-EQUAL to its own cell. ⛔ Nothing here
|
|
60
|
+
* invents a renderer-side format (AGENTS.md #0.1): every kind lands either on
|
|
61
|
+
* its own renderer or on the one coercion this repo already had.
|
|
62
|
+
*/
|
|
63
|
+
export declare const CHIP_UNFIT_RENDERER_TYPES: ReadonlySet<string>;
|
|
64
|
+
/**
|
|
65
|
+
* May the chip draw `rendererType` with the field's own cell renderer?
|
|
66
|
+
*
|
|
67
|
+
* Takes the type ALREADY resolved through `resolveCellRendererType`, because
|
|
68
|
+
* that is the key `getCellRenderer` dispatches on — asking this question of the
|
|
69
|
+
* authored spelling would answer for a renderer the chip is not about to use.
|
|
70
|
+
*
|
|
71
|
+
* ⚠️ **The default is PERMISSIVE, and what makes that safe is the census, not
|
|
72
|
+
* this function** (objectui#8734). A type absent from
|
|
73
|
+
* {@link CHIP_UNFIT_RENDERER_TYPES} is admitted, so an UNMEASURED type is
|
|
74
|
+
* admitted too. Inverting that — unknown ⇒ refused — is not the free repair it
|
|
75
|
+
* looks like: it would silently downgrade a legitimately-fitting new type to
|
|
76
|
+
* `coerceToSafeValue`, which is a product decision about the chip and not a
|
|
77
|
+
* defect. What objectui#8734 closed instead is the way an unknown type used to
|
|
78
|
+
* arrive: unnoticed. The census reconciles its table against
|
|
79
|
+
* `listCellRendererTypes()`, so a newly registered type turns CI red and names
|
|
80
|
+
* itself before it can reach this predicate in a release.
|
|
81
|
+
*/
|
|
82
|
+
export declare function chipTakesCellRenderer(rendererType: string): boolean;
|
|
83
|
+
//# sourceMappingURL=summaryChipRenderers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summaryChipRenderers.d.ts","sourceRoot":"","sources":["../src/summaryChipRenderers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AACH,eAAO,MAAM,yBAAyB,EAAE,WAAW,CAAC,MAAM,CAgCxD,CAAC;AAEH;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAEnE"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ServiceObject } from '@objectstack/spec/data';
|
|
1
|
+
import { SelectOptionKind, ServiceObject } from '@objectstack/spec/data';
|
|
2
2
|
import { detectStatusField } from '@object-ui/types';
|
|
3
3
|
/** Minimal shape of an object definition we read here. We deliberately
|
|
4
4
|
* duck-type so this helper has zero hard dependency on a specific
|
|
@@ -18,13 +18,30 @@ export interface ObjectDefLike {
|
|
|
18
18
|
/** Semantic role (ADR-0085): the object's most important fields —
|
|
19
19
|
* drives the highlight strip (first 4). */
|
|
20
20
|
highlightFields?: string[];
|
|
21
|
-
/**
|
|
22
|
-
*
|
|
23
|
-
*
|
|
21
|
+
/**
|
|
22
|
+
* ACCEPTED BUT NEVER READ — do not "tidy" this away (objectui#7287).
|
|
23
|
+
*
|
|
24
|
+
* `primaryField` is a `DetailViewSchema` key (`@object-ui/types` `views.ts`),
|
|
25
|
+
* and reading it off an OBJECT def is the defect objectui#7287 removed:
|
|
26
|
+
* `resolveTitleField` now delegates to `@object-ui/core`'s `resolveNameField`
|
|
27
|
+
* and no code in this module consults this member. No producer can populate
|
|
28
|
+
* it either — `@objectstack/spec`'s object schema is a `strictObject` that
|
|
29
|
+
* answers `unrecognized_keys: ['primaryField']`.
|
|
30
|
+
*
|
|
31
|
+
* It stays declared because this interface is REACHABLE, which is a
|
|
32
|
+
* different question from what it describes: `ObjectDefLike` is re-exported
|
|
33
|
+
* from this package's index and `@object-ui/plugin-detail` is published, so
|
|
34
|
+
* the member is part of a shipped `.d.ts`. Deleting it narrows a published
|
|
35
|
+
* type — an external `const d: ObjectDefLike = { primaryField: 'x' }`
|
|
36
|
+
* compiles today and would stop compiling — and that is a contract change
|
|
37
|
+
* owed its own card, not a rider on a behaviour fix. Retiring it is a
|
|
38
|
+
* deliberate act for someone to take on purpose.
|
|
39
|
+
*/
|
|
24
40
|
primaryField?: string;
|
|
25
|
-
/** Optional section grouping for the details region.
|
|
41
|
+
/** Optional section grouping for the details region. The heading rides
|
|
42
|
+
* `label` — the one slot `@object-ui/types` declares (objectui#6190). */
|
|
26
43
|
sections?: Array<{
|
|
27
|
-
|
|
44
|
+
label?: string;
|
|
28
45
|
columns?: number;
|
|
29
46
|
fields?: any[];
|
|
30
47
|
}>;
|
|
@@ -55,7 +72,7 @@ export interface ObjectDefLike {
|
|
|
55
72
|
fieldGroups?: Array<Partial<NonNullable<ServiceObject['fieldGroups']>[number]>>;
|
|
56
73
|
/**
|
|
57
74
|
* Spec `enable` capability toggles. Only `files` is read here:
|
|
58
|
-
* `enable.files === true` (opt-in, #2727) makes the synthesizer emit an
|
|
75
|
+
* `enable.files === true` (opt-in, objectstack-ai/objectstack#2727) makes the synthesizer emit an
|
|
59
76
|
* Attachments tab beside Details/Related (objectstack#4358).
|
|
60
77
|
*/
|
|
61
78
|
enable?: {
|
|
@@ -82,9 +99,17 @@ export interface ObjectDefFieldLike {
|
|
|
82
99
|
name?: string;
|
|
83
100
|
label?: string;
|
|
84
101
|
type?: string;
|
|
102
|
+
/**
|
|
103
|
+
* The picklist. `kind` is the option's declared lifecycle category
|
|
104
|
+
* (`SelectOption.kind` in `@objectstack/spec/data`, objectstack#23809):
|
|
105
|
+
* {@link deriveStages} carries a `won` / `lost` kind onto the derived stage
|
|
106
|
+
* as its `terminal`, and `record:path` lets any declared kind (`open`
|
|
107
|
+
* included) win over its spelling heuristic (objectui#12907).
|
|
108
|
+
*/
|
|
85
109
|
options?: Array<{
|
|
86
110
|
value: any;
|
|
87
111
|
label: string;
|
|
112
|
+
kind?: SelectOptionKind;
|
|
88
113
|
}>;
|
|
89
114
|
/** Declared group membership — matches a `fieldGroups[].key`. */
|
|
90
115
|
group?: string;
|
|
@@ -100,9 +125,10 @@ export interface BuildPageOptions {
|
|
|
100
125
|
value: any;
|
|
101
126
|
label: string;
|
|
102
127
|
}>;
|
|
103
|
-
/** Override the auto-derived section grouping.
|
|
128
|
+
/** Override the auto-derived section grouping. The heading rides `label` —
|
|
129
|
+
* the one slot `@object-ui/types` declares (objectui#6190). */
|
|
104
130
|
sections?: Array<{
|
|
105
|
-
|
|
131
|
+
label?: string;
|
|
106
132
|
columns?: number;
|
|
107
133
|
fields?: any[];
|
|
108
134
|
}>;
|
|
@@ -118,9 +144,13 @@ export interface BuildPageOptions {
|
|
|
118
144
|
* Opt in to the Reference Rail (aside region with
|
|
119
145
|
* `record:reference_rail`). The rail is OFF by default — it fans out a
|
|
120
146
|
* collection query per related list, which is wasteful on records the
|
|
121
|
-
* author never intended to summarize. Set `showReferenceRail: true`
|
|
122
|
-
*
|
|
147
|
+
* author never intended to summarize. Set `showReferenceRail: true` on
|
|
148
|
+
* this options object to surface it — that is the only route: ADR-0085
|
|
149
|
+
* removed the per-object `detail` hints block, so no object definition
|
|
150
|
+
* can switch the rail on, and a per-page rail is an authored
|
|
151
|
+
* `record:reference_rail` node in an assigned Page schema. It then
|
|
123
152
|
* emits only when `related` has at least 2 entries.
|
|
153
|
+
* Pinned by `__tests__/referenceRailRoute-9816.test.ts`.
|
|
124
154
|
*/
|
|
125
155
|
showReferenceRail?: boolean;
|
|
126
156
|
/**
|
|
@@ -150,7 +180,7 @@ export interface BuildPageOptions {
|
|
|
150
180
|
*
|
|
151
181
|
* - `objectName` and `relationshipField` are required.
|
|
152
182
|
* - `title` overrides the default child-object label.
|
|
153
|
-
* - `columns` / `limit` / `icon` are forwarded to the renderer.
|
|
183
|
+
* - `columns` / `limit` / `icon` / `sort` are forwarded to the renderer.
|
|
154
184
|
*/
|
|
155
185
|
related?: Array<{
|
|
156
186
|
title?: string;
|
|
@@ -159,6 +189,40 @@ export interface BuildPageOptions {
|
|
|
159
189
|
columns?: any[];
|
|
160
190
|
limit?: number;
|
|
161
191
|
icon?: string;
|
|
192
|
+
/**
|
|
193
|
+
* Row order for this list — the spec `record:related_list.sort` union,
|
|
194
|
+
* forwarded verbatim onto the synthesized node.
|
|
195
|
+
*
|
|
196
|
+
* The host supplies it; this synthesizer neither derives nor overrides it.
|
|
197
|
+
* `RecordDetailView` fills it from the child object's DEFAULT LIST VIEW
|
|
198
|
+
* sort (objectui#5795 — ruled direction 1 on objectstack#11345,
|
|
199
|
+
* maintainer 2026-08-23: inherit the child list view's sort, NO new spec
|
|
200
|
+
* key), already lowered to the array arm. Omitted → the node carries no
|
|
201
|
+
* `sort` and the related list falls back to the server's PK order, exactly
|
|
202
|
+
* as before this key had a producer.
|
|
203
|
+
*/
|
|
204
|
+
sort?: string | Array<{
|
|
205
|
+
field: string;
|
|
206
|
+
order: 'asc' | 'desc';
|
|
207
|
+
}>;
|
|
208
|
+
/**
|
|
209
|
+
* This list's own declared SCOPE — forwarded verbatim onto the synthesized
|
|
210
|
+
* node's `filter`, the key `record:related_list` has read since
|
|
211
|
+
* objectstack#7118 (`RelatedList` ANDs it with `{ [relationshipField]:
|
|
212
|
+
* parentId }`, never substituting for it).
|
|
213
|
+
*
|
|
214
|
+
* The host supplies it; this synthesizer neither derives nor merges it.
|
|
215
|
+
* `RecordDetailView` fills it from the FK field's `relatedListFilter`
|
|
216
|
+
* (objectui#4664 — the spec key from objectstack#8704 / PR objectstack-ai/objectstack#8955), already
|
|
217
|
+
* in the canonical Query-DSL `FilterCondition` shape that key declares. The
|
|
218
|
+
* component-level authored `filter` and this derived one are therefore the
|
|
219
|
+
* same vocabulary arriving at the same prop, which is the point: one read
|
|
220
|
+
* site, one lowering, no per-producer dialect.
|
|
221
|
+
*
|
|
222
|
+
* Omitted → the node carries no `filter` and the list sends the parent
|
|
223
|
+
* scope alone, exactly as before this key had a producer.
|
|
224
|
+
*/
|
|
225
|
+
filter?: Record<string, any> | any[];
|
|
162
226
|
/**
|
|
163
227
|
* `relatedList: 'primary'` — a CORE relationship. Under the default
|
|
164
228
|
* layout this list is promoted to its OWN tab; non-primary lists collapse
|
|
@@ -268,24 +332,78 @@ export interface BuildPageOptions {
|
|
|
268
332
|
* long-standing plugin-detail import path.
|
|
269
333
|
*/
|
|
270
334
|
export { detectStatusField };
|
|
335
|
+
/**
|
|
336
|
+
* The `record:path` terminal a declared option `kind` stands for: `won` and
|
|
337
|
+
* `lost` are the spec's `stages[].terminal` values verbatim (the vocabulary
|
|
338
|
+
* objectstack#23809 chose to match), and `open` is no terminal.
|
|
339
|
+
*/
|
|
340
|
+
export declare function stageTerminalOfKind(kind: SelectOptionKind | undefined): 'won' | 'lost' | undefined;
|
|
271
341
|
/**
|
|
272
342
|
* Derive stage values from an object field's `options` (picklist).
|
|
343
|
+
*
|
|
344
|
+
* A stage carries `terminal` from its option's declared `kind`
|
|
345
|
+
* ({@link stageTerminalOfKind}, objectui#12907), so a `won` option is the
|
|
346
|
+
* path's forward terminus and a `lost` one sits in the separated group
|
|
347
|
+
* whatever it is called. An option that declares no kind, or `open`, gets no
|
|
348
|
+
* `terminal` key: the stage shape is the spec's strict `stages[]` row, which
|
|
349
|
+
* has no way to say "declared open" — `record:path` reads that off the field
|
|
350
|
+
* itself ({@link declaredStageKinds}).
|
|
273
351
|
*/
|
|
274
352
|
export declare function deriveStages(def: ObjectDefLike | undefined, statusField: string | null): Array<{
|
|
275
353
|
value: any;
|
|
276
354
|
label: string;
|
|
355
|
+
terminal?: 'won' | 'lost';
|
|
277
356
|
}> | null;
|
|
278
357
|
/**
|
|
279
|
-
*
|
|
280
|
-
*
|
|
281
|
-
*
|
|
282
|
-
*
|
|
283
|
-
*
|
|
358
|
+
* The lifecycle `kind` each option of `statusField` declares, keyed by option
|
|
359
|
+
* value — only the options that declare one (objectui#12907).
|
|
360
|
+
*
|
|
361
|
+
* ⚠️ Package-internal: exported for `renderers/record-path.tsx`, NOT
|
|
362
|
+
* re-exported from the package entry. `record:path` consults it after a
|
|
363
|
+
* stage's explicit `terminal` and before its spelling heuristic, because the
|
|
364
|
+
* spec's strict `stages[]` row can carry `won` / `lost` but not `open`: a
|
|
365
|
+
* declared `open` on a value spelled `closed_won` has to beat the heuristic
|
|
366
|
+
* from here. Returns `null` when there is nothing to consult.
|
|
367
|
+
*/
|
|
368
|
+
export declare function declaredStageKinds(def: ObjectDefLike | undefined, statusField: string | null): Map<unknown, SelectOptionKind> | null;
|
|
369
|
+
/**
|
|
370
|
+
* WHICH FIELD titles this record — the field whose value the page renders as
|
|
371
|
+
* its H1, in NAME space.
|
|
372
|
+
*
|
|
373
|
+
* DELEGATES to `@object-ui/core`'s `resolveNameField`: the ONE shared ADR-0079
|
|
374
|
+
* ladder (`nameField` -> deprecated `displayNameField` / `NAME_FIELD_KEY` ->
|
|
375
|
+
* type-aware derivation), the same spelling `getRecordDisplayName` reads to
|
|
376
|
+
* produce the H1's VALUE and `leadWithNameField` reads to lead a list. It does
|
|
377
|
+
* not re-implement that ladder. ADR-0079 collapsed ~6 divergent title
|
|
378
|
+
* resolvers and this module grew one back (objectui#7287); a second ladder
|
|
379
|
+
* that agrees today diverges again on the next change, which is the whole
|
|
380
|
+
* history of this defect.
|
|
381
|
+
*
|
|
382
|
+
* Two rungs went away with the delegation:
|
|
383
|
+
*
|
|
384
|
+
* - `def.primaryField` — a `DetailViewSchema` key (`@object-ui/types`
|
|
385
|
+
* `views.ts`), read here off an OBJECT def and ranked ABOVE the canonical
|
|
386
|
+
* `nameField` ADR-0079 Phase 2 made the pointer. No producer can put it
|
|
387
|
+
* there: `@objectstack/spec`'s object schema is a `strictObject` that
|
|
388
|
+
* answers `unrecognized_keys: ['primaryField']`, and `ObjectSchema.create()`
|
|
389
|
+
* throws — which is why objectstack#6326 deleted the identical read from
|
|
390
|
+
* two lint rules. A census across both repos found zero object payloads
|
|
391
|
+
* carrying it. Same shape as the undeclared `objectDef.titleField` read
|
|
392
|
+
* objectui#6531 measured and #6557 removed.
|
|
393
|
+
* - the literal `['name','full_name','title','subject','display_name']` walk
|
|
394
|
+
* — a NAME match with no type check. `deriveTitleField` ranks those same
|
|
395
|
+
* name-ish names first AND rejects non-title types, so a `select` named
|
|
396
|
+
* `title` stops being named as the H1 field that the H1 never shows.
|
|
397
|
+
*
|
|
398
|
+
* Returns `null` rather than `undefined` for this module's `!== titleField`
|
|
399
|
+
* filters and app-shell's `?? 'name'` call site.
|
|
284
400
|
*/
|
|
285
401
|
export declare function resolveTitleField(def: ObjectDefLike | undefined): string | null;
|
|
286
402
|
/**
|
|
287
403
|
* Pick up to N "highlight" fields by name. Skips the status field
|
|
288
404
|
* (already shown in `record:path`) and obvious junk like id / created_at.
|
|
405
|
+
* Members of a group gated by `visibleWhen` are never picked
|
|
406
|
+
* ({@link membersOfGatedFieldGroups}, objectui#12720).
|
|
289
407
|
*/
|
|
290
408
|
export declare function deriveHighlightFields(def: ObjectDefLike | undefined, statusField: string | null, max?: number): string[];
|
|
291
409
|
/**
|
|
@@ -313,6 +431,40 @@ export declare function buildDefaultActions(_def: ObjectDefLike | undefined, hea
|
|
|
313
431
|
* two adjacent nodes.
|
|
314
432
|
*/
|
|
315
433
|
export declare function buildDefaultHighlights(def: ObjectDefLike | undefined, options?: Pick<BuildPageOptions, 'highlightFields' | 'statusField' | 'stages' | 'hideHighlights' | 'hidePath'>): any[];
|
|
434
|
+
/**
|
|
435
|
+
* One field group, resolved — the section a `record:details` `{ group }`
|
|
436
|
+
* reference stands for — plus the group's own ADR-0089 `visibleWhen`
|
|
437
|
+
* (objectui#11630).
|
|
438
|
+
*
|
|
439
|
+
* ⚠️ Package-internal. It is exported from this module for
|
|
440
|
+
* `renderers/record-details.tsx` and is NOT re-exported from the package entry.
|
|
441
|
+
* The predicate travels BESIDE the section, never on it: `section` is exactly
|
|
442
|
+
* what the public {@link deriveFieldGroupDetailSections} returns, so no caller
|
|
443
|
+
* of the public function can copy a `visibleWhen` onto an enumerated
|
|
444
|
+
* `record:details` section. `@objectstack/spec`'s `RecordDetailsProps.sections[]`
|
|
445
|
+
* is strict and refuses that key on parse; the spec's way to gate a section is
|
|
446
|
+
* to reference the gated group with `{ group }`, which inherits its predicate.
|
|
447
|
+
*/
|
|
448
|
+
export interface FieldGroupDetailEntry {
|
|
449
|
+
/** The group key. Absent on the trailing ungrouped bucket. */
|
|
450
|
+
key?: string;
|
|
451
|
+
/**
|
|
452
|
+
* The group's `visibleWhen`, verbatim and unevaluated — a bare CEL string or
|
|
453
|
+
* an Expression envelope, as `deriveFieldGroupLayout` passes it through.
|
|
454
|
+
* Never present on the ungrouped bucket.
|
|
455
|
+
*/
|
|
456
|
+
visibleWhen?: unknown;
|
|
457
|
+
/** The resolved section, in DetailSection's shape. */
|
|
458
|
+
section: Record<string, any>;
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* The derivation behind both {@link deriveFieldGroupDetailSections} and the
|
|
462
|
+
* `{ group }` references {@link resolveDetailSections} emits — one code path,
|
|
463
|
+
* so a reference and the section it resolves to cannot disagree.
|
|
464
|
+
*
|
|
465
|
+
* Package-internal; see {@link FieldGroupDetailEntry}.
|
|
466
|
+
*/
|
|
467
|
+
export declare function deriveFieldGroupDetailEntries(def: ObjectDefLike | undefined): FieldGroupDetailEntry[] | null;
|
|
316
468
|
/**
|
|
317
469
|
* Derive detail sections from the object's declared `fieldGroups` plus each
|
|
318
470
|
* field's `group` membership. The grouping SEMANTICS (declared order, empty
|
|
@@ -328,14 +480,29 @@ export declare function buildDefaultHighlights(def: ObjectDefLike | undefined, o
|
|
|
328
480
|
* Section fields are emitted as rich descriptors (`{ name, label, type,
|
|
329
481
|
* options }`) so DetailSection renders typed values without re-resolving
|
|
330
482
|
* the object definition.
|
|
483
|
+
*
|
|
484
|
+
* ⚠️ This is the RESOLVED form of a group — what `record:details` renders for
|
|
485
|
+
* a `{ group }` reference — and not a page section to write into a
|
|
486
|
+
* `record:details` node: the rich `fields` descriptors are refused by
|
|
487
|
+
* `@objectstack/spec`'s `RecordDetailsProps.sections[].fields` (bare names), and
|
|
488
|
+
* a group's `visibleWhen` is deliberately not on it. A page references the group
|
|
489
|
+
* instead, which is what {@link resolveDetailSections} emits (objectui#11630).
|
|
331
490
|
*/
|
|
332
491
|
export declare function deriveFieldGroupDetailSections(def: ObjectDefLike | undefined): Array<Record<string, any>> | null;
|
|
333
492
|
/**
|
|
334
493
|
* Resolve the sections for the Details tab body:
|
|
335
494
|
* 1) explicit `options.sections` from the caller (programmatic API —
|
|
336
495
|
* Studio preview / metadata-admin anchors);
|
|
337
|
-
* 2) else
|
|
338
|
-
*
|
|
496
|
+
* 2) else the object's `fieldGroups` semantic role, as `{ group }`
|
|
497
|
+
* references plus the ungrouped bucket's field names
|
|
498
|
+
* (`fieldGroupSectionReferences`, objectui#11630);
|
|
499
|
+
* 3) else `undefined` — a bare `record:details`, which draws the object's
|
|
500
|
+
* `highlightFields` (the spec's declared fallback for a node with
|
|
501
|
+
* neither `sections` nor `fields`, objectui#12433), and an empty body
|
|
502
|
+
* when the object declares none. It does NOT draw every field: a caller
|
|
503
|
+
* that wants the running app's default body passes that body's sections
|
|
504
|
+
* in (1) — app-shell's `RecordDetailView`, and Studio's page-create seed
|
|
505
|
+
* and slotted preview, take them from one derivation (objectui#12442).
|
|
339
506
|
*/
|
|
340
507
|
export declare function resolveDetailSections(def: ObjectDefLike | undefined, sections?: BuildPageOptions['sections']): BuildPageOptions['sections'] | undefined;
|
|
341
508
|
/**
|
|
@@ -356,7 +523,7 @@ export declare function buildDefaultTabs(def: ObjectDefLike | undefined, options
|
|
|
356
523
|
*/
|
|
357
524
|
export declare function buildDefaultDiscussion(): any;
|
|
358
525
|
/**
|
|
359
|
-
* Sub-builder: the `record:attachments` panel (#2727). Emitted only when the
|
|
526
|
+
* Sub-builder: the `record:attachments` panel (objectstack-ai/objectstack#2727). Emitted only when the
|
|
360
527
|
* object opts in via `enable.files: true` — the same gate the server enforces
|
|
361
528
|
* on `sys_attachment` rows (403 FILES_DISABLED otherwise).
|
|
362
529
|
*/
|
|
@@ -366,7 +533,7 @@ export declare function buildDefaultAttachments(): any;
|
|
|
366
533
|
* page.
|
|
367
534
|
*
|
|
368
535
|
* Shape:
|
|
369
|
-
* { type:'record', template:'
|
|
536
|
+
* { type:'record', template:'default', regions:[ { name:'main',
|
|
370
537
|
* components: [page:header, record:highlights?, record:path?,
|
|
371
538
|
* page:tabs, record:discussion?] } ] }
|
|
372
539
|
* For `enable.files: true` objects the tabs node carries a peer
|