@developer_tribe/react-builder 1.2.26 → 1.2.28

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 +15 -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 +27 -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 +56 -8
  125. package/src/logger.ts +39 -0
  126. package/src/modals/InspectModal.tsx +331 -0
  127. package/src/modals/ProductPresetsModal.tsx +6 -13
  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 +28 -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
@@ -3,7 +3,7 @@ import { Icon } from './Icon.generated';
3
3
  import type { IconsType } from '../types/Icons';
4
4
  import { useRenderStore } from '../store';
5
5
  import type { Localication } from '../types/PreviewConfig';
6
- import { LocalicationModal, Modal, ScreenColorsModal } from '../modals';
6
+ import { InspectModal, LocalicationModal, Modal } from '../modals';
7
7
  import type { Node } from '../types/Node';
8
8
  import type { Project } from '../types/Project';
9
9
  import { DebugJsonPage } from '../pages/DebugJsonPage';
@@ -28,29 +28,45 @@ export function BottomBar({
28
28
  const magicCursorIcon: IconsType = 'magicpen';
29
29
  const debugIcon: IconsType = 'speedometer-03';
30
30
  const localizationIcon: IconsType = 'globe-01';
31
- const colorIcon: IconsType = 'colors';
32
-
33
- const { appConfig, setAppConfig, previewMode, setPreviewMode } =
34
- useRenderStore((s) => ({
35
- appConfig: s.appConfig,
36
- setAppConfig: s.setAppConfig,
37
- previewMode: s.previewMode,
38
- setPreviewMode: s.setPreviewMode,
39
- }));
31
+ const inspectIcon: IconsType = 'info-circle';
32
+
33
+ const {
34
+ appConfig,
35
+ setAppConfig,
36
+ theme,
37
+ setTheme,
38
+ defaultLanguage,
39
+ setDefaultLanguage,
40
+ previewMode,
41
+ setPreviewMode,
42
+ isRtl,
43
+ setIsRtl,
44
+ } = useRenderStore((s) => ({
45
+ appConfig: s.appConfig,
46
+ setAppConfig: s.setAppConfig,
47
+ theme: s.theme,
48
+ setTheme: s.setTheme,
49
+ defaultLanguage: s.defaultLanguage,
50
+ setDefaultLanguage: s.setDefaultLanguage,
51
+ previewMode: s.previewMode,
52
+ setPreviewMode: s.setPreviewMode,
53
+ isRtl: s.isRtl,
54
+ setIsRtl: s.setIsRtl,
55
+ }));
40
56
 
41
57
  const [isDebugOpen, setIsDebugOpen] = useState(false);
42
58
  const [isLocalizationOpen, setIsLocalizationOpen] = useState(false);
43
- const [isColorsOpen, setIsColorsOpen] = useState(false);
59
+ const [isInspectOpen, setIsInspectOpen] = useState(false);
44
60
 
45
61
  const languages = useMemo(() => ['en', 'tr', 'ar'], []);
46
- const activeLanguage = appConfig.defaultLanguage ?? 'en';
62
+ const activeLanguage = defaultLanguage;
47
63
 
48
64
  const handleLocalicationChange = (next: Localication) => {
49
65
  setAppConfig({ ...appConfig, localication: next });
50
66
  };
51
67
 
52
- const themeIsActive = appConfig.theme === 'dark';
53
- const rtlIsActive = appConfig.isRtl ?? false;
68
+ const themeIsActive = theme === 'dark';
69
+ const rtlIsActive = isRtl;
54
70
  const previewIsActive = previewMode;
55
71
  const themeIcon: IconsType = themeIsActive ? 'moon-bold' : 'sun';
56
72
 
@@ -62,12 +78,7 @@ export function BottomBar({
62
78
  className={`rb-bottom-bar__button${themeIsActive ? ' is-active' : ''}`}
63
79
  aria-label="Theme"
64
80
  aria-pressed={themeIsActive}
65
- onClick={() =>
66
- setAppConfig({
67
- ...appConfig,
68
- theme: appConfig.theme === 'dark' ? 'light' : 'dark',
69
- })
70
- }
81
+ onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
71
82
  >
72
83
  <Icon iconType={themeIcon} size={20} color="currentColor" alt="" />
73
84
  </button>
@@ -79,9 +90,7 @@ export function BottomBar({
79
90
  }`}
80
91
  aria-label="RTL"
81
92
  aria-pressed={rtlIsActive}
82
- onClick={() =>
83
- setAppConfig({ ...appConfig, isRtl: !(appConfig.isRtl ?? false) })
84
- }
93
+ onClick={() => setIsRtl(!isRtl)}
85
94
  >
86
95
  <Icon iconType={rtlIcon} size={18} color="currentColor" alt="" />
87
96
  <span className="rb-bottom-bar__rtl-text">RTL</span>
@@ -133,12 +142,12 @@ export function BottomBar({
133
142
 
134
143
  <button
135
144
  type="button"
136
- className={`rb-bottom-bar__button${isColorsOpen ? ' is-active' : ''}`}
137
- aria-label="Color"
138
- aria-pressed={isColorsOpen}
139
- onClick={() => setIsColorsOpen(true)}
145
+ className={`rb-bottom-bar__button${isInspectOpen ? ' is-active' : ''}`}
146
+ aria-label="Inspect"
147
+ aria-pressed={isInspectOpen}
148
+ onClick={() => setIsInspectOpen(true)}
140
149
  >
141
- <Icon iconType={colorIcon} size={20} color="currentColor" alt="" />
150
+ <Icon iconType={inspectIcon} size={20} color="currentColor" alt="" />
142
151
  </button>
143
152
 
144
153
  <div className="rb-bottom-bar__spacer" />
@@ -151,9 +160,7 @@ export function BottomBar({
151
160
  className={`rb-bottom-bar__lang${
152
161
  activeLanguage === language ? ' is-active' : ''
153
162
  }`}
154
- onClick={() =>
155
- setAppConfig({ ...appConfig, defaultLanguage: language })
156
- }
163
+ onClick={() => setDefaultLanguage(language)}
157
164
  >
158
165
  {language}
159
166
  </button>
@@ -169,14 +176,6 @@ export function BottomBar({
169
176
  />
170
177
  )}
171
178
 
172
- {isColorsOpen && (
173
- <ScreenColorsModal
174
- appConfig={appConfig}
175
- onChange={setAppConfig}
176
- onClose={() => setIsColorsOpen(false)}
177
- />
178
- )}
179
-
180
179
  {isDebugOpen && (
181
180
  <Modal
182
181
  onClose={() => setIsDebugOpen(false)}
@@ -198,6 +197,10 @@ export function BottomBar({
198
197
  />
199
198
  </Modal>
200
199
  )}
200
+
201
+ {isInspectOpen && (
202
+ <InspectModal onClose={() => setIsInspectOpen(false)} />
203
+ )}
201
204
  </>
202
205
  );
203
206
  }
@@ -1,7 +1,13 @@
1
1
  import React, { createContext, useContext, useMemo } from 'react';
2
2
  import type { Product } from '../paywall/types/paywall-types';
3
3
  import type { PaywallBenefits } from '../paywall/types/benefits';
4
- import type { AppConfig } from '../types/PreviewConfig';
4
+ import {
5
+ type AppConfig,
6
+ type Theme,
7
+ defaultLocalization,
8
+ defaultTheme,
9
+ mergeLocalization,
10
+ } from '../types/PreviewConfig';
5
11
  import type { Fonts } from '../types/Fonts';
6
12
  import type { ProjectColors } from '../types/Project';
7
13
  import { defaultProjectColors, mergeProjectColors } from '../utils';
@@ -9,13 +15,12 @@ import { defaultProjectColors, mergeProjectColors } from '../utils';
9
15
  // NOTE: We keep this context intentionally tiny.
10
16
  // IMPORTANT: This provider may be mounted once but consumed by multiple `build-components`
11
17
  // on the same screen. Keep the value minimal + stable to avoid unnecessary rerenders.
12
- // In React Native, `products` should be sourced from an IAP wrapper (e.g. `react-native-iap`)
13
- // and passed in via `params` from the host app.
18
+ // In React Native, pass real IAP products here; in the web builder they come from mock presets.
14
19
  export type Products = Product;
15
20
 
16
21
  export type BuilderProviderParams = {
17
- products: Products[];
18
- benefits: PaywallBenefits;
22
+ mockProducts: Products[];
23
+ mockBenefits: PaywallBenefits;
19
24
  /**
20
25
  * Render platform for style extraction + meta filtering.
21
26
  * - 'web' (default): returns CSS-friendly styles for DOM rendering.
@@ -28,6 +33,8 @@ export type BuilderProviderParams = {
28
33
  * These are intentionally passed down via BuilderProvider so `build-components`
29
34
  * never need to touch `useRenderStore`.
30
35
  */
36
+ theme?: Theme;
37
+ defaultLanguage?: string;
31
38
  appConfig?: AppConfig;
32
39
  projectColors?: ProjectColors;
33
40
  fonts?: Fonts;
@@ -51,18 +58,34 @@ const builderContext = createContext<BuilderProviderParams | undefined>(
51
58
  export function BuilderProvider({ params, children }: BuilderProviderProps) {
52
59
  const value = useMemo<BuilderProviderParams>(
53
60
  () => ({
54
- products: Array.isArray(params?.products) ? params.products : [],
55
- benefits:
56
- params?.benefits && typeof params.benefits === 'object'
57
- ? (params.benefits as PaywallBenefits)
61
+ mockProducts: Array.isArray(params?.mockProducts)
62
+ ? params.mockProducts
63
+ : [],
64
+ mockBenefits:
65
+ params?.mockBenefits && typeof params.mockBenefits === 'object'
66
+ ? (params.mockBenefits as PaywallBenefits)
58
67
  : {},
59
68
  onPaywallSubscribe:
60
69
  typeof params?.onPaywallSubscribe === 'function'
61
70
  ? params.onPaywallSubscribe
62
71
  : undefined,
72
+ theme:
73
+ params?.theme === 'light' || params?.theme === 'dark'
74
+ ? params.theme
75
+ : defaultTheme,
76
+ defaultLanguage:
77
+ typeof params?.defaultLanguage === 'string'
78
+ ? params.defaultLanguage
79
+ : 'en',
63
80
  appConfig:
64
81
  params?.appConfig && typeof params.appConfig === 'object'
65
- ? (params.appConfig as AppConfig)
82
+ ? {
83
+ ...(params.appConfig as AppConfig),
84
+ localication: mergeLocalization(
85
+ defaultLocalization,
86
+ (params.appConfig as AppConfig).localication ?? {},
87
+ ),
88
+ }
66
89
  : undefined,
67
90
  projectColors:
68
91
  params?.projectColors && typeof params.projectColors === 'object'
@@ -78,10 +101,12 @@ export function BuilderProvider({ params, children }: BuilderProviderProps) {
78
101
  : undefined,
79
102
  }),
80
103
  [
81
- params?.benefits,
82
- params?.products,
104
+ params?.mockBenefits,
105
+ params?.mockProducts,
83
106
  params?.platform,
84
107
  params?.onPaywallSubscribe,
108
+ params?.theme,
109
+ params?.defaultLanguage,
85
110
  params?.appConfig,
86
111
  params?.projectColors,
87
112
  params?.fonts,
@@ -99,9 +124,11 @@ export function BuilderProvider({ params, children }: BuilderProviderProps) {
99
124
  export function useBuilderParams(): Readonly<BuilderProviderParams> {
100
125
  return (
101
126
  useContext(builderContext) ?? {
102
- products: [],
103
- benefits: {},
127
+ mockProducts: [],
128
+ mockBenefits: {},
104
129
  platform: 'web',
130
+ theme: defaultTheme,
131
+ defaultLanguage: 'en',
105
132
  projectColors: defaultProjectColors,
106
133
  }
107
134
  );
@@ -15,7 +15,7 @@ export function LocalizationParamsProvider({
15
15
  children,
16
16
  }: LocalizationParamsProviderProps) {
17
17
  return (
18
- <ParamsProvider localizationParams={params} otherParams={{}}>
18
+ <ParamsProvider localizationParams={params} nestedLocalizationParams={{}}>
19
19
  {children}
20
20
  </ParamsProvider>
21
21
  );
@@ -1,44 +1,69 @@
1
- import React, { createContext, useMemo } from 'react';
1
+ import React, { createContext, useEffect, useMemo } from 'react';
2
+ import type { ProductParams, SingleProductParams } from '../product-base/types';
2
3
 
3
- export type LocalizationParams = Record<string, string>;
4
- export type OtherParams = Record<string, string | boolean | number>;
4
+ /** Provider-level params not tied to a single product. */
5
+ export type ContextLocalizationParams = {
6
+ platform?: string;
7
+ [key: `benefit${number}`]: string | undefined;
8
+ };
9
+
10
+ export type LocalizationParams = Partial<ProductParams> &
11
+ ContextLocalizationParams;
12
+ export type NestedLocalizationParams = Partial<SingleProductParams>;
13
+
14
+ export type OtherParams = {
15
+ singleProductIsSelected?: boolean;
16
+ };
5
17
 
6
18
  export type ParamsContextValue = {
7
19
  localizationParams: LocalizationParams;
20
+ nestedLocalizationParams: NestedLocalizationParams;
8
21
  otherParams: OtherParams;
9
- /**
10
- * `true` when the value comes from an actual `<ParamsProvider />` in the tree.
11
- * Used to detect nesting vs the default context value.
12
- */
13
- isProvided: boolean;
14
22
  };
15
23
 
16
24
  export type ParamsProviderProps = {
17
25
  localizationParams?: LocalizationParams;
26
+ nestedLocalizationParams?: NestedLocalizationParams;
18
27
  otherParams?: OtherParams;
19
28
  children: React.ReactNode;
20
29
  };
21
30
 
22
31
  export const ParamsContext = createContext<ParamsContextValue>({
23
32
  localizationParams: {},
33
+ nestedLocalizationParams: {},
24
34
  otherParams: {},
25
- isProvided: false,
26
35
  });
27
36
 
37
+ let _lastParamsSnapshot: ParamsContextValue = {
38
+ localizationParams: {},
39
+ nestedLocalizationParams: {},
40
+ otherParams: {},
41
+ };
42
+
43
+ /** Read-only snapshot of the most recent ParamsProvider value (for debug UIs rendered outside the context tree). */
44
+ export function getLastParamsSnapshot(): Readonly<ParamsContextValue> {
45
+ return _lastParamsSnapshot;
46
+ }
47
+
28
48
  export function ParamsProvider({
29
49
  localizationParams,
50
+ nestedLocalizationParams,
30
51
  otherParams,
31
52
  children,
32
53
  }: ParamsProviderProps) {
33
54
  const value = useMemo<ParamsContextValue>(
34
55
  () => ({
35
56
  localizationParams: localizationParams ?? {},
57
+ nestedLocalizationParams: nestedLocalizationParams ?? {},
36
58
  otherParams: otherParams ?? {},
37
- isProvided: true,
38
59
  }),
39
- [localizationParams, otherParams],
60
+ [localizationParams, nestedLocalizationParams, otherParams],
40
61
  );
41
62
 
63
+ useEffect(() => {
64
+ _lastParamsSnapshot = value;
65
+ }, [value]);
66
+
42
67
  return (
43
68
  <ParamsContext.Provider value={value}>{children}</ParamsContext.Provider>
44
69
  );
@@ -8,15 +8,18 @@ import { replaceLocalizationParams } from '../utils/replaceLocalizationParams';
8
8
  export type LocalizeFn = (keyOrText: string) => string;
9
9
 
10
10
  export function useLocalize(options?: { appConfig?: AppConfig }): LocalizeFn {
11
- const { appConfig: builderAppConfig } = useBuilderParams();
11
+ const {
12
+ appConfig: builderAppConfig,
13
+ defaultLanguage: builderDefaultLanguage,
14
+ } = useBuilderParams();
12
15
  const appConfig = options?.appConfig ?? builderAppConfig ?? defaultAppConfig;
13
- const { defaultLanguage, localication } = appConfig;
16
+ const defaultLanguage = builderDefaultLanguage ?? 'en';
17
+ const { localication } = appConfig;
14
18
  const params = useLocalizationParams();
15
19
 
16
20
  return useCallback(
17
21
  (keyOrText: string) => {
18
- const raw =
19
- localication?.[defaultLanguage ?? 'en']?.[keyOrText] ?? keyOrText;
22
+ const raw = localication?.[defaultLanguage]?.[keyOrText] ?? keyOrText;
20
23
  return replaceLocalizationParams(raw, params);
21
24
  },
22
25
  [defaultLanguage, localication, params],
@@ -5,8 +5,8 @@ export function useParams() {
5
5
  return (
6
6
  useContext(ParamsContext) ?? {
7
7
  localizationParams: {},
8
+ nestedLocalizationParams: {},
8
9
  otherParams: {},
9
- isProvided: false,
10
10
  }
11
11
  );
12
12
  }
@@ -2,13 +2,13 @@ import { useEffect } from 'react';
2
2
  import { useRenderStore } from '../store';
3
3
 
4
4
  /**
5
- * Syncs the builder's `appConfig.theme` to the DOM so CSS can react to `.dark`.
5
+ * Syncs the builder's `theme` to the DOM so CSS can react to `.dark`.
6
6
  *
7
7
  * - Uses `html.dark` as the toggle (shadcn/tailwind convention).
8
8
  * - Also toggles `html.light` so system dark can be overridden back to light.
9
9
  */
10
10
  export function useSyncHtmlThemeClass() {
11
- const theme = useRenderStore((s) => s.appConfig.theme);
11
+ const theme = useRenderStore((s) => s.theme);
12
12
 
13
13
  useEffect(() => {
14
14
  if (typeof document === 'undefined') return;
package/src/index.ts CHANGED
@@ -15,8 +15,18 @@ export type { TargetedScreenSize } from './types/TargetedScreenSize';
15
15
  export type { Node, NodeData, NodeDefaultAttribute } from './types/Node';
16
16
  export type { Project, ProjectColors, ProjectMeta } from './types/Project';
17
17
  export type { Device } from './types/Device';
18
- export type { AppConfig, Localication } from './types/PreviewConfig';
19
- export { defaultAppConfig } from './types/PreviewConfig';
18
+ export type {
19
+ AppConfig,
20
+ Theme,
21
+ Localication,
22
+ LocalizationKey,
23
+ } from './types/PreviewConfig';
24
+ export {
25
+ defaultAppConfig,
26
+ defaultTheme,
27
+ defaultLocalization,
28
+ mergeLocalization,
29
+ } from './types/PreviewConfig';
20
30
  export type { Fonts, FontDefinition } from './types/Fonts';
21
31
  export type {
22
32
  PaywallBenefitValue,
@@ -25,13 +35,51 @@ export type {
25
35
  PaywallModel,
26
36
  } from './paywall/types/paywall-types';
27
37
 
28
- // Paywall hooks (RN-safe placeholders)
38
+ // Paywall hooks (RN-safe)
29
39
  export {
30
40
  useCalculateLocalizedPrice,
31
41
  useDiscountRate,
32
42
  useChangeDelayByPaywall,
33
43
  } from './paywall/hooks';
34
44
 
45
+ // Product base — centralized product utilities (RN-safe)
46
+ export type {
47
+ Product,
48
+ PurchaseType,
49
+ ProductInput,
50
+ PricingPhase,
51
+ SubscriptionOffer,
52
+ IOSDiscount,
53
+ IOSIntroductoryPrice,
54
+ AndroidOfferDetails,
55
+ PeriodUnit,
56
+ IOSPeriodUnit,
57
+ RecurrenceMode,
58
+ } from './product-base';
59
+ export type { AndroidParams } from './product-base';
60
+ export type { IOSParams } from './product-base';
61
+ export type { ProductParams, SingleProductParams } from './product-base';
62
+ /** @deprecated Use ProductParams instead */
63
+ export type { ProductParams as PaywallLocalizationParams } from './product-base';
64
+ export type { PaywallLocalizationConfig } from './product-base';
65
+ export {
66
+ extractPrice,
67
+ calculateDiscount,
68
+ calculatePricePerMonth,
69
+ calculatePricePerYear,
70
+ } from './product-base';
71
+ export {
72
+ PERIOD_LOCALIZATION_KEYS,
73
+ getPeriodLocalizationKey,
74
+ parseBillingPeriod,
75
+ convertIOSPeriodUnit,
76
+ } from './product-base';
77
+ export { extractAndroidParams, extractIOSParams } from './product-base';
78
+ export {
79
+ buildPaywallLocalizationParams,
80
+ usePaywallLocalizationParams,
81
+ } from './product-base';
82
+
35
83
  // Context (RN-safe). In React Native, `products` should come from an IAP wrapper
36
84
  // (e.g. `react-native-iap`) and be passed into `BuilderProvider` by the host app.
37
85
  export {
@@ -84,13 +132,13 @@ export type * from './build-components';
84
132
  export { default as useNode } from './build-components/useNode';
85
133
 
86
134
  // Static sample data helpers (RN-safe)
87
- export {
88
- getSamples,
89
- getBasicSamples,
90
- getOnboardSamples,
91
- } from './assets/samples/getSamples';
135
+ export { getSamples } from './assets/samples/getSamples';
92
136
  export { getDefaultProject } from './utils/getDefaultProject';
93
137
  export type { EventObjectGenerated } from './build-components/OnboardButton/OnboardButtonProps.generated';
94
138
 
95
139
  export { parseColor } from './utils/parseColor';
96
140
  export type { ParseColorOptions } from './utils/parseColor';
141
+ export {
142
+ defaultProjectColors,
143
+ mergeProjectColors,
144
+ } from './utils/projectColors';
package/src/logger.ts ADDED
@@ -0,0 +1,39 @@
1
+ /**
2
+ * IAP logger shim — delegates to console.
3
+ *
4
+ * The core project replaces this with a richer logger (Bugsnag remote, etc.).
5
+ * This minimal version keeps product-base compilable in the builder context.
6
+ */
7
+
8
+ type LogPayload = Record<string, unknown>;
9
+ type LogOptions = { remote?: boolean };
10
+
11
+ function noop() {}
12
+
13
+ export const iapLogger = {
14
+ error(
15
+ _tags: string[],
16
+ message: string,
17
+ payload?: LogPayload,
18
+ _opts?: LogOptions,
19
+ ) {
20
+ console.error(`[iap] ${message}`, payload);
21
+ },
22
+ warn(
23
+ _tags: string[],
24
+ message: string,
25
+ payload?: LogPayload,
26
+ _opts?: LogOptions,
27
+ ) {
28
+ console.warn(`[iap] ${message}`, payload);
29
+ },
30
+ info(
31
+ _tags: string[],
32
+ message: string,
33
+ payload?: LogPayload,
34
+ _opts?: LogOptions,
35
+ ) {
36
+ console.info(`[iap] ${message}`, payload);
37
+ },
38
+ debug: noop,
39
+ };