Merge pull request #12584 from Budibase/fix-hover-component-spam

Massively improve performance of hovering components
This commit is contained in:
deanhannigan 2024-01-10 12:30:59 +00:00 committed by GitHub
commit a59c7c2c33
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 71 additions and 74 deletions

View File

@ -85,7 +85,6 @@ const INITIAL_FRONTEND_STATE = {
selectedScreenId: null,
selectedComponentId: null,
selectedLayoutId: null,
hoverComponentId: null,
// Client state
selectedComponentInstance: null,
@ -93,6 +92,9 @@ const INITIAL_FRONTEND_STATE = {
// Onboarding
onboarding: false,
tourNodes: null,
// UI state
hoveredComponentId: null,
}
export const getFrontendStore = () => {
@ -1413,6 +1415,18 @@ export const getFrontendStore = () => {
return state
})
},
hover: (componentId, notifyClient = true) => {
if (componentId === get(store).hoveredComponentId) {
return
}
store.update(state => {
state.hoveredComponentId = componentId
return state
})
if (notifyClient) {
store.actions.preview.sendEvent("hover-component", componentId)
}
},
},
links: {
save: async (url, title) => {

View File

@ -36,14 +36,12 @@
// Determine selected component ID
$: selectedComponentId = $store.selectedComponentId
$: hoverComponentId = $store.hoverComponentId
$: previewData = {
appId: $store.appId,
layout,
screen,
selectedComponentId,
hoverComponentId,
theme: $store.theme,
customTheme: $store.customTheme,
previewDevice: $store.previewDevice,
@ -119,8 +117,8 @@
error = event.error || "An unknown error occurred"
} else if (type === "select-component" && data.id) {
$store.selectedComponentId = data.id
} else if (type === "hover-component" && data.id) {
$store.hoverComponentId = data.id
} else if (type === "hover-component") {
store.actions.components.hover(data.id, false)
} else if (type === "update-prop") {
await store.actions.components.updateSetting(data.prop, data.value)
} else if (type === "update-styles") {

View File

@ -90,16 +90,7 @@
return findComponentPath($selectedComponent, component._id)?.length > 0
}
const handleMouseover = componentId => {
if ($store.hoverComponentId !== componentId) {
$store.hoverComponentId = componentId
}
}
const handleMouseout = componentId => {
if ($store.hoverComponentId === componentId) {
$store.hoverComponentId = null
}
}
const hover = store.actions.components.hover
</script>
<ul>
@ -120,9 +111,9 @@
on:dragover={dragover(component, index)}
on:iconClick={() => toggleNodeOpen(component._id)}
on:drop={onDrop}
hovering={$store.hoverComponentId === component._id}
on:mouseenter={() => handleMouseover(component._id)}
on:mouseleave={() => handleMouseout(component._id)}
hovering={$store.hoveredComponentId === component._id}
on:mouseenter={() => hover(component._id)}
on:mouseleave={() => hover(null)}
text={getComponentText(component)}
icon={getComponentIcon(component)}
iconTooltip={getComponentName(component)}

View File

@ -12,6 +12,9 @@
let scrolling = false
$: screenComponentId = `${$store.selectedScreenId}-screen`
$: navComponentId = `${$store.selectedScreenId}-navigation`
const toNewComponentRoute = () => {
if ($isActive(`./:componentId/new`)) {
$goto(`./:componentId`)
@ -33,16 +36,7 @@
scrolling = e.target.scrollTop !== 0
}
const handleMouseover = componentId => {
if ($store.hoverComponentId !== componentId) {
$store.hoverComponentId = componentId
}
}
const handleMouseout = componentId => {
if ($store.hoverComponentId === componentId) {
$store.hoverComponentId = null
}
}
const hover = store.actions.components.hover
</script>
<div class="components">
@ -65,46 +59,31 @@
scrollable
icon="WebPage"
on:drop={onDrop}
on:click={() => {
$store.selectedComponentId = `${$store.selectedScreenId}-screen`
}}
hovering={$store.hoverComponentId ===
`${$store.selectedScreenId}-screen`}
on:mouseenter={() =>
handleMouseover(`${$store.selectedScreenId}-screen`)}
on:mouseleave={() =>
handleMouseout(`${$store.selectedScreenId}-screen`)}
id={`component-screen`}
selectedBy={$userSelectedResourceMap[
`${$store.selectedScreenId}-screen`
]}
on:click={() => ($store.selectedComponentId = screenComponentId)}
hovering={$store.hoveredComponentId === screenComponentId}
on:mouseenter={() => hover(screenComponentId)}
on:mouseleave={() => hover(null)}
id="component-screen"
selectedBy={$userSelectedResourceMap[screenComponentId]}
>
<ScreenslotDropdownMenu component={$selectedScreen?.props} />
</NavItem>
<NavItem
text="Navigation"
indentLevel={0}
selected={$store.selectedComponentId ===
`${$store.selectedScreenId}-navigation`}
selected={$store.selectedComponentId === navComponentId}
opened
scrollable
icon={$selectedScreen.showNavigation
? "Visibility"
: "VisibilityOff"}
on:drop={onDrop}
on:click={() => {
$store.selectedComponentId = `${$store.selectedScreenId}-navigation`
}}
hovering={$store.hoverComponentId ===
`${$store.selectedScreenId}-navigation`}
on:mouseenter={() =>
handleMouseover(`${$store.selectedScreenId}-navigation`)}
on:mouseleave={() =>
handleMouseout(`${$store.selectedScreenId}-navigation`)}
id={`component-nav`}
selectedBy={$userSelectedResourceMap[
`${$store.selectedScreenId}-navigation`
]}
on:click={() => ($store.selectedComponentId = navComponentId)}
hovering={$store.hoveredComponentId === navComponentId}
on:mouseenter={() => hover(navComponentId)}
on:mouseleave={() => hover(null)}
id="component-nav"
selectedBy={$userSelectedResourceMap[navComponentId]}
/>
<ComponentTree
level={0}

View File

@ -1,9 +1,9 @@
<script>
import { onMount, onDestroy } from "svelte"
import IndicatorSet from "./IndicatorSet.svelte"
import { builderStore, dndIsDragging } from "stores"
import { builderStore, dndIsDragging, hoverStore } from "stores"
$: componentId = $builderStore.hoverComponentId
$: componentId = $hoverStore.hoveredComponentId
$: zIndex = componentId === $builderStore.selectedComponentId ? 900 : 920
const onMouseOver = e => {
@ -23,12 +23,12 @@
}
if (newId !== componentId) {
builderStore.actions.hoverComponent(newId)
hoverStore.actions.hoverComponent(newId)
}
}
const onMouseLeave = () => {
builderStore.actions.hoverComponent(null)
hoverStore.actions.hoverComponent(null)
}
onMount(() => {

View File

@ -8,6 +8,7 @@ import {
environmentStore,
dndStore,
eventStore,
hoverStore,
} from "./stores"
import loadSpectrumIcons from "@budibase/bbui/spectrum-icons-rollup.js"
import { get } from "svelte/store"
@ -33,7 +34,6 @@ const loadBudibase = async () => {
layout: window["##BUDIBASE_PREVIEW_LAYOUT##"],
screen: window["##BUDIBASE_PREVIEW_SCREEN##"],
selectedComponentId: window["##BUDIBASE_SELECTED_COMPONENT_ID##"],
hoverComponentId: window["##BUDIBASE_HOVER_COMPONENT_ID##"],
previewId: window["##BUDIBASE_PREVIEW_ID##"],
theme: window["##BUDIBASE_PREVIEW_THEME##"],
customTheme: window["##BUDIBASE_PREVIEW_CUSTOM_THEME##"],
@ -84,6 +84,8 @@ const loadBudibase = async () => {
} else {
dndStore.actions.reset()
}
} else if (type === "hover-component") {
hoverStore.actions.hoverComponent(data)
} else if (type === "builder-meta") {
builderStore.actions.setMetadata(data)
}

View File

@ -8,7 +8,6 @@ const createBuilderStore = () => {
inBuilder: false,
screen: null,
selectedComponentId: null,
hoverComponentId: null,
editMode: false,
previewId: null,
theme: null,
@ -25,16 +24,6 @@ const createBuilderStore = () => {
}
const store = writable(initialState)
const actions = {
hoverComponent: id => {
if (id === get(store).hoverComponentId) {
return
}
store.update(state => ({
...state,
hoverComponentId: id,
}))
eventStore.actions.dispatchEvent("hover-component", { id })
},
selectComponent: id => {
if (id === get(store).selectedComponentId) {
return

View File

@ -0,0 +1,25 @@
import { get, writable } from "svelte/store"
import { eventStore } from "./events.js"
const createHoverStore = () => {
const store = writable({
hoveredComponentId: null,
})
const hoverComponent = id => {
if (id === get(store).hoveredComponentId) {
return
}
store.set({ hoveredComponentId: id })
eventStore.actions.dispatchEvent("hover-component", { id })
}
return {
...store,
actions: {
hoverComponent,
},
}
}
export const hoverStore = createHoverStore()

View File

@ -27,6 +27,7 @@ export {
dndIsDragging,
} from "./dnd"
export { sidePanelStore } from "./sidePanel"
export { hoverStore } from "./hover"
// Context stores are layered and duplicated, so it is not a singleton
export { createContextStore } from "./context"

View File

@ -63,7 +63,6 @@
// Extract data from message
const {
selectedComponentId,
hoverComponentId,
layout,
screen,
appId,
@ -82,7 +81,6 @@
window["##BUDIBASE_PREVIEW_LAYOUT##"] = layout
window["##BUDIBASE_PREVIEW_SCREEN##"] = screen
window["##BUDIBASE_SELECTED_COMPONENT_ID##"] = selectedComponentId
window["##BUDIBASE_HOVER_COMPONENT_ID##"] = hoverComponentId
window["##BUDIBASE_PREVIEW_ID##"] = Math.random()
window["##BUDIBASE_PREVIEW_THEME##"] = theme
window["##BUDIBASE_PREVIEW_CUSTOM_THEME##"] = customTheme