@bravostudioai/react 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/encore-lib.js +3 -0
- package/dist/_virtual/_commonjsHelpers.js +7 -0
- package/dist/_virtual/_commonjsHelpers.js.map +1 -0
- package/dist/_virtual/main.js +8 -0
- package/dist/_virtual/main.js.map +1 -0
- package/dist/_virtual/main2.js +5 -0
- package/dist/_virtual/main2.js.map +1 -0
- package/dist/app.js +9 -0
- package/dist/app.js.map +1 -0
- package/dist/cli/commands/download.js +82 -0
- package/dist/cli/commands/download.js.map +1 -0
- package/dist/cli/commands/generate.js +1526 -0
- package/dist/cli/commands/generate.js.map +1 -0
- package/dist/cli.js +25 -0
- package/dist/cli.js.map +1 -0
- package/dist/components/DynamicComponent.js +24 -0
- package/dist/components/DynamicComponent.js.map +1 -0
- package/dist/components/EncoreApp.js +259 -0
- package/dist/components/EncoreApp.js.map +1 -0
- package/dist/components/EncoreErrorBoundary.js +33 -0
- package/dist/components/EncoreErrorBoundary.js.map +1 -0
- package/dist/components/EncoreLoadingFallback.js +20 -0
- package/dist/components/EncoreLoadingFallback.js.map +1 -0
- package/dist/components.js +1454 -0
- package/dist/components.js.map +1 -0
- package/dist/constants.d.ts +3 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/contexts/EncoreActionContext.js +6 -0
- package/dist/contexts/EncoreActionContext.js.map +1 -0
- package/dist/contexts/EncoreAppContext.js +9 -0
- package/dist/contexts/EncoreAppContext.js.map +1 -0
- package/dist/contexts/EncoreBindingContext.js +6 -0
- package/dist/contexts/EncoreBindingContext.js.map +1 -0
- package/dist/contexts/EncoreComponentIdContext.js +8 -0
- package/dist/contexts/EncoreComponentIdContext.js.map +1 -0
- package/dist/contexts/EncoreRepeatingContainerContext.js +6 -0
- package/dist/contexts/EncoreRepeatingContainerContext.js.map +1 -0
- package/dist/hooks/usePusherUpdates.js +60 -0
- package/dist/hooks/usePusherUpdates.js.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/dynamicModules.js +132 -0
- package/dist/lib/dynamicModules.js.map +1 -0
- package/dist/lib/fetcher.js +58 -0
- package/dist/lib/fetcher.js.map +1 -0
- package/dist/lib/localMode.js +21 -0
- package/dist/lib/localMode.js.map +1 -0
- package/dist/lib/packages.js +18 -0
- package/dist/lib/packages.js.map +1 -0
- package/dist/node_modules/dotenv/lib/main.js +198 -0
- package/dist/node_modules/dotenv/lib/main.js.map +1 -0
- package/dist/node_modules/dotenv/package.json.js +8 -0
- package/dist/node_modules/dotenv/package.json.js.map +1 -0
- package/dist/packages/encore-lib/constants.js +6 -0
- package/dist/packages/encore-lib/constants.js.map +1 -0
- package/dist/src/app.d.ts +5 -0
- package/dist/src/app.d.ts.map +1 -0
- package/dist/src/cli/commands/download.d.ts +2 -0
- package/dist/src/cli/commands/download.d.ts.map +1 -0
- package/dist/src/cli/commands/generate.d.ts +2 -0
- package/dist/src/cli/commands/generate.d.ts.map +1 -0
- package/dist/src/cli/index.d.ts +2 -0
- package/dist/src/cli/index.d.ts.map +1 -0
- package/dist/src/components/DynamicComponent.d.ts +12 -0
- package/dist/src/components/DynamicComponent.d.ts.map +1 -0
- package/dist/src/components/EncoreApp.d.ts +27 -0
- package/dist/src/components/EncoreApp.d.ts.map +1 -0
- package/dist/src/components/EncoreErrorBoundary.d.ts +17 -0
- package/dist/src/components/EncoreErrorBoundary.d.ts.map +1 -0
- package/dist/src/components/EncoreLoadingFallback.d.ts +4 -0
- package/dist/src/components/EncoreLoadingFallback.d.ts.map +1 -0
- package/dist/src/components.d.ts +4 -0
- package/dist/src/components.d.ts.map +1 -0
- package/dist/src/contexts/EncoreActionContext.d.ts +13 -0
- package/dist/src/contexts/EncoreActionContext.d.ts.map +1 -0
- package/dist/src/contexts/EncoreAppContext.d.ts +8 -0
- package/dist/src/contexts/EncoreAppContext.d.ts.map +1 -0
- package/dist/src/contexts/EncoreBindingContext.d.ts +5 -0
- package/dist/src/contexts/EncoreBindingContext.d.ts.map +1 -0
- package/dist/src/contexts/EncoreComponentIdContext.d.ts +8 -0
- package/dist/src/contexts/EncoreComponentIdContext.d.ts.map +1 -0
- package/dist/src/contexts/EncoreRepeatingContainerContext.d.ts +21 -0
- package/dist/src/contexts/EncoreRepeatingContainerContext.d.ts.map +1 -0
- package/dist/src/hooks/useAuthRedirect.d.ts +3 -0
- package/dist/src/hooks/useAuthRedirect.d.ts.map +1 -0
- package/dist/src/hooks/usePusherUpdates.d.ts +18 -0
- package/dist/src/hooks/usePusherUpdates.d.ts.map +1 -0
- package/dist/src/index.d.ts +8 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/lib/dynamicModules.d.ts +8 -0
- package/dist/src/lib/dynamicModules.d.ts.map +1 -0
- package/dist/src/lib/fetcher.d.ts +5 -0
- package/dist/src/lib/fetcher.d.ts.map +1 -0
- package/dist/src/lib/localMode.d.ts +3 -0
- package/dist/src/lib/localMode.d.ts.map +1 -0
- package/dist/src/lib/packages.d.ts +6 -0
- package/dist/src/lib/packages.d.ts.map +1 -0
- package/dist/src/stores/useEncoreState.d.ts +33 -0
- package/dist/src/stores/useEncoreState.d.ts.map +1 -0
- package/dist/stores/useEncoreState.js +70 -0
- package/dist/stores/useEncoreState.js.map +1 -0
- package/package.json +60 -0
- package/src/AGENTS.md +161 -0
- package/src/README.md +110 -0
- package/src/app.ts +5 -0
- package/src/cli/commands/download.ts +133 -0
- package/src/cli/commands/generate.ts +3045 -0
- package/src/cli/index.ts +35 -0
- package/src/components/DynamicComponent.tsx +40 -0
- package/src/components/EncoreApp.tsx +759 -0
- package/src/components/EncoreErrorBoundary.tsx +49 -0
- package/src/components/EncoreLoadingFallback.tsx +25 -0
- package/src/components.tsx +3155 -0
- package/src/contexts/EncoreActionContext.ts +18 -0
- package/src/contexts/EncoreAppContext.ts +13 -0
- package/src/contexts/EncoreBindingContext.ts +6 -0
- package/src/contexts/EncoreComponentIdContext.ts +12 -0
- package/src/contexts/EncoreRepeatingContainerContext.ts +30 -0
- package/src/hooks/useAuthRedirect.ts +63 -0
- package/src/hooks/usePusherUpdates.ts +156 -0
- package/src/index.ts +16 -0
- package/src/lib/dynamicModules.ts +193 -0
- package/src/lib/fetcher.ts +108 -0
- package/src/lib/localMode.ts +30 -0
- package/src/lib/moduleRegistry.ts +24 -0
- package/src/lib/packages.ts +33 -0
- package/src/stores/useEncoreState.ts +121 -0
package/src/README.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Bravo Library
|
|
2
|
+
|
|
3
|
+
This directory contains the Bravo library code that will be extracted as a standalone library.
|
|
4
|
+
|
|
5
|
+
## Styling Rules
|
|
6
|
+
|
|
7
|
+
**No Tailwind CSS classes are allowed in this directory.**
|
|
8
|
+
|
|
9
|
+
To keep the library dependency-free and portable, all styling must be done using:
|
|
10
|
+
- Inline styles (via the `style` prop)
|
|
11
|
+
- Regular CSS classes (if needed, but prefer inline styles)
|
|
12
|
+
- CSS-in-JS solutions that don't require build-time dependencies
|
|
13
|
+
|
|
14
|
+
This rule is enforced via ESLint. If you see an error about Tailwind classes, refactor to use inline styles instead.
|
|
15
|
+
|
|
16
|
+
### Example
|
|
17
|
+
|
|
18
|
+
❌ **Don't:**
|
|
19
|
+
```tsx
|
|
20
|
+
<div className="flex items-center justify-center bg-white">
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
✅ **Do:**
|
|
24
|
+
```tsx
|
|
25
|
+
<div style={{
|
|
26
|
+
display: 'flex',
|
|
27
|
+
alignItems: 'center',
|
|
28
|
+
justifyContent: 'center',
|
|
29
|
+
backgroundColor: 'white'
|
|
30
|
+
}}>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Observations & Lessons (Rendering and Layout)
|
|
34
|
+
|
|
35
|
+
These notes summarize fixes and principles we applied while aligning the renderer with Figma/Bravo semantics:
|
|
36
|
+
|
|
37
|
+
1) Container positioning context
|
|
38
|
+
- Absolutely positioned children must resolve relative to their nearest positioned ancestor.
|
|
39
|
+
- We set `position: 'relative'` on layout containers (`ContainerComponent`, `TopBarContainerComponent`, page scroll area) so children with `style.positioning` use the correct reference box.
|
|
40
|
+
- Background layers must not participate in normal flow. `BackgroundContainerComponent` stays `position: 'absolute'` with `zIndex: -1` to prevent pushing content offstage.
|
|
41
|
+
|
|
42
|
+
2) Accurate container measurements
|
|
43
|
+
- Percent-based sizes and radii should use the actual container dimensions, not the window.
|
|
44
|
+
- Implemented `useContainerDimensions()` with a `ref` + `ResizeObserver` and pass `{ dimensions }` through `BravoContainerContext`.
|
|
45
|
+
- Components use `ref={ref}` instead of `onLoad` to ensure reliable measurement updates.
|
|
46
|
+
|
|
47
|
+
3) Percent sizing and aspect ratio
|
|
48
|
+
- `useBravoStyle` now derives:
|
|
49
|
+
- width = `style.width * containerWidth * 0.01`
|
|
50
|
+
- height = `style.height * containerHeight * 0.01` (or from `aspectRatio` when present)
|
|
51
|
+
- Border radii and corner radii are computed in pixels from parent width to match Figma scaling.
|
|
52
|
+
|
|
53
|
+
4) Page scaffolding
|
|
54
|
+
- `PageComponent` wraps content in a full-size positioned container and provides measured dimensions to children.
|
|
55
|
+
- Non-scrollable layers (backgrounds, top bars) render in a separate provider; the main page area is `overflow: 'auto'` to match scrolling behavior.
|
|
56
|
+
|
|
57
|
+
5) Error tolerance
|
|
58
|
+
- Image preloading uses `Promise.allSettled` and resolves on `onerror` to avoid halting rendering due to asset hiccups during development.
|
|
59
|
+
|
|
60
|
+
6) Flex container wrapping and spacing
|
|
61
|
+
- When using `flex-wrap: wrap` with `gap: 0px`, also set `alignContent: "flex-start"` to prevent spacing between wrapped rows.
|
|
62
|
+
- The `align-content` property controls spacing between wrapped flex lines, and default values can create unwanted gaps even when gap properties are zero.
|
|
63
|
+
|
|
64
|
+
6) Debugging tips
|
|
65
|
+
- If content appears “gone” behind a solid background, verify:
|
|
66
|
+
- Background layers are absolute and behind (`zIndex: -1`).
|
|
67
|
+
- Parent containers establishing positioning have `position: 'relative'`.
|
|
68
|
+
- Percent calculations use container dimensions (check `BravoContainerContext.dimensions`).
|
|
69
|
+
|
|
70
|
+
These conventions help keep the renderer predictable and closer to the Bravo/Figma mental model while remaining dependency-free.
|
|
71
|
+
|
|
72
|
+
## Common Pitfalls We Hit (and how we fixed them)
|
|
73
|
+
|
|
74
|
+
1) Background layer covering or pushing content
|
|
75
|
+
- Symptom: Only the preview’s green frame shows; content appears pushed offstage.
|
|
76
|
+
- Cause: Background container participating in layout or measuring as 0×0.
|
|
77
|
+
- Fix: Keep `BackgroundContainerComponent` absolute with `zIndex: -1`, size to `width:'100%', height:'100%'`, and measure via `ResizeObserver`.
|
|
78
|
+
|
|
79
|
+
2) Text not visible due to extreme line-height
|
|
80
|
+
- Symptom: Text node exists in DOM but height collapses or content clips.
|
|
81
|
+
- Cause: Unitless `lineHeightPx` multiplied, applied without `px` → giant computed line-height.
|
|
82
|
+
- Fix: Convert to pixels: `lineHeight = (lineHeightPx * scaleFactor) + 'px'`.
|
|
83
|
+
|
|
84
|
+
3) Containers collapsing to 0×0, children positioned off-canvas
|
|
85
|
+
- Symptom: Child elements show 0 width/height or absolutely position relative to the page.
|
|
86
|
+
- Cause: Container had no explicit size and no positioned ancestor.
|
|
87
|
+
- Fix: For container wrappers (`ContainerComponent`, `TopBarContainerComponent`, page scroll area), set `position:'relative'`. Default `width/height` to `'100%'` when not computed yet so measurement settles on first paint.
|
|
88
|
+
|
|
89
|
+
4) Percent sizing using window instead of container
|
|
90
|
+
- Symptom: Elements look “scaled wrong” inside the preview frame.
|
|
91
|
+
- Cause: Converting `%` using `window.innerWidth/innerHeight`.
|
|
92
|
+
- Fix: Convert `%` using nearest container’s measured dimensions from context.
|
|
93
|
+
|
|
94
|
+
5) Preloading assets blocking rendering
|
|
95
|
+
- Symptom: "Uncaught (in promise)" and blank screen if an image fails.
|
|
96
|
+
- Fix: Use `Promise.allSettled` and resolve on `img.onerror` so rendering continues during development.
|
|
97
|
+
|
|
98
|
+
6) Unwanted gaps between wrapped flex rows
|
|
99
|
+
- Symptom: When flex items wrap (e.g., Banner at 100% width wrapping to its own row, with Slider/Header on next row), there's visible spacing between rows even when `gap: 0px` and `rowGap: 0px` are set.
|
|
100
|
+
- Cause: When `flex-wrap: wrap` is enabled, the `align-content` property controls spacing between wrapped rows. The default value can create spacing even when gap properties are set to 0.
|
|
101
|
+
- Fix: Explicitly set `alignContent: "flex-start"` when `flexWrap` is `"wrap"` or `"wrap-reverse"`. This ensures wrapped rows have no spacing between them.
|
|
102
|
+
- Location: In `useEncoreStyle`, after setting gap properties for flex containers with wrapping enabled.
|
|
103
|
+
|
|
104
|
+
## Audit checklist for new/changed components
|
|
105
|
+
- Does this wrapper need to be a positioning context? If yes, add `position:'relative'`.
|
|
106
|
+
- Could this container start at 0×0? If yes, consider default `width:'100%', height:'100%'` until measured.
|
|
107
|
+
- Do any styles derived from numeric values need units (e.g., `px`)? Ensure units are added.
|
|
108
|
+
- Are percent-based sizes converted using container dimensions (not window)?
|
|
109
|
+
- Do overlays/action wrappers accidentally sit above content? Verify `zIndex` and hit areas.
|
|
110
|
+
|
package/src/app.ts
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
import { writeFile, mkdir } from "fs/promises";
|
|
4
|
+
import { join } from "path";
|
|
5
|
+
import { existsSync } from "fs";
|
|
6
|
+
import dotenv from "dotenv";
|
|
7
|
+
import { CONST_APPS_SERVICE_URL, CONST_COMPONENTS_CDN_URL } from "../../../constants";
|
|
8
|
+
|
|
9
|
+
dotenv.config();
|
|
10
|
+
|
|
11
|
+
// Default apps service URL (can be overridden with APPS_SERVICE_URL env var)
|
|
12
|
+
const APPS_SERVICE_URL =
|
|
13
|
+
process.env.VITE_APPS_SERVICE_URL ||
|
|
14
|
+
CONST_APPS_SERVICE_URL ||
|
|
15
|
+
"https://apps-service-dev.bravostudio.app";
|
|
16
|
+
const COMPONENTS_CDN_URL =
|
|
17
|
+
CONST_COMPONENTS_CDN_URL || "https://apps-public-dev.bravostudio.app";
|
|
18
|
+
|
|
19
|
+
interface DownloadOptions {
|
|
20
|
+
appId: string;
|
|
21
|
+
pageId: string;
|
|
22
|
+
targetPath: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function downloadFile(
|
|
26
|
+
url: string,
|
|
27
|
+
headers?: Record<string, string>
|
|
28
|
+
): Promise<string> {
|
|
29
|
+
const response = await fetch(url, {
|
|
30
|
+
headers: headers || {},
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
if (!response.ok) {
|
|
34
|
+
throw new Error(
|
|
35
|
+
`Failed to download ${url}: ${response.status} ${response.statusText}`
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return await response.text();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function downloadEncoreFiles({
|
|
43
|
+
appId,
|
|
44
|
+
pageId,
|
|
45
|
+
targetPath,
|
|
46
|
+
}: DownloadOptions) {
|
|
47
|
+
console.log(`Downloading Encore files for app: ${appId}, page: ${pageId}`);
|
|
48
|
+
console.log(`Target path: ${targetPath}`);
|
|
49
|
+
|
|
50
|
+
// Ensure target directory exists
|
|
51
|
+
if (!existsSync(targetPath)) {
|
|
52
|
+
await mkdir(targetPath, { recursive: true });
|
|
53
|
+
console.log(`Created directory: ${targetPath}`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const files: Array<{
|
|
57
|
+
url: string;
|
|
58
|
+
filename: string;
|
|
59
|
+
headers?: Record<string, string>;
|
|
60
|
+
}> = [
|
|
61
|
+
{
|
|
62
|
+
url: `${APPS_SERVICE_URL}/devices/apps/${appId}`,
|
|
63
|
+
filename: "app.json",
|
|
64
|
+
headers: { "x-app-clientrendered": "true" },
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
url: `${APPS_SERVICE_URL}/devices/apps/${appId}/node/${pageId}`,
|
|
68
|
+
filename: "page.json",
|
|
69
|
+
headers: { "x-app-clientrendered": "true" },
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
url: `${COMPONENTS_CDN_URL}/${appId}/draft/components/${pageId}.js`,
|
|
73
|
+
filename: "component.js",
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
for (const file of files) {
|
|
78
|
+
try {
|
|
79
|
+
console.log(`Downloading ${file.filename} from ${file.url}...`);
|
|
80
|
+
const content = await downloadFile(file.url, file.headers);
|
|
81
|
+
const filePath = join(targetPath, file.filename);
|
|
82
|
+
await writeFile(filePath, content, "utf-8");
|
|
83
|
+
console.log(`✓ Saved ${file.filename} to ${filePath}`);
|
|
84
|
+
} catch (error) {
|
|
85
|
+
console.error(`✗ Failed to download ${file.filename} at :`, error);
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
console.log("\n✓ All files downloaded successfully!");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function printUsage() {
|
|
94
|
+
console.log(`
|
|
95
|
+
Usage: download-bravo.ts <appId> <pageId> <targetPath>
|
|
96
|
+
|
|
97
|
+
Arguments:
|
|
98
|
+
appId The Encore app ID
|
|
99
|
+
pageId The Encore page ID
|
|
100
|
+
targetPath Path where files should be saved
|
|
101
|
+
|
|
102
|
+
Environment variables:
|
|
103
|
+
APPS_SERVICE_URL Base URL for the apps service (default: https://apps-service-dev.bravostudio.app)
|
|
104
|
+
|
|
105
|
+
Example:
|
|
106
|
+
download-bravo.ts my-app-id my-page-id ./bravo-files
|
|
107
|
+
APPS_SERVICE_URL=https://api.example.com download-bravo.ts my-app-id my-page-id ./bravo-files
|
|
108
|
+
`);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
export async function runDownload(args: string[]) {
|
|
113
|
+
if (args.length < 3 || args.includes("--help") || args.includes("-h")) {
|
|
114
|
+
printUsage();
|
|
115
|
+
process.exit(args.includes("--help") || args.includes("-h") ? 0 : 1);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const [appId, pageId, targetPath] = args;
|
|
119
|
+
|
|
120
|
+
if (!appId || !pageId || !targetPath) {
|
|
121
|
+
console.error("Error: Missing required arguments");
|
|
122
|
+
printUsage();
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
await downloadEncoreFiles({ appId, pageId, targetPath });
|
|
128
|
+
} catch (error) {
|
|
129
|
+
console.error("\nError:", error instanceof Error ? error.message : error);
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|