Skip to content

Commit 61535bd

Browse files
authored
Merge pull request #21 from olliethedev/fix/rendering
fix: font rendering
2 parents b88da7c + 84a667d commit 61535bd

File tree

5 files changed

+56
-18
lines changed

5 files changed

+56
-18
lines changed

README.md

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,11 @@ See the [docs site](https://uibuilder.app/) for more information.
2525

2626
---
2727

28-
## Tailwind 4, React 19 Support and latest Shadcn/ui
28+
## Compatibility Notes
2929

30-
Migration will be coming soon. Some 3rd party shadcn component dependencies are not yet compatible with the latest versions of Tailwind, so we are waiting for the latest versions of these components to be stable.
31-
If you are having issues with latest shadcn/ui cli you can try using older version in the command like `npx shadcn@2.1.8 add ...`
30+
**Tailwind 4 + React 19**: Migration coming soon. Currently blocked by 3rd party component compatibility. If using latest shadcn/ui CLI fails, try: `npx shadcn@2.1.8 add ...`
31+
32+
**Server Components**: Not supported. RSC can't be re-rendered client-side for live preview. A separate RSC renderer for final page rendering is possible — open an issue if you have a use case.
3233

3334

3435
# Quick Start
@@ -496,7 +497,7 @@ Separate content from structure, allowing non-technical users to update dynamic
496497
---
497498

498499

499-
## Changelog
500+
## Breaking Changes
500501

501502
### v1.0.0
502503
- Removed _page_ layer type in favor of using any component type (like `div`, `main`, or custom containers) as the root page layer. This enhances flexibility, enabling use cases like building react-email templates directly. You should migrate any layers stored in the database to use a standard component type as the root. The [migrateV2ToV3](lib/ui-builder/store/layer-utils.ts) function in `layer-utils.ts` can assist with this migration.
@@ -537,6 +538,9 @@ npm run test
537538

538539
## Roadmap
539540

541+
- [ ] Config options to make pages and variables immutable
542+
- [ ] Add variable binding to layer children and not just props
543+
- [ ] Improve DX. End to end type safety.
540544
- [ ] Documentation site for UI Builder with more hands-on examples
541545
- [ ] Configurable Tailwind Class subset for things like React-Email components
542546
- [ ] Drag and drop component in the editor panel and not just in the layers panel
@@ -546,8 +550,7 @@ npm run test
546550
- [ ] Add Blocks. Reusable component blocks that can be used in multiple pages
547551
- [ ] Move component schemas to separate shadcn registry to keep main registry light
548552
- [ ] Move prop form field components (overrides) to separate shadcn registry to keep main registry light
549-
- [ ] Add data sources (functions) to component layers (ex, getUser() binds prop user.name) - Connect variables to live data sources
550-
- [ ] Add visual data model editor + code gen for backend code for CRUD operations
553+
- [ ] Add visual data model editor + code gen for backend code for CRUD operations. (ex Zenstack schema editor)
551554
- [ ] Add event handlers to component layers (onClick, onSubmit, etc)
552555
- [ ] Update to new AutoForm when stable
553556
- [ ] Update to Zod v4 (when stable) for native json schema conversion to enforce safety in layer props

__tests__/page.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jest.mock("../components/ui/ui-builder/codeblock", () => {
1111
};
1212
});
1313

14-
it("App Router: Works with Server Components", async () => {
14+
it("Main Component", async () => {
1515
render(<Page />);
1616
const mainPage = await screen.findByTestId("main-page");
1717
expect(mainPage).toBeInTheDocument();

components/ui/ui-builder/internal/classname-control/breakpoint-classname-control.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ export const BreakpointClassNameControl = ({
183183
>
184184
<AccordionItem
185185
value="classes"
186-
className="border-t border-b-0 px-4"
186+
className="border-t border-b-0 px-4 [&_#accordion-content[data-state=open]]:overflow-visible [&_#accordion-content[data-state=closed]]:overflow-hidden"
187187
data-testid="classes-accordion-item"
188188
>
189189
<AccordionTrigger
@@ -192,7 +192,10 @@ export const BreakpointClassNameControl = ({
192192
>
193193
Edit Classes
194194
</AccordionTrigger>
195-
<AccordionContent data-testid="classes-accordion-content">
195+
<AccordionContent
196+
data-testid="classes-accordion-content"
197+
id="accordion-content"
198+
>
196199
<ClassNameMultiselect
197200
value={classString}
198201
onChange={handleMultiselectChange}

components/ui/ui-builder/internal/iframe-wrapper.tsx

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import React, { useCallback, useLayoutEffect, useMemo, useRef, useState } from "react";
1+
import React, {
2+
useCallback,
3+
useLayoutEffect,
4+
useMemo,
5+
useRef,
6+
useState,
7+
} from "react";
28
import ReactDOM from "react-dom";
39
import { GripVertical } from "lucide-react";
410
import { DragConfig, useDrag } from "@use-gesture/react";
@@ -61,12 +67,12 @@ export const IframeWrapper: React.FC<IframeWrapperProps> = React.memo(
6167
);
6268

6369
useLayoutEffect(() => {
64-
if (resizable && iframeRef.current) {
65-
setIframeSize({
66-
width: iframeRef.current.parentElement?.offsetWidth || 600, // Fallback to 600px or any default width
67-
});
68-
}
69-
}, [resizable]);
70+
if (resizable && iframeRef.current) {
71+
setIframeSize({
72+
width: iframeRef.current.parentElement?.offsetWidth || 600, // Fallback to 600px or any default width
73+
});
74+
}
75+
}, [resizable]);
7076

7177
useLayoutEffect(() => {
7278
const iframe = iframeRef.current;
@@ -86,6 +92,32 @@ export const IframeWrapper: React.FC<IframeWrapperProps> = React.memo(
8692

8793
iframeDoc.body.style.backgroundColor = "transparent";
8894

95+
// Copy font variables and classes from parent to iframe
96+
const parentBody = document.body;
97+
const parentHtml = document.documentElement;
98+
const parentComputedStyle = window.getComputedStyle(parentHtml);
99+
100+
// Copy all CSS custom properties (variables) from parent html element
101+
for (let i = 0; i < parentComputedStyle.length; i++) {
102+
const property = parentComputedStyle[i];
103+
if (property.startsWith("--")) {
104+
const value = parentComputedStyle.getPropertyValue(property);
105+
iframeDoc.documentElement.style.setProperty(property, value);
106+
iframeDoc.body.style.setProperty(property, value);
107+
}
108+
}
109+
110+
// Copy font-related classes from parent body
111+
parentBody.classList.forEach((className) => {
112+
if (
113+
className.includes("font-") ||
114+
className === "antialiased" ||
115+
className.includes("__variable")
116+
) {
117+
iframeDoc.body.classList.add(className);
118+
}
119+
});
120+
89121
// Function to inject stylesheets into the iframe
90122
const injectStylesheets = () => {
91123
// Select all linked stylesheets in the parent document

0 commit comments

Comments
 (0)