feat: use improved style calculation for change editor submenu (#899)
This commit is contained in:
@@ -1,10 +1,6 @@
|
|||||||
import { KeyboardKey } from '@/services/ioService';
|
import { KeyboardKey } from '@/services/ioService';
|
||||||
import { WebApplication } from '@/ui_models/application';
|
import { WebApplication } from '@/ui_models/application';
|
||||||
import { AppState } from '@/ui_models/app_state';
|
import { AppState } from '@/ui_models/app_state';
|
||||||
import {
|
|
||||||
MENU_MARGIN_FROM_APP_BORDER,
|
|
||||||
MAX_MENU_SIZE_MULTIPLIER,
|
|
||||||
} from '@/constants';
|
|
||||||
import {
|
import {
|
||||||
Disclosure,
|
Disclosure,
|
||||||
DisclosureButton,
|
DisclosureButton,
|
||||||
@@ -21,6 +17,10 @@ import { useEffect, useRef, useState } from 'preact/hooks';
|
|||||||
import { Icon } from '../Icon';
|
import { Icon } from '../Icon';
|
||||||
import { createEditorMenuGroups } from './changeEditor/createEditorMenuGroups';
|
import { createEditorMenuGroups } from './changeEditor/createEditorMenuGroups';
|
||||||
import { ChangeEditorMenu } from './changeEditor/ChangeEditorMenu';
|
import { ChangeEditorMenu } from './changeEditor/ChangeEditorMenu';
|
||||||
|
import {
|
||||||
|
calculateSubmenuStyle,
|
||||||
|
SubmenuStyle,
|
||||||
|
} from '@/utils/calculateSubmenuStyle';
|
||||||
|
|
||||||
type ChangeEditorOptionProps = {
|
type ChangeEditorOptionProps = {
|
||||||
appState: AppState;
|
appState: AppState;
|
||||||
@@ -44,92 +44,6 @@ 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';
|
|
||||||
visibility?: 'hidden' | 'visible';
|
|
||||||
};
|
|
||||||
|
|
||||||
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,
|
|
||||||
visibility: 'hidden',
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
position = {
|
|
||||||
bottom: positionBottom,
|
|
||||||
left: buttonRect.right,
|
|
||||||
visibility: 'hidden',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (menuBoundingRect && menuBoundingRect.height && 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',
|
|
||||||
visibility: 'visible',
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
...position,
|
|
||||||
top: MENU_MARGIN_FROM_APP_BORDER,
|
|
||||||
bottom: 'auto',
|
|
||||||
visibility: 'visible',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return position;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const ChangeEditorOption: FunctionComponent<ChangeEditorOptionProps> = ({
|
export const ChangeEditorOption: FunctionComponent<ChangeEditorOptionProps> = ({
|
||||||
application,
|
application,
|
||||||
closeOnBlur,
|
closeOnBlur,
|
||||||
@@ -137,14 +51,11 @@ export const ChangeEditorOption: FunctionComponent<ChangeEditorOptionProps> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const [changeEditorMenuOpen, setChangeEditorMenuOpen] = useState(false);
|
const [changeEditorMenuOpen, setChangeEditorMenuOpen] = useState(false);
|
||||||
const [changeEditorMenuVisible, setChangeEditorMenuVisible] = useState(false);
|
const [changeEditorMenuVisible, setChangeEditorMenuVisible] = useState(false);
|
||||||
const [changeEditorMenuMaxHeight, setChangeEditorMenuMaxHeight] = useState<
|
const [menuStyle, setMenuStyle] = useState<SubmenuStyle>({
|
||||||
number | 'auto'
|
right: 0,
|
||||||
>('auto');
|
bottom: 0,
|
||||||
const [changeEditorMenuPosition, setChangeEditorMenuPosition] =
|
maxHeight: 'auto',
|
||||||
useState<MenuPositionStyle>({
|
});
|
||||||
right: 0,
|
|
||||||
bottom: 0,
|
|
||||||
});
|
|
||||||
const changeEditorMenuRef = useRef<HTMLDivElement>(null);
|
const changeEditorMenuRef = useRef<HTMLDivElement>(null);
|
||||||
const changeEditorButtonRef = useRef<HTMLButtonElement>(null);
|
const changeEditorButtonRef = useRef<HTMLButtonElement>(null);
|
||||||
const [editors] = useState<SNComponent[]>(() =>
|
const [editors] = useState<SNComponent[]>(() =>
|
||||||
@@ -171,9 +82,9 @@ export const ChangeEditorOption: FunctionComponent<ChangeEditorOptionProps> = ({
|
|||||||
|
|
||||||
const toggleChangeEditorMenu = () => {
|
const toggleChangeEditorMenu = () => {
|
||||||
if (!changeEditorMenuOpen) {
|
if (!changeEditorMenuOpen) {
|
||||||
const menuPosition = calculateMenuPosition(changeEditorButtonRef.current);
|
const menuStyle = calculateSubmenuStyle(changeEditorButtonRef.current);
|
||||||
if (menuPosition) {
|
if (menuStyle) {
|
||||||
setChangeEditorMenuPosition(menuPosition);
|
setMenuStyle(menuStyle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,32 +94,13 @@ export const ChangeEditorOption: FunctionComponent<ChangeEditorOptionProps> = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (changeEditorMenuOpen) {
|
if (changeEditorMenuOpen) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const newMenuPosition = calculateMenuPosition(
|
const newMenuStyle = calculateSubmenuStyle(
|
||||||
changeEditorButtonRef.current,
|
changeEditorButtonRef.current,
|
||||||
changeEditorMenuRef.current
|
changeEditorMenuRef.current
|
||||||
);
|
);
|
||||||
|
|
||||||
if (newMenuPosition) {
|
if (newMenuStyle) {
|
||||||
const { clientHeight } = document.documentElement;
|
setMenuStyle(newMenuStyle);
|
||||||
const footerElementRect = document
|
|
||||||
.getElementById('footer-bar')
|
|
||||||
?.getBoundingClientRect();
|
|
||||||
const footerHeightInPx = footerElementRect?.height;
|
|
||||||
|
|
||||||
if (
|
|
||||||
footerHeightInPx &&
|
|
||||||
newMenuPosition.top &&
|
|
||||||
newMenuPosition.top !== 'auto'
|
|
||||||
) {
|
|
||||||
setChangeEditorMenuMaxHeight(
|
|
||||||
clientHeight -
|
|
||||||
newMenuPosition.top -
|
|
||||||
footerHeightInPx -
|
|
||||||
MENU_MARGIN_FROM_APP_BORDER
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
setChangeEditorMenuPosition(newMenuPosition);
|
|
||||||
setChangeEditorMenuVisible(true);
|
setChangeEditorMenuVisible(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -242,8 +134,7 @@ export const ChangeEditorOption: FunctionComponent<ChangeEditorOptionProps> = ({
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
...changeEditorMenuPosition,
|
...menuStyle,
|
||||||
maxHeight: changeEditorMenuMaxHeight,
|
|
||||||
position: 'fixed',
|
position: 'fixed',
|
||||||
}}
|
}}
|
||||||
className="sn-dropdown flex flex-col max-h-120 min-w-68 fixed overflow-y-auto"
|
className="sn-dropdown flex flex-col max-h-120 min-w-68 fixed overflow-y-auto"
|
||||||
|
|||||||
Reference in New Issue
Block a user