@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.
- package/dist/build-components/patterns.generated.d.ts +56 -56
- package/dist/components/AttributesEditorPanel.d.ts +2 -2
- package/dist/components/BottomBar.d.ts +6 -2
- package/dist/components/Checkbox.d.ts +1 -1
- package/dist/index.cjs.js +3 -3
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.esm.js +3 -3
- package/dist/index.esm.js.map +1 -1
- package/dist/index.native.cjs.js +1 -1
- package/dist/index.native.cjs.js.map +1 -1
- package/dist/index.native.esm.js +4 -4
- package/dist/index.native.esm.js.map +1 -1
- package/dist/modals/ScreenColorsModal.d.ts +1 -1
- package/dist/pages/ProjectPage.d.ts +3 -2
- package/dist/pages/tabs/BuilderPanel.d.ts +2 -2
- package/dist/pages/tabs/SideTool.d.ts +8 -0
- package/dist/store.d.ts +0 -6
- package/dist/styles.css +1 -1
- package/package.json +5 -2
- package/src/RenderPage.tsx +1 -4
- package/src/assets/samples/carousel-sample.json +81 -99
- package/src/assets/samples/simple-1.json +2 -8
- package/src/assets/samples/simple-2.json +9 -36
- package/src/assets/samples/vpn-onboard-1.json +23 -27
- package/src/assets/samples/vpn-onboard-2.json +275 -279
- package/src/assets/samples/vpn-onboard-3.json +246 -247
- package/src/assets/samples/vpn-onboard-4.json +246 -247
- package/src/assets/samples/vpn-onboard-5.json +369 -375
- package/src/assets/samples/vpn-onboard-6.json +248 -252
- package/src/build-components/View/pattern.json +2 -2
- package/src/build-components/patterns.generated.ts +56 -56
- package/src/components/AttributesEditorPanel.tsx +8 -12
- package/src/components/BottomBar.tsx +31 -25
- package/src/components/EditorHeader.tsx +4 -11
- package/src/index.ts +2 -1
- package/src/modals/ScreenColorsModal.tsx +57 -51
- package/src/pages/ProjectPage.tsx +147 -48
- package/src/pages/tabs/BuilderPanel.tsx +8 -14
- package/src/pages/tabs/SideTool.tsx +253 -0
- package/src/store.ts +6 -10
- package/src/styles/base/_global.scss +29 -32
- package/src/styles/components/_attributes-editor.scss +27 -33
- package/src/styles/components/_bottom-bar.scss +11 -23
- package/src/styles/components/_editor-shell.scss +38 -18
- package/src/styles/components/_mockos-router.scss +16 -14
- package/src/styles/components/_ui-components.scss +14 -15
- package/src/styles/foundation/_colors.scss +28 -8
- package/src/styles/foundation/_mixins.scss +1 -1
- package/src/styles/foundation/_sizes.scss +4 -2
- package/src/styles/layout/_builder.scss +1 -1
- package/src/styles/modals/_add-component.scss +2 -2
- package/src/styles/modals/_color-modal.scss +2 -2
- package/src/styles/modals/_modal-shell.scss +1 -1
- package/src/utils/analyseNodeByPatterns.ts +0 -15
- package/dist/components/MobilePanelToggleButton.d.ts +0 -8
- package/dist/hooks/useMinimumDelay.d.ts +0 -7
- package/dist/hooks/useMobileEditorPanels.d.ts +0 -12
- package/dist/hooks/useSyncProjectPageStore.d.ts +0 -15
- package/src/components/MobilePanelToggleButton.tsx +0 -39
- package/src/hooks/useMinimumDelay.ts +0 -20
- package/src/hooks/useMobileEditorPanels.ts +0 -56
- 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
|
-
|
|
6
|
-
|
|
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
|
|
11
|
-
|
|
9
|
+
type ScreenColorsModalProps = {
|
|
10
|
+
appConfig: AppConfig;
|
|
11
|
+
onChange: (next: AppConfig) => void;
|
|
12
|
+
onClose: () => void;
|
|
13
|
+
};
|
|
12
14
|
|
|
13
|
-
|
|
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
|
|
17
|
-
mode: 'light'
|
|
18
|
-
key: 'backgroundColor'
|
|
25
|
+
label: 'Light Background',
|
|
26
|
+
mode: 'light',
|
|
27
|
+
key: 'backgroundColor',
|
|
19
28
|
},
|
|
20
29
|
{
|
|
21
30
|
id: 'light-color',
|
|
22
|
-
label: 'Light
|
|
23
|
-
mode: 'light'
|
|
24
|
-
key: 'color'
|
|
31
|
+
label: 'Light Text',
|
|
32
|
+
mode: 'light',
|
|
33
|
+
key: 'color',
|
|
25
34
|
},
|
|
26
35
|
{
|
|
27
36
|
id: 'dark-bg',
|
|
28
|
-
label: 'Dark Background
|
|
29
|
-
mode: 'dark'
|
|
30
|
-
key: 'backgroundColor'
|
|
37
|
+
label: 'Dark Background',
|
|
38
|
+
mode: 'dark',
|
|
39
|
+
key: 'backgroundColor',
|
|
31
40
|
},
|
|
32
41
|
{
|
|
33
42
|
id: 'dark-color',
|
|
34
|
-
label: 'Dark
|
|
35
|
-
mode: 'dark'
|
|
36
|
-
key: 'color'
|
|
43
|
+
label: 'Dark Text',
|
|
44
|
+
mode: 'dark',
|
|
45
|
+
key: 'color',
|
|
37
46
|
},
|
|
38
|
-
]
|
|
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
|
|
52
|
-
appConfig.screenStyle?.[mode]?.[key] ?? screenStyleDefaults[mode][key];
|
|
54
|
+
const defaults = defaultAppConfig.screenStyle;
|
|
53
55
|
|
|
54
|
-
const
|
|
55
|
-
mode
|
|
56
|
-
|
|
57
|
-
|
|
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
|
-
...
|
|
63
|
+
...defaults,
|
|
63
64
|
...appConfig.screenStyle,
|
|
64
65
|
[mode]: {
|
|
65
|
-
...
|
|
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-
|
|
77
|
-
|
|
82
|
+
ariaLabelledBy="screen-colors-title"
|
|
83
|
+
contentClassName="localication-modal__content"
|
|
78
84
|
>
|
|
79
|
-
<div className="modal__header">
|
|
80
|
-
<
|
|
81
|
-
|
|
82
|
-
|
|
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
|
-
|
|
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={
|
|
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
|
-
|
|
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
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
-
<
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
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
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
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
|
|
275
|
+
<BuilderPanel
|
|
276
|
+
data={editorData}
|
|
277
|
+
setData={setEditorData}
|
|
278
|
+
onDeleteNode={handleDeleteNode}
|
|
279
|
+
/>
|
|
206
280
|
</div>
|
|
207
281
|
</div>
|
|
208
282
|
<div
|
|
209
|
-
style={{
|
|
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={
|
|
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
|
|
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
|
|
8
|
-
setData
|
|
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
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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={
|
|
36
|
-
setData={
|
|
29
|
+
data={data}
|
|
30
|
+
setData={setData}
|
|
37
31
|
current={current}
|
|
38
32
|
setCurrent={setCurrent}
|
|
39
33
|
onDeleteNode={onDeleteNode}
|