@arch-ui/modal-utils
Advanced tools
Comparing version 1.0.10 to 1.0.11
# @arch-ui/modal-utils | ||
## 1.0.11 | ||
### Patch Changes | ||
- [`a212ae6e7`](https://github.com/keystonejs/keystone/commit/a212ae6e780d36160cf6089a59601acaaadaf210) [#3131](https://github.com/keystonejs/keystone/pull/3131) Thanks [@Vultraz](https://github.com/Vultraz)! - Converted withModalHandlers to a functional component. | ||
## 1.0.10 | ||
@@ -4,0 +10,0 @@ |
@@ -22,3 +22,3 @@ 'use strict'; | ||
const transitionDurationMs = 220; | ||
const transitionDuration = "".concat(transitionDurationMs, "ms"); | ||
const transitionDuration = `${transitionDurationMs}ms`; | ||
const transitionTimingFunction = 'cubic-bezier(0.2, 0, 0, 1)'; | ||
@@ -64,3 +64,3 @@ const TransitionProvider = (_ref) => { | ||
const fade = transitionState => _objectSpread({}, makeTransitionBase('opacity'), { | ||
const fade = transitionState => _objectSpread(_objectSpread({}, makeTransitionBase('opacity')), {}, { | ||
opacity: { | ||
@@ -80,3 +80,3 @@ entering: 1, | ||
}; | ||
return _objectSpread({}, makeTransitionBase('opacity, transform'), {}, { | ||
return _objectSpread(_objectSpread({}, makeTransitionBase('opacity, transform')), { | ||
entering: { | ||
@@ -97,5 +97,5 @@ opacity: 1 | ||
opacity: 0, | ||
transform: "translate3d(0,".concat(from, ",0)") | ||
transform: `translate3d(0,${from},0)` | ||
}; | ||
return _objectSpread({}, makeTransitionBase('opacity, transform'), {}, { | ||
return _objectSpread(_objectSpread({}, makeTransitionBase('opacity, transform')), { | ||
entering: { | ||
@@ -120,3 +120,3 @@ opacity: 1 | ||
const initial = fromMap[slideInFrom]; | ||
return _objectSpread({}, makeTransitionBase('transform'), {}, { | ||
return _objectSpread(_objectSpread({}, makeTransitionBase('transform')), { | ||
entering: { | ||
@@ -129,6 +129,6 @@ transform: 'translate3d(0,0,0)' | ||
exiting: { | ||
transform: "translate3d(".concat(initial, ", 0, 0)") | ||
transform: `translate3d(${initial}, 0, 0)` | ||
}, | ||
exited: { | ||
transform: "translate3d(".concat(initial, ", 0, 0)") | ||
transform: `translate3d(${initial}, 0, 0)` | ||
} | ||
@@ -214,9 +214,7 @@ }[transitionState]); | ||
function getDisplayName(C) { | ||
return "withModalHandlers(".concat(C.displayName || C.name || 'Component', ")"); | ||
} | ||
const getDisplayName = C => { | ||
return `withModalHandlers(${C.displayName || C.name || 'Component'})`; | ||
}; | ||
const NOOP = () => {}; | ||
let Target = React.memo(function Target({ | ||
const Target = React.memo(({ | ||
isOpen, | ||
@@ -228,3 +226,3 @@ mode, | ||
toggle | ||
}) { | ||
}) => { | ||
const cloneProps = { | ||
@@ -238,75 +236,52 @@ isActive: isOpen, | ||
}); | ||
function withModalHandlers(WrappedComponent, { | ||
const withModalHandlers = (WrappedComponent, { | ||
transition | ||
}) { | ||
class IntermediateComponent extends React.Component { | ||
constructor(...args) { | ||
super(...args); | ||
}) => { | ||
return React.forwardRef((_ref, ref) => { | ||
let { | ||
defaultIsOpen = false, | ||
mode = 'click', | ||
onClose = () => {}, | ||
onOpen = () => {}, | ||
target | ||
} = _ref, | ||
props = _objectWithoutProperties(_ref, ["defaultIsOpen", "mode", "onClose", "onOpen", "target"]); | ||
_defineProperty(this, "state", { | ||
isOpen: this.props.defaultIsOpen, | ||
clientX: 0, | ||
clientY: 0 | ||
}); | ||
const [isOpen, setIsOpen] = React.useState(defaultIsOpen); // TODO: remove. Wrapped components (currently only Dropdown) use these for calculating position, | ||
// but react-popper should be used instead | ||
_defineProperty(this, "open", event => { | ||
if (event.defaultPrevented) return; | ||
if (this.props.mode === 'contextmenu') event.preventDefault(); | ||
const { | ||
clientX, | ||
clientY | ||
} = event; | ||
this.setState({ | ||
isOpen: true, | ||
clientX, | ||
clientY | ||
}); | ||
document.addEventListener('mousedown', this.handleMouseDown); | ||
document.addEventListener('keydown', this.handleKeyDown, false); | ||
}); | ||
const [clientX, setClientX] = React.useState(0); | ||
const [clientY, setClientY] = React.useState(0); | ||
const contentNode = React.useRef(); | ||
const targetNode = React.useRef(); // Expose open() and close() for via ref | ||
_defineProperty(this, "close", event => { | ||
if (event && event.defaultPrevented) return; | ||
this.setState({ | ||
isOpen: false, | ||
clientX: 0, | ||
clientY: 0 | ||
}); | ||
document.removeEventListener('mousedown', this.handleMouseDown); | ||
document.removeEventListener('keydown', this.handleKeyDown, false); | ||
}); | ||
React.useImperativeHandle(ref, () => ({ | ||
open, | ||
close | ||
})); | ||
React.useEffect(() => { | ||
// If the dialog was closed, don't do anything. The cleanup function already removed the handlers. | ||
if (!isOpen) return; | ||
_defineProperty(this, "toggle", event => { | ||
if (this.state.isOpen) { | ||
this.close(event); | ||
} else { | ||
this.open(event); | ||
} | ||
}); | ||
_defineProperty(this, "handleScroll", event => { | ||
event.preventDefault(); | ||
}); | ||
_defineProperty(this, "handleMouseDown", event => { | ||
const handleMouseDown = event => { | ||
const { | ||
target | ||
} = event; | ||
const { | ||
isOpen | ||
} = this.state; | ||
if (!(target instanceof HTMLElement) && !(target instanceof SVGElement)) { | ||
return; | ||
} // NOTE: Why not use the <Blanket /> component to close? | ||
// We don't want to interupt the user's flow. Taking this approach allows | ||
} | ||
const clickNotIn = node => !node.current.contains(target); // NOTE: Why not use the <Blanket /> component to close? | ||
// We don't want to interrupt the user's flow. Taking this approach allows | ||
// user to click "through" to other elements and close the popout. | ||
if (isOpen && !this.contentNode.contains(target) && !this.targetNode.contains(target)) { | ||
this.close(event); | ||
if (isOpen && clickNotIn(contentNode) && clickNotIn(targetNode)) { | ||
close(event); | ||
} | ||
}); | ||
}; | ||
_defineProperty(this, "handleKeyDown", event => { | ||
const handleKeyDown = event => { | ||
const { | ||
@@ -317,65 +292,77 @@ key | ||
if (key === 'Escape') { | ||
this.close(event); | ||
close(event); | ||
} | ||
}); | ||
}; | ||
_defineProperty(this, "getTarget", ref => { | ||
this.targetNode = ref; | ||
}); | ||
document.addEventListener('mousedown', handleMouseDown); | ||
document.addEventListener('keydown', handleKeyDown, false); | ||
return () => { | ||
document.removeEventListener('mousedown', handleMouseDown); | ||
document.removeEventListener('keydown', handleKeyDown, false); | ||
}; | ||
}, [isOpen]); | ||
React.useDebugValue(getDisplayName(WrappedComponent)); | ||
_defineProperty(this, "getContent", ref => { | ||
this.contentNode = ref; | ||
}); | ||
} | ||
render() { | ||
const open = event => { | ||
if (event.defaultPrevented) return; | ||
if (mode === 'contextmenu') event.preventDefault(); | ||
const { | ||
mode, | ||
onClose, | ||
onOpen, | ||
target | ||
} = this.props; | ||
const { | ||
clientX, | ||
clientY, | ||
isOpen | ||
} = this.state; | ||
return React__default.createElement(React.Fragment, null, React__default.createElement(Target, { | ||
targetRef: this.getTarget, | ||
target: target, | ||
mode: mode, | ||
isOpen: isOpen, | ||
toggle: this.toggle, | ||
open: this.open | ||
}), isOpen ? React__default.createElement(ScrollLock, null) : null, React__default.createElement(TransitionProvider, { | ||
isOpen: isOpen, | ||
onEntered: onOpen, | ||
onExited: onClose | ||
}, transitionState => React__default.createElement(WrappedComponent, _extends({ | ||
close: this.close, | ||
open: this.open, | ||
getModalRef: this.getContent, | ||
targetNode: this.targetNode, | ||
contentNode: this.contentNode, | ||
isOpen: isOpen, | ||
mouseCoords: { | ||
clientX, | ||
clientY | ||
}, | ||
style: transition(transitionState) | ||
}, this.props)))); | ||
} | ||
clientY | ||
} = event; | ||
setIsOpen(true); | ||
setClientX(clientX); | ||
setClientY(clientY); | ||
}; | ||
} | ||
const close = event => { | ||
if (event && event.defaultPrevented) return; | ||
setIsOpen(false); | ||
setClientX(0); | ||
setClientY(0); | ||
}; | ||
_defineProperty(IntermediateComponent, "defaultProps", { | ||
mode: 'click', | ||
onClose: NOOP, | ||
onOpen: NOOP | ||
const toggle = event => { | ||
if (isOpen) { | ||
close(event); | ||
} else { | ||
open(event); | ||
} | ||
}; | ||
const getTarget = ref => { | ||
targetNode.current = ref; | ||
}; | ||
const getContent = ref => { | ||
contentNode.current = ref; | ||
}; | ||
return React__default.createElement(React.Fragment, null, React__default.createElement(Target, { | ||
targetRef: getTarget, | ||
target: target, | ||
mode: mode, | ||
isOpen: isOpen, | ||
toggle: toggle, | ||
open: open | ||
}), isOpen && React__default.createElement(ScrollLock, null), React__default.createElement(TransitionProvider, { | ||
isOpen: isOpen, | ||
onEntered: onOpen, | ||
onExited: onClose | ||
}, transitionState => React__default.createElement(WrappedComponent, _extends({ | ||
close: close, | ||
open: open, | ||
getModalRef: getContent, | ||
targetNode: targetNode.current, | ||
contentNode: contentNode.current, | ||
isOpen: isOpen, | ||
mouseCoords: { | ||
clientX, | ||
clientY | ||
}, | ||
style: transition(transitionState) | ||
}, props)))); | ||
}); | ||
}; | ||
IntermediateComponent.displayName = getDisplayName(WrappedComponent); | ||
return IntermediateComponent; | ||
} | ||
function generateUEID() { | ||
@@ -382,0 +369,0 @@ let first = Math.random() * 46656 | 0; |
@@ -36,3 +36,3 @@ "use strict"; | ||
const transitionDurationMs = 220, transitionDuration = "".concat(220, "ms"), transitionTimingFunction = "cubic-bezier(0.2, 0, 0, 1)", TransitionProvider = _ref => { | ||
const transitionDurationMs = 220, transitionDuration = "220ms", transitionTimingFunction = "cubic-bezier(0.2, 0, 0, 1)", TransitionProvider = _ref => { | ||
let {children: children, isOpen: isOpen} = _ref, props = _objectWithoutProperties(_ref, [ "children", "isOpen" ]); | ||
@@ -59,3 +59,3 @@ return React__default.createElement(reactTransitionGroup.TransitionGroup, { | ||
transitionProperty: transitionProperty, | ||
transitionDuration: transitionDuration, | ||
transitionDuration: "220ms", | ||
transitionTimingFunction: transitionTimingFunction | ||
@@ -65,3 +65,3 @@ }; | ||
const fade = transitionState => _objectSpread({}, makeTransitionBase("opacity"), { | ||
const fade = transitionState => _objectSpread(_objectSpread({}, makeTransitionBase("opacity")), {}, { | ||
opacity: { | ||
@@ -78,3 +78,3 @@ entering: 1, | ||
}; | ||
return _objectSpread({}, makeTransitionBase("opacity, transform"), {}, { | ||
return _objectSpread(_objectSpread({}, makeTransitionBase("opacity, transform")), { | ||
entering: { | ||
@@ -92,5 +92,5 @@ opacity: 1 | ||
opacity: 0, | ||
transform: "translate3d(0,".concat(from, ",0)") | ||
transform: `translate3d(0,${from},0)` | ||
}; | ||
return _objectSpread({}, makeTransitionBase("opacity, transform"), {}, { | ||
return _objectSpread(_objectSpread({}, makeTransitionBase("opacity, transform")), { | ||
entering: { | ||
@@ -110,3 +110,3 @@ opacity: 1 | ||
const initial = fromMap[slideInFrom]; | ||
return _objectSpread({}, makeTransitionBase("transform"), {}, { | ||
return _objectSpread(_objectSpread({}, makeTransitionBase("transform")), { | ||
entering: { | ||
@@ -119,6 +119,6 @@ transform: "translate3d(0,0,0)" | ||
exiting: { | ||
transform: "translate3d(".concat(initial, ", 0, 0)") | ||
transform: `translate3d(${initial}, 0, 0)` | ||
}, | ||
exited: { | ||
transform: "translate3d(".concat(initial, ", 0, 0)") | ||
transform: `translate3d(${initial}, 0, 0)` | ||
} | ||
@@ -129,3 +129,3 @@ }[transitionState]); | ||
transitionProperty: "opacity, transform", | ||
transitionDuration: transitionDuration, | ||
transitionDuration: "220ms", | ||
transitionTimingFunction: transitionTimingFunction | ||
@@ -152,3 +152,3 @@ }, { | ||
transitionProperty: "opacity, transform", | ||
transitionDuration: transitionDuration, | ||
transitionDuration: "220ms", | ||
transitionTimingFunction: "cubic-bezier(0.2, 0, 0.16, 1.6)" | ||
@@ -186,11 +186,3 @@ }, { | ||
}, props)); | ||
}; | ||
function getDisplayName(C) { | ||
return "withModalHandlers(".concat(C.displayName || C.name || "Component", ")"); | ||
} | ||
const NOOP = () => {}; | ||
let Target = React.memo((function({isOpen: isOpen, mode: mode, target: target, targetRef: targetRef, open: open, toggle: toggle}) { | ||
}, getDisplayName = C => `withModalHandlers(${C.displayName || C.name || "Component"})`, Target = React.memo(({isOpen: isOpen, mode: mode, target: target, targetRef: targetRef, open: open, toggle: toggle}) => { | ||
const cloneProps = { | ||
@@ -202,80 +194,69 @@ isActive: isOpen, | ||
target(cloneProps); | ||
})); | ||
}), withModalHandlers = (WrappedComponent, {transition: transition}) => React.forwardRef((_ref, ref) => { | ||
let {defaultIsOpen: defaultIsOpen = !1, mode: mode = "click", onClose: onClose = (() => {}), onOpen: onOpen = (() => {}), target: target} = _ref, props = _objectWithoutProperties(_ref, [ "defaultIsOpen", "mode", "onClose", "onOpen", "target" ]); | ||
const [isOpen, setIsOpen] = React.useState(defaultIsOpen), [clientX, setClientX] = React.useState(0), [clientY, setClientY] = React.useState(0), contentNode = React.useRef(), targetNode = React.useRef(); | ||
var C; | ||
React.useImperativeHandle(ref, () => ({ | ||
open: open, | ||
close: close | ||
})), React.useEffect(() => { | ||
if (!isOpen) return; | ||
const handleMouseDown = event => { | ||
const {target: target} = event; | ||
if (!(target instanceof HTMLElement || target instanceof SVGElement)) return; | ||
const clickNotIn = node => !node.current.contains(target); | ||
isOpen && clickNotIn(contentNode) && clickNotIn(targetNode) && close(event); | ||
}, handleKeyDown = event => { | ||
const {key: key} = event; | ||
"Escape" === key && close(event); | ||
}; | ||
return document.addEventListener("mousedown", handleMouseDown), document.addEventListener("keydown", handleKeyDown, !1), | ||
() => { | ||
document.removeEventListener("mousedown", handleMouseDown), document.removeEventListener("keydown", handleKeyDown, !1); | ||
}; | ||
}, [ isOpen ]), React.useDebugValue(`withModalHandlers(${(C = WrappedComponent).displayName || C.name || "Component"})`); | ||
const open = event => { | ||
if (event.defaultPrevented) return; | ||
"contextmenu" === mode && event.preventDefault(); | ||
const {clientX: clientX, clientY: clientY} = event; | ||
setIsOpen(!0), setClientX(clientX), setClientY(clientY); | ||
}, close = event => { | ||
event && event.defaultPrevented || (setIsOpen(!1), setClientX(0), setClientY(0)); | ||
}, getContent = ref => { | ||
contentNode.current = ref; | ||
}; | ||
return React__default.createElement(React.Fragment, null, React__default.createElement(Target, { | ||
targetRef: ref => { | ||
targetNode.current = ref; | ||
}, | ||
target: target, | ||
mode: mode, | ||
isOpen: isOpen, | ||
toggle: event => { | ||
isOpen ? close(event) : open(event); | ||
}, | ||
open: open | ||
}), isOpen && React__default.createElement(ScrollLock, null), React__default.createElement(TransitionProvider, { | ||
isOpen: isOpen, | ||
onEntered: onOpen, | ||
onExited: onClose | ||
}, transitionState => React__default.createElement(WrappedComponent, _extends({ | ||
close: close, | ||
open: open, | ||
getModalRef: getContent, | ||
targetNode: targetNode.current, | ||
contentNode: contentNode.current, | ||
isOpen: isOpen, | ||
mouseCoords: { | ||
clientX: clientX, | ||
clientY: clientY | ||
}, | ||
style: transition(transitionState) | ||
}, props)))); | ||
}); | ||
function withModalHandlers(WrappedComponent, {transition: transition}) { | ||
class IntermediateComponent extends React.Component { | ||
constructor(...args) { | ||
super(...args), _defineProperty(this, "state", { | ||
isOpen: this.props.defaultIsOpen, | ||
clientX: 0, | ||
clientY: 0 | ||
}), _defineProperty(this, "open", event => { | ||
if (event.defaultPrevented) return; | ||
"contextmenu" === this.props.mode && event.preventDefault(); | ||
const {clientX: clientX, clientY: clientY} = event; | ||
this.setState({ | ||
isOpen: !0, | ||
clientX: clientX, | ||
clientY: clientY | ||
}), document.addEventListener("mousedown", this.handleMouseDown), document.addEventListener("keydown", this.handleKeyDown, !1); | ||
}), _defineProperty(this, "close", event => { | ||
event && event.defaultPrevented || (this.setState({ | ||
isOpen: !1, | ||
clientX: 0, | ||
clientY: 0 | ||
}), document.removeEventListener("mousedown", this.handleMouseDown), document.removeEventListener("keydown", this.handleKeyDown, !1)); | ||
}), _defineProperty(this, "toggle", event => { | ||
this.state.isOpen ? this.close(event) : this.open(event); | ||
}), _defineProperty(this, "handleScroll", event => { | ||
event.preventDefault(); | ||
}), _defineProperty(this, "handleMouseDown", event => { | ||
const {target: target} = event, {isOpen: isOpen} = this.state; | ||
(target instanceof HTMLElement || target instanceof SVGElement) && (!isOpen || this.contentNode.contains(target) || this.targetNode.contains(target) || this.close(event)); | ||
}), _defineProperty(this, "handleKeyDown", event => { | ||
const {key: key} = event; | ||
"Escape" === key && this.close(event); | ||
}), _defineProperty(this, "getTarget", ref => { | ||
this.targetNode = ref; | ||
}), _defineProperty(this, "getContent", ref => { | ||
this.contentNode = ref; | ||
}); | ||
} | ||
render() { | ||
const {mode: mode, onClose: onClose, onOpen: onOpen, target: target} = this.props, {clientX: clientX, clientY: clientY, isOpen: isOpen} = this.state; | ||
return React__default.createElement(React.Fragment, null, React__default.createElement(Target, { | ||
targetRef: this.getTarget, | ||
target: target, | ||
mode: mode, | ||
isOpen: isOpen, | ||
toggle: this.toggle, | ||
open: this.open | ||
}), isOpen ? React__default.createElement(ScrollLock, null) : null, React__default.createElement(TransitionProvider, { | ||
isOpen: isOpen, | ||
onEntered: onOpen, | ||
onExited: onClose | ||
}, transitionState => React__default.createElement(WrappedComponent, _extends({ | ||
close: this.close, | ||
open: this.open, | ||
getModalRef: this.getContent, | ||
targetNode: this.targetNode, | ||
contentNode: this.contentNode, | ||
isOpen: isOpen, | ||
mouseCoords: { | ||
clientX: clientX, | ||
clientY: clientY | ||
}, | ||
style: transition(transitionState) | ||
}, this.props)))); | ||
} | ||
} | ||
return _defineProperty(IntermediateComponent, "defaultProps", { | ||
mode: "click", | ||
onClose: NOOP, | ||
onOpen: NOOP | ||
}), IntermediateComponent.displayName = getDisplayName(WrappedComponent), IntermediateComponent; | ||
} | ||
function generateUEID() { | ||
let first = 46656 * Math.random() | 0, second = 46656 * Math.random() | 0; | ||
return (first = ("000" + first.toString(36)).slice(-3)) + (second = ("000" + second.toString(36)).slice(-3)); | ||
return first = ("000" + first.toString(36)).slice(-3), second = ("000" + second.toString(36)).slice(-3), | ||
first + second; | ||
} | ||
@@ -282,0 +263,0 @@ |
import _defineProperty from '@babel/runtime/helpers/esm/defineProperty'; | ||
import _extends from '@babel/runtime/helpers/esm/extends'; | ||
import _objectWithoutProperties from '@babel/runtime/helpers/esm/objectWithoutProperties'; | ||
import React, { memo, Component, Fragment } from 'react'; | ||
import React, { memo, forwardRef, useState, useRef, useImperativeHandle, useEffect, useDebugValue, Fragment } from 'react'; | ||
import { TransitionGroup, Transition } from 'react-transition-group'; | ||
@@ -15,3 +15,3 @@ import { jsx } from '@emotion/core'; | ||
const transitionDurationMs = 220; | ||
const transitionDuration = "".concat(transitionDurationMs, "ms"); | ||
const transitionDuration = `${transitionDurationMs}ms`; | ||
const transitionTimingFunction = 'cubic-bezier(0.2, 0, 0, 1)'; | ||
@@ -57,3 +57,3 @@ const TransitionProvider = (_ref) => { | ||
const fade = transitionState => _objectSpread({}, makeTransitionBase('opacity'), { | ||
const fade = transitionState => _objectSpread(_objectSpread({}, makeTransitionBase('opacity')), {}, { | ||
opacity: { | ||
@@ -73,3 +73,3 @@ entering: 1, | ||
}; | ||
return _objectSpread({}, makeTransitionBase('opacity, transform'), {}, { | ||
return _objectSpread(_objectSpread({}, makeTransitionBase('opacity, transform')), { | ||
entering: { | ||
@@ -90,5 +90,5 @@ opacity: 1 | ||
opacity: 0, | ||
transform: "translate3d(0,".concat(from, ",0)") | ||
transform: `translate3d(0,${from},0)` | ||
}; | ||
return _objectSpread({}, makeTransitionBase('opacity, transform'), {}, { | ||
return _objectSpread(_objectSpread({}, makeTransitionBase('opacity, transform')), { | ||
entering: { | ||
@@ -113,3 +113,3 @@ opacity: 1 | ||
const initial = fromMap[slideInFrom]; | ||
return _objectSpread({}, makeTransitionBase('transform'), {}, { | ||
return _objectSpread(_objectSpread({}, makeTransitionBase('transform')), { | ||
entering: { | ||
@@ -122,6 +122,6 @@ transform: 'translate3d(0,0,0)' | ||
exiting: { | ||
transform: "translate3d(".concat(initial, ", 0, 0)") | ||
transform: `translate3d(${initial}, 0, 0)` | ||
}, | ||
exited: { | ||
transform: "translate3d(".concat(initial, ", 0, 0)") | ||
transform: `translate3d(${initial}, 0, 0)` | ||
} | ||
@@ -207,9 +207,7 @@ }[transitionState]); | ||
function getDisplayName(C) { | ||
return "withModalHandlers(".concat(C.displayName || C.name || 'Component', ")"); | ||
} | ||
const getDisplayName = C => { | ||
return `withModalHandlers(${C.displayName || C.name || 'Component'})`; | ||
}; | ||
const NOOP = () => {}; | ||
let Target = memo(function Target({ | ||
const Target = memo(({ | ||
isOpen, | ||
@@ -221,3 +219,3 @@ mode, | ||
toggle | ||
}) { | ||
}) => { | ||
const cloneProps = { | ||
@@ -231,75 +229,52 @@ isActive: isOpen, | ||
}); | ||
function withModalHandlers(WrappedComponent, { | ||
const withModalHandlers = (WrappedComponent, { | ||
transition | ||
}) { | ||
class IntermediateComponent extends Component { | ||
constructor(...args) { | ||
super(...args); | ||
}) => { | ||
return forwardRef((_ref, ref) => { | ||
let { | ||
defaultIsOpen = false, | ||
mode = 'click', | ||
onClose = () => {}, | ||
onOpen = () => {}, | ||
target | ||
} = _ref, | ||
props = _objectWithoutProperties(_ref, ["defaultIsOpen", "mode", "onClose", "onOpen", "target"]); | ||
_defineProperty(this, "state", { | ||
isOpen: this.props.defaultIsOpen, | ||
clientX: 0, | ||
clientY: 0 | ||
}); | ||
const [isOpen, setIsOpen] = useState(defaultIsOpen); // TODO: remove. Wrapped components (currently only Dropdown) use these for calculating position, | ||
// but react-popper should be used instead | ||
_defineProperty(this, "open", event => { | ||
if (event.defaultPrevented) return; | ||
if (this.props.mode === 'contextmenu') event.preventDefault(); | ||
const { | ||
clientX, | ||
clientY | ||
} = event; | ||
this.setState({ | ||
isOpen: true, | ||
clientX, | ||
clientY | ||
}); | ||
document.addEventListener('mousedown', this.handleMouseDown); | ||
document.addEventListener('keydown', this.handleKeyDown, false); | ||
}); | ||
const [clientX, setClientX] = useState(0); | ||
const [clientY, setClientY] = useState(0); | ||
const contentNode = useRef(); | ||
const targetNode = useRef(); // Expose open() and close() for via ref | ||
_defineProperty(this, "close", event => { | ||
if (event && event.defaultPrevented) return; | ||
this.setState({ | ||
isOpen: false, | ||
clientX: 0, | ||
clientY: 0 | ||
}); | ||
document.removeEventListener('mousedown', this.handleMouseDown); | ||
document.removeEventListener('keydown', this.handleKeyDown, false); | ||
}); | ||
useImperativeHandle(ref, () => ({ | ||
open, | ||
close | ||
})); | ||
useEffect(() => { | ||
// If the dialog was closed, don't do anything. The cleanup function already removed the handlers. | ||
if (!isOpen) return; | ||
_defineProperty(this, "toggle", event => { | ||
if (this.state.isOpen) { | ||
this.close(event); | ||
} else { | ||
this.open(event); | ||
} | ||
}); | ||
_defineProperty(this, "handleScroll", event => { | ||
event.preventDefault(); | ||
}); | ||
_defineProperty(this, "handleMouseDown", event => { | ||
const handleMouseDown = event => { | ||
const { | ||
target | ||
} = event; | ||
const { | ||
isOpen | ||
} = this.state; | ||
if (!(target instanceof HTMLElement) && !(target instanceof SVGElement)) { | ||
return; | ||
} // NOTE: Why not use the <Blanket /> component to close? | ||
// We don't want to interupt the user's flow. Taking this approach allows | ||
} | ||
const clickNotIn = node => !node.current.contains(target); // NOTE: Why not use the <Blanket /> component to close? | ||
// We don't want to interrupt the user's flow. Taking this approach allows | ||
// user to click "through" to other elements and close the popout. | ||
if (isOpen && !this.contentNode.contains(target) && !this.targetNode.contains(target)) { | ||
this.close(event); | ||
if (isOpen && clickNotIn(contentNode) && clickNotIn(targetNode)) { | ||
close(event); | ||
} | ||
}); | ||
}; | ||
_defineProperty(this, "handleKeyDown", event => { | ||
const handleKeyDown = event => { | ||
const { | ||
@@ -310,65 +285,77 @@ key | ||
if (key === 'Escape') { | ||
this.close(event); | ||
close(event); | ||
} | ||
}); | ||
}; | ||
_defineProperty(this, "getTarget", ref => { | ||
this.targetNode = ref; | ||
}); | ||
document.addEventListener('mousedown', handleMouseDown); | ||
document.addEventListener('keydown', handleKeyDown, false); | ||
return () => { | ||
document.removeEventListener('mousedown', handleMouseDown); | ||
document.removeEventListener('keydown', handleKeyDown, false); | ||
}; | ||
}, [isOpen]); | ||
useDebugValue(getDisplayName(WrappedComponent)); | ||
_defineProperty(this, "getContent", ref => { | ||
this.contentNode = ref; | ||
}); | ||
} | ||
render() { | ||
const open = event => { | ||
if (event.defaultPrevented) return; | ||
if (mode === 'contextmenu') event.preventDefault(); | ||
const { | ||
mode, | ||
onClose, | ||
onOpen, | ||
target | ||
} = this.props; | ||
const { | ||
clientX, | ||
clientY, | ||
isOpen | ||
} = this.state; | ||
return React.createElement(Fragment, null, React.createElement(Target, { | ||
targetRef: this.getTarget, | ||
target: target, | ||
mode: mode, | ||
isOpen: isOpen, | ||
toggle: this.toggle, | ||
open: this.open | ||
}), isOpen ? React.createElement(ScrollLock, null) : null, React.createElement(TransitionProvider, { | ||
isOpen: isOpen, | ||
onEntered: onOpen, | ||
onExited: onClose | ||
}, transitionState => React.createElement(WrappedComponent, _extends({ | ||
close: this.close, | ||
open: this.open, | ||
getModalRef: this.getContent, | ||
targetNode: this.targetNode, | ||
contentNode: this.contentNode, | ||
isOpen: isOpen, | ||
mouseCoords: { | ||
clientX, | ||
clientY | ||
}, | ||
style: transition(transitionState) | ||
}, this.props)))); | ||
} | ||
clientY | ||
} = event; | ||
setIsOpen(true); | ||
setClientX(clientX); | ||
setClientY(clientY); | ||
}; | ||
} | ||
const close = event => { | ||
if (event && event.defaultPrevented) return; | ||
setIsOpen(false); | ||
setClientX(0); | ||
setClientY(0); | ||
}; | ||
_defineProperty(IntermediateComponent, "defaultProps", { | ||
mode: 'click', | ||
onClose: NOOP, | ||
onOpen: NOOP | ||
const toggle = event => { | ||
if (isOpen) { | ||
close(event); | ||
} else { | ||
open(event); | ||
} | ||
}; | ||
const getTarget = ref => { | ||
targetNode.current = ref; | ||
}; | ||
const getContent = ref => { | ||
contentNode.current = ref; | ||
}; | ||
return React.createElement(Fragment, null, React.createElement(Target, { | ||
targetRef: getTarget, | ||
target: target, | ||
mode: mode, | ||
isOpen: isOpen, | ||
toggle: toggle, | ||
open: open | ||
}), isOpen && React.createElement(ScrollLock, null), React.createElement(TransitionProvider, { | ||
isOpen: isOpen, | ||
onEntered: onOpen, | ||
onExited: onClose | ||
}, transitionState => React.createElement(WrappedComponent, _extends({ | ||
close: close, | ||
open: open, | ||
getModalRef: getContent, | ||
targetNode: targetNode.current, | ||
contentNode: contentNode.current, | ||
isOpen: isOpen, | ||
mouseCoords: { | ||
clientX, | ||
clientY | ||
}, | ||
style: transition(transitionState) | ||
}, props)))); | ||
}); | ||
}; | ||
IntermediateComponent.displayName = getDisplayName(WrappedComponent); | ||
return IntermediateComponent; | ||
} | ||
function generateUEID() { | ||
@@ -375,0 +362,0 @@ let first = Math.random() * 46656 | 0; |
{ | ||
"name": "@arch-ui/modal-utils", | ||
"description": "Modal Utilities as used in @keystonejs Admin UI.", | ||
"version": "1.0.10", | ||
"version": "1.0.11", | ||
"author": "Jed Watson", | ||
@@ -6,0 +6,0 @@ "license": "MIT", |
@@ -1,11 +0,19 @@ | ||
import React, { Component, Fragment, memo } from 'react'; | ||
import React, { | ||
Fragment, | ||
memo, | ||
forwardRef, | ||
useState, | ||
useDebugValue, | ||
useEffect, | ||
useRef, | ||
useImperativeHandle, | ||
} from 'react'; | ||
import ScrollLock from 'react-scrolllock'; | ||
import { TransitionProvider } from './transitions'; | ||
function getDisplayName(C) { | ||
const getDisplayName = C => { | ||
return `withModalHandlers(${C.displayName || C.name || 'Component'})`; | ||
} | ||
const NOOP = () => {}; | ||
}; | ||
let Target = memo(function Target({ isOpen, mode, target, targetRef, open, toggle }) { | ||
const Target = memo(({ isOpen, mode, target, targetRef, open, toggle }) => { | ||
const cloneProps = { isActive: isOpen, ref: targetRef }; | ||
@@ -17,99 +25,126 @@ if (mode === 'click') cloneProps.onClick = toggle; | ||
export default function withModalHandlers(WrappedComponent, { transition }) { | ||
class IntermediateComponent extends Component { | ||
state = { isOpen: this.props.defaultIsOpen, clientX: 0, clientY: 0 }; | ||
static defaultProps = { | ||
mode: 'click', | ||
onClose: NOOP, | ||
onOpen: NOOP, | ||
}; | ||
const withModalHandlers = (WrappedComponent, { transition }) => { | ||
return forwardRef( | ||
( | ||
{ | ||
defaultIsOpen = false, | ||
mode = 'click', | ||
onClose = () => {}, | ||
onOpen = () => {}, | ||
target, | ||
...props | ||
}, | ||
ref | ||
) => { | ||
const [isOpen, setIsOpen] = useState(defaultIsOpen); | ||
open = event => { | ||
if (event.defaultPrevented) return; | ||
if (this.props.mode === 'contextmenu') event.preventDefault(); | ||
// TODO: remove. Wrapped components (currently only Dropdown) use these for calculating position, | ||
// but react-popper should be used instead | ||
const [clientX, setClientX] = useState(0); | ||
const [clientY, setClientY] = useState(0); | ||
const { clientX, clientY } = event; | ||
const contentNode = useRef(); | ||
const targetNode = useRef(); | ||
this.setState({ isOpen: true, clientX, clientY }); | ||
// Expose open() and close() for via ref | ||
useImperativeHandle(ref, () => ({ open, close })); | ||
document.addEventListener('mousedown', this.handleMouseDown); | ||
document.addEventListener('keydown', this.handleKeyDown, false); | ||
}; | ||
close = event => { | ||
if (event && event.defaultPrevented) return; | ||
useEffect(() => { | ||
// If the dialog was closed, don't do anything. The cleanup function already removed the handlers. | ||
if (!isOpen) return; | ||
this.setState({ isOpen: false, clientX: 0, clientY: 0 }); | ||
const handleMouseDown = event => { | ||
const { target } = event; | ||
document.removeEventListener('mousedown', this.handleMouseDown); | ||
document.removeEventListener('keydown', this.handleKeyDown, false); | ||
}; | ||
if (!(target instanceof HTMLElement) && !(target instanceof SVGElement)) { | ||
return; | ||
} | ||
toggle = event => { | ||
if (this.state.isOpen) { | ||
this.close(event); | ||
} else { | ||
this.open(event); | ||
} | ||
}; | ||
const clickNotIn = node => !node.current.contains(target); | ||
handleScroll = event => { | ||
event.preventDefault(); | ||
}; | ||
handleMouseDown = event => { | ||
const { target } = event; | ||
const { isOpen } = this.state; | ||
// NOTE: Why not use the <Blanket /> component to close? | ||
// We don't want to interrupt the user's flow. Taking this approach allows | ||
// user to click "through" to other elements and close the popout. | ||
if (isOpen && clickNotIn(contentNode) && clickNotIn(targetNode)) { | ||
close(event); | ||
} | ||
}; | ||
if (!(target instanceof HTMLElement) && !(target instanceof SVGElement)) { | ||
return; | ||
} | ||
const handleKeyDown = event => { | ||
const { key } = event; | ||
// NOTE: Why not use the <Blanket /> component to close? | ||
// We don't want to interupt the user's flow. Taking this approach allows | ||
// user to click "through" to other elements and close the popout. | ||
if (isOpen && !this.contentNode.contains(target) && !this.targetNode.contains(target)) { | ||
this.close(event); | ||
} | ||
}; | ||
handleKeyDown = event => { | ||
const { key } = event; | ||
if (key === 'Escape') { | ||
close(event); | ||
} | ||
}; | ||
if (key === 'Escape') { | ||
this.close(event); | ||
} | ||
}; | ||
document.addEventListener('mousedown', handleMouseDown); | ||
document.addEventListener('keydown', handleKeyDown, false); | ||
getTarget = ref => { | ||
this.targetNode = ref; | ||
}; | ||
getContent = ref => { | ||
this.contentNode = ref; | ||
}; | ||
return () => { | ||
document.removeEventListener('mousedown', handleMouseDown); | ||
document.removeEventListener('keydown', handleKeyDown, false); | ||
}; | ||
}, [isOpen]); | ||
render() { | ||
const { mode, onClose, onOpen, target } = this.props; | ||
const { clientX, clientY, isOpen } = this.state; | ||
useDebugValue(getDisplayName(WrappedComponent)); | ||
const open = event => { | ||
if (event.defaultPrevented) return; | ||
if (mode === 'contextmenu') event.preventDefault(); | ||
const { clientX, clientY } = event; | ||
setIsOpen(true); | ||
setClientX(clientX); | ||
setClientY(clientY); | ||
}; | ||
const close = event => { | ||
if (event && event.defaultPrevented) return; | ||
setIsOpen(false); | ||
setClientX(0); | ||
setClientY(0); | ||
}; | ||
const toggle = event => { | ||
if (isOpen) { | ||
close(event); | ||
} else { | ||
open(event); | ||
} | ||
}; | ||
const getTarget = ref => { | ||
targetNode.current = ref; | ||
}; | ||
const getContent = ref => { | ||
contentNode.current = ref; | ||
}; | ||
return ( | ||
<Fragment> | ||
<Target | ||
targetRef={this.getTarget} | ||
targetRef={getTarget} | ||
target={target} | ||
mode={mode} | ||
isOpen={isOpen} | ||
toggle={this.toggle} | ||
open={this.open} | ||
toggle={toggle} | ||
open={open} | ||
/> | ||
{isOpen ? <ScrollLock /> : null} | ||
{isOpen && <ScrollLock />} | ||
<TransitionProvider isOpen={isOpen} onEntered={onOpen} onExited={onClose}> | ||
{transitionState => ( | ||
<WrappedComponent | ||
close={this.close} | ||
open={this.open} | ||
getModalRef={this.getContent} | ||
targetNode={this.targetNode} | ||
contentNode={this.contentNode} | ||
close={close} | ||
open={open} | ||
getModalRef={getContent} | ||
targetNode={targetNode.current} | ||
contentNode={contentNode.current} | ||
isOpen={isOpen} | ||
mouseCoords={{ clientX, clientY }} | ||
style={transition(transitionState)} | ||
{...this.props} | ||
{...props} | ||
/> | ||
@@ -121,5 +156,5 @@ )} | ||
} | ||
} | ||
IntermediateComponent.displayName = getDisplayName(WrappedComponent); | ||
return IntermediateComponent; | ||
} | ||
); | ||
}; | ||
export default withModalHandlers; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
46445
1234