@developer_tribe/react-builder 1.2.23 → 1.2.25
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/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 +0 -2
- package/dist/build-components/Counter/CounterProps.generated.d.ts +0 -2
- 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/PaywallCounter/PaywallCounterProps.generated.d.ts +0 -2
- package/dist/build-components/PaywallOptions/PaywallOptionsProps.generated.d.ts +0 -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/patterns.generated.d.ts +80 -66
- package/dist/index.cjs.js +2 -2
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.esm.js +2 -2
- package/dist/index.esm.js.map +1 -1
- package/dist/index.web.cjs.js +3 -3
- 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/types/Project.d.ts +6 -0
- package/dist/utils/attributeStyle.d.ts +12 -0
- package/dist/utils/patterns.d.ts +2 -0
- package/package.json +6 -1
- package/scripts/prebuild/utils/validateAllComponentsOrThrow.js +11 -2
- package/src/AttributesEditor.tsx +15 -4
- 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/assets/samples/paywall-app-delete-offer.json +0 -1
- package/src/assets/samples/paywall-app-open-offer.json +0 -1
- package/src/assets/samples/paywall-back-offer.json +0 -1
- package/src/assets/samples/paywall-notification-offer.json +0 -1
- package/src/assets/samples/simple-2.json +0 -1
- 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/attributes-editor/AttributesEditorView.tsx +43 -36
- package/src/attributes-editor/SpecialCategorySection.tsx +5 -3
- package/src/attributes-editor/attributesEditorModelTypes.ts +2 -0
- package/src/attributes-editor/useAttributesEditorModel.ts +6 -0
- package/src/build-components/BIcon/BIconProps.generated.ts +0 -2
- package/src/build-components/BIcon/pattern.json +5 -3
- package/src/build-components/BackgroundImage/BackgroundImageProps.generated.ts +0 -2
- package/src/build-components/BackgroundImage/pattern.json +12 -4
- package/src/build-components/Button/ButtonProps.generated.ts +0 -2
- package/src/build-components/Button/pattern.json +5 -3
- package/src/build-components/Carousel/CarouselProps.generated.ts +0 -2
- package/src/build-components/Carousel/pattern.json +11 -5
- package/src/build-components/CarouselButtons/CarouselButtonsProps.generated.ts +0 -2
- package/src/build-components/CarouselButtons/pattern.json +11 -4
- package/src/build-components/CarouselDots/CarouselDotsProps.generated.ts +0 -2
- package/src/build-components/CarouselDots/pattern.json +5 -3
- package/src/build-components/CarouselItem/CarouselItemProps.generated.ts +0 -2
- package/src/build-components/CarouselItem/pattern.json +6 -6
- package/src/build-components/CarouselProvider/CarouselProviderProps.generated.ts +0 -2
- package/src/build-components/CarouselProvider/pattern.json +6 -5
- package/src/build-components/CountDown/CountDownProps.generated.ts +0 -2
- package/src/build-components/CountDown/pattern.json +6 -3
- package/src/build-components/Counter/CounterProps.generated.ts +0 -2
- package/src/build-components/Counter/pattern.json +5 -1
- package/src/build-components/Image/ImageProps.generated.ts +0 -2
- package/src/build-components/Image/pattern.json +7 -2
- package/src/build-components/Main/MainProps.generated.ts +0 -2
- package/src/build-components/Main/pattern.json +5 -3
- package/src/build-components/NavigationBarColor/NavigationBarColorProps.generated.ts +0 -2
- package/src/build-components/NavigationBarColor/pattern.json +5 -3
- package/src/build-components/Onboard/OnboardProps.generated.ts +0 -2
- package/src/build-components/Onboard/pattern.json +9 -7
- package/src/build-components/OnboardButton/OnboardButton.tsx +19 -5
- package/src/build-components/OnboardButton/OnboardButtonProps.generated.ts +0 -2
- package/src/build-components/OnboardButton/pattern.json +16 -5
- package/src/build-components/OnboardButtons/OnboardButtonsProps.generated.ts +0 -2
- package/src/build-components/OnboardButtons/pattern.json +17 -6
- package/src/build-components/OnboardDot/OnboardDotProps.generated.ts +0 -2
- package/src/build-components/OnboardDot/pattern.json +5 -3
- package/src/build-components/OnboardFooter/OnboardFooter.tsx +15 -4
- package/src/build-components/OnboardFooter/OnboardFooterProps.generated.ts +0 -2
- package/src/build-components/OnboardFooter/pattern.json +5 -3
- package/src/build-components/OnboardImage/OnboardImageProps.generated.ts +0 -2
- package/src/build-components/OnboardImage/pattern.json +7 -3
- package/src/build-components/OnboardItem/OnboardItemProps.generated.ts +0 -2
- package/src/build-components/OnboardItem/pattern.json +13 -5
- package/src/build-components/OnboardProvider/OnboardProviderProps.generated.ts +0 -2
- package/src/build-components/OnboardProvider/pattern.json +10 -4
- package/src/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.ts +0 -2
- package/src/build-components/OnboardSubtitle/pattern.json +7 -6
- package/src/build-components/OnboardTitle/OnboardTitleProps.generated.ts +0 -2
- package/src/build-components/OnboardTitle/pattern.json +7 -6
- package/src/build-components/PaywallBackground/PaywallBackgroundProps.generated.ts +0 -2
- package/src/build-components/PaywallBackground/pattern.json +5 -5
- package/src/build-components/PaywallCloseButton/PaywallCloseButtonProps.generated.ts +0 -2
- package/src/build-components/PaywallCloseButton/pattern.json +6 -6
- package/src/build-components/PaywallCounter/PaywallCounterProps.generated.ts +0 -2
- package/src/build-components/PaywallCounter/pattern.json +6 -3
- package/src/build-components/PaywallOptions/PaywallOptionsProps.generated.ts +0 -2
- package/src/build-components/PaywallOptions/pattern.json +6 -6
- package/src/build-components/PaywallProvider/PaywallProviderProps.generated.ts +0 -2
- package/src/build-components/PaywallProvider/pattern.json +5 -3
- package/src/build-components/PaywallSubscribeButton/PaywallSubscribeButtonProps.generated.ts +0 -2
- package/src/build-components/PaywallSubscribeButton/pattern.json +6 -6
- package/src/build-components/RadioButton/RadioButtonProps.generated.ts +0 -2
- package/src/build-components/RadioButton/pattern.json +5 -3
- package/src/build-components/Separator/SeparatorProps.generated.ts +0 -2
- package/src/build-components/Separator/pattern.json +5 -3
- package/src/build-components/StatusBarColor/StatusBarColorProps.generated.ts +0 -2
- package/src/build-components/StatusBarColor/pattern.json +5 -3
- package/src/build-components/Text/TextProps.generated.ts +0 -2
- package/src/build-components/Text/pattern.json +11 -5
- package/src/build-components/View/pattern.json +18 -4
- package/src/build-components/patterns.generated.ts +72 -66
- package/src/components/AttributesEditorPanel.tsx +48 -32
- package/src/components/Builder.tsx +4 -1
- package/src/components/BuilderProvider.tsx +6 -6
- package/src/index.ts +4 -1
- package/src/pages/ProjectPage.tsx +45 -22
- package/src/pages/projectPageUtils.ts +15 -1
- package/src/types/Project.ts +7 -0
- package/src/utils/attributeStyle.ts +78 -0
- package/src/utils/patterns.ts +2 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type { Project, ProjectColors } from '../types/Project';
|
|
1
|
+
import type { Project, ProjectColors, ProjectMeta } from '../types/Project';
|
|
2
2
|
import { AppConfig } from '../types/PreviewConfig';
|
|
3
3
|
import type { LogLevel } from '../types/Project';
|
|
4
4
|
import type { Fonts } from '../types/Fonts';
|
|
5
5
|
export type ProjectPageProps = {
|
|
6
6
|
project: Project;
|
|
7
|
-
onSaveProject: (project:
|
|
7
|
+
onSaveProject: (project: ProjectMeta) => void;
|
|
8
8
|
appConfig?: AppConfig;
|
|
9
9
|
logLevel?: LogLevel;
|
|
10
10
|
projectColors?: ProjectColors;
|
|
@@ -1,7 +1,13 @@
|
|
|
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
|
export declare function resolveProjectForSave(args: {
|
|
4
4
|
project: Project;
|
|
5
5
|
overrideProject?: Project | null;
|
|
6
6
|
data: Node;
|
|
7
7
|
}): Project;
|
|
8
|
+
/**
|
|
9
|
+
* Strips a full Project down to its essential persistence fields.
|
|
10
|
+
* Use before handing the project to onSaveProject so consumers only
|
|
11
|
+
* receive the canonical metadata (name, version, type, data).
|
|
12
|
+
*/
|
|
13
|
+
export declare function toProjectMeta(project: Project): ProjectMeta;
|
package/dist/types/Project.d.ts
CHANGED
|
@@ -24,6 +24,12 @@ export interface ProjectBase<T> {
|
|
|
24
24
|
}
|
|
25
25
|
export interface Project extends ProjectBase<Node> {
|
|
26
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Lightweight subset of Project containing only the essential metadata
|
|
29
|
+
* needed for persistence (name, version, type, data).
|
|
30
|
+
* Excludes runtime/editor-only fields like appConfig and projectColors.
|
|
31
|
+
*/
|
|
32
|
+
export type ProjectMeta = Pick<Project, 'name' | 'version' | 'type' | 'data'>;
|
|
27
33
|
export type LogLevel = 'NONE' | 'ERROR' | 'WARN' | 'INFO' | 'VERBOSE';
|
|
28
34
|
export type LogSource = string;
|
|
29
35
|
export interface LogEntry {
|
|
@@ -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/dist/utils/patterns.d.ts
CHANGED
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.25",
|
|
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
|
}
|
|
@@ -120,11 +120,20 @@ async function validatePatternJson(componentDir, componentName) {
|
|
|
120
120
|
`[${componentName}] pattern.json -> 'pattern.children' must be one of: node | string | never`
|
|
121
121
|
);
|
|
122
122
|
}
|
|
123
|
-
|
|
123
|
+
// pattern.attributes is optional – components that only declare title/description
|
|
124
|
+
// (now at pattern level) may have no extra attributes at all.
|
|
125
|
+
if (
|
|
126
|
+
Object.prototype.hasOwnProperty.call(pattern, 'attributes') &&
|
|
127
|
+
(typeof pattern.attributes !== 'object' || pattern.attributes == null)
|
|
128
|
+
) {
|
|
124
129
|
return fail(
|
|
125
|
-
`[${componentName}] pattern.json -> 'pattern.attributes' must be an object`
|
|
130
|
+
`[${componentName}] pattern.json -> 'pattern.attributes' must be an object (or omitted)`
|
|
126
131
|
);
|
|
127
132
|
}
|
|
133
|
+
// Normalise missing attributes to empty object for the rest of the validation
|
|
134
|
+
if (!pattern.attributes) {
|
|
135
|
+
pattern.attributes = {};
|
|
136
|
+
}
|
|
128
137
|
|
|
129
138
|
// Helpers for validating custom types
|
|
130
139
|
const isPrimitive = t =>
|
package/src/AttributesEditor.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect } from 'react';
|
|
1
|
+
import { useEffect, useRef } from 'react';
|
|
2
2
|
import type { AttributesEditorProps } from './attributes-editor/attributesEditorModelTypes';
|
|
3
3
|
import { useLogRender } from './utils/useLogRender';
|
|
4
4
|
import { AttributesEditorView } from './attributes-editor/AttributesEditorView';
|
|
@@ -8,11 +8,22 @@ export function AttributesEditor(props: AttributesEditorProps) {
|
|
|
8
8
|
useLogRender('AttributesEditor');
|
|
9
9
|
const model = useAttributesEditorModel(props);
|
|
10
10
|
const titleValue = model.attributes?.title;
|
|
11
|
+
const hasTitleField = model.hasTitleField;
|
|
12
|
+
|
|
13
|
+
// Keep a stable ref so the effect doesn't re-run when the callback
|
|
14
|
+
// reference changes (which happens every render due to unstable onChange prop).
|
|
15
|
+
const handleAttributeChangeRef = useRef(model.handleAttributeChange);
|
|
16
|
+
handleAttributeChangeRef.current = model.handleAttributeChange;
|
|
17
|
+
|
|
11
18
|
useEffect(() => {
|
|
12
|
-
if (
|
|
13
|
-
|
|
19
|
+
if (
|
|
20
|
+
hasTitleField &&
|
|
21
|
+
typeof titleValue === 'string' &&
|
|
22
|
+
titleValue.length > 20
|
|
23
|
+
) {
|
|
24
|
+
handleAttributeChangeRef.current('title', titleValue.slice(0, 20));
|
|
14
25
|
}
|
|
15
|
-
}, [
|
|
26
|
+
}, [hasTitleField, titleValue]);
|
|
16
27
|
return <AttributesEditorView {...model} />;
|
|
17
28
|
}
|
|
18
29
|
|
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)",
|
|
@@ -68,7 +68,6 @@
|
|
|
68
68
|
"type": "PaywallBackground",
|
|
69
69
|
"attributes": {
|
|
70
70
|
"src": "https://images.unsplash.com/photo-1496307042754-b4aa456c4a2d?auto=format&fit=crop&w=1200&q=80",
|
|
71
|
-
"resizeMode": "cover",
|
|
72
71
|
"description": "Paywall background.",
|
|
73
72
|
"title": "Paywall Background"
|
|
74
73
|
},
|
|
@@ -68,7 +68,6 @@
|
|
|
68
68
|
"type": "PaywallBackground",
|
|
69
69
|
"attributes": {
|
|
70
70
|
"src": "https://images.unsplash.com/photo-1501785888041-af3ef285b470?auto=format&fit=crop&w=1200&q=80",
|
|
71
|
-
"resizeMode": "cover",
|
|
72
71
|
"description": "Paywall background.",
|
|
73
72
|
"title": "Paywall Background"
|
|
74
73
|
},
|
|
@@ -68,7 +68,6 @@
|
|
|
68
68
|
"type": "PaywallBackground",
|
|
69
69
|
"attributes": {
|
|
70
70
|
"src": "https://images.unsplash.com/photo-1470770903676-69b98201ea1c?auto=format&fit=crop&w=1200&q=80",
|
|
71
|
-
"resizeMode": "cover",
|
|
72
71
|
"description": "Paywall background.",
|
|
73
72
|
"title": "Paywall Background"
|
|
74
73
|
},
|
|
@@ -68,7 +68,6 @@
|
|
|
68
68
|
"type": "PaywallBackground",
|
|
69
69
|
"attributes": {
|
|
70
70
|
"src": "https://images.unsplash.com/photo-1469474968028-56623f02e42e?auto=format&fit=crop&w=1200&q=80",
|
|
71
|
-
"resizeMode": "cover",
|
|
72
71
|
"description": "Paywall background.",
|
|
73
72
|
"title": "Paywall Background"
|
|
74
73
|
},
|
|
@@ -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
|
}
|
|
@@ -63,6 +63,8 @@ export function AttributesEditorView(props: AttributesEditorViewProps) {
|
|
|
63
63
|
firstAvailableTab,
|
|
64
64
|
activeEntries,
|
|
65
65
|
activeSpecialSections,
|
|
66
|
+
hasTitleField,
|
|
67
|
+
hasDescriptionField,
|
|
66
68
|
hasStringChildren,
|
|
67
69
|
childrenValue,
|
|
68
70
|
handleChildrenChange,
|
|
@@ -94,37 +96,46 @@ export function AttributesEditorView(props: AttributesEditorViewProps) {
|
|
|
94
96
|
|
|
95
97
|
const titleValue = getAttributeValue('title');
|
|
96
98
|
const descriptionValue = getAttributeValue('description');
|
|
97
|
-
const
|
|
99
|
+
const showTopFields =
|
|
100
|
+
!isInvalidNode && (hasTitleField || hasDescriptionField);
|
|
101
|
+
const topFieldsSection = showTopFields ? (
|
|
98
102
|
<section className="attributes-editor__top-fields">
|
|
99
|
-
|
|
100
|
-
<
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
103
|
+
{hasTitleField ? (
|
|
104
|
+
<div className="attributes-editor__field-wrapper">
|
|
105
|
+
<label className="attributes-editor__field-label" htmlFor="title">
|
|
106
|
+
Title (max 20 characters for display purposes)
|
|
107
|
+
</label>
|
|
108
|
+
<input
|
|
109
|
+
id="title"
|
|
110
|
+
className="input"
|
|
111
|
+
type="text"
|
|
112
|
+
maxLength={20}
|
|
113
|
+
value={typeof titleValue === 'string' ? titleValue : ''}
|
|
114
|
+
onChange={(event) =>
|
|
115
|
+
handleAttributeChange('title', event.target.value)
|
|
116
|
+
}
|
|
117
|
+
/>
|
|
118
|
+
</div>
|
|
119
|
+
) : null}
|
|
120
|
+
{hasDescriptionField ? (
|
|
121
|
+
<div className="attributes-editor__field-wrapper">
|
|
122
|
+
<label
|
|
123
|
+
className="attributes-editor__field-label"
|
|
124
|
+
htmlFor="description"
|
|
125
|
+
>
|
|
126
|
+
Description (for display purposes)
|
|
127
|
+
</label>
|
|
128
|
+
<input
|
|
129
|
+
id="description"
|
|
130
|
+
className="input"
|
|
131
|
+
type="text"
|
|
132
|
+
value={typeof descriptionValue === 'string' ? descriptionValue : ''}
|
|
133
|
+
onChange={(event) =>
|
|
134
|
+
handleAttributeChange('description', event.target.value)
|
|
135
|
+
}
|
|
136
|
+
/>
|
|
137
|
+
</div>
|
|
138
|
+
) : null}
|
|
128
139
|
</section>
|
|
129
140
|
) : null;
|
|
130
141
|
|
|
@@ -346,18 +357,14 @@ export function AttributesEditorView(props: AttributesEditorViewProps) {
|
|
|
346
357
|
);
|
|
347
358
|
}
|
|
348
359
|
|
|
349
|
-
const sectionAttributes =
|
|
350
|
-
section.meta?.category === 'style'
|
|
351
|
-
? ((styleBag ?? {}) as unknown as NodeDefaultAttribute)
|
|
352
|
-
: attributes;
|
|
353
|
-
|
|
354
360
|
return (
|
|
355
361
|
<SpecialCategorySection
|
|
356
362
|
key={section.key}
|
|
357
363
|
category={section.key}
|
|
358
364
|
entries={section.entries}
|
|
359
365
|
attributeMeta={attributeMeta}
|
|
360
|
-
attributes={
|
|
366
|
+
attributes={attributes}
|
|
367
|
+
getAttributeValue={getAttributeValue}
|
|
361
368
|
onAttributeChange={handleAttributeChange}
|
|
362
369
|
componentType={data?.type}
|
|
363
370
|
projectColors={projectColorsForPicker}
|
|
@@ -16,6 +16,7 @@ type SpecialCategorySectionProps = {
|
|
|
16
16
|
entries: SchemaEntry[];
|
|
17
17
|
attributeMeta?: AttributeMetaMap;
|
|
18
18
|
attributes: NodeDefaultAttribute;
|
|
19
|
+
getAttributeValue: (name: string) => unknown;
|
|
19
20
|
onAttributeChange: (name: string, value: unknown) => void;
|
|
20
21
|
componentType?: string;
|
|
21
22
|
projectColors?: ProjectColors;
|
|
@@ -41,6 +42,7 @@ export function SpecialCategorySection({
|
|
|
41
42
|
entries,
|
|
42
43
|
attributeMeta,
|
|
43
44
|
attributes,
|
|
45
|
+
getAttributeValue,
|
|
44
46
|
onAttributeChange,
|
|
45
47
|
componentType,
|
|
46
48
|
projectColors,
|
|
@@ -96,7 +98,7 @@ export function SpecialCategorySection({
|
|
|
96
98
|
const preferredScale = toPreferredScale(
|
|
97
99
|
attributeMeta?.[name]?.preferedScale,
|
|
98
100
|
);
|
|
99
|
-
const currentValue = (
|
|
101
|
+
const currentValue = getAttributeValue(name);
|
|
100
102
|
const isBoolean = isBooleanFieldType(type);
|
|
101
103
|
const fieldSlot = detectFieldSlot(name);
|
|
102
104
|
const wrapperClassNames = [
|
|
@@ -175,7 +177,7 @@ export function SpecialCategorySection({
|
|
|
175
177
|
const preferredScale = toPreferredScale(
|
|
176
178
|
attributeMeta?.[name]?.preferedScale,
|
|
177
179
|
);
|
|
178
|
-
const currentValue = (
|
|
180
|
+
const currentValue = getAttributeValue(name);
|
|
179
181
|
const isBoolean = isBooleanFieldType(type);
|
|
180
182
|
const fieldSlot = detectFieldSlot(name);
|
|
181
183
|
const wrapperClassNames = [
|
|
@@ -220,7 +222,7 @@ export function SpecialCategorySection({
|
|
|
220
222
|
const preferredScale = toPreferredScale(
|
|
221
223
|
attributeMeta?.[name]?.preferedScale,
|
|
222
224
|
);
|
|
223
|
-
const currentValue = (
|
|
225
|
+
const currentValue = getAttributeValue(name);
|
|
224
226
|
const isBoolean = isBooleanFieldType(type);
|
|
225
227
|
const wrapperClassNames = [
|
|
226
228
|
'attributes-editor__field-wrapper',
|
|
@@ -81,6 +81,8 @@ export type AttributesEditorModel = {
|
|
|
81
81
|
mockableFeatureKeys: string[];
|
|
82
82
|
activeMockableFeature: string | null;
|
|
83
83
|
setActiveMockableFeature: (next: string | null) => void;
|
|
84
|
+
hasTitleField: boolean;
|
|
85
|
+
hasDescriptionField: boolean;
|
|
84
86
|
hasStringChildren: boolean;
|
|
85
87
|
childrenValue: string;
|
|
86
88
|
};
|