import { MinusIcon, PlusIcon } from "@phosphor-icons/react"; import * as React from "react"; import { Button, Field, InputGroup, InputGroupAddon, InputGroupInput, InputGroupText, } from "../../primitives"; import { selectedItemSurfaceClassName } from "../../primitives/selection-state"; import { cn } from "../../../lib/utils"; import { formatStopPosition, maxGradientStops, minGradientStops, normalizeStopOpacity, parseStopOpacity, parseStopPosition, type IndexedGradientStop, } from "./gradient-control-utils"; import { ColorValueControl } from "../color"; import { ControlFieldLabel } from "../../control-layout"; function GradientStopsHeader({ canAdd, onAdd, }: { canAdd: boolean; onAdd: () => void; }): React.JSX.Element { return (
Stops
); } function GradientStopColorControls({ onColorChange, onOpacityChange, stop, stopLabel, stopName, }: { onColorChange: (nextColor: string) => void; onOpacityChange: (nextOpacity: number) => void; stop: IndexedGradientStop; stopLabel: string; stopName: string; }): React.JSX.Element { return ( ); } function GradientStopOpacityInput({ onOpacityChange, stop, stopLabel, stopName, }: { onOpacityChange: (nextOpacity: number) => void; stop: IndexedGradientStop; stopLabel: string; stopName: string; }): React.JSX.Element { const committedOpacity = String(parseStopOpacity(stop.opacity)); const [draftOpacity, setDraftOpacity] = React.useState(committedOpacity); React.useEffect(() => { setDraftOpacity(committedOpacity); }, [committedOpacity]); function commitOpacity(nextDraft = draftOpacity): void { const trimmedDraft = nextDraft.trim(); if (trimmedDraft === "" || !Number.isFinite(Number.parseFloat(trimmedDraft))) { setDraftOpacity(committedOpacity); return; } const nextOpacity = normalizeStopOpacity(trimmedDraft); setDraftOpacity(String(nextOpacity)); if (nextOpacity !== parseStopOpacity(stop.opacity)) { onOpacityChange(nextOpacity); } } return ( commitOpacity()} onChange={(event) => setDraftOpacity(event.target.value)} onKeyDown={(event) => { if (event.key === "Enter") { event.preventDefault(); commitOpacity(event.currentTarget.value); event.currentTarget.blur(); return; } if (event.key === "Escape") { event.preventDefault(); setDraftOpacity(committedOpacity); event.currentTarget.blur(); } }} type="text" value={draftOpacity} /> % ); } function getStopPositionInputValue(position: string): string { return String(Math.round(parseStopPosition(position) * 100)); } function getNormalizedStopPositionFromInputValue(value: string): string | null { const parsedValue = Number.parseFloat(value); if (!Number.isFinite(parsedValue)) { return null; } return formatStopPosition(parsedValue / 100); } function GradientStopPositionInput({ onPositionChange, stop, stopLabel, stopName, }: { onPositionChange: (nextPosition: string) => void; stop: IndexedGradientStop; stopLabel: string; stopName: string; }): React.JSX.Element { const committedPosition = formatStopPosition(parseStopPosition(stop.position)); const committedInputValue = getStopPositionInputValue(stop.position); const [draftValue, setDraftValue] = React.useState(committedInputValue); const skipNextBlurCommitRef = React.useRef(false); React.useEffect(() => { setDraftValue(committedInputValue); }, [committedInputValue]); function commitPosition(nextValue = draftValue): void { const nextPosition = getNormalizedStopPositionFromInputValue(nextValue); if (nextPosition === null) { setDraftValue(committedInputValue); return; } setDraftValue(getStopPositionInputValue(nextPosition)); if (nextPosition !== committedPosition) { onPositionChange(nextPosition); } } return ( { if (skipNextBlurCommitRef.current) { skipNextBlurCommitRef.current = false; return; } commitPosition(); }} onChange={(event) => setDraftValue(event.target.value)} onKeyDown={(event) => { if (event.key === "Enter") { event.preventDefault(); commitPosition(event.currentTarget.value); skipNextBlurCommitRef.current = true; event.currentTarget.blur(); } if (event.key === "Escape") { event.preventDefault(); setDraftValue(committedInputValue); skipNextBlurCommitRef.current = true; event.currentTarget.blur(); } }} type="text" value={draftValue} /> % ); } function GradientStopRowSelectionSurface({ isSelected, }: { isSelected: boolean; }): React.JSX.Element { return (