From f3ff1cc316af4716b4990670878f0617d2fe67bb Mon Sep 17 00:00:00 2001 From: Alex TYRODE Date: Sun, 27 Apr 2025 22:25:09 +0000 Subject: [PATCH 1/2] fix: allow scrolling over embeddables - Added CSS variable for pointer-events to manage interaction during scrolling. - Introduced lockEmbeddables function to disable pointer-events while scrolling and reset after scrolling ends using a debounced function. - Updated ExcalidrawWrapper to integrate scrolling behavior with embeddables. --- src/frontend/index.scss | 7 +++++- src/frontend/src/CustomEmbeddableRenderer.tsx | 22 +++++++++++++++++++ src/frontend/src/ExcalidrawWrapper.tsx | 5 ++++- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/frontend/index.scss b/src/frontend/index.scss index 9807f32..af2312b 100644 --- a/src/frontend/index.scss +++ b/src/frontend/index.scss @@ -7,6 +7,11 @@ font-display: swap; } +/* CSS Variables */ +:root { + --embeddable-pointer-events: all; +} + /* Override Excalidraw styles */ body { @@ -77,6 +82,6 @@ body { .excalidraw__embeddable__outer { /* 3rd layer */ padding: 0px !important; - pointer-events: all !important; + pointer-events: var(--embeddable-pointer-events, all) !important; display: flex; } diff --git a/src/frontend/src/CustomEmbeddableRenderer.tsx b/src/frontend/src/CustomEmbeddableRenderer.tsx index ee65e42..c3b3e78 100644 --- a/src/frontend/src/CustomEmbeddableRenderer.tsx +++ b/src/frontend/src/CustomEmbeddableRenderer.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { debounce } from './utils/debounce'; import type { NonDeleted, ExcalidrawEmbeddableElement } from '@atyrode/excalidraw/element/types'; import type { AppState } from '@atyrode/excalidraw/types'; import { @@ -85,3 +86,24 @@ export const renderCustomEmbeddable = ( ); } }; + +// Track scrolling state +let isScrolling = false; + +export const lockEmbeddables = (appState: AppState) => { + if (!isScrolling) { + isScrolling = true; + // Set pointer-events to none during scrolling + document.documentElement.style.setProperty('--embeddable-pointer-events', 'none'); + } + + // Reset the pointer-events after scrolling stops + debouncedScrollEnd(); +}; + +// Create a debounced function to detect when scrolling ends +const debouncedScrollEnd = debounce(() => { + isScrolling = false; + // Set pointer-events back to all when not scrolling + document.documentElement.style.setProperty('--embeddable-pointer-events', 'all'); +}, 150); // 150ms debounce seems reasonable, but can be adjusted as needed diff --git a/src/frontend/src/ExcalidrawWrapper.tsx b/src/frontend/src/ExcalidrawWrapper.tsx index 0d084c8..b2095e1 100644 --- a/src/frontend/src/ExcalidrawWrapper.tsx +++ b/src/frontend/src/ExcalidrawWrapper.tsx @@ -5,7 +5,7 @@ import type { ExcalidrawImperativeAPI } from '@atyrode/excalidraw/types'; import type { NonDeletedExcalidrawElement } from '@atyrode/excalidraw/element/types'; import type { AppState } from '@atyrode/excalidraw/types'; import { MainMenuConfig } from './ui/MainMenu'; -import { renderCustomEmbeddable } from './CustomEmbeddableRenderer'; +import { lockEmbeddables, renderCustomEmbeddable } from './CustomEmbeddableRenderer'; import AuthDialog from './ui/AuthDialog'; import BackupsModal from './ui/BackupsDialog'; @@ -25,6 +25,7 @@ interface ExcalidrawWrapperProps { setExcalidrawAPI: (api: ExcalidrawImperativeAPI) => void; initialData?: any; onChange: (elements: NonDeletedExcalidrawElement[], state: AppState) => void; + onScrollChange: (scrollX: number, scrollY: number) => void; MainMenu: any; renderTopRightUI?: () => React.ReactNode; isAuthenticated?: boolean | null; @@ -37,6 +38,7 @@ export const ExcalidrawWrapper: React.FC = ({ setExcalidrawAPI, initialData, onChange, + onScrollChange, MainMenu, renderTopRightUI, isAuthenticated = null, @@ -80,6 +82,7 @@ export const ExcalidrawWrapper: React.FC = ({ initialData: initialData ?? defaultInitialData, onChange: onChange, name: "Pad.ws", + onScrollChange: lockEmbeddables, validateEmbeddable: true, renderEmbeddable: (element, appState) => renderCustomEmbeddable(element, appState, excalidrawAPI), renderTopRightUI: renderTopRightUI ?? (() => ( From a41f654233061d2e201d998c052c064ca9eedbfd Mon Sep 17 00:00:00 2001 From: Alex TYRODE Date: Sun, 27 Apr 2025 22:29:13 +0000 Subject: [PATCH 2/2] fix: simplify lockEmbeddables function signature --- src/frontend/src/CustomEmbeddableRenderer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/src/CustomEmbeddableRenderer.tsx b/src/frontend/src/CustomEmbeddableRenderer.tsx index c3b3e78..9e6bb87 100644 --- a/src/frontend/src/CustomEmbeddableRenderer.tsx +++ b/src/frontend/src/CustomEmbeddableRenderer.tsx @@ -90,7 +90,7 @@ export const renderCustomEmbeddable = ( // Track scrolling state let isScrolling = false; -export const lockEmbeddables = (appState: AppState) => { +export const lockEmbeddables = () => { if (!isScrolling) { isScrolling = true; // Set pointer-events to none during scrolling