@developer_tribe/react-builder 1.0.8 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build-components/BIcon/BIconProps.generated.d.ts +3 -0
- package/dist/build-components/BackgroundImage/BackgroundImageProps.generated.d.ts +1 -0
- package/dist/build-components/Button/ButtonProps.generated.d.ts +1 -0
- package/dist/build-components/Carousel/CarouselProps.generated.d.ts +5 -0
- package/dist/build-components/CarouselButtons/CarouselButtonsProps.generated.d.ts +1 -0
- package/dist/build-components/CarouselDots/CarouselDotsProps.generated.d.ts +1 -0
- package/dist/build-components/CarouselItem/CarouselItemProps.generated.d.ts +1 -0
- package/dist/build-components/CarouselProvider/CarouselProviderProps.generated.d.ts +1 -0
- package/dist/build-components/Image/ImageProps.generated.d.ts +1 -0
- package/dist/build-components/Main/MainProps.generated.d.ts +1 -1
- package/dist/build-components/Onboard/OnboardProps.generated.d.ts +1 -0
- package/dist/build-components/OnboardButton/OnboardButtonProps.generated.d.ts +1 -0
- package/dist/build-components/OnboardButtons/OnboardButtonsProps.generated.d.ts +1 -0
- package/dist/build-components/OnboardDot/OnboardDotProps.generated.d.ts +1 -0
- package/dist/build-components/OnboardFooter/OnboardFooterProps.generated.d.ts +3 -0
- package/dist/build-components/OnboardImage/OnboardImageProps.generated.d.ts +1 -0
- package/dist/build-components/OnboardItem/OnboardItemProps.generated.d.ts +1 -0
- package/dist/build-components/OnboardProvider/OnboardProviderProps.generated.d.ts +3 -0
- package/dist/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.d.ts +3 -0
- package/dist/build-components/OnboardTitle/OnboardTitleProps.generated.d.ts +3 -0
- package/dist/build-components/PaywallBackground/PaywallBackgroundProps.generated.d.ts +1 -1
- package/dist/build-components/PaywallCloseButton/PaywallCloseButtonProps.generated.d.ts +3 -1
- package/dist/build-components/PaywallOptions/PaywallOptionsProps.generated.d.ts +1 -1
- package/dist/build-components/PaywallProvider/PaywallContext.d.ts +12 -0
- package/dist/build-components/PaywallProvider/PaywallProviderProps.generated.d.ts +1 -1
- package/dist/build-components/PaywallSubscribeButton/PaywallSubscribeButtonProps.generated.d.ts +1 -0
- package/dist/build-components/RadioButton/RadioButtonProps.generated.d.ts +1 -1
- package/dist/build-components/Text/TextProps.generated.d.ts +3 -0
- package/dist/build-components/View/ViewProps.generated.d.ts +1 -0
- package/dist/build-components/patterns.generated.d.ts +372 -374
- package/dist/components/BuilderProvider.d.ts +2 -0
- package/dist/components/ParamsProvider.d.ts +5 -0
- package/dist/components/RenderErrorBoundary.d.ts +28 -0
- package/dist/hooks/useSyncHtmlThemeClass.d.ts +7 -0
- package/dist/index.cjs.js +5 -5
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.esm.js +3 -3
- package/dist/index.esm.js.map +1 -1
- package/dist/index.native.cjs.js +4 -4
- package/dist/index.native.cjs.js.map +1 -1
- package/dist/index.native.d.ts +1 -0
- package/dist/index.native.esm.js +4 -4
- package/dist/index.native.esm.js.map +1 -1
- package/dist/migrations/migratePipe.d.ts +14 -0
- package/dist/migrations/migrations/1.1.0_normalize_style_attributes.d.ts +2 -0
- package/dist/migrations/semver.d.ts +8 -0
- package/dist/migrations/types.d.ts +8 -0
- package/dist/mockOS/components/SubscriptionModal.d.ts +7 -0
- package/dist/mockOS/context/MockOSContextBase.d.ts +1 -0
- package/dist/mockOS/hooks/useMockIap.d.ts +3 -0
- package/dist/mockOS/index.d.ts +4 -0
- package/dist/mockOS/managers/mockOSIapManager.d.ts +6 -0
- package/dist/mockOS/managers/subscriptionManager.d.ts +10 -0
- package/dist/pages/ProjectDebug.d.ts +14 -0
- package/dist/pages/ProjectMigrationPage.d.ts +23 -0
- package/dist/pages/ProjectValidationPage.d.ts +15 -0
- package/dist/styles.css +1 -1
- package/dist/types/Device.d.ts +5 -0
- package/dist/utils/__special_exceptions.d.ts +7 -0
- package/dist/utils/getImage.d.ts +23 -0
- package/dist/utils/pasteNode.d.ts +15 -0
- package/dist/utils/patterns.d.ts +1 -2
- package/package.json +6 -2
- package/scripts/migrate-patterns-to-v2.mjs +131 -0
- package/scripts/migrate-samples-to-current.ts +79 -0
- package/scripts/prebuild/utils/createGeneratedProps.js +4 -5
- package/scripts/prebuild/utils/validateAllComponentsOrThrow.js +32 -21
- package/scripts/prebuild/utils/validatePatternJson.js +12 -10
- package/src/.DS_Store +0 -0
- package/src/AttributesEditor.tsx +41 -11
- package/src/RenderPage.tsx +55 -0
- package/src/assets/.DS_Store +0 -0
- package/src/assets/devices.json +91 -0
- package/src/assets/samples/carousel-sample.json +141 -29
- package/src/assets/samples/getSamples.ts +9 -0
- package/src/assets/samples/paywall-1.json +119 -71
- package/src/assets/samples/simple-1.json +28 -16
- package/src/assets/samples/simple-2.json +157 -82
- package/src/assets/samples/unmigrated-builder1.json +42 -0
- package/src/assets/samples/unvalidated-builder1.json +49 -0
- package/src/assets/samples/unvalidated-crash1.json +19 -0
- package/src/assets/samples/unvalidated-crashcomponent1.json +16 -0
- package/src/assets/samples/vpn-onboard-1.json +91 -51
- package/src/assets/samples/vpn-onboard-2.json +318 -278
- package/src/assets/samples/vpn-onboard-3.json +286 -252
- package/src/assets/samples/vpn-onboard-4.json +286 -252
- package/src/assets/samples/vpn-onboard-5.json +434 -374
- package/src/assets/samples/vpn-onboard-6.json +290 -250
- package/src/attributes-editor/Field.tsx +1 -1
- package/src/attributes-editor/LayoutPreviewPicker.tsx +5 -2
- package/src/build-components/BIcon/BIconProps.generated.ts +3 -0
- package/src/build-components/BIcon/pattern.json +12 -9
- package/src/build-components/BackgroundImage/BackgroundImage.tsx +3 -1
- package/src/build-components/BackgroundImage/BackgroundImageProps.generated.ts +1 -0
- package/src/build-components/BackgroundImage/pattern.json +25 -16
- package/src/build-components/Button/Button.tsx +26 -3
- package/src/build-components/Button/ButtonProps.generated.ts +1 -0
- package/src/build-components/Button/pattern.json +10 -6
- package/src/build-components/Carousel/CarouselProps.generated.ts +5 -0
- package/src/build-components/Carousel/pattern.json +19 -8
- package/src/build-components/CarouselButtons/CarouselButtonsProps.generated.ts +1 -0
- package/src/build-components/CarouselButtons/pattern.json +11 -5
- package/src/build-components/CarouselDots/CarouselDotsProps.generated.ts +1 -0
- package/src/build-components/CarouselDots/pattern.json +5 -4
- package/src/build-components/CarouselItem/CarouselItemProps.generated.ts +1 -0
- package/src/build-components/CarouselItem/pattern.json +5 -4
- package/src/build-components/CarouselProvider/CarouselProvider.tsx +44 -2
- package/src/build-components/CarouselProvider/CarouselProviderProps.generated.ts +1 -0
- package/src/build-components/Image/Image.tsx +2 -1
- package/src/build-components/Image/ImageProps.generated.ts +1 -0
- package/src/build-components/Image/pattern.json +11 -5
- package/src/build-components/Main/MainProps.generated.ts +1 -1
- package/src/build-components/Main/pattern.json +12 -9
- package/src/build-components/Onboard/OnboardProps.generated.ts +1 -0
- package/src/build-components/Onboard/pattern.json +14 -9
- package/src/build-components/OnboardButton/OnboardButtonProps.generated.ts +1 -0
- package/src/build-components/OnboardButton/pattern.json +5 -4
- package/src/build-components/OnboardButtons/OnboardButtonsProps.generated.ts +1 -0
- package/src/build-components/OnboardButtons/pattern.json +5 -4
- package/src/build-components/OnboardDot/OnboardDotProps.generated.ts +1 -0
- package/src/build-components/OnboardDot/pattern.json +5 -4
- package/src/build-components/OnboardFooter/OnboardFooterProps.generated.ts +3 -0
- package/src/build-components/OnboardFooter/pattern.json +8 -5
- package/src/build-components/OnboardImage/OnboardImageProps.generated.ts +1 -0
- package/src/build-components/OnboardImage/pattern.json +7 -4
- package/src/build-components/OnboardItem/OnboardItemProps.generated.ts +1 -0
- package/src/build-components/OnboardItem/pattern.json +18 -9
- package/src/build-components/OnboardProvider/OnboardProviderProps.generated.ts +3 -0
- package/src/build-components/OnboardProvider/pattern.json +21 -6
- package/src/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.ts +3 -0
- package/src/build-components/OnboardSubtitle/pattern.json +10 -6
- package/src/build-components/OnboardTitle/OnboardTitleProps.generated.ts +3 -0
- package/src/build-components/OnboardTitle/pattern.json +11 -7
- package/src/build-components/PaywallBackground/PaywallBackgroundProps.generated.ts +1 -1
- package/src/build-components/PaywallBackground/pattern.json +5 -4
- package/src/build-components/PaywallCloseButton/PaywallCloseButton.tsx +6 -1
- package/src/build-components/PaywallCloseButton/PaywallCloseButtonProps.generated.ts +3 -1
- package/src/build-components/PaywallCloseButton/pattern.json +15 -12
- package/src/build-components/PaywallOptions/PaywallOptionButton.tsx +0 -1
- package/src/build-components/PaywallOptions/PaywallOptions.tsx +3 -2
- package/src/build-components/PaywallOptions/PaywallOptionsProps.generated.ts +1 -1
- package/src/build-components/PaywallOptions/pattern.json +14 -11
- package/src/build-components/PaywallProvider/PaywallContext.ts +25 -0
- package/src/build-components/PaywallProvider/PaywallProvider.tsx +102 -5
- package/src/build-components/PaywallProvider/PaywallProviderProps.generated.ts +1 -1
- package/src/build-components/PaywallProvider/pattern.json +11 -8
- package/src/build-components/PaywallSubscribeButton/PaywallSubscribeButton.tsx +7 -0
- package/src/build-components/PaywallSubscribeButton/PaywallSubscribeButtonProps.generated.ts +1 -0
- package/src/build-components/PaywallSubscribeButton/pattern.json +16 -13
- package/src/build-components/RadioButton/RadioButtonProps.generated.ts +1 -1
- package/src/build-components/RadioButton/pattern.json +5 -4
- package/src/build-components/Text/Text.tsx +107 -4
- package/src/build-components/Text/TextProps.generated.ts +3 -0
- package/src/build-components/Text/pattern.json +19 -4
- package/src/build-components/View/ViewProps.generated.ts +1 -0
- package/src/build-components/View/pattern.json +28 -13
- package/src/build-components/other.tsx +15 -0
- package/src/build-components/patterns.generated.ts +340 -235
- package/src/build-components/useNode.ts +22 -3
- package/src/components/Builder.tsx +20 -6
- package/src/components/BuilderButton.tsx +75 -38
- package/src/components/BuilderProvider.tsx +22 -2
- package/src/components/DeviceButton.tsx +12 -5
- package/src/components/EditorHeader.tsx +296 -38
- package/src/components/ParamsProvider.tsx +7 -0
- package/src/components/RenderErrorBoundary.tsx +200 -0
- package/src/hooks/useParams.ts +5 -1
- package/src/hooks/useSyncHtmlThemeClass.ts +19 -0
- package/src/index.native.ts +7 -0
- package/src/index.ts +8 -0
- package/src/migrations/migratePipe.ts +59 -0
- package/src/migrations/migrations/1.1.0_normalize_style_attributes.ts +80 -0
- package/src/migrations/semver.ts +24 -0
- package/src/migrations/types.ts +9 -0
- package/src/mockOS/components/PermissionModal.tsx +3 -2
- package/src/mockOS/components/SubscriptionModal.tsx +400 -0
- package/src/mockOS/context/MockOSContext.tsx +61 -10
- package/src/mockOS/context/MockOSContextBase.ts +1 -0
- package/src/mockOS/hooks/useMockIap.ts +11 -0
- package/src/mockOS/index.ts +7 -0
- package/src/mockOS/managers/mockOSIapManager.ts +10 -0
- package/src/mockOS/managers/subscriptionManager.ts +36 -0
- package/src/modals/IconPickerModal.tsx +1 -1
- package/src/pages/ProjectDebug.tsx +331 -0
- package/src/pages/ProjectMigrationPage.tsx +92 -0
- package/src/pages/ProjectPage.tsx +313 -161
- package/src/pages/ProjectValidationPage.tsx +54 -0
- package/src/styles/base/_global.scss +58 -11
- package/src/styles/components/_attributes-editor.scss +1 -1
- package/src/styles/components/_bottom-bar.scss +7 -4
- package/src/styles/components/_editor-shell.scss +126 -4
- package/src/styles/components/_mockos-router.scss +3 -2
- package/src/styles/components/_ui-components.scss +10 -5
- package/src/styles/foundation/_colors.scss +78 -11
- package/src/styles/foundation/_mixins.scss +4 -1
- package/src/styles/foundation/_sizes.scss +4 -2
- package/src/styles/index.scss +1 -0
- package/src/styles/layout/_builder.scss +61 -0
- package/src/styles/layout/_project-validation.scss +214 -0
- package/src/styles/modals/_add-component.scss +4 -2
- package/src/styles/modals/_color-modal.scss +4 -2
- package/src/styles/modals/_modal-shell.scss +3 -1
- package/src/types/Device.ts +5 -0
- package/src/utils/__special_exceptions.ts +88 -0
- package/src/utils/analyseNode.ts +8 -2
- package/src/utils/analyseNodeByPatterns.ts +43 -9
- package/src/utils/extractTextStyle.ts +19 -6
- package/src/utils/extractViewStyle.ts +68 -59
- package/src/utils/getImage.ts +76 -0
- package/src/utils/novaToJson.ts +2 -1
- package/src/utils/pasteNode.ts +172 -0
- package/src/utils/patterns.ts +4 -3
- package/dist/android.svg +0 -43
- package/dist/apple.svg +0 -16
- package/dist/background.jpg +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useId, useMemo } from 'react';
|
|
1
|
+
import React, { useCallback, useEffect, useId, useMemo, useState } from 'react';
|
|
2
2
|
import type { PaywallProviderComponentProps } from './PaywallProviderProps.generated';
|
|
3
3
|
import RenderNode from '../RenderNode.generated';
|
|
4
4
|
import type { Node } from '../../types/Node';
|
|
@@ -10,6 +10,8 @@ import { isNodeSelected, SELECTED_OUTLINE_STYLE } from '../../utils/selection';
|
|
|
10
10
|
import { useMergedStyle } from '../../utils/useMergedStyle';
|
|
11
11
|
import { LocalizationParamsProvider } from '../../components/LocalizationParamsProvider';
|
|
12
12
|
import { useBuilderParams } from '../../components/BuilderProvider';
|
|
13
|
+
import { PaywallContext } from './PaywallContext';
|
|
14
|
+
import { useMockOSContext } from '../../mockOS/context/MockOSContextBase';
|
|
13
15
|
|
|
14
16
|
function PaywallProvider({ node }: PaywallProviderComponentProps) {
|
|
15
17
|
useLogRender('PaywallProvider');
|
|
@@ -29,7 +31,9 @@ function PaywallProvider({ node }: PaywallProviderComponentProps) {
|
|
|
29
31
|
}),
|
|
30
32
|
);
|
|
31
33
|
|
|
32
|
-
const { benefits } =
|
|
34
|
+
const { benefits, products, onPaywallClose, onPaywallSubscribe } =
|
|
35
|
+
useBuilderParams();
|
|
36
|
+
const mockOS = useMockOSContext();
|
|
33
37
|
const benefitLocalizationParams = useMemo(() => {
|
|
34
38
|
const raw =
|
|
35
39
|
benefits && typeof benefits === 'object' && !Array.isArray(benefits)
|
|
@@ -62,15 +66,108 @@ function PaywallProvider({ node }: PaywallProviderComponentProps) {
|
|
|
62
66
|
isSelected ? SELECTED_OUTLINE_STYLE : undefined,
|
|
63
67
|
);
|
|
64
68
|
|
|
69
|
+
const [selectedProductId, setSelectedProductId] = useState<string>('');
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
const list = Array.isArray(products) ? products : [];
|
|
72
|
+
if (list.length === 0) {
|
|
73
|
+
if (selectedProductId) setSelectedProductId('');
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const exists = list.some((p) => p?.productId === selectedProductId);
|
|
78
|
+
if (!selectedProductId || !exists) {
|
|
79
|
+
setSelectedProductId(list[0]?.productId ?? '');
|
|
80
|
+
}
|
|
81
|
+
}, [products, selectedProductId]);
|
|
82
|
+
|
|
83
|
+
const selectedProduct = useMemo(() => {
|
|
84
|
+
const list = Array.isArray(products) ? products : [];
|
|
85
|
+
return (
|
|
86
|
+
list.find((p) => p?.productId === selectedProductId) ??
|
|
87
|
+
(list.length > 0 ? list[0] : undefined)
|
|
88
|
+
);
|
|
89
|
+
}, [products, selectedProductId]);
|
|
90
|
+
|
|
91
|
+
const handleClose = useCallback(() => {
|
|
92
|
+
// Host app override wins.
|
|
93
|
+
if (onPaywallClose) {
|
|
94
|
+
onPaywallClose();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Default: in MockOS go back (simulate dismissing paywall screen).
|
|
98
|
+
// TODO: at react native merge it will change
|
|
99
|
+
if (mockOS?.isEnabled && mockOS.goBack) {
|
|
100
|
+
mockOS.goBack();
|
|
101
|
+
}
|
|
102
|
+
}, [mockOS, onPaywallClose]);
|
|
103
|
+
|
|
104
|
+
const handleSubscribe = useCallback(
|
|
105
|
+
async (product?: { productId?: string }) => {
|
|
106
|
+
// Host app override wins.
|
|
107
|
+
if (onPaywallSubscribe) {
|
|
108
|
+
const result = onPaywallSubscribe(product as any);
|
|
109
|
+
const ok =
|
|
110
|
+
result instanceof Promise
|
|
111
|
+
? await result
|
|
112
|
+
: result === true
|
|
113
|
+
? true
|
|
114
|
+
: false;
|
|
115
|
+
|
|
116
|
+
// If host signals success, go back (OS return).
|
|
117
|
+
if (ok && mockOS?.isEnabled) {
|
|
118
|
+
mockOS.goBack?.();
|
|
119
|
+
}
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Default: in MockOS show a native-like subscription prompt.
|
|
124
|
+
// TODO: at react native merge it will change
|
|
125
|
+
const productId = product?.productId;
|
|
126
|
+
if (
|
|
127
|
+
mockOS?.isEnabled &&
|
|
128
|
+
productId &&
|
|
129
|
+
mockOS.requestSubscriptionPurchase
|
|
130
|
+
) {
|
|
131
|
+
const ok = await mockOS.requestSubscriptionPurchase(productId);
|
|
132
|
+
if (ok) {
|
|
133
|
+
// On success, go back (simulate dismissing paywall after purchase).
|
|
134
|
+
// TODO: at react native merge it will change
|
|
135
|
+
mockOS.goBack?.();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
[mockOS, onPaywallSubscribe],
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
const paywallContextValue = useMemo(
|
|
143
|
+
() => ({
|
|
144
|
+
products: Array.isArray(products) ? products : [],
|
|
145
|
+
selectedProductId,
|
|
146
|
+
setSelectedProductId,
|
|
147
|
+
selectedProduct,
|
|
148
|
+
onClose: handleClose,
|
|
149
|
+
onSubscribe: handleSubscribe as any,
|
|
150
|
+
}),
|
|
151
|
+
[
|
|
152
|
+
products,
|
|
153
|
+
selectedProductId,
|
|
154
|
+
selectedProduct,
|
|
155
|
+
handleClose,
|
|
156
|
+
handleSubscribe,
|
|
157
|
+
],
|
|
158
|
+
);
|
|
159
|
+
|
|
65
160
|
return (
|
|
66
161
|
<div
|
|
67
162
|
attribute-name={attributeName}
|
|
68
163
|
attribute-key={attributeKey}
|
|
69
164
|
style={style}
|
|
70
165
|
>
|
|
71
|
-
<
|
|
72
|
-
<
|
|
73
|
-
|
|
166
|
+
<PaywallContext.Provider value={paywallContextValue}>
|
|
167
|
+
<LocalizationParamsProvider params={benefitLocalizationParams}>
|
|
168
|
+
<RenderNode node={node.children as Node} />
|
|
169
|
+
</LocalizationParamsProvider>
|
|
170
|
+
</PaywallContext.Provider>
|
|
74
171
|
</div>
|
|
75
172
|
);
|
|
76
173
|
}
|
|
@@ -21,6 +21,7 @@ export type PositionOptionType = 'relative' | 'absolute';
|
|
|
21
21
|
export interface PaywallProviderPropsGenerated {
|
|
22
22
|
child: string;
|
|
23
23
|
attributes: {
|
|
24
|
+
style?: Record<string, unknown>;
|
|
24
25
|
scrollable?: boolean;
|
|
25
26
|
flexDirection?: FlexDirectionOptionType;
|
|
26
27
|
alignItems?: AlignItemsOptionType;
|
|
@@ -54,7 +55,6 @@ export interface PaywallProviderPropsGenerated {
|
|
|
54
55
|
left?: string;
|
|
55
56
|
right?: string;
|
|
56
57
|
zIndex?: number;
|
|
57
|
-
[key: string]: string | number | boolean | undefined;
|
|
58
58
|
};
|
|
59
59
|
}
|
|
60
60
|
|
|
@@ -1,24 +1,27 @@
|
|
|
1
1
|
{
|
|
2
|
-
"schemaVersion":
|
|
3
|
-
"allowUnknownAttributes": true,
|
|
2
|
+
"schemaVersion": 2,
|
|
4
3
|
"pattern": {
|
|
5
4
|
"type": "PaywallProvider",
|
|
6
|
-
"children":
|
|
5
|
+
"children": "node",
|
|
7
6
|
"extends": "View",
|
|
8
7
|
"attributes": {}
|
|
9
8
|
},
|
|
10
9
|
"defaults": {
|
|
11
|
-
"
|
|
12
|
-
|
|
10
|
+
"style": {
|
|
11
|
+
"width": "100%",
|
|
12
|
+
"height": "100%"
|
|
13
|
+
}
|
|
13
14
|
},
|
|
14
15
|
"meta": {
|
|
15
|
-
"desiredParent": [
|
|
16
|
+
"desiredParent": [
|
|
17
|
+
"all"
|
|
18
|
+
],
|
|
16
19
|
"label": "Paywall Provider",
|
|
17
20
|
"description": "Provider/wrapper for paywall screen components.",
|
|
18
|
-
"attributes": {},
|
|
19
21
|
"mockableFeatures": {
|
|
20
22
|
"products": true,
|
|
21
23
|
"benefits": true
|
|
22
|
-
}
|
|
24
|
+
},
|
|
25
|
+
"styles": {}
|
|
23
26
|
}
|
|
24
27
|
}
|
|
@@ -7,12 +7,14 @@ import { extractTextStyle } from '../../utils/extractTextStyle';
|
|
|
7
7
|
import { isNodeSelected, SELECTED_OUTLINE_STYLE } from '../../utils/selection';
|
|
8
8
|
import { useMergedStyle } from '../../utils/useMergedStyle';
|
|
9
9
|
import { useLocalize } from '../../hooks/useLocalize';
|
|
10
|
+
import { usePaywallContext } from '../PaywallProvider/PaywallContext';
|
|
10
11
|
|
|
11
12
|
function PaywallSubscribeButton({
|
|
12
13
|
node,
|
|
13
14
|
}: PaywallSubscribeButtonComponentProps) {
|
|
14
15
|
useLogRender('PaywallSubscribeButton');
|
|
15
16
|
node = useNode(node);
|
|
17
|
+
const { onSubscribe, selectedProduct } = usePaywallContext();
|
|
16
18
|
|
|
17
19
|
const generatedId = useId();
|
|
18
20
|
const attributeName =
|
|
@@ -50,6 +52,11 @@ function PaywallSubscribeButton({
|
|
|
50
52
|
type="button"
|
|
51
53
|
attribute-name={attributeName}
|
|
52
54
|
attribute-key={attributeKey}
|
|
55
|
+
href="#"
|
|
56
|
+
onClick={(e) => {
|
|
57
|
+
e.preventDefault();
|
|
58
|
+
onSubscribe?.(selectedProduct);
|
|
59
|
+
}}
|
|
53
60
|
style={{ ...style, cursor: 'pointer' }}
|
|
54
61
|
>
|
|
55
62
|
{localize(label)}
|
package/src/build-components/PaywallSubscribeButton/PaywallSubscribeButtonProps.generated.ts
CHANGED
|
@@ -33,6 +33,7 @@ export type PositionOptionType = 'relative' | 'absolute';
|
|
|
33
33
|
export interface PaywallSubscribeButtonPropsGenerated {
|
|
34
34
|
child: string;
|
|
35
35
|
attributes: {
|
|
36
|
+
style?: Record<string, unknown>;
|
|
36
37
|
color?: string;
|
|
37
38
|
fontSize?: string;
|
|
38
39
|
fontWeight?: FontWeightOptionType;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"schemaVersion":
|
|
3
|
-
"allowUnknownAttributes": false,
|
|
2
|
+
"schemaVersion": 2,
|
|
4
3
|
"pattern": {
|
|
5
4
|
"type": "PaywallSubscribeButton",
|
|
6
5
|
"children": "string",
|
|
@@ -8,20 +7,24 @@
|
|
|
8
7
|
"attributes": {}
|
|
9
8
|
},
|
|
10
9
|
"defaults": {
|
|
11
|
-
"
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
10
|
+
"style": {
|
|
11
|
+
"paddingHorizontal": "20@s",
|
|
12
|
+
"paddingVertical": "12@vs",
|
|
13
|
+
"borderRadius": "12@s",
|
|
14
|
+
"backgroundColor": "#6495ED",
|
|
15
|
+
"color": "#FFFFFF",
|
|
16
|
+
"fontSize": "16@fs",
|
|
17
|
+
"fontWeight": "700",
|
|
18
|
+
"justifyContent": "center",
|
|
19
|
+
"alignItems": "center"
|
|
20
|
+
}
|
|
20
21
|
},
|
|
21
22
|
"meta": {
|
|
22
|
-
"desiredParent": [
|
|
23
|
+
"desiredParent": [
|
|
24
|
+
">PaywallProvider"
|
|
25
|
+
],
|
|
23
26
|
"label": "Paywall Subscribe Button",
|
|
24
27
|
"description": "Paywall subscribe call-to-action button. Extends Button.",
|
|
25
|
-
"
|
|
28
|
+
"styles": {}
|
|
26
29
|
}
|
|
27
30
|
}
|
|
@@ -21,6 +21,7 @@ export type PositionOptionType = 'relative' | 'absolute';
|
|
|
21
21
|
export interface RadioButtonPropsGenerated {
|
|
22
22
|
child: string;
|
|
23
23
|
attributes: {
|
|
24
|
+
style?: Record<string, unknown>;
|
|
24
25
|
scrollable?: boolean;
|
|
25
26
|
flexDirection?: FlexDirectionOptionType;
|
|
26
27
|
alignItems?: AlignItemsOptionType;
|
|
@@ -57,7 +58,6 @@ export interface RadioButtonPropsGenerated {
|
|
|
57
58
|
selected?: boolean;
|
|
58
59
|
color?: string;
|
|
59
60
|
size?: number;
|
|
60
|
-
[key: string]: string | number | boolean | undefined;
|
|
61
61
|
};
|
|
62
62
|
}
|
|
63
63
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"schemaVersion":
|
|
3
|
-
"allowUnknownAttributes": true,
|
|
2
|
+
"schemaVersion": 2,
|
|
4
3
|
"pattern": {
|
|
5
4
|
"type": "RadioButton",
|
|
6
5
|
"children": "never",
|
|
@@ -12,10 +11,12 @@
|
|
|
12
11
|
}
|
|
13
12
|
},
|
|
14
13
|
"meta": {
|
|
15
|
-
"desiredParent": [
|
|
14
|
+
"desiredParent": [
|
|
15
|
+
"all"
|
|
16
|
+
],
|
|
16
17
|
"label": "Radio Button",
|
|
17
18
|
"description": "Generic radio button icon.",
|
|
18
|
-
"
|
|
19
|
+
"styles": {
|
|
19
20
|
"selected": {
|
|
20
21
|
"label": "Selected",
|
|
21
22
|
"description": "Whether the radio is selected.",
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, {
|
|
2
|
+
useId,
|
|
3
|
+
useLayoutEffect,
|
|
4
|
+
useMemo,
|
|
5
|
+
useRef,
|
|
6
|
+
useState,
|
|
7
|
+
} from 'react';
|
|
2
8
|
import type { TextComponentProps } from './TextProps.generated';
|
|
3
9
|
import useNode from '../useNode';
|
|
4
10
|
import { useRenderStore } from '../../store';
|
|
@@ -14,6 +20,8 @@ function Text({ node }: TextComponentProps) {
|
|
|
14
20
|
const generatedId = useId();
|
|
15
21
|
const attributeName = (node as any)?.sourceType ?? node.type ?? 'text';
|
|
16
22
|
const attributeKey = node.key ?? generatedId;
|
|
23
|
+
const textRef = useRef<HTMLParagraphElement | null>(null);
|
|
24
|
+
const [autoFontSizePx, setAutoFontSizePx] = useState<number | null>(null);
|
|
17
25
|
const { appConfig, projectColors, previewMode, current } = useRenderStore(
|
|
18
26
|
(s) => ({
|
|
19
27
|
appConfig: s.appConfig,
|
|
@@ -28,18 +36,113 @@ function Text({ node }: TextComponentProps) {
|
|
|
28
36
|
[node, appConfig, projectColors],
|
|
29
37
|
);
|
|
30
38
|
const isSelected = isNodeSelected({ previewMode, current, node });
|
|
39
|
+
const localize = useLocalize();
|
|
40
|
+
|
|
41
|
+
const localizedText = useMemo(
|
|
42
|
+
() => localize(keyOrText),
|
|
43
|
+
[localize, keyOrText],
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
const attrs = (node as any)?.attributes as
|
|
47
|
+
| (Record<string, unknown> & { style?: Record<string, unknown> })
|
|
48
|
+
| undefined;
|
|
49
|
+
const styleBag = attrs?.style;
|
|
50
|
+
const adjustsFontSizeToFit =
|
|
51
|
+
(attrs?.adjustsFontSizeToFit as boolean | undefined) ??
|
|
52
|
+
(styleBag?.adjustsFontSizeToFit as boolean | undefined) ??
|
|
53
|
+
false;
|
|
54
|
+
const showEllipsis =
|
|
55
|
+
(attrs?.showEllipsis as boolean | undefined) ??
|
|
56
|
+
(styleBag?.showEllipsis as boolean | undefined) ??
|
|
57
|
+
false;
|
|
58
|
+
|
|
59
|
+
useLayoutEffect(() => {
|
|
60
|
+
if (!adjustsFontSizeToFit) {
|
|
61
|
+
setAutoFontSizePx(null);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const el = textRef.current;
|
|
66
|
+
if (!el) return;
|
|
67
|
+
|
|
68
|
+
const compute = () => {
|
|
69
|
+
const availableWidth = el.clientWidth;
|
|
70
|
+
const availableHeight = el.clientHeight;
|
|
71
|
+
const len = localizedText?.length ?? 0;
|
|
72
|
+
|
|
73
|
+
if (!availableWidth || !availableHeight || !len) {
|
|
74
|
+
setAutoFontSizePx(null);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// TODO: fontSize = Math.sqrt(textWidth*textHeight/text.length)
|
|
79
|
+
const candidate = Math.sqrt((availableWidth * availableHeight) / len);
|
|
80
|
+
const computedFontSizePx = Number.parseFloat(
|
|
81
|
+
window.getComputedStyle(el).fontSize,
|
|
82
|
+
);
|
|
83
|
+
const maxPx = Number.isFinite(computedFontSizePx)
|
|
84
|
+
? computedFontSizePx
|
|
85
|
+
: undefined;
|
|
86
|
+
|
|
87
|
+
// Keep it within a sane range and never increase beyond current font size.
|
|
88
|
+
const clamped = Math.max(
|
|
89
|
+
8,
|
|
90
|
+
maxPx ? Math.min(candidate, maxPx) : candidate,
|
|
91
|
+
);
|
|
92
|
+
setAutoFontSizePx(Number.isFinite(clamped) ? clamped : null);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
compute();
|
|
96
|
+
|
|
97
|
+
let ro: ResizeObserver | null = null;
|
|
98
|
+
if (typeof ResizeObserver !== 'undefined') {
|
|
99
|
+
ro = new ResizeObserver(() => compute());
|
|
100
|
+
ro.observe(el);
|
|
101
|
+
} else {
|
|
102
|
+
window.addEventListener('resize', compute);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return () => {
|
|
106
|
+
ro?.disconnect();
|
|
107
|
+
window.removeEventListener('resize', compute);
|
|
108
|
+
};
|
|
109
|
+
}, [adjustsFontSizeToFit, localizedText]);
|
|
110
|
+
|
|
111
|
+
const extraStyle = useMemo((): React.CSSProperties | undefined => {
|
|
112
|
+
let next: React.CSSProperties | undefined;
|
|
113
|
+
|
|
114
|
+
if (showEllipsis) {
|
|
115
|
+
next = {
|
|
116
|
+
...(next ?? {}),
|
|
117
|
+
overflow: 'hidden',
|
|
118
|
+
textOverflow: 'ellipsis',
|
|
119
|
+
whiteSpace: 'nowrap',
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (autoFontSizePx !== null) {
|
|
124
|
+
next = {
|
|
125
|
+
...(next ?? {}),
|
|
126
|
+
fontSize: `${autoFontSizePx}px`,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return next;
|
|
131
|
+
}, [showEllipsis, autoFontSizePx]);
|
|
132
|
+
|
|
31
133
|
const style = useMergedStyle(
|
|
32
|
-
textStyle,
|
|
134
|
+
useMergedStyle(textStyle, extraStyle),
|
|
33
135
|
isSelected ? SELECTED_OUTLINE_STYLE : undefined,
|
|
34
136
|
);
|
|
35
|
-
|
|
137
|
+
|
|
36
138
|
return (
|
|
37
139
|
<p
|
|
140
|
+
ref={textRef}
|
|
38
141
|
attribute-name={attributeName}
|
|
39
142
|
attribute-key={attributeKey}
|
|
40
143
|
style={style}
|
|
41
144
|
>
|
|
42
|
-
{
|
|
145
|
+
{localizedText}
|
|
43
146
|
</p>
|
|
44
147
|
);
|
|
45
148
|
}
|
|
@@ -34,6 +34,7 @@ export type TextAlignOptionType = 'left' | 'center' | 'right' | 'justify';
|
|
|
34
34
|
export interface TextPropsGenerated {
|
|
35
35
|
child: string;
|
|
36
36
|
attributes: {
|
|
37
|
+
style?: Record<string, unknown>;
|
|
37
38
|
scrollable?: boolean;
|
|
38
39
|
flexDirection?: FlexDirectionOptionType;
|
|
39
40
|
alignItems?: AlignItemsOptionType;
|
|
@@ -71,6 +72,8 @@ export interface TextPropsGenerated {
|
|
|
71
72
|
fontSize?: string;
|
|
72
73
|
fontWeight?: FontWeightOptionType;
|
|
73
74
|
textAlign?: TextAlignOptionType;
|
|
75
|
+
adjustsFontSizeToFit?: boolean;
|
|
76
|
+
showEllipsis?: boolean;
|
|
74
77
|
};
|
|
75
78
|
}
|
|
76
79
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"schemaVersion":
|
|
3
|
-
"allowUnknownAttributes": false,
|
|
2
|
+
"schemaVersion": 2,
|
|
4
3
|
"pattern": {
|
|
5
4
|
"type": "Text",
|
|
6
5
|
"children": "string",
|
|
@@ -21,14 +20,16 @@
|
|
|
21
20
|
"800",
|
|
22
21
|
"900"
|
|
23
22
|
],
|
|
24
|
-
"textAlign": ["left", "center", "right", "justify"]
|
|
23
|
+
"textAlign": ["left", "center", "right", "justify"],
|
|
24
|
+
"adjustsFontSizeToFit": "boolean",
|
|
25
|
+
"showEllipsis": "boolean"
|
|
25
26
|
}
|
|
26
27
|
},
|
|
27
28
|
"meta": {
|
|
28
29
|
"desiredParent": ["all"],
|
|
29
30
|
"label": "Text",
|
|
30
31
|
"description": "Displays simple text.",
|
|
31
|
-
"
|
|
32
|
+
"styles": {
|
|
32
33
|
"color": {
|
|
33
34
|
"label": "Color",
|
|
34
35
|
"description": "Text color.",
|
|
@@ -57,6 +58,20 @@
|
|
|
57
58
|
"category": "style",
|
|
58
59
|
"specialCategory": null,
|
|
59
60
|
"sort": 4
|
|
61
|
+
},
|
|
62
|
+
"adjustsFontSizeToFit": {
|
|
63
|
+
"label": "Adjust Font Size To Fit",
|
|
64
|
+
"description": "Automatically reduces font size to fit the available space.",
|
|
65
|
+
"category": "style",
|
|
66
|
+
"specialCategory": null,
|
|
67
|
+
"sort": 5
|
|
68
|
+
},
|
|
69
|
+
"showEllipsis": {
|
|
70
|
+
"label": "Show Ellipsis",
|
|
71
|
+
"description": "If text overflows, show ellipsis (…); applied as single-line truncation.",
|
|
72
|
+
"category": "style",
|
|
73
|
+
"specialCategory": null,
|
|
74
|
+
"sort": 6
|
|
60
75
|
}
|
|
61
76
|
}
|
|
62
77
|
}
|
|
@@ -21,6 +21,7 @@ export type PositionOptionType = 'relative' | 'absolute';
|
|
|
21
21
|
export interface ViewPropsGenerated {
|
|
22
22
|
child: string;
|
|
23
23
|
attributes: {
|
|
24
|
+
style?: Record<string, unknown>;
|
|
24
25
|
scrollable?: boolean;
|
|
25
26
|
flexDirection?: FlexDirectionOptionType;
|
|
26
27
|
alignItems?: AlignItemsOptionType;
|
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
{
|
|
2
|
-
"schemaVersion":
|
|
3
|
-
"allowUnknownAttributes": false,
|
|
2
|
+
"schemaVersion": 2,
|
|
4
3
|
"pattern": {
|
|
5
4
|
"type": "View",
|
|
6
|
-
"children":
|
|
5
|
+
"children": "node",
|
|
7
6
|
"attributes": {
|
|
8
7
|
"scrollable": "boolean",
|
|
9
|
-
"flexDirection": [
|
|
10
|
-
|
|
8
|
+
"flexDirection": [
|
|
9
|
+
"row",
|
|
10
|
+
"column"
|
|
11
|
+
],
|
|
12
|
+
"alignItems": [
|
|
13
|
+
"flex-start",
|
|
14
|
+
"center",
|
|
15
|
+
"flex-end",
|
|
16
|
+
"stretch",
|
|
17
|
+
"baseline"
|
|
18
|
+
],
|
|
11
19
|
"justifyContent": [
|
|
12
20
|
"flex-start",
|
|
13
21
|
"center",
|
|
@@ -39,21 +47,21 @@
|
|
|
39
47
|
"minHeight": "size",
|
|
40
48
|
"maxHeight": "size",
|
|
41
49
|
"flex": "number",
|
|
42
|
-
"position": [
|
|
50
|
+
"position": [
|
|
51
|
+
"relative",
|
|
52
|
+
"absolute"
|
|
53
|
+
],
|
|
43
54
|
"top": "size",
|
|
44
55
|
"bottom": "size",
|
|
45
56
|
"left": "size",
|
|
46
57
|
"right": "size",
|
|
47
58
|
"zIndex": "number"
|
|
48
|
-
},
|
|
49
|
-
"defaults": {
|
|
50
|
-
"flexDirection": "column",
|
|
51
|
-
"position": "relative",
|
|
52
|
-
"zIndex": 1
|
|
53
59
|
}
|
|
54
60
|
},
|
|
55
61
|
"meta": {
|
|
56
|
-
"desiredParent": [
|
|
62
|
+
"desiredParent": [
|
|
63
|
+
"all"
|
|
64
|
+
],
|
|
57
65
|
"label": "View",
|
|
58
66
|
"description": "Base layout container.",
|
|
59
67
|
"specialCategories": {
|
|
@@ -82,7 +90,7 @@
|
|
|
82
90
|
"sort": 4
|
|
83
91
|
}
|
|
84
92
|
},
|
|
85
|
-
"
|
|
93
|
+
"styles": {
|
|
86
94
|
"scrollable": {
|
|
87
95
|
"label": "Scrollable",
|
|
88
96
|
"description": "Turns scroll interaction on.",
|
|
@@ -348,5 +356,12 @@
|
|
|
348
356
|
"sort": 26
|
|
349
357
|
}
|
|
350
358
|
}
|
|
359
|
+
},
|
|
360
|
+
"defaults": {
|
|
361
|
+
"style": {
|
|
362
|
+
"flexDirection": "column",
|
|
363
|
+
"position": "relative",
|
|
364
|
+
"zIndex": 1
|
|
365
|
+
}
|
|
351
366
|
}
|
|
352
367
|
}
|
|
@@ -2,5 +2,20 @@ import React from 'react';
|
|
|
2
2
|
import type { Node } from '../types/Node';
|
|
3
3
|
|
|
4
4
|
export function other(type: string, node: Node): React.ReactNode {
|
|
5
|
+
// Intentionally-crashing component for testing error boundaries / unvalidated flows.
|
|
6
|
+
// NOTE: This is NOT part of the generated component patterns, so it will never
|
|
7
|
+
// show up in the "Add component" modal. It can only be used by loading JSON
|
|
8
|
+
// that contains { type: "CrashComponent" }.
|
|
9
|
+
if (type === 'CrashComponent') {
|
|
10
|
+
const details =
|
|
11
|
+
node && typeof node === 'object' && !Array.isArray(node)
|
|
12
|
+
? (node as any).attributes
|
|
13
|
+
: undefined;
|
|
14
|
+
throw new Error(
|
|
15
|
+
`CrashComponent: intentional crash for testing${
|
|
16
|
+
details ? ` (attributes=${JSON.stringify(details)})` : ''
|
|
17
|
+
}`,
|
|
18
|
+
);
|
|
19
|
+
}
|
|
5
20
|
return null;
|
|
6
21
|
}
|