@arkcit/engine-react 0.3.8 → 0.3.9

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 CHANGED
@@ -1,51 +1,23 @@
1
- # @arkcit/engine-react
1
+ # arkcit-engine-react
2
2
 
3
- Concrete React renderer package for the Arkcit platform.
3
+ Adapter React du moteur Arkcit.
4
4
 
5
- ## Position In The Flow
5
+ ## Comprendre le projet
6
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
- ```
7
+ - [SUMMARY.md](docs/SUMMARY.md) - explication courte du projet et liens architecture.
8
+ - [ARCHITECTURE.md](docs/ARCHITECTURE.md) - carte visuelle, couches et flux.
9
+ - [DECOUPLING.md](docs/DECOUPLING.md) - refactor, decouplage, couverture et risques.
10
+ - [ROADMAP.md](docs/ROADMAP.md) - reste-a-faire uniquement.
11
+ - [NOTES.md](docs/NOTES.md) - log nettoyable des acquis et decisions.
12
+ - [ENVIRONNEMENT.md](docs/ENVIRONNEMENT.md) - variables d'environnement detectees.
13
+ - [GOUVERNANCE.md](docs/GOUVERNANCE.md) - maintenance, validation et production.
14
+ - [AGENTS.md](AGENTS.md) - consignes de travail pour Codex et agents.
21
15
 
22
- ## What Goes In
16
+ ## Commandes utiles
23
17
 
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`
18
+ - `npm run typecheck`
19
+ - `npm run test`
20
+ - `npm run test:smoke`
21
+ - `npm run test:unit`
22
+ - `npm run test:coverage`
23
+ - `npm run build`
@@ -219,6 +219,7 @@ var materializeTabsContent = ({
219
219
  renderSafeNode,
220
220
  normalizeRenderableChild
221
221
  }) => tabs.map((tab) => ({
222
+ disabled: Boolean(tab.disabled),
222
223
  id: tab.id,
223
224
  title: tab.title,
224
225
  label: tab.label,
package/dist/engine.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
2
1
  import React__default from 'react';
3
2
  import { UIEngineProps, UINodeSize, UINodeWrapperProps } from '@arkcit/engine-core';
4
3
  import { UINode } from '@arkcit/engine-schema';
@@ -10,7 +9,7 @@ import '@arkcit/engine-render-layer';
10
9
  type EngineWarningFallbackProps = {
11
10
  message: string;
12
11
  };
13
- declare const EngineWarningFallback: ({ message }: EngineWarningFallbackProps) => react_jsx_runtime.JSX.Element;
12
+ declare const EngineWarningFallback: ({ message }: EngineWarningFallbackProps) => React__default.JSX.Element;
14
13
 
15
14
  type NodeErrorBoundaryProps = {
16
15
  nodeId: string;
@@ -27,7 +26,7 @@ declare class NodeErrorBoundary extends React__default.Component<NodeErrorBounda
27
26
  componentDidUpdate(prevProps: Readonly<{
28
27
  resetToken: string;
29
28
  }>): void;
30
- render(): string | number | bigint | boolean | Iterable<React__default.ReactNode> | Promise<string | number | bigint | boolean | React__default.ReactPortal | React__default.ReactElement<unknown, string | React__default.JSXElementConstructor<any>> | Iterable<React__default.ReactNode> | null | undefined> | react_jsx_runtime.JSX.Element | null | undefined;
29
+ render(): string | number | bigint | boolean | Iterable<React__default.ReactNode> | Promise<string | number | bigint | boolean | React__default.ReactPortal | React__default.ReactElement<unknown, string | React__default.JSXElementConstructor<any>> | Iterable<React__default.ReactNode> | null | undefined> | React__default.JSX.Element | null | undefined;
31
30
  }
32
31
 
33
32
  type ReactWebUseUIEngineEffectsArgs = {
@@ -92,6 +91,6 @@ type ReactWebEngineRootDependencies<TInlineEditing = unknown> = {
92
91
  type ReactWebEngineRootArgs<TInlineEditing = unknown> = UIEngineProps & {
93
92
  dependencies: ReactWebEngineRootDependencies<TInlineEditing>;
94
93
  };
95
- declare const ReactWebEngineRoot: <TInlineEditing = unknown>({ schema, registry, store, onNodeClick, onInlineTextEdit, onNodeResize, onNodeResizeStart, onNodeResizeEnd, onNodeDragStart, onNodeDragOverTarget, onNodeDropTarget, selectedNodeId, nodeWrapper, dependencies, }: ReactWebEngineRootArgs<TInlineEditing>) => react_jsx_runtime.JSX.Element;
94
+ declare const ReactWebEngineRoot: <TInlineEditing = unknown>({ schema, registry, store, onNodeClick, onInlineTextEdit, onNodeResize, onNodeResizeStart, onNodeResizeEnd, onNodeDragStart, onNodeDragOverTarget, onNodeDropTarget, selectedNodeId, nodeWrapper, dependencies, }: ReactWebEngineRootArgs<TInlineEditing>) => React__default.JSX.Element;
96
95
 
97
96
  export { EngineWarningFallback, NodeErrorBoundary, ReactWebEngineRoot, type ReactWebEngineRootArgs, type ReactWebEngineRootDependencies, type ReactWebRenderSafeNodeArgs, type ReactWebUseUIEngineEffectsArgs, type ReactWebUseUIEngineEffectsResult };
package/dist/index.d.ts CHANGED
@@ -11,4 +11,3 @@ export { ComponentRegistry, ComponentRegistryEntry } from '@arkcit/engine-core';
11
11
  import 'react';
12
12
  import '@arkcit/engine-schema';
13
13
  import '@arkcit/engine-runtime';
14
- import 'react/jsx-runtime';
package/dist/index.js CHANGED
@@ -219,6 +219,7 @@ var materializeTabsContent = ({
219
219
  renderSafeNode,
220
220
  normalizeRenderableChild: normalizeRenderableChild2
221
221
  }) => tabs.map((tab) => ({
222
+ disabled: Boolean(tab.disabled),
222
223
  id: tab.id,
223
224
  title: tab.title,
224
225
  label: tab.label,
@@ -1344,7 +1345,10 @@ import React12 from "react";
1344
1345
  var configurePreviewLinkBehavior = (componentProps) => {
1345
1346
  const existingOnClick = componentProps.onClick;
1346
1347
  componentProps.onClick = (event) => {
1347
- event.preventDefault();
1348
+ const href = componentProps.href;
1349
+ if (!(typeof href === "string" && href.startsWith("#"))) {
1350
+ event.preventDefault();
1351
+ }
1348
1352
  if (typeof existingOnClick === "function") {
1349
1353
  existingOnClick(event);
1350
1354
  }
@@ -1352,6 +1356,7 @@ var configurePreviewLinkBehavior = (componentProps) => {
1352
1356
  };
1353
1357
 
1354
1358
  // src/rendering/finalizeRenderedNode.tsx
1359
+ import { jsx as jsx13 } from "react/jsx-runtime";
1355
1360
  var RESPONSIVE_MEDIA_NODE_TYPES = /* @__PURE__ */ new Set(["Image", "Video", "EmbeddedVideo", "Cover", "Document"]);
1356
1361
  var RESPONSIVE_MEDIA_CLASS_NAME = "max-md:!w-full max-md:![flex-basis:100%!important] max-md:!h-auto";
1357
1362
  var RESPONSIVE_TEXT_NODE_TYPES = /* @__PURE__ */ new Set([
@@ -1394,6 +1399,45 @@ var RESPONSIVE_TEXT_CLASS_NAME = "max-md:!h-auto";
1394
1399
  var hasExplicitStudioSizing = (studioSizing) => Boolean(
1395
1400
  studioSizing && (studioSizing.widthPct !== null || studioSizing.heightPct !== null || studioSizing.heightPx !== null)
1396
1401
  );
1402
+ var buildExplicitSizingWrapperStyle = (studioSizing) => {
1403
+ if (!hasExplicitStudioSizing(studioSizing)) return null;
1404
+ return __spreadValues(__spreadValues(__spreadValues({}, (studioSizing == null ? void 0 : studioSizing.widthPct) !== null && (studioSizing == null ? void 0 : studioSizing.widthPct) !== void 0 ? {
1405
+ width: `${studioSizing.widthPct}%`,
1406
+ flexBasis: `${studioSizing.widthPct}%`,
1407
+ maxWidth: "100%"
1408
+ } : {}), (studioSizing == null ? void 0 : studioSizing.heightPx) !== null && (studioSizing == null ? void 0 : studioSizing.heightPx) !== void 0 ? { height: `${studioSizing.heightPx}px` } : {}), (studioSizing == null ? void 0 : studioSizing.heightPx) === null && (studioSizing == null ? void 0 : studioSizing.heightPct) !== null && (studioSizing == null ? void 0 : studioSizing.heightPct) !== void 0 ? { height: `${studioSizing.heightPct}%` } : {});
1409
+ };
1410
+ var removeExplicitSizingFromComponentStyle = (componentProps, shouldWrapExplicitSizing) => {
1411
+ if (!shouldWrapExplicitSizing) return;
1412
+ const currentStyle = componentProps.style && typeof componentProps.style === "object" ? __spreadValues({}, componentProps.style) : null;
1413
+ if (!currentStyle) return;
1414
+ delete currentStyle.width;
1415
+ delete currentStyle.flexBasis;
1416
+ delete currentStyle.maxWidth;
1417
+ delete currentStyle.height;
1418
+ componentProps.style = currentStyle;
1419
+ };
1420
+ var removeInternalLayoutProps = (componentProps) => {
1421
+ delete componentProps.fullBleed;
1422
+ };
1423
+ var wrapExplicitlySizedNode = ({
1424
+ nodeId,
1425
+ nodeType,
1426
+ element,
1427
+ wrapperStyle
1428
+ }) => {
1429
+ if (!wrapperStyle) return element;
1430
+ return /* @__PURE__ */ jsx13(
1431
+ "div",
1432
+ {
1433
+ "data-node-id": nodeId,
1434
+ "data-node-type": nodeType,
1435
+ className: "relative min-w-0 max-w-full flex-none",
1436
+ style: wrapperStyle,
1437
+ children: /* @__PURE__ */ jsx13("div", { className: "min-w-0 max-w-full", style: { width: "100%", height: "100%" }, children: element })
1438
+ }
1439
+ );
1440
+ };
1397
1441
  var finalizeRenderedNode = ({
1398
1442
  node,
1399
1443
  children,
@@ -1436,6 +1480,9 @@ var finalizeRenderedNode = ({
1436
1480
  delete componentProps.layout;
1437
1481
  }
1438
1482
  }
1483
+ const explicitSizingWrapperStyle = !isStudioRendererContext ? buildExplicitSizingWrapperStyle(studioSizing) : null;
1484
+ removeExplicitSizingFromComponentStyle(componentProps, explicitSizingWrapperStyle !== null);
1485
+ removeInternalLayoutProps(componentProps);
1439
1486
  if (plans.some((plan) => plan.kind === "table-fallback")) {
1440
1487
  const tableNode = materializeBoundTable({
1441
1488
  nodeId: node.id,
@@ -1444,17 +1491,31 @@ var finalizeRenderedNode = ({
1444
1491
  TableComponent: registryComponent
1445
1492
  });
1446
1493
  if (tableNode) {
1447
- return tableNode;
1494
+ return wrapExplicitlySizedNode({
1495
+ nodeId: node.id,
1496
+ nodeType: node.type,
1497
+ element: tableNode,
1498
+ wrapperStyle: explicitSizingWrapperStyle
1499
+ });
1448
1500
  }
1449
1501
  }
1450
1502
  const finalComponentProps = dependencies.omitStudioProps(componentProps);
1503
+ let renderedElement;
1451
1504
  if (children && children.length > 0) {
1452
1505
  if (node.type === "Cover" || node.type === "Tabs" || node.type === "Accordion") {
1453
- return React12.createElement(registryComponent, finalComponentProps);
1506
+ renderedElement = React12.createElement(registryComponent, finalComponentProps);
1507
+ } else {
1508
+ renderedElement = React12.createElement(registryComponent, finalComponentProps, children);
1454
1509
  }
1455
- return React12.createElement(registryComponent, finalComponentProps, children);
1510
+ } else {
1511
+ renderedElement = React12.createElement(registryComponent, finalComponentProps);
1456
1512
  }
1457
- return React12.createElement(registryComponent, finalComponentProps);
1513
+ return wrapExplicitlySizedNode({
1514
+ nodeId: node.id,
1515
+ nodeType: node.type,
1516
+ element: renderedElement,
1517
+ wrapperStyle: explicitSizingWrapperStyle
1518
+ });
1458
1519
  };
1459
1520
 
1460
1521
  // src/rendering/nodeResetToken.ts
@@ -1487,7 +1548,7 @@ var buildNodeResetToken = (node) => {
1487
1548
 
1488
1549
  // src/rendering/renderChildren.tsx
1489
1550
  import React13, { isValidElement as isValidElement2 } from "react";
1490
- import { jsx as jsx13 } from "react/jsx-runtime";
1551
+ import { jsx as jsx14 } from "react/jsx-runtime";
1491
1552
  var toBoolean = (value) => {
1492
1553
  if (typeof value === "boolean") return value;
1493
1554
  if (typeof value === "string") return value.toLowerCase() === "true";
@@ -1498,7 +1559,7 @@ var normalizeRenderableChild = (value) => {
1498
1559
  if (typeof value === "string" || typeof value === "number") return value;
1499
1560
  if (isValidElement2(value)) return value;
1500
1561
  if (Array.isArray(value)) {
1501
- return value.map((item, index) => /* @__PURE__ */ jsx13(React13.Fragment, { children: normalizeRenderableChild(item) }, `normalized-child-${index}`));
1562
+ return value.map((item, index) => /* @__PURE__ */ jsx14(React13.Fragment, { children: normalizeRenderableChild(item) }, `normalized-child-${index}`));
1502
1563
  }
1503
1564
  if (value && typeof value === "object") {
1504
1565
  const candidate = value;
@@ -1,4 +1,3 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
2
1
  import React__default from 'react';
3
2
  import { UINode } from '@arkcit/engine-schema';
4
3
  import { UIRuntimeAdapter } from '@arkcit/engine-runtime';
@@ -13,15 +12,15 @@ declare const buildCoverContent: ({ rawChildren, renderSafeNode, }: {
13
12
  rawChildren: UINode[];
14
13
  renderSafeNode: (node: UINode) => React__default.ReactNode;
15
14
  }) => {
16
- actions: react_jsx_runtime.JSX.Element | undefined;
17
- children: react_jsx_runtime.JSX.Element | null;
15
+ actions: React__default.JSX.Element | undefined;
16
+ children: React__default.JSX.Element | null;
18
17
  };
19
18
  declare const buildScrollRevealChildren: ({ rawChildren, renderSafeNode, normalizeRenderableChild, fallbackChildren, }: {
20
19
  rawChildren: UINode[];
21
20
  renderSafeNode: (node: UINode) => React__default.ReactNode;
22
21
  normalizeRenderableChild: (value: unknown) => React__default.ReactNode;
23
22
  fallbackChildren: unknown;
24
- }) => string | number | bigint | boolean | Iterable<React__default.ReactNode> | Promise<string | number | bigint | boolean | React__default.ReactPortal | React__default.ReactElement<unknown, string | React__default.JSXElementConstructor<any>> | Iterable<React__default.ReactNode> | null | undefined> | react_jsx_runtime.JSX.Element | null | undefined;
23
+ }) => string | number | bigint | boolean | Iterable<React__default.ReactNode> | Promise<string | number | bigint | boolean | React__default.ReactPortal | React__default.ReactElement<unknown, string | React__default.JSXElementConstructor<any>> | Iterable<React__default.ReactNode> | null | undefined> | React__default.JSX.Element | null | undefined;
25
24
 
26
25
  type TableComponentShape = {
27
26
  Header: React__default.ComponentType<Record<string, unknown>>;
@@ -46,8 +45,8 @@ declare const materializeCoverContent: ({ descriptor, renderSafeNode, }: {
46
45
  descriptor: CoverContentDescriptor;
47
46
  renderSafeNode: (node: UINode) => React__default.ReactNode;
48
47
  }) => {
49
- actions: react_jsx_runtime.JSX.Element | undefined;
50
- children: react_jsx_runtime.JSX.Element | null;
48
+ actions: React__default.JSX.Element | undefined;
49
+ children: React__default.JSX.Element | null;
51
50
  };
52
51
 
53
52
  declare const materializeAccordionItems: ({ items, renderSafeNode, }: {
@@ -57,30 +56,31 @@ declare const materializeAccordionItems: ({ items, renderSafeNode, }: {
57
56
  id: string;
58
57
  title: string;
59
58
  disabled: boolean;
60
- content: string | react_jsx_runtime.JSX.Element;
59
+ content: string | React__default.JSX.Element;
61
60
  }[];
62
61
  declare const materializeExpandablePanelContent: ({ descriptor, renderSafeNode, }: {
63
62
  descriptor: ExpandablePanelContentDescriptor;
64
63
  renderSafeNode: (node: UINode) => React__default.ReactNode;
65
- }) => react_jsx_runtime.JSX.Element | undefined;
64
+ }) => React__default.JSX.Element | undefined;
66
65
 
67
66
  declare const materializeTabsContent: ({ tabs, renderSafeNode, normalizeRenderableChild, }: {
68
67
  tabs: TabsContentDescriptor[];
69
68
  renderSafeNode: (node: UINode) => React__default.ReactNode;
70
69
  normalizeRenderableChild: (value: unknown) => React__default.ReactNode;
71
70
  }) => {
71
+ disabled: boolean;
72
72
  id: string;
73
73
  title: unknown;
74
74
  label: unknown;
75
- content: string | number | bigint | boolean | React__default.ReactElement<unknown, string | React__default.JSXElementConstructor<any>> | Iterable<React__default.ReactNode> | Promise<string | number | bigint | boolean | React__default.ReactPortal | React__default.ReactElement<unknown, string | React__default.JSXElementConstructor<any>> | Iterable<React__default.ReactNode> | null | undefined> | react_jsx_runtime.JSX.Element[] | null | undefined;
75
+ content: string | number | bigint | boolean | React__default.ReactElement<unknown, string | React__default.JSXElementConstructor<any>> | Iterable<React__default.ReactNode> | Promise<string | number | bigint | boolean | React__default.ReactPortal | React__default.ReactElement<unknown, string | React__default.JSXElementConstructor<any>> | Iterable<React__default.ReactNode> | null | undefined> | React__default.JSX.Element[] | null | undefined;
76
76
  }[];
77
77
 
78
78
  declare const buildAccordionItems: (accordionChildren: UINode[], renderSafeNode: (node: UINode) => React__default.ReactNode) => {
79
79
  id: string;
80
80
  title: string;
81
- content: string | react_jsx_runtime.JSX.Element;
81
+ content: string | React__default.JSX.Element;
82
82
  disabled: boolean;
83
83
  }[];
84
- declare const buildExpandablePanelChildren: (panelChildren: UINode[], renderSafeNode: (node: UINode) => React__default.ReactNode) => react_jsx_runtime.JSX.Element | undefined;
84
+ declare const buildExpandablePanelChildren: (panelChildren: UINode[], renderSafeNode: (node: UINode) => React__default.ReactNode) => React__default.JSX.Element | undefined;
85
85
 
86
86
  export { buildAccordionItems, buildCoverContent, buildCoverMedia, buildExpandablePanelChildren, buildScrollRevealChildren, materializeAccordionItems, materializeBoundTable, materializeChildContent, materializeCoverContent, materializeExpandablePanelContent, materializeTabsContent };
@@ -342,6 +342,7 @@ var materializeTabsContent = ({
342
342
  renderSafeNode,
343
343
  normalizeRenderableChild
344
344
  }) => tabs.map((tab) => ({
345
+ disabled: Boolean(tab.disabled),
345
346
  id: tab.id,
346
347
  title: tab.title,
347
348
  label: tab.label,
@@ -2,7 +2,6 @@ import React__default from 'react';
2
2
  import { FinalRenderPlan, ResolvedNodeChildDescriptor, ResolvedNodeContentDescriptor, ResolvedNodeBase, ResolvedEngineNode } from '@arkcit/engine-render-layer';
3
3
  import { UINode } from '@arkcit/engine-schema';
4
4
  import { UIRuntimeAdapter } from '@arkcit/engine-runtime';
5
- import * as react_jsx_runtime from 'react/jsx-runtime';
6
5
  export { R as RenderReactNodeArgs, a as RenderReactNodeDependencies, r as renderReactNode } from './renderReactNode-xwA81IXf.js';
7
6
  import { ComponentRegistry } from '@arkcit/engine-core';
8
7
 
@@ -56,7 +55,7 @@ type PrepareRenderableChildrenArgs = {
56
55
  childContentDescriptor?: ResolvedNodeContentDescriptor;
57
56
  };
58
57
  declare const prepareRenderableChildren: ({ node, internalStudioNodeTypes, renderSafeNode, childDescriptors, childContentDescriptor, }: PrepareRenderableChildrenArgs) => {
59
- children: react_jsx_runtime.JSX.Element[];
58
+ children: React__default.JSX.Element[];
60
59
  resolvedChildContent: React__default.ReactNode;
61
60
  childDescriptors: ResolvedNodeChildDescriptor[];
62
61
  childContentDescriptor: ResolvedNodeContentDescriptor;
package/dist/rendering.js CHANGED
@@ -25,7 +25,10 @@ import React2 from "react";
25
25
  var configurePreviewLinkBehavior = (componentProps) => {
26
26
  const existingOnClick = componentProps.onClick;
27
27
  componentProps.onClick = (event) => {
28
- event.preventDefault();
28
+ const href = componentProps.href;
29
+ if (!(typeof href === "string" && href.startsWith("#"))) {
30
+ event.preventDefault();
31
+ }
29
32
  if (typeof existingOnClick === "function") {
30
33
  existingOnClick(event);
31
34
  }
@@ -174,6 +177,7 @@ var materializeBoundTable = ({
174
177
  };
175
178
 
176
179
  // src/rendering/finalizeRenderedNode.tsx
180
+ import { jsx } from "react/jsx-runtime";
177
181
  var RESPONSIVE_MEDIA_NODE_TYPES = /* @__PURE__ */ new Set(["Image", "Video", "EmbeddedVideo", "Cover", "Document"]);
178
182
  var RESPONSIVE_MEDIA_CLASS_NAME = "max-md:!w-full max-md:![flex-basis:100%!important] max-md:!h-auto";
179
183
  var RESPONSIVE_TEXT_NODE_TYPES = /* @__PURE__ */ new Set([
@@ -216,6 +220,45 @@ var RESPONSIVE_TEXT_CLASS_NAME = "max-md:!h-auto";
216
220
  var hasExplicitStudioSizing = (studioSizing) => Boolean(
217
221
  studioSizing && (studioSizing.widthPct !== null || studioSizing.heightPct !== null || studioSizing.heightPx !== null)
218
222
  );
223
+ var buildExplicitSizingWrapperStyle = (studioSizing) => {
224
+ if (!hasExplicitStudioSizing(studioSizing)) return null;
225
+ return __spreadValues(__spreadValues(__spreadValues({}, (studioSizing == null ? void 0 : studioSizing.widthPct) !== null && (studioSizing == null ? void 0 : studioSizing.widthPct) !== void 0 ? {
226
+ width: `${studioSizing.widthPct}%`,
227
+ flexBasis: `${studioSizing.widthPct}%`,
228
+ maxWidth: "100%"
229
+ } : {}), (studioSizing == null ? void 0 : studioSizing.heightPx) !== null && (studioSizing == null ? void 0 : studioSizing.heightPx) !== void 0 ? { height: `${studioSizing.heightPx}px` } : {}), (studioSizing == null ? void 0 : studioSizing.heightPx) === null && (studioSizing == null ? void 0 : studioSizing.heightPct) !== null && (studioSizing == null ? void 0 : studioSizing.heightPct) !== void 0 ? { height: `${studioSizing.heightPct}%` } : {});
230
+ };
231
+ var removeExplicitSizingFromComponentStyle = (componentProps, shouldWrapExplicitSizing) => {
232
+ if (!shouldWrapExplicitSizing) return;
233
+ const currentStyle = componentProps.style && typeof componentProps.style === "object" ? __spreadValues({}, componentProps.style) : null;
234
+ if (!currentStyle) return;
235
+ delete currentStyle.width;
236
+ delete currentStyle.flexBasis;
237
+ delete currentStyle.maxWidth;
238
+ delete currentStyle.height;
239
+ componentProps.style = currentStyle;
240
+ };
241
+ var removeInternalLayoutProps = (componentProps) => {
242
+ delete componentProps.fullBleed;
243
+ };
244
+ var wrapExplicitlySizedNode = ({
245
+ nodeId,
246
+ nodeType,
247
+ element,
248
+ wrapperStyle
249
+ }) => {
250
+ if (!wrapperStyle) return element;
251
+ return /* @__PURE__ */ jsx(
252
+ "div",
253
+ {
254
+ "data-node-id": nodeId,
255
+ "data-node-type": nodeType,
256
+ className: "relative min-w-0 max-w-full flex-none",
257
+ style: wrapperStyle,
258
+ children: /* @__PURE__ */ jsx("div", { className: "min-w-0 max-w-full", style: { width: "100%", height: "100%" }, children: element })
259
+ }
260
+ );
261
+ };
219
262
  var finalizeRenderedNode = ({
220
263
  node,
221
264
  children,
@@ -258,6 +301,9 @@ var finalizeRenderedNode = ({
258
301
  delete componentProps.layout;
259
302
  }
260
303
  }
304
+ const explicitSizingWrapperStyle = !isStudioRendererContext ? buildExplicitSizingWrapperStyle(studioSizing) : null;
305
+ removeExplicitSizingFromComponentStyle(componentProps, explicitSizingWrapperStyle !== null);
306
+ removeInternalLayoutProps(componentProps);
261
307
  if (plans.some((plan) => plan.kind === "table-fallback")) {
262
308
  const tableNode = materializeBoundTable({
263
309
  nodeId: node.id,
@@ -266,17 +312,31 @@ var finalizeRenderedNode = ({
266
312
  TableComponent: registryComponent
267
313
  });
268
314
  if (tableNode) {
269
- return tableNode;
315
+ return wrapExplicitlySizedNode({
316
+ nodeId: node.id,
317
+ nodeType: node.type,
318
+ element: tableNode,
319
+ wrapperStyle: explicitSizingWrapperStyle
320
+ });
270
321
  }
271
322
  }
272
323
  const finalComponentProps = dependencies.omitStudioProps(componentProps);
324
+ let renderedElement;
273
325
  if (children && children.length > 0) {
274
326
  if (node.type === "Cover" || node.type === "Tabs" || node.type === "Accordion") {
275
- return React2.createElement(registryComponent, finalComponentProps);
327
+ renderedElement = React2.createElement(registryComponent, finalComponentProps);
328
+ } else {
329
+ renderedElement = React2.createElement(registryComponent, finalComponentProps, children);
276
330
  }
277
- return React2.createElement(registryComponent, finalComponentProps, children);
331
+ } else {
332
+ renderedElement = React2.createElement(registryComponent, finalComponentProps);
278
333
  }
279
- return React2.createElement(registryComponent, finalComponentProps);
334
+ return wrapExplicitlySizedNode({
335
+ nodeId: node.id,
336
+ nodeType: node.type,
337
+ element: renderedElement,
338
+ wrapperStyle: explicitSizingWrapperStyle
339
+ });
280
340
  };
281
341
 
282
342
  // src/rendering/gridItemWrapperProps.ts
@@ -353,7 +413,7 @@ import {
353
413
 
354
414
  // src/materialization/materializeChildContent.tsx
355
415
  import React3 from "react";
356
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
416
+ import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
357
417
  var materializeChildContent = ({
358
418
  descriptor,
359
419
  renderSafeNode
@@ -363,7 +423,7 @@ var materializeChildContent = ({
363
423
  }
364
424
  const renderDescriptor = (childDescriptor) => {
365
425
  if (childDescriptor.kind === "grid-item") {
366
- return /* @__PURE__ */ jsx(
426
+ return /* @__PURE__ */ jsx2(
367
427
  "div",
368
428
  __spreadProps(__spreadValues({}, getGridItemWrapperProps(
369
429
  childDescriptor.colSpan,
@@ -376,22 +436,22 @@ var materializeChildContent = ({
376
436
  childDescriptor.child.id
377
437
  );
378
438
  }
379
- return /* @__PURE__ */ jsx(React3.Fragment, { children: renderSafeNode(childDescriptor.child) }, childDescriptor.child.id);
439
+ return /* @__PURE__ */ jsx2(React3.Fragment, { children: renderSafeNode(childDescriptor.child) }, childDescriptor.child.id);
380
440
  };
381
441
  if (descriptor.kind === "single") {
382
442
  return /* @__PURE__ */ jsxs(Fragment, { children: [
383
- descriptor.child.kind === "grid-item" ? /* @__PURE__ */ jsx("style", { children: GRID_ITEM_RESPONSIVE_STYLE }) : null,
443
+ descriptor.child.kind === "grid-item" ? /* @__PURE__ */ jsx2("style", { children: GRID_ITEM_RESPONSIVE_STYLE }) : null,
384
444
  renderDescriptor(descriptor.child)
385
445
  ] });
386
446
  }
387
447
  return /* @__PURE__ */ jsxs(Fragment, { children: [
388
- descriptor.children.some((child) => child.kind === "grid-item") ? /* @__PURE__ */ jsx("style", { children: GRID_ITEM_RESPONSIVE_STYLE }) : null,
448
+ descriptor.children.some((child) => child.kind === "grid-item") ? /* @__PURE__ */ jsx2("style", { children: GRID_ITEM_RESPONSIVE_STYLE }) : null,
389
449
  descriptor.children.map(renderDescriptor)
390
450
  ] });
391
451
  };
392
452
 
393
453
  // src/rendering/prepareRenderableChildren.tsx
394
- import { jsx as jsx2 } from "react/jsx-runtime";
454
+ import { jsx as jsx3 } from "react/jsx-runtime";
395
455
  var prepareRenderableChildren = ({
396
456
  node,
397
457
  internalStudioNodeTypes,
@@ -405,7 +465,7 @@ var prepareRenderableChildren = ({
405
465
  });
406
466
  const children = resolvedDescriptors.map((descriptor) => {
407
467
  if (descriptor.kind === "grid-item") {
408
- return /* @__PURE__ */ jsx2(
468
+ return /* @__PURE__ */ jsx3(
409
469
  "div",
410
470
  __spreadProps(__spreadValues({}, getGridItemWrapperProps(
411
471
  descriptor.colSpan,
@@ -418,10 +478,10 @@ var prepareRenderableChildren = ({
418
478
  descriptor.child.id
419
479
  );
420
480
  }
421
- return /* @__PURE__ */ jsx2(React4.Fragment, { children: renderSafeNode(descriptor.child) }, descriptor.child.id);
481
+ return /* @__PURE__ */ jsx3(React4.Fragment, { children: renderSafeNode(descriptor.child) }, descriptor.child.id);
422
482
  });
423
483
  const hasGridItems = resolvedDescriptors.some((descriptor) => descriptor.kind === "grid-item");
424
- const wrappedChildren = hasGridItems ? [/* @__PURE__ */ jsx2("style", { children: GRID_ITEM_RESPONSIVE_STYLE }, "arkcit-grid-item-responsive-style"), ...children] : children;
484
+ const wrappedChildren = hasGridItems ? [/* @__PURE__ */ jsx3("style", { children: GRID_ITEM_RESPONSIVE_STYLE }, "arkcit-grid-item-responsive-style"), ...children] : children;
425
485
  const resolvedChildContentDescriptor = childContentDescriptor != null ? childContentDescriptor : resolveChildContentDescriptor({
426
486
  childDescriptors: resolvedDescriptors
427
487
  });
@@ -439,7 +499,7 @@ var prepareRenderableChildren = ({
439
499
 
440
500
  // src/rendering/renderChildren.tsx
441
501
  import React5, { isValidElement as isValidElement2 } from "react";
442
- import { jsx as jsx3 } from "react/jsx-runtime";
502
+ import { jsx as jsx4 } from "react/jsx-runtime";
443
503
  var toBoolean = (value) => {
444
504
  if (typeof value === "boolean") return value;
445
505
  if (typeof value === "string") return value.toLowerCase() === "true";
@@ -450,7 +510,7 @@ var normalizeRenderableChild = (value) => {
450
510
  if (typeof value === "string" || typeof value === "number") return value;
451
511
  if (isValidElement2(value)) return value;
452
512
  if (Array.isArray(value)) {
453
- return value.map((item, index) => /* @__PURE__ */ jsx3(React5.Fragment, { children: normalizeRenderableChild(item) }, `normalized-child-${index}`));
513
+ return value.map((item, index) => /* @__PURE__ */ jsx4(React5.Fragment, { children: normalizeRenderableChild(item) }, `normalized-child-${index}`));
454
514
  }
455
515
  if (value && typeof value === "object") {
456
516
  const candidate = value;
@@ -468,8 +528,8 @@ var normalizeRenderableChild = (value) => {
468
528
  };
469
529
 
470
530
  // src/engine/EngineWarningFallback.tsx
471
- import { jsx as jsx4 } from "react/jsx-runtime";
472
- var EngineWarningFallback = ({ message }) => /* @__PURE__ */ jsx4(
531
+ import { jsx as jsx5 } from "react/jsx-runtime";
532
+ var EngineWarningFallback = ({ message }) => /* @__PURE__ */ jsx5(
473
533
  "div",
474
534
  {
475
535
  role: "alert",
@@ -518,7 +578,7 @@ var resolveResolvedReactNode = ({
518
578
  };
519
579
 
520
580
  // src/rendering/renderReactNode.tsx
521
- import { jsx as jsx5 } from "react/jsx-runtime";
581
+ import { jsx as jsx6 } from "react/jsx-runtime";
522
582
  var renderReactNode = ({
523
583
  node,
524
584
  runtime,
@@ -555,7 +615,7 @@ var renderReactNode = ({
555
615
  studioSizing
556
616
  });
557
617
  if (!resolvedNode) {
558
- return /* @__PURE__ */ jsx5(
618
+ return /* @__PURE__ */ jsx6(
559
619
  EngineWarningFallback_default,
560
620
  {
561
621
  message: `Unknown component type "${node.type}" for node "${node.id}".`
@@ -641,7 +701,7 @@ var renderReactNode = ({
641
701
  plans: finalRenderPlans
642
702
  });
643
703
  } catch (e) {
644
- return /* @__PURE__ */ jsx5(
704
+ return /* @__PURE__ */ jsx6(
645
705
  EngineWarningFallback_default,
646
706
  {
647
707
  message: `Renderer fallback: node "${node.type}" (${node.id}) could not be resolved.`
@@ -1,4 +1,3 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
2
1
  import React__default from 'react';
3
2
  import { UIEngineProps, UINodeWrapperProps } from '@arkcit/engine-core';
4
3
  import { UINode } from '@arkcit/engine-schema';
@@ -44,6 +43,6 @@ type StaticReactWebEngineRootDependencies<TInlineEditing = unknown> = {
44
43
  type StaticReactWebEngineRootArgs<TInlineEditing = unknown> = UIEngineProps & {
45
44
  dependencies: StaticReactWebEngineRootDependencies<TInlineEditing>;
46
45
  };
47
- declare const StaticReactWebEngineRoot: <TInlineEditing = unknown>({ schema, registry, store, nodeWrapper, dependencies, }: StaticReactWebEngineRootArgs<TInlineEditing>) => react_jsx_runtime.JSX.Element;
46
+ declare const StaticReactWebEngineRoot: <TInlineEditing = unknown>({ schema, registry, store, nodeWrapper, dependencies, }: StaticReactWebEngineRootArgs<TInlineEditing>) => React__default.JSX.Element;
48
47
 
49
48
  export { StaticReactWebEngineRoot, type StaticReactWebEngineRootArgs, type StaticReactWebEngineRootDependencies, type StaticRenderSafeNodeArgs };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@arkcit/engine-react",
3
3
  "private": false,
4
- "version": "0.3.8",
4
+ "version": "0.3.9",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "description": "React-specific renderer package for the Arkcit engine platform.",