zrmc
Version:
ZRMC is an ES7 React wrapper for Material Components Web.
225 lines (195 loc) • 9.81 kB
JavaScript
"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;