@backstage/plugin-techdocs-react
Version:
Shared frontend utilities for TechDocs and Addons
291 lines (283 loc) • 9.93 kB
TypeScript
import * as react from 'react';
import { ComponentType, PropsWithChildren, Dispatch, SetStateAction, ReactNode } from 'react';
import { Extension, RouteFunc } from '@backstage/core-plugin-api';
import { a as TechDocsAddonOptions, T as TechDocsAddonLocations, c as TechDocsMetadata, b as TechDocsEntityMetadata } from './types/types.d-Df3n0RUP.js';
import * as _backstage_frontend_plugin_api from '@backstage/frontend-plugin-api';
import { CompoundEntityRef, Entity } from '@backstage/catalog-model';
import * as react_jsx_runtime from 'react/jsx-runtime';
import { AsyncState } from 'react-use/esm/useAsync';
import { Config } from '@backstage/config';
/**
* Key for each addon.
* @public
*/
declare const TECHDOCS_ADDONS_KEY = "techdocs.addons.addon.v1";
/**
* Marks the `<TechDocsAddons>` registry component.
* @public
*/
declare const TECHDOCS_ADDONS_WRAPPER_KEY = "techdocs.addons.wrapper.v1";
/**
* TechDocs Addon registry.
* @public
*/
declare const TechDocsAddons: ComponentType<PropsWithChildren<{}>>;
/**
* Create a TechDocs addon overload signature without props.
* @public
*/
declare function createTechDocsAddonExtension(options: TechDocsAddonOptions): Extension<() => JSX.Element | null>;
/**
* Create a TechDocs addon overload signature with props.
* @public
*/
declare function createTechDocsAddonExtension<TComponentProps>(options: TechDocsAddonOptions<TComponentProps>): Extension<(props: TComponentProps) => JSX.Element | null>;
/**
* hook to use addons in components
* @public
*/
declare const useTechDocsAddons: () => {
renderComponentByName: (name: string) => JSX.Element | null;
renderComponentsByLocation: (location: keyof typeof TechDocsAddonLocations) => (JSX.Element | null)[] | null;
};
/**
* API to talk to techdocs-backend.
*
* @public
*/
interface TechDocsApi {
getCookie(): Promise<{
expiresAt: string;
}>;
getApiOrigin(): Promise<string>;
getTechDocsMetadata(entityId: CompoundEntityRef): Promise<TechDocsMetadata>;
getEntityMetadata(entityId: CompoundEntityRef): Promise<TechDocsEntityMetadata>;
}
/**
* Utility API reference for the {@link TechDocsApi}.
*
* @public
*/
declare const techdocsApiRef: _backstage_frontend_plugin_api.ApiRef<TechDocsApi>;
/**
* The outcome of a docs sync operation.
*
* @public
*/
type SyncResult = 'cached' | 'updated';
/**
* API which talks to TechDocs storage to fetch files to render.
*
* @public
*/
interface TechDocsStorageApi {
getApiOrigin(): Promise<string>;
getStorageUrl(): Promise<string>;
getBuilder(): Promise<string>;
getEntityDocs(entityId: CompoundEntityRef, path: string): Promise<string>;
syncEntityDocs(entityId: CompoundEntityRef, logHandler?: (line: string) => void): Promise<SyncResult>;
getBaseUrl(oldBaseUrl: string, entityId: CompoundEntityRef, path: string): Promise<string>;
}
/**
* Utility API reference for the {@link TechDocsStorageApi}.
*
* @public
*/
declare const techdocsStorageApiRef: _backstage_frontend_plugin_api.ApiRef<TechDocsStorageApi>;
/**
* @public type for the value of the TechDocsReaderPageContext
*/
type TechDocsReaderPageValue = {
metadata: AsyncState<TechDocsMetadata>;
entityRef: CompoundEntityRef;
entityMetadata: AsyncState<TechDocsEntityMetadata>;
shadowRoot?: ShadowRoot;
setShadowRoot: Dispatch<SetStateAction<ShadowRoot | undefined>>;
title: string;
setTitle: Dispatch<SetStateAction<string>>;
subtitle: string;
setSubtitle: Dispatch<SetStateAction<string>>;
/**
* @deprecated property can be passed down directly to the `TechDocsReaderPageContent` instead.
*/
onReady?: () => void;
};
/**
* render function for {@link TechDocsReaderPageProvider}
*
* @public
*/
type TechDocsReaderPageProviderRenderFunction = (value: TechDocsReaderPageValue) => JSX.Element;
/**
* Props for {@link TechDocsReaderPageProvider}
*
* @public
*/
type TechDocsReaderPageProviderProps = {
entityRef: CompoundEntityRef;
children: TechDocsReaderPageProviderRenderFunction | ReactNode;
};
/**
* A context to store the reader page state
* @public
*/
declare const TechDocsReaderPageProvider: react.MemoExoticComponent<(props: TechDocsReaderPageProviderProps) => react_jsx_runtime.JSX.Element>;
/**
* Hook used to get access to shared state between reader page components.
* @public
*/
declare const useTechDocsReaderPage: () => TechDocsReaderPageValue;
/**
* Name for the event dispatched when ShadowRoot styles are loaded.
* @public
*/
declare const SHADOW_DOM_STYLE_LOAD_EVENT = "TECH_DOCS_SHADOW_DOM_STYLE_LOAD";
/**
* Returns the style's loading state.
*
* @example
* Here's an example that updates the sidebar position only after styles are calculated:
* ```jsx
* import {
* TechDocsShadowDom,
* useShadowDomStylesLoading,
* } from '@backstage/plugin-techdocs-react';
*
* export const TechDocsReaderPageContent = () => {
* // ...
* const dom = useTechDocsReaderDom(entity);
* const isStyleLoading = useShadowDomStylesLoading(dom);
*
* const updateSidebarPosition = useCallback(() => {
* //...
* }, [dom]);
*
* useEffect(() => {
* if (!isStyleLoading) {
* updateSidebarPosition();
* }
* }, [isStyleLoading, updateSidebarPosition]);
*
* const handleDomAppend = useCallback(
* (newShadowRoot: ShadowRoot) => {
* setShadowRoot(newShadowRoot);
* },
* [setShadowRoot],
* );
*
* return <TechDocsShadowDom element={dom} onAppend={handleDomAppend} />;
* };
* ```
*
* @param element - which is the ShadowRoot tree.
* @returns a boolean value, true if styles are being loaded.
* @public
*/
declare const useShadowDomStylesLoading: (element: Element | null) => boolean;
/**
* Props for {@link TechDocsShadowDom}.
*
* @remarks
* If you want to use portals to render Material UI components in the Shadow DOM,
* you must render these portals as children because this component wraps its children in a Material UI StylesProvider
* to ensure that Material UI styles are applied.
*
* @public
*/
type TechDocsShadowDomProps = PropsWithChildren<{
/**
* Element tree that is appended to ShadowRoot.
*/
element: Element;
/**
* Callback called when the element tree is appended in ShadowRoot.
*/
onAppend?: (shadowRoot: ShadowRoot) => void;
}>;
/**
* Renders a tree of elements in a Shadow DOM.
*
* @remarks
* Centers the styles loaded event to avoid having multiple locations setting the opacity style in Shadow DOM causing the screen to flash multiple times,
* so if you want to know when Shadow DOM styles are computed, you can listen for the "TECH_DOCS_SHADOW_DOM_STYLE_LOAD" event dispatched by the element tree.
*
* @example
* Here is an example using this component and also listening for styles loaded event:
*```jsx
* import {
* TechDocsShadowDom,
* SHADOW_DOM_STYLE_LOAD_EVENT,
* } from '@backstage/plugin-techdocs-react';
*
* export const TechDocsReaderPageContent = ({ entity }: TechDocsReaderPageContentProps) => {
* // ...
* const dom = useTechDocsReaderDom(entity);
*
* useEffect(() => {
* const updateSidebarPosition = () => {
* // ...
* };
* dom?.addEventListener(SHADOW_DOM_STYLE_LOAD_EVENT, updateSidebarPosition);
* return () => {
* dom?.removeEventListener(SHADOW_DOM_STYLE_LOAD_EVENT, updateSidebarPosition);
* };
* }, [dom]);
*
* const handleDomAppend = useCallback(
* (newShadowRoot: ShadowRoot) => {
* setShadowRoot(newShadowRoot);
* },
* [setShadowRoot],
* );
*
* return <TechDocsShadowDom element={dom} onAppend={handleDomAppend} />;
* };
* ```
*
* @param props - see {@link TechDocsShadowDomProps}.
* @public
*/
declare const TechDocsShadowDom: (props: TechDocsShadowDomProps) => react_jsx_runtime.JSX.Element;
/**
* Hook for use within TechDocs addons that provides access to the underlying
* shadow root of the current page, allowing the DOM within to be mutated.
* @public
*/
declare const useShadowRoot: () => ShadowRoot | undefined;
/**
* Convenience hook for use within TechDocs addons that provides access to
* elements that match a given selector within the shadow root.
*
* @public
*/
declare const useShadowRootElements: <TReturnedElement extends HTMLElement = HTMLElement>(selectors: string[]) => TReturnedElement[];
/**
* Hook for retrieving a selection within the ShadowRoot.
* @public
*/
declare const useShadowRootSelection: (waitMillis?: number) => Selection | null;
/**
* Lower-case entity triplets by default, but allow override.
*
* @public
*/
declare function toLowercaseEntityRefMaybe(entityRef: CompoundEntityRef, config: Config): CompoundEntityRef;
/**
* Get the entity path annotation from the given entity and ensure it starts with a slash.
*
* @public
*/
declare function getEntityRootTechDocsPath(entity: Entity): string;
/**
* Build the TechDocs URL for the given entity. This helper should be used anywhere there
* is a link to an entity's TechDocs.
*
* @public
*/
declare const buildTechDocsURL: (entity: Entity, routeFunc: RouteFunc<{
namespace: string;
kind: string;
name: string;
}> | undefined) => string | undefined;
export { SHADOW_DOM_STYLE_LOAD_EVENT, TECHDOCS_ADDONS_KEY, TECHDOCS_ADDONS_WRAPPER_KEY, TechDocsAddonLocations, TechDocsAddonOptions, TechDocsAddons, TechDocsEntityMetadata, TechDocsMetadata, TechDocsReaderPageProvider, TechDocsShadowDom, buildTechDocsURL, createTechDocsAddonExtension, getEntityRootTechDocsPath, techdocsApiRef, techdocsStorageApiRef, toLowercaseEntityRefMaybe, useShadowDomStylesLoading, useShadowRoot, useShadowRootElements, useShadowRootSelection, useTechDocsAddons, useTechDocsReaderPage };
export type { SyncResult, TechDocsApi, TechDocsReaderPageProviderProps, TechDocsReaderPageProviderRenderFunction, TechDocsReaderPageValue, TechDocsShadowDomProps, TechDocsStorageApi };