@developer_tribe/react-builder 1.0.4 → 1.0.5

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 (499) hide show
  1. package/README.md +6 -0
  2. package/dist/assets/samples/getSamples.d.ts +1 -0
  3. package/dist/background.jpg +0 -0
  4. package/dist/build-components/BIcon/BIcon.d.ts +5 -0
  5. package/dist/build-components/BIcon/BIconProps.generated.d.ts +55 -0
  6. package/dist/build-components/BackgroundImage/BackgroundImageProps.generated.d.ts +4 -0
  7. package/dist/build-components/Button/ButtonProps.generated.d.ts +4 -0
  8. package/dist/build-components/Carousel/CarouselProps.generated.d.ts +4 -0
  9. package/dist/build-components/CarouselButtons/CarouselButtonsProps.generated.d.ts +4 -0
  10. package/dist/build-components/CarouselDots/CarouselDotsProps.generated.d.ts +4 -0
  11. package/dist/build-components/CarouselItem/CarouselItemProps.generated.d.ts +4 -0
  12. package/dist/build-components/CarouselProvider/CarouselProviderProps.generated.d.ts +4 -0
  13. package/dist/build-components/Image/ImageProps.generated.d.ts +4 -0
  14. package/dist/build-components/Main/Main.d.ts +5 -0
  15. package/dist/build-components/Main/MainProps.generated.d.ts +48 -0
  16. package/dist/build-components/Onboard/OnboardProps.generated.d.ts +4 -0
  17. package/dist/build-components/OnboardButton/OnboardButtonProps.generated.d.ts +4 -0
  18. package/dist/build-components/OnboardButtons/OnboardButtonsProps.generated.d.ts +4 -0
  19. package/dist/build-components/OnboardDot/OnboardDotProps.generated.d.ts +4 -0
  20. package/dist/build-components/OnboardFooter/OnboardFooterProps.generated.d.ts +4 -0
  21. package/dist/build-components/OnboardImage/OnboardImageProps.generated.d.ts +4 -0
  22. package/dist/build-components/OnboardItem/OnboardItemProps.generated.d.ts +4 -0
  23. package/dist/build-components/OnboardProvider/OnboardProviderProps.generated.d.ts +4 -1
  24. package/dist/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.d.ts +4 -0
  25. package/dist/build-components/OnboardTitle/OnboardTitleProps.generated.d.ts +4 -0
  26. package/dist/build-components/PaywallBackground/PaywallBackground.d.ts +5 -0
  27. package/dist/build-components/PaywallBackground/PaywallBackgroundProps.generated.d.ts +47 -0
  28. package/dist/build-components/PaywallCloseButton/PaywallCloseButton.d.ts +5 -0
  29. package/dist/build-components/PaywallCloseButton/PaywallCloseButtonProps.generated.d.ts +56 -0
  30. package/dist/build-components/PaywallOptions/PaywallOptionButton.d.ts +9 -0
  31. package/dist/build-components/PaywallOptions/PaywallOptions.d.ts +5 -0
  32. package/dist/build-components/PaywallOptions/PaywallOptionsProps.generated.d.ts +47 -0
  33. package/dist/build-components/PaywallOptions/usePaywallOptionParamsFactory.d.ts +10 -0
  34. package/dist/build-components/PaywallProvider/PaywallProvider.d.ts +5 -0
  35. package/dist/build-components/PaywallProvider/PaywallProviderProps.generated.d.ts +47 -0
  36. package/dist/build-components/PaywallSubscriButton/PaywallSubscriButton.d.ts +5 -0
  37. package/dist/build-components/PaywallSubscriButton/PaywallSubscriButtonProps.generated.d.ts +50 -0
  38. package/dist/build-components/PaywallSubscribeButton/PaywallSubscribeButton.d.ts +5 -0
  39. package/dist/build-components/PaywallSubscribeButton/PaywallSubscribeButtonProps.generated.d.ts +50 -0
  40. package/dist/build-components/RadioButton/RadioButton.d.ts +11 -0
  41. package/dist/build-components/RadioButton/RadioButtonProps.generated.d.ts +50 -0
  42. package/dist/build-components/RenderNode.generated.d.ts +1 -1
  43. package/dist/build-components/Text/TextProps.generated.d.ts +4 -0
  44. package/dist/build-components/View/ViewProps.generated.d.ts +4 -0
  45. package/dist/build-components/index.d.ts +10 -1
  46. package/dist/build-components/patterns.generated.d.ts +4831 -661
  47. package/dist/components/AttributesEditorPanel.d.ts +2 -1
  48. package/dist/components/Builder.d.ts +1 -1
  49. package/dist/components/BuilderButton.d.ts +1 -1
  50. package/dist/components/BuilderProvider.d.ts +15 -0
  51. package/dist/components/EditorHeader.d.ts +1 -1
  52. package/dist/components/Icon.generated.d.ts +11 -0
  53. package/dist/components/LocalizationParamsProvider.d.ts +11 -0
  54. package/dist/components/ParamsProvider.d.ts +14 -0
  55. package/dist/hooks/useLocalizationParams.d.ts +1 -0
  56. package/dist/hooks/useLocalize.d.ts +2 -0
  57. package/dist/hooks/useParams.d.ts +1 -0
  58. package/dist/hooks/useSafeAreaViewStyle.d.ts +1 -0
  59. package/dist/index.cjs.js +5 -5
  60. package/dist/index.cjs.js.map +1 -1
  61. package/dist/index.d.ts +8 -0
  62. package/dist/index.esm.js +5 -5
  63. package/dist/index.esm.js.map +1 -1
  64. package/dist/index.native.cjs.js +29 -0
  65. package/dist/index.native.cjs.js.map +1 -0
  66. package/dist/index.native.d.ts +31 -0
  67. package/dist/index.native.esm.js +29 -0
  68. package/dist/index.native.esm.js.map +1 -0
  69. package/dist/mockOS/components/MockOSRouter.d.ts +1 -1
  70. package/dist/mockOS/context/MockOSContext.d.ts +4 -18
  71. package/dist/mockOS/context/MockOSContextBase.d.ts +21 -0
  72. package/dist/mockOS/index.d.ts +3 -2
  73. package/dist/modals/BenefitEditModal.d.ts +13 -0
  74. package/dist/modals/BenefitPresetsModal.d.ts +9 -0
  75. package/dist/modals/IconPickerModal.d.ts +9 -0
  76. package/dist/modals/MockableFeatureModal.d.ts +6 -0
  77. package/dist/modals/ProductEditModal.d.ts +9 -0
  78. package/dist/modals/ProductPresetsModal.d.ts +9 -0
  79. package/dist/modals/index.d.ts +6 -0
  80. package/dist/pages/ProjectPage.d.ts +3 -2
  81. package/dist/pages/tabs/BuilderPanel.d.ts +1 -1
  82. package/dist/pages/tabs/SideTool.d.ts +1 -1
  83. package/dist/paywall/hooks/index.d.ts +5 -0
  84. package/dist/paywall/hooks/useCalculateLocalizedPrice.d.ts +4 -0
  85. package/dist/paywall/hooks/useCarouselOptionsSeperator.d.ts +6 -0
  86. package/dist/paywall/hooks/useCloseStatusPaywall.d.ts +4 -0
  87. package/dist/paywall/hooks/useDiscountRate.d.ts +4 -0
  88. package/dist/paywall/hooks/usePaywallCounter.d.ts +4 -0
  89. package/dist/paywall/types/benefits.d.ts +14 -0
  90. package/dist/paywall/types/paywall-types.d.ts +43 -0
  91. package/dist/store.d.ts +29 -1
  92. package/dist/styles.css +1 -1
  93. package/dist/types/Icons.d.ts +2 -0
  94. package/dist/types/Project.d.ts +5 -0
  95. package/dist/utils/analyseNode.d.ts +1 -4
  96. package/dist/utils/analyseNodeByPatterns.d.ts +16 -0
  97. package/dist/utils/analyseNodeStructural.d.ts +11 -0
  98. package/dist/utils/findNodeByKeyNested.d.ts +2 -0
  99. package/dist/utils/nodeGuards.d.ts +5 -0
  100. package/dist/utils/novaToJson.d.ts +5 -0
  101. package/dist/utils/patterns.d.ts +14 -0
  102. package/dist/utils/replaceLocalizationParams.d.ts +1 -0
  103. package/package.json +33 -3
  104. package/scripts/prebuild/assets/icon.template +71 -0
  105. package/scripts/prebuild/build-components.js +5 -0
  106. package/scripts/prebuild/icon-generator.js +206 -0
  107. package/scripts/prebuild/prebuild.js +10 -1
  108. package/scripts/prebuild/utils/createComponentTsx.js +6 -3
  109. package/scripts/prebuild/utils/createGeneratedProps.js +4 -2
  110. package/scripts/prebuild/utils/createRenderNodeGenerated.js +43 -8
  111. package/scripts/prebuild/utils/validateAllComponentsOrThrow.js +20 -9
  112. package/scripts/prebuild/utils/validatePatternJson.js +3 -2
  113. package/src/AttributesEditor.tsx +178 -34
  114. package/src/DeviceMockFrame.tsx +41 -43
  115. package/src/RenderPage.tsx +8 -49
  116. package/src/assets/benefits.json +24 -0
  117. package/src/assets/iconset/activity-heart.svg +3 -0
  118. package/src/assets/iconset/activity.svg +3 -0
  119. package/src/assets/iconset/alert-circle.svg +3 -0
  120. package/src/assets/iconset/alert-triangle.svg +3 -0
  121. package/src/assets/iconset/anchor.svg +3 -0
  122. package/src/assets/iconset/archive.svg +3 -0
  123. package/src/assets/iconset/arrow-down.svg +3 -0
  124. package/src/assets/iconset/arrow-left.svg +3 -0
  125. package/src/assets/iconset/arrow-narrow-down-left.svg +3 -0
  126. package/src/assets/iconset/arrow-narrow-up-right.svg +3 -0
  127. package/src/assets/iconset/arrow-right-smooth.svg +4 -0
  128. package/src/assets/iconset/arrow-right.svg +7 -0
  129. package/src/assets/iconset/asterisk-01.svg +3 -0
  130. package/src/assets/iconset/asterisk-02.svg +3 -0
  131. package/src/assets/iconset/at-sign.svg +3 -0
  132. package/src/assets/iconset/award.svg +4 -0
  133. package/src/assets/iconset/battery-charging.svg +6 -0
  134. package/src/assets/iconset/bell-01.svg +5 -0
  135. package/src/assets/iconset/bell-02.svg +3 -0
  136. package/src/assets/iconset/bell-ringing-02.svg +3 -0
  137. package/src/assets/iconset/bookmark-add.svg +3 -0
  138. package/src/assets/iconset/bookmark-check.svg +3 -0
  139. package/src/assets/iconset/bookmark-minus.svg +3 -0
  140. package/src/assets/iconset/bookmark-x.svg +3 -0
  141. package/src/assets/iconset/bookmark.svg +3 -0
  142. package/src/assets/iconset/bubble.svg +5 -0
  143. package/src/assets/iconset/building-01.svg +3 -0
  144. package/src/assets/iconset/building-02.svg +3 -0
  145. package/src/assets/iconset/building-03.svg +3 -0
  146. package/src/assets/iconset/building-04.svg +3 -0
  147. package/src/assets/iconset/building-05.svg +3 -0
  148. package/src/assets/iconset/building-06.svg +3 -0
  149. package/src/assets/iconset/building-07.svg +3 -0
  150. package/src/assets/iconset/building-08.svg +3 -0
  151. package/src/assets/iconset/building-09.svg +3 -0
  152. package/src/assets/iconset/camera-01.svg +8 -0
  153. package/src/assets/iconset/camera-steel.svg +4 -0
  154. package/src/assets/iconset/camera.svg +4 -0
  155. package/src/assets/iconset/check-circle-bold.svg +3 -0
  156. package/src/assets/iconset/check-circle-broken.svg +3 -0
  157. package/src/assets/iconset/check-circle.svg +3 -0
  158. package/src/assets/iconset/check-done-01.svg +3 -0
  159. package/src/assets/iconset/check-done-02.svg +3 -0
  160. package/src/assets/iconset/check-heart.svg +3 -0
  161. package/src/assets/iconset/check-square-broken.svg +3 -0
  162. package/src/assets/iconset/check-square.svg +3 -0
  163. package/src/assets/iconset/check-verified-01.svg +3 -0
  164. package/src/assets/iconset/check-verified-02.svg +3 -0
  165. package/src/assets/iconset/check-verified-03.svg +3 -0
  166. package/src/assets/iconset/check.svg +3 -0
  167. package/src/assets/iconset/checkbox.svg +4 -0
  168. package/src/assets/iconset/checkv.svg +3 -0
  169. package/src/assets/iconset/chevron-down.svg +3 -0
  170. package/src/assets/iconset/chevron-down2.svg +3 -0
  171. package/src/assets/iconset/chevron-left-2.svg +3 -0
  172. package/src/assets/iconset/chevron-left.svg +3 -0
  173. package/src/assets/iconset/chevron-right-empty.svg +3 -0
  174. package/src/assets/iconset/chevron-right-smooth.svg +3 -0
  175. package/src/assets/iconset/chevron-right.svg +3 -0
  176. package/src/assets/iconset/chevron-up.svg +3 -0
  177. package/src/assets/iconset/circle.svg +32 -0
  178. package/src/assets/iconset/clock-fast-forward.svg +10 -0
  179. package/src/assets/iconset/clock.svg +3 -0
  180. package/src/assets/iconset/close-circle.svg +3 -0
  181. package/src/assets/iconset/close.svg +3 -0
  182. package/src/assets/iconset/cloud-01.svg +5 -0
  183. package/src/assets/iconset/cloud-blank-01.svg +3 -0
  184. package/src/assets/iconset/cloud-blank-02.svg +3 -0
  185. package/src/assets/iconset/coin.svg +5 -0
  186. package/src/assets/iconset/coins-02.svg +3 -0
  187. package/src/assets/iconset/colors.svg +3 -0
  188. package/src/assets/iconset/copy-01.svg +3 -0
  189. package/src/assets/iconset/copy-02.svg +3 -0
  190. package/src/assets/iconset/copy-03.svg +3 -0
  191. package/src/assets/iconset/copy-04.svg +3 -0
  192. package/src/assets/iconset/copy-05.svg +3 -0
  193. package/src/assets/iconset/copy-06.svg +3 -0
  194. package/src/assets/iconset/copy-07.svg +3 -0
  195. package/src/assets/iconset/corner-down-right.svg +3 -0
  196. package/src/assets/iconset/crypto-bold.svg +4 -0
  197. package/src/assets/iconset/delete-icon.svg +5 -0
  198. package/src/assets/iconset/diamond.svg +3 -0
  199. package/src/assets/iconset/dice-3.svg +3 -0
  200. package/src/assets/iconset/divide-01.svg +3 -0
  201. package/src/assets/iconset/divide-02.svg +3 -0
  202. package/src/assets/iconset/divide-03.svg +3 -0
  203. package/src/assets/iconset/document-check-bold.svg +4 -0
  204. package/src/assets/iconset/dots-circle.svg +10 -0
  205. package/src/assets/iconset/dots-grid.svg +11 -0
  206. package/src/assets/iconset/dots-horizontal.svg +5 -0
  207. package/src/assets/iconset/dots-vertical.svg +5 -0
  208. package/src/assets/iconset/download-01.svg +3 -0
  209. package/src/assets/iconset/download-02.svg +3 -0
  210. package/src/assets/iconset/download-03.svg +3 -0
  211. package/src/assets/iconset/edit-03.svg +3 -0
  212. package/src/assets/iconset/edit-04.svg +3 -0
  213. package/src/assets/iconset/edit-05.svg +3 -0
  214. package/src/assets/iconset/element-3.svg +6 -0
  215. package/src/assets/iconset/ellipse-127.svg +3 -0
  216. package/src/assets/iconset/exclaimation-circle.svg +8 -0
  217. package/src/assets/iconset/eye-off-line.svg +5 -0
  218. package/src/assets/iconset/face-smile.svg +5 -0
  219. package/src/assets/iconset/file-04.svg +3 -0
  220. package/src/assets/iconset/file-05.svg +3 -0
  221. package/src/assets/iconset/file-check-02.svg +3 -0
  222. package/src/assets/iconset/file-plus-01.svg +5 -0
  223. package/src/assets/iconset/file-shield-02.svg +5 -0
  224. package/src/assets/iconset/filter-funnel-01.svg +3 -0
  225. package/src/assets/iconset/flag-03.svg +3 -0
  226. package/src/assets/iconset/flash.svg +3 -0
  227. package/src/assets/iconset/folder-plus.svg +3 -0
  228. package/src/assets/iconset/folder.svg +3 -0
  229. package/src/assets/iconset/gallery.svg +3 -0
  230. package/src/assets/iconset/globe-01.svg +3 -0
  231. package/src/assets/iconset/globe-04.svg +5 -0
  232. package/src/assets/iconset/globe-bold.svg +4 -0
  233. package/src/assets/iconset/guard.svg +3 -0
  234. package/src/assets/iconset/headphones-01.svg +3 -0
  235. package/src/assets/iconset/headphones-02.svg +5 -0
  236. package/src/assets/iconset/headset-bold.svg +4 -0
  237. package/src/assets/iconset/heart-bold.svg +3 -0
  238. package/src/assets/iconset/heart.svg +3 -0
  239. package/src/assets/iconset/help-circle.svg +5 -0
  240. package/src/assets/iconset/home-2.svg +4 -0
  241. package/src/assets/iconset/home-line.svg +3 -0
  242. package/src/assets/iconset/hourglass-02.svg +5 -0
  243. package/src/assets/iconset/image-01.svg +5 -0
  244. package/src/assets/iconset/image-03.svg +3 -0
  245. package/src/assets/iconset/image.svg +4 -0
  246. package/src/assets/iconset/inbox-01.svg +3 -0
  247. package/src/assets/iconset/inbox-arrow-down.svg +3 -0
  248. package/src/assets/iconset/info-circle.svg +3 -0
  249. package/src/assets/iconset/keyboard-line.svg +9 -0
  250. package/src/assets/iconset/lamp-charge.svg +5 -0
  251. package/src/assets/iconset/layer.svg +3 -0
  252. package/src/assets/iconset/light.svg +6 -0
  253. package/src/assets/iconset/like-dislike.svg +6 -0
  254. package/src/assets/iconset/lock-03.svg +3 -0
  255. package/src/assets/iconset/logout.svg +3 -0
  256. package/src/assets/iconset/magicpen.svg +7 -0
  257. package/src/assets/iconset/mail-01.svg +5 -0
  258. package/src/assets/iconset/mail.svg +3 -0
  259. package/src/assets/iconset/marker.svg +3 -0
  260. package/src/assets/iconset/medal-star.svg +5 -0
  261. package/src/assets/iconset/menu-04.svg +3 -0
  262. package/src/assets/iconset/menu.svg +5 -0
  263. package/src/assets/iconset/message-circle-01.svg +5 -0
  264. package/src/assets/iconset/message-plus-circle.svg +3 -0
  265. package/src/assets/iconset/message-question-circle.svg +5 -0
  266. package/src/assets/iconset/message-text-circle-01.svg +5 -0
  267. package/src/assets/iconset/message-text-square-02.svg +3 -0
  268. package/src/assets/iconset/message-x-square.svg +3 -0
  269. package/src/assets/iconset/microphone-02.svg +3 -0
  270. package/src/assets/iconset/microphone-slash.svg +8 -0
  271. package/src/assets/iconset/mirror.svg +4 -0
  272. package/src/assets/iconset/moon-01.svg +3 -0
  273. package/src/assets/iconset/moon-bold.svg +3 -0
  274. package/src/assets/iconset/mouse-circle.svg +4 -0
  275. package/src/assets/iconset/move.svg +5 -0
  276. package/src/assets/iconset/notification-fill.svg +3 -0
  277. package/src/assets/iconset/notification-text.svg +3 -0
  278. package/src/assets/iconset/notification.svg +5 -0
  279. package/src/assets/iconset/pdf-01.svg +6 -0
  280. package/src/assets/iconset/pencil-01.svg +5 -0
  281. package/src/assets/iconset/phone-01.svg +3 -0
  282. package/src/assets/iconset/phone-arrow-down-left.svg +4 -0
  283. package/src/assets/iconset/phone-arrow-up-right.svg +8 -0
  284. package/src/assets/iconset/phone-hang-up.svg +5 -0
  285. package/src/assets/iconset/phone-hangup2.svg +8 -0
  286. package/src/assets/iconset/phone-incoming-01.svg +3 -0
  287. package/src/assets/iconset/phone-outgoing-01.svg +3 -0
  288. package/src/assets/iconset/phone-plus.svg +3 -0
  289. package/src/assets/iconset/phone-x.svg +3 -0
  290. package/src/assets/iconset/phone.svg +3 -0
  291. package/src/assets/iconset/plus-circle.svg +3 -0
  292. package/src/assets/iconset/plus.svg +4 -0
  293. package/src/assets/iconset/printer.svg +3 -0
  294. package/src/assets/iconset/question-mark-circle.svg +5 -0
  295. package/src/assets/iconset/refresh-ccw-01.svg +3 -0
  296. package/src/assets/iconset/refresh-cw-01.svg +3 -0
  297. package/src/assets/iconset/refresh-cw-04.svg +3 -0
  298. package/src/assets/iconset/refresh-right-square-bold.svg +3 -0
  299. package/src/assets/iconset/remove-circle.svg +12 -0
  300. package/src/assets/iconset/repeat-04.svg +3 -0
  301. package/src/assets/iconset/repeat-bold.svg +3 -0
  302. package/src/assets/iconset/ruler-pen.svg +4 -0
  303. package/src/assets/iconset/search-lg.svg +3 -0
  304. package/src/assets/iconset/search-md.svg +5 -0
  305. package/src/assets/iconset/search-refraction.svg +5 -0
  306. package/src/assets/iconset/search.svg +3 -0
  307. package/src/assets/iconset/send-01.svg +3 -0
  308. package/src/assets/iconset/send-02.svg +5 -0
  309. package/src/assets/iconset/send-diagonal.svg +3 -0
  310. package/src/assets/iconset/setting-2.svg +4 -0
  311. package/src/assets/iconset/settings-02.svg +4 -0
  312. package/src/assets/iconset/settings-04.svg +5 -0
  313. package/src/assets/iconset/settings-2.svg +4 -0
  314. package/src/assets/iconset/settings-cog.svg +3 -0
  315. package/src/assets/iconset/settings.svg +4 -0
  316. package/src/assets/iconset/share-01.svg +4 -0
  317. package/src/assets/iconset/share-03.svg +3 -0
  318. package/src/assets/iconset/share-04.svg +3 -0
  319. package/src/assets/iconset/share-05.svg +5 -0
  320. package/src/assets/iconset/share-06.svg +3 -0
  321. package/src/assets/iconset/share-bold.svg +3 -0
  322. package/src/assets/iconset/shield-01.svg +3 -0
  323. package/src/assets/iconset/shield-bold.svg +3 -0
  324. package/src/assets/iconset/solar-check.svg +3 -0
  325. package/src/assets/iconset/speaker-wave.svg +9 -0
  326. package/src/assets/iconset/speaker.svg +5 -0
  327. package/src/assets/iconset/speedometer-03.svg +3 -0
  328. package/src/assets/iconset/star-rounded.svg +3 -0
  329. package/src/assets/iconset/star.svg +3 -0
  330. package/src/assets/iconset/sun.svg +5 -0
  331. package/src/assets/iconset/target-03.svg +3 -0
  332. package/src/assets/iconset/text-input.svg +3 -0
  333. package/src/assets/iconset/translate.svg +7 -0
  334. package/src/assets/iconset/trash-02.svg +3 -0
  335. package/src/assets/iconset/trash-03.svg +5 -0
  336. package/src/assets/iconset/trash-04.svg +3 -0
  337. package/src/assets/iconset/trash.svg +7 -0
  338. package/src/assets/iconset/trush-square-bold.svg +3 -0
  339. package/src/assets/iconset/unlimited.svg +3 -0
  340. package/src/assets/iconset/user-circle.svg +3 -0
  341. package/src/assets/iconset/user-jogging.svg +3 -0
  342. package/src/assets/iconset/user-plus-01.svg +5 -0
  343. package/src/assets/iconset/user-square.svg +5 -0
  344. package/src/assets/iconset/user-x-01.svg +5 -0
  345. package/src/assets/iconset/user-x-02.svg +3 -0
  346. package/src/assets/iconset/user2.svg +3 -0
  347. package/src/assets/iconset/users-02.svg +5 -0
  348. package/src/assets/iconset/users-speaker.svg +7 -0
  349. package/src/assets/iconset/verify.svg +3 -0
  350. package/src/assets/iconset/voice-cricle.svg +8 -0
  351. package/src/assets/iconset/x-circle.svg +3 -0
  352. package/src/assets/iconset/x-close.svg +3 -0
  353. package/src/assets/iconset/x-sm.svg +3 -0
  354. package/src/assets/iconset/zap.svg +3 -0
  355. package/src/assets/images/background.jpg +0 -0
  356. package/src/assets/loading_animation.json +1 -0
  357. package/src/assets/products.json +98 -0
  358. package/src/assets/samples/carousel-sample.json +1 -0
  359. package/src/assets/samples/getSamples.ts +39 -66
  360. package/src/assets/samples/paywall-1.json +220 -0
  361. package/src/assets/samples/simple-1.json +1 -0
  362. package/src/assets/samples/simple-2.json +1 -0
  363. package/src/assets/samples/vpn-onboard-1.json +324 -720
  364. package/src/assets/samples/vpn-onboard-2.json +299 -683
  365. package/src/assets/samples/vpn-onboard-3.json +270 -680
  366. package/src/assets/samples/vpn-onboard-4.json +270 -681
  367. package/src/assets/samples/vpn-onboard-5.json +408 -893
  368. package/src/assets/samples/vpn-onboard-6.json +279 -594
  369. package/src/attributes-editor/SpecialCategorySection.tsx +1 -1
  370. package/src/build-components/BIcon/BIcon.tsx +56 -0
  371. package/src/build-components/BIcon/BIconProps.generated.ts +82 -0
  372. package/src/build-components/BIcon/pattern.json +47 -0
  373. package/src/build-components/BackgroundImage/BackgroundImageProps.generated.ts +4 -0
  374. package/src/build-components/BackgroundImage/pattern.json +2 -2
  375. package/src/build-components/Button/Button.tsx +14 -1
  376. package/src/build-components/Button/ButtonProps.generated.ts +4 -0
  377. package/src/build-components/Button/pattern.json +4 -1
  378. package/src/build-components/Carousel/CarouselProps.generated.ts +4 -0
  379. package/src/build-components/Carousel/pattern.json +2 -2
  380. package/src/build-components/CarouselButtons/CarouselButtonsProps.generated.ts +4 -0
  381. package/src/build-components/CarouselButtons/pattern.json +1 -1
  382. package/src/build-components/CarouselDots/CarouselDotsProps.generated.ts +4 -0
  383. package/src/build-components/CarouselDots/pattern.json +1 -1
  384. package/src/build-components/CarouselItem/CarouselItem.tsx +1 -1
  385. package/src/build-components/CarouselItem/CarouselItemProps.generated.ts +4 -0
  386. package/src/build-components/CarouselItem/pattern.json +1 -1
  387. package/src/build-components/CarouselProvider/CarouselProvider.tsx +1 -1
  388. package/src/build-components/CarouselProvider/CarouselProviderProps.generated.ts +4 -0
  389. package/src/build-components/CarouselProvider/pattern.json +1 -1
  390. package/src/build-components/Image/ImageProps.generated.ts +4 -0
  391. package/src/build-components/Image/pattern.json +1 -1
  392. package/src/build-components/Main/Main.tsx +61 -0
  393. package/src/build-components/Main/MainProps.generated.ts +64 -0
  394. package/src/build-components/Main/pattern.json +35 -0
  395. package/src/build-components/Onboard/OnboardProps.generated.ts +4 -0
  396. package/src/build-components/OnboardButton/OnboardButtonProps.generated.ts +4 -0
  397. package/src/build-components/OnboardButtons/OnboardButtonsProps.generated.ts +4 -0
  398. package/src/build-components/OnboardDot/OnboardDotProps.generated.ts +4 -0
  399. package/src/build-components/OnboardFooter/OnboardFooterProps.generated.ts +4 -0
  400. package/src/build-components/OnboardImage/OnboardImageProps.generated.ts +4 -0
  401. package/src/build-components/OnboardItem/OnboardItem.tsx +1 -1
  402. package/src/build-components/OnboardItem/OnboardItemProps.generated.ts +4 -0
  403. package/src/build-components/OnboardProvider/OnboardProviderProps.generated.ts +4 -1
  404. package/src/build-components/OnboardProvider/pattern.json +6 -16
  405. package/src/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.ts +4 -0
  406. package/src/build-components/OnboardTitle/OnboardTitleProps.generated.ts +4 -0
  407. package/src/build-components/PaywallBackground/PaywallBackground.tsx +47 -0
  408. package/src/build-components/PaywallBackground/PaywallBackgroundProps.generated.ts +63 -0
  409. package/src/build-components/PaywallBackground/pattern.json +16 -0
  410. package/src/build-components/PaywallCloseButton/PaywallCloseButton.tsx +62 -0
  411. package/src/build-components/PaywallCloseButton/PaywallCloseButtonProps.generated.ts +83 -0
  412. package/src/build-components/PaywallCloseButton/pattern.json +23 -0
  413. package/src/build-components/PaywallOptions/PaywallOptionButton.tsx +64 -0
  414. package/src/build-components/PaywallOptions/PaywallOptions.tsx +92 -0
  415. package/src/build-components/PaywallOptions/PaywallOptionsProps.generated.ts +63 -0
  416. package/src/build-components/PaywallOptions/pattern.json +22 -0
  417. package/src/build-components/PaywallOptions/usePaywallOptionParamsFactory.ts +42 -0
  418. package/src/build-components/PaywallProvider/PaywallProvider.tsx +78 -0
  419. package/src/build-components/PaywallProvider/PaywallProviderProps.generated.ts +63 -0
  420. package/src/build-components/PaywallProvider/pattern.json +24 -0
  421. package/src/build-components/PaywallSubscriButton/PaywallSubscriButton.tsx +10 -0
  422. package/src/build-components/PaywallSubscriButton/PaywallSubscriButtonProps.generated.ts +77 -0
  423. package/src/build-components/PaywallSubscriButton/pattern.json +27 -0
  424. package/src/build-components/PaywallSubscribeButton/PaywallSubscribeButton.tsx +60 -0
  425. package/src/build-components/PaywallSubscribeButton/PaywallSubscribeButtonProps.generated.ts +77 -0
  426. package/src/build-components/PaywallSubscribeButton/pattern.json +27 -0
  427. package/src/build-components/RadioButton/RadioButton.tsx +123 -0
  428. package/src/build-components/RadioButton/RadioButtonProps.generated.ts +66 -0
  429. package/src/build-components/RadioButton/pattern.json +42 -0
  430. package/src/build-components/RenderNode.generated.tsx +140 -37
  431. package/src/build-components/Text/Text.tsx +3 -3
  432. package/src/build-components/Text/TextProps.generated.ts +4 -0
  433. package/src/build-components/Text/pattern.json +1 -1
  434. package/src/build-components/View/ViewProps.generated.ts +4 -0
  435. package/src/build-components/View/pattern.json +42 -4
  436. package/src/build-components/index.ts +55 -10
  437. package/src/build-components/patterns.generated.ts +4909 -706
  438. package/src/components/AttributesEditorPanel.tsx +3 -1
  439. package/src/components/Builder.tsx +3 -5
  440. package/src/components/BuilderButton.tsx +2 -7
  441. package/src/components/BuilderProvider.tsx +45 -0
  442. package/src/components/DeviceNavigationBar.tsx +1 -1
  443. package/src/components/EditorHeader.tsx +4 -1
  444. package/src/components/Icon.generated.tsx +540 -0
  445. package/src/components/LocalizationParamsProvider.tsx +22 -0
  446. package/src/components/ParamsProvider.tsx +38 -0
  447. package/src/hooks/useLocalizationParams.ts +5 -0
  448. package/src/hooks/useLocalize.ts +23 -0
  449. package/src/hooks/useParams.ts +8 -0
  450. package/src/hooks/useSafeAreaViewStyle.ts +67 -0
  451. package/src/index.native.ts +75 -0
  452. package/src/index.ts +26 -0
  453. package/src/mockOS/components/MockOSRouter.tsx +9 -14
  454. package/src/mockOS/context/MockOSContext.tsx +12 -36
  455. package/src/mockOS/context/MockOSContextBase.ts +35 -0
  456. package/src/mockOS/index.ts +3 -2
  457. package/src/modals/AddComponentModal.tsx +1 -0
  458. package/src/modals/BenefitEditModal.tsx +160 -0
  459. package/src/modals/BenefitPresetsModal.tsx +166 -0
  460. package/src/modals/IconPickerModal.tsx +109 -0
  461. package/src/modals/MockableFeatureModal.tsx +292 -0
  462. package/src/modals/ProductEditModal.tsx +215 -0
  463. package/src/modals/ProductPresetsModal.tsx +151 -0
  464. package/src/modals/index.ts +6 -0
  465. package/src/pages/ProjectPage.tsx +72 -15
  466. package/src/pages/tabs/BuilderPanel.tsx +1 -1
  467. package/src/pages/tabs/SideTool.tsx +3 -10
  468. package/src/paywall/hooks/index.ts +5 -0
  469. package/src/paywall/hooks/useCalculateLocalizedPrice.ts +6 -0
  470. package/src/paywall/hooks/useCarouselOptionsSeperator.ts +8 -0
  471. package/src/paywall/hooks/useCloseStatusPaywall.ts +6 -0
  472. package/src/paywall/hooks/useDiscountRate.ts +6 -0
  473. package/src/paywall/hooks/usePaywallCounter.ts +6 -0
  474. package/src/paywall/types/benefits.ts +44 -0
  475. package/src/paywall/types/paywall-types.ts +51 -0
  476. package/src/store.ts +155 -41
  477. package/src/styles/base/_global.scss +49 -41
  478. package/src/styles/components/_attributes-editor.scss +40 -5
  479. package/src/styles/components/_editor-shell.scss +5 -11
  480. package/src/styles/components/_ui-components.scss +2 -1
  481. package/src/styles/index.scss +5 -0
  482. package/src/styles/modals/_benefit-edit-modal.scss +17 -0
  483. package/src/styles/modals/_benefit-presets-modal.scss +79 -0
  484. package/src/styles/modals/_mockable-feature-modal.scss +15 -0
  485. package/src/styles/modals/_product-edit-modal.scss +23 -0
  486. package/src/styles/modals/_product-presets-modal.scss +81 -0
  487. package/src/types/Icons.ts +244 -0
  488. package/src/types/Project.ts +5 -0
  489. package/src/types/jest-globals.d.ts +13 -0
  490. package/src/utils/analyseNode.ts +22 -109
  491. package/src/utils/analyseNodeByPatterns.ts +438 -0
  492. package/src/utils/analyseNodeStructural.ts +52 -0
  493. package/src/utils/extractViewStyle.ts +19 -0
  494. package/src/utils/findNodeByKeyNested.ts +32 -0
  495. package/src/utils/isCarousel.ts +21 -5
  496. package/src/utils/nodeGuards.ts +26 -0
  497. package/src/utils/novaToJson.ts +21 -9
  498. package/src/utils/patterns.ts +62 -3
  499. package/src/utils/replaceLocalizationParams.ts +15 -0
package/package.json CHANGED
@@ -1,11 +1,29 @@
1
1
  {
2
2
  "name": "@developer_tribe/react-builder",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
+ "license": "UNLICENSED",
4
5
  "type": "module",
5
6
  "restricted": true,
6
7
  "main": "dist/index.cjs.js",
7
8
  "module": "dist/index.esm.js",
8
9
  "types": "dist/index.d.ts",
10
+ "react-native": "dist/index.native.cjs.js",
11
+ "exports": {
12
+ ".": {
13
+ "react-native": {
14
+ "types": "./dist/index.native.d.ts",
15
+ "default": "./dist/index.native.cjs.js"
16
+ },
17
+ "types": "./dist/index.d.ts",
18
+ "import": "./dist/index.esm.js",
19
+ "require": "./dist/index.cjs.js",
20
+ "default": "./dist/index.esm.js"
21
+ },
22
+ "./native": {
23
+ "types": "./dist/index.native.d.ts",
24
+ "default": "./dist/index.native.cjs.js"
25
+ }
26
+ },
9
27
  "files": [
10
28
  "dist",
11
29
  "src",
@@ -13,7 +31,7 @@
13
31
  ],
14
32
  "scripts": {
15
33
  "prebuild": "node ./scripts/prebuild/prebuild.js",
16
- "build": "rimraf dist && rollup -c",
34
+ "build": "yarn prebuild && yarn rimraf dist && rollup -c",
17
35
  "build:watch": "rollup -c -w",
18
36
  "lint": "eslint src",
19
37
  "format": "prettier --write .",
@@ -22,6 +40,7 @@
22
40
  "example:build": "npm --prefix example run build",
23
41
  "example:preview": "npm --prefix example run preview",
24
42
  "builder": "node ./scripts/public/bin.js",
43
+ "test": "jest",
25
44
  "release": "yarn prebuild && yarn build && yarn publish --access restricted"
26
45
  },
27
46
  "bin": {
@@ -35,6 +54,7 @@
35
54
  "@rollup/plugin-json": "^6.1.0",
36
55
  "@rollup/plugin-node-resolve": "^16.0.1",
37
56
  "@rollup/plugin-url": "^8.0.2",
57
+ "@types/jest": "^29.5.14",
38
58
  "@types/node": "^22.7.4",
39
59
  "@types/react": "^18.3.9",
40
60
  "@types/react-dom": "^18.3.0",
@@ -43,6 +63,7 @@
43
63
  "eslint-plugin-react": "^7.37.5",
44
64
  "eslint-plugin-react-hooks": "^5.2.0",
45
65
  "globals": "^16.4.0",
66
+ "jest": "^29.7.0",
46
67
  "lottie-react": "^2.4.1",
47
68
  "prettier": "^3.6.2",
48
69
  "react": "^18.3.1",
@@ -53,6 +74,7 @@
53
74
  "rollup-plugin-terser": "^7.0.2",
54
75
  "rollup-plugin-typescript2": "^0.36.0",
55
76
  "sass": "^1.93.2",
77
+ "ts-jest": "^29.2.6",
56
78
  "typescript": "^5.9.2",
57
79
  "typescript-eslint": "^8.44.1",
58
80
  "use-sync-external-store": "^1.6.0",
@@ -64,8 +86,16 @@
64
86
  "react-dom": ">=17",
65
87
  "react-router-dom": ">=6.0.0"
66
88
  },
89
+ "peerDependenciesMeta": {
90
+ "react-dom": {
91
+ "optional": true
92
+ },
93
+ "react-router-dom": {
94
+ "optional": true
95
+ }
96
+ },
67
97
  "optionalDependencies": {
68
- "embla-carousel-react": ">=8.6.0"
98
+ "embla-carousel-react": "^8.6.0"
69
99
  },
70
100
  "engines": {
71
101
  "node": ">=18"
@@ -0,0 +1,71 @@
1
+ /* eslint-disable max-lines */
2
+ // NOTE: This file is generated. Do not edit it manually.
3
+ import React from 'react';
4
+ import type { CSSProperties, HTMLAttributes } from 'react';
5
+ import type { IconsType } from '../types/Icons';
6
+
7
+ {%properties1}
8
+
9
+ export type IconProps = Omit<HTMLAttributes<HTMLSpanElement>, 'color'> & {
10
+ iconType: IconsType;
11
+ size?: number;
12
+ color?: string;
13
+ strokeWidth?: number;
14
+ title?: string;
15
+ alt?: string;
16
+ };
17
+
18
+ function applyStrokeWidth(svg: string, strokeWidth: number): string {
19
+ const w = String(strokeWidth);
20
+ // Override any explicit stroke-width values (on paths or root)
21
+ let next = svg.replace(/\bstroke-width="[^"]*"/gi, `stroke-width="${w}"`);
22
+ // If the SVG had no stroke-width at all, add it to the root <svg> tag
23
+ if (next === svg) {
24
+ next = svg.replace(/<svg\b([^>]*?)>/i, (full, attrs) => {
25
+ if (/\bstroke-width=/i.test(attrs)) return full;
26
+ return `<svg${attrs} stroke-width="${w}">`;
27
+ });
28
+ }
29
+ return next;
30
+ }
31
+
32
+ export function Icon({
33
+ iconType,
34
+ size = 16,
35
+ color,
36
+ strokeWidth,
37
+ title,
38
+ alt,
39
+ style,
40
+ ...rest
41
+ }: IconProps) {
42
+ const sizeStyle: CSSProperties = size
43
+ ? { minWidth: size, minHeight: size, width: size, height: size }
44
+ : {};
45
+ const mergedStyle: CSSProperties = {
46
+ display: 'inline-block',
47
+ lineHeight: 0,
48
+ color,
49
+ ...sizeStyle,
50
+ ...style,
51
+ };
52
+
53
+ const baseSvg = ICON_SVGS[iconType];
54
+ const svg =
55
+ typeof strokeWidth === 'number' && Number.isFinite(strokeWidth)
56
+ ? applyStrokeWidth(baseSvg, strokeWidth)
57
+ : baseSvg;
58
+ if (!svg) return null;
59
+
60
+ return (
61
+ <span
62
+ role="img"
63
+ aria-label={alt ?? title ?? iconType}
64
+ title={title}
65
+ style={mergedStyle}
66
+ // eslint-disable-next-line react/no-danger
67
+ dangerouslySetInnerHTML={{ __html: svg }}
68
+ {...rest}
69
+ />
70
+ );
71
+ }
@@ -20,6 +20,11 @@ import {
20
20
  // lintNonGeneratedOrThrow,
21
21
  } from './utils/index.js';
22
22
 
23
+ // TODO: We currently repeat “provider-level” attributes across multiple pattern.json files
24
+ // (e.g. safe-area related flags like `use_safe_area_inset` / `useSafeAreaView`).
25
+ // Consider introducing shared/common attributes (or a shared `Main`/base provider pattern)
26
+ // to keep patterns consistent and avoid drift.
27
+
23
28
  const __filename = url.fileURLToPath(import.meta.url);
24
29
  const __dirname = path.dirname(__filename);
25
30
 
@@ -0,0 +1,206 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Generates:
4
+ * - `src/types/Icons.ts`
5
+ * - `src/components/Icon.generated.tsx`
6
+ *
7
+ * Based on SVG files under `src/assets/iconset` and template at
8
+ * `scripts/prebuild/assets/icon.template`.
9
+ */
10
+
11
+ import fs from 'fs/promises';
12
+ import path from 'path';
13
+ import url from 'url';
14
+
15
+ const __filename = url.fileURLToPath(import.meta.url);
16
+ const __dirname = path.dirname(__filename);
17
+
18
+ const PROJECT_ROOT = path.resolve(__dirname, '../..');
19
+ const SRC_ROOT = path.join(PROJECT_ROOT, 'src');
20
+
21
+ const ICONSET_DIR = path.join(SRC_ROOT, 'assets', 'iconset');
22
+ const TEMPLATE_FILE = path.join(__dirname, 'assets', 'icon.template');
23
+
24
+ const OUTPUT_TYPES_FILE = path.join(SRC_ROOT, 'types', 'Icons.ts');
25
+ const OUTPUT_COMPONENT_FILE = path.join(
26
+ SRC_ROOT,
27
+ 'components',
28
+ 'Icon.generated.tsx'
29
+ );
30
+
31
+ function normalizeSvg(svgText) {
32
+ let svg = String(svgText ?? '').trim();
33
+ if (!svg) return svg;
34
+
35
+ // Remove XML declarations if present
36
+ svg = svg.replace(/<\?xml[\s\S]*?\?>/g, '').trim();
37
+
38
+ // Ensure width/height are controlled by wrapper (100%)
39
+ // Replace existing width/height attributes on the root <svg>
40
+ svg = svg.replace(
41
+ /<svg\b([^>]*?)>/i,
42
+ (full, attrs) => {
43
+ let next = attrs;
44
+ if (/\bwidth="/i.test(next)) {
45
+ next = next.replace(/\bwidth="[^"]*"/i, 'width="100%"');
46
+ } else {
47
+ next += ' width="100%"';
48
+ }
49
+ if (/\bheight="/i.test(next)) {
50
+ next = next.replace(/\bheight="[^"]*"/i, 'height="100%"');
51
+ } else {
52
+ next += ' height="100%"';
53
+ }
54
+
55
+ // If root explicitly disables stroke, enable it so path-only icons render (e.g. chevrons)
56
+ if (/\bstroke="none"/i.test(next)) {
57
+ next = next.replace(/\bstroke="none"/i, 'stroke="currentColor"');
58
+ } else if (!/\bstroke="/i.test(next)) {
59
+ next += ' stroke="currentColor"';
60
+ } else {
61
+ // Normalize common stroke color values to currentColor on root
62
+ next = next
63
+ .replace(/\bstroke="black"/gi, 'stroke="currentColor"')
64
+ .replace(/\bstroke="#[0-9a-fA-F]{3,8}"/g, 'stroke="currentColor"')
65
+ .replace(/\bstroke="rgb\([^"]+\)"/gi, 'stroke="currentColor"');
66
+ }
67
+
68
+ // Normalize common fill color values to currentColor (keep fill="none")
69
+ next = next
70
+ .replace(/\bfill="black"/gi, 'fill="currentColor"')
71
+ .replace(/\bfill="#[0-9a-fA-F]{3,8}"/g, 'fill="currentColor"')
72
+ .replace(/\bfill="rgb\([^"]+\)"/gi, 'fill="currentColor"');
73
+
74
+ return `<svg${next}>`;
75
+ },
76
+ );
77
+
78
+ // Normalize any remaining explicit colors on child elements (keep "none")
79
+ svg = svg
80
+ .replace(/\bstroke="black"/gi, 'stroke="currentColor"')
81
+ .replace(/\bstroke="#[0-9a-fA-F]{3,8}"/g, 'stroke="currentColor"')
82
+ .replace(/\bstroke="rgb\([^"]+\)"/gi, 'stroke="currentColor"')
83
+ .replace(/\bfill="black"/gi, 'fill="currentColor"')
84
+ .replace(/\bfill="#[0-9a-fA-F]{3,8}"/g, 'fill="currentColor"')
85
+ .replace(/\bfill="rgb\([^"]+\)"/gi, 'fill="currentColor"');
86
+
87
+ return svg.trim();
88
+ }
89
+
90
+ function toIdentifier(iconName) {
91
+ // turns "arrow-right" into "arrowRight" etc; still avoids collisions later
92
+ const parts = iconName
93
+ .split(/[^a-zA-Z0-9]+/g)
94
+ .filter(Boolean)
95
+ .map(p => p.trim());
96
+ if (parts.length === 0) return 'icon';
97
+ const [first, ...rest] = parts;
98
+ const base =
99
+ first.toLowerCase() +
100
+ rest
101
+ .map(w => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())
102
+ .join('');
103
+ const safe = base.replace(/[^a-zA-Z0-9_]/g, '');
104
+ if (/^[0-9]/.test(safe)) return `icon${safe}`;
105
+ return safe || 'icon';
106
+ }
107
+
108
+ function uniqueIdentifiers(iconNames) {
109
+ const used = new Map();
110
+ const out = new Map();
111
+ for (const name of iconNames) {
112
+ const base = toIdentifier(name);
113
+ const count = used.get(base) ?? 0;
114
+ used.set(base, count + 1);
115
+ out.set(name, count === 0 ? base : `${base}${count + 1}`);
116
+ }
117
+ return out;
118
+ }
119
+
120
+ async function getIconNames() {
121
+ const entries = await fs.readdir(ICONSET_DIR, { withFileTypes: true });
122
+ const names = entries
123
+ .filter(e => e.isFile())
124
+ .map(e => e.name)
125
+ .filter(n => n.toLowerCase().endsWith('.svg'))
126
+ .map(n => n.slice(0, -'.svg'.length));
127
+
128
+ names.sort((a, b) => a.localeCompare(b));
129
+ return names;
130
+ }
131
+
132
+ function renderIconsTs(iconNames) {
133
+ const items = iconNames.map(n => ` '${n}',`).join('\n');
134
+ return `// NOTE: This file is generated. Do not edit it manually.
135
+ //TODO: we might use font-icon or something more optimize
136
+ export const Icons = [
137
+ ${items}
138
+ ] as const;
139
+
140
+ export type IconsType = (typeof Icons)[number];
141
+ `;
142
+ }
143
+
144
+ async function renderTemplate(template, iconNames) {
145
+ const entries = await Promise.all(
146
+ iconNames.map(async (iconName) => {
147
+ const svgPath = path.join(ICONSET_DIR, `${iconName}.svg`);
148
+ const raw = await fs.readFile(svgPath, 'utf8');
149
+ const normalized = normalizeSvg(raw);
150
+ return ` '${iconName}': ${JSON.stringify(normalized)},`;
151
+ }),
152
+ );
153
+
154
+ const mapBlock =
155
+ `const ICON_SVGS: Record<IconsType, string> = {\n` +
156
+ entries.join('\n') +
157
+ `\n};\n`;
158
+
159
+ return template.replace('{%properties1}', `\n${mapBlock}\n`);
160
+ }
161
+
162
+ async function ensureDirForFile(filePath) {
163
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
164
+ }
165
+
166
+ async function writeIfChanged(filePath, content) {
167
+ let existing = null;
168
+ try {
169
+ existing = await fs.readFile(filePath, 'utf8');
170
+ } catch {
171
+ // ignore
172
+ }
173
+ if (existing === content) return false;
174
+ await ensureDirForFile(filePath);
175
+ await fs.writeFile(filePath, content, 'utf8');
176
+ return true;
177
+ }
178
+
179
+ export default async function run() {
180
+ const iconNames = await getIconNames();
181
+ const template = await fs.readFile(TEMPLATE_FILE, 'utf8');
182
+
183
+ const iconsTs = renderIconsTs(iconNames);
184
+ const iconComponentTsx = await renderTemplate(template, iconNames);
185
+
186
+ const wroteTypes = await writeIfChanged(OUTPUT_TYPES_FILE, iconsTs);
187
+ const wroteComponent = await writeIfChanged(
188
+ OUTPUT_COMPONENT_FILE,
189
+ iconComponentTsx
190
+ );
191
+
192
+ return { wroteTypes, wroteComponent, count: iconNames.length };
193
+ }
194
+
195
+ // Allow running directly: `node scripts/prebuild/icon-generator.js`
196
+ if (
197
+ process.argv[1] &&
198
+ path.resolve(process.argv[1]) === path.resolve(__filename)
199
+ ) {
200
+ const res = await run();
201
+ console.info(
202
+ `Generated icons (${res.count}) -> types: ${res.wroteTypes ? 'updated' : 'unchanged'}, component: ${
203
+ res.wroteComponent ? 'updated' : 'unchanged'
204
+ }`
205
+ );
206
+ }
@@ -1,9 +1,18 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import run from './build-components.js';
4
+ import runIconGenerator from './icon-generator.js';
4
5
 
5
- console.info('Building components...');
6
6
  try {
7
+ console.info('Generating icons...');
8
+ const { count, wroteTypes, wroteComponent } = await runIconGenerator();
9
+ console.info(
10
+ `Generated icons (${count}) -> types: ${
11
+ wroteTypes ? 'updated' : 'unchanged'
12
+ }, component: ${wroteComponent ? 'updated' : 'unchanged'}`
13
+ );
14
+
15
+ console.info('Building components...');
7
16
  await run();
8
17
  } catch (err) {
9
18
  console.error(err?.stack || err?.message || err);
@@ -11,9 +11,12 @@ export async function createComponentTsx(componentDir, componentName) {
11
11
  if (exists) return; // Will be validated later
12
12
 
13
13
  const content =
14
- `import React from 'react';\n\n` +
15
- `function ${componentName}() {\n` +
16
- ` return "hello world";\n` +
14
+ `import React from 'react';\n` +
15
+ `import type { ${componentName}ComponentProps } from './${componentName}Props.generated';\n` +
16
+ `import useNode from '../useNode';\n\n` +
17
+ `function ${componentName}({ node }: ${componentName}ComponentProps) {\n` +
18
+ ` node = useNode(node);\n` +
19
+ ` return null;\n` +
17
20
  `}\n\n` +
18
21
  `export default React.memo(${componentName});\n`;
19
22
  const formatted = await formatWithPrettier(content);
@@ -9,8 +9,10 @@ const isPrimitive = t =>
9
9
  t === 'number' ||
10
10
  t === 'boolean' ||
11
11
  t === 'color' ||
12
- t === 'size';
13
- const toTsPrimitive = t => (t === 'color' || t === 'size' ? 'string' : t);
12
+ t === 'size' ||
13
+ t === 'iconType';
14
+ const toTsPrimitive = t =>
15
+ t === 'color' || t === 'size' || t === 'iconType' ? 'string' : t;
14
16
  const getArrayItem = t =>
15
17
  typeof t === 'string' && t.endsWith('[]') ? t.slice(0, -2) : null;
16
18
  // Convert a property name like "animation" or "on-press" to PascalCase
@@ -6,6 +6,10 @@ export async function createRenderNodeGenerated(validated, paths) {
6
6
  const { COMPONENTS_ROOT } = paths;
7
7
  const targetPath = path.join(COMPONENTS_ROOT, 'RenderNode.generated.tsx');
8
8
 
9
+ const textPatternType =
10
+ validated.find(v => v.componentName === 'Text')?.patternJson?.pattern
11
+ ?.type ?? 'Text';
12
+
9
13
  // Build imports for all components discovered
10
14
  const componentImports = validated
11
15
  .map(
@@ -14,12 +18,30 @@ export async function createRenderNodeGenerated(validated, paths) {
14
18
  )
15
19
  .join('\n');
16
20
 
21
+ // Import each component's generated prop type so we can build a strongly-typed node union
22
+ const componentPropTypeImports = validated
23
+ .map(
24
+ ({ componentName }) =>
25
+ `import type { ${componentName}ComponentProps } from './${componentName}/${componentName}Props.generated';`
26
+ )
27
+ .join('\n');
28
+
29
+ const builderNodeUnion = validated
30
+ .map(({ componentName, patternJson }) => {
31
+ const type = patternJson?.pattern?.type;
32
+ return typeof type === 'string'
33
+ ? ` | (${componentName}ComponentProps['node'] & { type: ${JSON.stringify(type)} })`
34
+ : null;
35
+ })
36
+ .filter(Boolean)
37
+ .join('\n');
38
+
17
39
  // Build switch cases from each component's pattern.type
18
40
  const cases = validated
19
41
  .map(({ componentName, patternJson }) => {
20
42
  const type = patternJson?.pattern?.type;
21
43
  return typeof type === 'string'
22
- ? ` case ${JSON.stringify(type)}:\n return <${componentName} node={simpleNode} />;`
44
+ ? ` case ${JSON.stringify(type)}:\n return <${componentName} node={normalizedNode} />;`
23
45
  : null;
24
46
  })
25
47
  .filter(Boolean)
@@ -28,23 +50,28 @@ export async function createRenderNodeGenerated(validated, paths) {
28
50
  const fileContent =
29
51
  `/* AUTO-GENERATED FILE - DO NOT EDIT */\n` +
30
52
  `import React from 'react';\n\n` +
53
+ `import { normalizeComponentType } from '../utils/patterns';\n\n` +
54
+ `import type { Node } from '../types/Node';\n` +
31
55
  `import {\n` +
32
- ` Node,\n` +
33
- ` NodeData,\n` +
34
56
  ` isNodeArray,\n` +
35
57
  ` isNodeNullOrUndefined,\n` +
36
58
  ` isNodeString,\n` +
37
- `} from '../index';\n\n` +
59
+ `} from '../utils/analyseNode';\n\n` +
38
60
  `import { other } from './other';\n\n` +
39
61
  `// Builder components\n` +
62
+ componentPropTypeImports +
63
+ `\n` +
40
64
  componentImports +
41
65
  `\n\n` +
66
+ `type BuilderNode =\n` +
67
+ (builderNodeUnion ? `${builderNodeUnion}\n` : ` never\n`) +
68
+ `;\n\n` +
42
69
  `function RenderNode({ node }: { node: Node }) {\n` +
43
70
  ` if (isNodeNullOrUndefined(node)) {\n` +
44
71
  ` return null;\n` +
45
72
  ` }\n` +
46
73
  ` if (isNodeString(node)) {\n` +
47
- ` return <Text node={{ children: node as string, type: 'text' }} />;\n` +
74
+ ` return <Text node={{ children: node as string, type: ${JSON.stringify(textPatternType)} }} />;\n` +
48
75
  ` }\n` +
49
76
  ` if (isNodeArray(node)) {\n` +
50
77
  ` return (\n` +
@@ -55,11 +82,19 @@ export async function createRenderNodeGenerated(validated, paths) {
55
82
  ` </>\n` +
56
83
  ` );\n` +
57
84
  ` }\n\n` +
58
- ` const simpleNode = node as NodeData;\n` +
59
- ` switch (simpleNode?.type) {\n` +
85
+ ` const nodeType =\n` +
86
+ ` typeof (node as { type?: unknown })?.type === 'string'\n` +
87
+ ` ? (node as { type: string }).type\n` +
88
+ ` : 'unknown';\n` +
89
+ `\n` +
90
+ ` const normalizedType = normalizeComponentType(nodeType) ?? nodeType;\n` +
91
+ `\n` +
92
+ ` // Force a stable discriminant so TS can narrow the BuilderNode union.\n` +
93
+ ` const normalizedNode = { ...(node as any), type: normalizedType } as BuilderNode;\n` +
94
+ ` switch (normalizedNode.type) {\n` +
60
95
  cases +
61
96
  `\n default:\n` +
62
- ` return other(simpleNode?.type, node);\n` +
97
+ ` return other(nodeType, node);\n` +
63
98
  ` }\n` +
64
99
  `}\n\n` +
65
100
  `export default React.memo(RenderNode);\n`;
@@ -105,6 +105,11 @@ async function validatePatternJson(componentDir, componentName) {
105
105
  `[${componentName}] pattern.json -> 'pattern.type' must be a string`
106
106
  );
107
107
  }
108
+ if (pattern.type !== componentName) {
109
+ return fail(
110
+ `[${componentName}] pattern.json -> 'pattern.type' must match the component folder name '${componentName}' (PascalCase).`
111
+ );
112
+ }
108
113
  if (
109
114
  typeof pattern.children !== 'string' &&
110
115
  !Array.isArray(pattern.children)
@@ -125,7 +130,8 @@ async function validatePatternJson(componentDir, componentName) {
125
130
  t === 'number' ||
126
131
  t === 'boolean' ||
127
132
  t === 'color' ||
128
- t === 'size';
133
+ t === 'size' ||
134
+ t === 'iconType';
129
135
  const isNeverType = t => t === 'never';
130
136
  const hasCustomTypes = typeof data.types === 'object' && data.types != null;
131
137
  const isCustomType = t =>
@@ -193,12 +199,18 @@ async function validatePatternJson(componentDir, componentName) {
193
199
 
194
200
  // Resolve chained extends: walk up the chain, detect cycles, merge from base to child
195
201
  const componentsRoot = path.dirname(componentDir);
196
- const visited = new Set();
202
+ // Track visited folders and visited pattern.type values separately.
203
+ // Because we enforce `pattern.type === component folder name` (PascalCase),
204
+ // mixing them in a single Set can incorrectly flag a "cycle" immediately
205
+ // when a component extends `View`.
206
+ const visitedFolders = new Set();
207
+ const visitedTypes = new Set();
197
208
  const ancestorStack = [];
198
209
 
199
210
  // Track both componentName and current type for cycle detection
200
- visited.add(componentName);
201
- if (typeof data?.pattern?.type === 'string') visited.add(data.pattern.type);
211
+ visitedFolders.add(componentName);
212
+ if (typeof data?.pattern?.type === 'string')
213
+ visitedTypes.add(data.pattern.type);
202
214
 
203
215
  let cursor = data;
204
216
  // Collect raw ancestors without mutating child yet
@@ -207,12 +219,12 @@ async function validatePatternJson(componentDir, componentName) {
207
219
  cursor.pattern.extends.trim().length > 0
208
220
  ) {
209
221
  const parentName = cursor.pattern.extends.trim();
210
- if (visited.has(parentName)) {
222
+ if (visitedFolders.has(parentName)) {
211
223
  return fail(
212
224
  `Circular dependency detected in extends chain at '${parentName}'. We don't allow circular dependency.`
213
225
  );
214
226
  }
215
- visited.add(parentName);
227
+ visitedFolders.add(parentName);
216
228
 
217
229
  const parentDir = path.join(componentsRoot, parentName);
218
230
  const parentDirExists = await fs
@@ -257,14 +269,13 @@ async function validatePatternJson(componentDir, componentName) {
257
269
  );
258
270
  }
259
271
 
260
- // Detect cycle by type name too
261
272
  const parentType = parentData.pattern.type;
262
- if (visited.has(parentType)) {
273
+ if (visitedTypes.has(parentType)) {
263
274
  return fail(
264
275
  `Circular dependency detected in extends chain via type '${parentType}'. We don't allow circular dependency.`
265
276
  );
266
277
  }
267
- visited.add(parentType);
278
+ visitedTypes.add(parentType);
268
279
 
269
280
  ancestorStack.push(parentData);
270
281
  cursor = parentData;
@@ -65,7 +65,8 @@ export async function validatePatternJson(componentDir, componentName) {
65
65
  value === 'number' ||
66
66
  value === 'boolean' ||
67
67
  value === 'color' ||
68
- value === 'size';
68
+ value === 'size' ||
69
+ value === 'iconType';
69
70
 
70
71
  for (const [attrName, attrType] of Object.entries(pattern.attributes)) {
71
72
  const isValidType =
@@ -76,7 +77,7 @@ export async function validatePatternJson(componentDir, componentName) {
76
77
  (Array.isArray(attrType) && attrType.every(v => typeof v === 'string'));
77
78
  if (!isValidType) {
78
79
  return fail(
79
- `[${componentName}] pattern.json -> 'pattern.attributes.${attrName}' must be 'string' | 'number' | 'boolean' | 'color' | string[]`
80
+ `[${componentName}] pattern.json -> 'pattern.attributes.${attrName}' must be 'string' | 'number' | 'boolean' | 'color' | 'size' | 'iconType' | string[]`
80
81
  );
81
82
  }
82
83
  }