import React, { useEffect, useRef } from 'react'; import styled, { css } from 'styled-components'; import type { JSX } from 'react'; import type { CodeBlockItems } from '@redocly/theme/components/CodeBlock/CodeBlock'; import { useCodeBlockTabsControls } from '@redocly/theme/core/hooks'; import { Button } from '@redocly/theme/components/Button/Button'; import { ChevronLeftIcon } from '@redocly/theme/icons/ChevronLeftIcon/ChevronLeftIcon'; import { ChevronRightIcon } from '@redocly/theme/icons/ChevronRightIcon/ChevronRightIcon'; import { getFileIconByExt, getFileIconByLanguage } from '@redocly/theme/core/utils'; export type CodeBlockTabsProps = { tabs: CodeBlockItems; }; export function CodeBlockTabs({ tabs }: CodeBlockTabsProps): JSX.Element { const containerRef = useRef(null); const tabRefs = useRef([]); const { showControls, handlePrevTab, handleNextTab } = useCodeBlockTabsControls({ tabs, containerRef, tabRefs, }); useEffect(() => { const activeTab = tabRefs.current.find((tab) => tab?.dataset.id === tabs.value); if (activeTab) { activeTab.scrollIntoView({ block: 'nearest', inline: 'center' }); } }, [tabs.value]); return ( {tabs.items.map((item, i) => { const { name, lang, id } = item; const ext = name.match(/\.([^.]+)$/)?.[1]; const fileIcon = lang ? getFileIconByLanguage(lang) : ext ? getFileIconByExt(ext) : null; return ( { tabRefs.current[i] = el as HTMLButtonElement; }} data-name={name} active={id === tabs.value} key={id} onClick={() => tabs.onChange(id)} > {fileIcon} {name} ); })} {showControls && ( )} ); } const CodeBlockTabsWrapper = styled.div` display: flex; overflow: hidden; `; const Controls = styled.div` display: flex; gap: calc(var(--spacing-xxs) / 2); `; const ControlButton = styled(Button)` padding: 0 calc(var(--spacing-xxs) / 2); & + & { margin-left: 0; } `; const ShadowWrapper = styled.div` position: relative; overflow: hidden; &:after { position: absolute; content: ''; width: 16px; height: 100%; right: 0; top: 0; background: var(--bg-raised-gradient); } `; const Tabs = styled.div` display: flex; overflow-x: auto; padding-right: var(--spacing-base); &::-webkit-scrollbar { display: none; } `; const Tab = styled.button<{ active: boolean }>` --icon-size: 18px; display: inline-flex; align-items: center; padding: 0 var(--spacing-sm); background-color: transparent; height: 24px; border-radius: var(--border-radius); cursor: pointer; gap: var(--spacing-xs); color: var(--text-color-secondary); ${({ active }) => active ? css` color: var(--text-color-primary); background-color: var(--tab-bg-color-filled); ` : css` &:hover { color: var(--text-color-primary); } `} `;