mirror of https://github.com/stashapp/stash.git
UI nested instead (#5125)
* Support multiple calls to PluginApi.patch.instead for a component. Allow calling the original/chained function from the hook function. * Add example of new usage of instead * Update documentation
This commit is contained in:
parent
a94bf29b34
commit
49060e6686
|
@ -33,4 +33,15 @@
|
|||
.scene-performer-popover .image-thumbnail {
|
||||
margin: 1em;
|
||||
}
|
||||
|
||||
|
||||
.example-react-component-custom-overlay {
|
||||
display: block;
|
||||
font-weight: 900;
|
||||
height: 100%;
|
||||
opacity: 0.25;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: 8;
|
||||
}
|
|
@ -132,10 +132,18 @@ interface IPluginApi {
|
|||
);
|
||||
}
|
||||
|
||||
function Overlays() {
|
||||
return <span className="example-react-component-custom-overlay">Custom overlay</span>;
|
||||
}
|
||||
|
||||
PluginApi.patch.instead("SceneCard.Details", function (props: any, _: any, original: any) {
|
||||
return <SceneDetails {...props} />;
|
||||
});
|
||||
|
||||
PluginApi.patch.instead("SceneCard.Overlays", function (props: any, _: any, original: (props: any) => any) {
|
||||
return <><Overlays />{original({...props})}</>;
|
||||
});
|
||||
|
||||
const TestPage: React.FC = () => {
|
||||
const componentsLoading = PluginApi.hooks.useLoadComponents([PluginApi.loadableComponents.SceneCard]);
|
||||
|
||||
|
|
|
@ -117,12 +117,12 @@ Returns `void`.
|
|||
|
||||
#### `PluginApi.patch.instead`
|
||||
|
||||
Registers a replacement function for a component. The provided function will be called with the arguments passed to the original render function, plus the original render function as the last argument. An error will be thrown if the component already has a replacement function registered.
|
||||
Registers a replacement function for a component. The provided function will be called with the arguments passed to the original render function, plus the next render function as the last argument. Replacement functions will be called in the order that they are registered. If a replacement function does not call the next render function then the following replacement functions will not be called or applied.
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|-----------|------|-------------|
|
||||
| `component` | `string` | The name of the component to patch. |
|
||||
| `fn` | `Function` | The replacement function. It accepts the same arguments as the original render function, plus the original render function, and is expected to return the replacement component. |
|
||||
| `fn` | `Function` | The replacement function. It accepts the same arguments as the original render function, plus the next render function, and is expected to return the replacement component. |
|
||||
|
||||
Returns `void`.
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ export const components: Record<string, Function> = {
|
|||
};
|
||||
|
||||
const beforeFns: Record<string, Function[]> = {};
|
||||
const insteadFns: Record<string, Function> = {};
|
||||
const insteadFns: Record<string, Function[]> = {};
|
||||
const afterFns: Record<string, Function[]> = {};
|
||||
|
||||
// patch functions
|
||||
|
@ -23,11 +23,14 @@ export function before(component: string, fn: Function) {
|
|||
beforeFns[component].push(fn);
|
||||
}
|
||||
|
||||
// registers a patch to a function. Instead functions receive the original arguments,
|
||||
// plus the next function to call. In order for all instead functions to be called,
|
||||
// it is expected that the provided next() function will be called.
|
||||
export function instead(component: string, fn: Function) {
|
||||
if (insteadFns[component]) {
|
||||
throw new Error("instead has already been called for " + component);
|
||||
if (!insteadFns[component]) {
|
||||
insteadFns[component] = [];
|
||||
}
|
||||
insteadFns[component] = fn;
|
||||
insteadFns[component].push(fn);
|
||||
}
|
||||
|
||||
export function after(component: string, fn: Function) {
|
||||
|
@ -51,6 +54,35 @@ export function RegisterComponent<T extends Function>(
|
|||
return fn;
|
||||
}
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
function runInstead(
|
||||
fns: Function[],
|
||||
targetFn: Function,
|
||||
thisArg: any,
|
||||
argArray: any[]
|
||||
) {
|
||||
if (!fns.length) {
|
||||
return targetFn.apply(thisArg, argArray);
|
||||
}
|
||||
|
||||
let i = 1;
|
||||
function next(): any {
|
||||
if (i >= fns.length) {
|
||||
return targetFn;
|
||||
}
|
||||
|
||||
const thisTarget = fns[i++];
|
||||
return new Proxy(thisTarget, {
|
||||
apply: function (target, ctx, args) {
|
||||
return target.apply(ctx, args.concat(next()));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return fns[0].apply(thisArg, argArray.concat(next()));
|
||||
}
|
||||
/* eslint-enable @typescript-eslint/no-explicit-any */
|
||||
|
||||
// patches a function to implement the before/instead/after functionality
|
||||
export function PatchFunction<T extends Function>(name: string, fn: T) {
|
||||
return new Proxy(fn, {
|
||||
|
@ -61,7 +93,7 @@ export function PatchFunction<T extends Function>(name: string, fn: T) {
|
|||
args = beforeFn.apply(ctx, args);
|
||||
}
|
||||
if (insteadFns[name]) {
|
||||
result = insteadFns[name].apply(ctx, args.concat(target));
|
||||
result = runInstead(insteadFns[name], target, ctx, args);
|
||||
} else {
|
||||
result = target.apply(ctx, args);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue