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,
} from '@standardnotes/snjs';
import { FunctionComponent } from 'preact';
import { useEffect, useRef, useState } from 'preact/hooks';
import { useEffect, useLayoutEffect, useRef, useState } from 'preact/hooks';
import { Icon } from '../Icon';
import { createEditorMenuGroups } from './changeEditor/createEditorMenuGroups';
import { EditorAccordionMenu } from './changeEditor/EditorAccordionMenu';
@@ -54,6 +54,87 @@ export type 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> = ({
application,
appState,
@@ -61,15 +142,11 @@ export const ChangeEditorOption: FunctionComponent<ChangeEditorOptionProps> = ({
note,
}) => {
const [changeEditorMenuOpen, setChangeEditorMenuOpen] = useState(false);
const [changeEditorMenuPosition, setChangeEditorMenuPosition] = useState<{
top?: number | 'auto';
right?: number | 'auto';
bottom: number | 'auto';
left?: number | 'auto';
}>({
right: 0,
bottom: 0,
});
const [changeEditorMenuPosition, setChangeEditorMenuPosition] =
useState<MenuPositionStyle>({
right: 0,
bottom: 0,
});
const changeEditorMenuRef = useRef<HTMLDivElement>(null);
const changeEditorButtonRef = useRef<HTMLButtonElement>(null);
const [editors] = useState<SNComponent[]>(() =>
@@ -95,78 +172,28 @@ export const ChangeEditorOption: FunctionComponent<ChangeEditorOptionProps> = ({
}, [application, note]);
const toggleChangeEditorMenu = () => {
const defaultFontSize = window.getComputedStyle(
document.documentElement
).fontSize;
const maxChangeEditorMenuSize =
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,
});
if (!changeEditorMenuOpen) {
const menuPosition = calculateMenuPosition(changeEditorButtonRef.current);
if (menuPosition) {
setChangeEditorMenuPosition(menuPosition);
}
}
setChangeEditorMenuOpen(!changeEditorMenuOpen);
};
useEffect(() => {
useLayoutEffect(() => {
if (changeEditorMenuOpen) {
const defaultFontSize = window.getComputedStyle(
document.documentElement
).fontSize;
const maxChangeEditorMenuSize =
parseFloat(defaultFontSize) * MAX_MENU_SIZE_MULTIPLIER;
const changeEditorMenuBoundingRect =
changeEditorMenuRef.current?.getBoundingClientRect();
const buttonRect = changeEditorButtonRef.current?.getBoundingClientRect();
const newMenuPosition = calculateMenuPosition(
changeEditorButtonRef.current,
changeEditorMenuRef.current
);
if (changeEditorMenuBoundingRect && buttonRect) {
if (changeEditorMenuBoundingRect.y < MENU_MARGIN_FROM_APP_BORDER) {
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',
});
}
}
if (newMenuPosition) {
setChangeEditorMenuPosition(newMenuPosition);
}
}
}, [changeEditorMenuOpen, changeEditorMenuPosition]);
}, [changeEditorMenuOpen]);
const selectComponent = async (component: SNComponent | null) => {
if (component) {