UNPKG

zrmc

Version:

ZRMC is an ES7 React wrapper for Material Components Web.

225 lines (195 loc) 9.81 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck"); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require("babel-runtime/helpers/createClass"); var _createClass3 = _interopRequireDefault(_createClass2); var _ = require("../"); var _2 = _interopRequireDefault(_); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // From https://github.com/material-components/material-components-web/blob/master/packages/mdc-menu/constants.js var ANCHOR_TO_MENU_WIDTH_RATIO = 0.67; /** * Copyright (c) 2015-present, CWB SAS * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ var OFFSET_TO_MENU_HEIGHT_RATIO = 0.1; var MARGIN_TO_EDGE = 32; var CORNER_ORIGIN = 0; var CORNER_BOTTOM = 1; // const CORNER_CENTER = 2; var CORNER_RIGHT = 4; var CORNER_FLIP_RTL = 8; // From https://github.com/material-components/material-components-web/blob/master/packages/mdc-menu/foundation.js var RMDCMenuFoundation = function () { function RMDCMenuFoundation() { (0, _classCallCheck3.default)(this, RMDCMenuFoundation); } (0, _createClass3.default)(RMDCMenuFoundation, null, [{ key: "getAutoLayoutMeasurements", value: function getAutoLayoutMeasurements(adapter) { var anchorRect = adapter.anchorRef.getBoundingClientRect(); var menuRect = adapter.menuRef.innerRef.getBoundingClientRect(); var viewport = { width: window.innerWidth, height: window.innerHeight }; return { viewport: viewport, viewportDistance: { top: anchorRect.top, right: viewport.width - anchorRect.right, left: anchorRect.left, bottom: viewport.height - anchorRect.bottom }, anchorHeight: anchorRect.height, anchorWidth: anchorRect.width, menuHeight: menuRect.height, menuWidth: menuRect.width }; } }, { key: "getAnchorCorner", value: function getAnchorCorner(adapter) { // TODO return adapter.props.children.corner || 0; } }, { key: "getAnchorMargin", value: function getAnchorMargin(adapter) { var margin = adapter.props.children && adapter.props.children.margin || {}; return { top: margin.top || 0, bottom: margin.bottom || 0, left: margin.left || 0, right: margin.right || 0 }; } }, { key: "getOriginCorner", value: function getOriginCorner(origin, anchorMargin, anchorCorner, isRtl, _ref) { var viewportDistance = _ref.viewportDistance, anchorHeight = _ref.anchorHeight, anchorWidth = _ref.anchorWidth, menuHeight = _ref.menuHeight, menuWidth = _ref.menuWidth; var corner = origin; var isBottomAligned = Boolean(anchorCorner && CORNER_BOTTOM); var availableTop = isBottomAligned ? viewportDistance.top + anchorHeight + anchorMargin.bottom : viewportDistance.top + anchorMargin.top; var availableBottom = isBottomAligned ? viewportDistance.bottom - anchorMargin.bottom : viewportDistance.bottom + anchorHeight - anchorMargin.top; var topOverflow = menuHeight - availableTop; var bottomOverflow = menuHeight - availableBottom; if (bottomOverflow > 0 && topOverflow < bottomOverflow) { corner = corner || CORNER_BOTTOM; } var isFlipRtl = Boolean(anchorCorner && CORNER_FLIP_RTL); var avoidHorizontalOverlap = anchorCorner && CORNER_RIGHT; var isAlignedRight = Boolean(avoidHorizontalOverlap && !isRtl) || !avoidHorizontalOverlap && isFlipRtl && isRtl; var availableLeft = isAlignedRight ? viewportDistance.left + anchorWidth + anchorMargin.right : viewportDistance.left + anchorMargin.left; var availableRight = isAlignedRight ? viewportDistance.right - anchorMargin.right : viewportDistance.right + anchorWidth - anchorMargin.left; var leftOverflow = menuWidth - availableLeft; var rightOverflow = menuWidth - availableRight; if (leftOverflow < 0 && isAlignedRight && isRtl || avoidHorizontalOverlap && !isAlignedRight && leftOverflow < 0 || rightOverflow > 0 && leftOverflow < rightOverflow) { corner = corner || CORNER_RIGHT; } return corner; } }, { key: "getHorizontalOriginOffset", value: function getHorizontalOriginOffset(corner, anchorMargin, anchorCorner, _ref2) { var anchorWidth = _ref2.anchorWidth; var isRightAligned = Boolean(corner && CORNER_RIGHT); var avoidHorizontalOverlap = Boolean(anchorCorner && CORNER_RIGHT); var x = 0; if (isRightAligned) { var rightOffset = avoidHorizontalOverlap ? anchorWidth - anchorMargin.left : anchorMargin.right; x = rightOffset; } else { var leftOffset = avoidHorizontalOverlap ? anchorWidth - anchorMargin.right : anchorMargin.left; x = leftOffset; } return x; } }, { key: "getVerticalOriginOffset", value: function getVerticalOriginOffset(corner, anchorMargin, anchorCorner, _ref3) { var viewport = _ref3.viewport, viewportDistance = _ref3.viewportDistance, anchorHeight = _ref3.anchorHeight, menuHeight = _ref3.menuHeight; var isBottomAligned = Boolean(corner && CORNER_BOTTOM); var avoidVerticalOverlap = Boolean(anchorCorner && CORNER_BOTTOM); var canOverlapVertically = !avoidVerticalOverlap; var y = 0; if (isBottomAligned) { y = avoidVerticalOverlap ? anchorHeight - anchorMargin.top : -anchorMargin.bottom; // adjust for when menu can overlap anchor, but too tall to be aligned to bottom // anchor corner. Bottom margin is ignored in such cases. if (canOverlapVertically && menuHeight > viewportDistance.top + anchorHeight) { y = -(Math.min(menuHeight, viewport.height - MARGIN_TO_EDGE) - (viewportDistance.top + anchorHeight)); } } else { y = avoidVerticalOverlap ? anchorHeight + anchorMargin.bottom : anchorMargin.top; // adjust for when menu can overlap anchor, but too tall to be aligned to top // anchor corners. Top margin is ignored in that case. if (canOverlapVertically && menuHeight > viewportDistance.bottom + anchorHeight) { y = -(Math.min(menuHeight, viewport.height - MARGIN_TO_EDGE) - (viewportDistance.bottom + anchorHeight)); } } return y; } }, { key: "getMenuMaxHeight", value: function getMenuMaxHeight(corner, anchorMargin, anchorCorner, _ref4) { var viewportDistance = _ref4.viewportDistance; var maxHeight = 0; var isBottomAligned = Boolean(corner && CORNER_BOTTOM); // When maximum height is not specified, it is handled from css. if (anchorCorner && CORNER_BOTTOM) { if (isBottomAligned) { maxHeight = viewportDistance.top + anchorMargin.top; } else { maxHeight = viewportDistance.bottom - anchorMargin.bottom; } } return maxHeight; } }, { key: "autoPosition", value: function autoPosition(adapter) { // Compute measurements for autoposition methods reuse. var measures = RMDCMenuFoundation.getAutoLayoutMeasurements(adapter); var anchorMargin = RMDCMenuFoundation.getAnchorMargin(adapter); var anchorCorner = RMDCMenuFoundation.getAnchorCorner(adapter); var isRtl = _2.default.isRtl(adapter); var corner = RMDCMenuFoundation.getOriginCorner(CORNER_ORIGIN, anchorMargin, anchorCorner, isRtl, measures); var maxMenuHeight = RMDCMenuFoundation.getMenuMaxHeight(corner, anchorMargin, anchorCorner, measures); var verticalAlignment = corner && CORNER_BOTTOM ? "bottom" : "top"; var horizontalAlignment = corner && CORNER_RIGHT ? "right" : "left"; var horizontalOffset = RMDCMenuFoundation.getHorizontalOriginOffset(corner, anchorMargin, anchorCorner, measures); var verticalOffset = RMDCMenuFoundation.getVerticalOriginOffset(corner, anchorMargin, anchorCorner, measures); var h = horizontalOffset ? horizontalOffset + "px" : "0"; var v = verticalOffset ? verticalOffset + "px" : "0"; var position = horizontalAlignment + ": " + h + "; " + verticalAlignment + ": " + v + ";"; var anchorWidth = measures.anchorWidth, menuHeight = measures.menuHeight, menuWidth = measures.menuWidth; // Center align when anchor width is comparable or greater than menu, otherwise keep corner. if (anchorWidth / menuWidth > ANCHOR_TO_MENU_WIDTH_RATIO) { horizontalAlignment = "center"; } // Adjust vertical origin when menu is positioned with significant offset from anchor. // This is done so that scale animation is "anchored" on the anchor. if (!(anchorCorner && CORNER_BOTTOM) && Math.abs(verticalOffset / menuHeight) > OFFSET_TO_MENU_HEIGHT_RATIO) { var verticalOffsetPercent = Math.abs(verticalOffset / menuHeight) * 100; var originPercent = corner && CORNER_BOTTOM ? 100 - verticalOffsetPercent : verticalOffsetPercent; verticalAlignment = Math.round(originPercent * 100) / 100 + "%"; } var maxHeight = "maxHeight: " + maxMenuHeight; var transform = "transform-origin: " + horizontalAlignment + " " + verticalAlignment + ";"; return "position: absolute; " + transform + " " + position + " " + maxHeight; } }]); return RMDCMenuFoundation; }(); exports.default = RMDCMenuFoundation;