;
return (
diff --git a/src/components/puck/container.tsx b/src/components/puck/container.tsx
index 43914831..b31a6cae 100644
--- a/src/components/puck/container.tsx
+++ b/src/components/puck/container.tsx
@@ -1,4 +1,4 @@
-import type { ComponentConfig } from "@puckeditor/core";
+import type { ComponentConfig, Slot } from "@puckeditor/core";
import type { ElementType } from "react";
import {
getContainerSlotClassName,
@@ -21,12 +21,12 @@ const tag = defineToken({
type Tag = TokenValue;
type ContainerProps = ContainerStyle & {
- content: any;
+ content: Slot;
tag: Tag;
};
const props = defineProps({
- content: field.raw({ type: "slot" } as const),
+ content: field.slot(),
layout: field.radio(layout, { label: "Layout" }),
padding: responsive.token(padding, { label: "Padding", default: "md" }),
gap: responsive.token(gap, { label: "Gap", default: "md" }),
diff --git a/src/components/puck/grid.tsx b/src/components/puck/grid.tsx
index 67c284ee..668060a1 100644
--- a/src/components/puck/grid.tsx
+++ b/src/components/puck/grid.tsx
@@ -1,18 +1,18 @@
-import type { ComponentConfig } from "@puckeditor/core";
+import type { ComponentConfig, Slot } from "@puckeditor/core";
import { defineProps, responsive, field } from "@/lib/puck/define-props";
import type { ResponsiveValue } from "@/lib/puck/responsive";
import { columnCount, gap, gridRows, type ColumnCount, type Spacing, type GridRows } from "@/lib/puck/tokens";
import { getGridClassName } from "@/lib/puck/layout";
type GridProps = {
- content: any;
+ content: Slot;
columns: ResponsiveValue;
rows: ResponsiveValue;
gap: ResponsiveValue;
};
const props = defineProps({
- content: field.raw({ type: "slot" } as const),
+ content: field.slot(),
columns: responsive.token(columnCount, { label: "Columns", default: "3" }),
rows: responsive.token(gridRows, { label: "Rows", default: "auto" }),
gap: responsive.token(gap, { label: "Gap", default: "md" }),
diff --git a/src/components/puck/media.tsx b/src/components/puck/media.tsx
index 00314d3d..545e390a 100644
--- a/src/components/puck/media.tsx
+++ b/src/components/puck/media.tsx
@@ -29,8 +29,8 @@ type MediaProps = {
};
const props = defineProps({
- url: field.raw({ type: "text", label: "URL" } as const, ""),
- alt: field.raw({ type: "text", label: "Alt text" } as const, ""),
+ url: field.raw({ type: "text", label: "URL" }, ""),
+ alt: field.raw({ type: "text", label: "Alt text" }, ""),
objectFit: field.select(objectFit, { label: "Object fit" }),
aspectRatio: field.select(aspectRatio, { label: "Aspect ratio" }),
radius: field.select(radius, { label: "Corners" }),
diff --git a/src/components/puck/rich-text.tsx b/src/components/puck/rich-text.tsx
index bbbd0af5..1716d77e 100644
--- a/src/components/puck/rich-text.tsx
+++ b/src/components/puck/rich-text.tsx
@@ -24,8 +24,8 @@ type RichTextProps = {
const props = defineProps({
content: field.raw(
- { type: "richtext", contentEditable: true } as const,
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." as unknown as RichText,
+ { type: "richtext", contentEditable: true },
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
),
textColor: field.select(textColor, { label: "Text color", default: "foreground" }),
align: field.radio(textAlign, { label: "Text align", default: "left" }),
diff --git a/src/components/puck/section.tsx b/src/components/puck/section.tsx
index 63ef3425..a7c00808 100644
--- a/src/components/puck/section.tsx
+++ b/src/components/puck/section.tsx
@@ -1,4 +1,4 @@
-import type { ComponentConfig } from "@puckeditor/core";
+import type { ComponentConfig, Slot } from "@puckeditor/core";
import type { ResponsiveValue } from "@/lib/puck/responsive";
import { resolveResponsive } from "@/lib/puck/responsive-tailwind";
import { cn } from "@/lib/utils";
@@ -16,7 +16,7 @@ import {
} from "@/lib/puck/tokens";
type SectionProps = {
- content: any;
+ content: Slot;
anchorId: string;
paddingX: ResponsiveValue;
paddingY: ResponsiveValue;
@@ -27,8 +27,8 @@ type SectionProps = {
};
const props = defineProps({
- content: field.raw({ type: "slot" } as const),
- anchorId: field.raw({ type: "text", label: "Anchor ID" } as const, ""),
+ content: field.slot(),
+ anchorId: field.raw({ type: "text", label: "Anchor ID" }, ""),
paddingX: responsive.token(paddingX, { label: "Horizontal padding", default: "md" }),
paddingY: responsive.token(paddingY, { label: "Vertical padding", default: "lg" }),
gap: responsive.token(gapToken, { label: "Gap", default: "md" }),
diff --git a/src/lib/puck/define-props.test.ts b/src/lib/puck/define-props.test.ts
index e3269e13..86e0d818 100644
--- a/src/lib/puck/define-props.test.ts
+++ b/src/lib/puck/define-props.test.ts
@@ -44,7 +44,7 @@ describe("prop builders", () => {
describe("defineProps", () => {
it("splits mixed prop specs into fields and defaultProps", () => {
const props = defineProps({
- content: field.raw({ type: "slot" }),
+ content: field.slot(),
size: field.select(size, { label: "Size", default: "md" }),
gap: responsive.token(size, {
label: "Gap",
@@ -60,7 +60,7 @@ describe("defineProps", () => {
color: { type: "radio", label: "Color", options: colorToken.options },
});
expect(props.defaultProps).toEqual({
- content: undefined,
+ content: [],
size: "md",
gap: { base: "sm", md: "lg" },
color: "red",
diff --git a/src/lib/puck/define-props.ts b/src/lib/puck/define-props.ts
index 37953934..f3af0a8e 100644
--- a/src/lib/puck/define-props.ts
+++ b/src/lib/puck/define-props.ts
@@ -1,4 +1,4 @@
-import type { CustomField } from "@puckeditor/core";
+import type { CustomField, Slot } from "@puckeditor/core";
import type { Token, TokenOption } from "@/lib/puck/tokens";
import type { ResponsiveValue } from "@/lib/puck/responsive";
import { responsiveField } from "@/components/puck/fields/responsive-field";
@@ -35,6 +35,13 @@ export const responsive = {
type FieldDescriptor = { type: "select" | "radio"; label: string; options: TokenOption[] };
export const field = {
+ slot(descriptor?: { allow?: string[]; disallow?: string[] }): PropSpec<{ type: "slot" } & typeof descriptor, Slot> {
+ return {
+ field: { type: "slot" as const, ...descriptor },
+ defaultValue: [] as Slot,
+ };
+ },
+
select(
token: Token,
opts: { label: string; default?: NoInfer },
@@ -58,12 +65,11 @@ export const field = {
raw: fieldRaw,
};
-function fieldRaw(descriptor: D): PropSpec;
function fieldRaw(descriptor: D, defaultValue: T): PropSpec;
-function fieldRaw(descriptor: D, defaultValue?: T): PropSpec {
+function fieldRaw(descriptor: D, defaultValue: T): PropSpec {
return {
field: descriptor,
- defaultValue: defaultValue as T | undefined,
+ defaultValue,
};
}
From 925560ce50fef4e423fe48b57762e738cf4ac46d Mon Sep 17 00:00:00 2001
From: wlenig <30681316+wlenig@users.noreply.github.com>
Date: Fri, 27 Mar 2026 01:49:45 -0400
Subject: [PATCH 11/13] WEB-111 Remove unnecessary explicit `defaultProps`
---
docs/STYLING.md | 213 ++++++++++++++++++++++--------
src/components/puck/container.tsx | 1 -
src/components/puck/grid.tsx | 1 -
src/components/puck/section.tsx | 1 -
4 files changed, 159 insertions(+), 57 deletions(-)
diff --git a/docs/STYLING.md b/docs/STYLING.md
index 7d8b6f32..40849abe 100644
--- a/docs/STYLING.md
+++ b/docs/STYLING.md
@@ -1,27 +1,16 @@
# Styling System
-Components are styled through **design tokens** that map editor choices to Tailwind classes. Any token can be made responsive, letting editors pick different values per breakpoint.
+Components in the Puck editor are styled through **design tokens** — named choices that map to arbitrary properties, but mostly Tailwind classes. Editors pick tokens from dropdowns; the system turns those choices into class names at render time.
-## Responsive values
+Any token can be made **responsive**, letting editors pick different values per breakpoint (base / tablet / desktop). Unset breakpoints inherit from the nearest smaller one.
-A `ResponsiveValue` has a required `base` and optional `md` / `lg` overrides:
+## Core concepts
-```ts
-type ResponsiveValue = { base: T } & Partial