import React , { useMemo } from "react" ; import { Button , ButtonGroup , Tooltip } from "@geist-ui/react" ; import Cell from "@/components/cell" ; import ShowMore from "@/components/show-more" ; import { InsertBefore , InsertAfter , InsertBranch , CapturingGroup , NonCapturingGroup , NamedCapturingGroup , Lookahead , Lookbehind , } from "@/components/icons" ; import { AST } from "@/parser" ; import { dispatchInsert , dispatchGroupIt , dispatchLookAroundIt } from "@/atom" ; type Props = { ast : AST . Regex ; nodes : AST . Node [ ] ; } ; type InsertDirection = "prev" | "next" | "branch" ; type Option = { desc : string ; value : string ; Icon : ( ) => JSX . Element ; } ; const Insert = ( { ast , nodes } ) => { const insertOptions = useMemo ( ( ) => { const options = [ ] ; const { body } = ast ; if ( nodes . length === 0 ) { return [ ] ; } const bodyHead = body [ 0 ] ; const head = nodes [ 0 ] ; const bodyTail = body [ body . length - 1 ] ; const tail = nodes [ nodes . length - 1 ] ; if ( bodyHead . id !== head . id && ! ( head . type === "boundaryAssertion" && head . kind === "beginning" ) ) { options . push ( { value : "prev" , desc : "Insert before" , Icon : InsertBefore , } ) ; } if ( bodyHead . id !== head . id && bodyTail . id !== tail . id && tail . type !== "boundaryAssertion" ) { options . push ( { value : "branch" , desc : "Insert as a branch" , Icon : InsertBranch , } ) ; } if ( bodyTail . id !== tail . id && ! ( tail . type === "boundaryAssertion" && tail . kind === "end" ) ) { options . push ( { value : "next" , desc : "Insert after" , Icon : InsertAfter , } ) ; } return options ; } , [ ast , nodes ] ) ; const groupOptions = useMemo ( ( ) => { if ( nodes . length === 1 && nodes [ 0 ] . type === "group" ) { return [ ] ; } return [ { desc : "Capturing group" , value : "capturing" , Icon : CapturingGroup } , { desc : "Non-capturing group" , value : "nonCapturing" , Icon : NonCapturingGroup , } , { desc : "Named capturing group" , value : "namedCapturing" , Icon : NamedCapturingGroup , } , ] ; } , [ nodes ] ) ; const lookAroundOptions = useMemo ( ( ) => { if ( nodes . length === 1 && nodes [ 0 ] . type === "lookAroundAssertion" ) { return [ ] ; } return [ { desc : "Lookahead assertion" , value : "lookahead" , Icon : Lookahead } , { desc : "Lookbehind assertion" , value : "lookbehind" , Icon : Lookbehind } , ] ; } , [ nodes ] ) ; const handleInsert = ( direction ) => dispatchInsert ( direction ) ; const handleWrapGroup = ( kind ) => { let payload ; switch ( kind ) { case "capturing" : payload = { kind , name : "" , index : 0 } ; break ; case "nonCapturing" : payload = { kind } ; break ; case "namedCapturing" : payload = { kind , name : "name" , index : 0 } ; break ; default : return ; } dispatchGroupIt ( payload ) ; } ; const handleWrapLookAroundAssertion = ( kind ) => dispatchLookAroundIt ( kind as "lookahead" | "lookbehind" ) ; return ( < div id = "test" > { insertOptions . length > 0 && ( < Cell label = "Insert around" > < ButtonGroup > { insertOptions . map ( ( { value , desc , Icon } ) => ( < Button onClick = { ( ) => handleInsert ( value as InsertDirection ) } key = { value } > < Tooltip text = { desc } placement = "topEnd" > < Icon /> < /Tooltip> < /Button>))} < /ButtonGroup> < /Cell>)} { groupOptions . length > 0 && ( < Cell label = "Group selection" question = "group" > < ButtonGroup > { groupOptions . map ( ( { value , desc , Icon } ) => ( < Button onClick = { ( ) => handleWrapGroup ( value ) } key = { value } > < Tooltip text = { desc } placement = "topEnd" > < Icon /> < /Tooltip> < /Button>))} < /ButtonGroup> < /Cell>)} { lookAroundOptions . length > 0 && ( < ShowMore id = "lookAround" > < Cell label = "LookAround selection" question = "lookAround" > < ButtonGroup > { lookAroundOptions . map ( ( { value , desc , Icon } ) => ( < Button onClick = { ( ) => handleWrapLookAroundAssertion ( value ) } key = { value } > < Tooltip text = { desc } placement = "topEnd" > < Icon /> < /Tooltip> < /Button>))} < /ButtonGroup> < /Cell> < /ShowMore>)} < /div>); } ; export default Insert ;