import React, { useState, useContext, useRef, useEffect } from 'react'; import Tabs, { TabPane } from 'rc-tabs'; // @ts-ignore import { history } from 'dumi'; import type { IPreviewerComponentProps} from 'dumi/theme'; import { context, useCodeSandbox, useRiddle, useMotions, useCopy, useLocaleProps, useDemoUrl, useTSPlaygroundUrl, Link, AnchorLink, usePrefersColor } from 'dumi/theme'; import type { ICodeBlockProps } from './SourceCode'; import SourceCode from './SourceCode'; import './Previewer.less'; export interface IPreviewerProps extends IPreviewerComponentProps { /** * enable transform to change CSS containing block for demo */ transform?: boolean; /** * modify background for demo area */ background?: string; /** * collapse padding of demo area */ compact?: boolean; /** * configurations for action button */ hideActions?: ('CSB' | 'EXTERNAL' | 'RIDDLE')[]; /** * show source code by default */ defaultShowCode?: boolean; /** * use iframe mode for this demo */ iframe?: true | number; /** * replace builtin demo url */ demoUrl?: string; } /** * get source code type for file * @param file file path * @param source file source object */ function getSourceType(file: string, source: IPreviewerComponentProps['sources']['_']) { // use file extension as source type first let type = file.match(/\.(\w+)$/)?.[1]; if (!type) { type = source.tsx ? 'tsx' : 'jsx'; } return type as ICodeBlockProps['lang']; } const Previewer: React.FC = oProps => { const demoRef = useRef(); const { locale } = useContext(context); const props = useLocaleProps(locale, oProps); const builtinDemoUrl = useDemoUrl(props.identifier); const demoUrl = props.demoUrl || builtinDemoUrl; const isActive = history?.location.hash === `#${props.identifier}`; const isSingleFile = Object.keys(props.sources).length === 1; const openCSB = useCodeSandbox(props.hideActions?.includes('CSB') ? null : props); const openRiddle = useRiddle(props.hideActions?.includes('RIDDLE') ? null : props); const [execMotions, isMotionRunning] = useMotions(props.motions || [], demoRef.current); const [copyCode, copyStatus] = useCopy(); const [currentFile, setCurrentFile] = useState('_'); const [sourceType, setSourceType] = useState( getSourceType(currentFile, props.sources[currentFile]), ); const [showSource, setShowSource] = useState(Boolean(props.defaultShowCode)); const [iframeKey, setIframeKey] = useState(Math.random()); const currentFileCode = props.sources[currentFile][sourceType] || props.sources[currentFile].content; const playgroundUrl = useTSPlaygroundUrl(locale, currentFileCode); const iframeRef = useRef(); const [color] = usePrefersColor(); // re-render iframe if prefers color changed useEffect(() => { setIframeKey(Math.random()); }, [color]); function handleFileChange(filename: string) { setCurrentFile(filename); setSourceType(getSourceType(filename, props.sources[filename])); } return (
{props.iframe &&
}
{props.iframe ? (