@developer_tribe/react-builder 1.2.22 → 1.2.23
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/attribute-analyser/style/native/useExtractImageStyle.d.ts +2 -2
- package/dist/build-components/Image/ImageProps.generated.d.ts +2 -4
- package/dist/build-components/NavigationBarColor/NavigationBarColor.d.ts +5 -0
- package/dist/build-components/NavigationBarColor/NavigationBarColorProps.generated.d.ts +54 -0
- package/dist/build-components/OnboardImage/OnboardImageProps.generated.d.ts +1 -3
- package/dist/build-components/Separator/Separator.d.ts +5 -0
- package/dist/build-components/Separator/SeparatorProps.generated.d.ts +21 -0
- package/dist/build-components/StatusBarColor/StatusBarColor.d.ts +5 -0
- package/dist/build-components/StatusBarColor/StatusBarColorProps.generated.d.ts +54 -0
- package/dist/build-components/index.d.ts +4 -1
- package/dist/build-components/patterns.generated.d.ts +2105 -1253
- package/dist/components/AttributesEditorPanel.d.ts +1 -1
- package/dist/components/BuilderProvider.d.ts +1 -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 +6 -6
- package/dist/index.web.cjs.js.map +1 -1
- package/dist/index.web.esm.js +4 -4
- package/dist/index.web.esm.js.map +1 -1
- package/dist/store.d.ts +4 -0
- package/dist/styles.css +1 -1
- package/dist/utils/attributeStyle.d.ts +9 -0
- package/dist/utils/extractImageStyle.d.ts +1 -1
- package/dist/utils/extractViewStyle/extractViewStyleNative.d.ts +1 -1
- package/package.json +2 -2
- package/src/DeviceMockFrame.tsx +8 -2
- package/src/assets/meta.json +1 -1
- package/src/assets/samples/paywall-1.json +39 -34
- package/src/assets/samples/paywall-2.json +39 -20
- package/src/assets/samples/paywall-app-delete-offer.json +40 -21
- package/src/assets/samples/paywall-app-open-offer.json +40 -21
- package/src/assets/samples/paywall-back-offer.json +40 -21
- package/src/assets/samples/paywall-notification-offer.json +40 -21
- package/src/assets/samples/vpn-onboard-1.json +84 -39
- package/src/assets/samples/vpn-onboard-2.json +85 -40
- package/src/assets/samples/vpn-onboard-3.json +84 -39
- package/src/assets/samples/vpn-onboard-4.json +84 -39
- package/src/assets/samples/vpn-onboard-5.json +102 -55
- package/src/assets/samples/vpn-onboard-6.json +87 -38
- package/src/attribute-analyser/style/native/useExtractImageStyle.ts +24 -22
- package/src/attribute-analyser/style/native/useExtractTextStyle.ts +9 -4
- package/src/attribute-analyser/style/native/useExtractViewStyle.ts +19 -7
- package/src/attributes-editor/useAttributesEditorModel.ts +23 -17
- package/src/build-components/BackgroundImage/pattern.json +9 -7
- package/src/build-components/CarouselDots/CarouselDots.tsx +12 -11
- package/src/build-components/CarouselProvider/CarouselProvider.tsx +3 -1
- package/src/build-components/Image/ImageProps.generated.ts +2 -4
- package/src/build-components/Image/pattern.json +12 -25
- package/src/build-components/NavigationBarColor/NavigationBarColor.tsx +39 -0
- package/src/build-components/NavigationBarColor/NavigationBarColorProps.generated.ts +71 -0
- package/src/build-components/NavigationBarColor/pattern.json +34 -0
- package/src/build-components/OnboardButtons/OnboardButtons.tsx +8 -10
- package/src/build-components/OnboardDot/OnboardDot.tsx +12 -10
- package/src/build-components/OnboardImage/OnboardImage.tsx +1 -1
- package/src/build-components/OnboardImage/OnboardImageProps.generated.ts +1 -3
- package/src/build-components/OnboardProvider/OnboardProvider.tsx +3 -1
- package/src/build-components/RenderNode.generated.tsx +15 -0
- package/src/build-components/Separator/Separator.tsx +41 -0
- package/src/build-components/Separator/SeparatorProps.generated.ts +26 -0
- package/src/build-components/Separator/pattern.json +59 -0
- package/src/build-components/StatusBarColor/StatusBarColor.tsx +39 -0
- package/src/build-components/StatusBarColor/StatusBarColorProps.generated.ts +71 -0
- package/src/build-components/StatusBarColor/pattern.json +34 -0
- package/src/build-components/Text/pattern.json +45 -38
- package/src/build-components/index.ts +15 -0
- package/src/build-components/patterns.generated.ts +2149 -1272
- package/src/build-components/useNode.ts +24 -25
- package/src/components/AttributesEditorPanel.tsx +4 -5
- package/src/components/Builder.tsx +1 -2
- package/src/components/BuilderProvider.tsx +40 -3
- package/src/components/JsonTextEditor.tsx +2 -2
- package/src/components/LoadingComponent.tsx +1 -1
- package/src/components/RenderErrorBoundary.tsx +1 -3
- package/src/migrations/migrations/1.1.2_extract_component_attributes_from_style.ts +3 -3
- package/src/modals/BenefitPresetsModal.tsx +1 -1
- package/src/modals/ProductPresetsModal.tsx +1 -1
- package/src/pages/DebugJsonPage.tsx +7 -4
- package/src/pages/ProjectDebug.tsx +1 -1
- package/src/pages/ProjectPage.tsx +31 -32
- package/src/pages/ProjectValidationPage.tsx +2 -2
- package/src/store.ts +13 -0
- package/src/styles/layout/_builder.scss +6 -0
- package/src/utils/__special_exceptions.ts +5 -5
- package/src/utils/analyseNode.ts +2 -2
- package/src/utils/analyseNodeByPatterns.ts +10 -9
- package/src/utils/analyseNodeStructural.ts +1 -1
- package/src/utils/attributeStyle.ts +26 -0
- package/src/utils/extractImageStyle.ts +17 -13
- package/src/utils/extractTextStyle/extractTextStyle.ts +7 -7
- package/src/utils/extractTextStyle/extractTextStyleNative.ts +10 -10
- package/src/utils/extractViewStyle/extractViewStyle.ts +8 -11
- package/src/utils/extractViewStyle/extractViewStyleNative.ts +19 -19
- package/src/utils/loadFontFamily.ts +14 -19
- package/src/utils/logRenderStore.ts +5 -4
- package/src/utils/nodeTree.ts +1 -1
- package/src/utils/patterns.ts +26 -31
- package/src/utils/repairNodeKeys.ts +5 -7
- package/src/utils/wrapNodeInMain.ts +3 -3
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared utilities for attribute/style bag access.
|
|
3
|
+
* schemaVersion=2 uses `attributes.styles`, legacy uses `attributes.style`.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { NodeDefaultAttribute } from '../types/Node';
|
|
7
|
+
|
|
8
|
+
/** Returns styles or style bag from attributes (schemaVersion=2 uses styles, legacy uses style). */
|
|
9
|
+
export function getStyleBag(
|
|
10
|
+
attributes: NodeDefaultAttribute | undefined,
|
|
11
|
+
): Record<string, unknown> | undefined {
|
|
12
|
+
const record = toAttributeRecord(attributes);
|
|
13
|
+
const bag = record.styles ?? record.style;
|
|
14
|
+
return isPlainObject(bag) ? (bag as Record<string, unknown>) : undefined;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Safe indexed access to attributes. Use for reading style/direct props. */
|
|
18
|
+
export function toAttributeRecord(
|
|
19
|
+
attributes: unknown,
|
|
20
|
+
): Record<string, unknown> {
|
|
21
|
+
return (attributes ?? {}) as Record<string, unknown>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
25
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
26
|
+
}
|
|
@@ -1,26 +1,29 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type ImagePropsGenerated,
|
|
3
|
+
type ResizeModeOptionType,
|
|
4
|
+
} from '../build-components/Image/ImageProps.generated';
|
|
2
5
|
import type { NodeData } from '../types/Node';
|
|
3
6
|
import {
|
|
4
7
|
extractViewStyle,
|
|
5
8
|
extractViewStyleNative,
|
|
6
9
|
ExtractViewStyleOptions,
|
|
7
10
|
} from './extractViewStyle';
|
|
11
|
+
import { getStyleBag } from './attributeStyle';
|
|
8
12
|
|
|
9
13
|
export function extractImageStyle<T extends ImagePropsGenerated['attributes']>(
|
|
10
14
|
node: NodeData<T>,
|
|
11
15
|
options: ExtractViewStyleOptions = {},
|
|
12
16
|
) {
|
|
13
17
|
const attributes = node.attributes;
|
|
14
|
-
const styleBag = (attributes as any)?.style as
|
|
15
|
-
| Record<string, unknown>
|
|
16
|
-
| undefined;
|
|
17
18
|
const style: React.CSSProperties = {};
|
|
18
19
|
|
|
19
20
|
if (!attributes) return style;
|
|
20
21
|
|
|
21
|
-
// Map resizeMode to CSS object-fit
|
|
22
|
-
const
|
|
23
|
-
|
|
22
|
+
// Map resizeMode to CSS object-fit (schemaVersion=2 uses `styles`, fallback to legacy `style`)
|
|
23
|
+
const stylesBag = getStyleBag(attributes) as
|
|
24
|
+
| ImagePropsGenerated['attributes']['style']
|
|
25
|
+
| undefined;
|
|
26
|
+
const resizeMode: ResizeModeOptionType | undefined = stylesBag?.resizeMode;
|
|
24
27
|
if (resizeMode === 'cover') style.objectFit = 'cover';
|
|
25
28
|
else if (resizeMode === 'contain') style.objectFit = 'contain';
|
|
26
29
|
else if (resizeMode === 'stretch') style.objectFit = 'fill';
|
|
@@ -33,18 +36,19 @@ export function extractImageStyleNative<
|
|
|
33
36
|
T extends ImagePropsGenerated['attributes'],
|
|
34
37
|
>(node: NodeData<T>, options: ExtractViewStyleOptions = {}) {
|
|
35
38
|
const attributes = node.attributes;
|
|
36
|
-
const styleBag = (attributes as any)?.style as
|
|
37
|
-
| Record<string, unknown>
|
|
38
|
-
| undefined;
|
|
39
39
|
if (!attributes) return {};
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
// schemaVersion=2 uses `styles`, fallback to legacy `style`
|
|
42
|
+
const nativeStylesBag = getStyleBag(attributes) as
|
|
43
|
+
| ImagePropsGenerated['attributes']['style']
|
|
44
|
+
| undefined;
|
|
45
|
+
const resizeMode: ResizeModeOptionType | undefined =
|
|
46
|
+
nativeStylesBag?.resizeMode;
|
|
43
47
|
|
|
44
48
|
// In RN, resizeMode is usually an Image prop, but many codebases also accept it on ImageStyle.
|
|
45
49
|
// We return it here so consumers can pass it through as they prefer.
|
|
46
50
|
const nativeStyle: Record<string, unknown> = {};
|
|
47
51
|
if (resizeMode) nativeStyle.resizeMode = resizeMode;
|
|
48
52
|
|
|
49
|
-
return { ...extractViewStyleNative(node, options
|
|
53
|
+
return { ...extractViewStyleNative(node, options), ...nativeStyle };
|
|
50
54
|
}
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
resolveClosestFontWeightKey,
|
|
18
18
|
} from '../loadFontFamily';
|
|
19
19
|
import { fontsDebug } from '../fontsDebug';
|
|
20
|
+
import { getStyleBag, toAttributeRecord } from '../attributeStyle';
|
|
20
21
|
|
|
21
22
|
const inFlightFontLoads: Map<string, Promise<void>> = new Map<
|
|
22
23
|
string,
|
|
@@ -97,11 +98,10 @@ export function extractTextStyle<T extends TextPropsGenerated['attributes']>(
|
|
|
97
98
|
options: ExtractTextStyleOptions = {},
|
|
98
99
|
) {
|
|
99
100
|
const attributes = node.attributes;
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
| undefined;
|
|
101
|
+
const attrRecord = toAttributeRecord(attributes);
|
|
102
|
+
const styleBag = getStyleBag(attributes) as TextStyleGenerated | undefined;
|
|
103
103
|
const get = (key: string): unknown => {
|
|
104
|
-
const direct =
|
|
104
|
+
const direct = attrRecord[key];
|
|
105
105
|
if (direct !== undefined && direct !== null) return direct;
|
|
106
106
|
return styleBag?.[key as keyof TextStyleGenerated];
|
|
107
107
|
};
|
|
@@ -199,15 +199,15 @@ export function extractTextStyle<T extends TextPropsGenerated['attributes']>(
|
|
|
199
199
|
'textTransform',
|
|
200
200
|
]);
|
|
201
201
|
|
|
202
|
-
const textStyle:
|
|
202
|
+
const textStyle: Record<string, unknown> = {};
|
|
203
203
|
for (const key in fullStyle) {
|
|
204
204
|
const typedKey = key as keyof React.CSSProperties;
|
|
205
205
|
if (textStyleProperties.has(typedKey)) {
|
|
206
|
-
|
|
206
|
+
textStyle[key] = fullStyle[typedKey];
|
|
207
207
|
}
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
-
return textStyle;
|
|
210
|
+
return textStyle as React.CSSProperties;
|
|
211
211
|
}
|
|
212
212
|
|
|
213
213
|
return fullStyle;
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
findFontDefinition,
|
|
13
13
|
resolveClosestFontWeightKey,
|
|
14
14
|
} from '../loadFontFamily';
|
|
15
|
+
import { getStyleBag, toAttributeRecord } from '../attributeStyle';
|
|
15
16
|
|
|
16
17
|
export type ExtractTextStyleNativeOptions = {
|
|
17
18
|
appConfig?: AppConfig;
|
|
@@ -37,11 +38,10 @@ export function extractTextStyleNative<
|
|
|
37
38
|
T extends TextPropsGenerated['attributes'],
|
|
38
39
|
>(node: NodeData<T>, options: ExtractTextStyleNativeOptions = {}) {
|
|
39
40
|
const attributes = node.attributes;
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
| undefined;
|
|
41
|
+
const attrRecord = toAttributeRecord(attributes);
|
|
42
|
+
const styleBag = getStyleBag(attributes);
|
|
43
43
|
const get = (key: string): unknown => {
|
|
44
|
-
const direct =
|
|
44
|
+
const direct = attrRecord[key];
|
|
45
45
|
if (direct !== undefined && direct !== null) return direct;
|
|
46
46
|
return styleBag?.[key];
|
|
47
47
|
};
|
|
@@ -58,13 +58,13 @@ export function extractTextStyleNative<
|
|
|
58
58
|
return style;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
const rawFontSize = get('fontSize') as
|
|
61
|
+
const rawFontSize = get('fontSize') as string | number | undefined;
|
|
62
62
|
const parsedFontSize = parseSize(rawFontSize);
|
|
63
63
|
if (typeof parsedFontSize === 'number') style.fontSize = parsedFontSize;
|
|
64
64
|
else style.fontSize = fs(14);
|
|
65
65
|
|
|
66
|
-
const fontFamily = get('fontFamily') as
|
|
67
|
-
const fontWeight = get('fontWeight') as
|
|
66
|
+
const fontFamily = get('fontFamily') as string | undefined;
|
|
67
|
+
const fontWeight = get('fontWeight') as string | number | undefined;
|
|
68
68
|
const requestedWeight = weightToNumericKey(fontWeight);
|
|
69
69
|
const normalizedFontFamily =
|
|
70
70
|
typeof fontFamily === 'string' && fontFamily.trim().length > 0
|
|
@@ -89,14 +89,14 @@ export function extractTextStyleNative<
|
|
|
89
89
|
if (!normalizedFontFamily && normalizedFontWeight)
|
|
90
90
|
style.fontWeight = normalizedFontWeight;
|
|
91
91
|
|
|
92
|
-
const resolvedTextColor = parseColor(get('color') as
|
|
92
|
+
const resolvedTextColor = parseColor(get('color') as string | undefined, {
|
|
93
93
|
projectColors: options.projectColors,
|
|
94
94
|
theme,
|
|
95
95
|
});
|
|
96
96
|
style.color = resolvedTextColor ?? fallbackColor;
|
|
97
97
|
|
|
98
|
-
const textAlign = get('textAlign');
|
|
99
|
-
if (textAlign) style.textAlign = textAlign
|
|
98
|
+
const textAlign = get('textAlign') as string | undefined;
|
|
99
|
+
if (textAlign) style.textAlign = textAlign;
|
|
100
100
|
|
|
101
101
|
const viewStyle = extractViewStyleNative(node, {
|
|
102
102
|
projectColors: options.projectColors,
|
|
@@ -6,6 +6,7 @@ import type { NodeData } from '../../types/Node';
|
|
|
6
6
|
import type { ProjectColors } from '../../types/Project';
|
|
7
7
|
import { parseSize } from '../../size-matters';
|
|
8
8
|
import { parseColor } from '../parseColor';
|
|
9
|
+
import { getStyleBag, toAttributeRecord } from '../attributeStyle';
|
|
9
10
|
|
|
10
11
|
export type ExtractViewStyleOptions = {
|
|
11
12
|
projectColors?: ProjectColors;
|
|
@@ -17,11 +18,10 @@ export function extractViewStyle<T extends ViewPropsGenerated['attributes']>(
|
|
|
17
18
|
options: ExtractViewStyleOptions = {},
|
|
18
19
|
) {
|
|
19
20
|
const attributes = node.attributes;
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
| undefined;
|
|
21
|
+
const attrRecord = toAttributeRecord(attributes);
|
|
22
|
+
const styleBag = getStyleBag(attributes) as ViewStyleGenerated | undefined;
|
|
23
23
|
const get = (key: string): unknown => {
|
|
24
|
-
const direct =
|
|
24
|
+
const direct = attrRecord[key];
|
|
25
25
|
if (direct !== undefined && direct !== null) return direct;
|
|
26
26
|
return styleBag?.[key as keyof ViewStyleGenerated];
|
|
27
27
|
};
|
|
@@ -112,10 +112,7 @@ export function extractViewStyle<T extends ViewPropsGenerated['attributes']>(
|
|
|
112
112
|
);
|
|
113
113
|
|
|
114
114
|
const marginHorizontalRaw =
|
|
115
|
-
(
|
|
116
|
-
| string
|
|
117
|
-
| number
|
|
118
|
-
| undefined) ??
|
|
115
|
+
(attrRecord.marginHorizontal as string | number | undefined) ??
|
|
119
116
|
(styleBag?.marginHorizontal as string | number | undefined);
|
|
120
117
|
if (!isEmptySizeValue(marginHorizontalRaw)) {
|
|
121
118
|
const parsed = parseSize(marginHorizontalRaw);
|
|
@@ -209,13 +206,13 @@ export function extractViewStyle<T extends ViewPropsGenerated['attributes']>(
|
|
|
209
206
|
'overflowY',
|
|
210
207
|
]);
|
|
211
208
|
|
|
212
|
-
const filteredStyle:
|
|
209
|
+
const filteredStyle: Record<string, unknown> = {};
|
|
213
210
|
for (const key in style) {
|
|
214
211
|
const typedKey = key as keyof React.CSSProperties;
|
|
215
212
|
if (viewStyleProperties.has(typedKey)) {
|
|
216
|
-
|
|
213
|
+
filteredStyle[key] = style[typedKey];
|
|
217
214
|
}
|
|
218
215
|
}
|
|
219
216
|
|
|
220
|
-
return filteredStyle;
|
|
217
|
+
return filteredStyle as React.CSSProperties;
|
|
221
218
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { ViewPropsGenerated } from '../../build-components/View/ViewProps.generated';
|
|
1
|
+
import type { ViewPropsGenerated } from '../../build-components/View/ViewProps.generated';
|
|
2
2
|
import type { NodeData } from '../../types/Node';
|
|
3
3
|
import type { ProjectColors } from '../../types/Project';
|
|
4
4
|
import { parseSize } from '../../size-matters';
|
|
5
5
|
import { parseColor } from '../parseColor';
|
|
6
|
+
import { getStyleBag, toAttributeRecord } from '../attributeStyle';
|
|
6
7
|
|
|
7
8
|
export type ExtractViewStyleNativeOptions = {
|
|
8
9
|
projectColors?: ProjectColors;
|
|
@@ -17,11 +18,10 @@ export function extractViewStyleNative<
|
|
|
17
18
|
T extends ViewPropsGenerated['attributes'],
|
|
18
19
|
>(node: NodeData<T>, options: ExtractViewStyleNativeOptions = {}) {
|
|
19
20
|
const attributes = node.attributes;
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
| undefined;
|
|
21
|
+
const attrRecord = toAttributeRecord(attributes);
|
|
22
|
+
const styleBag = getStyleBag(attributes);
|
|
23
23
|
const get = (key: string): unknown => {
|
|
24
|
-
const direct =
|
|
24
|
+
const direct = attrRecord[key];
|
|
25
25
|
if (direct !== undefined && direct !== null) return direct;
|
|
26
26
|
return styleBag?.[key];
|
|
27
27
|
};
|
|
@@ -41,18 +41,18 @@ export function extractViewStyleNative<
|
|
|
41
41
|
// We intentionally do not map it to overflowX/Y.
|
|
42
42
|
|
|
43
43
|
const flexDirection = get('flexDirection');
|
|
44
|
-
if (flexDirection) style.flexDirection = flexDirection
|
|
44
|
+
if (flexDirection) style.flexDirection = String(flexDirection);
|
|
45
45
|
const alignItems = get('alignItems');
|
|
46
|
-
if (alignItems) style.alignItems = alignItems
|
|
46
|
+
if (alignItems) style.alignItems = String(alignItems);
|
|
47
47
|
const justifyContent = get('justifyContent');
|
|
48
|
-
if (justifyContent) style.justifyContent = justifyContent
|
|
48
|
+
if (justifyContent) style.justifyContent = String(justifyContent);
|
|
49
49
|
|
|
50
50
|
const setParsedSize = (property: string, rawValue: unknown) => {
|
|
51
51
|
if (isEmptySizeValue(rawValue)) return;
|
|
52
|
-
const parsed = parseSize(rawValue as
|
|
52
|
+
const parsed = parseSize(rawValue as string | number);
|
|
53
53
|
// RN generally expects numbers (dp). We allow percentages for width/height-like props.
|
|
54
54
|
if (typeof parsed === 'number' || typeof parsed === 'string') {
|
|
55
|
-
|
|
55
|
+
style[property] = parsed;
|
|
56
56
|
}
|
|
57
57
|
};
|
|
58
58
|
|
|
@@ -68,7 +68,7 @@ export function extractViewStyleNative<
|
|
|
68
68
|
setParsedSize('margin', get('margin'));
|
|
69
69
|
setParsedSize(
|
|
70
70
|
'marginHorizontal',
|
|
71
|
-
|
|
71
|
+
attrRecord.marginHorizontal ?? styleBag?.marginHorizontal,
|
|
72
72
|
);
|
|
73
73
|
setParsedSize('marginVertical', get('marginVertical'));
|
|
74
74
|
setParsedSize('marginTop', get('marginTop'));
|
|
@@ -76,9 +76,9 @@ export function extractViewStyleNative<
|
|
|
76
76
|
setParsedSize('marginLeft', get('marginLeft'));
|
|
77
77
|
setParsedSize('marginRight', get('marginRight'));
|
|
78
78
|
|
|
79
|
-
const backgroundColor = get('backgroundColor') as
|
|
79
|
+
const backgroundColor = get('backgroundColor') as string | undefined;
|
|
80
80
|
if (backgroundColor) {
|
|
81
|
-
|
|
81
|
+
style.backgroundColor =
|
|
82
82
|
parseColor(backgroundColor, {
|
|
83
83
|
projectColors: options.projectColors,
|
|
84
84
|
theme: options.theme,
|
|
@@ -93,19 +93,19 @@ export function extractViewStyleNative<
|
|
|
93
93
|
setParsedSize('minHeight', get('minHeight'));
|
|
94
94
|
setParsedSize('maxHeight', get('maxHeight'));
|
|
95
95
|
|
|
96
|
-
const flex = get('flex') as
|
|
97
|
-
if (flex !== undefined)
|
|
96
|
+
const flex = get('flex') as number | undefined;
|
|
97
|
+
if (flex !== undefined) style.flex = flex;
|
|
98
98
|
|
|
99
|
-
const position = get('position') as
|
|
100
|
-
if (position)
|
|
99
|
+
const position = get('position') as string | undefined;
|
|
100
|
+
if (position) style.position = position;
|
|
101
101
|
|
|
102
102
|
setParsedSize('top', get('top'));
|
|
103
103
|
setParsedSize('bottom', get('bottom'));
|
|
104
104
|
setParsedSize('left', get('left'));
|
|
105
105
|
setParsedSize('right', get('right'));
|
|
106
106
|
|
|
107
|
-
const zIndex = get('zIndex') as
|
|
108
|
-
if (zIndex !== undefined)
|
|
107
|
+
const zIndex = get('zIndex') as number | undefined;
|
|
108
|
+
if (zIndex !== undefined) style.zIndex = zIndex;
|
|
109
109
|
|
|
110
110
|
return style;
|
|
111
111
|
}
|
|
@@ -124,25 +124,20 @@ export async function loadFontFamily(
|
|
|
124
124
|
// Not a browser environment (SSR / RN): do nothing.
|
|
125
125
|
if (typeof document === 'undefined') return;
|
|
126
126
|
|
|
127
|
-
const fontsApi =
|
|
128
|
-
if (!fontsApi || typeof
|
|
127
|
+
const fontsApi = document.fonts;
|
|
128
|
+
if (!fontsApi || typeof globalThis.FontFace !== 'function') {
|
|
129
129
|
throw new Error('Font loading is not supported in this environment');
|
|
130
130
|
}
|
|
131
|
-
const safeFontsApi = fontsApi as FontFaceSet;
|
|
132
131
|
|
|
133
132
|
function hasLoadedFace(familyName: string, weight: string): boolean {
|
|
134
133
|
try {
|
|
135
|
-
const
|
|
136
|
-
for (const face of set) {
|
|
137
|
-
const f = face as unknown as {
|
|
138
|
-
family?: string;
|
|
139
|
-
weight?: string;
|
|
140
|
-
status?: string;
|
|
141
|
-
};
|
|
134
|
+
for (const face of fontsApi) {
|
|
142
135
|
const fam =
|
|
143
|
-
typeof
|
|
144
|
-
|
|
145
|
-
|
|
136
|
+
typeof face.family === 'string'
|
|
137
|
+
? face.family.replace(/['"]/g, '')
|
|
138
|
+
: '';
|
|
139
|
+
const w = typeof face.weight === 'string' ? face.weight.trim() : '';
|
|
140
|
+
if (fam === familyName && w === weight && face.status === 'loaded') {
|
|
146
141
|
return true;
|
|
147
142
|
}
|
|
148
143
|
}
|
|
@@ -251,17 +246,17 @@ export async function loadFontFamily(
|
|
|
251
246
|
}
|
|
252
247
|
|
|
253
248
|
async function loadAndAdd(src: string | ArrayBuffer, label: string) {
|
|
254
|
-
const face = new
|
|
249
|
+
const face = new FontFace(name, src, {
|
|
255
250
|
weight: preferWeight,
|
|
256
251
|
display: 'swap',
|
|
257
|
-
})
|
|
252
|
+
});
|
|
258
253
|
fontsDebug.info('loadFontFamily: FontFace.load() begin', {
|
|
259
254
|
familyName: name,
|
|
260
255
|
weight: preferWeight,
|
|
261
256
|
source: label,
|
|
262
257
|
});
|
|
263
258
|
const loaded = await face.load();
|
|
264
|
-
|
|
259
|
+
fontsApi.add(loaded);
|
|
265
260
|
fontsDebug.info('loadFontFamily: loaded + added to document.fonts', {
|
|
266
261
|
familyName: name,
|
|
267
262
|
weight: preferWeight,
|
|
@@ -296,18 +291,18 @@ export async function loadFontFamily(
|
|
|
296
291
|
|
|
297
292
|
try {
|
|
298
293
|
const afterQuery = `${preferWeight} 16px "${name}"`;
|
|
299
|
-
const after =
|
|
294
|
+
const after = fontsApi.check(afterQuery);
|
|
300
295
|
fontsDebug.info('loadFontFamily: document.fonts.check after add', {
|
|
301
296
|
familyName: name,
|
|
302
297
|
weight: preferWeight,
|
|
303
298
|
result: after,
|
|
304
299
|
});
|
|
305
300
|
// Force the browser to "activate" the face for this query (and reveal errors if any).
|
|
306
|
-
if (typeof
|
|
301
|
+
if (typeof fontsApi.load === 'function') {
|
|
307
302
|
fontsDebug.info('loadFontFamily: document.fonts.load begin', {
|
|
308
303
|
query: afterQuery,
|
|
309
304
|
});
|
|
310
|
-
await
|
|
305
|
+
await fontsApi.load(afterQuery);
|
|
311
306
|
fontsDebug.info('loadFontFamily: document.fonts.load done', {
|
|
312
307
|
query: afterQuery,
|
|
313
308
|
});
|
|
@@ -67,20 +67,21 @@ export function logRenderStore(options: LogRenderStoreOptions = {}): void {
|
|
|
67
67
|
const { label, includeLocalStorage = true, extra } = options;
|
|
68
68
|
|
|
69
69
|
const state = useRenderStore.getState();
|
|
70
|
-
const
|
|
70
|
+
const stateRecord = state as Record<string, unknown>;
|
|
71
|
+
const keys = Object.keys(stateRecord).sort();
|
|
71
72
|
|
|
72
73
|
const snapshot: Record<string, unknown> = {};
|
|
73
74
|
const actions: string[] = [];
|
|
74
75
|
|
|
75
76
|
for (const key of keys) {
|
|
76
|
-
const v =
|
|
77
|
+
const v = stateRecord[key];
|
|
77
78
|
if (isFn(v)) actions.push(key);
|
|
78
79
|
else snapshot[key] = v;
|
|
79
80
|
}
|
|
80
81
|
|
|
81
82
|
const title = `[RB Debug] Render store${label ? ` (${label})` : ''}`;
|
|
82
|
-
const groupCollapsed =
|
|
83
|
-
const groupEnd =
|
|
83
|
+
const groupCollapsed = console.groupCollapsed as unknown;
|
|
84
|
+
const groupEnd = console.groupEnd as unknown;
|
|
84
85
|
|
|
85
86
|
if (isFn(groupCollapsed)) groupCollapsed(title);
|
|
86
87
|
else {
|
package/src/utils/nodeTree.ts
CHANGED
|
@@ -19,7 +19,7 @@ export function deleteNodeFromTree(root: Node, target: Node): Node {
|
|
|
19
19
|
return changed ? nextChildren : root;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
const data = root as
|
|
22
|
+
const data = root as NodeData;
|
|
23
23
|
if ('children' in data) {
|
|
24
24
|
const prev = data.children as Node;
|
|
25
25
|
if (!prev) return root;
|
package/src/utils/patterns.ts
CHANGED
|
@@ -61,7 +61,7 @@ type Pattern = {
|
|
|
61
61
|
meta?: PatternMeta;
|
|
62
62
|
};
|
|
63
63
|
|
|
64
|
-
const patterns
|
|
64
|
+
const patterns = generatedPatterns as unknown as Pattern[];
|
|
65
65
|
|
|
66
66
|
export type BuilderPlatform = 'web' | 'native';
|
|
67
67
|
|
|
@@ -86,16 +86,22 @@ export const NON_STYLE_ATTRIBUTE_KEYS = new Set<string>([
|
|
|
86
86
|
* known non-style props (behavior flags).
|
|
87
87
|
*/
|
|
88
88
|
export function getStyleAttributeKeySet(): Set<string> {
|
|
89
|
-
const viewSchema = getAttributeSchema('View') ?? {}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
89
|
+
const viewSchema = (getAttributeSchema('View') ?? {}) as Record<
|
|
90
|
+
string,
|
|
91
|
+
unknown
|
|
92
|
+
>;
|
|
93
|
+
const textSchema = (getAttributeSchema('Text') ?? {}) as Record<
|
|
94
|
+
string,
|
|
95
|
+
unknown
|
|
96
|
+
>;
|
|
97
|
+
const getNestedStyleKeys = (schema: Record<string, unknown>): string[] => {
|
|
98
|
+
const nested = schema.style;
|
|
99
|
+
return typeof nested === 'object' && nested
|
|
100
|
+
? Object.keys(nested)
|
|
101
|
+
: Object.keys(schema);
|
|
102
|
+
};
|
|
103
|
+
const viewStyle = getNestedStyleKeys(viewSchema);
|
|
104
|
+
const textStyle = getNestedStyleKeys(textSchema);
|
|
99
105
|
const out = new Set<string>([...viewStyle, ...textStyle]);
|
|
100
106
|
for (const k of NON_STYLE_ATTRIBUTE_KEYS) out.delete(k);
|
|
101
107
|
return out;
|
|
@@ -209,23 +215,18 @@ export function getAttributeMeta(
|
|
|
209
215
|
const attributes = p?.meta?.attributes;
|
|
210
216
|
|
|
211
217
|
// Some patterns store style meta under `meta.attributes.styles` (nested) instead of `meta.styles`.
|
|
218
|
+
const attrsRecord = attributes as Record<string, unknown> | undefined;
|
|
212
219
|
const nestedStyles =
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
(attributes as any).styles &&
|
|
216
|
-
typeof (attributes as any).styles === 'object'
|
|
217
|
-
? ((attributes as any).styles as Record<string, AttributeMeta>)
|
|
220
|
+
attrsRecord && typeof attrsRecord.styles === 'object' && attrsRecord.styles
|
|
221
|
+
? (attrsRecord.styles as Record<string, AttributeMeta>)
|
|
218
222
|
: undefined;
|
|
219
223
|
|
|
220
224
|
// When `meta.attributes.styles` exists, treat `meta.attributes` (minus `styles`) as non-style meta.
|
|
221
|
-
const attributesWithoutNestedStyles =
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
),
|
|
227
|
-
)
|
|
228
|
-
: attributes;
|
|
225
|
+
const attributesWithoutNestedStyles = attrsRecord
|
|
226
|
+
? Object.fromEntries(
|
|
227
|
+
Object.entries(attrsRecord).filter(([k]) => k !== 'styles'),
|
|
228
|
+
)
|
|
229
|
+
: attributes;
|
|
229
230
|
|
|
230
231
|
// schemaVersion=2 prefers `meta.styles` but some repos split UI meta into:
|
|
231
232
|
// - meta.styles: style-tab fields
|
|
@@ -261,13 +262,7 @@ export function getTypeSchema(
|
|
|
261
262
|
): Record<string, string | string[]> | undefined {
|
|
262
263
|
if (!componentType || !typeName) return undefined;
|
|
263
264
|
const p = getPatternByType(componentType);
|
|
264
|
-
|
|
265
|
-
const types: Record<string, Record<string, string | string[]>> | undefined = (
|
|
266
|
-
p as unknown as {
|
|
267
|
-
types?: Record<string, Record<string, string | string[]>>;
|
|
268
|
-
}
|
|
269
|
-
)?.types;
|
|
270
|
-
return types?.[typeName];
|
|
265
|
+
return p?.types?.[typeName];
|
|
271
266
|
}
|
|
272
267
|
|
|
273
268
|
/** Utility: returns true if the type name refers to a primitive scalar */
|
|
@@ -2,13 +2,11 @@ import type { Node, NodeData } from '../types/Node';
|
|
|
2
2
|
import { generateRandomKeyForNode } from './generateRandomKeyForNode';
|
|
3
3
|
|
|
4
4
|
function isNodeDataLike(value: unknown): value is NodeData {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
'children' in (value as any)
|
|
11
|
-
);
|
|
5
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
6
|
+
return false;
|
|
7
|
+
}
|
|
8
|
+
const record = value as Record<string, unknown>;
|
|
9
|
+
return 'type' in record && 'children' in record;
|
|
12
10
|
}
|
|
13
11
|
|
|
14
12
|
function normalizeKey(value: unknown): string | undefined {
|
|
@@ -39,10 +39,10 @@ function stripNestedIsMain(node: Node, isRoot: boolean): Node {
|
|
|
39
39
|
if (!shouldDemote && nextChildren === prevChildren) return node;
|
|
40
40
|
|
|
41
41
|
return {
|
|
42
|
-
...
|
|
42
|
+
...node,
|
|
43
43
|
...(shouldDemote ? { isMain: false } : null),
|
|
44
44
|
children: nextChildren,
|
|
45
|
-
}
|
|
45
|
+
};
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
export function wrapNodeInMain(node: Node): NodeData {
|
|
@@ -50,7 +50,7 @@ export function wrapNodeInMain(node: Node): NodeData {
|
|
|
50
50
|
// Ensure no nested nodes keep `isMain: true`.
|
|
51
51
|
const cleaned = stripNestedIsMain(node, true) as NodeData;
|
|
52
52
|
// Keep root as main.
|
|
53
|
-
if (cleaned.isMain !== true) return { ...
|
|
53
|
+
if (cleaned.isMain !== true) return { ...cleaned, isMain: true };
|
|
54
54
|
return cleaned;
|
|
55
55
|
}
|
|
56
56
|
|