@enact/ui
Version:
A collection of simplified unstyled cross-platform UI components for Enact
298 lines (295 loc) • 14.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = exports.FloatingLayerBase = exports.FloatingLayer = void 0;
var _dispatcher = require("@enact/core/dispatcher");
var _handle = require("@enact/core/handle");
var _classnames = _interopRequireDefault(require("classnames"));
var _invariant = _interopRequireDefault(require("invariant"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _react = require("react");
var _reactDom = _interopRequireDefault(require("react-dom"));
var _Cancelable = _interopRequireDefault(require("../Cancelable"));
var _FloatingLayerDecorator = require("./FloatingLayerDecorator");
var _Scrim = _interopRequireDefault(require("./Scrim"));
var _FloatingLayerModule = _interopRequireDefault(require("./FloatingLayer.module.css"));
var _jsxRuntime = require("react/jsx-runtime");
var _excluded = ["children", "className", "floatLayerClassName", "open", "scrimType"];
function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
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; }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); }
function _possibleConstructorReturn(t, e) { if (e && ("object" == typeof e || "function" == typeof e)) return e; if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined"); return _assertThisInitialized(t); }
function _assertThisInitialized(e) { if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return e; }
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
function _getPrototypeOf(t) { return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) { return t.__proto__ || Object.getPrototypeOf(t); }, _getPrototypeOf(t); }
function _inherits(t, e) { if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function"); t.prototype = Object.create(e && e.prototype, { constructor: { value: t, writable: !0, configurable: !0 } }), Object.defineProperty(t, "prototype", { writable: !1 }), e && _setPrototypeOf(t, e); }
function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); } /**
* A component that creates an entry point to the new render tree.
*
* This is used for modal components such as popups.
*
* @class FloatingLayerBase
* @memberof ui/FloatingLayer
* @ui
* @public
*/
var FloatingLayerBase = exports.FloatingLayerBase = /*#__PURE__*/function (_Component) {
function FloatingLayerBase(props) {
var _this;
_classCallCheck(this, FloatingLayerBase);
_this = _callSuper(this, FloatingLayerBase, [props]);
_this.handleNotify = (0, _handle.oneOf)([(0, _handle.forEventProp)('action', 'close'), (0, _handle.call)('handleClose')], [(0, _handle.forEventProp)('action', 'mount'), (0, _handle.call)('setFloatingLayer')]).bind(_this);
_this.handleClose = (0, _handle.handle)((0, _handle.forProp)('open', true), (0, _handle.forwardCustom)('onDismiss')).bind(_this);
_this.handleClick = (0, _handle.handle)((0, _handle.forProp)('noAutoDismiss', false), (0, _handle.forProp)('open', true), (0, _handle.forwardCustom)('onDismiss', function () {
return {
detail: {
inputType: 'click'
}
};
})).bind(_this);
_this.handleScroll = function (ev) {
var currentTarget = ev.currentTarget;
currentTarget.scrollTop = 0;
currentTarget.scrollLeft = 0;
};
_this.stopPropagation = function (ev) {
ev.nativeEvent.stopImmediatePropagation();
if (_this.props.children.props.onClick) {
_this.props.children.props.onClick();
}
};
_this.node = null;
_this.state = {
readyToRender: false
};
return _this;
}
_inherits(FloatingLayerBase, _Component);
return _createClass(FloatingLayerBase, [{
key: "componentDidMount",
value: function componentDidMount() {
// Must register first in order to obtain the floating layer node reference before trying
// to render into it
if (this.context && typeof this.context === 'function') {
this.controller = this.context(this.handleNotify.bind(this));
}
if (this.props.scrimType === 'none' && this.props.open) {
(0, _dispatcher.on)('click', this.handleClick);
}
}
}, {
key: "componentDidUpdate",
value: function componentDidUpdate(prevProps, prevState) {
var _this$props = this.props,
open = _this$props.open,
scrimType = _this$props.scrimType;
if (prevProps.open && !open) {
// when open changes to false, forward close
(0, _handle.forwardCustom)('onClose')(null, this.props);
} else if (!prevProps.open && open && !this.state.readyToRender) {
// when open changes to true and node hasn't rendered, render it
this.readyToRender();
} else if (this.state.readyToRender && (!prevState.readyToRender || prevState.readyToRender && open && !prevProps.open)) {
// when node has been rendered and either it was just rendered in this update cycle or
// the open prop changed in this cycle, forward open
(0, _handle.forwardCustom)('onOpen')(null, this.props);
}
if (scrimType === 'none') {
if (!prevProps.open && open) {
(0, _dispatcher.on)('click', this.handleClick);
} else if (prevProps.open && !open) {
(0, _dispatcher.off)('click', this.handleClick);
}
}
}
}, {
key: "componentWillUnmount",
value: function componentWillUnmount() {
if (this.floatingLayer) {
(0, _dispatcher.off)('scroll', this.handleScroll, this.floatingLayer);
this.floatingLayer = null;
}
(0, _dispatcher.off)('click', this.handleClick);
if (this.controller) {
this.controller.unregister();
}
}
}, {
key: "setFloatingLayer",
value: function setFloatingLayer(_ref) {
var floatingLayer = _ref.floatingLayer;
var isNewLayer = !this.floatingLayer && floatingLayer;
this.floatingLayer = floatingLayer;
// the first time we have a valid floating layer container and this instance is set to open,
// we need to render the layer.
if (isNewLayer && this.props.open && !this.state.readyToRender) {
this.readyToRender();
}
}
}, {
key: "readyToRender",
value: function readyToRender() {
if (this.state.readyToRender) return;
!this.floatingLayer ? process.env.NODE_ENV !== "production" ? (0, _invariant["default"])(false, 'FloatingLayer cannot be used outside the subtree of a FloatingLayerDecorator') : (0, _invariant["default"])(false) : void 0;
(0, _dispatcher.on)('scroll', this.handleScroll, this.floatingLayer);
this.setState({
readyToRender: true
});
}
}, {
key: "render",
value: function render() {
var _this$props2 = this.props,
children = _this$props2.children,
className = _this$props2.className,
floatLayerClassName = _this$props2.floatLayerClassName,
open = _this$props2.open,
scrimType = _this$props2.scrimType,
rest = _objectWithoutProperties(_this$props2, _excluded);
var mergedClassName = (0, _classnames["default"])(floatLayerClassName, _FloatingLayerModule["default"].floatingLayer, className);
delete rest.floatLayerId;
delete rest.noAutoDismiss;
delete rest.onClose;
delete rest.onDismiss;
delete rest.onOpen;
if (open && this.state.readyToRender) {
return /*#__PURE__*/_reactDom["default"].createPortal(/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", _objectSpread(_objectSpread({
className: mergedClassName
}, rest), {}, {
children: [scrimType !== 'none' ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Scrim["default"], {
type: scrimType,
onClick: this.handleClick
}) : null, /*#__PURE__*/(0, _react.cloneElement)(children, {
onClick: this.stopPropagation
})]
})), this.floatingLayer);
}
return null;
}
}]);
}(_react.Component);
FloatingLayerBase.displayName = 'FloatingLayer';
FloatingLayerBase.propTypes = /** @lends ui/FloatingLayer.FloatingLayerBase.prototype */{
/**
* CSS classes for FloatingLayer.
*
* @type {String}
* @default 'enact-fit enact-clip enact-untouchable'
* @public
*/
floatLayerClassName: _propTypes["default"].string,
/**
* Element id for floating layer.
*
* @type {String}
* @default 'floatLayer'
* @public
*/
floatLayerId: _propTypes["default"].string,
/**
* Prevents FloatingLayer from hiding when the user presses cancel/back (e.g. `ESC`) key or
* clicks outside the floating layer.
*
* @type {Boolean}
* @default false
* @public
*/
noAutoDismiss: _propTypes["default"].bool,
/**
* Called when floating layer is closed.
*
* @type {Function}
* @public
*/
onClose: _propTypes["default"].func,
/**
* Called when a closing action is invoked.
*
* These actions may include pressing cancel/back (e.g. `ESC`) key or programmatically closing
* by `FloatingLayerDecorator`. When cancel key is pressed, the function will only invoke if
* `noAutoDismiss` is set to `false`.
*
* When pressing `ESC` key, event payload carries `detail` property containing `inputType`
* value of `'key'`.
* When clicking outside the boundary of the popup, event payload carries `detail` property
* containing `inputType` value of `'click'`.
*
* @type {Function}
* @public
*/
onDismiss: _propTypes["default"].func,
/**
* Called when floating layer is opened. It will only be invoked for the first render.
*
* @type {Function}
* @public
*/
onOpen: _propTypes["default"].func,
/**
* Renders the floating layer and its components.
*
* @type {Boolean}
* @default false
* @public
*/
open: _propTypes["default"].bool,
/**
* The scrim type that overlays FloatingLayer.
*
* It can be either `'transparent'`, `'translucent'`, or `'none'`.
*
* @type {String}
* @default 'translucent'
* @public
*/
scrimType: _propTypes["default"].oneOf(['transparent', 'translucent', 'none'])
};
FloatingLayerBase.contextType = _FloatingLayerDecorator.FloatingLayerContext;
FloatingLayerBase.defaultProps = {
floatLayerClassName: 'enact-fit enact-clip enact-untouchable',
floatLayerId: 'floatLayer',
noAutoDismiss: false,
open: false,
scrimType: 'translucent'
};
var handleCancel = (0, _handle.handle)(
// can't use forProp safely since either could be undefined ~= false
function (ev, _ref2) {
var open = _ref2.open,
noAutoDismiss = _ref2.noAutoDismiss,
onDismiss = _ref2.onDismiss;
return open && !noAutoDismiss && onDismiss;
}, (0, _handle.forwardCustom)('onDismiss', function () {
return {
detail: {
inputType: 'key'
}
};
}), _handle.stop);
/**
* FloatingLayer that mixes {@link ui/Cancelable.Cancelable} to handle FloatingLayer dismissal.
*
* This is used for modal components such as popups.
*
* @class FloatingLayer
* @memberof ui/FloatingLayer
* @ui
* @extends ui/FloatingLayer.FloatingLayerBase
* @mixes ui/Cancelable.Cancelable
* @public
*/
var FloatingLayer = exports.FloatingLayer = (0, _Cancelable["default"])({
modal: true,
onCancel: handleCancel
}, FloatingLayerBase);
var _default = exports["default"] = FloatingLayer;