Skip to content

Commit

Permalink
Desktop: Improve focus handling for notebook edit, share, and sync di…
Browse files Browse the repository at this point in the history
…alogs (#10779)
  • Loading branch information
personalizedrefrigerator authored Jul 26, 2024
1 parent 3fbb3b6 commit dd5240d
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 51 deletions.
75 changes: 36 additions & 39 deletions packages/app-desktop/gui/Dialog.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,46 @@
import styled from 'styled-components';

const DialogModalLayer = styled.div`
z-index: 9999;
display: flex;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.6);
align-items: flex-start;
justify-content: center;
overflow: auto;
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
`;

const DialogRoot = styled.div`
background-color: ${props => props.theme.backgroundColor};
padding: 16px;
box-shadow: 6px 6px 20px rgba(0,0,0,0.5);
margin: 20px;
min-height: fit-content;
display: flex;
flex-direction: column;
border-radius: 10px;
`;
import * as React from 'react';
import { ReactElement, ReactEventHandler, useCallback, useEffect, useRef, useState } from 'react';

interface Props {
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
renderContent: Function;
renderContent: ()=> ReactElement;
className?: string;
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
onClose?: Function;
onClose?: ()=> void;
}

export default function Dialog(props: Props) {
const [dialogElement, setDialogRef] = useState<HTMLDialogElement>();

useEffect(() => {
if (!dialogElement) return;

// Use .showModal instead of the open attribute: .showModal correctly
// traps the keyboard focus in the dialog
dialogElement.showModal();
}, [dialogElement]);

const onCloseRef = useRef(props.onClose);
onCloseRef.current = props.onClose;

const onCancel: ReactEventHandler<HTMLDialogElement> = useCallback((event) => {
const canCancel = !!onCloseRef.current;
if (canCancel) {
// Prevents [Escape] from closing the dialog. In many places, this is handled
// elsewhere.
// See https://stackoverflow.com/a/61021326
event.preventDefault();
}
}, []);

return (
<DialogModalLayer className={props.className}>
<DialogRoot>
<dialog
ref={setDialogRef}
className={`dialog-modal-layer ${props.className}`}
onClose={props.onClose}
onCancel={onCancel}
>
<div className='content'>
{props.renderContent()}
</DialogRoot>
</DialogModalLayer>
</div>
</dialog>
);
}
4 changes: 3 additions & 1 deletion packages/app-desktop/gui/EditFolderDialog/IconSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ interface Props {
export const IconSelector = (props: Props) => {
const [emojiButtonClassReady, setEmojiButtonClassReady] = useState<boolean>(false);
const [picker, setPicker] = useState<EmojiButton>();
const buttonRef = useRef(null);
const buttonRef = useRef<HTMLButtonElement>(null);

useAsyncEffect(async (event: AsyncEffectEvent) => {
const loadScripts = async () => {
Expand Down Expand Up @@ -61,6 +61,7 @@ export const IconSelector = (props: Props) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
const p: EmojiButton = new (window as any).EmojiButton({
zIndex: 10000,
rootElement: buttonRef.current?.parentElement,
});

const onEmoji = (selection: FolderIcon) => {
Expand All @@ -73,6 +74,7 @@ export const IconSelector = (props: Props) => {

return () => {
p.off('emoji', onEmoji);
p.destroyPicker();
};
}, [emojiButtonClassReady, props.onChange]);

Expand Down
21 changes: 10 additions & 11 deletions packages/app-desktop/gui/SyncWizard/Dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -140,17 +140,16 @@ type SyncTargetInfoName = 'dropbox' | 'onedrive' | 'joplinCloud';
export default function(props: Props) {
const joplinCloudDescriptionRef = useRef(null);

// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
function closeDialog(dispatch: Function) {
dispatch({
const closeDialog = useCallback(() => {
props.dispatch({
type: 'DIALOG_CLOSE',
name: 'syncWizard',
});
}
}, [props.dispatch]);

const onButtonRowClick = useCallback(() => {
closeDialog(props.dispatch);
}, [props.dispatch]);
closeDialog();
}, [closeDialog]);

const { height: descriptionHeight } = useElementSize(joplinCloudDescriptionRef);

Expand Down Expand Up @@ -184,12 +183,12 @@ export default function(props: Props) {

Setting.setValue('sync.target', route.target);
await Setting.saveAll();
closeDialog(props.dispatch);
closeDialog();
props.dispatch({
type: 'NAV_GO',
routeName: route.name,
});
}, [props.dispatch]);
}, [props.dispatch, closeDialog]);

function renderSelectArea(info: SyncTargetInfo) {
return (
Expand Down Expand Up @@ -229,7 +228,7 @@ export default function(props: Props) {
}

const onSelfHostingClick = useCallback(() => {
closeDialog(props.dispatch);
closeDialog();

props.dispatch({
type: 'NAV_GO',
Expand All @@ -238,7 +237,7 @@ export default function(props: Props) {
defaultSection: 'sync',
},
});
}, [props.dispatch]);
}, [props.dispatch, closeDialog]);

function renderContent() {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
Expand Down Expand Up @@ -278,6 +277,6 @@ export default function(props: Props) {
}

return (
<Dialog renderContent={renderDialogWrapper}/>
<Dialog onClose={closeDialog} renderContent={renderDialogWrapper}/>
);
}
28 changes: 28 additions & 0 deletions packages/app-desktop/gui/styles/dialog-modal-layer.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

.dialog-modal-layer {
display: flex;
top: 0;
left: 0;
width: 100%;
height: 100%;
align-items: flex-start;
justify-content: center;
border: none;
margin: 0;
background-color: transparent;

> .content {
background-color: var(--joplin-background-color);
padding: 16px;
box-shadow: 6px 6px 20px rgba(0,0,0,0.5);
margin: 20px;
min-height: fit-content;
display: flex;
flex-direction: column;
border-radius: 10px;
}

&::backdrop {
background-color: rgba(0,0,0,0.6);
}
}
2 changes: 2 additions & 0 deletions packages/app-desktop/gui/styles/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

@use './dialog-modal-layer.scss';
1 change: 1 addition & 0 deletions packages/app-desktop/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@
@use 'gui/NoteListHeader/style.scss' as note-list-header;
@use 'gui/TrashNotification/style.scss' as trash-notification;
@use 'gui/Sidebar/style.scss' as sidebar-styles;
@use 'gui/styles/index.scss';
@use 'main.scss' as main;

0 comments on commit dd5240d

Please sign in to comment.