@developer_tribe/react-builder 0.1.31 → 1.1.0

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 (102) hide show
  1. package/dist/DeviceMockFrame.d.ts +1 -17
  2. package/dist/RenderPage.d.ts +1 -9
  3. package/dist/build-components/Button/ButtonProps.generated.d.ts +2 -1
  4. package/dist/build-components/CarouselButtons/CarouselButtonsProps.generated.d.ts +2 -1
  5. package/dist/build-components/CarouselDots/CarouselDotsProps.generated.d.ts +2 -1
  6. package/dist/build-components/Image/ImageProps.generated.d.ts +2 -1
  7. package/dist/build-components/OnboardButton/OnboardButtonProps.generated.d.ts +8 -4
  8. package/dist/build-components/OnboardButtons/OnboardButtonsProps.generated.d.ts +6 -3
  9. package/dist/build-components/OnboardDot/OnboardDotProps.generated.d.ts +2 -1
  10. package/dist/build-components/OnboardFooter/OnboardFooterProps.generated.d.ts +10 -5
  11. package/dist/build-components/OnboardImage/OnboardImageProps.generated.d.ts +4 -1
  12. package/dist/build-components/OnboardItem/OnboardItemProps.generated.d.ts +4 -2
  13. package/dist/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.d.ts +10 -5
  14. package/dist/build-components/OnboardTitle/OnboardTitleProps.generated.d.ts +10 -5
  15. package/dist/build-components/Text/TextProps.generated.d.ts +10 -5
  16. package/dist/build-components/View/ViewProps.generated.d.ts +6 -3
  17. package/dist/build-components/index.d.ts +1 -0
  18. package/dist/build-components/patterns.generated.d.ts +7 -2
  19. package/dist/components/AttributesEditorPanel.d.ts +9 -0
  20. package/dist/components/Breadcrumb.d.ts +13 -0
  21. package/dist/components/Builder.d.ts +9 -0
  22. package/dist/components/EditorHeader.d.ts +15 -0
  23. package/dist/index.cjs.js +7 -4
  24. package/dist/index.cjs.js.map +1 -0
  25. package/dist/index.d.ts +5 -4
  26. package/dist/index.esm.js +7 -4
  27. package/dist/index.esm.js.map +1 -0
  28. package/dist/pages/ProjectPage.d.ts +9 -0
  29. package/dist/pages/tabs/BuilderTab.d.ts +9 -0
  30. package/dist/pages/tabs/DebugTab.d.ts +7 -0
  31. package/dist/pages/tabs/PreviewTab.d.ts +3 -0
  32. package/dist/store.d.ts +8 -18
  33. package/dist/styles.css +1 -1
  34. package/dist/types/PreviewConfig.d.ts +6 -3
  35. package/dist/types/Project.d.ts +2 -2
  36. package/dist/utils/copyNode.d.ts +2 -0
  37. package/package.json +17 -9
  38. package/scripts/prebuild/utils/createBuildComponentsIndex.js +15 -1
  39. package/scripts/prebuild/utils/createGeneratedProps.js +64 -5
  40. package/src/DeviceMockFrame.tsx +20 -31
  41. package/src/RenderPage.tsx +3 -38
  42. package/src/assets/images/android.svg +43 -0
  43. package/src/assets/images/apple.svg +16 -0
  44. package/src/assets/images/background.jpg +0 -0
  45. package/src/assets/samples/carousel-sample.json +2 -3
  46. package/src/assets/samples/getSamples.ts +51 -8
  47. package/src/assets/samples/simple-1.json +1 -2
  48. package/src/assets/samples/simple-2.json +1 -2
  49. package/src/assets/samples/vpn-onboard-1.json +1 -2
  50. package/src/assets/samples/vpn-onboard-2.json +1 -2
  51. package/src/assets/samples/vpn-onboard-3.json +1 -2
  52. package/src/assets/samples/vpn-onboard-4.json +1 -2
  53. package/src/assets/samples/vpn-onboard-5.json +1024 -0
  54. package/src/assets/samples/vpn-onboard-6.json +708 -0
  55. package/src/build-components/Button/ButtonProps.generated.ts +14 -12
  56. package/src/build-components/CarouselButtons/CarouselButtonsProps.generated.ts +6 -1
  57. package/src/build-components/CarouselDots/CarouselDotsProps.generated.ts +9 -7
  58. package/src/build-components/Image/ImageProps.generated.ts +3 -1
  59. package/src/build-components/OnboardButton/OnboardButton.tsx +5 -4
  60. package/src/build-components/OnboardButton/OnboardButtonProps.generated.ts +14 -9
  61. package/src/build-components/OnboardButton/pattern.json +3 -2
  62. package/src/build-components/OnboardButtons/OnboardButtons.tsx +5 -7
  63. package/src/build-components/OnboardButtons/OnboardButtonsProps.generated.ts +10 -3
  64. package/src/build-components/OnboardDot/OnboardDotProps.generated.ts +9 -7
  65. package/src/build-components/OnboardFooter/OnboardFooter.tsx +3 -3
  66. package/src/build-components/OnboardFooter/OnboardFooterProps.generated.ts +33 -22
  67. package/src/build-components/OnboardImage/OnboardImage.tsx +24 -1
  68. package/src/build-components/OnboardImage/OnboardImageProps.generated.ts +5 -1
  69. package/src/build-components/OnboardImage/pattern.json +3 -5
  70. package/src/build-components/OnboardItem/OnboardItemProps.generated.ts +5 -2
  71. package/src/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.ts +33 -22
  72. package/src/build-components/OnboardTitle/OnboardTitleProps.generated.ts +33 -22
  73. package/src/build-components/Text/Text.tsx +3 -3
  74. package/src/build-components/Text/TextProps.generated.ts +33 -22
  75. package/src/build-components/View/ViewProps.generated.ts +18 -9
  76. package/src/build-components/index.ts +22 -0
  77. package/src/build-components/patterns.generated.ts +7 -2
  78. package/src/components/AttributesEditorPanel.tsx +110 -0
  79. package/src/components/Breadcrumb.tsx +46 -0
  80. package/src/components/Builder.tsx +270 -0
  81. package/src/components/EditorHeader.tsx +184 -0
  82. package/src/index.ts +5 -4
  83. package/src/pages/ProjectPage.tsx +112 -0
  84. package/src/pages/tabs/BuilderTab.tsx +31 -0
  85. package/src/pages/tabs/DebugTab.tsx +21 -0
  86. package/src/pages/tabs/PreviewTab.tsx +192 -0
  87. package/src/size-matters/index.ts +5 -1
  88. package/src/store.ts +26 -38
  89. package/src/styles/_mixins.scss +21 -0
  90. package/src/styles/_variables.scss +27 -0
  91. package/src/styles/builder.scss +60 -0
  92. package/src/styles/components.scss +88 -0
  93. package/src/styles/editor.scss +174 -0
  94. package/src/styles/global.scss +200 -0
  95. package/src/styles/index.scss +7 -0
  96. package/src/styles/pages.scss +2 -0
  97. package/src/types/PreviewConfig.ts +14 -5
  98. package/src/types/Project.ts +2 -2
  99. package/src/utils/copyNode.ts +7 -0
  100. package/src/utils/extractTextStyle.ts +4 -2
  101. package/src/utils/getDevices.ts +1 -0
  102. package/src/utils/novaToJson.ts +5 -0
@@ -0,0 +1,9 @@
1
+ import { Project } from '..';
2
+ import { AppConfig } from '../types/PreviewConfig';
3
+ type ProjectPageProps = {
4
+ project: Project;
5
+ onSaveProject: (project: Project) => void;
6
+ appConfig?: AppConfig;
7
+ };
8
+ export declare function ProjectPage({ project, appConfig, onSaveProject, }: ProjectPageProps): import("react/jsx-runtime").JSX.Element;
9
+ export {};
@@ -0,0 +1,9 @@
1
+ import { Node } from '../..';
2
+ type BuilderTabProps = {
3
+ data: Node;
4
+ setData: (data: Node) => void;
5
+ current: Node;
6
+ setCurrent: (current: Node) => void;
7
+ };
8
+ export declare function BuilderTab({ data, setData, current, setCurrent, }: BuilderTabProps): import("react/jsx-runtime").JSX.Element;
9
+ export {};
@@ -0,0 +1,7 @@
1
+ import { Node } from '../..';
2
+ type DebugTabProps = {
3
+ data: Node;
4
+ setData: (data: Node) => void;
5
+ };
6
+ export declare function DebugTab({ data, setData }: DebugTabProps): import("react/jsx-runtime").JSX.Element;
7
+ export {};
@@ -0,0 +1,3 @@
1
+ type PreviewTabProps = {};
2
+ export declare function PreviewTab({}: PreviewTabProps): import("react/jsx-runtime").JSX.Element;
3
+ export {};
package/dist/store.d.ts CHANGED
@@ -1,25 +1,15 @@
1
1
  import type { Device } from './types/Device';
2
- import type { Localication } from './types/PreviewConfig';
3
- import { ScreenStyle } from './RenderPage';
2
+ import { type AppConfig } from './types/PreviewConfig';
3
+ import { Node } from './types/Node';
4
4
  type RenderStore = {
5
+ copiedNode: Node | null;
6
+ setCopiedNode: (node: Node | null) => void;
5
7
  device: Device;
6
- localication: Localication | null;
7
- defaultLanguage?: string;
8
- baseSize: {
9
- width: number;
10
- height: number;
11
- };
12
- theme: 'dark' | 'light';
13
- screenStyle: ScreenStyle;
14
- setBaseSize: (baseSize: {
15
- width: number;
16
- height: number;
17
- }) => void;
18
8
  setDevice: (device: Device) => void;
19
- setLocalication: (localication: Localication | null) => void;
20
- setDefaultLanguage: (defaultLanguage?: string) => void;
21
- setTheme: (theme: 'dark' | 'light') => void;
22
- setScreenStyle: (screenStyle: ScreenStyle) => void;
9
+ appConfig: AppConfig;
10
+ setAppConfig: (appConfig: AppConfig) => void;
11
+ renderCount: number;
12
+ forceRender: () => void;
23
13
  };
24
14
  export declare const useRenderStore: import("zustand/traditional").UseBoundStoreWithEqualityFn<import("zustand/vanilla").StoreApi<RenderStore>>;
25
15
  export {};
package/dist/styles.css CHANGED
@@ -1 +1 @@
1
- *,*::before,*::after{box-sizing:border-box}html,body,#root{height:100%;margin:0;padding:0}body{background:#fff;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;overflow:hidden}button{font-family:inherit}input,button{font-size:100%}p{margin:0;padding:0}.embla{max-width:48rem;margin:auto;--slide-height: 19rem;--slide-spacing: 1rem;--slide-size: 70%}.embla__viewport{overflow:hidden}.embla__container{display:flex;touch-action:pan-y pinch-zoom;margin-left:calc(var(--slide-spacing)*-1)}.embla__slide{transform:translate3d(0, 0, 0);flex:0 0 var(--slide-size);min-width:0;padding-left:var(--slide-spacing);flex:0 0 100%}.embla__slide__number{box-shadow:inset 0 0 0 .2rem var(--detail-medium-contrast);border-radius:1.8rem;font-size:4rem;font-weight:600;display:flex;align-items:center;justify-content:center;height:var(--slide-height);user-select:none}.embla__controls{display:grid;grid-template-columns:auto 1fr;justify-content:space-between;gap:1.2rem;margin-top:1.8rem}.embla__buttons{display:grid;grid-template-columns:repeat(2, 1fr);gap:.6rem;align-items:center}.embla__button{-webkit-tap-highlight-color:rgba(var(--text-high-contrast-rgb-value), 0.5);-webkit-appearance:none;appearance:none;background-color:rgba(0,0,0,0);touch-action:manipulation;display:inline-flex;text-decoration:none;cursor:pointer;border:0;padding:0;margin:0;box-shadow:inset 0 0 0 .2rem var(--detail-medium-contrast);width:3.6rem;height:3.6rem;z-index:1;border-radius:50%;color:var(--text-body);display:flex;align-items:center;justify-content:center}.embla__button:disabled{color:var(--detail-high-contrast)}.embla__button__svg{width:35%;height:35%}.embla__dots{display:flex;flex-wrap:wrap;justify-content:center;align-items:center;margin-right:0;height:50px}.embla__dot{-webkit-tap-highlight-color:rgba(var(--text-high-contrast-rgb-value), 0.5);-webkit-appearance:none;appearance:none;background-color:rgba(0,0,0,0);touch-action:manipulation;display:inline-flex;text-decoration:none;cursor:pointer;border:0;padding:0;margin:0;width:2.6rem;height:2.6rem;display:flex;align-items:center;justify-content:center;border-radius:50%}.embla__dot:after{box-shadow:inset 0 0 0 .2rem var(--detail-medium-contrast);width:1.4rem;height:1.4rem;border-radius:50%;display:flex;align-items:center;content:""}.embla__dot--selected:after{box-shadow:inset 0 0 0 .2rem var(--text-body)}.carousel-provider{height:100%}.embla{height:100%}.embla__viewport{height:100%;display:flex;flex-direction:column}.embla__container{flex:1}
1
+ *,*::before,*::after{box-sizing:border-box}html,body,#root{height:100%;margin:0;padding:0}body{background:#fff;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;overflow:hidden}button{font-family:inherit}input,button{font-size:100%}p{margin:0;padding:0}html,body,#root{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol",sans-serif}.editor-container{height:100vh;width:100vw;display:flex;overflow:hidden}.editor-panel-builder{padding:4px 8px}.app-shell{min-height:100vh;display:flex;flex-direction:column}.app-main{flex:1 1 auto;background:#f3f4f6}.page-bg{background:#f3f4f6}.grid-cards{display:grid;grid-template-columns:repeat(auto-fill, minmax(160px, 1fr));gap:16px}.btn-add{height:120px;border:2px dashed #9ca3af;border-radius:12px;background:#fff;cursor:pointer;font-weight:600;color:#111827;transition:border-color .2s ease,transform .1s ease,box-shadow .2s ease;box-shadow:0 1px 2px rgba(0,0,0,.04)}.btn-add:hover{border-color:rgb(127.7932960894,136.7877094972,152.2067039106);transform:translateY(-1px);box-shadow:0 6px 16px rgba(0,0,0,.1)}.split-left{scrollbar-width:thin;scrollbar-color:rgba(0,0,0,.25) rgba(0,0,0,0)}.split-left::-webkit-scrollbar{width:8px;height:4px}.split-left{flex:1 1 30%;min-width:0;border-right:1px solid #e5e7eb;overflow:auto}.split-right{position:relative;flex:1 1 45%;min-width:0;max-height:calc(100vh - 120px);overflow:auto}.split-third{flex:1 1 25%;min-width:0;border-right:1px solid #e5e7eb;overflow:auto;max-height:calc(100vh - 120px)}.split-right-background{position:absolute;inset:0;background-size:cover;background-position:center;background-repeat:repeat;background-size:500px auto;opacity:.2}.stage-wrapper{display:flex;justify-content:center;background:#f3f4f6;padding:16px}.stage{background:#fff;border:1px solid #e5e7eb;border-radius:4px;border:1px solid #e5e7eb}.stage .scroll-container::-webkit-scrollbar{width:8px;height:8px}.stage .scroll-container::-webkit-scrollbar-track{background:rgba(0,0,0,0)}.stage .scroll-container::-webkit-scrollbar-thumb{background:rgba(0,0,0,.25);border-radius:8px}.stage .scroll-container{scrollbar-width:thin;scrollbar-color:rgba(0,0,0,.25) rgba(0,0,0,0)}.app-header{position:sticky;top:0;z-index:10;background:#fff;border-bottom:1px solid #e5e7eb;height:60px;padding:0 16px;display:flex;align-items:center;justify-content:space-between}.app-header a{color:#111827;text-decoration:none}.app-header__brand{font-weight:700}.app-header__nav{display:flex;gap:16px}.warning{color:#ef4444;font-size:12px;font-weight:600;margin-bottom:16px}.breadcrumb{display:block;font-size:12px;color:#9ca3af}.breadcrumb__list{list-style:none;padding:0;margin:0;display:flex;align-items:center;gap:8px}.breadcrumb__item{display:inline-flex;align-items:center}.breadcrumb__separator{color:#e5e7eb;margin:0 4px}.breadcrumb__link{color:#111827;text-decoration:none}.breadcrumb__link:hover{text-decoration:underline}.breadcrumb__current{color:#9ca3af}.editor-controls{display:grid;grid-template-columns:auto 1fr;gap:12px;padding:16px}.editor-section{background:#fff;border:1px solid #e5e7eb;border-radius:12px;padding:16px}.form-row{display:grid;grid-template-columns:160px 1fr;align-items:center;gap:12px;margin-bottom:12px}.form-actions{display:flex;gap:12px;margin-top:16px}.btn{padding:8px 12px;border-radius:8px;border:1px solid #e5e7eb;background:#fff;cursor:pointer;transition:background .2s ease,box-shadow .2s ease}.btn:hover{background:#f9fafb;box-shadow:0 6px 16px rgba(0,0,0,.06)}.input{display:inline-flex;align-items:center;height:32px;padding:0 8px;border:1px solid #e5e7eb;border-radius:12px;background:#fff;color:#111827;font:inherit;outline:none;transition:border-color .15s ease,box-shadow .15s ease}.input:focus{border-color:hsl(220,13.0434782609%,82.9803921569%);box-shadow:0 0 0 3px rgba(0,0,0,.04)}.input--color{padding:0;width:40px;height:28px;border-radius:6px;cursor:pointer}.input--color::-webkit-color-swatch-wrapper{padding:0}.input--color::-webkit-color-swatch{border:none;border-radius:4px}.input--color::-moz-color-swatch{border:none;border-radius:4px}.builder{display:flex;flex-direction:column;gap:12px}.builder__breadcrumbs{display:flex;flex-direction:row;gap:8px}.builder__breadcrumb{color:#9ca3af;font-size:12px}.builder__current{font-weight:600}.builder__list{display:flex;flex-wrap:wrap;gap:8px}.builder__button{background:#fff;border:1px solid #e5e7eb;border-radius:4px;padding:12px 12px;font-size:14px;background:#6495ed;color:#fff;cursor:pointer}.builder__node{background:#fff;border:1px solid #e5e7eb;border-radius:4px;padding:12px}.builder__node-type{margin:0 0 8px 0;font-weight:600}.builder__children{display:flex;flex-direction:column;gap:8px}.builder__text,.builder__placeholder{color:#9ca3af;font-size:12px}.editor-tabs{display:flex;gap:8px;border-bottom:1px solid #e5e7eb}.editor-tab{padding:8px 12px;cursor:pointer;border:1px solid rgba(0,0,0,0);border-top-left-radius:4px;border-top-right-radius:4px;color:#111827;padding:8px 12px}.editor-tab--active{background:#fff;border-color:#e5e7eb #e5e7eb #fff #e5e7eb}.editor-panels{padding:12px}.editor-panels.editor-panels-debug{padding:0}.jer-editor-container{padding-left:0 !important;padding-right:0 !important}.editor-panel{display:none}.editor-panel--active{display:block}.editor-header{display:flex;align-items:center;gap:12px;padding:0 16px;height:60px;background:#f9fafb;border-bottom:1px solid #e5e7eb}.editor-header__title{color:#111827;font-weight:600}.editor-header__devices{scrollbar-width:thin;scrollbar-color:rgba(0,0,0,.25) rgba(0,0,0,0)}.editor-header__devices::-webkit-scrollbar{width:8px;height:4px}.editor-header__devices{display:flex;flex-direction:row;align-items:stretch;gap:8px;overflow:auto;height:60px;padding:4px}.editor-device-button{position:relative;min-width:160px;height:100%;border:1px solid #e5e7eb;border-radius:6px;background:#fff;color:#111827;cursor:pointer;font-size:12px}.editor-device-button.editor-device-button--selected{border-color:#000}.editor-device-button img{position:absolute;bottom:4px;right:4px;width:16px;height:16px}.editor-header__actions{margin-left:auto;display:flex;align-items:center;gap:8px}.editor-button{display:inline-flex;align-items:center;justify-content:center;height:36px;min-width:120px;padding:0 12px;border:1px solid #e5e7eb;border-radius:6px;background:#fff;color:#111827;cursor:pointer}.editor-button:disabled{opacity:.6;cursor:default}.editor-save-button,.editor-save-previewconfig-button{color:#000;font-weight:600;font-size:12px}.editor-modal{position:fixed;inset:0;z-index:1000}.editor-modal__overlay{position:absolute;inset:0;background:rgba(0,0,0,.4)}.editor-modal__content{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);background:#fff;border-radius:8px;box-shadow:0 10px 30px rgba(0,0,0,.2);width:min(960px,100vw - 40px);max-height:calc(100vh - 120px);display:flex;flex-direction:column}.editor-modal__header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid #e5e7eb}.editor-device-grid{padding:16px;display:grid;grid-template-columns:repeat(auto-fill, minmax(180px, 1fr));gap:12px;overflow:auto}.editor-device-grid .editor-device-button{height:80px;min-width:unset}.embla{max-width:48rem;margin:auto;--slide-height: 19rem;--slide-spacing: 1rem;--slide-size: 70%}.embla__viewport{overflow:hidden}.embla__container{display:flex;touch-action:pan-y pinch-zoom;margin-left:calc(var(--slide-spacing)*-1)}.embla__slide{transform:translate3d(0, 0, 0);flex:0 0 var(--slide-size);min-width:0;padding-left:var(--slide-spacing);flex:0 0 100%}.embla__slide__number{box-shadow:inset 0 0 0 .2rem var(--detail-medium-contrast);border-radius:1.8rem;font-size:4rem;font-weight:600;display:flex;align-items:center;justify-content:center;height:var(--slide-height);user-select:none}.embla__controls{display:grid;grid-template-columns:auto 1fr;justify-content:space-between;gap:1.2rem;margin-top:1.8rem}.embla__buttons{display:grid;grid-template-columns:repeat(2, 1fr);gap:.6rem;align-items:center}.embla__button{-webkit-tap-highlight-color:rgba(var(--text-high-contrast-rgb-value), 0.5);-webkit-appearance:none;appearance:none;background-color:rgba(0,0,0,0);touch-action:manipulation;display:inline-flex;text-decoration:none;cursor:pointer;border:0;padding:0;margin:0;box-shadow:inset 0 0 0 .2rem var(--detail-medium-contrast);width:3.6rem;height:3.6rem;z-index:1;border-radius:50%;color:var(--text-body);display:flex;align-items:center;justify-content:center}.embla__button:disabled{color:var(--detail-high-contrast)}.embla__button__svg{width:35%;height:35%}.embla__dots{display:flex;flex-wrap:wrap;justify-content:center;align-items:center;margin-right:0;height:50px}.embla__dot{-webkit-tap-highlight-color:rgba(var(--text-high-contrast-rgb-value), 0.5);-webkit-appearance:none;appearance:none;background-color:rgba(0,0,0,0);touch-action:manipulation;display:inline-flex;text-decoration:none;cursor:pointer;border:0;padding:0;margin:0;width:2.6rem;height:2.6rem;display:flex;align-items:center;justify-content:center;border-radius:50%}.embla__dot:after{box-shadow:inset 0 0 0 .2rem var(--detail-medium-contrast);width:1.4rem;height:1.4rem;border-radius:50%;display:flex;align-items:center;content:""}.embla__dot--selected:after{box-shadow:inset 0 0 0 .2rem var(--text-body)}.carousel-provider{height:100%}.embla{height:100%}.embla__viewport{height:100%;display:flex;flex-direction:column}.embla__container{flex:1}
@@ -1,7 +1,5 @@
1
- import { TargetedScreenSize } from './TargetedScreenSize';
2
- export interface PreviewConfig {
1
+ export interface AppConfig {
3
2
  theme: 'light' | 'dark';
4
- screenSize: TargetedScreenSize;
5
3
  isRtl: boolean;
6
4
  screenStyle: {
7
5
  light: {
@@ -17,7 +15,12 @@ export interface PreviewConfig {
17
15
  };
18
16
  localication: Localication;
19
17
  defaultLanguage?: string;
18
+ baseSize: {
19
+ width: number;
20
+ height: number;
21
+ };
20
22
  }
23
+ export declare const defaultAppConfig: AppConfig;
21
24
  export type Localication = {
22
25
  [key: string]: {
23
26
  [key: string]: string;
@@ -1,10 +1,10 @@
1
1
  import { Node } from '../types/Node';
2
- import { PreviewConfig } from './PreviewConfig';
2
+ import { AppConfig } from './PreviewConfig';
3
3
  export interface ProjectBase<T> {
4
4
  name: string;
5
5
  version: string;
6
6
  data: T;
7
- previewConfig?: PreviewConfig;
7
+ appConfig?: AppConfig;
8
8
  }
9
9
  export interface Project extends ProjectBase<Node> {
10
10
  }
@@ -0,0 +1,2 @@
1
+ import { Node } from '../types/Node';
2
+ export declare function copyNode(node: Node): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@developer_tribe/react-builder",
3
- "version": "0.1.31",
3
+ "version": "1.1.0",
4
4
  "type": "module",
5
5
  "restricted": true,
6
6
  "main": "dist/index.cjs.js",
@@ -27,24 +27,24 @@
27
27
  "bin": {
28
28
  "builder": "./scripts/public/bin.js"
29
29
  },
30
- "peerDependencies": {
31
- "react": ">=17",
32
- "react-dom": ">=17"
33
- },
34
30
  "devDependencies": {
35
31
  "@eslint/compat": "^1.4.0",
36
32
  "@eslint/eslintrc": "^3.3.1",
37
33
  "@eslint/js": "^9.36.0",
38
34
  "@rollup/plugin-commonjs": "^28.0.6",
35
+ "@rollup/plugin-json": "^6.1.0",
39
36
  "@rollup/plugin-node-resolve": "^16.0.1",
40
37
  "@svgr/rollup": "^8.1.0",
41
38
  "@types/node": "^22.7.4",
42
39
  "@types/react": "^18.3.9",
43
40
  "@types/react-dom": "^18.3.0",
41
+ "embla-carousel-react": "^8.6.0",
44
42
  "eslint": "^9.36.0",
45
43
  "eslint-plugin-react": "^7.37.5",
46
44
  "eslint-plugin-react-hooks": "^5.2.0",
47
45
  "globals": "^16.4.0",
46
+ "json-edit-react": "^1.29.0",
47
+ "lottie-react": "^2.4.1",
48
48
  "prettier": "^3.6.2",
49
49
  "react": "^18.3.1",
50
50
  "rimraf": "^6.0.1",
@@ -57,7 +57,17 @@
57
57
  "typescript": "^5.9.2",
58
58
  "typescript-eslint": "^8.44.1",
59
59
  "use-sync-external-store": "^1.6.0",
60
- "yargs": "^18.0.0"
60
+ "yargs": "^18.0.0",
61
+ "zustand": "^5.0.8"
62
+ },
63
+ "peerDependencies": {
64
+ "react": ">=17",
65
+ "react-dom": ">=17",
66
+ "react-router-dom": ">=6.0.0"
67
+ },
68
+ "optionalDependencies": {
69
+ "embla-carousel-react": ">=8.6.0",
70
+ "json-edit-react": ">=1.29.0"
61
71
  },
62
72
  "engines": {
63
73
  "node": ">=18"
@@ -66,8 +76,6 @@
66
76
  "access": "public"
67
77
  },
68
78
  "dependencies": {
69
- "@rollup/plugin-json": "^6.1.0",
70
- "embla-carousel-react": "^8.6.0",
71
- "zustand": "^5.0.8"
79
+ "axios": "^1.12.2"
72
80
  }
73
81
  }
@@ -18,7 +18,21 @@ export async function createBuildComponentsIndex(validated, paths) {
18
18
 
19
19
  const patternsExport = `export { patterns } from './patterns.generated';`;
20
20
 
21
- const sections = [renderNodeExport, patternsExport, exportLines]
21
+ // Export array of all component names derived from pattern.type
22
+ const allComponentNames = validated
23
+ .map(({ patternJson }) => patternJson?.pattern?.type)
24
+ .filter(t => typeof t === 'string');
25
+ const allcomponentNamesExport =
26
+ `export const allcomponentNames = [\n ` +
27
+ allComponentNames.map(t => JSON.stringify(t)).join(', ') +
28
+ `\n] as const;`;
29
+
30
+ const sections = [
31
+ renderNodeExport,
32
+ patternsExport,
33
+ allcomponentNamesExport,
34
+ exportLines,
35
+ ]
22
36
  .filter(Boolean)
23
37
  .join('\n\n');
24
38
 
@@ -7,15 +7,43 @@ import { formatWithPrettier } from './formatWithPrettier.js';
7
7
  const isPrimitive = t => t === 'string' || t === 'number' || t === 'boolean';
8
8
  const getArrayItem = t =>
9
9
  typeof t === 'string' && t.endsWith('[]') ? t.slice(0, -2) : null;
10
+ // Convert a property name like "animation" or "on-press" to PascalCase
11
+ const toPascalCase = s =>
12
+ String(s)
13
+ .replace(/([A-Z]+)/g, ' $1')
14
+ .split(/[^a-zA-Z0-9]+|\s+/)
15
+ .filter(Boolean)
16
+ .map(part => part.charAt(0).toUpperCase() + part.slice(1))
17
+ .join('');
10
18
 
11
19
  // Convert attribute type spec to TS type. Supports enum arrays, primitives, CustomType, and CustomType[]
12
- function tsTypeFromAttributeType(attrType, allTypes) {
20
+ // If an enum array is detected, "registerEnumAlias" will be called to create an exported alias
21
+ function tsTypeFromAttributeType(
22
+ attrType,
23
+ allTypes,
24
+ propertyName,
25
+ registerEnumAlias
26
+ ) {
13
27
  if (attrType === 'string') return 'string';
14
28
  if (attrType === 'number') return 'number';
15
29
  if (attrType === 'boolean') return 'boolean';
16
30
  if (Array.isArray(attrType)) {
17
- const literals = attrType.map(v => JSON.stringify(v)).join(' | ');
18
- return literals.length > 0 ? literals : 'string';
31
+ const rawMembers = attrType;
32
+ if (rawMembers.length === 0) return 'string';
33
+ const hasNull = rawMembers.some(v => v === 'null');
34
+ const nonNullMembers = rawMembers.filter(v => v !== 'null');
35
+ const nonNullLiteralMembers = nonNullMembers.map(v => JSON.stringify(v));
36
+
37
+ // Only null specified
38
+ if (hasNull && nonNullLiteralMembers.length === 0) return 'null';
39
+
40
+ if (typeof registerEnumAlias === 'function' && propertyName) {
41
+ const alias = registerEnumAlias(propertyName, nonNullLiteralMembers);
42
+ return hasNull ? `${alias} | null` : alias;
43
+ }
44
+ // Fallback if no registrar provided
45
+ const baseUnion = nonNullLiteralMembers.join(' | ');
46
+ return hasNull ? `${baseUnion} | null` : baseUnion;
19
47
  }
20
48
  if (typeof attrType === 'string') {
21
49
  const item = getArrayItem(attrType);
@@ -44,11 +72,36 @@ export async function createGeneratedProps(
44
72
  const attributes = pattern.attributes || {};
45
73
  const allTypes = patternJson.types || {};
46
74
 
75
+ // Collect option type aliases for any enum arrays encountered across attributes and custom types
76
+ const optionAliases = new Map(); // name -> union (string like `'a' | 'b'`)
77
+ const registerEnumAlias = (propName, literalMembers) => {
78
+ const base = `${toPascalCase(propName)}OptionType`;
79
+ const union = literalMembers.join(' | ');
80
+ if (!optionAliases.has(base)) {
81
+ optionAliases.set(base, union);
82
+ return base;
83
+ }
84
+ const existing = optionAliases.get(base);
85
+ if (existing === union) return base;
86
+ let i = 2;
87
+ // find a non-conflicting alias name
88
+ // eslint-disable-next-line no-constant-condition
89
+ while (true) {
90
+ const candidate = `${base}${i}`;
91
+ if (!optionAliases.has(candidate)) {
92
+ optionAliases.set(candidate, union);
93
+ return candidate;
94
+ }
95
+ if (optionAliases.get(candidate) === union) return candidate;
96
+ i += 1;
97
+ }
98
+ };
99
+
47
100
  // Emit custom type interfaces if present
48
101
  const customTypeEntries = Object.entries(allTypes);
49
102
  const customTypeBlocks = customTypeEntries.map(([typeName, schema]) => {
50
103
  const fields = Object.entries(schema).map(([k, t]) => {
51
- const tsType = tsTypeFromAttributeType(t, allTypes);
104
+ const tsType = tsTypeFromAttributeType(t, allTypes, k, registerEnumAlias);
52
105
  return ` ${k}?: ${tsType};`;
53
106
  });
54
107
  return (
@@ -59,7 +112,7 @@ export async function createGeneratedProps(
59
112
  });
60
113
 
61
114
  const attributeLines = Object.entries(attributes).map(([key, t]) => {
62
- const tsType = tsTypeFromAttributeType(t, allTypes);
115
+ const tsType = tsTypeFromAttributeType(t, allTypes, key, registerEnumAlias);
63
116
  return ` ${key}?: ${tsType};`;
64
117
  });
65
118
 
@@ -81,6 +134,12 @@ export async function createGeneratedProps(
81
134
  // Re-export a component props helper to avoid repeating the local type in each component file
82
135
  `import type { NodeData } from '../../types/Node';\n` +
83
136
  `\n` +
137
+ // Export per-property option types for enum arrays
138
+ (optionAliases.size
139
+ ? Array.from(optionAliases.entries())
140
+ .map(([name, union]) => `export type ${name} = ${union};`)
141
+ .join('\n') + '\n\n'
142
+ : '') +
84
143
  (customTypeBlocks.length ? customTypeBlocks.join('\n') + '\n' : '') +
85
144
  `\n` +
86
145
  `export interface ${componentName}PropsGenerated {\n` +
@@ -1,29 +1,16 @@
1
1
  import React from 'react';
2
- import { Device } from './types/Device';
2
+ import { useRenderStore } from './store';
3
3
 
4
4
  type DeviceMockFrameProps = {
5
- width: number;
6
- height: number;
7
- isRtl: boolean;
8
- screenStyle: {
9
- light: { backgroundColor: string; color: string };
10
- dark: { backgroundColor: string; color: string };
11
- };
12
- theme: 'dark' | 'light';
13
5
  children: React.ReactNode;
14
- device: Device;
15
6
  };
16
7
 
17
- export function DeviceMockFrame({
18
- width,
19
- height,
20
- isRtl,
21
- screenStyle,
22
- theme,
23
- children,
24
- device,
25
- }: DeviceMockFrameProps) {
26
- const isDark = theme === 'dark';
8
+ export function DeviceMockFrame({ children }: DeviceMockFrameProps) {
9
+ const { appConfig, device } = useRenderStore((s) => ({
10
+ appConfig: s.appConfig,
11
+ device: s.device,
12
+ }));
13
+ const isDark = appConfig.theme === 'dark';
27
14
  const [insetTop, insetRight, insetBottom, insetLeft] = device.insets ?? [
28
15
  0, 0, 0, 0,
29
16
  ];
@@ -58,22 +45,24 @@ export function DeviceMockFrame({
58
45
  <div
59
46
  className="stage"
60
47
  style={{
61
- width: width,
62
- height: height,
63
- minWidth: width,
64
- maxWidth: width,
65
- minHeight: height,
66
- maxHeight: height,
48
+ width: device.width,
49
+ height: device.height,
50
+ minWidth: device.width,
51
+ maxWidth: device.width,
52
+ minHeight: device.height,
53
+ maxHeight: device.height,
67
54
  overflow: 'hidden',
68
55
  position: 'relative',
69
56
  padding: 4,
70
- direction: isRtl ? 'rtl' : 'ltr',
57
+ direction: appConfig.isRtl ? 'rtl' : 'ltr',
71
58
  backgroundColor:
72
- theme === 'dark'
73
- ? screenStyle.dark.backgroundColor
74
- : screenStyle.light.backgroundColor,
59
+ appConfig.theme === 'dark'
60
+ ? appConfig.screenStyle.dark.backgroundColor
61
+ : appConfig.screenStyle.light.backgroundColor,
75
62
  color:
76
- theme === 'dark' ? screenStyle.dark.color : screenStyle.light.color,
63
+ appConfig.theme === 'dark'
64
+ ? appConfig.screenStyle.dark.color
65
+ : appConfig.screenStyle.light.color,
77
66
  display: 'flex',
78
67
  flexDirection: 'column',
79
68
  borderRadius: device.radius ?? 0,
@@ -12,22 +12,9 @@ export type ScreenStyle = {
12
12
  };
13
13
  type RenderPageProps = {
14
14
  data: Node;
15
- isRtl: boolean;
16
- screenStyle: ScreenStyle;
17
- theme: 'dark' | 'light';
18
- localication: Localication;
19
- defaultLanguage?: string;
20
- device: Device;
21
15
  };
22
- export function RenderPage({
23
- data,
24
- theme,
25
- isRtl,
26
- screenStyle,
27
- localication,
28
- defaultLanguage,
29
- device,
30
- }: RenderPageProps) {
16
+ export function RenderPage({ data }: RenderPageProps) {
17
+ const { device } = useRenderStore((s) => ({ device: s.device }));
31
18
  const screenPreviewHeight = 800;
32
19
  // The calculation is correct for maintaining the aspect ratio of the target screen size.
33
20
  // It scales the width proportionally to a fixed preview height.
@@ -35,30 +22,8 @@ export function RenderPage({
35
22
  const height = screenPreviewHeight;
36
23
  const width = (height * device.width) / device.height;
37
24
 
38
- useEffect(() => {
39
- const {
40
- setDevice,
41
- setLocalication,
42
- setDefaultLanguage,
43
- setTheme,
44
- setScreenStyle,
45
- } = useRenderStore.getState();
46
- setDevice(device);
47
- setLocalication(localication);
48
- setDefaultLanguage(defaultLanguage);
49
- setTheme(theme);
50
- setScreenStyle(screenStyle);
51
- }, [device, localication, defaultLanguage, theme, screenStyle]);
52
-
53
25
  return (
54
- <DeviceMockFrame
55
- width={width}
56
- height={height}
57
- isRtl={isRtl}
58
- screenStyle={screenStyle}
59
- theme={theme}
60
- device={device}
61
- >
26
+ <DeviceMockFrame>
62
27
  <RenderNode node={data} />
63
28
  </DeviceMockFrame>
64
29
  );
@@ -0,0 +1,43 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
3
+ <svg height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
4
+ viewBox="0 0 502.857 502.857" xml:space="preserve">
5
+ <g>
6
+ <path style="fill:#57C927;" d="M115.428,155.433v217.664c0,17,10.208,30.336,27.704,30.336h22.84c-0.784,0-2.544,5.768-2.544,8.6
7
+ v61.648c0,16.112,15.448,29.176,32,29.176c16.56,0,32-13.064,32-29.176v-61.648c0-2.832-3.088-8.6-3.848-8.6h55.712
8
+ c-0.76,0-3.864,5.768-3.864,8.6v61.648c0,16.112,15.416,29.176,31.968,29.176c16.592,0,32.032-13.064,32.032-29.176v-61.648
9
+ c0-2.832-1.752-8.6-2.536-8.6h22.872c17.496,0,27.664-13.336,27.664-30.336V155.433H113.596H115.428z"/>
10
+ <path style="fill:#57C927;" d="M59.428,158.977c-16.568,0-32,13.072-32,29.176v124.92c0,16.112,15.432,29.176,32,29.176
11
+ c16.56,0,32-13.064,32-29.176V188.161C91.428,172.049,75.988,158.977,59.428,158.977z"/>
12
+ <path style="fill:#57C927;" d="M320.3,42.057l5.584-8.192l5.592-8.096l12.456-18.2c1.56-2.256,0.912-5.264-1.384-6.744
13
+ c-2.272-1.512-5.416-0.88-6.904,1.36l-19.016,27.704l-5.72,8.344c-18.072-6.832-38.208-10.64-59.48-10.64
14
+ c-21.224,0-41.4,3.816-59.472,10.64l-5.688-8.336l-5.624-8.184l-13.36-19.512c-1.544-2.248-4.648-2.84-6.952-1.36
15
+ c-2.28,1.488-2.912,4.496-1.392,6.744l12.448,18.208l5.592,8.104l5.616,8.168c-42.432,19.24-71.144,57.368-71.144,97.368h279.96
16
+ C391.412,99.433,362.708,61.305,320.3,42.057z M191.436,100.593c-8.312,0-15.008-6.536-15.008-14.608s6.696-14.576,15.008-14.576
17
+ c8.288,0,15,6.504,15,14.576S199.732,100.593,191.436,100.593z M311.436,100.593c-8.304,0-15.016-6.536-15.016-14.608
18
+ s6.712-14.576,15.016-14.576c8.288,0,15,6.504,15,14.576S319.724,100.593,311.436,100.593z"/>
19
+ </g>
20
+ <path style="fill:#1CB71C;" d="M60.852,224.193c-12.472,0-25.424-11.768-33.424-30.432v119.32c0,16.112,15.432,29.176,32,29.176
21
+ c16.56,0,32-13.064,32-29.176V199.985C83.428,214.977,71.86,224.193,60.852,224.193z"/>
22
+ <path style="fill:#57C927;" d="M443.428,158.977c-16.568,0-32,13.072-32,29.176v124.92c0,16.112,15.432,29.176,32,29.176
23
+ c16.56,0,32-13.064,32-29.176V188.161C475.428,172.049,459.988,158.977,443.428,158.977z"/>
24
+ <g>
25
+ <path style="fill:#1CB71C;" d="M444.852,224.193c-12.472,0-25.424-11.768-33.424-30.432v119.32c0,16.112,15.432,29.176,32,29.176
26
+ c16.56,0,32-13.064,32-29.176V199.985C467.428,214.977,455.86,224.193,444.852,224.193z"/>
27
+ <path style="fill:#1CB71C;" d="M251.428,179.337c-63.28,0-120-7.32-136-17.712v211.472c0,17,10.208,30.336,27.704,30.336h22.84
28
+ c-0.784,0-2.544,5.768-2.544,8.6v61.648c0,16.112,15.448,29.176,32,29.176c16.56,0,32-13.064,32-29.176v-61.648
29
+ c0-2.832-3.088-8.6-3.848-8.6h55.712c-0.76,0-3.864,5.768-3.864,8.6v61.648c0,16.112,15.416,29.176,31.968,29.176
30
+ c16.592,0,32.032-13.064,32.032-29.176v-61.648c0-2.832-1.752-8.6-2.536-8.6h22.872c17.496,0,27.664-13.336,27.664-30.336v-211.48
31
+ C371.428,172.009,314.716,179.337,251.428,179.337z"/>
32
+ <path style="fill:#1CB71C;" d="M326.436,85.977c0,8.072-6.712,14.608-15,14.608c-8.304,0-15.016-6.536-15.016-14.608
33
+ c0-4.376,2.008-8.24,5.136-10.912c-15.816-2.64-32.64-4.088-50.128-4.088s-34.304,1.448-50.128,4.088
34
+ c3.136,2.664,5.144,6.536,5.144,10.912c0,8.072-6.712,14.608-15,14.608c-8.312,0-15.008-6.536-15.008-14.608
35
+ c0-2.064,0.456-4.024,1.248-5.808c-23.984,6.304-44.592,15.504-60.144,26.808c-3.92,10.296-6.088,24.456-6.088,32.456h279.96
36
+ c0-8-2.168-22.152-6.08-32.44c-15.544-11.32-36.16-20.536-60.128-26.84C325.988,81.937,326.436,83.921,326.436,85.977z"/>
37
+ </g>
38
+ <path style="fill:#049E42;" d="M251.428,262.817c-53.896,0-104-10.632-136-28.056v138.336c0,17,10.208,30.336,27.704,30.336h22.84
39
+ c-0.784,0-2.544,5.768-2.544,8.6v61.648c0,16.112,15.448,29.176,32,29.176c16.56,0,32-13.064,32-29.176v-61.648
40
+ c0-2.832-3.088-8.6-3.848-8.6h55.712c-0.76,0-3.864,5.768-3.864,8.6v61.648c0,16.112,15.416,29.176,31.968,29.176
41
+ c16.592,0,32.032-13.064,32.032-29.176v-61.648c0-2.832-1.752-8.6-2.536-8.6h22.872c17.496,0,27.664-13.336,27.664-30.336V234.761
42
+ C355.428,252.193,305.324,262.817,251.428,262.817z"/>
43
+ </svg>
@@ -0,0 +1,16 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
3
+ <svg height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
4
+ viewBox="0 0 496.412 496.412" xml:space="preserve">
5
+ <path d="M317.222,80.584C333.414,59.696,345.686,30.152,341.246,0c-26.472,1.84-57.384,18.768-75.432,40.832
6
+ c-16.456,20-29.976,49.728-24.688,78.608C270.054,120.344,299.91,103.008,317.222,80.584z"/>
7
+ <path style="fill:#1B546B;" d="M445.838,166.544c-25.4-31.872-61.12-50.344-94.848-50.344c-44.512,0-63.352,21.312-94.264,21.312
8
+ c-31.896,0-56.12-21.248-94.624-21.248c-37.832,0-78.112,23.12-103.64,62.64C22.574,234.576,28.694,339.2,86.894,428.336
9
+ c20.808,31.904,48.592,67.744,84.952,68.072c32.36,0.32,41.488-20.752,85.336-20.992c43.832-0.256,52.16,21.264,84.456,20.896
10
+ c36.384-0.288,65.712-40.016,86.512-71.92c14.912-22.848,20.48-34.376,32.056-60.184
11
+ C376.014,332.184,362.518,212.488,445.838,166.544z"/>
12
+ <path d="M394.774,228.08c-63.632,51.52-153.592,83.712-253.44,83.712c-35.776,0-70.288-4.144-102.768-11.808
13
+ c5.496,41.808,21.16,86.736,48.336,128.344c20.808,31.904,48.592,67.744,84.952,68.072c32.36,0.32,41.488-20.752,85.336-20.992
14
+ c43.832-0.256,52.16,21.264,84.456,20.896c36.384-0.288,65.712-40.016,86.512-71.92c14.912-22.848,20.48-34.376,32.056-60.184
15
+ C402.966,342.44,378.454,280.176,394.774,228.08z"/>
16
+ </svg>
Binary file
@@ -1,9 +1,8 @@
1
1
  {
2
2
  "name": "carousel-sample",
3
3
  "version": "1.0.0",
4
- "previewConfig": {
5
- "theme": "light",
6
- "screenSize": { "width": 375, "height": 812 }
4
+ "appConfig": {
5
+ "theme": "light"
7
6
  },
8
7
  "data": {
9
8
  "type": "carouselProvider",
@@ -6,14 +6,37 @@ import vpnOnboard1 from './vpn-onboard-1.json';
6
6
  import vpnOnboard2 from './vpn-onboard-2.json';
7
7
  import vpnOnboard3 from './vpn-onboard-3.json';
8
8
  import vpnOnboard4 from './vpn-onboard-4.json';
9
+ import vpnOnboard5 from './vpn-onboard-5.json';
10
+ import vpnOnboard6 from './vpn-onboard-6.json';
9
11
  import { novaToJson } from '../../utils/novaToJson';
12
+ import { defaultAppConfig } from '../../types/PreviewConfig';
10
13
 
11
14
  export function getSamples(): Project[] {
12
15
  const legacySamples = [
13
- { ...vpnOnboard1 } as ProjectBase<unknown>,
14
- { ...vpnOnboard2 } as ProjectBase<unknown>,
15
- { ...vpnOnboard3 } as ProjectBase<unknown>,
16
- { ...vpnOnboard4 } as ProjectBase<unknown>,
16
+ {
17
+ ...vpnOnboard1,
18
+ appConfig: { ...defaultAppConfig, ...vpnOnboard1.appConfig },
19
+ } as ProjectBase<unknown>,
20
+ {
21
+ ...vpnOnboard2,
22
+ appConfig: { ...defaultAppConfig, ...vpnOnboard2.appConfig },
23
+ } as ProjectBase<unknown>,
24
+ {
25
+ ...vpnOnboard3,
26
+ appConfig: { ...defaultAppConfig, ...vpnOnboard3.appConfig },
27
+ } as ProjectBase<unknown>,
28
+ {
29
+ ...vpnOnboard4,
30
+ appConfig: { ...defaultAppConfig, ...vpnOnboard4.appConfig },
31
+ } as ProjectBase<unknown>,
32
+ {
33
+ ...vpnOnboard5,
34
+ appConfig: { ...defaultAppConfig, ...vpnOnboard5.appConfig },
35
+ } as ProjectBase<unknown>,
36
+ {
37
+ ...vpnOnboard6,
38
+ appConfig: { ...defaultAppConfig, ...vpnOnboard6.appConfig },
39
+ } as ProjectBase<unknown>,
17
40
  ];
18
41
  legacySamples.forEach((sample) => {
19
42
  sample.data = novaToJson(sample);
@@ -33,10 +56,30 @@ export function getBasicSamples(): Project[] {
33
56
 
34
57
  export function getOnboardSamples(): Project[] {
35
58
  const legacySamples = [
36
- vpnOnboard1 as Project,
37
- vpnOnboard2 as Project,
38
- vpnOnboard3 as Project,
39
- vpnOnboard4 as Project,
59
+ {
60
+ ...vpnOnboard1,
61
+ appConfig: { ...defaultAppConfig, ...vpnOnboard1.appConfig },
62
+ } as ProjectBase<unknown>,
63
+ {
64
+ ...vpnOnboard2,
65
+ appConfig: { ...defaultAppConfig, ...vpnOnboard2.appConfig },
66
+ } as ProjectBase<unknown>,
67
+ {
68
+ ...vpnOnboard3,
69
+ appConfig: { ...defaultAppConfig, ...vpnOnboard3.appConfig },
70
+ } as ProjectBase<unknown>,
71
+ {
72
+ ...vpnOnboard4,
73
+ appConfig: { ...defaultAppConfig, ...vpnOnboard4.appConfig },
74
+ } as ProjectBase<unknown>,
75
+ {
76
+ ...vpnOnboard5,
77
+ appConfig: { ...defaultAppConfig, ...vpnOnboard5.appConfig },
78
+ } as ProjectBase<unknown>,
79
+ {
80
+ ...vpnOnboard6,
81
+ appConfig: { ...defaultAppConfig, ...vpnOnboard6.appConfig },
82
+ } as ProjectBase<unknown>,
40
83
  ];
41
84
  legacySamples.forEach((sample) => {
42
85
  sample.data = novaToJson(sample);
@@ -1,9 +1,8 @@
1
1
  {
2
2
  "name": "hello-world",
3
3
  "version": "1.0.0",
4
- "previewConfig": {
4
+ "appConfig": {
5
5
  "theme": "light",
6
- "screenSize": { "width": 375, "height": 812 },
7
6
  "isRtl": false,
8
7
  "screenStyle": {
9
8
  "light": { "backgroundColor": "#FDFDFD", "color": "#161827" },
@@ -1,9 +1,8 @@
1
1
  {
2
2
  "name": "hello-world-2-advanced",
3
3
  "version": "1.0.0",
4
- "previewConfig": {
4
+ "appConfig": {
5
5
  "theme": "light",
6
- "screenSize": { "width": 390, "height": 844 },
7
6
  "isRtl": false,
8
7
  "screenStyle": {
9
8
  "light": { "backgroundColor": "#FDFDFD", "color": "#161827" },