@arkcit/engine-react 0.3.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/README.md ADDED
@@ -0,0 +1,51 @@
1
+ # @arkcit/engine-react
2
+
3
+ Concrete React renderer package for the Arkcit platform.
4
+
5
+ ## Position In The Flow
6
+
7
+ ```text
8
+ @arkcit/engine-schema
9
+ @arkcit/engine-runtime
10
+ @arkcit/engine-core
11
+ @arkcit/engine-render-layer
12
+
13
+ @arkcit/engine-react
14
+
15
+ @arkcit/engine
16
+
17
+ @arkcit/react-ui
18
+ @arkcit/studio preview adapters
19
+ @arkcit/docs-shell
20
+ ```
21
+
22
+ ## What Goes In
23
+
24
+ - neutral resolved-node contracts
25
+ - shared engine primitives
26
+ - React-specific rendering needs
27
+
28
+ ## What Comes Out
29
+
30
+ - React rendering helpers
31
+ - React engine root pieces
32
+ - React-specific composition/materialization utilities
33
+
34
+ ## Responsibilities
35
+
36
+ - own React-only rendering behavior
37
+ - keep React-specific utilities out of neutral engine layers
38
+ - expose reusable React renderer seams to `@arkcit/engine`
39
+
40
+ ## Do Not Put Here
41
+
42
+ - canonical schema rules
43
+ - runtime contract ownership
44
+ - Angular or React Native behavior
45
+
46
+ ## Main Consumers
47
+
48
+ - `@arkcit/engine`
49
+ - `@arkcit/react-ui`
50
+ - `@arkcit/studio`
51
+ - `@arkcit/docs-shell`
@@ -0,0 +1,116 @@
1
+ import React__default from 'react';
2
+ import { ContentCompositionPlan, NavigationCompositionPlan } from '@arkcit/engine-render-layer';
3
+ import { UINode } from '@arkcit/engine-schema';
4
+ import { UIRuntimeAdapter } from '@arkcit/engine-runtime';
5
+
6
+ type ApplyContentCompositionParams = {
7
+ node: UINode;
8
+ componentProps: Record<string, unknown>;
9
+ isStudioRendererContext: boolean;
10
+ internalStudioNodeTypes: Set<string>;
11
+ schemaNodes: UINode[];
12
+ onInlineTextEdit?: (nodeId: string, propName: string, value: unknown) => void;
13
+ captureFieldFocus: (target: EventTarget | null) => void;
14
+ renderSafeNode: (node: UINode) => React__default.ReactNode;
15
+ normalizeRenderableChild: (value: unknown) => React__default.ReactNode;
16
+ findNodeById: (nodeId: string, nodes: UINode[]) => UINode | null;
17
+ runtime: UIRuntimeAdapter;
18
+ plans?: ContentCompositionPlan[];
19
+ dependencies: {
20
+ resolveContentCompositionPlan: (args: {
21
+ node: UINode;
22
+ isStudioRendererContext: boolean;
23
+ internalStudioNodeTypes: Set<string>;
24
+ }) => ContentCompositionPlan[];
25
+ renderStudioForm: (args: {
26
+ node: UINode;
27
+ componentProps: Record<string, unknown>;
28
+ visibleChildren: UINode[];
29
+ runtime: UIRuntimeAdapter;
30
+ onInlineTextEdit?: (nodeId: string, propName: string, value: unknown) => void;
31
+ captureFieldFocus: (target: EventTarget | null) => void;
32
+ renderSafeNode: (node: UINode) => React__default.ReactNode;
33
+ }) => React__default.ReactNode | null;
34
+ buildScrollRevealChildren: (args: {
35
+ rawChildren: unknown;
36
+ renderSafeNode: (node: UINode) => React__default.ReactNode;
37
+ normalizeRenderableChild: (value: unknown) => React__default.ReactNode;
38
+ fallbackChildren: unknown;
39
+ }) => React__default.ReactNode;
40
+ };
41
+ };
42
+ declare const applyContentComposition: ({ node, componentProps, isStudioRendererContext, internalStudioNodeTypes, schemaNodes, onInlineTextEdit, captureFieldFocus, renderSafeNode, normalizeRenderableChild, findNodeById, runtime, plans: providedPlans, dependencies, }: ApplyContentCompositionParams) => React__default.ReactNode | null;
43
+
44
+ type ApplyNavigationCompositionParams<TInlineEditing = unknown> = {
45
+ node: UINode;
46
+ componentProps: Record<string, unknown>;
47
+ isStudioRendererContext: boolean;
48
+ selectedNodeId: string | null;
49
+ wizardActiveStepByNodeId: Record<string, string>;
50
+ accordionOpenIdsByNodeId: Record<string, string[]>;
51
+ expandablePanelOpenByNodeId: Record<string, boolean>;
52
+ runtime: UIRuntimeAdapter;
53
+ setWizardActiveStepByNodeId: React__default.Dispatch<React__default.SetStateAction<Record<string, string>>>;
54
+ setAccordionOpenIdsByNodeId: React__default.Dispatch<React__default.SetStateAction<Record<string, string[]>>>;
55
+ setExpandablePanelOpenByNodeId: React__default.Dispatch<React__default.SetStateAction<Record<string, boolean>>>;
56
+ onNodeClick?: (nodeId: string) => void;
57
+ onInlineTextEdit?: (nodeId: string, propName: string, value: unknown) => void;
58
+ renderSafeNode: (node: UINode) => React__default.ReactNode;
59
+ normalizeRenderableChild: (value: unknown) => React__default.ReactNode;
60
+ captureFieldFocus: (target: EventTarget | null) => void;
61
+ setInlineEditing: React__default.Dispatch<React__default.SetStateAction<TInlineEditing | null>>;
62
+ internalStudioNodeTypes: Set<string>;
63
+ plans?: NavigationCompositionPlan[];
64
+ dependencies: {
65
+ resolveNavigationCompositionPlan: (args: {
66
+ node: UINode;
67
+ componentProps: Record<string, unknown>;
68
+ internalStudioNodeTypes: Set<string>;
69
+ runtime: UIRuntimeAdapter;
70
+ }) => NavigationCompositionPlan[];
71
+ createInlineEditingState: (targetNodeId: string, propName: string, rawValue: unknown) => TInlineEditing;
72
+ configureStudioFormWizard: (args: {
73
+ node: UINode;
74
+ componentProps: Record<string, unknown>;
75
+ isStudioRendererContext: boolean;
76
+ selectedNodeId: string | null;
77
+ wizardActiveStepByNodeId: Record<string, string>;
78
+ runtime: UIRuntimeAdapter;
79
+ setWizardActiveStepByNodeId: React__default.Dispatch<React__default.SetStateAction<Record<string, string>>>;
80
+ onNodeClick?: (nodeId: string) => void;
81
+ onInlineTextEdit?: (nodeId: string, propName: string, value: unknown) => void;
82
+ renderSafeNode: (node: UINode) => React__default.ReactNode;
83
+ captureFieldFocus: (target: EventTarget | null) => void;
84
+ openInlineEditorForNodeProp: (targetNodeId: string, propName: string, rawValue: unknown) => void;
85
+ internalStudioNodeTypes: Set<string>;
86
+ }) => void;
87
+ configureStudioAccordion: (args: {
88
+ node: UINode;
89
+ componentProps: Record<string, unknown>;
90
+ accordionChildren: UINode[];
91
+ selectedNodeId: string | null;
92
+ accordionOpenIdsByNodeId: Record<string, string[]>;
93
+ setAccordionOpenIdsByNodeId: React__default.Dispatch<React__default.SetStateAction<Record<string, string[]>>>;
94
+ renderSafeNode: (node: UINode) => React__default.ReactNode;
95
+ }) => void;
96
+ configureStudioExpandablePanel: (args: {
97
+ node: UINode;
98
+ componentProps: Record<string, unknown>;
99
+ panelChildren: UINode[];
100
+ expandablePanelOpenByNodeId: Record<string, boolean>;
101
+ setExpandablePanelOpenByNodeId: React__default.Dispatch<React__default.SetStateAction<Record<string, boolean>>>;
102
+ renderSafeNode: (node: UINode) => React__default.ReactNode;
103
+ }) => void;
104
+ configureStudioTabs: (args: {
105
+ componentProps: Record<string, unknown>;
106
+ tabItems: Array<Record<string, unknown>>;
107
+ rawChildren: unknown;
108
+ runtime: UIRuntimeAdapter;
109
+ renderSafeNode: (node: UINode) => React__default.ReactNode;
110
+ normalizeRenderableChild: (value: unknown) => React__default.ReactNode;
111
+ }) => void;
112
+ };
113
+ };
114
+ declare const applyNavigationComposition: <TInlineEditing = unknown>({ node, componentProps, isStudioRendererContext, selectedNodeId, wizardActiveStepByNodeId, accordionOpenIdsByNodeId, expandablePanelOpenByNodeId, runtime, setWizardActiveStepByNodeId, setAccordionOpenIdsByNodeId, setExpandablePanelOpenByNodeId, onNodeClick, onInlineTextEdit, renderSafeNode, normalizeRenderableChild, captureFieldFocus, setInlineEditing, internalStudioNodeTypes, plans: providedPlans, dependencies, }: ApplyNavigationCompositionParams<TInlineEditing>) => void;
115
+
116
+ export { applyContentComposition, applyNavigationComposition };
@@ -0,0 +1,344 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __spreadValues = (a, b) => {
9
+ for (var prop in b || (b = {}))
10
+ if (__hasOwnProp.call(b, prop))
11
+ __defNormalProp(a, prop, b[prop]);
12
+ if (__getOwnPropSymbols)
13
+ for (var prop of __getOwnPropSymbols(b)) {
14
+ if (__propIsEnum.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ }
17
+ return a;
18
+ };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+
21
+ // src/materialization/materializeCoverContent.tsx
22
+ import React from "react";
23
+ import { Fragment, jsx } from "react/jsx-runtime";
24
+ var materializeCoverContent = ({
25
+ descriptor,
26
+ renderSafeNode
27
+ }) => {
28
+ const resolvedActionChildren = descriptor.actionNodes.map((child) => /* @__PURE__ */ jsx("span", { className: "inline-flex align-middle", children: renderSafeNode(child) }, child.id));
29
+ const resolvedContentChildren = descriptor.contentNodes.map((child) => /* @__PURE__ */ jsx(React.Fragment, { children: renderSafeNode(child) }, child.id));
30
+ return {
31
+ actions: resolvedActionChildren.length > 0 ? resolvedActionChildren.length === 1 ? resolvedActionChildren[0] : /* @__PURE__ */ jsx(Fragment, { children: resolvedActionChildren }) : void 0,
32
+ children: resolvedContentChildren.length > 0 ? resolvedContentChildren.length === 1 ? resolvedContentChildren[0] : /* @__PURE__ */ jsx(Fragment, { children: resolvedContentChildren }) : null
33
+ };
34
+ };
35
+
36
+ // src/composition/applyContentComposition.tsx
37
+ var applyContentComposition = ({
38
+ node,
39
+ componentProps,
40
+ isStudioRendererContext,
41
+ internalStudioNodeTypes,
42
+ schemaNodes,
43
+ onInlineTextEdit,
44
+ captureFieldFocus,
45
+ renderSafeNode,
46
+ normalizeRenderableChild,
47
+ findNodeById,
48
+ runtime,
49
+ plans: providedPlans,
50
+ dependencies
51
+ }) => {
52
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
53
+ const plans = providedPlans != null ? providedPlans : dependencies.resolveContentCompositionPlan({
54
+ node,
55
+ isStudioRendererContext,
56
+ internalStudioNodeTypes
57
+ });
58
+ if (plans.some((plan) => plan.kind === "button-toggle" && plan.disableOnClick)) {
59
+ delete componentProps.onClick;
60
+ }
61
+ if (plans.some((plan) => plan.kind === "form-field")) {
62
+ const rawProps = (_a = node.props) != null ? _a : {};
63
+ const existingField = componentProps.field && typeof componentProps.field === "object" && !Array.isArray(componentProps.field) ? componentProps.field : {};
64
+ const fieldName = String((_c = (_b = existingField.name) != null ? _b : rawProps.name) != null ? _c : "").trim();
65
+ const fieldType = String((_e = (_d = existingField.type) != null ? _d : rawProps.type) != null ? _e : "text");
66
+ const fallbackLabel = fieldName || "Field";
67
+ const fieldLabel = String((_g = (_f = existingField.label) != null ? _f : rawProps.label) != null ? _g : fallbackLabel);
68
+ componentProps.field = __spreadProps(__spreadValues(__spreadValues({}, rawProps), existingField), {
69
+ name: fieldName || "field",
70
+ type: fieldType,
71
+ label: fieldLabel
72
+ });
73
+ if (componentProps.value === void 0) {
74
+ componentProps.value = (_i = (_h = rawProps.value) != null ? _h : rawProps.defaultValue) != null ? _i : "";
75
+ }
76
+ if (!componentProps.dict || typeof componentProps.dict !== "object" || Array.isArray(componentProps.dict)) {
77
+ componentProps.dict = {
78
+ submit: "Submit",
79
+ reset: "Reset",
80
+ loading: "Loading...",
81
+ success: "Saved",
82
+ search: "Search...",
83
+ noResultToShow: "No result"
84
+ };
85
+ }
86
+ if (!componentProps.onChange) {
87
+ componentProps.onChange = (event) => {
88
+ var _a2;
89
+ captureFieldFocus(event.target);
90
+ const target = event.target;
91
+ const nextValue = target.type === "checkbox" ? Boolean(target.checked) : target.value;
92
+ const findParentFormId = (nodes, targetId, lineage = []) => {
93
+ var _a3, _b2;
94
+ for (const candidate of nodes) {
95
+ const nextLineage = [...lineage, candidate];
96
+ if (candidate.id === targetId) {
97
+ for (let index = nextLineage.length - 2; index >= 0; index -= 1) {
98
+ if (((_a3 = nextLineage[index]) == null ? void 0 : _a3.type) === "Form") {
99
+ return nextLineage[index].id;
100
+ }
101
+ }
102
+ return null;
103
+ }
104
+ if ((_b2 = candidate.children) == null ? void 0 : _b2.length) {
105
+ const found = findParentFormId(candidate.children, targetId, nextLineage);
106
+ if (found) return found;
107
+ }
108
+ }
109
+ return null;
110
+ };
111
+ const parentFormId = findParentFormId(schemaNodes, node.id);
112
+ if (parentFormId && onInlineTextEdit && fieldName) {
113
+ const parentForm = findNodeById(parentFormId, schemaNodes);
114
+ const parentProps = (_a2 = parentForm == null ? void 0 : parentForm.props) != null ? _a2 : {};
115
+ const currentValues = parentProps.values && typeof parentProps.values === "object" && !Array.isArray(parentProps.values) ? parentProps.values : {};
116
+ onInlineTextEdit(parentFormId, "values", __spreadProps(__spreadValues({}, currentValues), {
117
+ [fieldName]: nextValue
118
+ }));
119
+ return;
120
+ }
121
+ onInlineTextEdit == null ? void 0 : onInlineTextEdit(node.id, "value", nextValue);
122
+ };
123
+ }
124
+ }
125
+ const studioFormPlan = plans.find((plan) => plan.kind === "studio-form");
126
+ if ((studioFormPlan == null ? void 0 : studioFormPlan.kind) === "studio-form") {
127
+ return dependencies.renderStudioForm({
128
+ node,
129
+ componentProps,
130
+ visibleChildren: studioFormPlan.visibleChildren,
131
+ runtime,
132
+ onInlineTextEdit,
133
+ captureFieldFocus,
134
+ renderSafeNode
135
+ });
136
+ }
137
+ if (isStudioRendererContext && node.type === "Form" && onInlineTextEdit) {
138
+ const existingStudioConfig = componentProps.studio && typeof componentProps.studio === "object" && !Array.isArray(componentProps.studio) ? componentProps.studio : {};
139
+ componentProps.studio = __spreadProps(__spreadValues({}, existingStudioConfig), {
140
+ onSubmitLabelDoubleClick: () => {
141
+ var _a2, _b2;
142
+ return onInlineTextEdit(
143
+ node.id,
144
+ "dict.submit",
145
+ String(
146
+ (_b2 = (_a2 = componentProps.dict) == null ? void 0 : _a2.submit) != null ? _b2 : "Submit"
147
+ )
148
+ );
149
+ },
150
+ onResetLabelDoubleClick: () => {
151
+ var _a2, _b2;
152
+ return onInlineTextEdit(
153
+ node.id,
154
+ "dict.reset",
155
+ String(
156
+ (_b2 = (_a2 = componentProps.dict) == null ? void 0 : _a2.reset) != null ? _b2 : "Reset"
157
+ )
158
+ );
159
+ }
160
+ });
161
+ }
162
+ const coverPlan = plans.find((plan) => plan.kind === "cover-content");
163
+ if ((coverPlan == null ? void 0 : coverPlan.kind) === "cover-content") {
164
+ const content = materializeCoverContent({
165
+ descriptor: coverPlan.descriptor,
166
+ renderSafeNode
167
+ });
168
+ if (content.actions !== void 0) {
169
+ componentProps.actions = content.actions;
170
+ }
171
+ if (content.children !== null) {
172
+ componentProps.children = content.children;
173
+ } else if (componentProps.children === void 0) {
174
+ componentProps.children = null;
175
+ }
176
+ }
177
+ const scrollRevealPlan = plans.find((plan) => plan.kind === "scroll-reveal");
178
+ if ((scrollRevealPlan == null ? void 0 : scrollRevealPlan.kind) === "scroll-reveal") {
179
+ componentProps.children = dependencies.buildScrollRevealChildren({
180
+ rawChildren: scrollRevealPlan.rawChildren,
181
+ renderSafeNode,
182
+ normalizeRenderableChild,
183
+ fallbackChildren: componentProps.children
184
+ });
185
+ }
186
+ return null;
187
+ };
188
+
189
+ // src/materialization/materializeNavigationContent.tsx
190
+ import React2 from "react";
191
+ import { jsx as jsx2 } from "react/jsx-runtime";
192
+ var materializeAccordionItems = ({
193
+ items,
194
+ renderSafeNode
195
+ }) => items.map((item) => {
196
+ var _a;
197
+ return {
198
+ id: item.id,
199
+ title: item.title,
200
+ disabled: item.disabled,
201
+ content: item.contentKind === "nodes" ? /* @__PURE__ */ jsx2("div", { className: "space-y-2", children: item.contentNodes.map((nested) => /* @__PURE__ */ jsx2(React2.Fragment, { children: renderSafeNode(nested) }, nested.id)) }) : (_a = item.contentText) != null ? _a : ""
202
+ };
203
+ });
204
+ var materializeExpandablePanelContent = ({
205
+ descriptor,
206
+ renderSafeNode
207
+ }) => {
208
+ if (descriptor.kind === "empty") {
209
+ return void 0;
210
+ }
211
+ return /* @__PURE__ */ jsx2("div", { className: "space-y-2", children: descriptor.nodes.map((child) => /* @__PURE__ */ jsx2(React2.Fragment, { children: renderSafeNode(child) }, child.id)) });
212
+ };
213
+
214
+ // src/materialization/materializeTabsContent.tsx
215
+ import React3 from "react";
216
+ import { jsx as jsx3 } from "react/jsx-runtime";
217
+ var materializeTabsContent = ({
218
+ tabs,
219
+ renderSafeNode,
220
+ normalizeRenderableChild
221
+ }) => tabs.map((tab) => ({
222
+ id: tab.id,
223
+ title: tab.title,
224
+ label: tab.label,
225
+ content: tab.contentKind === "nodes" ? tab.contentNodes.length === 1 ? renderSafeNode(tab.contentNodes[0]) : tab.contentNodes.map((child) => /* @__PURE__ */ jsx3(React3.Fragment, { children: renderSafeNode(child) }, child.id)) : normalizeRenderableChild(tab.fallbackContent)
226
+ }));
227
+
228
+ // src/composition/applyNavigationComposition.tsx
229
+ var applyNavigationComposition = ({
230
+ node,
231
+ componentProps,
232
+ isStudioRendererContext,
233
+ selectedNodeId,
234
+ wizardActiveStepByNodeId,
235
+ accordionOpenIdsByNodeId,
236
+ expandablePanelOpenByNodeId,
237
+ runtime,
238
+ setWizardActiveStepByNodeId,
239
+ setAccordionOpenIdsByNodeId,
240
+ setExpandablePanelOpenByNodeId,
241
+ onNodeClick,
242
+ onInlineTextEdit,
243
+ renderSafeNode,
244
+ normalizeRenderableChild,
245
+ captureFieldFocus,
246
+ setInlineEditing,
247
+ internalStudioNodeTypes,
248
+ plans: providedPlans,
249
+ dependencies
250
+ }) => {
251
+ const plans = providedPlans != null ? providedPlans : dependencies.resolveNavigationCompositionPlan({
252
+ node,
253
+ componentProps,
254
+ internalStudioNodeTypes,
255
+ runtime
256
+ });
257
+ if (plans.some((plan) => plan.kind === "form-wizard")) {
258
+ const openInlineEditorForNodeProp = (targetNodeId, propName, rawValue) => {
259
+ setInlineEditing(dependencies.createInlineEditingState(targetNodeId, propName, rawValue));
260
+ };
261
+ dependencies.configureStudioFormWizard({
262
+ node,
263
+ componentProps,
264
+ isStudioRendererContext,
265
+ selectedNodeId,
266
+ wizardActiveStepByNodeId,
267
+ runtime,
268
+ setWizardActiveStepByNodeId,
269
+ onNodeClick,
270
+ onInlineTextEdit,
271
+ renderSafeNode,
272
+ captureFieldFocus,
273
+ openInlineEditorForNodeProp,
274
+ internalStudioNodeTypes
275
+ });
276
+ }
277
+ const accordionPlan = plans.find((plan) => plan.kind === "accordion");
278
+ if ((accordionPlan == null ? void 0 : accordionPlan.kind) === "accordion") {
279
+ const accordionChildren = accordionPlan.accordionChildren;
280
+ if (accordionChildren.length > 0) {
281
+ if (isStudioRendererContext) {
282
+ dependencies.configureStudioAccordion({
283
+ node,
284
+ componentProps,
285
+ accordionChildren,
286
+ selectedNodeId,
287
+ accordionOpenIdsByNodeId,
288
+ setAccordionOpenIdsByNodeId,
289
+ renderSafeNode
290
+ });
291
+ } else {
292
+ componentProps.items = materializeAccordionItems({
293
+ items: accordionPlan.itemDescriptors,
294
+ renderSafeNode
295
+ });
296
+ }
297
+ }
298
+ }
299
+ const expandablePanelPlan = plans.find((plan) => plan.kind === "expandable-panel");
300
+ if ((expandablePanelPlan == null ? void 0 : expandablePanelPlan.kind) === "expandable-panel") {
301
+ const panelChildren = expandablePanelPlan.panelChildren;
302
+ if (isStudioRendererContext) {
303
+ dependencies.configureStudioExpandablePanel({
304
+ node,
305
+ componentProps,
306
+ panelChildren,
307
+ expandablePanelOpenByNodeId,
308
+ setExpandablePanelOpenByNodeId,
309
+ renderSafeNode
310
+ });
311
+ } else if (panelChildren.length > 0) {
312
+ componentProps.children = materializeExpandablePanelContent({
313
+ descriptor: expandablePanelPlan.contentDescriptor,
314
+ renderSafeNode
315
+ });
316
+ }
317
+ }
318
+ const tabsPlan = plans.find((plan) => plan.kind === "tabs");
319
+ if ((tabsPlan == null ? void 0 : tabsPlan.kind) === "tabs") {
320
+ Object.assign(componentProps, tabsPlan.normalizedComponentProps);
321
+ if (isStudioRendererContext) {
322
+ const tabItems = Array.isArray(componentProps.tabs) ? componentProps.tabs : [];
323
+ dependencies.configureStudioTabs({
324
+ componentProps,
325
+ tabItems,
326
+ rawChildren: tabsPlan.rawChildren,
327
+ runtime,
328
+ renderSafeNode,
329
+ normalizeRenderableChild
330
+ });
331
+ } else {
332
+ componentProps.tabs = materializeTabsContent({
333
+ tabs: tabsPlan.tabDescriptors,
334
+ renderSafeNode,
335
+ normalizeRenderableChild
336
+ });
337
+ delete componentProps.children;
338
+ }
339
+ }
340
+ };
341
+ export {
342
+ applyContentComposition,
343
+ applyNavigationComposition
344
+ };
@@ -0,0 +1,49 @@
1
+ import { RenderDirectivePlan } from '@arkcit/engine-render-layer';
2
+ import { UINode } from '@arkcit/engine-schema';
3
+ import { UIRuntimeAdapter } from '@arkcit/engine-runtime';
4
+
5
+ type ApplyRenderDirectivesParams = {
6
+ node: UINode;
7
+ componentProps: Record<string, unknown>;
8
+ renderBindingProps: Record<string, unknown>;
9
+ runtime: UIRuntimeAdapter;
10
+ plans?: RenderDirectivePlan[];
11
+ dependencies: {
12
+ resolveRenderDirectivePlan: (args: {
13
+ node: UINode;
14
+ renderBindingProps: Record<string, unknown>;
15
+ }) => RenderDirectivePlan[];
16
+ applyRowsAndColumnsBinding: (args: {
17
+ componentProps: Record<string, unknown>;
18
+ runtime: UIRuntimeAdapter;
19
+ rowsBindingKey: string;
20
+ columnsBindingKey: string;
21
+ }) => void;
22
+ filterRowsByRuntimeQuery: (args: {
23
+ nodeId: string;
24
+ componentProps: Record<string, unknown>;
25
+ runtime: UIRuntimeAdapter;
26
+ }) => void;
27
+ buildCoverMedia: (args: {
28
+ mediaSource: unknown;
29
+ mediaSrc: unknown;
30
+ mediaAlt: unknown;
31
+ }) => unknown;
32
+ applyObjectBinding: (args: {
33
+ componentProps: Record<string, unknown>;
34
+ runtime: UIRuntimeAdapter;
35
+ bindingKey: string;
36
+ }) => void;
37
+ applyDecodeTranslationBinding: (args: {
38
+ componentProps: Record<string, unknown>;
39
+ runtime: UIRuntimeAdapter;
40
+ tagContentTranslationKey?: string;
41
+ tagContentTranslationValue?: unknown;
42
+ hrefTranslationKey?: string;
43
+ hrefTranslationValue?: unknown;
44
+ }) => void;
45
+ };
46
+ };
47
+ declare const applyRenderDirectives: ({ node, componentProps, renderBindingProps, runtime, plans: providedPlans, dependencies, }: ApplyRenderDirectivesParams) => void;
48
+
49
+ export { applyRenderDirectives };
@@ -0,0 +1,58 @@
1
+ // src/directives/applyRenderDirectives.ts
2
+ var applyRenderDirectives = ({
3
+ node,
4
+ componentProps,
5
+ renderBindingProps,
6
+ runtime,
7
+ plans: providedPlans,
8
+ dependencies
9
+ }) => {
10
+ const directives = providedPlans != null ? providedPlans : dependencies.resolveRenderDirectivePlan({
11
+ node,
12
+ renderBindingProps
13
+ });
14
+ for (const directive of directives) {
15
+ if (directive.kind === "rows-columns-binding") {
16
+ dependencies.applyRowsAndColumnsBinding({
17
+ componentProps,
18
+ runtime,
19
+ rowsBindingKey: directive.rowsBindingKey,
20
+ columnsBindingKey: directive.columnsBindingKey
21
+ });
22
+ }
23
+ if (directive.kind === "filter-rows-by-query") {
24
+ dependencies.filterRowsByRuntimeQuery({
25
+ nodeId: directive.nodeId,
26
+ componentProps,
27
+ runtime
28
+ });
29
+ }
30
+ if (directive.kind === "cover-media") {
31
+ componentProps.media = dependencies.buildCoverMedia({
32
+ mediaSource: directive.mediaSource,
33
+ mediaSrc: directive.mediaSrc,
34
+ mediaAlt: directive.mediaAlt
35
+ });
36
+ }
37
+ if (directive.kind === "object-binding") {
38
+ dependencies.applyObjectBinding({
39
+ componentProps,
40
+ runtime,
41
+ bindingKey: directive.bindingKey
42
+ });
43
+ }
44
+ if (directive.kind === "decode-translation-binding") {
45
+ dependencies.applyDecodeTranslationBinding({
46
+ componentProps,
47
+ runtime,
48
+ tagContentTranslationKey: directive.tagContentTranslationKey,
49
+ tagContentTranslationValue: directive.tagContentTranslationValue,
50
+ hrefTranslationKey: directive.hrefTranslationKey,
51
+ hrefTranslationValue: directive.hrefTranslationValue
52
+ });
53
+ }
54
+ }
55
+ };
56
+ export {
57
+ applyRenderDirectives
58
+ };