@developer_tribe/react-builder 1.2.23 → 1.2.24
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 +5 -5
- package/dist/attribute-analyser/style/native/useExtractTextStyle.d.ts +6 -4
- package/dist/attribute-analyser/style/native/useExtractViewStyle.d.ts +5 -3
- package/dist/build-components/patterns.generated.d.ts +8 -0
- package/dist/index.cjs.js +2 -2
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +2 -0
- 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/utils/attributeStyle.d.ts +12 -0
- package/package.json +6 -1
- package/src/assets/meta.json +1 -1
- package/src/assets/samples/paywall-1.json +5 -5
- package/src/assets/samples/paywall-2.json +5 -5
- package/src/attribute-analyser/style/native/useExtractImageStyle.ts +19 -15
- package/src/attribute-analyser/style/native/useExtractTextStyle.ts +25 -15
- package/src/attribute-analyser/style/native/useExtractViewStyle.ts +19 -21
- package/src/build-components/Image/pattern.json +3 -0
- package/src/build-components/OnboardButton/OnboardButton.tsx +19 -5
- package/src/build-components/OnboardFooter/OnboardFooter.tsx +15 -4
- package/src/build-components/patterns.generated.ts +4 -0
- package/src/components/BuilderProvider.tsx +6 -6
- package/src/index.ts +3 -0
- package/src/utils/attributeStyle.ts +78 -0
|
@@ -7,3 +7,15 @@ import type { NodeDefaultAttribute } from '../types/Node';
|
|
|
7
7
|
export declare function getStyleBag(attributes: NodeDefaultAttribute | undefined): Record<string, unknown> | undefined;
|
|
8
8
|
/** Safe indexed access to attributes. Use for reading style/direct props. */
|
|
9
9
|
export declare function toAttributeRecord(attributes: unknown): Record<string, unknown>;
|
|
10
|
+
/**
|
|
11
|
+
* All attribute keys that represent visual style properties.
|
|
12
|
+
* Used to separate style keys from non-style (behavioral/content) keys.
|
|
13
|
+
*
|
|
14
|
+
* Keep in sync with ViewStyleGenerated, TextStyleGenerated, and ImageStyleGenerated.
|
|
15
|
+
*/
|
|
16
|
+
declare const STYLE_ATTR_KEYS_LIST: readonly ["style", "styles", "flexDirection", "flexWrap", "alignItems", "justifyContent", "gap", "padding", "paddingHorizontal", "paddingVertical", "paddingTop", "paddingBottom", "paddingLeft", "paddingRight", "margin", "marginHorizontal", "marginVertical", "marginTop", "marginBottom", "marginLeft", "marginRight", "backgroundColor", "borderRadius", "width", "minWidth", "maxWidth", "height", "minHeight", "maxHeight", "flex", "position", "top", "bottom", "left", "right", "zIndex", "color", "fontSize", "fontFamily", "fontWeight", "textAlign", "resizeMode"];
|
|
17
|
+
/** Type-level union of all style attribute keys. Use with `Omit<T, StyleAttrKey>`. */
|
|
18
|
+
export type StyleAttrKey = (typeof STYLE_ATTR_KEYS_LIST)[number];
|
|
19
|
+
/** Strips all visual-style keys from an attributes record, returning only non-style keys. */
|
|
20
|
+
export declare function stripStyleKeys(attrs: Record<string, unknown>): Record<string, unknown>;
|
|
21
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@developer_tribe/react-builder",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.24",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"restricted": true,
|
|
@@ -73,6 +73,7 @@
|
|
|
73
73
|
"lottie-react": "^2.4.1",
|
|
74
74
|
"prettier": "^3.6.2",
|
|
75
75
|
"react": "^18.3.1",
|
|
76
|
+
"react-native": "^0.83.1",
|
|
76
77
|
"rimraf": "^6.0.1",
|
|
77
78
|
"rollup": "^4.52.2",
|
|
78
79
|
"rollup-plugin-peer-deps-external": "^2.2.4",
|
|
@@ -90,12 +91,16 @@
|
|
|
90
91
|
"peerDependencies": {
|
|
91
92
|
"react": ">=17",
|
|
92
93
|
"react-dom": ">=17",
|
|
94
|
+
"react-native": ">=0.70",
|
|
93
95
|
"react-router-dom": ">=6.0.0"
|
|
94
96
|
},
|
|
95
97
|
"peerDependenciesMeta": {
|
|
96
98
|
"react-dom": {
|
|
97
99
|
"optional": true
|
|
98
100
|
},
|
|
101
|
+
"react-native": {
|
|
102
|
+
"optional": true
|
|
103
|
+
},
|
|
99
104
|
"react-router-dom": {
|
|
100
105
|
"optional": true
|
|
101
106
|
}
|
package/src/assets/meta.json
CHANGED
|
@@ -146,7 +146,7 @@
|
|
|
146
146
|
"children": null
|
|
147
147
|
},
|
|
148
148
|
{
|
|
149
|
-
"type": "
|
|
149
|
+
"type": "Text",
|
|
150
150
|
"attributes": {
|
|
151
151
|
"description": "Metin öğesi. (#1)",
|
|
152
152
|
"title": "text 1",
|
|
@@ -190,7 +190,7 @@
|
|
|
190
190
|
"children": null
|
|
191
191
|
},
|
|
192
192
|
{
|
|
193
|
-
"type": "
|
|
193
|
+
"type": "Text",
|
|
194
194
|
"attributes": {
|
|
195
195
|
"description": "Metin öğesi. (#2)",
|
|
196
196
|
"title": "text 2",
|
|
@@ -234,7 +234,7 @@
|
|
|
234
234
|
"children": null
|
|
235
235
|
},
|
|
236
236
|
{
|
|
237
|
-
"type": "
|
|
237
|
+
"type": "Text",
|
|
238
238
|
"attributes": {
|
|
239
239
|
"description": "Metin öğesi. (#3)",
|
|
240
240
|
"title": "text 3",
|
|
@@ -273,7 +273,7 @@
|
|
|
273
273
|
"children": null
|
|
274
274
|
},
|
|
275
275
|
{
|
|
276
|
-
"type": "
|
|
276
|
+
"type": "Text",
|
|
277
277
|
"attributes": {
|
|
278
278
|
"description": "Metin öğesi. (#4)",
|
|
279
279
|
"title": "Product Desc(s)",
|
|
@@ -284,7 +284,7 @@
|
|
|
284
284
|
"children": "@productDescription — Unlock all premium features for a month."
|
|
285
285
|
},
|
|
286
286
|
{
|
|
287
|
-
"type": "
|
|
287
|
+
"type": "Text",
|
|
288
288
|
"attributes": {
|
|
289
289
|
"description": "Metin öğesi. (#5)",
|
|
290
290
|
"title": "Product Price(s)",
|
|
@@ -144,7 +144,7 @@
|
|
|
144
144
|
"children": null
|
|
145
145
|
},
|
|
146
146
|
{
|
|
147
|
-
"type": "
|
|
147
|
+
"type": "Text",
|
|
148
148
|
"attributes": {
|
|
149
149
|
"description": "Text item.",
|
|
150
150
|
"title": "text 1",
|
|
@@ -188,7 +188,7 @@
|
|
|
188
188
|
"children": null
|
|
189
189
|
},
|
|
190
190
|
{
|
|
191
|
-
"type": "
|
|
191
|
+
"type": "Text",
|
|
192
192
|
"attributes": {
|
|
193
193
|
"description": "Text item.",
|
|
194
194
|
"title": "text 2",
|
|
@@ -232,7 +232,7 @@
|
|
|
232
232
|
"children": null
|
|
233
233
|
},
|
|
234
234
|
{
|
|
235
|
-
"type": "
|
|
235
|
+
"type": "Text",
|
|
236
236
|
"attributes": {
|
|
237
237
|
"description": "Text item.",
|
|
238
238
|
"title": "text 3",
|
|
@@ -271,7 +271,7 @@
|
|
|
271
271
|
"children": null
|
|
272
272
|
},
|
|
273
273
|
{
|
|
274
|
-
"type": "
|
|
274
|
+
"type": "Text",
|
|
275
275
|
"attributes": {
|
|
276
276
|
"description": "Product description.",
|
|
277
277
|
"title": "Product Desc(s)",
|
|
@@ -282,7 +282,7 @@
|
|
|
282
282
|
"children": "@productDescription — Unlock all premium features for a month."
|
|
283
283
|
},
|
|
284
284
|
{
|
|
285
|
-
"type": "
|
|
285
|
+
"type": "Text",
|
|
286
286
|
"attributes": {
|
|
287
287
|
"description": "Product price.",
|
|
288
288
|
"title": "Product Price(s)",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useMemo } from 'react';
|
|
2
|
+
import type { ImageStyle } from 'react-native';
|
|
2
3
|
import type { NodeData } from '../../../types/Node';
|
|
3
4
|
import type {
|
|
4
5
|
ImagePropsGenerated,
|
|
@@ -7,11 +8,21 @@ import type {
|
|
|
7
8
|
import { useBuilderParams } from '../../../components/BuilderProvider';
|
|
8
9
|
import { extractImageStyleNative } from '../../../utils/extractImageStyle';
|
|
9
10
|
import { defaultAppConfig } from '../../../types/PreviewConfig';
|
|
10
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
getStyleBag,
|
|
13
|
+
toAttributeRecord,
|
|
14
|
+
stripStyleKeys,
|
|
15
|
+
type StyleAttrKey,
|
|
16
|
+
} from '../../../utils/attributeStyle';
|
|
11
17
|
|
|
12
18
|
export function useExtractImageStyle<
|
|
13
19
|
T extends ImagePropsGenerated['attributes'],
|
|
14
|
-
>(
|
|
20
|
+
>(
|
|
21
|
+
node: NodeData<T>,
|
|
22
|
+
): {
|
|
23
|
+
style: ImageStyle;
|
|
24
|
+
other: Omit<T, StyleAttrKey> & { resizeMode?: ResizeModeOptionType };
|
|
25
|
+
} {
|
|
15
26
|
const { appConfig, projectColors: builderProjectColors } = useBuilderParams();
|
|
16
27
|
const theme = appConfig?.theme ?? defaultAppConfig.theme;
|
|
17
28
|
const projectColors = builderProjectColors;
|
|
@@ -23,26 +34,19 @@ export function useExtractImageStyle<
|
|
|
23
34
|
extractImageStyleNative(node, { theme, projectColors });
|
|
24
35
|
|
|
25
36
|
const attrs = node.attributes;
|
|
26
|
-
|
|
27
|
-
// Prefer the typed resizeMode from attributes, fall back to extracted style value.
|
|
37
|
+
const stripped = stripStyleKeys(toAttributeRecord(attrs));
|
|
28
38
|
const imgStylesBag = getStyleBag(attrs);
|
|
39
|
+
|
|
40
|
+
// Prefer the typed resizeMode from style bag, fall back to extracted style value.
|
|
29
41
|
const resizeMode = ((imgStylesBag?.resizeMode as string | undefined) ??
|
|
30
42
|
resizeModeFromStyle) as ResizeModeOptionType | undefined;
|
|
31
43
|
|
|
32
|
-
// Forward all non-style attributes; style bag is already consumed above.
|
|
33
|
-
//Optimzation trade off by readability: fromEntries+filter avoids generic-to-Record double assertion.
|
|
34
|
-
const forwardedAttrs = Object.fromEntries(
|
|
35
|
-
Object.entries(attrs ?? {}).filter(
|
|
36
|
-
([key]) => key !== 'style' && key !== 'styles',
|
|
37
|
-
),
|
|
38
|
-
);
|
|
39
|
-
|
|
40
44
|
return {
|
|
41
|
-
style,
|
|
45
|
+
style: style as ImageStyle,
|
|
42
46
|
other: {
|
|
43
|
-
...
|
|
47
|
+
...stripped,
|
|
44
48
|
resizeMode,
|
|
45
|
-
},
|
|
49
|
+
} as Omit<T, StyleAttrKey> & { resizeMode?: ResizeModeOptionType },
|
|
46
50
|
};
|
|
47
51
|
}, [node, theme, projectColors]);
|
|
48
52
|
}
|
|
@@ -1,14 +1,26 @@
|
|
|
1
1
|
import { useMemo } from 'react';
|
|
2
|
+
import type { TextStyle } from 'react-native';
|
|
2
3
|
import type { NodeData } from '../../../types/Node';
|
|
3
4
|
import type { TextPropsGenerated } from '../../../build-components/Text/TextProps.generated';
|
|
4
5
|
import { defaultAppConfig } from '../../../types/PreviewConfig';
|
|
5
6
|
import { useBuilderParams } from '../../../components/BuilderProvider';
|
|
6
7
|
import { extractTextStyleNative } from '../../../utils/extractTextStyle';
|
|
7
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
getStyleBag,
|
|
10
|
+
toAttributeRecord,
|
|
11
|
+
stripStyleKeys,
|
|
12
|
+
type StyleAttrKey,
|
|
13
|
+
} from '../../../utils/attributeStyle';
|
|
8
14
|
|
|
9
15
|
export function useExtractTextStyle<T extends TextPropsGenerated['attributes']>(
|
|
10
16
|
node: NodeData<T>,
|
|
11
|
-
) {
|
|
17
|
+
): {
|
|
18
|
+
style: TextStyle;
|
|
19
|
+
other: Omit<T, StyleAttrKey> & {
|
|
20
|
+
adjustsFontSizeToFit?: boolean;
|
|
21
|
+
showEllipsis?: boolean;
|
|
22
|
+
};
|
|
23
|
+
} {
|
|
12
24
|
const {
|
|
13
25
|
appConfig: builderAppConfig,
|
|
14
26
|
projectColors: builderProjectColors,
|
|
@@ -27,25 +39,23 @@ export function useExtractTextStyle<T extends TextPropsGenerated['attributes']>(
|
|
|
27
39
|
fonts,
|
|
28
40
|
});
|
|
29
41
|
|
|
30
|
-
const attrs = node.attributes
|
|
42
|
+
const attrs = node.attributes;
|
|
43
|
+
const stripped = stripStyleKeys(toAttributeRecord(attrs));
|
|
31
44
|
const styleBag = getStyleBag(attrs);
|
|
32
|
-
const {
|
|
33
|
-
style: _style,
|
|
34
|
-
styles: _styles,
|
|
35
|
-
...rest
|
|
36
|
-
} = attrs as Record<string, unknown>;
|
|
37
|
-
void _style;
|
|
38
|
-
void _styles;
|
|
39
45
|
|
|
40
46
|
return {
|
|
41
|
-
style,
|
|
47
|
+
style: style as TextStyle,
|
|
42
48
|
other: {
|
|
43
|
-
...
|
|
44
|
-
// These are "behavior" flags
|
|
45
|
-
adjustsFontSizeToFit:
|
|
49
|
+
...stripped,
|
|
50
|
+
// These are "behavior" flags that may reside in the style bag.
|
|
51
|
+
adjustsFontSizeToFit: (stripped.adjustsFontSizeToFit ??
|
|
52
|
+
styleBag?.adjustsFontSizeToFit) as boolean | undefined,
|
|
53
|
+
showEllipsis: (stripped.showEllipsis ?? styleBag?.showEllipsis) as
|
|
46
54
|
| boolean
|
|
47
55
|
| undefined,
|
|
48
|
-
|
|
56
|
+
} as Omit<T, StyleAttrKey> & {
|
|
57
|
+
adjustsFontSizeToFit?: boolean;
|
|
58
|
+
showEllipsis?: boolean;
|
|
49
59
|
},
|
|
50
60
|
};
|
|
51
61
|
},
|
|
@@ -1,44 +1,42 @@
|
|
|
1
1
|
import { useMemo } from 'react';
|
|
2
|
+
import type { ViewStyle } from 'react-native';
|
|
2
3
|
import type { NodeData } from '../../../types/Node';
|
|
3
4
|
import type { ViewPropsGenerated } from '../../../build-components/View/ViewProps.generated';
|
|
4
5
|
import { useBuilderParams } from '../../../components/BuilderProvider';
|
|
5
6
|
import { extractViewStyleNative } from '../../../utils/extractViewStyle';
|
|
6
7
|
import { defaultAppConfig } from '../../../types/PreviewConfig';
|
|
7
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
getStyleBag,
|
|
10
|
+
toAttributeRecord,
|
|
11
|
+
stripStyleKeys,
|
|
12
|
+
type StyleAttrKey,
|
|
13
|
+
} from '../../../utils/attributeStyle';
|
|
8
14
|
|
|
9
15
|
export function useExtractViewStyle<T extends ViewPropsGenerated['attributes']>(
|
|
10
16
|
node: NodeData<T>,
|
|
11
|
-
) {
|
|
17
|
+
): {
|
|
18
|
+
style: ViewStyle;
|
|
19
|
+
other: Omit<T, StyleAttrKey> & { scrollable?: boolean };
|
|
20
|
+
} {
|
|
12
21
|
const { appConfig, projectColors: builderProjectColors } = useBuilderParams();
|
|
13
22
|
const theme = appConfig?.theme ?? defaultAppConfig.theme;
|
|
14
23
|
const projectColors = builderProjectColors;
|
|
15
24
|
|
|
16
25
|
return useMemo(() => {
|
|
17
26
|
const style = extractViewStyleNative(node, { theme, projectColors });
|
|
18
|
-
|
|
19
27
|
const attrs = node.attributes;
|
|
20
|
-
|
|
21
|
-
// Forward all non-style attributes; style bag is already consumed by extractViewStyleNative.
|
|
22
|
-
//Optimzation trade off by readability: fromEntries+filter avoids generic-to-Record double assertion.
|
|
23
|
-
const forwardedAttrs = Object.fromEntries(
|
|
24
|
-
Object.entries(attrs ?? {}).filter(
|
|
25
|
-
([key]) => key !== 'style' && key !== 'styles',
|
|
26
|
-
),
|
|
27
|
-
);
|
|
28
|
-
|
|
29
|
-
// scrollable may reside inside the styles bag at runtime (not on ViewStyleGenerated).
|
|
30
|
-
const attrRecord = toAttributeRecord(attrs);
|
|
28
|
+
const stripped = stripStyleKeys(toAttributeRecord(attrs));
|
|
31
29
|
const styleBag = getStyleBag(attrs);
|
|
32
|
-
const scrollable = (attrRecord.scrollable ?? styleBag?.scrollable) as
|
|
33
|
-
| boolean
|
|
34
|
-
| undefined;
|
|
35
30
|
|
|
36
31
|
return {
|
|
37
|
-
style,
|
|
32
|
+
style: style as ViewStyle,
|
|
38
33
|
other: {
|
|
39
|
-
...
|
|
40
|
-
scrollable
|
|
41
|
-
|
|
34
|
+
...stripped,
|
|
35
|
+
// scrollable may reside inside the styles bag at runtime.
|
|
36
|
+
scrollable: (stripped.scrollable ?? styleBag?.scrollable) as
|
|
37
|
+
| boolean
|
|
38
|
+
| undefined,
|
|
39
|
+
} as Omit<T, StyleAttrKey> & { scrollable?: boolean },
|
|
42
40
|
};
|
|
43
41
|
}, [node, theme, projectColors]);
|
|
44
42
|
}
|
|
@@ -10,13 +10,16 @@ import { useLogRender } from '../../utils/useLogRender';
|
|
|
10
10
|
import { useExtractViewStyle } from '../../attribute-analyser/style/web/useExtractViewStyle';
|
|
11
11
|
import { useMockOSContext, useMockPermission } from '../../mockOS';
|
|
12
12
|
import { useLocalize } from '../../hooks/useLocalize';
|
|
13
|
+
import { parseColor } from '../../utils/parseColor';
|
|
14
|
+
import { getStyleBag, toAttributeRecord } from '../../utils/attributeStyle';
|
|
13
15
|
|
|
14
16
|
function OnboardButton({ node }: OnboardButtonComponentProps) {
|
|
15
17
|
useLogRender('OnboardButton');
|
|
16
18
|
node = useNode(node);
|
|
17
19
|
const attributeName = node.sourceType ?? node.type ?? 'OnboardButton';
|
|
18
20
|
const { emblaApi } = useContext(onboardContext) ?? {};
|
|
19
|
-
const { appConfig } = useBuilderParams();
|
|
21
|
+
const { appConfig, projectColors } = useBuilderParams();
|
|
22
|
+
const theme = appConfig?.theme;
|
|
20
23
|
|
|
21
24
|
const context = useMockOSContext();
|
|
22
25
|
const mockPermissionManager = useMockPermission(context);
|
|
@@ -25,14 +28,25 @@ function OnboardButton({ node }: OnboardButtonComponentProps) {
|
|
|
25
28
|
const attributeKey = node.key ?? generatedId;
|
|
26
29
|
|
|
27
30
|
const attrs = node.attributes;
|
|
28
|
-
const
|
|
31
|
+
const attrRecord = toAttributeRecord(attrs);
|
|
32
|
+
const styleBag = getStyleBag(attrs);
|
|
29
33
|
const labelRaw = attrs?.labelKey ?? '';
|
|
30
34
|
const localize = useLocalize({ appConfig });
|
|
31
35
|
const label = localize(labelRaw);
|
|
32
36
|
|
|
33
|
-
const flex = styleBag?.flex ?? 1;
|
|
34
|
-
|
|
35
|
-
|
|
37
|
+
const flex = (attrRecord.flex ?? styleBag?.flex ?? 1) as number;
|
|
38
|
+
|
|
39
|
+
// The editor saves color attrs inside `styles` (meta category === 'style'),
|
|
40
|
+
// but legacy JSON may have them at the top level.
|
|
41
|
+
const rawTextColor = (attrRecord.button_text_color ??
|
|
42
|
+
styleBag?.button_text_color) as string | undefined;
|
|
43
|
+
const rawBgColor = (attrRecord.button_background_color ??
|
|
44
|
+
styleBag?.button_background_color) as string | undefined;
|
|
45
|
+
|
|
46
|
+
const textColor =
|
|
47
|
+
parseColor(rawTextColor, { projectColors, theme }) ?? '#FFFFFF';
|
|
48
|
+
const backgroundColor =
|
|
49
|
+
parseColor(rawBgColor, { projectColors, theme }) ?? '#0066FF';
|
|
36
50
|
const viewStyle = useExtractViewStyle(node);
|
|
37
51
|
|
|
38
52
|
const handleClick = () => {
|
|
@@ -9,6 +9,7 @@ import { isNodeSelected, SELECTED_OUTLINE_STYLE } from '../../utils/selection';
|
|
|
9
9
|
import { useMergedStyle } from '../../utils/useMergedStyle';
|
|
10
10
|
import { defaultAppConfig } from '../../types/PreviewConfig';
|
|
11
11
|
import { parseColor } from '../../utils/parseColor';
|
|
12
|
+
import { getStyleBag, toAttributeRecord } from '../../utils/attributeStyle';
|
|
12
13
|
|
|
13
14
|
type Segment =
|
|
14
15
|
| { type: 'text'; value: string }
|
|
@@ -107,26 +108,36 @@ function OnboardFooter({ node }: OnboardFooterComponentProps) {
|
|
|
107
108
|
key ? (localication?.[defaultLanguage ?? 'en']?.[key] ?? key) : '';
|
|
108
109
|
|
|
109
110
|
const attrs = node?.attributes;
|
|
111
|
+
const attrRecord = toAttributeRecord(attrs);
|
|
112
|
+
const styleBag = getStyleBag(attrs);
|
|
110
113
|
const text = t(attrs?.textLocalizationKey);
|
|
111
114
|
const textStyle = useExtractTextStyle(node, true);
|
|
112
115
|
const viewStyle = useExtractViewStyle(node);
|
|
113
116
|
|
|
117
|
+
// Read linked-word colors from both top-level attributes and the styles bag.
|
|
118
|
+
// The editor saves them inside `styles` (meta category === 'style'),
|
|
119
|
+
// but legacy JSON may have them at the top level.
|
|
120
|
+
const rawFirstColor = (attrRecord.linkedWordFirstColor ??
|
|
121
|
+
styleBag?.linkedWordFirstColor) as string | undefined;
|
|
122
|
+
const rawSecondColor = (attrRecord.linkedWordSecondColor ??
|
|
123
|
+
styleBag?.linkedWordSecondColor) as string | undefined;
|
|
124
|
+
|
|
114
125
|
// Parse colors for linked words
|
|
115
126
|
const parsedFirstColor = useMemo(
|
|
116
127
|
() =>
|
|
117
|
-
parseColor(
|
|
128
|
+
parseColor(rawFirstColor, {
|
|
118
129
|
projectColors,
|
|
119
130
|
theme,
|
|
120
131
|
}),
|
|
121
|
-
[
|
|
132
|
+
[rawFirstColor, projectColors, theme],
|
|
122
133
|
);
|
|
123
134
|
const parsedSecondColor = useMemo(
|
|
124
135
|
() =>
|
|
125
|
-
parseColor(
|
|
136
|
+
parseColor(rawSecondColor, {
|
|
126
137
|
projectColors,
|
|
127
138
|
theme,
|
|
128
139
|
}),
|
|
129
|
-
[
|
|
140
|
+
[rawSecondColor, projectColors, theme],
|
|
130
141
|
);
|
|
131
142
|
|
|
132
143
|
const mergedTextStyle = useMergedStyle(textStyle, {
|
|
@@ -4205,6 +4205,7 @@ export const patterns = [
|
|
|
4205
4205
|
description: 'description',
|
|
4206
4206
|
src: 'string',
|
|
4207
4207
|
},
|
|
4208
|
+
defaults: { resizeMode: 'contain' },
|
|
4208
4209
|
},
|
|
4209
4210
|
meta: {
|
|
4210
4211
|
desiredParent: ['all'],
|
|
@@ -4527,6 +4528,7 @@ export const patterns = [
|
|
|
4527
4528
|
},
|
|
4528
4529
|
},
|
|
4529
4530
|
defaults: {
|
|
4531
|
+
resizeMode: 'contain',
|
|
4530
4532
|
style: {
|
|
4531
4533
|
flexDirection: 'column',
|
|
4532
4534
|
position: 'relative',
|
|
@@ -7589,6 +7591,7 @@ export const patterns = [
|
|
|
7589
7591
|
video_url: 'string',
|
|
7590
7592
|
lottie: 'string',
|
|
7591
7593
|
},
|
|
7594
|
+
defaults: { resizeMode: 'contain' },
|
|
7592
7595
|
},
|
|
7593
7596
|
meta: {
|
|
7594
7597
|
desiredParent: ['>OnboardProvider', '>OnboardItem', '!=Onboard'],
|
|
@@ -7925,6 +7928,7 @@ export const patterns = [
|
|
|
7925
7928
|
},
|
|
7926
7929
|
},
|
|
7927
7930
|
defaults: {
|
|
7931
|
+
resizeMode: 'contain',
|
|
7928
7932
|
style: {
|
|
7929
7933
|
flexDirection: 'column',
|
|
7930
7934
|
position: 'relative',
|
|
@@ -43,7 +43,7 @@ type BuilderProviderProps = {
|
|
|
43
43
|
children: React.ReactNode;
|
|
44
44
|
};
|
|
45
45
|
|
|
46
|
-
const
|
|
46
|
+
const builderContext = createContext<BuilderProviderParams | undefined>(
|
|
47
47
|
undefined,
|
|
48
48
|
);
|
|
49
49
|
|
|
@@ -91,7 +91,7 @@ export function BuilderProvider({ params, children }: BuilderProviderProps) {
|
|
|
91
91
|
);
|
|
92
92
|
|
|
93
93
|
return (
|
|
94
|
-
<
|
|
94
|
+
<builderContext.Provider value={value}>{children}</builderContext.Provider>
|
|
95
95
|
);
|
|
96
96
|
}
|
|
97
97
|
|
|
@@ -119,10 +119,10 @@ const defaultProjectColors: Readonly<ProjectColors> = {
|
|
|
119
119
|
FOOTER_TEXT: '#81838F',
|
|
120
120
|
},
|
|
121
121
|
dark: {
|
|
122
|
-
TEXT: '#
|
|
123
|
-
BACKGROUND: '#
|
|
122
|
+
TEXT: '#E9EBF9',
|
|
123
|
+
BACKGROUND: '#080A17',
|
|
124
124
|
ICON: '#0450E2',
|
|
125
|
-
LINE: '#
|
|
125
|
+
LINE: '#161827',
|
|
126
126
|
ONBOARD_TITLE: '#FDFDFD',
|
|
127
127
|
ONBOARD_SUBTITLE: '#C7C7C7',
|
|
128
128
|
BUTTON_SECONDARY_TEXT: '#A9AAAC',
|
|
@@ -133,7 +133,7 @@ const defaultProjectColors: Readonly<ProjectColors> = {
|
|
|
133
133
|
|
|
134
134
|
export function useBuilderParams(): Readonly<BuilderProviderParams> {
|
|
135
135
|
return (
|
|
136
|
-
useContext(
|
|
136
|
+
useContext(builderContext) ?? {
|
|
137
137
|
products: [],
|
|
138
138
|
benefits: {},
|
|
139
139
|
platform: 'web',
|
package/src/index.ts
CHANGED
|
@@ -91,3 +91,6 @@ export {
|
|
|
91
91
|
} from './assets/samples/getSamples';
|
|
92
92
|
export { getDefaultProject } from './utils/getDefaultProject';
|
|
93
93
|
export type { EventObjectGenerated } from './build-components/OnboardButton/OnboardButtonProps.generated';
|
|
94
|
+
|
|
95
|
+
export { parseColor } from './utils/parseColor';
|
|
96
|
+
export type { ParseColorOptions } from './utils/parseColor';
|
|
@@ -24,3 +24,81 @@ export function toAttributeRecord(
|
|
|
24
24
|
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
25
25
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
26
26
|
}
|
|
27
|
+
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
// Style-key filtering – separates visual style keys from non-style attributes
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* All attribute keys that represent visual style properties.
|
|
34
|
+
* Used to separate style keys from non-style (behavioral/content) keys.
|
|
35
|
+
*
|
|
36
|
+
* Keep in sync with ViewStyleGenerated, TextStyleGenerated, and ImageStyleGenerated.
|
|
37
|
+
*/
|
|
38
|
+
const STYLE_ATTR_KEYS_LIST = [
|
|
39
|
+
// Style bag containers
|
|
40
|
+
'style',
|
|
41
|
+
'styles',
|
|
42
|
+
// Layout
|
|
43
|
+
'flexDirection',
|
|
44
|
+
'flexWrap',
|
|
45
|
+
'alignItems',
|
|
46
|
+
'justifyContent',
|
|
47
|
+
'gap',
|
|
48
|
+
// Padding
|
|
49
|
+
'padding',
|
|
50
|
+
'paddingHorizontal',
|
|
51
|
+
'paddingVertical',
|
|
52
|
+
'paddingTop',
|
|
53
|
+
'paddingBottom',
|
|
54
|
+
'paddingLeft',
|
|
55
|
+
'paddingRight',
|
|
56
|
+
// Margin
|
|
57
|
+
'margin',
|
|
58
|
+
'marginHorizontal',
|
|
59
|
+
'marginVertical',
|
|
60
|
+
'marginTop',
|
|
61
|
+
'marginBottom',
|
|
62
|
+
'marginLeft',
|
|
63
|
+
'marginRight',
|
|
64
|
+
// Background & border
|
|
65
|
+
'backgroundColor',
|
|
66
|
+
'borderRadius',
|
|
67
|
+
// Sizing
|
|
68
|
+
'width',
|
|
69
|
+
'minWidth',
|
|
70
|
+
'maxWidth',
|
|
71
|
+
'height',
|
|
72
|
+
'minHeight',
|
|
73
|
+
'maxHeight',
|
|
74
|
+
// Flex & position
|
|
75
|
+
'flex',
|
|
76
|
+
'position',
|
|
77
|
+
'top',
|
|
78
|
+
'bottom',
|
|
79
|
+
'left',
|
|
80
|
+
'right',
|
|
81
|
+
'zIndex',
|
|
82
|
+
// Text
|
|
83
|
+
'color',
|
|
84
|
+
'fontSize',
|
|
85
|
+
'fontFamily',
|
|
86
|
+
'fontWeight',
|
|
87
|
+
'textAlign',
|
|
88
|
+
// Image
|
|
89
|
+
'resizeMode',
|
|
90
|
+
] as const;
|
|
91
|
+
|
|
92
|
+
/** Type-level union of all style attribute keys. Use with `Omit<T, StyleAttrKey>`. */
|
|
93
|
+
export type StyleAttrKey = (typeof STYLE_ATTR_KEYS_LIST)[number];
|
|
94
|
+
|
|
95
|
+
const STYLE_ATTR_KEYS: ReadonlySet<string> = new Set(STYLE_ATTR_KEYS_LIST);
|
|
96
|
+
|
|
97
|
+
/** Strips all visual-style keys from an attributes record, returning only non-style keys. */
|
|
98
|
+
export function stripStyleKeys(
|
|
99
|
+
attrs: Record<string, unknown>,
|
|
100
|
+
): Record<string, unknown> {
|
|
101
|
+
return Object.fromEntries(
|
|
102
|
+
Object.entries(attrs).filter(([key]) => !STYLE_ATTR_KEYS.has(key)),
|
|
103
|
+
);
|
|
104
|
+
}
|