Skip to content

Commit

Permalink
feat: make Layout setting cumulative
Browse files Browse the repository at this point in the history
BREAKING CHANGE: The `Layout` setting cannot be overriden anymore because it's now cumulative, see:
 - https://vike.dev/Layout#multiple-layouts
 - https://vike.dev/Layout#nested-layouts
  • Loading branch information
Blankeos committed Jun 17, 2024
1 parent caf0317 commit 7e2ebc8
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 7 deletions.
1 change: 1 addition & 0 deletions vike-solid/+config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const config = {
},
Layout: {
env: { server: true, client: true },
cumulative: true,
},
title: {
env: { server: true, client: true },
Expand Down
52 changes: 46 additions & 6 deletions vike-solid/renderer/getPageElement.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import type { PageContext } from "vike/types";
import { PageContextProvider } from "./PageContextProvider.js";
import { usePageContext } from "../hooks/usePageContext.js";
import type { JSX } from "solid-js";
import type { JSX, FlowComponent, FlowProps } from "solid-js";
import { createComponent, createEffect, createMemo } from "solid-js";
import { Dynamic } from "solid-js/web";
import type { Store } from "solid-js/store";
import { createStore, reconcile, unwrap, type Store } from "solid-js/store";

export function getPageElement(pageContext: Store<PageContext>): JSX.Element {
const page = (
Expand All @@ -18,11 +19,34 @@ export function getPageElement(pageContext: Store<PageContext>): JSX.Element {

function Layout(props: { children: JSX.Element }) {
const pageContext = usePageContext();
return (
<Dynamic component={pageContext.config.Layout ?? Passthrough}>
{props.children}
</Dynamic>

const [layoutStore, setLayoutStore] = createStore(
pageContext.config.Layout?.toReversed() as FlowComponent[]
);

createEffect(() => {
deepTrack(pageContext.config.Layout);

setLayoutStore(
reconcile(pageContext.config.Layout?.toReversed() as FlowComponent[])
);
});

const renderLayouts = (i: number = 0) => {
let item: FlowComponent = layoutStore[i];

if (!item) return props.children;

if (typeof item !== "function") item = Passthrough;

return createComponent(item, {
get children(): JSX.Element {
return renderLayouts(i + 1);
},
});
};

return renderLayouts();
}

function Page() {
Expand All @@ -37,3 +61,19 @@ function Page() {
function Passthrough(props: { children: JSX.Element }) {
return <>{props.children}</>;
}

/**
* Utility for tracking non-primitive values inside a store. (e.g. Arrays, Objects, Functions).
*
* Otherwise, your createMemo or createEffect won't run even if it actually changed.
*
* Reference: https://github.com/solidjs/solid/discussions/829#discussioncomment-2102335
*/
function deepTrack(store: any) {
for (const k in store) {
const value = store[k];
if (typeof value === "object") {
deepTrack(store);
}
}
}
5 changes: 4 additions & 1 deletion vike-solid/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
export type { Component } from "solid-js";

import type { JSX } from "solid-js";
import type { Component, JSX } from "solid-js";

type Page = () => JSX.Element;

declare global {
namespace Vike {
interface ConfigResolved {
Layout?: Array<Component>;
}
interface PageContext {
// Page is undefined in onRenderHtml() when setting the `ssr` config flag to `false`
Page?: Page;
Expand Down

0 comments on commit 7e2ebc8

Please sign in to comment.