@developer_tribe/react-builder 1.2.40 → 1.2.41

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 (34) hide show
  1. package/dist/attributes-editor/FallbackLocalizationField.d.ts +6 -0
  2. package/dist/index.cjs.js +1 -1
  3. package/dist/index.cjs.js.map +1 -1
  4. package/dist/index.esm.js +1 -1
  5. package/dist/index.esm.js.map +1 -1
  6. package/dist/index.web.cjs.js +2 -2
  7. package/dist/index.web.cjs.js.map +1 -1
  8. package/dist/index.web.d.ts +8 -0
  9. package/dist/index.web.esm.js +2 -2
  10. package/dist/index.web.esm.js.map +1 -1
  11. package/dist/product-base/types.d.ts +3 -0
  12. package/dist/store.d.ts +25 -0
  13. package/dist/types/PreviewConfig.d.ts +1 -1
  14. package/package.json +1 -1
  15. package/scripts/public/bin.js +0 -0
  16. package/src/assets/meta.json +1 -1
  17. package/src/assets/prompt-scheme-onboard.generated.ts +1 -1
  18. package/src/assets/prompt-scheme-paywall.generated.ts +1 -1
  19. package/src/assets/samples/paywall-1.json +1 -1
  20. package/src/assets/samples/paywall-2.json +2 -2
  21. package/src/assets/samples/paywall-app-delete-offer.json +2 -2
  22. package/src/assets/samples/paywall-app-open-offer.json +2 -2
  23. package/src/assets/samples/paywall-back-offer.json +1 -1
  24. package/src/assets/samples/paywall-notification-offer.json +1 -1
  25. package/src/attributes-editor/AttributesEditorView.tsx +17 -6
  26. package/src/attributes-editor/FallbackLocalizationField.tsx +384 -0
  27. package/src/components/BottomBar.tsx +135 -31
  28. package/src/hooks/useLocalize.ts +3 -1
  29. package/src/index.web.ts +19 -0
  30. package/src/modals/InspectModal.tsx +112 -4
  31. package/src/product-base/buildPaywallLocalizationParams.ts +3 -0
  32. package/src/product-base/types.ts +3 -0
  33. package/src/store.ts +39 -0
  34. package/src/types/PreviewConfig.ts +6 -0
@@ -113,8 +113,41 @@ function LocalizationsTab({
113
113
  );
114
114
  }
115
115
 
116
+ const handleDownloadCSV = () => {
117
+ let csvContent = 'Key,Value,Source\n';
118
+ allKeys.forEach((key) => {
119
+ const hasCustom = key in langKeys;
120
+ const customValue = langKeys[key];
121
+ const defaultValue = defaultLangKeys[key];
122
+
123
+ const isCustom =
124
+ hasCustom && customValue !== defaultValue && customValue !== undefined;
125
+ const value = isCustom ? customValue : (defaultValue ?? '');
126
+
127
+ const escape = (str: string) => `"${String(str).replace(/"/g, '""')}"`;
128
+ csvContent += `${escape(key)},${escape(String(value))},${isCustom ? 'spreadsheet' : 'fallback'}\n`;
129
+ });
130
+
131
+ downloadCSV(`localizations-${language}.csv`, csvContent);
132
+ };
133
+
116
134
  return (
117
135
  <div className="inspect-modal__table-wrap">
136
+ <div
137
+ style={{
138
+ display: 'flex',
139
+ justifyContent: 'flex-end',
140
+ marginBottom: '8px',
141
+ }}
142
+ >
143
+ <button
144
+ type="button"
145
+ className="editor-button"
146
+ onClick={handleDownloadCSV}
147
+ >
148
+ Download CSV
149
+ </button>
150
+ </div>
118
151
  <table className="inspect-modal__table">
119
152
  <thead>
120
153
  <tr>
@@ -148,7 +181,7 @@ function LocalizationsTab({
148
181
  <span style={{ color: 'red' }}>!</span> fallback
149
182
  </>
150
183
  ) : (
151
- 'custom'
184
+ 'spreadsheet'
152
185
  )}
153
186
  </span>
154
187
  </td>
@@ -179,13 +212,43 @@ function ParamsTab({
179
212
  if (!hasAny) {
180
213
  return (
181
214
  <p className="inspect-modal__empty">
182
- No params available. Params are populated inside a PaywallProvider.
215
+ No params available. Params are populated inside a ParamsProvider.
183
216
  </p>
184
217
  );
185
218
  }
186
219
 
220
+ const handleDownloadCSV = () => {
221
+ let csvContent = 'Param,Value,Type\n';
222
+ const escape = (str: string) => `"${String(str).replace(/"/g, '""')}"`;
223
+
224
+ flatEntries.forEach(([key, value]) => {
225
+ csvContent += `${escape(key)},${escape(formatValue(value))},Flat\n`;
226
+ });
227
+
228
+ nestedEntries.forEach(([key, value]) => {
229
+ csvContent += `${escape(key)},${escape(formatValue(value))},Nested\n`;
230
+ });
231
+
232
+ downloadCSV('params.csv', csvContent);
233
+ };
234
+
187
235
  return (
188
236
  <div className="inspect-modal__table-wrap">
237
+ <div
238
+ style={{
239
+ display: 'flex',
240
+ justifyContent: 'flex-end',
241
+ marginBottom: '8px',
242
+ }}
243
+ >
244
+ <button
245
+ type="button"
246
+ className="editor-button"
247
+ onClick={handleDownloadCSV}
248
+ >
249
+ Download CSV
250
+ </button>
251
+ </div>
189
252
  <table className="inspect-modal__table">
190
253
  <thead>
191
254
  <tr>
@@ -249,8 +312,29 @@ function ColorsTab({
249
312
  return <p className="inspect-modal__empty">No project colors defined.</p>;
250
313
  }
251
314
 
315
+ const handleDownloadJSON = () => {
316
+ const data = projectColors ?? {};
317
+ const jsonContent = JSON.stringify(data, null, 2);
318
+ downloadJSON('colors.json', jsonContent);
319
+ };
320
+
252
321
  return (
253
322
  <div className="inspect-modal__table-wrap">
323
+ <div
324
+ style={{
325
+ display: 'flex',
326
+ justifyContent: 'flex-end',
327
+ marginBottom: '8px',
328
+ }}
329
+ >
330
+ <button
331
+ type="button"
332
+ className="editor-button"
333
+ onClick={handleDownloadJSON}
334
+ >
335
+ Download JSON
336
+ </button>
337
+ </div>
254
338
  {staticEntries.length > 0 && (
255
339
  <>
256
340
  <h4 className="inspect-modal__section-title">Static Colors</h4>
@@ -284,7 +368,7 @@ function ColorsTab({
284
368
  <span style={{ color: 'red' }}>!</span> fallback
285
369
  </>
286
370
  ) : (
287
- 'custom'
371
+ 'added to project'
288
372
  )}
289
373
  </span>
290
374
  </td>
@@ -331,7 +415,7 @@ function ColorsTab({
331
415
  <span style={{ color: 'red' }}>!</span> fallback
332
416
  </>
333
417
  ) : (
334
- 'custom'
418
+ 'added to project'
335
419
  )}
336
420
  </span>
337
421
  </td>
@@ -357,3 +441,27 @@ function formatValue(v: unknown): string {
357
441
  if (typeof v === 'number' || typeof v === 'boolean') return String(v);
358
442
  return JSON.stringify(v);
359
443
  }
444
+
445
+ function downloadCSV(filename: string, csvContent: string) {
446
+ const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
447
+ const url = URL.createObjectURL(blob);
448
+ const link = document.createElement('a');
449
+ link.setAttribute('href', url);
450
+ link.setAttribute('download', filename);
451
+ document.body.appendChild(link);
452
+ link.click();
453
+ document.body.removeChild(link);
454
+ }
455
+
456
+ function downloadJSON(filename: string, jsonContent: string) {
457
+ const blob = new Blob([jsonContent], {
458
+ type: 'application/json;charset=utf-8;',
459
+ });
460
+ const url = URL.createObjectURL(blob);
461
+ const link = document.createElement('a');
462
+ link.setAttribute('href', url);
463
+ link.setAttribute('download', filename);
464
+ document.body.appendChild(link);
465
+ link.click();
466
+ document.body.removeChild(link);
467
+ }
@@ -105,5 +105,8 @@ export function buildPaywallLocalizationParams(
105
105
  productCurreny: extractedParams.currency,
106
106
  productId: String(product.productId ?? ''),
107
107
  productSelected: 'true',
108
+ subscribe: hasTrial
109
+ ? resolve('base.builder.paywall.button.subscribe-free')
110
+ : resolve('base.builder.paywall.button.subscribe'),
108
111
  };
109
112
  }
@@ -116,6 +116,8 @@ export interface Product {
116
116
  displayPrice?: string;
117
117
  localizedPrice?: string;
118
118
  price?: string;
119
+ promoPrice?: string;
120
+ localizedPromoPrice?: string;
119
121
  currency?: string;
120
122
  currencyCode?: string;
121
123
  platform?: 'android' | 'ios';
@@ -169,6 +171,7 @@ export interface ProductParams {
169
171
  productCurreny: string;
170
172
  productId: string;
171
173
  productSelected: string;
174
+ subscribe: string;
172
175
  }
173
176
 
174
177
  /** Keys excluded from single (per-option) params — these are global/context-level. */
package/src/store.ts CHANGED
@@ -1,3 +1,18 @@
1
+ import type { ComponentType } from 'react';
2
+
3
+ export type LocalizationApiConfig = {
4
+ forgeUrl: string;
5
+ forgeToken: string;
6
+ forgeAppId?: string | number | null;
7
+ };
8
+
9
+ export type LanguageColumn = {
10
+ id: number;
11
+ code: string;
12
+ title: string;
13
+ iso_code: string;
14
+ is_right_alignment: boolean;
15
+ };
1
16
  import { createWithEqualityFn } from 'zustand/traditional';
2
17
  import { shallow } from 'zustand/shallow';
3
18
  import type { Device } from './types/Device';
@@ -43,6 +58,8 @@ type RenderStore = {
43
58
  setLocalization: (localization: Localication) => void;
44
59
  isRtl: boolean;
45
60
  setIsRtl: (isRtl: boolean) => void;
61
+ languageColumns: LanguageColumn[];
62
+ setLanguageColumns: (cols: LanguageColumn[]) => void;
46
63
  previewMode: boolean;
47
64
  setPreviewMode: (previewMode: boolean) => void;
48
65
  // Mockable: products (persisted)
@@ -101,6 +118,18 @@ type RenderStore = {
101
118
 
102
119
  favoriteDevices: string[];
103
120
  toggleFavoriteDevice: (name: string) => void;
121
+
122
+ // Host-provided custom renderer for the "Text" (string children) field
123
+ renderStringChildrenField?: ComponentType<{
124
+ value: string;
125
+ onChange: (v: string) => void;
126
+ }>;
127
+ setRenderStringChildrenField: (
128
+ comp?: ComponentType<{ value: string; onChange: (v: string) => void }>,
129
+ ) => void;
130
+
131
+ localizationApiConfig?: LocalizationApiConfig;
132
+ setLocalizationApiConfig: (config?: LocalizationApiConfig) => void;
104
133
  };
105
134
 
106
135
  export const useRenderStore = createWithEqualityFn<RenderStore>()(
@@ -129,6 +158,8 @@ export const useRenderStore = createWithEqualityFn<RenderStore>()(
129
158
  setLocalization: (localization) => set({ localization }),
130
159
  isRtl: false,
131
160
  setIsRtl: (isRtl) => set({ isRtl }),
161
+ languageColumns: [],
162
+ setLanguageColumns: (cols) => set({ languageColumns: cols }),
132
163
  previewMode: false,
133
164
  setPreviewMode: (previewMode) => set({ previewMode }),
134
165
  products: [],
@@ -296,6 +327,14 @@ export const useRenderStore = createWithEqualityFn<RenderStore>()(
296
327
  : [...devs, name],
297
328
  };
298
329
  }),
330
+
331
+ renderStringChildrenField: undefined,
332
+ setRenderStringChildrenField: (comp) =>
333
+ set({ renderStringChildrenField: comp }),
334
+
335
+ localizationApiConfig: undefined,
336
+ setLocalizationApiConfig: (config) =>
337
+ set({ localizationApiConfig: config }),
299
338
  }),
300
339
  {
301
340
  name: 'render-store',
@@ -15,6 +15,8 @@ export type LocalizationKey =
15
15
  | 'base.builder.paywall.promo.default.text'
16
16
  | 'base.builder.paywall.promo.freeTrial.text'
17
17
  | 'base.builder.paywall.promo.regular.text'
18
+ | 'base.builder.paywall.button.subscribe'
19
+ | 'base.builder.paywall.button.subscribe-free'
18
20
  // onboard – titles
19
21
  | 'base.onboard.title.one-page'
20
22
  | 'base.onboard.title.two-page'
@@ -79,6 +81,8 @@ export const defaultLocalization: Localication = {
79
81
  '@trialPeriod-@trialPeriodUnit free trial',
80
82
  'base.builder.paywall.promo.regular.text':
81
83
  '@localizedPrice @localizedPeriod',
84
+ 'base.builder.paywall.button.subscribe': 'Subscribe',
85
+ 'base.builder.paywall.button.subscribe-free': 'Subscribe with Free Trial',
82
86
  // onboard – titles
83
87
  'base.onboard.title.one-page': 'Secure your connection',
84
88
  'base.onboard.title.two-page': 'Access content worldwide',
@@ -146,6 +150,8 @@ export const defaultLocalization: Localication = {
146
150
  '@trialPeriod @trialPeriodUnit ücretsiz deneme',
147
151
  'base.builder.paywall.promo.regular.text':
148
152
  '@localizedPrice @localizedPeriod',
153
+ 'base.builder.paywall.button.subscribe': 'Abone Ol',
154
+ 'base.builder.paywall.button.subscribe-free': 'Ücretsiz Denemeyi Başlat',
149
155
  // onboard – titles
150
156
  'base.onboard.title.five-page': 'Deneyiminizi geliştirin',
151
157
  'base.onboard.title.six-page': 'Her şey hazır!',