diff --git a/apps/demo/app/[...puckPath]/client.tsx b/apps/demo/app/[...puckPath]/client.tsx index 3d6bee1ce1..f9b7e643de 100644 --- a/apps/demo/app/[...puckPath]/client.tsx +++ b/apps/demo/app/[...puckPath]/client.tsx @@ -5,7 +5,7 @@ import { Puck } from "@/core/components/Puck"; import { Render } from "@/core/components/Render"; import { Button } from "@/core/components/Button"; import headingAnalyzer from "@/plugin-heading-analyzer/src/HeadingAnalyzer"; -import config from "../../config"; +import config, { UserConfig } from "../../config"; import { useDemoData } from "../../lib/use-demo-data"; export function Client({ path, isEdit }: { path: string; isEdit: boolean }) { @@ -17,7 +17,7 @@ export function Client({ path, isEdit }: { path: string; isEdit: boolean }) { if (isEdit) { return (
- config={config} data={data} onPublish={async (data: Data) => { @@ -42,7 +42,7 @@ export function Client({ path, isEdit }: { path: string; isEdit: boolean }) { } if (data) { - return ; + return config={config} data={resolvedData} />; } return ( diff --git a/apps/demo/app/custom-ui/[...puckPath]/client.tsx b/apps/demo/app/custom-ui/[...puckPath]/client.tsx index 940d284212..957702a1ce 100644 --- a/apps/demo/app/custom-ui/[...puckPath]/client.tsx +++ b/apps/demo/app/custom-ui/[...puckPath]/client.tsx @@ -5,7 +5,7 @@ import { Puck } from "@/core/components/Puck"; import { Render } from "@/core/components/Render"; import { Button } from "@/core/components/Button"; import { HeadingAnalyzer } from "@/plugin-heading-analyzer/src/HeadingAnalyzer"; -import config from "../../../config"; +import config, { UserConfig } from "../../../config"; import { useDemoData } from "../../../lib/use-demo-data"; import { IconButton, usePuck } from "@/core"; import { ReactNode, useEffect, useRef, useState } from "react"; @@ -287,7 +287,7 @@ export function Client({ path, isEdit }: { path: string; isEdit: boolean }) { if (isEdit) { return ( - config={config} data={data} headerPath={path} @@ -336,7 +336,7 @@ export function Client({ path, isEdit }: { path: string; isEdit: boolean }) { } if (data) { - return ; + return config={config} data={resolvedData} />; } return ( diff --git a/apps/demo/config/index.tsx b/apps/demo/config/index.tsx index 37f974ad1d..1430e93ee0 100644 --- a/apps/demo/config/index.tsx +++ b/apps/demo/config/index.tsx @@ -27,12 +27,14 @@ export type Props = { VerticalSpace: VerticalSpaceProps; }; -// We avoid the name config as next gets confused -export const conf: Config< +export type UserConfig = Config< Props, RootProps, "layout" | "typography" | "interactive" -> = { +>; + +// We avoid the name config as next gets confused +export const conf: UserConfig = { root: { render: Root, }, diff --git a/packages/core/components/DropZone/context.tsx b/packages/core/components/DropZone/context.tsx index d6fc1a6df3..3bbeb2b396 100644 --- a/packages/core/components/DropZone/context.tsx +++ b/packages/core/components/DropZone/context.tsx @@ -15,9 +15,11 @@ import { getZoneId } from "../../lib/get-zone-id"; export type PathData = Record; -export type DropZoneContext = { +export type DropZoneContext< + UserConfig extends Config = Config +> = { data: Data; - config: Config; + config: UserConfig; componentState?: Record; itemSelector?: ItemSelector | null; setItemSelector?: (newIndex: ItemSelector | null) => void; diff --git a/packages/core/components/Puck/context.tsx b/packages/core/components/Puck/context.tsx index 61c5379741..bbe50a61f9 100644 --- a/packages/core/components/Puck/context.tsx +++ b/packages/core/components/Puck/context.tsx @@ -18,10 +18,12 @@ export const defaultAppState: AppState = { }, }; -type AppContext = { +type AppContext< + UserConfig extends Config = Config +> = { state: AppState; dispatch: (action: PuckAction) => void; - config: Config; + config: UserConfig; componentState: Record; resolveData: (newAppState: AppState) => void; plugins: Plugin[]; @@ -42,8 +44,10 @@ export const appContext = createContext({ export const AppProvider = appContext.Provider; -export const useAppContext = () => { - const mainContext = useContext(appContext); +export function useAppContext< + UserConfig extends Config = Config +>() { + const mainContext = useContext(appContext) as AppContext; const selectedItem = mainContext.state.ui.itemSelector ? getItem(mainContext.state.ui.itemSelector, mainContext.state.data) @@ -61,4 +65,4 @@ export const useAppContext = () => { }); }, }; -}; +} diff --git a/packages/core/components/Puck/index.tsx b/packages/core/components/Puck/index.tsx index 30d94ea8dc..b889c0e6b2 100644 --- a/packages/core/components/Puck/index.tsx +++ b/packages/core/components/Puck/index.tsx @@ -45,7 +45,9 @@ import { useHistoryStore } from "../../lib/use-history-store"; const getClassName = getClassNameFactory("Puck", styles); -export function Puck({ +export function Puck< + UserConfig extends Config = Config +>({ children, config, data: initialData = { content: [], root: { props: { title: "" } } }, @@ -60,7 +62,7 @@ export function Puck({ headerPath, }: { children?: ReactNode; - config: Config; + config: UserConfig; data: Data; ui?: Partial; onChange?: (data: Data) => void; @@ -82,7 +84,7 @@ export function Puck({ const historyStore = useHistoryStore(); const [reducer] = useState(() => - createReducer({ config, record: historyStore.record }) + createReducer({ config, record: historyStore.record }) ); const [initialAppState] = useState(() => ({ diff --git a/packages/core/components/Render/index.tsx b/packages/core/components/Render/index.tsx index f8d391a5ef..69da3471bd 100644 --- a/packages/core/components/Render/index.tsx +++ b/packages/core/components/Render/index.tsx @@ -4,13 +4,9 @@ import { rootDroppableId } from "../../lib/root-droppable-id"; import { Config, Data } from "../../types/Config"; import { DropZone, DropZoneProvider } from "../DropZone"; -export function Render({ - config, - data, -}: { - config: Config; - data: Data; -}) { +export function Render< + UserConfig extends Config = Config +>({ config, data }: { config: UserConfig; data: Data }) { // DEPRECATED const rootProps = data.root.props || data.root; const title = rootProps?.title || ""; diff --git a/packages/core/components/ServerRender/index.tsx b/packages/core/components/ServerRender/index.tsx index 0cbee99cd0..ec017fd7e7 100644 --- a/packages/core/components/ServerRender/index.tsx +++ b/packages/core/components/ServerRender/index.tsx @@ -59,13 +59,9 @@ function DropZoneRender({ ); } -export function Render({ - config, - data, -}: { - config: Config; - data: Data; -}) { +export function Render< + UserConfig extends Config = Config +>({ config, data }: { config: UserConfig; data: Data }) { if (config.root?.render) { // DEPRECATED const rootProps = data.root.props || data.root; diff --git a/packages/core/reducer/index.ts b/packages/core/reducer/index.ts index 1d762d7c08..1508cf6f6f 100644 --- a/packages/core/reducer/index.ts +++ b/packages/core/reducer/index.ts @@ -49,14 +49,16 @@ export const setAction = (state: AppState, action: SetAction) => { return { ...state, ...action.state(state) }; }; -export const createReducer = ({ +export function createReducer< + UserConfig extends Config = Config +>({ config, record, }: { - config: Config; + config: UserConfig; record?: (appState: AppState) => void; -}): StateReducer => - storeInterceptor((state, action) => { +}): StateReducer { + return storeInterceptor((state, action) => { const data = reduceData(state.data, action, config); const ui = reduceUi(state.ui, action); @@ -66,3 +68,4 @@ export const createReducer = ({ return { data, ui }; }, record); +} diff --git a/packages/core/types/Config.tsx b/packages/core/types/Config.tsx index 4aabb95c0e..ffaf879924 100644 --- a/packages/core/types/Config.tsx +++ b/packages/core/types/Config.tsx @@ -173,7 +173,7 @@ type Category = { export type Config< Props extends { [key: string]: any } = { [key: string]: any }, RootProps extends DefaultRootProps = DefaultRootProps, - CategoryName extends string = string + CategoryName extends string = any > = { categories?: Record> & { other?: Category;