@developer_tribe/react-builder 1.2.8 → 1.2.10

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 (192) hide show
  1. package/dist/AttributesEditor.d.ts +2 -11
  2. package/dist/attribute-analyser/style/native/useExtractImageStyle.d.ts +10 -0
  3. package/dist/attribute-analyser/style/native/useExtractTextStyle.d.ts +9 -0
  4. package/dist/attribute-analyser/style/native/useExtractViewStyle.d.ts +8 -0
  5. package/dist/attribute-analyser/style/web/useExtractImageStyle.d.ts +4 -0
  6. package/dist/attribute-analyser/style/web/useExtractTextStyle.d.ts +4 -0
  7. package/dist/attribute-analyser/style/web/useExtractViewStyle.d.ts +4 -0
  8. package/dist/attributes-editor/AttributesEditorFields.d.ts +18 -0
  9. package/dist/attributes-editor/AttributesEditorView.d.ts +4 -0
  10. package/dist/attributes-editor/attributesEditorModelTypes.d.ts +67 -0
  11. package/dist/attributes-editor/attributesEditorUtils.d.ts +19 -0
  12. package/dist/attributes-editor/useAttributesEditorModel.d.ts +2 -0
  13. package/dist/build-components/BIcon/BIconProps.generated.d.ts +6 -6
  14. package/dist/build-components/BackgroundImage/BackgroundImageProps.generated.d.ts +3 -3
  15. package/dist/build-components/Button/ButtonProps.generated.d.ts +1 -1
  16. package/dist/build-components/Carousel/CarouselProps.generated.d.ts +2 -2
  17. package/dist/build-components/CarouselButtons/CarouselButtonsProps.generated.d.ts +4 -4
  18. package/dist/build-components/CarouselDots/CarouselDotsProps.generated.d.ts +3 -3
  19. package/dist/build-components/CarouselItem/CarouselItemProps.generated.d.ts +1 -1
  20. package/dist/build-components/CarouselProvider/CarouselProviderProps.generated.d.ts +1 -1
  21. package/dist/build-components/Image/ImageProps.generated.d.ts +5 -3
  22. package/dist/build-components/Main/MainProps.generated.d.ts +2 -2
  23. package/dist/build-components/Onboard/OnboardProps.generated.d.ts +1 -1
  24. package/dist/build-components/OnboardButton/OnboardButtonProps.generated.d.ts +9 -8
  25. package/dist/build-components/OnboardButtons/OnboardButtonsProps.generated.d.ts +11 -11
  26. package/dist/build-components/OnboardDot/OnboardDotProps.generated.d.ts +15 -9
  27. package/dist/build-components/OnboardFooter/OnboardFooterProps.generated.d.ts +10 -10
  28. package/dist/build-components/OnboardImage/OnboardImageProps.generated.d.ts +8 -6
  29. package/dist/build-components/OnboardItem/OnboardItemProps.generated.d.ts +6 -3
  30. package/dist/build-components/OnboardProvider/OnboardProviderProps.generated.d.ts +5 -4
  31. package/dist/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.d.ts +3 -3
  32. package/dist/build-components/OnboardTitle/OnboardTitleProps.generated.d.ts +3 -3
  33. package/dist/build-components/PaywallBackground/PaywallBackgroundProps.generated.d.ts +1 -1
  34. package/dist/build-components/PaywallCloseButton/PaywallCloseButtonProps.generated.d.ts +6 -6
  35. package/dist/build-components/PaywallOptions/PaywallOptionsProps.generated.d.ts +1 -1
  36. package/dist/build-components/PaywallProvider/PaywallProviderProps.generated.d.ts +1 -1
  37. package/dist/build-components/PaywallSubscribeButton/PaywallSubscribeButtonProps.generated.d.ts +1 -1
  38. package/dist/build-components/RadioButton/RadioButtonProps.generated.d.ts +4 -4
  39. package/dist/build-components/Text/TextProps.generated.d.ts +3 -3
  40. package/dist/build-components/View/ViewProps.generated.d.ts +1 -1
  41. package/dist/build-components/patterns.generated.d.ts +2690 -5804
  42. package/dist/index.cjs.js +5 -5
  43. package/dist/index.cjs.js.map +1 -1
  44. package/dist/index.d.ts +1 -0
  45. package/dist/index.esm.js +5 -5
  46. package/dist/index.esm.js.map +1 -1
  47. package/dist/index.native.cjs.js +6 -4
  48. package/dist/index.native.cjs.js.map +1 -1
  49. package/dist/index.native.d.ts +5 -6
  50. package/dist/index.native.esm.js +6 -4
  51. package/dist/index.native.esm.js.map +1 -1
  52. package/dist/migrations/migratePipe.d.ts +1 -1
  53. package/dist/migrations/migrations/1.1.2_extract_component_attributes_from_style.d.ts +2 -0
  54. package/dist/mockOS/components/PermissionModal.d.ts +1 -2
  55. package/dist/styles.css +1 -1
  56. package/dist/types/PreviewConfig.d.ts +1 -5
  57. package/dist/utils/getMeta.d.ts +5 -0
  58. package/dist/utils/patterns.d.ts +12 -0
  59. package/package.json +4 -2
  60. package/scripts/prebuild/prebuild.js +14 -0
  61. package/scripts/prebuild/utils/createGeneratedProps.js +19 -13
  62. package/scripts/prebuild/utils/index.js +1 -0
  63. package/scripts/prebuild/utils/updateMetaJson.js +66 -0
  64. package/scripts/prebuild/utils/validateAllComponentsOrThrow.js +37 -3
  65. package/scripts/prebuild/utils/validatePatternJson.js +27 -2
  66. package/scripts/public/scripts/build/index.js +20 -3
  67. package/scripts/public/scripts/build/info.json +6 -0
  68. package/scripts/public/scripts/build/utils/createComponentsIndex.js +9 -3
  69. package/scripts/public/scripts/build/utils/createRenderNodeGenerated.js +66 -8
  70. package/src/AttributesEditor.tsx +8 -944
  71. package/src/assets/meta.json +4 -0
  72. package/src/assets/samples/carousel-sample.json +1 -1
  73. package/src/assets/samples/getSamples.ts +2 -0
  74. package/src/assets/samples/paywall-1.json +11 -7
  75. package/src/assets/samples/simple-1.json +3 -3
  76. package/src/assets/samples/simple-2.json +3 -3
  77. package/src/assets/samples/unmigrated-builder-1.1.1.json +87 -0
  78. package/src/assets/samples/unmigrated-builder1.json +1 -1
  79. package/src/assets/samples/unvalidated-builder1.json +3 -3
  80. package/src/assets/samples/unvalidated-crash1.json +1 -1
  81. package/src/assets/samples/unvalidated-crashcomponent1.json +1 -1
  82. package/src/assets/samples/vpn-onboard-1.json +1 -1
  83. package/src/assets/samples/vpn-onboard-2.json +1 -1
  84. package/src/assets/samples/vpn-onboard-3.json +1 -1
  85. package/src/assets/samples/vpn-onboard-4.json +1 -1
  86. package/src/assets/samples/vpn-onboard-5.json +1 -1
  87. package/src/assets/samples/vpn-onboard-6.json +1 -1
  88. package/src/attribute-analyser/style/native/useExtractImageStyle.ts +46 -0
  89. package/src/attribute-analyser/style/native/useExtractTextStyle.ts +50 -0
  90. package/src/attribute-analyser/style/native/useExtractViewStyle.ts +32 -0
  91. package/src/attribute-analyser/style/web/useExtractImageStyle.ts +20 -0
  92. package/src/attribute-analyser/style/web/useExtractTextStyle.ts +27 -0
  93. package/src/attribute-analyser/style/web/useExtractViewStyle.ts +20 -0
  94. package/src/attributes-editor/AttributesEditorFields.tsx +248 -0
  95. package/src/attributes-editor/AttributesEditorView.tsx +360 -0
  96. package/src/attributes-editor/attributesEditorModelTypes.ts +86 -0
  97. package/src/attributes-editor/attributesEditorUtils.ts +102 -0
  98. package/src/attributes-editor/useAttributesEditorModel.ts +477 -0
  99. package/src/build-components/BIcon/BIcon.tsx +4 -4
  100. package/src/build-components/BIcon/BIconProps.generated.ts +6 -6
  101. package/src/build-components/BIcon/pattern.json +5 -6
  102. package/src/build-components/BackgroundImage/BackgroundImage.tsx +3 -2
  103. package/src/build-components/BackgroundImage/BackgroundImageProps.generated.ts +3 -3
  104. package/src/build-components/Button/Button.tsx +2 -2
  105. package/src/build-components/Button/ButtonProps.generated.ts +1 -1
  106. package/src/build-components/Button/pattern.json +17 -15
  107. package/src/build-components/Carousel/Carousel.tsx +1 -1
  108. package/src/build-components/Carousel/CarouselProps.generated.ts +2 -2
  109. package/src/build-components/CarouselButtons/CarouselButtons.tsx +4 -7
  110. package/src/build-components/CarouselButtons/CarouselButtonsProps.generated.ts +7 -7
  111. package/src/build-components/CarouselButtons/pattern.json +2 -1
  112. package/src/build-components/CarouselDots/CarouselDots.tsx +2 -2
  113. package/src/build-components/CarouselDots/CarouselDotsProps.generated.ts +9 -9
  114. package/src/build-components/CarouselItem/CarouselItem.tsx +1 -1
  115. package/src/build-components/CarouselItem/CarouselItemProps.generated.ts +1 -1
  116. package/src/build-components/CarouselProvider/CarouselProvider.tsx +1 -1
  117. package/src/build-components/CarouselProvider/CarouselProviderProps.generated.ts +1 -1
  118. package/src/build-components/Image/Image.tsx +1 -1
  119. package/src/build-components/Image/ImageProps.generated.ts +5 -3
  120. package/src/build-components/Image/pattern.json +10 -9
  121. package/src/build-components/Main/Main.tsx +2 -2
  122. package/src/build-components/Main/MainProps.generated.ts +2 -2
  123. package/src/build-components/Main/pattern.json +2 -1
  124. package/src/build-components/Onboard/OnboardProps.generated.ts +1 -1
  125. package/src/build-components/OnboardButton/OnboardButton.tsx +7 -6
  126. package/src/build-components/OnboardButton/OnboardButtonProps.generated.ts +14 -13
  127. package/src/build-components/OnboardButton/pattern.json +9 -7
  128. package/src/build-components/OnboardButtons/OnboardButtons.tsx +31 -31
  129. package/src/build-components/OnboardButtons/OnboardButtonsProps.generated.ts +14 -14
  130. package/src/build-components/OnboardButtons/pattern.json +9 -7
  131. package/src/build-components/OnboardDot/OnboardDot.tsx +7 -6
  132. package/src/build-components/OnboardDot/OnboardDotProps.generated.ts +26 -9
  133. package/src/build-components/OnboardFooter/OnboardFooter.tsx +17 -16
  134. package/src/build-components/OnboardFooter/OnboardFooterProps.generated.ts +10 -10
  135. package/src/build-components/OnboardFooter/pattern.json +16 -14
  136. package/src/build-components/OnboardImage/OnboardImage.tsx +8 -8
  137. package/src/build-components/OnboardImage/OnboardImageProps.generated.ts +8 -6
  138. package/src/build-components/OnboardImage/pattern.json +2 -1
  139. package/src/build-components/OnboardItem/OnboardItem.tsx +1 -1
  140. package/src/build-components/OnboardItem/OnboardItemProps.generated.ts +6 -3
  141. package/src/build-components/OnboardItem/pattern.json +2 -1
  142. package/src/build-components/OnboardProvider/OnboardProvider.tsx +1 -1
  143. package/src/build-components/OnboardProvider/OnboardProviderProps.generated.ts +5 -4
  144. package/src/build-components/OnboardProvider/pattern.json +2 -1
  145. package/src/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.ts +3 -3
  146. package/src/build-components/OnboardTitle/OnboardTitleProps.generated.ts +3 -3
  147. package/src/build-components/PaywallBackground/PaywallBackground.tsx +1 -1
  148. package/src/build-components/PaywallBackground/PaywallBackgroundProps.generated.ts +1 -1
  149. package/src/build-components/PaywallCloseButton/PaywallCloseButton.tsx +5 -4
  150. package/src/build-components/PaywallCloseButton/PaywallCloseButtonProps.generated.ts +6 -6
  151. package/src/build-components/PaywallOptions/PaywallOptionButton.tsx +1 -1
  152. package/src/build-components/PaywallOptions/PaywallOptionsProps.generated.ts +1 -1
  153. package/src/build-components/PaywallProvider/PaywallProvider.tsx +1 -1
  154. package/src/build-components/PaywallProvider/PaywallProviderProps.generated.ts +1 -1
  155. package/src/build-components/PaywallSubscribeButton/PaywallSubscribeButton.tsx +1 -1
  156. package/src/build-components/PaywallSubscribeButton/PaywallSubscribeButtonProps.generated.ts +1 -1
  157. package/src/build-components/RadioButton/RadioButton.tsx +5 -5
  158. package/src/build-components/RadioButton/RadioButtonProps.generated.ts +4 -4
  159. package/src/build-components/RadioButton/pattern.json +9 -7
  160. package/src/build-components/Text/Text.tsx +6 -6
  161. package/src/build-components/Text/TextProps.generated.ts +3 -3
  162. package/src/build-components/Text/pattern.json +15 -11
  163. package/src/build-components/View/View.tsx +1 -1
  164. package/src/build-components/View/ViewProps.generated.ts +1 -1
  165. package/src/build-components/View/pattern.json +71 -66
  166. package/src/build-components/patterns.generated.ts +3059 -6008
  167. package/src/components/AttributesEditorPanel.tsx +2 -2
  168. package/src/index.native.ts +6 -9
  169. package/src/index.ts +1 -0
  170. package/src/migrations/migratePipe.ts +7 -3
  171. package/src/migrations/migrations/1.1.2_extract_component_attributes_from_style.ts +211 -0
  172. package/src/mockOS/components/MockOSRouter.tsx +3 -1
  173. package/src/mockOS/components/PermissionModal.tsx +20 -160
  174. package/src/mockOS/components/SubscriptionModal.tsx +41 -278
  175. package/src/pages/ProjectPage.tsx +12 -6
  176. package/src/styles/components/_attributes-editor.scss +122 -0
  177. package/src/styles/components/_mockos-router.scss +388 -0
  178. package/src/styles/components/_onboard.scss +23 -0
  179. package/src/styles/index.scss +1 -0
  180. package/src/types/PreviewConfig.ts +1 -5
  181. package/src/utils/analyseNodeByPatterns.ts +39 -4
  182. package/src/utils/extractTextStyle/extractTextStyle.ts +4 -1
  183. package/src/utils/getMeta.ts +15 -0
  184. package/src/utils/patterns.ts +47 -4
  185. package/dist/hooks/useExtractImageStyle.d.ts +0 -5
  186. package/dist/hooks/useExtractTextStyle.d.ts +0 -3
  187. package/dist/hooks/useExtractViewStyle.d.ts +0 -3
  188. package/dist/migrations/migrations/1.1.0_normalize_style_attributes.d.ts +0 -2
  189. package/src/hooks/useExtractImageStyle.ts +0 -30
  190. package/src/hooks/useExtractTextStyle.ts +0 -34
  191. package/src/hooks/useExtractViewStyle.ts +0 -30
  192. package/src/migrations/migrations/1.1.0_normalize_style_attributes.ts +0 -80
@@ -40,355 +40,118 @@ export function SubscriptionModal({
40
40
  // Bottom sheet (both iOS + Android)
41
41
  return (
42
42
  <div
43
- style={{
44
- position: 'absolute',
45
- top: 0,
46
- left: 0,
47
- right: 0,
48
- bottom: 0,
49
- backgroundColor: isIOS ? 'rgba(0, 0, 0, 0.35)' : 'rgba(0, 0, 0, 0.5)',
50
- display: 'flex',
51
- alignItems: 'flex-end',
52
- justifyContent: 'stretch',
53
- zIndex: 9999,
54
- padding: 0,
55
- }}
43
+ className={[
44
+ 'mockos-modal-overlay',
45
+ 'mockos-modal-overlay--bottom',
46
+ isIOS ? 'mockos-modal-overlay--ios' : 'mockos-modal-overlay--android',
47
+ ].join(' ')}
56
48
  onClick={onOverlayClick}
57
49
  >
58
50
  <div
59
- style={{
60
- width: '100%',
61
- backgroundColor: isIOS
62
- ? 'hsl(var(--card, var(--rb-card, 0 0% 100%)) / 0.96)'
63
- : 'hsl(var(--card, var(--rb-card, 0 0% 100%)))',
64
- borderTopLeftRadius: 16,
65
- borderTopRightRadius: 16,
66
- overflow: 'hidden',
67
- backdropFilter: isIOS ? 'blur(20px)' : undefined,
68
- boxShadow: isIOS
69
- ? '0 -12px 30px rgba(0,0,0,0.18), 0 -2px 6px rgba(0,0,0,0.08)'
70
- : '0 -10px 20px rgba(0,0,0,0.22), 0 -2px 6px rgba(0,0,0,0.14)',
71
- paddingBottom: 'max(12px, env(safe-area-inset-bottom))',
72
- transform: 'translateY(0px)',
73
- }}
51
+ className={[
52
+ 'mockos-subscription-sheet',
53
+ isIOS
54
+ ? 'mockos-subscription-sheet--ios'
55
+ : 'mockos-subscription-sheet--android',
56
+ ].join(' ')}
74
57
  >
75
- <div
76
- aria-hidden
77
- style={{
78
- width: 44,
79
- height: 5,
80
- borderRadius: 999,
81
- background:
82
- 'hsl(var(--foreground, var(--rb-foreground, 220.9 39.3% 11%)) / 0.18)',
83
- margin: '10px auto 0',
84
- }}
85
- />
58
+ <div aria-hidden className="mockos-subscription-sheet__handle" />
86
59
 
87
60
  {isIOS ? (
88
- <div
89
- style={{
90
- padding: '10px 16px 10px',
91
- textAlign: 'center',
92
- }}
93
- >
94
- <div
95
- style={{
96
- display: 'flex',
97
- justifyContent: 'flex-end',
98
- marginBottom: 6,
99
- }}
100
- >
61
+ <div className="mockos-subscription-sheet__content mockos-subscription-sheet__content--ios">
62
+ <div className="mockos-subscription-sheet__top-actions">
101
63
  <button
102
64
  onClick={onCancel}
103
65
  aria-label="Close"
104
- style={{
105
- width: 28,
106
- height: 28,
107
- borderRadius: 999,
108
- border: 'none',
109
- background:
110
- 'hsl(var(--foreground, var(--rb-foreground, 220.9 39.3% 11%)) / 0.06)',
111
- color:
112
- 'hsl(var(--foreground, var(--rb-foreground, 220.9 39.3% 11%)) / 0.55)',
113
- fontSize: 18,
114
- lineHeight: '28px',
115
- cursor: 'pointer',
116
- }}
66
+ className="mockos-subscription-sheet__close"
117
67
  >
118
68
  ×
119
69
  </button>
120
70
  </div>
121
- <div
122
- style={{
123
- fontSize: 15,
124
- fontWeight: 600,
125
- color: '#000',
126
- marginBottom: 8,
127
- lineHeight: 1.3,
128
- letterSpacing: 0.2,
129
- }}
130
- >
71
+ <div className="mockos-subscription-sheet__title mockos-subscription-sheet__title--ios">
131
72
  Confirm with Apple ID
132
73
  </div>
133
- <div
134
- style={{
135
- fontSize: 13,
136
- color: '#000',
137
- lineHeight: 1.4,
138
- opacity: 0.6,
139
- }}
140
- >
74
+ <div className="mockos-subscription-sheet__subtitle mockos-subscription-sheet__subtitle--ios">
141
75
  Subscribe to <b>{titleFromProductId}</b>
142
76
  </div>
143
- <div
144
- style={{
145
- marginTop: 12,
146
- padding: '10px 12px',
147
- borderRadius: 12,
148
- background:
149
- 'hsl(var(--foreground, var(--rb-foreground, 220.9 39.3% 11%)) / 0.04)',
150
- textAlign: 'left',
151
- }}
152
- >
153
- <div
154
- style={{
155
- display: 'flex',
156
- alignItems: 'center',
157
- gap: 10,
158
- }}
159
- >
160
- <div
161
- aria-hidden
162
- style={{
163
- width: 38,
164
- height: 38,
165
- borderRadius: 10,
166
- background:
167
- 'linear-gradient(135deg, rgba(0,122,255,0.25), rgba(88,86,214,0.22))',
168
- border: '1px solid rgba(0,0,0,0.06)',
169
- }}
170
- />
171
- <div style={{ flex: 1, minWidth: 0 }}>
77
+ <div className="mockos-subscription-sheet__card mockos-subscription-sheet__card--ios">
78
+ <div className="mockos-subscription-sheet__row">
79
+ <div aria-hidden className="mockos-subscription-sheet__icon" />
80
+ <div className="mockos-subscription-sheet__meta">
172
81
  <div
173
- style={{
174
- fontSize: 14,
175
- fontWeight: 600,
176
- color: 'rgba(0,0,0,0.88)',
177
- lineHeight: 1.2,
178
- whiteSpace: 'nowrap',
179
- overflow: 'hidden',
180
- textOverflow: 'ellipsis',
181
- }}
82
+ className="mockos-subscription-sheet__product-id"
182
83
  title={productId}
183
84
  >
184
85
  {productId}
185
86
  </div>
186
- <div
187
- style={{
188
- marginTop: 2,
189
- fontSize: 12,
190
- color: 'rgba(0,0,0,0.55)',
191
- }}
192
- >
87
+ <div className="mockos-subscription-sheet__meta-subtitle">
193
88
  Renews automatically until cancelled.
194
89
  </div>
195
90
  </div>
196
- <div
197
- style={{
198
- fontSize: 13,
199
- fontWeight: 700,
200
- color: 'rgba(0,0,0,0.8)',
201
- }}
202
- >
203
- $4.99
204
- </div>
91
+ <div className="mockos-subscription-sheet__price">$4.99</div>
205
92
  </div>
206
93
  </div>
207
94
  </div>
208
95
  ) : (
209
- <div style={{ padding: '14px 16px 10px' }}>
210
- <div
211
- style={{
212
- display: 'flex',
213
- justifyContent: 'space-between',
214
- alignItems: 'center',
215
- gap: 12,
216
- }}
217
- >
218
- <div
219
- style={{
220
- fontSize: 16,
221
- fontWeight: 600,
222
- color: 'rgba(0,0,0,0.87)',
223
- }}
224
- >
96
+ <div className="mockos-subscription-sheet__content mockos-subscription-sheet__content--android">
97
+ <div className="mockos-subscription-sheet__android-header">
98
+ <div className="mockos-subscription-sheet__title mockos-subscription-sheet__title--android">
225
99
  Subscribe with Google Play
226
100
  </div>
227
101
  <button
228
102
  onClick={onCancel}
229
103
  aria-label="Close"
230
- style={{
231
- width: 28,
232
- height: 28,
233
- borderRadius: 999,
234
- border: 'none',
235
- background:
236
- 'hsl(var(--foreground, var(--rb-foreground, 220.9 39.3% 11%)) / 0.06)',
237
- color:
238
- 'hsl(var(--foreground, var(--rb-foreground, 220.9 39.3% 11%)) / 0.55)',
239
- fontSize: 18,
240
- lineHeight: '28px',
241
- cursor: 'pointer',
242
- }}
104
+ className="mockos-subscription-sheet__close"
243
105
  >
244
106
  ×
245
107
  </button>
246
108
  </div>
247
- <div
248
- style={{
249
- marginTop: 8,
250
- fontSize: 14,
251
- color: 'rgba(0, 0, 0, 0.6)',
252
- lineHeight: 1.5,
253
- }}
254
- >
109
+ <div className="mockos-subscription-sheet__subtitle mockos-subscription-sheet__subtitle--android">
255
110
  You’re about to subscribe to <b>{titleFromProductId}</b>.
256
111
  </div>
257
112
 
258
- <div
259
- style={{
260
- marginTop: 14,
261
- padding: '10px 12px',
262
- borderRadius: 10,
263
- background:
264
- 'hsl(var(--foreground, var(--rb-foreground, 220.9 39.3% 11%)) / 0.04)',
265
- border: '1px solid rgba(0,0,0,0.06)',
266
- }}
267
- >
268
- <div
269
- style={{
270
- display: 'flex',
271
- alignItems: 'center',
272
- justifyContent: 'space-between',
273
- gap: 10,
274
- }}
275
- >
276
- <div style={{ minWidth: 0 }}>
277
- <div
278
- style={{
279
- fontSize: 13,
280
- fontWeight: 600,
281
- color: 'rgba(0,0,0,0.78)',
282
- whiteSpace: 'nowrap',
283
- overflow: 'hidden',
284
- textOverflow: 'ellipsis',
285
- }}
286
- >
113
+ <div className="mockos-subscription-sheet__card mockos-subscription-sheet__card--android">
114
+ <div className="mockos-subscription-sheet__row mockos-subscription-sheet__row--space-between">
115
+ <div className="mockos-subscription-sheet__meta mockos-subscription-sheet__meta--android">
116
+ <div className="mockos-subscription-sheet__product-id">
287
117
  {productId}
288
118
  </div>
289
- <div
290
- style={{
291
- marginTop: 2,
292
- fontSize: 12,
293
- color: 'rgba(0,0,0,0.55)',
294
- }}
295
- >
119
+ <div className="mockos-subscription-sheet__meta-subtitle">
296
120
  Auto-renews • Cancel anytime in Play Store
297
121
  </div>
298
122
  </div>
299
- <div
300
- style={{
301
- fontSize: 13,
302
- fontWeight: 700,
303
- color: 'rgba(0,0,0,0.8)',
304
- }}
305
- >
306
- $4.99
307
- </div>
123
+ <div className="mockos-subscription-sheet__price">$4.99</div>
308
124
  </div>
309
125
  </div>
310
126
  </div>
311
127
  )}
312
128
 
313
129
  {isIOS ? (
314
- <div
315
- style={{
316
- borderTop: '0.5px solid rgba(0, 0, 0, 0.16)',
317
- display: 'flex',
318
- }}
319
- >
130
+ <div className="mockos-subscription-sheet__actions mockos-subscription-sheet__actions--ios">
320
131
  <button
321
132
  onClick={onCancel}
322
- style={{
323
- flex: 1,
324
- padding: '13px 0',
325
- fontSize: 17,
326
- fontWeight: 400,
327
- color: '#007AFF',
328
- background: 'transparent',
329
- border: 'none',
330
- borderRight: '0.5px solid rgba(0, 0, 0, 0.16)',
331
- cursor: 'pointer',
332
- }}
133
+ className="mockos-subscription-sheet__action mockos-subscription-sheet__action--ios"
333
134
  >
334
135
  Cancel
335
136
  </button>
336
137
  <button
337
138
  onClick={onBuy}
338
- style={{
339
- flex: 1,
340
- padding: '13px 0',
341
- fontSize: 17,
342
- fontWeight: 600,
343
- color: '#007AFF',
344
- background: 'transparent',
345
- border: 'none',
346
- cursor: 'pointer',
347
- }}
139
+ className="mockos-subscription-sheet__action mockos-subscription-sheet__action--ios mockos-subscription-sheet__action--bold"
348
140
  >
349
141
  Subscribe
350
142
  </button>
351
143
  </div>
352
144
  ) : (
353
- <div
354
- style={{
355
- padding: '10px 12px 12px',
356
- display: 'flex',
357
- justifyContent: 'flex-end',
358
- gap: 8,
359
- }}
360
- >
145
+ <div className="mockos-subscription-sheet__actions mockos-subscription-sheet__actions--android">
361
146
  <button
362
147
  onClick={onCancel}
363
- style={{
364
- padding: '10px 16px',
365
- fontSize: 14,
366
- fontWeight: 500,
367
- color: '#5F6368',
368
- background: 'transparent',
369
- border: 'none',
370
- borderRadius: 4,
371
- cursor: 'pointer',
372
- textTransform: 'uppercase',
373
- letterSpacing: 0.5,
374
- }}
148
+ className="mockos-subscription-sheet__action mockos-subscription-sheet__action--android mockos-subscription-sheet__action--cancel"
375
149
  >
376
150
  Cancel
377
151
  </button>
378
152
  <button
379
153
  onClick={onBuy}
380
- style={{
381
- padding: '10px 16px',
382
- fontSize: 14,
383
- fontWeight: 700,
384
- color: '#1A73E8',
385
- background: 'rgba(26,115,232,0.12)',
386
- border: 'none',
387
- borderRadius: 999,
388
- cursor: 'pointer',
389
- textTransform: 'uppercase',
390
- letterSpacing: 0.5,
391
- }}
154
+ className="mockos-subscription-sheet__action mockos-subscription-sheet__action--android mockos-subscription-sheet__action--primary"
392
155
  >
393
156
  Subscribe
394
157
  </button>
@@ -58,7 +58,7 @@ const MOBILE_BREAKPOINT = 1000;
58
58
 
59
59
  export function ProjectPage({
60
60
  project,
61
- appConfig = defaultAppConfig,
61
+ appConfig,
62
62
  onSaveProject,
63
63
  logLevel,
64
64
  projectColors,
@@ -84,6 +84,8 @@ export function ProjectPage({
84
84
  setCurrent,
85
85
  setProjectColors,
86
86
  setProjectName,
87
+ setAppConfig,
88
+ storeAppConfig,
87
89
  products,
88
90
  benefits,
89
91
  previewMode,
@@ -92,10 +94,13 @@ export function ProjectPage({
92
94
  setCurrent: s.setCurrent,
93
95
  setProjectColors: s.setProjectColors,
94
96
  setProjectName: s.setProjectName,
97
+ setAppConfig: s.setAppConfig,
98
+ storeAppConfig: s.appConfig,
95
99
  products: s.products,
96
100
  benefits: s.benefits,
97
101
  previewMode: s.previewMode,
98
102
  }));
103
+ const resolvedAppConfig = appConfig ?? storeAppConfig ?? defaultAppConfig;
99
104
  const [editorData, setEditorData] = useState<Node>(() => {
100
105
  if (!isEmptyProjectData) return null;
101
106
  // Empty project should start in a usable state (no loader / no error).
@@ -134,7 +139,6 @@ export function ProjectPage({
134
139
  return;
135
140
  }
136
141
  const updated: Node = deleteNodeFromTree(editorData, nodeToDelete);
137
- //@ts-ignore
138
142
  setEditorData(updated);
139
143
 
140
144
  if (current === nodeToDelete) {
@@ -157,12 +161,14 @@ export function ProjectPage({
157
161
 
158
162
  useEffect(() => {
159
163
  logger.info('ProjectPage', 'mount', { projectName: project.name });
160
- useRenderStore.getState().setAppConfig(appConfig);
161
- logger.verbose('ProjectPage', 'appConfig applied', appConfig);
164
+ if (appConfig) {
165
+ setAppConfig(appConfig);
166
+ logger.verbose('ProjectPage', 'appConfig applied', appConfig);
167
+ }
162
168
  return () => {
163
169
  logger.info('ProjectPage', 'unmount');
164
170
  };
165
- }, [appConfig, project.name]);
171
+ }, [appConfig, project.name, setAppConfig]);
166
172
 
167
173
  useEffect(() => {
168
174
  setProjectName(resolvedName);
@@ -474,7 +480,7 @@ export function ProjectPage({
474
480
  ? (benefits as PaywallBenefits)
475
481
  : {},
476
482
  // Theme/colors/fonts must be passed via BuilderProvider params so build-components never touch useRenderStore.
477
- appConfig,
483
+ appConfig: resolvedAppConfig,
478
484
  projectColors: resolvedProjectColors,
479
485
  fonts: typography.fonts,
480
486
  appFont: resolvedAppFont,
@@ -149,6 +149,128 @@
149
149
  padding: sizes.$spaceCompact 0;
150
150
  text-align: right;
151
151
  }
152
+
153
+ &__picker-button {
154
+ width: 100%;
155
+ display: flex;
156
+ align-items: center;
157
+ justify-content: space-between;
158
+ gap: sizes.$spaceCompact;
159
+ border-radius: sizes.$radiusMid;
160
+ border: sizes.$borderWidthHairline solid colors.$borderColor;
161
+ padding: sizes.$spaceSnug sizes.$spaceInset;
162
+ background: hsl(var(--card, var(--rb-card, 0 0% 100%)));
163
+ cursor: pointer;
164
+ }
165
+
166
+ &__picker-button-left {
167
+ display: flex;
168
+ align-items: center;
169
+ gap: sizes.$spaceCompact;
170
+ min-width: 0;
171
+ }
172
+
173
+ &__picker-button-label {
174
+ font-weight: 600;
175
+
176
+ &--fill {
177
+ flex: 1;
178
+ text-align: left;
179
+ overflow: hidden;
180
+ text-overflow: ellipsis;
181
+ white-space: nowrap;
182
+ }
183
+ }
184
+
185
+ &__picker-button-open {
186
+ font-size: sizes.$fontSizeSm;
187
+ color: colors.$mutedTextColor;
188
+ flex: 0 0 auto;
189
+ }
190
+
191
+ &__font-modal {
192
+ display: grid;
193
+ gap: sizes.$spaceComfy;
194
+ }
195
+
196
+ &__font-modal-header {
197
+ display: flex;
198
+ align-items: center;
199
+ gap: sizes.$spaceCompact;
200
+ }
201
+
202
+ &__font-modal-title {
203
+ margin: 0;
204
+ font-weight: 700;
205
+ }
206
+
207
+ &__font-modal-spacer {
208
+ flex: 1;
209
+ }
210
+
211
+ &__font-modal-note {
212
+ font-size: sizes.$fontSizeSm;
213
+ color: colors.$mutedTextColor;
214
+ }
215
+
216
+ &__font-modal-error {
217
+ font-size: sizes.$fontSizeSm;
218
+ color: colors.$dangerColor;
219
+ }
220
+
221
+ &__font-grid {
222
+ display: grid;
223
+ grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
224
+ gap: sizes.$spaceCompact;
225
+ max-height: 60vh;
226
+ overflow: auto;
227
+ padding-right: sizes.$spaceTight;
228
+ }
229
+
230
+ &__font-option {
231
+ display: flex;
232
+ align-items: center;
233
+ justify-content: space-between;
234
+ gap: sizes.$spaceCompact;
235
+ border-radius: sizes.$radiusRounded;
236
+ border: sizes.$borderWidthHairline solid colors.$borderColor;
237
+ padding: sizes.$spaceSnug sizes.$spaceInset;
238
+ background: hsl(var(--card, var(--rb-card, 0 0% 100%)));
239
+ cursor: pointer;
240
+
241
+ &:disabled {
242
+ opacity: 0.6;
243
+ cursor: not-allowed;
244
+ }
245
+
246
+ &--active {
247
+ border: 2px solid colors.$textColor;
248
+ }
249
+ }
250
+
251
+ &__font-option-name {
252
+ font-size: sizes.$fontSizeSm;
253
+ font-weight: 600;
254
+ text-align: left;
255
+ overflow: hidden;
256
+ text-overflow: ellipsis;
257
+ white-space: nowrap;
258
+ min-width: 0;
259
+ }
260
+
261
+ &__font-option--active &__font-option-name {
262
+ font-weight: 700;
263
+ }
264
+
265
+ &__font-option-status {
266
+ font-size: sizes.$fontSizeXs;
267
+ color: colors.$mutedTextColor;
268
+ flex: 0 0 auto;
269
+ }
270
+ }
271
+
272
+ .attributes-editor-panel {
273
+ padding: sizes.$spaceComfy;
152
274
  }
153
275
 
154
276
  .field-info-tooltip {