feat: Bind keyboard events to the current excalidraw container and add handleKeyboardGlobally prop to allow host to bind to document (#3430)
* fix: Bind keyboard events to excalidraw container * fix cases around blurring * fix modal rendering so keyboard shortcuts work on modal as well * Revert "fix modal rendering so keyboard shortcuts work on modal as well" This reverts commit 2c8ec6be8eff7d308591467fe2c33cfbca16138f. * Attach keyboard event in react way so we need not handle portals separately (modals) * dnt propagate esc event when modal shown * focus the container when help dialog closed with shift+? * focus the help icon when help dialog on close triggered * move focusNearestTabbableParent to util * rename util to focusNearestParent and remove outline from excal and modal * Add prop bindKeyGlobally to decide if keyboard events should be binded to document and allow it in excal app, revert tests * fix * focus container after installing library, reset library and closing error dialog * fix tests and create util to focus container * Add excalidraw-container class to focus on the container * pass focus container to library to focus current instance of excal * update docs * remove util as it wont be used anywhere * fix propagation not being stopped for React keyboard handling * tweak reamde Co-authored-by: David Luzar <luzar.david@gmail.com> * tweak changelog * rename prop to handleKeyboardGlobally Co-authored-by: dwelle <luzar.david@gmail.com>
This commit is contained in:
@ -72,6 +72,7 @@ interface LayerUIProps {
|
||||
viewModeEnabled: boolean;
|
||||
libraryReturnUrl: ExcalidrawProps["libraryReturnUrl"];
|
||||
UIOptions: AppProps["UIOptions"];
|
||||
focusContainer: () => void;
|
||||
}
|
||||
|
||||
const useOnClickOutside = (
|
||||
@ -111,6 +112,7 @@ const LibraryMenuItems = ({
|
||||
setAppState,
|
||||
setLibraryItems,
|
||||
libraryReturnUrl,
|
||||
focusContainer,
|
||||
}: {
|
||||
library: LibraryItems;
|
||||
pendingElements: LibraryItem;
|
||||
@ -120,6 +122,7 @@ const LibraryMenuItems = ({
|
||||
setAppState: React.Component<any, AppState>["setState"];
|
||||
setLibraryItems: (library: LibraryItems) => void;
|
||||
libraryReturnUrl: ExcalidrawProps["libraryReturnUrl"];
|
||||
focusContainer: () => void;
|
||||
}) => {
|
||||
const isMobile = useIsMobile();
|
||||
const numCells = library.length + (pendingElements.length > 0 ? 1 : 0);
|
||||
@ -178,6 +181,7 @@ const LibraryMenuItems = ({
|
||||
if (window.confirm(t("alerts.resetLibrary"))) {
|
||||
Library.resetLibrary();
|
||||
setLibraryItems([]);
|
||||
focusContainer();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
@ -242,6 +246,7 @@ const LibraryMenu = ({
|
||||
onAddToLibrary,
|
||||
setAppState,
|
||||
libraryReturnUrl,
|
||||
focusContainer,
|
||||
}: {
|
||||
pendingElements: LibraryItem;
|
||||
onClickOutside: (event: MouseEvent) => void;
|
||||
@ -249,6 +254,7 @@ const LibraryMenu = ({
|
||||
onAddToLibrary: () => void;
|
||||
setAppState: React.Component<any, AppState>["setState"];
|
||||
libraryReturnUrl: ExcalidrawProps["libraryReturnUrl"];
|
||||
focusContainer: () => void;
|
||||
}) => {
|
||||
const ref = useRef<HTMLDivElement | null>(null);
|
||||
useOnClickOutside(ref, (event) => {
|
||||
@ -322,6 +328,7 @@ const LibraryMenu = ({
|
||||
setAppState={setAppState}
|
||||
setLibraryItems={setLibraryItems}
|
||||
libraryReturnUrl={libraryReturnUrl}
|
||||
focusContainer={focusContainer}
|
||||
/>
|
||||
)}
|
||||
</Island>
|
||||
@ -347,6 +354,7 @@ const LayerUI = ({
|
||||
viewModeEnabled,
|
||||
libraryReturnUrl,
|
||||
UIOptions,
|
||||
focusContainer,
|
||||
}: LayerUIProps) => {
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
@ -517,6 +525,7 @@ const LayerUI = ({
|
||||
onAddToLibrary={deselectItems}
|
||||
setAppState={setAppState}
|
||||
libraryReturnUrl={libraryReturnUrl}
|
||||
focusContainer={focusContainer}
|
||||
/>
|
||||
) : null;
|
||||
|
||||
@ -660,7 +669,15 @@ const LayerUI = ({
|
||||
/>
|
||||
)}
|
||||
{appState.showHelpDialog && (
|
||||
<HelpDialog onClose={() => setAppState({ showHelpDialog: false })} />
|
||||
<HelpDialog
|
||||
onClose={() => {
|
||||
const helpIcon = document.querySelector(
|
||||
".help-icon",
|
||||
)! as HTMLElement;
|
||||
helpIcon.focus();
|
||||
setAppState({ showHelpDialog: false });
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{appState.pasteDialog.shown && (
|
||||
<PasteChartDialog
|
||||
|
Reference in New Issue
Block a user