diff --git a/packages/core-plugin-api/api-report.md b/packages/core-plugin-api/api-report.md index 6e8cda3d83..90ea1f5e46 100644 --- a/packages/core-plugin-api/api-report.md +++ b/packages/core-plugin-api/api-report.md @@ -228,6 +228,20 @@ export type DiscoveryApi = { // @public (undocumented) export const discoveryApiRef: ApiRef; +// @public +export interface ElementCollection { + findComponentData(query: { + key: string; + }): T[]; + getElements(): Array>; + selectByComponentData(query: { + key: string; + withStrictError?: string; + }): ElementCollection; +} + // @public export type ErrorApi = { post(error: Error_2, context?: ErrorContext): void; @@ -515,7 +529,7 @@ export function useApiHolder(): ApiHolder; // @public (undocumented) export const useApp: () => AppContext; -// @public (undocumented) +// @public export function useElementFilter(node: ReactNode, filterFn: (arg: ElementCollection) => T, dependencies?: any[]): T; // @public (undocumented) diff --git a/packages/core-plugin-api/src/extensions/index.ts b/packages/core-plugin-api/src/extensions/index.ts index 71373db1a3..0ee1447b4e 100644 --- a/packages/core-plugin-api/src/extensions/index.ts +++ b/packages/core-plugin-api/src/extensions/index.ts @@ -21,3 +21,4 @@ export { createComponentExtension, } from './extensions'; export { useElementFilter } from './useElementFilter'; +export type { ElementCollection } from './useElementFilter'; diff --git a/packages/core-plugin-api/src/extensions/useElementFilter.tsx b/packages/core-plugin-api/src/extensions/useElementFilter.tsx index e79d2ba508..0549472ab2 100644 --- a/packages/core-plugin-api/src/extensions/useElementFilter.tsx +++ b/packages/core-plugin-api/src/extensions/useElementFilter.tsx @@ -78,12 +78,17 @@ function selectChildren( }); } -class ElementCollection { - constructor( - private readonly node: ReactNode, - private readonly featureFlagsApi: FeatureFlagsApi, - ) {} - +/** + * A querying interface tailored to traversing a set of selected React elements + * and extracting data. + * + * Methods prefixed with `selectBy` are used to narrow the set of selected elements. + * + * Methods prefixed with `find` return concrete data using a deep traversal of the set. + * + * Methods prefixed with `get` return concrete data using a shallow traversal of the set. + */ +export interface ElementCollection { /** * Narrows the set of selected components by doing a deep traversal and * only including those that have defined component data for the given `key`. @@ -100,6 +105,31 @@ class ElementCollection { * 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; + }): ElementCollection; + + /** + * 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[]; + + /** + * Returns all of the elements currently selected by this collection. + */ + getElements(): Array< + ReactElement + >; +} + +class Collection implements ElementCollection { + constructor( + private readonly node: ReactNode, + private readonly featureFlagsApi: FeatureFlagsApi, + ) {} + selectByComponentData(query: { key: string; withStrictError?: string }) { const selection = selectChildren( this.node, @@ -107,13 +137,9 @@ class ElementCollection { node => getComponentData(node, query.key) !== undefined, query.withStrictError, ); - return new ElementCollection(selection, this.featureFlagsApi); + return new Collection(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, @@ -125,9 +151,6 @@ class ElementCollection { .filter((data: T | undefined): data is T => data !== undefined); } - /** - * Returns all of the elements currently selected by this collection. - */ getElements(): Array< ReactElement > { @@ -159,7 +182,7 @@ export function useElementFilter( dependencies: any[] = [], ) { const featureFlagsApi = useApi(featureFlagsApiRef); - const elements = new ElementCollection(node, featureFlagsApi); + const elements = new Collection(node, featureFlagsApi); // eslint-disable-next-line react-hooks/exhaustive-deps return useMemo(() => filterFn(elements), [node, ...dependencies]); }