diff --git a/packages/client/manifest.json b/packages/client/manifest.json index 08d614391b..2f52085e38 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -6487,7 +6487,27 @@ "illegalChildren": ["section", "sidepanel"], "showEmptyState": false, "draggable": false, - "info": "Side panels are hidden by default. They will only be revealed when triggered by the 'Open Side Panel' action." + "info": "Side panels are hidden by default. They will only be revealed when triggered by the 'Open Side Panel' action.", + "sendEvents": true, + "settings": [ + { + "type": "boolean", + "key": "clickOutsideToClose", + "label": "Click away to close", + "defaultValue": true + }, + { + "type": "event", + "key": "sidePanelOpen", + "label": "Side Panel Open" + }, + { + "type": "event", + "key": "sidePanelClose", + "label": "Side Panel Close", + "info": "Side panel actions configured here will run after the 'Open side panel' action runs, and are not capable of preventing or stopping it. Any form validation should therefore be done before that action if invoked, and not here." + } + ] }, "rowexplorer": { "block": true, diff --git a/packages/client/src/components/app/Layout.svelte b/packages/client/src/components/app/Layout.svelte index 992a166143..5b68171539 100644 --- a/packages/client/src/components/app/Layout.svelte +++ b/packages/client/src/components/app/Layout.svelte @@ -292,7 +292,11 @@ id="side-panel-container" class:open={$sidePanelStore.open} use:clickOutside={{ - callback: autoCloseSidePanel ? sidePanelStore.actions.close : null, + callback: + $sidePanelStore.clickOutsideToClose && autoCloseSidePanel + ? sidePanelStore.actions.close + : null, + allowedType: "mousedown", }} class:builder={$builderStore.inBuilder} diff --git a/packages/client/src/components/app/SidePanel.svelte b/packages/client/src/components/app/SidePanel.svelte index 825b401bb8..48c84828b0 100644 --- a/packages/client/src/components/app/SidePanel.svelte +++ b/packages/client/src/components/app/SidePanel.svelte @@ -5,6 +5,13 @@ const { styleable, sidePanelStore, builderStore, dndIsDragging } = getContext("sdk") + let handlingSidePanelOpen + let handlingSidePanelClose + + export let sidePanelOpen + export let sidePanelClose + export let clickOutsideToClose + // Automatically show and hide the side panel when inside the builder. // For some unknown reason, svelte reactivity breaks if we reference the // reactive variable "open" inside the following expression, or if we define @@ -26,6 +33,10 @@ } } + $: { + sidePanelStore.actions.setSidepanelState(clickOutsideToClose) + } + // Derive visibility $: open = $sidePanelStore.contentId === $component.id @@ -40,6 +51,22 @@ } } + const handleSidePanelOpen = async () => { + handlingSidePanelOpen = true + if (sidePanelOpen) { + await sidePanelOpen() + } + handlingSidePanelOpen = false + } + + const handleSidePanelClose = async () => { + handlingSidePanelClose = true + if (sidePanelClose) { + await sidePanelClose() + } + handlingSidePanelOpen = false + } + const showInSidePanel = (el, visible) => { const update = visible => { const target = document.getElementById("side-panel-container") @@ -47,10 +74,12 @@ if (visible) { if (!target.contains(node)) { target.appendChild(node) + handleSidePanelOpen() } } else { if (target.contains(node)) { target.removeChild(node) + handleSidePanelClose() } } } diff --git a/packages/client/src/stores/sidePanel.js b/packages/client/src/stores/sidePanel.js index 3b3b9f5f4d..df66eca01c 100644 --- a/packages/client/src/stores/sidePanel.js +++ b/packages/client/src/stores/sidePanel.js @@ -3,6 +3,7 @@ import { writable, derived } from "svelte/store" export const createSidePanelStore = () => { const initialState = { contentId: null, + clickOutsideToClose: true, } const store = writable(initialState) const derivedStore = derived(store, $store => { @@ -32,11 +33,19 @@ export const createSidePanelStore = () => { }, 50) } + const setSidepanelState = bool => { + clearTimeout(timeout) + store.update(state => { + state.clickOutsideToClose = bool + return state + }) + } return { subscribe: derivedStore.subscribe, actions: { open, close, + setSidepanelState, }, } }