Skip to content

Commit 8ff0091

Browse files
committed
WEB-111 Use Slot type where possible, add builder for slot fields, add tailwind hints
1 parent b16143b commit 8ff0091

10 files changed

Lines changed: 37 additions & 27 deletions

File tree

src/app/styles.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
@import "tw-animate-css";
33
@import "shadcn/tailwind.css";
44

5-
@source inline("{md:,lg:,}p-{0,1,2,4,6,8,12}");
5+
@source inline("{md:,lg:,}{p,px,py}-{0,1,2,4,6,8,12}");
66
@source inline("{md:,lg:,}gap-{0,1,2,4,6,8,12}");
77
@source inline("{md:,lg:,}grid-cols-{1,2,3,4,5,6}");
88
@source inline("{md:,lg:,}grid-rows-{none,1,2,3,4,5,6}");

src/components/puck/button.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ type PuckButtonProps = {
2828
};
2929

3030
const props = defineProps({
31-
label: field.raw({ type: "text", label: "Label" } as const, "Click me"),
32-
href: field.raw({ type: "text", label: "Link URL" } as const, ""),
31+
label: field.raw({ type: "text", label: "Label" }, "Click me"),
32+
href: field.raw({ type: "text", label: "Link URL" }, ""),
3333
variant: field.select(variant, { label: "Variant" }),
3434
size: field.select(size, { label: "Size" }),
3535
});

src/components/puck/columns.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { ComponentConfig } from "@puckeditor/core";
1+
import type { ComponentConfig, Slot, SlotComponent } from "@puckeditor/core";
22
import { defineProps, responsive, field } from "@/lib/puck/define-props";
33
import { columnCount, gap, type ColumnCount, type Spacing } from "@/lib/puck/tokens";
44
import type { ResponsiveValue } from "@/lib/puck/responsive";
@@ -7,7 +7,7 @@ import { getGridClassName, getMaxCols } from "@/lib/puck/layout";
77
type SlotKey = `column${ColumnCount}`;
88

99
type ColumnsProps = {
10-
[K in SlotKey]: any;
10+
[K in SlotKey]: Slot;
1111
} & {
1212
columns: ResponsiveValue<ColumnCount>;
1313
gap: ResponsiveValue<Spacing>;
@@ -22,6 +22,10 @@ const columnSlotFields = Object.fromEntries(
2222
columnSlotKeys.map((key) => [key, slotField]),
2323
) as Record<SlotKey, typeof slotField>;
2424

25+
const columnSlotDefaults = Object.fromEntries(
26+
columnSlotKeys.map((key) => [key, [] as Slot]),
27+
) as Record<SlotKey, Slot>;
28+
2529
const props = defineProps({
2630
columns: responsive.token(columnCount, { label: "Columns", default: { base: "1", md: "2" } }),
2731
gap: responsive.token(gap, { label: "Gap", default: "md" }),
@@ -30,7 +34,7 @@ const props = defineProps({
3034
export const Columns: ComponentConfig<ColumnsProps> = {
3135
label: "Columns",
3236
fields: { ...columnSlotFields, ...props.fields },
33-
defaultProps: props.defaultProps as ColumnsProps,
37+
defaultProps: { ...columnSlotDefaults, ...props.defaultProps },
3438
// Hide column slot fields that exceed the selected column count,
3539
// so the editor sidebar only shows slots that are actually rendered.
3640
resolveFields: (data) => {
@@ -46,7 +50,7 @@ export const Columns: ComponentConfig<ColumnsProps> = {
4650
},
4751
render: ({ columns, gap, ...slots }) => {
4852
const maxCols = getMaxCols(columns);
49-
const slotMap = slots as Record<SlotKey, any>;
53+
const slotMap = slots as Record<SlotKey, SlotComponent>;
5054

5155
return (
5256
<div className={getGridClassName({ columns, rows: { base: "auto" }, gap })}>

src/components/puck/container.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { ComponentConfig } from "@puckeditor/core";
1+
import type { ComponentConfig, Slot } from "@puckeditor/core";
22
import type { ElementType } from "react";
33
import {
44
getContainerSlotClassName,
@@ -21,12 +21,12 @@ const tag = defineToken({
2121
type Tag = TokenValue<typeof tag>;
2222

2323
type ContainerProps = ContainerStyle & {
24-
content: any;
24+
content: Slot;
2525
tag: Tag;
2626
};
2727

2828
const props = defineProps({
29-
content: field.raw({ type: "slot" } as const),
29+
content: field.slot(),
3030
layout: field.radio(layout, { label: "Layout" }),
3131
padding: responsive.token(padding, { label: "Padding", default: "md" }),
3232
gap: responsive.token(gap, { label: "Gap", default: "md" }),

src/components/puck/grid.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
import type { ComponentConfig } from "@puckeditor/core";
1+
import type { ComponentConfig, Slot } from "@puckeditor/core";
22
import { defineProps, responsive, field } from "@/lib/puck/define-props";
33
import type { ResponsiveValue } from "@/lib/puck/responsive";
44
import { columnCount, gap, gridRows, type ColumnCount, type Spacing, type GridRows } from "@/lib/puck/tokens";
55
import { getGridClassName } from "@/lib/puck/layout";
66

77
type GridProps = {
8-
content: any;
8+
content: Slot;
99
columns: ResponsiveValue<ColumnCount>;
1010
rows: ResponsiveValue<GridRows>;
1111
gap: ResponsiveValue<Spacing>;
1212
};
1313

1414
const props = defineProps({
15-
content: field.raw({ type: "slot" } as const),
15+
content: field.slot(),
1616
columns: responsive.token(columnCount, { label: "Columns", default: "3" }),
1717
rows: responsive.token(gridRows, { label: "Rows", default: "auto" }),
1818
gap: responsive.token(gap, { label: "Gap", default: "md" }),

src/components/puck/media.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ type MediaProps = {
2929
};
3030

3131
const props = defineProps({
32-
url: field.raw({ type: "text", label: "URL" } as const, ""),
33-
alt: field.raw({ type: "text", label: "Alt text" } as const, ""),
32+
url: field.raw({ type: "text", label: "URL" }, ""),
33+
alt: field.raw({ type: "text", label: "Alt text" }, ""),
3434
objectFit: field.select(objectFit, { label: "Object fit" }),
3535
aspectRatio: field.select(aspectRatio, { label: "Aspect ratio" }),
3636
radius: field.select(radius, { label: "Corners" }),

src/components/puck/rich-text.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ type RichTextProps = {
2424

2525
const props = defineProps({
2626
content: field.raw(
27-
{ type: "richtext", contentEditable: true } as const,
28-
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." as unknown as RichText,
27+
{ type: "richtext", contentEditable: true },
28+
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
2929
),
3030
textColor: field.select(textColor, { label: "Text color", default: "foreground" }),
3131
align: field.radio(textAlign, { label: "Text align", default: "left" }),

src/components/puck/section.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { ComponentConfig } from "@puckeditor/core";
1+
import type { ComponentConfig, Slot } from "@puckeditor/core";
22
import type { ResponsiveValue } from "@/lib/puck/responsive";
33
import { resolveResponsive } from "@/lib/puck/responsive-tailwind";
44
import { cn } from "@/lib/utils";
@@ -16,7 +16,7 @@ import {
1616
} from "@/lib/puck/tokens";
1717

1818
type SectionProps = {
19-
content: any;
19+
content: Slot;
2020
anchorId: string;
2121
paddingX: ResponsiveValue<Spacing>;
2222
paddingY: ResponsiveValue<Spacing>;
@@ -27,8 +27,8 @@ type SectionProps = {
2727
};
2828

2929
const props = defineProps({
30-
content: field.raw({ type: "slot" } as const),
31-
anchorId: field.raw({ type: "text", label: "Anchor ID" } as const, ""),
30+
content: field.slot(),
31+
anchorId: field.raw({ type: "text", label: "Anchor ID" }, ""),
3232
paddingX: responsive.token(paddingX, { label: "Horizontal padding", default: "md" }),
3333
paddingY: responsive.token(paddingY, { label: "Vertical padding", default: "lg" }),
3434
gap: responsive.token(gapToken, { label: "Gap", default: "md" }),

src/lib/puck/define-props.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ describe("prop builders", () => {
4444
describe("defineProps", () => {
4545
it("splits mixed prop specs into fields and defaultProps", () => {
4646
const props = defineProps({
47-
content: field.raw({ type: "slot" }),
47+
content: field.slot(),
4848
size: field.select(size, { label: "Size", default: "md" }),
4949
gap: responsive.token(size, {
5050
label: "Gap",
@@ -60,7 +60,7 @@ describe("defineProps", () => {
6060
color: { type: "radio", label: "Color", options: colorToken.options },
6161
});
6262
expect(props.defaultProps).toEqual({
63-
content: undefined,
63+
content: [],
6464
size: "md",
6565
gap: { base: "sm", md: "lg" },
6666
color: "red",

src/lib/puck/define-props.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { CustomField } from "@puckeditor/core";
1+
import type { CustomField, Slot } from "@puckeditor/core";
22
import type { Token, TokenOption } from "@/lib/puck/tokens";
33
import type { ResponsiveValue } from "@/lib/puck/responsive";
44
import { responsiveField } from "@/components/puck/fields/responsive-field";
@@ -35,6 +35,13 @@ export const responsive = {
3535
type FieldDescriptor = { type: "select" | "radio"; label: string; options: TokenOption[] };
3636

3737
export const field = {
38+
slot(descriptor?: { allow?: string[]; disallow?: string[] }): PropSpec<{ type: "slot" } & typeof descriptor, Slot> {
39+
return {
40+
field: { type: "slot" as const, ...descriptor },
41+
defaultValue: [] as Slot,
42+
};
43+
},
44+
3845
select<K extends string>(
3946
token: Token<K>,
4047
opts: { label: string; default?: NoInfer<K> },
@@ -58,12 +65,11 @@ export const field = {
5865
raw: fieldRaw,
5966
};
6067

61-
function fieldRaw<const D>(descriptor: D): PropSpec<D, undefined>;
6268
function fieldRaw<const D, T>(descriptor: D, defaultValue: T): PropSpec<D, T>;
63-
function fieldRaw<const D, T>(descriptor: D, defaultValue?: T): PropSpec<D, T | undefined> {
69+
function fieldRaw<const D, T>(descriptor: D, defaultValue: T): PropSpec<D, T> {
6470
return {
6571
field: descriptor,
66-
defaultValue: defaultValue as T | undefined,
72+
defaultValue,
6773
};
6874
}
6975

0 commit comments

Comments
 (0)