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: 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: boolean) { toggleEditingMin(force); toggleEditingMax(force); } function cancelEditing() { if (isEditing) { toggleEditing(false); tooltipRef.current?.cancelEditing(); } } const rootRef = useRef(null); const tooltipRef = useRef(null); useClickOutside(rootRef, cancelEditing); useKeyboardEvent('Escape', () => { toggleHovered(false); cancelEditing(); }); return (
toggleHovered(true)} onPointerLeave={() => toggleHovered(false)} > { setSliderDomain(newValue); toggleEditing(false); }} onAfterChange={(hasMinChanged, hasMaxChanged) => { onCustomDomainChange([ hasMinChanged ? sliderDomain[0] : customDomain[0], hasMaxChanged ? sliderDomain[1] : customDomain[1], ]); }} /> toggleEditing(!isEditing)} /> { 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 && ( )}
); } export type { Props as DomainSliderProps }; export default DomainSlider;