Add extension points for source tree (#1816)

This change will add an extension point which allows to wrap the source tree. This is required in order to use a context provider e.g. to capture a selected file. Another extension point allows to add a row between the row of a file.
In order to implement the extension points ui-extensions has now a wrapper property and passes the children of an extension point to implementing extension.
This commit is contained in:
Sebastian Sdorra
2021-09-30 16:41:04 +02:00
committed by GitHub
parent 2b85081032
commit f5d9855a24
8 changed files with 279 additions and 70 deletions

View File

@@ -21,9 +21,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import * as React from "react";
import React, { FC, ReactNode } from "react";
import { Binder } from "./binder";
import { Component, FC, ReactNode } from "react";
import useBinder from "./useBinder";
type PropTransformer = (props: object) => object;
@@ -33,12 +32,14 @@ type Props = {
renderAll?: boolean;
props?: object;
propTransformer?: PropTransformer;
wrapper?: boolean;
};
const createInstance = (Component: any, props: object, key?: number) => {
const instanceProps = {
...props,
key
...(Component.props || {}),
key,
};
if (React.isValidElement(Component)) {
return React.cloneElement(Component, instanceProps);
@@ -51,12 +52,28 @@ const renderAllExtensions = (binder: Binder, name: string, props: object) => {
return <>{extensions.map((cmp, index) => createInstance(cmp, props, index))}</>;
};
const renderWrapperExtensions = (binder: Binder, name: string, props: object) => {
const extensions = [...(binder.getExtensions(name, props) || [])];
extensions.reverse();
let instance: any = null;
extensions.forEach((cmp, index) => {
let instanceProps = props;
if (instance) {
instanceProps = { ...props, children: instance };
}
instance = createInstance(cmp, instanceProps, index);
});
return instance;
};
const renderSingleExtension = (binder: Binder, name: string, props: object) => {
const cmp = binder.getExtension(name, props);
if (!cmp) {
return null;
}
return createInstance(cmp, props, undefined);
return createInstance(cmp, props);
};
const renderDefault = (children: ReactNode) => {
@@ -67,11 +84,11 @@ const renderDefault = (children: ReactNode) => {
};
const createRenderProps = (propTransformer?: PropTransformer, props?: object) => {
const transform = (props: object) => {
const transform = (untransformedProps: object) => {
if (!propTransformer) {
return props;
return untransformedProps;
}
return propTransformer(props);
return propTransformer(untransformedProps);
};
return transform(props || {});
@@ -80,12 +97,15 @@ const createRenderProps = (propTransformer?: PropTransformer, props?: object) =>
/**
* ExtensionPoint renders components which are bound to an extension point.
*/
const ExtensionPoint: FC<Props> = ({ name, propTransformer, props, renderAll, children }) => {
const ExtensionPoint: FC<Props> = ({ name, propTransformer, props, renderAll, wrapper, children }) => {
const binder = useBinder();
const renderProps = createRenderProps(propTransformer, props);
const renderProps = createRenderProps(propTransformer, { ...(props || {}), children });
if (!binder.hasExtension(name, renderProps)) {
return renderDefault(children);
} else if (renderAll) {
if (wrapper) {
return renderWrapperExtensions(binder, name, renderProps);
}
return renderAllExtensions(binder, name, renderProps);
}
return renderSingleExtension(binder, name, renderProps);