export type EditorDropdownButtonOptions = {
showOnHover?: boolean;
direction?: 'vertical'|'horizontal';
+ showAside?: boolean;
button: EditorBasicButtonDefinition|EditorButton;
};
const defaultOptions: EditorDropdownButtonOptions = {
showOnHover: false,
direction: 'horizontal',
+ showAside: undefined,
button: {label: 'Menu'},
}
handleDropdown({toggle: button, menu : menu,
showOnHover: this.options.showOnHover,
+ showAside: typeof this.options.showAside === 'boolean' ? this.options.showAside : (this.options.direction === 'vertical'),
onOpen : () => {
this.open = true;
this.getContext().manager.triggerStateUpdateForElement(this.button);
-
-
-
interface HandleDropdownParams {
toggle: HTMLElement;
menu: HTMLElement;
showOnHover?: boolean,
onOpen?: Function | undefined;
onClose?: Function | undefined;
+ showAside?: boolean;
+}
+
+function positionMenu(menu: HTMLElement, toggle: HTMLElement, showAside: boolean) {
+ const toggleRect = toggle.getBoundingClientRect();
+ const menuBounds = menu.getBoundingClientRect();
+
+ menu.style.position = 'fixed';
+
+ if (showAside) {
+ let targetLeft = toggleRect.right;
+ const isRightOOB = toggleRect.right + menuBounds.width > window.innerWidth;
+ if (isRightOOB) {
+ targetLeft = Math.max(toggleRect.left - menuBounds.width, 0);
+ }
+
+ menu.style.top = toggleRect.top + 'px';
+ menu.style.left = targetLeft + 'px';
+ } else {
+ const isRightOOB = toggleRect.left + menuBounds.width > window.innerWidth;
+ let targetLeft = toggleRect.left;
+ if (isRightOOB) {
+ targetLeft = Math.max(toggleRect.right - menuBounds.width, 0);
+ }
+
+ menu.style.top = toggleRect.bottom + 'px';
+ menu.style.left = targetLeft + 'px';
+ }
}
export function handleDropdown(options: HandleDropdownParams) {
- const {menu, toggle, onClose, onOpen, showOnHover} = options;
+ const {menu, toggle, onClose, onOpen, showOnHover, showAside} = options;
let clickListener: Function|null = null;
const hide = () => {
menu.hidden = true;
+ menu.style.removeProperty('position');
+ menu.style.removeProperty('left');
+ menu.style.removeProperty('top');
if (clickListener) {
window.removeEventListener('click', clickListener as EventListener);
}
const show = () => {
menu.hidden = false
+ positionMenu(menu, toggle, Boolean(showAside));
clickListener = (event: MouseEvent) => {
if (!toggle.contains(event.target as HTMLElement) && !menu.contains(event.target as HTMLElement)) {
hide();
toggle.addEventListener('mouseenter', toggleShowing);
}
- menu.parentElement?.addEventListener('mouseleave', hide);
+ menu.parentElement?.addEventListener('mouseleave', (event: MouseEvent) => {
+
+ // Prevent mouseleave hiding if withing the same bounds of the toggle.
+ // Avoids hiding in the event the mouse is interrupted by a high z-index
+ // item like a browser scrollbar.
+ const toggleBounds = toggle.getBoundingClientRect();
+ const withinX = event.clientX <= toggleBounds.right && event.clientX >= toggleBounds.left;
+ const withinY = event.clientY <= toggleBounds.bottom && event.clientY >= toggleBounds.top;
+ const withinToggle = withinX && withinY;
+
+ if (!withinToggle) {
+ hide();
+ }
+ });
}
\ No newline at end of file
new EditorOverflowContainer(4, [
new EditorButton(link),
- new EditorDropdownButton({button: table, direction: 'vertical'}, [
- new EditorDropdownButton({button: {label: 'Insert', format: 'long'}, showOnHover: true}, [
+ new EditorDropdownButton({button: table, direction: 'vertical', showAside: false}, [
+ new EditorDropdownButton({button: {label: 'Insert', format: 'long'}, showOnHover: true, showAside: true}, [
new EditorTableCreator(),
]),
new EditorSeparator(),