@steambrew/client
Version:
A support library for creating plugins with Millennium.
105 lines (104 loc) • 3.77 kB
JavaScript
/**
* Create a Regular Expression to search for a React component that uses certain props in order.
*
* @export
* @param {string[]} propList Ordererd list of properties to search for
* @returns {RegExp} RegEx to call .test(component.toString()) on
*/
export function createPropListRegex(propList, fromStart = true) {
let regexString = fromStart ? "const\{" : "";
propList.forEach((prop, propIdx) => {
regexString += `"?${prop}"?:[a-zA-Z_$]{1,2}`;
if (propIdx < propList.length - 1) {
regexString += ",";
}
});
// TODO provide a way to enable this
// console.debug(`[DFL:Utils] createPropListRegex generated regex "${regexString}" for props`, propList);
return new RegExp(regexString);
}
export function fakeRenderComponent(fun, customHooks = {}) {
const hooks = window.SP_REACT.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentDispatcher
.current;
// TODO: add more hooks
let oldHooks = {
useContext: hooks.useContext,
useCallback: hooks.useCallback,
useLayoutEffect: hooks.useLayoutEffect,
useEffect: hooks.useEffect,
useMemo: hooks.useMemo,
useRef: hooks.useRef,
useState: hooks.useState,
};
hooks.useCallback = (cb) => cb;
hooks.useContext = (cb) => cb._currentValue;
hooks.useLayoutEffect = (_) => { }; //cb();
hooks.useMemo = (cb, _) => cb;
hooks.useEffect = (_) => { }; //cb();
hooks.useRef = (val) => ({ current: val || {} });
hooks.useState = (v) => {
let val = v;
return [val, (n) => (val = n)];
};
Object.assign(hooks, customHooks);
const res = fun(hooks);
Object.assign(hooks, oldHooks);
return res;
}
export function wrapReactType(node, prop = 'type') {
if (node[prop]?.__DECKY_WRAPPED) {
return node[prop];
}
else {
return (node[prop] = { ...node[prop], __DECKY_WRAPPED: true });
}
}
export function wrapReactClass(node, prop = 'type') {
var _a;
if (node[prop]?.__DECKY_WRAPPED) {
return node[prop];
}
else {
const cls = node[prop];
const wrappedCls = (_a = class extends cls {
},
_a.__DECKY_WRAPPED = true,
_a);
return (node[prop] = wrappedCls);
}
}
export function getReactRoot(o) {
return (
// @ts-ignore
o[Object.keys(o).find((k) => k.startsWith('__reactContainer$'))] ||
// @ts-ignore
o['_reactRootContainer']?._internalRoot?.current);
}
export function getReactInstance(o) {
return (
// @ts-ignore
o[Object.keys(o).find((k) => k.startsWith('__reactFiber'))] ||
// @ts-ignore
o[Object.keys(o).find((k) => k.startsWith('__reactInternalInstance'))]);
}
export const findInTree = (parent, filter, opts) => {
const { walkable = null, ignore = [] } = opts ?? {};
if (!parent || typeof parent !== 'object') {
// Parent is invalid to search through
return null;
}
if (filter(parent))
return parent; // Parent matches, just return
if (Array.isArray(parent)) {
// Parent is an array, go through values
return parent.map((x) => findInTree(x, filter, opts)).find((x) => x);
}
// Parent is an object, go through values (or option to only use certain keys)
return (walkable || Object.keys(parent))
.map((x) => !ignore.includes(x) && findInTree(parent[x], filter, opts))
.find((x) => x);
};
export const findInReactTree = (node, filter) => findInTree(node, filter, {
// Specialised findInTree for React nodes
walkable: ['props', 'children', 'child', 'sibling'],
});