core-plugin-api: document useElementFilter

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2021-06-16 17:51:54 +02:00
parent 4d63ce7c1b
commit 814b3d0dc2
2 changed files with 42 additions and 1 deletions
@@ -59,7 +59,9 @@ describe('useElementFilter', () => {
</WrappingComponent>
<MockComponent>
<WrappingComponent key="second">
<InnerComponent />
<WrappingComponent key="third">
<InnerComponent />
</WrappingComponent>
</WrappingComponent>
</MockComponent>
</MockComponent>
@@ -84,6 +84,22 @@ class ElementCollection {
private readonly featureFlagsApi: FeatureFlagsApi,
) {}
/**
* Narrows the set of selected components by doing a deep traversal and
* only including those that have defined component data for the given `key`.
*
* Whether an element in the tree has component data set for the given key
* is determined by whether `getComponentData` returns undefined.
*
* The traversal does not continue deeper past elements that match the criteria,
* and it also includes the root children in the selection, meaning that if the,
* of all the currently selected elements contain data for the given key, this
* method is a no-op.
*
* If `withStrictError` is set, the resulting selection must be a full match, meaning
* there may be no elements that were excluded in the selection. If the selection
* is not a clean match, an error will be throw with `withStrictError` as the message.
*/
selectByComponentData(query: { key: string; withStrictError?: string }) {
const selection = selectChildren(
this.node,
@@ -94,6 +110,10 @@ class ElementCollection {
return new ElementCollection(selection, this.featureFlagsApi);
}
/**
* Finds all elements using the same criteria as `selectByComponentData`, but
* returns the actual component data of each of those elements instead.
*/
findComponentData<T>(query: { key: string }): T[] {
const selection = selectChildren(
this.node,
@@ -105,6 +125,9 @@ class ElementCollection {
.filter((data: T | undefined): data is T => data !== undefined);
}
/**
* Returns all of the elements currently selected by this collection.
*/
getElements<Props extends { [name: string]: unknown }>(): Array<
ReactElement<Props>
> {
@@ -114,6 +137,22 @@ class ElementCollection {
}
}
/**
* useElementFilter is a utility that helps you narrow down and retrieve data
* from a React element tree, typically operating on the `children` property
* passed in to a component. A common use-case is to construct declarative APIs
* where a React component defines its behavior based on its children, such as
* the relationship between `Routes` and `Route` in `react-router`.
*
* The purpose of this hook is similar to `React.Children.map`, and it expands upon
* it to also handle traversal of fragments and Backstage specific things like the
* `FeatureFlagged` component.
*
* The return value of the hook is computed by the provided filter function, but
* with added memoization based on the input `node`. If further memoization
* dependencies are used in the filter function, they should be added to the
* third `dependencies` argument, just like `useMemo`, `useEffect`, etc.
*/
export function useElementFilter<T>(
node: ReactNode,
filterFn: (arg: ElementCollection) => T,