@developer_tribe/react-builder 1.0.4 → 1.0.6
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.
- package/README.md +6 -0
- package/dist/assets/samples/getSamples.d.ts +1 -0
- package/dist/background.jpg +0 -0
- package/dist/build-components/BIcon/BIcon.d.ts +5 -0
- package/dist/build-components/BIcon/BIconProps.generated.d.ts +55 -0
- package/dist/build-components/BackgroundImage/BackgroundImageProps.generated.d.ts +4 -0
- package/dist/build-components/Button/ButtonProps.generated.d.ts +4 -0
- package/dist/build-components/Carousel/CarouselProps.generated.d.ts +4 -0
- package/dist/build-components/CarouselButtons/CarouselButtonsProps.generated.d.ts +4 -0
- package/dist/build-components/CarouselDots/CarouselDotsProps.generated.d.ts +4 -0
- package/dist/build-components/CarouselItem/CarouselItemProps.generated.d.ts +4 -0
- package/dist/build-components/CarouselProvider/CarouselProviderProps.generated.d.ts +4 -0
- package/dist/build-components/Image/ImageProps.generated.d.ts +4 -0
- package/dist/build-components/Main/Main.d.ts +5 -0
- package/dist/build-components/Main/MainProps.generated.d.ts +48 -0
- package/dist/build-components/Onboard/OnboardProps.generated.d.ts +4 -0
- package/dist/build-components/OnboardButton/OnboardButtonProps.generated.d.ts +4 -0
- package/dist/build-components/OnboardButtons/OnboardButtonsProps.generated.d.ts +4 -0
- package/dist/build-components/OnboardDot/OnboardDotProps.generated.d.ts +4 -0
- package/dist/build-components/OnboardFooter/OnboardFooterProps.generated.d.ts +4 -0
- package/dist/build-components/OnboardImage/OnboardImageProps.generated.d.ts +4 -0
- package/dist/build-components/OnboardItem/OnboardItemProps.generated.d.ts +4 -0
- package/dist/build-components/OnboardProvider/OnboardProviderProps.generated.d.ts +4 -1
- package/dist/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.d.ts +4 -0
- package/dist/build-components/OnboardTitle/OnboardTitleProps.generated.d.ts +4 -0
- package/dist/build-components/PaywallBackground/PaywallBackground.d.ts +5 -0
- package/dist/build-components/PaywallBackground/PaywallBackgroundProps.generated.d.ts +47 -0
- package/dist/build-components/PaywallCloseButton/PaywallCloseButton.d.ts +5 -0
- package/dist/build-components/PaywallCloseButton/PaywallCloseButtonProps.generated.d.ts +56 -0
- package/dist/build-components/PaywallOptions/PaywallOptionButton.d.ts +9 -0
- package/dist/build-components/PaywallOptions/PaywallOptions.d.ts +5 -0
- package/dist/build-components/PaywallOptions/PaywallOptionsProps.generated.d.ts +47 -0
- package/dist/build-components/PaywallOptions/usePaywallOptionParamsFactory.d.ts +10 -0
- package/dist/build-components/PaywallProvider/PaywallProvider.d.ts +5 -0
- package/dist/build-components/PaywallProvider/PaywallProviderProps.generated.d.ts +47 -0
- package/dist/build-components/PaywallSubscribeButton/PaywallSubscribeButton.d.ts +5 -0
- package/dist/build-components/PaywallSubscribeButton/PaywallSubscribeButtonProps.generated.d.ts +50 -0
- package/dist/build-components/RadioButton/RadioButton.d.ts +11 -0
- package/dist/build-components/RadioButton/RadioButtonProps.generated.d.ts +50 -0
- package/dist/build-components/RenderNode.generated.d.ts +1 -1
- package/dist/build-components/Text/TextProps.generated.d.ts +4 -0
- package/dist/build-components/View/ViewProps.generated.d.ts +4 -0
- package/dist/build-components/index.d.ts +9 -1
- package/dist/build-components/patterns.generated.d.ts +4442 -655
- package/dist/components/AttributesEditorPanel.d.ts +4 -3
- package/dist/components/BottomBar.d.ts +8 -0
- package/dist/components/Builder.d.ts +1 -1
- package/dist/components/BuilderButton.d.ts +1 -1
- package/dist/components/BuilderProvider.d.ts +15 -0
- package/dist/components/Checkbox.d.ts +1 -1
- package/dist/components/EditorHeader.d.ts +1 -1
- package/dist/components/Icon.generated.d.ts +11 -0
- package/dist/components/LoadingComponent.d.ts +1 -0
- package/dist/components/LocalizationParamsProvider.d.ts +11 -0
- package/dist/components/MobilePanelToggleButton.d.ts +8 -0
- package/dist/components/ParamsProvider.d.ts +14 -0
- package/dist/hooks/useLocalizationParams.d.ts +1 -0
- package/dist/hooks/useLocalize.d.ts +2 -0
- package/dist/hooks/useMinimumDelay.d.ts +7 -0
- package/dist/hooks/useMobileEditorPanels.d.ts +12 -0
- package/dist/hooks/useParams.d.ts +1 -0
- package/dist/hooks/useSafeAreaViewStyle.d.ts +1 -0
- package/dist/hooks/useSyncProjectPageStore.d.ts +15 -0
- package/dist/index.cjs.js +5 -5
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +8 -0
- package/dist/index.esm.js +5 -5
- package/dist/index.esm.js.map +1 -1
- package/dist/index.native.cjs.js +29 -0
- package/dist/index.native.cjs.js.map +1 -0
- package/dist/index.native.d.ts +31 -0
- package/dist/index.native.esm.js +29 -0
- package/dist/index.native.esm.js.map +1 -0
- package/dist/mockOS/components/MockOSRouter.d.ts +1 -1
- package/dist/mockOS/context/MockOSContext.d.ts +4 -18
- package/dist/mockOS/context/MockOSContextBase.d.ts +21 -0
- package/dist/mockOS/index.d.ts +3 -2
- package/dist/modals/BenefitEditModal.d.ts +13 -0
- package/dist/modals/BenefitPresetsModal.d.ts +9 -0
- package/dist/modals/IconPickerModal.d.ts +9 -0
- package/dist/modals/MockableFeatureModal.d.ts +6 -0
- package/dist/modals/ProductEditModal.d.ts +9 -0
- package/dist/modals/ProductPresetsModal.d.ts +9 -0
- package/dist/modals/ScreenColorsModal.d.ts +8 -0
- package/dist/modals/index.d.ts +7 -0
- package/dist/pages/ProjectPage.d.ts +3 -2
- package/dist/pages/tabs/BuilderPanel.d.ts +3 -3
- package/dist/paywall/hooks/index.d.ts +5 -0
- package/dist/paywall/hooks/useCalculateLocalizedPrice.d.ts +4 -0
- package/dist/paywall/hooks/useCarouselOptionsSeperator.d.ts +6 -0
- package/dist/paywall/hooks/useCloseStatusPaywall.d.ts +4 -0
- package/dist/paywall/hooks/useDiscountRate.d.ts +4 -0
- package/dist/paywall/hooks/usePaywallCounter.d.ts +4 -0
- package/dist/paywall/types/benefits.d.ts +14 -0
- package/dist/paywall/types/paywall-types.d.ts +43 -0
- package/dist/store.d.ts +35 -1
- package/dist/styles.css +1 -1
- package/dist/types/Icons.d.ts +2 -0
- package/dist/types/Project.d.ts +5 -0
- package/dist/utils/analyseNode.d.ts +1 -4
- package/dist/utils/analyseNodeByPatterns.d.ts +16 -0
- package/dist/utils/analyseNodeStructural.d.ts +11 -0
- package/dist/utils/findNodeByKeyNested.d.ts +2 -0
- package/dist/utils/nodeGuards.d.ts +5 -0
- package/dist/utils/nodeTree.d.ts +5 -0
- package/dist/utils/novaToJson.d.ts +5 -0
- package/dist/utils/patterns.d.ts +14 -0
- package/dist/utils/replaceLocalizationParams.d.ts +1 -0
- package/package.json +33 -3
- package/scripts/prebuild/assets/icon.template +71 -0
- package/scripts/prebuild/build-components.js +5 -0
- package/scripts/prebuild/icon-generator.js +206 -0
- package/scripts/prebuild/prebuild.js +10 -1
- package/scripts/prebuild/utils/createComponentTsx.js +6 -3
- package/scripts/prebuild/utils/createGeneratedProps.js +4 -2
- package/scripts/prebuild/utils/createRenderNodeGenerated.js +43 -8
- package/scripts/prebuild/utils/validateAllComponentsOrThrow.js +20 -9
- package/scripts/prebuild/utils/validatePatternJson.js +3 -2
- package/src/AttributesEditor.tsx +178 -34
- package/src/DeviceMockFrame.tsx +41 -43
- package/src/RenderPage.tsx +11 -49
- package/src/assets/benefits.json +24 -0
- package/src/assets/iconset/activity-heart.svg +3 -0
- package/src/assets/iconset/activity.svg +3 -0
- package/src/assets/iconset/alert-circle.svg +3 -0
- package/src/assets/iconset/alert-triangle.svg +3 -0
- package/src/assets/iconset/anchor.svg +3 -0
- package/src/assets/iconset/archive.svg +3 -0
- package/src/assets/iconset/arrow-down.svg +3 -0
- package/src/assets/iconset/arrow-left.svg +3 -0
- package/src/assets/iconset/arrow-narrow-down-left.svg +3 -0
- package/src/assets/iconset/arrow-narrow-up-right.svg +3 -0
- package/src/assets/iconset/arrow-right-smooth.svg +4 -0
- package/src/assets/iconset/arrow-right.svg +7 -0
- package/src/assets/iconset/asterisk-01.svg +3 -0
- package/src/assets/iconset/asterisk-02.svg +3 -0
- package/src/assets/iconset/at-sign.svg +3 -0
- package/src/assets/iconset/award.svg +4 -0
- package/src/assets/iconset/battery-charging.svg +6 -0
- package/src/assets/iconset/bell-01.svg +5 -0
- package/src/assets/iconset/bell-02.svg +3 -0
- package/src/assets/iconset/bell-ringing-02.svg +3 -0
- package/src/assets/iconset/bookmark-add.svg +3 -0
- package/src/assets/iconset/bookmark-check.svg +3 -0
- package/src/assets/iconset/bookmark-minus.svg +3 -0
- package/src/assets/iconset/bookmark-x.svg +3 -0
- package/src/assets/iconset/bookmark.svg +3 -0
- package/src/assets/iconset/bubble.svg +5 -0
- package/src/assets/iconset/building-01.svg +3 -0
- package/src/assets/iconset/building-02.svg +3 -0
- package/src/assets/iconset/building-03.svg +3 -0
- package/src/assets/iconset/building-04.svg +3 -0
- package/src/assets/iconset/building-05.svg +3 -0
- package/src/assets/iconset/building-06.svg +3 -0
- package/src/assets/iconset/building-07.svg +3 -0
- package/src/assets/iconset/building-08.svg +3 -0
- package/src/assets/iconset/building-09.svg +3 -0
- package/src/assets/iconset/camera-01.svg +8 -0
- package/src/assets/iconset/camera-steel.svg +4 -0
- package/src/assets/iconset/camera.svg +4 -0
- package/src/assets/iconset/check-circle-bold.svg +3 -0
- package/src/assets/iconset/check-circle-broken.svg +3 -0
- package/src/assets/iconset/check-circle.svg +3 -0
- package/src/assets/iconset/check-done-01.svg +3 -0
- package/src/assets/iconset/check-done-02.svg +3 -0
- package/src/assets/iconset/check-heart.svg +3 -0
- package/src/assets/iconset/check-square-broken.svg +3 -0
- package/src/assets/iconset/check-square.svg +3 -0
- package/src/assets/iconset/check-verified-01.svg +3 -0
- package/src/assets/iconset/check-verified-02.svg +3 -0
- package/src/assets/iconset/check-verified-03.svg +3 -0
- package/src/assets/iconset/check.svg +3 -0
- package/src/assets/iconset/checkbox.svg +4 -0
- package/src/assets/iconset/checkv.svg +3 -0
- package/src/assets/iconset/chevron-down.svg +3 -0
- package/src/assets/iconset/chevron-down2.svg +3 -0
- package/src/assets/iconset/chevron-left-2.svg +3 -0
- package/src/assets/iconset/chevron-left.svg +3 -0
- package/src/assets/iconset/chevron-right-empty.svg +3 -0
- package/src/assets/iconset/chevron-right-smooth.svg +3 -0
- package/src/assets/iconset/chevron-right.svg +3 -0
- package/src/assets/iconset/chevron-up.svg +3 -0
- package/src/assets/iconset/circle.svg +32 -0
- package/src/assets/iconset/clock-fast-forward.svg +10 -0
- package/src/assets/iconset/clock.svg +3 -0
- package/src/assets/iconset/close-circle.svg +3 -0
- package/src/assets/iconset/close.svg +3 -0
- package/src/assets/iconset/cloud-01.svg +5 -0
- package/src/assets/iconset/cloud-blank-01.svg +3 -0
- package/src/assets/iconset/cloud-blank-02.svg +3 -0
- package/src/assets/iconset/coin.svg +5 -0
- package/src/assets/iconset/coins-02.svg +3 -0
- package/src/assets/iconset/colors.svg +3 -0
- package/src/assets/iconset/copy-01.svg +3 -0
- package/src/assets/iconset/copy-02.svg +3 -0
- package/src/assets/iconset/copy-03.svg +3 -0
- package/src/assets/iconset/copy-04.svg +3 -0
- package/src/assets/iconset/copy-05.svg +3 -0
- package/src/assets/iconset/copy-06.svg +3 -0
- package/src/assets/iconset/copy-07.svg +3 -0
- package/src/assets/iconset/corner-down-right.svg +3 -0
- package/src/assets/iconset/crypto-bold.svg +4 -0
- package/src/assets/iconset/delete-icon.svg +5 -0
- package/src/assets/iconset/diamond.svg +3 -0
- package/src/assets/iconset/dice-3.svg +3 -0
- package/src/assets/iconset/divide-01.svg +3 -0
- package/src/assets/iconset/divide-02.svg +3 -0
- package/src/assets/iconset/divide-03.svg +3 -0
- package/src/assets/iconset/document-check-bold.svg +4 -0
- package/src/assets/iconset/dots-circle.svg +10 -0
- package/src/assets/iconset/dots-grid.svg +11 -0
- package/src/assets/iconset/dots-horizontal.svg +5 -0
- package/src/assets/iconset/dots-vertical.svg +5 -0
- package/src/assets/iconset/download-01.svg +3 -0
- package/src/assets/iconset/download-02.svg +3 -0
- package/src/assets/iconset/download-03.svg +3 -0
- package/src/assets/iconset/edit-03.svg +3 -0
- package/src/assets/iconset/edit-04.svg +3 -0
- package/src/assets/iconset/edit-05.svg +3 -0
- package/src/assets/iconset/element-3.svg +6 -0
- package/src/assets/iconset/ellipse-127.svg +3 -0
- package/src/assets/iconset/exclaimation-circle.svg +8 -0
- package/src/assets/iconset/eye-off-line.svg +5 -0
- package/src/assets/iconset/face-smile.svg +5 -0
- package/src/assets/iconset/file-04.svg +3 -0
- package/src/assets/iconset/file-05.svg +3 -0
- package/src/assets/iconset/file-check-02.svg +3 -0
- package/src/assets/iconset/file-plus-01.svg +5 -0
- package/src/assets/iconset/file-shield-02.svg +5 -0
- package/src/assets/iconset/filter-funnel-01.svg +3 -0
- package/src/assets/iconset/flag-03.svg +3 -0
- package/src/assets/iconset/flash.svg +3 -0
- package/src/assets/iconset/folder-plus.svg +3 -0
- package/src/assets/iconset/folder.svg +3 -0
- package/src/assets/iconset/gallery.svg +3 -0
- package/src/assets/iconset/globe-01.svg +3 -0
- package/src/assets/iconset/globe-04.svg +5 -0
- package/src/assets/iconset/globe-bold.svg +4 -0
- package/src/assets/iconset/guard.svg +3 -0
- package/src/assets/iconset/headphones-01.svg +3 -0
- package/src/assets/iconset/headphones-02.svg +5 -0
- package/src/assets/iconset/headset-bold.svg +4 -0
- package/src/assets/iconset/heart-bold.svg +3 -0
- package/src/assets/iconset/heart.svg +3 -0
- package/src/assets/iconset/help-circle.svg +5 -0
- package/src/assets/iconset/home-2.svg +4 -0
- package/src/assets/iconset/home-line.svg +3 -0
- package/src/assets/iconset/hourglass-02.svg +5 -0
- package/src/assets/iconset/image-01.svg +5 -0
- package/src/assets/iconset/image-03.svg +3 -0
- package/src/assets/iconset/image.svg +4 -0
- package/src/assets/iconset/inbox-01.svg +3 -0
- package/src/assets/iconset/inbox-arrow-down.svg +3 -0
- package/src/assets/iconset/info-circle.svg +3 -0
- package/src/assets/iconset/keyboard-line.svg +9 -0
- package/src/assets/iconset/lamp-charge.svg +5 -0
- package/src/assets/iconset/layer.svg +3 -0
- package/src/assets/iconset/light.svg +6 -0
- package/src/assets/iconset/like-dislike.svg +6 -0
- package/src/assets/iconset/lock-03.svg +3 -0
- package/src/assets/iconset/logout.svg +3 -0
- package/src/assets/iconset/magicpen.svg +7 -0
- package/src/assets/iconset/mail-01.svg +5 -0
- package/src/assets/iconset/mail.svg +3 -0
- package/src/assets/iconset/marker.svg +3 -0
- package/src/assets/iconset/medal-star.svg +5 -0
- package/src/assets/iconset/menu-04.svg +3 -0
- package/src/assets/iconset/menu.svg +5 -0
- package/src/assets/iconset/message-circle-01.svg +5 -0
- package/src/assets/iconset/message-plus-circle.svg +3 -0
- package/src/assets/iconset/message-question-circle.svg +5 -0
- package/src/assets/iconset/message-text-circle-01.svg +5 -0
- package/src/assets/iconset/message-text-square-02.svg +3 -0
- package/src/assets/iconset/message-x-square.svg +3 -0
- package/src/assets/iconset/microphone-02.svg +3 -0
- package/src/assets/iconset/microphone-slash.svg +8 -0
- package/src/assets/iconset/mirror.svg +4 -0
- package/src/assets/iconset/moon-01.svg +3 -0
- package/src/assets/iconset/moon-bold.svg +3 -0
- package/src/assets/iconset/mouse-circle.svg +4 -0
- package/src/assets/iconset/move.svg +5 -0
- package/src/assets/iconset/notification-fill.svg +3 -0
- package/src/assets/iconset/notification-text.svg +3 -0
- package/src/assets/iconset/notification.svg +5 -0
- package/src/assets/iconset/pdf-01.svg +6 -0
- package/src/assets/iconset/pencil-01.svg +5 -0
- package/src/assets/iconset/phone-01.svg +3 -0
- package/src/assets/iconset/phone-arrow-down-left.svg +4 -0
- package/src/assets/iconset/phone-arrow-up-right.svg +8 -0
- package/src/assets/iconset/phone-hang-up.svg +5 -0
- package/src/assets/iconset/phone-hangup2.svg +8 -0
- package/src/assets/iconset/phone-incoming-01.svg +3 -0
- package/src/assets/iconset/phone-outgoing-01.svg +3 -0
- package/src/assets/iconset/phone-plus.svg +3 -0
- package/src/assets/iconset/phone-x.svg +3 -0
- package/src/assets/iconset/phone.svg +3 -0
- package/src/assets/iconset/plus-circle.svg +3 -0
- package/src/assets/iconset/plus.svg +4 -0
- package/src/assets/iconset/printer.svg +3 -0
- package/src/assets/iconset/question-mark-circle.svg +5 -0
- package/src/assets/iconset/refresh-ccw-01.svg +3 -0
- package/src/assets/iconset/refresh-cw-01.svg +3 -0
- package/src/assets/iconset/refresh-cw-04.svg +3 -0
- package/src/assets/iconset/refresh-right-square-bold.svg +3 -0
- package/src/assets/iconset/remove-circle.svg +12 -0
- package/src/assets/iconset/repeat-04.svg +3 -0
- package/src/assets/iconset/repeat-bold.svg +3 -0
- package/src/assets/iconset/ruler-pen.svg +4 -0
- package/src/assets/iconset/search-lg.svg +3 -0
- package/src/assets/iconset/search-md.svg +5 -0
- package/src/assets/iconset/search-refraction.svg +5 -0
- package/src/assets/iconset/search.svg +3 -0
- package/src/assets/iconset/send-01.svg +3 -0
- package/src/assets/iconset/send-02.svg +5 -0
- package/src/assets/iconset/send-diagonal.svg +3 -0
- package/src/assets/iconset/setting-2.svg +4 -0
- package/src/assets/iconset/settings-02.svg +4 -0
- package/src/assets/iconset/settings-04.svg +5 -0
- package/src/assets/iconset/settings-2.svg +4 -0
- package/src/assets/iconset/settings-cog.svg +3 -0
- package/src/assets/iconset/settings.svg +4 -0
- package/src/assets/iconset/share-01.svg +4 -0
- package/src/assets/iconset/share-03.svg +3 -0
- package/src/assets/iconset/share-04.svg +3 -0
- package/src/assets/iconset/share-05.svg +5 -0
- package/src/assets/iconset/share-06.svg +3 -0
- package/src/assets/iconset/share-bold.svg +3 -0
- package/src/assets/iconset/shield-01.svg +3 -0
- package/src/assets/iconset/shield-bold.svg +3 -0
- package/src/assets/iconset/solar-check.svg +3 -0
- package/src/assets/iconset/speaker-wave.svg +9 -0
- package/src/assets/iconset/speaker.svg +5 -0
- package/src/assets/iconset/speedometer-03.svg +3 -0
- package/src/assets/iconset/star-rounded.svg +3 -0
- package/src/assets/iconset/star.svg +3 -0
- package/src/assets/iconset/sun.svg +5 -0
- package/src/assets/iconset/target-03.svg +3 -0
- package/src/assets/iconset/text-input.svg +3 -0
- package/src/assets/iconset/translate.svg +7 -0
- package/src/assets/iconset/trash-02.svg +3 -0
- package/src/assets/iconset/trash-03.svg +5 -0
- package/src/assets/iconset/trash-04.svg +3 -0
- package/src/assets/iconset/trash.svg +7 -0
- package/src/assets/iconset/trush-square-bold.svg +3 -0
- package/src/assets/iconset/unlimited.svg +3 -0
- package/src/assets/iconset/user-circle.svg +3 -0
- package/src/assets/iconset/user-jogging.svg +3 -0
- package/src/assets/iconset/user-plus-01.svg +5 -0
- package/src/assets/iconset/user-square.svg +5 -0
- package/src/assets/iconset/user-x-01.svg +5 -0
- package/src/assets/iconset/user-x-02.svg +3 -0
- package/src/assets/iconset/user2.svg +3 -0
- package/src/assets/iconset/users-02.svg +5 -0
- package/src/assets/iconset/users-speaker.svg +7 -0
- package/src/assets/iconset/verify.svg +3 -0
- package/src/assets/iconset/voice-cricle.svg +8 -0
- package/src/assets/iconset/x-circle.svg +3 -0
- package/src/assets/iconset/x-close.svg +3 -0
- package/src/assets/iconset/x-sm.svg +3 -0
- package/src/assets/iconset/zap.svg +3 -0
- package/src/assets/images/background.jpg +0 -0
- package/src/assets/loading_animation.json +1 -0
- package/src/assets/products.json +98 -0
- package/src/assets/samples/carousel-sample.json +100 -81
- package/src/assets/samples/getSamples.ts +39 -66
- package/src/assets/samples/paywall-1.json +220 -0
- package/src/assets/samples/simple-1.json +9 -2
- package/src/assets/samples/simple-2.json +37 -9
- package/src/assets/samples/vpn-onboard-1.json +326 -718
- package/src/assets/samples/vpn-onboard-2.json +329 -709
- package/src/assets/samples/vpn-onboard-3.json +297 -706
- package/src/assets/samples/vpn-onboard-4.json +297 -707
- package/src/assets/samples/vpn-onboard-5.json +440 -919
- package/src/assets/samples/vpn-onboard-6.json +301 -612
- package/src/attributes-editor/SpecialCategorySection.tsx +1 -1
- package/src/build-components/BIcon/BIcon.tsx +56 -0
- package/src/build-components/BIcon/BIconProps.generated.ts +82 -0
- package/src/build-components/BIcon/pattern.json +47 -0
- package/src/build-components/BackgroundImage/BackgroundImageProps.generated.ts +4 -0
- package/src/build-components/BackgroundImage/pattern.json +2 -2
- package/src/build-components/Button/Button.tsx +14 -1
- package/src/build-components/Button/ButtonProps.generated.ts +4 -0
- package/src/build-components/Button/pattern.json +4 -1
- package/src/build-components/Carousel/CarouselProps.generated.ts +4 -0
- package/src/build-components/Carousel/pattern.json +2 -2
- package/src/build-components/CarouselButtons/CarouselButtonsProps.generated.ts +4 -0
- package/src/build-components/CarouselButtons/pattern.json +1 -1
- package/src/build-components/CarouselDots/CarouselDotsProps.generated.ts +4 -0
- package/src/build-components/CarouselDots/pattern.json +1 -1
- package/src/build-components/CarouselItem/CarouselItem.tsx +1 -1
- package/src/build-components/CarouselItem/CarouselItemProps.generated.ts +4 -0
- package/src/build-components/CarouselItem/pattern.json +1 -1
- package/src/build-components/CarouselProvider/CarouselProvider.tsx +1 -1
- package/src/build-components/CarouselProvider/CarouselProviderProps.generated.ts +4 -0
- package/src/build-components/CarouselProvider/pattern.json +1 -1
- package/src/build-components/Image/ImageProps.generated.ts +4 -0
- package/src/build-components/Image/pattern.json +1 -1
- package/src/build-components/Main/Main.tsx +61 -0
- package/src/build-components/Main/MainProps.generated.ts +64 -0
- package/src/build-components/Main/pattern.json +35 -0
- package/src/build-components/Onboard/OnboardProps.generated.ts +4 -0
- package/src/build-components/OnboardButton/OnboardButtonProps.generated.ts +4 -0
- package/src/build-components/OnboardButtons/OnboardButtonsProps.generated.ts +4 -0
- package/src/build-components/OnboardDot/OnboardDotProps.generated.ts +4 -0
- package/src/build-components/OnboardFooter/OnboardFooterProps.generated.ts +4 -0
- package/src/build-components/OnboardImage/OnboardImageProps.generated.ts +4 -0
- package/src/build-components/OnboardItem/OnboardItem.tsx +1 -1
- package/src/build-components/OnboardItem/OnboardItemProps.generated.ts +4 -0
- package/src/build-components/OnboardProvider/OnboardProviderProps.generated.ts +4 -1
- package/src/build-components/OnboardProvider/pattern.json +6 -16
- package/src/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.ts +4 -0
- package/src/build-components/OnboardTitle/OnboardTitleProps.generated.ts +4 -0
- package/src/build-components/PaywallBackground/PaywallBackground.tsx +47 -0
- package/src/build-components/PaywallBackground/PaywallBackgroundProps.generated.ts +63 -0
- package/src/build-components/PaywallBackground/pattern.json +16 -0
- package/src/build-components/PaywallCloseButton/PaywallCloseButton.tsx +62 -0
- package/src/build-components/PaywallCloseButton/PaywallCloseButtonProps.generated.ts +83 -0
- package/src/build-components/PaywallCloseButton/pattern.json +23 -0
- package/src/build-components/PaywallOptions/PaywallOptionButton.tsx +64 -0
- package/src/build-components/PaywallOptions/PaywallOptions.tsx +92 -0
- package/src/build-components/PaywallOptions/PaywallOptionsProps.generated.ts +63 -0
- package/src/build-components/PaywallOptions/pattern.json +22 -0
- package/src/build-components/PaywallOptions/usePaywallOptionParamsFactory.ts +42 -0
- package/src/build-components/PaywallProvider/PaywallProvider.tsx +78 -0
- package/src/build-components/PaywallProvider/PaywallProviderProps.generated.ts +63 -0
- package/src/build-components/PaywallProvider/pattern.json +24 -0
- package/src/build-components/PaywallSubscribeButton/PaywallSubscribeButton.tsx +60 -0
- package/src/build-components/PaywallSubscribeButton/PaywallSubscribeButtonProps.generated.ts +77 -0
- package/src/build-components/PaywallSubscribeButton/pattern.json +27 -0
- package/src/build-components/RadioButton/RadioButton.tsx +123 -0
- package/src/build-components/RadioButton/RadioButtonProps.generated.ts +66 -0
- package/src/build-components/RadioButton/pattern.json +42 -0
- package/src/build-components/RenderNode.generated.tsx +133 -37
- package/src/build-components/Text/Text.tsx +3 -3
- package/src/build-components/Text/TextProps.generated.ts +4 -0
- package/src/build-components/Text/pattern.json +1 -1
- package/src/build-components/View/ViewProps.generated.ts +4 -0
- package/src/build-components/View/pattern.json +44 -6
- package/src/build-components/index.ts +50 -10
- package/src/build-components/patterns.generated.ts +4516 -712
- package/src/components/AttributesEditorPanel.tsx +15 -9
- package/src/components/BottomBar.tsx +236 -0
- package/src/components/Builder.tsx +3 -5
- package/src/components/BuilderButton.tsx +2 -7
- package/src/components/BuilderProvider.tsx +45 -0
- package/src/components/DeviceNavigationBar.tsx +1 -1
- package/src/components/EditorHeader.tsx +15 -5
- package/src/components/Icon.generated.tsx +540 -0
- package/src/components/LoadingComponent.tsx +10 -0
- package/src/components/LocalizationParamsProvider.tsx +22 -0
- package/src/components/MobilePanelToggleButton.tsx +39 -0
- package/src/components/ParamsProvider.tsx +38 -0
- package/src/hooks/useLocalizationParams.ts +5 -0
- package/src/hooks/useLocalize.ts +23 -0
- package/src/hooks/useMinimumDelay.ts +20 -0
- package/src/hooks/useMobileEditorPanels.ts +56 -0
- package/src/hooks/useParams.ts +8 -0
- package/src/hooks/useSafeAreaViewStyle.ts +67 -0
- package/src/hooks/useSyncProjectPageStore.ts +40 -0
- package/src/index.native.ts +75 -0
- package/src/index.ts +26 -0
- package/src/mockOS/components/MockOSRouter.tsx +9 -14
- package/src/mockOS/context/MockOSContext.tsx +12 -36
- package/src/mockOS/context/MockOSContextBase.ts +35 -0
- package/src/mockOS/index.ts +3 -2
- package/src/modals/AddComponentModal.tsx +1 -0
- package/src/modals/BenefitEditModal.tsx +160 -0
- package/src/modals/BenefitPresetsModal.tsx +166 -0
- package/src/modals/IconPickerModal.tsx +109 -0
- package/src/modals/MockableFeatureModal.tsx +292 -0
- package/src/modals/ProductEditModal.tsx +215 -0
- package/src/modals/ProductPresetsModal.tsx +151 -0
- package/src/modals/ScreenColorsModal.tsx +115 -0
- package/src/modals/index.ts +7 -0
- package/src/pages/ProjectPage.tsx +99 -232
- package/src/pages/tabs/BuilderPanel.tsx +15 -9
- package/src/paywall/hooks/index.ts +5 -0
- package/src/paywall/hooks/useCalculateLocalizedPrice.ts +6 -0
- package/src/paywall/hooks/useCarouselOptionsSeperator.ts +8 -0
- package/src/paywall/hooks/useCloseStatusPaywall.ts +6 -0
- package/src/paywall/hooks/useDiscountRate.ts +6 -0
- package/src/paywall/hooks/usePaywallCounter.ts +6 -0
- package/src/paywall/types/benefits.ts +44 -0
- package/src/paywall/types/paywall-types.ts +51 -0
- package/src/store.ts +165 -47
- package/src/styles/base/_global.scss +61 -45
- package/src/styles/components/_attributes-editor.scss +49 -6
- package/src/styles/components/_bottom-bar.scss +113 -0
- package/src/styles/components/_editor-shell.scss +0 -25
- package/src/styles/components/_ui-components.scss +2 -1
- package/src/styles/index.scss +6 -0
- package/src/styles/modals/_benefit-edit-modal.scss +17 -0
- package/src/styles/modals/_benefit-presets-modal.scss +79 -0
- package/src/styles/modals/_mockable-feature-modal.scss +15 -0
- package/src/styles/modals/_product-edit-modal.scss +23 -0
- package/src/styles/modals/_product-presets-modal.scss +81 -0
- package/src/types/Icons.ts +244 -0
- package/src/types/Project.ts +5 -0
- package/src/types/jest-globals.d.ts +13 -0
- package/src/utils/analyseNode.ts +22 -109
- package/src/utils/analyseNodeByPatterns.ts +453 -0
- package/src/utils/analyseNodeStructural.ts +52 -0
- package/src/utils/extractViewStyle.ts +19 -0
- package/src/utils/findNodeByKeyNested.ts +32 -0
- package/src/utils/isCarousel.ts +21 -5
- package/src/utils/nodeGuards.ts +26 -0
- package/src/utils/nodeTree.ts +99 -0
- package/src/utils/novaToJson.ts +21 -9
- package/src/utils/patterns.ts +62 -3
- package/src/utils/replaceLocalizationParams.ts +15 -0
- package/dist/pages/tabs/SideTool.d.ts +0 -8
- package/src/pages/tabs/SideTool.tsx +0 -260
package/src/utils/analyseNode.ts
CHANGED
|
@@ -1,59 +1,15 @@
|
|
|
1
1
|
import { Node, NodeData, NodeDefaultAttribute } from '../types/Node';
|
|
2
2
|
import { generateRandomKeyForNode } from './generateRandomKeyForNode';
|
|
3
|
+
import { analyseNodeByPatterns } from './analyseNodeByPatterns';
|
|
4
|
+
import { analyseNodeStructural } from './analyseNodeStructural';
|
|
5
|
+
import { isNodeArray, isNodeNullOrUndefined, isNodeString } from './nodeGuards';
|
|
3
6
|
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
return typeof node === 'string';
|
|
11
|
-
}
|
|
12
|
-
export function isNodeArray<T = NodeDefaultAttribute>(node: Node<T>): boolean {
|
|
13
|
-
return node instanceof Array;
|
|
14
|
-
}
|
|
15
|
-
export function isEmptyObject<T = NodeDefaultAttribute>(
|
|
16
|
-
node: Node<T>,
|
|
17
|
-
): boolean {
|
|
18
|
-
return Object.keys(node as Object).length === 0;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function collectDuplicateKey(
|
|
22
|
-
node: Node<NodeDefaultAttribute>,
|
|
23
|
-
usedKeys: Set<string>,
|
|
24
|
-
): string | null {
|
|
25
|
-
if (isNodeNullOrUndefined(node) || isNodeString(node)) {
|
|
26
|
-
return null;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (isNodeArray(node)) {
|
|
30
|
-
const nodeArray = node as unknown as Node<NodeDefaultAttribute>[];
|
|
31
|
-
for (const value of nodeArray) {
|
|
32
|
-
const duplicate = collectDuplicateKey(value, usedKeys);
|
|
33
|
-
if (duplicate) {
|
|
34
|
-
return duplicate;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
return null;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const recordData = node as NodeData<NodeDefaultAttribute>;
|
|
41
|
-
if (recordData.key) {
|
|
42
|
-
if (usedKeys.has(recordData.key)) {
|
|
43
|
-
return recordData.key;
|
|
44
|
-
}
|
|
45
|
-
usedKeys.add(recordData.key);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (recordData.children) {
|
|
49
|
-
return collectDuplicateKey(
|
|
50
|
-
recordData.children as Node<NodeDefaultAttribute>,
|
|
51
|
-
usedKeys,
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return null;
|
|
56
|
-
}
|
|
7
|
+
export {
|
|
8
|
+
isEmptyObject,
|
|
9
|
+
isNodeArray,
|
|
10
|
+
isNodeNullOrUndefined,
|
|
11
|
+
isNodeString,
|
|
12
|
+
} from './nodeGuards';
|
|
57
13
|
|
|
58
14
|
function assignMissingKeys(
|
|
59
15
|
node: Node<NodeDefaultAttribute>,
|
|
@@ -73,12 +29,17 @@ function assignMissingKeys(
|
|
|
73
29
|
const recordData = node as NodeData<NodeDefaultAttribute>;
|
|
74
30
|
|
|
75
31
|
let key = recordData.key;
|
|
32
|
+
if (key && usedKeys.has(key)) {
|
|
33
|
+
// Repair duplicate keys by generating a new unique key.
|
|
34
|
+
key = undefined;
|
|
35
|
+
}
|
|
36
|
+
|
|
76
37
|
if (!key) {
|
|
77
38
|
do {
|
|
78
39
|
key = generateRandomKeyForNode(recordData.type);
|
|
79
40
|
} while (usedKeys.has(key));
|
|
80
|
-
usedKeys.add(key);
|
|
81
41
|
}
|
|
42
|
+
usedKeys.add(key);
|
|
82
43
|
|
|
83
44
|
const children = recordData.children
|
|
84
45
|
? (assignMissingKeys(
|
|
@@ -98,59 +59,16 @@ export function analyseNode(node: Node<NodeDefaultAttribute>): {
|
|
|
98
59
|
valid: boolean;
|
|
99
60
|
message?: string;
|
|
100
61
|
} {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
valid: true,
|
|
104
|
-
message: 'null or undefined is valid',
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (isNodeString(node)) {
|
|
109
|
-
return {
|
|
110
|
-
valid: true,
|
|
111
|
-
message: 'string is valid',
|
|
112
|
-
};
|
|
113
|
-
}
|
|
62
|
+
const structural = analyseNodeStructural(node);
|
|
63
|
+
if (!structural.valid) return structural;
|
|
114
64
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if (!valid) {
|
|
120
|
-
return {
|
|
121
|
-
valid: false,
|
|
122
|
-
message: message,
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
return {
|
|
127
|
-
// array is valid
|
|
128
|
-
valid: true,
|
|
129
|
-
message: 'Array is valid',
|
|
130
|
-
};
|
|
65
|
+
const patternRes = analyseNodeByPatterns(node);
|
|
66
|
+
if (!patternRes.valid) {
|
|
67
|
+
const prefix = patternRes.path ? `${patternRes.path}: ` : '';
|
|
68
|
+
return { valid: false, message: `${prefix}${patternRes.message ?? ''}` };
|
|
131
69
|
}
|
|
132
|
-
const recordData = node as NodeData;
|
|
133
|
-
if (isEmptyObject(recordData)) {
|
|
134
|
-
return {
|
|
135
|
-
valid: true,
|
|
136
|
-
message: 'empty object is valid',
|
|
137
|
-
};
|
|
138
|
-
} else {
|
|
139
|
-
if (recordData.children) {
|
|
140
|
-
const { valid, message } = analyseNode(recordData.children);
|
|
141
|
-
if (!valid) {
|
|
142
|
-
return {
|
|
143
|
-
valid: false,
|
|
144
|
-
message: message,
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
70
|
|
|
149
|
-
|
|
150
|
-
valid: true,
|
|
151
|
-
message: 'everthing is valid',
|
|
152
|
-
};
|
|
153
|
-
}
|
|
71
|
+
return { valid: true, message: 'Node is valid (structure + patterns)' };
|
|
154
72
|
}
|
|
155
73
|
|
|
156
74
|
export function analyseAndProccess(
|
|
@@ -166,10 +84,5 @@ export function analyseAndProccess(
|
|
|
166
84
|
}
|
|
167
85
|
|
|
168
86
|
const usedKeys = new Set<string>();
|
|
169
|
-
const duplicateKey = collectDuplicateKey(node, usedKeys);
|
|
170
|
-
if (duplicateKey) {
|
|
171
|
-
throw new Error(`Duplicate node key detected: ${duplicateKey}`);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
87
|
return assignMissingKeys(node, usedKeys);
|
|
175
88
|
}
|
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
import type { Node, NodeData, NodeDefaultAttribute } from '../types/Node';
|
|
2
|
+
import {
|
|
3
|
+
getArrayItemType,
|
|
4
|
+
getAttributeSchema,
|
|
5
|
+
getPatternByType,
|
|
6
|
+
getTypeSchema,
|
|
7
|
+
isPrimitiveType,
|
|
8
|
+
normalizeComponentType,
|
|
9
|
+
} from './patterns';
|
|
10
|
+
import {
|
|
11
|
+
isEmptyObject,
|
|
12
|
+
isNodeArray,
|
|
13
|
+
isNodeNullOrUndefined,
|
|
14
|
+
isNodeString,
|
|
15
|
+
} from './nodeGuards';
|
|
16
|
+
|
|
17
|
+
export type AnalyseResultWithPath = {
|
|
18
|
+
valid: boolean;
|
|
19
|
+
message?: string;
|
|
20
|
+
path?: string;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
type AttributeTypeSpec = string | string[];
|
|
24
|
+
type AttributeSchema = Record<string, AttributeTypeSpec>;
|
|
25
|
+
|
|
26
|
+
type PatternLike = {
|
|
27
|
+
allowUnknownAttributes: boolean;
|
|
28
|
+
pattern: {
|
|
29
|
+
type: string;
|
|
30
|
+
children: unknown;
|
|
31
|
+
attributes?: AttributeSchema;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
function ok(): AnalyseResultWithPath {
|
|
36
|
+
return { valid: true };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function fail(message: string, path?: string): AnalyseResultWithPath {
|
|
40
|
+
return { valid: false, message, path };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function joinPath(base: string, next: string): string {
|
|
44
|
+
if (!base) return next;
|
|
45
|
+
if (!next) return base;
|
|
46
|
+
// next may already include brackets (e.g. [0])
|
|
47
|
+
return next.startsWith('[') ? `${base}${next}` : `${base}.${next}`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
51
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function isNodeDataLike(
|
|
55
|
+
value: unknown,
|
|
56
|
+
): value is NodeData<NodeDefaultAttribute> {
|
|
57
|
+
if (!isPlainObject(value)) return false;
|
|
58
|
+
const maybeType = (value as Record<string, unknown>).type;
|
|
59
|
+
return typeof maybeType === 'string' && 'children' in value;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function normalizeTypeOrFallback(type: string): string {
|
|
63
|
+
return normalizeComponentType(type) ?? type;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function getChildrenSpecTokens(pattern: PatternLike): string[] {
|
|
67
|
+
const raw = pattern?.pattern?.children;
|
|
68
|
+
if (typeof raw === 'string') return [raw];
|
|
69
|
+
if (Array.isArray(raw)) return raw.filter((x) => typeof x === 'string');
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function splitChildrenSpec(tokens: string[]): {
|
|
74
|
+
baseKinds: Set<'never' | 'string' | 'node' | 'array'>;
|
|
75
|
+
allowedComponentTypes: Set<string>;
|
|
76
|
+
} {
|
|
77
|
+
const baseKinds = new Set<'never' | 'string' | 'node' | 'array'>();
|
|
78
|
+
const allowedComponentTypes = new Set<string>();
|
|
79
|
+
for (const t of tokens) {
|
|
80
|
+
if (t === 'never' || t === 'string' || t === 'node' || t === 'array') {
|
|
81
|
+
baseKinds.add(t);
|
|
82
|
+
} else if (typeof t === 'string' && t) {
|
|
83
|
+
allowedComponentTypes.add(normalizeTypeOrFallback(t));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return { baseKinds, allowedComponentTypes };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function validateChildrenNeverRule(
|
|
90
|
+
children: Node<NodeDefaultAttribute>,
|
|
91
|
+
baseKinds: Set<'never' | 'string' | 'node' | 'array'>,
|
|
92
|
+
path: string,
|
|
93
|
+
): AnalyseResultWithPath {
|
|
94
|
+
if (!baseKinds.has('never')) return ok();
|
|
95
|
+
if (isNodeNullOrUndefined(children) || isEmptyObject(children)) return ok();
|
|
96
|
+
return fail(`Children not allowed (pattern.children = "never")`, path);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function validateChildrenKindRule(
|
|
100
|
+
children: Node<NodeDefaultAttribute>,
|
|
101
|
+
baseKinds: Set<'never' | 'string' | 'node' | 'array'>,
|
|
102
|
+
allowedComponentTypes: Set<string>,
|
|
103
|
+
path: string,
|
|
104
|
+
): AnalyseResultWithPath {
|
|
105
|
+
if (isNodeNullOrUndefined(children) || isEmptyObject(children)) return ok();
|
|
106
|
+
|
|
107
|
+
// Component-type specs allow either a single node or an array of nodes.
|
|
108
|
+
if (allowedComponentTypes.size > 0) {
|
|
109
|
+
if (isNodeArray(children)) return ok();
|
|
110
|
+
if (isNodeDataLike(children)) return ok();
|
|
111
|
+
return fail(
|
|
112
|
+
`Children must be a node or array of nodes (allowed: ${Array.from(
|
|
113
|
+
allowedComponentTypes,
|
|
114
|
+
).join(', ')})`,
|
|
115
|
+
path,
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (isNodeString(children)) {
|
|
120
|
+
return baseKinds.has('string')
|
|
121
|
+
? ok()
|
|
122
|
+
: fail(`Children must not be a string`, path);
|
|
123
|
+
}
|
|
124
|
+
if (isNodeArray(children)) {
|
|
125
|
+
return baseKinds.has('array')
|
|
126
|
+
? ok()
|
|
127
|
+
: fail(`Children must not be an array`, path);
|
|
128
|
+
}
|
|
129
|
+
if (isNodeDataLike(children)) {
|
|
130
|
+
return baseKinds.has('node')
|
|
131
|
+
? ok()
|
|
132
|
+
: fail(`Children must not be a node`, path);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Unknown object shape
|
|
136
|
+
return fail(`Children has invalid shape`, path);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function validateChildrenAllowedComponentTypesRule(
|
|
140
|
+
children: Node<NodeDefaultAttribute>,
|
|
141
|
+
allowedComponentTypes: Set<string>,
|
|
142
|
+
path: string,
|
|
143
|
+
): AnalyseResultWithPath {
|
|
144
|
+
if (allowedComponentTypes.size === 0) return ok();
|
|
145
|
+
if (isNodeNullOrUndefined(children) || isEmptyObject(children)) return ok();
|
|
146
|
+
|
|
147
|
+
const allowed = Array.from(allowedComponentTypes);
|
|
148
|
+
|
|
149
|
+
const validateChildType = (child: unknown, childPath: string) => {
|
|
150
|
+
if (!isNodeDataLike(child)) {
|
|
151
|
+
return fail(`Child must be an object node`, childPath);
|
|
152
|
+
}
|
|
153
|
+
const actual = normalizeTypeOrFallback(child.type);
|
|
154
|
+
if (!allowedComponentTypes.has(actual)) {
|
|
155
|
+
return fail(
|
|
156
|
+
`Child type "${child.type}" is not allowed here (allowed: ${allowed.join(
|
|
157
|
+
', ',
|
|
158
|
+
)})`,
|
|
159
|
+
joinPath(childPath, 'type'),
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
return ok();
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
if (isNodeArray(children)) {
|
|
166
|
+
const arr = children as unknown[];
|
|
167
|
+
for (let i = 0; i < arr.length; i++) {
|
|
168
|
+
const res = validateChildType(arr[i], `${path}[${i}]`);
|
|
169
|
+
if (!res.valid) return res;
|
|
170
|
+
}
|
|
171
|
+
return ok();
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return validateChildType(children, path);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function validateChildrenByPattern(
|
|
178
|
+
nodeData: NodeData<NodeDefaultAttribute>,
|
|
179
|
+
pattern: PatternLike,
|
|
180
|
+
path: string,
|
|
181
|
+
): AnalyseResultWithPath {
|
|
182
|
+
const tokens = getChildrenSpecTokens(pattern);
|
|
183
|
+
const { baseKinds, allowedComponentTypes } = splitChildrenSpec(tokens);
|
|
184
|
+
|
|
185
|
+
const neverRes = validateChildrenNeverRule(
|
|
186
|
+
nodeData.children,
|
|
187
|
+
baseKinds,
|
|
188
|
+
path,
|
|
189
|
+
);
|
|
190
|
+
if (!neverRes.valid) return neverRes;
|
|
191
|
+
|
|
192
|
+
const kindRes = validateChildrenKindRule(
|
|
193
|
+
nodeData.children,
|
|
194
|
+
baseKinds,
|
|
195
|
+
allowedComponentTypes,
|
|
196
|
+
path,
|
|
197
|
+
);
|
|
198
|
+
if (!kindRes.valid) return kindRes;
|
|
199
|
+
|
|
200
|
+
return validateChildrenAllowedComponentTypesRule(
|
|
201
|
+
nodeData.children,
|
|
202
|
+
allowedComponentTypes,
|
|
203
|
+
path,
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function validatePrimitiveValue(
|
|
208
|
+
value: unknown,
|
|
209
|
+
primitiveType: string,
|
|
210
|
+
path: string,
|
|
211
|
+
): AnalyseResultWithPath {
|
|
212
|
+
switch (primitiveType) {
|
|
213
|
+
case 'string':
|
|
214
|
+
return typeof value === 'string' ? ok() : fail(`Expected string`, path);
|
|
215
|
+
case 'number':
|
|
216
|
+
return typeof value === 'number' ? ok() : fail(`Expected number`, path);
|
|
217
|
+
case 'boolean':
|
|
218
|
+
return typeof value === 'boolean' ? ok() : fail(`Expected boolean`, path);
|
|
219
|
+
case 'color':
|
|
220
|
+
return typeof value === 'string'
|
|
221
|
+
? ok()
|
|
222
|
+
: fail(`Expected color (string)`, path);
|
|
223
|
+
case 'size':
|
|
224
|
+
// Sizes can be numbers or strings like "16@fs" / "100%" / "20px"
|
|
225
|
+
return typeof value === 'number' || typeof value === 'string'
|
|
226
|
+
? ok()
|
|
227
|
+
: fail(`Expected size (string or number)`, path);
|
|
228
|
+
case 'iconType':
|
|
229
|
+
return typeof value === 'string'
|
|
230
|
+
? ok()
|
|
231
|
+
: fail(`Expected iconType (string)`, path);
|
|
232
|
+
default:
|
|
233
|
+
return fail(`Unknown primitive type "${primitiveType}"`, path);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function validateEnumValue(
|
|
238
|
+
value: unknown,
|
|
239
|
+
options: string[],
|
|
240
|
+
path: string,
|
|
241
|
+
): AnalyseResultWithPath {
|
|
242
|
+
if (typeof value === 'string') {
|
|
243
|
+
return options.includes(value)
|
|
244
|
+
? ok()
|
|
245
|
+
: fail(`Expected one of: ${options.join(', ')}`, path);
|
|
246
|
+
}
|
|
247
|
+
if (Array.isArray(value)) {
|
|
248
|
+
for (let i = 0; i < value.length; i++) {
|
|
249
|
+
const v = value[i];
|
|
250
|
+
if (typeof v !== 'string' || !options.includes(v)) {
|
|
251
|
+
return fail(
|
|
252
|
+
`Expected an array of: ${options.join(', ')}`,
|
|
253
|
+
`${path}[${i}]`,
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return ok();
|
|
258
|
+
}
|
|
259
|
+
return fail(`Expected a string or string[] enum value`, path);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function validateCustomObjectValue(
|
|
263
|
+
componentType: string,
|
|
264
|
+
value: unknown,
|
|
265
|
+
typeName: string,
|
|
266
|
+
path: string,
|
|
267
|
+
): AnalyseResultWithPath {
|
|
268
|
+
const schema = getTypeSchema(componentType, typeName);
|
|
269
|
+
if (!schema) {
|
|
270
|
+
return fail(`Unknown custom type "${typeName}"`, path);
|
|
271
|
+
}
|
|
272
|
+
if (!isPlainObject(value)) {
|
|
273
|
+
return fail(`Expected object for type "${typeName}"`, path);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
for (const [fieldName, fieldSpec] of Object.entries(schema)) {
|
|
277
|
+
if (!(fieldName in value)) continue;
|
|
278
|
+
const fieldValue = (value as Record<string, unknown>)[fieldName];
|
|
279
|
+
const fieldPath = joinPath(path, fieldName);
|
|
280
|
+
const res = validateAttributeValue(
|
|
281
|
+
componentType,
|
|
282
|
+
fieldValue,
|
|
283
|
+
fieldSpec,
|
|
284
|
+
fieldPath,
|
|
285
|
+
);
|
|
286
|
+
if (!res.valid) return res;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return ok();
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function validateAttributeValue(
|
|
293
|
+
componentType: string,
|
|
294
|
+
value: unknown,
|
|
295
|
+
spec: AttributeTypeSpec,
|
|
296
|
+
path: string,
|
|
297
|
+
): AnalyseResultWithPath {
|
|
298
|
+
if (Array.isArray(spec)) {
|
|
299
|
+
return validateEnumValue(value, spec, path);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const arrayItemType = getArrayItemType(spec);
|
|
303
|
+
if (arrayItemType) {
|
|
304
|
+
if (!Array.isArray(value)) {
|
|
305
|
+
return fail(`Expected array for type "${spec}"`, path);
|
|
306
|
+
}
|
|
307
|
+
for (let i = 0; i < value.length; i++) {
|
|
308
|
+
const item = value[i];
|
|
309
|
+
const itemPath = `${path}[${i}]`;
|
|
310
|
+
const res = validateAttributeValue(
|
|
311
|
+
componentType,
|
|
312
|
+
item,
|
|
313
|
+
arrayItemType,
|
|
314
|
+
itemPath,
|
|
315
|
+
);
|
|
316
|
+
if (!res.valid) return res;
|
|
317
|
+
}
|
|
318
|
+
return ok();
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (isPrimitiveType(spec)) {
|
|
322
|
+
return validatePrimitiveValue(value, spec, path);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
return validateCustomObjectValue(componentType, value, spec, path);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function validateAttributesByPattern(
|
|
329
|
+
nodeData: NodeData<NodeDefaultAttribute>,
|
|
330
|
+
pattern: PatternLike,
|
|
331
|
+
path: string,
|
|
332
|
+
): AnalyseResultWithPath {
|
|
333
|
+
const attrs = nodeData.attributes;
|
|
334
|
+
if (attrs == null) return ok();
|
|
335
|
+
if (!isPlainObject(attrs)) return fail(`attributes must be an object`, path);
|
|
336
|
+
|
|
337
|
+
const componentType = normalizeTypeOrFallback(pattern.pattern.type);
|
|
338
|
+
|
|
339
|
+
const schema: AttributeSchema = (getAttributeSchema(pattern.pattern.type) ??
|
|
340
|
+
pattern.pattern.attributes ??
|
|
341
|
+
{}) as AttributeSchema;
|
|
342
|
+
|
|
343
|
+
for (const [attrName, attrValue] of Object.entries(attrs)) {
|
|
344
|
+
// Legacy compatibility: older onboard samples/projects stored theme on the provider.
|
|
345
|
+
// Modern projects store theme under `appConfig.theme`, but we still accept this
|
|
346
|
+
// attribute to avoid breaking existing JSON.
|
|
347
|
+
if (componentType === 'OnboardProvider' && attrName === 'theme') {
|
|
348
|
+
if (typeof attrValue !== 'string') {
|
|
349
|
+
return fail(`Expected one of: light, dark`, joinPath(path, attrName));
|
|
350
|
+
}
|
|
351
|
+
if (attrValue !== 'light' && attrValue !== 'dark') {
|
|
352
|
+
return fail(`Expected one of: light, dark`, joinPath(path, attrName));
|
|
353
|
+
}
|
|
354
|
+
continue;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
const attrSpec = schema?.[attrName];
|
|
358
|
+
if (!attrSpec) {
|
|
359
|
+
if (pattern.allowUnknownAttributes) continue;
|
|
360
|
+
return fail(`Unknown attribute "${attrName}"`, joinPath(path, attrName));
|
|
361
|
+
}
|
|
362
|
+
const res = validateAttributeValue(
|
|
363
|
+
pattern.pattern.type,
|
|
364
|
+
attrValue,
|
|
365
|
+
attrSpec,
|
|
366
|
+
joinPath(path, attrName),
|
|
367
|
+
);
|
|
368
|
+
if (!res.valid) return res;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
return ok();
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function validateNodeDataByPatterns(
|
|
375
|
+
nodeData: NodeData<NodeDefaultAttribute>,
|
|
376
|
+
path: string,
|
|
377
|
+
): AnalyseResultWithPath {
|
|
378
|
+
const normalizedType = normalizeTypeOrFallback(nodeData.type);
|
|
379
|
+
const pattern = getPatternByType(normalizedType) as unknown as
|
|
380
|
+
| PatternLike
|
|
381
|
+
| undefined;
|
|
382
|
+
if (!pattern) {
|
|
383
|
+
return fail(
|
|
384
|
+
`Unknown component type "${nodeData.type}"`,
|
|
385
|
+
joinPath(path, 'type'),
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
const attrRes = validateAttributesByPattern(
|
|
390
|
+
{ ...nodeData, type: normalizedType },
|
|
391
|
+
pattern,
|
|
392
|
+
joinPath(path, 'attributes'),
|
|
393
|
+
);
|
|
394
|
+
if (!attrRes.valid) return attrRes;
|
|
395
|
+
|
|
396
|
+
const childrenRes = validateChildrenByPattern(
|
|
397
|
+
{ ...nodeData, type: normalizedType },
|
|
398
|
+
pattern,
|
|
399
|
+
joinPath(path, 'children'),
|
|
400
|
+
);
|
|
401
|
+
if (!childrenRes.valid) return childrenRes;
|
|
402
|
+
|
|
403
|
+
return ok();
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function validateAnyNodeByPatterns(
|
|
407
|
+
node: Node<NodeDefaultAttribute>,
|
|
408
|
+
path: string,
|
|
409
|
+
): AnalyseResultWithPath {
|
|
410
|
+
if (
|
|
411
|
+
isNodeNullOrUndefined(node) ||
|
|
412
|
+
isNodeString(node) ||
|
|
413
|
+
isEmptyObject(node)
|
|
414
|
+
) {
|
|
415
|
+
return ok();
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
if (isNodeArray(node)) {
|
|
419
|
+
const arr = node as unknown as Node<NodeDefaultAttribute>[];
|
|
420
|
+
for (let i = 0; i < arr.length; i++) {
|
|
421
|
+
const res = validateAnyNodeByPatterns(arr[i], `${path}[${i}]`);
|
|
422
|
+
if (!res.valid) return res;
|
|
423
|
+
}
|
|
424
|
+
return ok();
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
if (!isNodeDataLike(node)) {
|
|
428
|
+
return fail(`Invalid node shape`, path);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
const selfRes = validateNodeDataByPatterns(node, path);
|
|
432
|
+
if (!selfRes.valid) return selfRes;
|
|
433
|
+
|
|
434
|
+
return validateAnyNodeByPatterns(
|
|
435
|
+
node.children as Node<NodeDefaultAttribute>,
|
|
436
|
+
joinPath(path, 'children'),
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Validates a Node tree against the generated component patterns:
|
|
442
|
+
* - Enforces `pattern.children` including "never"
|
|
443
|
+
* - Validates `attributes` against `pattern.attributes` (+ custom `types`)
|
|
444
|
+
*
|
|
445
|
+
* Notes:
|
|
446
|
+
* - Null/undefined children are considered "no children" and are allowed even
|
|
447
|
+
* when patterns expect some kind of children.
|
|
448
|
+
*/
|
|
449
|
+
export function analyseNodeByPatterns(
|
|
450
|
+
node: Node<NodeDefaultAttribute>,
|
|
451
|
+
): AnalyseResultWithPath {
|
|
452
|
+
return validateAnyNodeByPatterns(node, 'root');
|
|
453
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { Node, NodeData, NodeDefaultAttribute } from '../types/Node';
|
|
2
|
+
import {
|
|
3
|
+
isEmptyObject,
|
|
4
|
+
isNodeArray,
|
|
5
|
+
isNodeNullOrUndefined,
|
|
6
|
+
isNodeString,
|
|
7
|
+
} from './nodeGuards';
|
|
8
|
+
|
|
9
|
+
export type AnalyseResult = {
|
|
10
|
+
valid: boolean;
|
|
11
|
+
message?: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Structural validation only:
|
|
16
|
+
* - Ensures the input is a valid Node union recursively (null/string/array/object)
|
|
17
|
+
* - Does NOT validate against component patterns.
|
|
18
|
+
*/
|
|
19
|
+
export function analyseNodeStructural(
|
|
20
|
+
node: Node<NodeDefaultAttribute>,
|
|
21
|
+
): AnalyseResult {
|
|
22
|
+
if (isNodeNullOrUndefined(node)) {
|
|
23
|
+
return { valid: true, message: 'null or undefined is valid' };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (isNodeString(node)) {
|
|
27
|
+
return { valid: true, message: 'string is valid' };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (isNodeArray(node)) {
|
|
31
|
+
const nodeArray = node as unknown as Node[];
|
|
32
|
+
for (const value of nodeArray) {
|
|
33
|
+
const res = analyseNodeStructural(value as Node<NodeDefaultAttribute>);
|
|
34
|
+
if (!res.valid) return res;
|
|
35
|
+
}
|
|
36
|
+
return { valid: true, message: 'Array is valid' };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const recordData = node as NodeData;
|
|
40
|
+
if (isEmptyObject(recordData)) {
|
|
41
|
+
return { valid: true, message: 'empty object is valid' };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (recordData.children) {
|
|
45
|
+
const res = analyseNodeStructural(
|
|
46
|
+
recordData.children as Node<NodeDefaultAttribute>,
|
|
47
|
+
);
|
|
48
|
+
if (!res.valid) return res;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return { valid: true, message: 'everything is structurally valid' };
|
|
52
|
+
}
|
|
@@ -26,6 +26,9 @@ export function extractViewStyle<T extends ViewPropsGenerated['attributes']>(
|
|
|
26
26
|
value === null ||
|
|
27
27
|
(typeof value === 'string' && value.trim() === '');
|
|
28
28
|
if (scrollable) {
|
|
29
|
+
// Important for flex children: allow the element to shrink so overflow scroll can work.
|
|
30
|
+
style.minWidth = 0;
|
|
31
|
+
style.minHeight = 0;
|
|
29
32
|
if (attributes.flexDirection === 'row') {
|
|
30
33
|
style.overflowX = 'auto';
|
|
31
34
|
style.overflowY = 'hidden';
|
|
@@ -102,7 +105,23 @@ export function extractViewStyle<T extends ViewPropsGenerated['attributes']>(
|
|
|
102
105
|
}
|
|
103
106
|
setParsedSize('borderRadius', attributes.borderRadius);
|
|
104
107
|
setParsedSize('width', attributes.width);
|
|
108
|
+
setParsedSize(
|
|
109
|
+
'minWidth',
|
|
110
|
+
(attributes as ViewPropsGenerated['attributes']).minWidth,
|
|
111
|
+
);
|
|
112
|
+
setParsedSize(
|
|
113
|
+
'maxWidth',
|
|
114
|
+
(attributes as ViewPropsGenerated['attributes']).maxWidth,
|
|
115
|
+
);
|
|
105
116
|
setParsedSize('height', attributes.height);
|
|
117
|
+
setParsedSize(
|
|
118
|
+
'minHeight',
|
|
119
|
+
(attributes as ViewPropsGenerated['attributes']).minHeight,
|
|
120
|
+
);
|
|
121
|
+
setParsedSize(
|
|
122
|
+
'maxHeight',
|
|
123
|
+
(attributes as ViewPropsGenerated['attributes']).maxHeight,
|
|
124
|
+
);
|
|
106
125
|
if (attributes.flex !== undefined)
|
|
107
126
|
style.flex = attributes.flex as React.CSSProperties['flex'];
|
|
108
127
|
if (attributes.position)
|