@redocly/theme 0.62.0-next.0 → 0.62.0-next.1

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.
Files changed (33) hide show
  1. package/lib/components/Catalog/CatalogEntity/CatalogEntity.js +2 -2
  2. package/lib/components/Catalog/CatalogEntity/CatalogEntityHistory/CatalogEntityHistorySidebar.js +1 -1
  3. package/lib/components/Catalog/CatalogEntity/CatalogEntityProperties/TagsProperty.js +2 -2
  4. package/lib/components/Catalog/CatalogTableView/CatalogTableViewRow.js +1 -1
  5. package/lib/components/JsonViewer/JsonViewer.js +1 -1
  6. package/lib/components/Search/SearchAiMessage.js +2 -2
  7. package/lib/core/hooks/use-page-actions.js +3 -3
  8. package/lib/core/hooks/use-unique-svg-ids.d.ts +6 -0
  9. package/lib/core/hooks/use-unique-svg-ids.js +15 -0
  10. package/lib/core/openapi/index.d.ts +1 -0
  11. package/lib/core/openapi/index.js +3 -1
  12. package/lib/index.d.ts +3 -0
  13. package/lib/index.js +3 -0
  14. package/lib/layouts/DocumentationLayout.js +4 -25
  15. package/lib/layouts/DocumentationLayoutBottom.d.ts +11 -0
  16. package/lib/layouts/DocumentationLayoutBottom.js +28 -0
  17. package/lib/layouts/DocumentationLayoutTop.d.ts +13 -0
  18. package/lib/layouts/DocumentationLayoutTop.js +33 -0
  19. package/package.json +3 -3
  20. package/src/components/Catalog/CatalogEntity/CatalogEntity.tsx +1 -1
  21. package/src/components/Catalog/CatalogEntity/CatalogEntityHistory/CatalogEntityHistorySidebar.tsx +1 -2
  22. package/src/components/Catalog/CatalogEntity/CatalogEntityProperties/TagsProperty.tsx +1 -1
  23. package/src/components/Catalog/CatalogTableView/CatalogTableViewRow.tsx +1 -2
  24. package/src/components/JsonViewer/JsonViewer.tsx +1 -2
  25. package/src/components/Search/SearchAiMessage.tsx +2 -3
  26. package/src/core/hooks/__mocks__/use-theme-hooks.ts +1 -0
  27. package/src/core/hooks/use-page-actions.ts +3 -2
  28. package/src/core/hooks/use-unique-svg-ids.ts +12 -0
  29. package/src/core/openapi/index.ts +1 -0
  30. package/src/index.ts +3 -0
  31. package/src/layouts/DocumentationLayout.tsx +4 -30
  32. package/src/layouts/DocumentationLayoutBottom.tsx +42 -0
  33. package/src/layouts/DocumentationLayoutTop.tsx +52 -0
@@ -18,7 +18,7 @@ const hooks_1 = require("../../../core/hooks");
18
18
  const CatalogEntitySchema_1 = require("../../../components/Catalog/CatalogEntity/CatalogEntitySchema");
19
19
  const CatalogEntityMethodAndPath_1 = require("../../../components/Catalog/CatalogEntity/CatalogEntityMethodAndPath");
20
20
  const CatalogEntityRelationsGraph_lazy_1 = require("../../../components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsGraph.lazy");
21
- const theme_1 = require("../../../index.js");
21
+ const CatalogEntityHistorySidebar_1 = require("../../../components/Catalog/CatalogEntity/CatalogEntityHistory/CatalogEntityHistorySidebar");
22
22
  const renderFirstColumnEntitySection = (entity) => {
23
23
  switch (entity.type) {
24
24
  case 'api-operation':
@@ -45,7 +45,7 @@ function CatalogEntity({ RedocSchema, StoreProvider, GraphqlTypeRenderer, }) {
45
45
  const linkToMainCatalogLabel = translate(catalogConfig.titleTranslationKey);
46
46
  const { searchQuery, setSearchQuery } = useCatalog();
47
47
  return (react_1.default.createElement(CatalogPageWrapper, { "data-component-name": "Catalog/CatalogEntity/CatalogEntity" },
48
- react_1.default.createElement(theme_1.CatalogEntityHistorySidebar, { entityKey: entity.key, revision: revision, version: version }),
48
+ react_1.default.createElement(CatalogEntityHistorySidebar_1.CatalogEntityHistorySidebar, { entityKey: entity.key, revision: revision, version: version }),
49
49
  react_1.default.createElement(CatalogPageContent, null,
50
50
  react_1.default.createElement(Breadcrumbs_1.Breadcrumbs, { additionalBreadcrumbs: [
51
51
  { label: linkToMainCatalogLabel, link: linkToMainCatalog },
@@ -45,7 +45,7 @@ const hooks_1 = require("../../../../core/hooks");
45
45
  const MenuContainer_1 = require("../../../../components/Menu/MenuContainer");
46
46
  const utils_1 = require("../../../../core/utils");
47
47
  const constants_1 = require("../../../../core/constants");
48
- const CatalogEntityVersionItem_1 = require("./CatalogEntityVersionItem");
48
+ const CatalogEntityVersionItem_1 = require("../../../../components/Catalog/CatalogEntity/CatalogEntityHistory/CatalogEntityVersionItem");
49
49
  function CatalogEntityHistorySidebar({ entityKey, revision, version, className, }) {
50
50
  const [isOpen, setIsOpen] = (0, react_1.useState)(false);
51
51
  const location = (0, react_router_dom_1.useLocation)();
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.TagsProperty = TagsProperty;
7
7
  const react_1 = __importDefault(require("react"));
8
8
  const TagsIcon_1 = require("../../../../icons/TagsIcon/TagsIcon");
9
- const theme_1 = require("../../../../index.js");
9
+ const CatalogTagsWithTooltip_1 = require("../../../../components/Catalog/CatalogTagsWithTooltip");
10
10
  const CatalogEntityPropertyCard_1 = require("../../../../components/Catalog/CatalogEntity/CatalogEntityProperties/CatalogEntityPropertyCard");
11
11
  const hooks_1 = require("../../../../core/hooks");
12
12
  function TagsProperty({ entity }) {
@@ -15,7 +15,7 @@ function TagsProperty({ entity }) {
15
15
  return (react_1.default.createElement("div", { "data-component-name": "Catalog/CatalogEntity/CatalogEntityProperties/TagsProperty" },
16
16
  react_1.default.createElement(CatalogEntityPropertyCard_1.CatalogEntityPropertyCard, { header: react_1.default.createElement(react_1.default.Fragment, null,
17
17
  react_1.default.createElement(TagsIcon_1.TagsIcon, null),
18
- translate('catalog.tags.label', 'Tags')), content: react_1.default.createElement(theme_1.CatalogTagsWithTooltip, { itemsToShow: 8, items: entity.tags || [], tagProps: {
18
+ translate('catalog.tags.label', 'Tags')), content: react_1.default.createElement(CatalogTagsWithTooltip_1.CatalogTagsWithTooltip, { itemsToShow: 8, items: entity.tags || [], tagProps: {
19
19
  style: {
20
20
  fontSize: 'var(--font-size-base)',
21
21
  borderRadius: 'var(--border-radius)',
@@ -12,7 +12,7 @@ const CatalogEntityCell_1 = require("../../../components/Catalog/CatalogTableVie
12
12
  const CatalogTagsCell_1 = require("../../../components/Catalog/CatalogTableView/CatalogTagsCell");
13
13
  const hooks_1 = require("../../../core/hooks");
14
14
  const CatalogEntityTypeTag_1 = require("../../../components/Catalog/CatalogEntityTypeTag");
15
- const Link_1 = require("../../Link/Link");
15
+ const Link_1 = require("../../../components/Link/Link");
16
16
  const baseColumns = [
17
17
  {
18
18
  key: 'entity',
@@ -40,7 +40,7 @@ exports.JsonViewerWrap = exports.JsonViewer = void 0;
40
40
  const react_1 = __importStar(require("react"));
41
41
  const styled_components_1 = __importDefault(require("styled-components"));
42
42
  const CodeBlock_1 = require("../../components/CodeBlock/CodeBlock");
43
- const Helpers_1 = require("./Helpers");
43
+ const Helpers_1 = require("../../components/JsonViewer/Helpers");
44
44
  function JsonComponent({ data, expandLevel = 1, className, onCopyClick, onPanelToggle, title, controls = {}, }) {
45
45
  const showFoldingButtons = data && Object.values(data).some((value) => typeof value === 'object' && value !== null);
46
46
  const [expandAllSignal, setExpandAllSignal] = react_1.default.useState(undefined);
@@ -48,8 +48,8 @@ const Markdown_1 = require("../../components/Markdown/Markdown");
48
48
  const DocumentIcon_1 = require("../../icons/DocumentIcon/DocumentIcon");
49
49
  const AiStarsIcon_1 = require("../../icons/AiStarsIcon/AiStarsIcon");
50
50
  const CheckmarkOutlineIcon_1 = require("../../icons/CheckmarkOutlineIcon/CheckmarkOutlineIcon");
51
- const SearchAiActionButtons_1 = require("./SearchAiActionButtons");
52
- const SearchAiNegativeFeedbackForm_1 = require("./SearchAiNegativeFeedbackForm");
51
+ const SearchAiActionButtons_1 = require("../../components/Search/SearchAiActionButtons");
52
+ const SearchAiNegativeFeedbackForm_1 = require("../../components/Search/SearchAiNegativeFeedbackForm");
53
53
  function SearchAiMessageComponent({ role, content, isThinking, resources, className, messageId, feedback, onFeedbackChange, }) {
54
54
  var _a;
55
55
  const { useMarkdownText, useTranslate, useTelemetry } = (0, hooks_1.useThemeHooks)();
@@ -181,7 +181,7 @@ function createMCPAction({ clientType, mcpConfig, translate, onClickCallback, })
181
181
  return Object.assign(Object.assign({}, sharedProps), { buttonText: translate('page.actions.connectMcp.vscode', 'Connect to VS Code'), title: translate('page.actions.connectMcp.vscode', 'Connect to VS Code'), description: translate('page.actions.connectMcp.vscodeDescription', 'Install MCP server on VS Code'), iconComponent: VSCodeIcon_1.VSCodeIcon });
182
182
  }
183
183
  function shouldHidePageActions(pageProps, themeConfig, openapiExcludeFromSearch) {
184
- var _a, _b, _c, _d, _e, _f;
184
+ var _a, _b, _c, _d, _e, _f, _g;
185
185
  // Can't use any actions if no markdown files are generated for LLMs
186
186
  if ((_b = (_a = pageProps === null || pageProps === void 0 ? void 0 : pageProps.seo) === null || _a === void 0 ? void 0 : _a.llmstxt) === null || _b === void 0 ? void 0 : _b.hide) {
187
187
  return true;
@@ -191,8 +191,8 @@ function shouldHidePageActions(pageProps, themeConfig, openapiExcludeFromSearch)
191
191
  return true;
192
192
  }
193
193
  // Page is excluded from search
194
- const isPageExcludedFromSearch = ((_e = pageProps === null || pageProps === void 0 ? void 0 : pageProps.frontmatter) === null || _e === void 0 ? void 0 : _e.excludeFromSearch) ||
195
- (((_f = pageProps === null || pageProps === void 0 ? void 0 : pageProps.metadata) === null || _f === void 0 ? void 0 : _f.type) === 'openapi' && openapiExcludeFromSearch);
194
+ const isOpenApiPage = ((_e = pageProps === null || pageProps === void 0 ? void 0 : pageProps.metadata) === null || _e === void 0 ? void 0 : _e.type) === 'openapi' || ((_f = pageProps === null || pageProps === void 0 ? void 0 : pageProps.metadata) === null || _f === void 0 ? void 0 : _f.subType) === 'openapi-operation';
195
+ const isPageExcludedFromSearch = ((_g = pageProps === null || pageProps === void 0 ? void 0 : pageProps.frontmatter) === null || _g === void 0 ? void 0 : _g.excludeFromSearch) || (isOpenApiPage && openapiExcludeFromSearch);
196
196
  if (isPageExcludedFromSearch) {
197
197
  return true;
198
198
  }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Returns a function that appends a per-component-instance suffix to SVG ids.
3
+ * This prevents collisions when multiple identical SVGs are rendered on the same page,
4
+ * which can break `url(#...)` references (gradients, clipPath, masks, filters) on reflow.
5
+ */
6
+ export declare function useUniqueSvgIds(): (id: string) => string;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useUniqueSvgIds = useUniqueSvgIds;
4
+ const react_1 = require("react");
5
+ /**
6
+ * Returns a function that appends a per-component-instance suffix to SVG ids.
7
+ * This prevents collisions when multiple identical SVGs are rendered on the same page,
8
+ * which can break `url(#...)` references (gradients, clipPath, masks, filters) on reflow.
9
+ */
10
+ function useUniqueSvgIds() {
11
+ const reactId = (0, react_1.useId)();
12
+ const safeSuffix = reactId.replace(/:/g, '_');
13
+ return (id) => `${id}-${safeSuffix}`;
14
+ }
15
+ //# sourceMappingURL=use-unique-svg-ids.js.map
@@ -25,3 +25,4 @@ export { SecurityVariablesEnvSuffix } from '../constants/environments';
25
25
  export { isUndefined, isString, isNotNull, isObject } from '../utils/type-guards';
26
26
  export { ThemeDataContext, type ThemeDataTransferObject } from '../contexts/ThemeDataContext';
27
27
  export { SearchSessionProvider, SearchSessionContext } from '../contexts/SearchContext';
28
+ export { useUniqueSvgIds } from '../hooks/use-unique-svg-ids';
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SearchSessionContext = exports.SearchSessionProvider = exports.ThemeDataContext = exports.isObject = exports.isNotNull = exports.isString = exports.isUndefined = exports.SecurityVariablesEnvSuffix = exports.useDialogHotKeys = exports.useSearchDialog = exports.useModalScrollLock = exports.useActiveSectionId = exports.useOutsideClick = exports.useThemeHooks = exports.useFocusTrap = exports.getUserAgent = exports.ClipboardService = exports.getOperationColor = exports.isPrimitive = exports.breakpoints = exports.GlobalStyle = exports.useMount = exports.typedMemo = exports.capitalize = exports.withPathPrefix = exports.addTrailingSlash = exports.combineUrls = exports.getPathPrefix = exports.removeLeadingSlash = exports.addLeadingSlash = exports.IS_BROWSER = void 0;
3
+ exports.useUniqueSvgIds = exports.SearchSessionContext = exports.SearchSessionProvider = exports.ThemeDataContext = exports.isObject = exports.isNotNull = exports.isString = exports.isUndefined = exports.SecurityVariablesEnvSuffix = exports.useDialogHotKeys = exports.useSearchDialog = exports.useModalScrollLock = exports.useActiveSectionId = exports.useOutsideClick = exports.useThemeHooks = exports.useFocusTrap = exports.getUserAgent = exports.ClipboardService = exports.getOperationColor = exports.isPrimitive = exports.breakpoints = exports.GlobalStyle = exports.useMount = exports.typedMemo = exports.capitalize = exports.withPathPrefix = exports.addTrailingSlash = exports.combineUrls = exports.getPathPrefix = exports.removeLeadingSlash = exports.addLeadingSlash = exports.IS_BROWSER = void 0;
4
4
  var dom_1 = require("../utils/dom");
5
5
  Object.defineProperty(exports, "IS_BROWSER", { enumerable: true, get: function () { return dom_1.IS_BROWSER; } });
6
6
  var urls_1 = require("../utils/urls");
@@ -54,4 +54,6 @@ Object.defineProperty(exports, "ThemeDataContext", { enumerable: true, get: func
54
54
  var SearchContext_1 = require("../contexts/SearchContext");
55
55
  Object.defineProperty(exports, "SearchSessionProvider", { enumerable: true, get: function () { return SearchContext_1.SearchSessionProvider; } });
56
56
  Object.defineProperty(exports, "SearchSessionContext", { enumerable: true, get: function () { return SearchContext_1.SearchSessionContext; } });
57
+ var use_unique_svg_ids_1 = require("../hooks/use-unique-svg-ids");
58
+ Object.defineProperty(exports, "useUniqueSvgIds", { enumerable: true, get: function () { return use_unique_svg_ids_1.useUniqueSvgIds; } });
57
59
  //# sourceMappingURL=index.js.map
package/lib/index.d.ts CHANGED
@@ -274,5 +274,8 @@ export * from './layouts/OIDCForbidden';
274
274
  export * from './layouts/ThreePanelLayout';
275
275
  export * from './layouts/CodeWalkthroughLayout';
276
276
  export * from './layouts/InternalServerErrorLayout';
277
+ export * from './layouts/DocumentationLayout';
278
+ export * from './layouts/DocumentationLayoutTop';
279
+ export * from './layouts/DocumentationLayoutBottom';
277
280
  export * as markdoc from './markdoc/default';
278
281
  export * from './components/DatePicker/DatePicker';
package/lib/index.js CHANGED
@@ -338,6 +338,9 @@ __exportStar(require("./layouts/OIDCForbidden"), exports);
338
338
  __exportStar(require("./layouts/ThreePanelLayout"), exports);
339
339
  __exportStar(require("./layouts/CodeWalkthroughLayout"), exports);
340
340
  __exportStar(require("./layouts/InternalServerErrorLayout"), exports);
341
+ __exportStar(require("./layouts/DocumentationLayout"), exports);
342
+ __exportStar(require("./layouts/DocumentationLayoutTop"), exports);
343
+ __exportStar(require("./layouts/DocumentationLayoutBottom"), exports);
341
344
  /* Markdoc */
342
345
  exports.markdoc = __importStar(require("./markdoc/default"));
343
346
  /* DatePicker */
@@ -6,26 +6,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.DocumentationLayout = DocumentationLayout;
7
7
  const react_1 = __importDefault(require("react"));
8
8
  const styled_components_1 = __importDefault(require("styled-components"));
9
- const EditPageButton_1 = require("../components/Buttons/EditPageButton");
10
9
  const utils_1 = require("../core/utils");
11
- const PageNavigation_1 = require("../components/PageNavigation/PageNavigation");
12
- const LastUpdated_1 = require("../components/LastUpdated/LastUpdated");
13
- const Breadcrumbs_1 = require("../components/Breadcrumbs/Breadcrumbs");
14
10
  const CodeSnippetContext_1 = require("../core/contexts/CodeSnippetContext");
11
+ const DocumentationLayoutTop_1 = require("../layouts/DocumentationLayoutTop");
12
+ const DocumentationLayoutBottom_1 = require("../layouts/DocumentationLayoutBottom");
15
13
  function DocumentationLayout({ tableOfContent, feedback, config, editPage, lastModified, nextPage, prevPage, className, children, }) {
16
14
  var _a;
17
- const { editPage: themeEditPage } = config || {};
18
- const mergedConf = editPage ? Object.assign(Object.assign({}, themeEditPage), editPage) : undefined;
19
15
  return (react_1.default.createElement(CodeSnippetContext_1.CodeSnippetProvider, null,
20
16
  react_1.default.createElement(LayoutWrapper, { "data-component-name": "Layout/DocumentationLayout", className: className },
21
17
  react_1.default.createElement(ContentWrapper, { withToc: !((_a = config === null || config === void 0 ? void 0 : config.toc) === null || _a === void 0 ? void 0 : _a.hide) },
22
- react_1.default.createElement(Breadcrumbs, null),
23
- react_1.default.createElement(LayoutTop, null,
24
- lastModified && react_1.default.createElement(LastUpdated_1.LastUpdated, { lastModified: new Date(lastModified) }),
25
- mergedConf && react_1.default.createElement(EditPageButton_1.EditPageButton, { to: mergedConf.to })),
18
+ react_1.default.createElement(DocumentationLayoutTop_1.DocumentationLayoutTop, { config: config, editPage: editPage, lastModified: lastModified }),
26
19
  children,
27
- react_1.default.createElement(LayoutBottom, null, feedback),
28
- react_1.default.createElement(PageNavigation_1.PageNavigation, { nextPage: nextPage, prevPage: prevPage })),
20
+ react_1.default.createElement(DocumentationLayoutBottom_1.DocumentationLayoutBottom, { feedback: feedback, nextPage: nextPage, prevPage: prevPage })),
29
21
  tableOfContent)));
30
22
  }
31
23
  const LayoutWrapper = styled_components_1.default.div.attrs(({ className }) => ({
@@ -58,17 +50,4 @@ const ContentWrapper = styled_components_1.default.section `
58
50
  width: ${({ withToc }) => (withToc ? `calc(90% - var(--toc-width))` : '90%')};
59
51
  }
60
52
  `;
61
- const LayoutTop = styled_components_1.default.div `
62
- display: flex;
63
- justify-content: space-between;
64
- flex-flow: row nowrap;
65
- `;
66
- const Breadcrumbs = (0, styled_components_1.default)(Breadcrumbs_1.Breadcrumbs) `
67
- margin-bottom: var(--breadcrumbs-margin-bottom);
68
- `;
69
- const LayoutBottom = (0, styled_components_1.default)(LayoutTop) `
70
- > * {
71
- margin: 25px 0;
72
- }
73
- `;
74
53
  //# sourceMappingURL=DocumentationLayout.js.map
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ import type { JSX } from 'react';
3
+ import type { ResolvedNavItemWithLink } from '@redocly/config';
4
+ type DocumentationLayoutBottomProps = {
5
+ feedback: React.ReactNode;
6
+ nextPage?: ResolvedNavItemWithLink | null;
7
+ prevPage?: ResolvedNavItemWithLink | null;
8
+ className?: string;
9
+ };
10
+ export declare function DocumentationLayoutBottom({ feedback, nextPage, prevPage, }: React.PropsWithChildren<DocumentationLayoutBottomProps>): JSX.Element;
11
+ export {};
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.DocumentationLayoutBottom = DocumentationLayoutBottom;
7
+ const react_1 = __importDefault(require("react"));
8
+ const styled_components_1 = __importDefault(require("styled-components"));
9
+ const PageNavigation_1 = require("../components/PageNavigation/PageNavigation");
10
+ function DocumentationLayoutBottom({ feedback, nextPage, prevPage, }) {
11
+ return (react_1.default.createElement(Wrapper, { "data-component-name": "Layout/DocumentationLayoutBottom" },
12
+ react_1.default.createElement(LayoutBottom, null, feedback),
13
+ react_1.default.createElement(PageNavigation_1.PageNavigation, { nextPage: nextPage, prevPage: prevPage })));
14
+ }
15
+ const Wrapper = styled_components_1.default.div `
16
+ display: flex;
17
+ flex-direction: column;
18
+ `;
19
+ const LayoutBottom = styled_components_1.default.div `
20
+ display: flex;
21
+ justify-content: space-between;
22
+ flex-flow: row nowrap;
23
+
24
+ > * {
25
+ margin: 25px 0;
26
+ }
27
+ `;
28
+ //# sourceMappingURL=DocumentationLayoutBottom.js.map
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import type { JSX } from 'react';
3
+ import type { MarkdownConfig } from '@redocly/config';
4
+ type DocumentationLayoutTopProps = {
5
+ config?: MarkdownConfig;
6
+ editPage?: {
7
+ to: string;
8
+ };
9
+ /** String in ISO format */
10
+ lastModified?: string | null;
11
+ };
12
+ export declare function DocumentationLayoutTop({ config, editPage, lastModified, }: React.PropsWithChildren<DocumentationLayoutTopProps>): JSX.Element;
13
+ export {};
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.DocumentationLayoutTop = DocumentationLayoutTop;
7
+ const react_1 = __importDefault(require("react"));
8
+ const styled_components_1 = __importDefault(require("styled-components"));
9
+ const EditPageButton_1 = require("../components/Buttons/EditPageButton");
10
+ const LastUpdated_1 = require("../components/LastUpdated/LastUpdated");
11
+ const Breadcrumbs_1 = require("../components/Breadcrumbs/Breadcrumbs");
12
+ function DocumentationLayoutTop({ config, editPage, lastModified, }) {
13
+ const { editPage: themeEditPage } = config || {};
14
+ const mergedConf = editPage ? Object.assign(Object.assign({}, themeEditPage), editPage) : undefined;
15
+ return (react_1.default.createElement(Wrapper, { "data-component-name": "Layout/DocumentationLayoutTop" },
16
+ react_1.default.createElement(Breadcrumbs, null),
17
+ react_1.default.createElement(LayoutTop, null,
18
+ lastModified && react_1.default.createElement(LastUpdated_1.LastUpdated, { lastModified: new Date(lastModified) }),
19
+ mergedConf && react_1.default.createElement(EditPageButton_1.EditPageButton, { to: mergedConf.to }))));
20
+ }
21
+ const Wrapper = styled_components_1.default.div `
22
+ display: flex;
23
+ flex-direction: column;
24
+ `;
25
+ const LayoutTop = styled_components_1.default.div `
26
+ display: flex;
27
+ justify-content: space-between;
28
+ flex-flow: row nowrap;
29
+ `;
30
+ const Breadcrumbs = (0, styled_components_1.default)(Breadcrumbs_1.Breadcrumbs) `
31
+ margin-bottom: var(--breadcrumbs-margin-bottom);
32
+ `;
33
+ //# sourceMappingURL=DocumentationLayoutTop.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redocly/theme",
3
- "version": "0.62.0-next.0",
3
+ "version": "0.62.0-next.1",
4
4
  "description": "Shared UI components lib",
5
5
  "keywords": [
6
6
  "theme",
@@ -63,7 +63,7 @@
63
63
  "vitest": "4.0.10",
64
64
  "vitest-when": "0.6.2",
65
65
  "webpack": "5.94.0",
66
- "@redocly/realm-asyncapi-sdk": "0.8.0-next.0"
66
+ "@redocly/realm-asyncapi-sdk": "0.8.0-next.1"
67
67
  },
68
68
  "dependencies": {
69
69
  "@tanstack/react-query": "5.62.3",
@@ -88,7 +88,7 @@
88
88
  "ts:check": "tsc --noEmit --skipLibCheck",
89
89
  "clean": "rimraf lib",
90
90
  "compile": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
91
- "build": "npm run clean && npm run compile",
91
+ "build": "pnpm run clean && pnpm run compile",
92
92
  "test": "vitest run",
93
93
  "test:update": "vitest run --update",
94
94
  "test:watch": "vitest",
@@ -20,7 +20,7 @@ import { useThemeHooks } from '@redocly/theme/core/hooks';
20
20
  import { CatalogEntitySchema } from '@redocly/theme/components/Catalog/CatalogEntity/CatalogEntitySchema';
21
21
  import { CatalogEntityMethodAndPath } from '@redocly/theme/components/Catalog/CatalogEntity/CatalogEntityMethodAndPath';
22
22
  import { CatalogEntityRelationsGraph } from '@redocly/theme/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsGraph.lazy';
23
- import { CatalogEntityHistorySidebar } from '@redocly/theme';
23
+ import { CatalogEntityHistorySidebar } from '@redocly/theme/components/Catalog/CatalogEntity/CatalogEntityHistory/CatalogEntityHistorySidebar';
24
24
 
25
25
  export type CatalogEntityProps = {
26
26
  /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
@@ -7,8 +7,7 @@ import { useThemeHooks } from '@redocly/theme/core/hooks';
7
7
  import { MenuContainer } from '@redocly/theme/components/Menu/MenuContainer';
8
8
  import { transformRevisionsToVersionHistory } from '@redocly/theme/core/utils';
9
9
  import { DEFAULT_LOCALE_PLACEHOLDER } from '@redocly/theme/core/constants';
10
-
11
- import { CatalogEntityVersionItem } from './CatalogEntityVersionItem';
10
+ import { CatalogEntityVersionItem } from '@redocly/theme/components/Catalog/CatalogEntity/CatalogEntityHistory/CatalogEntityVersionItem';
12
11
 
13
12
  export type CatalogHistorySidebarProps = {
14
13
  entityKey: string;
@@ -2,7 +2,7 @@ import React, { JSX } from 'react';
2
2
 
3
3
  import { BffCatalogEntity } from '@redocly/theme/core/types';
4
4
  import { TagsIcon } from '@redocly/theme/icons/TagsIcon/TagsIcon';
5
- import { CatalogTagsWithTooltip } from '@redocly/theme';
5
+ import { CatalogTagsWithTooltip } from '@redocly/theme/components/Catalog/CatalogTagsWithTooltip';
6
6
  import { CatalogEntityPropertyCard } from '@redocly/theme/components/Catalog/CatalogEntity/CatalogEntityProperties/CatalogEntityPropertyCard';
7
7
  import { useThemeHooks } from '@redocly/theme/core/hooks';
8
8
 
@@ -10,8 +10,7 @@ import { CatalogEntityCell } from '@redocly/theme/components/Catalog/CatalogTabl
10
10
  import { CatalogTagsCell } from '@redocly/theme/components/Catalog/CatalogTableView/CatalogTagsCell';
11
11
  import { useCatalogEntityDetails } from '@redocly/theme/core/hooks';
12
12
  import { CatalogEntityTypeTag } from '@redocly/theme/components/Catalog/CatalogEntityTypeTag';
13
-
14
- import { Link } from '../../Link/Link';
13
+ import { Link } from '@redocly/theme/components/Link/Link';
15
14
 
16
15
  export type BaseEntity = {
17
16
  id: string;
@@ -5,8 +5,7 @@ import type { JSX } from 'react';
5
5
  import type { CodeBlockControlsProps } from '@redocly/theme/components/CodeBlock/CodeBlockControls';
6
6
 
7
7
  import { CodeBlock } from '@redocly/theme/components/CodeBlock/CodeBlock';
8
-
9
- import { JsonValue } from './Helpers';
8
+ import { JsonValue } from '@redocly/theme/components/JsonViewer/Helpers';
10
9
 
11
10
  export type PanelType = 'request' | 'responses' | 'request-samples' | 'response-samples';
12
11
 
@@ -12,9 +12,8 @@ import { Markdown } from '@redocly/theme/components/Markdown/Markdown';
12
12
  import { DocumentIcon } from '@redocly/theme/icons/DocumentIcon/DocumentIcon';
13
13
  import { AiStarsIcon } from '@redocly/theme/icons/AiStarsIcon/AiStarsIcon';
14
14
  import { CheckmarkOutlineIcon } from '@redocly/theme/icons/CheckmarkOutlineIcon/CheckmarkOutlineIcon';
15
-
16
- import { SearchAiActionButtons } from './SearchAiActionButtons';
17
- import { SearchAiNegativeFeedbackForm } from './SearchAiNegativeFeedbackForm';
15
+ import { SearchAiActionButtons } from '@redocly/theme/components/Search/SearchAiActionButtons';
16
+ import { SearchAiNegativeFeedbackForm } from '@redocly/theme/components/Search/SearchAiNegativeFeedbackForm';
18
17
 
19
18
  export type SearchAiMessageProps = {
20
19
  role: AiSearchConversationRole;
@@ -16,6 +16,7 @@ export const useThemeHooks = vi.fn(() => ({
16
16
  send: vi.fn(),
17
17
  sendCodeSnippetReportedMessage: vi.fn(),
18
18
  sendPageActionsButtonClickedMessage: vi.fn(),
19
+ sendColorModeSwitchedMessage: vi.fn(),
19
20
  })),
20
21
  useBreadcrumbs: vi.fn().mockReturnValue({ breadcrumbs: [], siblings: undefined }),
21
22
  useBanner: vi.fn(() => ({
@@ -280,9 +280,10 @@ function shouldHidePageActions(
280
280
  }
281
281
 
282
282
  // Page is excluded from search
283
+ const isOpenApiPage =
284
+ pageProps?.metadata?.type === 'openapi' || pageProps?.metadata?.subType === 'openapi-operation';
283
285
  const isPageExcludedFromSearch =
284
- pageProps?.frontmatter?.excludeFromSearch ||
285
- (pageProps?.metadata?.type === 'openapi' && openapiExcludeFromSearch);
286
+ pageProps?.frontmatter?.excludeFromSearch || (isOpenApiPage && openapiExcludeFromSearch);
286
287
 
287
288
  if (isPageExcludedFromSearch) {
288
289
  return true;
@@ -0,0 +1,12 @@
1
+ import { useId } from 'react';
2
+
3
+ /**
4
+ * Returns a function that appends a per-component-instance suffix to SVG ids.
5
+ * This prevents collisions when multiple identical SVGs are rendered on the same page,
6
+ * which can break `url(#...)` references (gradients, clipPath, masks, filters) on reflow.
7
+ */
8
+ export function useUniqueSvgIds(): (id: string) => string {
9
+ const reactId = useId();
10
+ const safeSuffix = reactId.replace(/:/g, '_');
11
+ return (id: string): string => `${id}-${safeSuffix}`;
12
+ }
@@ -38,3 +38,4 @@ export { SecurityVariablesEnvSuffix } from '../constants/environments';
38
38
  export { isUndefined, isString, isNotNull, isObject } from '../utils/type-guards';
39
39
  export { ThemeDataContext, type ThemeDataTransferObject } from '../contexts/ThemeDataContext';
40
40
  export { SearchSessionProvider, SearchSessionContext } from '../contexts/SearchContext';
41
+ export { useUniqueSvgIds } from '../hooks/use-unique-svg-ids';
package/src/index.ts CHANGED
@@ -302,6 +302,9 @@ export * from '@redocly/theme/layouts/OIDCForbidden';
302
302
  export * from '@redocly/theme/layouts/ThreePanelLayout';
303
303
  export * from '@redocly/theme/layouts/CodeWalkthroughLayout';
304
304
  export * from '@redocly/theme/layouts/InternalServerErrorLayout';
305
+ export * from '@redocly/theme/layouts/DocumentationLayout';
306
+ export * from '@redocly/theme/layouts/DocumentationLayoutTop';
307
+ export * from '@redocly/theme/layouts/DocumentationLayoutBottom';
305
308
  /* Markdoc */
306
309
  export * as markdoc from '@redocly/theme/markdoc/default';
307
310
  /* DatePicker */
@@ -4,12 +4,10 @@ import styled from 'styled-components';
4
4
  import type { JSX } from 'react';
5
5
  import type { ResolvedNavItemWithLink, MarkdownConfig } from '@redocly/config';
6
6
 
7
- import { EditPageButton } from '@redocly/theme/components/Buttons/EditPageButton';
8
7
  import { breakpoints } from '@redocly/theme/core/utils';
9
- import { PageNavigation } from '@redocly/theme/components/PageNavigation/PageNavigation';
10
- import { LastUpdated } from '@redocly/theme/components/LastUpdated/LastUpdated';
11
- import { Breadcrumbs as ThemeBreadcrumbs } from '@redocly/theme/components/Breadcrumbs/Breadcrumbs';
12
8
  import { CodeSnippetProvider } from '@redocly/theme/core/contexts/CodeSnippetContext';
9
+ import { DocumentationLayoutTop } from '@redocly/theme/layouts/DocumentationLayoutTop';
10
+ import { DocumentationLayoutBottom } from '@redocly/theme/layouts/DocumentationLayoutBottom';
13
11
 
14
12
  type DocumentationLayoutProps = {
15
13
  tableOfContent: React.ReactNode;
@@ -36,21 +34,13 @@ export function DocumentationLayout({
36
34
  className,
37
35
  children,
38
36
  }: React.PropsWithChildren<DocumentationLayoutProps>): JSX.Element {
39
- const { editPage: themeEditPage } = config || {};
40
- const mergedConf = editPage ? { ...themeEditPage, ...editPage } : undefined;
41
-
42
37
  return (
43
38
  <CodeSnippetProvider>
44
39
  <LayoutWrapper data-component-name="Layout/DocumentationLayout" className={className}>
45
40
  <ContentWrapper withToc={!config?.toc?.hide}>
46
- <Breadcrumbs />
47
- <LayoutTop>
48
- {lastModified && <LastUpdated lastModified={new Date(lastModified)} />}
49
- {mergedConf && <EditPageButton to={mergedConf.to} />}
50
- </LayoutTop>
41
+ <DocumentationLayoutTop config={config} editPage={editPage} lastModified={lastModified} />
51
42
  {children}
52
- <LayoutBottom>{feedback}</LayoutBottom>
53
- <PageNavigation nextPage={nextPage} prevPage={prevPage} />
43
+ <DocumentationLayoutBottom feedback={feedback} nextPage={nextPage} prevPage={prevPage} />
54
44
  </ContentWrapper>
55
45
  {tableOfContent}
56
46
  </LayoutWrapper>
@@ -89,19 +79,3 @@ const ContentWrapper = styled.section<{ withToc: boolean }>`
89
79
  width: ${({ withToc }) => (withToc ? `calc(90% - var(--toc-width))` : '90%')};
90
80
  }
91
81
  `;
92
-
93
- const LayoutTop = styled.div`
94
- display: flex;
95
- justify-content: space-between;
96
- flex-flow: row nowrap;
97
- `;
98
-
99
- const Breadcrumbs = styled(ThemeBreadcrumbs)`
100
- margin-bottom: var(--breadcrumbs-margin-bottom);
101
- `;
102
-
103
- const LayoutBottom = styled(LayoutTop)`
104
- > * {
105
- margin: 25px 0;
106
- }
107
- `;
@@ -0,0 +1,42 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ import type { JSX } from 'react';
5
+ import type { ResolvedNavItemWithLink } from '@redocly/config';
6
+
7
+ import { PageNavigation } from '@redocly/theme/components/PageNavigation/PageNavigation';
8
+
9
+ type DocumentationLayoutBottomProps = {
10
+ feedback: React.ReactNode;
11
+ nextPage?: ResolvedNavItemWithLink | null;
12
+ prevPage?: ResolvedNavItemWithLink | null;
13
+ className?: string;
14
+ };
15
+
16
+ export function DocumentationLayoutBottom({
17
+ feedback,
18
+ nextPage,
19
+ prevPage,
20
+ }: React.PropsWithChildren<DocumentationLayoutBottomProps>): JSX.Element {
21
+ return (
22
+ <Wrapper data-component-name="Layout/DocumentationLayoutBottom">
23
+ <LayoutBottom>{feedback}</LayoutBottom>
24
+ <PageNavigation nextPage={nextPage} prevPage={prevPage} />
25
+ </Wrapper>
26
+ );
27
+ }
28
+
29
+ const Wrapper = styled.div`
30
+ display: flex;
31
+ flex-direction: column;
32
+ `;
33
+
34
+ const LayoutBottom = styled.div`
35
+ display: flex;
36
+ justify-content: space-between;
37
+ flex-flow: row nowrap;
38
+
39
+ > * {
40
+ margin: 25px 0;
41
+ }
42
+ `;
@@ -0,0 +1,52 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ import type { JSX } from 'react';
5
+ import type { MarkdownConfig } from '@redocly/config';
6
+
7
+ import { EditPageButton } from '@redocly/theme/components/Buttons/EditPageButton';
8
+ import { LastUpdated } from '@redocly/theme/components/LastUpdated/LastUpdated';
9
+ import { Breadcrumbs as ThemeBreadcrumbs } from '@redocly/theme/components/Breadcrumbs/Breadcrumbs';
10
+
11
+ type DocumentationLayoutTopProps = {
12
+ config?: MarkdownConfig;
13
+ editPage?: {
14
+ to: string;
15
+ };
16
+ /** String in ISO format */
17
+ lastModified?: string | null;
18
+ };
19
+
20
+ export function DocumentationLayoutTop({
21
+ config,
22
+ editPage,
23
+ lastModified,
24
+ }: React.PropsWithChildren<DocumentationLayoutTopProps>): JSX.Element {
25
+ const { editPage: themeEditPage } = config || {};
26
+ const mergedConf = editPage ? { ...themeEditPage, ...editPage } : undefined;
27
+
28
+ return (
29
+ <Wrapper data-component-name="Layout/DocumentationLayoutTop">
30
+ <Breadcrumbs />
31
+ <LayoutTop>
32
+ {lastModified && <LastUpdated lastModified={new Date(lastModified)} />}
33
+ {mergedConf && <EditPageButton to={mergedConf.to} />}
34
+ </LayoutTop>
35
+ </Wrapper>
36
+ );
37
+ }
38
+
39
+ const Wrapper = styled.div`
40
+ display: flex;
41
+ flex-direction: column;
42
+ `;
43
+
44
+ const LayoutTop = styled.div`
45
+ display: flex;
46
+ justify-content: space-between;
47
+ flex-flow: row nowrap;
48
+ `;
49
+
50
+ const Breadcrumbs = styled(ThemeBreadcrumbs)`
51
+ margin-bottom: var(--breadcrumbs-margin-bottom);
52
+ `;