UNPKG

@toolpad/utils

Version:

Shared utilities used by Toolpad packages.

126 lines (120 loc) 4.18 kB
"use strict"; 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 }; }