Skip to content

Commit 69948b5

Browse files
authored
docs: sync selected code lang across all CodeTabs components and all opened docs pages (#5992)
1 parent 71b51ea commit 69948b5

File tree

1 file changed

+72
-7
lines changed

1 file changed

+72
-7
lines changed

docs/src/components/CodeTabs/CodeTabs.tsx

Lines changed: 72 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,30 @@
11
import * as React from 'react';
2-
import { useState, useEffect, type FC } from 'react';
2+
import { useState, useEffect, useMemo, type FC } from 'react';
33
import { langs } from './dictionary';
44

55
import classnames from 'classnames/bind';
66
import * as classes from './CodeTabs.module.css';
77
const cn = classnames.bind(classes);
88

9+
interface CustomEventMap {
10+
'codetabs.changed': CustomEvent<{ lang: string }>;
11+
}
12+
13+
declare global {
14+
interface Window {
15+
addEventListener<K extends keyof CustomEventMap>(
16+
type: K,
17+
listener: (this: Document, ev: CustomEventMap[K]) => void
18+
): void;
19+
removeEventListener<K extends keyof CustomEventMap>(
20+
type: K,
21+
listener: (this: Window, ev: CustomEventMap[K]) => any,
22+
options?: boolean | EventListenerOptions
23+
): void;
24+
dispatchEvent<K extends keyof CustomEventMap>(ev: CustomEventMap[K]): void;
25+
}
26+
}
27+
928
const STORAGE_KEY = 'cube-docs.default-code-lang';
1029

1130
export interface CodeTabsProps {
@@ -19,17 +38,52 @@ export interface CodeTabsProps {
1938

2039
export const CodeTabs: FC<CodeTabsProps> = ({ children }) => {
2140
const [selectedTab, setSelectedTab] = useState(0);
41+
const tabs = useMemo(
42+
() =>
43+
children.reduce<Record<string, number>>((dict, tab, i) => {
44+
const result = {
45+
...dict,
46+
};
47+
if (result[tab.props['data-language']] === undefined) {
48+
result[tab.props['data-language']] = i;
49+
}
50+
return result;
51+
}, {}),
52+
children
53+
);
2254

2355
useEffect(() => {
2456
const defaultLang = localStorage.getItem(STORAGE_KEY);
2557

2658
if (defaultLang) {
27-
children.some((tab, i) => {
28-
if (tab.props['data-language'] === defaultLang) {
29-
setSelectedTab(i);
30-
}
31-
});
59+
if (tabs[defaultLang] !== undefined) {
60+
setSelectedTab(tabs[defaultLang]);
61+
}
3262
}
63+
64+
const syncHanlder = (e: CustomEvent<{ lang: string }>) => {
65+
const lang = e.detail.lang;
66+
if (tabs[lang] !== undefined) {
67+
setSelectedTab(tabs[lang]);
68+
}
69+
};
70+
71+
const storageHandler = (e: StorageEvent) => {
72+
if (e.key === STORAGE_KEY) {
73+
const lang = e.newValue;
74+
if (lang && tabs[lang] !== undefined) {
75+
setSelectedTab(tabs[lang]);
76+
}
77+
}
78+
};
79+
80+
window.addEventListener('storage', storageHandler);
81+
window.addEventListener('codetabs.changed', syncHanlder);
82+
83+
return () => {
84+
window.removeEventListener('storage', storageHandler);
85+
window.removeEventListener('codetabs.changed', syncHanlder);
86+
};
3387
}, []);
3488

3589
return (
@@ -44,12 +98,23 @@ export const CodeTabs: FC<CodeTabsProps> = ({ children }) => {
4498
}
4599
return (
46100
<div
101+
key={i}
47102
className={cn('CodeBlocks__tab', {
48103
[classes.SelectedTab]: i === selectedTab,
49104
})}
50105
onClick={() => {
51-
if (lang === 'javascript' || lang === 'yaml') {
106+
if (
107+
i !== selectedTab &&
108+
(lang === 'javascript' || lang === 'yaml')
109+
) {
52110
localStorage.setItem(STORAGE_KEY, lang);
111+
window.dispatchEvent(
112+
new CustomEvent('codetabs.changed', {
113+
detail: {
114+
lang,
115+
},
116+
})
117+
);
53118
}
54119
setSelectedTab(i);
55120
}}

0 commit comments

Comments
 (0)