11import * as React from 'react' ;
2- import { useState , useEffect , type FC } from 'react' ;
2+ import { useState , useEffect , useMemo , type FC } from 'react' ;
33import { langs } from './dictionary' ;
44
55import classnames from 'classnames/bind' ;
66import * as classes from './CodeTabs.module.css' ;
77const 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+
928const STORAGE_KEY = 'cube-docs.default-code-lang' ;
1029
1130export interface CodeTabsProps {
@@ -19,17 +38,52 @@ export interface CodeTabsProps {
1938
2039export 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