Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions packages/core/components/DropZone/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,14 @@ export const DropZoneEdit = forwardRef<HTMLDivElement, DropZoneProps>(
[dropRef]
);

const El = as ?? "div";
const config = useAppStore((s) => s.config);

const Wrapper = useMemo(
() => config.overrides?.slot || "div",
[config.overrides]
);

const El = as ?? Wrapper;

return (
<El
Expand Down Expand Up @@ -583,6 +590,11 @@ const DropZoneRender = forwardRef<HTMLDivElement, DropZoneProps>(
let zoneCompound = `${areaId}:${zone}`;
let content = data?.content || [];

const Wrapper = useMemo(
() => config.overrides?.slot || "div",
[config.overrides]
);

// Register zones if running Render mode inside editor (i.e. previewMode === "interactive")
useEffect(() => {
// Only register zones, not slots
Expand All @@ -593,7 +605,7 @@ const DropZoneRender = forwardRef<HTMLDivElement, DropZoneProps>(
}
}, [content]);

const El = as ?? "div";
const El = as ?? Wrapper;

if (!data || !config) {
return null;
Expand Down
9 changes: 7 additions & 2 deletions packages/core/components/SlotRender/server.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { forwardRef } from "react";
import { forwardRef, useMemo } from "react";
import { DropZoneProps } from "../DropZone/types";
import {
ComponentData,
Expand Down Expand Up @@ -60,7 +60,12 @@ export const SlotRender = forwardRef<HTMLDivElement, SlotRenderProps>(
{ className, style, content, config, metadata, as },
ref
) {
const El = as ?? "div";
const Wrapper = useMemo(
() => config.overrides?.slot || "div",
[config.overrides]
);

const El = as ?? Wrapper;

return (
<El className={className} style={style} ref={ref}>
Expand Down
34 changes: 33 additions & 1 deletion packages/core/lib/bubble-pointer-event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,40 @@ export interface BubbledPointerEventType extends PointerEvent {
originalTarget: EventTarget | null;
}

// Necessary for environments without DOM
class EventShim {
type: string;
bubbles: boolean;
cancelable: boolean;
defaultPrevented: boolean;

constructor(
type: string,
data: { bubbles?: boolean; cancelable?: boolean } = {}
) {
this.type = type;
this.bubbles = !!data.bubbles;
this.cancelable = !!data.cancelable;
this.defaultPrevented = false;
}

preventDefault() {
if (this.cancelable) {
this.defaultPrevented = true;
}
}

stopPropagation() {}
stopImmediatePropagation() {}
}

// Necessary to enable server build
const BaseEvent = typeof PointerEvent !== "undefined" ? PointerEvent : Event;
const BaseEvent =
typeof PointerEvent !== "undefined"
? PointerEvent
: typeof Event !== "undefined"
? Event
: EventShim;

export class BubbledPointerEvent extends BaseEvent {
_originalTarget: EventTarget | null = null;
Expand Down
8 changes: 8 additions & 0 deletions packages/core/types/API/Overrides.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,11 @@ export type FieldRenderFunctions<
},
"custom"
>;

export interface RenderOverrides {
slot?: RenderFunc<{
children?: ReactNode;
className?: string;
style?: React.CSSProperties;
}>;
}
4 changes: 2 additions & 2 deletions packages/core/types/API/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { WithDeepSlots } from "../Internal";
import { DefaultComponentProps } from "../Props";
import { AppState } from "./../AppState";
import { ComponentDataOptionalId, Content, Data } from "./../Data";
import { Overrides } from "./Overrides";
import { Overrides, RenderOverrides } from "./Overrides";
import { FieldTransforms } from "./FieldTransforms";
import { Config, DefaultComponents } from "../Config";
import { ReactNode } from "react";
Expand Down Expand Up @@ -75,6 +75,6 @@ export type RichText = string | ReactNode;
export * from "./DropZone";
export * from "./Viewports";

export type { Overrides };
export type { Overrides, RenderOverrides };

export * from "./FieldTransforms";
3 changes: 2 additions & 1 deletion packages/core/types/Config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { ComponentData, ComponentMetadata, RootData } from "./Data";
import { AsFieldProps, WithChildren, WithId, WithPuckProps } from "./Utils";
import { AppState } from "./AppState";
import { DefaultComponentProps, DefaultRootFieldProps } from "./Props";
import { Permissions } from "./API";
import { Permissions, RenderOverrides } from "./API";
import { DropZoneProps } from "../components/DropZone/types";
import {
AssertHasValue,
Expand Down Expand Up @@ -175,6 +175,7 @@ type ConfigInternal<
>;
};
root?: RootConfigInternal<RootProps, UserField>;
overrides?: RenderOverrides;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change doesn't seem necessary

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is necessary – render overrides is provided via the config object. That way both <Puck> and <Render> use the same overrides as they share the config. I suppose the correct place for documentation would be here.

Perhaps the prop should be renamed e.g. renderOverrides so it's not confused with editor overrides.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies for the delay on this one. Just catching up after a busy start to the year and checking back.

I hesitated on this one because adding overrides (or renderOverrides) to the config is quite a significant change and needs further thought.

We've hit things like this a few times, where there's a good use-case for editor APIs to be available within the renderer, such as with field transforms.

However, I think having overrides on the config is definitely confusing when we already have overrides as a prop.

I think the easier thing might be to use as for now. I'm going to close this one out, but feel free to open another one if you want to get the event shim in, or drop a reply.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth adding, we're also experimenting with a useSlot hook

};

// This _deliberately_ casts as any so the user can pass in something that widens the types
Expand Down
Loading