@developer_tribe/react-builder 1.0.1 → 1.0.2

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 (187) hide show
  1. package/dist/DeviceMockFrame.d.ts +2 -1
  2. package/dist/RenderPage.d.ts +4 -3
  3. package/dist/attributes-editor/Field.d.ts +16 -0
  4. package/dist/attributes-editor/FieldInfoTooltip.d.ts +7 -0
  5. package/dist/attributes-editor/LayoutPreviewPicker.d.ts +12 -0
  6. package/dist/attributes-editor/SpecialCategorySection.d.ts +19 -0
  7. package/dist/attributes-editor/types.d.ts +14 -0
  8. package/dist/background.jpg +0 -0
  9. package/dist/build-components/Button/Button.d.ts +1 -1
  10. package/dist/build-components/Button/ButtonProps.generated.d.ts +26 -1
  11. package/dist/build-components/Carousel/CarouselProps.generated.d.ts +27 -1
  12. package/dist/build-components/CarouselButtons/CarouselButtonsProps.generated.d.ts +25 -0
  13. package/dist/build-components/CarouselDots/CarouselDotsProps.generated.d.ts +25 -0
  14. package/dist/build-components/CarouselItem/CarouselItemProps.generated.d.ts +27 -1
  15. package/dist/build-components/CarouselProvider/CarouselProviderProps.generated.d.ts +27 -1
  16. package/dist/build-components/Image/ImageProps.generated.d.ts +25 -3
  17. package/dist/build-components/Onboard/OnboardProps.generated.d.ts +27 -1
  18. package/dist/build-components/OnboardButton/OnboardButtonProps.generated.d.ts +25 -0
  19. package/dist/build-components/OnboardButtons/OnboardButtonsProps.generated.d.ts +25 -0
  20. package/dist/build-components/OnboardDot/OnboardDot.d.ts +1 -1
  21. package/dist/build-components/OnboardDot/OnboardDotProps.generated.d.ts +22 -0
  22. package/dist/build-components/OnboardFooter/OnboardFooterProps.generated.d.ts +4 -5
  23. package/dist/build-components/OnboardImage/OnboardImageProps.generated.d.ts +25 -3
  24. package/dist/build-components/OnboardItem/OnboardItemProps.generated.d.ts +24 -3
  25. package/dist/build-components/OnboardProvider/OnboardProviderProps.generated.d.ts +25 -4
  26. package/dist/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.d.ts +4 -5
  27. package/dist/build-components/OnboardTitle/OnboardTitleProps.generated.d.ts +4 -5
  28. package/dist/build-components/Text/TextProps.generated.d.ts +4 -5
  29. package/dist/build-components/View/ViewProps.generated.d.ts +3 -4
  30. package/dist/build-components/patterns.generated.d.ts +4855 -132
  31. package/dist/components/Breadcrumb.d.ts +3 -1
  32. package/dist/components/Checkbox.d.ts +17 -0
  33. package/dist/components/DeviceButton.d.ts +8 -0
  34. package/dist/components/DeviceNavigationBar.d.ts +10 -0
  35. package/dist/components/DeviceStatusBar.d.ts +9 -0
  36. package/dist/components/EditorHeader.d.ts +3 -8
  37. package/dist/index.cjs.js +5 -5
  38. package/dist/index.cjs.js.map +1 -1
  39. package/dist/index.esm.js +5 -5
  40. package/dist/index.esm.js.map +1 -1
  41. package/dist/mockOS/components/MockLaunchScreenComponent.d.ts +6 -0
  42. package/dist/mockOS/components/MockOSRouter.d.ts +8 -0
  43. package/dist/mockOS/components/PermissionModal.d.ts +9 -0
  44. package/dist/mockOS/context/MockOSContext.d.ts +36 -0
  45. package/dist/mockOS/hooks/useMockNavigation.d.ts +3 -0
  46. package/dist/mockOS/hooks/useMockPermission.d.ts +3 -0
  47. package/dist/mockOS/index.d.ts +9 -0
  48. package/dist/mockOS/managers/mockPermissionManager.d.ts +10 -0
  49. package/dist/mockOS/managers/navigationManager.d.ts +17 -0
  50. package/dist/modals/AddComponentModal.d.ts +8 -0
  51. package/dist/modals/ColorModal.d.ts +9 -0
  52. package/dist/modals/DeviceSelectorModal.d.ts +9 -0
  53. package/dist/modals/LocalicationModal.d.ts +8 -0
  54. package/dist/modals/Modal.d.ts +12 -0
  55. package/dist/modals/index.d.ts +5 -0
  56. package/dist/pages/ProjectPage.d.ts +1 -1
  57. package/dist/store.d.ts +0 -2
  58. package/dist/styles.css +1 -1
  59. package/dist/utils/patterns.d.ts +24 -0
  60. package/package.json +2 -1
  61. package/scripts/prebuild/utils/createGeneratedProps.js +11 -3
  62. package/scripts/prebuild/utils/validateAllComponentsOrThrow.js +45 -6
  63. package/scripts/prebuild/utils/validatePatternJson.js +13 -5
  64. package/src/AttributesEditor.tsx +433 -312
  65. package/src/DeviceMockFrame.tsx +21 -37
  66. package/src/RenderPage.tsx +5 -4
  67. package/src/assets/images/android.svg +42 -42
  68. package/src/assets/images/apple.svg +15 -15
  69. package/src/attributes-editor/Field.tsx +662 -0
  70. package/src/attributes-editor/FieldInfoTooltip.tsx +49 -0
  71. package/src/attributes-editor/LayoutPreviewPicker.tsx +199 -0
  72. package/src/attributes-editor/SpecialCategorySection.tsx +284 -0
  73. package/src/attributes-editor/types.ts +30 -0
  74. package/src/build-components/Button/Button.tsx +10 -2
  75. package/src/build-components/Button/ButtonProps.generated.ts +37 -1
  76. package/src/build-components/Button/pattern.json +31 -2
  77. package/src/build-components/Carousel/Carousel.tsx +15 -2
  78. package/src/build-components/Carousel/CarouselProps.generated.ts +39 -1
  79. package/src/build-components/Carousel/pattern.json +10 -0
  80. package/src/build-components/CarouselButtons/CarouselButtons.tsx +6 -2
  81. package/src/build-components/CarouselButtons/CarouselButtonsProps.generated.ts +36 -0
  82. package/src/build-components/CarouselButtons/pattern.json +22 -0
  83. package/src/build-components/CarouselDots/CarouselDots.tsx +40 -8
  84. package/src/build-components/CarouselDots/CarouselDotsProps.generated.ts +36 -0
  85. package/src/build-components/CarouselDots/pattern.json +15 -0
  86. package/src/build-components/CarouselItem/CarouselItem.tsx +5 -2
  87. package/src/build-components/CarouselItem/CarouselItemProps.generated.ts +39 -1
  88. package/src/build-components/CarouselItem/pattern.json +7 -0
  89. package/src/build-components/CarouselProvider/CarouselProvider.tsx +10 -2
  90. package/src/build-components/CarouselProvider/CarouselProviderProps.generated.ts +39 -1
  91. package/src/build-components/CarouselProvider/pattern.json +7 -0
  92. package/src/build-components/Image/Image.tsx +8 -2
  93. package/src/build-components/Image/ImageProps.generated.ts +36 -3
  94. package/src/build-components/Image/pattern.json +46 -3
  95. package/src/build-components/Onboard/Onboard.tsx +6 -1
  96. package/src/build-components/Onboard/OnboardProps.generated.ts +39 -1
  97. package/src/build-components/Onboard/pattern.json +11 -0
  98. package/src/build-components/OnboardButton/OnboardButton.tsx +46 -5
  99. package/src/build-components/OnboardButton/OnboardButtonProps.generated.ts +36 -0
  100. package/src/build-components/OnboardButton/pattern.json +71 -5
  101. package/src/build-components/OnboardButtons/OnboardButtons.tsx +20 -10
  102. package/src/build-components/OnboardButtons/OnboardButtonsProps.generated.ts +36 -0
  103. package/src/build-components/OnboardButtons/pattern.json +70 -4
  104. package/src/build-components/OnboardDot/OnboardDot.tsx +104 -4
  105. package/src/build-components/OnboardDot/OnboardDotProps.generated.ts +22 -0
  106. package/src/build-components/OnboardDot/pattern.json +54 -1
  107. package/src/build-components/OnboardFooter/OnboardFooter.tsx +9 -3
  108. package/src/build-components/OnboardFooter/OnboardFooterProps.generated.ts +4 -5
  109. package/src/build-components/OnboardFooter/pattern.json +58 -2
  110. package/src/build-components/OnboardImage/OnboardImage.tsx +27 -5
  111. package/src/build-components/OnboardImage/OnboardImageProps.generated.ts +36 -3
  112. package/src/build-components/OnboardImage/pattern.json +21 -0
  113. package/src/build-components/OnboardItem/OnboardItem.tsx +6 -1
  114. package/src/build-components/OnboardItem/OnboardItemProps.generated.ts +35 -3
  115. package/src/build-components/OnboardItem/pattern.json +38 -2
  116. package/src/build-components/OnboardProvider/OnboardProvider.tsx +20 -8
  117. package/src/build-components/OnboardProvider/OnboardProviderProps.generated.ts +37 -4
  118. package/src/build-components/OnboardProvider/pattern.json +51 -4
  119. package/src/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.ts +4 -5
  120. package/src/build-components/OnboardSubtitle/pattern.json +6 -0
  121. package/src/build-components/OnboardTitle/OnboardTitleProps.generated.ts +4 -5
  122. package/src/build-components/OnboardTitle/pattern.json +6 -0
  123. package/src/build-components/Text/Text.tsx +7 -3
  124. package/src/build-components/Text/TextProps.generated.ts +4 -5
  125. package/src/build-components/Text/pattern.json +38 -2
  126. package/src/build-components/View/View.tsx +9 -6
  127. package/src/build-components/View/ViewProps.generated.ts +3 -4
  128. package/src/build-components/View/pattern.json +227 -19
  129. package/src/build-components/patterns.generated.ts +4905 -139
  130. package/src/components/AttributesEditorPanel.tsx +7 -61
  131. package/src/components/Breadcrumb.tsx +37 -5
  132. package/src/components/Builder.tsx +180 -77
  133. package/src/components/Checkbox.tsx +81 -0
  134. package/src/components/DeviceButton.tsx +39 -0
  135. package/src/components/DeviceNavigationBar.tsx +201 -0
  136. package/src/components/DeviceStatusBar.tsx +85 -0
  137. package/src/components/EditorHeader.tsx +26 -74
  138. package/src/mockOS/components/MockLaunchScreenComponent.tsx +43 -0
  139. package/src/mockOS/components/MockOSRouter.tsx +115 -0
  140. package/src/mockOS/components/PermissionModal.tsx +270 -0
  141. package/src/mockOS/context/MockOSContext.tsx +179 -0
  142. package/src/mockOS/hooks/useMockNavigation.ts +11 -0
  143. package/src/mockOS/hooks/useMockPermission.ts +11 -0
  144. package/src/mockOS/index.ts +26 -0
  145. package/src/mockOS/managers/mockPermissionManager.ts +54 -0
  146. package/src/mockOS/managers/navigationManager.ts +91 -0
  147. package/src/modals/AddComponentModal.tsx +313 -0
  148. package/src/modals/ColorModal.tsx +268 -0
  149. package/src/modals/DeviceSelectorModal.tsx +57 -0
  150. package/src/modals/LocalicationModal.tsx +54 -0
  151. package/src/modals/Modal.tsx +57 -0
  152. package/src/modals/index.ts +5 -0
  153. package/src/pages/ProjectPage.tsx +19 -21
  154. package/src/pages/tabs/DebugTab.tsx +50 -9
  155. package/src/pages/tabs/PreviewTab.tsx +52 -40
  156. package/src/size-matters/index.ts +21 -5
  157. package/src/store.ts +0 -4
  158. package/src/styles/{global.scss → base/_global.scss} +92 -39
  159. package/src/styles/components/_attributes-editor.scss +261 -0
  160. package/src/styles/{editor.scss → components/_editor-shell.scss} +72 -57
  161. package/src/styles/components/_mockos-router.scss +140 -0
  162. package/src/styles/components/_ui-components.scss +183 -0
  163. package/src/styles/foundation/_colors.scss +8 -0
  164. package/src/styles/{_mixins.scss → foundation/_mixins.scss} +5 -4
  165. package/src/styles/{_reset.scss → foundation/_reset.scss} +5 -2
  166. package/src/styles/foundation/_sizes.scss +37 -0
  167. package/src/styles/foundation/_typography.scss +4 -0
  168. package/src/styles/foundation/_variables.scss +3 -0
  169. package/src/styles/index.scss +22 -136
  170. package/src/styles/layout/_builder.scss +68 -0
  171. package/src/styles/layout/_pages.scss +3 -0
  172. package/src/styles/modals/_add-component.scss +122 -0
  173. package/src/styles/modals/_color-modal.scss +130 -0
  174. package/src/styles/modals/_device-selector.scss +18 -0
  175. package/src/styles/modals/_localication-modal.scss +68 -0
  176. package/src/styles/modals/_modal-shell.scss +46 -0
  177. package/src/styles/utilities/_carousel.scss +125 -0
  178. package/src/types/images.d.ts +8 -0
  179. package/src/utils/extractTextStyle.ts +4 -2
  180. package/src/utils/extractViewStyle.ts +51 -7
  181. package/src/utils/patterns.ts +33 -0
  182. package/dist/build-components/OnboardDot/OnboardExpandingDotProps.generated.d.ts +0 -10
  183. package/src/build-components/OnboardDot/OnboardExpandingDotProps.generated.ts +0 -20
  184. package/src/styles/_variables.scss +0 -27
  185. package/src/styles/builder.scss +0 -60
  186. package/src/styles/components.scss +0 -88
  187. package/src/styles/pages.scss +0 -2
@@ -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';
@@ -0,0 +1,54 @@
1
+ import { MockOSContextValue } from '../context/MockOSContext';
2
+
3
+ export type PermissionType =
4
+ | 'camera'
5
+ | 'microphone'
6
+ | 'location'
7
+ | 'notifications'
8
+ | 'photos'
9
+ | 'contacts'
10
+ | 'att'; // App Tracking Transparency
11
+
12
+ export type PermissionStatus = 'granted' | 'denied' | 'not-determined';
13
+
14
+ export class MockPermissionManager {
15
+ private context: MockOSContextValue | null;
16
+
17
+ constructor(context: MockOSContextValue | null) {
18
+ this.context = context;
19
+ }
20
+
21
+ requestPermission(permission: PermissionType | string): PermissionStatus {
22
+ if (this.context === null) {
23
+ alert(
24
+ `Permission requested: ${permission}\n(Mock OS context not available)`,
25
+ );
26
+ return 'not-determined';
27
+ }
28
+
29
+ console.log(`[Mock OS] Permission requested: ${permission}`);
30
+ // Set permission to trigger modal display
31
+ this.context.setPermission(permission);
32
+ // Default behavior: grant all permissions in mock environment
33
+ return 'granted';
34
+ }
35
+
36
+ checkPermission(permission: PermissionType | string): PermissionStatus {
37
+ if (this.context === null) {
38
+ alert(`Permission check: ${permission}\n(Mock OS context not available)`);
39
+ return 'not-determined';
40
+ }
41
+
42
+ console.log(`[Mock OS] Permission checked: ${permission}`);
43
+ return 'granted';
44
+ }
45
+
46
+ openSettings(): void {
47
+ if (this.context === null) {
48
+ alert('Opening Settings\n(Mock OS context not available)');
49
+ return;
50
+ }
51
+
52
+ console.log('[Mock OS] Opening Settings');
53
+ }
54
+ }
@@ -0,0 +1,91 @@
1
+ import { MockOSContextValue } from '../context/MockOSContext';
2
+
3
+ export type NavigationDestination =
4
+ | 'home'
5
+ | 'subscriptions'
6
+ | 'launchApp'
7
+ | 'settings'
8
+ | 'profile';
9
+
10
+ export interface NavigationStackItem {
11
+ destination: NavigationDestination;
12
+ timestamp: number;
13
+ }
14
+
15
+ export class MockNavigationManager {
16
+ private context: MockOSContextValue | null;
17
+ private stack: NavigationStackItem[] = [];
18
+
19
+ constructor(context: MockOSContextValue | null) {
20
+ this.context = context;
21
+ }
22
+
23
+ goToHome(): void {
24
+ if (this.context === null) {
25
+ alert('Navigate to Home\n(Mock OS context not available)');
26
+ return;
27
+ }
28
+
29
+ const item: NavigationStackItem = {
30
+ destination: 'home',
31
+ timestamp: Date.now(),
32
+ };
33
+ this.stack.push(item);
34
+ console.log('[Mock OS] Navigate to Home', { stack: this.stack });
35
+ }
36
+
37
+ goToSubscriptions(): void {
38
+ if (this.context === null) {
39
+ alert('Navigate to Subscriptions\n(Mock OS context not available)');
40
+ return;
41
+ }
42
+
43
+ const item: NavigationStackItem = {
44
+ destination: 'subscriptions',
45
+ timestamp: Date.now(),
46
+ };
47
+ this.stack.push(item);
48
+ console.log('[Mock OS] Navigate to Subscriptions', { stack: this.stack });
49
+ }
50
+
51
+ goToLaunchApp(): void {
52
+ if (this.context === null) {
53
+ alert('Navigate to Launch App\n(Mock OS context not available)');
54
+ return;
55
+ }
56
+
57
+ const item: NavigationStackItem = {
58
+ destination: 'launchApp',
59
+ timestamp: Date.now(),
60
+ };
61
+ this.stack.push(item);
62
+ console.log('[Mock OS] Navigate to Launch App', { stack: this.stack });
63
+ }
64
+
65
+ goBack(): boolean {
66
+ if (this.context === null) {
67
+ alert('Go Back\n(Mock OS context not available)');
68
+ return false;
69
+ }
70
+
71
+ if (this.stack.length > 0) {
72
+ const popped = this.stack.pop();
73
+ console.log('[Mock OS] Go Back', { popped, stack: this.stack });
74
+ return true;
75
+ }
76
+
77
+ console.log('[Mock OS] Cannot go back - stack is empty');
78
+ return false;
79
+ }
80
+
81
+ getStack(): NavigationStackItem[] {
82
+ return [...this.stack];
83
+ }
84
+
85
+ clearStack(): void {
86
+ this.stack = [];
87
+ if (this.context) {
88
+ console.log('[Mock OS] Navigation stack cleared');
89
+ }
90
+ }
91
+ }