diff --git a/blocks/section.ts b/blocks/section.ts index 2869b9058..c2d0f0336 100644 --- a/blocks/section.ts +++ b/blocks/section.ts @@ -1,8 +1,9 @@ // deno-lint-ignore-file no-explicit-any +import { PartialProps } from "$fresh/src/runtime/Partial.tsx"; import { ComponentType } from "preact"; import { HttpContext } from "../blocks/handler.ts"; import { PropsLoader, propsLoader } from "../blocks/propsLoader.ts"; -import { fnContextFromHttpContext, RequestState } from "../blocks/utils.tsx"; +import { RequestState, fnContextFromHttpContext } from "../blocks/utils.tsx"; import StubSection, { Empty } from "../components/StubSection.tsx"; import { withSection } from "../components/section.tsx"; import { Context } from "../deco.ts"; @@ -16,7 +17,6 @@ import { } from "../engine/block.ts"; import { Resolver } from "../engine/core/resolver.ts"; import { AppManifest, FunctionContext } from "../types.ts"; -import { PartialProps } from "$fresh/src/runtime/Partial.tsx"; /** * @widget none @@ -44,9 +44,13 @@ export const isSection = < return (s as Section)?.metadata?.component === section; }; -export type SectionProps = T extends PropsLoader ? Props +type ReturnProps = TFunc extends PropsLoader ? Props : unknown; +export type SectionProps = + | ReturnProps + | ReturnProps; + export interface ErrorBoundaryParams { error: any; props: TProps; @@ -55,15 +59,21 @@ export interface ErrorBoundaryParams { export type ErrorBoundaryComponent = ComponentFunc< ErrorBoundaryParams >; -export interface SectionModule extends +export interface SectionModule< + TConfig = any, + TProps = any, + TLoaderProps = TProps, + TActionProps = TLoaderProps, +> extends BlockModule< - ComponentFunc, - ReturnType>, + ComponentFunc, + ReturnType>, PreactComponent > { LoadingFallback?: ComponentType; ErrorFallback?: ComponentType<{ error?: Error }>; - loader?: PropsLoader; + loader?: PropsLoader; + action?: PropsLoader; partialMode?: PartialProps["mode"]; } @@ -101,7 +111,10 @@ export const createSectionBlock = ( type: "sections" | "pages", ): Block => ({ type, - introspect: { funcNames: ["loader", "default"], includeReturn: true }, + introspect: { + funcNames: ["loader", "action", "default"], + includeReturn: true, + }, adapt: ( mod: SectionModule, resolver: string, @@ -123,8 +136,8 @@ export const createSectionBlock = ( mod.ErrorFallback, mod.partialMode, ); - const loader = mod.loader; - if (!loader) { + + if (!mod.action && !mod.loader) { return ( props: TProps, ctx: HttpContext, @@ -142,17 +155,26 @@ export const createSectionBlock = ( resolve, } = httpCtx; + const loaderSectionProps = request.method === "POST" + ? mod.action ?? mod.loader + : mod.loader; + + if (!loaderSectionProps) { + return componentFunc(props as unknown as TProps, httpCtx); + } + const ctx = { ...context, state: { ...context.state, $live: props, resolve }, } as FunctionContext; + const fnContext = fnContextFromHttpContext(httpCtx); const p = await wrapCaughtErrors(() => propsLoader( - loader, + loaderSectionProps, ctx.state.$live, request, - fnContextFromHttpContext(httpCtx), + fnContext, ), props ?? {}); return componentFunc(p, httpCtx); diff --git a/hooks/useAction.ts b/hooks/useAction.ts new file mode 100644 index 000000000..3642d290b --- /dev/null +++ b/hooks/useAction.ts @@ -0,0 +1,8 @@ +import { usePartialSection } from "./usePartialSection.ts"; + +/** + * @returns the action url of the current section. + */ +export const useAction = () => { + return usePartialSection()["f-partial"]; +};