@redocly/theme 0.58.0-next.8 → 0.58.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.
- package/lib/components/Catalog/CatalogEntity/CatalogEntity.d.ts +5 -1
- package/lib/components/Catalog/CatalogEntity/CatalogEntity.js +4 -4
- package/lib/components/Catalog/CatalogEntity/CatalogEntityMetadata.js +3 -3
- package/lib/components/Catalog/CatalogEntity/CatalogEntitySchema.d.ts +5 -1
- package/lib/components/Catalog/CatalogEntity/CatalogEntitySchema.js +9 -7
- package/lib/components/CatalogClassic/CatalogClassic.js +9 -2
- package/lib/components/CodeBlock/CodeBlock.d.ts +5 -12
- package/lib/components/CodeBlock/CodeBlockControls.d.ts +3 -3
- package/lib/components/CodeBlock/CodeBlockControls.js +1 -1
- package/lib/components/CodeBlock/CodeBlockDropdown.d.ts +2 -2
- package/lib/components/CodeBlock/CodeBlockDropdown.js +4 -13
- package/lib/components/CodeBlock/CodeBlockTabs.d.ts +2 -2
- package/lib/components/CodeBlock/CodeBlockTabs.js +4 -3
- package/lib/components/JsonViewer/JsonViewer.d.ts +1 -1
- package/lib/components/JsonViewer/JsonViewer.js +9 -10
- package/lib/components/PageActions/PageActions.d.ts +4 -1
- package/lib/components/PageActions/PageActions.js +2 -2
- package/lib/core/constants/catalog.js +4 -0
- package/lib/core/contexts/CodeSnippetContext.d.ts +14 -6
- package/lib/core/contexts/CodeSnippetContext.js +57 -14
- package/lib/core/hooks/use-codeblock-tabs-controls.d.ts +2 -2
- package/lib/core/hooks/use-local-state.js +22 -18
- package/lib/core/hooks/use-page-actions.d.ts +2 -1
- package/lib/core/hooks/use-page-actions.js +48 -6
- package/lib/core/openapi/index.d.ts +1 -0
- package/lib/core/openapi/index.js +3 -1
- package/lib/core/types/l10n.d.ts +1 -1
- package/lib/core/types/open-api-server.d.ts +1 -0
- package/lib/icons/CursorIcon/CursorIcon.d.ts +9 -0
- package/lib/icons/CursorIcon/CursorIcon.js +22 -0
- package/lib/layouts/DocumentationLayout.js +1 -3
- package/lib/markdoc/components/CodeGroup/CodeGroup.js +49 -27
- package/lib/markdoc/components/Tabs/TabList.js +2 -0
- package/package.json +4 -4
- package/src/components/Catalog/CatalogEntity/CatalogEntity.tsx +15 -2
- package/src/components/Catalog/CatalogEntity/CatalogEntityMetadata.tsx +3 -3
- package/src/components/Catalog/CatalogEntity/CatalogEntitySchema.tsx +27 -18
- package/src/components/CatalogClassic/CatalogClassic.tsx +26 -10
- package/src/components/CodeBlock/CodeBlock.tsx +5 -11
- package/src/components/CodeBlock/CodeBlockControls.tsx +4 -7
- package/src/components/CodeBlock/CodeBlockDropdown.tsx +11 -20
- package/src/components/CodeBlock/CodeBlockTabs.tsx +8 -8
- package/src/components/JsonViewer/JsonViewer.tsx +16 -9
- package/src/components/PageActions/PageActions.tsx +6 -4
- package/src/core/constants/catalog.ts +4 -0
- package/src/core/contexts/CodeSnippetContext.tsx +54 -18
- package/src/core/hooks/use-codeblock-tabs-controls.ts +2 -2
- package/src/core/hooks/use-local-state.ts +28 -19
- package/src/core/hooks/use-page-actions.ts +63 -6
- package/src/core/openapi/index.ts +1 -0
- package/src/core/types/l10n.ts +13 -0
- package/src/core/types/open-api-server.ts +1 -0
- package/src/icons/CursorIcon/CursorIcon.tsx +35 -0
- package/src/layouts/DocumentationLayout.tsx +3 -10
- package/src/markdoc/components/CodeGroup/CodeGroup.tsx +81 -52
- package/src/markdoc/components/Tabs/TabList.tsx +1 -0
|
@@ -5,65 +5,55 @@ import {
|
|
|
5
5
|
type CodeBlockProps,
|
|
6
6
|
} from '@redocly/theme/components/CodeBlock/CodeBlock';
|
|
7
7
|
import { langToName } from '@redocly/theme/core/utils';
|
|
8
|
-
import {
|
|
8
|
+
import { useActiveCodeSnippetId } from '@redocly/theme/core/contexts';
|
|
9
|
+
|
|
10
|
+
type SnippetData = {
|
|
11
|
+
name: string;
|
|
12
|
+
languageName: string;
|
|
13
|
+
lang: string;
|
|
14
|
+
props: CodeBlockProps;
|
|
15
|
+
id: string;
|
|
16
|
+
};
|
|
9
17
|
|
|
10
18
|
export function CodeGroup(props: React.PropsWithChildren<{ mode?: 'tabs' | 'dropdown' }>) {
|
|
11
19
|
const mode = props.mode || 'tabs';
|
|
12
20
|
const isTabsMode = mode === 'tabs';
|
|
13
21
|
|
|
14
22
|
const rawSnippets = React.useMemo(
|
|
15
|
-
() =>
|
|
16
|
-
React.Children.toArray(props.children).map((child, idx) => {
|
|
17
|
-
const childProps = child as React.ReactElement<CodeBlockProps>;
|
|
18
|
-
return {
|
|
19
|
-
name: getTabName(childProps.props, idx),
|
|
20
|
-
languageName: langToName(childProps.props.lang || 'Default'),
|
|
21
|
-
lang: childProps.props.lang || '',
|
|
22
|
-
props: childProps.props,
|
|
23
|
-
};
|
|
24
|
-
}),
|
|
23
|
+
() => parseSnippetsFromChildren(props.children),
|
|
25
24
|
[props.children],
|
|
26
25
|
);
|
|
27
26
|
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const getItemName = (snippet: (typeof rawSnippets)[number]) =>
|
|
35
|
-
isTabsMode ? snippet?.name : snippet?.languageName || '';
|
|
36
|
-
|
|
37
|
-
const name = getItemName(snippet);
|
|
38
|
-
|
|
39
|
-
const items = rawSnippets.map((item) => ({
|
|
40
|
-
name: getItemName(item),
|
|
41
|
-
lang: item.lang,
|
|
42
|
-
}));
|
|
43
|
-
const itemsProps = {
|
|
44
|
-
items,
|
|
45
|
-
onChange: (name: string | string[]) => {
|
|
46
|
-
setActiveSnippetName(name as string);
|
|
47
|
-
},
|
|
48
|
-
value: activeSnippetName || getItemName(rawSnippets[0]),
|
|
49
|
-
};
|
|
50
|
-
const snippetProps = {
|
|
51
|
-
...snippet.props,
|
|
52
|
-
header: {
|
|
53
|
-
...snippet.props.header,
|
|
54
|
-
title: isTabsMode ? undefined : snippet.name,
|
|
55
|
-
},
|
|
56
|
-
...(isTabsMode ? { tabs: itemsProps } : { dropdown: itemsProps }),
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
return [name, snippetProps];
|
|
60
|
-
}),
|
|
61
|
-
),
|
|
62
|
-
[rawSnippets, activeSnippetName, isTabsMode, setActiveSnippetName],
|
|
63
|
-
);
|
|
27
|
+
const groupId = React.useMemo(() => generateGroupId(rawSnippets, mode), [rawSnippets, mode]);
|
|
28
|
+
|
|
29
|
+
const [activeSnippetId, setActiveSnippetId] = useActiveCodeSnippetId(groupId, rawSnippets);
|
|
30
|
+
|
|
31
|
+
const snippets = React.useMemo(() => {
|
|
32
|
+
const items = createItemsFromSnippets(rawSnippets, isTabsMode);
|
|
64
33
|
|
|
65
|
-
|
|
66
|
-
|
|
34
|
+
const itemsProps = {
|
|
35
|
+
items,
|
|
36
|
+
onChange: (id: string | string[]) => setActiveSnippetId(id as string),
|
|
37
|
+
value: activeSnippetId,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
return Object.fromEntries(
|
|
41
|
+
rawSnippets.map((snippet: SnippetData) => {
|
|
42
|
+
const snippetProps = {
|
|
43
|
+
...snippet.props,
|
|
44
|
+
header: {
|
|
45
|
+
...snippet.props.header,
|
|
46
|
+
title: isTabsMode ? undefined : snippet.name,
|
|
47
|
+
},
|
|
48
|
+
...(isTabsMode ? { tabs: itemsProps } : { dropdown: itemsProps }),
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
return [snippet.id, snippetProps];
|
|
52
|
+
}),
|
|
53
|
+
);
|
|
54
|
+
}, [rawSnippets, activeSnippetId, isTabsMode, setActiveSnippetId]);
|
|
55
|
+
|
|
56
|
+
const activeSnippet = snippets[activeSnippetId];
|
|
67
57
|
if (!activeSnippet) {
|
|
68
58
|
return null;
|
|
69
59
|
}
|
|
@@ -71,8 +61,47 @@ export function CodeGroup(props: React.PropsWithChildren<{ mode?: 'tabs' | 'drop
|
|
|
71
61
|
return <CodeBlockComponent {...activeSnippet} />;
|
|
72
62
|
}
|
|
73
63
|
|
|
64
|
+
function generateContentHash(content: string): number {
|
|
65
|
+
let hash = 0;
|
|
66
|
+
for (let i = 0; i < content.length; i++) {
|
|
67
|
+
hash = content.charCodeAt(i) + ((hash << 5) - hash);
|
|
68
|
+
}
|
|
69
|
+
return Math.abs(hash);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Generate unique group ID for CodeGroup instance
|
|
73
|
+
// Examples: "dropdown-8901234", "tabs-1234567"
|
|
74
|
+
function generateGroupId(rawSnippets: SnippetData[], mode: string): string {
|
|
75
|
+
const content = rawSnippets.map((s) => s.id + (s.props.source || '')).join('|') + `|${mode}`;
|
|
76
|
+
const hash = generateContentHash(content);
|
|
77
|
+
|
|
78
|
+
return `${mode}-${hash}`;
|
|
79
|
+
}
|
|
80
|
+
|
|
74
81
|
function getTabName(props: CodeBlockProps, idx: number): string {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
82
|
+
const fallbackName = `Tab ${idx + 1}`;
|
|
83
|
+
return String(props.header?.title || props.file || langToName(props.lang || '') || fallbackName);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function parseSnippetsFromChildren(children: React.ReactNode): SnippetData[] {
|
|
87
|
+
return React.Children.toArray(children).map((child, idx) => {
|
|
88
|
+
const childProps = child as React.ReactElement<CodeBlockProps>;
|
|
89
|
+
const props = childProps.props;
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
name: getTabName(props, idx),
|
|
93
|
+
languageName: String(langToName(props.lang || 'Default') || ''),
|
|
94
|
+
lang: props.lang || '',
|
|
95
|
+
props,
|
|
96
|
+
id: `${props.lang || ''}-${idx}`,
|
|
97
|
+
};
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function createItemsFromSnippets(snippets: SnippetData[], isTabsMode: boolean) {
|
|
102
|
+
return snippets.map((snippet) => ({
|
|
103
|
+
name: isTabsMode ? snippet.name : snippet.languageName || '',
|
|
104
|
+
lang: snippet.lang,
|
|
105
|
+
id: snippet.id,
|
|
106
|
+
}));
|
|
78
107
|
}
|