diff --git a/docs/src/components/CodeTabs/CodeTabs.tsx b/docs/src/components/CodeTabs/CodeTabs.tsx index f1dc1b5b758b5..c16161dd357e3 100644 --- a/docs/src/components/CodeTabs/CodeTabs.tsx +++ b/docs/src/components/CodeTabs/CodeTabs.tsx @@ -1,11 +1,30 @@ import * as React from 'react'; -import { useState, useEffect, type FC } from 'react'; +import { useState, useEffect, useMemo, type FC } from 'react'; import { langs } from './dictionary'; import classnames from 'classnames/bind'; import * as classes from './CodeTabs.module.css'; const cn = classnames.bind(classes); +interface CustomEventMap { + 'codetabs.changed': CustomEvent<{ lang: string }>; +} + +declare global { + interface Window { + addEventListener( + type: K, + listener: (this: Document, ev: CustomEventMap[K]) => void + ): void; + removeEventListener( + type: K, + listener: (this: Window, ev: CustomEventMap[K]) => any, + options?: boolean | EventListenerOptions + ): void; + dispatchEvent(ev: CustomEventMap[K]): void; + } +} + const STORAGE_KEY = 'cube-docs.default-code-lang'; export interface CodeTabsProps { @@ -19,17 +38,52 @@ export interface CodeTabsProps { export const CodeTabs: FC = ({ children }) => { const [selectedTab, setSelectedTab] = useState(0); + const tabs = useMemo( + () => + children.reduce>((dict, tab, i) => { + const result = { + ...dict, + }; + if (result[tab.props['data-language']] === undefined) { + result[tab.props['data-language']] = i; + } + return result; + }, {}), + children + ); useEffect(() => { const defaultLang = localStorage.getItem(STORAGE_KEY); if (defaultLang) { - children.some((tab, i) => { - if (tab.props['data-language'] === defaultLang) { - setSelectedTab(i); - } - }); + if (tabs[defaultLang] !== undefined) { + setSelectedTab(tabs[defaultLang]); + } } + + const syncHanlder = (e: CustomEvent<{ lang: string }>) => { + const lang = e.detail.lang; + if (tabs[lang] !== undefined) { + setSelectedTab(tabs[lang]); + } + }; + + const storageHandler = (e: StorageEvent) => { + if (e.key === STORAGE_KEY) { + const lang = e.newValue; + if (lang && tabs[lang] !== undefined) { + setSelectedTab(tabs[lang]); + } + } + }; + + window.addEventListener('storage', storageHandler); + window.addEventListener('codetabs.changed', syncHanlder); + + return () => { + window.removeEventListener('storage', storageHandler); + window.removeEventListener('codetabs.changed', syncHanlder); + }; }, []); return ( @@ -44,12 +98,23 @@ export const CodeTabs: FC = ({ children }) => { } return (
{ - if (lang === 'javascript' || lang === 'yaml') { + if ( + i !== selectedTab && + (lang === 'javascript' || lang === 'yaml') + ) { localStorage.setItem(STORAGE_KEY, lang); + window.dispatchEvent( + new CustomEvent('codetabs.changed', { + detail: { + lang, + }, + }) + ); } setSelectedTab(i); }}