Skip to content

Commit 95e6550

Browse files
authored
perf: improve instance selection performance (#5151)
We had a few issues - instance selector was resynced even though computed from awareness - when click in navigator both click and focus events do selection So fixed by reducing 6 or more reselections when click on instances in navigator.
1 parent bcababe commit 95e6550

5 files changed

Lines changed: 27 additions & 30 deletions

File tree

apps/builder/app/canvas/instance-hovering.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import {
33
$blockChildOutline,
44
$hoveredInstanceSelector,
55
$instances,
6-
$selectedInstanceSelector,
76
$textEditingInstanceSelector,
87
findBlockChildSelector,
98
} from "~/shared/nano-states";
@@ -15,6 +14,7 @@ import {
1514
} from "~/shared/dom-utils";
1615
import { subscribeScrollState } from "./shared/scroll-state";
1716
import { isDescendantOrSelf, type InstanceSelector } from "~/shared/tree-utils";
17+
import { $awareness } from "~/shared/awareness";
1818

1919
type TimeoutId = undefined | ReturnType<typeof setTimeout>;
2020

@@ -203,15 +203,14 @@ export const subscribeInstanceHovering = ({
203203
);
204204

205205
// selected instance selection can change hovered instance outlines (example Block/Template/Child)
206-
const usubscribeSelectedInstanceSelector =
207-
$selectedInstanceSelector.subscribe(() => {
208-
const instanceSelector = $hoveredInstanceSelector.get();
209-
if (instanceSelector) {
210-
updateHoveredRect(instanceSelector);
211-
} else {
212-
$hoveredInstanceOutline.set(undefined);
213-
}
214-
});
206+
const usubscribeSelectedInstanceSelector = $awareness.subscribe(() => {
207+
const instanceSelector = $hoveredInstanceSelector.get();
208+
if (instanceSelector) {
209+
updateHoveredRect(instanceSelector);
210+
} else {
211+
$hoveredInstanceOutline.set(undefined);
212+
}
213+
});
215214

216215
signal.addEventListener("abort", () => {
217216
unsubscribeScrollState();

apps/builder/app/canvas/instance-selected.ts

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import {
1111
$selectedInstanceRenderState,
1212
$stylesIndex,
1313
$instances,
14-
$selectedInstanceSelector,
1514
$propValuesByInstanceSelectorWithMemoryProps,
1615
$styles,
1716
$selectedInstanceStates,
@@ -33,6 +32,7 @@ import {
3332
setDataCollapsed,
3433
} from "~/canvas/collapsed";
3534
import type { InstanceSelector } from "~/shared/tree-utils";
35+
import { $awareness } from "~/shared/awareness";
3636

3737
const setOutline = (instanceId: Instance["id"], elements: HTMLElement[]) => {
3838
$selectedInstanceOutline.set({
@@ -347,17 +347,16 @@ export const subscribeSelected = (
347347
let previousSelectedInstance: readonly string[] | undefined = undefined;
348348
let unsubscribeSelectedInstance = () => {};
349349

350-
const unsubscribe = $selectedInstanceSelector.subscribe(
351-
(instanceSelector) => {
352-
if (instanceSelector !== previousSelectedInstance) {
353-
unsubscribeSelectedInstance();
354-
unsubscribeSelectedInstance =
355-
subscribeSelectedInstance(instanceSelector ?? [], debounceEffect) ??
356-
(() => {});
357-
previousSelectedInstance = instanceSelector;
358-
}
350+
const unsubscribe = $awareness.subscribe((awareness) => {
351+
const instanceSelector = awareness?.instanceSelector;
352+
if (instanceSelector !== previousSelectedInstance) {
353+
unsubscribeSelectedInstance();
354+
unsubscribeSelectedInstance =
355+
subscribeSelectedInstance(instanceSelector ?? [], debounceEffect) ??
356+
(() => {});
357+
previousSelectedInstance = instanceSelector;
359358
}
360-
);
359+
});
361360

362361
return () => {
363362
unsubscribe();

apps/builder/app/shared/awareness.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,12 @@ export const selectInstance = (
178178
instanceSelector: undefined | Instance["id"][]
179179
) => {
180180
const awareness = $awareness.get();
181-
if (awareness) {
181+
if (
182+
awareness &&
183+
// prevent triggering select across the builder when selector is the same
184+
// useful when click and focus events have to select instance
185+
awareness.instanceSelector?.join() !== instanceSelector?.join()
186+
) {
182187
$awareness.set({
183188
pageId: awareness.pageId,
184189
instanceSelector,

apps/builder/app/shared/nano-states/misc.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,8 @@ import type { TokenPermissions } from "@webstudio-is/authorization-token";
2323
import type { AssetType } from "@webstudio-is/asset-uploader";
2424
import type { DragStartPayload } from "~/canvas/shared/use-drag-drop";
2525
import { type InstanceSelector } from "../tree-utils";
26-
import { $selectedInstanceSelector } from "./instances";
2726
import type { ChildrenOrientation } from "node_modules/@webstudio-is/design-system/src/components/primitives/dnd/geometry-utils";
28-
import { $selectedInstance } from "../awareness";
27+
import { $awareness, $selectedInstance } from "../awareness";
2928
import type { UserPlanFeatures } from "../db/user-plan-features.server";
3029

3130
export const $project = atom<Project | undefined>();
@@ -92,7 +91,7 @@ export const $selectedStyleSources = atom(
9291
);
9392
export const $selectedStyleState = atom<StyleDecl["state"]>();
9493
// reset style state whenever selected instance change
95-
onSet($selectedInstanceSelector, () => {
94+
onSet($awareness, () => {
9695
$selectedStyleState.set(undefined);
9796
});
9897

apps/builder/app/shared/sync/sync-stores.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import {
1313
$styleSourceSelections,
1414
$assets,
1515
$selectedPageHash,
16-
$selectedInstanceSelector,
1716
$selectedInstanceSizes,
1817
$selectedInstanceRenderState,
1918
$hoveredInstanceSelector,
@@ -86,10 +85,6 @@ export const createObjectPool = () => {
8685
return new SyncObjectPool([
8786
new ImmerhinSyncObject("server", serverSyncStore),
8887
new ImmerhinSyncObject("client", clientSyncStore),
89-
new NanostoresSyncObject(
90-
"selectedInstanceSelector",
91-
$selectedInstanceSelector
92-
),
9388
new NanostoresSyncObject("awareness", $awareness),
9489
new NanostoresSyncObject("temporaryInstances", $temporaryInstances),
9590

0 commit comments

Comments
 (0)