@developer_tribe/react-builder 1.2.12 → 1.2.13
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/PaywallBackground/PaywallBackgroundProps.generated.d.ts +3 -0
- package/dist/build-components/patterns.generated.d.ts +5289 -1965
- package/dist/components/BottomBar.d.ts +3 -1
- package/dist/index.cjs.js +4 -4
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +4 -4
- package/dist/index.esm.js.map +1 -1
- package/dist/index.web.cjs.js +5 -5
- package/dist/index.web.cjs.js.map +1 -1
- package/dist/index.web.d.ts +1 -0
- package/dist/index.web.esm.js +5 -5
- package/dist/index.web.esm.js.map +1 -1
- package/dist/pages/DebugJsonPage.d.ts +17 -0
- package/dist/pages/projectPageUtils.d.ts +7 -0
- package/dist/styles.css +1 -1
- package/dist/utils/logRenderStore.d.ts +6 -0
- package/package.json +2 -1
- package/scripts/prebuild/utils/validateAllComponentsOrThrow.js +28 -11
- package/src/AttributesEditor.tsx +1 -0
- package/src/assets/meta.json +1 -1
- package/src/assets/samples/paywall-1.json +159 -150
- package/src/assets/samples/simple-1.json +3 -3
- package/src/build-components/BackgroundImage/BackgroundImage.tsx +1 -1
- package/src/build-components/BackgroundImage/pattern.json +12 -0
- package/src/build-components/PaywallBackground/PaywallBackground.tsx +3 -33
- package/src/build-components/PaywallBackground/PaywallBackgroundProps.generated.ts +3 -0
- package/src/build-components/PaywallBackground/pattern.json +15 -5
- package/src/build-components/Text/pattern.json +39 -38
- package/src/build-components/patterns.generated.ts +5289 -1951
- package/src/components/BottomBar.tsx +21 -60
- package/src/index.web.ts +1 -0
- package/src/pages/DebugJsonPage.tsx +135 -0
- package/src/pages/ProjectPage.tsx +17 -5
- package/src/pages/projectPageUtils.ts +14 -0
- package/src/pages/tabs/SideTool.tsx +8 -23
- package/src/styles/modals/_localication-modal.scss +6 -0
- package/src/utils/logRenderStore.ts +128 -0
- package/src/utils/patterns.ts +26 -3
|
@@ -2,23 +2,28 @@ import React, { useMemo, useState } from 'react';
|
|
|
2
2
|
import { Icon } from './Icon.generated';
|
|
3
3
|
import type { IconsType } from '../types/Icons';
|
|
4
4
|
import { useRenderStore } from '../store';
|
|
5
|
-
import { Checkbox } from './Checkbox';
|
|
6
5
|
import type { Localication } from '../types/PreviewConfig';
|
|
7
6
|
import { LocalicationModal, Modal, ScreenColorsModal } from '../modals';
|
|
8
|
-
import { JsonTextEditor } from './JsonTextEditor';
|
|
9
7
|
import type { Node } from '../types/Node';
|
|
10
|
-
import {
|
|
8
|
+
import type { Project } from '../types/Project';
|
|
9
|
+
import { DebugJsonPage } from '../pages/DebugJsonPage';
|
|
11
10
|
|
|
12
11
|
type BottomBarProps = {
|
|
13
12
|
className?: string;
|
|
14
13
|
data: Node;
|
|
15
14
|
setData: React.Dispatch<React.SetStateAction<Node>>;
|
|
15
|
+
project?: Project;
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Bottom tool bar (Figma-like).
|
|
20
20
|
*/
|
|
21
|
-
export function BottomBar({
|
|
21
|
+
export function BottomBar({
|
|
22
|
+
className,
|
|
23
|
+
data,
|
|
24
|
+
setData,
|
|
25
|
+
project,
|
|
26
|
+
}: BottomBarProps) {
|
|
22
27
|
const rtlIcon: IconsType = 'translate';
|
|
23
28
|
const magicCursorIcon: IconsType = 'magicpen';
|
|
24
29
|
const debugIcon: IconsType = 'speedometer-03';
|
|
@@ -179,62 +184,18 @@ export function BottomBar({ className, data, setData }: BottomBarProps) {
|
|
|
179
184
|
className="modal--large modal--scrollable"
|
|
180
185
|
contentClassName="localication-modal__content"
|
|
181
186
|
>
|
|
182
|
-
<
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
onClick={() => setIsDebugOpen(false)}
|
|
195
|
-
>
|
|
196
|
-
Close
|
|
197
|
-
</button>
|
|
198
|
-
</div>
|
|
199
|
-
<div className="localication-modal__body">
|
|
200
|
-
<div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
|
|
201
|
-
<Checkbox
|
|
202
|
-
label="Preview mode"
|
|
203
|
-
checked={previewMode}
|
|
204
|
-
onChange={setPreviewMode}
|
|
205
|
-
/>
|
|
206
|
-
<Checkbox
|
|
207
|
-
label="Dark Mode"
|
|
208
|
-
checked={appConfig.theme === 'dark'}
|
|
209
|
-
onChange={(checked) =>
|
|
210
|
-
setAppConfig({
|
|
211
|
-
...appConfig,
|
|
212
|
-
theme: checked ? 'dark' : 'light',
|
|
213
|
-
})
|
|
214
|
-
}
|
|
215
|
-
/>
|
|
216
|
-
<Checkbox
|
|
217
|
-
label="Is RTL"
|
|
218
|
-
checked={appConfig.isRtl ?? false}
|
|
219
|
-
onChange={(checked) =>
|
|
220
|
-
setAppConfig({ ...appConfig, isRtl: checked })
|
|
221
|
-
}
|
|
222
|
-
/>
|
|
223
|
-
</div>
|
|
224
|
-
<div
|
|
225
|
-
className="localication-modal__editor"
|
|
226
|
-
style={{ marginTop: 12 }}
|
|
227
|
-
>
|
|
228
|
-
<JsonTextEditor
|
|
229
|
-
rootName="node"
|
|
230
|
-
value={data ?? {}}
|
|
231
|
-
onChange={(next) =>
|
|
232
|
-
setData(analyseAndProccess(next as Node) as Node)
|
|
233
|
-
}
|
|
234
|
-
className="localication-modal__json-editor"
|
|
235
|
-
/>
|
|
236
|
-
</div>
|
|
237
|
-
</div>
|
|
187
|
+
<DebugJsonPage
|
|
188
|
+
project={project}
|
|
189
|
+
data={data}
|
|
190
|
+
setData={setData}
|
|
191
|
+
onClose={() => setIsDebugOpen(false)}
|
|
192
|
+
description="Inspect and edit raw node JSON."
|
|
193
|
+
previewMode={previewMode}
|
|
194
|
+
setPreviewMode={setPreviewMode}
|
|
195
|
+
appConfig={appConfig}
|
|
196
|
+
setAppConfig={setAppConfig}
|
|
197
|
+
logLabel="BottomBar Debug JSON"
|
|
198
|
+
/>
|
|
238
199
|
</Modal>
|
|
239
200
|
)}
|
|
240
201
|
</>
|
package/src/index.web.ts
CHANGED
|
@@ -2,6 +2,7 @@ import './styles/index.scss';
|
|
|
2
2
|
|
|
3
3
|
// Web entrypoint.
|
|
4
4
|
export { ProjectPage } from './pages/ProjectPage';
|
|
5
|
+
export { DebugJsonPage } from './pages/DebugJsonPage';
|
|
5
6
|
|
|
6
7
|
// Re-export the RN-safe/root entry so `react-builder/web` can also access shared APIs.
|
|
7
8
|
export * from './index';
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { Node } from '../types/Node';
|
|
3
|
+
import type { AppConfig } from '../types/PreviewConfig';
|
|
4
|
+
import { Checkbox } from '../components/Checkbox';
|
|
5
|
+
import { JsonTextEditor } from '../components/JsonTextEditor';
|
|
6
|
+
import { analyseAndProccess } from '../utils/analyseNode';
|
|
7
|
+
import { logRenderStore } from '../utils/logRenderStore';
|
|
8
|
+
|
|
9
|
+
export type DebugJsonPageProps = {
|
|
10
|
+
data: Node | null | undefined;
|
|
11
|
+
setData: React.Dispatch<React.SetStateAction<Node>>;
|
|
12
|
+
project?: unknown;
|
|
13
|
+
onClose?: () => void;
|
|
14
|
+
title?: string;
|
|
15
|
+
description?: string;
|
|
16
|
+
|
|
17
|
+
previewMode?: boolean;
|
|
18
|
+
setPreviewMode?: (next: boolean) => void;
|
|
19
|
+
|
|
20
|
+
appConfig?: AppConfig;
|
|
21
|
+
setAppConfig?: (next: AppConfig) => void;
|
|
22
|
+
|
|
23
|
+
logLabel?: string;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export function DebugJsonPage({
|
|
27
|
+
data,
|
|
28
|
+
setData,
|
|
29
|
+
project,
|
|
30
|
+
onClose,
|
|
31
|
+
title = 'Debug JSON',
|
|
32
|
+
description,
|
|
33
|
+
previewMode,
|
|
34
|
+
setPreviewMode,
|
|
35
|
+
appConfig,
|
|
36
|
+
setAppConfig,
|
|
37
|
+
logLabel,
|
|
38
|
+
}: DebugJsonPageProps) {
|
|
39
|
+
const canTogglePreviewMode = typeof setPreviewMode === 'function';
|
|
40
|
+
const canToggleTheme =
|
|
41
|
+
typeof setAppConfig === 'function' && typeof appConfig?.theme === 'string';
|
|
42
|
+
const canToggleRtl =
|
|
43
|
+
typeof setAppConfig === 'function' &&
|
|
44
|
+
typeof (appConfig as any)?.isRtl !== 'undefined';
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<>
|
|
48
|
+
<div className="modal__header localication-modal__header">
|
|
49
|
+
<div className="localication-modal__header-main">
|
|
50
|
+
<h3 id="debug-json-editor-title" className="modal__title">
|
|
51
|
+
{title}
|
|
52
|
+
</h3>
|
|
53
|
+
{description ? (
|
|
54
|
+
<p className="localication-modal__description">{description}</p>
|
|
55
|
+
) : null}
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<button
|
|
59
|
+
type="button"
|
|
60
|
+
className="editor-button"
|
|
61
|
+
title="Log render store to console"
|
|
62
|
+
onClick={() =>
|
|
63
|
+
logRenderStore({
|
|
64
|
+
label: logLabel,
|
|
65
|
+
extra: {
|
|
66
|
+
project: project ?? null,
|
|
67
|
+
projectData: data ?? null,
|
|
68
|
+
},
|
|
69
|
+
})
|
|
70
|
+
}
|
|
71
|
+
>
|
|
72
|
+
Log store
|
|
73
|
+
</button>
|
|
74
|
+
|
|
75
|
+
{onClose ? (
|
|
76
|
+
<button
|
|
77
|
+
type="button"
|
|
78
|
+
className="editor-button"
|
|
79
|
+
onClick={() => onClose()}
|
|
80
|
+
>
|
|
81
|
+
Close
|
|
82
|
+
</button>
|
|
83
|
+
) : null}
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
<div className="localication-modal__body">
|
|
87
|
+
{canTogglePreviewMode || canToggleTheme || canToggleRtl ? (
|
|
88
|
+
<div className="localication-modal__controls">
|
|
89
|
+
{canTogglePreviewMode ? (
|
|
90
|
+
<Checkbox
|
|
91
|
+
label="Preview mode"
|
|
92
|
+
checked={Boolean(previewMode)}
|
|
93
|
+
onChange={setPreviewMode!}
|
|
94
|
+
/>
|
|
95
|
+
) : null}
|
|
96
|
+
|
|
97
|
+
{canToggleTheme ? (
|
|
98
|
+
<Checkbox
|
|
99
|
+
label="Dark Mode"
|
|
100
|
+
checked={(appConfig?.theme ?? 'light') === 'dark'}
|
|
101
|
+
onChange={(checked) =>
|
|
102
|
+
setAppConfig!({
|
|
103
|
+
...(appConfig as AppConfig),
|
|
104
|
+
theme: checked ? 'dark' : 'light',
|
|
105
|
+
})
|
|
106
|
+
}
|
|
107
|
+
/>
|
|
108
|
+
) : null}
|
|
109
|
+
|
|
110
|
+
{canToggleRtl ? (
|
|
111
|
+
<Checkbox
|
|
112
|
+
label="Is RTL"
|
|
113
|
+
checked={Boolean((appConfig as any)?.isRtl)}
|
|
114
|
+
onChange={(checked) =>
|
|
115
|
+
setAppConfig!({ ...(appConfig as AppConfig), isRtl: checked })
|
|
116
|
+
}
|
|
117
|
+
/>
|
|
118
|
+
) : null}
|
|
119
|
+
</div>
|
|
120
|
+
) : null}
|
|
121
|
+
|
|
122
|
+
<div className="localication-modal__editor">
|
|
123
|
+
<JsonTextEditor
|
|
124
|
+
rootName="node"
|
|
125
|
+
value={data ?? ({} as any)}
|
|
126
|
+
onChange={(next) =>
|
|
127
|
+
setData(analyseAndProccess(next as Node) as Node)
|
|
128
|
+
}
|
|
129
|
+
className="localication-modal__json-editor"
|
|
130
|
+
/>
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
</>
|
|
134
|
+
);
|
|
135
|
+
}
|
|
@@ -35,6 +35,7 @@ import {
|
|
|
35
35
|
} from '../utils/nodeTree';
|
|
36
36
|
import type { Fonts } from '../types/Fonts';
|
|
37
37
|
import { useProjectFonts } from '../hooks/useProjectFonts';
|
|
38
|
+
import { resolveProjectForSave } from './projectPageUtils';
|
|
38
39
|
export type ProjectPageProps = {
|
|
39
40
|
project: Project;
|
|
40
41
|
onSaveProject: (project: Project) => void;
|
|
@@ -101,6 +102,7 @@ export function ProjectPage({
|
|
|
101
102
|
previewMode: s.previewMode,
|
|
102
103
|
}));
|
|
103
104
|
const resolvedAppConfig = appConfig ?? storeAppConfig ?? defaultAppConfig;
|
|
105
|
+
const [overrideProject, setOverrideProject] = useState<Project | null>(null);
|
|
104
106
|
const [editorData, setEditorData] = useState<Node>(() => {
|
|
105
107
|
if (!isEmptyProjectData) return null;
|
|
106
108
|
// Empty project should start in a usable state (no loader / no error).
|
|
@@ -161,6 +163,7 @@ export function ProjectPage({
|
|
|
161
163
|
|
|
162
164
|
useEffect(() => {
|
|
163
165
|
logger.info('ProjectPage', 'mount', { projectName: project.name });
|
|
166
|
+
setOverrideProject(null);
|
|
164
167
|
if (appConfig) {
|
|
165
168
|
setAppConfig(appConfig);
|
|
166
169
|
logger.verbose('ProjectPage', 'appConfig applied', appConfig);
|
|
@@ -290,10 +293,13 @@ export function ProjectPage({
|
|
|
290
293
|
if (onSaveProjectColors && resolvedProjectColors) {
|
|
291
294
|
onSaveProjectColors(resolvedProjectColors);
|
|
292
295
|
}
|
|
293
|
-
onSaveProject(
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
296
|
+
onSaveProject(
|
|
297
|
+
resolveProjectForSave({
|
|
298
|
+
project,
|
|
299
|
+
overrideProject,
|
|
300
|
+
data: editorData,
|
|
301
|
+
}),
|
|
302
|
+
);
|
|
297
303
|
toast.success('Saved');
|
|
298
304
|
} catch (e) {
|
|
299
305
|
logger.error('ProjectPage', 'save project failed', e);
|
|
@@ -302,6 +308,7 @@ export function ProjectPage({
|
|
|
302
308
|
}}
|
|
303
309
|
onRestoreProject={() => {
|
|
304
310
|
logger.info('ProjectPage', 'restore project', { name: project.name });
|
|
311
|
+
setOverrideProject(null);
|
|
305
312
|
setValidationError(null);
|
|
306
313
|
setValidationErrorStack(null);
|
|
307
314
|
setBypassValidation(false);
|
|
@@ -341,6 +348,7 @@ export function ProjectPage({
|
|
|
341
348
|
const { project: migratedProject } =
|
|
342
349
|
runProjectMigrations(project);
|
|
343
350
|
onSaveProject(migratedProject);
|
|
351
|
+
setOverrideProject(migratedProject);
|
|
344
352
|
setBypassValidation(true);
|
|
345
353
|
setMigrationGate(null);
|
|
346
354
|
setEditorData(migratedProject.data as unknown as Node);
|
|
@@ -494,7 +502,11 @@ export function ProjectPage({
|
|
|
494
502
|
)}
|
|
495
503
|
</div>
|
|
496
504
|
{/* BOTOM BAR */}
|
|
497
|
-
<BottomBar
|
|
505
|
+
<BottomBar
|
|
506
|
+
project={project}
|
|
507
|
+
data={editorData}
|
|
508
|
+
setData={setEditorData}
|
|
509
|
+
/>
|
|
498
510
|
<div
|
|
499
511
|
id="split-attributes-panel"
|
|
500
512
|
className={`split-third${attributesPanelIsOpen ? ' is-open' : ''}`}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Project } from '../types/Project';
|
|
2
|
+
import type { Node } from '../types/Node';
|
|
3
|
+
|
|
4
|
+
export function resolveProjectForSave(args: {
|
|
5
|
+
project: Project;
|
|
6
|
+
overrideProject?: Project | null;
|
|
7
|
+
data: Node;
|
|
8
|
+
}): Project {
|
|
9
|
+
const base = args.overrideProject ?? args.project;
|
|
10
|
+
return {
|
|
11
|
+
...base,
|
|
12
|
+
data: args.data,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import React, { useEffect, useState } from 'react';
|
|
2
|
-
import { JsonTextEditor } from '../../components/JsonTextEditor';
|
|
3
2
|
import { Modal } from '../../modals';
|
|
4
3
|
import type { Node } from '../../types/Node';
|
|
5
4
|
import type { Localication } from '../../types/PreviewConfig';
|
|
@@ -7,7 +6,7 @@ import { useLogRender } from '../../utils/useLogRender';
|
|
|
7
6
|
import { useRenderStore } from '../../store';
|
|
8
7
|
import { Checkbox } from '../../components/Checkbox';
|
|
9
8
|
import { LocalicationModal } from '../../modals/LocalicationModal';
|
|
10
|
-
import {
|
|
9
|
+
import { DebugJsonPage } from '../DebugJsonPage';
|
|
11
10
|
|
|
12
11
|
const screenStyleDefaults = {
|
|
13
12
|
light: { backgroundColor: '#FDFDFD', color: '#161827' },
|
|
@@ -215,27 +214,13 @@ export function SideTool({ data, setData }: SideToolProps) {
|
|
|
215
214
|
className="modal--large modal--scrollable"
|
|
216
215
|
contentClassName="localication-modal__content"
|
|
217
216
|
>
|
|
218
|
-
<
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
</button>
|
|
226
|
-
</div>
|
|
227
|
-
<div className="localication-modal__body">
|
|
228
|
-
<div className="localication-modal__editor">
|
|
229
|
-
<JsonTextEditor
|
|
230
|
-
rootName="node"
|
|
231
|
-
value={data ?? {}}
|
|
232
|
-
onChange={(next) =>
|
|
233
|
-
setData(analyseAndProccess(next as Node) as Node)
|
|
234
|
-
}
|
|
235
|
-
className="localication-modal__json-editor"
|
|
236
|
-
/>
|
|
237
|
-
</div>
|
|
238
|
-
</div>
|
|
217
|
+
<DebugJsonPage
|
|
218
|
+
data={data}
|
|
219
|
+
setData={setData}
|
|
220
|
+
onClose={() => setIsDebugModalOpen(false)}
|
|
221
|
+
description="Inspect and edit raw node JSON."
|
|
222
|
+
logLabel="SideTool Debug JSON"
|
|
223
|
+
/>
|
|
239
224
|
</Modal>
|
|
240
225
|
)}
|
|
241
226
|
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { useRenderStore } from '../store';
|
|
2
|
+
|
|
3
|
+
export type LogRenderStoreOptions = {
|
|
4
|
+
label?: string;
|
|
5
|
+
includeLocalStorage?: boolean;
|
|
6
|
+
extra?: Record<string, unknown>;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
function isFn(value: unknown): value is (...args: unknown[]) => unknown {
|
|
10
|
+
return typeof value === 'function';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function safeStringify(value: unknown): string {
|
|
14
|
+
try {
|
|
15
|
+
const seen = new WeakSet<object>();
|
|
16
|
+
return JSON.stringify(
|
|
17
|
+
value,
|
|
18
|
+
(_key, v) => {
|
|
19
|
+
if (typeof v === 'function') {
|
|
20
|
+
const name = (v as Function).name;
|
|
21
|
+
return `[Function${name ? `: ${name}` : ''}]`;
|
|
22
|
+
}
|
|
23
|
+
if (typeof v === 'bigint') return v.toString();
|
|
24
|
+
if (v instanceof Error) {
|
|
25
|
+
return { name: v.name, message: v.message, stack: v.stack };
|
|
26
|
+
}
|
|
27
|
+
if (v instanceof Map) {
|
|
28
|
+
return { __type: 'Map', entries: Array.from(v.entries()) };
|
|
29
|
+
}
|
|
30
|
+
if (v instanceof Set) {
|
|
31
|
+
return { __type: 'Set', values: Array.from(v.values()) };
|
|
32
|
+
}
|
|
33
|
+
if (typeof v === 'object' && v !== null) {
|
|
34
|
+
if (seen.has(v as object)) return '[Circular]';
|
|
35
|
+
seen.add(v as object);
|
|
36
|
+
}
|
|
37
|
+
return v;
|
|
38
|
+
},
|
|
39
|
+
2,
|
|
40
|
+
);
|
|
41
|
+
} catch (e) {
|
|
42
|
+
return `<< Unable to stringify value: ${String(e)} >>`;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function safeParseJson(text: unknown): unknown {
|
|
47
|
+
if (typeof text !== 'string' || !text.trim()) return null;
|
|
48
|
+
try {
|
|
49
|
+
return JSON.parse(text);
|
|
50
|
+
} catch {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function safeGetPersistedRenderStore(): unknown {
|
|
56
|
+
try {
|
|
57
|
+
if (typeof localStorage === 'undefined') return null;
|
|
58
|
+
return localStorage.getItem('render-store');
|
|
59
|
+
} catch (e) {
|
|
60
|
+
return { error: String(e) };
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function logRenderStore(options: LogRenderStoreOptions = {}): void {
|
|
65
|
+
const { label, includeLocalStorage = true, extra } = options;
|
|
66
|
+
|
|
67
|
+
const state = useRenderStore.getState();
|
|
68
|
+
const keys = Object.keys(state as Record<string, unknown>).sort();
|
|
69
|
+
|
|
70
|
+
const snapshot: Record<string, unknown> = {};
|
|
71
|
+
const actions: string[] = [];
|
|
72
|
+
|
|
73
|
+
for (const key of keys) {
|
|
74
|
+
const v = (state as any)[key];
|
|
75
|
+
if (isFn(v)) actions.push(key);
|
|
76
|
+
else snapshot[key] = v;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const title = `[RB Debug] Render store${label ? ` (${label})` : ''}`;
|
|
80
|
+
const groupCollapsed = (console as any).groupCollapsed as unknown;
|
|
81
|
+
const groupEnd = (console as any).groupEnd as unknown;
|
|
82
|
+
|
|
83
|
+
if (isFn(groupCollapsed)) groupCollapsed(title);
|
|
84
|
+
else {
|
|
85
|
+
// eslint-disable-next-line no-console
|
|
86
|
+
console.log(title);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const persistedRaw = includeLocalStorage
|
|
90
|
+
? safeGetPersistedRenderStore()
|
|
91
|
+
: null;
|
|
92
|
+
const persistedParsed = includeLocalStorage
|
|
93
|
+
? safeParseJson(persistedRaw)
|
|
94
|
+
: null;
|
|
95
|
+
const json = safeStringify({
|
|
96
|
+
snapshot,
|
|
97
|
+
actions,
|
|
98
|
+
extra: extra ?? null,
|
|
99
|
+
persisted: includeLocalStorage
|
|
100
|
+
? { raw: persistedRaw, parsed: persistedParsed }
|
|
101
|
+
: null,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// NOTE: Logging objects in devtools can be confusing because they are "live" references.
|
|
105
|
+
// This JSON string is a stable snapshot of this click, and is copy/paste-friendly.
|
|
106
|
+
// eslint-disable-next-line no-console
|
|
107
|
+
console.log('json', json);
|
|
108
|
+
|
|
109
|
+
// eslint-disable-next-line no-console
|
|
110
|
+
console.log('state', snapshot);
|
|
111
|
+
// eslint-disable-next-line no-console
|
|
112
|
+
console.log('actions', actions);
|
|
113
|
+
// eslint-disable-next-line no-console
|
|
114
|
+
console.log('rawState (includes functions)', state);
|
|
115
|
+
|
|
116
|
+
if (includeLocalStorage) {
|
|
117
|
+
// eslint-disable-next-line no-console
|
|
118
|
+
console.log('localStorage.render-store (raw)', persistedRaw);
|
|
119
|
+
// eslint-disable-next-line no-console
|
|
120
|
+
console.log('localStorage.render-store (parsed)', persistedParsed);
|
|
121
|
+
}
|
|
122
|
+
if (extra) {
|
|
123
|
+
// eslint-disable-next-line no-console
|
|
124
|
+
console.log('extra', extra);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (isFn(groupEnd)) groupEnd();
|
|
128
|
+
}
|
package/src/utils/patterns.ts
CHANGED
|
@@ -211,14 +211,37 @@ export function getAttributeMeta(
|
|
|
211
211
|
const styles = p?.meta?.styles;
|
|
212
212
|
const attributes = p?.meta?.attributes;
|
|
213
213
|
|
|
214
|
+
// Some patterns store style meta under `meta.attributes.styles` (nested) instead of `meta.styles`.
|
|
215
|
+
const nestedStyles =
|
|
216
|
+
attributes &&
|
|
217
|
+
typeof attributes === 'object' &&
|
|
218
|
+
(attributes as any).styles &&
|
|
219
|
+
typeof (attributes as any).styles === 'object'
|
|
220
|
+
? ((attributes as any).styles as Record<string, AttributeMeta>)
|
|
221
|
+
: undefined;
|
|
222
|
+
|
|
223
|
+
// When `meta.attributes.styles` exists, treat `meta.attributes` (minus `styles`) as non-style meta.
|
|
224
|
+
const attributesWithoutNestedStyles =
|
|
225
|
+
attributes && typeof attributes === 'object'
|
|
226
|
+
? Object.fromEntries(
|
|
227
|
+
Object.entries(attributes as Record<string, unknown>).filter(
|
|
228
|
+
([k]) => k !== 'styles',
|
|
229
|
+
),
|
|
230
|
+
)
|
|
231
|
+
: attributes;
|
|
232
|
+
|
|
214
233
|
// schemaVersion=2 prefers `meta.styles` but some repos split UI meta into:
|
|
215
234
|
// - meta.styles: style-tab fields
|
|
216
235
|
// - meta.attributes: non-style fields (container/other)
|
|
217
236
|
// Merge both to keep the editor + platform adjustments working.
|
|
218
237
|
const merged =
|
|
219
|
-
styles
|
|
220
|
-
? {
|
|
221
|
-
|
|
238
|
+
styles || attributesWithoutNestedStyles || nestedStyles
|
|
239
|
+
? {
|
|
240
|
+
...(attributesWithoutNestedStyles as Record<string, AttributeMeta>),
|
|
241
|
+
...(styles as Record<string, AttributeMeta>),
|
|
242
|
+
...(nestedStyles as Record<string, AttributeMeta>),
|
|
243
|
+
}
|
|
244
|
+
: undefined;
|
|
222
245
|
|
|
223
246
|
return adjustMetaForPlatform(merged, platform);
|
|
224
247
|
}
|