Review feedback.
Co-authored-by: Emma Indal <emma.indahl@gmail.com> Co-authored-by: Anders Näsman <andersn@spotify.com> Signed-off-by: Eric Peterson <ericpeterson@spotify.com>
This commit is contained in:
committed by
Emma Indal
parent
ff1cc8bced
commit
d8db6db3d7
@@ -18,7 +18,10 @@ then be composed within a Backstage app.
|
||||
When you create a new Addon, it requires three things.
|
||||
|
||||
1. A `name` for debugging and analytics purposes)
|
||||
2. A `location`, indicating where/how the addon will be rendered
|
||||
2. A `location`, indicating where/how the addon will be rendered. Valid
|
||||
locations include: `header`, `subheader`, `primary sidebar`,
|
||||
`secondary sidebar`, `content`, and `component`. Values are available on an
|
||||
enumerable `TechDocsAddonLocations` and are type-hinted.
|
||||
3. A `component`, encapsulating the addon's logic and functionality
|
||||
|
||||
```tsx
|
||||
@@ -31,7 +34,7 @@ import { StackOverflowSecondarySidebarAddon } from './components';
|
||||
export const StackOverflowSecondarySidebar = yourBackstagePlugin.provide(
|
||||
createTechDocsAddon({
|
||||
name: 'StackOverflowSecondarySidebar',
|
||||
type: TechDocsAddonLocations.SECONDARY_SIDEBAR,
|
||||
location: TechDocsAddonLocations.SECONDARY_SIDEBAR,
|
||||
component: StackOverflowSecondarySidebarAddon,
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -100,7 +100,7 @@ export const useTechDocsAddons = () => {
|
||||
[collection],
|
||||
);
|
||||
|
||||
const renderComponentWithName = useCallback(
|
||||
const renderComponentByName = useCallback(
|
||||
(name: string) => {
|
||||
const data = options.find(option => option.name === name);
|
||||
return data ? findAddonByData(data) : null;
|
||||
@@ -108,7 +108,7 @@ export const useTechDocsAddons = () => {
|
||||
[options, findAddonByData],
|
||||
);
|
||||
|
||||
const renderComponentsWithLocation = useCallback(
|
||||
const renderComponentsByLocation = useCallback(
|
||||
(location: TechDocsAddonLocations) => {
|
||||
const data = options.filter(option => option.location === location);
|
||||
return data.length ? data.map(findAddonByData) : null;
|
||||
@@ -116,5 +116,5 @@ export const useTechDocsAddons = () => {
|
||||
[options, findAddonByData],
|
||||
);
|
||||
|
||||
return { renderComponentWithName, renderComponentsWithLocation };
|
||||
return { renderComponentByName, renderComponentsByLocation };
|
||||
};
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { CompoundEntityRef } from '@backstage/catalog-model';
|
||||
import { Page } from '@backstage/core-components';
|
||||
// todo(backstage/techdocs-core): Export these from @backstage/plugin-techdocs
|
||||
import {
|
||||
withTechDocsReaderProvider,
|
||||
// @ts-ignore
|
||||
TechDocsStateIndicator as TechDocReaderPageIndicator,
|
||||
} from '@backstage/plugin-techdocs';
|
||||
import React from 'react';
|
||||
|
||||
import {
|
||||
TechDocsMetadataProvider,
|
||||
TechDocsEntityProvider,
|
||||
TechDocsReaderPageProvider,
|
||||
} from '../../context';
|
||||
import { TechDocsReaderPageContent } from '../TechDocsReaderPageContent';
|
||||
import { TechDocsReaderPageHeader } from '../TechDocsReaderPageHeader';
|
||||
import { TechDocsReaderPageSubheader } from '../TechDocsReaderPageSubheader';
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type TechDocsReaderPageProps = { entityName: CompoundEntityRef };
|
||||
|
||||
/**
|
||||
* An addon-aware implementation of the TechDocsReaderPage.
|
||||
* @public
|
||||
*/
|
||||
export const TechDocsReaderPage = (props: TechDocsReaderPageProps) => {
|
||||
const { entityName } = props;
|
||||
const Component = withTechDocsReaderProvider(() => {
|
||||
return (
|
||||
<TechDocsMetadataProvider entityName={entityName}>
|
||||
<TechDocsEntityProvider entityName={entityName}>
|
||||
<TechDocsReaderPageProvider entityName={entityName}>
|
||||
<Page themeId="documentation">
|
||||
<TechDocsReaderPageHeader />
|
||||
<TechDocsReaderPageSubheader />
|
||||
<TechDocReaderPageIndicator />
|
||||
<TechDocsReaderPageContent />
|
||||
</Page>
|
||||
</TechDocsReaderPageProvider>
|
||||
</TechDocsEntityProvider>
|
||||
</TechDocsMetadataProvider>
|
||||
);
|
||||
}, entityName);
|
||||
return <Component />;
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { TechDocsReaderPage } from './TechDocsReaderPage';
|
||||
export type { TechDocsReaderPageProps } from './TechDocsReaderPage';
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Content, Progress } from '@backstage/core-components';
|
||||
// todo(backstage/techdocs-core): Export these from @backstage/plugin-techdocs
|
||||
// @ts-ignore
|
||||
import { useTechDocsReaderDom } from '@backstage/plugin-techdocs';
|
||||
import { Portal } from '@material-ui/core';
|
||||
import { StylesProvider, jssPreset } from '@material-ui/styles';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { create } from 'jss';
|
||||
|
||||
import { useTechDocsAddons } from '../../addons';
|
||||
import { useTechDocsReaderPage } from '../../context';
|
||||
import { TechDocsAddonLocations as locations } from '../../types';
|
||||
|
||||
export const TechDocsReaderPageContent = () => {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const [jss, setJss] = useState(
|
||||
create({
|
||||
...jssPreset(),
|
||||
insertionPoint: undefined,
|
||||
}),
|
||||
);
|
||||
|
||||
const addons = useTechDocsAddons();
|
||||
const { entityName, setShadowRoot } = useTechDocsReaderPage();
|
||||
const dom = useTechDocsReaderDom(entityName);
|
||||
|
||||
useEffect(() => {
|
||||
const shadowHost = ref.current;
|
||||
if (!dom || !shadowHost || shadowHost.shadowRoot) return;
|
||||
|
||||
setJss(
|
||||
create({
|
||||
...jssPreset(),
|
||||
insertionPoint: dom.querySelector('head') || undefined,
|
||||
}),
|
||||
);
|
||||
|
||||
const shadowRoot = shadowHost.attachShadow({ mode: 'open' });
|
||||
shadowRoot.innerHTML = '';
|
||||
shadowRoot.appendChild(dom);
|
||||
setShadowRoot(shadowRoot);
|
||||
}, [dom, setShadowRoot]);
|
||||
|
||||
const contentElement = ref.current?.shadowRoot?.querySelector(
|
||||
'[data-md-component="container"]',
|
||||
);
|
||||
const primarySidebarElement = ref.current?.shadowRoot?.querySelector(
|
||||
'[data-md-component="navigation"]',
|
||||
);
|
||||
const secondarySidebarElement = ref.current?.shadowRoot?.querySelector(
|
||||
'[data-md-component="toc"]',
|
||||
);
|
||||
|
||||
const primarySidebarAddonLocation = document.createElement('div');
|
||||
primarySidebarElement?.prepend(primarySidebarAddonLocation);
|
||||
|
||||
const secondarySidebarAddonLocation = document.createElement('div');
|
||||
secondarySidebarElement?.prepend(secondarySidebarAddonLocation);
|
||||
|
||||
// do not return content until dom is ready
|
||||
if (!dom) {
|
||||
return (
|
||||
<Content>
|
||||
<Progress />
|
||||
</Content>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Content>
|
||||
{/* sheetsManager={new Map()} is needed in order to deduplicate the injection of CSS in the page. */}
|
||||
<StylesProvider jss={jss} sheetsManager={new Map()}>
|
||||
<div ref={ref} data-testid="techdocs-native-shadowroot" />
|
||||
<Portal container={primarySidebarAddonLocation}>
|
||||
{addons.renderComponentsByLocation(locations.PRIMARY_SIDEBAR)}
|
||||
</Portal>
|
||||
<Portal container={contentElement}>
|
||||
{addons.renderComponentsByLocation(locations.CONTENT)}
|
||||
</Portal>
|
||||
<Portal container={secondarySidebarAddonLocation}>
|
||||
{addons.renderComponentsByLocation(locations.SECONDARY_SIDEBAR)}
|
||||
</Portal>
|
||||
</StylesProvider>
|
||||
</Content>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { TechDocsReaderPageContent } from './TechDocsReaderPageContent';
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Header } from '@backstage/core-components';
|
||||
import { configApiRef, useApi } from '@backstage/core-plugin-api';
|
||||
// todo(backstage/techdocs-core): Export these from @backstage/plugin-techdocs
|
||||
import { Skeleton } from '@material-ui/lab';
|
||||
import React, { useEffect } from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
|
||||
import { useTechDocsAddons } from '../../addons';
|
||||
import { useMetadata, useTechDocsReaderPage } from '../../context';
|
||||
import { TechDocsAddonLocations as locations } from '../../types';
|
||||
|
||||
const skeleton = <Skeleton animation="wave" variant="text" height={40} />;
|
||||
|
||||
export const TechDocsReaderPageHeader = () => {
|
||||
const addons = useTechDocsAddons();
|
||||
const configApi = useApi(configApiRef);
|
||||
|
||||
const metadata = useMetadata();
|
||||
|
||||
const { title, setTitle, subtitle, setSubtitle } = useTechDocsReaderPage();
|
||||
|
||||
useEffect(() => {
|
||||
if (!metadata) return;
|
||||
setTitle(prevTitle => prevTitle || metadata.site_name);
|
||||
setSubtitle(
|
||||
prevSubtitle => prevSubtitle || metadata.site_description || 'Home',
|
||||
);
|
||||
}, [metadata, setTitle, setSubtitle]);
|
||||
|
||||
const appTitle = configApi.getOptional('app.title') || 'Backstage';
|
||||
const tabTitle = [subtitle, title, appTitle].filter(Boolean).join(' | ');
|
||||
|
||||
return (
|
||||
<Header
|
||||
type="Documentation"
|
||||
title={title || skeleton}
|
||||
subtitle={subtitle || skeleton}
|
||||
>
|
||||
<Helmet titleTemplate="%s">
|
||||
<title>{tabTitle}</title>
|
||||
</Helmet>
|
||||
{addons.renderComponentsByLocation(locations.HEADER)}
|
||||
</Header>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { TechDocsReaderPageHeader } from './TechDocsReaderPageHeader';
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Box, Toolbar, ToolbarProps, withStyles } from '@material-ui/core';
|
||||
import React from 'react';
|
||||
|
||||
import { useTechDocsAddons } from '../../addons';
|
||||
import { TechDocsAddonLocations as locations } from '../../types';
|
||||
|
||||
export const TechDocsReaderPageSubheader = withStyles(theme => ({
|
||||
root: {
|
||||
gridArea: 'pageSubheader',
|
||||
flexDirection: 'column',
|
||||
minHeight: 'auto',
|
||||
padding: theme.spacing(3, 3, 0),
|
||||
},
|
||||
}))(({ ...rest }: ToolbarProps) => {
|
||||
const addons = useTechDocsAddons();
|
||||
|
||||
if (!addons.renderComponentsByLocation(locations.SUBHEADER)) return null;
|
||||
|
||||
return (
|
||||
<Toolbar {...rest}>
|
||||
{addons.renderComponentsByLocation(locations.SUBHEADER) && (
|
||||
<Box
|
||||
display="flex"
|
||||
justifyContent="flex-end"
|
||||
width="100%"
|
||||
flexWrap="wrap"
|
||||
>
|
||||
{addons.renderComponentsByLocation(locations.SUBHEADER)}
|
||||
</Box>
|
||||
)}
|
||||
</Toolbar>
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { TechDocsReaderPageSubheader } from './TechDocsReaderPageSubheader';
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export * from './TechDocsReaderPage';
|
||||
@@ -21,12 +21,11 @@
|
||||
*/
|
||||
|
||||
export { createTechDocsAddon, TechDocsAddons } from './addons';
|
||||
export * from './components';
|
||||
export {
|
||||
useEntityMetadata,
|
||||
useMetadata,
|
||||
useShadowRoot,
|
||||
useShadowRootElements,
|
||||
} from './context';
|
||||
export { TechDocsReaderPage } from './reader';
|
||||
export type { TechDocsReaderPageProps } from './reader';
|
||||
export type { TechDocsAddonLocations, TechDocsAddonOptions } from './types';
|
||||
|
||||
@@ -1,217 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { CompoundEntityRef } from '@backstage/catalog-model';
|
||||
import { Content, Header, Page, Progress } from '@backstage/core-components';
|
||||
import { configApiRef, useApi } from '@backstage/core-plugin-api';
|
||||
// todo(backstage/techdocs-core): Export these from @backstage/plugin-techdocs
|
||||
import {
|
||||
// @ts-ignore
|
||||
useTechDocsReaderDom,
|
||||
// @ts-ignore
|
||||
withTechDocsReaderProvider,
|
||||
// @ts-ignore
|
||||
TechDocsStateIndicator as TechDocReaderPageIndicator,
|
||||
} from '@backstage/plugin-techdocs';
|
||||
import {
|
||||
withStyles,
|
||||
Portal,
|
||||
Box,
|
||||
Toolbar,
|
||||
ToolbarProps,
|
||||
} from '@material-ui/core';
|
||||
import { Skeleton } from '@material-ui/lab';
|
||||
import { StylesProvider, jssPreset } from '@material-ui/styles';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { create } from 'jss';
|
||||
import Helmet from 'react-helmet';
|
||||
|
||||
import { useTechDocsAddons } from './addons';
|
||||
import {
|
||||
TechDocsMetadataProvider,
|
||||
useMetadata,
|
||||
TechDocsEntityProvider,
|
||||
TechDocsReaderPageProvider,
|
||||
useTechDocsReaderPage,
|
||||
} from './context';
|
||||
import { TechDocsAddonLocations as locations } from './types';
|
||||
|
||||
const TechDocsReaderPageSubheader = withStyles(theme => ({
|
||||
root: {
|
||||
gridArea: 'pageSubheader',
|
||||
flexDirection: 'column',
|
||||
minHeight: 'auto',
|
||||
padding: theme.spacing(3, 3, 0),
|
||||
},
|
||||
}))(({ ...rest }: ToolbarProps) => {
|
||||
const addons = useTechDocsAddons();
|
||||
|
||||
if (!addons.renderComponentsWithLocation(locations.SUBHEADER)) return null;
|
||||
|
||||
return (
|
||||
<Toolbar {...rest}>
|
||||
{addons.renderComponentsWithLocation(locations.SUBHEADER) && (
|
||||
<Box
|
||||
display="flex"
|
||||
justifyContent="flex-end"
|
||||
width="100%"
|
||||
flexWrap="wrap"
|
||||
>
|
||||
{addons.renderComponentsWithLocation(locations.SUBHEADER)}
|
||||
</Box>
|
||||
)}
|
||||
</Toolbar>
|
||||
);
|
||||
});
|
||||
|
||||
const skeleton = <Skeleton animation="wave" variant="text" height={40} />;
|
||||
|
||||
const TechDocsReaderPageHeader = () => {
|
||||
const addons = useTechDocsAddons();
|
||||
const configApi = useApi(configApiRef);
|
||||
|
||||
const metadata = useMetadata();
|
||||
|
||||
const { title, setTitle, subtitle, setSubtitle } = useTechDocsReaderPage();
|
||||
|
||||
useEffect(() => {
|
||||
if (!metadata) return;
|
||||
setTitle(prevTitle => prevTitle || metadata.site_name);
|
||||
setSubtitle(
|
||||
prevSubtitle => prevSubtitle || metadata.site_description || 'Home',
|
||||
);
|
||||
}, [metadata, setTitle, setSubtitle]);
|
||||
|
||||
const appTitle = configApi.getOptional('app.title') || 'Backstage';
|
||||
const tabTitle = [subtitle, title, appTitle].filter(Boolean).join(' | ');
|
||||
|
||||
return (
|
||||
<Header
|
||||
type="Documentation"
|
||||
title={title || skeleton}
|
||||
subtitle={subtitle || skeleton}
|
||||
>
|
||||
<Helmet titleTemplate="%s">
|
||||
<title>{tabTitle}</title>
|
||||
</Helmet>
|
||||
{addons.renderComponentsWithLocation(locations.HEADER)}
|
||||
</Header>
|
||||
);
|
||||
};
|
||||
|
||||
const TechDocsReaderPageContent = () => {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const [jss, setJss] = useState(
|
||||
create({
|
||||
...jssPreset(),
|
||||
insertionPoint: undefined,
|
||||
}),
|
||||
);
|
||||
|
||||
const addons = useTechDocsAddons();
|
||||
const { entityName, setShadowRoot } = useTechDocsReaderPage();
|
||||
const dom = useTechDocsReaderDom(entityName);
|
||||
|
||||
useEffect(() => {
|
||||
const shadowHost = ref.current;
|
||||
if (!dom || !shadowHost || shadowHost.shadowRoot) return;
|
||||
|
||||
setJss(
|
||||
create({
|
||||
...jssPreset(),
|
||||
insertionPoint: dom.querySelector('head') || undefined,
|
||||
}),
|
||||
);
|
||||
|
||||
const shadowRoot = shadowHost.attachShadow({ mode: 'open' });
|
||||
shadowRoot.innerHTML = '';
|
||||
shadowRoot.appendChild(dom);
|
||||
setShadowRoot(shadowRoot);
|
||||
}, [dom, setShadowRoot]);
|
||||
|
||||
const contentElement = ref.current?.shadowRoot?.querySelector(
|
||||
'[data-md-component="container"]',
|
||||
);
|
||||
const primarySidebarElement = ref.current?.shadowRoot?.querySelector(
|
||||
'[data-md-component="navigation"]',
|
||||
);
|
||||
const secondarySidebarElement = ref.current?.shadowRoot?.querySelector(
|
||||
'[data-md-component="toc"]',
|
||||
);
|
||||
|
||||
const primarySidebarAddonSpace = document.createElement('div');
|
||||
primarySidebarElement?.prepend(primarySidebarAddonSpace);
|
||||
|
||||
const secondarySidebarAddonSpace = document.createElement('div');
|
||||
secondarySidebarElement?.prepend(secondarySidebarAddonSpace);
|
||||
|
||||
// do not return content until dom is ready
|
||||
if (!dom) {
|
||||
return (
|
||||
<Content>
|
||||
<Progress />
|
||||
</Content>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Content>
|
||||
{/* sheetsManager={new Map()} is needed in order to deduplicate the injection of CSS in the page. */}
|
||||
<StylesProvider jss={jss} sheetsManager={new Map()}>
|
||||
<div ref={ref} data-testid="techdocs-native-shadowroot" />
|
||||
<Portal container={primarySidebarAddonSpace}>
|
||||
{addons.renderComponentsWithLocation(locations.PRIMARY_SIDEBAR)}
|
||||
</Portal>
|
||||
<Portal container={contentElement}>
|
||||
{addons.renderComponentsWithLocation(locations.CONTENT)}
|
||||
</Portal>
|
||||
<Portal container={secondarySidebarAddonSpace}>
|
||||
{addons.renderComponentsWithLocation(locations.SECONDARY_SIDEBAR)}
|
||||
</Portal>
|
||||
</StylesProvider>
|
||||
</Content>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type TechDocsReaderPageProps = { entityName: CompoundEntityRef };
|
||||
|
||||
/**
|
||||
* An addon-aware implementation of the TechDocsReaderPage.
|
||||
* @public
|
||||
*/
|
||||
export const TechDocsReaderPage = (props: TechDocsReaderPageProps) => {
|
||||
const { entityName } = props;
|
||||
const Component = withTechDocsReaderProvider(() => {
|
||||
return (
|
||||
<TechDocsMetadataProvider entityName={entityName}>
|
||||
<TechDocsEntityProvider entityName={entityName}>
|
||||
<TechDocsReaderPageProvider entityName={entityName}>
|
||||
<Page themeId="documentation">
|
||||
<TechDocsReaderPageHeader />
|
||||
<TechDocsReaderPageSubheader />
|
||||
<TechDocReaderPageIndicator />
|
||||
<TechDocsReaderPageContent />
|
||||
</Page>
|
||||
</TechDocsReaderPageProvider>
|
||||
</TechDocsEntityProvider>
|
||||
</TechDocsMetadataProvider>
|
||||
);
|
||||
}, entityName);
|
||||
return <Component />;
|
||||
};
|
||||
Reference in New Issue
Block a user