"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PanelsResizable = void 0; var _eui = require("@elastic/eui"); var _react = require("@emotion/react"); var _lodash = require("lodash"); var _react2 = _interopRequireWildcard(require("react")); function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License * 2.0 and the Server Side Public License, v 1; you may not use this file except * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ const percentToPixels = (containerHeight, percentage) => Math.round(containerHeight * (percentage / 100)); const pixelsToPercent = (containerHeight, pixels) => pixels / containerHeight * 100; const PanelsResizable = ({ className, resizeRef, topPanelHeight, minTopPanelHeight, minMainPanelHeight, topPanel, mainPanel, onTopPanelHeightChange }) => { const topPanelId = (0, _eui.useGeneratedHtmlId)({ prefix: 'topPanel' }); const { height: containerHeight } = (0, _eui.useResizeObserver)(resizeRef.current); const [panelSizes, setPanelSizes] = (0, _react2.useState)({ topPanelSize: 0, mainPanelSize: 0 }); // EuiResizableContainer doesn't work properly when used with react-reverse-portal and // will cancel the resize. To work around this we keep track of when resizes start and // end to toggle the rendering of a transparent overlay which prevents the cancellation. // EUI issue: https://github.com/elastic/eui/issues/6199 const [resizeWithPortalsHackIsResizing, setResizeWithPortalsHackIsResizing] = (0, _react2.useState)(false); const enableResizeWithPortalsHack = (0, _react2.useCallback)(() => setResizeWithPortalsHackIsResizing(true), []); const disableResizeWithPortalsHack = (0, _react2.useCallback)(() => setResizeWithPortalsHackIsResizing(false), []); const resizeWithPortalsHackButtonCss = (0, _react.css)` z-index: 3 !important; // !important can be removed once EuiResizableButton is converted to Emotion `; const resizeWithPortalsHackOverlayCss = (0, _react.css)` position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 2; `; // We convert the top panel height from a percentage of the container height // to a pixel value and emit the change to the parent component. We also convert // the pixel value back to a percentage before updating the panel sizes to avoid // rounding issues with the isEqual check in the effect below. const onPanelSizeChange = (0, _react2.useCallback)(({ [topPanelId]: topPanelSize }) => { const newTopPanelHeight = percentToPixels(containerHeight, topPanelSize); const newTopPanelSize = pixelsToPercent(containerHeight, newTopPanelHeight); setPanelSizes({ topPanelSize: (0, _lodash.round)(newTopPanelSize, 4), mainPanelSize: (0, _lodash.round)(100 - newTopPanelSize, 4) }); onTopPanelHeightChange === null || onTopPanelHeightChange === void 0 ? void 0 : onTopPanelHeightChange(newTopPanelHeight); }, [containerHeight, onTopPanelHeightChange, topPanelId]); // This effect will update the panel sizes based on the top panel height whenever // it or the container height changes. This allows us to keep the height of the // top panel fixed when the window is resized. (0, _react2.useEffect)(() => { if (!containerHeight) { return; } let topPanelSize; let mainPanelSize; // If the container height is less than the minimum main content height // plus the current top panel height, then we need to make some adjustments. if (containerHeight < minMainPanelHeight + topPanelHeight) { const newTopPanelHeight = containerHeight - minMainPanelHeight; // Try to make the top panel height fit within the container, but if it // doesn't then just use the minimum heights. if (newTopPanelHeight < minTopPanelHeight) { topPanelSize = pixelsToPercent(containerHeight, minTopPanelHeight); mainPanelSize = pixelsToPercent(containerHeight, minMainPanelHeight); } else { topPanelSize = pixelsToPercent(containerHeight, newTopPanelHeight); mainPanelSize = 100 - topPanelSize; } } else { topPanelSize = pixelsToPercent(containerHeight, topPanelHeight); mainPanelSize = 100 - topPanelSize; } const newPanelSizes = { topPanelSize: (0, _lodash.round)(topPanelSize, 4), mainPanelSize: (0, _lodash.round)(mainPanelSize, 4) }; // Skip updating the panel sizes if they haven't changed // since onPanelSizeChange will also trigger this effect. if (!(0, _lodash.isEqual)(panelSizes, newPanelSizes)) { setPanelSizes(newPanelSizes); } }, [containerHeight, minMainPanelHeight, minTopPanelHeight, panelSizes, topPanelHeight]); const onResizeStart = (0, _react2.useCallback)(trigger => { if (trigger !== 'pointer') { return; } enableResizeWithPortalsHack(); }, [enableResizeWithPortalsHack]); const onResizeEnd = (0, _react2.useCallback)(() => { if (!resizeWithPortalsHackIsResizing) { return; } // We don't want the resize button to retain focus after the resize is complete, // but EuiResizableContainer will force focus it onClick. To work around this we // use setTimeout to wait until after onClick has been called before blurring. if (document.activeElement instanceof HTMLElement) { const button = document.activeElement; setTimeout(() => { button.blur(); }); } disableResizeWithPortalsHack(); }, [disableResizeWithPortalsHack, resizeWithPortalsHackIsResizing]); const { euiTheme } = (0, _eui.useEuiTheme)(); const buttonCss = (0, _react.css)` // The selectors here are intended to override EuiResizableButtons's Sass styles // it can be removed once EuiResizableButton has been converted to Emotion &.euiResizableButton.euiResizableButton--vertical { margin-top: -${euiTheme.size.base}; margin-bottom: 0; } `; return /*#__PURE__*/_react2.default.createElement(_eui.EuiResizableContainer, { className: className, direction: "vertical", onPanelWidthChange: onPanelSizeChange, onResizeStart: onResizeStart, onResizeEnd: onResizeEnd, "data-test-subj": "unifiedHistogramResizableContainer" }, (EuiResizablePanel, EuiResizableButton) => /*#__PURE__*/_react2.default.createElement(_react2.default.Fragment, null, /*#__PURE__*/_react2.default.createElement(EuiResizablePanel, { id: topPanelId, minSize: `${minTopPanelHeight}px`, size: panelSizes.topPanelSize, paddingSize: "none", "data-test-subj": "unifiedHistogramResizablePanelTop" }, topPanel), /*#__PURE__*/_react2.default.createElement(EuiResizableButton, { css: [resizeWithPortalsHackButtonCss, buttonCss], "data-test-subj": "unifiedHistogramResizableButton" }), /*#__PURE__*/_react2.default.createElement(EuiResizablePanel, { minSize: `${minMainPanelHeight}px`, size: panelSizes.mainPanelSize, paddingSize: "none", "data-test-subj": "unifiedHistogramResizablePanelMain" }, mainPanel), resizeWithPortalsHackIsResizing ? /*#__PURE__*/_react2.default.createElement("div", { css: resizeWithPortalsHackOverlayCss }) : /*#__PURE__*/_react2.default.createElement(_react2.default.Fragment, null))); }; exports.PanelsResizable = PanelsResizable;