UNPKG

@create-figma-plugin/ui

Version:

Production-grade Preact components that replicate the Figma UI design

89 lines 3.76 kB
import { INVALID_ID, ITEM_ID_DATA_ATTRIBUTE_NAME, VIEWPORT_MARGIN } from '../../../utilities/private/constants.js'; export function updateMenuElementLayout(rootElement, menuElement, selectedId) { const rootElementBoundingClientRect = rootElement.getBoundingClientRect(); const rootWidth = rootElement.offsetWidth; const rootHeight = rootElement.offsetHeight; const rootLeft = rootElementBoundingClientRect.left; const rootTop = rootElementBoundingClientRect.top; menuElement.style.minWidth = `${rootWidth}px`; const menuElementMaxWidth = window.innerWidth - 2 * VIEWPORT_MARGIN; menuElement.style.maxWidth = `${menuElementMaxWidth}px`; const menuElementMaxHeight = window.innerHeight - 2 * VIEWPORT_MARGIN; menuElement.style.maxHeight = `${menuElementMaxHeight}px`; const menuWidth = menuElement.offsetWidth; const menuHeight = menuElement.offsetHeight; const menuScrollHeight = menuElement.scrollHeight; const menuPaddingTop = parseInt(window.getComputedStyle(menuElement).paddingTop, 10); const labelElement = getSelectedLabelElement(menuElement, selectedId); const left = computeLeft({ menuWidth, rootLeft }); menuElement.style.left = `${left}px`; const top = computeTop({ menuHeight, rootTop, selectedTop: labelElement.offsetTop }); menuElement.style.top = `${top}px`; const isScrollable = menuScrollHeight > menuHeight; if (isScrollable === false) { return; } menuElement.scrollTop = computeScrollTop({ menuHeight, menuPaddingTop, menuScrollHeight, rootHeight, rootTop, selectedTop: labelElement.offsetTop }); } function getSelectedLabelElement(menuElement, selectedId) { const inputElement = menuElement.querySelector(selectedId === INVALID_ID ? `[${ITEM_ID_DATA_ATTRIBUTE_NAME}]` : `[${ITEM_ID_DATA_ATTRIBUTE_NAME}='${selectedId}']`); if (inputElement === null) { throw new Error('`inputElement` is `null`'); } const labelElement = inputElement.parentElement; if (labelElement === null) { throw new Error('`labelElement` is `null`'); } return labelElement; } function computeLeft(options) { const { menuWidth, rootLeft } = options; if (rootLeft <= VIEWPORT_MARGIN) { return VIEWPORT_MARGIN; } const viewportWidth = window.innerWidth; if (rootLeft + menuWidth > viewportWidth - VIEWPORT_MARGIN) { return viewportWidth - VIEWPORT_MARGIN - menuWidth; } return rootLeft; } function computeTop(options) { const { menuHeight, rootTop, selectedTop } = options; const viewportHeight = window.innerHeight; if (rootTop <= VIEWPORT_MARGIN || menuHeight === viewportHeight - 2 * VIEWPORT_MARGIN) { return VIEWPORT_MARGIN; } const top = rootTop - selectedTop; const minimumTop = VIEWPORT_MARGIN; const maximumTop = viewportHeight - VIEWPORT_MARGIN - menuHeight; return restrictToRange(top, minimumTop, maximumTop); } function computeScrollTop(options) { const { menuHeight, menuPaddingTop, menuScrollHeight, rootHeight, rootTop, selectedTop } = options; const restrictedRootTop = restrictToRange(rootTop, VIEWPORT_MARGIN, window.innerHeight - VIEWPORT_MARGIN - rootHeight + menuPaddingTop / 2); const scrollTop = selectedTop - (restrictedRootTop - VIEWPORT_MARGIN); const minimumScrollTop = 0; const maximumScrollTop = menuScrollHeight - menuHeight; return restrictToRange(scrollTop, minimumScrollTop, maximumScrollTop); } function restrictToRange(number, minimum, maximum) { return Math.min(Math.max(number, minimum), maximum); } //# sourceMappingURL=update-menu-element-layout.js.map