@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
@@ -1,10 +1,15 @@
1
- import React, { useContext, useEffect, useId, useState } from 'react';
1
+ import React, { useContext, useEffect, useId, useMemo, useState } from 'react';
2
2
  import type { CarouselDotsComponentProps } from './CarouselDotsProps.generated';
3
3
  import { carouselContext } from '../CarouselProvider/CarouselProvider';
4
4
  import { onboardContext } from '../OnboardProvider/OnboardProvider';
5
5
  import useNode from '../useNode';
6
6
  import { useLogRender } from '../../utils/useLogRender';
7
7
  import { useExtractViewStyle } from '../../attribute-analyser/style/web/useExtractViewStyle';
8
+ import { useMergedStyle } from '../../utils/useMergedStyle';
9
+ import { parseColor } from '../../utils/parseColor';
10
+ import { parseSize } from '../../size-matters';
11
+ import { useBuilderParams } from '../../components/BuilderProvider';
12
+ import { defaultAppConfig } from '../../types/PreviewConfig';
8
13
 
9
14
  function CarouselDots({ node }: CarouselDotsComponentProps) {
10
15
  useLogRender('CarouselDots');
@@ -15,7 +20,13 @@ function CarouselDots({ node }: CarouselDotsComponentProps) {
15
20
  const attributeName = node.sourceType ?? node.type ?? 'carouselDots';
16
21
  const attributeKey = node.key ?? generatedId;
17
22
 
18
- const dotType = node.attributes?.dotType ?? 'normal_dot';
23
+ const attrsAny = node.attributes as any;
24
+ const stylesBag =
25
+ (attrsAny?.styles as Record<string, unknown> | undefined) ??
26
+ (attrsAny?.style as Record<string, unknown> | undefined) ??
27
+ undefined;
28
+ const dotType =
29
+ (stylesBag?.dotType as any) ?? (attrsAny?.dotType as any) ?? 'normal_dot';
19
30
  const style = useExtractViewStyle(node);
20
31
 
21
32
  // Use the appropriate context based on sourceType
@@ -24,6 +35,71 @@ function CarouselDots({ node }: CarouselDotsComponentProps) {
24
35
  const onboardApi = useContext(onboardContext);
25
36
  const emblaApi = isOnboard ? onboardApi?.emblaApi : carouselApi;
26
37
 
38
+ // When used as OnboardDot (sourceType), support OnboardDot-specific attributes too.
39
+ const GHOST_DOT_DARK_COLOR = '#E4E5E7';
40
+ const GHOST_DOT_LIGHT_COLOR = '#F7F7F9';
41
+ const inactiveDotOpacity =
42
+ (stylesBag?.inactive_dot_opacity as number | undefined) ??
43
+ attrsAny?.inactive_dot_opacity ??
44
+ 0.3;
45
+ const inactiveDotColorOverride =
46
+ (stylesBag?.inactive_dot_color as string | undefined) ??
47
+ attrsAny?.inactive_dot_color;
48
+ const activeDotColor =
49
+ (stylesBag?.active_dot_color as string | undefined) ??
50
+ attrsAny?.active_dot_color;
51
+ const dotThicknessRaw =
52
+ (stylesBag?.dot_thickness as any) ?? attrsAny?.dot_thickness;
53
+
54
+ const { appConfig: builderAppConfig, projectColors } = useBuilderParams();
55
+ const appConfig = builderAppConfig ?? defaultAppConfig;
56
+ const isDark = appConfig.theme === 'dark';
57
+ const inactiveDotColorBase = isDark
58
+ ? GHOST_DOT_DARK_COLOR
59
+ : GHOST_DOT_LIGHT_COLOR;
60
+
61
+ const resolvedActiveDotColor = useMemo(
62
+ () => parseColor(activeDotColor, { theme: appConfig.theme, projectColors }),
63
+ [activeDotColor, appConfig.theme, projectColors],
64
+ );
65
+ const resolvedInactiveDotColor = useMemo(() => {
66
+ const parsed = parseColor(inactiveDotColorOverride, {
67
+ theme: appConfig.theme,
68
+ projectColors,
69
+ });
70
+ return parsed ?? inactiveDotColorBase;
71
+ }, [
72
+ inactiveDotColorBase,
73
+ inactiveDotColorOverride,
74
+ appConfig.theme,
75
+ projectColors,
76
+ ]);
77
+
78
+ const dotSizeCss = useMemo(() => {
79
+ const parsed = parseSize(dotThicknessRaw);
80
+ if (parsed === undefined) return '10px';
81
+ if (typeof parsed === 'number') return `${parsed}px`;
82
+ if (typeof parsed === 'string' && parsed.trim()) return parsed;
83
+ return '10px';
84
+ }, [dotThicknessRaw]);
85
+
86
+ const dotGapCss = useMemo((): string => {
87
+ const px =
88
+ typeof dotSizeCss === 'string' && dotSizeCss.trim().endsWith('px')
89
+ ? Number.parseFloat(dotSizeCss)
90
+ : Number.NaN;
91
+ const n = Number.isFinite(px) ? px : 10;
92
+ return `${Math.max(0, n / 3)}px`;
93
+ }, [dotSizeCss]);
94
+
95
+ const gapValue = (style as any)?.gap ?? dotGapCss;
96
+ const containerStyle = useMergedStyle(style, {
97
+ display: 'flex',
98
+ flexWrap: 'wrap',
99
+ gap: gapValue,
100
+ alignItems: 'center',
101
+ });
102
+
27
103
  const [selectedIndex, setSelectedIndex] = useState(0);
28
104
  const [scrollSnaps, setScrollSnaps] = useState<number[]>([]);
29
105
 
@@ -53,17 +129,41 @@ function CarouselDots({ node }: CarouselDotsComponentProps) {
53
129
  attribute-name={attributeName}
54
130
  attribute-key={attributeKey}
55
131
  className={`embla__dots embla__dots--${dotType}`}
56
- style={style}
132
+ style={containerStyle}
57
133
  >
58
- {scrollSnaps.map((snap, index) => (
59
- <button
60
- key={index}
61
- onClick={() => emblaApi?.scrollTo(snap)}
62
- className={`embla__dot ${selectedIndex === index ? 'embla__dot--selected' : ''}`}
63
- >
64
- {index === selectedIndex ? '●' : '○'}
65
- </button>
66
- ))}
134
+ {scrollSnaps.map((snap, index) => {
135
+ const isDotSelected = selectedIndex === index;
136
+ const dotSize = dotSizeCss;
137
+ const resolvedColor =
138
+ isDotSelected && resolvedActiveDotColor
139
+ ? resolvedActiveDotColor
140
+ : resolvedInactiveDotColor;
141
+ const activeFallback = '#007AFF';
142
+ const dotColor = resolvedColor ?? activeFallback;
143
+
144
+ return (
145
+ <button
146
+ key={index}
147
+ onClick={() => emblaApi?.scrollTo(snap)}
148
+ className="embla__dot"
149
+ style={{
150
+ width: dotSize,
151
+ height: dotSize,
152
+ backgroundColor: dotColor,
153
+ opacity: isDotSelected ? 1 : inactiveDotOpacity,
154
+ borderRadius: '9999px',
155
+ border: 0,
156
+ padding: 0,
157
+ margin: 0,
158
+ display: 'inline-block',
159
+ cursor: 'pointer',
160
+ boxSizing: 'border-box',
161
+ }}
162
+ aria-label={`Go to slide ${index + 1}`}
163
+ aria-current={isDotSelected ? 'true' : undefined}
164
+ />
165
+ );
166
+ })}
67
167
  </div>
68
168
  );
69
169
  }
@@ -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 CarouselDotsStyleGenerated {
29
30
  flexDirection?: FlexDirectionOptionType;
31
+ flexWrap?: FlexWrapOptionType;
30
32
  alignItems?: AlignItemsOptionType;
31
33
  justifyContent?: JustifyContentOptionType;
32
34
  gap?: string;
@@ -18,9 +18,7 @@
18
18
  }
19
19
  },
20
20
  "meta": {
21
- "desiredParent": [
22
- ">CarouselProvider"
23
- ],
21
+ "desiredParent": [">CarouselProvider"],
24
22
  "label": "Carousel Dots",
25
23
  "description": "Renders page indicator dots.",
26
24
  "styles": {
@@ -3,6 +3,7 @@
3
3
  import type { NodeData } from '../../types/Node';
4
4
 
5
5
  export type FlexDirectionOptionType = 'row' | 'column';
6
+ export type FlexWrapOptionType = 'nowrap' | 'wrap' | 'wrap-reverse';
6
7
  export type AlignItemsOptionType =
7
8
  | 'flex-start'
8
9
  | 'center'
@@ -20,6 +21,7 @@ export type PositionOptionType = 'relative' | 'absolute';
20
21
 
21
22
  export interface CarouselItemStyleGenerated {
22
23
  flexDirection?: FlexDirectionOptionType;
24
+ flexWrap?: FlexWrapOptionType;
23
25
  alignItems?: AlignItemsOptionType;
24
26
  justifyContent?: JustifyContentOptionType;
25
27
  gap?: string;
@@ -10,9 +10,7 @@
10
10
  }
11
11
  },
12
12
  "meta": {
13
- "desiredParent": [
14
- "=Carousel"
15
- ],
13
+ "desiredParent": ["=Carousel"],
16
14
  "label": "Carousel Item",
17
15
  "description": "Single slide inside a carousel.",
18
16
  "styles": {}
@@ -4,9 +4,8 @@ import RenderNode from '../RenderNode.generated';
4
4
  import useEmblaCarousel from 'embla-carousel-react';
5
5
  import useNode from '../useNode';
6
6
  import { useExtractViewStyle } from '../../attribute-analyser/style/web/useExtractViewStyle';
7
- import { isCarousel } from '../../utils/isCarousel';
8
- import type { Node, NodeData } from '../../types/Node';
9
7
 
8
+ //TODO: hızlıca carousel paywall ekelyebiliriz.
10
9
  export const carouselContext = createContext<any>(undefined);
11
10
  function CarouselProvider({ node }: CarouselProviderComponentProps) {
12
11
  node = useNode(node);
@@ -16,58 +15,20 @@ function CarouselProvider({ node }: CarouselProviderComponentProps) {
16
15
  const attributeKey = node.key ?? generatedId;
17
16
  const viewStyle = useExtractViewStyle(node);
18
17
 
19
- const { carouselChild, otherChildren } = useMemo(() => {
20
- const children = node.children as Node;
21
-
22
- if (!children) {
23
- return {
24
- carouselChild: null as NodeData | null,
25
- otherChildren: [] as Node[],
26
- };
27
- }
28
-
29
- if (Array.isArray(children)) {
30
- const idx = children.findIndex((c) => isCarousel(c));
31
- const carousel = idx >= 0 ? (children[idx] as NodeData) : null;
32
- const rest = idx >= 0 ? children.filter((_, i) => i !== idx) : children;
33
- return { carouselChild: carousel, otherChildren: rest };
34
- }
35
-
36
- if (isCarousel(children)) {
37
- return {
38
- carouselChild: children as NodeData,
39
- otherChildren: [] as Node[],
40
- };
41
- }
42
-
43
- // Non-carousel single child (e.g. dots/buttons): treat as "other" so we don't mount embla with an invalid DOM.
44
- return {
45
- carouselChild: null as NodeData | null,
46
- otherChildren: [children],
47
- };
48
- }, [node.children]);
49
-
50
18
  return (
51
19
  <carouselContext.Provider value={emblaApi}>
52
20
  <div
53
21
  attribute-name={attributeName}
54
22
  attribute-key={attributeKey}
55
23
  className="carousel-provider"
56
- style={viewStyle}
24
+ //NOTE: this feature is only for embla hack. On RN we use flatlist
25
+ style={{ ...viewStyle, display: 'block' }}
57
26
  >
58
27
  <div className="embla">
59
- <div
60
- className="embla__viewport"
61
- ref={carouselChild ? emblaRef : undefined}
62
- >
63
- {carouselChild ? <RenderNode node={carouselChild} /> : null}
28
+ <div className="embla__viewport" ref={emblaRef}>
29
+ {node.children && <RenderNode node={node.children} />}
64
30
  </div>
65
31
  </div>
66
- {otherChildren.length > 0
67
- ? otherChildren.map((child, index) => (
68
- <RenderNode key={index} node={child} />
69
- ))
70
- : null}
71
32
  </div>
72
33
  </carouselContext.Provider>
73
34
  );
@@ -3,6 +3,7 @@
3
3
  import type { NodeData } from '../../types/Node';
4
4
 
5
5
  export type FlexDirectionOptionType = 'row' | 'column';
6
+ export type FlexWrapOptionType = 'nowrap' | 'wrap' | 'wrap-reverse';
6
7
  export type AlignItemsOptionType =
7
8
  | 'flex-start'
8
9
  | 'center'
@@ -20,6 +21,7 @@ export type PositionOptionType = 'relative' | 'absolute';
20
21
 
21
22
  export interface CarouselProviderStyleGenerated {
22
23
  flexDirection?: FlexDirectionOptionType;
24
+ flexWrap?: FlexWrapOptionType;
23
25
  alignItems?: AlignItemsOptionType;
24
26
  justifyContent?: JustifyContentOptionType;
25
27
  gap?: string;
@@ -8,6 +8,12 @@
8
8
  "attributes": {
9
9
  "title": "title",
10
10
  "description": "description"
11
+ },
12
+ "defaults": {
13
+ "style": {
14
+ "width": "100%",
15
+ "height": "100%"
16
+ }
11
17
  }
12
18
  },
13
19
  "meta": {
@@ -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 CountDownStyleGenerated {
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;
@@ -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 CounterStyleGenerated {
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;
@@ -33,7 +33,7 @@ function Image({ node }: ImageComponentProps) {
33
33
  attribute-name={attributeName}
34
34
  attribute-key={attributeKey}
35
35
  src={resolveImageSrc(src)}
36
- style={style}
36
+ style={{ ...style, width: 'auto', maxWidth: '100%' }}
37
37
  alt=""
38
38
  />
39
39
  );
@@ -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 ImageStyleGenerated {
23
24
  flexDirection?: FlexDirectionOptionType;
25
+ flexWrap?: FlexWrapOptionType;
24
26
  alignItems?: AlignItemsOptionType;
25
27
  justifyContent?: JustifyContentOptionType;
26
28
  gap?: string;
@@ -3,6 +3,7 @@
3
3
  import type { NodeData } from '../../types/Node';
4
4
 
5
5
  export type FlexDirectionOptionType = 'row' | 'column';
6
+ export type FlexWrapOptionType = 'nowrap' | 'wrap' | 'wrap-reverse';
6
7
  export type AlignItemsOptionType =
7
8
  | 'flex-start'
8
9
  | 'center'
@@ -20,6 +21,7 @@ export type PositionOptionType = 'relative' | 'absolute';
20
21
 
21
22
  export interface MainStyleGenerated {
22
23
  flexDirection?: FlexDirectionOptionType;
24
+ flexWrap?: FlexWrapOptionType;
23
25
  alignItems?: AlignItemsOptionType;
24
26
  justifyContent?: JustifyContentOptionType;
25
27
  gap?: string;
@@ -20,9 +20,7 @@
20
20
  }
21
21
  },
22
22
  "meta": {
23
- "desiredParent": [
24
- "root"
25
- ],
23
+ "desiredParent": ["root"],
26
24
  "label": "Main",
27
25
  "description": "Top-level screen wrapper (safe area, base layout).",
28
26
  "hideAllAttributes": true,
@@ -3,6 +3,7 @@
3
3
  import type { NodeData } from '../../types/Node';
4
4
 
5
5
  export type FlexDirectionOptionType = 'row' | 'column';
6
+ export type FlexWrapOptionType = 'nowrap' | 'wrap' | 'wrap-reverse';
6
7
  export type AlignItemsOptionType =
7
8
  | 'flex-start'
8
9
  | 'center'
@@ -20,6 +21,7 @@ export type PositionOptionType = 'relative' | 'absolute';
20
21
 
21
22
  export interface OnboardStyleGenerated {
22
23
  flexDirection?: FlexDirectionOptionType;
24
+ flexWrap?: FlexWrapOptionType;
23
25
  alignItems?: AlignItemsOptionType;
24
26
  justifyContent?: JustifyContentOptionType;
25
27
  gap?: string;
@@ -10,12 +10,8 @@
10
10
  }
11
11
  },
12
12
  "meta": {
13
- "desiredParent": [
14
- "=OnboardProvider"
15
- ],
16
- "desiredChildren": [
17
- "=OnboardItem"
18
- ],
13
+ "desiredParent": ["=OnboardProvider"],
14
+ "desiredChildren": ["=OnboardItem"],
19
15
  "label": "Onboard",
20
16
  "description": "Wraps the onboarding flow.",
21
17
  "styles": {}
@@ -80,7 +80,6 @@ function OnboardButton({ node }: OnboardButtonComponentProps) {
80
80
  <button
81
81
  attribute-name={attributeName}
82
82
  attribute-key={attributeKey}
83
- className="onboard__button"
84
83
  onClick={handleClick}
85
84
  style={{
86
85
  ...viewStyle,
@@ -88,10 +87,7 @@ function OnboardButton({ node }: OnboardButtonComponentProps) {
88
87
  color: textColor,
89
88
  backgroundColor,
90
89
  border: 'none',
91
- borderRadius: 20,
92
- height: '100%',
93
90
  display: 'flex',
94
- alignItems: 'center',
95
91
  justifyContent: 'center',
96
92
  cursor: 'pointer',
97
93
  }}
@@ -11,6 +11,7 @@ export type AnimationOptionType =
11
11
  | 'blur-animation'
12
12
  | 'blur-line-animation';
13
13
  export type FlexDirectionOptionType = 'row' | 'column';
14
+ export type FlexWrapOptionType = 'nowrap' | 'wrap' | 'wrap-reverse';
14
15
  export type AlignItemsOptionType =
15
16
  | 'flex-start'
16
17
  | 'center'
@@ -35,6 +36,7 @@ export interface EventObjectGenerated {
35
36
 
36
37
  export interface OnboardButtonStyleGenerated {
37
38
  flexDirection?: FlexDirectionOptionType;
39
+ flexWrap?: FlexWrapOptionType;
38
40
  alignItems?: AlignItemsOptionType;
39
41
  justifyContent?: JustifyContentOptionType;
40
42
  gap?: string;
@@ -20,29 +20,24 @@
20
20
  "button_background_color": "color",
21
21
  "flex": "number",
22
22
  "events": "EventObject[]"
23
+ },
24
+ "defaults": {
25
+ "style": {
26
+ "height": "40@vs",
27
+ "borderRadius": "12@s"
28
+ }
23
29
  }
24
30
  },
25
31
  "types": {
26
32
  "EventObject": {
27
- "type": [
28
- "Permission",
29
- "Navigate"
30
- ],
31
- "permission": [
32
- "att",
33
- "notification",
34
- "rating",
35
- "GDPR",
36
- "null"
37
- ],
33
+ "type": ["Permission", "Navigate"],
34
+ "permission": ["att", "notification", "rating", "GDPR", "null"],
38
35
  "navigate_to": "string",
39
36
  "targetIndex": "number"
40
37
  }
41
38
  },
42
39
  "meta": {
43
- "desiredParent": [
44
- "=OnboardButtons"
45
- ],
40
+ "desiredParent": ["=OnboardButtons"],
46
41
  "label": "Onboard Button",
47
42
  "description": "Single action button for onboarding.",
48
43
  "styles": {
@@ -7,12 +7,14 @@ import useNode from '../useNode';
7
7
  import { useBuilderParams } from '../../components/BuilderProvider';
8
8
  import { useLogRender } from '../../utils/useLogRender';
9
9
  import { useExtractViewStyle } from '../../attribute-analyser/style/web/useExtractViewStyle';
10
+ import { isNodeSelected, SELECTED_OUTLINE_STYLE } from '../../utils/selection';
11
+ import { useMergedStyle } from '../../utils/useMergedStyle';
10
12
 
11
13
  function OnboardButtons({ node }: OnboardButtonsComponentProps) {
12
14
  useLogRender('OnboardButtons');
13
15
  node = useNode(node);
14
16
  const attributeName = node.sourceType ?? node.type ?? 'OnboardButtons';
15
- const { appConfig } = useBuilderParams();
17
+ const { appConfig, previewMode, selectedKey } = useBuilderParams();
16
18
  const seperatorColorDefault =
17
19
  appConfig?.theme === 'light'
18
20
  ? appConfig?.screenStyle?.light?.seperatorColor
@@ -35,14 +37,6 @@ function OnboardButtons({ node }: OnboardButtonsComponentProps) {
35
37
  'column'
36
38
  ? 'column'
37
39
  : 'row';
38
- const seperatorColor =
39
- attributes?.seperatorColor ??
40
- (styleBag as any)?.seperatorColor ??
41
- seperatorColorDefault;
42
- const buttonsClassName =
43
- direction === 'column'
44
- ? 'onboard__buttons onboard__buttons--column'
45
- : 'onboard__buttons onboard__buttons--row';
46
40
 
47
41
  const children = useMemo(() => {
48
42
  const raw = node.children as unknown;
@@ -52,7 +46,16 @@ function OnboardButtons({ node }: OnboardButtonsComponentProps) {
52
46
  return [raw as Node];
53
47
  }, [node.children]);
54
48
 
55
- const viewStyle = useExtractViewStyle(node);
49
+ const baseStyle = useExtractViewStyle(node);
50
+ const isSelected = isNodeSelected({
51
+ previewMode: !!previewMode,
52
+ current: selectedKey ? { key: selectedKey } : undefined,
53
+ node,
54
+ });
55
+ const viewStyle = useMergedStyle(
56
+ baseStyle,
57
+ isSelected ? SELECTED_OUTLINE_STYLE : undefined,
58
+ );
56
59
 
57
60
  // NOTE: Hooks must not be called conditionally.
58
61
  // Generate the id before any early returns so the hook order stays stable.
@@ -75,17 +78,11 @@ function OnboardButtons({ node }: OnboardButtonsComponentProps) {
75
78
  <div
76
79
  attribute-name={attributeName}
77
80
  attribute-key={node.key ?? generatedId}
78
- style={viewStyle}
81
+ style={{ ...viewStyle, boxSizing: 'border-box' }}
79
82
  >
80
- <div
81
- className="onboard__separator"
82
- style={seperatorColor ? { backgroundColor: seperatorColor } : undefined}
83
- />
84
- <div className={buttonsClassName}>
85
- {children.map((child, idx) => (
86
- <RenderNode key={(child as any)?.key ?? idx} node={child} />
87
- ))}
88
- </div>
83
+ {children.map((child, idx) => (
84
+ <RenderNode key={(child as any)?.key ?? idx} node={child} />
85
+ ))}
89
86
  </div>
90
87
  );
91
88
  }
@@ -9,6 +9,7 @@ export type ButtonTypeOptionType =
9
9
  export type ButtonsDirectionOptionType = 'row' | 'column';
10
10
  export type ConditionOptionType = 'carousel-index';
11
11
  export type FlexDirectionOptionType = 'row' | 'column';
12
+ export type FlexWrapOptionType = 'nowrap' | 'wrap' | 'wrap-reverse';
12
13
  export type AlignItemsOptionType =
13
14
  | 'flex-start'
14
15
  | 'center'
@@ -26,6 +27,7 @@ export type PositionOptionType = 'relative' | 'absolute';
26
27
 
27
28
  export interface OnboardButtonsStyleGenerated {
28
29
  flexDirection?: FlexDirectionOptionType;
30
+ flexWrap?: FlexWrapOptionType;
29
31
  alignItems?: AlignItemsOptionType;
30
32
  justifyContent?: JustifyContentOptionType;
31
33
  gap?: string;
@@ -7,28 +7,28 @@
7
7
  "attributes": {
8
8
  "title": "title",
9
9
  "description": "description",
10
- "buttonType": [
11
- "previous_button",
12
- "next_button",
13
- "skip_button"
14
- ],
10
+ "buttonType": ["previous_button", "next_button", "skip_button"],
15
11
  "skipNumber": "number",
16
- "buttons_direction": [
17
- "row",
18
- "column"
19
- ],
12
+ "buttons_direction": ["row", "column"],
20
13
  "forIndex": "number",
21
14
  "seperatorColor": "color",
22
- "condition": [
23
- "carousel-index"
24
- ],
15
+ "condition": ["carousel-index"],
25
16
  "conditionVariable": "number"
17
+ },
18
+ "defaults": {
19
+ "style": {
20
+ "display": "flex",
21
+ "flexDirection": "row",
22
+ "gap": 12,
23
+ "alignItems": "center",
24
+ "justifyContent": "center",
25
+ "marginVertical": "12@vs",
26
+ "marginHorizontal": "24@s"
27
+ }
26
28
  }
27
29
  },
28
30
  "meta": {
29
- "desiredParent": [
30
- "=OnboardItem"
31
- ],
31
+ "desiredParent": ["=OnboardItem"],
32
32
  "label": "Onboard Buttons",
33
33
  "description": "Wrapper for onboarding button set.",
34
34
  "styles": {