fix: change editor menu position on large viewport (#857)
This commit is contained in:
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user