@developer_tribe/react-builder 1.0.1 → 1.0.3
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/dist/AttributesEditor.d.ts +3 -1
- package/dist/DeviceMockFrame.d.ts +2 -1
- package/dist/RenderPage.d.ts +5 -3
- package/dist/attributes-editor/Field.d.ts +17 -0
- package/dist/attributes-editor/FieldInfoTooltip.d.ts +7 -0
- package/dist/attributes-editor/LayoutPreviewPicker.d.ts +12 -0
- package/dist/attributes-editor/SpecialCategorySection.d.ts +20 -0
- package/dist/attributes-editor/types.d.ts +14 -0
- package/dist/background.jpg +0 -0
- package/dist/build-components/BackgroundImage/BackgroundImage.d.ts +5 -0
- package/dist/build-components/BackgroundImage/BackgroundImageProps.generated.d.ts +44 -0
- package/dist/build-components/Button/Button.d.ts +1 -1
- package/dist/build-components/Button/ButtonProps.generated.d.ts +33 -1
- package/dist/build-components/Carousel/CarouselProps.generated.d.ts +34 -1
- package/dist/build-components/CarouselButtons/CarouselButtonsProps.generated.d.ts +32 -0
- package/dist/build-components/CarouselDots/CarouselDotsProps.generated.d.ts +32 -0
- package/dist/build-components/CarouselItem/CarouselItemProps.generated.d.ts +34 -1
- package/dist/build-components/CarouselProvider/CarouselProviderProps.generated.d.ts +34 -1
- package/dist/build-components/Image/ImageProps.generated.d.ts +32 -3
- package/dist/build-components/Onboard/OnboardProps.generated.d.ts +34 -1
- package/dist/build-components/OnboardButton/OnboardButtonProps.generated.d.ts +32 -0
- package/dist/build-components/OnboardButtons/OnboardButtonsProps.generated.d.ts +32 -0
- package/dist/build-components/OnboardDot/OnboardDot.d.ts +1 -1
- package/dist/build-components/OnboardDot/OnboardDotProps.generated.d.ts +29 -0
- package/dist/build-components/OnboardFooter/OnboardFooterProps.generated.d.ts +11 -5
- package/dist/build-components/OnboardImage/OnboardImageProps.generated.d.ts +32 -3
- package/dist/build-components/OnboardItem/OnboardItemProps.generated.d.ts +31 -3
- package/dist/build-components/OnboardProvider/OnboardProviderProps.generated.d.ts +32 -5
- package/dist/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.d.ts +11 -5
- package/dist/build-components/OnboardTitle/OnboardTitleProps.generated.d.ts +11 -5
- package/dist/build-components/Text/TextProps.generated.d.ts +11 -5
- package/dist/build-components/View/ViewProps.generated.d.ts +10 -4
- package/dist/build-components/index.d.ts +2 -1
- package/dist/build-components/patterns.generated.d.ts +6288 -136
- package/dist/components/AttributesEditorPanel.d.ts +3 -4
- package/dist/components/Breadcrumb.d.ts +3 -1
- package/dist/components/Builder.d.ts +2 -1
- package/dist/components/BuilderButton.d.ts +9 -0
- package/dist/components/Checkbox.d.ts +17 -0
- package/dist/components/DeviceButton.d.ts +8 -0
- package/dist/components/DeviceNavigationBar.d.ts +10 -0
- package/dist/components/DeviceStatusBar.d.ts +9 -0
- package/dist/components/EditorHeader.d.ts +3 -8
- package/dist/index.cjs.js +5 -5
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.esm.js +5 -5
- package/dist/index.esm.js.map +1 -1
- package/dist/mockOS/components/MockLaunchScreenComponent.d.ts +6 -0
- package/dist/mockOS/components/MockOSRouter.d.ts +8 -0
- package/dist/mockOS/components/PermissionModal.d.ts +9 -0
- package/dist/mockOS/context/MockOSContext.d.ts +36 -0
- package/dist/mockOS/hooks/useMockNavigation.d.ts +3 -0
- package/dist/mockOS/hooks/useMockPermission.d.ts +3 -0
- package/dist/mockOS/index.d.ts +9 -0
- package/dist/mockOS/managers/mockPermissionManager.d.ts +10 -0
- package/dist/mockOS/managers/navigationManager.d.ts +17 -0
- package/dist/modals/AddComponentModal.d.ts +8 -0
- package/dist/modals/ColorModal.d.ts +11 -0
- package/dist/modals/DeviceSelectorModal.d.ts +9 -0
- package/dist/modals/LocalicationModal.d.ts +8 -0
- package/dist/modals/Modal.d.ts +12 -0
- package/dist/modals/index.d.ts +5 -0
- package/dist/pages/ProjectPage.d.ts +3 -3
- package/dist/pages/tabs/BuilderPanel.d.ts +8 -0
- package/dist/pages/tabs/{DebugTab.d.ts → SideTool.d.ts} +2 -2
- package/dist/store.d.ts +7 -3
- package/dist/styles.css +1 -1
- package/dist/types/Project.d.ts +11 -0
- package/dist/utils/analyseNode.d.ts +1 -0
- package/dist/utils/extractTextStyle.d.ts +8 -1
- package/dist/utils/extractViewStyle.d.ts +8 -1
- package/dist/utils/parseColor.d.ts +7 -0
- package/dist/utils/patterns.d.ts +24 -0
- package/package.json +2 -1
- package/scripts/prebuild/utils/createGeneratedProps.js +11 -3
- package/scripts/prebuild/utils/validateAllComponentsOrThrow.js +45 -6
- package/scripts/prebuild/utils/validatePatternJson.js +13 -5
- package/src/AttributesEditor.tsx +493 -310
- package/src/DeviceMockFrame.tsx +21 -37
- package/src/RenderPage.tsx +86 -7
- package/src/assets/images/android.svg +42 -42
- package/src/assets/images/apple.svg +15 -15
- package/src/attributes-editor/Field.tsx +669 -0
- package/src/attributes-editor/FieldInfoTooltip.tsx +49 -0
- package/src/attributes-editor/LayoutPreviewPicker.tsx +199 -0
- package/src/attributes-editor/SpecialCategorySection.tsx +285 -0
- package/src/attributes-editor/types.ts +30 -0
- package/src/build-components/BackgroundImage/BackgroundImage.tsx +87 -0
- package/src/build-components/BackgroundImage/BackgroundImageProps.generated.ts +60 -0
- package/src/build-components/BackgroundImage/pattern.json +45 -0
- package/src/build-components/Button/Button.tsx +37 -2
- package/src/build-components/Button/ButtonProps.generated.ts +44 -1
- package/src/build-components/Button/pattern.json +31 -2
- package/src/build-components/Carousel/Carousel.tsx +39 -2
- package/src/build-components/Carousel/CarouselProps.generated.ts +46 -1
- package/src/build-components/Carousel/pattern.json +10 -0
- package/src/build-components/CarouselButtons/CarouselButtons.tsx +21 -2
- package/src/build-components/CarouselButtons/CarouselButtonsProps.generated.ts +43 -0
- package/src/build-components/CarouselButtons/pattern.json +22 -0
- package/src/build-components/CarouselDots/CarouselDots.tsx +49 -8
- package/src/build-components/CarouselDots/CarouselDotsProps.generated.ts +43 -0
- package/src/build-components/CarouselDots/pattern.json +15 -0
- package/src/build-components/CarouselItem/CarouselItem.tsx +21 -2
- package/src/build-components/CarouselItem/CarouselItemProps.generated.ts +46 -1
- package/src/build-components/CarouselItem/pattern.json +7 -0
- package/src/build-components/CarouselProvider/CarouselProvider.tsx +21 -2
- package/src/build-components/CarouselProvider/CarouselProviderProps.generated.ts +46 -1
- package/src/build-components/CarouselProvider/pattern.json +7 -0
- package/src/build-components/Image/Image.tsx +33 -2
- package/src/build-components/Image/ImageProps.generated.ts +43 -3
- package/src/build-components/Image/pattern.json +46 -3
- package/src/build-components/Onboard/Onboard.tsx +6 -1
- package/src/build-components/Onboard/OnboardProps.generated.ts +46 -1
- package/src/build-components/Onboard/pattern.json +11 -0
- package/src/build-components/OnboardButton/OnboardButton.tsx +54 -6
- package/src/build-components/OnboardButton/OnboardButtonProps.generated.ts +43 -0
- package/src/build-components/OnboardButton/pattern.json +71 -5
- package/src/build-components/OnboardButtons/OnboardButtons.tsx +33 -11
- package/src/build-components/OnboardButtons/OnboardButtonsProps.generated.ts +43 -0
- package/src/build-components/OnboardButtons/pattern.json +70 -4
- package/src/build-components/OnboardDot/OnboardDot.tsx +113 -4
- package/src/build-components/OnboardDot/OnboardDotProps.generated.ts +29 -0
- package/src/build-components/OnboardDot/pattern.json +55 -2
- package/src/build-components/OnboardFooter/OnboardFooter.tsx +20 -4
- package/src/build-components/OnboardFooter/OnboardFooterProps.generated.ts +11 -5
- package/src/build-components/OnboardFooter/pattern.json +58 -2
- package/src/build-components/OnboardImage/OnboardImage.tsx +49 -5
- package/src/build-components/OnboardImage/OnboardImageProps.generated.ts +43 -3
- package/src/build-components/OnboardImage/pattern.json +21 -0
- package/src/build-components/OnboardItem/OnboardItem.tsx +17 -1
- package/src/build-components/OnboardItem/OnboardItemProps.generated.ts +42 -3
- package/src/build-components/OnboardItem/pattern.json +38 -2
- package/src/build-components/OnboardProvider/OnboardProvider.tsx +52 -18
- package/src/build-components/OnboardProvider/OnboardProviderProps.generated.ts +44 -5
- package/src/build-components/OnboardProvider/pattern.json +44 -5
- package/src/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.ts +11 -5
- package/src/build-components/OnboardSubtitle/pattern.json +7 -1
- package/src/build-components/OnboardTitle/OnboardTitleProps.generated.ts +11 -5
- package/src/build-components/OnboardTitle/pattern.json +7 -1
- package/src/build-components/RenderNode.generated.tsx +3 -0
- package/src/build-components/Text/Text.tsx +34 -6
- package/src/build-components/Text/TextProps.generated.ts +11 -5
- package/src/build-components/Text/pattern.json +38 -2
- package/src/build-components/View/View.tsx +33 -6
- package/src/build-components/View/ViewProps.generated.ts +10 -4
- package/src/build-components/View/pattern.json +285 -19
- package/src/build-components/index.ts +5 -0
- package/src/build-components/patterns.generated.ts +6346 -143
- package/src/components/AttributesEditorPanel.tsx +17 -64
- package/src/components/Breadcrumb.tsx +37 -5
- package/src/components/Builder.tsx +311 -108
- package/src/components/BuilderButton.tsx +127 -0
- package/src/components/Checkbox.tsx +81 -0
- package/src/components/DeviceButton.tsx +39 -0
- package/src/components/DeviceNavigationBar.tsx +201 -0
- package/src/components/DeviceStatusBar.tsx +85 -0
- package/src/components/EditorHeader.tsx +26 -74
- package/src/index.ts +2 -2
- package/src/mockOS/components/MockLaunchScreenComponent.tsx +43 -0
- package/src/mockOS/components/MockOSRouter.tsx +123 -0
- package/src/mockOS/components/PermissionModal.tsx +270 -0
- package/src/mockOS/context/MockOSContext.tsx +179 -0
- package/src/mockOS/hooks/useMockNavigation.ts +11 -0
- package/src/mockOS/hooks/useMockPermission.ts +11 -0
- package/src/mockOS/index.ts +26 -0
- package/src/mockOS/managers/mockPermissionManager.ts +54 -0
- package/src/mockOS/managers/navigationManager.ts +91 -0
- package/src/modals/AddComponentModal.tsx +313 -0
- package/src/modals/ColorModal.tsx +425 -0
- package/src/modals/DeviceSelectorModal.tsx +57 -0
- package/src/modals/LocalicationModal.tsx +54 -0
- package/src/modals/Modal.tsx +57 -0
- package/src/modals/index.ts +5 -0
- package/src/pages/ProjectPage.tsx +307 -71
- package/src/pages/tabs/{BuilderTab.tsx → BuilderPanel.tsx} +13 -9
- package/src/pages/tabs/SideTool.tsx +259 -0
- package/src/size-matters/index.ts +27 -5
- package/src/store.ts +13 -5
- package/src/styles/base/_global.scss +404 -0
- package/src/styles/components/_attributes-editor.scss +273 -0
- package/src/styles/components/_editor-shell.scss +212 -0
- package/src/styles/components/_mockos-router.scss +140 -0
- package/src/styles/components/_ui-components.scss +183 -0
- package/src/styles/foundation/_colors.scss +8 -0
- package/src/styles/{_mixins.scss → foundation/_mixins.scss} +5 -4
- package/src/styles/{_reset.scss → foundation/_reset.scss} +5 -2
- package/src/styles/foundation/_sizes.scss +37 -0
- package/src/styles/foundation/_typography.scss +4 -0
- package/src/styles/foundation/_variables.scss +3 -0
- package/src/styles/index.scss +22 -136
- package/src/styles/layout/_builder.scss +124 -0
- package/src/styles/layout/_pages.scss +3 -0
- package/src/styles/modals/_add-component.scss +122 -0
- package/src/styles/modals/_color-modal.scss +159 -0
- package/src/styles/modals/_device-selector.scss +18 -0
- package/src/styles/modals/_localication-modal.scss +68 -0
- package/src/styles/modals/_modal-shell.scss +46 -0
- package/src/styles/utilities/_carousel.scss +125 -0
- package/src/types/Project.ts +14 -0
- package/src/types/images.d.ts +8 -0
- package/src/utils/analyseNode.ts +98 -0
- package/src/utils/extractTextStyle.ts +28 -10
- package/src/utils/extractViewStyle.ts +77 -9
- package/src/utils/parseColor.ts +43 -0
- package/src/utils/patterns.ts +33 -0
- package/dist/build-components/OnboardDot/OnboardExpandingDotProps.generated.d.ts +0 -10
- package/dist/pages/tabs/BuilderTab.d.ts +0 -9
- package/dist/pages/tabs/PreviewTab.d.ts +0 -3
- package/src/build-components/OnboardDot/OnboardExpandingDotProps.generated.ts +0 -20
- package/src/pages/tabs/DebugTab.tsx +0 -23
- package/src/pages/tabs/PreviewTab.tsx +0 -194
- package/src/styles/_variables.scss +0 -27
- package/src/styles/builder.scss +0 -60
- package/src/styles/components.scss +0 -88
- package/src/styles/editor.scss +0 -174
- package/src/styles/global.scss +0 -200
- package/src/styles/pages.scss +0 -2
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
interface MockLaunchScreenComponentProps {
|
|
4
|
+
appName: string;
|
|
5
|
+
onAppClick: () => void;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function MockLaunchScreenComponent({
|
|
9
|
+
appName,
|
|
10
|
+
onAppClick,
|
|
11
|
+
}: MockLaunchScreenComponentProps) {
|
|
12
|
+
return (
|
|
13
|
+
<div className="mockos-screen mockos-screen--launchscreen">
|
|
14
|
+
<div className="mockos-launcher">
|
|
15
|
+
<div className="mockos-launcher__grid">
|
|
16
|
+
<button
|
|
17
|
+
className="mockos-launcher__app"
|
|
18
|
+
onClick={onAppClick}
|
|
19
|
+
type="button"
|
|
20
|
+
>
|
|
21
|
+
<div className="mockos-launcher__app-icon">
|
|
22
|
+
<svg
|
|
23
|
+
viewBox="0 0 60 60"
|
|
24
|
+
fill="none"
|
|
25
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
26
|
+
>
|
|
27
|
+
<rect width="60" height="60" rx="13" fill="#007AFF" />
|
|
28
|
+
<path
|
|
29
|
+
d="M30 15C21.716 15 15 21.716 15 30s6.716 15 15 15 15-6.716 15-15-6.716-15-15-15zm0 27c-6.617 0-12-5.383-12-12s5.383-12 12-12 12 5.383 12 12-5.383 12-12 12z"
|
|
30
|
+
fill="white"
|
|
31
|
+
/>
|
|
32
|
+
<circle cx="30" cy="30" r="5" fill="white" />
|
|
33
|
+
</svg>
|
|
34
|
+
</div>
|
|
35
|
+
<div className="mockos-launcher__app-name">{appName}</div>
|
|
36
|
+
</button>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export default MockLaunchScreenComponent;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import React, { ReactNode, useCallback, useEffect } from 'react';
|
|
2
|
+
import { useMockOSContext } from '../context/MockOSContext';
|
|
3
|
+
import { MockLaunchScreenComponent } from './MockLaunchScreenComponent';
|
|
4
|
+
// Note: We might use react-router or similar library in the future for more complex routing
|
|
5
|
+
|
|
6
|
+
interface MockOSRouterProps {
|
|
7
|
+
children?: ReactNode;
|
|
8
|
+
childrenBelongTo?: 'launchscreen' | 'home' | 'onboard' | 'subscription';
|
|
9
|
+
appName?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function HomeComponent() {
|
|
13
|
+
return (
|
|
14
|
+
<div className="mockos-screen mockos-screen--home">
|
|
15
|
+
<div className="mockos-screen__heading">Home</div>
|
|
16
|
+
<div className="mockos-screen__text">Welcome to the home screen</div>
|
|
17
|
+
</div>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function OnboardComponent() {
|
|
22
|
+
return (
|
|
23
|
+
<div className="mockos-screen mockos-screen--onboard">
|
|
24
|
+
<div className="mockos-screen__heading">Onboarding</div>
|
|
25
|
+
<div className="mockos-screen__text">Welcome! Let's get you started.</div>
|
|
26
|
+
</div>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function SubscriptionComponent() {
|
|
31
|
+
return (
|
|
32
|
+
<div className="mockos-screen mockos-screen--subscription">
|
|
33
|
+
<div className="mockos-screen__heading">Subscription</div>
|
|
34
|
+
<div className="mockos-screen__text">Choose your plan</div>
|
|
35
|
+
<div className="mockos-screen__plan mockos-screen__plan--premium">
|
|
36
|
+
Premium - $9.99/month
|
|
37
|
+
</div>
|
|
38
|
+
<div className="mockos-screen__plan mockos-screen__plan--basic">
|
|
39
|
+
Basic - Free
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function ScreenRenderer({
|
|
46
|
+
currentRoute,
|
|
47
|
+
children,
|
|
48
|
+
childrenBelongTo,
|
|
49
|
+
appName,
|
|
50
|
+
onLaunchApp,
|
|
51
|
+
}: {
|
|
52
|
+
currentRoute: string;
|
|
53
|
+
children?: ReactNode;
|
|
54
|
+
childrenBelongTo?: string;
|
|
55
|
+
appName: string;
|
|
56
|
+
onLaunchApp: () => void;
|
|
57
|
+
}) {
|
|
58
|
+
// If children provided and current route matches childrenBelongTo, render children
|
|
59
|
+
if (children && childrenBelongTo && currentRoute === childrenBelongTo) {
|
|
60
|
+
return <>{children}</>;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Otherwise render default screens based on route
|
|
64
|
+
switch (currentRoute) {
|
|
65
|
+
case 'launchscreen':
|
|
66
|
+
return (
|
|
67
|
+
<MockLaunchScreenComponent appName={appName} onAppClick={onLaunchApp} />
|
|
68
|
+
);
|
|
69
|
+
case 'home':
|
|
70
|
+
return <HomeComponent />;
|
|
71
|
+
case 'onboard':
|
|
72
|
+
return <OnboardComponent />;
|
|
73
|
+
case 'subscription':
|
|
74
|
+
return <SubscriptionComponent />;
|
|
75
|
+
default:
|
|
76
|
+
return (
|
|
77
|
+
<MockLaunchScreenComponent appName={appName} onAppClick={onLaunchApp} />
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function MockOSRouter({
|
|
83
|
+
children,
|
|
84
|
+
childrenBelongTo,
|
|
85
|
+
appName = 'My App',
|
|
86
|
+
}: MockOSRouterProps) {
|
|
87
|
+
const context = useMockOSContext();
|
|
88
|
+
|
|
89
|
+
if (!context) {
|
|
90
|
+
throw new Error('MockOSRouter must be used within MockOSProvider');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const { currentRoute, navigation } = context;
|
|
94
|
+
|
|
95
|
+
const handleLaunchApp = useCallback(() => {
|
|
96
|
+
// Navigate to the route specified in childrenBelongTo or default to 'onboard'
|
|
97
|
+
const targetRoute = childrenBelongTo || 'onboard';
|
|
98
|
+
navigation(targetRoute);
|
|
99
|
+
}, [childrenBelongTo, navigation]);
|
|
100
|
+
|
|
101
|
+
useEffect(() => {
|
|
102
|
+
const timer = setTimeout(() => {
|
|
103
|
+
handleLaunchApp();
|
|
104
|
+
}, 1000);
|
|
105
|
+
|
|
106
|
+
return () => clearTimeout(timer);
|
|
107
|
+
}, [handleLaunchApp]);
|
|
108
|
+
|
|
109
|
+
return (
|
|
110
|
+
<div className="mockos-router">
|
|
111
|
+
<ScreenRenderer
|
|
112
|
+
currentRoute={currentRoute}
|
|
113
|
+
childrenBelongTo={childrenBelongTo}
|
|
114
|
+
appName={appName}
|
|
115
|
+
onLaunchApp={handleLaunchApp}
|
|
116
|
+
>
|
|
117
|
+
{children}
|
|
118
|
+
</ScreenRenderer>
|
|
119
|
+
</div>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export default MockOSRouter;
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useRenderStore } from '../../store';
|
|
3
|
+
import type { PermissionType } from '../managers/mockPermissionManager';
|
|
4
|
+
|
|
5
|
+
interface PermissionModalProps {
|
|
6
|
+
permission: PermissionType | string;
|
|
7
|
+
onAllow: () => void;
|
|
8
|
+
onDeny: () => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const getPermissionText = (permission: PermissionType | string) => {
|
|
12
|
+
const texts: Record<string, { title: string; message: string }> = {
|
|
13
|
+
camera: {
|
|
14
|
+
title: 'Camera Access',
|
|
15
|
+
message:
|
|
16
|
+
'This app would like to access your camera to take photos and videos.',
|
|
17
|
+
},
|
|
18
|
+
microphone: {
|
|
19
|
+
title: 'Microphone Access',
|
|
20
|
+
message: 'This app would like to access your microphone to record audio.',
|
|
21
|
+
},
|
|
22
|
+
location: {
|
|
23
|
+
title: 'Location Access',
|
|
24
|
+
message:
|
|
25
|
+
'This app would like to access your location to provide location-based services.',
|
|
26
|
+
},
|
|
27
|
+
notifications: {
|
|
28
|
+
title: 'Allow Notifications',
|
|
29
|
+
message: 'This app would like to send you notifications.',
|
|
30
|
+
},
|
|
31
|
+
photos: {
|
|
32
|
+
title: 'Photo Library Access',
|
|
33
|
+
message: 'This app would like to access your photos.',
|
|
34
|
+
},
|
|
35
|
+
contacts: {
|
|
36
|
+
title: 'Contacts Access',
|
|
37
|
+
message: 'This app would like to access your contacts.',
|
|
38
|
+
},
|
|
39
|
+
att: {
|
|
40
|
+
title: 'Allow Tracking',
|
|
41
|
+
message:
|
|
42
|
+
"This app would like to track your activity across other companies' apps and websites.",
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
return (
|
|
46
|
+
texts[permission] || {
|
|
47
|
+
title: 'Permission Required',
|
|
48
|
+
message: `This app would like to access ${permission}.`,
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const PermissionModal: React.FC<PermissionModalProps> = ({
|
|
54
|
+
permission,
|
|
55
|
+
onAllow,
|
|
56
|
+
onDeny,
|
|
57
|
+
}) => {
|
|
58
|
+
const device = useRenderStore((s) => s.device);
|
|
59
|
+
const isIOS = device.platform === 'ios';
|
|
60
|
+
const { title, message } = getPermissionText(permission);
|
|
61
|
+
|
|
62
|
+
// iOS Style
|
|
63
|
+
if (isIOS) {
|
|
64
|
+
return (
|
|
65
|
+
<div
|
|
66
|
+
style={{
|
|
67
|
+
position: 'absolute',
|
|
68
|
+
top: 0,
|
|
69
|
+
left: 0,
|
|
70
|
+
right: 0,
|
|
71
|
+
bottom: 0,
|
|
72
|
+
backgroundColor: 'rgba(0, 0, 0, 0.4)',
|
|
73
|
+
display: 'flex',
|
|
74
|
+
alignItems: 'center',
|
|
75
|
+
justifyContent: 'center',
|
|
76
|
+
zIndex: 9999,
|
|
77
|
+
padding: 20,
|
|
78
|
+
}}
|
|
79
|
+
onClick={(e) => {
|
|
80
|
+
if (e.target === e.currentTarget) {
|
|
81
|
+
onDeny();
|
|
82
|
+
}
|
|
83
|
+
}}
|
|
84
|
+
>
|
|
85
|
+
<div
|
|
86
|
+
style={{
|
|
87
|
+
backgroundColor: 'rgba(255, 255, 255, 0.95)',
|
|
88
|
+
borderRadius: 14,
|
|
89
|
+
width: '100%',
|
|
90
|
+
maxWidth: 270,
|
|
91
|
+
overflow: 'hidden',
|
|
92
|
+
backdropFilter: 'blur(20px)',
|
|
93
|
+
}}
|
|
94
|
+
>
|
|
95
|
+
<div
|
|
96
|
+
style={{
|
|
97
|
+
padding: '20px 16px',
|
|
98
|
+
textAlign: 'center',
|
|
99
|
+
}}
|
|
100
|
+
>
|
|
101
|
+
<div
|
|
102
|
+
style={{
|
|
103
|
+
fontSize: 17,
|
|
104
|
+
fontWeight: 600,
|
|
105
|
+
color: '#000',
|
|
106
|
+
marginBottom: 8,
|
|
107
|
+
lineHeight: 1.3,
|
|
108
|
+
}}
|
|
109
|
+
>
|
|
110
|
+
{title}
|
|
111
|
+
</div>
|
|
112
|
+
<div
|
|
113
|
+
style={{
|
|
114
|
+
fontSize: 13,
|
|
115
|
+
color: '#000',
|
|
116
|
+
lineHeight: 1.4,
|
|
117
|
+
opacity: 0.6,
|
|
118
|
+
}}
|
|
119
|
+
>
|
|
120
|
+
{message}
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
<div
|
|
124
|
+
style={{
|
|
125
|
+
borderTop: '0.5px solid rgba(0, 0, 0, 0.2)',
|
|
126
|
+
display: 'flex',
|
|
127
|
+
}}
|
|
128
|
+
>
|
|
129
|
+
<button
|
|
130
|
+
onClick={onDeny}
|
|
131
|
+
style={{
|
|
132
|
+
flex: 1,
|
|
133
|
+
padding: '11px 0',
|
|
134
|
+
fontSize: 17,
|
|
135
|
+
fontWeight: 400,
|
|
136
|
+
color: '#007AFF',
|
|
137
|
+
background: 'transparent',
|
|
138
|
+
border: 'none',
|
|
139
|
+
borderRight: '0.5px solid rgba(0, 0, 0, 0.2)',
|
|
140
|
+
cursor: 'pointer',
|
|
141
|
+
}}
|
|
142
|
+
>
|
|
143
|
+
Don't Allow
|
|
144
|
+
</button>
|
|
145
|
+
<button
|
|
146
|
+
onClick={onAllow}
|
|
147
|
+
style={{
|
|
148
|
+
flex: 1,
|
|
149
|
+
padding: '11px 0',
|
|
150
|
+
fontSize: 17,
|
|
151
|
+
fontWeight: 600,
|
|
152
|
+
color: '#007AFF',
|
|
153
|
+
background: 'transparent',
|
|
154
|
+
border: 'none',
|
|
155
|
+
cursor: 'pointer',
|
|
156
|
+
}}
|
|
157
|
+
>
|
|
158
|
+
Allow
|
|
159
|
+
</button>
|
|
160
|
+
</div>
|
|
161
|
+
</div>
|
|
162
|
+
</div>
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Android Material Design Style
|
|
167
|
+
return (
|
|
168
|
+
<div
|
|
169
|
+
style={{
|
|
170
|
+
position: 'absolute',
|
|
171
|
+
top: 0,
|
|
172
|
+
left: 0,
|
|
173
|
+
right: 0,
|
|
174
|
+
bottom: 0,
|
|
175
|
+
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
|
176
|
+
display: 'flex',
|
|
177
|
+
alignItems: 'center',
|
|
178
|
+
justifyContent: 'center',
|
|
179
|
+
zIndex: 9999,
|
|
180
|
+
padding: 24,
|
|
181
|
+
}}
|
|
182
|
+
onClick={(e) => {
|
|
183
|
+
if (e.target === e.currentTarget) {
|
|
184
|
+
onDeny();
|
|
185
|
+
}
|
|
186
|
+
}}
|
|
187
|
+
>
|
|
188
|
+
<div
|
|
189
|
+
style={{
|
|
190
|
+
backgroundColor: '#FFFFFF',
|
|
191
|
+
borderRadius: 4,
|
|
192
|
+
width: '100%',
|
|
193
|
+
maxWidth: 280,
|
|
194
|
+
boxShadow:
|
|
195
|
+
'0 11px 15px -7px rgba(0,0,0,0.2), 0 24px 38px 3px rgba(0,0,0,0.14)',
|
|
196
|
+
}}
|
|
197
|
+
>
|
|
198
|
+
<div
|
|
199
|
+
style={{
|
|
200
|
+
padding: '24px 24px 20px',
|
|
201
|
+
}}
|
|
202
|
+
>
|
|
203
|
+
<div
|
|
204
|
+
style={{
|
|
205
|
+
fontSize: 20,
|
|
206
|
+
fontWeight: 500,
|
|
207
|
+
color: 'rgba(0, 0, 0, 0.87)',
|
|
208
|
+
marginBottom: 16,
|
|
209
|
+
lineHeight: 1.2,
|
|
210
|
+
}}
|
|
211
|
+
>
|
|
212
|
+
{title}
|
|
213
|
+
</div>
|
|
214
|
+
<div
|
|
215
|
+
style={{
|
|
216
|
+
fontSize: 16,
|
|
217
|
+
color: 'rgba(0, 0, 0, 0.6)',
|
|
218
|
+
lineHeight: 1.5,
|
|
219
|
+
}}
|
|
220
|
+
>
|
|
221
|
+
{message}
|
|
222
|
+
</div>
|
|
223
|
+
</div>
|
|
224
|
+
<div
|
|
225
|
+
style={{
|
|
226
|
+
padding: '8px 8px 8px 0',
|
|
227
|
+
display: 'flex',
|
|
228
|
+
justifyContent: 'flex-end',
|
|
229
|
+
gap: 8,
|
|
230
|
+
}}
|
|
231
|
+
>
|
|
232
|
+
<button
|
|
233
|
+
onClick={onDeny}
|
|
234
|
+
style={{
|
|
235
|
+
padding: '8px 16px',
|
|
236
|
+
fontSize: 14,
|
|
237
|
+
fontWeight: 500,
|
|
238
|
+
color: '#5F6368',
|
|
239
|
+
background: 'transparent',
|
|
240
|
+
border: 'none',
|
|
241
|
+
borderRadius: 4,
|
|
242
|
+
cursor: 'pointer',
|
|
243
|
+
textTransform: 'uppercase',
|
|
244
|
+
letterSpacing: 0.5,
|
|
245
|
+
}}
|
|
246
|
+
>
|
|
247
|
+
Deny
|
|
248
|
+
</button>
|
|
249
|
+
<button
|
|
250
|
+
onClick={onAllow}
|
|
251
|
+
style={{
|
|
252
|
+
padding: '8px 16px',
|
|
253
|
+
fontSize: 14,
|
|
254
|
+
fontWeight: 500,
|
|
255
|
+
color: '#1A73E8',
|
|
256
|
+
background: 'transparent',
|
|
257
|
+
border: 'none',
|
|
258
|
+
borderRadius: 4,
|
|
259
|
+
cursor: 'pointer',
|
|
260
|
+
textTransform: 'uppercase',
|
|
261
|
+
letterSpacing: 0.5,
|
|
262
|
+
}}
|
|
263
|
+
>
|
|
264
|
+
Allow
|
|
265
|
+
</button>
|
|
266
|
+
</div>
|
|
267
|
+
</div>
|
|
268
|
+
</div>
|
|
269
|
+
);
|
|
270
|
+
};
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
createContext,
|
|
3
|
+
useContext,
|
|
4
|
+
ReactNode,
|
|
5
|
+
useState,
|
|
6
|
+
useCallback,
|
|
7
|
+
} from 'react';
|
|
8
|
+
import type { PermissionType } from '../managers/mockPermissionManager';
|
|
9
|
+
import { PermissionModal } from '../components/PermissionModal';
|
|
10
|
+
import { MockOSRouter } from '../components/MockOSRouter';
|
|
11
|
+
import { DeviceStatusBar } from '../../components/DeviceStatusBar';
|
|
12
|
+
import { DeviceNavigationBar } from '../../components/DeviceNavigationBar';
|
|
13
|
+
import type { Device } from '../../types/Device';
|
|
14
|
+
|
|
15
|
+
export type RouteType = 'launchscreen' | 'home' | 'onboard' | 'subscription';
|
|
16
|
+
|
|
17
|
+
export interface RouteStackItem {
|
|
18
|
+
route: RouteType;
|
|
19
|
+
timestamp: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface MockOSContextValue {
|
|
23
|
+
isEnabled: boolean;
|
|
24
|
+
permission: PermissionType | string | null;
|
|
25
|
+
setPermission: (permission: PermissionType | string | null) => void;
|
|
26
|
+
// Router
|
|
27
|
+
currentRoute: RouteType;
|
|
28
|
+
navigation: (route: RouteType) => void;
|
|
29
|
+
goBack: () => boolean;
|
|
30
|
+
navigationStack: RouteStackItem[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const MockOSContext = createContext<MockOSContextValue | null>(null);
|
|
34
|
+
|
|
35
|
+
export const useMockOSContext = () => {
|
|
36
|
+
return useContext(MockOSContext);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
interface MockOSProviderProps {
|
|
40
|
+
children: ReactNode;
|
|
41
|
+
defaultRoute?: RouteType;
|
|
42
|
+
appName?: string;
|
|
43
|
+
// Status Bar props
|
|
44
|
+
statusBarHeight: number;
|
|
45
|
+
statusBarBackgroundColor: string;
|
|
46
|
+
statusBarPlatform: Device['platform'];
|
|
47
|
+
statusBarIsDark: boolean;
|
|
48
|
+
// Navigation Bar props
|
|
49
|
+
navBarHeight: number;
|
|
50
|
+
navBarBackgroundColor: string;
|
|
51
|
+
navBarPlatform: Device['platform'];
|
|
52
|
+
navBarNavigationBarType: Device['navigationBarType'];
|
|
53
|
+
navBarIsDark: boolean;
|
|
54
|
+
// Insets
|
|
55
|
+
insetLeft: number;
|
|
56
|
+
insetRight: number;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function MockOSProvider({
|
|
60
|
+
children,
|
|
61
|
+
defaultRoute = 'launchscreen',
|
|
62
|
+
appName,
|
|
63
|
+
statusBarHeight,
|
|
64
|
+
statusBarBackgroundColor,
|
|
65
|
+
statusBarPlatform,
|
|
66
|
+
statusBarIsDark,
|
|
67
|
+
navBarHeight,
|
|
68
|
+
navBarBackgroundColor,
|
|
69
|
+
navBarPlatform,
|
|
70
|
+
navBarNavigationBarType,
|
|
71
|
+
navBarIsDark,
|
|
72
|
+
insetLeft,
|
|
73
|
+
insetRight,
|
|
74
|
+
}: MockOSProviderProps) {
|
|
75
|
+
const [permission, setPermission] = useState<PermissionType | string | null>(
|
|
76
|
+
null,
|
|
77
|
+
);
|
|
78
|
+
const [currentRoute, setCurrentRoute] = useState<RouteType>(defaultRoute);
|
|
79
|
+
const [navigationStack, setNavigationStack] = useState<RouteStackItem[]>([
|
|
80
|
+
{ route: defaultRoute, timestamp: Date.now() },
|
|
81
|
+
]);
|
|
82
|
+
|
|
83
|
+
const navigation = useCallback((route: RouteType) => {
|
|
84
|
+
console.log(`[Mock OS] Navigating to: ${route}`);
|
|
85
|
+
setCurrentRoute(route);
|
|
86
|
+
|
|
87
|
+
// If navigating from launchscreen and the last item in stack is launchscreen,
|
|
88
|
+
// replace it instead of adding new item
|
|
89
|
+
setNavigationStack((prev) => {
|
|
90
|
+
const lastItem = prev[prev.length - 1];
|
|
91
|
+
if (
|
|
92
|
+
lastItem &&
|
|
93
|
+
lastItem.route === 'launchscreen' &&
|
|
94
|
+
route !== 'launchscreen'
|
|
95
|
+
) {
|
|
96
|
+
// Replace the last launchscreen item
|
|
97
|
+
const newStack = [...prev];
|
|
98
|
+
newStack[newStack.length - 1] = { route, timestamp: Date.now() };
|
|
99
|
+
return newStack;
|
|
100
|
+
}
|
|
101
|
+
// Otherwise add new item to stack
|
|
102
|
+
return [...prev, { route, timestamp: Date.now() }];
|
|
103
|
+
});
|
|
104
|
+
}, []);
|
|
105
|
+
|
|
106
|
+
const goBack = useCallback(() => {
|
|
107
|
+
if (navigationStack.length > 1) {
|
|
108
|
+
const newStack = [...navigationStack];
|
|
109
|
+
newStack.pop();
|
|
110
|
+
const previousRoute = newStack[newStack.length - 1];
|
|
111
|
+
|
|
112
|
+
console.log(`[Mock OS] Going back to: ${previousRoute.route}`);
|
|
113
|
+
setCurrentRoute(previousRoute.route);
|
|
114
|
+
setNavigationStack(newStack);
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
console.log('[Mock OS] Cannot go back - at root');
|
|
118
|
+
return false;
|
|
119
|
+
}, [navigationStack]);
|
|
120
|
+
|
|
121
|
+
const value: MockOSContextValue = {
|
|
122
|
+
isEnabled: true,
|
|
123
|
+
permission,
|
|
124
|
+
setPermission,
|
|
125
|
+
currentRoute,
|
|
126
|
+
navigation,
|
|
127
|
+
goBack,
|
|
128
|
+
navigationStack,
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const handleAllow = () => {
|
|
132
|
+
console.log(`[Mock OS] Permission granted: ${permission}`);
|
|
133
|
+
setPermission(null);
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const handleDeny = () => {
|
|
137
|
+
console.log(`[Mock OS] Permission denied: ${permission}`);
|
|
138
|
+
setPermission(null);
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
return (
|
|
142
|
+
<MockOSContext.Provider value={value}>
|
|
143
|
+
{permission !== null && (
|
|
144
|
+
<PermissionModal
|
|
145
|
+
permission={permission}
|
|
146
|
+
onAllow={handleAllow}
|
|
147
|
+
onDeny={handleDeny}
|
|
148
|
+
/>
|
|
149
|
+
)}
|
|
150
|
+
<DeviceStatusBar
|
|
151
|
+
height={statusBarHeight}
|
|
152
|
+
backgroundColor={statusBarBackgroundColor}
|
|
153
|
+
platform={statusBarPlatform}
|
|
154
|
+
isDark={statusBarIsDark}
|
|
155
|
+
/>
|
|
156
|
+
<div
|
|
157
|
+
className="device-content"
|
|
158
|
+
style={{
|
|
159
|
+
flex: 1,
|
|
160
|
+
overflow: 'hidden',
|
|
161
|
+
position: 'relative',
|
|
162
|
+
paddingLeft: insetLeft,
|
|
163
|
+
paddingRight: insetRight,
|
|
164
|
+
}}
|
|
165
|
+
>
|
|
166
|
+
<MockOSRouter childrenBelongTo="onboard" appName={appName}>
|
|
167
|
+
{children}
|
|
168
|
+
</MockOSRouter>
|
|
169
|
+
</div>
|
|
170
|
+
<DeviceNavigationBar
|
|
171
|
+
height={navBarHeight}
|
|
172
|
+
backgroundColor={navBarBackgroundColor}
|
|
173
|
+
platform={navBarPlatform}
|
|
174
|
+
navigationBarType={navBarNavigationBarType}
|
|
175
|
+
isDark={navBarIsDark}
|
|
176
|
+
/>
|
|
177
|
+
</MockOSContext.Provider>
|
|
178
|
+
);
|
|
179
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { MockOSContextValue } from '../context/MockOSContext';
|
|
3
|
+
import { MockNavigationManager } from '../managers/navigationManager';
|
|
4
|
+
|
|
5
|
+
export function useMockNavigation(context: MockOSContextValue | null) {
|
|
6
|
+
const navigationManager = useMemo(() => {
|
|
7
|
+
return new MockNavigationManager(context);
|
|
8
|
+
}, [context]);
|
|
9
|
+
|
|
10
|
+
return navigationManager;
|
|
11
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { MockOSContextValue } from '../context/MockOSContext';
|
|
3
|
+
import { MockPermissionManager } from '../managers/mockPermissionManager';
|
|
4
|
+
|
|
5
|
+
export function useMockPermission(context: MockOSContextValue | null) {
|
|
6
|
+
const permissionManager = useMemo(() => {
|
|
7
|
+
return new MockPermissionManager(context);
|
|
8
|
+
}, [context]);
|
|
9
|
+
|
|
10
|
+
return permissionManager;
|
|
11
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Context
|
|
2
|
+
export { MockOSProvider, useMockOSContext } from './context/MockOSContext';
|
|
3
|
+
export type {
|
|
4
|
+
MockOSContextValue,
|
|
5
|
+
RouteType,
|
|
6
|
+
RouteStackItem,
|
|
7
|
+
} from './context/MockOSContext';
|
|
8
|
+
|
|
9
|
+
// Components
|
|
10
|
+
export { MockOSRouter } from './components/MockOSRouter';
|
|
11
|
+
|
|
12
|
+
// Managers
|
|
13
|
+
export { MockPermissionManager } from './managers/mockPermissionManager';
|
|
14
|
+
export type {
|
|
15
|
+
PermissionType,
|
|
16
|
+
PermissionStatus,
|
|
17
|
+
} from './managers/mockPermissionManager';
|
|
18
|
+
export { MockNavigationManager } from './managers/navigationManager';
|
|
19
|
+
export type {
|
|
20
|
+
NavigationDestination,
|
|
21
|
+
NavigationStackItem,
|
|
22
|
+
} from './managers/navigationManager';
|
|
23
|
+
|
|
24
|
+
// Hooks
|
|
25
|
+
export { useMockPermission } from './hooks/useMockPermission';
|
|
26
|
+
export { useMockNavigation } from './hooks/useMockNavigation';
|