UNPKG

react-lightning-design-system

Version:

Salesforce Lightning Design System components built with React

378 lines (376 loc) 17.6 kB
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator"; import _defineProperty from "@babel/runtime/helpers/defineProperty"; import _slicedToArray from "@babel/runtime/helpers/slicedToArray"; import _regeneratorRuntime from "@babel/runtime/regenerator"; function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; import classnames from 'classnames'; import RelativePortal from 'react-relative-portal'; import { ComponentSettingsContext } from './ComponentSettings'; import { useControlledValue, useEventCallback } from './hooks'; function delay(ms) { return new Promise(function (resolve) { setTimeout(resolve, ms); }); } function getViewportRect() { var _ref = window || {}, _ref$innerHeight = _ref.innerHeight, height = _ref$innerHeight === void 0 ? Infinity : _ref$innerHeight, _ref$innerWidth = _ref.innerWidth, width = _ref$innerWidth === void 0 ? Infinity : _ref$innerWidth; return { top: 0, left: 0, width: width, height: height }; } function calcAlignmentRect(target, rect, alignment) { var _alignment = _slicedToArray(alignment, 2), firstAlign = _alignment[0], secondAlign = _alignment[1]; return _objectSpread(_objectSpread({}, rect), {}, { top: firstAlign === 'top-absolute' || secondAlign === 'top-absolute' ? 0 : firstAlign === 'bottom-absolute' || secondAlign === 'bottom-absolute' ? getViewportRect().height - rect.height : firstAlign === 'top' ? target.top + target.height : firstAlign === 'bottom' ? target.top - rect.height : secondAlign === 'top' ? target.top : secondAlign === 'bottom' ? target.top + target.height - rect.height : // valign middle target.top + (target.height - rect.height) * 0.5, left: firstAlign === 'left-absolute' || secondAlign === 'left-absolute' ? 0 : firstAlign === 'right-absolute' || secondAlign === 'right-absolute' ? getViewportRect().width - rect.width : firstAlign === 'left' ? target.left + target.width : firstAlign === 'right' ? target.left - rect.width : secondAlign === 'left' ? target.left : secondAlign === 'right' ? target.left + target.width - rect.width : // halign center target.left + (target.width - rect.width) * 0.5 }); } function hasViewportIntersection(_ref2) { var top = _ref2.top, left = _ref2.left, width = _ref2.width, height = _ref2.height; var _getViewportRect = getViewportRect(), viewportWidth = _getViewportRect.width, viewportHeight = _getViewportRect.height; return top < 0 || top + height > viewportHeight || left < 0 || left + width > viewportWidth; } function isEqualRect(aRect, bRect) { if (aRect === bRect) { return true; } if (!aRect || !bRect) { return false; } return aRect.top === bRect.top && aRect.left === bRect.left && aRect.width === bRect.width && aRect.height === bRect.height; } function getCenterPoint(rect) { return { x: rect.left + 0.5 * rect.width, y: rect.top + 0.5 * rect.height }; } function getPreferAlignment(rect) { if (!rect) { return { v: 'top', h: 'left' }; } var _getCenterPoint = getCenterPoint(rect), rx = _getCenterPoint.x, ry = _getCenterPoint.y; var _getCenterPoint2 = getCenterPoint(getViewportRect()), vx = _getCenterPoint2.x, vy = _getCenterPoint2.y; return { h: rx < vx ? 'left' : 'right', v: ry < vy ? 'top' : 'bottom' }; } function throttle(func, ms) { var last = 0; return function () { var now = Date.now(); if (last + ms < now) { func.apply(void 0, arguments); last = now; } }; } function ignoreFirstCall(func) { var called = false; return function () { if (called) { func.apply(void 0, arguments); } called = true; }; } function removeAbsoluteAlign(alignment) { return alignment.map(function (a) { return a.replace(/-absolute$/, ''); }); } function getPossibleAlignments(alignmentStyle, align, target) { var _getPreferAlignment = getPreferAlignment(target), h = _getPreferAlignment.h, v = _getPreferAlignment.v; var alignments = [['top', 'left'], ['top', 'right'], ['top'], ['bottom', 'left'], ['bottom', 'right'], ['bottom'], ['left', 'top'], ['left', 'bottom'], ['left'], ['right', 'top'], ['right', 'bottom'], ['right'], ['top', "".concat(h, "-absolute")], ['bottom', "".concat(h, "-absolute")], ['left', "".concat(v, "-absolute")], ['right', "".concat(v, "-absolute")], ["".concat(v, "-absolute"), 'left'], ["".concat(v, "-absolute"), 'right'], ["".concat(h, "-absolute"), 'top'], ["".concat(h, "-absolute"), 'bottom'], ["".concat(v, "-absolute")], ["".concat(h, "-absolute")], ["".concat(v, "-absolute"), "".concat(h, "-absolute")]]; return alignments.filter(function (_ref3) { var _ref4 = _slicedToArray(_ref3, 2), firstAlign = _ref4[0], secondAlign = _ref4[1]; return !align || firstAlign === align || secondAlign === align; }).filter(function (_ref5) { var _ref6 = _slicedToArray(_ref5, 2), firstAlign = _ref6[0], secondAlign = _ref6[1]; return alignmentStyle === 'menu' ? secondAlign && /^(top|bottom)/.test(firstAlign) : true; }); } var EMPTY_RECT = { top: 0, left: 0, width: 0, height: 0 }; /** * */ function useAutoAlign(props) { var _rootNodeRect$top, _rootNodeRect$left; var triggerSelector = props.triggerSelector, alignmentStyle = props.alignmentStyle, align = props.align, alignment_ = props.alignment; var pidRef = useRef(null); var elRef = useRef(null); var autoAlignContentRef = useRef(null); var _useControlledValue = useControlledValue(alignment_, getPossibleAlignments(alignmentStyle, align)[0]), _useControlledValue2 = _slicedToArray(_useControlledValue, 2), alignment = _useControlledValue2[0], setAlignment = _useControlledValue2[1]; var _useState = useState(), _useState2 = _slicedToArray(_useState, 2), rootNodeRect = _useState2[0], setRootNodeRect = _useState2[1]; var _useState3 = useState(), _useState4 = _slicedToArray(_useState3, 2), triggerNodeRect = _useState4[0], setTriggerNodeRect = _useState4[1]; var updateAlignment = useEventCallback(function () { var _elRef$current$getBou, _elRef$current, _autoAlignContentRef$, _autoAlignContentRef$2; var newTriggerNodeRect = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : EMPTY_RECT; var newRootNodeRect = (_elRef$current$getBou = (_elRef$current = elRef.current) === null || _elRef$current === void 0 ? void 0 : _elRef$current.getBoundingClientRect()) !== null && _elRef$current$getBou !== void 0 ? _elRef$current$getBou : EMPTY_RECT; var _ref7 = (_autoAlignContentRef$ = (_autoAlignContentRef$2 = autoAlignContentRef.current) === null || _autoAlignContentRef$2 === void 0 ? void 0 : _autoAlignContentRef$2.getBoundingClientRect()) !== null && _autoAlignContentRef$ !== void 0 ? _autoAlignContentRef$ : EMPTY_RECT, contentRectWidth = _ref7.width, contentRectHeight = _ref7.height; var newAlignment = null; var possibleAlignments = getPossibleAlignments(alignmentStyle, align, newTriggerNodeRect); var _iterator = _createForOfIteratorHelper(possibleAlignments), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var possibleAlignment = _step.value; var aRect = calcAlignmentRect(newTriggerNodeRect, { width: contentRectWidth, height: contentRectHeight }, possibleAlignment); if (!hasViewportIntersection(aRect)) { newAlignment = possibleAlignment; break; } } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } if (!newAlignment) { newAlignment = possibleAlignments[possibleAlignments.length - 1]; } if (newAlignment[0] !== alignment[0] || newAlignment[1] !== alignment[1]) { setAlignment(newAlignment); setTriggerNodeRect(newTriggerNodeRect); setRootNodeRect(newRootNodeRect); } else if (!triggerNodeRect || newTriggerNodeRect.width !== triggerNodeRect.width || newTriggerNodeRect.height !== triggerNodeRect.height || /absolute$/.test(alignment[0]) || /absolute$/.test(alignment[1] || '')) { setTriggerNodeRect(newTriggerNodeRect); setRootNodeRect(newRootNodeRect); } }); var recalcAlignment = useEventCallback(function () { var el = elRef.current; if (el) { var _ref8, _el$matches; var matches = // eslint-disable-next-line @typescript-eslint/unbound-method (_ref8 = (_el$matches = el.matches) !== null && _el$matches !== void 0 ? _el$matches : el.matchesSelector) !== null && _ref8 !== void 0 ? _ref8 : el.msMatchesSelector; var triggerEl = el; try { while (triggerEl) { if (matches.call(triggerEl, triggerSelector)) { break; } triggerEl = triggerEl.parentElement; } } catch (e) { triggerEl = null; } if (triggerEl) { var _triggerEl$getBoundin = triggerEl.getBoundingClientRect(), _top = _triggerEl$getBoundin.top, _left = _triggerEl$getBoundin.left, width = _triggerEl$getBoundin.width, height = _triggerEl$getBoundin.height; if (!isEqualRect(triggerNodeRect, { top: _top, left: _left, width: width, height: height })) { updateAlignment({ top: _top, left: _left, width: width, height: height }); } else { updateAlignment(triggerNodeRect); } } else { updateAlignment(triggerNodeRect); } } }); var requestRecalcAlignment = useMemo(function () { return throttle( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() { var _pidRef$current; var pid, _i, _arr, ms; return _regeneratorRuntime.wrap(function _callee$(_context) { while (1) switch (_context.prev = _context.next) { case 0: pid = ((_pidRef$current = pidRef.current) !== null && _pidRef$current !== void 0 ? _pidRef$current : 0) + 1; pidRef.current = pid; _i = 0, _arr = [0, 300, 400, 300, 200]; case 3: if (!(_i < _arr.length)) { _context.next = 13; break; } ms = _arr[_i]; _context.next = 7; return delay(ms); case 7: if (!(pidRef.current !== pid)) { _context.next = 9; break; } return _context.abrupt("return"); case 9: recalcAlignment(); case 10: _i++; _context.next = 3; break; case 13: pidRef.current = 0; case 14: case "end": return _context.stop(); } }, _callee); })), 100); }, [recalcAlignment]); var onScroll = useMemo(function () { return ignoreFirstCall(requestRecalcAlignment); }, [requestRecalcAlignment]); var elRefCallback = useCallback(function (el) { if (el) { elRef.current = el; requestRecalcAlignment(); } }, [requestRecalcAlignment]); useEffect(function () { return function () { pidRef.current = null; }; }, []); var _calcAlignmentRect = calcAlignmentRect(triggerNodeRect !== null && triggerNodeRect !== void 0 ? triggerNodeRect : EMPTY_RECT, rootNodeRect !== null && rootNodeRect !== void 0 ? rootNodeRect : EMPTY_RECT, alignment), top = _calcAlignmentRect.top, left_ = _calcAlignmentRect.left; var left = left_; if ((alignment[0] === 'top' || alignment[0] === 'bottom') && !alignment[1]) { var _triggerNodeRect$left, _triggerNodeRect$widt; left = ((_triggerNodeRect$left = triggerNodeRect === null || triggerNodeRect === void 0 ? void 0 : triggerNodeRect.left) !== null && _triggerNodeRect$left !== void 0 ? _triggerNodeRect$left : 0) + ((_triggerNodeRect$widt = triggerNodeRect === null || triggerNodeRect === void 0 ? void 0 : triggerNodeRect.width) !== null && _triggerNodeRect$widt !== void 0 ? _triggerNodeRect$widt : 0) * 0.5; } var offsetTop = top - ((_rootNodeRect$top = rootNodeRect === null || rootNodeRect === void 0 ? void 0 : rootNodeRect.top) !== null && _rootNodeRect$top !== void 0 ? _rootNodeRect$top : 0); var offsetLeft = left - ((_rootNodeRect$left = rootNodeRect === null || rootNodeRect === void 0 ? void 0 : rootNodeRect.left) !== null && _rootNodeRect$left !== void 0 ? _rootNodeRect$left : 0); var returnAlignment = useMemo(function () { return removeAbsoluteAlign(alignment); }, [alignment]); return { initialized: triggerNodeRect != null, alignment: returnAlignment, offsetTop: offsetTop, offsetLeft: offsetLeft, onScroll: onScroll, elRef: elRefCallback, autoAlignContentRef: autoAlignContentRef }; } /** * */ export var AutoAlign = function AutoAlign(props) { var preventPortalize = props.preventPortalize, additionalPortalClassName = props.portalClassName, _props$portalStyle = props.portalStyle, additionalPortalStyle = _props$portalStyle === void 0 ? {} : _props$portalStyle, _props$offsetX = props.offsetX, offsetX = _props$offsetX === void 0 ? 0 : _props$offsetX, _props$offsetY = props.offsetY, offsetY = _props$offsetY === void 0 ? 0 : _props$offsetY, children = props.children; var _useAutoAlign = useAutoAlign(props), initialized = _useAutoAlign.initialized, alignment = _useAutoAlign.alignment, offsetLeft = _useAutoAlign.offsetLeft, offsetTop = _useAutoAlign.offsetTop, onScroll = _useAutoAlign.onScroll, elRef = _useAutoAlign.elRef, autoAlignContentRef = _useAutoAlign.autoAlignContentRef; var compSettings = useContext(ComponentSettingsContext); var _compSettings$portalC = compSettings.portalClassName, portalClassName = _compSettings$portalC === void 0 ? 'slds-scope' : _compSettings$portalC, _compSettings$portalS = compSettings.portalStyle, portalStyle = _compSettings$portalS === void 0 ? { position: 'absolute', top: 0, left: 0, right: 0 } : _compSettings$portalS; var adjustedOffsetLeft = offsetLeft + offsetX; var adjustedOffsetTop = offsetTop + offsetY; if (typeof children !== 'function') { return /*#__PURE__*/React.isValidElement(children) ? children : /*#__PURE__*/React.createElement(React.Fragment, null, children); } var content = children({ alignment: alignment, autoAlignContentRef: autoAlignContentRef }); return preventPortalize || process.env.NODE_ENV === 'test' ? content : /*#__PURE__*/React.createElement("div", { ref: elRef }, /*#__PURE__*/React.createElement(RelativePortal, { fullWidth: true, top: adjustedOffsetTop, left: adjustedOffsetLeft, right: -adjustedOffsetLeft, onScroll: onScroll, component: "div", className: classnames(portalClassName, additionalPortalClassName), style: _objectSpread(_objectSpread({}, portalStyle), additionalPortalStyle) }, /*#__PURE__*/React.createElement(ComponentSettingsContext.Provider, { value: compSettings }, initialized ? content : /*#__PURE__*/React.createElement("div", { className: "slds-hidden" }, content)))); }; //# sourceMappingURL=AutoAlign.js.map