Skip to content

Commit

Permalink
feat: support React server components via @measured/puck/rsc bundle
Browse files Browse the repository at this point in the history
Provide a Render component via a separate `rsc` bundle
  • Loading branch information
4leite authored Nov 10, 2023
1 parent ddf5f92 commit 90ac161
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 9 deletions.
6 changes: 5 additions & 1 deletion packages/core/components/DropZone/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ function DropZoneEdit({ zone, style }: DropZoneProps) {
const defaultedProps = {
...config.components[item.type]?.defaultProps,
...item.props,
puck: { renderDropZone: DropZone },
editMode: true,
};

Expand Down Expand Up @@ -364,7 +365,10 @@ function DropZoneRender({ zone }: DropZoneProps) {
key={item.props.id}
value={{ data, config, areaId: item.props.id }}
>
<Component.render {...item.props} />
<Component.render
{...item.props}
puck={{ renderDropZone: DropZone }}
/>
</DropZoneProvider>
);
}
Expand Down
2 changes: 0 additions & 2 deletions packages/core/components/Puck/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
"use client";

import {
ReactElement,
ReactNode,
Expand Down
3 changes: 3 additions & 0 deletions packages/core/components/Render/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ export function Render({ config, data }: { config: Config; data: Data }) {
<DropZoneProvider value={{ data, config, mode: "render" }}>
<config.root.render
{...rootProps}
puck={{
renderDropZone: DropZone,
}}
title={title}
editMode={false}
id={"puck-root"}
Expand Down
87 changes: 87 additions & 0 deletions packages/core/components/ServerRender/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { CSSProperties } from "react";
import { rootDroppableId } from "../../lib/root-droppable-id";
import { Config, Data } from "../../types/Config";
import { setupZone } from "../../lib/setup-zone";

type DropZoneRenderProps = {
zone: string;
data: Data;
config: Config;
areaId?: string;
style?: CSSProperties;
};

function DropZoneRender({
zone,
data,
areaId = "root",
config,
}: DropZoneRenderProps) {
let zoneCompound = rootDroppableId;
let content = data?.content || [];

if (!data || !config) {
return null;
}

if (areaId && zone && zone !== rootDroppableId) {
zoneCompound = `${areaId}:${zone}`;
content = setupZone(data, zoneCompound).zones[zoneCompound];
}

return (
<>
{content.map((item) => {
const Component = config.components[item.type];

if (Component) {
return (
<Component.render
key={item.props.id}
{...item.props}
puck={{
renderDropZone: ({ zone }: { zone: string }) => (
<DropZoneRender
zone={zone}
data={data}
areaId={item.props.id}
config={config}
/>
),
}}
/>
);
}

return null;
})}
</>
);
}

export function Render({ config, data }: { config: Config; data: Data }) {
if (config.root?.render) {
// DEPRECATED
const rootProps = data.root.props || data.root;

const title = rootProps.title || "";

return (
<config.root.render
{...rootProps}
puck={{
renderDropZone: ({ zone }: { zone: string }) => (
<DropZoneRender zone={zone} data={data} config={config} />
),
}}
title={title}
editMode={false}
id={"puck-root"}
>
<DropZoneRender config={config} data={data} zone={rootDroppableId} />
</config.root.render>
);
}

return <DropZoneRender config={config} data={data} zone={rootDroppableId} />;
}
1 change: 1 addition & 0 deletions packages/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import "./styles/global.css";

export * from "./types/Config";
export * from "./components/Button";
// DEPRECATED
export * from "./components/DropZone";
export * from "./components/IconButton";
export * from "./components/Puck";
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"license": "MIT",
"scripts": {
"lint": "eslint \"**/*.ts*\"",
"build": "rm -rf dist && tsup index.ts",
"build": "rm -rf dist && tsup index.ts rsc.tsx",
"test": "jest",
"prepare": "cp ../../README.md . && yarn build",
"postpublish": "rm README.md"
Expand Down
1 change: 1 addition & 0 deletions packages/core/rsc.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { Render } from "./components/ServerRender";
15 changes: 10 additions & 5 deletions packages/core/types/Config.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ReactElement } from "react";
import { ReactNode } from "react";
import { ItemSelector } from "../lib/get-item";
import { DropZone } from "../components/DropZone";

type WithPuckProps<Props> = Props & {
id: string;
Expand Down Expand Up @@ -93,10 +94,6 @@ export type DefaultRootProps = {
[key: string]: any;
};

export type DefaultRootRenderProps = {
editMode: boolean;
} & DefaultRootProps;

export type DefaultComponentProps = { [key: string]: any; editMode?: boolean };

export type Fields<
Expand All @@ -112,12 +109,20 @@ export type Content<
Props extends { [key: string]: any } = { [key: string]: any }
> = ComponentData<Props>[];

export type PuckComponent<
Props extends DefaultComponentProps = DefaultComponentProps
> = (props: WithPuckProps<Props & { puck: PuckContext }>) => JSX.Element;

export type PuckContext = {
renderDropZone: typeof DropZone;
};

export type ComponentConfig<
ComponentProps extends DefaultComponentProps = DefaultComponentProps,
DefaultProps = ComponentProps,
DataShape = ComponentData<ComponentProps>
> = {
render: (props: WithPuckProps<ComponentProps>) => ReactElement;
render: PuckComponent<ComponentProps>;
defaultProps?: DefaultProps;
fields?: Fields<ComponentProps>;
resolveData?: (
Expand Down

0 comments on commit 90ac161

Please sign in to comment.