@enact/ui
Version:
A collection of simplified unstyled cross-platform UI components for Enact
221 lines (218 loc) • 10.3 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = exports.Toggleable = void 0;
Object.defineProperty(exports, "useToggle", {
enumerable: true,
get: function get() {
return _useToggle.useToggle;
}
});
var _handle = _interopRequireWildcard(require("@enact/core/handle"));
var _hoc = _interopRequireDefault(require("@enact/core/hoc"));
var _useHandlers = _interopRequireDefault(require("@enact/core/useHandlers"));
var _util = require("@enact/core/util");
var _propTypes = _interopRequireDefault(require("prop-types"));
var _pick = _interopRequireDefault(require("ramda/src/pick"));
var _react = require("react");
var _warning = _interopRequireDefault(require("warning"));
var _useToggle = require("./useToggle");
var _jsxRuntime = require("react/jsx-runtime");
var _excluded = ["disabled"];
function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, "default": e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
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 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 _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); } /**
* A higher-order component at handles toggle state.
*
* @module ui/Toggleable
* @exports Toggleable
*/ /**
* Default config for `Toggleable`.
*
* @memberof ui/Toggleable.Toggleable
* @hocconfig
*/
var defaultConfig = {
/**
* Configures the event name that activates the component.
*
* **Note**: When using `activate`/`deactivate`, the event payload will only forward the original
* event and not include toggled `prop` value. Use `toggle` to receive toggled value from the
* event payload.
*
* Example:
* ```
* const ToggleItem = Toggleable({activate: 'onFocus', deactivate: 'onBlur'}, Item);
*
* handleEvent = (ev) => {
* // do something with `ev.selected` here
* }
*
* <ToggleItem onToggle={handleEvent}>This is a toggle item</Item>
*
* @type {String}
* @memberof ui/Toggleable.Toggleable.defaultConfig
*/
activate: null,
/**
* Configures the event name that deactivates the component.
*
* **Note**: When using `activate`/`deactivate`, the event payload will only forward the original
* event and not include toggled `prop` value. Use `toggle` to receive toggled value from the
* event payload.
*
* Example:
* ```
* const ToggleItem = Toggleable({activate: 'onFocus', deactivate: 'onBlur'}, Item);
*
* handleEvent = (ev) => {
* // do something with `ev.selected` here
* }
*
* <ToggleItem onToggle={handleEvent}>This is a toggle item</Item>
* ```
* @type {String}
* @memberof ui/Toggleable.Toggleable.defaultConfig
*/
deactivate: null,
/**
* Configures additional props to attach to the event that is sent when toggled.
*
* @type {String[]}
* @default []
* @memberof ui/Toggleable.Toggleable.defaultConfig
*/
eventProps: [],
/**
* Configures the property that is passed to the wrapped component when toggled.
*
* @type {String}
* @default 'selected'
* @memberof ui/Toggleable.Toggleable.defaultConfig
*/
prop: 'selected',
/**
* Configures the event name that toggles the component.
*
* The payload includes a toggled Boolean value of `prop`.
*
* **Note**: The payload will override the original event. If a native event is set, then the native
* event payload will be lost.
*
* @type {String}
* @default 'onToggle'
* @memberof ui/Toggleable.Toggleable.defaultConfig
*/
toggle: 'onToggle',
/**
* Allows you to remap the incoming `toggle` callback to an event name of your choosing.
*
* For example, run `onToggle` when the wrapped component has an `onClick` property and you've specified
* `onClick` here.
*
* @type {String}
* @default null
* @memberof ui/Toggleable.Toggleable.defaultConfig
*/
toggleProp: null
};
/**
* A higher-order component that applies a 'toggleable' behavior to its wrapped component.
*
* Its default event and property can be configured when applied to a component.
*
* Note: This HoC passes a number of props to the wrapped component that should be passed to the
* main DOM node or consumed by the wrapped component.
*
* Example:
* ```
* const Item = ({selected, ...rest}) => (<div {...rest}>{selected}</div>);
* ...
* const ToggleItem = Toggleable({toggleProp: 'onClick'}, Item);
* ```
*
* @class Toggleable
* @memberof ui/Toggleable
* @hoc
* @public
*/
var ToggleableHOC = exports.Toggleable = (0, _hoc["default"])(defaultConfig, function (config, Wrapped) {
var activate = config.activate,
deactivate = config.deactivate,
eventProps = config.eventProps,
prop = config.prop,
toggle = config.toggle,
toggleProp = config.toggleProp;
var defaultPropKey = 'default' + (0, _util.cap)(prop);
var adapter = function adapter(ev, props) {
return _objectSpread(_objectSpread({}, (0, _pick["default"])(eventProps, props)), ev);
};
var toggleHandlers = {
onToggle: (0, _handle["default"])(function (ev, props, context) {
return context.toggle();
}, (0, _handle.forwardCustom)(toggleProp, adapter)),
onActivate: (0, _handle["default"])(function (ev, props, context) {
return context.activate();
}, (0, _handle.forwardCustom)(activate, adapter)),
onDeactivate: (0, _handle["default"])(function (ev, props, context) {
return context.deactivate();
}, (0, _handle.forwardCustom)(deactivate, adapter))
};
function Toggleable(_ref) {
var _ref$disabled = _ref.disabled,
disabled = _ref$disabled === void 0 ? false : _ref$disabled,
rest = _objectWithoutProperties(_ref, _excluded);
var props = _objectSpread({
disabled: disabled
}, rest);
var updated = _objectSpread({}, props);
var propSelected = props[prop];
var hook = (0, _useToggle.useToggle)({
defaultSelected: props[defaultPropKey],
disabled: disabled,
onToggle: function onToggle(ev) {
return (0, _handle.forwardCustom)(toggle, adapter)(ev, props);
},
prop: prop,
// FIXME: Current behavior for Toggleable treats `null` as undefined so we coerce it
// here to maintain that behavior while using useControlledState.
// eslint-disable-next-line no-undefined
selected: propSelected == null ? undefined : propSelected
});
var handlers = (0, _useHandlers["default"])(toggleHandlers, props, hook);
process.env.NODE_ENV !== "production" ? (0, _warning["default"])(!(prop in props && defaultPropKey in props), "Do not specify both '".concat(prop, "' and '").concat(defaultPropKey, "' for Toggleable instances.\n\t\t\t'").concat(defaultPropKey, "' will be ignored unless '").concat(prop, "' is 'null' or 'undefined'.")) : void 0;
// FIXME: Current behavior is to use `false` when switching from a truthy value to
// either null or undefined. The ternary below enforces that but we don't want to
// continue this exception in the future and should sunset it with this HOC.
var _useRef = (0, _react.useRef)({
selected: null
}),
instance = _useRef.current;
var selected = instance.selected && propSelected == null ? false : hook.selected;
instance.selected = propSelected;
if (prop) {
updated[prop] = selected;
}
if (toggleProp || toggle) {
updated[toggleProp || toggle] = handlers.onToggle;
}
if (activate) {
updated[activate] = handlers.onActivate;
}
if (deactivate) {
updated[deactivate] = handlers.onDeactivate;
}
delete updated[defaultPropKey];
return /*#__PURE__*/(0, _jsxRuntime.jsx)(Wrapped, _objectSpread({}, updated));
}
Toggleable.propTypes = _defineProperty(_defineProperty(_defineProperty(_defineProperty({}, defaultPropKey, _propTypes["default"].bool), "disabled", _propTypes["default"].bool), prop, _propTypes["default"].bool), toggle, _propTypes["default"].func);
return Toggleable;
});
var _default = exports["default"] = ToggleableHOC;