From fa875ab5c180f84ceca60a29068d64bc1671ed7a Mon Sep 17 00:00:00 2001 From: Bogdan Chadkin Date: Tue, 20 May 2025 12:24:27 +0300 Subject: [PATCH] feat: use body element on new pages (#5222) Ref https://github.com/webstudio-is/webstudio/issues/3632 Now new project and new page will have body element in the root instead of body component. Screenshot 2025-05-20 at 00 15 37 --- .../builder/features/marketplace/templates.tsx | 10 +++++++--- .../app/builder/features/pages/page-settings.tsx | 4 +++- .../settings-panel/controls/tag-control.tsx | 6 +++++- apps/builder/app/canvas/canvas.tsx | 12 +----------- apps/builder/app/canvas/shared/body.tsx | 14 -------------- apps/builder/app/routes/_canvas.canvas.tsx | 15 ++++++++++++--- packages/project-build/src/db/build.ts | 4 +++- 7 files changed, 31 insertions(+), 34 deletions(-) delete mode 100644 apps/builder/app/canvas/shared/body.tsx diff --git a/apps/builder/app/builder/features/marketplace/templates.tsx b/apps/builder/app/builder/features/marketplace/templates.tsx index 099cfdb5ee..4789bf30c1 100644 --- a/apps/builder/app/builder/features/marketplace/templates.tsx +++ b/apps/builder/app/builder/features/marketplace/templates.tsx @@ -12,6 +12,7 @@ import { } from "@webstudio-is/design-system"; import { ChevronLeftIcon, ExternalLinkIcon } from "@webstudio-is/icons"; import { + elementComponent, ROOT_FOLDER_ID, type Asset, type Page, @@ -50,9 +51,12 @@ const insertSection = ({ ); // remove body and use its children as root insrances if (body) { - fragment.instances = fragment.instances.filter( - (instance) => instance.component !== "Body" - ); + fragment.instances = fragment.instances.filter((instance) => { + const isBody = + instance.component === "Body" || + (instance.component === elementComponent && instance.tag === "body"); + return !isBody; + }); fragment.children = body.children; } const insertable = findClosestInsertable(fragment); diff --git a/apps/builder/app/builder/features/pages/page-settings.tsx b/apps/builder/app/builder/features/pages/page-settings.tsx index d44f22559e..d0c51da0a7 100644 --- a/apps/builder/app/builder/features/pages/page-settings.tsx +++ b/apps/builder/app/builder/features/pages/page-settings.tsx @@ -29,6 +29,7 @@ import { isLiteralExpression, documentTypes, isRootFolder, + elementComponent, } from "@webstudio-is/sdk"; import { theme, @@ -1307,7 +1308,8 @@ const createPage = (pageId: Page["id"], values: Values) => { instances.set(rootInstanceId, { type: "instance", id: rootInstanceId, - component: "Body", + component: elementComponent, + tag: "body", children: [], }); registerFolderChildMutable(pages.folders, pageId, values.parentFolderId); diff --git a/apps/builder/app/builder/features/settings-panel/controls/tag-control.tsx b/apps/builder/app/builder/features/settings-panel/controls/tag-control.tsx index 9f86a379ac..993f0e47e3 100644 --- a/apps/builder/app/builder/features/settings-panel/controls/tag-control.tsx +++ b/apps/builder/app/builder/features/settings-panel/controls/tag-control.tsx @@ -46,7 +46,11 @@ export const TagControl = ({ meta, prop }: ControlProps<"tag">) => { const instanceTag = instance?.tag; const defaultTag = meta.options[0]; const computedTag = instanceTag ?? propTag ?? defaultTag; - const satisfyingTags = useStore($satisfyingTags); + let satisfyingTags = useStore($satisfyingTags); + // forbid changing tag on body element + if (computedTag === "body") { + satisfyingTags = ["body"]; + } const options = meta.options.filter((tag) => satisfyingTags.includes(tag)); const [value, setValue] = useState(); const updateTag = (value: string) => { diff --git a/apps/builder/app/canvas/canvas.tsx b/apps/builder/app/canvas/canvas.tsx index 0db362e372..0db6362aba 100644 --- a/apps/builder/app/canvas/canvas.tsx +++ b/apps/builder/app/canvas/canvas.tsx @@ -71,7 +71,6 @@ import { subscribeSelected } from "./instance-selected"; import { subscribeScrollNewInstanceIntoView } from "./shared/scroll-new-instance-into-view"; import { $selectedPage } from "~/shared/awareness"; import { createInstanceElement } from "./elements"; -import { Body } from "./shared/body"; import { subscribeScrollbarSize } from "./scrollbar-width"; import { compareMedia } from "@webstudio-is/css-engine"; import { builderApi } from "~/shared/builder-api"; @@ -248,15 +247,6 @@ export const Canvas = () => { hooks: baseComponentHooks, templates: baseComponentTemplates, }); - registerComponentLibrary({ - components: { - // override only canvas specific body component - // not related to sdk-components-react-remix anymore - Body, - }, - metas: {}, - templates: {}, - }); registerComponentLibrary({ namespace: "@webstudio-is/sdk-components-react-radix", components: radixComponents, @@ -321,7 +311,7 @@ export const Canvas = () => { }, []); if (components.size === 0 || instances.size === 0) { - return ; + return; } return ( diff --git a/apps/builder/app/canvas/shared/body.tsx b/apps/builder/app/canvas/shared/body.tsx deleted file mode 100644 index eb42bf4586..0000000000 --- a/apps/builder/app/canvas/shared/body.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { forwardRef, type ElementRef, type ComponentProps } from "react"; -import { Scripts, ScrollRestoration } from "@remix-run/react"; - -export const Body = forwardRef, ComponentProps<"body">>( - ({ children, ...props }, ref) => ( - - {children} - - - - ) -); - -Body.displayName = "Body"; diff --git a/apps/builder/app/routes/_canvas.canvas.tsx b/apps/builder/app/routes/_canvas.canvas.tsx index f55679b46f..b6f0cf3d7b 100644 --- a/apps/builder/app/routes/_canvas.canvas.tsx +++ b/apps/builder/app/routes/_canvas.canvas.tsx @@ -1,8 +1,8 @@ import { lazy } from "react"; -import { type LoaderFunctionArgs } from "@remix-run/server-runtime"; +import type { LoaderFunctionArgs } from "@remix-run/server-runtime"; +import { Scripts, ScrollRestoration } from "@remix-run/react"; import { isCanvas } from "~/shared/router-utils"; import { ClientOnly } from "~/shared/client-only"; -import { Body } from "~/canvas/shared/body"; export { ErrorBoundary } from "~/shared/error/error-boundary"; @@ -22,7 +22,16 @@ const Canvas = lazy(async () => { const CanvasRoute = () => { return ( - }> + // this setup remix scripts on canvas and after rendering a website + // scripts will continue to work even though removed from dom + + + + + } + > ); diff --git a/packages/project-build/src/db/build.ts b/packages/project-build/src/db/build.ts index a6ef58c3ea..33037b0c3f 100644 --- a/packages/project-build/src/db/build.ts +++ b/packages/project-build/src/db/build.ts @@ -20,6 +20,7 @@ import { type StyleDecl, Pages, initialBreakpoints, + elementComponent, } from "@webstudio-is/sdk"; import type { Build, CompactBuild } from "../types"; import { parseDeployment } from "./deployment"; @@ -229,7 +230,8 @@ const createNewPageInstances = (): Build["instances"] => { { type: "instance", id: instanceId, - component: "Body", + component: elementComponent, + tag: "body", children: [], }, ],