import { useState , useRef , useEffect } from "react" ; import { validateRefName } from "../validators" ; import { useStringFormEntry , FormEntry , useDialogForm , } from "../components/Form" ; import { valuesAsArray } from "../helpers/immutable-map" ; import uuid from "uuid/v4" ; import * as T from "../types" ; import { layerTreeToArray } from "../layerUtils" ; export function useToggle ( defaultValue ) { const [ isActive , setValue ] = useState ( defaultValue ) ; return { isActive : isActive , activate : ( ) => setValue ( true ) , deactivate : ( ) => setValue ( false ) , } ; } export function useStateWithGetter < T > ( getter ) { const [ value , setValue ] = useState < T | undefined > ( undefined ) ; return [ value === undefined ? getter ( ) : value , ( newValue ) => setValue ( newValue ) , ] ; } function getComponentsThatUseRef ( refId , components , isLayerUsingRef ) { return valuesAsArray ( components ) . filter ( ( component ) => layerTreeToArray ( component . layout ) . some ( ( l ) => isLayerUsingRef ( l , refId ) ) ) ; } export function useWarningDialog ( title , description ) { const [ isOpen , setIsOpen ] = useState ( false ) ; const okButtonRef = useRef < HTMLButtonElement > ( null ) ; useEffect ( ( ) => { if ( isOpen ) { okButtonRef . current ! . focus ( ) ; } } , [ isOpen ] ) ; return { open : ( ) => setIsOpen ( true ) , dialogProps : { isOpen , title , description , form : null , onKeyDown : ( e ) => { if ( e . key === "Enter" ) { setIsOpen ( false ) ; } else if ( e . key === "Escape" ) { setIsOpen ( false ) ; } } , } , okProps : { onClick : ( ) => setIsOpen ( false ) , onKeyDown : ( e ) => { if ( e . key === "Enter" ) { e . stopPropagation ( ) ; } if ( e . key === "Tab" ) { okButtonRef . current ! . focus ( ) ; e . preventDefault ( ) ; } } , ref : okButtonRef , } , } ; } export function useDeleteRefDialog < TRef extends { name : string ; } > ( refTypeName , refs , selectedRefId , isLayerUsingRef , components ) { const ref = selectedRefId ? refs . get ( selectedRefId ) : null ; const description = ref ? `${ refTypeName } "${ ref . name }" is used by the following components ${ getComponentsThatUseRef ( selectedRefId ! , components , isLayerUsingRef ) . map ( ( c ) => `"${ c . name }"` ) . join ( ", " ) }.` : "" ; return useWarningDialog ( `Can't delete ${ refTypeName . toLowerCase ( ) }` , description ) ; } export function useRefManagement < TRef extends { name : string ; } > ( refType , prefix , refs , applyAction , formEntries , prepareEditForm , formToRef , isLayerUsingRef , components ) { const [ selectedRefId , selectRef ] = useState < string | null > ( null ) ; const [ isEditing , setIsEditing ] = useState ( false ) ; const nameEntry = useStringFormEntry ( "" , ( value ) => validateRefName ( value , selectedRefId , refs , prefix ) ) ; const dialog = useDialogForm ( [ nameEntry ] . concat ( formEntries ) , ( ) => { applyAction ( { type : "updateRef" , refType , refId : isEditing ? selectedRefId ! : uuid ( ) , newRef : formToRef ( nameEntry . value ) , } ) ; } ) ; const deleteRefDialog = useDeleteRefDialog ( prefix , refs , selectedRefId , isLayerUsingRef , components ) ; return { nameEntry , selectedRefId , selectRef , isEditing , dialog , deleteRefDialogProps : deleteRefDialog . dialogProps , closeDeleteRefDialogProps : deleteRefDialog . okProps , refActionsProps : { onAdd : ( ) => { setIsEditing ( false ) ; dialog . open ( ) ; } , canEdit : selectedRefId !== null , onEdit : ( ) => { if ( selectedRefId == null ) { throw new Error ( "selectedRefId can't be null on edit" ) ; } const selectedItem = refs . get ( selectedRefId ) ; if ( selectedItem == null ) { throw new Error ( "Ref not found" ) ; } setIsEditing ( true ) ; dialog . open ( ) ; nameEntry . setValue ( selectedItem . name ) ; prepareEditForm ( selectedItem ) ; } , canDelete : selectedRefId !== null && refs . size > 1 , onDelete : ( ) => { const componentsThatUseRef = getComponentsThatUseRef ( selectedRefId ! , components , isLayerUsingRef ) ; if ( componentsThatUseRef . length > 0 ) { deleteRefDialog . open ( ) ; } else { applyAction ( { type : "deleteRef" , refId : selectedRefId ! , refType } ) ; selectRef ( null ) ; } } , } , } ; }