@magicvr/schema-ui-renderer 0.3.1 → 0.3.2
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/package.json +3 -3
- package/components/account-session-toolbar.d.ts +0 -2
- package/components/activity-export.d.ts +0 -2
- package/components/cron-preview.d.ts +0 -2
- package/components/data-permission-scopes.d.ts +0 -2
- package/components/data-table.d.ts +0 -43
- package/components/email-identity.d.ts +0 -2
- package/components/force-password-change.d.ts +0 -1
- package/components/import-template-download.d.ts +0 -2
- package/components/invite-accept.d.ts +0 -6
- package/components/invite-issue-card.d.ts +0 -7
- package/components/invite-resend-dialog.d.ts +0 -9
- package/components/locale-switcher.d.ts +0 -23
- package/components/mail-admin-tab.d.ts +0 -2
- package/components/mfa-manager.d.ts +0 -2
- package/components/monitoring-auto-refresh.d.ts +0 -2
- package/components/notification-center.d.ts +0 -2
- package/components/password-policy-tab.d.ts +0 -6
- package/components/qr-code.d.ts +0 -16
- package/components/theme-toggle.d.ts +0 -10
- package/components/timezone-switcher.d.ts +0 -16
- package/components/wallet-ensure.d.ts +0 -2
- package/renderer/confirm.d.ts +0 -17
- package/renderer/custom-components.d.ts +0 -14
- package/renderer/form-controls.d.ts +0 -45
- package/renderer/form-controls.types.d.ts +0 -135
- package/renderer/index.d.ts +0 -13
- package/renderer/modal.d.ts +0 -6
- package/renderer/permissions.d.ts +0 -53
- package/renderer/reaction-engine.d.ts +0 -92
- package/renderer/reaction-expression.d.ts +0 -74
- package/renderer/reactions.d.ts +0 -64
- package/renderer/render.d.ts +0 -194
- package/renderer/render.types.d.ts +0 -289
- package/renderer/resource.d.ts +0 -114
- package/renderer/row-action.d.ts +0 -28
- package/renderer/schema-table.d.ts +0 -90
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Full protocol expression engine (schema-ui-docs@2.7.0 · docs/02-reaction-expression.md).
|
|
3
|
-
*
|
|
4
|
-
* Whitelisted grammar (no eval / new Function):
|
|
5
|
-
* - namespaces: $deps.<field>, $self, $context.user.* / $context.features.*
|
|
6
|
-
* - operators: == != > >= < <= contains && || !
|
|
7
|
-
* - grouping: ( )
|
|
8
|
-
* - literals: 'str' | "str" | number (int/float/exponent) | true | false | null
|
|
9
|
-
*
|
|
10
|
-
* Semantics (ADR-0016 / §7-§14):
|
|
11
|
-
* - strict typing, no coercion: 1 == 1.0 true; 1 == '1' false; true == 1 false
|
|
12
|
-
* - contains: array left operand, strict element equality; non-array → false
|
|
13
|
-
* - string ordering by Unicode code points (not UTF-16 code units)
|
|
14
|
-
* - undefined values compare as false (missing deps never throw)
|
|
15
|
-
*/
|
|
16
|
-
export type ExprValue = string | number | boolean | null | ExprValue[] | {
|
|
17
|
-
[key: string]: ExprValue;
|
|
18
|
-
} | undefined;
|
|
19
|
-
export interface ReactionEnv {
|
|
20
|
-
/** $deps.<field> values (form field snapshot). */
|
|
21
|
-
deps?: Record<string, unknown>;
|
|
22
|
-
/** $self (current field value). */
|
|
23
|
-
self?: unknown;
|
|
24
|
-
/** $context.user.* / $context.features.* snapshots. */
|
|
25
|
-
context?: Record<string, unknown>;
|
|
26
|
-
}
|
|
27
|
-
export type ParseError = {
|
|
28
|
-
ok: false;
|
|
29
|
-
code: "SYNTAX";
|
|
30
|
-
message: string;
|
|
31
|
-
} | {
|
|
32
|
-
ok: false;
|
|
33
|
-
code: "FORBIDDEN_VARIABLE";
|
|
34
|
-
message: string;
|
|
35
|
-
} | {
|
|
36
|
-
ok: false;
|
|
37
|
-
code: "UNSUPPORTED_OPERATOR";
|
|
38
|
-
message: string;
|
|
39
|
-
};
|
|
40
|
-
export type ParsedExpr = {
|
|
41
|
-
kind: "literal";
|
|
42
|
-
value: ExprValue;
|
|
43
|
-
} | {
|
|
44
|
-
kind: "var";
|
|
45
|
-
path: string[];
|
|
46
|
-
} | {
|
|
47
|
-
kind: "self";
|
|
48
|
-
} | {
|
|
49
|
-
kind: "not";
|
|
50
|
-
operand: ParsedExpr;
|
|
51
|
-
} | {
|
|
52
|
-
kind: "and";
|
|
53
|
-
left: ParsedExpr;
|
|
54
|
-
right: ParsedExpr;
|
|
55
|
-
} | {
|
|
56
|
-
kind: "or";
|
|
57
|
-
left: ParsedExpr;
|
|
58
|
-
right: ParsedExpr;
|
|
59
|
-
} | {
|
|
60
|
-
kind: "compare";
|
|
61
|
-
op: "==" | "!=" | ">" | ">=" | "<" | "<=" | "contains";
|
|
62
|
-
left: ParsedExpr;
|
|
63
|
-
right: ParsedExpr;
|
|
64
|
-
};
|
|
65
|
-
/** Parses a whitelisted expression; returns the AST or a typed error. */
|
|
66
|
-
export declare function parseExpression(source: string): ParsedExpr | ParseError;
|
|
67
|
-
/** Deep equality (arrays/objects by structure; scalars by strict identity). */
|
|
68
|
-
export declare function deepEqual(left: unknown, right: unknown): boolean;
|
|
69
|
-
/** Evaluates a whitelisted expression to a boolean; invalid input → false. */
|
|
70
|
-
export declare function evaluateFullExpression(source: string, env: ReactionEnv): boolean;
|
|
71
|
-
/** True when `source` parses under the full grammar. */
|
|
72
|
-
export declare function isValidFullExpression(source: string): boolean;
|
|
73
|
-
/** Extracts the $deps.<root> field names referenced by an expression. */
|
|
74
|
-
export declare function expressionDependencyFields(source: string): string[];
|
package/renderer/reactions.d.ts
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* R5 D-EXPR reaction surface (frozen Q: reactions operate on the $context
|
|
3
|
-
* namespace only; no field-value triggers).
|
|
4
|
-
*
|
|
5
|
-
* A reaction is a `{ when, apply }` rule: `when` is a frozen $context
|
|
6
|
-
* expression (evaluateExpression grammar), and `apply` turns a form control
|
|
7
|
-
* state on/off when the expression holds. This is the renderer-level
|
|
8
|
-
* equivalent of the navigation visibleWhen gate, applied to form fields.
|
|
9
|
-
*
|
|
10
|
-
* Fails closed: an unparseable `when` expression or an unknown apply target
|
|
11
|
-
* keeps the field at its default state instead of mutating it silently.
|
|
12
|
-
*/
|
|
13
|
-
export interface ReactionApply {
|
|
14
|
-
fieldId: string;
|
|
15
|
-
/** visible/disabled toggles are explicit booleans (no implicit flip). */
|
|
16
|
-
visible?: boolean;
|
|
17
|
-
disabled?: boolean;
|
|
18
|
-
}
|
|
19
|
-
export interface ReactionRule {
|
|
20
|
-
id: string;
|
|
21
|
-
when: string;
|
|
22
|
-
apply: ReactionApply[];
|
|
23
|
-
}
|
|
24
|
-
export type ReactionErrorCode = "REACTION_EXPRESSION_INVALID" | "REACTION_APPLY_FIELD_UNKNOWN" | "REACTION_APPLY_INVALID";
|
|
25
|
-
export interface ReactionError {
|
|
26
|
-
code: ReactionErrorCode;
|
|
27
|
-
path: string;
|
|
28
|
-
message: string;
|
|
29
|
-
}
|
|
30
|
-
export interface FormControlState {
|
|
31
|
-
visible: boolean;
|
|
32
|
-
disabled: boolean;
|
|
33
|
-
}
|
|
34
|
-
export type FormControlStateMap = Record<string, FormControlState>;
|
|
35
|
-
export interface ReactionEvaluation {
|
|
36
|
-
state: FormControlStateMap;
|
|
37
|
-
errors: ReactionError[];
|
|
38
|
-
}
|
|
39
|
-
/** Parses a raw reaction rule, fail-closed on malformed shapes. */
|
|
40
|
-
export declare function parseReactionRule(value: unknown, path: string): ReactionRule | ReactionError;
|
|
41
|
-
/**
|
|
42
|
-
* Evaluates a reaction rule list against the frozen $context snapshot.
|
|
43
|
-
* Unknown apply fieldIds fail closed (keep default) and are reported.
|
|
44
|
-
*/
|
|
45
|
-
export declare function evaluateReactions(rules: ReactionRule[], context: Record<string, unknown>, fieldIds: string[]): ReactionEvaluation;
|
|
46
|
-
/** Validates raw rules and returns parsed rules + fail-closed errors. */
|
|
47
|
-
export declare function parseAndEvaluateReactions(rawRules: unknown, context: Record<string, unknown>, fieldIds: string[]): ReactionEvaluation;
|
|
48
|
-
export interface FullReactionResult {
|
|
49
|
-
/** True when the form declares upstream-shaped per-field reactions ($deps). */
|
|
50
|
-
usesFullEngine: boolean;
|
|
51
|
-
/** Per-field control state after convergence (visible/disabled). */
|
|
52
|
-
state: FormControlStateMap;
|
|
53
|
-
/** Value commits to merge into the form values (last-wins, convergent). */
|
|
54
|
-
values: Record<string, unknown>;
|
|
55
|
-
errors: ReactionError[];
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Resolves the full multi-round $deps reaction engine over a form's fields.
|
|
59
|
-
*
|
|
60
|
-
* Upstream shape (02-reaction-expression.md): each field node carries
|
|
61
|
-
* `reactions: [{ when, fulfill, otherwise }]`. Returns the convergent control
|
|
62
|
-
* state + value commits; malformed rules fail closed (reported, not applied).
|
|
63
|
-
*/
|
|
64
|
-
export declare function resolveFullFormReactions(rawFields: unknown, values: Record<string, unknown>, baselines: Record<string, unknown>): FullReactionResult;
|
package/renderer/render.d.ts
DELETED
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
import { type ComponentType, type ReactNode } from "react";
|
|
2
|
-
import { type UploadableFile } from "@schema-ui/protocol/conformance/upload-orchestration";
|
|
3
|
-
import { type FormControlField } from "@schema-ui/renderer/renderer/form-controls.types";
|
|
4
|
-
import { type ResourceList, type ResourceQuery } from "@schema-ui/renderer/renderer/resource";
|
|
5
|
-
import { type RenderActionButtonNode, type RenderChartNode, type RenderFormNode, type RenderPageDocument, type RenderStatCardNode, type RenderTableNode } from "@schema-ui/renderer/renderer/render.types";
|
|
6
|
-
/**
|
|
7
|
-
* R5 D-COMP minimal Renderer (resolve R4 F-002) + S4 Schema CRUD (GOAL-007).
|
|
8
|
-
*
|
|
9
|
-
* Dispatch layer: parses a page document, applies the frozen $context
|
|
10
|
-
* reaction engine to form field state, and renders whitelisted node types
|
|
11
|
-
* through the components in this directory. Unknown node types fail closed.
|
|
12
|
-
*
|
|
13
|
-
* S4 one-time completion (I-007-003 v0.2.2 §9): a SchemaCrudProvider owns the
|
|
14
|
-
* cross-node state a Schema-driven CRUD page needs — selected row (feeds
|
|
15
|
-
* recordView + edit-form prefill), per-table query (search form-to-query
|
|
16
|
-
* binding), a reload token, the active modal, the pending delete confirm, and
|
|
17
|
-
* a generic action executor that gates through the frozen `executeAction`
|
|
18
|
-
* engine and constructs requests with the pinned conformance constructor
|
|
19
|
-
* (`request-construction.ts`). Every page-level behaviour stays fixture-driven;
|
|
20
|
-
* after this completion page behavior remains schema-owned; core fixtures and
|
|
21
|
-
* module-owned schema packages can add pages without Renderer changes.
|
|
22
|
-
*
|
|
23
|
-
* Scope: the frozen §5 node whitelist — layout (grid/section/tabs),
|
|
24
|
-
* data/action (text/table/recordView/actionButton) and form. The form control
|
|
25
|
-
* whitelist itself is enforced by D-FORM (isWhitelistedFormControl /
|
|
26
|
-
* checkFormCapabilities) via gateRenderFormFields. The default app path wires
|
|
27
|
-
* a schema-driven table surface (SchemaTable, GOAL-004) as `tableRenderer`;
|
|
28
|
-
* a table node dispatched without one fails closed with an observable note.
|
|
29
|
-
*
|
|
30
|
-
* A-002 F-002-002 (GOAL-009 S1): form submission is blocked while any
|
|
31
|
-
* gate/reaction error is present — the submit button is disabled and
|
|
32
|
-
* handleSubmit re-rejects before any request can be constructed.
|
|
33
|
-
*/
|
|
34
|
-
export interface RendererComponentProps {
|
|
35
|
-
document: RenderPageDocument;
|
|
36
|
-
context: Record<string, unknown>;
|
|
37
|
-
/** Renders a table node; provided by the example page that owns data. */
|
|
38
|
-
tableRenderer?: (node: RenderTableNode) => ReactNode;
|
|
39
|
-
/** Renders statCard/chart nodes (supportsData display, registry); defaults to built-ins. */
|
|
40
|
-
dataRenderer?: (node: RenderStatCardNode | RenderChartNode) => ReactNode;
|
|
41
|
-
/** Invoked when an actionButton node is activated. */
|
|
42
|
-
onAction?: (node: RenderActionButtonNode) => void;
|
|
43
|
-
/**
|
|
44
|
-
* Session-internal navigation hook (ADR-0021 navigate actions; GOAL-015
|
|
45
|
-
* F-001): the host pushes the target onto its own history/visit stack so
|
|
46
|
-
* breadcrumbs survive. Falls back to window.location.assign when absent.
|
|
47
|
-
*/
|
|
48
|
-
onNavigate?: (url: string) => void;
|
|
49
|
-
/** Overrides the default FormControls component (keeps field wiring local). */
|
|
50
|
-
formComponent?: ComponentType<{
|
|
51
|
-
fields: FormControlField[];
|
|
52
|
-
values: Record<string, unknown>;
|
|
53
|
-
onChange: (id: string, value: unknown) => void;
|
|
54
|
-
fieldDisabled?: (id: string) => boolean;
|
|
55
|
-
onUpload?: (field: FormControlField, files: UploadableFile[]) => Promise<unknown>;
|
|
56
|
-
/** W11 · U-01/U-02: auth-aware transport for dynamic option sources. */
|
|
57
|
-
fetcher?: typeof fetch;
|
|
58
|
-
}>;
|
|
59
|
-
}
|
|
60
|
-
export interface SchemaCrudFeedback {
|
|
61
|
-
kind: "success" | "error";
|
|
62
|
-
message: string;
|
|
63
|
-
code?: string;
|
|
64
|
-
/** VP-007 S4: catalog key for the frontend localization floor. */
|
|
65
|
-
messageKey?: string;
|
|
66
|
-
/** VP-007 S4: interpolation params for messageKey. */
|
|
67
|
-
params?: Record<string, unknown>;
|
|
68
|
-
}
|
|
69
|
-
export interface SchemaCrudConfirm {
|
|
70
|
-
actionRef: string;
|
|
71
|
-
actionKey: string;
|
|
72
|
-
row: Record<string, unknown>;
|
|
73
|
-
requestMapping?: Record<string, unknown>;
|
|
74
|
-
message: string;
|
|
75
|
-
/** Batch trigger confirm (ADR-0022 D4/D5): carries the selection snapshot. */
|
|
76
|
-
batch?: {
|
|
77
|
-
tableId: string;
|
|
78
|
-
selection: TableSelection;
|
|
79
|
-
};
|
|
80
|
-
/** Toolbar item batchMapping carried through confirm. */
|
|
81
|
-
batchMapping?: Record<string, unknown>;
|
|
82
|
-
}
|
|
83
|
-
/** Selection snapshot (ADR-0022 D3): ordered keys + count. */
|
|
84
|
-
export interface TableSelection {
|
|
85
|
-
keys: unknown[];
|
|
86
|
-
count: number;
|
|
87
|
-
}
|
|
88
|
-
export type ActionResult = {
|
|
89
|
-
ok: true;
|
|
90
|
-
fieldErrors?: Array<{
|
|
91
|
-
field: string;
|
|
92
|
-
reason: string;
|
|
93
|
-
rowNumber?: number;
|
|
94
|
-
}>;
|
|
95
|
-
message?: string;
|
|
96
|
-
messageKey?: string;
|
|
97
|
-
} | {
|
|
98
|
-
ok: false;
|
|
99
|
-
code: string;
|
|
100
|
-
message: string;
|
|
101
|
-
messageKey?: string;
|
|
102
|
-
params?: Record<string, unknown>;
|
|
103
|
-
/** GOAL-014 D-002 §2: server field-level validation failures. */
|
|
104
|
-
fieldErrors?: Array<{
|
|
105
|
-
field: string;
|
|
106
|
-
reason: string;
|
|
107
|
-
rowNumber?: number;
|
|
108
|
-
}>;
|
|
109
|
-
};
|
|
110
|
-
export interface SchemaCrudValue {
|
|
111
|
-
selectedRow: Record<string, unknown> | null;
|
|
112
|
-
selectRow: (row: Record<string, unknown> | null) => void;
|
|
113
|
-
tableQuery: (id: string) => ResourceQuery | undefined;
|
|
114
|
-
setTableQuery: (id: string, query: ResourceQuery) => void;
|
|
115
|
-
reloadToken: number;
|
|
116
|
-
reloadList: () => void;
|
|
117
|
-
/**
|
|
118
|
-
* Fetches a resource list through the page-level in-flight coalescer:
|
|
119
|
-
* simultaneous consumers of the same URL share ONE network request (three
|
|
120
|
-
* statCards + the wallet-ensure probe on one "我的钱包" visit merge into a
|
|
121
|
-
* single GET /me). Requests are otherwise never memoized — every query,
|
|
122
|
-
* reset or reload refetches — and reloadList drops the in-flight map so a
|
|
123
|
-
* reload issued during a slow fetch starts its own fresh request.
|
|
124
|
-
* `transport` is the caller's own transport (a directly injected fixture or
|
|
125
|
-
* the auth fetcher); defaults to the provider's registered fetcher.
|
|
126
|
-
*/
|
|
127
|
-
fetchList: (dataSource: string, query: ResourceQuery, extraQuery?: string, transport?: typeof fetch) => Promise<ResourceList>;
|
|
128
|
-
/**
|
|
129
|
-
* Targeted display-data refresh (W25): bumps the per-URL refresh token for
|
|
130
|
-
* the standard display query of `dataSource` (statCard/chart consume it),
|
|
131
|
-
* so a consumer can refetch ONE surface without a full-page reload wave.
|
|
132
|
-
* Only applies to display nodes without route-param bindings (the standard
|
|
133
|
-
* DISPLAY_LIST_QUERY shape); tables/misc surfaces keep their data until a
|
|
134
|
-
* manual reload.
|
|
135
|
-
*/
|
|
136
|
-
refreshList: (dataSource: string) => void;
|
|
137
|
-
/** Current refresh token for a display dataSource (0 when untouched). */
|
|
138
|
-
listRefreshToken: (dataSource: string) => number;
|
|
139
|
-
activeModal: {
|
|
140
|
-
actionRef: string;
|
|
141
|
-
row: Record<string, unknown> | null;
|
|
142
|
-
title: string;
|
|
143
|
-
} | null;
|
|
144
|
-
modalRow: Record<string, unknown> | null;
|
|
145
|
-
openModal: (actionRef: string, row: Record<string, unknown> | null, title: string) => void;
|
|
146
|
-
closeModal: () => void;
|
|
147
|
-
pendingConfirm: SchemaCrudConfirm | null;
|
|
148
|
-
requestConfirm: (confirm: SchemaCrudConfirm) => void;
|
|
149
|
-
resolveConfirm: (confirmed: boolean) => Promise<void>;
|
|
150
|
-
feedback: SchemaCrudFeedback | null;
|
|
151
|
-
registerFetcher: (fetcher: typeof fetch) => void;
|
|
152
|
-
/** The currently registered transport (globalThis.fetch until injected). */
|
|
153
|
-
fetcher: typeof fetch;
|
|
154
|
-
/** Runs a request action end-to-end (gate → construct → fetch → feedback/reload). */
|
|
155
|
-
runRowAction: (actionRef: string, opts: RunRequestOptions) => Promise<ActionResult>;
|
|
156
|
-
/** Dispatches a toolbar/row action entry: modal open, confirm, or request. */
|
|
157
|
-
invokeAction: (item: Record<string, unknown>, row: Record<string, unknown> | null) => void;
|
|
158
|
-
/** Dispatches a batch toolbar trigger (ADR-0022): gate → confirm → request. */
|
|
159
|
-
invokeBatchAction: (item: Record<string, unknown>, tableId: string) => void;
|
|
160
|
-
/** Upload control transport (ADR-0012): resolves action/actionRef → validates → uploads. */
|
|
161
|
-
uploadFiles: (field: FormControlField, files: UploadableFile[]) => Promise<unknown>;
|
|
162
|
-
/** Per-table selection state (keys + count; normalized by the table). */
|
|
163
|
-
selection: (tableId: string) => TableSelection | undefined;
|
|
164
|
-
setSelection: (tableId: string, keys: unknown[]) => void;
|
|
165
|
-
clearSelection: (tableId: string) => void;
|
|
166
|
-
/** Submits a default-mode form against its `submitAction`. */
|
|
167
|
-
submitForm: (form: RenderFormNode, values: Record<string, unknown>) => Promise<ActionResult>;
|
|
168
|
-
/** Binds a search-mode form's fields to its target table query. */
|
|
169
|
-
searchFormSubmit: (form: RenderFormNode, values: Record<string, unknown>) => void;
|
|
170
|
-
effectivePermission: (targetId: string) => boolean;
|
|
171
|
-
/**
|
|
172
|
-
* Current route snapshot (from the render context; App injects
|
|
173
|
-
* route: {params, query}). Used for ADR-0039 dataSource bindings and
|
|
174
|
-
* create-modal readOnly seeding instead of reading window.location.
|
|
175
|
-
*/
|
|
176
|
-
route: {
|
|
177
|
-
query: Record<string, string>;
|
|
178
|
-
params: Record<string, string>;
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
export interface RunRequestOptions {
|
|
182
|
-
row?: Record<string, unknown> | null;
|
|
183
|
-
formValues?: Record<string, unknown>;
|
|
184
|
-
requestMapping?: Record<string, unknown>;
|
|
185
|
-
gateTargetId?: string;
|
|
186
|
-
confirmed?: boolean;
|
|
187
|
-
}
|
|
188
|
-
/** Page CRUD context consumed by custom components (rendered nodes). */
|
|
189
|
-
export declare const SchemaCrudContext: import("react").Context<SchemaCrudValue | null>;
|
|
190
|
-
/** Reads the page-level Schema CRUD provider (null when rendered bare). */
|
|
191
|
-
export declare function useSchemaCrud(): SchemaCrudValue | null;
|
|
192
|
-
export declare function RenderPage({ document, context, tableRenderer, dataFetcher, onAction, onNavigate, formComponent, }: RendererComponentProps & {
|
|
193
|
-
dataFetcher?: typeof fetch;
|
|
194
|
-
}): import("react").JSX.Element;
|
|
@@ -1,289 +0,0 @@
|
|
|
1
|
-
import { type FormControlField, type FormControlGateError } from "@schema-ui/renderer/renderer/form-controls.types";
|
|
2
|
-
import { type FormControlStateMap, type ReactionError } from "@schema-ui/renderer/renderer/reactions";
|
|
3
|
-
/**
|
|
4
|
-
* D-COMP page renderer (frozen §5 whitelist + I-PROTO-FULL-001 full registry
|
|
5
|
-
* surface; resolve R4 F-002).
|
|
6
|
-
*
|
|
7
|
-
* The renderer walks a page document's node tree and dispatches whitelisted
|
|
8
|
-
* node types to the components in this directory. It is deliberately minimal:
|
|
9
|
-
* only the node types surfaced by the example pages are handled, and any
|
|
10
|
-
* other type fails closed instead of rendering a silent fallback.
|
|
11
|
-
*
|
|
12
|
-
* A page document looks like the example pages' `PAGE_DOCUMENT`:
|
|
13
|
-
* { meta: { protocolVersion, requiredCapabilities }, body: Node }
|
|
14
|
-
*
|
|
15
|
-
* Node types supported (registry surface):
|
|
16
|
-
* - layout: grid / section / tabs
|
|
17
|
-
* - data/action: text / table / recordView / actionButton / statCard / chart
|
|
18
|
-
* - form: form → FormControls (with reactions applied to field state)
|
|
19
|
-
* The form control whitelist itself is enforced by D-FORM
|
|
20
|
-
* (isWhitelistedFormControl / checkFormCapabilities).
|
|
21
|
-
*/
|
|
22
|
-
export type RenderNodeType = "form" | "section" | "table" | "grid" | "tabs" | "text" | "recordView" | "actionButton" | "statCard" | "chart" | "custom";
|
|
23
|
-
export interface RenderMeta {
|
|
24
|
-
protocolVersion: string;
|
|
25
|
-
requiredCapabilities: string[];
|
|
26
|
-
}
|
|
27
|
-
export interface ReactionState {
|
|
28
|
-
/** fieldId → control state after reactions. */
|
|
29
|
-
state: FormControlStateMap;
|
|
30
|
-
errors: ReactionError[];
|
|
31
|
-
}
|
|
32
|
-
export interface RenderFormNode {
|
|
33
|
-
type: "form";
|
|
34
|
-
id?: string;
|
|
35
|
-
props: {
|
|
36
|
-
fields: Array<Record<string, unknown>>;
|
|
37
|
-
reactions?: unknown;
|
|
38
|
-
submitLabel?: string;
|
|
39
|
-
/** S2 (VP-007): i18n key resolved before `submitLabel` (local doc convention). */
|
|
40
|
-
submitLabelKey?: string;
|
|
41
|
-
/** Default-mode submit: the top-level action id to run on submit (S4). */
|
|
42
|
-
submitAction?: string;
|
|
43
|
-
/** Search-mode form: binds its fields to the target table's query (S4). */
|
|
44
|
-
mode?: "default" | "search";
|
|
45
|
-
targetTable?: string;
|
|
46
|
-
/** Section heading rendered above the fields (registry form `title`/`titleKey`). */
|
|
47
|
-
title?: string;
|
|
48
|
-
/** i18n key resolved before `title`. */
|
|
49
|
-
titleKey?: string;
|
|
50
|
-
/**
|
|
51
|
-
* ADR-0021 edit-form record GET prefill (registry since 2.1): loads current
|
|
52
|
-
* values from a detail GET and initializes the fields via `responseMapping`
|
|
53
|
-
* (field id → dot-path in the response). Requires capability
|
|
54
|
-
* `form.record.load`; search-mode forms forbid it.
|
|
55
|
-
*/
|
|
56
|
-
recordSource?: Record<string, unknown>;
|
|
57
|
-
/** GOAL-014 D-002 §4: responsive form column count (>1 enables the grid). */
|
|
58
|
-
columns?: number;
|
|
59
|
-
};
|
|
60
|
-
children?: RenderNode[];
|
|
61
|
-
}
|
|
62
|
-
export interface RenderSectionNode {
|
|
63
|
-
type: "section";
|
|
64
|
-
id?: string;
|
|
65
|
-
props?: Record<string, unknown>;
|
|
66
|
-
children: RenderNode[];
|
|
67
|
-
}
|
|
68
|
-
export interface RenderGridNode {
|
|
69
|
-
type: "grid";
|
|
70
|
-
id?: string;
|
|
71
|
-
props?: Record<string, unknown>;
|
|
72
|
-
children?: RenderNode[];
|
|
73
|
-
}
|
|
74
|
-
export interface RenderTabsNode {
|
|
75
|
-
type: "tabs";
|
|
76
|
-
id?: string;
|
|
77
|
-
props?: Record<string, unknown>;
|
|
78
|
-
children?: RenderNode[];
|
|
79
|
-
}
|
|
80
|
-
export interface RenderTextNode {
|
|
81
|
-
type: "text";
|
|
82
|
-
id?: string;
|
|
83
|
-
props?: {
|
|
84
|
-
text?: string;
|
|
85
|
-
/** i18n key resolved before `text` (F-01 · GOAL-003 A-003 F-001). */
|
|
86
|
-
textKey?: string;
|
|
87
|
-
};
|
|
88
|
-
children?: RenderNode[];
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* v2.9 DataRef subset consumed by data nodes (ADR-0039): source:api url +
|
|
92
|
-
* params (literal scalars or whole $context.route.query.* / params.* bindings).
|
|
93
|
-
*/
|
|
94
|
-
export interface RenderDataRef {
|
|
95
|
-
url: string;
|
|
96
|
-
params?: Record<string, unknown>;
|
|
97
|
-
}
|
|
98
|
-
export interface RenderTableNode {
|
|
99
|
-
type: "table";
|
|
100
|
-
id?: string;
|
|
101
|
-
/** v2.9 node-level DataRef (source:api). Preferred over props.dataSource. */
|
|
102
|
-
data?: RenderDataRef;
|
|
103
|
-
props: {
|
|
104
|
-
columns?: Array<Record<string, unknown>>;
|
|
105
|
-
actions?: Array<Record<string, unknown>>;
|
|
106
|
-
toolbar?: Array<Record<string, unknown>>;
|
|
107
|
-
dataSource?: string;
|
|
108
|
-
/** Table heading (literal fallback for titleKey). */
|
|
109
|
-
title?: string;
|
|
110
|
-
/** i18n key resolved before title. */
|
|
111
|
-
titleKey?: string;
|
|
112
|
-
/** Direct field name of each row's unique key (F-002 · I-010-001 v0.2.0 §3; default "id"). */
|
|
113
|
-
rowKey?: string;
|
|
114
|
-
/** ADR-0022 multi-select model (registry; mode: multiple only). */
|
|
115
|
-
selection?: {
|
|
116
|
-
mode?: string;
|
|
117
|
-
};
|
|
118
|
-
/** Schema-driven filters (select-only; see schemaTableFilters). */
|
|
119
|
-
filters?: Array<Record<string, unknown>>;
|
|
120
|
-
};
|
|
121
|
-
children?: RenderNode[];
|
|
122
|
-
}
|
|
123
|
-
/** Read-only field row on a recordView (registry `fields[]` since 2.4). */
|
|
124
|
-
export interface RenderRecordViewField {
|
|
125
|
-
key: string;
|
|
126
|
-
label?: string;
|
|
127
|
-
labelKey?: string;
|
|
128
|
-
}
|
|
129
|
-
export interface RenderRecordViewNode {
|
|
130
|
-
type: "recordView";
|
|
131
|
-
id?: string;
|
|
132
|
-
props?: {
|
|
133
|
-
record?: Record<string, unknown>;
|
|
134
|
-
/** Detail panel heading (registry `title` since 2.4). */
|
|
135
|
-
title?: string;
|
|
136
|
-
/** i18n key resolved before `title`. */
|
|
137
|
-
titleKey?: string;
|
|
138
|
-
/** Declared display fields; when set, only these rows render. */
|
|
139
|
-
fields?: RenderRecordViewField[];
|
|
140
|
-
};
|
|
141
|
-
children?: RenderNode[];
|
|
142
|
-
}
|
|
143
|
-
export interface RenderActionButtonNode {
|
|
144
|
-
type: "actionButton";
|
|
145
|
-
id?: string;
|
|
146
|
-
props?: {
|
|
147
|
-
label?: string;
|
|
148
|
-
/** i18n key resolved before `label` (S3). */
|
|
149
|
-
labelKey?: string;
|
|
150
|
-
actionId?: string;
|
|
151
|
-
visibleWhen?: unknown;
|
|
152
|
-
disabledWhen?: unknown;
|
|
153
|
-
/** Permission-intent key (ADR-0023 D4b mount); gates the button target. */
|
|
154
|
-
permissionIntent?: string;
|
|
155
|
-
/** Target id for the permission target / action gate (falls back to node id). */
|
|
156
|
-
key?: string;
|
|
157
|
-
/** Confirm message (shown before executing the referenced action). */
|
|
158
|
-
confirm?: string;
|
|
159
|
-
/** i18n key resolved before `confirm`. */
|
|
160
|
-
confirmKey?: string;
|
|
161
|
-
};
|
|
162
|
-
children?: RenderNode[];
|
|
163
|
-
}
|
|
164
|
-
export interface RenderStatCardNode {
|
|
165
|
-
type: "statCard";
|
|
166
|
-
id?: string;
|
|
167
|
-
/** v2.9 node-level DataRef (source:api). Preferred over props.dataSource. */
|
|
168
|
-
data?: RenderDataRef;
|
|
169
|
-
props?: {
|
|
170
|
-
label?: string;
|
|
171
|
-
/** i18n key resolved before `label` (F-01 · GOAL-003 A-003 F-001). */
|
|
172
|
-
labelKey?: string;
|
|
173
|
-
unit?: string;
|
|
174
|
-
/** plain | currency | percent (registry enum). */
|
|
175
|
-
format?: string;
|
|
176
|
-
/** Field of the dataSource rows to display (registry, required since 0.2). */
|
|
177
|
-
valueField?: string;
|
|
178
|
-
/** Single-slash same-origin data path (same invariant as table.dataSource). */
|
|
179
|
-
dataSource?: string;
|
|
180
|
-
};
|
|
181
|
-
children?: RenderNode[];
|
|
182
|
-
}
|
|
183
|
-
export interface RenderChartNode {
|
|
184
|
-
type: "chart";
|
|
185
|
-
id?: string;
|
|
186
|
-
/** v2.9 node-level DataRef (source:api). Preferred over props.dataSource. */
|
|
187
|
-
data?: RenderDataRef;
|
|
188
|
-
props?: {
|
|
189
|
-
/** line | bar | pie (registry enum, required). */
|
|
190
|
-
chartType?: string;
|
|
191
|
-
xField?: string;
|
|
192
|
-
yField?: string;
|
|
193
|
-
/** Single-slash same-origin data path (same invariant as table.dataSource). */
|
|
194
|
-
dataSource?: string;
|
|
195
|
-
};
|
|
196
|
-
children?: RenderNode[];
|
|
197
|
-
}
|
|
198
|
-
export interface RenderCustomNode {
|
|
199
|
-
type: "custom";
|
|
200
|
-
id?: string;
|
|
201
|
-
/** Registered component key (GOAL-018: renderer custom-component registry). */
|
|
202
|
-
component: string;
|
|
203
|
-
props?: Record<string, unknown>;
|
|
204
|
-
children?: RenderNode[];
|
|
205
|
-
}
|
|
206
|
-
export type RenderNode = RenderFormNode | RenderSectionNode | RenderGridNode | RenderTabsNode | RenderTextNode | RenderTableNode | RenderRecordViewNode | RenderActionButtonNode | RenderStatCardNode | RenderChartNode | RenderCustomNode;
|
|
207
|
-
/** Page-level action table entry (registry: modal | request | navigate). */
|
|
208
|
-
export interface RenderPageAction {
|
|
209
|
-
type: string;
|
|
210
|
-
/** Modal content; required when type=modal. */
|
|
211
|
-
content?: RenderNode;
|
|
212
|
-
/** Request/navigate target URL. */
|
|
213
|
-
url?: string;
|
|
214
|
-
/** HTTP method for request-shaped actions. */
|
|
215
|
-
method?: string;
|
|
216
|
-
/** Permission intent name, gated against page-level permissionCascade. */
|
|
217
|
-
permissionIntent?: string;
|
|
218
|
-
}
|
|
219
|
-
export interface RenderPageDocument {
|
|
220
|
-
meta: RenderMeta;
|
|
221
|
-
body: RenderNode;
|
|
222
|
-
/** Page-level action table referenced by actionRef / actionId. */
|
|
223
|
-
actions?: Record<string, RenderPageAction>;
|
|
224
|
-
}
|
|
225
|
-
export type RenderErrorCode = "RENDER_UNKNOWN_NODE_TYPE" | "RENDER_INVALID_BODY" | "RENDER_META_INVALID" | "RENDER_FORM_FIELD_INVALID";
|
|
226
|
-
export interface RenderError {
|
|
227
|
-
code: RenderErrorCode;
|
|
228
|
-
path: string;
|
|
229
|
-
message: string;
|
|
230
|
-
}
|
|
231
|
-
export type ActionGateErrorCode = "ACTION_GATE_EXPRESSION_INVALID";
|
|
232
|
-
export interface ActionGateError {
|
|
233
|
-
code: ActionGateErrorCode;
|
|
234
|
-
path: string;
|
|
235
|
-
message: string;
|
|
236
|
-
}
|
|
237
|
-
export type ActionGateResult = {
|
|
238
|
-
kind: "ok";
|
|
239
|
-
value: boolean;
|
|
240
|
-
} | {
|
|
241
|
-
kind: "error";
|
|
242
|
-
error: ActionGateError;
|
|
243
|
-
};
|
|
244
|
-
export interface RenderFormFieldGate {
|
|
245
|
-
/** Fields that passed the type whitelist and the version/capability gate. */
|
|
246
|
-
fields: FormControlField[];
|
|
247
|
-
/** Deterministic errors for rejected fields and gate failures. */
|
|
248
|
-
errors: FormControlGateError[];
|
|
249
|
-
}
|
|
250
|
-
/** Keeps only well-formed recordView field rows (key required). */
|
|
251
|
-
export declare function parseRecordViewFields(raw: unknown): RenderRecordViewField[];
|
|
252
|
-
export declare function isWhitelistedNodeType(type: string): type is RenderNodeType;
|
|
253
|
-
/**
|
|
254
|
-
* Resolves a dot-path on a record for `form.recordSource.responseMapping`
|
|
255
|
-
* (e.g. `"customer.name"` → record.customer.name). Missing segments or a
|
|
256
|
-
* non-object intermediate return `undefined` (field keeps its default/empty).
|
|
257
|
-
*/
|
|
258
|
-
export declare function resolveResponsePath(record: unknown, path: string): unknown;
|
|
259
|
-
/** Normalizes an unknown body value into a typed RenderNode, fail-closed. */
|
|
260
|
-
export declare function parseRenderNode(value: unknown, path: string): RenderNode | RenderError;
|
|
261
|
-
/** Collects all form fieldIds from a page document (for reaction resolution). */
|
|
262
|
-
export declare function collectFieldIds(node: RenderNode, into?: string[]): string[];
|
|
263
|
-
/** Resolves the reaction state for a form node's fields. */
|
|
264
|
-
export declare function resolveFormReactions(form: RenderFormNode, context: Record<string, unknown>): ReactionState;
|
|
265
|
-
/**
|
|
266
|
-
* Resolves a table action gate expression.
|
|
267
|
-
*
|
|
268
|
-
* Distinguishes an absent property (→ `absentDefault`) from an explicit but
|
|
269
|
-
* invalid expression (→ fail-closed `error`, no silent default). Valid $context
|
|
270
|
-
* expressions are evaluated against the frozen engine; booleans pass through.
|
|
271
|
-
*/
|
|
272
|
-
export declare function resolveActionGate(expression: unknown, context: Record<string, unknown>, absentDefault: boolean, path: string): ActionGateResult;
|
|
273
|
-
/**
|
|
274
|
-
* Evaluates a whitelisted table action's visibility/disabled gate.
|
|
275
|
-
* Explicit invalid expressions fail closed (hidden / disabled) and are reported.
|
|
276
|
-
*/
|
|
277
|
-
export declare function tableActionGate(action: Record<string, unknown>, context: Record<string, unknown>): {
|
|
278
|
-
visible: boolean;
|
|
279
|
-
disabled: boolean;
|
|
280
|
-
errors: ActionGateError[];
|
|
281
|
-
};
|
|
282
|
-
/**
|
|
283
|
-
* Parses and gates a form node's raw fields against the D-FORM §5 whitelist
|
|
284
|
-
* and the page meta version/capability rules (F-002 / F-003).
|
|
285
|
-
*
|
|
286
|
-
* Returns only the fields that pass every gate; rejected fields produce
|
|
287
|
-
* deterministic errors instead of being silently rendered (or silently dropped).
|
|
288
|
-
*/
|
|
289
|
-
export declare function gateRenderFormFields(metaValue: unknown, rawFields: unknown, path: string): RenderFormFieldGate;
|