// makeControls(): the typed-factory escape from React context invariance. // Returns the field primitives with their `uniform` prop narrowed to the keys of // the shader's uniform type whose value matches the widget (numeric keys for the // Slider, RGB-tuple keys for the ColorPicker). A shader fragment authors // `const { Slider, ColorPicker } = makeControls()`, after which a // typo'd or wrong-typed `uniform` is a compile error. The components still // self-wire through the nearest ControlForm at runtime. import type { ReactElement } from 'react'; import type { RGB } from '../../lib/primitives.types'; import { ColorPicker, type ColorPickerProps } from '../ui/color-picker'; import { Slider, type SliderProps } from '../ui/slider'; type NumericKeys = { [K in keyof U]: U[K] extends number ? K : never }[keyof U]; type RgbKeys = { [K in keyof U]: U[K] extends RGB ? K : never }[keyof U]; type TypedSlider = ( props: Omit & { readonly uniform: NumericKeys & string }, ) => ReactElement; type TypedColorPicker = ( props: Omit & { readonly uniform: RgbKeys & string }, ) => ReactElement; export function makeControls(): { readonly Slider: TypedSlider; readonly ColorPicker: TypedColorPicker; } { return { Slider: Slider as TypedSlider, ColorPicker: ColorPicker as TypedColorPicker, }; }