import { reduce , difference , size , map } from 'lodash-es' ; import classNames from 'classnames' ; import { Tooltip , Menu , Input } from 'antd' ; import { useTranslation } from 'react-i18next' ; import React , { useState , useEffect , ReactNode , useRef } from 'react' ; import Icon , { createFromIconfontCN , SearchOutlined } from '@ant-design/icons' ; import type { TreeItem } from './PlayGround' ; import CollaspeAllSvg from '../images/collapse-all.svg' ; import styles from './PlayGrounds.module.less' ; const MenuIcon = createFromIconfontCN ( { scriptUrl : '//at.alicdn.com/t/font_470089_1lnym745udm.js' , } ) ; const { SubMenu } = Menu ; export interface PlayGroundItemProps { source : string ; examples : PlayGroundItemProps [ ] ; babeledSource : string ; absolutePath ? : string ; relativePath ? : string ; screenshot ? : string ; recommended ? : boolean ; filename : string ; title ? : string ; location ? : Location ; playground ? : { container ? : string ; playgroundDidMount ? : string ; playgroundWillUnmount ? : string ; dependencies ? : { [ key ] : string ; } ; devDependencies ? : { [ key ] : string ; } ; htmlCodeTemplate ? : string ; } ; } interface PlayGroundsProps { getPath : ( currentExample : PlayGroundItemProps ) => string ; currentExample : PlayGroundItemProps ; updateCurrentExample : ( val : PlayGroundItemProps ) => void ; treeData : TreeItem [ ] ; showExampleDemoTitle : boolean ; } const PlayGrounds = ( { getPath , currentExample , updateCurrentExample , treeData , showExampleDemoTitle , } ) => { const { t } = useTranslation ( ) ; const [ openKeys , setOpenKeys ] = useState < string [ ] > ( [ ] ) ; const menuRef = useRef < Menu | null > ( null ) ; const [ aRef , setARef ] = useState < HTMLAnchorElement > ( ) ; const [ searchValue , setSearchValue ] = useState < string > ( '' ) ; const findSearchTreeData = ( data ) : TreeItem [ ] => reduce ( data , ( value , item ) => { if ( item . title ?. match ( searchValue ) ) { return [ ... value , item ] ; } if ( item . children ) { const searchData = findSearchTreeData ( item . children ) ; return size ( searchData ) ? [ ... value , { ... item , children : searchData } ] : value ; } return value ; } , [ ] ) ; const getTreeData = ( ) => searchValue ? findSearchTreeData ( treeData ) : treeData ; const onOpenChange = ( keys ) => { let newKeys = keys ; const diffKey = difference ( keys , openKeys ) [ 0 ] ; if ( diffKey && /^secondaryKey-/ . test ( diffKey ) ) { newKeys = [ ... newKeys . filter ( ( key ) => ! /^secondaryKey-/ . test ( key ) ) , diffKey , ] ; } setOpenKeys ( newKeys ) ; } ; const getDefaultOpenKeys = ( data , key ) : string [ ] => reduce ( data , ( value , item ) => { if ( item . children ) { const keys = getDefaultOpenKeys ( item . children , key ) ; return keys . length ? [ ... value , item . value , ... keys ] : value ; } return key === item . value ? [ item . value ] : value ; } , [ ] ) ; useEffect ( ( ) => { const exampleKey = getPath ( currentExample ) ; setOpenKeys ( getDefaultOpenKeys ( getTreeData ( ) , exampleKey ) ) ; } , [ currentExample ] ) ; useEffect ( ( ) => { if ( aRef ) { aRef . scrollIntoView ( { block : 'center' , behavior : 'smooth' , } ) ; } } , [ aRef ] ) ; const getSearchValueTitle = ( title ) : ReactNode => searchValue && title . match ( searchValue ) ? ( < > < span > { title . replace ( new RegExp ( `${ searchValue }.*` ) , '' ) } < /span> < span className = { styles . searchValue } > { searchValue } < /span> < span > { title . replace ( new RegExp ( `.*?${ searchValue }` ) , '' ) } < /span> < />) : (title); const example = ( item ) => ( < Tooltip placement = "right" title = { getSearchValueTitle ( item . title || '' ) } key = { item . relativePath } > { } < a ref = { ( dom ) => { if ( dom && ! aRef && item . value === getPath ( currentExample ) ) { setARef ( dom ) ; } } } className = { classNames ( styles . card , { [ styles . current ] : currentExample && item . relativePath === currentExample . relativePath , } ) } > < div className = { classNames ( styles . screenshot ) } style = { { backgroundImage : `url(${ item . screenshot || 'https://gw.alipayobjects.com/os/s/prod/antv/assets/image/screenshot-placeholder-b8e70.png' })` , } } title = { item . title || item . relativePath } > { ( showExampleDemoTitle || ! item . screenshot ) && ( < div className = { classNames ( styles . exampleDemoTitle ) } > { item . title } < /div>)} < /div> < /a> < /Tooltip>); const getMenuSub = ( data ) => map ( data , ( item ) => item . children ? ( < SubMenu key = { item . value } title = { < div > { item . icon && ( < MenuIcon className = { styles . menuIcon } type = { `icon-${ item . icon }` } />)} < span className = { classNames ( styles . menuTitleContent , styles . subMenuTitleContent ) } > { item . title && getSearchValueTitle ( item . title ) } < /span> < /div>}> { getMenuSub ( item . children ) } < /SubMenu>) : (<Menu.Item key={item.value} style={{ height : 70 , padding : 0 , cursor : 'pointer' , } } onClick = { ( ) => { if ( item . value ?. match ( window . location . pathname ) ) { window . history . replaceState ( { } , '' , `${ item . value }` ) ; updateCurrentExample ( item as any ) ; } else { window . location . href = `${ window . location . origin }${ item . value }` ; } } } > < span className = { styles . menuTitleContent } > { example ( item ) } < /span> < /Menu.Item>)); const searchSider = ( ) => ( < div className = { styles . searchSider } > < Input size = "small" placeholder = { t ( '搜索' ) } prefix = { < SearchOutlined / > } value = { searchValue } onChange = { ( e ) => setSearchValue ( e . target . value ) } /> < Tooltip placement = "right" title = { t ( '收起所有' ) } > < Icon component = { CollaspeAllSvg } className = { styles . searchSiderIcon } onClick = { ( ) => setOpenKeys ( [ ] ) } /> < /Tooltip> < /div>); return ( < div className = { classNames ( styles . shadowWrapper ) } > { searchSider ( ) } { openKeys && ( < Menu ref = { menuRef } mode = "inline" style = { { width : '100%' } } className = { styles . siderbarMenu } openKeys = { openKeys } selectedKeys = { [ getPath ( currentExample ) ] } onOpenChange = { onOpenChange } > { getMenuSub ( getTreeData ( ) ) } < /Menu>)} < /div>); } ; export default PlayGrounds ;