@ui5/webcomponents-react
Version:
React Wrapper for UI5 Web Components and additional components
185 lines (182 loc) • 6.23 kB
JavaScript
import { useCallback, useEffect, useLayoutEffect, useRef } from 'react';
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
const renderErr = 'Renderer Error ☝️';
export const actions = {
init: 'init'
};
export const defaultRenderer = ({
value = ''
}) => value;
export const emptyRenderer = () => /*#__PURE__*/_jsx(_Fragment, {
children: "\xA0"
});
export const defaultColumn = {
Cell: defaultRenderer,
width: 150,
minWidth: 0,
maxWidth: Number.MAX_SAFE_INTEGER
};
function mergeProps(...propList) {
return propList.reduce((props, next) => {
const {
style,
className,
...rest
} = next;
props = {
...props,
...rest
};
if (style) {
props.style = props.style ? {
...props.style,
...style
} : style;
}
if (className) {
props.className = props.className ? props.className + ' ' + className : className;
}
if (props.className === '') {
delete props.className;
}
return props;
}, {});
}
function handlePropGetter(prevProps, userProps, meta) {
if (typeof userProps === 'function') {
return handlePropGetter({}, userProps(prevProps, meta));
}
if (Array.isArray(userProps)) {
return mergeProps(prevProps, ...userProps);
}
return mergeProps(prevProps, userProps);
}
export const makePropGetter = (hooks, meta = {}) => {
return (userProps = {}) => [...hooks, userProps].reduce((prev, next) => handlePropGetter(prev, next, {
...meta,
userProps
}), {});
};
export const reduceHooks = (hooks, initial, meta = {}, allowUndefined) => hooks.reduce((prev, next) => {
const nextValue = next(prev, meta);
if (process.env.NODE_ENV !== 'production') {
if (!allowUndefined && typeof nextValue === 'undefined') {
console.info(next);
throw new Error('React Table: A reducer hook ☝️ just returned undefined! This is not allowed.');
}
}
return nextValue;
}, initial);
export const loopHooks = (hooks, context, meta = {}) => hooks.forEach(hook => {
const nextValue = hook(context, meta);
if (process.env.NODE_ENV !== 'production') {
if (typeof nextValue !== 'undefined') {
console.info(hook, nextValue);
throw new Error('React Table: A loop-type hook ☝️ just returned a value! This is not allowed.');
}
}
});
export function ensurePluginOrder(plugins, befores, pluginName, afters) {
if (process.env.NODE_ENV !== 'production' && afters) {
throw new Error(`Defining plugins in the "after" section of ensurePluginOrder is no longer supported (see plugin ${pluginName})`);
}
const pluginIndex = plugins.findIndex(plugin => plugin.pluginName === pluginName);
if (pluginIndex === -1) {
if (process.env.NODE_ENV !== 'production') {
throw new Error(`The plugin "${pluginName}" was not found in the plugin list!
This usually means you need to need to name your plugin hook by setting the 'pluginName' property of the hook function, eg:
${pluginName}.pluginName = '${pluginName}'
`);
}
}
befores.forEach(before => {
const beforeIndex = plugins.findIndex(plugin => plugin.pluginName === before);
if (beforeIndex > -1 && beforeIndex > pluginIndex) {
if (process.env.NODE_ENV !== 'production') {
throw new Error(`React Table: The ${pluginName} plugin hook must be placed after the ${before} plugin hook!`);
}
}
});
}
export function functionalUpdate(updater, old) {
return typeof updater === 'function' ? updater(old) : updater;
}
export function useGetLatest(obj) {
const ref = useRef(obj);
// eslint-disable-next-line react-hooks/refs
ref.current = obj;
return useCallback(() => ref.current, []);
}
export const safeUseLayoutEffect = typeof document !== 'undefined' ? useLayoutEffect : useEffect;
export function useMountedLayoutEffect(fn, deps) {
const mountedRef = useRef(false);
// eslint-disable-next-line react-hooks/refs
safeUseLayoutEffect(() => {
if (mountedRef.current) {
fn();
}
mountedRef.current = true;
}, deps);
}
export function useAsyncDebounce(defaultFn, defaultWait = 0) {
const debounceRef = useRef({});
const getDefaultFn = useGetLatest(defaultFn);
const getDefaultWait = useGetLatest(defaultWait);
return useCallback(
// eslint-disable-next-line @typescript-eslint/require-await
async (...args) => {
if (!debounceRef.current.promise) {
debounceRef.current.promise = new Promise((resolve, reject) => {
debounceRef.current.resolve = resolve;
debounceRef.current.reject = reject;
});
}
if (debounceRef.current.timeout) {
clearTimeout(debounceRef.current.timeout);
}
// eslint-disable-next-line @typescript-eslint/no-misused-promises
debounceRef.current.timeout = setTimeout(async () => {
delete debounceRef.current.timeout;
try {
debounceRef.current.resolve(await getDefaultFn()(...args));
} catch (err) {
debounceRef.current.reject(err);
} finally {
delete debounceRef.current.promise;
}
}, getDefaultWait());
return debounceRef.current.promise;
}, [getDefaultFn, getDefaultWait]);
}
export function makeRenderer(instance, column, meta = {}) {
return (type, userProps = {}) => {
const Comp = typeof type === 'string' ? column[type] : type;
if (typeof Comp === 'undefined') {
console.info(column);
throw new Error(renderErr);
}
return flexRender(Comp, {
...instance,
column,
...meta,
...userProps
});
};
}
export function flexRender(Comp, props) {
return isReactComponent(Comp) ? /*#__PURE__*/_jsx(Comp, {
...props
}) : Comp;
}
function isReactComponent(component) {
return isClassComponent(component) || typeof component === 'function' || isExoticComponent(component);
}
function isClassComponent(component) {
return typeof component === 'function' && (() => {
const proto = Object.getPrototypeOf(component);
return proto.prototype && proto.prototype.isReactComponent;
})();
}
function isExoticComponent(component) {
return typeof component === 'object' && typeof component.$$typeof === 'symbol' && ['react.memo', 'react.forward_ref'].includes(component.$$typeof.description);
}