@developer_tribe/react-builder 0.1.25 → 0.1.26
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/DeviceMockFrame.d.ts +22 -0
- package/dist/RenderPage.d.ts +6 -3
- package/dist/build-components/OnboardProvider/OnboardProviderProps.generated.d.ts +4 -1
- package/dist/build-components/index.d.ts +0 -1
- package/dist/build-components/useNode.d.ts +2 -0
- package/dist/index.cjs.js +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.esm.js +1 -1
- package/dist/types/Device.d.ts +16 -0
- package/dist/types/Node.d.ts +2 -1
- package/dist/utils/patterns.d.ts +4 -0
- package/package.json +1 -1
- package/scripts/prebuild/build-components.js +4 -4
- package/scripts/prebuild/utils/createBuildComponentsIndex.js +1 -4
- package/scripts/prebuild/utils/createBuildComponentsRootGetDefaults.js +2 -55
- package/scripts/prebuild/utils/createGetDefaultsPerComponent.js +2 -19
- package/scripts/prebuild/utils/createRootGetDefaults.js +2 -44
- package/scripts/prebuild/utils/validateAllComponentsOrThrow.js +3 -1
- package/src/AttributesEditor.tsx +19 -15
- package/src/DeviceMockFrame.tsx +119 -0
- package/src/RenderPage.tsx +19 -27
- package/src/assets/devices.json +364 -91
- package/src/build-components/Button/Button.tsx +2 -0
- package/src/build-components/Carousel/Carousel.tsx +2 -0
- package/src/build-components/CarouselButtons/CarouselButtons.tsx +2 -0
- package/src/build-components/CarouselDots/CarouselDots.tsx +2 -0
- package/src/build-components/CarouselItem/CarouselItem.tsx +2 -0
- package/src/build-components/CarouselProvider/CarouselProvider.tsx +2 -0
- package/src/build-components/Image/Image.tsx +2 -0
- package/src/build-components/Onboard/Onboard.tsx +2 -0
- package/src/build-components/OnboardButton/OnboardButton.tsx +2 -0
- package/src/build-components/OnboardButtons/OnboardButtons.tsx +2 -0
- package/src/build-components/OnboardDot/OnboardDot.tsx +2 -0
- package/src/build-components/OnboardFooter/OnboardFooter.tsx +2 -0
- package/src/build-components/OnboardImage/OnboardImage.tsx +2 -0
- package/src/build-components/OnboardItem/OnboardItem.tsx +2 -0
- package/src/build-components/OnboardProvider/OnboardProvider.tsx +13 -1
- package/src/build-components/OnboardProvider/OnboardProviderProps.generated.ts +4 -1
- package/src/build-components/OnboardProvider/pattern.json +4 -1
- package/src/build-components/OnboardSubtitle/OnboardSubtitle.tsx +2 -0
- package/src/build-components/OnboardSubtitle/pattern.json +1 -1
- package/src/build-components/OnboardTitle/OnboardTitle.tsx +2 -0
- package/src/build-components/OnboardTitle/pattern.json +1 -1
- package/src/build-components/Text/Text.tsx +2 -0
- package/src/build-components/View/View.tsx +2 -0
- package/src/build-components/index.ts +0 -2
- package/src/build-components/useNode.ts +15 -0
- package/src/index.ts +2 -0
- package/src/types/Device.ts +21 -0
- package/src/types/Node.ts +2 -11
- package/src/utils/novaToJson.ts +7 -0
- package/src/utils/patterns.ts +11 -0
- package/dist/build-components/Button/getDefaults.d.ts +0 -3
- package/dist/build-components/Carousel/getDefaults.d.ts +0 -3
- package/dist/build-components/CarouselButtons/getDefaults.d.ts +0 -3
- package/dist/build-components/CarouselDots/getDefaults.d.ts +0 -3
- package/dist/build-components/CarouselItem/getDefaults.d.ts +0 -3
- package/dist/build-components/CarouselProvider/getDefaults.d.ts +0 -3
- package/dist/build-components/Image/getDefaults.d.ts +0 -3
- package/dist/build-components/Onboard/getDefaults.d.ts +0 -3
- package/dist/build-components/OnboardButton/getDefaults.d.ts +0 -3
- package/dist/build-components/OnboardButtons/getDefaults.d.ts +0 -3
- package/dist/build-components/OnboardDot/getDefaults.d.ts +0 -3
- package/dist/build-components/OnboardFooter/getDefaults.d.ts +0 -3
- package/dist/build-components/OnboardImage/getDefaults.d.ts +0 -3
- package/dist/build-components/OnboardItem/getDefaults.d.ts +0 -3
- package/dist/build-components/OnboardProvider/getDefaults.d.ts +0 -3
- package/dist/build-components/OnboardSubtitle/getDefaults.d.ts +0 -3
- package/dist/build-components/OnboardTitle/getDefaults.d.ts +0 -3
- package/dist/build-components/Text/getDefaults.d.ts +0 -3
- package/dist/build-components/View/getDefaults.d.ts +0 -3
- package/dist/build-components/getDefaults.d.ts +0 -25
- package/src/build-components/Button/getDefaults.ts +0 -11
- package/src/build-components/Carousel/getDefaults.ts +0 -11
- package/src/build-components/CarouselButtons/getDefaults.ts +0 -13
- package/src/build-components/CarouselDots/getDefaults.ts +0 -13
- package/src/build-components/CarouselItem/getDefaults.ts +0 -13
- package/src/build-components/CarouselProvider/getDefaults.ts +0 -13
- package/src/build-components/Image/getDefaults.ts +0 -11
- package/src/build-components/Onboard/getDefaults.ts +0 -11
- package/src/build-components/OnboardButton/getDefaults.ts +0 -13
- package/src/build-components/OnboardButtons/getDefaults.ts +0 -13
- package/src/build-components/OnboardDot/getDefaults.ts +0 -13
- package/src/build-components/OnboardFooter/getDefaults.ts +0 -13
- package/src/build-components/OnboardImage/getDefaults.ts +0 -13
- package/src/build-components/OnboardItem/getDefaults.ts +0 -13
- package/src/build-components/OnboardProvider/getDefaults.ts +0 -13
- package/src/build-components/OnboardSubtitle/getDefaults.ts +0 -13
- package/src/build-components/OnboardTitle/getDefaults.ts +0 -13
- package/src/build-components/Text/getDefaults.ts +0 -11
- package/src/build-components/View/getDefaults.ts +0 -11
- package/src/build-components/getDefaults.ts +0 -149
package/dist/types/Device.d.ts
CHANGED
|
@@ -4,6 +4,22 @@ export interface Device {
|
|
|
4
4
|
width: number;
|
|
5
5
|
height: number;
|
|
6
6
|
type: 'phone' | 'tablet';
|
|
7
|
+
/**
|
|
8
|
+
* Optional physical corner radius of the device screen area in CSS pixels.
|
|
9
|
+
* Used only for visual preview rounding; has no effect on layout calculations.
|
|
10
|
+
*/
|
|
11
|
+
radius?: number;
|
|
12
|
+
/**
|
|
13
|
+
* Insets in CSS pixels in the order: [top, right, bottom, left]
|
|
14
|
+
* Represents safe area or system UI overlaps (status bar, home indicator, etc.).
|
|
15
|
+
*/
|
|
16
|
+
insets?: [number, number, number, number];
|
|
17
|
+
/**
|
|
18
|
+
* Navigation bar style depending on platform.
|
|
19
|
+
* - iOS: 'none' | 'homeIndicator' | 'tabBar' (visual reference only)
|
|
20
|
+
* - Android: 'threeButtons' | 'gesture' | 'none'
|
|
21
|
+
*/
|
|
22
|
+
navigationBarType?: 'none' | 'homeIndicator' | 'tabBar' | 'threeButtons' | 'gesture';
|
|
7
23
|
/**
|
|
8
24
|
* Relative importance for generic targeting and display ordering.
|
|
9
25
|
* 1 = highest importance, 100 = lowest importance
|
package/dist/types/Node.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
export type NodeDefaultAttribute = Record<string,
|
|
1
|
+
export type NodeDefaultAttribute = Record<string, unknown>;
|
|
2
2
|
export type Node<T = NodeDefaultAttribute> = null | undefined | string | {} | Node<T>[] | NodeData<T>;
|
|
3
3
|
export interface NodeData<T = Record<string, unknown>> {
|
|
4
4
|
type: string;
|
|
5
5
|
children: Node<Record<string, unknown>>;
|
|
6
6
|
attributes?: T;
|
|
7
7
|
key?: string;
|
|
8
|
+
isMain?: boolean;
|
|
8
9
|
}
|
package/dist/utils/patterns.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { NodeDefaultAttribute } from '../types/Node';
|
|
1
2
|
type Pattern = {
|
|
2
3
|
schemaVersion: number;
|
|
3
4
|
allowUnknownAttributes: boolean;
|
|
@@ -7,9 +8,12 @@ type Pattern = {
|
|
|
7
8
|
attributes: Record<string, string | string[]>;
|
|
8
9
|
};
|
|
9
10
|
types?: Record<string, Record<string, string | string[]>>;
|
|
11
|
+
defaults?: NodeDefaultAttribute;
|
|
10
12
|
};
|
|
11
13
|
export declare function getPatternByType(type?: string | null): Pattern | undefined;
|
|
12
14
|
export declare function getAttributeSchema(type?: string | null): Record<string, string | string[]> | undefined;
|
|
15
|
+
/** Returns defaults block (if any) for a given component type */
|
|
16
|
+
export declare function getDefaultsForType(type?: string | null): NodeDefaultAttribute | undefined;
|
|
13
17
|
/**
|
|
14
18
|
* Returns the schema of a custom complex type declared under a component pattern's `types` block.
|
|
15
19
|
* For example, OnboardButton.pattern.types.EventObject
|
package/package.json
CHANGED
|
@@ -13,8 +13,8 @@ import {
|
|
|
13
13
|
validateExistingComponentTsx,
|
|
14
14
|
createRenderNodeGenerated,
|
|
15
15
|
createBuildComponentsIndex,
|
|
16
|
-
createGetDefaultsPerComponent,
|
|
17
|
-
createBuildComponentsRootGetDefaults,
|
|
16
|
+
// createGetDefaultsPerComponent,
|
|
17
|
+
// createBuildComponentsRootGetDefaults,
|
|
18
18
|
formatAllSourceFiles,
|
|
19
19
|
// lintNonGeneratedOrThrow,
|
|
20
20
|
} from './utils/index.js';
|
|
@@ -38,12 +38,12 @@ async function run() {
|
|
|
38
38
|
await ensurePropsTs(componentDir, componentName);
|
|
39
39
|
await createComponentTsx(componentDir, componentName);
|
|
40
40
|
await validateExistingComponentTsx(componentDir, componentName);
|
|
41
|
-
|
|
41
|
+
// Removed: per-component getDefaults generation
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
await createRenderNodeGenerated(validated, paths);
|
|
45
45
|
await createBuildComponentsIndex(validated, paths);
|
|
46
|
-
|
|
46
|
+
// Removed: root getDefaults generator
|
|
47
47
|
await formatAllSourceFiles(paths);
|
|
48
48
|
}
|
|
49
49
|
|
|
@@ -15,11 +15,8 @@ export async function createBuildComponentsIndex(validated, paths) {
|
|
|
15
15
|
.join('\n');
|
|
16
16
|
|
|
17
17
|
const renderNodeExport = `export { default as RenderNode } from './RenderNode.generated';`;
|
|
18
|
-
const getDefaultsExport = `export { getDefaults } from './getDefaults';`;
|
|
19
18
|
|
|
20
|
-
const sections = [renderNodeExport,
|
|
21
|
-
.filter(Boolean)
|
|
22
|
-
.join('\n\n');
|
|
19
|
+
const sections = [renderNodeExport, exportLines].filter(Boolean).join('\n\n');
|
|
23
20
|
|
|
24
21
|
const fileContent =
|
|
25
22
|
`/* AUTO-GENERATED FILE - DO NOT EDIT */\n\n` +
|
|
@@ -6,59 +6,6 @@ import { formatWithPrettier } from './formatWithPrettier.js';
|
|
|
6
6
|
* Creates src/build-components/getDefaults.ts aggregating all component getDefaults
|
|
7
7
|
* with signature: getDefaults<T>(type: T, node: NodeData<List<T>>)
|
|
8
8
|
*/
|
|
9
|
-
export async function createBuildComponentsRootGetDefaults(
|
|
10
|
-
|
|
11
|
-
const targetPath = path.join(COMPONENTS_ROOT, 'getDefaults.ts');
|
|
12
|
-
|
|
13
|
-
const importLines = validated
|
|
14
|
-
.map(({ componentName }) => {
|
|
15
|
-
return `import { getDefaults as get${componentName}Defaults } from './${componentName}/getDefaults';`;
|
|
16
|
-
})
|
|
17
|
-
.join('\n');
|
|
18
|
-
|
|
19
|
-
const typeImports = `import type { ${validated
|
|
20
|
-
.map(({ componentName }) => `${componentName}PropsGenerated`)
|
|
21
|
-
.join(', ')} } from './index';`;
|
|
22
|
-
|
|
23
|
-
const nodeImport = `import type { NodeData } from '../types/Node';`;
|
|
24
|
-
|
|
25
|
-
const typesMap = validated
|
|
26
|
-
.map(({ componentName, patternJson }) => {
|
|
27
|
-
const type = patternJson?.pattern?.type;
|
|
28
|
-
return ` ${JSON.stringify(type)}: ${componentName}PropsGenerated['attributes']`;
|
|
29
|
-
})
|
|
30
|
-
.join(';\n');
|
|
31
|
-
|
|
32
|
-
const switchCases = validated
|
|
33
|
-
.map(({ componentName, patternJson }) => {
|
|
34
|
-
const type = patternJson?.pattern?.type;
|
|
35
|
-
return ` case ${JSON.stringify(type)}:\n defaults = get${componentName}Defaults() as Partial<Types[T]>;\n break;`;
|
|
36
|
-
})
|
|
37
|
-
.join('\n');
|
|
38
|
-
|
|
39
|
-
const fileContent =
|
|
40
|
-
`/* AUTO-GENERATED FILE - DO NOT EDIT */\n\n` +
|
|
41
|
-
`${importLines}\n` +
|
|
42
|
-
`${typeImports}\n` +
|
|
43
|
-
`${nodeImport}\n\n` +
|
|
44
|
-
`export type Types = {\n${typesMap}\n};\n\n` +
|
|
45
|
-
`export type List<T> = T extends keyof Types ? Types[T] : never;\n\n` +
|
|
46
|
-
`export function getDefaults<T extends keyof Types>(type: T, node: NodeData<List<T>>): Partial<Types[T]> {\n` +
|
|
47
|
-
` let defaults: Partial<Types[T]> = {};\n\n` +
|
|
48
|
-
` switch (type as unknown as string) {\n` +
|
|
49
|
-
`${switchCases}\n` +
|
|
50
|
-
` default:\n` +
|
|
51
|
-
` defaults = {} as Partial<Types[T]>;\n` +
|
|
52
|
-
` }\n\n` +
|
|
53
|
-
` if ((node as unknown as { type?: string })?.type !== (type as unknown as string)) {\n` +
|
|
54
|
-
` throw new Error(\n` +
|
|
55
|
-
` \`getDefaults: node.type mismatch; expected \${String(type)}, received \${(node as unknown as { type?: string })?.type ?? 'undefined'}\`\n` +
|
|
56
|
-
` );\n` +
|
|
57
|
-
` }\n\n` +
|
|
58
|
-
` (node as unknown as { attributes?: unknown }).attributes = defaults as Types[T];\n\n` +
|
|
59
|
-
` return defaults;\n` +
|
|
60
|
-
`}\n`;
|
|
61
|
-
|
|
62
|
-
const formatted = await formatWithPrettier(fileContent);
|
|
63
|
-
await fs.writeFile(targetPath, formatted, 'utf8');
|
|
9
|
+
export async function createBuildComponentsRootGetDefaults() {
|
|
10
|
+
// intentionally removed; no longer generating build-components/getDefaults.ts
|
|
64
11
|
}
|
|
@@ -6,23 +6,6 @@ import { formatWithPrettier } from './formatWithPrettier.js';
|
|
|
6
6
|
* Creates src/build-components/<Component>/getDefaults.ts
|
|
7
7
|
* This file returns the `default` block from the folder's pattern.json.
|
|
8
8
|
*/
|
|
9
|
-
export async function createGetDefaultsPerComponent(
|
|
10
|
-
|
|
11
|
-
componentName
|
|
12
|
-
) {
|
|
13
|
-
const targetPath = path.join(componentDir, 'getDefaults.ts');
|
|
14
|
-
|
|
15
|
-
const importPath = `./${componentName}Props.generated`;
|
|
16
|
-
|
|
17
|
-
const fileContent =
|
|
18
|
-
`/* AUTO-GENERATED FILE - DO NOT EDIT */\n\n` +
|
|
19
|
-
`import pattern from './pattern.json';\n` +
|
|
20
|
-
`import type { ${componentName}PropsGenerated } from '${importPath}';\n\n` +
|
|
21
|
-
`export type ${componentName}Defaults = Partial<${componentName}PropsGenerated['attributes']>;\n\n` +
|
|
22
|
-
`export function getDefaults(): ${componentName}Defaults {\n` +
|
|
23
|
-
` return ((pattern as unknown as { default?: unknown })?.default ?? {}) as ${componentName}Defaults;\n` +
|
|
24
|
-
`}\n`;
|
|
25
|
-
|
|
26
|
-
const formatted = await formatWithPrettier(fileContent);
|
|
27
|
-
await fs.writeFile(targetPath, formatted, 'utf8');
|
|
9
|
+
export async function createGetDefaultsPerComponent() {
|
|
10
|
+
// intentionally removed; no longer generating per-component getDefaults.ts
|
|
28
11
|
}
|
|
@@ -5,48 +5,6 @@ import { formatWithPrettier } from './formatWithPrettier.js';
|
|
|
5
5
|
/**
|
|
6
6
|
* Creates src/getDefaults.ts aggregating all component getDefaults.
|
|
7
7
|
*/
|
|
8
|
-
export async function createRootGetDefaults(
|
|
9
|
-
|
|
10
|
-
const targetPath = path.join(SRC_ROOT, 'getDefaults.ts');
|
|
11
|
-
|
|
12
|
-
// Build import lines for all components
|
|
13
|
-
const importLines = validated
|
|
14
|
-
.map(({ componentName }) => {
|
|
15
|
-
return `import { getDefaults as get${componentName}Defaults } from './build-components/${componentName}/getDefaults';`;
|
|
16
|
-
})
|
|
17
|
-
.join('\n');
|
|
18
|
-
|
|
19
|
-
const typeImports = `import type { ${validated
|
|
20
|
-
.map(({ componentName }) => `${componentName}PropsGenerated`)
|
|
21
|
-
.join(', ')} } from './build-components';`;
|
|
22
|
-
|
|
23
|
-
const typesMap = validated
|
|
24
|
-
.map(({ componentName, patternJson }) => {
|
|
25
|
-
const type = patternJson?.pattern?.type;
|
|
26
|
-
return ` ${JSON.stringify(type)}: ${componentName}PropsGenerated['attributes']`;
|
|
27
|
-
})
|
|
28
|
-
.join(';\n');
|
|
29
|
-
|
|
30
|
-
const switchCases = validated
|
|
31
|
-
.map(({ componentName, patternJson }) => {
|
|
32
|
-
const type = patternJson?.pattern?.type;
|
|
33
|
-
return ` case ${JSON.stringify(type)}:\n return get${componentName}Defaults() as Partial<Types[T]>`;
|
|
34
|
-
})
|
|
35
|
-
.join('\n');
|
|
36
|
-
|
|
37
|
-
const fileContent =
|
|
38
|
-
`/* AUTO-GENERATED FILE - DO NOT EDIT */\n\n` +
|
|
39
|
-
`${importLines}\n` +
|
|
40
|
-
`${typeImports}\n\n` +
|
|
41
|
-
`export type Types = {\n${typesMap}\n};\n\n` +
|
|
42
|
-
`export function getDefaults<T extends keyof Types>(type: T): Partial<Types[T]> {\n` +
|
|
43
|
-
` switch (type as unknown as string) {\n` +
|
|
44
|
-
`${switchCases}\n` +
|
|
45
|
-
` default:\n` +
|
|
46
|
-
` return {};\n` +
|
|
47
|
-
` }\n` +
|
|
48
|
-
`}\n`;
|
|
49
|
-
|
|
50
|
-
const formatted = await formatWithPrettier(fileContent);
|
|
51
|
-
await fs.writeFile(targetPath, formatted, 'utf8');
|
|
8
|
+
export async function createRootGetDefaults() {
|
|
9
|
+
// intentionally removed; no longer generating src/getDefaults.ts
|
|
52
10
|
}
|
|
@@ -22,7 +22,9 @@ async function getAllEntriesInComponentsRoot(paths) {
|
|
|
22
22
|
d.name !== 'RenderNode.generated.tsx' &&
|
|
23
23
|
d.name !== 'other.tsx' &&
|
|
24
24
|
d.name !== 'index.ts' &&
|
|
25
|
-
d.name !== 'getDefaults.ts'
|
|
25
|
+
d.name !== 'getDefaults.ts' &&
|
|
26
|
+
d.name !== 'useDefaults.ts' &&
|
|
27
|
+
d.name !== 'useNode.ts'
|
|
26
28
|
);
|
|
27
29
|
});
|
|
28
30
|
}
|
package/src/AttributesEditor.tsx
CHANGED
|
@@ -319,23 +319,27 @@ export function AttributesEditor({ node, onChange }: AttributesEditorProps) {
|
|
|
319
319
|
}
|
|
320
320
|
|
|
321
321
|
return (
|
|
322
|
-
<div style={{
|
|
322
|
+
<div style={{}}>
|
|
323
323
|
{entries.map(([name, type]) => (
|
|
324
324
|
<React.Fragment key={name}>
|
|
325
|
-
<
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
325
|
+
<p style={{ alignSelf: 'center', marginBottom: 4, fontWeight: 700 }}>
|
|
326
|
+
{name}
|
|
327
|
+
</p>
|
|
328
|
+
<div style={{ marginBottom: 16 }}>
|
|
329
|
+
<Field
|
|
330
|
+
name={name}
|
|
331
|
+
type={type}
|
|
332
|
+
value={attributes?.[name]}
|
|
333
|
+
onChange={(val) => {
|
|
334
|
+
const next: NodeData<NodeDefaultAttribute> = {
|
|
335
|
+
...data,
|
|
336
|
+
attributes: { ...(attributes ?? {}), [name]: val },
|
|
337
|
+
};
|
|
338
|
+
onChange(next);
|
|
339
|
+
}}
|
|
340
|
+
componentType={data?.type}
|
|
341
|
+
/>
|
|
342
|
+
</div>
|
|
339
343
|
</React.Fragment>
|
|
340
344
|
))}
|
|
341
345
|
</div>
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Device } from './types/Device';
|
|
3
|
+
|
|
4
|
+
type DeviceMockFrameProps = {
|
|
5
|
+
width: number;
|
|
6
|
+
height: number;
|
|
7
|
+
isRtl: boolean;
|
|
8
|
+
screenStyle: {
|
|
9
|
+
light: { backgroundColor: string; color: string };
|
|
10
|
+
dark: { backgroundColor: string; color: string };
|
|
11
|
+
};
|
|
12
|
+
theme: 'dark' | 'light';
|
|
13
|
+
children: React.ReactNode;
|
|
14
|
+
device: Device;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export function DeviceMockFrame({
|
|
18
|
+
width,
|
|
19
|
+
height,
|
|
20
|
+
isRtl,
|
|
21
|
+
screenStyle,
|
|
22
|
+
theme,
|
|
23
|
+
children,
|
|
24
|
+
device,
|
|
25
|
+
}: DeviceMockFrameProps) {
|
|
26
|
+
const isDark = theme === 'dark';
|
|
27
|
+
const [insetTop, insetRight, insetBottom, insetLeft] = device.insets ?? [
|
|
28
|
+
0, 0, 0, 0,
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
// Determine bar heights from device properties with platform-aware fallbacks
|
|
32
|
+
const statusBarHeight = insetTop || (device.platform === 'ios' ? 20 : 24);
|
|
33
|
+
const navBarHeight = (() => {
|
|
34
|
+
switch (device.navigationBarType) {
|
|
35
|
+
case 'none':
|
|
36
|
+
return 0;
|
|
37
|
+
case 'homeIndicator':
|
|
38
|
+
return insetBottom || 6; // minimal visual indicator on iOS
|
|
39
|
+
case 'gesture':
|
|
40
|
+
return insetBottom || 24;
|
|
41
|
+
case 'threeButtons':
|
|
42
|
+
return insetBottom || 48;
|
|
43
|
+
case 'tabBar':
|
|
44
|
+
return insetBottom || 49;
|
|
45
|
+
default:
|
|
46
|
+
return insetBottom || 0;
|
|
47
|
+
}
|
|
48
|
+
})();
|
|
49
|
+
const statusBarColor = isDark
|
|
50
|
+
? 'rgba(255, 255, 255, 0.08)'
|
|
51
|
+
: 'rgba(0, 0, 0, 0.06)';
|
|
52
|
+
const navBarColor = isDark
|
|
53
|
+
? 'rgba(255, 255, 255, 0.06)'
|
|
54
|
+
: 'rgba(0, 0, 0, 0.04)';
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<div className="stage-wrapper" style={{ overflow: 'auto' }}>
|
|
58
|
+
<div
|
|
59
|
+
className="stage"
|
|
60
|
+
style={{
|
|
61
|
+
width: width,
|
|
62
|
+
height: height,
|
|
63
|
+
minWidth: width,
|
|
64
|
+
maxWidth: width,
|
|
65
|
+
minHeight: height,
|
|
66
|
+
maxHeight: height,
|
|
67
|
+
overflow: 'hidden',
|
|
68
|
+
position: 'relative',
|
|
69
|
+
padding: 4,
|
|
70
|
+
direction: isRtl ? 'rtl' : 'ltr',
|
|
71
|
+
backgroundColor:
|
|
72
|
+
theme === 'dark'
|
|
73
|
+
? screenStyle.dark.backgroundColor
|
|
74
|
+
: screenStyle.light.backgroundColor,
|
|
75
|
+
color:
|
|
76
|
+
theme === 'dark' ? screenStyle.dark.color : screenStyle.light.color,
|
|
77
|
+
display: 'flex',
|
|
78
|
+
flexDirection: 'column',
|
|
79
|
+
borderRadius: device.radius ?? 0,
|
|
80
|
+
}}
|
|
81
|
+
>
|
|
82
|
+
<div
|
|
83
|
+
className="device-status-bar"
|
|
84
|
+
style={{
|
|
85
|
+
position: 'absolute',
|
|
86
|
+
top: 0,
|
|
87
|
+
left: 0,
|
|
88
|
+
right: 0,
|
|
89
|
+
height: statusBarHeight,
|
|
90
|
+
backgroundColor: statusBarColor,
|
|
91
|
+
flex: '0 0 auto',
|
|
92
|
+
}}
|
|
93
|
+
/>
|
|
94
|
+
<div
|
|
95
|
+
className="device-content"
|
|
96
|
+
style={{
|
|
97
|
+
flex: 1,
|
|
98
|
+
overflow: 'hidden',
|
|
99
|
+
position: 'relative',
|
|
100
|
+
paddingLeft: insetLeft,
|
|
101
|
+
paddingRight: insetRight,
|
|
102
|
+
}}
|
|
103
|
+
>
|
|
104
|
+
{children}
|
|
105
|
+
</div>
|
|
106
|
+
<div
|
|
107
|
+
className="device-navigation-bar"
|
|
108
|
+
style={{
|
|
109
|
+
height: navBarHeight,
|
|
110
|
+
backgroundColor: navBarColor,
|
|
111
|
+
flex: '0 0 auto',
|
|
112
|
+
}}
|
|
113
|
+
/>
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export default DeviceMockFrame;
|
package/src/RenderPage.tsx
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { Localication } from './types/PreviewConfig';
|
|
2
2
|
import { TargetedScreenSize } from './types/TargetedScreenSize';
|
|
3
3
|
import { RenderMainNode } from './RenderMainNode';
|
|
4
|
+
import { DeviceMockFrame } from './DeviceMockFrame';
|
|
4
5
|
import { Node } from './types/Node';
|
|
5
6
|
import { RenderNode } from './build-components';
|
|
7
|
+
import { Device } from './types/Device';
|
|
8
|
+
import { createContext } from 'react';
|
|
6
9
|
type RenderPageProps = {
|
|
7
10
|
data: Node;
|
|
8
|
-
screenSize: TargetedScreenSize;
|
|
9
11
|
isRtl: boolean;
|
|
10
12
|
screenStyle: {
|
|
11
13
|
light: { backgroundColor: string; color: string };
|
|
@@ -14,45 +16,35 @@ type RenderPageProps = {
|
|
|
14
16
|
theme: 'dark' | 'light';
|
|
15
17
|
localication: Localication;
|
|
16
18
|
defaultLanguage?: string;
|
|
19
|
+
device: Device;
|
|
17
20
|
};
|
|
18
|
-
|
|
21
|
+
export const renderPageContext = createContext<{
|
|
22
|
+
device: Device;
|
|
23
|
+
} | null>(null);
|
|
19
24
|
export function RenderPage({
|
|
20
25
|
data,
|
|
21
|
-
screenSize,
|
|
22
26
|
theme,
|
|
23
27
|
isRtl,
|
|
24
28
|
screenStyle,
|
|
25
29
|
localication,
|
|
26
30
|
defaultLanguage,
|
|
31
|
+
device,
|
|
27
32
|
}: RenderPageProps) {
|
|
28
33
|
const screenPreviewHeight = 800;
|
|
29
34
|
// The calculation is correct for maintaining the aspect ratio of the target screen size.
|
|
30
35
|
// It scales the width proportionally to a fixed preview height.
|
|
31
36
|
// width = (previewHeight * targetWidth) / targetHeight
|
|
32
37
|
const height = screenPreviewHeight;
|
|
33
|
-
const width = (height *
|
|
38
|
+
const width = (height * device.width) / device.height;
|
|
34
39
|
return (
|
|
35
|
-
<
|
|
36
|
-
<
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
minHeight: height,
|
|
44
|
-
maxHeight: height,
|
|
45
|
-
overflow: 'hidden',
|
|
46
|
-
position: 'relative',
|
|
47
|
-
padding: 4,
|
|
48
|
-
direction: isRtl ? 'rtl' : 'ltr',
|
|
49
|
-
backgroundColor:
|
|
50
|
-
theme === 'dark'
|
|
51
|
-
? screenStyle.dark.backgroundColor
|
|
52
|
-
: screenStyle.light.backgroundColor,
|
|
53
|
-
color:
|
|
54
|
-
theme === 'dark' ? screenStyle.dark.color : screenStyle.light.color,
|
|
55
|
-
}}
|
|
40
|
+
<renderPageContext.Provider value={{ device }}>
|
|
41
|
+
<DeviceMockFrame
|
|
42
|
+
width={width}
|
|
43
|
+
height={height}
|
|
44
|
+
isRtl={isRtl}
|
|
45
|
+
screenStyle={screenStyle}
|
|
46
|
+
theme={theme}
|
|
47
|
+
device={device}
|
|
56
48
|
>
|
|
57
49
|
{
|
|
58
50
|
<RenderMainNode
|
|
@@ -63,7 +55,7 @@ export function RenderPage({
|
|
|
63
55
|
<RenderNode node={data} />
|
|
64
56
|
</RenderMainNode>
|
|
65
57
|
}
|
|
66
|
-
</
|
|
67
|
-
</
|
|
58
|
+
</DeviceMockFrame>
|
|
59
|
+
</renderPageContext.Provider>
|
|
68
60
|
);
|
|
69
61
|
}
|