@developer_tribe/react-builder 1.2.41 → 1.2.42

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 (55) hide show
  1. package/dist/build-components/PaywallFooter/PaywallFooter.d.ts +5 -0
  2. package/dist/build-components/PaywallFooter/PaywallFooterProps.generated.d.ts +68 -0
  3. package/dist/build-components/index.d.ts +2 -1
  4. package/dist/build-components/patterns.generated.d.ts +495 -3
  5. package/dist/index.cjs.js +1 -1
  6. package/dist/index.cjs.js.map +1 -1
  7. package/dist/index.esm.js +1 -1
  8. package/dist/index.esm.js.map +1 -1
  9. package/dist/index.web.cjs.js +4 -4
  10. package/dist/index.web.cjs.js.map +1 -1
  11. package/dist/index.web.esm.js +4 -4
  12. package/dist/index.web.esm.js.map +1 -1
  13. package/dist/modals/IconPickerModal.d.ts +1 -1
  14. package/dist/styles.css +1 -1
  15. package/dist/types/PreviewConfig.d.ts +1 -1
  16. package/package.json +2 -2
  17. package/src/RenderPage.tsx +1 -1
  18. package/src/assets/meta.json +1 -1
  19. package/src/assets/prompt-scheme-onboard.generated.ts +1 -1
  20. package/src/assets/prompt-scheme-paywall.generated.ts +1 -1
  21. package/src/assets/samples/paywall-1.json +17 -0
  22. package/src/assets/samples/vpn-onboard-1.json +3 -3
  23. package/src/assets/samples/vpn-onboard-2.json +3 -3
  24. package/src/assets/samples/vpn-onboard-3.json +3 -3
  25. package/src/assets/samples/vpn-onboard-4.json +3 -3
  26. package/src/assets/samples/vpn-onboard-5.json +3 -3
  27. package/src/assets/samples/vpn-onboard-6.json +3 -3
  28. package/src/assets/samples/vpn-onboard-7.json +3 -3
  29. package/src/attributes-editor/AttributesEditorFields.tsx +1 -1
  30. package/src/build-components/BIcon/BIcon.tsx +1 -1
  31. package/src/build-components/OnboardButton/OnboardButton.tsx +1 -1
  32. package/src/build-components/OnboardButton/pattern.json +1 -1
  33. package/src/build-components/OnboardFooter/OnboardFooter.tsx +29 -20
  34. package/src/build-components/OnboardFooter/pattern.json +2 -1
  35. package/src/build-components/OnboardProvider/pattern.json +1 -1
  36. package/src/build-components/PaywallCloseButton/PaywallCloseButton.tsx +1 -1
  37. package/src/build-components/PaywallFooter/PaywallFooter.tsx +242 -0
  38. package/src/build-components/PaywallFooter/PaywallFooterProps.generated.ts +85 -0
  39. package/src/build-components/PaywallFooter/pattern.json +86 -0
  40. package/src/build-components/RenderNode.generated.tsx +5 -0
  41. package/src/build-components/index.ts +5 -0
  42. package/src/build-components/patterns.generated.ts +511 -3
  43. package/src/components/BottomBar.tsx +1 -1
  44. package/src/components/DeviceNavigationBar.tsx +2 -2
  45. package/src/hooks/useLocalize.ts +11 -1
  46. package/src/mockOS/managers/mockPermissionManager.ts +5 -3
  47. package/src/mockOS/managers/navigationManager.ts +6 -4
  48. package/src/modals/IconPickerModal.tsx +1 -1
  49. package/src/modals/InspectModal.tsx +22 -24
  50. package/src/styles/base/_global.scss +1 -1
  51. package/src/types/PreviewConfig.ts +24 -6
  52. package/dist/build-components/index.generated.d.ts +0 -38
  53. package/dist/types/Icons.generated.d.ts +0 -2
  54. package/src/build-components/index.generated.ts +0 -184
  55. package/src/types/Icons.generated.ts +0 -244
@@ -404,6 +404,23 @@
404
404
  "testID": "Promo-test-id-1"
405
405
  },
406
406
  "children": "@baseLocalizedPromoText"
407
+ },
408
+ {
409
+ "type": "PaywallFooter",
410
+ "attributes": {
411
+ "textLocalizationKey": "base.builder.paywall.footer.description",
412
+ "linkedWordFirstLocalizationKey": "base.builder.paywall.btnPrivacy",
413
+ "linkedWordFirstColor": "STATIC_COLORS.ONBOARD_LINK_COLOR",
414
+ "linkedWordFirstPage": "privacy",
415
+ "linkedWordSecondLocalizationKey": "base.builder.paywall.btnTerms",
416
+ "linkedWordSecondColor": "STATIC_COLORS.ONBOARD_LINK_COLOR",
417
+ "linkedWordSecondPage": "terms",
418
+ "styles": {
419
+ "gap": 8,
420
+ "color": "THEME_COLORS.ONBOARD_FOOTER_TEXT"
421
+ },
422
+ "testID": "PaywallFooter-test-id-1"
423
+ }
407
424
  }
408
425
  ]
409
426
  }
@@ -522,11 +522,11 @@
522
522
  {
523
523
  "type": "OnboardFooter",
524
524
  "attributes": {
525
- "textLocalizationKey": "view.onboarding.footer.description",
526
- "linkedWordFirstLocalizationKey": "view.onboarding.btnPrivacy",
525
+ "textLocalizationKey": "base.onboard.footer.description",
526
+ "linkedWordFirstLocalizationKey": "base.onboard.btnPrivacy",
527
527
  "linkedWordFirstColor": "STATIC_COLORS.ONBOARD_LINK_COLOR",
528
528
  "linkedWordFirstPage": "privacy",
529
- "linkedWordSecondLocalizationKey": "view.onboarding.btnTerms",
529
+ "linkedWordSecondLocalizationKey": "base.onboard.btnTerms",
530
530
  "linkedWordSecondColor": "STATIC_COLORS.ONBOARD_LINK_COLOR",
531
531
  "linkedWordSecondPage": "terms",
532
532
  "styles": {
@@ -525,11 +525,11 @@
525
525
  {
526
526
  "type": "OnboardFooter",
527
527
  "attributes": {
528
- "textLocalizationKey": "view.onboarding.footer.description",
529
- "linkedWordFirstLocalizationKey": "view.onboarding.btnPrivacy",
528
+ "textLocalizationKey": "base.onboard.footer.description",
529
+ "linkedWordFirstLocalizationKey": "base.onboard.btnPrivacy",
530
530
  "linkedWordFirstColor": "STATIC_COLORS.ONBOARD_LINK_COLOR",
531
531
  "linkedWordFirstPage": "privacy",
532
- "linkedWordSecondLocalizationKey": "view.onboarding.btnTerms",
532
+ "linkedWordSecondLocalizationKey": "base.onboard.btnTerms",
533
533
  "linkedWordSecondColor": "STATIC_COLORS.ONBOARD_LINK_COLOR",
534
534
  "linkedWordSecondPage": "terms",
535
535
  "styles": {
@@ -486,11 +486,11 @@
486
486
  {
487
487
  "type": "OnboardFooter",
488
488
  "attributes": {
489
- "textLocalizationKey": "view.onboarding.footer.description",
490
- "linkedWordFirstLocalizationKey": "view.onboarding.btnPrivacy",
489
+ "textLocalizationKey": "base.onboard.footer.description",
490
+ "linkedWordFirstLocalizationKey": "base.onboard.btnPrivacy",
491
491
  "linkedWordFirstColor": "STATIC_COLORS.ONBOARD_LINK_COLOR",
492
492
  "linkedWordFirstPage": "privacy",
493
- "linkedWordSecondLocalizationKey": "view.onboarding.btnTerms",
493
+ "linkedWordSecondLocalizationKey": "base.onboard.btnTerms",
494
494
  "linkedWordSecondColor": "STATIC_COLORS.ONBOARD_LINK_COLOR",
495
495
  "linkedWordSecondPage": "terms",
496
496
  "styles": {
@@ -486,11 +486,11 @@
486
486
  {
487
487
  "type": "OnboardFooter",
488
488
  "attributes": {
489
- "textLocalizationKey": "view.onboarding.footer.description",
490
- "linkedWordFirstLocalizationKey": "view.onboarding.btnPrivacy",
489
+ "textLocalizationKey": "base.onboard.footer.description",
490
+ "linkedWordFirstLocalizationKey": "base.onboard.btnPrivacy",
491
491
  "linkedWordFirstColor": "STATIC_COLORS.ONBOARD_LINK_COLOR",
492
492
  "linkedWordFirstPage": "privacy",
493
- "linkedWordSecondLocalizationKey": "view.onboarding.btnTerms",
493
+ "linkedWordSecondLocalizationKey": "base.onboard.btnTerms",
494
494
  "linkedWordSecondColor": "STATIC_COLORS.ONBOARD_LINK_COLOR",
495
495
  "linkedWordSecondPage": "terms",
496
496
  "styles": {
@@ -710,11 +710,11 @@
710
710
  {
711
711
  "type": "OnboardFooter",
712
712
  "attributes": {
713
- "textLocalizationKey": "view.onboarding.footer.description",
714
- "linkedWordFirstLocalizationKey": "view.onboarding.btnPrivacy",
713
+ "textLocalizationKey": "base.onboard.footer.description",
714
+ "linkedWordFirstLocalizationKey": "base.onboard.btnPrivacy",
715
715
  "linkedWordFirstColor": "STATIC_COLORS.ONBOARD_LINK_COLOR",
716
716
  "linkedWordFirstPage": "privacy",
717
- "linkedWordSecondLocalizationKey": "view.onboarding.btnTerms",
717
+ "linkedWordSecondLocalizationKey": "base.onboard.btnTerms",
718
718
  "linkedWordSecondColor": "STATIC_COLORS.ONBOARD_LINK_COLOR",
719
719
  "linkedWordSecondPage": "terms",
720
720
  "styles": {
@@ -498,11 +498,11 @@
498
498
  {
499
499
  "type": "OnboardFooter",
500
500
  "attributes": {
501
- "textLocalizationKey": "view.onboarding.footer.description",
502
- "linkedWordFirstLocalizationKey": "view.onboarding.btnPrivacy",
501
+ "textLocalizationKey": "base.onboard.footer.description",
502
+ "linkedWordFirstLocalizationKey": "base.onboard.btnPrivacy",
503
503
  "linkedWordFirstColor": "STATIC_COLORS.ONBOARD_LINK_COLOR",
504
504
  "linkedWordFirstPage": "privacy",
505
- "linkedWordSecondLocalizationKey": "view.onboarding.btnTerms",
505
+ "linkedWordSecondLocalizationKey": "base.onboard.btnTerms",
506
506
  "linkedWordSecondColor": "STATIC_COLORS.ONBOARD_LINK_COLOR",
507
507
  "linkedWordSecondPage": "terms",
508
508
  "styles": {
@@ -536,11 +536,11 @@
536
536
  {
537
537
  "type": "OnboardFooter",
538
538
  "attributes": {
539
- "textLocalizationKey": "view.onboarding.footer.description",
540
- "linkedWordFirstLocalizationKey": "view.onboarding.btnPrivacy",
539
+ "textLocalizationKey": "base.onboard.footer.description",
540
+ "linkedWordFirstLocalizationKey": "base.onboard.btnPrivacy",
541
541
  "linkedWordFirstColor": "STATIC_COLORS.ONBOARD_LINK_COLOR",
542
542
  "linkedWordFirstPage": "privacy",
543
- "linkedWordSecondLocalizationKey": "view.onboarding.btnTerms",
543
+ "linkedWordSecondLocalizationKey": "base.onboard.btnTerms",
544
544
  "linkedWordSecondColor": "STATIC_COLORS.ONBOARD_LINK_COLOR",
545
545
  "linkedWordSecondPage": "terms",
546
546
  "styles": {
@@ -5,7 +5,7 @@ import { IconPickerModal } from '../modals/IconPickerModal';
5
5
  import Modal from '../modals/Modal';
6
6
  import { loadFontFamily } from '../utils/loadFontFamily';
7
7
  import { fontsDebug } from '../utils/fontsDebug';
8
- import type { IconsType } from '../types/Icons.generated';
8
+ import type { IconsType } from '../types/Icons';
9
9
 
10
10
  type IconTypePickerFieldProps = {
11
11
  name: string;
@@ -6,7 +6,7 @@ import { useLogRender } from '../../utils/useLogRender';
6
6
  import { isNodeSelected, SELECTED_OUTLINE_STYLE } from '../../utils/selection';
7
7
  import { useMergedStyle } from '../../utils/useMergedStyle';
8
8
  import { Icon } from '../../components/Icon.generated';
9
- import { IconsType } from '../../types/Icons.generated';
9
+ import { IconsType } from '../../types/Icons';
10
10
  import { useExtractTextStyle } from '../../attribute-analyser/style/web/useExtractTextStyle';
11
11
 
12
12
  export function BIcon({ node }: BIconComponentProps) {
@@ -56,7 +56,7 @@ export function OnboardButton({ node }: OnboardButtonComponentProps) {
56
56
  if (context) {
57
57
  context.navigation(eventTarget as any);
58
58
  } else {
59
- alert('Mock OS context not available for navigation.');
59
+ console.warn('Mock OS context not available for navigation.');
60
60
  }
61
61
  }
62
62
  }
@@ -41,7 +41,7 @@
41
41
  "meta": {
42
42
  "desiredParent": ["=OnboardButtons"],
43
43
  "label": "Onboard Button",
44
- "description": "Single action button for onboarding.",
44
+ "description": "Single action button for onboard.",
45
45
  "attributes": {
46
46
  "labelKey": {
47
47
  "label": "Label Key",
@@ -7,7 +7,7 @@ import { useExtractViewStyle } from '../../attribute-analyser/style/web/useExtra
7
7
  import { useLogRender } from '../../utils/useLogRender';
8
8
  import { isNodeSelected, SELECTED_OUTLINE_STYLE } from '../../utils/selection';
9
9
  import { useMergedStyle } from '../../utils/useMergedStyle';
10
- import { defaultLocalization } from '../../types/PreviewConfig';
10
+ import { useLocalize } from '../../hooks/useLocalize';
11
11
  import { parseColor } from '../../utils/parseColor';
12
12
  import { toAttributeRecord } from '../../utils/attributeStyle';
13
13
 
@@ -96,17 +96,14 @@ function OnboardFooter({ node }: OnboardFooterComponentProps) {
96
96
  node = useNode(node);
97
97
  const attributeName = node.sourceType ?? node.type ?? 'OnboardFooter';
98
98
  const {
99
- localization: builderLocalization,
100
99
  selectedTheme: theme,
101
- selectedLanguage,
102
100
  previewMode,
103
101
  selectedKey,
104
102
  projectColors: builderProjectColors,
105
103
  } = useBuilderParams();
106
- const localization = builderLocalization ?? defaultLocalization;
107
104
  const projectColors = builderProjectColors;
108
- const lang = selectedLanguage ?? 'en';
109
- const t = (key?: string) => (key ? (localization?.[lang]?.[key] ?? key) : '');
105
+ const localize = useLocalize();
106
+ const t = (key?: string) => (key ? localize(key) : '');
110
107
 
111
108
  const attrs = node?.attributes;
112
109
  const attrRecord = toAttributeRecord(attrs);
@@ -178,18 +175,25 @@ function OnboardFooter({ node }: OnboardFooterComponentProps) {
178
175
  };
179
176
 
180
177
  return (
181
- <>
178
+ <span
179
+ style={{
180
+ ...mergedTextStyle,
181
+ display: '-webkit-box',
182
+ WebkitLineClamp: 2,
183
+ WebkitBoxOrient: 'vertical',
184
+ overflow: 'hidden',
185
+ textOverflow: 'ellipsis',
186
+ }}
187
+ >
182
188
  {segments.map((seg, i) =>
183
189
  seg.type === 'text' ? (
184
- <span key={i} style={mergedTextStyle}>
185
- {seg.value}
186
- </span>
190
+ <React.Fragment key={i}>{seg.value}</React.Fragment>
187
191
  ) : (
188
192
  <span
189
193
  key={i}
190
194
  style={{
191
- ...mergedTextStyle,
192
- color: seg.color,
195
+ ...(seg.color ? { color: seg.color } : {}),
196
+ cursor: 'pointer',
193
197
  }}
194
198
  onClick={() => handleClick(seg.page)}
195
199
  >
@@ -198,32 +202,37 @@ function OnboardFooter({ node }: OnboardFooterComponentProps) {
198
202
  ),
199
203
  )}
200
204
  {matchCount === 0 && (
201
- <div>
205
+ <>
206
+ {' '}
202
207
  {attrs?.linkedWordFirstLocalizationKey && (
203
208
  <span
204
209
  style={{
205
- ...mergedTextStyle,
206
- color: parsedFirstColor ?? undefined,
210
+ ...(parsedFirstColor
211
+ ? { color: parsedFirstColor }
212
+ : {}),
213
+ cursor: 'pointer',
207
214
  }}
208
215
  onClick={() => handleClick(attrs?.linkedWordFirstPage)}
209
216
  >
210
217
  {firstText}
211
218
  </span>
212
- )}
219
+ )}{' '}
213
220
  {attrs?.linkedWordSecondLocalizationKey && (
214
221
  <span
215
222
  style={{
216
- ...mergedTextStyle,
217
- color: parsedSecondColor ?? undefined,
223
+ ...(parsedSecondColor
224
+ ? { color: parsedSecondColor }
225
+ : {}),
226
+ cursor: 'pointer',
218
227
  }}
219
228
  onClick={() => handleClick(attrs?.linkedWordSecondPage)}
220
229
  >
221
230
  {secondText}
222
231
  </span>
223
232
  )}
224
- </div>
233
+ </>
225
234
  )}
226
- </>
235
+ </span>
227
236
  );
228
237
  })()}
229
238
  </div>
@@ -18,12 +18,13 @@
18
18
  },
19
19
  "defaults": {
20
20
  "styles": {
21
+ "minHeight":"50@vs",
21
22
  "flexDirection": "row",
22
23
  "flexWrap": "wrap",
23
24
  "alignItems": "center",
24
25
  "justifyContent": "center",
25
26
  "textAlign": "center",
26
- "paddingHorizontal": "24@s"
27
+ "paddingHorizontal": "16@s"
27
28
  }
28
29
  },
29
30
  "meta": {
@@ -20,7 +20,7 @@
20
20
  "meta": {
21
21
  "desiredParent": ["root"],
22
22
  "label": "Onboard Provider",
23
- "description": "Provides shared settings for onboarding.",
23
+ "description": "Provides shared settings for onboard.",
24
24
  "styles": {},
25
25
  "attributes": {
26
26
  "theme": {
@@ -8,7 +8,7 @@ import { useLogRender } from '../../utils/useLogRender';
8
8
  import { isNodeSelected, SELECTED_OUTLINE_STYLE } from '../../utils/selection';
9
9
  import { useMergedStyle } from '../../utils/useMergedStyle';
10
10
  import { Icon } from '../../components/Icon.generated';
11
- import { IconsType } from '../../types/Icons.generated';
11
+ import { IconsType } from '../../types/Icons';
12
12
  import { usePaywallContext } from '../PaywallProvider/PaywallContext';
13
13
 
14
14
  export function PaywallCloseButton({ node }: PaywallCloseButtonComponentProps) {
@@ -0,0 +1,242 @@
1
+ import React, { useId, useMemo } from 'react';
2
+ import type { PaywallFooterComponentProps } from './PaywallFooterProps.generated';
3
+ import useNode from '../useNode';
4
+ import { useBuilderParams } from '../../components/BuilderProvider';
5
+ import { useExtractTextStyle } from '../../attribute-analyser/style/web/useExtractTextStyle';
6
+ import { useExtractViewStyle } from '../../attribute-analyser/style/web/useExtractViewStyle';
7
+ import { useLogRender } from '../../utils/useLogRender';
8
+ import { isNodeSelected, SELECTED_OUTLINE_STYLE } from '../../utils/selection';
9
+ import { useMergedStyle } from '../../utils/useMergedStyle';
10
+ import { useLocalize } from '../../hooks/useLocalize';
11
+ import { parseColor } from '../../utils/parseColor';
12
+ import { toAttributeRecord } from '../../utils/attributeStyle';
13
+
14
+ type Segment =
15
+ | { type: 'text'; value: string }
16
+ | {
17
+ type: 'match';
18
+ value: string;
19
+ color?: string;
20
+ page?: string;
21
+ };
22
+
23
+ function escapeRegExp(str: string) {
24
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
25
+ }
26
+
27
+ function buildSegments(
28
+ text: string,
29
+ patterns: { value: string; color?: string; page?: string }[],
30
+ ): { segments: Segment[]; matchCount: number } {
31
+ type RawMatch = {
32
+ start: number;
33
+ end: number;
34
+ value: string;
35
+ color?: string;
36
+ page?: string;
37
+ };
38
+
39
+ const rawMatches: RawMatch[] = [];
40
+
41
+ for (const p of patterns) {
42
+ if (!p.value) continue;
43
+ const re = new RegExp(escapeRegExp(p.value), 'gi');
44
+ for (const m of text.matchAll(re)) {
45
+ if (m.index == null) continue;
46
+ const matched = m[0];
47
+ if (!matched) continue;
48
+ rawMatches.push({
49
+ start: m.index,
50
+ end: m.index + matched.length,
51
+ value: matched,
52
+ color: p.color,
53
+ page: p.page,
54
+ });
55
+ }
56
+ }
57
+
58
+ if (rawMatches.length === 0) {
59
+ return { segments: [{ type: 'text', value: text }], matchCount: 0 };
60
+ }
61
+
62
+ rawMatches.sort((a, b) => {
63
+ if (a.start !== b.start) return a.start - b.start;
64
+ const lenA = a.end - a.start;
65
+ const lenB = b.end - b.start;
66
+ return lenB - lenA;
67
+ });
68
+
69
+ const kept: RawMatch[] = [];
70
+ let lastEnd = -1;
71
+ for (const m of rawMatches) {
72
+ if (m.start >= lastEnd) {
73
+ kept.push(m);
74
+ lastEnd = m.end;
75
+ }
76
+ }
77
+
78
+ const segments: Segment[] = [];
79
+ let cursor = 0;
80
+ for (const { start, end, value, color, page } of kept) {
81
+ if (start > cursor) {
82
+ segments.push({ type: 'text', value: text.slice(cursor, start) });
83
+ }
84
+ segments.push({ type: 'match', value, color, page });
85
+ cursor = end;
86
+ }
87
+ if (cursor < text.length) {
88
+ segments.push({ type: 'text', value: text.slice(cursor) });
89
+ }
90
+
91
+ return { segments, matchCount: kept.length };
92
+ }
93
+
94
+ function PaywallFooter({ node }: PaywallFooterComponentProps) {
95
+ useLogRender('PaywallFooter');
96
+ node = useNode(node);
97
+ const attributeName = node.sourceType ?? node.type ?? 'PaywallFooter';
98
+ const {
99
+ selectedTheme: theme,
100
+ previewMode,
101
+ selectedKey,
102
+ projectColors: builderProjectColors,
103
+ } = useBuilderParams();
104
+ const projectColors = builderProjectColors;
105
+ const localize = useLocalize();
106
+ const t = (key?: string) => (key ? localize(key) : '');
107
+
108
+ const attrs = node?.attributes;
109
+ const attrRecord = toAttributeRecord(attrs);
110
+ const text = t(attrs?.textLocalizationKey);
111
+ const textStyle = useExtractTextStyle(node, true);
112
+ const viewStyle = useExtractViewStyle(node);
113
+
114
+ const rawFirstColor = attrRecord.linkedWordSecondColor as string | undefined;
115
+ const rawSecondColor = attrRecord.linkedWordFirstColor as string | undefined;
116
+
117
+ // Parse colors for linked words
118
+ const parsedFirstColor = useMemo(
119
+ () =>
120
+ parseColor(rawFirstColor, {
121
+ projectColors,
122
+ theme,
123
+ }),
124
+ [rawFirstColor, projectColors, theme],
125
+ );
126
+ const parsedSecondColor = useMemo(
127
+ () =>
128
+ parseColor(rawSecondColor, {
129
+ projectColors,
130
+ theme,
131
+ }),
132
+ [rawSecondColor, projectColors, theme],
133
+ );
134
+
135
+ const mergedTextStyle = useMergedStyle(textStyle, {
136
+ cursor: 'pointer',
137
+ });
138
+ const isSelected = isNodeSelected({
139
+ previewMode: !!previewMode,
140
+ current: selectedKey ? { key: selectedKey } : undefined,
141
+ node,
142
+ });
143
+ const mergedViewStyle = useMergedStyle(
144
+ viewStyle,
145
+ isSelected ? SELECTED_OUTLINE_STYLE : undefined,
146
+ );
147
+ const generatedId = useId();
148
+ const attributeKey = node.key ?? generatedId;
149
+
150
+ return (
151
+ <div
152
+ attribute-name={attributeName}
153
+ attribute-key={attributeKey}
154
+ style={mergedViewStyle}
155
+ >
156
+ {!!text &&
157
+ (() => {
158
+ const firstText = t(attrs?.linkedWordFirstLocalizationKey);
159
+ const secondText = t(attrs?.linkedWordSecondLocalizationKey);
160
+ const { segments, matchCount } = buildSegments(text, [
161
+ {
162
+ value: firstText,
163
+ color: parsedFirstColor ?? undefined,
164
+ page: attrs?.linkedWordFirstPage,
165
+ },
166
+ {
167
+ value: secondText,
168
+ color: parsedSecondColor ?? undefined,
169
+ page: attrs?.linkedWordSecondPage,
170
+ },
171
+ ]);
172
+
173
+ const handleClick = (page?: string) => {
174
+ if (!page) return;
175
+ };
176
+
177
+ return (
178
+ <span
179
+ style={{
180
+ ...mergedTextStyle,
181
+ display: '-webkit-box',
182
+ WebkitLineClamp: 2,
183
+ WebkitBoxOrient: 'vertical',
184
+ overflow: 'hidden',
185
+ textOverflow: 'ellipsis',
186
+ }}
187
+ >
188
+ {segments.map((seg, i) =>
189
+ seg.type === 'text' ? (
190
+ <React.Fragment key={i}>{seg.value}</React.Fragment>
191
+ ) : (
192
+ <span
193
+ key={i}
194
+ style={{
195
+ ...(seg.color ? { color: seg.color } : {}),
196
+ cursor: 'pointer',
197
+ }}
198
+ onClick={() => handleClick(seg.page)}
199
+ >
200
+ {seg.value}
201
+ </span>
202
+ ),
203
+ )}
204
+ {matchCount === 0 && (
205
+ <>
206
+ {' '}
207
+ {attrs?.linkedWordFirstLocalizationKey && (
208
+ <span
209
+ style={{
210
+ ...(parsedFirstColor
211
+ ? { color: parsedFirstColor }
212
+ : {}),
213
+ cursor: 'pointer',
214
+ }}
215
+ onClick={() => handleClick(attrs?.linkedWordFirstPage)}
216
+ >
217
+ {firstText}
218
+ </span>
219
+ )}{' '}
220
+ {attrs?.linkedWordSecondLocalizationKey && (
221
+ <span
222
+ style={{
223
+ ...(parsedSecondColor
224
+ ? { color: parsedSecondColor }
225
+ : {}),
226
+ cursor: 'pointer',
227
+ }}
228
+ onClick={() => handleClick(attrs?.linkedWordSecondPage)}
229
+ >
230
+ {secondText}
231
+ </span>
232
+ )}
233
+ </>
234
+ )}
235
+ </span>
236
+ );
237
+ })()}
238
+ </div>
239
+ );
240
+ }
241
+
242
+ export default React.memo(PaywallFooter);
@@ -0,0 +1,85 @@
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 PaywallFooterStyleGenerated {
23
+ color?: string;
24
+ fontSize?: string;
25
+ fontFamily?: string;
26
+ fontWeight?: string;
27
+ textAlign?: string;
28
+ flexDirection?: FlexDirectionOptionType;
29
+ flexWrap?: FlexWrapOptionType;
30
+ alignItems?: AlignItemsOptionType;
31
+ justifyContent?: JustifyContentOptionType;
32
+ gap?: string;
33
+ padding?: string;
34
+ paddingHorizontal?: string;
35
+ paddingVertical?: string;
36
+ paddingTop?: string;
37
+ paddingBottom?: string;
38
+ paddingLeft?: string;
39
+ paddingRight?: string;
40
+ margin?: string;
41
+ marginHorizontal?: string;
42
+ marginVertical?: string;
43
+ marginTop?: string;
44
+ marginBottom?: string;
45
+ marginLeft?: string;
46
+ marginRight?: string;
47
+ backgroundColor?: string;
48
+ borderRadius?: string;
49
+ width?: string;
50
+ minWidth?: string;
51
+ maxWidth?: string;
52
+ height?: string;
53
+ minHeight?: string;
54
+ maxHeight?: string;
55
+ flex?: number;
56
+ position?: PositionOptionType;
57
+ top?: string;
58
+ bottom?: string;
59
+ left?: string;
60
+ right?: string;
61
+ zIndex?: number;
62
+ }
63
+
64
+ export interface PaywallFooterPropsGenerated {
65
+ child: string;
66
+ attributes: {
67
+ styles?: PaywallFooterStyleGenerated;
68
+ adjustsFontSizeToFit?: boolean;
69
+ showEllipsis?: boolean;
70
+ translateCounter?: number;
71
+ scrollable?: boolean;
72
+ testID?: string;
73
+ textLocalizationKey?: string;
74
+ linkedWordFirstLocalizationKey?: string;
75
+ linkedWordFirstColor?: string;
76
+ linkedWordFirstPage?: string;
77
+ linkedWordSecondLocalizationKey?: string;
78
+ linkedWordSecondColor?: string;
79
+ linkedWordSecondPage?: string;
80
+ };
81
+ }
82
+
83
+ export interface PaywallFooterComponentProps {
84
+ node: NodeData<PaywallFooterPropsGenerated['attributes']>;
85
+ }