jobiqo-cl
Version:
[](https://circleci.com/gh/jobiqo/jobiqo-cl)
262 lines (220 loc) • 9.31 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var React = require('react');
var React__default = _interopDefault(React);
var index$2 = require('../../utils/es/index.js');
var index = require('../../portal/es/index.js');
var index$1 = require('../../rect/es/index.js');
var index$3 = require('../node_modules/tabbable/index.js');
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
// Popover
var Popover = React.forwardRef(function Popover(props, ref) {
return React__default.createElement(index.default, null, React__default.createElement(PopoverImpl, _extends({
ref: ref
}, props)));
});
Popover.displayName = "Popover";
// PopoverImpl
// Popover is conditionally rendered so we can't start measuring until it shows
// up, so useRect needs to live down here not up in Popover
var PopoverImpl = React.forwardRef(function PopoverImpl(_ref, forwardedRef) {
var targetRef = _ref.targetRef,
_ref$position = _ref.position,
position = _ref$position === void 0 ? positionDefault : _ref$position,
style = _ref.style,
rest = _objectWithoutPropertiesLoose(_ref, ["targetRef", "position", "style"]);
var popoverRef = React.useRef();
var popoverRect = index$1.useRect(popoverRef);
var targetRect = index$1.useRect(targetRef);
var ref = index$2.useForkedRef(popoverRef, forwardedRef);
useSimulateTabNavigationForReactTree(targetRef, popoverRef);
return React__default.createElement("div", _extends({
"data-reach-popover": "",
ref: ref,
style: _extends({}, style, {
position: "absolute"
}, getStyles(position, targetRect, popoverRect))
}, rest));
});
PopoverImpl.displayName = "PopoverImpl"; ////////////////////////////////////////////////////////////////////////////////
function getStyles(position, targetRect, popoverRect) {
var needToMeasurePopup = !popoverRect;
if (needToMeasurePopup) {
return {
visibility: "hidden"
};
}
return position(targetRect, popoverRect);
}
function positionDefault(targetRect, popoverRect) {
var _getCollisions = getCollisions(targetRect, popoverRect),
directionUp = _getCollisions.directionUp,
directionRight = _getCollisions.directionRight;
return {
left: directionRight ? targetRect.right - popoverRect.width + window.pageXOffset + "px" : targetRect.left + window.pageXOffset + "px",
top: directionUp ? targetRect.top - popoverRect.height + window.pageYOffset + "px" : targetRect.top + targetRect.height + window.pageYOffset + "px"
};
}
function positionMatchWidth(targetRect, popoverRect) {
var _getCollisions2 = getCollisions(targetRect, popoverRect),
directionUp = _getCollisions2.directionUp;
return {
width: targetRect.width,
left: targetRect.left,
top: directionUp ? targetRect.top - popoverRect.height + window.pageYOffset + "px" : targetRect.top + targetRect.height + window.pageYOffset + "px"
};
} // Finish this another time
// export function positionHorizontalCenter(targetRect, popoverRect) {
// const targetCenter = targetRect.width / 2 + targetRect.left;
// const popoverHalf = popoverRect.width / 2;
// const collisions = {
// right: window.innerWidth < targetCenter - popoverHalf,
// left: targetCenter - popoverHalf < 0
// // top:
// // bottom:
// };
// return {
// left: collisions.right
// ? `${targetRect.right - popoverRect.width + window.pageXOffset}px`
// : collisions.left ? `` : ``
// };
// }
function getCollisions(targetRect, popoverRect, offsetLeft, offsetBottom) {
if (offsetLeft === void 0) {
offsetLeft = 0;
}
if (offsetBottom === void 0) {
offsetBottom = 0;
}
var collisions = {
top: targetRect.top - popoverRect.height < 0,
right: window.innerWidth < targetRect.left + popoverRect.width - offsetLeft,
bottom: window.innerHeight < targetRect.bottom + popoverRect.height - offsetBottom,
left: targetRect.left - popoverRect.width < 0
};
var directionRight = collisions.right && !collisions.left;
var directionUp = collisions.bottom && !collisions.top;
return {
directionRight: directionRight,
directionUp: directionUp
};
} // Heads up, my jQuery past haunts this function. This hook scopes the tab
// order to the React element tree, instead of the DOM tree. This way, when the
// user navigates with tab from the targetRef, the tab order moves into the
// popup, and then out of the popup back to the rest of the document.
// (We call targetRef, triggerRef inside this function to avoid confusion with
// event.target)
function useSimulateTabNavigationForReactTree(triggerRef, popoverRef) {
var doc = triggerRef.current.ownerDocument; // maybe in devtools
function handleKeyDown(event) {
if (event.key === "Tab" && index$3.default(popoverRef.current).length === 0) {
return;
}
if (event.key === "Tab" && event.shiftKey) {
if (shiftTabbedFromElementAfterTrigger(event)) {
focusLastTabbableInPopover(event);
} else if (shiftTabbedOutOfPopover(event)) {
focusTriggerRef(event);
} else if (shiftTabbedToBrowserChrome(event)) {
disableTabbablesInPopover();
}
} else if (event.key === "Tab") {
if (tabbedFromTriggerToPopover()) {
focusFirstPopoverTabbable(event);
} else if (tabbedOutOfPopover()) {
focusTabbableAfterTrigger(event);
} else if (tabbedToBrowserChrome(event)) {
disableTabbablesInPopover();
}
}
}
React.useEffect(function () {
doc.addEventListener("keydown", handleKeyDown);
return function () {
return doc.removeEventListener("keydown", handleKeyDown);
}; // eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
function getElementAfterTrigger() {
var elements = index$3.default(doc);
var targetIndex = elements.indexOf(triggerRef.current);
return elements[targetIndex + 1];
}
function tabbedFromTriggerToPopover() {
return triggerRef.current === document.activeElement;
}
function focusFirstPopoverTabbable(event) {
var elements = index$3.default(popoverRef.current);
if (elements[0]) {
event.preventDefault();
elements[0].focus();
}
}
function tabbedOutOfPopover(event) {
var inPopover = popoverRef.current.contains(document.activeElement);
if (inPopover) {
var elements = index$3.default(popoverRef.current);
return elements[elements.length - 1] === document.activeElement;
}
}
function focusTabbableAfterTrigger(event) {
var elementAfterTrigger = getElementAfterTrigger();
if (elementAfterTrigger) {
event.preventDefault();
elementAfterTrigger.focus();
}
}
function shiftTabbedFromElementAfterTrigger(event) {
if (!event.shiftKey) return;
var elementAfterTrigger = getElementAfterTrigger();
return event.target === elementAfterTrigger;
}
function focusLastTabbableInPopover(event) {
var elements = index$3.default(popoverRef.current);
var last = elements[elements.length - 1];
if (last) {
event.preventDefault();
last.focus();
}
}
function shiftTabbedOutOfPopover(event) {
var elements = index$3.default(popoverRef.current);
return elements.length === 0 ? false : event.target === elements[0];
}
function focusTriggerRef(event) {
event.preventDefault();
triggerRef.current.focus();
}
function tabbedToBrowserChrome(event) {
var elements = index$3.default(doc).filter(function (element) {
return !popoverRef.current.contains(element);
});
return event.target === elements[elements.length - 1];
}
function shiftTabbedToBrowserChrome(event) {
// we're assuming the popover will never contain the first tabbable
// element, and it better not, because the trigger needs to be tabbable!
return event.target === index$3.default(doc)[0];
}
var restoreTabIndexTuplés = [];
function disableTabbablesInPopover() {
var elements = index$3.default(popoverRef.current);
elements.forEach(function (element) {
restoreTabIndexTuplés.push([element, element.tabIndex]);
element.tabIndex = -1;
});
doc.addEventListener("focusin", enableTabbablesInPopover);
}
function enableTabbablesInPopover(event) {
doc.removeEventListener("focusin", enableTabbablesInPopover);
restoreTabIndexTuplés.forEach(function (_ref2) {
var element = _ref2[0],
tabIndex = _ref2[1];
element.tabIndex = tabIndex;
});
}
}
exports.default = Popover;
exports.positionDefault = positionDefault;
exports.positionMatchWidth = positionMatchWidth;