@developer_tribe/react-builder 1.2.24 → 1.2.26
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/attributes-editor/AttributesEditorFields.d.ts +1 -1
- package/dist/attributes-editor/SpecialCategorySection.d.ts +2 -1
- package/dist/attributes-editor/attributesEditorModelTypes.d.ts +2 -0
- package/dist/build-components/BIcon/BIconProps.generated.d.ts +0 -2
- package/dist/build-components/BackgroundImage/BackgroundImageProps.generated.d.ts +0 -2
- package/dist/build-components/Button/ButtonProps.generated.d.ts +0 -2
- package/dist/build-components/Carousel/CarouselProps.generated.d.ts +0 -2
- package/dist/build-components/CarouselButtons/CarouselButtonsProps.generated.d.ts +0 -2
- package/dist/build-components/CarouselDots/CarouselDotsProps.generated.d.ts +0 -2
- package/dist/build-components/CarouselItem/CarouselItemProps.generated.d.ts +0 -2
- package/dist/build-components/CarouselProvider/CarouselProviderProps.generated.d.ts +0 -2
- package/dist/build-components/CountDown/CountDownProps.generated.d.ts +3 -6
- package/dist/build-components/Image/ImageProps.generated.d.ts +0 -2
- package/dist/build-components/Main/MainProps.generated.d.ts +0 -2
- package/dist/build-components/NavigationBarColor/NavigationBarColorProps.generated.d.ts +0 -2
- package/dist/build-components/Onboard/OnboardProps.generated.d.ts +0 -2
- package/dist/build-components/OnboardButton/OnboardButtonProps.generated.d.ts +0 -2
- package/dist/build-components/OnboardButtons/OnboardButtonsProps.generated.d.ts +0 -2
- package/dist/build-components/OnboardDot/OnboardDotProps.generated.d.ts +0 -2
- package/dist/build-components/OnboardFooter/OnboardFooterProps.generated.d.ts +0 -2
- package/dist/build-components/OnboardImage/OnboardImageProps.generated.d.ts +0 -2
- package/dist/build-components/OnboardItem/OnboardItemProps.generated.d.ts +0 -2
- package/dist/build-components/OnboardProvider/OnboardProviderProps.generated.d.ts +0 -2
- package/dist/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.d.ts +0 -2
- package/dist/build-components/OnboardTitle/OnboardTitleProps.generated.d.ts +0 -2
- package/dist/build-components/PaywallBackground/PaywallBackgroundProps.generated.d.ts +0 -2
- package/dist/build-components/PaywallCloseButton/PaywallCloseButtonProps.generated.d.ts +0 -2
- package/dist/build-components/PaywallOptions/PaywallOptionButton.d.ts +1 -1
- package/dist/build-components/PaywallOptions/PaywallOptionsProps.generated.d.ts +0 -2
- package/dist/build-components/PaywallProvider/PaywallContext.d.ts +1 -2
- package/dist/build-components/PaywallProvider/PaywallProviderProps.generated.d.ts +0 -2
- package/dist/build-components/PaywallSubscribeButton/PaywallSubscribeButtonProps.generated.d.ts +0 -2
- package/dist/build-components/RadioButton/RadioButtonProps.generated.d.ts +0 -2
- package/dist/build-components/Separator/SeparatorProps.generated.d.ts +0 -2
- package/dist/build-components/StatusBarColor/StatusBarColorProps.generated.d.ts +0 -2
- package/dist/build-components/Text/TextProps.generated.d.ts +0 -2
- package/dist/build-components/index.d.ts +1 -3
- package/dist/build-components/patterns.generated.d.ts +818 -1690
- package/dist/index.cjs.js +3 -3
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.esm.js +4 -4
- package/dist/index.esm.js.map +1 -1
- package/dist/index.web.cjs.js +4 -4
- package/dist/index.web.cjs.js.map +1 -1
- package/dist/index.web.esm.js +3 -3
- package/dist/index.web.esm.js.map +1 -1
- package/dist/pages/ProjectPage.d.ts +2 -2
- package/dist/pages/projectPageUtils.d.ts +7 -1
- package/dist/paywall/hooks/index.d.ts +0 -1
- package/dist/styles.css +1 -1
- package/dist/types/Project.d.ts +6 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/patterns.d.ts +2 -0
- package/dist/utils/projectColors.d.ts +7 -0
- package/package.json +3 -3
- package/scripts/prebuild/utils/validateAllComponentsOrThrow.js +11 -2
- package/src/AttributesEditor.tsx +15 -4
- package/src/DeviceMockFrame.tsx +0 -2
- package/src/RenderPage.tsx +0 -9
- package/src/assets/.DS_Store +0 -0
- package/src/assets/meta.json +1 -1
- package/src/assets/samples/paywall-1.json +0 -1
- package/src/assets/samples/paywall-2.json +2 -3
- package/src/assets/samples/paywall-app-delete-offer.json +2 -4
- package/src/assets/samples/paywall-app-open-offer.json +2 -4
- package/src/assets/samples/paywall-back-offer.json +2 -4
- package/src/assets/samples/paywall-notification-offer.json +2 -4
- package/src/assets/samples/simple-2.json +0 -1
- package/src/assets/samples/vpn-onboard-1.json +15 -15
- package/src/assets/samples/vpn-onboard-2.json +15 -15
- package/src/assets/samples/vpn-onboard-3.json +15 -15
- package/src/assets/samples/vpn-onboard-4.json +15 -15
- package/src/assets/samples/vpn-onboard-5.json +21 -21
- package/src/assets/samples/vpn-onboard-6.json +15 -15
- package/src/attributes-editor/AttributesEditorFields.tsx +0 -1
- package/src/attributes-editor/AttributesEditorView.tsx +43 -38
- package/src/attributes-editor/Field.tsx +1 -1
- package/src/attributes-editor/SpecialCategorySection.tsx +5 -4
- package/src/attributes-editor/attributesEditorModelTypes.ts +2 -0
- package/src/attributes-editor/useAttributesEditorModel.ts +24 -8
- package/src/build-components/BIcon/BIcon.tsx +1 -1
- package/src/build-components/BIcon/BIconProps.generated.ts +0 -2
- package/src/build-components/BIcon/pattern.json +2 -2
- package/src/build-components/BackgroundImage/BackgroundImageProps.generated.ts +0 -2
- package/src/build-components/BackgroundImage/pattern.json +2 -2
- package/src/build-components/Button/ButtonProps.generated.ts +0 -2
- package/src/build-components/Button/pattern.json +2 -2
- package/src/build-components/Carousel/Carousel.tsx +1 -1
- package/src/build-components/Carousel/CarouselProps.generated.ts +0 -2
- package/src/build-components/Carousel/pattern.json +3 -3
- package/src/build-components/CarouselButtons/CarouselButtonsProps.generated.ts +0 -2
- package/src/build-components/CarouselButtons/pattern.json +2 -2
- package/src/build-components/CarouselDots/CarouselDotsProps.generated.ts +0 -2
- package/src/build-components/CarouselDots/pattern.json +2 -2
- package/src/build-components/CarouselItem/CarouselItemProps.generated.ts +0 -2
- package/src/build-components/CarouselItem/pattern.json +3 -5
- package/src/build-components/CarouselProvider/CarouselProvider.tsx +1 -1
- package/src/build-components/CarouselProvider/CarouselProviderProps.generated.ts +0 -2
- package/src/build-components/CarouselProvider/pattern.json +2 -4
- package/src/build-components/CountDown/CountDown.tsx +25 -1
- package/src/build-components/CountDown/CountDownProps.generated.ts +3 -6
- package/src/build-components/CountDown/pattern.json +10 -2
- package/src/build-components/Image/ImageProps.generated.ts +0 -2
- package/src/build-components/Image/pattern.json +5 -3
- package/src/build-components/Main/MainProps.generated.ts +0 -2
- package/src/build-components/Main/pattern.json +2 -2
- package/src/build-components/NavigationBarColor/NavigationBarColorProps.generated.ts +0 -2
- package/src/build-components/NavigationBarColor/pattern.json +2 -2
- package/src/build-components/Onboard/OnboardProps.generated.ts +0 -2
- package/src/build-components/Onboard/pattern.json +3 -5
- package/src/build-components/OnboardButton/OnboardButton.tsx +1 -4
- package/src/build-components/OnboardButton/OnboardButtonProps.generated.ts +0 -2
- package/src/build-components/OnboardButton/pattern.json +2 -2
- package/src/build-components/OnboardButtons/OnboardButtons.tsx +1 -9
- package/src/build-components/OnboardButtons/OnboardButtonsProps.generated.ts +0 -2
- package/src/build-components/OnboardButtons/pattern.json +2 -2
- package/src/build-components/OnboardDot/OnboardDot.tsx +2 -1
- package/src/build-components/OnboardDot/OnboardDotProps.generated.ts +0 -2
- package/src/build-components/OnboardDot/pattern.json +2 -2
- package/src/build-components/OnboardFooter/OnboardFooterProps.generated.ts +0 -2
- package/src/build-components/OnboardFooter/pattern.json +2 -2
- package/src/build-components/OnboardImage/OnboardImageProps.generated.ts +0 -2
- package/src/build-components/OnboardImage/pattern.json +2 -2
- package/src/build-components/OnboardItem/OnboardItem.tsx +1 -1
- package/src/build-components/OnboardItem/OnboardItemProps.generated.ts +0 -2
- package/src/build-components/OnboardItem/pattern.json +2 -2
- package/src/build-components/OnboardProvider/OnboardProvider.tsx +0 -1
- package/src/build-components/OnboardProvider/OnboardProviderProps.generated.ts +0 -2
- package/src/build-components/OnboardProvider/pattern.json +2 -2
- package/src/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.ts +0 -2
- package/src/build-components/OnboardSubtitle/pattern.json +3 -5
- package/src/build-components/OnboardTitle/OnboardTitleProps.generated.ts +0 -2
- package/src/build-components/OnboardTitle/pattern.json +3 -5
- package/src/build-components/PaywallBackground/PaywallBackgroundProps.generated.ts +0 -2
- package/src/build-components/PaywallBackground/pattern.json +2 -4
- package/src/build-components/PaywallCloseButton/PaywallCloseButtonProps.generated.ts +0 -2
- package/src/build-components/PaywallCloseButton/pattern.json +3 -5
- package/src/build-components/PaywallOptions/PaywallOptionButton.tsx +1 -2
- package/src/build-components/PaywallOptions/PaywallOptionsProps.generated.ts +0 -2
- package/src/build-components/PaywallOptions/pattern.json +3 -5
- package/src/build-components/PaywallProvider/PaywallContext.ts +1 -1
- package/src/build-components/PaywallProvider/PaywallProvider.tsx +0 -10
- package/src/build-components/PaywallProvider/PaywallProviderProps.generated.ts +0 -2
- package/src/build-components/PaywallProvider/pattern.json +2 -2
- package/src/build-components/PaywallSubscribeButton/PaywallSubscribeButton.tsx +1 -1
- package/src/build-components/PaywallSubscribeButton/PaywallSubscribeButtonProps.generated.ts +0 -2
- package/src/build-components/PaywallSubscribeButton/pattern.json +3 -5
- package/src/build-components/RadioButton/RadioButton.tsx +1 -1
- package/src/build-components/RadioButton/RadioButtonProps.generated.ts +0 -2
- package/src/build-components/RadioButton/pattern.json +2 -2
- package/src/build-components/RenderNode.generated.tsx +0 -10
- package/src/build-components/Separator/SeparatorProps.generated.ts +0 -2
- package/src/build-components/Separator/pattern.json +2 -2
- package/src/build-components/StatusBarColor/StatusBarColorProps.generated.ts +0 -2
- package/src/build-components/StatusBarColor/pattern.json +2 -2
- package/src/build-components/Text/TextProps.generated.ts +0 -2
- package/src/build-components/Text/pattern.json +2 -3
- package/src/build-components/View/pattern.json +2 -0
- package/src/build-components/index.ts +0 -10
- package/src/build-components/patterns.generated.ts +850 -1759
- package/src/components/AttributesEditorPanel.tsx +48 -32
- package/src/components/Builder.tsx +9 -1
- package/src/components/BuilderProvider.tsx +2 -37
- package/src/hooks/useSafeAreaViewStyle.ts +1 -3
- package/src/index.ts +1 -1
- package/src/mockOS/managers/navigationManager.ts +1 -1
- package/src/pages/ProjectPage.tsx +47 -22
- package/src/pages/projectPageUtils.ts +15 -1
- package/src/pages/tabs/SideTool.tsx +1 -22
- package/src/paywall/hooks/index.ts +0 -1
- package/src/store.ts +1 -6
- package/src/styles/base/_global.scss +2 -0
- package/src/types/Project.ts +7 -0
- package/src/utils/analyseNodeByPatterns.ts +4 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/logRenderStore.ts +0 -1
- package/src/utils/novaToJson.ts +1 -5
- package/src/utils/parseColor.ts +1 -0
- package/src/utils/patterns.ts +2 -0
- package/src/utils/projectColors.ts +71 -0
- package/dist/build-components/Counter/Counter.d.ts +0 -2
- package/dist/build-components/Counter/CounterProps.generated.d.ts +0 -63
- package/dist/build-components/PaywallCounter/PaywallCounter.d.ts +0 -2
- package/dist/build-components/PaywallCounter/PaywallCounterProps.generated.d.ts +0 -63
- package/dist/paywall/hooks/useHandleGoBack.d.ts +0 -1
- package/src/build-components/Counter/Counter.tsx +0 -44
- package/src/build-components/Counter/CounterProps.generated.ts +0 -80
- package/src/build-components/Counter/pattern.json +0 -25
- package/src/build-components/PaywallCounter/PaywallCounter.tsx +0 -46
- package/src/build-components/PaywallCounter/PaywallCounterProps.generated.ts +0 -80
- package/src/build-components/PaywallCounter/pattern.json +0 -23
- package/src/paywall/hooks/useHandleGoBack.ts +0 -60
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useCallback, useRef } from 'react';
|
|
1
2
|
import { AttributesEditor } from '../AttributesEditor';
|
|
2
3
|
import type { Node, NodeData } from '../types/Node';
|
|
3
4
|
import type { ProjectColors } from '../types/Project';
|
|
@@ -11,6 +12,32 @@ interface AttributesEditorPanelProps {
|
|
|
11
12
|
projectColors?: ProjectColors;
|
|
12
13
|
}
|
|
13
14
|
|
|
15
|
+
function replaceNode(root: Node, target: Node, next: Node): Node {
|
|
16
|
+
if (root === target) return next;
|
|
17
|
+
if (root === null || root === undefined) return root;
|
|
18
|
+
if (typeof root === 'string') return root;
|
|
19
|
+
if (Array.isArray(root)) {
|
|
20
|
+
let changed = false;
|
|
21
|
+
const arr = root.map((item) => {
|
|
22
|
+
const r = replaceNode(item, target, next);
|
|
23
|
+
if (r !== item) changed = true;
|
|
24
|
+
return r;
|
|
25
|
+
});
|
|
26
|
+
return changed ? arr : root;
|
|
27
|
+
}
|
|
28
|
+
const data = root as NodeData;
|
|
29
|
+
if ('children' in data) {
|
|
30
|
+
const prev = data.children;
|
|
31
|
+
const replaced = Array.isArray(prev)
|
|
32
|
+
? prev.map((c: Node) => replaceNode(c, target, next))
|
|
33
|
+
: replaceNode(prev as Node, target, next);
|
|
34
|
+
if (replaced !== prev) {
|
|
35
|
+
return { ...data, children: replaced } as Node;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return root;
|
|
39
|
+
}
|
|
40
|
+
|
|
14
41
|
export function AttributesEditorPanel({
|
|
15
42
|
attributes,
|
|
16
43
|
onChange,
|
|
@@ -21,6 +48,27 @@ export function AttributesEditorPanel({
|
|
|
21
48
|
current: s.current,
|
|
22
49
|
setCurrent: s.setCurrent,
|
|
23
50
|
}));
|
|
51
|
+
|
|
52
|
+
// Stable refs so the onChange callback doesn't change identity every render.
|
|
53
|
+
const attributesRef = useRef(attributes);
|
|
54
|
+
attributesRef.current = attributes;
|
|
55
|
+
const currentRef = useRef(current);
|
|
56
|
+
currentRef.current = current;
|
|
57
|
+
const onChangeRef = useRef(onChange);
|
|
58
|
+
onChangeRef.current = onChange;
|
|
59
|
+
|
|
60
|
+
const handleAttributesChange = useCallback(
|
|
61
|
+
(next: Node) => {
|
|
62
|
+
const root = attributesRef.current as Node;
|
|
63
|
+
const target = currentRef.current;
|
|
64
|
+
if (!target) return;
|
|
65
|
+
const updated = replaceNode(root, target, next);
|
|
66
|
+
onChangeRef.current(updated);
|
|
67
|
+
setCurrent(next);
|
|
68
|
+
},
|
|
69
|
+
[setCurrent],
|
|
70
|
+
);
|
|
71
|
+
|
|
24
72
|
if (!current) return null;
|
|
25
73
|
|
|
26
74
|
const currentKey =
|
|
@@ -33,38 +81,6 @@ export function AttributesEditorPanel({
|
|
|
33
81
|
: null;
|
|
34
82
|
const nodeForEditor = resolvedCurrent ?? current;
|
|
35
83
|
|
|
36
|
-
function replaceNode(root: Node, target: Node, next: Node): Node {
|
|
37
|
-
if (root === target) return next;
|
|
38
|
-
if (root === null || root === undefined) return root;
|
|
39
|
-
if (typeof root === 'string') return root;
|
|
40
|
-
if (Array.isArray(root)) {
|
|
41
|
-
let changed = false;
|
|
42
|
-
const arr = root.map((item) => {
|
|
43
|
-
const r = replaceNode(item, target, next);
|
|
44
|
-
if (r !== item) changed = true;
|
|
45
|
-
return r;
|
|
46
|
-
});
|
|
47
|
-
return changed ? arr : root;
|
|
48
|
-
}
|
|
49
|
-
const data = root as NodeData;
|
|
50
|
-
if ('children' in data) {
|
|
51
|
-
const prev = data.children;
|
|
52
|
-
const replaced = Array.isArray(prev)
|
|
53
|
-
? prev.map((c: Node) => replaceNode(c, target, next))
|
|
54
|
-
: replaceNode(prev as Node, target, next);
|
|
55
|
-
if (replaced !== prev) {
|
|
56
|
-
return { ...data, children: replaced } as Node;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return root;
|
|
60
|
-
}
|
|
61
|
-
const handleAttributesChange = (next: Node) => {
|
|
62
|
-
const root = attributes as Node;
|
|
63
|
-
const updated = replaceNode(root, current, next);
|
|
64
|
-
onChange(updated);
|
|
65
|
-
setCurrent(next);
|
|
66
|
-
};
|
|
67
|
-
|
|
68
84
|
return (
|
|
69
85
|
<div className="attributes-editor-panel">
|
|
70
86
|
<AttributesEditor
|
|
@@ -330,11 +330,13 @@ export function Builder({
|
|
|
330
330
|
setData(updatedRoot);
|
|
331
331
|
setCurrent(updatedParent);
|
|
332
332
|
},
|
|
333
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
333
334
|
[current, data, setData, setCurrent, usedKeys],
|
|
334
335
|
);
|
|
335
336
|
|
|
336
337
|
const allowedChildTypes = useMemo(
|
|
337
338
|
() => getAllowedChildTypes(current),
|
|
339
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
338
340
|
[current],
|
|
339
341
|
);
|
|
340
342
|
const parentType = useMemo(() => {
|
|
@@ -378,6 +380,7 @@ export function Builder({
|
|
|
378
380
|
setCurrent(next);
|
|
379
381
|
}
|
|
380
382
|
},
|
|
383
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
381
384
|
[current, data, setCurrent, setData],
|
|
382
385
|
);
|
|
383
386
|
|
|
@@ -407,6 +410,7 @@ export function Builder({
|
|
|
407
410
|
setCurrent(updatedParent);
|
|
408
411
|
}
|
|
409
412
|
},
|
|
413
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
410
414
|
[current, data, setCurrent, setData],
|
|
411
415
|
);
|
|
412
416
|
|
|
@@ -436,6 +440,7 @@ export function Builder({
|
|
|
436
440
|
setCurrent(updatedParent);
|
|
437
441
|
}
|
|
438
442
|
},
|
|
443
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
439
444
|
[current, data, setCurrent, setData],
|
|
440
445
|
);
|
|
441
446
|
|
|
@@ -603,7 +608,10 @@ function getNodeLabel(node: Node): string {
|
|
|
603
608
|
if (isNodeNullOrUndefined(node)) return 'Empty';
|
|
604
609
|
if (isNodeString(node)) return node as string;
|
|
605
610
|
if (isNodeArray(node)) return 'Collection';
|
|
606
|
-
|
|
611
|
+
const nodeData = node as NodeData<NodeDefaultAttribute>;
|
|
612
|
+
const title = (nodeData.attributes as Record<string, unknown>)?.title;
|
|
613
|
+
if (typeof title === 'string' && title.trim().length > 0) return title;
|
|
614
|
+
return nodeData.type ?? 'Node';
|
|
607
615
|
}
|
|
608
616
|
|
|
609
617
|
function findNodePath(root: Node, target: Node): Node[] {
|
|
@@ -4,6 +4,7 @@ import type { PaywallBenefits } from '../paywall/types/benefits';
|
|
|
4
4
|
import type { AppConfig } from '../types/PreviewConfig';
|
|
5
5
|
import type { Fonts } from '../types/Fonts';
|
|
6
6
|
import type { ProjectColors } from '../types/Project';
|
|
7
|
+
import { defaultProjectColors, mergeProjectColors } from '../utils';
|
|
7
8
|
|
|
8
9
|
// NOTE: We keep this context intentionally tiny.
|
|
9
10
|
// IMPORTANT: This provider may be mounted once but consumed by multiple `build-components`
|
|
@@ -65,7 +66,7 @@ export function BuilderProvider({ params, children }: BuilderProviderProps) {
|
|
|
65
66
|
: undefined,
|
|
66
67
|
projectColors:
|
|
67
68
|
params?.projectColors && typeof params.projectColors === 'object'
|
|
68
|
-
? (params.projectColors
|
|
69
|
+
? mergeProjectColors(defaultProjectColors, params.projectColors)
|
|
69
70
|
: defaultProjectColors,
|
|
70
71
|
fonts: Array.isArray(params?.fonts) ? (params.fonts as Fonts) : undefined,
|
|
71
72
|
appFont: params?.appFont,
|
|
@@ -95,42 +96,6 @@ export function BuilderProvider({ params, children }: BuilderProviderProps) {
|
|
|
95
96
|
);
|
|
96
97
|
}
|
|
97
98
|
|
|
98
|
-
const defaultProjectColors: Readonly<ProjectColors> = {
|
|
99
|
-
STATIC_COLORS: {
|
|
100
|
-
BLACK: '#000',
|
|
101
|
-
WHITE: '#FFFFFF',
|
|
102
|
-
TRANSPARENT: '#ffffff00',
|
|
103
|
-
ONBOARD_DOT_INACTIVE: '#E4E5E7',
|
|
104
|
-
ONBOARD_DOT_ACTIVE: '#007AFF',
|
|
105
|
-
BUTTON_PRIMARY_BACKGROUND: '#0066FF',
|
|
106
|
-
BUTTON_PRIMARY_TEXT: '#FFFFFF',
|
|
107
|
-
LINK_COLOR: '#1778F2',
|
|
108
|
-
SEPARATOR_COLOR: '#44454D',
|
|
109
|
-
},
|
|
110
|
-
THEME_COLORS: {
|
|
111
|
-
light: {
|
|
112
|
-
TEXT: '#161827',
|
|
113
|
-
BACKGROUND: '#F4F5FF',
|
|
114
|
-
ICON: '#0450E2',
|
|
115
|
-
LINE: '#E9EBF9',
|
|
116
|
-
ONBOARD_TITLE: '#161827',
|
|
117
|
-
ONBOARD_SUBTITLE: '#44454D',
|
|
118
|
-
BUTTON_SECONDARY_TEXT: '#81838F',
|
|
119
|
-
FOOTER_TEXT: '#81838F',
|
|
120
|
-
},
|
|
121
|
-
dark: {
|
|
122
|
-
TEXT: '#E9EBF9',
|
|
123
|
-
BACKGROUND: '#080A17',
|
|
124
|
-
ICON: '#0450E2',
|
|
125
|
-
LINE: '#161827',
|
|
126
|
-
ONBOARD_TITLE: '#FDFDFD',
|
|
127
|
-
ONBOARD_SUBTITLE: '#C7C7C7',
|
|
128
|
-
BUTTON_SECONDARY_TEXT: '#A9AAAC',
|
|
129
|
-
FOOTER_TEXT: '#A2A4B1',
|
|
130
|
-
},
|
|
131
|
-
},
|
|
132
|
-
} as const;
|
|
133
|
-
|
|
134
99
|
export function useBuilderParams(): Readonly<BuilderProviderParams> {
|
|
135
100
|
return (
|
|
136
101
|
useContext(builderContext) ?? {
|
|
@@ -33,9 +33,7 @@ export function useSafeAreaViewStyle(
|
|
|
33
33
|
return useMemo(() => {
|
|
34
34
|
if (!enabled) return baseStyle;
|
|
35
35
|
|
|
36
|
-
const [insetTop, insetRight,
|
|
37
|
-
0, 0, 0, 0,
|
|
38
|
-
];
|
|
36
|
+
const [insetTop, insetRight, , insetLeft] = device?.insets ?? [0, 0, 0, 0];
|
|
39
37
|
|
|
40
38
|
// Match DeviceMockFrame fallbacks: status bar overlays content, so we treat it as top safe area.
|
|
41
39
|
const top =
|
package/src/index.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
// Types
|
|
14
14
|
export type { TargetedScreenSize } from './types/TargetedScreenSize';
|
|
15
15
|
export type { Node, NodeData, NodeDefaultAttribute } from './types/Node';
|
|
16
|
-
export type { Project, ProjectColors } from './types/Project';
|
|
16
|
+
export type { Project, ProjectColors, ProjectMeta } from './types/Project';
|
|
17
17
|
export type { Device } from './types/Device';
|
|
18
18
|
export type { AppConfig, Localication } from './types/PreviewConfig';
|
|
19
19
|
export { defaultAppConfig } from './types/PreviewConfig';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { useCallback, useEffect, useState } from 'react';
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
2
|
import type { Node, NodeData } from '../types/Node';
|
|
3
|
-
import type { Project, ProjectColors } from '../types/Project';
|
|
3
|
+
import type { Project, ProjectColors, ProjectMeta } from '../types/Project';
|
|
4
4
|
import { ToastContainer, toast } from 'react-toastify';
|
|
5
5
|
import { RenderPage } from '../RenderPage';
|
|
6
6
|
import { EditorHeader } from '../components/EditorHeader';
|
|
@@ -31,16 +31,16 @@ import {
|
|
|
31
31
|
deleteNodeFromTree,
|
|
32
32
|
findNodeByKey,
|
|
33
33
|
isNodeRecord,
|
|
34
|
-
nodeHasChild,
|
|
35
34
|
} from '../utils/nodeTree';
|
|
36
35
|
import type { Fonts } from '../types/Fonts';
|
|
37
36
|
import { useProjectFonts } from '../hooks/useProjectFonts';
|
|
38
|
-
import { resolveProjectForSave } from './projectPageUtils';
|
|
37
|
+
import { resolveProjectForSave, toProjectMeta } from './projectPageUtils';
|
|
39
38
|
import { getDefaultProject } from '../utils/getDefaultProject';
|
|
40
39
|
import { CURRENT_PROJECT_VERSION } from '../migrations/migratePipe';
|
|
41
40
|
export type ProjectPageProps = {
|
|
42
41
|
project: Project;
|
|
43
|
-
|
|
42
|
+
// TODO: Tüm onSaveProject call-site'ları toProjectMeta kullanacak şekilde migrate et
|
|
43
|
+
onSaveProject: (project: ProjectMeta) => void;
|
|
44
44
|
appConfig?: AppConfig;
|
|
45
45
|
logLevel?: LogLevel;
|
|
46
46
|
projectColors?: ProjectColors;
|
|
@@ -151,16 +151,18 @@ export function ProjectPage({
|
|
|
151
151
|
return;
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
154
|
+
// Refresh current's reference so the Builder re-renders the updated subtree.
|
|
155
|
+
// deleteNodeFromTree creates new objects for ancestors of the removed node,
|
|
156
|
+
// so the old `current` reference becomes stale when the deleted node was a
|
|
157
|
+
// descendant of `current`.
|
|
158
|
+
if (isNodeRecord(current) && current.key) {
|
|
159
|
+
const nextCurrent = findNodeByKey(updated, current.key);
|
|
160
|
+
setCurrent(nextCurrent ?? updated);
|
|
161
|
+
} else {
|
|
162
|
+
setCurrent(updated);
|
|
162
163
|
}
|
|
163
164
|
},
|
|
165
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
164
166
|
[editorData, current],
|
|
165
167
|
);
|
|
166
168
|
|
|
@@ -224,10 +226,29 @@ export function ProjectPage({
|
|
|
224
226
|
setMinLoadingDelayDone(false);
|
|
225
227
|
const timer = setTimeout(() => setMinLoadingDelayDone(true), 1000);
|
|
226
228
|
return () => clearTimeout(timer);
|
|
229
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
227
230
|
}, [activeProject.data]);
|
|
228
231
|
|
|
232
|
+
// Ref for the full project (used inside effect for migration check etc.)
|
|
233
|
+
const activeProjectRef = useRef(activeProject);
|
|
234
|
+
activeProjectRef.current = activeProject;
|
|
235
|
+
// Ref for current editorData so the effect can compare without depending on it.
|
|
236
|
+
const editorDataRef = useRef(editorData);
|
|
237
|
+
editorDataRef.current = editorData;
|
|
238
|
+
|
|
229
239
|
useEffect(() => {
|
|
230
240
|
try {
|
|
241
|
+
const currentProject = activeProjectRef.current;
|
|
242
|
+
const projectData = currentProject.data;
|
|
243
|
+
|
|
244
|
+
// Guard: skip reinit when the incoming project data is the same reference
|
|
245
|
+
// we already hold in editorData. After a save round-trip the parent pushes
|
|
246
|
+
// a new project object whose .data is the very same reference as editorData.
|
|
247
|
+
// Re-processing it would flash a loading state and discard in-flight changes.
|
|
248
|
+
if (projectData != null && projectData === editorDataRef.current) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
|
|
231
252
|
// Reset to "loading" immediately on project change so the loader is shown
|
|
232
253
|
// until a valid node is available (and for at least 2 seconds).
|
|
233
254
|
if (!isEmptyProjectData) {
|
|
@@ -237,7 +258,7 @@ export function ProjectPage({
|
|
|
237
258
|
setValidationError(null);
|
|
238
259
|
setValidationErrorStack(null);
|
|
239
260
|
// Version gate: if project is older than the current schema, show migration UI.
|
|
240
|
-
const pipe = getMigrationPipe(
|
|
261
|
+
const pipe = getMigrationPipe(currentProject);
|
|
241
262
|
if (!bypassValidation && pipe.required) {
|
|
242
263
|
setMigrationGate(pipe);
|
|
243
264
|
setEditorData(null);
|
|
@@ -248,8 +269,8 @@ export function ProjectPage({
|
|
|
248
269
|
if (bypassValidation) {
|
|
249
270
|
// Best-effort: let the user continue with the raw data even if invalid.
|
|
250
271
|
// This may still crash the preview, but it unblocks users for debugging.
|
|
251
|
-
setEditorData(
|
|
252
|
-
setCurrent(
|
|
272
|
+
setEditorData(currentProject.data as Node);
|
|
273
|
+
setCurrent(currentProject.data as Node);
|
|
253
274
|
return;
|
|
254
275
|
}
|
|
255
276
|
if (isEmptyProjectData) {
|
|
@@ -258,7 +279,7 @@ export function ProjectPage({
|
|
|
258
279
|
return;
|
|
259
280
|
}
|
|
260
281
|
|
|
261
|
-
const inputNode: Node =
|
|
282
|
+
const inputNode: Node = currentProject.data as Node;
|
|
262
283
|
|
|
263
284
|
const processed = analyseAndProccess(inputNode);
|
|
264
285
|
if (!processed) return;
|
|
@@ -275,7 +296,9 @@ export function ProjectPage({
|
|
|
275
296
|
setEditorData(null);
|
|
276
297
|
setCurrent(null);
|
|
277
298
|
}
|
|
278
|
-
|
|
299
|
+
// Note: depend on activeProject.data (not activeProject object) to avoid
|
|
300
|
+
// reinit when the project wrapper changes but data is the same reference.
|
|
301
|
+
}, [activeProject.data, isEmptyProjectData, bypassValidation, setCurrent]);
|
|
279
302
|
|
|
280
303
|
const showLoading =
|
|
281
304
|
!isEmptyProjectData && (editorData === null || !minLoadingDelayDone);
|
|
@@ -300,13 +323,15 @@ export function ProjectPage({
|
|
|
300
323
|
if (onSaveProjectColors && resolvedProjectColors) {
|
|
301
324
|
onSaveProjectColors(resolvedProjectColors);
|
|
302
325
|
}
|
|
303
|
-
|
|
326
|
+
const projectMeta = toProjectMeta(
|
|
304
327
|
resolveProjectForSave({
|
|
305
328
|
project,
|
|
306
329
|
overrideProject,
|
|
307
330
|
data: editorData,
|
|
308
331
|
}),
|
|
309
332
|
);
|
|
333
|
+
logger.info('ProjectPage', 'saving project meta', projectMeta);
|
|
334
|
+
onSaveProject(projectMeta);
|
|
310
335
|
toast.success('Saved');
|
|
311
336
|
} catch (e) {
|
|
312
337
|
logger.error('ProjectPage', 'save project failed', e);
|
|
@@ -377,7 +402,7 @@ export function ProjectPage({
|
|
|
377
402
|
|
|
378
403
|
const { project: migratedProject } =
|
|
379
404
|
runProjectMigrations(projectForMigration);
|
|
380
|
-
onSaveProject(migratedProject);
|
|
405
|
+
onSaveProject(toProjectMeta(migratedProject));
|
|
381
406
|
setOverrideProject(migratedProject);
|
|
382
407
|
setBypassValidation(true);
|
|
383
408
|
setMigrationGate(null);
|
|
@@ -430,7 +455,7 @@ export function ProjectPage({
|
|
|
430
455
|
|
|
431
456
|
// This action only fixes project metadata. It intentionally does NOT
|
|
432
457
|
// validate/normalize node data (it might still be invalid).
|
|
433
|
-
onSaveProject(fixedProject);
|
|
458
|
+
onSaveProject(toProjectMeta(fixedProject));
|
|
434
459
|
setOverrideProject(fixedProject);
|
|
435
460
|
setBypassValidation(false);
|
|
436
461
|
setMigrationGate(null);
|
|
@@ -488,7 +513,7 @@ export function ProjectPage({
|
|
|
488
513
|
data: nodeCandidate as Project['data'],
|
|
489
514
|
};
|
|
490
515
|
|
|
491
|
-
onSaveProject(nextProject);
|
|
516
|
+
onSaveProject(toProjectMeta(nextProject));
|
|
492
517
|
setOverrideProject(nextProject);
|
|
493
518
|
setBypassValidation(false);
|
|
494
519
|
setValidationError(null);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Project } from '../types/Project';
|
|
1
|
+
import type { Project, ProjectMeta } from '../types/Project';
|
|
2
2
|
import type { Node } from '../types/Node';
|
|
3
3
|
import { getDefaultProject } from '../utils/getDefaultProject';
|
|
4
4
|
|
|
@@ -13,3 +13,17 @@ export function resolveProjectForSave(args: {
|
|
|
13
13
|
data: args.data,
|
|
14
14
|
});
|
|
15
15
|
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Strips a full Project down to its essential persistence fields.
|
|
19
|
+
* Use before handing the project to onSaveProject so consumers only
|
|
20
|
+
* receive the canonical metadata (name, version, type, data).
|
|
21
|
+
*/
|
|
22
|
+
export function toProjectMeta(project: Project): ProjectMeta {
|
|
23
|
+
return {
|
|
24
|
+
name: project.name,
|
|
25
|
+
version: project.version,
|
|
26
|
+
...(project.type ? { type: project.type } : {}),
|
|
27
|
+
data: project.data,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
2
|
import { Modal } from '../../modals';
|
|
3
3
|
import type { Node } from '../../types/Node';
|
|
4
4
|
import type { Localication } from '../../types/PreviewConfig';
|
|
@@ -52,12 +52,6 @@ export function SideTool({ data, setData }: SideToolProps) {
|
|
|
52
52
|
useLogRender('SideTool');
|
|
53
53
|
const [isDebugModalOpen, setIsDebugModalOpen] = useState(false);
|
|
54
54
|
const [isLocalicationModalOpen, setIsLocalicationModalOpen] = useState(false);
|
|
55
|
-
const [isCompactMode, setIsCompactMode] = useState(() => {
|
|
56
|
-
if (typeof window === 'undefined') {
|
|
57
|
-
return false;
|
|
58
|
-
}
|
|
59
|
-
return window.innerWidth < 1000;
|
|
60
|
-
});
|
|
61
55
|
const [isCompactPanelVisible, setIsCompactPanelVisible] = useState(false);
|
|
62
56
|
const { appConfig, setAppConfig, previewMode, setPreviewMode } =
|
|
63
57
|
useRenderStore((s) => ({
|
|
@@ -67,21 +61,6 @@ export function SideTool({ data, setData }: SideToolProps) {
|
|
|
67
61
|
setPreviewMode: s.setPreviewMode,
|
|
68
62
|
}));
|
|
69
63
|
|
|
70
|
-
useEffect(() => {
|
|
71
|
-
if (typeof window === 'undefined') {
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const handleResize = () => {
|
|
76
|
-
const compact = window.innerWidth < 1000;
|
|
77
|
-
setIsCompactMode(compact);
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
handleResize();
|
|
81
|
-
window.addEventListener('resize', handleResize);
|
|
82
|
-
return () => window.removeEventListener('resize', handleResize);
|
|
83
|
-
}, []);
|
|
84
|
-
|
|
85
64
|
const getScreenColorValue = (mode: ScreenMode, key: ScreenColorKey) =>
|
|
86
65
|
appConfig.screenStyle?.[mode]?.[key] ?? screenStyleDefaults[mode][key];
|
|
87
66
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export { useCalculateLocalizedPrice } from './useCalculateLocalizedPrice';
|
|
2
2
|
export { useDiscountRate } from './useDiscountRate';
|
|
3
3
|
export { useChangeDelayByPaywall } from './useChangeDelayByPaywall';
|
|
4
|
-
export { useHandleGoBack } from './useHandleGoBack';
|
|
5
4
|
export { useMockOSBackHandler } from './useMockOSBackHandler';
|
package/src/store.ts
CHANGED
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
import { createWithEqualityFn } from 'zustand/traditional';
|
|
2
2
|
import { shallow } from 'zustand/shallow';
|
|
3
3
|
import type { Device } from './types/Device';
|
|
4
|
-
import {
|
|
5
|
-
defaultAppConfig,
|
|
6
|
-
type AppConfig,
|
|
7
|
-
type Localication,
|
|
8
|
-
} from './types/PreviewConfig';
|
|
4
|
+
import { defaultAppConfig, type AppConfig } from './types/PreviewConfig';
|
|
9
5
|
import { getDefaultDevice } from './utils/getDevices';
|
|
10
|
-
import { ScreenStyle } from './RenderPage';
|
|
11
6
|
import { createJSONStorage, persist } from 'zustand/middleware';
|
|
12
7
|
import { Node } from './types/Node';
|
|
13
8
|
import type { LogEntry, LogLevel, ProjectColors } from './types/Project';
|
package/src/types/Project.ts
CHANGED
|
@@ -29,6 +29,13 @@ export interface ProjectBase<T> {
|
|
|
29
29
|
|
|
30
30
|
export interface Project extends ProjectBase<Node> {}
|
|
31
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Lightweight subset of Project containing only the essential metadata
|
|
34
|
+
* needed for persistence (name, version, type, data).
|
|
35
|
+
* Excludes runtime/editor-only fields like appConfig and projectColors.
|
|
36
|
+
*/
|
|
37
|
+
export type ProjectMeta = Pick<Project, 'name' | 'version' | 'type' | 'data'>;
|
|
38
|
+
|
|
32
39
|
export type LogLevel = 'NONE' | 'ERROR' | 'WARN' | 'INFO' | 'VERBOSE';
|
|
33
40
|
|
|
34
41
|
export type LogSource = string;
|
|
@@ -344,6 +344,10 @@ function validateAttributeValue(
|
|
|
344
344
|
// null to clear fields (e.g. events[].navigate_to = null).
|
|
345
345
|
if (value == null) return ok();
|
|
346
346
|
|
|
347
|
+
// "never" type means the attribute is marked as not to be validated.
|
|
348
|
+
// Skip validation for attributes with "never" type.
|
|
349
|
+
if (spec === 'never') return ok();
|
|
350
|
+
|
|
347
351
|
if (Array.isArray(spec)) {
|
|
348
352
|
return validateEnumValue(value, spec, path);
|
|
349
353
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { defaultProjectColors, mergeProjectColors } from './projectColors';
|
package/src/utils/novaToJson.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Node, NodeData } from '../types/Node';
|
|
2
|
-
import {
|
|
2
|
+
import { ProjectBase } from '../types/Project';
|
|
3
3
|
//TODO: deprecated olmasına rağmen snapshot testi ekle
|
|
4
4
|
/**
|
|
5
5
|
* @deprecated Legacy converter for old "nova" onboard JSON formats.
|
|
@@ -226,7 +226,6 @@ function buildCarouselItem(
|
|
|
226
226
|
const flex = attrs?.flex ? Number(attrs.flex) : undefined;
|
|
227
227
|
|
|
228
228
|
// Normalize events and compute Navigate target indices when resolvable
|
|
229
|
-
let targetIndex: number | undefined = undefined;
|
|
230
229
|
//@eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
231
230
|
const actions = (attrs?.actions || []) as any[];
|
|
232
231
|
const normalizedEvents: {
|
|
@@ -263,9 +262,6 @@ function buildCarouselItem(
|
|
|
263
262
|
? { targetIndex: pageKeyToIndex.get(nextKey!)! }
|
|
264
263
|
: {}),
|
|
265
264
|
});
|
|
266
|
-
if (hasTarget) {
|
|
267
|
-
targetIndex = pageKeyToIndex.get(nextKey!)!;
|
|
268
|
-
}
|
|
269
265
|
}
|
|
270
266
|
}
|
|
271
267
|
}
|
package/src/utils/parseColor.ts
CHANGED
|
@@ -19,6 +19,7 @@ export function parseColor(value?: string, options: ParseColorOptions = {}) {
|
|
|
19
19
|
if (trimmed.startsWith(STATIC_PREFIX)) {
|
|
20
20
|
const token = trimmed.slice(STATIC_PREFIX.length);
|
|
21
21
|
const resolved = projectColors.STATIC_COLORS?.[token];
|
|
22
|
+
console.log('resolved', value, resolved);
|
|
22
23
|
return typeof resolved === 'string' && resolved.trim()
|
|
23
24
|
? resolved.trim()
|
|
24
25
|
: trimmed;
|
package/src/utils/patterns.ts
CHANGED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ProjectColors,
|
|
3
|
+
ProjectColorTokenMap,
|
|
4
|
+
ProjectThemeColors,
|
|
5
|
+
} from '../types/Project';
|
|
6
|
+
|
|
7
|
+
export const defaultProjectColors: ProjectColors = {
|
|
8
|
+
STATIC_COLORS: {
|
|
9
|
+
BLACK: '#000',
|
|
10
|
+
WHITE: '#FFFFFF',
|
|
11
|
+
TRANSPARENT: '#ffffff00',
|
|
12
|
+
ONBOARD_DOT_INACTIVE: '#E4E5E7',
|
|
13
|
+
ONBOARD_DOT_ACTIVE: '#007AFF',
|
|
14
|
+
ONBOARD_BUTTON_PRIMARY_BACKGROUND: '#0000FF',
|
|
15
|
+
ONBOARD_BUTTON_PRIMARY_TEXT: '#000',
|
|
16
|
+
ONBOARD_LINK_COLOR: '#1778F2',
|
|
17
|
+
ONBOARD_SEPARATOR_COLOR: '#44454D',
|
|
18
|
+
},
|
|
19
|
+
THEME_COLORS: {
|
|
20
|
+
light: {
|
|
21
|
+
TEXT: '#161827',
|
|
22
|
+
BACKGROUND: '#F4F5FF',
|
|
23
|
+
ICON: '#0450E2',
|
|
24
|
+
LINE: '#E9EBF9',
|
|
25
|
+
ONBOARD_TITLE: '#161827',
|
|
26
|
+
ONBOARD_SUBTITLE: '#44454D',
|
|
27
|
+
ONBOARD_BUTTON_SECONDARY_TEXT: '#81838F',
|
|
28
|
+
ONBOARD_FOOTER_TEXT: '#81838F',
|
|
29
|
+
},
|
|
30
|
+
dark: {
|
|
31
|
+
TEXT: '#E9EBF9',
|
|
32
|
+
BACKGROUND: '#080A17',
|
|
33
|
+
ICON: '#0450E2',
|
|
34
|
+
LINE: '#161827',
|
|
35
|
+
ONBOARD_TITLE: '#FDFDFD',
|
|
36
|
+
ONBOARD_SUBTITLE: '#C7C7C7',
|
|
37
|
+
ONBOARD_BUTTON_SECONDARY_TEXT: '#A9AAAC',
|
|
38
|
+
ONBOARD_FOOTER_TEXT: '#A2A4B1',
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Merges custom project colors with base colors.
|
|
45
|
+
* Custom colors override base colors on a per-token basis.
|
|
46
|
+
*/
|
|
47
|
+
export function mergeProjectColors(
|
|
48
|
+
baseColors: ProjectColors,
|
|
49
|
+
customColors: ProjectColors,
|
|
50
|
+
): ProjectColors {
|
|
51
|
+
const staticColors: ProjectColorTokenMap = {
|
|
52
|
+
...baseColors.STATIC_COLORS,
|
|
53
|
+
...(customColors.STATIC_COLORS || {}),
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const themeColors: ProjectThemeColors = {
|
|
57
|
+
light: {
|
|
58
|
+
...(baseColors.THEME_COLORS?.light || {}),
|
|
59
|
+
...(customColors.THEME_COLORS?.light || {}),
|
|
60
|
+
},
|
|
61
|
+
dark: {
|
|
62
|
+
...(baseColors.THEME_COLORS?.dark || {}),
|
|
63
|
+
...(customColors.THEME_COLORS?.dark || {}),
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
STATIC_COLORS: staticColors,
|
|
69
|
+
THEME_COLORS: themeColors,
|
|
70
|
+
};
|
|
71
|
+
}
|