import type { Domain , ScaleType } from '@h5web/shared' ; import { useClickOutside , useKeyboardEvent , useToggle } from '@react-hookz/web' ; import { useEffect , useRef , useState } from 'react' ; import { FiEdit3 } from 'react-icons/fi' ; import { useSafeDomain , useVisDomain } from '../../../vis/heatmap/hooks' ; import type { CustomDomain , HistogramParams } from '../../../vis/models' ; import ToggleBtn from '../ToggleBtn' ; import styles from './DomainSlider.module.css' ; import type { DomainTooltipHandle } from './DomainTooltip' ; import DomainTooltip from './DomainTooltip' ; import Histogram from './Histogram' ; import ScaledSlider from './ScaledSlider' ; const TOOLTIP_ID = 'domain-tooltip' ; interface Props { dataDomain : Domain ; customDomain : CustomDomain ; scaleType : ScaleType ; onCustomDomainChange : ( domain : CustomDomain ) => void ; histogram ? : HistogramParams ; } function DomainSlider ( props ) { const { dataDomain , customDomain , scaleType } = props ; const { onCustomDomainChange , histogram } = props ; const visDomain = useVisDomain ( customDomain , dataDomain ) ; const [ safeDomain , errors ] = useSafeDomain ( visDomain , dataDomain , scaleType ) ; const [ sliderDomain , setSliderDomain ] = useState ( visDomain ) ; useEffect ( ( ) => { setSliderDomain ( visDomain ) ; } , [ visDomain , setSliderDomain ] ) ; const isAutoMin = customDomain [ 0 ] === null ; const isAutoMax = customDomain [ 1 ] === null ; const [ hovered , toggleHovered ] = useToggle ( false ) ; const [ isEditingMin , toggleEditingMin ] = useToggle ( false ) ; const [ isEditingMax , toggleEditingMax ] = useToggle ( false ) ; const isEditing = isEditingMin || isEditingMax ; function toggleEditing ( force ) { toggleEditingMin ( force ) ; toggleEditingMax ( force ) ; } function cancelEditing ( ) { if ( isEditing ) { toggleEditing ( false ) ; tooltipRef . current ?. cancelEditing ( ) ; } } const rootRef = useRef ( null ) ; const tooltipRef = useRef < DomainTooltipHandle > ( null ) ; useClickOutside ( rootRef , cancelEditing ) ; useKeyboardEvent ( 'Escape' , ( ) => { toggleHovered ( false ) ; cancelEditing ( ) ; } ) ; return ( < div ref = { rootRef } className = { styles . root } onPointerEnter = { ( ) => toggleHovered ( true ) } onPointerLeave = { ( ) => toggleHovered ( false ) } > < ScaledSlider value = { sliderDomain } safeVisDomain = { safeDomain } dataDomain = { dataDomain } scaleType = { scaleType } errors = { errors } isAutoMin = { isAutoMin } isAutoMax = { isAutoMax } onChange = { ( newValue ) => { setSliderDomain ( newValue ) ; toggleEditing ( false ) ; } } onAfterChange = { ( hasMinChanged , hasMaxChanged ) => { onCustomDomainChange ( [ hasMinChanged ? sliderDomain [ 0 ] : customDomain [ 0 ] , hasMaxChanged ? sliderDomain [ 1 ] : customDomain [ 1 ] , ] ) ; } } /> < ToggleBtn iconOnly small label = "Edit domain" aria - expanded = { hovered || isEditing } aria - controls = { TOOLTIP_ID } icon = { FiEdit3 } value = { isEditing } onToggle = { ( ) => toggleEditing ( ! isEditing ) } /> < DomainTooltip ref = { tooltipRef } id = { TOOLTIP_ID } open = { hovered || isEditing } sliderDomain = { sliderDomain } dataDomain = { dataDomain } errors = { errors } isAutoMin = { isAutoMin } isAutoMax = { isAutoMax } onAutoMinToggle = { ( ) => { const newMin = isAutoMin ? dataDomain [ 0 ] : null ; onCustomDomainChange ( [ newMin , customDomain [ 1 ] ] ) ; if ( ! isAutoMin ) { toggleEditingMin ( false ) ; } } } onAutoMaxToggle = { ( ) => { const newMax = isAutoMax ? dataDomain [ 1 ] : null ; onCustomDomainChange ( [ customDomain [ 0 ] , newMax ] ) ; if ( ! isAutoMax ) { toggleEditingMax ( false ) ; } } } isEditingMin = { isEditingMin } isEditingMax = { isEditingMax } onEditMin = { toggleEditingMin } onEditMax = { toggleEditingMax } onChangeMin = { ( val ) => onCustomDomainChange ( [ val , customDomain [ 1 ] ] ) } onChangeMax = { ( val ) => onCustomDomainChange ( [ customDomain [ 0 ] , val ] ) } onSwap = { ( ) => onCustomDomainChange ( [ customDomain [ 1 ] , customDomain [ 0 ] ] ) } > { histogram && ( < Histogram dataDomain = { dataDomain } sliderDomain = { sliderDomain } scaleType = { scaleType } { ... histogram } />)} < /DomainTooltip> < /div>); } export type { Props as DomainSliderProps } ; export default DomainSlider ;