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.
This commit is contained in:
Bogdan Chadkin authored and GitHub committed 2022-12-17 10:44:58 +03:00
1 parent 703a9fe215
commit 83060cd94a
3 files changed
+48 -45

No files matched your search

@@ -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<typeof useUserProps>;
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;
@@ -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 <Component ref={ref} {...props} contentEditable={true} />;
};
type UserProps = Record<UserProp["prop"], string | number | boolean>;
type WrapperComponentDevProps = {
instance: Instance;
children: Array<JSX.Element | string>;
@@ -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<HTMLElement>();
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 = ({
<SelectedInstanceConnector
instanceElementRef={instanceElementRef}
instance={instance}
instanceProps={userProps}
instanceProps={instanceProps}
/>
)}
{/* Component includes many types and it's hard to provide right ref type with useRef */}
+8 -35
View File
@@ -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 = () => {