@developer_tribe/react-builder 1.0.6 → 1.0.8

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 (63) hide show
  1. package/dist/build-components/patterns.generated.d.ts +56 -56
  2. package/dist/components/AttributesEditorPanel.d.ts +2 -2
  3. package/dist/components/BottomBar.d.ts +6 -2
  4. package/dist/components/Checkbox.d.ts +1 -1
  5. package/dist/index.cjs.js +3 -3
  6. package/dist/index.cjs.js.map +1 -1
  7. package/dist/index.d.ts +2 -1
  8. package/dist/index.esm.js +3 -3
  9. package/dist/index.esm.js.map +1 -1
  10. package/dist/index.native.cjs.js +1 -1
  11. package/dist/index.native.cjs.js.map +1 -1
  12. package/dist/index.native.esm.js +4 -4
  13. package/dist/index.native.esm.js.map +1 -1
  14. package/dist/modals/ScreenColorsModal.d.ts +1 -1
  15. package/dist/pages/ProjectPage.d.ts +3 -2
  16. package/dist/pages/tabs/BuilderPanel.d.ts +2 -2
  17. package/dist/pages/tabs/SideTool.d.ts +8 -0
  18. package/dist/store.d.ts +0 -6
  19. package/dist/styles.css +1 -1
  20. package/package.json +5 -2
  21. package/src/RenderPage.tsx +1 -4
  22. package/src/assets/samples/carousel-sample.json +81 -99
  23. package/src/assets/samples/simple-1.json +2 -8
  24. package/src/assets/samples/simple-2.json +9 -36
  25. package/src/assets/samples/vpn-onboard-1.json +23 -27
  26. package/src/assets/samples/vpn-onboard-2.json +275 -279
  27. package/src/assets/samples/vpn-onboard-3.json +246 -247
  28. package/src/assets/samples/vpn-onboard-4.json +246 -247
  29. package/src/assets/samples/vpn-onboard-5.json +369 -375
  30. package/src/assets/samples/vpn-onboard-6.json +248 -252
  31. package/src/build-components/View/pattern.json +2 -2
  32. package/src/build-components/patterns.generated.ts +56 -56
  33. package/src/components/AttributesEditorPanel.tsx +8 -12
  34. package/src/components/BottomBar.tsx +31 -25
  35. package/src/components/EditorHeader.tsx +4 -11
  36. package/src/index.ts +2 -1
  37. package/src/modals/ScreenColorsModal.tsx +57 -51
  38. package/src/pages/ProjectPage.tsx +147 -48
  39. package/src/pages/tabs/BuilderPanel.tsx +8 -14
  40. package/src/pages/tabs/SideTool.tsx +253 -0
  41. package/src/store.ts +6 -10
  42. package/src/styles/base/_global.scss +29 -32
  43. package/src/styles/components/_attributes-editor.scss +27 -33
  44. package/src/styles/components/_bottom-bar.scss +11 -23
  45. package/src/styles/components/_editor-shell.scss +38 -18
  46. package/src/styles/components/_mockos-router.scss +16 -14
  47. package/src/styles/components/_ui-components.scss +14 -15
  48. package/src/styles/foundation/_colors.scss +28 -8
  49. package/src/styles/foundation/_mixins.scss +1 -1
  50. package/src/styles/foundation/_sizes.scss +4 -2
  51. package/src/styles/layout/_builder.scss +1 -1
  52. package/src/styles/modals/_add-component.scss +2 -2
  53. package/src/styles/modals/_color-modal.scss +2 -2
  54. package/src/styles/modals/_modal-shell.scss +1 -1
  55. package/src/utils/analyseNodeByPatterns.ts +0 -15
  56. package/dist/components/MobilePanelToggleButton.d.ts +0 -8
  57. package/dist/hooks/useMinimumDelay.d.ts +0 -7
  58. package/dist/hooks/useMobileEditorPanels.d.ts +0 -12
  59. package/dist/hooks/useSyncProjectPageStore.d.ts +0 -15
  60. package/src/components/MobilePanelToggleButton.tsx +0 -39
  61. package/src/hooks/useMinimumDelay.ts +0 -20
  62. package/src/hooks/useMobileEditorPanels.ts +0 -56
  63. package/src/hooks/useSyncProjectPageStore.ts +0 -40
@@ -1,90 +1,100 @@
1
- import React from 'react';
1
+ import React, { useMemo } from 'react';
2
2
  import type { AppConfig } from '../types/PreviewConfig';
3
+ import { defaultAppConfig } from '../types/PreviewConfig';
3
4
  import Modal from './Modal';
4
5
 
5
- const screenStyleDefaults = {
6
- light: { backgroundColor: '#FDFDFD', color: '#161827' },
7
- dark: { backgroundColor: '#12131A', color: '#E9EBF9' },
8
- } as const;
6
+ type ScreenMode = 'light' | 'dark';
7
+ type ScreenColorKey = keyof AppConfig['screenStyle']['light'];
9
8
 
10
- type ScreenMode = keyof typeof screenStyleDefaults;
11
- type ScreenColorKey = keyof (typeof screenStyleDefaults)['light'];
9
+ type ScreenColorsModalProps = {
10
+ appConfig: AppConfig;
11
+ onChange: (next: AppConfig) => void;
12
+ onClose: () => void;
13
+ };
12
14
 
13
- const colorFields = [
15
+ type ColorField = {
16
+ id: string;
17
+ label: string;
18
+ mode: ScreenMode;
19
+ key: ScreenColorKey;
20
+ };
21
+
22
+ const colorFields: ColorField[] = [
14
23
  {
15
24
  id: 'light-bg',
16
- label: 'Light Background Color',
17
- mode: 'light' as ScreenMode,
18
- key: 'backgroundColor' as ScreenColorKey,
25
+ label: 'Light Background',
26
+ mode: 'light',
27
+ key: 'backgroundColor',
19
28
  },
20
29
  {
21
30
  id: 'light-color',
22
- label: 'Light Color',
23
- mode: 'light' as ScreenMode,
24
- key: 'color' as ScreenColorKey,
31
+ label: 'Light Text',
32
+ mode: 'light',
33
+ key: 'color',
25
34
  },
26
35
  {
27
36
  id: 'dark-bg',
28
- label: 'Dark Background Color',
29
- mode: 'dark' as ScreenMode,
30
- key: 'backgroundColor' as ScreenColorKey,
37
+ label: 'Dark Background',
38
+ mode: 'dark',
39
+ key: 'backgroundColor',
31
40
  },
32
41
  {
33
42
  id: 'dark-color',
34
- label: 'Dark Color',
35
- mode: 'dark' as ScreenMode,
36
- key: 'color' as ScreenColorKey,
43
+ label: 'Dark Text',
44
+ mode: 'dark',
45
+ key: 'color',
37
46
  },
38
- ] as const;
39
-
40
- type ScreenColorsModalProps = {
41
- appConfig: AppConfig;
42
- onChange: (next: AppConfig) => void;
43
- onClose: () => void;
44
- };
47
+ ];
45
48
 
46
49
  export function ScreenColorsModal({
47
50
  appConfig,
48
51
  onChange,
49
52
  onClose,
50
53
  }: ScreenColorsModalProps) {
51
- const getScreenColorValue = (mode: ScreenMode, key: ScreenColorKey) =>
52
- appConfig.screenStyle?.[mode]?.[key] ?? screenStyleDefaults[mode][key];
54
+ const defaults = defaultAppConfig.screenStyle;
53
55
 
54
- const handleScreenStyleChange = (
55
- mode: ScreenMode,
56
- key: ScreenColorKey,
57
- value: string,
58
- ) => {
56
+ const getValue = (mode: ScreenMode, key: ScreenColorKey) =>
57
+ appConfig.screenStyle?.[mode]?.[key] ?? defaults[mode][key];
58
+
59
+ const handleChange = (mode: ScreenMode, key: ScreenColorKey, value: string) =>
59
60
  onChange({
60
61
  ...appConfig,
61
62
  screenStyle: {
62
- ...screenStyleDefaults,
63
+ ...defaults,
63
64
  ...appConfig.screenStyle,
64
65
  [mode]: {
65
- ...screenStyleDefaults[mode],
66
+ ...defaults[mode],
66
67
  ...appConfig.screenStyle?.[mode],
67
68
  [key]: value,
68
69
  },
69
70
  },
70
71
  });
71
- };
72
+
73
+ const headerDescription = useMemo(
74
+ () =>
75
+ 'Edit light/dark screen background & text colors used in the preview.',
76
+ [],
77
+ );
72
78
 
73
79
  return (
74
80
  <Modal
75
81
  onClose={onClose}
76
- ariaLabelledBy="screen-colors-modal-title"
77
- className="modal--large modal--scrollable"
82
+ ariaLabelledBy="screen-colors-title"
83
+ contentClassName="localication-modal__content"
78
84
  >
79
- <div className="modal__header">
80
- <h3 id="screen-colors-modal-title" className="modal__title">
81
- Screen Colors
82
- </h3>
85
+ <div className="modal__header localication-modal__header">
86
+ <div className="localication-modal__header-main">
87
+ <h3 id="screen-colors-title" className="modal__title">
88
+ Screen Colors
89
+ </h3>
90
+ <p className="localication-modal__description">{headerDescription}</p>
91
+ </div>
83
92
  <button type="button" className="editor-button" onClick={onClose}>
84
93
  Close
85
94
  </button>
86
95
  </div>
87
- <div className="modal__body">
96
+
97
+ <div className="localication-modal__body">
88
98
  <div
89
99
  style={{
90
100
  display: 'grid',
@@ -94,15 +104,13 @@ export function ScreenColorsModal({
94
104
  >
95
105
  {colorFields.map(({ id, label, mode, key }) => (
96
106
  <React.Fragment key={id}>
97
- <div>{label}</div>
107
+ <div style={{ alignSelf: 'center' }}>{label}</div>
98
108
  <input
99
109
  id={id}
100
110
  type="color"
101
111
  className="input input--color"
102
- value={getScreenColorValue(mode, key)}
103
- onChange={(e) =>
104
- handleScreenStyleChange(mode, key, e.target.value)
105
- }
112
+ value={String(getValue(mode, key))}
113
+ onChange={(e) => handleChange(mode, key, e.target.value)}
106
114
  />
107
115
  </React.Fragment>
108
116
  ))}
@@ -111,5 +119,3 @@ export function ScreenColorsModal({
111
119
  </Modal>
112
120
  );
113
121
  }
114
-
115
- export default ScreenColorsModal;
@@ -1,4 +1,4 @@
1
- import { useCallback, useEffect } from 'react';
1
+ import { useCallback, useEffect, useState } from 'react';
2
2
  import type { Node } from '../types/Node';
3
3
  import type { Project, ProjectColors } from '../types/Project';
4
4
  import { RenderPage } from '../RenderPage';
@@ -6,6 +6,7 @@ import { EditorHeader } from '../components/EditorHeader';
6
6
  import { AttributesEditorPanel } from '../components/AttributesEditorPanel';
7
7
  import { BuilderProvider } from '../components/BuilderProvider';
8
8
  import { BuilderPanel } from './tabs/BuilderPanel';
9
+ import { BottomBar } from '../components/BottomBar';
9
10
  import { AppConfig, defaultAppConfig } from '../types/PreviewConfig';
10
11
  import { useRenderStore } from '../store';
11
12
  import { logger } from '../utils/logger';
@@ -15,11 +16,6 @@ import { analyseAndProccess } from '../utils/analyseNode';
15
16
  import backgroundImage from '../assets/images/background.jpg';
16
17
  import type { PaywallBenefits } from '../paywall/types/benefits';
17
18
  import { LoadingComponent } from '../components/LoadingComponent';
18
- import { MobilePanelToggleButton } from '../components/MobilePanelToggleButton';
19
- import { BottomBar } from '../components/BottomBar';
20
- import { useMobileEditorPanels } from '../hooks/useMobileEditorPanels';
21
- import { useSyncProjectPageStore } from '../hooks/useSyncProjectPageStore';
22
- import { useMinimumDelay } from '../hooks/useMinimumDelay';
23
19
  import {
24
20
  deleteNodeFromTree,
25
21
  findNodeByKey,
@@ -32,57 +28,48 @@ export type ProjectPageProps = {
32
28
  appConfig?: AppConfig;
33
29
  logLevel?: LogLevel;
34
30
  projectColors?: ProjectColors;
35
- name: string;
31
+ onSaveProjectColors?: (colors: ProjectColors) => void;
32
+ name?: string;
36
33
  };
37
34
 
35
+ const MOBILE_BREAKPOINT = 1000;
36
+
38
37
  export function ProjectPage({
39
38
  project,
40
39
  appConfig = defaultAppConfig,
41
40
  onSaveProject,
42
41
  logLevel,
43
42
  projectColors,
43
+ onSaveProjectColors,
44
44
  name,
45
45
  }: ProjectPageProps) {
46
46
  useLogRender('ProjectPage');
47
+ const resolvedName = name ?? project.name;
47
48
  const resolvedProjectColors = projectColors ?? project.projectColors;
48
49
  const {
49
50
  current,
50
51
  setCurrent,
51
- setAppConfig,
52
52
  setProjectColors,
53
53
  setProjectName,
54
- editorData,
55
- setEditorData,
56
54
  products,
57
55
  benefits,
58
56
  } = useRenderStore((s) => ({
59
57
  current: s.current,
60
58
  setCurrent: s.setCurrent,
61
- setAppConfig: s.setAppConfig,
62
59
  setProjectColors: s.setProjectColors,
63
60
  setProjectName: s.setProjectName,
64
- editorData: s.editorData,
65
- setEditorData: s.setEditorData,
66
61
  products: s.products,
67
62
  benefits: s.benefits,
68
63
  }));
69
- const minLoadingDelayDone = useMinimumDelay(1000, [project.data]);
70
- const {
71
- isMobile,
72
- mobilePanel,
73
- toggleMobilePanel,
74
- closeMobilePanels,
75
- leftPanelIsOpen,
76
- attributesPanelIsOpen,
77
- } = useMobileEditorPanels();
78
-
79
- useSyncProjectPageStore({
80
- appConfig,
81
- name,
82
- projectColors: resolvedProjectColors,
83
- setAppConfig,
84
- setProjectName,
85
- setProjectColors,
64
+ const [editorData, setEditorData] = useState<Node>(null);
65
+ const [minLoadingDelayDone, setMinLoadingDelayDone] =
66
+ useState<boolean>(false);
67
+ const [mobilePanel, setMobilePanel] = useState<
68
+ 'builder' | 'attributes' | null
69
+ >(null);
70
+ const [isMobile, setIsMobile] = useState<boolean>(() => {
71
+ if (typeof window === 'undefined') return false;
72
+ return window.innerWidth <= MOBILE_BREAKPOINT;
86
73
  });
87
74
 
88
75
  const handleDeleteNode = useCallback(
@@ -94,10 +81,13 @@ export function ProjectPage({
94
81
  );
95
82
  if (!shouldDeleteRoot) return;
96
83
  setEditorData(null);
84
+ setCurrent(null);
97
85
  return;
98
86
  }
99
87
  const updated: Node = deleteNodeFromTree(editorData, nodeToDelete);
88
+ //@ts-ignore
100
89
  setEditorData(updated);
90
+
101
91
  if (current === nodeToDelete) {
102
92
  setCurrent(updated);
103
93
  return;
@@ -118,30 +108,76 @@ export function ProjectPage({
118
108
 
119
109
  useEffect(() => {
120
110
  logger.info('ProjectPage', 'mount', { projectName: project.name });
111
+ useRenderStore.getState().setAppConfig(appConfig);
112
+ logger.verbose('ProjectPage', 'appConfig applied', appConfig);
121
113
  return () => {
122
114
  logger.info('ProjectPage', 'unmount');
123
115
  };
124
- }, [project.name]);
116
+ }, [appConfig, project.name]);
117
+
118
+ useEffect(() => {
119
+ setProjectName(resolvedName);
120
+ }, [resolvedName, setProjectName]);
121
+
122
+ useEffect(() => {
123
+ setProjectColors(resolvedProjectColors);
124
+ return () => setProjectColors(undefined);
125
+ }, [resolvedProjectColors, setProjectColors]);
125
126
 
126
127
  useEffect(() => {
127
128
  if (!logLevel) return;
128
129
  logger.setLevel(logLevel);
129
130
  }, [logLevel]);
130
131
 
132
+ useEffect(() => {
133
+ function handleResize() {
134
+ setIsMobile(window.innerWidth <= MOBILE_BREAKPOINT);
135
+ }
136
+
137
+ handleResize();
138
+ window.addEventListener('resize', handleResize);
139
+ return () => window.removeEventListener('resize', handleResize);
140
+ }, []);
141
+
142
+ useEffect(() => {
143
+ setMobilePanel(null);
144
+ }, [isMobile]);
145
+
146
+ const toggleMobilePanel = (panel: 'builder' | 'attributes') => {
147
+ setMobilePanel((prev) => (prev === panel ? null : panel));
148
+ };
149
+
150
+ const closeMobilePanels = () => {
151
+ setMobilePanel(null);
152
+ };
153
+
154
+ const leftPanelIsOpen = !isMobile || mobilePanel === 'builder';
155
+ const attributesPanelIsOpen = !isMobile || mobilePanel === 'attributes';
156
+
157
+ useEffect(() => {
158
+ setMinLoadingDelayDone(false);
159
+ const timer = setTimeout(() => setMinLoadingDelayDone(true), 1000);
160
+ return () => clearTimeout(timer);
161
+ }, [project.data]);
162
+
131
163
  useEffect(() => {
132
164
  try {
133
165
  // Reset to "loading" immediately on project change so the loader is shown
134
166
  // until a valid node is available (and for at least 2 seconds).
135
167
  setEditorData(null);
168
+ setCurrent(null);
136
169
  const processed = analyseAndProccess(project.data);
137
170
  if (!processed) {
138
171
  setEditorData(null);
172
+ setCurrent(null);
139
173
  return;
140
174
  }
141
175
  setEditorData(processed);
176
+ setCurrent(processed);
142
177
  } catch (error) {
143
178
  console.error(error);
144
179
  setEditorData(null);
180
+ setCurrent(null);
145
181
  }
146
182
  }, [project.data]);
147
183
 
@@ -152,6 +188,9 @@ export function ProjectPage({
152
188
  <EditorHeader
153
189
  onSaveProject={() => {
154
190
  logger.info('ProjectPage', 'save project', { name: project.name });
191
+ if (onSaveProjectColors && resolvedProjectColors) {
192
+ onSaveProjectColors(resolvedProjectColors);
193
+ }
155
194
  onSaveProject({
156
195
  ...project,
157
196
  data: editorData,
@@ -162,6 +201,9 @@ export function ProjectPage({
162
201
  setEditorData(project.data);
163
202
  setCurrent(project.data);
164
203
  }}
204
+ current={current}
205
+ editorData={editorData}
206
+ setEditorData={setEditorData}
165
207
  />
166
208
  {isMobile && (
167
209
  <div
@@ -169,20 +211,48 @@ export function ProjectPage({
169
211
  role="group"
170
212
  aria-label="Editor panels"
171
213
  >
172
- <MobilePanelToggleButton
173
- label="Builder"
174
- isActive={mobilePanel === 'builder'}
175
- ariaLabel="Toggle builder panel"
176
- ariaControls="split-left-panel"
214
+ <button
215
+ type="button"
216
+ className={`mobile-panel-toggle__button${mobilePanel === 'builder' ? ' mobile-panel-toggle__button--active' : ''}`}
217
+ aria-label="Toggle builder panel"
218
+ aria-expanded={mobilePanel === 'builder'}
219
+ aria-controls="split-left-panel"
177
220
  onClick={() => toggleMobilePanel('builder')}
178
- />
179
- <MobilePanelToggleButton
180
- label="Attributes"
181
- isActive={mobilePanel === 'attributes'}
182
- ariaLabel="Toggle attributes panel"
183
- ariaControls="split-attributes-panel"
221
+ >
222
+ <span className="mobile-panel-toggle__icon" aria-hidden="true">
223
+ <svg viewBox="0 0 16 12" role="presentation" focusable="false">
224
+ <path
225
+ d="M1 1h14M1 6h14M1 11h14"
226
+ stroke="currentColor"
227
+ strokeWidth="2"
228
+ strokeLinecap="round"
229
+ fill="none"
230
+ />
231
+ </svg>
232
+ </span>
233
+ <span className="mobile-panel-toggle__label">Builder</span>
234
+ </button>
235
+ <button
236
+ type="button"
237
+ className={`mobile-panel-toggle__button${mobilePanel === 'attributes' ? ' mobile-panel-toggle__button--active' : ''}`}
238
+ aria-label="Toggle attributes panel"
239
+ aria-expanded={mobilePanel === 'attributes'}
240
+ aria-controls="split-attributes-panel"
184
241
  onClick={() => toggleMobilePanel('attributes')}
185
- />
242
+ >
243
+ <span className="mobile-panel-toggle__icon" aria-hidden="true">
244
+ <svg viewBox="0 0 16 12" role="presentation" focusable="false">
245
+ <path
246
+ d="M1 1h14M1 6h14M1 11h14"
247
+ stroke="currentColor"
248
+ strokeWidth="2"
249
+ strokeLinecap="round"
250
+ fill="none"
251
+ />
252
+ </svg>
253
+ </span>
254
+ <span className="mobile-panel-toggle__label">Attributes</span>
255
+ </button>
186
256
  </div>
187
257
  )}
188
258
  <div className="editor-container">
@@ -202,11 +272,19 @@ export function ProjectPage({
202
272
  </button>
203
273
  )}
204
274
  <div>
205
- <BuilderPanel onDeleteNode={handleDeleteNode} />
275
+ <BuilderPanel
276
+ data={editorData}
277
+ setData={setEditorData}
278
+ onDeleteNode={handleDeleteNode}
279
+ />
206
280
  </div>
207
281
  </div>
208
282
  <div
209
- style={{ backgroundImage: `url(${backgroundImage})` }}
283
+ style={{
284
+ // Set as a CSS variable so `.dark .split-right` can override it.
285
+ // eslint-disable-next-line @typescript-eslint/naming-convention
286
+ ['--rb-canvas-bg' as any]: `url(${backgroundImage})`,
287
+ }}
210
288
  className="split-right"
211
289
  >
212
290
  {showLoading && (
@@ -225,11 +303,12 @@ export function ProjectPage({
225
303
  : {},
226
304
  }}
227
305
  >
228
- <RenderPage data={editorData} name={project.name} />
229
- <BottomBar />
306
+ <RenderPage data={editorData} name={resolvedName} />
230
307
  </BuilderProvider>
231
308
  )}
232
309
  </div>
310
+ {/* BOTOM BAR */}
311
+ <BottomBar data={editorData} setData={setEditorData} />
233
312
  <div
234
313
  id="split-attributes-panel"
235
314
  className={`split-third${attributesPanelIsOpen ? ' is-open' : ''}`}
@@ -245,7 +324,27 @@ export function ProjectPage({
245
324
  Close
246
325
  </button>
247
326
  )}
248
- <AttributesEditorPanel projectColors={resolvedProjectColors} />
327
+ <AttributesEditorPanel
328
+ attributes={editorData}
329
+ projectColors={resolvedProjectColors}
330
+ onChange={(data) => {
331
+ setEditorData(data);
332
+ let nodeKey: string | undefined = undefined;
333
+ if (
334
+ data &&
335
+ typeof data === 'object' &&
336
+ !Array.isArray(data) &&
337
+ 'key' in (data as any)
338
+ ) {
339
+ nodeKey = (data as any).key as string | undefined;
340
+ }
341
+ logger.verbose(
342
+ 'ProjectPage',
343
+ 'attributes change',
344
+ nodeKey ? { nodeKey } : undefined,
345
+ );
346
+ }}
347
+ />
249
348
  </div>
250
349
  {isMobile && mobilePanel && (
251
350
  <button
@@ -4,8 +4,8 @@ import { Builder } from '../../components/Builder';
4
4
  import { useRenderStore } from '../../store';
5
5
 
6
6
  type BuilderPanelProps = {
7
- data?: Node;
8
- setData?: (data: Node) => void;
7
+ data: Node;
8
+ setData: (data: Node) => void;
9
9
  onDeleteNode: (node: Node) => void;
10
10
  };
11
11
 
@@ -15,16 +15,10 @@ export function BuilderPanel({
15
15
  onDeleteNode,
16
16
  }: BuilderPanelProps) {
17
17
  useLogRender('BuilderPanel');
18
- const { current, setCurrent, editorData, setEditorData } = useRenderStore(
19
- (s) => ({
20
- current: s.current,
21
- setCurrent: s.setCurrent,
22
- editorData: s.editorData,
23
- setEditorData: s.setEditorData,
24
- }),
25
- );
26
- const effectiveData = data ?? editorData;
27
- const effectiveSetData = setData ?? setEditorData;
18
+ const { current, setCurrent } = useRenderStore((s) => ({
19
+ current: s.current,
20
+ setCurrent: s.setCurrent,
21
+ }));
28
22
  return (
29
23
  <div
30
24
  role="region"
@@ -32,8 +26,8 @@ export function BuilderPanel({
32
26
  aria-hidden={false}
33
27
  >
34
28
  <Builder
35
- data={effectiveData}
36
- setData={effectiveSetData}
29
+ data={data}
30
+ setData={setData}
37
31
  current={current}
38
32
  setCurrent={setCurrent}
39
33
  onDeleteNode={onDeleteNode}