@developer_tribe/react-builder 1.2.19 → 1.2.21

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 (162) hide show
  1. package/dist/attribute-analyser/style/web/useExtractTextStyle.d.ts +1 -1
  2. package/dist/build-components/BIcon/BIconProps.generated.d.ts +2 -0
  3. package/dist/build-components/BackgroundImage/BackgroundImageProps.generated.d.ts +2 -0
  4. package/dist/build-components/Button/ButtonProps.generated.d.ts +2 -0
  5. package/dist/build-components/Carousel/CarouselProps.generated.d.ts +2 -0
  6. package/dist/build-components/CarouselButtons/CarouselButtonsProps.generated.d.ts +2 -0
  7. package/dist/build-components/CarouselDots/CarouselDotsProps.generated.d.ts +2 -0
  8. package/dist/build-components/CarouselItem/CarouselItemProps.generated.d.ts +2 -0
  9. package/dist/build-components/CarouselProvider/CarouselProviderProps.generated.d.ts +2 -0
  10. package/dist/build-components/CountDown/CountDownProps.generated.d.ts +2 -0
  11. package/dist/build-components/Counter/CounterProps.generated.d.ts +2 -0
  12. package/dist/build-components/Image/ImageProps.generated.d.ts +2 -0
  13. package/dist/build-components/Main/MainProps.generated.d.ts +2 -0
  14. package/dist/build-components/Onboard/OnboardProps.generated.d.ts +2 -0
  15. package/dist/build-components/OnboardButton/OnboardButtonProps.generated.d.ts +2 -0
  16. package/dist/build-components/OnboardButtons/OnboardButtonsProps.generated.d.ts +2 -0
  17. package/dist/build-components/OnboardDot/OnboardDotProps.generated.d.ts +4 -1
  18. package/dist/build-components/OnboardFooter/OnboardFooterProps.generated.d.ts +2 -0
  19. package/dist/build-components/OnboardImage/OnboardImageProps.generated.d.ts +2 -0
  20. package/dist/build-components/OnboardItem/OnboardItemProps.generated.d.ts +2 -0
  21. package/dist/build-components/OnboardProvider/OnboardProviderProps.generated.d.ts +2 -0
  22. package/dist/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.d.ts +2 -0
  23. package/dist/build-components/OnboardTitle/OnboardTitleProps.generated.d.ts +2 -0
  24. package/dist/build-components/PaywallBackground/PaywallBackgroundProps.generated.d.ts +2 -0
  25. package/dist/build-components/PaywallCloseButton/PaywallCloseButtonProps.generated.d.ts +2 -0
  26. package/dist/build-components/PaywallCounter/PaywallCounterProps.generated.d.ts +2 -0
  27. package/dist/build-components/PaywallOptions/PaywallOptionsProps.generated.d.ts +2 -0
  28. package/dist/build-components/PaywallProvider/PaywallProviderProps.generated.d.ts +2 -0
  29. package/dist/build-components/PaywallSubscribeButton/PaywallSubscribeButtonProps.generated.d.ts +2 -0
  30. package/dist/build-components/RadioButton/RadioButtonProps.generated.d.ts +2 -0
  31. package/dist/build-components/Text/TextProps.generated.d.ts +2 -0
  32. package/dist/build-components/View/View.d.ts +1 -1
  33. package/dist/build-components/View/ViewProps.generated.d.ts +2 -0
  34. package/dist/build-components/patterns.generated.d.ts +310 -10
  35. package/dist/components/BuilderButton.d.ts +3 -1
  36. package/dist/index.cjs.js +4 -4
  37. package/dist/index.cjs.js.map +1 -1
  38. package/dist/index.esm.js +4 -4
  39. package/dist/index.esm.js.map +1 -1
  40. package/dist/index.web.cjs.js +6 -6
  41. package/dist/index.web.cjs.js.map +1 -1
  42. package/dist/index.web.esm.js +4 -4
  43. package/dist/index.web.esm.js.map +1 -1
  44. package/dist/store.d.ts +2 -0
  45. package/dist/styles.css +1 -1
  46. package/dist/utils/extractTextStyle/extractTextStyle.d.ts +1 -0
  47. package/package.json +1 -1
  48. package/scripts/migrate-patterns-to-v2.mjs +13 -8
  49. package/scripts/prebuild/icon-generator.js +34 -37
  50. package/src/assets/loading_animation.json +2587 -1
  51. package/src/assets/meta.json +1 -1
  52. package/src/assets/samples/carousel-sample.json +281 -199
  53. package/src/assets/samples/getSamples.ts +16 -1
  54. package/src/assets/samples/paywall-1.json +93 -77
  55. package/src/assets/samples/paywall-2.json +77 -77
  56. package/src/assets/samples/paywall-app-delete-offer.json +353 -0
  57. package/src/assets/samples/paywall-app-open-offer.json +353 -0
  58. package/src/assets/samples/paywall-back-offer.json +353 -0
  59. package/src/assets/samples/paywall-notification-offer.json +353 -0
  60. package/src/assets/samples/simple-1.json +13 -13
  61. package/src/assets/samples/simple-2.json +97 -97
  62. package/src/assets/samples/unmigrated-builder-1.1.1.json +25 -25
  63. package/src/assets/samples/unmigrated-builder1.json +1 -1
  64. package/src/assets/samples/unvalidated-builder1.json +15 -15
  65. package/src/assets/samples/unvalidated-crash1.json +4 -4
  66. package/src/assets/samples/vpn-onboard-1.json +122 -89
  67. package/src/assets/samples/vpn-onboard-2.json +119 -86
  68. package/src/assets/samples/vpn-onboard-3.json +125 -90
  69. package/src/assets/samples/vpn-onboard-4.json +125 -90
  70. package/src/assets/samples/vpn-onboard-5.json +161 -119
  71. package/src/assets/samples/vpn-onboard-6.json +122 -92
  72. package/src/attribute-analyser/style/web/useExtractTextStyle.ts +9 -2
  73. package/src/build-components/BIcon/BIconProps.generated.ts +2 -0
  74. package/src/build-components/BackgroundImage/BackgroundImageProps.generated.ts +2 -0
  75. package/src/build-components/Button/ButtonProps.generated.ts +2 -0
  76. package/src/build-components/Carousel/CarouselProps.generated.ts +2 -0
  77. package/src/build-components/Carousel/pattern.json +2 -8
  78. package/src/build-components/CarouselButtons/CarouselButtonsProps.generated.ts +2 -0
  79. package/src/build-components/CarouselButtons/pattern.json +2 -9
  80. package/src/build-components/CarouselDots/CarouselDots.tsx +112 -12
  81. package/src/build-components/CarouselDots/CarouselDotsProps.generated.ts +2 -0
  82. package/src/build-components/CarouselDots/pattern.json +1 -3
  83. package/src/build-components/CarouselItem/CarouselItemProps.generated.ts +2 -0
  84. package/src/build-components/CarouselItem/pattern.json +1 -3
  85. package/src/build-components/CarouselProvider/CarouselProvider.tsx +5 -44
  86. package/src/build-components/CarouselProvider/CarouselProviderProps.generated.ts +2 -0
  87. package/src/build-components/CarouselProvider/pattern.json +6 -0
  88. package/src/build-components/CountDown/CountDownProps.generated.ts +2 -0
  89. package/src/build-components/CountDown/pattern.json +0 -1
  90. package/src/build-components/Counter/CounterProps.generated.ts +2 -0
  91. package/src/build-components/Counter/pattern.json +0 -1
  92. package/src/build-components/Image/Image.tsx +1 -1
  93. package/src/build-components/Image/ImageProps.generated.ts +2 -0
  94. package/src/build-components/Main/MainProps.generated.ts +2 -0
  95. package/src/build-components/Main/pattern.json +1 -3
  96. package/src/build-components/Onboard/OnboardProps.generated.ts +2 -0
  97. package/src/build-components/Onboard/pattern.json +2 -6
  98. package/src/build-components/OnboardButton/OnboardButton.tsx +0 -4
  99. package/src/build-components/OnboardButton/OnboardButtonProps.generated.ts +2 -0
  100. package/src/build-components/OnboardButton/pattern.json +9 -14
  101. package/src/build-components/OnboardButtons/OnboardButtons.tsx +17 -20
  102. package/src/build-components/OnboardButtons/OnboardButtonsProps.generated.ts +2 -0
  103. package/src/build-components/OnboardButtons/pattern.json +15 -15
  104. package/src/build-components/OnboardDot/OnboardDot.tsx +73 -42
  105. package/src/build-components/OnboardDot/OnboardDotProps.generated.ts +4 -1
  106. package/src/build-components/OnboardDot/pattern.json +28 -10
  107. package/src/build-components/OnboardFooter/OnboardFooter.tsx +63 -51
  108. package/src/build-components/OnboardFooter/OnboardFooterProps.generated.ts +2 -0
  109. package/src/build-components/OnboardFooter/pattern.json +6 -3
  110. package/src/build-components/OnboardImage/OnboardImageProps.generated.ts +2 -0
  111. package/src/build-components/OnboardImage/pattern.json +1 -5
  112. package/src/build-components/OnboardItem/OnboardItemProps.generated.ts +2 -0
  113. package/src/build-components/OnboardItem/pattern.json +3 -11
  114. package/src/build-components/OnboardProvider/OnboardProviderProps.generated.ts +2 -0
  115. package/src/build-components/OnboardProvider/pattern.json +2 -8
  116. package/src/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.ts +2 -0
  117. package/src/build-components/OnboardSubtitle/pattern.json +1 -4
  118. package/src/build-components/OnboardTitle/OnboardTitleProps.generated.ts +2 -0
  119. package/src/build-components/OnboardTitle/pattern.json +1 -4
  120. package/src/build-components/PaywallBackground/PaywallBackgroundProps.generated.ts +2 -0
  121. package/src/build-components/PaywallCloseButton/PaywallCloseButtonProps.generated.ts +2 -0
  122. package/src/build-components/PaywallCloseButton/pattern.json +1 -3
  123. package/src/build-components/PaywallCounter/PaywallCounterProps.generated.ts +2 -0
  124. package/src/build-components/PaywallCounter/pattern.json +0 -1
  125. package/src/build-components/PaywallOptions/PaywallOptions.tsx +1 -1
  126. package/src/build-components/PaywallOptions/PaywallOptionsProps.generated.ts +2 -0
  127. package/src/build-components/PaywallOptions/pattern.json +1 -3
  128. package/src/build-components/PaywallProvider/PaywallProviderProps.generated.ts +2 -0
  129. package/src/build-components/PaywallProvider/pattern.json +1 -3
  130. package/src/build-components/PaywallSubscribeButton/PaywallSubscribeButtonProps.generated.ts +2 -0
  131. package/src/build-components/PaywallSubscribeButton/pattern.json +1 -3
  132. package/src/build-components/RadioButton/RadioButtonProps.generated.ts +2 -0
  133. package/src/build-components/RadioButton/pattern.json +1 -3
  134. package/src/build-components/RenderNode.generated.tsx +1 -1
  135. package/src/build-components/Text/TextProps.generated.ts +2 -0
  136. package/src/build-components/View/View.tsx +11 -7
  137. package/src/build-components/View/ViewProps.generated.ts +2 -0
  138. package/src/build-components/View/pattern.json +8 -0
  139. package/src/build-components/patterns.generated.ts +300 -10
  140. package/src/build-components/useNode.ts +20 -4
  141. package/src/components/Builder.tsx +98 -8
  142. package/src/components/BuilderButton.tsx +39 -7
  143. package/src/components/DeviceButton.tsx +5 -1
  144. package/src/pages/DebugJsonPage.tsx +109 -1
  145. package/src/pages/ProjectDebug.tsx +0 -1
  146. package/src/pages/ProjectPage.tsx +2 -2
  147. package/src/store.ts +8 -0
  148. package/src/styles/base/_global.scss +0 -5
  149. package/src/styles/components/_editor-shell.scss +18 -3
  150. package/src/styles/components/_onboard.scss +0 -17
  151. package/src/styles/foundation/_colors.scss +1 -4
  152. package/src/styles/foundation/_typography.scss +0 -1
  153. package/src/styles/layout/_builder.scss +20 -0
  154. package/src/styles/modals/_product-presets-modal.scss +0 -2
  155. package/src/styles/utilities/_carousel.scss +0 -32
  156. package/src/utils/analyseNodeByPatterns.ts +16 -6
  157. package/src/utils/extractTextStyle/extractTextStyle.ts +47 -13
  158. package/src/utils/extractViewStyle/extractViewStyle.ts +118 -39
  159. package/src/utils/logRenderStore.ts +7 -9
  160. package/src/utils/logger.ts +1 -5
  161. package/src/utils/novaToJson.ts +7 -3
  162. package/src/utils/repairNodeKeys.ts +1 -4
@@ -20,8 +20,12 @@ function OnboardDot({ node }: OnboardDotComponentProps) {
20
20
  const attributeName = node.type ?? 'OnboardDot';
21
21
  const attributeKey = node.key ?? generatedId;
22
22
  const attrs = node.attributes;
23
- const styleBag = attrs?.style;
24
- const dotType = attrs?.dotType || 'normal_dot';
23
+ const stylesBag =
24
+ ((attrs as any)?.styles as Record<string, unknown> | undefined) ??
25
+ ((attrs as any)?.style as Record<string, unknown> | undefined) ??
26
+ undefined;
27
+ const dotType =
28
+ (stylesBag?.dotType as any) ?? (attrs as any)?.dotType ?? 'normal_dot';
25
29
  const GHOST_DOT_DARK_COLOR = '#E4E5E7';
26
30
  const GHOST_DOT_LIGHT_COLOR = '#F7F7F9';
27
31
  const {
@@ -37,12 +41,32 @@ function OnboardDot({ node }: OnboardDotComponentProps) {
37
41
  const inactiveDotColor = isDark
38
42
  ? GHOST_DOT_DARK_COLOR
39
43
  : GHOST_DOT_LIGHT_COLOR;
40
- const inactiveDotOpacity = attrs?.inactive_dot_opacity ?? 0.3;
41
- const activeDotColor = attrs?.active_dot_color;
44
+ const inactiveDotOpacity =
45
+ (stylesBag?.inactive_dot_opacity as number | undefined) ??
46
+ (attrs as any)?.inactive_dot_opacity ??
47
+ 0.3;
48
+ const inactiveDotColorOverride =
49
+ (stylesBag?.inactive_dot_color as string | undefined) ??
50
+ (attrs as any)?.inactive_dot_color;
51
+ const activeDotColor =
52
+ (stylesBag?.active_dot_color as string | undefined) ??
53
+ (attrs as any)?.active_dot_color;
42
54
  const resolvedActiveDotColor = useMemo(
43
55
  () => parseColor(activeDotColor, { theme: appConfig.theme, projectColors }),
44
56
  [activeDotColor, appConfig.theme, projectColors],
45
57
  );
58
+ const resolvedInactiveDotColor = useMemo(() => {
59
+ const parsed = parseColor(inactiveDotColorOverride, {
60
+ theme: appConfig.theme,
61
+ projectColors,
62
+ });
63
+ return parsed ?? inactiveDotColor;
64
+ }, [
65
+ inactiveDotColor,
66
+ inactiveDotColorOverride,
67
+ appConfig.theme,
68
+ projectColors,
69
+ ]);
46
70
 
47
71
  const extractedStyle = useExtractViewStyle(node);
48
72
  const baseStyle = useMemo(() => {
@@ -58,27 +82,31 @@ function OnboardDot({ node }: OnboardDotComponentProps) {
58
82
  baseStyle,
59
83
  isSelected ? SELECTED_OUTLINE_STYLE : undefined,
60
84
  );
61
- const expandingDotWidthRaw = attrs?.expanding_dot_width;
62
- const expandingDotWidthOverride = useMemo(() => {
63
- const parsed = parseSize(expandingDotWidthRaw);
64
- if (parsed === undefined) return undefined;
65
-
66
- // `parseSize` may return number (px) or a string (e.g. "50%").
67
- const cssWidth =
68
- typeof parsed === 'number'
69
- ? `${parsed}px`
70
- : typeof parsed === 'string'
71
- ? parsed
72
- : undefined;
73
-
74
- if (!cssWidth) return undefined;
75
-
76
- return {
77
- // Controls the actual dot diameter (`.embla__dot:after`).
78
- '--embla-dot-size': cssWidth,
79
- } as React.CSSProperties & Record<`--${string}`, string>;
80
- }, [expandingDotWidthRaw]);
81
- const containerStyle = useMergedStyle(style, expandingDotWidthOverride);
85
+ const dotThicknessRaw =
86
+ (stylesBag?.dot_thickness as any) ?? (attrs as any)?.dot_thickness;
87
+ const dotSizeCss = useMemo((): string => {
88
+ const parsed = parseSize(dotThicknessRaw);
89
+ if (parsed === undefined) return '10px';
90
+ if (typeof parsed === 'number') return `${parsed}px`;
91
+ if (typeof parsed === 'string' && parsed.trim()) return parsed;
92
+ return '10px';
93
+ }, [dotThicknessRaw]);
94
+ const dotGapCss = useMemo((): string => {
95
+ // Prefer px math when possible; otherwise fall back to 10px/3.
96
+ const px =
97
+ typeof dotSizeCss === 'string' && dotSizeCss.trim().endsWith('px')
98
+ ? Number.parseFloat(dotSizeCss)
99
+ : Number.NaN;
100
+ const n = Number.isFinite(px) ? px : 10;
101
+ return `${Math.max(0, n / 3)}px`;
102
+ }, [dotSizeCss]);
103
+ const gapValue = (style as any)?.gap ?? dotGapCss;
104
+ const containerStyle = useMergedStyle(style, {
105
+ display: 'flex',
106
+ flexWrap: 'wrap',
107
+ gap: gapValue,
108
+ alignItems: 'center',
109
+ });
82
110
 
83
111
  const onboardApi = useContext(onboardContext);
84
112
  const emblaApi = onboardApi?.emblaApi;
@@ -115,30 +143,33 @@ function OnboardDot({ node }: OnboardDotComponentProps) {
115
143
  >
116
144
  {scrollSnaps.map((snap, index) => {
117
145
  const isDotSelected = selectedIndex === index;
118
- const dotStyles: React.CSSProperties & Record<`--${string}`, string> = {
119
- opacity: isDotSelected ? 1 : inactiveDotOpacity,
120
- };
121
-
122
- if (resolvedActiveDotColor && isDotSelected) {
123
- // Style the actual visual dot (rendered via `.embla__dot:after`) using a CSS variable.
124
- dotStyles['--embla-dot-color'] = resolvedActiveDotColor;
125
- } else if (!isDotSelected) {
126
- dotStyles['--embla-dot-color'] = inactiveDotColor;
127
- }
146
+ const resolvedColor =
147
+ isDotSelected && resolvedActiveDotColor
148
+ ? resolvedActiveDotColor
149
+ : resolvedInactiveDotColor;
150
+ const activeFallback = '#007AFF';
151
+ const dotColor = resolvedColor ?? activeFallback;
128
152
 
129
153
  return (
130
154
  <button
131
155
  key={index}
132
- onClick={() => {
133
- emblaApi?.scrollTo(snap);
156
+ className="embla__dot"
157
+ style={{
158
+ width: dotSizeCss,
159
+ height: dotSizeCss,
160
+ backgroundColor: dotColor,
161
+ opacity: isDotSelected ? 1 : inactiveDotOpacity,
162
+ borderRadius: '9999px',
163
+ border: 0,
164
+ padding: 0,
165
+ margin: 0,
166
+ display: 'inline-block',
167
+ cursor: 'pointer',
168
+ boxSizing: 'border-box',
134
169
  }}
135
- className={`embla__dot ${isDotSelected ? 'embla__dot--selected' : ''}`}
136
- style={dotStyles}
137
170
  aria-label={`Go to slide ${index + 1}`}
138
171
  aria-current={isDotSelected ? 'true' : undefined}
139
- >
140
- {/* Dot visuals are rendered via CSS (`.embla__dot:after`). */}
141
- </button>
172
+ />
142
173
  );
143
174
  })}
144
175
  </div>
@@ -10,6 +10,7 @@ export type DotTypeOptionType =
10
10
  | 'sliding_dot'
11
11
  | 'liquid_like';
12
12
  export type FlexDirectionOptionType = 'row' | 'column';
13
+ export type FlexWrapOptionType = 'nowrap' | 'wrap' | 'wrap-reverse';
13
14
  export type AlignItemsOptionType =
14
15
  | 'flex-start'
15
16
  | 'center'
@@ -27,6 +28,7 @@ export type PositionOptionType = 'relative' | 'absolute';
27
28
 
28
29
  export interface OnboardDotStyleGenerated {
29
30
  flexDirection?: FlexDirectionOptionType;
31
+ flexWrap?: FlexWrapOptionType;
30
32
  alignItems?: AlignItemsOptionType;
31
33
  justifyContent?: JustifyContentOptionType;
32
34
  gap?: string;
@@ -69,8 +71,9 @@ export interface OnboardDotPropsGenerated {
69
71
  title?: string;
70
72
  description?: string;
71
73
  dotType?: DotTypeOptionType;
74
+ dot_thickness?: string;
72
75
  inactive_dot_opacity?: number;
73
- expanding_dot_width?: string;
76
+ inactive_dot_color?: string;
74
77
  active_dot_color?: string;
75
78
  flexDirection?: never;
76
79
  alignItems?: never;
@@ -15,18 +15,29 @@
15
15
  "sliding_dot",
16
16
  "liquid_like"
17
17
  ],
18
+ "dot_thickness": "size",
18
19
  "inactive_dot_opacity": "number",
19
- "expanding_dot_width": "size",
20
+ "inactive_dot_color": "color",
20
21
  "active_dot_color": "color",
21
22
  "flexDirection": "never",
22
23
  "alignItems": "never",
23
24
  "justifyContent": "never"
24
25
  }
25
26
  },
27
+ "defaults": {
28
+ "dotType": "expanding_dot",
29
+ "dot_thickness": 10,
30
+ "inactive_dot_opacity": 0.3,
31
+ "active_dot_color": "#007AFF",
32
+ "style": {
33
+ "flexDirection": "row",
34
+ "alignItems": "center",
35
+ "justifyContent": "center",
36
+ "gap": "12@s"
37
+ }
38
+ },
26
39
  "meta": {
27
- "desiredParent": [
28
- ">OnboardProvider"
29
- ],
40
+ "desiredParent": [">OnboardProvider"],
30
41
  "label": "Onboard Dot",
31
42
  "description": "Renders onboarding progress dots.",
32
43
  "styles": {
@@ -42,21 +53,28 @@
42
53
  "description": "Opacity for inactive dots.",
43
54
  "category": "style",
44
55
  "specialCategory": null,
45
- "sort": 2
56
+ "sort": 3
46
57
  },
47
- "expanding_dot_width": {
48
- "label": "Expanding Dot Width",
49
- "description": "Width used while expanding.",
58
+ "inactive_dot_color": {
59
+ "label": "Inactive Dot Color",
60
+ "description": "Color of inactive dots.",
50
61
  "category": "style",
51
62
  "specialCategory": null,
52
- "sort": 3
63
+ "sort": 4
64
+ },
65
+ "dot_thickness": {
66
+ "label": "Dot Thickness",
67
+ "description": "Dot size/diameter.",
68
+ "category": "style",
69
+ "specialCategory": null,
70
+ "sort": 2
53
71
  },
54
72
  "active_dot_color": {
55
73
  "label": "Active Dot Color",
56
74
  "description": "Color of the active dot.",
57
75
  "category": "style",
58
76
  "specialCategory": null,
59
- "sort": 4
77
+ "sort": 5
60
78
  }
61
79
  }
62
80
  }
@@ -2,13 +2,13 @@ import React, { useId, useMemo } from 'react';
2
2
  import type { OnboardFooterComponentProps } from './OnboardFooterProps.generated';
3
3
  import useNode from '../useNode';
4
4
  import { useBuilderParams } from '../../components/BuilderProvider';
5
- import { parseSize } from '../../size-matters';
6
5
  import { useExtractTextStyle } from '../../attribute-analyser/style/web/useExtractTextStyle';
7
6
  import { useExtractViewStyle } from '../../attribute-analyser/style/web/useExtractViewStyle';
8
7
  import { useLogRender } from '../../utils/useLogRender';
9
- import { isNodeSelected } from '../../utils/selection';
8
+ import { isNodeSelected, SELECTED_OUTLINE_STYLE } from '../../utils/selection';
10
9
  import { useMergedStyle } from '../../utils/useMergedStyle';
11
10
  import { defaultAppConfig } from '../../types/PreviewConfig';
11
+ import { parseColor } from '../../utils/parseColor';
12
12
 
13
13
  type Segment =
14
14
  | { type: 'text'; value: string }
@@ -98,48 +98,57 @@ function OnboardFooter({ node }: OnboardFooterComponentProps) {
98
98
  appConfig: builderAppConfig,
99
99
  previewMode,
100
100
  selectedKey,
101
+ projectColors: builderProjectColors,
101
102
  } = useBuilderParams();
102
103
  const appConfig = builderAppConfig ?? defaultAppConfig;
103
- const { localication, defaultLanguage } = appConfig;
104
+ const projectColors = builderProjectColors;
105
+ const { localication, defaultLanguage, theme } = appConfig;
104
106
  const t = (key?: string) =>
105
107
  key ? (localication?.[defaultLanguage ?? 'en']?.[key] ?? key) : '';
106
108
 
107
109
  const attrs = node?.attributes;
108
- const styleBag = attrs?.style;
109
110
  const text = t(attrs?.textLocalizationKey);
110
- const textStyle = useExtractTextStyle(node);
111
+ const textStyle = useExtractTextStyle(node, true);
111
112
  const viewStyle = useExtractViewStyle(node);
112
113
 
113
- const linkStyle = (color?: string): React.CSSProperties => ({
114
- color,
115
- cursor: color ? 'pointer' : undefined,
116
- });
117
-
118
- const paddingHorizontal = parseSize(styleBag?.paddingHorizontal);
119
- const layoutStyle = useMemo<React.CSSProperties>(
120
- () => ({
121
- paddingLeft: paddingHorizontal,
122
- paddingRight: paddingHorizontal,
123
- textAlign: 'center',
124
- }),
125
- [paddingHorizontal],
114
+ // Parse colors for linked words
115
+ const parsedFirstColor = useMemo(
116
+ () =>
117
+ parseColor(attrs?.linkedWordFirstColor, {
118
+ projectColors,
119
+ theme,
120
+ }),
121
+ [attrs?.linkedWordFirstColor, projectColors, theme],
122
+ );
123
+ const parsedSecondColor = useMemo(
124
+ () =>
125
+ parseColor(attrs?.linkedWordSecondColor, {
126
+ projectColors,
127
+ theme,
128
+ }),
129
+ [attrs?.linkedWordSecondColor, projectColors, theme],
126
130
  );
127
131
 
132
+ const mergedTextStyle = useMergedStyle(textStyle, {
133
+ cursor: 'pointer',
134
+ });
128
135
  const isSelected = isNodeSelected({
129
136
  previewMode: !!previewMode,
130
137
  current: selectedKey ? { key: selectedKey } : undefined,
131
138
  node,
132
139
  });
133
- const baseStyle = useMergedStyle(viewStyle, textStyle);
134
- const paddedStyle = useMergedStyle(baseStyle, layoutStyle);
140
+ const mergedViewStyle = useMergedStyle(
141
+ viewStyle,
142
+ isSelected ? SELECTED_OUTLINE_STYLE : undefined,
143
+ );
135
144
  const generatedId = useId();
136
145
  const attributeKey = node.key ?? generatedId;
146
+
137
147
  return (
138
148
  <div
139
149
  attribute-name={attributeName}
140
150
  attribute-key={attributeKey}
141
- className={isSelected ? 'rb-node-selected' : undefined}
142
- style={paddedStyle}
151
+ style={mergedViewStyle}
143
152
  >
144
153
  {!!text &&
145
154
  (() => {
@@ -148,57 +157,60 @@ function OnboardFooter({ node }: OnboardFooterComponentProps) {
148
157
  const { segments, matchCount } = buildSegments(text, [
149
158
  {
150
159
  value: firstText,
151
- color: attrs?.linkedWordFirstColor,
152
- page: (attrs as any)?.linkedWordFirstPage,
160
+ color: parsedFirstColor,
161
+ page: attrs?.linkedWordFirstPage,
153
162
  },
154
163
  {
155
164
  value: secondText,
156
- color: attrs?.linkedWordSecondColor,
157
- page: (attrs as any)?.linkedWordSecondPage,
165
+ color: parsedSecondColor,
166
+ page: attrs?.linkedWordSecondPage,
158
167
  },
159
168
  ]);
160
169
 
161
- const textColor = styleBag?.color;
162
-
163
170
  const handleClick = (page?: string) => {
164
171
  if (!page) return;
165
172
  };
166
173
 
167
174
  return (
168
175
  <>
169
- <p style={{ color: textColor, alignItems: 'center' }}>
170
- {segments.map((seg, i) =>
171
- seg.type === 'text' ? (
172
- <span key={i}>{seg.value}</span>
173
- ) : (
174
- <span
175
- key={i}
176
- style={linkStyle(seg.color)}
177
- onClick={() => handleClick(seg.page)}
178
- >
179
- {seg.value}
180
- </span>
181
- ),
182
- )}
183
- </p>
176
+ {segments.map((seg, i) =>
177
+ seg.type === 'text' ? (
178
+ <span key={i} style={mergedTextStyle}>
179
+ {seg.value}
180
+ </span>
181
+ ) : (
182
+ <span
183
+ key={i}
184
+ style={{
185
+ ...mergedTextStyle,
186
+ color: seg.color,
187
+ }}
188
+ onClick={() => handleClick(seg.page)}
189
+ >
190
+ {seg.value}
191
+ </span>
192
+ ),
193
+ )}
184
194
  {matchCount === 0 && (
185
195
  <div>
186
196
  {attrs?.linkedWordFirstLocalizationKey && (
187
197
  <span
188
- style={linkStyle(attrs?.linkedWordFirstColor)}
189
- onClick={() =>
190
- handleClick((attrs as any)?.linkedWordFirstPage)
191
- }
198
+ style={{
199
+ ...mergedTextStyle,
200
+ color: parsedFirstColor,
201
+ }}
202
+ onClick={() => handleClick(attrs?.linkedWordFirstPage)}
192
203
  >
193
204
  {firstText}
194
205
  </span>
195
206
  )}
196
207
  {attrs?.linkedWordSecondLocalizationKey && (
197
208
  <span
198
- style={linkStyle(attrs?.linkedWordSecondColor)}
199
- onClick={() =>
200
- handleClick((attrs as any)?.linkedWordSecondPage)
201
- }
209
+ style={{
210
+ ...mergedTextStyle,
211
+ color: parsedSecondColor,
212
+ }}
213
+ onClick={() => handleClick(attrs?.linkedWordSecondPage)}
202
214
  >
203
215
  {secondText}
204
216
  </span>
@@ -4,6 +4,7 @@ import type { NodeData } from '../../types/Node';
4
4
 
5
5
  export type TextAlignOptionType = 'left' | 'center' | 'right' | 'justify';
6
6
  export type FlexDirectionOptionType = 'row' | 'column';
7
+ export type FlexWrapOptionType = 'nowrap' | 'wrap' | 'wrap-reverse';
7
8
  export type AlignItemsOptionType =
8
9
  | 'flex-start'
9
10
  | 'center'
@@ -26,6 +27,7 @@ export interface OnboardFooterStyleGenerated {
26
27
  fontWeight?: string;
27
28
  textAlign?: TextAlignOptionType;
28
29
  flexDirection?: FlexDirectionOptionType;
30
+ flexWrap?: FlexWrapOptionType;
29
31
  alignItems?: AlignItemsOptionType;
30
32
  justifyContent?: JustifyContentOptionType;
31
33
  gap?: string;
@@ -18,13 +18,16 @@
18
18
  },
19
19
  "defaults": {
20
20
  "style": {
21
+ "flexDirection": "row",
22
+ "flexWrap": "wrap",
23
+ "alignItems": "center",
24
+ "justifyContent": "center",
25
+ "textAlign": "center",
21
26
  "paddingHorizontal": "24@s"
22
27
  }
23
28
  },
24
29
  "meta": {
25
- "desiredParent": [
26
- ">OnboardItem"
27
- ],
30
+ "desiredParent": [">OnboardItem"],
28
31
  "label": "Onboard Footer",
29
32
  "description": "Footer text with optional links.",
30
33
  "styles": {
@@ -4,6 +4,7 @@ import type { NodeData } from '../../types/Node';
4
4
 
5
5
  export type ResizeModeOptionType = 'cover' | 'contain' | 'stretch' | 'center';
6
6
  export type FlexDirectionOptionType = 'row' | 'column';
7
+ export type FlexWrapOptionType = 'nowrap' | 'wrap' | 'wrap-reverse';
7
8
  export type AlignItemsOptionType =
8
9
  | 'flex-start'
9
10
  | 'center'
@@ -21,6 +22,7 @@ export type PositionOptionType = 'relative' | 'absolute';
21
22
 
22
23
  export interface OnboardImageStyleGenerated {
23
24
  flexDirection?: FlexDirectionOptionType;
25
+ flexWrap?: FlexWrapOptionType;
24
26
  alignItems?: AlignItemsOptionType;
25
27
  justifyContent?: JustifyContentOptionType;
26
28
  gap?: string;
@@ -12,11 +12,7 @@
12
12
  }
13
13
  },
14
14
  "meta": {
15
- "desiredParent": [
16
- ">OnboardProvider",
17
- ">OnboardItem",
18
- "!=Onboard"
19
- ],
15
+ "desiredParent": [">OnboardProvider", ">OnboardItem", "!=Onboard"],
20
16
  "label": "Onboard Image",
21
17
  "description": "Onboarding hero image with media.",
22
18
  "styles": {},
@@ -4,6 +4,7 @@ import type { NodeData } from '../../types/Node';
4
4
 
5
5
  export type DisplayOptionType = 'flex' | 'block';
6
6
  export type FlexDirectionOptionType = 'row' | 'column';
7
+ export type FlexWrapOptionType = 'nowrap' | 'wrap' | 'wrap-reverse';
7
8
  export type AlignItemsOptionType =
8
9
  | 'flex-start'
9
10
  | 'center'
@@ -21,6 +22,7 @@ export type PositionOptionType = 'relative' | 'absolute';
21
22
 
22
23
  export interface OnboardItemStyleGenerated {
23
24
  flexDirection?: FlexDirectionOptionType;
25
+ flexWrap?: FlexWrapOptionType;
24
26
  alignItems?: AlignItemsOptionType;
25
27
  justifyContent?: JustifyContentOptionType;
26
28
  gap?: string;
@@ -7,15 +7,9 @@
7
7
  "attributes": {
8
8
  "title": "title",
9
9
  "description": "description",
10
- "display": [
11
- "flex",
12
- "block"
13
- ],
10
+ "display": ["flex", "block"],
14
11
  "gap": "size",
15
- "flexDirection": [
16
- "row",
17
- "column"
18
- ],
12
+ "flexDirection": ["row", "column"],
19
13
  "paddingHorizontal": "size"
20
14
  }
21
15
  },
@@ -28,9 +22,7 @@
28
22
  }
29
23
  },
30
24
  "meta": {
31
- "desiredParent": [
32
- "=Onboard"
33
- ],
25
+ "desiredParent": ["=Onboard"],
34
26
  "label": "Onboard Item",
35
27
  "description": "Single onboarding screen section.",
36
28
  "styles": {},
@@ -4,6 +4,7 @@ import type { NodeData } from '../../types/Node';
4
4
 
5
5
  export type ThemeOptionType = 'light' | 'dark' | 'all';
6
6
  export type FlexDirectionOptionType = 'row' | 'column';
7
+ export type FlexWrapOptionType = 'nowrap' | 'wrap' | 'wrap-reverse';
7
8
  export type AlignItemsOptionType =
8
9
  | 'flex-start'
9
10
  | 'center'
@@ -21,6 +22,7 @@ export type PositionOptionType = 'relative' | 'absolute';
21
22
 
22
23
  export interface OnboardProviderStyleGenerated {
23
24
  flexDirection?: FlexDirectionOptionType;
25
+ flexWrap?: FlexWrapOptionType;
24
26
  alignItems?: AlignItemsOptionType;
25
27
  justifyContent?: JustifyContentOptionType;
26
28
  gap?: string;
@@ -7,11 +7,7 @@
7
7
  "attributes": {
8
8
  "title": "title",
9
9
  "description": "description",
10
- "theme": [
11
- "light",
12
- "dark",
13
- "all"
14
- ],
10
+ "theme": ["light", "dark", "all"],
15
11
  "borderRadius": "never"
16
12
  }
17
13
  },
@@ -22,9 +18,7 @@
22
18
  }
23
19
  },
24
20
  "meta": {
25
- "desiredParent": [
26
- "root"
27
- ],
21
+ "desiredParent": ["root"],
28
22
  "label": "Onboard Provider",
29
23
  "description": "Provides shared settings for onboarding.",
30
24
  "styles": {},
@@ -4,6 +4,7 @@ import type { NodeData } from '../../types/Node';
4
4
 
5
5
  export type TextAlignOptionType = 'left' | 'center' | 'right' | 'justify';
6
6
  export type FlexDirectionOptionType = 'row' | 'column';
7
+ export type FlexWrapOptionType = 'nowrap' | 'wrap' | 'wrap-reverse';
7
8
  export type AlignItemsOptionType =
8
9
  | 'flex-start'
9
10
  | 'center'
@@ -26,6 +27,7 @@ export interface OnboardSubtitleStyleGenerated {
26
27
  fontWeight?: string;
27
28
  textAlign?: TextAlignOptionType;
28
29
  flexDirection?: FlexDirectionOptionType;
30
+ flexWrap?: FlexWrapOptionType;
29
31
  alignItems?: AlignItemsOptionType;
30
32
  justifyContent?: JustifyContentOptionType;
31
33
  gap?: string;
@@ -16,10 +16,7 @@
16
16
  }
17
17
  },
18
18
  "meta": {
19
- "desiredParent": [
20
- ">OnboardProvider",
21
- ">OnboardItem"
22
- ],
19
+ "desiredParent": [">OnboardProvider", ">OnboardItem"],
23
20
  "label": "Onboard Subtitle",
24
21
  "description": "Subtitle text for an onboarding step.",
25
22
  "styles": {}
@@ -4,6 +4,7 @@ import type { NodeData } from '../../types/Node';
4
4
 
5
5
  export type TextAlignOptionType = 'left' | 'center' | 'right' | 'justify';
6
6
  export type FlexDirectionOptionType = 'row' | 'column';
7
+ export type FlexWrapOptionType = 'nowrap' | 'wrap' | 'wrap-reverse';
7
8
  export type AlignItemsOptionType =
8
9
  | 'flex-start'
9
10
  | 'center'
@@ -26,6 +27,7 @@ export interface OnboardTitleStyleGenerated {
26
27
  fontWeight?: string;
27
28
  textAlign?: TextAlignOptionType;
28
29
  flexDirection?: FlexDirectionOptionType;
30
+ flexWrap?: FlexWrapOptionType;
29
31
  alignItems?: AlignItemsOptionType;
30
32
  justifyContent?: JustifyContentOptionType;
31
33
  gap?: string;
@@ -17,10 +17,7 @@
17
17
  }
18
18
  },
19
19
  "meta": {
20
- "desiredParent": [
21
- ">OnboardItem",
22
- ">OnboardProvider"
23
- ],
20
+ "desiredParent": [">OnboardItem", ">OnboardProvider"],
24
21
  "label": "Onboard Title",
25
22
  "description": "Title text for an onboarding step.",
26
23
  "styles": {}