baseui
Version:
A React Component library implementing the Base design language
191 lines (173 loc) • 7.57 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getOverride = getOverride;
exports.getOverrideProps = getOverrideProps;
exports.getOverrides = getOverrides;
exports.mergeConfigurationOverrides = mergeConfigurationOverrides;
exports.mergeOverride = mergeOverride;
exports.mergeOverrides = mergeOverrides;
exports.toObjectOverride = toObjectOverride;
exports.useOverrides = useOverrides;
var React = _interopRequireWildcard(require("react"));
var _reactIs = require("react-is");
var _deepMerge = _interopRequireDefault(require("../utils/deep-merge"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
function _extends() { _extends = Object.assign ? Object.assign.bind() : 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); } /*
Copyright (c) Uber Technologies, Inc.
This source code is licensed under the MIT license found in the
LICENSE file in the root directory of this source tree.
*/
// Object -> any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-unused-vars,@typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-unused-vars,@typescript-eslint/no-explicit-any
/**
* Given an override argument, returns the component implementation override if it exists
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function getOverride(_override) {
if ((0, _reactIs.isValidElementType)(_override)) {
return _override;
}
// Check if override is OverrideObjectT
if (_override && typeof _override === 'object') {
// Remove this 'any' once this flow issue is fixed:
// https://github.com/facebook/flow/issues/6666
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return _override.component;
}
// null/undefined
return _override;
}
/**
* Given an override argument, returns the override props that should be passed
* to the component when rendering it.
*/
function getOverrideProps(_override) {
if (_override && typeof _override === 'object') {
if (typeof _override.props === 'object') {
//@ts-expect-error
return {
..._override.props,
$style: _override.style
};
} else {
//@ts-expect-error
return {
$style: _override.style
};
}
}
//@ts-expect-error
return {};
}
/**
* Coerces an override argument into an override object
* (sometimes it is just an override component)
*/
function toObjectOverride(_override) {
if ((0, _reactIs.isValidElementType)(_override)) {
return {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
component: _override
};
}
// Flow can't figure out that typeof 'function' above will
// catch React.StatelessFunctionalComponent
// (probably related to https://github.com/facebook/flow/issues/6666)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return _override || {};
}
/**
* Get a convenient override array that will always have [component, props]
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function getOverrides(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
_override,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
defaultComponent) {
const Component = getOverride(_override) || defaultComponent;
if (_override && typeof _override === 'object' && typeof _override.props === 'function') {
// TODO(v11)
if (process.env.NODE_ENV !== "production") {
console.warn('baseui:Overrides Props as a function will be removed in the next major version. Override the whole component instead. ' + 'See https://baseweb.design/guides/understanding-overrides/#override-the-entire-subcomponent');
}
const DynamicOverride = /*#__PURE__*/React.forwardRef((props, ref) => {
const mappedProps = _override.props(props);
const nextProps = getOverrideProps({
..._override,
props: mappedProps
});
return /*#__PURE__*/React.createElement(Component, _extends({
ref: ref
}, nextProps));
});
DynamicOverride.displayName = Component.displayName;
// @ts-expect-error
return [DynamicOverride, {}];
}
const props = getOverrideProps(_override);
return [Component, props];
}
/**
* Merges two overrides objects – this is useful if you want to inject your own
* overrides into a child component, but also accept further overrides from
* from upstream. See `mergeOverride` below.
*/
function mergeOverrides(target = {}, source = {}) {
const merged = Object.assign({}, target, source);
const allIdentifiers = Object.keys(merged);
// const allIdentifiers = Object.keys({...target, ...source});
return allIdentifiers.reduce((acc, name) => {
// @ts-ignore
acc[name] = mergeOverride(toObjectOverride(target[name]), toObjectOverride(source[name]));
return acc;
}, {});
}
/**
* Merges two override objects using the following behavior:
* - Component implementation from the source (parent) replaces target
* - Props and styles are both deep merged
*/
function mergeOverride(target, source) {
// Shallow merge should handle `component`
const merged = {
...target,
...source
};
if (target.props && source.props) {
merged.props = mergeConfigurationOverrides(target.props, source.props);
}
if (target.style && source.style) {
merged.style = mergeConfigurationOverrides(target.style, source.style);
}
return merged;
}
/**
* Since style or props overrides can be an object *or* a function, we need to handle
* the case that one of them is a function. We do this by returning a new
* function that deep merges the result of each style override
*/
function mergeConfigurationOverrides(target, source) {
// Simple case of both objects
if (typeof target === 'object' && typeof source === 'object') {
return (0, _deepMerge.default)({}, target, source);
}
// At least one is a function, return a new composite function
return (...args) => {
return (0, _deepMerge.default)({}, typeof target === 'function' ? target(...args) : target, typeof source === 'function' ? source(...args) : source);
};
}
// Lil' hook for memoized unpacking of overrides
function useOverrides(defaults, overrides = {}) {
return React.useMemo(() => Object.keys(defaults).reduce((obj, key) => {
obj[key] = getOverrides(overrides[key], defaults[key]);
return obj;
}, {}), [overrides]);
}