@enact/core
Version:
Enact is an open source JavaScript framework containing everything you need to create a fast, scalable mobile or web application.
229 lines (220 loc) • 11.5 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.kind = exports["default"] = void 0;
var _react = require("react");
var _useHandlers = _interopRequireDefault(require("../useHandlers"));
var _Handlers = _interopRequireDefault(require("../useHandlers/Handlers"));
var _computed = _interopRequireDefault(require("./computed"));
var _styles = _interopRequireDefault(require("./styles"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
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 _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); }
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); } /**
* Provides the {@link core/kind.kind} method to create components
*
* @module core/kind
* @exports kind
*/
// Because contextType is optional and hooks must be called in the same order, we need a fallback
// context when none is specified. This likely has some overhead so we may want to deprecate and
// remove contextType support for 4.0 since the context APIs have improved since this was added.
var NoContext = /*#__PURE__*/(0, _react.createContext)(null);
/**
* @callback RenderFunction
* @memberof core/kind
* @param {Object<string, any>} props
* @param {Object<string, any>} context
* @returns React.Element|null
*/
/**
* @callback ComputedPropFunction
* @memberof core/kind
* @param {Object<string, any>} props
* @param {Object<string, any>} context
* @returns any
*/
/**
* @callback HandlerFunction
* @memberof core/kind
* @param {any} event
* @param {Object<string, any>} props
* @param {Object<string, any>} context
*/
/**
* Configuration for CSS class name mapping
*
* @typedef {Object} StylesBlock
* @memberof core/kind
* @property {Object.<string, string>} css The CSS of the component
* @property {String} [className] The className of the component
* @property {Boolean|String|String[]} [publicClassNames] Specifies which class names are overridable.
* If this value is `true`, all the class names of the component CSS will become public.
*/
/**
* @typedef {Object} KindConfig
* @memberof core/kind
* @property {String} [name] The name of the component
* @property {Boolean} [functional] Boolean controlling whether the returned component should be a functional component
* @property {Object.<string, Function>} [propTypes] Specifies expected props
* @property {Object.<string, any>} [defaultProps] Sets the default props
* @property {Object} [contextType] Specifies context type
* @property {StylesBlock} [styles] Configures styles with the static className to merge with user className
* @property {Object.<string, HandlerFunction>} [handlers] Adds event handlers that are cached between calls to prevent recreating each call.
* Any handlers are added to the props passed to `render()`. See {@link core/handle.handle}.
* @property {Object.<string, ComputedPropFunction>} [computed] Adds some computed properties, these are added to props passed to `render()`
* @property {RenderFunction} render The render function
*/
/**
* Creates a new component with some helpful declarative syntactic sugar.
*
* Example:
* ```
* import css from './Button.module.less';
* const Button = kind({
* name: 'Button',
* // Return a functional component
* functional: true,
* // expect color and onClick properties but neither required
* propTypes: {
* color: PropTypes.string
* },
* // if no color is provided, it'll be green
* defaultProps: {
* color: 'green'
* },
* // expect backgroundColor via context
* contextType: React.createContext({ backgroundColor }),
* // configure styles with the static className to merge with user className
* styles: {
* // include the CSS modules map so 'button' can be resolved to the local name
* css,
* className: 'button'
* },
* // add event handlers that are cached between calls to prevent recreating each call. Any
* // handlers are added to the props passed to `render()`. See core/handle.
* handlers: {
* onKeyDown: (evt, props) => { .... }
* },
* // add some computed properties, these are added to props passed to `render()`
* computed: {
* // border color will be the color prepended by 'light'
* borderColor: ({color}) => 'light' + color,
* // background color will be the contextual background color if specified
* color: ({color}, context) => context.backgroundColor || color
* },
* // Render the thing, already!
* render: ({color, borderColor, children, ...rest}) => (
* <button
* {...rest}
* style={{backgroundColor: color, borderColor}}
* >
* {children}
* </button>
* )
* });
* ```
*
* @function
* @template Props
* @param {KindConfig} config Component configuration
*
* @returns {Component<Props>} Component
* @memberof core/kind
* @see {@link core/handle}
* @public
*/
var kind = exports.kind = function kind(config) {
var cfgComputed = config.computed,
_config$contextType = config.contextType,
contextType = _config$contextType === void 0 ? NoContext : _config$contextType,
defaultProps = config.defaultProps,
functional = config.functional,
handlers = config.handlers,
name = config.name,
propTypes = config.propTypes,
render = config.render,
cfgStyles = config.styles;
var renderStyles = cfgStyles ? (0, _styles["default"])(cfgStyles) : false;
var renderComputed = cfgComputed ? (0, _computed["default"])(cfgComputed) : false;
var renderKind = function renderKind(props, context) {
if (renderStyles) props = renderStyles(props, context);
if (renderComputed) props = renderComputed(props, context);
return render(props, context);
};
var Component;
// In 4.x, this branch will become the only supported version and the class branch will be
// removed.
if (functional) {
Component = function Component(props) {
var ctx = (0, _react.use)(contextType);
var boundHandlers = (0, _useHandlers["default"])(handlers, props, ctx);
var merged = _objectSpread(_objectSpread({}, props), boundHandlers);
return renderKind(merged, ctx);
};
} else {
var _Class;
Component = (_Class = /*#__PURE__*/function (_ReactComponent) {
function Component() {
var _this;
_classCallCheck(this, Component);
_this = _callSuper(this, Component);
_this.handlers = new _Handlers["default"](handlers);
return _this;
}
_inherits(Component, _ReactComponent);
return _createClass(Component, [{
key: "render",
value: function render() {
this.handlers.setContext(this.props, this.context);
var merged = _objectSpread(_objectSpread({}, this.props), this.handlers.handlers);
return renderKind(merged, this.context);
}
}]);
}(_react.Component), _Class.contextType = contextType, _Class);
}
if (name) Component.displayName = name;
if (propTypes) Component.propTypes = propTypes;
if (defaultProps) Component.defaultProps = defaultProps;
// Decorate the Component with the computed property object in DEV for easier testability
if (process.env.NODE_ENV !== "production" && cfgComputed) Component.computed = cfgComputed;
var defaultPropKeys = defaultProps ? Object.keys(defaultProps) : null;
var handlerKeys = handlers ? Object.keys(handlers) : null;
Component.inline = function (props, context) {
var updated = _objectSpread({}, props);
if (defaultPropKeys && defaultPropKeys.length > 0) {
defaultPropKeys.forEach(function (key) {
// eslint-disable-next-line no-undefined
if (props == null || props[key] === undefined) {
updated[key] = defaultProps[key];
}
});
}
if (handlerKeys && handlerKeys.length > 0) {
// generate a handler with a clone of updated to ensure each handler receives the same
// props without the kind.handlers injected.
updated = handlerKeys.reduce(function (_props, key) {
_props[key] = function (ev) {
return handlers[key](ev, updated, context);
};
return _props;
}, _objectSpread({}, updated));
}
return renderKind(updated, context);
};
return Component;
};
var _default = exports["default"] = kind;
;