@redocly/theme 0.58.0-next.9 → 0.59.0-next.0

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 (84) hide show
  1. package/lib/components/Catalog/CatalogEntity/CatalogEntity.d.ts +5 -1
  2. package/lib/components/Catalog/CatalogEntity/CatalogEntity.js +4 -4
  3. package/lib/components/Catalog/CatalogEntity/CatalogEntityMetadata.js +3 -3
  4. package/lib/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityApiDescriptionRelations.js +1 -1
  5. package/lib/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityTeamRelations.js +1 -1
  6. package/lib/components/Catalog/CatalogEntity/CatalogEntitySchema.d.ts +5 -1
  7. package/lib/components/Catalog/CatalogEntity/CatalogEntitySchema.js +9 -7
  8. package/lib/components/CodeBlock/CodeBlock.d.ts +5 -12
  9. package/lib/components/CodeBlock/CodeBlockControls.d.ts +3 -3
  10. package/lib/components/CodeBlock/CodeBlockControls.js +1 -1
  11. package/lib/components/CodeBlock/CodeBlockDropdown.d.ts +2 -2
  12. package/lib/components/CodeBlock/CodeBlockDropdown.js +4 -13
  13. package/lib/components/CodeBlock/CodeBlockTabs.d.ts +2 -2
  14. package/lib/components/CodeBlock/CodeBlockTabs.js +4 -3
  15. package/lib/components/JsonViewer/JsonViewer.d.ts +1 -1
  16. package/lib/components/JsonViewer/JsonViewer.js +9 -10
  17. package/lib/components/PageActions/PageActions.d.ts +4 -1
  18. package/lib/components/PageActions/PageActions.js +2 -2
  19. package/lib/components/Panel/variables.js +1 -0
  20. package/lib/components/Tag/Tag.d.ts +3 -2
  21. package/lib/components/Tag/Tag.js +21 -5
  22. package/lib/components/Tag/variables.dark.js +135 -0
  23. package/lib/components/Tag/variables.js +120 -58
  24. package/lib/core/constants/catalog.js +4 -0
  25. package/lib/core/contexts/CodeSnippetContext.d.ts +14 -6
  26. package/lib/core/contexts/CodeSnippetContext.js +57 -14
  27. package/lib/core/hooks/use-codeblock-tabs-controls.d.ts +2 -2
  28. package/lib/core/hooks/use-local-state.js +22 -18
  29. package/lib/core/hooks/use-page-actions.d.ts +2 -1
  30. package/lib/core/hooks/use-page-actions.js +48 -6
  31. package/lib/core/hooks/use-tabs.d.ts +11 -6
  32. package/lib/core/hooks/use-tabs.js +117 -207
  33. package/lib/core/openapi/index.d.ts +1 -0
  34. package/lib/core/openapi/index.js +3 -1
  35. package/lib/core/types/l10n.d.ts +1 -1
  36. package/lib/core/types/open-api-server.d.ts +1 -0
  37. package/lib/core/utils/index.d.ts +1 -0
  38. package/lib/core/utils/index.js +1 -0
  39. package/lib/core/utils/tabs.d.ts +1 -0
  40. package/lib/core/utils/tabs.js +8 -0
  41. package/lib/icons/CursorIcon/CursorIcon.d.ts +9 -0
  42. package/lib/icons/CursorIcon/CursorIcon.js +22 -0
  43. package/lib/layouts/DocumentationLayout.js +1 -3
  44. package/lib/markdoc/components/CodeGroup/CodeGroup.js +49 -27
  45. package/lib/markdoc/components/Tabs/Tab.js +1 -1
  46. package/lib/markdoc/components/Tabs/TabList.d.ts +2 -14
  47. package/lib/markdoc/components/Tabs/TabList.js +65 -16
  48. package/lib/markdoc/components/Tabs/Tabs.d.ts +2 -2
  49. package/lib/markdoc/components/Tabs/Tabs.js +11 -87
  50. package/lib/markdoc/tags/tabs.js +5 -0
  51. package/package.json +4 -4
  52. package/src/components/Catalog/CatalogEntity/CatalogEntity.tsx +15 -2
  53. package/src/components/Catalog/CatalogEntity/CatalogEntityMetadata.tsx +3 -3
  54. package/src/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityApiDescriptionRelations.tsx +1 -1
  55. package/src/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityTeamRelations.tsx +1 -1
  56. package/src/components/Catalog/CatalogEntity/CatalogEntitySchema.tsx +27 -18
  57. package/src/components/CodeBlock/CodeBlock.tsx +5 -11
  58. package/src/components/CodeBlock/CodeBlockControls.tsx +4 -7
  59. package/src/components/CodeBlock/CodeBlockDropdown.tsx +11 -20
  60. package/src/components/CodeBlock/CodeBlockTabs.tsx +8 -8
  61. package/src/components/JsonViewer/JsonViewer.tsx +16 -9
  62. package/src/components/PageActions/PageActions.tsx +6 -4
  63. package/src/components/Panel/variables.ts +1 -0
  64. package/src/components/Tag/Tag.tsx +33 -8
  65. package/src/components/Tag/variables.dark.ts +135 -0
  66. package/src/components/Tag/variables.ts +120 -58
  67. package/src/core/constants/catalog.ts +4 -0
  68. package/src/core/contexts/CodeSnippetContext.tsx +54 -18
  69. package/src/core/hooks/use-codeblock-tabs-controls.ts +2 -2
  70. package/src/core/hooks/use-local-state.ts +28 -19
  71. package/src/core/hooks/use-page-actions.ts +63 -6
  72. package/src/core/hooks/use-tabs.ts +160 -238
  73. package/src/core/openapi/index.ts +1 -0
  74. package/src/core/types/l10n.ts +13 -0
  75. package/src/core/types/open-api-server.ts +1 -0
  76. package/src/core/utils/index.ts +1 -0
  77. package/src/core/utils/tabs.ts +4 -0
  78. package/src/icons/CursorIcon/CursorIcon.tsx +35 -0
  79. package/src/layouts/DocumentationLayout.tsx +3 -10
  80. package/src/markdoc/components/CodeGroup/CodeGroup.tsx +81 -52
  81. package/src/markdoc/components/Tabs/Tab.tsx +1 -0
  82. package/src/markdoc/components/Tabs/TabList.tsx +85 -30
  83. package/src/markdoc/components/Tabs/Tabs.tsx +12 -125
  84. package/src/markdoc/tags/tabs.ts +5 -0
@@ -31,42 +31,64 @@ const contexts_1 = require("../../../core/contexts");
31
31
  function CodeGroup(props) {
32
32
  const mode = props.mode || 'tabs';
33
33
  const isTabsMode = mode === 'tabs';
34
- const rawSnippets = React.useMemo(() => React.Children.toArray(props.children).map((child, idx) => {
35
- const childProps = child;
36
- return {
37
- name: getTabName(childProps.props, idx),
38
- languageName: (0, utils_1.langToName)(childProps.props.lang || 'Default'),
39
- lang: childProps.props.lang || '',
40
- props: childProps.props,
41
- };
42
- }), [props.children]);
43
- const [activeSnippetName, setActiveSnippetName] = (0, contexts_1.useActiveCodeSnippetName)(mode);
44
- const snippets = React.useMemo(() => Object.fromEntries(rawSnippets.map((snippet) => {
45
- const getItemName = (snippet) => isTabsMode ? snippet === null || snippet === void 0 ? void 0 : snippet.name : (snippet === null || snippet === void 0 ? void 0 : snippet.languageName) || '';
46
- const name = getItemName(snippet);
47
- const items = rawSnippets.map((item) => ({
48
- name: getItemName(item),
49
- lang: item.lang,
50
- }));
34
+ const rawSnippets = React.useMemo(() => parseSnippetsFromChildren(props.children), [props.children]);
35
+ const groupId = React.useMemo(() => generateGroupId(rawSnippets, mode), [rawSnippets, mode]);
36
+ const [activeSnippetId, setActiveSnippetId] = (0, contexts_1.useActiveCodeSnippetId)(groupId, rawSnippets);
37
+ const snippets = React.useMemo(() => {
38
+ const items = createItemsFromSnippets(rawSnippets, isTabsMode);
51
39
  const itemsProps = {
52
40
  items,
53
- onChange: (name) => {
54
- setActiveSnippetName(name);
55
- },
56
- value: activeSnippetName || getItemName(rawSnippets[0]),
41
+ onChange: (id) => setActiveSnippetId(id),
42
+ value: activeSnippetId,
57
43
  };
58
- const snippetProps = Object.assign(Object.assign(Object.assign({}, snippet.props), { header: Object.assign(Object.assign({}, snippet.props.header), { title: isTabsMode ? undefined : snippet.name }) }), (isTabsMode ? { tabs: itemsProps } : { dropdown: itemsProps }));
59
- return [name, snippetProps];
60
- })), [rawSnippets, activeSnippetName, isTabsMode, setActiveSnippetName]);
61
- const firstName = Object.keys(snippets)[0];
62
- const activeSnippet = snippets[activeSnippetName] || snippets[firstName];
44
+ return Object.fromEntries(rawSnippets.map((snippet) => {
45
+ const snippetProps = Object.assign(Object.assign(Object.assign({}, snippet.props), { header: Object.assign(Object.assign({}, snippet.props.header), { title: isTabsMode ? undefined : snippet.name }) }), (isTabsMode ? { tabs: itemsProps } : { dropdown: itemsProps }));
46
+ return [snippet.id, snippetProps];
47
+ }));
48
+ }, [rawSnippets, activeSnippetId, isTabsMode, setActiveSnippetId]);
49
+ const activeSnippet = snippets[activeSnippetId];
63
50
  if (!activeSnippet) {
64
51
  return null;
65
52
  }
66
53
  return React.createElement(CodeBlock_1.CodeBlock, Object.assign({}, activeSnippet));
67
54
  }
55
+ function generateContentHash(content) {
56
+ let hash = 0;
57
+ for (let i = 0; i < content.length; i++) {
58
+ hash = content.charCodeAt(i) + ((hash << 5) - hash);
59
+ }
60
+ return Math.abs(hash);
61
+ }
62
+ // Generate unique group ID for CodeGroup instance
63
+ // Examples: "dropdown-8901234", "tabs-1234567"
64
+ function generateGroupId(rawSnippets, mode) {
65
+ const content = rawSnippets.map((s) => s.id + (s.props.source || '')).join('|') + `|${mode}`;
66
+ const hash = generateContentHash(content);
67
+ return `${mode}-${hash}`;
68
+ }
68
69
  function getTabName(props, idx) {
69
70
  var _a;
70
- return String(((_a = props.header) === null || _a === void 0 ? void 0 : _a.title) || props.file || (0, utils_1.langToName)(props.lang || '') || 'Tab ' + String(idx + 1));
71
+ const fallbackName = `Tab ${idx + 1}`;
72
+ return String(((_a = props.header) === null || _a === void 0 ? void 0 : _a.title) || props.file || (0, utils_1.langToName)(props.lang || '') || fallbackName);
73
+ }
74
+ function parseSnippetsFromChildren(children) {
75
+ return React.Children.toArray(children).map((child, idx) => {
76
+ const childProps = child;
77
+ const props = childProps.props;
78
+ return {
79
+ name: getTabName(props, idx),
80
+ languageName: String((0, utils_1.langToName)(props.lang || 'Default') || ''),
81
+ lang: props.lang || '',
82
+ props,
83
+ id: `${props.lang || ''}-${idx}`,
84
+ };
85
+ });
86
+ }
87
+ function createItemsFromSnippets(snippets, isTabsMode) {
88
+ return snippets.map((snippet) => ({
89
+ name: isTabsMode ? snippet.name : snippet.languageName || '',
90
+ lang: snippet.lang,
91
+ id: snippet.id,
92
+ }));
71
93
  }
72
94
  //# sourceMappingURL=CodeGroup.js.map
@@ -11,7 +11,7 @@ const TabList_1 = require("../../../markdoc/components/Tabs/TabList");
11
11
  const GenericIcon_1 = require("../../../icons/GenericIcon/GenericIcon");
12
12
  function TabComponent({ tabId, label, size, disabled, setRef, onKeyDown, onClick, icon, iconRawContent, }) {
13
13
  return (react_1.default.createElement(TabList_1.TabItem, { "data-component-name": "Markdoc/Tabs/Tab", size: size, tabIndex: 0 },
14
- react_1.default.createElement(TabList_1.TabButtonLink, { id: `tab-${tabId}`, role: "tab", "aria-selected": "false", "aria-controls": `panel-${tabId}`, tabIndex: -1, size: size, disabled: disabled, ref: setRef, onKeyDown: onKeyDown, onClick: onClick },
14
+ react_1.default.createElement(TabList_1.TabButtonLink, { id: `tab-${tabId}`, "data-label": label, role: "tab", "aria-selected": "false", "aria-controls": `panel-${tabId}`, tabIndex: -1, size: size, disabled: disabled, ref: setRef, onKeyDown: onKeyDown, onClick: onClick },
15
15
  react_1.default.createElement(LabelWrapper, null,
16
16
  react_1.default.createElement(GenericIcon_1.GenericIcon, { icon: icon, rawContent: iconRawContent }),
17
17
  label))));
@@ -4,22 +4,10 @@ import { TabItemProps, TabsSize } from '../../../markdoc/components/Tabs/Tabs';
4
4
  type TabListProps = {
5
5
  childrenArray: React.ReactElement<TabItemProps>[];
6
6
  size: TabsSize;
7
- overflowTabs: number[];
8
- visibleTabs: number[];
9
- setTabRef: (element: HTMLButtonElement | null, index: number) => void;
10
- onTabClick: (labelOrIndex: string | number) => void;
11
- handleKeyboard: (event: React.KeyboardEvent<HTMLButtonElement>, index: number) => void;
12
- getTabId: (label: string, index: number) => string;
13
7
  activeTab: string;
14
- isAnimating: boolean;
15
- highlightStyle: {
16
- left: number;
17
- width: number;
18
- };
19
- allTabsHidden: boolean;
20
- tabsContainerRef: React.RefObject<HTMLUListElement | null>;
8
+ onTabChange: (tab: string) => void;
21
9
  };
22
- export declare function TabList({ childrenArray, size, overflowTabs, visibleTabs, setTabRef, onTabClick, handleKeyboard, getTabId, activeTab, isAnimating, highlightStyle, allTabsHidden, tabsContainerRef, }: TabListProps): JSX.Element;
10
+ export declare function TabList({ childrenArray, size, activeTab, onTabChange, }: TabListProps): JSX.Element;
23
11
  export declare const TabListContainer: import("styled-components").StyledComponent<"ul", any, {}, never>;
24
12
  export declare const TabItem: import("styled-components").StyledComponent<"li", any, {
25
13
  active?: boolean;
@@ -22,35 +22,42 @@ var __importStar = (this && this.__importStar) || function (mod) {
22
22
  __setModuleDefault(result, mod);
23
23
  return result;
24
24
  };
25
- var __importDefault = (this && this.__importDefault) || function (mod) {
26
- return (mod && mod.__esModule) ? mod : { "default": mod };
27
- };
28
25
  Object.defineProperty(exports, "__esModule", { value: true });
29
26
  exports.TabButtonLink = exports.TabItem = exports.TabListContainer = void 0;
30
27
  exports.TabList = TabList;
31
- const react_1 = __importDefault(require("react"));
28
+ const react_1 = __importStar(require("react"));
32
29
  const styled_components_1 = __importStar(require("styled-components"));
33
30
  const Tab_1 = require("../../../markdoc/components/Tabs/Tab");
34
31
  const Dropdown_1 = require("../../../components/Dropdown/Dropdown");
35
32
  const DropdownMenu_1 = require("../../../components/Dropdown/DropdownMenu");
36
33
  const DropdownMenuItem_1 = require("../../../components/Dropdown/DropdownMenuItem");
37
34
  const Button_1 = require("../../../components/Button/Button");
38
- function TabList({ childrenArray, size, overflowTabs, visibleTabs, setTabRef, onTabClick, handleKeyboard, getTabId, activeTab, isAnimating, highlightStyle, allTabsHidden, tabsContainerRef, }) {
39
- return (react_1.default.createElement(exports.TabListContainer, { role: "tablist", ref: tabsContainerRef, "data-animating": isAnimating },
40
- react_1.default.createElement(HighlightBar, { size: size, style: { left: highlightStyle.left, width: highlightStyle.width } },
35
+ const hooks_1 = require("../../../core/hooks");
36
+ const utils_1 = require("../../../core/utils");
37
+ function TabList({ childrenArray, size, activeTab, onTabChange, }) {
38
+ const tabsContainerRef = (0, react_1.useRef)(null);
39
+ const { allTabsHidden, overflowTabs, visibleTabs, handleKeyboard, onTabClick, setTabRef } = (0, hooks_1.useTabs)({
40
+ activeTab,
41
+ onTabChange,
42
+ containerRef: tabsContainerRef,
43
+ totalTabs: childrenArray.length,
44
+ });
45
+ const { highlightStyle } = useHighlightBarAnimation({
46
+ activeTab,
47
+ childrenArray,
48
+ overflowTabs,
49
+ tabsContainerRef,
50
+ visibleTabs,
51
+ });
52
+ return (react_1.default.createElement(exports.TabListContainer, { role: "tablist", ref: tabsContainerRef },
53
+ react_1.default.createElement(HighlightBar, { size: size, style: highlightStyle },
41
54
  react_1.default.createElement("div", null)),
42
55
  childrenArray.map((child, index) => {
43
56
  if (!visibleTabs.includes(index))
44
57
  return null;
45
58
  const { label, icon } = child.props;
46
- const tabId = getTabId(label, index);
47
- return (react_1.default.createElement(Tab_1.Tab, { key: `key-${tabId}`, tabId: tabId, label: label, icon: icon, size: size, disabled: child.props.disable, setRef: (el) => {
48
- setTabRef(el, index);
49
- if (el) {
50
- el.setAttribute('data-label', label);
51
- el.setAttribute('data-animating', isAnimating.toString());
52
- }
53
- }, onKeyDown: (event) => handleKeyboard(event, index), onClick: () => {
59
+ const tabId = (0, utils_1.getTabId)(label, index);
60
+ return (react_1.default.createElement(Tab_1.Tab, { key: `key-${tabId}`, tabId: tabId, label: label, icon: icon, size: size, disabled: child.props.disable, setRef: (el) => setTabRef(el, index), onKeyDown: (event) => handleKeyboard(event, index), onClick: () => {
54
61
  var _a, _b;
55
62
  (_b = (_a = child.props).onClick) === null || _b === void 0 ? void 0 : _b.call(_a);
56
63
  onTabClick(label);
@@ -61,12 +68,54 @@ function TabList({ childrenArray, size, overflowTabs, visibleTabs, setTabRef, on
61
68
  : undefined }, allTabsHidden ? activeTab : 'More'), alignment: "start", withArrow: true },
62
69
  react_1.default.createElement(DropdownMenu_1.DropdownMenu, null, overflowTabs.map((index) => {
63
70
  const { label } = childrenArray[index].props;
64
- const tabId = getTabId(label, index);
71
+ const tabId = (0, utils_1.getTabId)(label, index);
65
72
  return (react_1.default.createElement(DropdownMenuItem_1.DropdownMenuItem, { key: `more-${tabId}`, active: activeTab === label, onAction: () => {
73
+ var _a, _b;
74
+ (_b = (_a = childrenArray[index].props).onClick) === null || _b === void 0 ? void 0 : _b.call(_a);
66
75
  onTabClick(index);
67
76
  }, disabled: childrenArray[index].props.disable }, label));
68
77
  })))))));
69
78
  }
79
+ const useHighlightBarAnimation = (props) => {
80
+ const { childrenArray, activeTab, tabsContainerRef, visibleTabs, overflowTabs } = props;
81
+ const [highlightStyle, setHighlightStyle] = react_1.default.useState({
82
+ left: 0,
83
+ width: 0,
84
+ });
85
+ (0, react_1.useEffect)(() => {
86
+ const activeIndex = childrenArray.findIndex((child) => child.props.label === activeTab);
87
+ const container = tabsContainerRef.current;
88
+ if (!container || activeIndex === -1) {
89
+ setHighlightStyle({ left: 0, width: 0 });
90
+ return;
91
+ }
92
+ const activeTabElement = container.querySelector(`[data-label="${activeTab}"]`);
93
+ if (!activeTabElement)
94
+ return;
95
+ container.querySelectorAll('[data-label]').forEach((el) => {
96
+ el.classList.remove('active');
97
+ });
98
+ const { offsetLeft, offsetWidth } = activeTabElement;
99
+ if (visibleTabs.includes(activeIndex)) {
100
+ activeTabElement.classList.add('active');
101
+ setHighlightStyle({ left: offsetLeft, width: offsetWidth });
102
+ return;
103
+ }
104
+ if (overflowTabs.includes(activeIndex)) {
105
+ const moreButton = container.querySelector('button');
106
+ if (!moreButton)
107
+ return;
108
+ const moreButtonRect = moreButton.getBoundingClientRect();
109
+ const containerRect = container.getBoundingClientRect();
110
+ setHighlightStyle({
111
+ left: moreButtonRect.left - containerRect.left,
112
+ width: moreButtonRect.width,
113
+ });
114
+ return;
115
+ }
116
+ }, [activeTab, childrenArray, visibleTabs, overflowTabs, tabsContainerRef]);
117
+ return { highlightStyle };
118
+ };
70
119
  exports.TabListContainer = styled_components_1.default.ul `
71
120
  position: relative;
72
121
  display: flex;
@@ -12,12 +12,12 @@ export type TabItemProps = {
12
12
  icon?: React.ReactNode | string;
13
13
  };
14
14
  type TabsProps = {
15
+ id?: string;
15
16
  children: React.ReactElement<TabItemProps>[];
16
17
  className?: string;
17
18
  size: TabsSize;
18
- forceReady?: boolean;
19
19
  initialTab?: string;
20
20
  };
21
- export declare function Tabs({ children, className, size, forceReady, initialTab: propInitialTab, }: TabsProps): JSX.Element;
21
+ export declare function Tabs({ id, children, className, size, initialTab: propInitialTab, }: TabsProps): JSX.Element;
22
22
  export declare const TabContent: import("styled-components").StyledComponent<"div", any, {}, never>;
23
23
  export {};
@@ -22,101 +22,35 @@ var __importStar = (this && this.__importStar) || function (mod) {
22
22
  __setModuleDefault(result, mod);
23
23
  return result;
24
24
  };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
25
28
  Object.defineProperty(exports, "__esModule", { value: true });
26
29
  exports.TabContent = exports.TabsSize = void 0;
27
30
  exports.Tabs = Tabs;
28
31
  const react_1 = __importStar(require("react"));
29
- const styled_components_1 = __importStar(require("styled-components"));
32
+ const styled_components_1 = __importDefault(require("styled-components"));
30
33
  const hooks_1 = require("../../../core/hooks");
31
34
  const TabList_1 = require("../../../markdoc/components/Tabs/TabList");
35
+ const utils_1 = require("../../../core/utils");
32
36
  var TabsSize;
33
37
  (function (TabsSize) {
34
38
  TabsSize["SMALL"] = "small";
35
39
  TabsSize["MEDIUM"] = "medium";
36
40
  })(TabsSize || (exports.TabsSize = TabsSize = {}));
37
- function Tabs({ children, className, size, forceReady = false, initialTab: propInitialTab, }) {
41
+ function Tabs({ id, children, className, size, initialTab: propInitialTab, }) {
38
42
  var _a, _b;
39
43
  const [childrenArray, setChildrenArray] = (0, react_1.useState)(react_1.default.Children.toArray(children));
44
+ const initialTab = (_b = propInitialTab !== null && propInitialTab !== void 0 ? propInitialTab : (_a = childrenArray[0]) === null || _a === void 0 ? void 0 : _a.props.label) !== null && _b !== void 0 ? _b : '';
45
+ const { activeTab, setActiveTab } = (0, hooks_1.useActiveTab)({ tabsId: id, initialTab });
40
46
  (0, react_1.useEffect)(() => {
41
47
  setChildrenArray(react_1.default.Children.toArray(children));
42
48
  }, [children]);
43
- const tabsContainerRef = (0, react_1.useRef)(null);
44
- const [isAnimating, setIsAnimating] = (0, react_1.useState)(false);
45
- const defaultInitialTab = (_b = (_a = childrenArray[0]) === null || _a === void 0 ? void 0 : _a.props.label) !== null && _b !== void 0 ? _b : '';
46
- const initialTab = propInitialTab !== null && propInitialTab !== void 0 ? propInitialTab : defaultInitialTab;
47
- const { activeTab, setTabRef, onTabClick, handleKeyboard, getTabId, visibleTabs, overflowTabs, ready, allTabsHidden, } = (0, hooks_1.useTabs)({
48
- initialTab,
49
- totalTabs: childrenArray.length,
50
- containerRef: tabsContainerRef,
51
- });
52
- const [prevTab, setPrevTab] = react_1.default.useState(initialTab);
53
- const [highlightStyle, setHighlightStyle] = react_1.default.useState({
54
- left: 0,
55
- width: 0,
56
- });
57
- (0, react_1.useEffect)(() => {
58
- setPrevTab(activeTab);
59
- setIsAnimating(true);
60
- const activeIndex = childrenArray.findIndex((child) => child.props.label === activeTab);
61
- const container = tabsContainerRef.current;
62
- if (container) {
63
- container.querySelectorAll('[data-label]').forEach((el) => {
64
- el.classList.remove('active');
65
- });
66
- container.getBoundingClientRect();
67
- requestAnimationFrame(() => {
68
- if (activeIndex >= 0) {
69
- let activeTabElement = null;
70
- let startPosition = { left: 0, width: 0 };
71
- if (visibleTabs.includes(activeIndex)) {
72
- activeTabElement = container.querySelector(`[data-label="${activeTab}"]`);
73
- }
74
- else if (overflowTabs.includes(activeIndex)) {
75
- const moreButton = container.querySelector('button');
76
- if (moreButton) {
77
- const moreButtonRect = moreButton.getBoundingClientRect();
78
- const containerRect = container.getBoundingClientRect();
79
- startPosition = {
80
- left: moreButtonRect.left - containerRect.left,
81
- width: moreButtonRect.width,
82
- };
83
- }
84
- }
85
- if (activeTabElement) {
86
- const { offsetLeft, offsetWidth } = activeTabElement;
87
- if (overflowTabs.includes(activeIndex)) {
88
- setHighlightStyle(startPosition);
89
- requestAnimationFrame(() => {
90
- setHighlightStyle({ left: offsetLeft, width: offsetWidth });
91
- });
92
- }
93
- else {
94
- setHighlightStyle({ left: offsetLeft, width: offsetWidth });
95
- }
96
- if (visibleTabs.includes(activeIndex)) {
97
- activeTabElement === null || activeTabElement === void 0 ? void 0 : activeTabElement.classList.add('active');
98
- }
99
- return () => {
100
- container.querySelectorAll('[data-label]').forEach((el) => {
101
- el.classList.remove('active');
102
- });
103
- };
104
- }
105
- }
106
- setHighlightStyle({ left: 0, width: 0 });
107
- setIsAnimating(false);
108
- });
109
- }
110
- else {
111
- setHighlightStyle({ left: 0, width: 0 });
112
- setIsAnimating(false);
113
- }
114
- }, [activeTab, prevTab, childrenArray, visibleTabs, overflowTabs]);
115
- return (react_1.default.createElement(TabsContainer, { "data-component-name": "Markdoc/Tabs/Tabs", className: className, isReady: ready || forceReady },
116
- react_1.default.createElement(TabList_1.TabList, { size: size, childrenArray: childrenArray, overflowTabs: overflowTabs, setTabRef: setTabRef, onTabClick: onTabClick, handleKeyboard: handleKeyboard, getTabId: getTabId, activeTab: activeTab, isAnimating: isAnimating, highlightStyle: highlightStyle, visibleTabs: visibleTabs, allTabsHidden: allTabsHidden, tabsContainerRef: tabsContainerRef }),
49
+ return (react_1.default.createElement(TabsContainer, { "data-component-name": "Markdoc/Tabs/Tabs", className: className, key: id },
50
+ react_1.default.createElement(TabList_1.TabList, { size: size, childrenArray: childrenArray, activeTab: activeTab, onTabChange: setActiveTab }),
117
51
  childrenArray.map((child, index) => {
118
52
  const { label } = child.props;
119
- const tabId = getTabId(label, index);
53
+ const tabId = (0, utils_1.getTabId)(label, index);
120
54
  return label === activeTab ? (react_1.default.createElement(exports.TabContent, { key: `content-${tabId}`, id: `panel-${tabId}`, "aria-labelledby": `tab-${tabId}`, tabIndex: 0, role: "tabpanel" }, child.props.children)) : null;
121
55
  })));
122
56
  }
@@ -132,16 +66,6 @@ const TabsContainer = styled_components_1.default.div `
132
66
  padding: var(--md-tabs-container-padding);
133
67
  border: var(--md-tabs-container-border);
134
68
 
135
- ${({ isReady }) => !isReady
136
- ? (0, styled_components_1.css) `
137
- visibility: hidden;
138
- overflow: hidden;
139
- `
140
- : (0, styled_components_1.css) `
141
- visibility: visible;
142
- overflow: visible;
143
- `}
144
-
145
69
  ol[class^='Tabs__TabList'] {
146
70
  margin: 0;
147
71
  padding: 0;
@@ -22,6 +22,11 @@ exports.tabs = {
22
22
  return new markdoc_1.default.Tag('Tabs', attributes, tabsContent);
23
23
  },
24
24
  attributes: {
25
+ /*
26
+ A unique persistent identifier assigned to a component.
27
+ This value is used as a key for the query parameter that stores the active tab to enable deep linking.
28
+ */
29
+ id: { type: String },
25
30
  size: { type: String, matches: ['small', 'medium'], default: 'medium' },
26
31
  },
27
32
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redocly/theme",
3
- "version": "0.58.0-next.9",
3
+ "version": "0.59.0-next.0",
4
4
  "description": "Shared UI components lib",
5
5
  "keywords": [
6
6
  "theme",
@@ -32,7 +32,7 @@
32
32
  "react": "^19.1.0",
33
33
  "react-dom": "^19.1.0",
34
34
  "react-router-dom": "^6.21.1",
35
- "styled-components": "^4.1.1 || ^5.3.11",
35
+ "styled-components": "^4.1.1 || ^5.3.11 || ^6.0.0",
36
36
  "styled-system": "^5.1.5"
37
37
  },
38
38
  "devDependencies": {
@@ -87,8 +87,8 @@
87
87
  "openapi-sampler": "1.6.1",
88
88
  "react-calendar": "5.1.0",
89
89
  "react-date-picker": "11.0.0",
90
- "@redocly/config": "0.35.0",
91
- "@redocly/realm-asyncapi-sdk": "0.4.0-next.4"
90
+ "@redocly/config": "0.35.1",
91
+ "@redocly/realm-asyncapi-sdk": "0.5.0-next.0"
92
92
  },
93
93
  "scripts": {
94
94
  "watch": "tsc -p tsconfig.build.json && (concurrently \"tsc -w -p tsconfig.build.json\" \"tsc-alias -w -p tsconfig.build.json\")",
@@ -24,6 +24,7 @@ import { CatalogEntityRelationsGraph } from '@redocly/theme/components/Catalog/C
24
24
  export type CatalogEntityProps = {
25
25
  RedocSchema: React.ComponentType<any>;
26
26
  StoreProvider: React.ComponentType<any>;
27
+ GraphqlTypeRenderer?: React.ComponentType<{ sdl: string; typeName: string }>;
27
28
  };
28
29
 
29
30
  type CatalogEntityPageProps = {
@@ -50,6 +51,7 @@ const renderDataSchemaSection = (
50
51
  relatedEntity: BffCatalogRelatedEntity | null,
51
52
  RedocSchema: React.ComponentType<any>,
52
53
  StoreProvider: React.ComponentType<any>,
54
+ GraphqlTypeRenderer?: React.ComponentType<{ sdl: string; typeName: string }>,
53
55
  ): React.ReactElement | null => {
54
56
  if (entity.type !== 'data-schema') {
55
57
  return null;
@@ -61,11 +63,16 @@ const renderDataSchemaSection = (
61
63
  relatedEntity={relatedEntity}
62
64
  RedocSchema={RedocSchema}
63
65
  StoreProvider={StoreProvider}
66
+ GraphqlTypeRenderer={GraphqlTypeRenderer}
64
67
  />
65
68
  );
66
69
  };
67
70
 
68
- export function CatalogEntity({ RedocSchema, StoreProvider }: CatalogEntityProps) {
71
+ export function CatalogEntity({
72
+ RedocSchema,
73
+ StoreProvider,
74
+ GraphqlTypeRenderer,
75
+ }: CatalogEntityProps) {
69
76
  const { useTranslate, useCatalog, usePageProps } = useThemeHooks();
70
77
  const { translate } = useTranslate();
71
78
  const { entity, relations, catalogConfig, entitiesCatalogConfig, relatedEntity } =
@@ -98,7 +105,13 @@ export function CatalogEntity({ RedocSchema, StoreProvider }: CatalogEntityProps
98
105
  tag={entity.key}
99
106
  />
100
107
  <CatalogEntityProperties entity={entity} />
101
- {renderDataSchemaSection(entity, relatedEntity, RedocSchema, StoreProvider)}
108
+ {renderDataSchemaSection(
109
+ entity,
110
+ relatedEntity,
111
+ RedocSchema,
112
+ StoreProvider,
113
+ GraphqlTypeRenderer,
114
+ )}
102
115
  <CatalogTwoColumnsSection>
103
116
  {renderFirstColumnEntitySection(entity)}
104
117
  <CatalogEntityLinks entity={entity} />
@@ -16,7 +16,7 @@ export type CatalogEntityMetadataProps = {
16
16
 
17
17
  function renderMetadataValue(value: any): React.JSX.Element {
18
18
  if (isPlainObject(value)) {
19
- return <JsonViewerWrapper data={value} expandLevel={3} hideHeader={true} />;
19
+ return <JsonViewerWrapper data={value} expandLevel={3} controls={false} />;
20
20
  }
21
21
 
22
22
  if (Array.isArray(value)) {
@@ -25,7 +25,7 @@ function renderMetadataValue(value: any): React.JSX.Element {
25
25
  {value.map((item, index) => (
26
26
  <div key={index}>
27
27
  {isPlainObject(item) ? (
28
- <JsonViewerWrapper data={item} expandLevel={3} hideHeader={true} />
28
+ <JsonViewerWrapper data={item} expandLevel={3} controls={false} />
29
29
  ) : (
30
30
  <span>{String(item)}</span>
31
31
  )}
@@ -41,7 +41,7 @@ function renderMetadataValue(value: any): React.JSX.Element {
41
41
  export function CatalogEntityMetadata({ entity }: CatalogEntityMetadataProps) {
42
42
  const { useTranslate } = useThemeHooks();
43
43
  const { translate } = useTranslate();
44
- const { schema, ...metadata } = entity.metadata || {};
44
+ const { schema, sdl, ...metadata } = entity.metadata || {};
45
45
  const metadataToShow = Object.entries(metadata).filter(
46
46
  ([key]) => !(entity.type === 'api-description' && key === 'descriptionFile'),
47
47
  );
@@ -46,7 +46,7 @@ export function CatalogEntityApiDescriptionRelations({
46
46
  }: CatalogEntityApiDescriptionRelationsProps): JSX.Element {
47
47
  return (
48
48
  <div data-component-name="Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityApiDescriptionRelations">
49
- <Tabs key={entity.id} forceReady={relations.length > 0} size={TabsSize.MEDIUM}>
49
+ <Tabs key={entity.id} size={TabsSize.MEDIUM}>
50
50
  <TabItem
51
51
  label="Operations"
52
52
  icon={<MoleculesIcon />}
@@ -74,7 +74,7 @@ export function CatalogEntityTeamRelations({
74
74
  }: CatalogEntityTeamRelationsProps): JSX.Element {
75
75
  return (
76
76
  <div data-component-name="Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityTeamRelations">
77
- <Tabs forceReady={relations.length > 0} size={TabsSize.MEDIUM}>
77
+ <Tabs size={TabsSize.MEDIUM}>
78
78
  <TabItem label="Members" icon={<PeopleIcon />} onClick={() => setFilter('type:user')}>
79
79
  <CatalogEntityRelationsTable
80
80
  key="members-table"
@@ -13,6 +13,7 @@ export type CatalogEntitySchemaProps = {
13
13
  relatedEntity: BffCatalogRelatedEntity | null;
14
14
  RedocSchema: React.ComponentType<any>;
15
15
  StoreProvider: React.ComponentType<any>;
16
+ GraphqlTypeRenderer?: React.ComponentType<{ sdl: string; typeName: string }>;
16
17
  };
17
18
 
18
19
  export function CatalogEntitySchema({
@@ -20,37 +21,45 @@ export function CatalogEntitySchema({
20
21
  relatedEntity,
21
22
  RedocSchema,
22
23
  StoreProvider,
24
+ GraphqlTypeRenderer,
23
25
  }: CatalogEntitySchemaProps) {
24
26
  const { useTranslate } = useThemeHooks();
25
27
  const { translate } = useTranslate();
26
28
  const { definition, parsedSchema, rawSchema } = useCatalogEntitySchema({ entity, relatedEntity });
29
+ const isGraphql = entity.metadata?.specType === 'graphql';
30
+ const graphqlSDL = entity?.metadata?.sdl;
27
31
 
28
32
  return (
29
33
  <MetadataWrapper data-component-name="Catalog/CatalogEntity/CatalogEntityMetadata">
30
34
  <HeaderWrapper>
31
35
  <Heading>{translate('catalog.entity.schema.title')}</Heading>
32
- <CopyButton
33
- data={rawSchema}
34
- buttonText="Copy Schema"
35
- type="compound"
36
- variant="secondary"
37
- iconPosition="right"
38
- size="medium"
39
- ></CopyButton>
36
+ {!isGraphql && (
37
+ <CopyButton
38
+ data={rawSchema}
39
+ buttonText="Copy Schema"
40
+ type="compound"
41
+ variant="secondary"
42
+ iconPosition="right"
43
+ size="medium"
44
+ ></CopyButton>
45
+ )}
40
46
  </HeaderWrapper>
41
47
  <SplitViewWrapper>
42
48
  <SchemaContentWrapper>
43
- <StoreProvider definition={definition}>
44
- <RedocSchema schema={parsedSchema} />
45
- </StoreProvider>
49
+ {isGraphql && graphqlSDL && GraphqlTypeRenderer ? (
50
+ <GraphqlTypeRenderer sdl={graphqlSDL} typeName={entity.title} />
51
+ ) : (
52
+ <StoreProvider definition={definition}>
53
+ <RedocSchema schema={parsedSchema} />
54
+ </StoreProvider>
55
+ )}
46
56
  </SchemaContentWrapper>
47
- <SchemaSampleWrapper>
48
- <JsonViewer
49
- data={Sampler.sample({ ...parsedSchema })}
50
- expandLevel={3}
51
- hideHeader={false}
52
- />
53
- </SchemaSampleWrapper>
57
+
58
+ {!isGraphql && (
59
+ <SchemaSampleWrapper>
60
+ <JsonViewer data={Sampler.sample({ ...parsedSchema })} expandLevel={3} />
61
+ </SchemaSampleWrapper>
62
+ )}
54
63
  </SplitViewWrapper>
55
64
  </MetadataWrapper>
56
65
  );
@@ -18,8 +18,8 @@ export type CodeBlockProps = {
18
18
  header?: CodeBlockControlsProps;
19
19
  dataTestId?: string;
20
20
  className?: string;
21
- tabs?: CodeBlockTabItems;
22
- dropdown?: CodeBlockDropdownItems;
21
+ tabs?: CodeBlockItems;
22
+ dropdown?: CodeBlockItems;
23
23
  withLineNumbers?: boolean;
24
24
  startLineNumber?: number;
25
25
  highlightedHtml?: string;
@@ -37,15 +37,9 @@ type UnstableExternalCodeSample = {
37
37
  get: (source: ExternalSource) => string;
38
38
  };
39
39
 
40
- export type CodeBlockTabItems = {
41
- items: { name: string; lang?: string }[];
42
- onChange: (name: string) => void;
43
- value: string;
44
- };
45
-
46
- export type CodeBlockDropdownItems = {
47
- items: { name: string; lang?: string }[];
48
- onChange: (name: string | string[]) => void;
40
+ export type CodeBlockItems = {
41
+ items: { name: string; lang?: string; id: string }[];
42
+ onChange: (id: string) => void;
49
43
  value: string;
50
44
  };
51
45