@developer_tribe/react-builder 1.2.1 → 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/dist/RenderPage.d.ts +3 -1
  2. package/dist/build-components/PaywallOptions/PaywallOptionButton.d.ts +1 -1
  3. package/dist/components/BuilderProvider.d.ts +17 -0
  4. package/dist/components/Checkbox.d.ts +1 -1
  5. package/dist/hooks/useExtractTextStyle.d.ts +3 -0
  6. package/dist/hooks/useExtractViewStyle.d.ts +3 -0
  7. package/dist/hooks/useLocalize.d.ts +4 -1
  8. package/dist/hooks/useSafeAreaViewStyle.d.ts +2 -1
  9. package/dist/index.cjs.js +5 -5
  10. package/dist/index.cjs.js.map +1 -1
  11. package/dist/index.d.ts +2 -6
  12. package/dist/index.esm.js +2 -2
  13. package/dist/index.esm.js.map +1 -1
  14. package/dist/index.native.cjs.js +1 -28
  15. package/dist/index.native.cjs.js.map +1 -1
  16. package/dist/index.native.d.ts +1 -0
  17. package/dist/index.native.esm.js +1 -28
  18. package/dist/index.native.esm.js.map +1 -1
  19. package/dist/types/Node.d.ts +1 -0
  20. package/dist/utils/extractTextStyle/extractTextStyle.d.ts +13 -0
  21. package/dist/utils/extractTextStyle.d.ts +2 -10
  22. package/dist/utils/extractViewStyle/extractViewStyle.d.ts +8 -0
  23. package/dist/utils/extractViewStyle.d.ts +2 -9
  24. package/dist/utils/parseColor.d.ts +1 -2
  25. package/package.json +1 -1
  26. package/src/RenderPage.tsx +32 -20
  27. package/src/build-components/BIcon/BIcon.tsx +10 -17
  28. package/src/build-components/BackgroundImage/BackgroundImage.tsx +10 -17
  29. package/src/build-components/Button/Button.tsx +23 -27
  30. package/src/build-components/Carousel/Carousel.tsx +10 -16
  31. package/src/build-components/CarouselButtons/CarouselButtons.tsx +4 -13
  32. package/src/build-components/CarouselDots/CarouselDots.tsx +5 -14
  33. package/src/build-components/CarouselItem/CarouselItem.tsx +4 -13
  34. package/src/build-components/CarouselProvider/CarouselProvider.tsx +3 -12
  35. package/src/build-components/Image/Image.tsx +11 -13
  36. package/src/build-components/Main/Main.tsx +12 -24
  37. package/src/build-components/OnboardButton/OnboardButton.tsx +8 -16
  38. package/src/build-components/OnboardButtons/OnboardButtons.tsx +9 -16
  39. package/src/build-components/OnboardDot/OnboardDot.tsx +25 -21
  40. package/src/build-components/OnboardFooter/OnboardFooter.tsx +18 -22
  41. package/src/build-components/OnboardImage/OnboardImage.tsx +12 -14
  42. package/src/build-components/OnboardItem/OnboardItem.tsx +3 -12
  43. package/src/build-components/OnboardProvider/OnboardProvider.tsx +11 -18
  44. package/src/build-components/PaywallBackground/PaywallBackground.tsx +9 -15
  45. package/src/build-components/PaywallCloseButton/PaywallCloseButton.tsx +10 -17
  46. package/src/build-components/PaywallOptions/PaywallOptionButton.tsx +12 -18
  47. package/src/build-components/PaywallProvider/PaywallProvider.tsx +16 -20
  48. package/src/build-components/PaywallSubscribeButton/PaywallSubscribeButton.tsx +11 -17
  49. package/src/build-components/RadioButton/RadioButton.tsx +12 -21
  50. package/src/build-components/Text/Text.tsx +14 -25
  51. package/src/build-components/View/View.tsx +11 -17
  52. package/src/build-components/other.tsx +1 -1
  53. package/src/components/BuilderProvider.tsx +38 -0
  54. package/src/hooks/useExtractTextStyle.ts +26 -0
  55. package/src/hooks/useExtractViewStyle.ts +19 -0
  56. package/src/hooks/useLocalize.ts +7 -6
  57. package/src/hooks/useSafeAreaViewStyle.ts +4 -5
  58. package/src/index.native.ts +3 -0
  59. package/src/index.ts +10 -7
  60. package/src/pages/ProjectDebug.tsx +16 -15
  61. package/src/pages/ProjectPage.tsx +17 -5
  62. package/src/types/Node.ts +1 -0
  63. package/src/utils/extractTextStyle/extractTextStyle.ts +179 -0
  64. package/src/utils/extractTextStyle.ts +2 -160
  65. package/src/utils/extractViewStyle/extractViewStyle.ts +144 -0
  66. package/src/utils/extractViewStyle.ts +2 -145
  67. package/src/utils/parseColor.ts +4 -5
@@ -1,8 +1,8 @@
1
1
  import React, { useContext, useId, useMemo } from 'react';
2
2
  import type { RadioButtonComponentProps } from './RadioButtonProps.generated';
3
3
  import useNode from '../useNode';
4
- import { useRenderStore } from '../../store';
5
- import { extractViewStyle } from '../../utils/extractViewStyle';
4
+ import { useBuilderParams } from '../../components/BuilderProvider';
5
+ import { useExtractViewStyle } from '../../hooks/useExtractViewStyle';
6
6
  import { useLogRender } from '../../utils/useLogRender';
7
7
  import { isNodeSelected, SELECTED_OUTLINE_STYLE } from '../../utils/selection';
8
8
  import { useMergedStyle } from '../../utils/useMergedStyle';
@@ -82,32 +82,23 @@ function RadioButton({ node }: RadioButtonComponentProps) {
82
82
  const attributeName = node.type ?? 'RadioButton';
83
83
  const attributeKey = node.key ?? generatedId;
84
84
 
85
- const { previewMode, current, appConfig, projectColors } = useRenderStore(
86
- (s) => ({
87
- previewMode: s.previewMode,
88
- current: s.current,
89
- appConfig: s.appConfig,
90
- projectColors: s.projectColors,
91
- }),
92
- );
85
+ const { previewMode, selectedKey } = useBuilderParams();
93
86
 
94
- const baseStyle = useMemo(
95
- () => extractViewStyle(node, { appConfig, projectColors }),
96
- [node, appConfig, projectColors],
97
- );
87
+ const baseStyle = useExtractViewStyle(node);
98
88
 
99
- const isSelected = isNodeSelected({ previewMode, current, node });
89
+ const isSelected = isNodeSelected({
90
+ previewMode: !!previewMode,
91
+ current: selectedKey ? { key: selectedKey } : undefined,
92
+ node,
93
+ });
100
94
  const style = useMergedStyle(
101
95
  baseStyle,
102
96
  isSelected ? SELECTED_OUTLINE_STYLE : undefined,
103
97
  );
104
98
 
105
- const selected = Boolean((node.attributes as any)?.selected);
106
- const color =
107
- typeof (node.attributes as any)?.color === 'string'
108
- ? ((node.attributes as any)?.color as string)
109
- : undefined;
110
- const size = parseNumberLike((node.attributes as any)?.size);
99
+ const selected = Boolean(node.attributes?.selected);
100
+ const color = node.attributes?.color;
101
+ const size = parseNumberLike(node.attributes?.size);
111
102
 
112
103
  return (
113
104
  <div
@@ -7,8 +7,8 @@ import React, {
7
7
  } from 'react';
8
8
  import type { TextComponentProps } from './TextProps.generated';
9
9
  import useNode from '../useNode';
10
- import { useRenderStore } from '../../store';
11
- import { extractTextStyle } from '../../utils/extractTextStyle';
10
+ import { useBuilderParams } from '../../components/BuilderProvider';
11
+ import { useExtractTextStyle } from '../../hooks/useExtractTextStyle';
12
12
  import { useLogRender } from '../../utils/useLogRender';
13
13
  import { isNodeSelected, SELECTED_OUTLINE_STYLE } from '../../utils/selection';
14
14
  import { useMergedStyle } from '../../utils/useMergedStyle';
@@ -18,41 +18,30 @@ function Text({ node }: TextComponentProps) {
18
18
  useLogRender('Text');
19
19
  node = useNode(node);
20
20
  const generatedId = useId();
21
- const attributeName = (node as any)?.sourceType ?? node.type ?? 'text';
21
+ const attributeName = node.sourceType ?? node.type ?? 'text';
22
22
  const attributeKey = node.key ?? generatedId;
23
23
  const textRef = useRef<HTMLParagraphElement | null>(null);
24
24
  const [autoFontSizePx, setAutoFontSizePx] = useState<number | null>(null);
25
- const { appConfig, projectColors, previewMode, current } = useRenderStore(
26
- (s) => ({
27
- appConfig: s.appConfig,
28
- projectColors: s.projectColors,
29
- previewMode: s.previewMode,
30
- current: s.current,
31
- }),
32
- );
25
+ const { appConfig, previewMode, selectedKey } = useBuilderParams();
33
26
  const keyOrText: string = node.children as string;
34
- const textStyle = useMemo(
35
- () => extractTextStyle(node, { appConfig, projectColors }),
36
- [node, appConfig, projectColors],
37
- );
38
- const isSelected = isNodeSelected({ previewMode, current, node });
39
- const localize = useLocalize();
27
+ const textStyle = useExtractTextStyle(node);
28
+ const isSelected = isNodeSelected({
29
+ previewMode: !!previewMode,
30
+ current: selectedKey ? { key: selectedKey } : undefined,
31
+ node,
32
+ });
33
+ const localize = useLocalize({ appConfig });
40
34
 
41
35
  const localizedText = useMemo(
42
36
  () => localize(keyOrText),
43
37
  [localize, keyOrText],
44
38
  );
45
39
 
46
- const attrs = (node as any)?.attributes as
47
- | (Record<string, unknown> & { style?: Record<string, unknown> })
48
- | undefined;
40
+ const attrs = node.attributes;
49
41
  const styleBag = attrs?.style;
50
- const adjustsFontSizeToFit =
51
- (attrs?.adjustsFontSizeToFit as boolean | undefined) ??
52
- (styleBag?.adjustsFontSizeToFit as boolean | undefined) ??
53
- false;
42
+ const adjustsFontSizeToFit = attrs?.adjustsFontSizeToFit ?? false;
54
43
  const showEllipsis =
55
- (attrs?.showEllipsis as boolean | undefined) ??
44
+ attrs?.showEllipsis ??
56
45
  (styleBag?.showEllipsis as boolean | undefined) ??
57
46
  false;
58
47
 
@@ -1,10 +1,10 @@
1
- import React, { useId, useMemo } from 'react';
1
+ import React, { useId } from 'react';
2
2
  import type { ViewComponentProps } from './ViewProps.generated';
3
3
  import RenderNode from '../RenderNode.generated';
4
4
  import { Node } from '../../types/Node';
5
5
  import useNode from '../useNode';
6
- import { useRenderStore } from '../../store';
7
- import { extractViewStyle } from '../../utils/extractViewStyle';
6
+ import { useBuilderParams } from '../../components/BuilderProvider';
7
+ import { useExtractViewStyle } from '../../hooks/useExtractViewStyle';
8
8
  import { useLogRender } from '../../utils/useLogRender';
9
9
  import { isNodeSelected, SELECTED_OUTLINE_STYLE } from '../../utils/selection';
10
10
  import { useMergedStyle } from '../../utils/useMergedStyle';
@@ -13,21 +13,15 @@ export function View({ node }: ViewComponentProps) {
13
13
  useLogRender('View');
14
14
  node = useNode(node);
15
15
  const generatedId = useId();
16
- const attributeName = (node as any)?.sourceType ?? node.type ?? 'view';
16
+ const attributeName = node.sourceType ?? node.type ?? 'view';
17
17
  const attributeKey = node.key ?? generatedId;
18
- const { previewMode, current, appConfig, projectColors } = useRenderStore(
19
- (s) => ({
20
- previewMode: s.previewMode,
21
- current: s.current,
22
- appConfig: s.appConfig,
23
- projectColors: s.projectColors,
24
- }),
25
- );
26
- const baseStyle = useMemo(
27
- () => extractViewStyle(node, { appConfig, projectColors }),
28
- [node, appConfig, projectColors],
29
- );
30
- const isSelected = isNodeSelected({ previewMode, current, node });
18
+ const { previewMode, selectedKey } = useBuilderParams();
19
+ const baseStyle = useExtractViewStyle(node);
20
+ const isSelected = isNodeSelected({
21
+ previewMode: !!previewMode,
22
+ current: selectedKey ? { key: selectedKey } : undefined,
23
+ node,
24
+ });
31
25
  const viewStyle = useMergedStyle(
32
26
  baseStyle,
33
27
  isSelected ? SELECTED_OUTLINE_STYLE : undefined,
@@ -9,7 +9,7 @@ export function other(type: string, node: Node): React.ReactNode {
9
9
  if (type === 'CrashComponent') {
10
10
  const details =
11
11
  node && typeof node === 'object' && !Array.isArray(node)
12
- ? (node as any).attributes
12
+ ? (node as { attributes?: unknown }).attributes
13
13
  : undefined;
14
14
  throw new Error(
15
15
  `CrashComponent: intentional crash for testing${
@@ -1,6 +1,9 @@
1
1
  import React, { createContext, useContext, useMemo } from 'react';
2
2
  import type { Product } from '../paywall/types/paywall-types';
3
3
  import type { PaywallBenefits } from '../paywall/types/benefits';
4
+ import type { AppConfig } from '../types/PreviewConfig';
5
+ import type { Fonts } from '../types/Fonts';
6
+ import type { ProjectColors } from '../types/Project';
4
7
  import { RenderErrorBoundary } from './RenderErrorBoundary';
5
8
 
6
9
  // NOTE: We keep this context intentionally tiny.
@@ -15,6 +18,20 @@ export type BuilderProviderParams = {
15
18
  benefits: PaywallBenefits;
16
19
  onPaywallClose?: () => void;
17
20
  onPaywallSubscribe?: (product?: Product) => void | boolean | Promise<boolean>;
21
+ /**
22
+ * Optional runtime config + styling inputs.
23
+ * These are intentionally passed down via BuilderProvider so `build-components`
24
+ * never need to touch `useRenderStore`.
25
+ */
26
+ appConfig?: AppConfig;
27
+ projectColors?: ProjectColors;
28
+ fonts?: Fonts;
29
+ appFont?: string | undefined;
30
+ /**
31
+ * Optional selection info (used by builder UI; ignored by host runtime).
32
+ */
33
+ previewMode?: boolean;
34
+ selectedKey?: string;
18
35
  };
19
36
 
20
37
  type BuilderProviderProps = {
@@ -42,12 +59,33 @@ export function BuilderProvider({ params, children }: BuilderProviderProps) {
42
59
  typeof params?.onPaywallSubscribe === 'function'
43
60
  ? params.onPaywallSubscribe
44
61
  : undefined,
62
+ appConfig:
63
+ params?.appConfig && typeof params.appConfig === 'object'
64
+ ? (params.appConfig as AppConfig)
65
+ : undefined,
66
+ projectColors:
67
+ params?.projectColors && typeof params.projectColors === 'object'
68
+ ? (params.projectColors as ProjectColors)
69
+ : undefined,
70
+ fonts: Array.isArray(params?.fonts) ? (params.fonts as Fonts) : undefined,
71
+ appFont: params?.appFont,
72
+ previewMode: !!params?.previewMode,
73
+ selectedKey:
74
+ typeof params?.selectedKey === 'string'
75
+ ? params.selectedKey
76
+ : undefined,
45
77
  }),
46
78
  [
47
79
  params?.benefits,
48
80
  params?.products,
49
81
  params?.onPaywallClose,
50
82
  params?.onPaywallSubscribe,
83
+ params?.appConfig,
84
+ params?.projectColors,
85
+ params?.fonts,
86
+ params?.appFont,
87
+ params?.previewMode,
88
+ params?.selectedKey,
51
89
  ],
52
90
  );
53
91
 
@@ -0,0 +1,26 @@
1
+ import { useMemo } from 'react';
2
+ import type { NodeData } from '../types/Node';
3
+ import type { TextPropsGenerated } from '../build-components/Text/TextProps.generated';
4
+ import { defaultAppConfig } from '../types/PreviewConfig';
5
+ import { useBuilderParams } from '../components/BuilderProvider';
6
+ import { extractTextStyle } from '../utils/extractTextStyle';
7
+
8
+ export function useExtractTextStyle<T extends TextPropsGenerated['attributes']>(
9
+ node: NodeData<T>,
10
+ ) {
11
+ const {
12
+ appConfig: builderAppConfig,
13
+ projectColors: builderProjectColors,
14
+ fonts: builderFonts,
15
+ } = useBuilderParams();
16
+
17
+ const appConfig = builderAppConfig ?? defaultAppConfig;
18
+ const projectColors = builderProjectColors;
19
+ const fonts = builderFonts;
20
+
21
+ return useMemo(
22
+ () => extractTextStyle(node, { appConfig, projectColors, fonts }),
23
+ // fonts is intentionally included: extractTextStyle resolves weights via font definitions.
24
+ [node, appConfig, projectColors, fonts],
25
+ );
26
+ }
@@ -0,0 +1,19 @@
1
+ import { useMemo } from 'react';
2
+ import type { NodeData } from '../types/Node';
3
+ import type { ViewPropsGenerated } from '../build-components/View/ViewProps.generated';
4
+ import { useBuilderParams } from '../components/BuilderProvider';
5
+ import { extractViewStyle } from '../utils/extractViewStyle';
6
+ import { defaultAppConfig } from '../types/PreviewConfig';
7
+
8
+ export function useExtractViewStyle<T extends ViewPropsGenerated['attributes']>(
9
+ node: NodeData<T>,
10
+ ) {
11
+ const { appConfig, projectColors: builderProjectColors } = useBuilderParams();
12
+ const theme = appConfig?.theme ?? defaultAppConfig.theme;
13
+ const projectColors = builderProjectColors;
14
+
15
+ return useMemo(
16
+ () => extractViewStyle(node, { theme, projectColors }),
17
+ [node, theme, projectColors],
18
+ );
19
+ }
@@ -1,15 +1,16 @@
1
1
  import { useCallback } from 'react';
2
- import { useRenderStore } from '../store';
2
+ import type { AppConfig } from '../types/PreviewConfig';
3
+ import { defaultAppConfig } from '../types/PreviewConfig';
4
+ import { useBuilderParams } from '../components/BuilderProvider';
3
5
  import { useLocalizationParams } from './useLocalizationParams';
4
6
  import { replaceLocalizationParams } from '../utils/replaceLocalizationParams';
5
7
 
6
8
  export type LocalizeFn = (keyOrText: string) => string;
7
9
 
8
- export function useLocalize(): LocalizeFn {
9
- const { defaultLanguage, localication } = useRenderStore((s) => ({
10
- defaultLanguage: s.appConfig?.defaultLanguage,
11
- localication: s.appConfig?.localication,
12
- }));
10
+ export function useLocalize(options?: { appConfig?: AppConfig }): LocalizeFn {
11
+ const { appConfig: builderAppConfig } = useBuilderParams();
12
+ const appConfig = options?.appConfig ?? builderAppConfig ?? defaultAppConfig;
13
+ const { defaultLanguage, localication } = appConfig;
13
14
  const params = useLocalizationParams();
14
15
 
15
16
  return useCallback(
@@ -1,5 +1,5 @@
1
1
  import { useMemo } from 'react';
2
- import { useRenderStore } from '../store';
2
+ import type { Device } from '../types/Device';
3
3
 
4
4
  function addInset(
5
5
  base: React.CSSProperties['paddingTop'],
@@ -28,19 +28,18 @@ function subtractInset(
28
28
  export function useSafeAreaViewStyle(
29
29
  baseStyle: React.CSSProperties,
30
30
  enabled: boolean,
31
+ device?: Device,
31
32
  ) {
32
- const device = useRenderStore((s) => s.device);
33
-
34
33
  return useMemo(() => {
35
34
  if (!enabled) return baseStyle;
36
35
 
37
- const [insetTop, insetRight, insetBottom, insetLeft] = device.insets ?? [
36
+ const [insetTop, insetRight, insetBottom, insetLeft] = device?.insets ?? [
38
37
  0, 0, 0, 0,
39
38
  ];
40
39
 
41
40
  // Match DeviceMockFrame fallbacks: status bar overlays content, so we treat it as top safe area.
42
41
  const top =
43
- insetTop || (device.platform === 'ios' ? 20 : device.platform ? 24 : 0);
42
+ insetTop || (device?.platform === 'ios' ? 20 : device?.platform ? 24 : 0);
44
43
 
45
44
  // Bottom safe area is handled visually by the mock navigation bar area, which takes layout space.
46
45
  // So we intentionally don't add bottom padding here to avoid double-spacing.
@@ -74,6 +74,9 @@ export {
74
74
  getArrayItemType,
75
75
  } from './utils/patterns';
76
76
 
77
+ // Node helpers (RN-safe)
78
+ export { default as useNode } from './build-components/useNode';
79
+
77
80
  // Static sample data helpers (RN-safe)
78
81
  export {
79
82
  getSamples,
package/src/index.ts CHANGED
@@ -1,5 +1,13 @@
1
1
  import './styles/index.scss';
2
2
  import AttributesEditor from './AttributesEditor';
3
+
4
+ // Example app (`example/`) uses these exports today:
5
+ // - `ProjectPage` (from `src/pages/ProjectPage.tsx`)
6
+ // - `getSamples` (from `src/assets/samples/getSamples.ts`)
7
+ // - types from `src/types/*` and `src/types/PreviewConfig.ts` (Project/ProjectColors/AppConfig/defaultAppConfig)
8
+ //
9
+ // React Native: a RN-safe entrypoint exists at `react-builder/native` (`src/index.native.ts`).
10
+ // More RN-focused exports/integration helpers are coming.
3
11
  // NOTE: In React Native, `products` should be sourced from an IAP wrapper (e.g. `react-native-iap`)
4
12
  // and passed into `BuilderProvider` from the host app.
5
13
  export {
@@ -12,6 +20,8 @@ export { RenderErrorBoundary } from './components/RenderErrorBoundary';
12
20
  export { useParams } from './hooks/useParams';
13
21
  export { useLocalizationParams } from './hooks/useLocalizationParams';
14
22
  export { useLocalize } from './hooks/useLocalize';
23
+ export { useExtractTextStyle } from './hooks/useExtractTextStyle';
24
+ export { useExtractViewStyle } from './hooks/useExtractViewStyle';
15
25
 
16
26
  export type { TargetedScreenSize } from './types/TargetedScreenSize';
17
27
  export type { Node, NodeData, NodeDefaultAttribute } from './types/Node';
@@ -25,11 +35,6 @@ export {
25
35
  analyseNode,
26
36
  } from './utils/analyseNode';
27
37
  export { getSamples } from './assets/samples/getSamples';
28
- export { getBasicSamples } from './assets/samples/getSamples';
29
- export { getOnboardSamples } from './assets/samples/getSamples';
30
- export { RenderPage } from './RenderPage';
31
- export { DeviceMockFrame } from './DeviceMockFrame';
32
- export { novaToJson } from './utils/novaToJson';
33
38
  export type { AppConfig, Localication } from './types/PreviewConfig';
34
39
  export { defaultAppConfig } from './types/PreviewConfig';
35
40
  export { getDevices, getDefaultDevice } from './utils/getDevices';
@@ -50,7 +55,6 @@ export {
50
55
  } from './utils/getImage';
51
56
  export { ProjectPage } from './pages/ProjectPage';
52
57
  export type { ProjectPageProps } from './pages/ProjectPage';
53
- export { copyNode } from './utils/copyNode';
54
58
  export { logger } from './utils/logger';
55
59
  export type { LogLevel } from './types/Project';
56
60
  export type {
@@ -59,7 +63,6 @@ export type {
59
63
  Product as PaywallProduct,
60
64
  PaywallModel,
61
65
  } from './paywall/types/paywall-types';
62
-
63
66
  // Paywall hooks
64
67
  export {
65
68
  usePaywallCounter,
@@ -1,6 +1,5 @@
1
1
  import { type ReactNode, useMemo, useState } from 'react';
2
2
  import { RenderPage } from '../RenderPage';
3
- import { BuilderProvider } from '../components/BuilderProvider';
4
3
  import { RenderErrorBoundary } from '../components/RenderErrorBoundary';
5
4
  import type { Node } from '../types/Node';
6
5
  import type { Product } from '../paywall/types/paywall-types';
@@ -267,20 +266,22 @@ export function ProjectDebug({
267
266
  ['--rb-canvas-bg' as any]: canvasBg ?? 'none',
268
267
  }}
269
268
  >
270
- <BuilderProvider params={{ products, benefits }}>
271
- <RenderErrorBoundary
272
- subtitle="caught by ProjectDebug preview"
273
- onError={(e, componentStack) =>
274
- setPreviewError({
275
- message: e?.message ?? String(e),
276
- stack: e?.stack,
277
- componentStack,
278
- })
279
- }
280
- >
281
- <RenderPage data={previewData} name={name} />
282
- </RenderErrorBoundary>
283
- </BuilderProvider>
269
+ <RenderErrorBoundary
270
+ subtitle="caught by ProjectDebug preview"
271
+ onError={(e, componentStack) =>
272
+ setPreviewError({
273
+ message: e?.message ?? String(e),
274
+ stack: e?.stack,
275
+ componentStack,
276
+ })
277
+ }
278
+ >
279
+ <RenderPage
280
+ data={previewData}
281
+ name={name}
282
+ params={{ products, benefits }}
283
+ />
284
+ </RenderErrorBoundary>
284
285
  </section>
285
286
 
286
287
  <section className="rb-project-debug__error" aria-label="Errors">
@@ -5,7 +5,6 @@ import { ToastContainer, toast } from 'react-toastify';
5
5
  import { RenderPage } from '../RenderPage';
6
6
  import { EditorHeader } from '../components/EditorHeader';
7
7
  import { AttributesEditorPanel } from '../components/AttributesEditorPanel';
8
- import { BuilderProvider } from '../components/BuilderProvider';
9
8
  import { BuilderPanel } from './tabs/BuilderPanel';
10
9
  import { BottomBar } from '../components/BottomBar';
11
10
  import { AppConfig, defaultAppConfig } from '../types/PreviewConfig';
@@ -79,6 +78,7 @@ export function ProjectPage({
79
78
  const resolvedProjectColors = projectColors ?? project.projectColors;
80
79
  const isEmptyProjectData =
81
80
  isNodeNullOrUndefined(project.data) || isEmptyObject(project.data);
81
+ // useRenderStore will be removed
82
82
  const {
83
83
  current,
84
84
  setCurrent,
@@ -86,6 +86,7 @@ export function ProjectPage({
86
86
  setProjectName,
87
87
  products,
88
88
  benefits,
89
+ previewMode,
89
90
  } = useRenderStore((s) => ({
90
91
  current: s.current,
91
92
  setCurrent: s.setCurrent,
@@ -93,6 +94,7 @@ export function ProjectPage({
93
94
  setProjectName: s.setProjectName,
94
95
  products: s.products,
95
96
  benefits: s.benefits,
97
+ previewMode: s.previewMode,
96
98
  }));
97
99
  const [editorData, setEditorData] = useState<Node>(() => {
98
100
  if (!isEmptyProjectData) return null;
@@ -462,17 +464,27 @@ export function ProjectPage({
462
464
  )}
463
465
  {/* NOTE: In React Native, `products` should come from an IAP wrapper (e.g. `react-native-iap`). */}
464
466
  {!showLoading && editorData && (
465
- <BuilderProvider
467
+ <RenderPage
468
+ data={editorData}
469
+ name={resolvedName}
466
470
  params={{
467
471
  products,
468
472
  benefits:
469
473
  benefits && typeof benefits === 'object'
470
474
  ? (benefits as PaywallBenefits)
471
475
  : {},
476
+ // Theme/colors/fonts must be passed via BuilderProvider params so build-components never touch useRenderStore.
477
+ appConfig,
478
+ projectColors: resolvedProjectColors,
479
+ fonts: typography.fonts,
480
+ appFont: resolvedAppFont,
481
+ previewMode,
482
+ selectedKey:
483
+ current && typeof current === 'object' && 'key' in current
484
+ ? ((current as any).key as string | undefined)
485
+ : undefined,
472
486
  }}
473
- >
474
- <RenderPage data={editorData} name={resolvedName} />
475
- </BuilderProvider>
487
+ />
476
488
  )}
477
489
  </div>
478
490
  {/* BOTOM BAR */}
package/src/types/Node.ts CHANGED
@@ -10,6 +10,7 @@ export type Node<T = NodeDefaultAttribute> =
10
10
 
11
11
  export interface NodeData<T = Record<string, unknown>> {
12
12
  type: string;
13
+ sourceType?: string;
13
14
  children: Node<Record<string, unknown>>;
14
15
  attributes?: T;
15
16
  key?: string;