From 83060cd94a1747be7ac3bb4dadacd6c985ca916d Mon Sep 17 00:00:00 2001 From: Bogdan Chadkin Date: Sat, 17 Dec 2022 10:44:58 +0300 Subject: [PATCH] Send selected instance data from connector (#637) Ref https://github.com/webstudio-is/webstudio-designer/issues/628 Same issue as with selected outline. Styles were sent from detached element when tag prop is changed. Moving it to selected instance connector just works because styles already applied when effect is called and it's remounted on every style change. --- .../selected-instance-connector.ts | 21 +++++++-- .../wrapper-component/wrapper-component.tsx | 29 ++++++++++--- apps/designer/app/canvas/shared/instance.ts | 43 ++++--------------- 3 files changed, 48 insertions(+), 45 deletions(-) diff --git a/apps/designer/app/canvas/features/wrapper-component/selected-instance-connector.ts b/apps/designer/app/canvas/features/wrapper-component/selected-instance-connector.ts index 828778a248..1fb729c043 100644 --- a/apps/designer/app/canvas/features/wrapper-component/selected-instance-connector.ts +++ b/apps/designer/app/canvas/features/wrapper-component/selected-instance-connector.ts @@ -1,6 +1,6 @@ import { useCallback, useEffect } from "react"; -import type { Instance } from "@webstudio-is/react-sdk"; -import { useUserProps } from "@webstudio-is/react-sdk"; +import type { Instance, InstanceProps } from "@webstudio-is/react-sdk"; +import { getBrowserStyle } from "@webstudio-is/react-sdk"; import { publish, subscribeAll } from "~/shared/pubsub"; import { useScrollState } from "~/shared/dom-hooks"; @@ -13,11 +13,12 @@ const publishSelectedRect = (element: HTMLElement) => { export const SelectedInstanceConnector = ({ instanceElementRef, + instance, instanceProps, }: { instanceElementRef: { current: undefined | HTMLElement }; instance: Instance; - instanceProps: ReturnType; + instanceProps: undefined | InstanceProps; }) => { useEffect(() => { const element = instanceElementRef.current; @@ -67,6 +68,18 @@ export const SelectedInstanceConnector = ({ }); } + // trigger style recomputing every time instance styles are changed + publish({ + type: "selectInstance", + payload: { + id: instance.id, + component: instance.component, + cssRules: instance.cssRules, + browserStyle: getBrowserStyle(element), + props: instanceProps, + }, + }); + return () => { resizeObserver.disconnect(); mutationObserver.disconnect(); @@ -74,7 +87,7 @@ export const SelectedInstanceConnector = ({ }; // instance props may change dom element - }, [instanceElementRef, instanceProps]); + }, [instanceElementRef, instance, instanceProps]); const onScrollEnd = useCallback(() => { const element = instanceElementRef.current; diff --git a/apps/designer/app/canvas/features/wrapper-component/wrapper-component.tsx b/apps/designer/app/canvas/features/wrapper-component/wrapper-component.tsx index 2e545f8615..3091259b69 100644 --- a/apps/designer/app/canvas/features/wrapper-component/wrapper-component.tsx +++ b/apps/designer/app/canvas/features/wrapper-component/wrapper-component.tsx @@ -1,14 +1,15 @@ -import type { MouseEvent, FormEvent } from "react"; +import { type MouseEvent, type FormEvent, useMemo } from "react"; import { useRef } from "react"; import { Suspense, lazy, useCallback } from "react"; import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext"; import { - useUserProps, - renderWrapperComponentChildren, - getComponent, type Instance, type OnChangeChildren, + type UserProp, + renderWrapperComponentChildren, + getComponent, idAttribute, + useAllUserProps, } from "@webstudio-is/react-sdk"; import { useTextEditingInstanceId } from "~/shared/nano-states"; import { @@ -42,6 +43,8 @@ const ContentEditable = ({ return ; }; +type UserProps = Record; + type WrapperComponentDevProps = { instance: Instance; children: Array; @@ -60,6 +63,21 @@ export const WrapperComponentDev = ({ const [selectedInstance] = useSelectedInstance(); const [, setSelectedElement] = useSelectedElement(); + const [allUserProps] = useAllUserProps(); + const instanceProps = allUserProps[instance.id]; + const userProps = useMemo(() => { + const result: UserProps = {}; + if (instanceProps === undefined) { + return result; + } + for (const item of instanceProps.props) { + if (item.type !== "asset") { + result[item.prop] = item.value; + } + } + return result; + }, [instanceProps]); + const instanceElementRef = useRef(); const refCallback = useCallback( @@ -73,7 +91,6 @@ export const WrapperComponentDev = ({ [setSelectedElement] ); - const userProps = useUserProps(instance.id); const readonlyProps = instance.component === "Input" ? { readOnly: true } : undefined; @@ -108,7 +125,7 @@ export const WrapperComponentDev = ({ )} {/* Component includes many types and it's hard to provide right ref type with useRef */} diff --git a/apps/designer/app/canvas/shared/instance.ts b/apps/designer/app/canvas/shared/instance.ts index f5e124714e..0331a795fc 100644 --- a/apps/designer/app/canvas/shared/instance.ts +++ b/apps/designer/app/canvas/shared/instance.ts @@ -1,12 +1,10 @@ -import { useCallback, useEffect, useReducer, useState } from "react"; +import { useCallback, useEffect, useState } from "react"; import { type Instance, type UserProp, type Tree, getComponentMeta, allUserPropsContainer, - getBrowserStyle, - useAllUserProps, } from "@webstudio-is/react-sdk"; import { useSubscribe } from "~/shared/pubsub"; @@ -17,11 +15,7 @@ import { type SelectedInstanceData, } from "@webstudio-is/project"; import store from "immerhin"; -import { - useSelectedInstance, - useSelectedElement, - useHoveredInstance, -} from "./nano-states"; +import { useSelectedInstance, useHoveredInstance } from "./nano-states"; import { rootInstanceContainer, useBreakpoints, @@ -189,37 +183,16 @@ export const useDeleteInstance = () => { export const usePublishSelectedInstanceData = () => { const [instance] = useSelectedInstance(); - const [selectedElement] = useSelectedElement(); - const [allUserProps] = useAllUserProps(); - - // trigger style recomputing every time - // new updates for this node are sent from designer - const [styleKey, recomputeStyles] = useReducer((d) => d + 1, 0); - useSubscribe("updateStyle", ({ id }) => { - if (id === instance?.id) { - recomputeStyles(); - } - }); useEffect(() => { // Unselects the instance by `undefined` - let payload: undefined | SelectedInstanceData; - if (instance !== undefined) { - const props = allUserProps[instance.id]; - const browserStyle = getBrowserStyle(selectedElement); - payload = { - id: instance.id, - component: instance.component, - cssRules: instance.cssRules, - browserStyle, - props, - }; + if (instance === undefined) { + publish({ + type: "selectInstance", + payload: undefined, + }); } - publish({ - type: "selectInstance", - payload, - }); - }, [instance, allUserProps, selectedElement, styleKey]); + }, [instance]); }; export const usePublishHoveredInstanceData = () => {