fix: change editor menu position on large viewport (#857)

This commit is contained in:
Aman Harwara
2022-02-10 17:36:58 +05:30
committed by GitHub
parent 78ec092bf0
commit 3b830b00d9

View File

@@ -27,7 +27,7 @@ import {
TransactionalMutation, TransactionalMutation,
} from '@standardnotes/snjs'; } from '@standardnotes/snjs';
import { FunctionComponent } from 'preact'; import { FunctionComponent } from 'preact';
import { useEffect, useRef, useState } from 'preact/hooks'; import { useEffect, useLayoutEffect, useRef, useState } from 'preact/hooks';
import { Icon } from '../Icon'; import { Icon } from '../Icon';
import { createEditorMenuGroups } from './changeEditor/createEditorMenuGroups'; import { createEditorMenuGroups } from './changeEditor/createEditorMenuGroups';
import { EditorAccordionMenu } from './changeEditor/EditorAccordionMenu'; import { EditorAccordionMenu } from './changeEditor/EditorAccordionMenu';
@@ -54,6 +54,87 @@ export type EditorMenuItem = {
export type EditorMenuGroup = AccordionMenuGroup<EditorMenuItem>; export type EditorMenuGroup = AccordionMenuGroup<EditorMenuItem>;
type MenuPositionStyle = {
top?: number | 'auto';
right?: number | 'auto';
bottom: number | 'auto';
left?: number | 'auto';
};
const calculateMenuPosition = (
button: HTMLButtonElement | null,
menu?: HTMLDivElement | null
): MenuPositionStyle | undefined => {
const defaultFontSize = window.getComputedStyle(
document.documentElement
).fontSize;
const maxChangeEditorMenuSize =
parseFloat(defaultFontSize) * MAX_MENU_SIZE_MULTIPLIER;
const { clientWidth, clientHeight } = document.documentElement;
const buttonRect = button?.getBoundingClientRect();
const buttonParentRect = button?.parentElement?.getBoundingClientRect();
const menuBoundingRect = menu?.getBoundingClientRect();
const footerElementRect = document
.getElementById('footer-bar')
?.getBoundingClientRect();
const footerHeightInPx = footerElementRect?.height ?? 0;
let position: MenuPositionStyle = {
bottom: 'auto',
};
if (buttonRect && buttonParentRect) {
let positionBottom =
clientHeight - buttonRect.bottom - buttonRect.height / 2;
if (positionBottom < footerHeightInPx) {
positionBottom = footerHeightInPx + MENU_MARGIN_FROM_APP_BORDER;
}
if (buttonRect.right + maxChangeEditorMenuSize > clientWidth) {
position = {
bottom: positionBottom,
right: clientWidth - buttonRect.left,
};
} else {
position = {
bottom: positionBottom,
left: buttonRect.right,
};
}
}
if (menuBoundingRect && buttonRect) {
if (menuBoundingRect.y < MENU_MARGIN_FROM_APP_BORDER) {
if (
buttonRect.right + maxChangeEditorMenuSize >
document.documentElement.clientWidth
) {
return {
...position,
top: MENU_MARGIN_FROM_APP_BORDER + buttonRect.top - buttonRect.height,
bottom: 'auto',
};
} else {
return {
...position,
top: MENU_MARGIN_FROM_APP_BORDER,
bottom: 'auto',
};
}
}
} else {
return position;
}
};
export const ChangeEditorOption: FunctionComponent<ChangeEditorOptionProps> = ({ export const ChangeEditorOption: FunctionComponent<ChangeEditorOptionProps> = ({
application, application,
appState, appState,
@@ -61,12 +142,8 @@ export const ChangeEditorOption: FunctionComponent<ChangeEditorOptionProps> = ({
note, note,
}) => { }) => {
const [changeEditorMenuOpen, setChangeEditorMenuOpen] = useState(false); const [changeEditorMenuOpen, setChangeEditorMenuOpen] = useState(false);
const [changeEditorMenuPosition, setChangeEditorMenuPosition] = useState<{ const [changeEditorMenuPosition, setChangeEditorMenuPosition] =
top?: number | 'auto'; useState<MenuPositionStyle>({
right?: number | 'auto';
bottom: number | 'auto';
left?: number | 'auto';
}>({
right: 0, right: 0,
bottom: 0, bottom: 0,
}); });
@@ -95,78 +172,28 @@ export const ChangeEditorOption: FunctionComponent<ChangeEditorOptionProps> = ({
}, [application, note]); }, [application, note]);
const toggleChangeEditorMenu = () => { const toggleChangeEditorMenu = () => {
const defaultFontSize = window.getComputedStyle( if (!changeEditorMenuOpen) {
document.documentElement const menuPosition = calculateMenuPosition(changeEditorButtonRef.current);
).fontSize; if (menuPosition) {
const maxChangeEditorMenuSize = setChangeEditorMenuPosition(menuPosition);
parseFloat(defaultFontSize) * MAX_MENU_SIZE_MULTIPLIER;
const { clientWidth, clientHeight } = document.documentElement;
const buttonRect = changeEditorButtonRef.current?.getBoundingClientRect();
const buttonParentRect =
changeEditorButtonRef.current?.parentElement?.getBoundingClientRect();
const footerElementRect = document
.getElementById('footer-bar')
?.getBoundingClientRect();
const footerHeightInPx = footerElementRect?.height;
if (buttonRect && buttonParentRect && footerHeightInPx) {
let positionBottom =
clientHeight - buttonRect.bottom - buttonRect.height / 2;
if (positionBottom < footerHeightInPx) {
positionBottom = footerHeightInPx + MENU_MARGIN_FROM_APP_BORDER;
}
if (buttonRect.right + maxChangeEditorMenuSize > clientWidth) {
setChangeEditorMenuPosition({
top: positionBottom - buttonParentRect.height / 2,
right: clientWidth - buttonRect.left,
bottom: 'auto',
});
} else {
setChangeEditorMenuPosition({
bottom: positionBottom,
left: buttonRect.right,
});
} }
} }
setChangeEditorMenuOpen(!changeEditorMenuOpen); setChangeEditorMenuOpen(!changeEditorMenuOpen);
}; };
useEffect(() => { useLayoutEffect(() => {
if (changeEditorMenuOpen) { if (changeEditorMenuOpen) {
const defaultFontSize = window.getComputedStyle( const newMenuPosition = calculateMenuPosition(
document.documentElement changeEditorButtonRef.current,
).fontSize; changeEditorMenuRef.current
const maxChangeEditorMenuSize = );
parseFloat(defaultFontSize) * MAX_MENU_SIZE_MULTIPLIER;
const changeEditorMenuBoundingRect =
changeEditorMenuRef.current?.getBoundingClientRect();
const buttonRect = changeEditorButtonRef.current?.getBoundingClientRect();
if (changeEditorMenuBoundingRect && buttonRect) { if (newMenuPosition) {
if (changeEditorMenuBoundingRect.y < MENU_MARGIN_FROM_APP_BORDER) { setChangeEditorMenuPosition(newMenuPosition);
if (
buttonRect.right + maxChangeEditorMenuSize >
document.documentElement.clientWidth
) {
setChangeEditorMenuPosition({
...changeEditorMenuPosition,
top: MENU_MARGIN_FROM_APP_BORDER + buttonRect.height,
bottom: 'auto',
});
} else {
setChangeEditorMenuPosition({
...changeEditorMenuPosition,
top: MENU_MARGIN_FROM_APP_BORDER,
bottom: 'auto',
});
} }
} }
} }, [changeEditorMenuOpen]);
}
}, [changeEditorMenuOpen, changeEditorMenuPosition]);
const selectComponent = async (component: SNComponent | null) => { const selectComponent = async (component: SNComponent | null) => {
if (component) { if (component) {