import React from 'react' import '@/components/ReactPlayground/CodeEditor/FileSelector/file-selector.scss' import { IFiles } from '@/components/ReactPlayground/shared' import { ENTRY_FILE_NAME, IMPORT_MAP_FILE_NAME } from '@/components/ReactPlayground/files' import Item from '@/components/ReactPlayground/CodeEditor/FileSelector/Item' import HideScrollbar, { HideScrollbarElement } from '@/components/common/HideScrollbar' import FlexBox from '@/components/common/FlexBox' interface FileSelectorProps { files?: IFiles onChange?: (fileName: string) => void onError?: (msg: string) => void readonly?: boolean notRemovableFiles?: string[] onRemoveFile?: (fileName: string) => void onAddFile?: (fileName: string) => void onUpdateFileName?: (newFileName: string, oldFileName: string) => void selectedFileName?: string } const FileSelector: React.FC = ({ files = {}, onChange, onError, readonly = false, notRemovableFiles = [], onRemoveFile, onAddFile, onUpdateFileName, selectedFileName = '' }) => { const hideScrollbarRef = useRef(null) const [tabs, setTabs] = useState([]) const [creating, setCreating] = useState(false) const [hasEditing, setHasEditing] = useState(false) const getMaxSequenceTabName = (filesName: string[]) => { const result = filesName.reduce((max, filesName) => { const match = filesName.match(/Component(\d+)\.tsx/) if (match) { const sequenceNumber = parseInt(match[1], 10) return Math.max(Number(max), sequenceNumber) } return max }, 0) return `Component${result + 1}.tsx` } const addTab = () => { setTabs([...tabs, getMaxSequenceTabName(tabs)]) setCreating(true) setTimeout(() => { hideScrollbarRef.current?.scrollRight(1000) }) } const handleOnCancel = () => { if (!creating) { return } tabs.pop() setTabs([...tabs]) setCreating(false) } const handleOnClickTab = (fileName: string) => { if (creating) { return } onChange?.(fileName) } const editImportMap = () => { onChange?.(IMPORT_MAP_FILE_NAME) } const handleOnSaveTab = (value: string, item: string) => { if (creating) { onAddFile?.(value) setCreating(false) } else { onUpdateFileName?.(value, item) } setTimeout(() => { handleOnClickTab(value) }) } const handleOnValidateTab = (newFileName: string, oldFileName: string) => { if (!/\.(jsx|tsx|js|ts|css|json|svg)$/.test(newFileName)) { onError?.( 'Playground only supports *.jsx, *.tsx, *.js, *.ts, *.css, *.json, *.svg files.' ) return false } if (tabs.includes(newFileName) && newFileName !== oldFileName) { onError?.(`File "${newFileName}" already exists.`) return false } return true } const handleOnRemove = (fileName: string) => { onRemoveFile?.(fileName) if (fileName === selectedFileName) { const index = Object.keys(files).indexOf(fileName) - 1 if (index >= 0) { handleOnClickTab(Object.keys(files)[index]) } else { handleOnClickTab(Object.keys(files)[1]) } } } useEffect(() => { Object.keys(files).length && setTabs( Object.keys(files).filter( (item) => ![IMPORT_MAP_FILE_NAME, ENTRY_FILE_NAME].includes(item) && !files[item].hidden ) ) }, [files]) return ( <>
{tabs.map((item, index) => ( handleOnSaveTab(name, item)} onCancel={handleOnCancel} onRemove={handleOnRemove} onClick={() => handleOnClickTab(item)} /> ))} {!readonly && ( )}
) } export default FileSelector