@backstage/plugin-techdocs 1.13.0-next.0 → 1.13.0-next.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,57 @@
1
1
  # @backstage/plugin-techdocs
2
2
 
3
+ ## 1.13.0-next.2
4
+
5
+ ### Minor Changes
6
+
7
+ - 3c59ece: **New Frontend System Only:**
8
+ The `TechDocs` plugin is now responsible for providing an entity icon link extension to read documentation from the catalog entity page.
9
+
10
+ ### Patch Changes
11
+
12
+ - Updated dependencies
13
+ - @backstage/core-components@0.17.3-next.0
14
+ - @backstage/plugin-catalog-react@1.19.0-next.2
15
+ - @backstage/plugin-search-react@1.9.1-next.1
16
+ - @backstage/frontend-plugin-api@0.10.3-next.1
17
+ - @backstage/integration-react@1.2.7
18
+ - @backstage/plugin-auth-react@0.1.16-next.0
19
+ - @backstage/plugin-techdocs-react@1.3.0-next.1
20
+ - @backstage/catalog-client@1.10.1-next.0
21
+ - @backstage/catalog-model@1.7.4
22
+ - @backstage/config@1.3.2
23
+ - @backstage/core-compat-api@0.4.3-next.2
24
+ - @backstage/core-plugin-api@1.10.7
25
+ - @backstage/errors@1.2.7
26
+ - @backstage/integration@1.17.0
27
+ - @backstage/theme@0.6.6
28
+ - @backstage/plugin-search-common@1.2.18
29
+ - @backstage/plugin-techdocs-common@0.1.1-next.0
30
+
31
+ ## 1.13.0-next.1
32
+
33
+ ### Patch Changes
34
+
35
+ - 9dde3ba: Improved Keyboard accessibility in techdocs.
36
+ - Updated dependencies
37
+ - @backstage/catalog-client@1.10.1-next.0
38
+ - @backstage/plugin-catalog-react@1.18.1-next.1
39
+ - @backstage/catalog-model@1.7.4
40
+ - @backstage/config@1.3.2
41
+ - @backstage/core-compat-api@0.4.3-next.1
42
+ - @backstage/core-components@0.17.2
43
+ - @backstage/core-plugin-api@1.10.7
44
+ - @backstage/errors@1.2.7
45
+ - @backstage/frontend-plugin-api@0.10.3-next.0
46
+ - @backstage/integration@1.17.0
47
+ - @backstage/integration-react@1.2.7
48
+ - @backstage/theme@0.6.6
49
+ - @backstage/plugin-auth-react@0.1.15
50
+ - @backstage/plugin-search-common@1.2.18
51
+ - @backstage/plugin-search-react@1.9.1-next.0
52
+ - @backstage/plugin-techdocs-common@0.1.1-next.0
53
+ - @backstage/plugin-techdocs-react@1.3.0-next.0
54
+
3
55
  ## 1.13.0-next.0
4
56
 
5
57
  ### Minor Changes
@@ -0,0 +1,24 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import DocsIcon from '@material-ui/icons/Description';
3
+ import { useRouteRef } from '@backstage/core-plugin-api';
4
+ import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
5
+ import { TECHDOCS_ANNOTATION, TECHDOCS_EXTERNAL_ANNOTATION } from '@backstage/plugin-techdocs-common';
6
+ import { buildTechDocsURL } from '@backstage/plugin-techdocs-react';
7
+ import { useEntity } from '@backstage/plugin-catalog-react';
8
+ import { techdocsTranslationRef } from '../../translation.esm.js';
9
+ import { rootDocsRouteRef } from '../../routes.esm.js';
10
+
11
+ function useTechdocsReaderIconLinkProps() {
12
+ const { entity } = useEntity();
13
+ const viewTechdocLink = useRouteRef(rootDocsRouteRef);
14
+ const { t } = useTranslationRef(techdocsTranslationRef);
15
+ return {
16
+ label: t("aboutCard.viewTechdocs"),
17
+ disabled: !(entity.metadata.annotations?.[TECHDOCS_ANNOTATION] || entity.metadata.annotations?.[TECHDOCS_EXTERNAL_ANNOTATION]) || !viewTechdocLink,
18
+ icon: /* @__PURE__ */ jsx(DocsIcon, {}),
19
+ href: buildTechDocsURL(entity, viewTechdocLink)
20
+ };
21
+ }
22
+
23
+ export { useTechdocsReaderIconLinkProps };
24
+ //# sourceMappingURL=useTechdocsReaderIconLinkProps.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTechdocsReaderIconLinkProps.esm.js","sources":["../../../src/alpha/hooks/useTechdocsReaderIconLinkProps.tsx"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport DocsIcon from '@material-ui/icons/Description';\n\nimport { useRouteRef } from '@backstage/core-plugin-api';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\n\nimport {\n TECHDOCS_ANNOTATION,\n TECHDOCS_EXTERNAL_ANNOTATION,\n} from '@backstage/plugin-techdocs-common';\nimport { buildTechDocsURL } from '@backstage/plugin-techdocs-react';\n\nimport { useEntity } from '@backstage/plugin-catalog-react';\n\nimport { techdocsTranslationRef } from '../../translation';\nimport { rootDocsRouteRef } from '../../routes';\n\n// Note: If you update this hook, please also update the \"useTechdocsReaderIconLinkProps\" hook\n// in the \"plugins/catalog/src/components/AboutCard/AboutCard.tsx\" file\n/** @alpha */\nexport function useTechdocsReaderIconLinkProps() {\n const { entity } = useEntity();\n const viewTechdocLink = useRouteRef(rootDocsRouteRef);\n const { t } = useTranslationRef(techdocsTranslationRef);\n\n return {\n label: t('aboutCard.viewTechdocs'),\n disabled:\n !(\n entity.metadata.annotations?.[TECHDOCS_ANNOTATION] ||\n entity.metadata.annotations?.[TECHDOCS_EXTERNAL_ANNOTATION]\n ) || !viewTechdocLink,\n icon: <DocsIcon />,\n href: buildTechDocsURL(entity, viewTechdocLink),\n };\n}\n"],"names":[],"mappings":";;;;;;;;;;AAmCO,SAAS,8BAAiC,GAAA;AAC/C,EAAM,MAAA,EAAE,MAAO,EAAA,GAAI,SAAU,EAAA;AAC7B,EAAM,MAAA,eAAA,GAAkB,YAAY,gBAAgB,CAAA;AACpD,EAAA,MAAM,EAAE,CAAA,EAAM,GAAA,iBAAA,CAAkB,sBAAsB,CAAA;AAEtD,EAAO,OAAA;AAAA,IACL,KAAA,EAAO,EAAE,wBAAwB,CAAA;AAAA,IACjC,QACE,EAAA,EACE,MAAO,CAAA,QAAA,CAAS,WAAc,GAAA,mBAAmB,CACjD,IAAA,MAAA,CAAO,QAAS,CAAA,WAAA,GAAc,4BAA4B,CAAA,CAAA,IACvD,CAAC,eAAA;AAAA,IACR,IAAA,sBAAO,QAAS,EAAA,EAAA,CAAA;AAAA,IAChB,IAAA,EAAM,gBAAiB,CAAA,MAAA,EAAQ,eAAe;AAAA,GAChD;AACF;;;;"}
package/dist/alpha.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as _backstage_core_plugin_api from '@backstage/core-plugin-api';
2
+ import * as _backstage_core_components from '@backstage/core-components';
2
3
  import * as _backstage_plugin_techdocs_react from '@backstage/plugin-techdocs-react';
3
4
  import * as _backstage_catalog_model from '@backstage/catalog-model';
4
5
  import * as _backstage_plugin_catalog_react_alpha from '@backstage/plugin-catalog-react/alpha';
@@ -131,6 +132,30 @@ declare const _default: _backstage_frontend_plugin_api.FrontendPlugin<{
131
132
  filter?: string | _backstage_plugin_catalog_react_alpha.EntityPredicate | ((entity: _backstage_catalog_model.Entity) => boolean);
132
133
  };
133
134
  }>;
135
+ "entity-icon-link:techdocs/read-docs": _backstage_frontend_plugin_api.ExtensionDefinition<{
136
+ kind: "entity-icon-link";
137
+ name: "read-docs";
138
+ config: {
139
+ label: string | undefined;
140
+ title: string | undefined;
141
+ filter: _backstage_plugin_catalog_react_alpha.EntityPredicate | undefined;
142
+ };
143
+ configInput: {
144
+ filter?: _backstage_plugin_catalog_react_alpha.EntityPredicate | undefined;
145
+ label?: string | undefined;
146
+ title?: string | undefined;
147
+ };
148
+ output: _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<(entity: _backstage_catalog_model.Entity) => boolean, "catalog.entity-filter-function", {
149
+ optional: true;
150
+ }> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<string, "catalog.entity-filter-expression", {
151
+ optional: true;
152
+ }> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<() => _backstage_core_components.IconLinkVerticalProps, "entity-icon-link-props", {}>;
153
+ inputs: {};
154
+ params: {
155
+ useProps: () => Omit<_backstage_core_components.IconLinkVerticalProps, "color">;
156
+ filter?: _backstage_plugin_catalog_react_alpha.EntityPredicate | ((entity: _backstage_catalog_model.Entity) => boolean);
157
+ };
158
+ }>;
134
159
  "nav-item:techdocs": _backstage_frontend_plugin_api.ExtensionDefinition<{
135
160
  kind: "nav-item";
136
161
  name: undefined;
package/dist/alpha.esm.js CHANGED
@@ -3,7 +3,7 @@ import LibraryBooks from '@material-ui/icons/LibraryBooks';
3
3
  import { ApiBlueprint, PageBlueprint, createExtensionInput, coreExtensionData, createExtension, NavItemBlueprint, createFrontendPlugin } from '@backstage/frontend-plugin-api';
4
4
  import { createApiFactory, configApiRef, discoveryApiRef, fetchApiRef } from '@backstage/core-plugin-api';
5
5
  import { compatWrapper, convertLegacyRouteRef, convertLegacyRouteRefs } from '@backstage/core-compat-api';
6
- import { EntityContentBlueprint } from '@backstage/plugin-catalog-react/alpha';
6
+ import { EntityIconLinkBlueprint, EntityContentBlueprint } from '@backstage/plugin-catalog-react/alpha';
7
7
  import { SearchResultListItemBlueprint } from '@backstage/plugin-search-react/alpha';
8
8
  import { AddonBlueprint, attachTechDocsAddonComponentData } from '@backstage/plugin-techdocs-react/alpha';
9
9
  import { TechDocsStorageClient, TechDocsClient } from './client.esm.js';
@@ -23,7 +23,14 @@ import 'lodash/capitalize';
23
23
  import 'react-router-dom';
24
24
  import './reader/components/TechDocsReaderPageContent/TechDocsReaderPageContent.esm.js';
25
25
  import './reader/components/TechDocsReaderPageSubheader/TechDocsReaderPageSubheader.esm.js';
26
+ import { useTechdocsReaderIconLinkProps } from './alpha/hooks/useTechdocsReaderIconLinkProps.esm.js';
26
27
 
28
+ const techdocsEntityIconLink = EntityIconLinkBlueprint.make({
29
+ name: "read-docs",
30
+ params: {
31
+ useProps: useTechdocsReaderIconLinkProps
32
+ }
33
+ });
27
34
  const techDocsStorageApi = ApiBlueprint.make({
28
35
  name: "storage",
29
36
  params: {
@@ -170,7 +177,7 @@ const techDocsNavItem = NavItemBlueprint.make({
170
177
  routeRef: convertLegacyRouteRef(rootRouteRef)
171
178
  }
172
179
  });
173
- var alpha = createFrontendPlugin({
180
+ var index = createFrontendPlugin({
174
181
  pluginId: "techdocs",
175
182
  info: { packageJson: () => import('./package.json.esm.js') },
176
183
  extensions: [
@@ -179,6 +186,7 @@ var alpha = createFrontendPlugin({
179
186
  techDocsNavItem,
180
187
  techDocsPage,
181
188
  techDocsReaderPage,
189
+ techdocsEntityIconLink,
182
190
  techDocsEntityContent,
183
191
  techDocsEntityContentEmptyState,
184
192
  techDocsSearchResultListItemExtension
@@ -190,5 +198,5 @@ var alpha = createFrontendPlugin({
190
198
  })
191
199
  });
192
200
 
193
- export { alpha as default, techDocsSearchResultListItemExtension };
201
+ export { index as default, techDocsSearchResultListItemExtension };
194
202
  //# sourceMappingURL=alpha.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"alpha.esm.js","sources":["../src/alpha.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport LibraryBooks from '@material-ui/icons/LibraryBooks';\nimport {\n createFrontendPlugin,\n ApiBlueprint,\n PageBlueprint,\n NavItemBlueprint,\n createExtensionInput,\n coreExtensionData,\n createExtension,\n} from '@backstage/frontend-plugin-api';\nimport {\n configApiRef,\n createApiFactory,\n discoveryApiRef,\n fetchApiRef,\n} from '@backstage/core-plugin-api';\nimport {\n compatWrapper,\n convertLegacyRouteRef,\n convertLegacyRouteRefs,\n} from '@backstage/core-compat-api';\nimport { EntityContentBlueprint } from '@backstage/plugin-catalog-react/alpha';\nimport { SearchResultListItemBlueprint } from '@backstage/plugin-search-react/alpha';\nimport { AddonBlueprint } from '@backstage/plugin-techdocs-react/alpha';\nimport { TechDocsClient, TechDocsStorageClient } from './client';\nimport {\n rootCatalogDocsRouteRef,\n rootDocsRouteRef,\n rootRouteRef,\n} from './routes';\nimport { TechDocsReaderLayout } from './reader';\nimport { attachTechDocsAddonComponentData } from '@backstage/plugin-techdocs-react/alpha';\nimport {\n TechDocsAddons,\n techdocsApiRef,\n techdocsStorageApiRef,\n} from '@backstage/plugin-techdocs-react';\n\n/** @alpha */\nconst techDocsStorageApi = ApiBlueprint.make({\n name: 'storage',\n params: {\n factory: createApiFactory({\n api: techdocsStorageApiRef,\n deps: {\n configApi: configApiRef,\n discoveryApi: discoveryApiRef,\n fetchApi: fetchApiRef,\n },\n factory: ({ configApi, discoveryApi, fetchApi }) =>\n new TechDocsStorageClient({\n configApi,\n discoveryApi,\n fetchApi,\n }),\n }),\n },\n});\n\n/** @alpha */\nconst techDocsClientApi = ApiBlueprint.make({\n params: {\n factory: createApiFactory({\n api: techdocsApiRef,\n deps: {\n configApi: configApiRef,\n discoveryApi: discoveryApiRef,\n fetchApi: fetchApiRef,\n },\n factory: ({ configApi, discoveryApi, fetchApi }) =>\n new TechDocsClient({\n configApi,\n discoveryApi,\n fetchApi,\n }),\n }),\n },\n});\n\n/** @alpha */\nexport const techDocsSearchResultListItemExtension =\n SearchResultListItemBlueprint.makeWithOverrides({\n config: {\n schema: {\n title: z => z.string().optional(),\n lineClamp: z => z.number().default(5),\n asLink: z => z.boolean().default(true),\n asListItem: z => z.boolean().default(true),\n },\n },\n factory(originalFactory, { config }) {\n return originalFactory({\n predicate: result => result.type === 'techdocs',\n component: async () => {\n const { TechDocsSearchResultListItem } = await import(\n './search/components/TechDocsSearchResultListItem'\n );\n return props =>\n compatWrapper(\n <TechDocsSearchResultListItem {...props} {...config} />,\n );\n },\n });\n },\n });\n\n/**\n * Responsible for rendering the provided router element\n *\n * @alpha\n */\nconst techDocsPage = PageBlueprint.make({\n params: {\n defaultPath: '/docs',\n routeRef: convertLegacyRouteRef(rootRouteRef),\n loader: () =>\n import('./home/components/TechDocsIndexPage').then(m =>\n compatWrapper(<m.TechDocsIndexPage />),\n ),\n },\n});\n\n/**\n * Component responsible for composing a TechDocs reader page experience\n *\n * @alpha\n */\nconst techDocsReaderPage = PageBlueprint.makeWithOverrides({\n name: 'reader',\n inputs: {\n addons: createExtensionInput([AddonBlueprint.dataRefs.addon]),\n },\n factory(originalFactory, { inputs }) {\n const addons = inputs.addons.map(output => {\n const options = output.get(AddonBlueprint.dataRefs.addon);\n const Addon = options.component;\n attachTechDocsAddonComponentData(Addon, options);\n return <Addon key={options.name} />;\n });\n\n return originalFactory({\n defaultPath: '/docs/:namespace/:kind/:name',\n routeRef: convertLegacyRouteRef(rootDocsRouteRef),\n loader: async () =>\n await import('./Router').then(({ TechDocsReaderRouter }) => {\n return compatWrapper(\n <TechDocsReaderRouter>\n <TechDocsReaderLayout />\n <TechDocsAddons>{addons}</TechDocsAddons>\n </TechDocsReaderRouter>,\n );\n }),\n });\n },\n});\n\n/**\n * Component responsible for rendering techdocs on entity pages\n *\n * @alpha\n */\nconst techDocsEntityContent = EntityContentBlueprint.makeWithOverrides({\n inputs: {\n addons: createExtensionInput([AddonBlueprint.dataRefs.addon]),\n emptyState: createExtensionInput(\n [coreExtensionData.reactElement.optional()],\n {\n singleton: true,\n optional: true,\n },\n ),\n },\n factory(originalFactory, context) {\n return originalFactory(\n {\n defaultPath: 'docs',\n defaultTitle: 'TechDocs',\n routeRef: convertLegacyRouteRef(rootCatalogDocsRouteRef),\n loader: () =>\n import('./Router').then(({ EmbeddedDocsRouter }) => {\n const addons = context.inputs.addons.map(output => {\n const options = output.get(AddonBlueprint.dataRefs.addon);\n const Addon = options.component;\n attachTechDocsAddonComponentData(Addon, options);\n return <Addon key={options.name} />;\n });\n return compatWrapper(\n <EmbeddedDocsRouter\n emptyState={context.inputs.emptyState?.get(\n coreExtensionData.reactElement,\n )}\n >\n <TechDocsAddons>{addons}</TechDocsAddons>\n </EmbeddedDocsRouter>,\n );\n }),\n },\n context,\n );\n },\n});\n\nconst techDocsEntityContentEmptyState = createExtension({\n kind: 'empty-state',\n name: 'entity-content',\n attachTo: { id: 'entity-content:techdocs', input: 'emptyState' },\n output: [coreExtensionData.reactElement.optional()],\n factory: () => [],\n});\n\n/** @alpha */\nconst techDocsNavItem = NavItemBlueprint.make({\n params: {\n icon: LibraryBooks,\n title: 'Docs',\n routeRef: convertLegacyRouteRef(rootRouteRef),\n },\n});\n\n/** @alpha */\nexport default createFrontendPlugin({\n pluginId: 'techdocs',\n info: { packageJson: () => import('../package.json') },\n extensions: [\n techDocsClientApi,\n techDocsStorageApi,\n techDocsNavItem,\n techDocsPage,\n techDocsReaderPage,\n techDocsEntityContent,\n techDocsEntityContentEmptyState,\n techDocsSearchResultListItemExtension,\n ],\n routes: convertLegacyRouteRefs({\n root: rootRouteRef,\n docRoot: rootDocsRouteRef,\n entityContent: rootCatalogDocsRouteRef,\n }),\n});\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"alpha.esm.js","sources":["../src/alpha/index.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport LibraryBooks from '@material-ui/icons/LibraryBooks';\nimport {\n createFrontendPlugin,\n ApiBlueprint,\n PageBlueprint,\n NavItemBlueprint,\n createExtensionInput,\n coreExtensionData,\n createExtension,\n} from '@backstage/frontend-plugin-api';\nimport {\n configApiRef,\n createApiFactory,\n discoveryApiRef,\n fetchApiRef,\n} from '@backstage/core-plugin-api';\nimport {\n compatWrapper,\n convertLegacyRouteRef,\n convertLegacyRouteRefs,\n} from '@backstage/core-compat-api';\nimport {\n EntityContentBlueprint,\n EntityIconLinkBlueprint,\n} from '@backstage/plugin-catalog-react/alpha';\nimport { SearchResultListItemBlueprint } from '@backstage/plugin-search-react/alpha';\nimport { AddonBlueprint } from '@backstage/plugin-techdocs-react/alpha';\nimport { TechDocsClient, TechDocsStorageClient } from '../client';\nimport {\n rootCatalogDocsRouteRef,\n rootDocsRouteRef,\n rootRouteRef,\n} from '../routes';\nimport { TechDocsReaderLayout } from '../reader';\nimport { attachTechDocsAddonComponentData } from '@backstage/plugin-techdocs-react/alpha';\nimport {\n TechDocsAddons,\n techdocsApiRef,\n techdocsStorageApiRef,\n} from '@backstage/plugin-techdocs-react';\n\nimport { useTechdocsReaderIconLinkProps } from './hooks/useTechdocsReaderIconLinkProps';\n\n/** @alpha */\nconst techdocsEntityIconLink = EntityIconLinkBlueprint.make({\n name: 'read-docs',\n params: {\n useProps: useTechdocsReaderIconLinkProps,\n },\n});\n\n/** @alpha */\nconst techDocsStorageApi = ApiBlueprint.make({\n name: 'storage',\n params: {\n factory: createApiFactory({\n api: techdocsStorageApiRef,\n deps: {\n configApi: configApiRef,\n discoveryApi: discoveryApiRef,\n fetchApi: fetchApiRef,\n },\n factory: ({ configApi, discoveryApi, fetchApi }) =>\n new TechDocsStorageClient({\n configApi,\n discoveryApi,\n fetchApi,\n }),\n }),\n },\n});\n\n/** @alpha */\nconst techDocsClientApi = ApiBlueprint.make({\n params: {\n factory: createApiFactory({\n api: techdocsApiRef,\n deps: {\n configApi: configApiRef,\n discoveryApi: discoveryApiRef,\n fetchApi: fetchApiRef,\n },\n factory: ({ configApi, discoveryApi, fetchApi }) =>\n new TechDocsClient({\n configApi,\n discoveryApi,\n fetchApi,\n }),\n }),\n },\n});\n\n/** @alpha */\nexport const techDocsSearchResultListItemExtension =\n SearchResultListItemBlueprint.makeWithOverrides({\n config: {\n schema: {\n title: z => z.string().optional(),\n lineClamp: z => z.number().default(5),\n asLink: z => z.boolean().default(true),\n asListItem: z => z.boolean().default(true),\n },\n },\n factory(originalFactory, { config }) {\n return originalFactory({\n predicate: result => result.type === 'techdocs',\n component: async () => {\n const { TechDocsSearchResultListItem } = await import(\n '../search/components/TechDocsSearchResultListItem'\n );\n return props =>\n compatWrapper(\n <TechDocsSearchResultListItem {...props} {...config} />,\n );\n },\n });\n },\n });\n\n/**\n * Responsible for rendering the provided router element\n *\n * @alpha\n */\nconst techDocsPage = PageBlueprint.make({\n params: {\n defaultPath: '/docs',\n routeRef: convertLegacyRouteRef(rootRouteRef),\n loader: () =>\n import('../home/components/TechDocsIndexPage').then(m =>\n compatWrapper(<m.TechDocsIndexPage />),\n ),\n },\n});\n\n/**\n * Component responsible for composing a TechDocs reader page experience\n *\n * @alpha\n */\nconst techDocsReaderPage = PageBlueprint.makeWithOverrides({\n name: 'reader',\n inputs: {\n addons: createExtensionInput([AddonBlueprint.dataRefs.addon]),\n },\n factory(originalFactory, { inputs }) {\n const addons = inputs.addons.map(output => {\n const options = output.get(AddonBlueprint.dataRefs.addon);\n const Addon = options.component;\n attachTechDocsAddonComponentData(Addon, options);\n return <Addon key={options.name} />;\n });\n\n return originalFactory({\n defaultPath: '/docs/:namespace/:kind/:name',\n routeRef: convertLegacyRouteRef(rootDocsRouteRef),\n loader: async () =>\n await import('../Router').then(({ TechDocsReaderRouter }) => {\n return compatWrapper(\n <TechDocsReaderRouter>\n <TechDocsReaderLayout />\n <TechDocsAddons>{addons}</TechDocsAddons>\n </TechDocsReaderRouter>,\n );\n }),\n });\n },\n});\n\n/**\n * Component responsible for rendering techdocs on entity pages\n *\n * @alpha\n */\nconst techDocsEntityContent = EntityContentBlueprint.makeWithOverrides({\n inputs: {\n addons: createExtensionInput([AddonBlueprint.dataRefs.addon]),\n emptyState: createExtensionInput(\n [coreExtensionData.reactElement.optional()],\n {\n singleton: true,\n optional: true,\n },\n ),\n },\n factory(originalFactory, context) {\n return originalFactory(\n {\n defaultPath: 'docs',\n defaultTitle: 'TechDocs',\n routeRef: convertLegacyRouteRef(rootCatalogDocsRouteRef),\n loader: () =>\n import('../Router').then(({ EmbeddedDocsRouter }) => {\n const addons = context.inputs.addons.map(output => {\n const options = output.get(AddonBlueprint.dataRefs.addon);\n const Addon = options.component;\n attachTechDocsAddonComponentData(Addon, options);\n return <Addon key={options.name} />;\n });\n return compatWrapper(\n <EmbeddedDocsRouter\n emptyState={context.inputs.emptyState?.get(\n coreExtensionData.reactElement,\n )}\n >\n <TechDocsAddons>{addons}</TechDocsAddons>\n </EmbeddedDocsRouter>,\n );\n }),\n },\n context,\n );\n },\n});\n\nconst techDocsEntityContentEmptyState = createExtension({\n kind: 'empty-state',\n name: 'entity-content',\n attachTo: { id: 'entity-content:techdocs', input: 'emptyState' },\n output: [coreExtensionData.reactElement.optional()],\n factory: () => [],\n});\n\n/** @alpha */\nconst techDocsNavItem = NavItemBlueprint.make({\n params: {\n icon: LibraryBooks,\n title: 'Docs',\n routeRef: convertLegacyRouteRef(rootRouteRef),\n },\n});\n\n/** @alpha */\nexport default createFrontendPlugin({\n pluginId: 'techdocs',\n info: { packageJson: () => import('../../package.json') },\n extensions: [\n techDocsClientApi,\n techDocsStorageApi,\n techDocsNavItem,\n techDocsPage,\n techDocsReaderPage,\n techdocsEntityIconLink,\n techDocsEntityContent,\n techDocsEntityContentEmptyState,\n techDocsSearchResultListItemExtension,\n ],\n routes: convertLegacyRouteRefs({\n root: rootRouteRef,\n docRoot: rootDocsRouteRef,\n entityContent: rootCatalogDocsRouteRef,\n }),\n});\n"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  var name = "@backstage/plugin-techdocs";
2
- var version = "1.13.0-next.0";
2
+ var version = "1.13.0-next.2";
3
3
  var description = "The Backstage plugin that renders technical documentation for your components";
4
4
  var backstage = {
5
5
  role: "frontend-plugin",
@@ -29,7 +29,7 @@ var license = "Apache-2.0";
29
29
  var sideEffects = false;
30
30
  var exports = {
31
31
  ".": "./src/index.ts",
32
- "./alpha": "./src/alpha.tsx",
32
+ "./alpha": "./src/alpha/index.tsx",
33
33
  "./package.json": "./package.json"
34
34
  };
35
35
  var main = "src/index.ts";
@@ -37,7 +37,7 @@ var types = "src/index.ts";
37
37
  var typesVersions = {
38
38
  "*": {
39
39
  alpha: [
40
- "src/alpha.tsx"
40
+ "src/alpha/index.tsx"
41
41
  ],
42
42
  "package.json": [
43
43
  "package.json"
@@ -19,6 +19,7 @@ import { onCssReady } from '../../transformers/onCssReady.esm.js';
19
19
  import { scrollIntoNavigation } from '../../transformers/scrollIntoNavigation.esm.js';
20
20
  import { transform } from '../../transformers/transformer.esm.js';
21
21
  import { handleMetaRedirects } from '../../transformers/handleMetaRedirects.esm.js';
22
+ import { addNavLinkKeyboardToggle } from '../../transformers/addNavLinkKeyboardToggle.esm.js';
22
23
  import { useNavigateUrl } from './useNavigateUrl.esm.js';
23
24
  import { useParams, useLocation, useNavigate } from 'react-router-dom';
24
25
 
@@ -190,7 +191,8 @@ const useTechDocsReaderDom = (entityRef, defaultPath) => {
190
191
  },
191
192
  onLoaded: () => {
192
193
  }
193
- })
194
+ }),
195
+ addNavLinkKeyboardToggle()
194
196
  ]),
195
197
  [theme, navigate, analytics, entityRef.name, configApi]
196
198
  );
@@ -1 +1 @@
1
- {"version":3,"file":"dom.esm.js","sources":["../../../../src/reader/components/TechDocsReaderPageContent/dom.tsx"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n useCallback,\n useEffect,\n useLayoutEffect,\n // useRef,\n useState,\n} from 'react';\n\nimport useMediaQuery from '@material-ui/core/useMediaQuery';\nimport { useTheme } from '@material-ui/core/styles';\n\nimport { CompoundEntityRef } from '@backstage/catalog-model';\nimport { configApiRef, useAnalytics, useApi } from '@backstage/core-plugin-api';\nimport { scmIntegrationsApiRef } from '@backstage/integration-react';\n\nimport {\n techdocsStorageApiRef,\n useShadowDomStylesLoading,\n} from '@backstage/plugin-techdocs-react';\n\nimport { useTechDocsReader } from '../TechDocsReaderProvider';\n\nimport {\n addBaseUrl,\n addGitFeedbackLink,\n addLinkClickListener,\n addSidebarToggle,\n onCssReady,\n removeMkdocsHeader,\n rewriteDocLinks,\n simplifyMkdocsFooter,\n scrollIntoNavigation,\n transform as transformer,\n copyToClipboard,\n useSanitizerTransformer,\n useStylesTransformer,\n handleMetaRedirects,\n} from '../../transformers';\nimport { useNavigateUrl } from './useNavigateUrl';\nimport { useLocation, useNavigate, useParams } from 'react-router-dom';\n\nconst MOBILE_MEDIA_QUERY = 'screen and (max-width: 76.1875em)';\n\n// If a defaultPath is specified then we should navigate to that path replacing the\n// current location in the history. This should only happen on the initial load so\n// navigating to the root of the docs doesn't also redirect.\nconst useInitialRedirect = (defaultPath?: string) => {\n // const hasRun = useRef(false);\n\n const location = useLocation();\n const navigate = useNavigate();\n const { '*': currPath = '' } = useParams();\n\n useLayoutEffect(() => {\n if (currPath === '' && defaultPath !== '') {\n navigate(`${location.pathname}${defaultPath}`, { replace: true });\n }\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n};\n\n/**\n * Hook that encapsulates the behavior of getting raw HTML and applying\n * transforms to it in order to make it function at a basic level in the\n * Backstage UI.\n */\nexport const useTechDocsReaderDom = (\n entityRef: CompoundEntityRef,\n defaultPath?: string,\n): Element | null => {\n const navigate = useNavigateUrl();\n const theme = useTheme();\n const isMobileMedia = useMediaQuery(MOBILE_MEDIA_QUERY);\n const sanitizerTransformer = useSanitizerTransformer();\n const stylesTransformer = useStylesTransformer();\n const analytics = useAnalytics();\n\n const techdocsStorageApi = useApi(techdocsStorageApiRef);\n const scmIntegrationsApi = useApi(scmIntegrationsApiRef);\n const configApi = useApi(configApiRef);\n\n const { state, path, content: rawPage } = useTechDocsReader();\n const { '*': currPath = '' } = useParams();\n\n const [dom, setDom] = useState<HTMLElement | null>(null);\n const isStyleLoading = useShadowDomStylesLoading(dom);\n\n useInitialRedirect(defaultPath);\n\n const updateSidebarPositionAndHeight = useCallback(() => {\n if (!dom) return;\n\n const sidebars = dom.querySelectorAll<HTMLElement>('.md-sidebar');\n\n sidebars.forEach(element => {\n // set sidebar position to render in correct position\n if (isMobileMedia) {\n element.style.top = '0px';\n } else {\n const page = document?.querySelector('.techdocs-reader-page');\n const pageTop = page?.getBoundingClientRect().top ?? 0;\n let domTop = dom.getBoundingClientRect().top ?? 0;\n\n const tabs = dom.querySelector('.md-container > .md-tabs');\n const tabsHeight = tabs?.getBoundingClientRect().height ?? 0;\n\n // the sidebars should not scroll beyond the total height of the header and tabs\n if (domTop < pageTop) {\n domTop = pageTop;\n }\n\n const scrollbarTopPx = Math.max(domTop, 0) + tabsHeight;\n\n element.style.top = `${scrollbarTopPx}px`;\n\n // set scrollbar height to ensure all links can be seen when content is small\n const footer = dom.querySelector('.md-container > .md-footer');\n // if no footer, fallback to using the bottom of the window\n const scrollbarEndPx =\n footer?.getBoundingClientRect().top ?? window.innerHeight;\n\n element.style.height = `${scrollbarEndPx - scrollbarTopPx}px`;\n }\n\n // show the sidebar only after updating its position\n element.style.setProperty('opacity', '1');\n });\n }, [dom, isMobileMedia]);\n\n useEffect(() => {\n window.addEventListener('resize', updateSidebarPositionAndHeight);\n window.addEventListener('scroll', updateSidebarPositionAndHeight, true);\n return () => {\n window.removeEventListener('resize', updateSidebarPositionAndHeight);\n window.removeEventListener(\n 'scroll',\n updateSidebarPositionAndHeight,\n true,\n );\n };\n }, [dom, updateSidebarPositionAndHeight]);\n\n // dynamically set width of footer to accommodate for pinning of the sidebar\n const updateFooterWidth = useCallback(() => {\n if (!dom) return;\n const footer = dom.querySelector<HTMLElement>('.md-footer');\n if (footer) {\n footer.style.width = `${dom.getBoundingClientRect().width}px`;\n }\n }, [dom]);\n\n useEffect(() => {\n window.addEventListener('resize', updateFooterWidth);\n return () => {\n window.removeEventListener('resize', updateFooterWidth);\n };\n }, [dom, updateFooterWidth]);\n\n // an update to \"state\" might lead to an updated UI so we include it as a trigger\n useEffect(() => {\n if (!isStyleLoading) {\n updateFooterWidth();\n updateSidebarPositionAndHeight();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n state,\n isStyleLoading,\n updateFooterWidth,\n updateSidebarPositionAndHeight,\n ]);\n\n // a function that performs transformations that are executed prior to adding it to the DOM\n const preRender = useCallback(\n (rawContent: string, contentPath: string) =>\n transformer(rawContent, [\n sanitizerTransformer,\n addBaseUrl({\n techdocsStorageApi,\n entityId: entityRef,\n path: contentPath,\n }),\n rewriteDocLinks(),\n addSidebarToggle(),\n removeMkdocsHeader(),\n simplifyMkdocsFooter(),\n addGitFeedbackLink(scmIntegrationsApi),\n stylesTransformer,\n ]),\n [\n // only add dependencies that are in state or memorized variables to avoid unnecessary calls between re-renders\n entityRef,\n scmIntegrationsApi,\n techdocsStorageApi,\n sanitizerTransformer,\n stylesTransformer,\n ],\n );\n\n // a function that performs transformations that are executed after adding it to the DOM\n const postRender = useCallback(\n async (transformedElement: Element) =>\n transformer(transformedElement, [\n handleMetaRedirects(navigate, entityRef.name),\n scrollIntoNavigation(),\n copyToClipboard(theme),\n addLinkClickListener({\n baseUrl:\n configApi.getOptionalString('app.baseUrl') ||\n window.location.origin,\n onClick: (event: MouseEvent, url: string) => {\n // detect if CTRL or META keys are pressed so that links can be opened in a new tab with `window.open`\n const modifierActive = event.ctrlKey || event.metaKey;\n const parsedUrl = new URL(url);\n\n // capture link clicks within documentation\n const linkText =\n (event.target as HTMLAnchorElement | undefined)?.innerText || url;\n const to = url.replace(window.location.origin, '');\n analytics.captureEvent('click', linkText, { attributes: { to } });\n\n // hash exists when anchor is clicked on secondary sidebar\n if (parsedUrl.hash) {\n if (modifierActive) {\n window.open(url, '_blank');\n } else {\n // If it's in a different page, we navigate to it\n if (window.location.pathname !== parsedUrl.pathname) {\n navigate(url);\n } else {\n // If it's in the same page we avoid using navigate that causes\n // the page to rerender.\n window.history.pushState(\n null,\n document.title,\n parsedUrl.hash,\n );\n }\n // Scroll to hash if it's on the current page\n transformedElement\n ?.querySelector(`[id=\"${parsedUrl.hash.slice(1)}\"]`)\n ?.scrollIntoView();\n\n // Focus first focusable element in the target section\n (\n transformedElement\n ?.querySelector(`[id=\"${parsedUrl.hash.slice(1)}\"]`)\n ?.querySelector('a, button, [tabindex]') as HTMLElement\n )?.focus();\n }\n } else {\n if (modifierActive) {\n window.open(url, '_blank');\n } else {\n navigate(url);\n }\n }\n },\n }),\n // disable MkDocs drawer toggling ('for' attribute => checkbox mechanism)\n onCssReady({\n onLoading: () => {},\n onLoaded: () => {\n transformedElement\n .querySelector('.md-nav__title')\n ?.removeAttribute('for');\n },\n }),\n // hide sidebars until their positions are updated\n onCssReady({\n onLoading: () => {\n const sidebars = Array.from(\n transformedElement.querySelectorAll<HTMLElement>('.md-sidebar'),\n );\n sidebars.forEach(element => {\n element.style.setProperty('opacity', '0');\n });\n },\n onLoaded: () => {},\n }),\n ]),\n [theme, navigate, analytics, entityRef.name, configApi],\n );\n\n useEffect(() => {\n if (!rawPage) return () => {};\n\n // if false, there is already a newer execution of this effect\n let shouldReplaceContent = true;\n\n // Pre-render\n preRender(rawPage, path).then(async preTransformedDomElement => {\n if (!preTransformedDomElement?.innerHTML) {\n return; // An unexpected error occurred\n }\n\n // don't manipulate the shadow dom if this isn't the latest effect execution\n if (!shouldReplaceContent) {\n return;\n }\n\n // Skip this update if the location's path has changed but the state\n // contains a page that isn't loaded yet.\n if (currPath !== path) {\n return;\n }\n\n // Scroll to top after render\n window.scroll({ top: 0 });\n\n // Post-render\n const postTransformedDomElement = await postRender(\n preTransformedDomElement,\n );\n\n setDom(postTransformedDomElement as HTMLElement);\n });\n\n // cancel this execution\n return () => {\n shouldReplaceContent = false;\n };\n }, [rawPage, currPath, path, preRender, postRender]);\n\n return dom;\n};\n"],"names":["transformer"],"mappings":"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"}
1
+ {"version":3,"file":"dom.esm.js","sources":["../../../../src/reader/components/TechDocsReaderPageContent/dom.tsx"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n useCallback,\n useEffect,\n useLayoutEffect,\n // useRef,\n useState,\n} from 'react';\n\nimport useMediaQuery from '@material-ui/core/useMediaQuery';\nimport { useTheme } from '@material-ui/core/styles';\n\nimport { CompoundEntityRef } from '@backstage/catalog-model';\nimport { configApiRef, useAnalytics, useApi } from '@backstage/core-plugin-api';\nimport { scmIntegrationsApiRef } from '@backstage/integration-react';\n\nimport {\n techdocsStorageApiRef,\n useShadowDomStylesLoading,\n} from '@backstage/plugin-techdocs-react';\n\nimport { useTechDocsReader } from '../TechDocsReaderProvider';\n\nimport {\n addBaseUrl,\n addGitFeedbackLink,\n addLinkClickListener,\n addSidebarToggle,\n onCssReady,\n removeMkdocsHeader,\n rewriteDocLinks,\n simplifyMkdocsFooter,\n scrollIntoNavigation,\n transform as transformer,\n copyToClipboard,\n useSanitizerTransformer,\n useStylesTransformer,\n handleMetaRedirects,\n addNavLinkKeyboardToggle,\n} from '../../transformers';\nimport { useNavigateUrl } from './useNavigateUrl';\nimport { useLocation, useNavigate, useParams } from 'react-router-dom';\n\nconst MOBILE_MEDIA_QUERY = 'screen and (max-width: 76.1875em)';\n\n// If a defaultPath is specified then we should navigate to that path replacing the\n// current location in the history. This should only happen on the initial load so\n// navigating to the root of the docs doesn't also redirect.\nconst useInitialRedirect = (defaultPath?: string) => {\n // const hasRun = useRef(false);\n\n const location = useLocation();\n const navigate = useNavigate();\n const { '*': currPath = '' } = useParams();\n\n useLayoutEffect(() => {\n if (currPath === '' && defaultPath !== '') {\n navigate(`${location.pathname}${defaultPath}`, { replace: true });\n }\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n};\n\n/**\n * Hook that encapsulates the behavior of getting raw HTML and applying\n * transforms to it in order to make it function at a basic level in the\n * Backstage UI.\n */\nexport const useTechDocsReaderDom = (\n entityRef: CompoundEntityRef,\n defaultPath?: string,\n): Element | null => {\n const navigate = useNavigateUrl();\n const theme = useTheme();\n const isMobileMedia = useMediaQuery(MOBILE_MEDIA_QUERY);\n const sanitizerTransformer = useSanitizerTransformer();\n const stylesTransformer = useStylesTransformer();\n const analytics = useAnalytics();\n\n const techdocsStorageApi = useApi(techdocsStorageApiRef);\n const scmIntegrationsApi = useApi(scmIntegrationsApiRef);\n const configApi = useApi(configApiRef);\n\n const { state, path, content: rawPage } = useTechDocsReader();\n const { '*': currPath = '' } = useParams();\n\n const [dom, setDom] = useState<HTMLElement | null>(null);\n const isStyleLoading = useShadowDomStylesLoading(dom);\n\n useInitialRedirect(defaultPath);\n\n const updateSidebarPositionAndHeight = useCallback(() => {\n if (!dom) return;\n\n const sidebars = dom.querySelectorAll<HTMLElement>('.md-sidebar');\n\n sidebars.forEach(element => {\n // set sidebar position to render in correct position\n if (isMobileMedia) {\n element.style.top = '0px';\n } else {\n const page = document?.querySelector('.techdocs-reader-page');\n const pageTop = page?.getBoundingClientRect().top ?? 0;\n let domTop = dom.getBoundingClientRect().top ?? 0;\n\n const tabs = dom.querySelector('.md-container > .md-tabs');\n const tabsHeight = tabs?.getBoundingClientRect().height ?? 0;\n\n // the sidebars should not scroll beyond the total height of the header and tabs\n if (domTop < pageTop) {\n domTop = pageTop;\n }\n\n const scrollbarTopPx = Math.max(domTop, 0) + tabsHeight;\n\n element.style.top = `${scrollbarTopPx}px`;\n\n // set scrollbar height to ensure all links can be seen when content is small\n const footer = dom.querySelector('.md-container > .md-footer');\n // if no footer, fallback to using the bottom of the window\n const scrollbarEndPx =\n footer?.getBoundingClientRect().top ?? window.innerHeight;\n\n element.style.height = `${scrollbarEndPx - scrollbarTopPx}px`;\n }\n\n // show the sidebar only after updating its position\n element.style.setProperty('opacity', '1');\n });\n }, [dom, isMobileMedia]);\n\n useEffect(() => {\n window.addEventListener('resize', updateSidebarPositionAndHeight);\n window.addEventListener('scroll', updateSidebarPositionAndHeight, true);\n return () => {\n window.removeEventListener('resize', updateSidebarPositionAndHeight);\n window.removeEventListener(\n 'scroll',\n updateSidebarPositionAndHeight,\n true,\n );\n };\n }, [dom, updateSidebarPositionAndHeight]);\n\n // dynamically set width of footer to accommodate for pinning of the sidebar\n const updateFooterWidth = useCallback(() => {\n if (!dom) return;\n const footer = dom.querySelector<HTMLElement>('.md-footer');\n if (footer) {\n footer.style.width = `${dom.getBoundingClientRect().width}px`;\n }\n }, [dom]);\n\n useEffect(() => {\n window.addEventListener('resize', updateFooterWidth);\n return () => {\n window.removeEventListener('resize', updateFooterWidth);\n };\n }, [dom, updateFooterWidth]);\n\n // an update to \"state\" might lead to an updated UI so we include it as a trigger\n useEffect(() => {\n if (!isStyleLoading) {\n updateFooterWidth();\n updateSidebarPositionAndHeight();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n state,\n isStyleLoading,\n updateFooterWidth,\n updateSidebarPositionAndHeight,\n ]);\n\n // a function that performs transformations that are executed prior to adding it to the DOM\n const preRender = useCallback(\n (rawContent: string, contentPath: string) =>\n transformer(rawContent, [\n sanitizerTransformer,\n addBaseUrl({\n techdocsStorageApi,\n entityId: entityRef,\n path: contentPath,\n }),\n rewriteDocLinks(),\n addSidebarToggle(),\n removeMkdocsHeader(),\n simplifyMkdocsFooter(),\n addGitFeedbackLink(scmIntegrationsApi),\n stylesTransformer,\n ]),\n [\n // only add dependencies that are in state or memorized variables to avoid unnecessary calls between re-renders\n entityRef,\n scmIntegrationsApi,\n techdocsStorageApi,\n sanitizerTransformer,\n stylesTransformer,\n ],\n );\n\n // a function that performs transformations that are executed after adding it to the DOM\n const postRender = useCallback(\n async (transformedElement: Element) =>\n transformer(transformedElement, [\n handleMetaRedirects(navigate, entityRef.name),\n scrollIntoNavigation(),\n copyToClipboard(theme),\n addLinkClickListener({\n baseUrl:\n configApi.getOptionalString('app.baseUrl') ||\n window.location.origin,\n onClick: (event: MouseEvent, url: string) => {\n // detect if CTRL or META keys are pressed so that links can be opened in a new tab with `window.open`\n const modifierActive = event.ctrlKey || event.metaKey;\n const parsedUrl = new URL(url);\n\n // capture link clicks within documentation\n const linkText =\n (event.target as HTMLAnchorElement | undefined)?.innerText || url;\n const to = url.replace(window.location.origin, '');\n analytics.captureEvent('click', linkText, { attributes: { to } });\n\n // hash exists when anchor is clicked on secondary sidebar\n if (parsedUrl.hash) {\n if (modifierActive) {\n window.open(url, '_blank');\n } else {\n // If it's in a different page, we navigate to it\n if (window.location.pathname !== parsedUrl.pathname) {\n navigate(url);\n } else {\n // If it's in the same page we avoid using navigate that causes\n // the page to rerender.\n window.history.pushState(\n null,\n document.title,\n parsedUrl.hash,\n );\n }\n // Scroll to hash if it's on the current page\n transformedElement\n ?.querySelector(`[id=\"${parsedUrl.hash.slice(1)}\"]`)\n ?.scrollIntoView();\n\n // Focus first focusable element in the target section\n (\n transformedElement\n ?.querySelector(`[id=\"${parsedUrl.hash.slice(1)}\"]`)\n ?.querySelector('a, button, [tabindex]') as HTMLElement\n )?.focus();\n }\n } else {\n if (modifierActive) {\n window.open(url, '_blank');\n } else {\n navigate(url);\n }\n }\n },\n }),\n // disable MkDocs drawer toggling ('for' attribute => checkbox mechanism)\n onCssReady({\n onLoading: () => {},\n onLoaded: () => {\n transformedElement\n .querySelector('.md-nav__title')\n ?.removeAttribute('for');\n },\n }),\n // hide sidebars until their positions are updated\n onCssReady({\n onLoading: () => {\n const sidebars = Array.from(\n transformedElement.querySelectorAll<HTMLElement>('.md-sidebar'),\n );\n sidebars.forEach(element => {\n element.style.setProperty('opacity', '0');\n });\n },\n onLoaded: () => {},\n }),\n addNavLinkKeyboardToggle(),\n ]),\n [theme, navigate, analytics, entityRef.name, configApi],\n );\n\n useEffect(() => {\n if (!rawPage) return () => {};\n\n // if false, there is already a newer execution of this effect\n let shouldReplaceContent = true;\n\n // Pre-render\n preRender(rawPage, path).then(async preTransformedDomElement => {\n if (!preTransformedDomElement?.innerHTML) {\n return; // An unexpected error occurred\n }\n\n // don't manipulate the shadow dom if this isn't the latest effect execution\n if (!shouldReplaceContent) {\n return;\n }\n\n // Skip this update if the location's path has changed but the state\n // contains a page that isn't loaded yet.\n if (currPath !== path) {\n return;\n }\n\n // Scroll to top after render\n window.scroll({ top: 0 });\n\n // Post-render\n const postTransformedDomElement = await postRender(\n preTransformedDomElement,\n );\n\n setDom(postTransformedDomElement as HTMLElement);\n });\n\n // cancel this execution\n return () => {\n shouldReplaceContent = false;\n };\n }, [rawPage, currPath, path, preRender, postRender]);\n\n return dom;\n};\n"],"names":["transformer"],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ function addNavLinkKeyboardToggle() {
2
+ return (element) => {
3
+ const navLabels = element.querySelectorAll("label.md-nav__link[for]");
4
+ navLabels.forEach((label) => {
5
+ label.setAttribute("tabIndex", "0");
6
+ label.addEventListener("keydown", (event) => {
7
+ const keyboardEvent = event;
8
+ if (keyboardEvent.key === "Enter" || keyboardEvent.key === " ") {
9
+ const forId = label.getAttribute("for");
10
+ if (!forId) return;
11
+ const checkbox = element.querySelector(
12
+ `#${forId}`
13
+ );
14
+ if (checkbox && checkbox.type === "checkbox") {
15
+ checkbox.checked = !checkbox.checked;
16
+ checkbox.dispatchEvent(new Event("change", { bubbles: true }));
17
+ event.preventDefault();
18
+ event.stopPropagation();
19
+ }
20
+ }
21
+ });
22
+ });
23
+ return element;
24
+ };
25
+ }
26
+
27
+ export { addNavLinkKeyboardToggle };
28
+ //# sourceMappingURL=addNavLinkKeyboardToggle.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"addNavLinkKeyboardToggle.esm.js","sources":["../../../src/reader/transformers/addNavLinkKeyboardToggle.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport function addNavLinkKeyboardToggle() {\n return (element: Element) => {\n const navLabels = element.querySelectorAll('label.md-nav__link[for]');\n navLabels.forEach(label => {\n label.setAttribute('tabIndex', '0');\n label.addEventListener('keydown', event => {\n const keyboardEvent = event as KeyboardEvent;\n if (keyboardEvent.key === 'Enter' || keyboardEvent.key === ' ') {\n const forId = label.getAttribute('for');\n if (!forId) return;\n const checkbox = element.querySelector(\n `#${forId}`,\n ) as HTMLInputElement | null;\n if (checkbox && checkbox.type === 'checkbox') {\n checkbox.checked = !checkbox.checked;\n checkbox.dispatchEvent(new Event('change', { bubbles: true }));\n event.preventDefault();\n event.stopPropagation();\n }\n }\n });\n });\n return element;\n };\n}\n"],"names":[],"mappings":"AAgBO,SAAS,wBAA2B,GAAA;AACzC,EAAA,OAAO,CAAC,OAAqB,KAAA;AAC3B,IAAM,MAAA,SAAA,GAAY,OAAQ,CAAA,gBAAA,CAAiB,yBAAyB,CAAA;AACpE,IAAA,SAAA,CAAU,QAAQ,CAAS,KAAA,KAAA;AACzB,MAAM,KAAA,CAAA,YAAA,CAAa,YAAY,GAAG,CAAA;AAClC,MAAM,KAAA,CAAA,gBAAA,CAAiB,WAAW,CAAS,KAAA,KAAA;AACzC,QAAA,MAAM,aAAgB,GAAA,KAAA;AACtB,QAAA,IAAI,aAAc,CAAA,GAAA,KAAQ,OAAW,IAAA,aAAA,CAAc,QAAQ,GAAK,EAAA;AAC9D,UAAM,MAAA,KAAA,GAAQ,KAAM,CAAA,YAAA,CAAa,KAAK,CAAA;AACtC,UAAA,IAAI,CAAC,KAAO,EAAA;AACZ,UAAA,MAAM,WAAW,OAAQ,CAAA,aAAA;AAAA,YACvB,IAAI,KAAK,CAAA;AAAA,WACX;AACA,UAAI,IAAA,QAAA,IAAY,QAAS,CAAA,IAAA,KAAS,UAAY,EAAA;AAC5C,YAAS,QAAA,CAAA,OAAA,GAAU,CAAC,QAAS,CAAA,OAAA;AAC7B,YAAS,QAAA,CAAA,aAAA,CAAc,IAAI,KAAM,CAAA,QAAA,EAAU,EAAE,OAAS,EAAA,IAAA,EAAM,CAAC,CAAA;AAC7D,YAAA,KAAA,CAAM,cAAe,EAAA;AACrB,YAAA,KAAA,CAAM,eAAgB,EAAA;AAAA;AACxB;AACF,OACD,CAAA;AAAA,KACF,CAAA;AACD,IAAO,OAAA,OAAA;AAAA,GACT;AACF;;;;"}
@@ -0,0 +1,13 @@
1
+ import { createTranslationRef } from '@backstage/core-plugin-api/alpha';
2
+
3
+ const techdocsTranslationRef = createTranslationRef({
4
+ id: "techdocs",
5
+ messages: {
6
+ aboutCard: {
7
+ viewTechdocs: "View TechDocs"
8
+ }
9
+ }
10
+ });
11
+
12
+ export { techdocsTranslationRef };
13
+ //# sourceMappingURL=translation.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translation.esm.js","sources":["../src/translation.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createTranslationRef } from '@backstage/core-plugin-api/alpha';\n\n/** @alpha */\nexport const techdocsTranslationRef = createTranslationRef({\n id: 'techdocs',\n messages: {\n aboutCard: {\n viewTechdocs: 'View TechDocs',\n },\n },\n});\n"],"names":[],"mappings":";;AAmBO,MAAM,yBAAyB,oBAAqB,CAAA;AAAA,EACzD,EAAI,EAAA,UAAA;AAAA,EACJ,QAAU,EAAA;AAAA,IACR,SAAW,EAAA;AAAA,MACT,YAAc,EAAA;AAAA;AAChB;AAEJ,CAAC;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-techdocs",
3
- "version": "1.13.0-next.0",
3
+ "version": "1.13.0-next.2",
4
4
  "description": "The Backstage plugin that renders technical documentation for your components",
5
5
  "backstage": {
6
6
  "role": "frontend-plugin",
@@ -71,22 +71,22 @@
71
71
  "test": "backstage-cli package test"
72
72
  },
73
73
  "dependencies": {
74
- "@backstage/catalog-client": "1.10.0",
74
+ "@backstage/catalog-client": "1.10.1-next.0",
75
75
  "@backstage/catalog-model": "1.7.4",
76
76
  "@backstage/config": "1.3.2",
77
- "@backstage/core-compat-api": "0.4.3-next.0",
78
- "@backstage/core-components": "0.17.2",
77
+ "@backstage/core-compat-api": "0.4.3-next.2",
78
+ "@backstage/core-components": "0.17.3-next.0",
79
79
  "@backstage/core-plugin-api": "1.10.7",
80
80
  "@backstage/errors": "1.2.7",
81
- "@backstage/frontend-plugin-api": "0.10.3-next.0",
81
+ "@backstage/frontend-plugin-api": "0.10.3-next.1",
82
82
  "@backstage/integration": "1.17.0",
83
83
  "@backstage/integration-react": "1.2.7",
84
- "@backstage/plugin-auth-react": "0.1.15",
85
- "@backstage/plugin-catalog-react": "1.18.1-next.0",
84
+ "@backstage/plugin-auth-react": "0.1.16-next.0",
85
+ "@backstage/plugin-catalog-react": "1.19.0-next.2",
86
86
  "@backstage/plugin-search-common": "1.2.18",
87
- "@backstage/plugin-search-react": "1.9.1-next.0",
87
+ "@backstage/plugin-search-react": "1.9.1-next.1",
88
88
  "@backstage/plugin-techdocs-common": "0.1.1-next.0",
89
- "@backstage/plugin-techdocs-react": "1.3.0-next.0",
89
+ "@backstage/plugin-techdocs-react": "1.3.0-next.1",
90
90
  "@backstage/theme": "0.6.6",
91
91
  "@material-ui/core": "^4.12.2",
92
92
  "@material-ui/icons": "^4.9.1",
@@ -101,11 +101,11 @@
101
101
  "react-use": "^17.2.4"
102
102
  },
103
103
  "devDependencies": {
104
- "@backstage/cli": "0.32.1",
104
+ "@backstage/cli": "0.33.0-next.1",
105
105
  "@backstage/core-app-api": "1.17.0",
106
- "@backstage/dev-utils": "1.1.11-next.0",
107
- "@backstage/plugin-catalog": "1.31.0-next.0",
108
- "@backstage/plugin-techdocs-module-addons-contrib": "1.1.25-next.0",
106
+ "@backstage/dev-utils": "1.1.11-next.2",
107
+ "@backstage/plugin-catalog": "1.31.0-next.2",
108
+ "@backstage/plugin-techdocs-module-addons-contrib": "1.1.25-next.2",
109
109
  "@backstage/test-utils": "1.7.8",
110
110
  "@testing-library/dom": "^10.0.0",
111
111
  "@testing-library/jest-dom": "^6.0.0",