@developer_tribe/react-builder 1.2.27 → 1.2.29

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.
Files changed (156) hide show
  1. package/dist/assets/samples/getSamples.d.ts +0 -3
  2. package/dist/build-components/BIcon/BIconProps.generated.d.ts +1 -2
  3. package/dist/build-components/CountDown/CountDownProps.generated.d.ts +2 -1
  4. package/dist/build-components/OnboardFooter/OnboardFooterProps.generated.d.ts +1 -2
  5. package/dist/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.d.ts +1 -2
  6. package/dist/build-components/OnboardTitle/OnboardTitleProps.generated.d.ts +1 -2
  7. package/dist/build-components/PaywallCloseButton/PaywallCloseButtonProps.generated.d.ts +1 -2
  8. package/dist/build-components/PaywallOptions/usePaywallOptionParamsFactory.d.ts +1 -1
  9. package/dist/build-components/PriceTag/PriceTag.d.ts +5 -0
  10. package/dist/build-components/PriceTag/PriceTagProps.generated.d.ts +63 -0
  11. package/dist/build-components/Pricing/Pricing.d.ts +5 -0
  12. package/dist/build-components/Pricing/PricingProps.generated.d.ts +59 -0
  13. package/dist/build-components/Promo/Promo.d.ts +5 -0
  14. package/dist/build-components/Promo/PromoProps.generated.d.ts +59 -0
  15. package/dist/build-components/Text/TextProps.generated.d.ts +1 -2
  16. package/dist/build-components/index.d.ts +4 -1
  17. package/dist/build-components/patterns.generated.d.ts +1405 -202
  18. package/dist/components/BuilderProvider.d.ts +5 -3
  19. package/dist/components/ParamsProvider.d.ts +16 -8
  20. package/dist/hooks/useSyncHtmlThemeClass.d.ts +1 -1
  21. package/dist/index.cjs.js +4 -4
  22. package/dist/index.cjs.js.map +1 -1
  23. package/dist/index.d.ts +16 -3
  24. package/dist/index.esm.js +4 -4
  25. package/dist/index.esm.js.map +1 -1
  26. package/dist/index.web.cjs.js +4 -4
  27. package/dist/index.web.cjs.js.map +1 -1
  28. package/dist/index.web.esm.js +4 -4
  29. package/dist/index.web.esm.js.map +1 -1
  30. package/dist/logger.d.ts +18 -0
  31. package/dist/modals/InspectModal.d.ts +5 -0
  32. package/dist/modals/index.d.ts +1 -1
  33. package/dist/pages/ProjectPage.d.ts +3 -3
  34. package/dist/paywall/hooks/useCalculateLocalizedPrice.d.ts +4 -2
  35. package/dist/paywall/hooks/useDiscountRate.d.ts +3 -2
  36. package/dist/paywall/types/paywall-types.d.ts +7 -32
  37. package/dist/product-base/buildPaywallLocalizationParams.d.ts +16 -0
  38. package/dist/product-base/calculations.d.ts +29 -0
  39. package/dist/product-base/extractAndroidParams.d.ts +24 -0
  40. package/dist/product-base/extractIOSParams.d.ts +24 -0
  41. package/dist/product-base/index.d.ts +51 -0
  42. package/dist/product-base/periodLocalizationKeys.d.ts +44 -0
  43. package/dist/product-base/types.d.ts +155 -0
  44. package/dist/product-base/usePaywallLocalizationParams.d.ts +29 -0
  45. package/dist/store.d.ts +7 -1
  46. package/dist/styles.css +1 -1
  47. package/dist/types/PreviewConfig.d.ts +10 -16
  48. package/dist/utils/extractTextStyle/extractTextStyle.d.ts +2 -2
  49. package/dist/utils/extractTextStyle/extractTextStyleNative.d.ts +2 -2
  50. package/dist/utils/replaceLocalizationParams.d.ts +1 -1
  51. package/package.json +2 -2
  52. package/scripts/migrate-samples-to-current.ts +3 -3
  53. package/scripts/prebuild/utils/validateAllComponentsOrThrow.js +28 -12
  54. package/src/DeviceMockFrame.tsx +15 -10
  55. package/src/assets/meta.json +1 -1
  56. package/src/assets/samples/carousel-sample.json +6 -5
  57. package/src/assets/samples/getSamples.ts +16 -49
  58. package/src/assets/samples/paywall-1.json +64 -22
  59. package/src/assets/samples/paywall-2.json +0 -15
  60. package/src/assets/samples/paywall-app-delete-offer.json +0 -15
  61. package/src/assets/samples/paywall-app-open-offer.json +0 -15
  62. package/src/assets/samples/paywall-back-offer.json +0 -15
  63. package/src/assets/samples/paywall-notification-offer.json +0 -15
  64. package/src/assets/samples/simple-1.json +1 -16
  65. package/src/assets/samples/simple-2.json +0 -15
  66. package/src/assets/samples/unmigrated-builder-1.1.1.json +0 -3
  67. package/src/assets/samples/unmigrated-builder1.json +0 -3
  68. package/src/assets/samples/unvalidated-builder1.json +0 -3
  69. package/src/assets/samples/unvalidated-crash1.json +0 -3
  70. package/src/assets/samples/unvalidated-crashcomponent1.json +0 -3
  71. package/src/assets/samples/vpn-onboard-1.json +1 -34
  72. package/src/assets/samples/vpn-onboard-2.json +1 -34
  73. package/src/assets/samples/vpn-onboard-3.json +1 -42
  74. package/src/assets/samples/vpn-onboard-4.json +0 -73
  75. package/src/assets/samples/vpn-onboard-5.json +0 -73
  76. package/src/assets/samples/vpn-onboard-6.json +0 -73
  77. package/src/assets/samples/vpn-onboard-7.json +529 -0
  78. package/src/attribute-analyser/style/native/useExtractImageStyle.ts +1 -4
  79. package/src/attribute-analyser/style/native/useExtractTextStyle.ts +3 -12
  80. package/src/attribute-analyser/style/native/useExtractViewStyle.ts +1 -4
  81. package/src/attribute-analyser/style/web/useExtractImageStyle.ts +1 -4
  82. package/src/attribute-analyser/style/web/useExtractTextStyle.ts +3 -12
  83. package/src/attribute-analyser/style/web/useExtractViewStyle.ts +1 -4
  84. package/src/attributes-editor/useAttributesEditorModel.ts +5 -52
  85. package/src/build-components/BIcon/BIconProps.generated.ts +1 -2
  86. package/src/build-components/CarouselDots/CarouselDots.tsx +6 -13
  87. package/src/build-components/CountDown/CountDownProps.generated.ts +2 -1
  88. package/src/build-components/NavigationBarColor/NavigationBarColor.tsx +2 -2
  89. package/src/build-components/OnboardButton/OnboardButton.tsx +1 -2
  90. package/src/build-components/OnboardDot/OnboardDot.tsx +6 -18
  91. package/src/build-components/OnboardFooter/OnboardFooter.tsx +5 -3
  92. package/src/build-components/OnboardFooter/OnboardFooterProps.generated.ts +1 -2
  93. package/src/build-components/OnboardFooter/pattern.json +1 -1
  94. package/src/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.ts +1 -2
  95. package/src/build-components/OnboardTitle/OnboardTitleProps.generated.ts +1 -2
  96. package/src/build-components/PaywallCloseButton/PaywallCloseButtonProps.generated.ts +1 -2
  97. package/src/build-components/PaywallOptions/PaywallOptions.tsx +3 -3
  98. package/src/build-components/PaywallOptions/usePaywallOptionParamsFactory.ts +26 -13
  99. package/src/build-components/PaywallProvider/PaywallProvider.tsx +51 -12
  100. package/src/build-components/PriceTag/PriceTag.tsx +25 -0
  101. package/src/build-components/PriceTag/PriceTagProps.generated.ts +83 -0
  102. package/src/build-components/PriceTag/pattern.json +53 -0
  103. package/src/build-components/Pricing/Pricing.tsx +13 -0
  104. package/src/build-components/Pricing/PricingProps.generated.ts +76 -0
  105. package/src/build-components/Pricing/pattern.json +25 -0
  106. package/src/build-components/Promo/Promo.tsx +13 -0
  107. package/src/build-components/Promo/PromoProps.generated.ts +76 -0
  108. package/src/build-components/Promo/pattern.json +25 -0
  109. package/src/build-components/RadioButton/RadioButton.tsx +3 -5
  110. package/src/build-components/RenderNode.generated.tsx +15 -0
  111. package/src/build-components/StatusBarColor/StatusBarColor.tsx +2 -2
  112. package/src/build-components/Text/Text.tsx +12 -5
  113. package/src/build-components/Text/TextProps.generated.ts +1 -2
  114. package/src/build-components/Text/pattern.json +3 -2
  115. package/src/build-components/index.ts +15 -0
  116. package/src/build-components/patterns.generated.ts +1454 -181
  117. package/src/components/BottomBar.tsx +42 -39
  118. package/src/components/BuilderProvider.tsx +41 -14
  119. package/src/components/LocalizationParamsProvider.tsx +1 -1
  120. package/src/components/ParamsProvider.tsx +36 -11
  121. package/src/hooks/useLocalize.ts +7 -4
  122. package/src/hooks/useParams.ts +1 -1
  123. package/src/hooks/useSyncHtmlThemeClass.ts +2 -2
  124. package/src/index.ts +54 -8
  125. package/src/logger.ts +39 -0
  126. package/src/modals/InspectModal.tsx +331 -0
  127. package/src/modals/ProductPresetsModal.tsx +7 -14
  128. package/src/modals/index.ts +1 -1
  129. package/src/pages/DebugJsonPage.tsx +9 -22
  130. package/src/pages/ProjectDebug.tsx +1 -1
  131. package/src/pages/ProjectPage.tsx +29 -11
  132. package/src/pages/tabs/SideTool.tsx +28 -104
  133. package/src/paywall/hooks/useCalculateLocalizedPrice.ts +8 -3
  134. package/src/paywall/hooks/useDiscountRate.ts +11 -3
  135. package/src/paywall/types/paywall-types.ts +7 -38
  136. package/src/product-base/buildPaywallLocalizationParams.ts +100 -0
  137. package/src/product-base/calculations.ts +93 -0
  138. package/src/product-base/extractAndroidParams.ts +207 -0
  139. package/src/product-base/extractIOSParams.ts +199 -0
  140. package/src/product-base/index.ts +64 -0
  141. package/src/product-base/mockProducts.json +489 -0
  142. package/src/product-base/periodLocalizationKeys.ts +114 -0
  143. package/src/product-base/types.ts +183 -0
  144. package/src/product-base/usePaywallLocalizationParams.ts +61 -0
  145. package/src/store.ts +18 -1
  146. package/src/styles/index.scss +1 -0
  147. package/src/styles/modals/_inspect-modal.scss +155 -0
  148. package/src/types/PreviewConfig.ts +157 -16
  149. package/src/utils/extractTextStyle/extractTextStyle.ts +14 -6
  150. package/src/utils/extractTextStyle/extractTextStyleNative.ts +8 -6
  151. package/src/utils/logRenderStore.ts +6 -10
  152. package/src/utils/parseColor.ts +0 -1
  153. package/src/utils/replaceLocalizationParams.ts +8 -4
  154. package/dist/modals/ScreenColorsModal.d.ts +0 -8
  155. package/src/assets/products.json +0 -98
  156. package/src/modals/ScreenColorsModal.tsx +0 -121
@@ -14,6 +14,9 @@ import { useMockOSContext } from '../../mockOS/context/MockOSContextBase';
14
14
  import type { Product } from '../../paywall/types/paywall-types';
15
15
  import { useChangeDelayByPaywall } from '../../paywall/hooks/useChangeDelayByPaywall';
16
16
  import { useMockOSBackHandler } from '../../paywall/hooks/useMockOSBackHandler';
17
+ import { usePaywallLocalizationParams } from '../../product-base';
18
+ import { useRenderStore } from '../../store';
19
+ import { useLocalize } from '../../hooks/useLocalize';
17
20
 
18
21
  function PaywallProvider({ node }: PaywallProviderComponentProps) {
19
22
  useLogRender('PaywallProvider');
@@ -23,13 +26,20 @@ function PaywallProvider({ node }: PaywallProviderComponentProps) {
23
26
  const attributeName = node.sourceType ?? node.type ?? 'PaywallProvider';
24
27
  const attributeKey = node.key ?? generatedId;
25
28
 
26
- const { benefits, products, onPaywallSubscribe, previewMode, selectedKey } =
27
- useBuilderParams();
29
+ const {
30
+ mockBenefits,
31
+ mockProducts,
32
+ onPaywallSubscribe,
33
+ previewMode,
34
+ selectedKey,
35
+ } = useBuilderParams();
28
36
  const mockOS = useMockOSContext();
29
37
  const benefitLocalizationParams = useMemo(() => {
30
38
  const raw =
31
- benefits && typeof benefits === 'object' && !Array.isArray(benefits)
32
- ? (benefits as Record<string, unknown>)
39
+ mockBenefits &&
40
+ typeof mockBenefits === 'object' &&
41
+ !Array.isArray(mockBenefits)
42
+ ? (mockBenefits as Record<string, unknown>)
33
43
  : {};
34
44
 
35
45
  const entries = Object.entries(raw).filter(([k]) => k.trim().length > 0);
@@ -45,7 +55,7 @@ function PaywallProvider({ node }: PaywallProviderComponentProps) {
45
55
  params[`benefit${idx}`] = value;
46
56
  }
47
57
  return params;
48
- }, [benefits]);
58
+ }, [mockBenefits]);
49
59
 
50
60
  const baseStyle = useExtractViewStyle(node);
51
61
 
@@ -64,7 +74,7 @@ function PaywallProvider({ node }: PaywallProviderComponentProps) {
64
74
  useChangeDelayByPaywall(node, setIsBackAllowed);
65
75
  useMockOSBackHandler(isBackAllowed);
66
76
  useEffect(() => {
67
- const list = Array.isArray(products) ? products : [];
77
+ const list = Array.isArray(mockProducts) ? mockProducts : [];
68
78
  if (list.length === 0) {
69
79
  if (selectedProductId) setSelectedProductId('');
70
80
  return;
@@ -74,15 +84,38 @@ function PaywallProvider({ node }: PaywallProviderComponentProps) {
74
84
  if (!selectedProductId || !exists) {
75
85
  setSelectedProductId(list[0]?.productId ?? '');
76
86
  }
77
- }, [products, selectedProductId]);
87
+ }, [mockProducts, selectedProductId]);
78
88
 
79
89
  const selectedProduct = useMemo(() => {
80
- const list = Array.isArray(products) ? products : [];
90
+ const list = Array.isArray(mockProducts) ? mockProducts : [];
81
91
  return (
82
92
  list.find((p) => p?.productId === selectedProductId) ??
83
93
  (list.length > 0 ? list[0] : undefined)
84
94
  );
85
- }, [products, selectedProductId]);
95
+ }, [mockProducts, selectedProductId]);
96
+
97
+ const device = useRenderStore((s) => s.device);
98
+ const localize = useLocalize();
99
+ const platformForExtraction = (
100
+ device.platform === 'ios' ? 'ios' : 'android'
101
+ ) as 'ios' | 'android';
102
+ const detailedProductParams = usePaywallLocalizationParams(
103
+ selectedProduct,
104
+ selectedProductId,
105
+ {
106
+ platform: platformForExtraction,
107
+ localize,
108
+ },
109
+ );
110
+
111
+ console.log('[PaywallProvider] extraction debug', {
112
+ platform: platformForExtraction,
113
+ selectedProductId,
114
+ hasSubscriptionOffers: !!selectedProduct?.subscriptionOffers?.length,
115
+ subscriptionOffersCount: selectedProduct?.subscriptionOffers?.length ?? 0,
116
+ detailedProductParams,
117
+ selectedProduct,
118
+ });
86
119
 
87
120
  const handleClose = useCallback(() => {
88
121
  if (!isBackAllowed) {
@@ -154,7 +187,7 @@ function PaywallProvider({ node }: PaywallProviderComponentProps) {
154
187
 
155
188
  const paywallContextValue = useMemo(
156
189
  () => ({
157
- products: Array.isArray(products) ? products : [],
190
+ products: Array.isArray(mockProducts) ? mockProducts : [],
158
191
  setSelectedProductId,
159
192
  selectedProduct,
160
193
  onClose: handleClose,
@@ -163,7 +196,7 @@ function PaywallProvider({ node }: PaywallProviderComponentProps) {
163
196
  isBackAllowed,
164
197
  }),
165
198
  [
166
- products,
199
+ mockProducts,
167
200
  selectedProduct,
168
201
  handleClose,
169
202
  handleSubscribe,
@@ -179,7 +212,13 @@ function PaywallProvider({ node }: PaywallProviderComponentProps) {
179
212
  style={style}
180
213
  >
181
214
  <PaywallContext.Provider value={paywallContextValue}>
182
- <LocalizationParamsProvider params={benefitLocalizationParams}>
215
+ <LocalizationParamsProvider
216
+ params={{
217
+ ...benefitLocalizationParams,
218
+ ...detailedProductParams,
219
+ platform: platformForExtraction,
220
+ }}
221
+ >
183
222
  <RenderNode node={node.children as Node} />
184
223
  </LocalizationParamsProvider>
185
224
  </PaywallContext.Provider>
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ import type { PriceTagComponentProps } from './PriceTagProps.generated';
3
+ import Text from '../Text/Text';
4
+ import useNode from '../useNode';
5
+ import { useLogRender } from '../../utils/useLogRender';
6
+ import { useLocalizationParams } from '../../hooks/useLocalizationParams';
7
+
8
+ function PriceTag({ node }: PriceTagComponentProps) {
9
+ useLogRender('PriceTag');
10
+ node = useNode(node);
11
+
12
+ const params = useLocalizationParams();
13
+ const hasDiscount = !!params?.promoPrice;
14
+
15
+ const hideIfItsNotDiscount =
16
+ (node.attributes as Record<string, unknown>)?.hideIfItsNotDiscount ?? false;
17
+
18
+ if (hideIfItsNotDiscount && !hasDiscount) {
19
+ return null;
20
+ }
21
+
22
+ return <Text node={node} />;
23
+ }
24
+
25
+ export default React.memo(PriceTag);
@@ -0,0 +1,83 @@
1
+ /* AUTO-GENERATED FILE - DO NOT EDIT */
2
+
3
+ import type { NodeData } from '../../types/Node';
4
+
5
+ export type FlexDirectionOptionType = 'row' | 'column';
6
+ export type FlexWrapOptionType = 'nowrap' | 'wrap' | 'wrap-reverse';
7
+ export type AlignItemsOptionType =
8
+ | 'flex-start'
9
+ | 'center'
10
+ | 'flex-end'
11
+ | 'stretch'
12
+ | 'baseline';
13
+ export type JustifyContentOptionType =
14
+ | 'flex-start'
15
+ | 'center'
16
+ | 'flex-end'
17
+ | 'space-between'
18
+ | 'space-around'
19
+ | 'space-evenly';
20
+ export type PositionOptionType = 'relative' | 'absolute';
21
+ export type TextDecorationLineOptionType =
22
+ | 'none'
23
+ | 'underline'
24
+ | 'line-through';
25
+
26
+ export interface PriceTagStyleGenerated {
27
+ color?: string;
28
+ fontSize?: string;
29
+ fontFamily?: string;
30
+ fontWeight?: string;
31
+ flexDirection?: FlexDirectionOptionType;
32
+ flexWrap?: FlexWrapOptionType;
33
+ alignItems?: AlignItemsOptionType;
34
+ justifyContent?: JustifyContentOptionType;
35
+ gap?: string;
36
+ padding?: string;
37
+ paddingHorizontal?: string;
38
+ paddingVertical?: string;
39
+ paddingTop?: string;
40
+ paddingBottom?: string;
41
+ paddingLeft?: string;
42
+ paddingRight?: string;
43
+ margin?: string;
44
+ marginHorizontal?: string;
45
+ marginVertical?: string;
46
+ marginTop?: string;
47
+ marginBottom?: string;
48
+ marginLeft?: string;
49
+ marginRight?: string;
50
+ backgroundColor?: string;
51
+ borderRadius?: string;
52
+ width?: string;
53
+ minWidth?: string;
54
+ maxWidth?: string;
55
+ height?: string;
56
+ minHeight?: string;
57
+ maxHeight?: string;
58
+ flex?: number;
59
+ position?: PositionOptionType;
60
+ top?: string;
61
+ bottom?: string;
62
+ left?: string;
63
+ right?: string;
64
+ zIndex?: number;
65
+ textDecorationLine?: TextDecorationLineOptionType;
66
+ }
67
+
68
+ export interface PriceTagPropsGenerated {
69
+ child: string;
70
+ attributes: {
71
+ style?: PriceTagStyleGenerated;
72
+ adjustsFontSizeToFit?: boolean;
73
+ showEllipsis?: boolean;
74
+ translateCounter?: number;
75
+ scrollable?: boolean;
76
+ showOriginalPricePossible?: boolean;
77
+ hideIfItsNotDiscount?: boolean;
78
+ };
79
+ }
80
+
81
+ export interface PriceTagComponentProps {
82
+ node: NodeData<PriceTagPropsGenerated['attributes']>;
83
+ }
@@ -0,0 +1,53 @@
1
+ {
2
+ "schemaVersion": 2,
3
+ "pattern": {
4
+ "type": "PriceTag",
5
+ "title": "title",
6
+ "description": "description",
7
+ "children": "string",
8
+ "extends": "Text",
9
+ "attributes": {
10
+ "showOriginalPricePossible": "boolean",
11
+ "hideIfItsNotDiscount": "boolean",
12
+ "style": {
13
+ "textDecorationLine": ["none", "underline", "line-through"]
14
+ }
15
+ }
16
+ },
17
+ "defaults": {
18
+ "style": {
19
+ "fontSize": "16@fs",
20
+ "fontWeight": "700"
21
+ }
22
+ },
23
+ "meta": {
24
+ "desiredParent": [">PaywallProvider"],
25
+ "label": "Price Tag",
26
+ "description": "Displays a price tag text. Extends Text.",
27
+ "styles": {
28
+ "textDecorationLine": {
29
+ "label": "Text Decoration",
30
+ "description": "Text decoration line style (e.g. line-through for strikethrough).",
31
+ "category": "style",
32
+ "specialCategory": null,
33
+ "sort": 6
34
+ }
35
+ },
36
+ "attributes": {
37
+ "showOriginalPricePossible": {
38
+ "label": "Show Original Price Possible",
39
+ "description": "When enabled, shows the original price if available.",
40
+ "category": "other",
41
+ "specialCategory": null,
42
+ "sort": 1
43
+ },
44
+ "hideIfItsNotDiscount": {
45
+ "label": "Hide If No Discount",
46
+ "description": "Hides this element when there is no active discount/promo.",
47
+ "category": "other",
48
+ "specialCategory": null,
49
+ "sort": 2
50
+ }
51
+ }
52
+ }
53
+ }
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import type { PricingComponentProps } from './PricingProps.generated';
3
+ import Text from '../Text/Text';
4
+ import useNode from '../useNode';
5
+ import { useLogRender } from '../../utils/useLogRender';
6
+
7
+ function Pricing({ node }: PricingComponentProps) {
8
+ useLogRender('Pricing');
9
+ node = useNode(node);
10
+ return <Text node={node} />;
11
+ }
12
+
13
+ export default React.memo(Pricing);
@@ -0,0 +1,76 @@
1
+ /* AUTO-GENERATED FILE - DO NOT EDIT */
2
+
3
+ import type { NodeData } from '../../types/Node';
4
+
5
+ export type FlexDirectionOptionType = 'row' | 'column';
6
+ export type FlexWrapOptionType = 'nowrap' | 'wrap' | 'wrap-reverse';
7
+ export type AlignItemsOptionType =
8
+ | 'flex-start'
9
+ | 'center'
10
+ | 'flex-end'
11
+ | 'stretch'
12
+ | 'baseline';
13
+ export type JustifyContentOptionType =
14
+ | 'flex-start'
15
+ | 'center'
16
+ | 'flex-end'
17
+ | 'space-between'
18
+ | 'space-around'
19
+ | 'space-evenly';
20
+ export type PositionOptionType = 'relative' | 'absolute';
21
+
22
+ export interface PricingStyleGenerated {
23
+ color?: string;
24
+ fontSize?: string;
25
+ fontFamily?: string;
26
+ fontWeight?: string;
27
+ flexDirection?: FlexDirectionOptionType;
28
+ flexWrap?: FlexWrapOptionType;
29
+ alignItems?: AlignItemsOptionType;
30
+ justifyContent?: JustifyContentOptionType;
31
+ gap?: string;
32
+ padding?: string;
33
+ paddingHorizontal?: string;
34
+ paddingVertical?: string;
35
+ paddingTop?: string;
36
+ paddingBottom?: string;
37
+ paddingLeft?: string;
38
+ paddingRight?: string;
39
+ margin?: string;
40
+ marginHorizontal?: string;
41
+ marginVertical?: string;
42
+ marginTop?: string;
43
+ marginBottom?: string;
44
+ marginLeft?: string;
45
+ marginRight?: string;
46
+ backgroundColor?: string;
47
+ borderRadius?: string;
48
+ width?: string;
49
+ minWidth?: string;
50
+ maxWidth?: string;
51
+ height?: string;
52
+ minHeight?: string;
53
+ maxHeight?: string;
54
+ flex?: number;
55
+ position?: PositionOptionType;
56
+ top?: string;
57
+ bottom?: string;
58
+ left?: string;
59
+ right?: string;
60
+ zIndex?: number;
61
+ }
62
+
63
+ export interface PricingPropsGenerated {
64
+ child: string;
65
+ attributes: {
66
+ style?: PricingStyleGenerated;
67
+ adjustsFontSizeToFit?: boolean;
68
+ showEllipsis?: boolean;
69
+ translateCounter?: number;
70
+ scrollable?: boolean;
71
+ };
72
+ }
73
+
74
+ export interface PricingComponentProps {
75
+ node: NodeData<PricingPropsGenerated['attributes']>;
76
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "schemaVersion": 2,
3
+ "pattern": {
4
+ "type": "Pricing",
5
+ "title": "title",
6
+ "description": "base.builder.paywall.pricing.default.text",
7
+ "children": "string",
8
+ "extends": "Text"
9
+ },
10
+ "defaults": {
11
+ "translateCounter": 2,
12
+ "style": {
13
+ "textAlign": "center",
14
+ "fontSize": "12@fs",
15
+ "fontWeight": "400",
16
+ "color": "rgba(255,255,255,0.6)"
17
+ }
18
+ },
19
+ "meta": {
20
+ "desiredParent": [">PaywallProvider"],
21
+ "label": "Pricing",
22
+ "description": "Displays pricing details (e.g. promo/trial breakdown). Extends Text.",
23
+ "styles": {}
24
+ }
25
+ }
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import type { PromoComponentProps } from './PromoProps.generated';
3
+ import Text from '../Text/Text';
4
+ import useNode from '../useNode';
5
+ import { useLogRender } from '../../utils/useLogRender';
6
+
7
+ function Promo({ node }: PromoComponentProps) {
8
+ useLogRender('Promo');
9
+ node = useNode(node);
10
+ return <Text node={node} />;
11
+ }
12
+
13
+ export default React.memo(Promo);
@@ -0,0 +1,76 @@
1
+ /* AUTO-GENERATED FILE - DO NOT EDIT */
2
+
3
+ import type { NodeData } from '../../types/Node';
4
+
5
+ export type FlexDirectionOptionType = 'row' | 'column';
6
+ export type FlexWrapOptionType = 'nowrap' | 'wrap' | 'wrap-reverse';
7
+ export type AlignItemsOptionType =
8
+ | 'flex-start'
9
+ | 'center'
10
+ | 'flex-end'
11
+ | 'stretch'
12
+ | 'baseline';
13
+ export type JustifyContentOptionType =
14
+ | 'flex-start'
15
+ | 'center'
16
+ | 'flex-end'
17
+ | 'space-between'
18
+ | 'space-around'
19
+ | 'space-evenly';
20
+ export type PositionOptionType = 'relative' | 'absolute';
21
+
22
+ export interface PromoStyleGenerated {
23
+ color?: string;
24
+ fontSize?: string;
25
+ fontFamily?: string;
26
+ fontWeight?: string;
27
+ flexDirection?: FlexDirectionOptionType;
28
+ flexWrap?: FlexWrapOptionType;
29
+ alignItems?: AlignItemsOptionType;
30
+ justifyContent?: JustifyContentOptionType;
31
+ gap?: string;
32
+ padding?: string;
33
+ paddingHorizontal?: string;
34
+ paddingVertical?: string;
35
+ paddingTop?: string;
36
+ paddingBottom?: string;
37
+ paddingLeft?: string;
38
+ paddingRight?: string;
39
+ margin?: string;
40
+ marginHorizontal?: string;
41
+ marginVertical?: string;
42
+ marginTop?: string;
43
+ marginBottom?: string;
44
+ marginLeft?: string;
45
+ marginRight?: string;
46
+ backgroundColor?: string;
47
+ borderRadius?: string;
48
+ width?: string;
49
+ minWidth?: string;
50
+ maxWidth?: string;
51
+ height?: string;
52
+ minHeight?: string;
53
+ maxHeight?: string;
54
+ flex?: number;
55
+ position?: PositionOptionType;
56
+ top?: string;
57
+ bottom?: string;
58
+ left?: string;
59
+ right?: string;
60
+ zIndex?: number;
61
+ }
62
+
63
+ export interface PromoPropsGenerated {
64
+ child: string;
65
+ attributes: {
66
+ style?: PromoStyleGenerated;
67
+ adjustsFontSizeToFit?: boolean;
68
+ showEllipsis?: boolean;
69
+ translateCounter?: number;
70
+ scrollable?: boolean;
71
+ };
72
+ }
73
+
74
+ export interface PromoComponentProps {
75
+ node: NodeData<PromoPropsGenerated['attributes']>;
76
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "schemaVersion": 2,
3
+ "pattern": {
4
+ "type": "Promo",
5
+ "title": "title",
6
+ "description": "base.builder.paywall.promo.default.text",
7
+ "children": "string",
8
+ "extends": "Text"
9
+ },
10
+ "defaults": {
11
+ "translateCounter": 2,
12
+ "style": {
13
+ "textAlign": "center",
14
+ "fontSize": "12@fs",
15
+ "fontWeight": "600",
16
+ "color": "#34D399"
17
+ }
18
+ },
19
+ "meta": {
20
+ "desiredParent": [">PaywallProvider"],
21
+ "label": "Promo",
22
+ "description": "Displays promotional badge/text (e.g. discount percentage). Extends Text.",
23
+ "styles": {}
24
+ }
25
+ }
@@ -35,11 +35,9 @@ export function RadioButtonBase({
35
35
  const sizeHalf = Math.round(size * 0.5);
36
36
 
37
37
  const paramsContext = useContext(ParamsContext);
38
- const otherParams = paramsContext?.otherParams ?? {};
39
- const newSelected =
40
- otherParams.isSelected !== undefined
41
- ? String(otherParams.isSelected).toLowerCase() === 'true'
42
- : selected;
38
+ const { singleProductIsSelected: contextIsSelected } =
39
+ paramsContext?.otherParams ?? {};
40
+ const newSelected = contextIsSelected ?? selected;
43
41
  return (
44
42
  <div style={{ marginLeft: 8, marginRight: 16 }}>
45
43
  <div
@@ -40,6 +40,9 @@ import type { PaywallCloseButtonComponentProps } from './PaywallCloseButton/Payw
40
40
  import type { PaywallOptionsComponentProps } from './PaywallOptions/PaywallOptionsProps.generated';
41
41
  import type { PaywallProviderComponentProps } from './PaywallProvider/PaywallProviderProps.generated';
42
42
  import type { PaywallSubscribeButtonComponentProps } from './PaywallSubscribeButton/PaywallSubscribeButtonProps.generated';
43
+ import type { PriceTagComponentProps } from './PriceTag/PriceTagProps.generated';
44
+ import type { PricingComponentProps } from './Pricing/PricingProps.generated';
45
+ import type { PromoComponentProps } from './Promo/PromoProps.generated';
43
46
  import type { RadioButtonComponentProps } from './RadioButton/RadioButtonProps.generated';
44
47
  import type { SeparatorComponentProps } from './Separator/SeparatorProps.generated';
45
48
  import type { StatusBarColorComponentProps } from './StatusBarColor/StatusBarColorProps.generated';
@@ -72,6 +75,9 @@ import PaywallCloseButton from './PaywallCloseButton/PaywallCloseButton';
72
75
  import PaywallOptions from './PaywallOptions/PaywallOptions';
73
76
  import PaywallProvider from './PaywallProvider/PaywallProvider';
74
77
  import PaywallSubscribeButton from './PaywallSubscribeButton/PaywallSubscribeButton';
78
+ import PriceTag from './PriceTag/PriceTag';
79
+ import Pricing from './Pricing/Pricing';
80
+ import Promo from './Promo/Promo';
75
81
  import RadioButton from './RadioButton/RadioButton';
76
82
  import Separator from './Separator/Separator';
77
83
  import StatusBarColor from './StatusBarColor/StatusBarColor';
@@ -108,6 +114,9 @@ type BuilderNode =
108
114
  | (PaywallSubscribeButtonComponentProps['node'] & {
109
115
  type: 'PaywallSubscribeButton';
110
116
  })
117
+ | (PriceTagComponentProps['node'] & { type: 'PriceTag' })
118
+ | (PricingComponentProps['node'] & { type: 'Pricing' })
119
+ | (PromoComponentProps['node'] & { type: 'Promo' })
111
120
  | (RadioButtonComponentProps['node'] & { type: 'RadioButton' })
112
121
  | (SeparatorComponentProps['node'] & { type: 'Separator' })
113
122
  | (StatusBarColorComponentProps['node'] & { type: 'StatusBarColor' })
@@ -198,6 +207,12 @@ function RenderNode({ node }: { node: Node }) {
198
207
  return <PaywallProvider node={normalizedNode} />;
199
208
  case 'PaywallSubscribeButton':
200
209
  return <PaywallSubscribeButton node={normalizedNode} />;
210
+ case 'PriceTag':
211
+ return <PriceTag node={normalizedNode} />;
212
+ case 'Pricing':
213
+ return <Pricing node={normalizedNode} />;
214
+ case 'Promo':
215
+ return <Promo node={normalizedNode} />;
201
216
  case 'RadioButton':
202
217
  return <RadioButton node={normalizedNode} />;
203
218
  case 'Separator':
@@ -11,7 +11,7 @@ function StatusBarColor({ node }: StatusBarColorComponentProps) {
11
11
  useLogRender('StatusBarColor');
12
12
  node = useNode(node);
13
13
 
14
- const { appConfig, projectColors } = useBuilderParams();
14
+ const { theme, projectColors } = useBuilderParams();
15
15
  const setStatusBarOverrideColor = useRenderStore(
16
16
  (s) => s.setStatusBarOverrideColor,
17
17
  );
@@ -21,7 +21,7 @@ function StatusBarColor({ node }: StatusBarColorComponentProps) {
21
21
  | undefined;
22
22
  const resolvedColor = parseColor(rawBg, {
23
23
  projectColors,
24
- theme: appConfig?.theme,
24
+ theme,
25
25
  });
26
26
 
27
27
  useEffect(() => {
@@ -26,11 +26,18 @@ function Text({ node }: TextComponentProps) {
26
26
  node,
27
27
  });
28
28
  const localize = useLocalize({ appConfig });
29
-
30
- const localizedText = useMemo(
31
- () => localize(keyOrText),
32
- [localize, keyOrText],
33
- );
29
+ const translateCounter = (node.attributes as Record<string, unknown>)
30
+ ?.translateCounter as number | undefined;
31
+
32
+ const localizedText = useMemo(() => {
33
+ let text = localize(keyOrText);
34
+ const passes = translateCounter ?? 1;
35
+ for (let i = 1; i < passes; i++) {
36
+ text = localize(text);
37
+ }
38
+ return text;
39
+ //Optimzation trade off by readability: could avoid dict lookup on subsequent passes
40
+ }, [localize, keyOrText, translateCounter]);
34
41
 
35
42
  const styleBag = node.attributes?.style as unknown as
36
43
  | { adjustsFontSizeToFit?: boolean; showEllipsis?: boolean }
@@ -18,7 +18,6 @@ export type JustifyContentOptionType =
18
18
  | 'space-around'
19
19
  | 'space-evenly';
20
20
  export type PositionOptionType = 'relative' | 'absolute';
21
- export type TextAlignOptionType = 'left' | 'center' | 'right' | 'justify';
22
21
 
23
22
  export interface TextStyleGenerated {
24
23
  flexDirection?: FlexDirectionOptionType;
@@ -59,7 +58,6 @@ export interface TextStyleGenerated {
59
58
  fontSize?: string;
60
59
  fontFamily?: string;
61
60
  fontWeight?: string;
62
- textAlign?: TextAlignOptionType;
63
61
  }
64
62
 
65
63
  export interface TextPropsGenerated {
@@ -69,6 +67,7 @@ export interface TextPropsGenerated {
69
67
  scrollable?: boolean;
70
68
  adjustsFontSizeToFit?: boolean;
71
69
  showEllipsis?: boolean;
70
+ translateCounter?: number;
72
71
  };
73
72
  }
74
73
 
@@ -9,15 +9,16 @@
9
9
  "attributes": {
10
10
  "adjustsFontSizeToFit": "boolean",
11
11
  "showEllipsis": "boolean",
12
+ "translateCounter": "number",
12
13
  "style": {
13
14
  "color": "color",
14
15
  "fontSize": "size",
15
16
  "fontFamily": "fontFamily",
16
- "fontWeight": "fontWeight",
17
- "textAlign": ["left", "center", "right", "justify"]
17
+ "fontWeight": "fontWeight"
18
18
  }
19
19
  },
20
20
  "defaults": {
21
+ "translateCounter": 1,
21
22
  "style": {
22
23
  "color": "THEME_COLORS.TEXT",
23
24
  "fontSize": "16@fs",