@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,57 @@
1
+ import React, { useEffect } from 'react';
2
+
3
+ type ModalProps = {
4
+ onClose: () => void;
5
+ ariaLabelledBy?: string;
6
+ children: React.ReactNode;
7
+ className?: string;
8
+ contentClassName?: string;
9
+ closeOnOverlayClick?: boolean;
10
+ closeOnEsc?: boolean;
11
+ };
12
+
13
+ export function Modal({
14
+ onClose,
15
+ ariaLabelledBy,
16
+ children,
17
+ className,
18
+ contentClassName,
19
+ closeOnOverlayClick = true,
20
+ closeOnEsc = true,
21
+ }: ModalProps) {
22
+ useEffect(() => {
23
+ if (!closeOnEsc) return undefined;
24
+ if (typeof window === 'undefined') return undefined;
25
+
26
+ const handleKeyDown = (event: KeyboardEvent) => {
27
+ if (event.key === 'Escape') {
28
+ onClose();
29
+ }
30
+ };
31
+
32
+ window.addEventListener('keydown', handleKeyDown);
33
+ return () => window.removeEventListener('keydown', handleKeyDown);
34
+ }, [closeOnEsc, onClose]);
35
+
36
+ return (
37
+ <div
38
+ className={`modal${className ? ` ${className}` : ''}`}
39
+ role="dialog"
40
+ aria-modal="true"
41
+ aria-labelledby={ariaLabelledBy}
42
+ >
43
+ <div
44
+ className="modal__overlay"
45
+ onClick={closeOnOverlayClick ? onClose : undefined}
46
+ />
47
+ <div
48
+ className={`modal__content${contentClassName ? ` ${contentClassName}` : ''}`}
49
+ role="document"
50
+ >
51
+ {children}
52
+ </div>
53
+ </div>
54
+ );
55
+ }
56
+
57
+ export default Modal;
@@ -0,0 +1,5 @@
1
+ export { default as Modal } from './Modal';
2
+ export { AddComponentModal } from './AddComponentModal';
3
+ export { DeviceSelectorModal } from './DeviceSelectorModal';
4
+ export { ColorModal } from './ColorModal';
5
+ export { LocalicationModal } from './LocalicationModal';
@@ -10,8 +10,8 @@ import { useRenderStore } from '../store';
10
10
  import { logger } from '../utils/logger';
11
11
  import { useLogRender } from '../utils/useLogRender';
12
12
  import type { LogLevel } from '../types/Project';
13
-
14
- export type Tab = 'builder' | 'preview' | 'debug';
13
+ import backgroundImage from '../assets/images/background.jpg';
14
+ export type Tab = 'builder' | 'preview';
15
15
 
16
16
  export type ProjectPageProps = {
17
17
  project: Project;
@@ -55,6 +55,11 @@ export function ProjectPage({
55
55
  data: editorData,
56
56
  });
57
57
  }}
58
+ onRestoreProject={() => {
59
+ logger.info('ProjectPage', 'restore project', { name: project.name });
60
+ setEditorData(project.data);
61
+ setCurrent(project.data);
62
+ }}
58
63
  current={current}
59
64
  editorData={editorData}
60
65
  setEditorData={setEditorData}
@@ -76,7 +81,7 @@ export function ProjectPage({
76
81
  logger.info('ProjectPage', 'tab change', { to: 'builder' });
77
82
  }}
78
83
  >
79
- Builder
84
+ <span className="editor-tab__label">Builder</span>
80
85
  </button>
81
86
  <button
82
87
  className={`editor-tab ${tab === 'preview' ? 'editor-tab--active' : ''}`}
@@ -87,18 +92,7 @@ export function ProjectPage({
87
92
  logger.info('ProjectPage', 'tab change', { to: 'preview' });
88
93
  }}
89
94
  >
90
- Preview Config
91
- </button>
92
- <button
93
- className={`editor-tab ${tab === 'debug' ? 'editor-tab--active' : ''}`}
94
- role="tab"
95
- aria-selected={tab === 'debug'}
96
- onClick={() => {
97
- setTab('debug');
98
- logger.info('ProjectPage', 'tab change', { to: 'debug' });
99
- }}
100
- >
101
- Debug
95
+ <span className="editor-tab__label">Preview Config</span>
102
96
  </button>
103
97
  </div>
104
98
 
@@ -112,15 +106,19 @@ export function ProjectPage({
112
106
  )}
113
107
 
114
108
  {tab === 'preview' && <PreviewTab />}
115
-
116
- {tab === 'debug' && (
117
- <DebugTab data={editorData} setData={setEditorData} />
118
- )}
119
109
  </div>
120
110
  </div>
121
111
  <div className="split-right">
122
- <div className="split-right-background" />
123
- <RenderPage data={editorData} />
112
+ <div className="split-right__controls">
113
+ <DebugTab data={editorData} setData={setEditorData} />
114
+ </div>
115
+ <div
116
+ className="split-right-background"
117
+ style={{
118
+ backgroundImage: `url(${backgroundImage})`,
119
+ }}
120
+ />
121
+ <RenderPage data={editorData} name={project.name} />
124
122
  </div>
125
123
  <div className="split-third">
126
124
  <AttributesEditorPanel
@@ -1,4 +1,6 @@
1
+ import React, { useState } from 'react';
1
2
  import { JsonEditor } from 'json-edit-react';
3
+ import { Modal } from '../../modals';
2
4
  import { Node } from '../..';
3
5
  import { useLogRender } from '../../utils/useLogRender';
4
6
 
@@ -9,15 +11,54 @@ type DebugTabProps = {
9
11
 
10
12
  export function DebugTab({ data, setData }: DebugTabProps) {
11
13
  useLogRender('DebugTab');
14
+ const [isOpen, setIsOpen] = useState(false);
12
15
  return (
13
- <div
14
- role="tabpanel"
15
- className="editor-panel editor-panel--active editor-panels-debug"
16
- aria-hidden={false}
17
- >
18
- <div style={{ flex: '1 1 auto', minHeight: 0, overflow: 'auto' }}>
19
- <JsonEditor data={data as any} setData={setData as any} />
20
- </div>
21
- </div>
16
+ <>
17
+ <button
18
+ type="button"
19
+ className="editor-button debug-button"
20
+ title="Inspect raw JSON data"
21
+ onClick={() => setIsOpen(true)}
22
+ >
23
+ Debug JSON
24
+ </button>
25
+ {isOpen ? (
26
+ <Modal
27
+ onClose={() => setIsOpen(false)}
28
+ ariaLabelledBy="debug-json-editor-title"
29
+ className="modal--large modal--scrollable"
30
+ contentClassName="localication-modal__content"
31
+ >
32
+ <div className="modal__header localication-modal__header">
33
+ <div className="localication-modal__header-main">
34
+ <h3 id="debug-json-editor-title" className="modal__title">
35
+ Debug data
36
+ </h3>
37
+ <p className="localication-modal__description">
38
+ Inspect and edit the current node tree using the JSON editor.
39
+ </p>
40
+ </div>
41
+ <button
42
+ type="button"
43
+ className="editor-button"
44
+ onClick={() => setIsOpen(false)}
45
+ >
46
+ Close
47
+ </button>
48
+ </div>
49
+ <div className="localication-modal__body">
50
+ <div className="localication-modal__editor">
51
+ <JsonEditor
52
+ rootName="debug"
53
+ data={data as any}
54
+ setData={setData as any}
55
+ className="localication-modal__json-editor"
56
+ maxWidth={'100%'}
57
+ />
58
+ </div>
59
+ </div>
60
+ </Modal>
61
+ ) : null}
62
+ </>
22
63
  );
23
64
  }
@@ -1,7 +1,9 @@
1
- import { JsonEditor } from 'json-edit-react';
2
- import { Localication, TargetedScreenSize } from '../..';
1
+ import React, { useCallback, useState } from 'react';
2
+ import { Localication } from '../..';
3
3
  import { useLogRender } from '../../utils/useLogRender';
4
4
  import { useRenderStore } from '../../store';
5
+ import { LocalicationModal } from '../../modals/LocalicationModal';
6
+ import { Checkbox } from '../../components/Checkbox';
5
7
 
6
8
  type PreviewTabProps = {};
7
9
 
@@ -11,6 +13,18 @@ export function PreviewTab({}: PreviewTabProps) {
11
13
  appConfig: s.appConfig,
12
14
  setAppConfig: s.setAppConfig,
13
15
  }));
16
+ const [isLocalicationModalOpen, setIsLocalicationModalOpen] = useState(false);
17
+
18
+ const handleLocalicationChange = useCallback(
19
+ (data: Localication) => {
20
+ setAppConfig({
21
+ ...appConfig,
22
+ localication: data,
23
+ });
24
+ },
25
+ [appConfig, setAppConfig],
26
+ );
27
+
14
28
  return (
15
29
  <div
16
30
  role="tabpanel"
@@ -134,21 +148,12 @@ export function PreviewTab({}: PreviewTabProps) {
134
148
  className="input input--color"
135
149
  />
136
150
  </div>
137
- <div
138
- style={{
139
- display: 'flex',
140
- alignItems: 'center',
141
- gap: 8,
142
- marginTop: 8,
143
- }}
144
- >
145
- <div>Dark Mode</div>
146
- <input
147
- type="checkbox"
151
+ <div style={{ marginTop: 8 }}>
152
+ <Checkbox
153
+ label="Dark Mode"
148
154
  checked={appConfig.theme === 'dark'}
149
- onChange={(e) => {
150
- const nextTheme = e.target.checked ? 'dark' : 'light';
151
-
155
+ onChange={(checked) => {
156
+ const nextTheme = checked ? 'dark' : 'light';
152
157
  setAppConfig({
153
158
  ...appConfig,
154
159
  theme: nextTheme,
@@ -156,39 +161,46 @@ export function PreviewTab({}: PreviewTabProps) {
156
161
  }}
157
162
  />
158
163
  </div>
159
- <div
160
- style={{
161
- display: 'flex',
162
- alignItems: 'center',
163
- gap: 8,
164
- marginTop: 8,
165
- }}
166
- >
167
- <div>Is RTL</div>
168
- <input
169
- type="checkbox"
164
+ <div style={{ marginTop: 8 }}>
165
+ <Checkbox
166
+ label="Is RTL"
170
167
  checked={appConfig.isRtl ?? false}
171
- onChange={(e) => {
168
+ onChange={(checked) => {
172
169
  setAppConfig({
173
170
  ...appConfig,
174
- isRtl: e.target.checked,
171
+ isRtl: checked,
175
172
  });
176
173
  }}
177
174
  />
178
175
  </div>
179
- <div style={{ marginTop: 8 }}>
180
- <JsonEditor
181
- rootName="localication"
182
- data={appConfig.localication ?? {}}
183
- setData={(data) => {
184
- setAppConfig({
185
- ...appConfig,
186
- localication: data as Localication,
187
- });
188
- }}
189
- />
176
+ <div
177
+ style={{
178
+ marginTop: 16,
179
+ display: 'flex',
180
+ flexDirection: 'column',
181
+ gap: 8,
182
+ }}
183
+ >
184
+ <div style={{ fontWeight: 600 }}>Localization</div>
185
+ <p style={{ margin: 0, fontSize: 13, color: '#4b5563' }}>
186
+ Manage translations for each language configured in your preview.
187
+ </p>
188
+ <button
189
+ type="button"
190
+ className="editor-button"
191
+ onClick={() => setIsLocalicationModalOpen(true)}
192
+ >
193
+ Open localization editor
194
+ </button>
190
195
  </div>
191
196
  </div>
197
+ {isLocalicationModalOpen ? (
198
+ <LocalicationModal
199
+ data={appConfig.localication ?? {}}
200
+ onChange={handleLocalicationChange}
201
+ onClose={() => setIsLocalicationModalOpen(false)}
202
+ />
203
+ ) : null}
192
204
  </div>
193
205
  );
194
206
  }
@@ -1,15 +1,31 @@
1
1
  import { useRenderStore } from '../store';
2
+ import { defaultAppConfig } from '../types/PreviewConfig';
3
+ import { getDefaultDevice } from '../utils/getDevices';
4
+
5
+ const fallbackDevice = getDefaultDevice();
6
+ const fallbackBaseSize = defaultAppConfig.baseSize;
7
+
8
+ function ensureNumber(value: number | undefined, fallback: number) {
9
+ return typeof value === 'number' && Number.isFinite(value) ? value : fallback;
10
+ }
2
11
 
3
12
  function getBaseDimensions() {
4
13
  const currentState = useRenderStore.getState();
5
- let device = currentState.device;
14
+ const device = currentState.device ?? fallbackDevice;
15
+ const baseSize = currentState.appConfig?.baseSize ?? fallbackBaseSize;
16
+
17
+ const deviceWidth = ensureNumber(device?.width, fallbackDevice.width);
18
+ const deviceHeight = ensureNumber(device?.height, fallbackDevice.height);
19
+ const baseWidth = ensureNumber(baseSize?.width, fallbackBaseSize.width);
20
+ const baseHeight = ensureNumber(baseSize?.height, fallbackBaseSize.height);
21
+
6
22
  const [shortDimension, longDimension] =
7
- device.width < device.height
8
- ? [device.width, device.height]
9
- : [device.height, device.width];
23
+ deviceWidth < deviceHeight
24
+ ? [deviceWidth, deviceHeight]
25
+ : [deviceHeight, deviceWidth];
10
26
 
11
27
  return {
12
- baseSize: currentState.appConfig.baseSize,
28
+ baseSize: { width: baseWidth, height: baseHeight },
13
29
  shortDimension,
14
30
  longDimension,
15
31
  };
package/src/store.ts CHANGED
@@ -19,8 +19,6 @@ type RenderStore = {
19
19
  setDevice: (device: Device) => void;
20
20
  appConfig: AppConfig;
21
21
  setAppConfig: (appConfig: AppConfig) => void;
22
- renderCount: number;
23
- forceRender: () => void;
24
22
  // Logging
25
23
  logs: LogEntry[];
26
24
  logLevel: LogLevel;
@@ -38,8 +36,6 @@ export const useRenderStore = createWithEqualityFn<RenderStore>()(
38
36
  (set) => ({
39
37
  copiedNode: null,
40
38
  setCopiedNode: (node) => set({ copiedNode: node }),
41
- renderCount: 0,
42
- forceRender: () => set((state) => ({ renderCount: state.renderCount + 1 })),
43
39
  device: getDefaultDevice(),
44
40
  setDevice: (device) => set({ device }),
45
41
  appConfig: defaultAppConfig,
@@ -1,12 +1,13 @@
1
- @use './variables' as *;
2
- @use './mixins' as *;
3
- @use './reset';
1
+ @use '../foundation/colors' as colors;
2
+ @use '../foundation/sizes' as sizes;
3
+ @use '../foundation/typography' as type;
4
+ @use '../foundation/mixins' as *;
4
5
 
5
6
  /* Global utility classes */
6
7
  html,
7
8
  body,
8
9
  #root {
9
- font-family: $font-sans;
10
+ font-family: type.$bodyFont;
10
11
  }
11
12
 
12
13
  .editor-container {
@@ -18,35 +19,30 @@ body,
18
19
  .editor-panel-builder {
19
20
  padding: 4px 8px;
20
21
  }
21
- .app-shell {
22
- min-height: 100vh;
23
- display: flex;
24
- flex-direction: column;
25
- }
26
22
 
27
23
  .app-main {
28
24
  flex: 1 1 auto;
29
- background: $color-background;
25
+ background: colors.$canvasColor;
30
26
  }
31
27
 
32
28
  .page-bg {
33
- background: $color-background;
29
+ background: colors.$canvasColor;
34
30
  }
35
31
 
36
32
  .grid-cards {
37
33
  display: grid;
38
34
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
39
- gap: $space-4;
35
+ gap: sizes.$spaceComfy;
40
36
  }
41
37
 
42
38
  .btn-add {
43
39
  height: 120px;
44
- border: 2px dashed $color-muted;
45
- border-radius: $radius-md;
40
+ border: 2px dashed colors.$mutedTextColor;
41
+ border-radius: sizes.$radiusRounded;
46
42
  background: #fff;
47
43
  cursor: pointer;
48
44
  font-weight: 600;
49
- color: $color-text;
45
+ color: colors.$textColor;
50
46
  transition:
51
47
  border-color 0.2s ease,
52
48
  transform 0.1s ease,
@@ -54,7 +50,7 @@ body,
54
50
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
55
51
 
56
52
  &:hover {
57
- border-color: darken($color-muted, 10%);
53
+ border-color: darken(colors.$mutedTextColor, 10%);
58
54
  transform: translateY(-1px);
59
55
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.1);
60
56
  }
@@ -62,48 +58,67 @@ body,
62
58
 
63
59
  .split-left {
64
60
  @include thin-scrollbar;
65
- flex: 1 1 30%;
61
+ flex: 1 1 10%;
66
62
  min-width: 0;
67
- border-right: 1px solid $color-border;
63
+ border-right: 1px solid colors.$borderColor;
68
64
  overflow: auto;
69
65
  }
70
66
 
71
67
  .split-right {
72
68
  position: relative;
73
69
  flex: 1 1 45%;
74
- min-width: 0;
75
- max-height: calc(100vh - 120px);
70
+ max-height: calc(100vh + 60px);
71
+ //NOTE: Found by trial and error. We want it to make it full height of the screen with padding
72
+ padding: sizes.$spaceComfy;
73
+ padding-bottom: 120px;
76
74
  overflow: auto;
77
75
  }
78
76
 
77
+ .split-right__controls {
78
+ position: sticky;
79
+ top: sizes.$spaceCozy;
80
+ z-index: 2;
81
+ display: flex;
82
+ margin-bottom: sizes.$spaceCozy;
83
+ }
84
+
79
85
  .split-third {
80
86
  flex: 1 1 25%;
81
- min-width: 0;
82
- border-right: 1px solid $color-border;
87
+ min-width: 450px;
88
+ border-right: 1px solid colors.$borderColor;
83
89
  overflow: auto;
84
90
  max-height: calc(100vh - 120px);
85
91
  }
86
92
 
87
93
  .split-right-background {
88
94
  position: absolute;
89
- inset: 0;
95
+ top: 0;
96
+ left: 0;
97
+ right: 0;
98
+ bottom: 0;
99
+ height: calc(100vh + 60px);
90
100
  background-size: cover;
91
101
  background-position: center;
92
102
  background-repeat: repeat;
93
103
  background-size: 500px auto;
94
104
  opacity: 0.2;
105
+ z-index: 0;
106
+ pointer-events: none;
95
107
  }
96
108
 
97
109
  .stage-wrapper {
98
110
  display: flex;
99
111
  justify-content: center;
100
- background: $color-background;
101
- padding: $space-4;
112
+ background: transparent;
113
+ padding: sizes.$spaceComfy;
114
+ position: relative;
115
+ z-index: 1;
102
116
  }
103
117
 
104
118
  .stage {
105
119
  @include card;
106
- border: 1px solid $color-border;
120
+ border: 1px solid colors.$borderColor;
121
+ overflow: hidden;
107
122
 
108
123
  .scroll-container {
109
124
  /* Mobile-like scrollbar styling */
@@ -133,15 +148,15 @@ body,
133
148
  top: 0;
134
149
  z-index: 10;
135
150
  background: #fff;
136
- border-bottom: 1px solid $color-border;
151
+ border-bottom: 1px solid colors.$borderColor;
137
152
  height: 60px;
138
- padding: 0 $space-4;
153
+ padding: 0 sizes.$spaceComfy;
139
154
  display: flex;
140
155
  align-items: center;
141
156
  justify-content: space-between;
142
157
 
143
158
  a {
144
- color: $color-text;
159
+ color: colors.$textColor;
145
160
  text-decoration: none;
146
161
  }
147
162
  }
@@ -152,20 +167,46 @@ body,
152
167
 
153
168
  .app-header__nav {
154
169
  display: flex;
155
- gap: $space-4;
170
+ gap: sizes.$spaceComfy;
156
171
  }
157
172
  .warning {
158
- color: $color-error;
173
+ color: colors.$dangerColor;
159
174
  font-size: 12px;
160
175
  font-weight: 600;
161
- margin-bottom: $space-4;
176
+ margin-bottom: sizes.$spaceComfy;
162
177
  }
163
178
 
164
179
  /* Breadcrumb */
165
180
  .breadcrumb {
166
- display: block;
181
+ display: flex;
182
+ align-items: center;
183
+ gap: sizes.$spaceCozy;
167
184
  font-size: 12px;
168
- color: $color-muted;
185
+ color: colors.$mutedTextColor;
186
+ }
187
+
188
+ .breadcrumb__back {
189
+ display: inline-flex;
190
+ align-items: center;
191
+ gap: sizes.$spaceTight;
192
+ padding: 0;
193
+ border: none;
194
+ background: none;
195
+ color: colors.$textColor;
196
+ font-weight: 600;
197
+ cursor: pointer;
198
+ transition: color 0.2s ease;
199
+
200
+ &:hover,
201
+ &:focus-visible {
202
+ color: colors.$accentColor;
203
+ outline: none;
204
+ }
205
+ }
206
+
207
+ .breadcrumb__back-icon {
208
+ font-size: 14px;
209
+ line-height: 1;
169
210
  }
170
211
 
171
212
  .breadcrumb__list {
@@ -174,21 +215,24 @@ body,
174
215
  margin: 0;
175
216
  display: flex;
176
217
  align-items: center;
177
- gap: $space-2;
218
+ gap: sizes.$spaceCompact;
178
219
  }
179
220
 
180
221
  .breadcrumb__item {
181
222
  display: inline-flex;
182
223
  align-items: center;
224
+ &--clickable {
225
+ cursor: pointer;
226
+ }
183
227
  }
184
228
 
185
229
  .breadcrumb__separator {
186
- color: $color-border;
187
- margin: 0 $space-1;
230
+ color: colors.$borderColor;
231
+ margin: 0 sizes.$spaceTight;
188
232
  }
189
233
 
190
234
  .breadcrumb__link {
191
- color: $color-text;
235
+ color: colors.$textColor;
192
236
  text-decoration: none;
193
237
  &:hover {
194
238
  text-decoration: underline;
@@ -196,5 +240,14 @@ body,
196
240
  }
197
241
 
198
242
  .breadcrumb__current {
199
- color: $color-muted;
243
+ color: colors.$mutedTextColor;
244
+ }
245
+
246
+ .device-status-bar {
247
+ position: relative;
248
+ z-index: 100;
249
+ }
250
+ .device-navigation-bar {
251
+ position: relative;
252
+ z-index: 100;
200
253
  }