// MaskControlPanel: the segmentation-edge panel, themed and controlled. // Either slider emits the full MaskInput (the mask verb is absolute). Not a // layer form, so it has no ControlForm (and thus no copy button) and uses the // raw slider directly with the themed Label/Readout primitives. import RNSlider from '@react-native-community/slider'; import { StyleSheet, View } from 'react-native'; import type { MaskInput } from '../../kaleidoscope/types'; import { MASK_TESTID_PREFIX } from '../../lib/test-id'; import { Label } from '../ui/label'; import { Readout } from '../ui/readout'; import { SLIDER_TINTS } from '../ui/slider-value'; import { ControlSection } from './control-section'; export type MaskControlPanelProps = { readonly hardness: number; readonly threshold: number; readonly onChange: (mask: MaskInput) => void; readonly disabled?: boolean; /** Root for this instance's test ids; override when a screen mounts two. */ readonly testIDPrefix?: string; }; function MaskRow({ label, value, disabled, onChange, testID, }: { readonly label: string; readonly value: number; readonly disabled: boolean; readonly onChange: (v: number) => void; readonly testID: string; }) { return ( {value.toFixed(2)} ); } export function MaskControlPanel({ hardness, threshold, onChange, disabled = false, testIDPrefix = MASK_TESTID_PREFIX, }: MaskControlPanelProps) { return ( onChange({ hardness: v, threshold })} testID={`${testIDPrefix}.hardness`} /> onChange({ hardness, threshold: v })} testID={`${testIDPrefix}.threshold`} /> ); } const styles = StyleSheet.create({ row: { gap: 2 }, line: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }, slider: { width: '100%', height: 32 }, });