@toolpad/utils
Version:
Shared utilities used by Toolpad packages.
126 lines (120 loc) • 4.18 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.createGlobalState = createGlobalState;
exports.createProvidedContext = createProvidedContext;
exports.default = getComponentDisplayName;
exports.interleave = interleave;
exports.useAssertedContext = useAssertedContext;
exports.useNonNullableContext = useNonNullableContext;
exports.useTraceUpdates = useTraceUpdates;
var React = _interopRequireWildcard(require("react"));
var ReactIs = _interopRequireWildcard(require("react-is"));
var _jsxRuntime = require("react/jsx-runtime");
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (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 (const 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); }
/**
* Like `Array.prototype.join`, but for React nodes.
*/
function interleave(items, separator) {
const result = [];
for (let i = 0; i < items.length; i += 1) {
if (i > 0) {
if (ReactIs.isElement(separator)) {
result.push(/*#__PURE__*/React.cloneElement(separator, {
key: `separator-${i}`
}));
} else {
result.push(separator);
}
}
const item = items[i];
result.push(item);
}
return /*#__PURE__*/(0, _jsxRuntime.jsx)(React.Fragment, {
children: result
});
}
/**
* Consume a context but throw when used outside of a provider.
*/
function useNonNullableContext(context, name) {
const maybeContext = React.useContext(context);
if (maybeContext === null || maybeContext === undefined) {
throw new Error(`context "${name}" was used without a Provider`);
}
return maybeContext;
}
/**
* Context that throws when used outside of a provider.
*/
function createProvidedContext(name) {
const context = /*#__PURE__*/React.createContext(undefined);
const useContext = () => useNonNullableContext(context, name);
return [useContext, context.Provider];
}
function useAssertedContext(context) {
const value = React.useContext(context);
if (value === undefined) {
throw new Error('context was used without a Provider');
}
return value;
}
/**
* Debugging tool that logs updates to props.
*/
function useTraceUpdates(prefix, props) {
const prev = React.useRef(props);
React.useEffect(() => {
const changedProps = {};
for (const key of Object.keys(props)) {
if (!Object.is(prev.current[key], props[key])) {
changedProps[key] = props[key];
}
}
if (Object.keys(changedProps).length > 0) {
// eslint-disable-next-line no-console
console.log(`${prefix} changed props:`, changedProps);
}
prev.current = props;
});
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function getComponentDisplayName(Component) {
if (typeof Component === 'string') {
return Component || 'Unknown';
}
return Component.displayName || Component.name;
}
/**
* Create a shared state to be used across the application. Returns a useState hook that
* is synchronized on the same state between all instances where it is called.
*/
function createGlobalState(initialState) {
let state = initialState;
const listeners = [];
const subscribe = cb => {
listeners.push(cb);
return () => {
const index = listeners.indexOf(cb);
listeners.splice(index, 1);
};
};
const getState = () => state;
const setState = newState => {
state = typeof newState === 'function' ? newState(state) : newState;
listeners.forEach(cb => cb(state));
};
const useValue = () => React.useSyncExternalStore(subscribe, getState, getState);
const useState = () => {
const value = useValue();
return [value, setState];
};
return {
getState,
setState,
useValue,
useState,
subscribe
};
}
;