From 814b3d0dc278e138898041f3d573acd7fc2a45d5 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 16 Jun 2021 17:51:54 +0200 Subject: [PATCH] core-plugin-api: document useElementFilter Signed-off-by: Patrik Oldsberg --- .../src/extensions/useElementFilter.test.tsx | 4 +- .../src/extensions/useElementFilter.tsx | 39 +++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/packages/core-plugin-api/src/extensions/useElementFilter.test.tsx b/packages/core-plugin-api/src/extensions/useElementFilter.test.tsx index bb2bcb06a5..73fbb9e5a3 100644 --- a/packages/core-plugin-api/src/extensions/useElementFilter.test.tsx +++ b/packages/core-plugin-api/src/extensions/useElementFilter.test.tsx @@ -59,7 +59,9 @@ describe('useElementFilter', () => { - + + + diff --git a/packages/core-plugin-api/src/extensions/useElementFilter.tsx b/packages/core-plugin-api/src/extensions/useElementFilter.tsx index fef777cb95..e79d2ba508 100644 --- a/packages/core-plugin-api/src/extensions/useElementFilter.tsx +++ b/packages/core-plugin-api/src/extensions/useElementFilter.tsx @@ -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(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(): Array< ReactElement > { @@ -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( node: ReactNode, filterFn: (arg: ElementCollection) => T,