"use client"; import * as React from "react"; import { ChannelMixer, Color, ColorOpacity, Curves, FontPicker, Gradient, ImagePicker, Palette, type ChannelMixerValues, type ColorControlInput, type ColorControlInputPair, type ControlChangeMeta, type ImagePickerItem, } from "@repo/ui"; import type { ToolcraftControlSchema } from "../../../schema/types"; import { asColorOpacityValue, asColorValue, asCurveInterpolation, asFontPickerValue, asGradientValue, asString, defaultChannelMixerValues, isRecord, } from "../values/controls-panel-values"; export type CompoundControlCommit = ( nextValue: unknown, meta?: ControlChangeMeta, ) => void; export type CompoundControlCommitWithLabel = ( label: string, ) => CompoundControlCommit; export type CompoundControlKeyframeWrap = (args: { children: React.ReactNode; control: ToolcraftControlSchema; disableAction: boolean; labelActionName?: string; name: string; providerKey: string; value: unknown; }) => React.ReactNode; export type CompoundShouldShowColorFieldLabel = (args: { control: ToolcraftControlSchema; sectionHasOnlyColorFields: boolean; }) => boolean; export type CompoundControlRenderArgs = { commit: CompoundControlCommit; commitWithLabel: CompoundControlCommitWithLabel; control: ToolcraftControlSchema; id: string; name: string; sectionHasOnlyColorFields: boolean; shouldShowColorFieldLabel: CompoundShouldShowColorFieldLabel; usesHeaderKeyframeAction: boolean; value: unknown; withKeyframeLabelAction: CompoundControlKeyframeWrap; }; export type CompoundColorGroupRenderArgs = { entries: readonly [id: string, control: ToolcraftControlSchema][]; getControlName: ( id: string, label: ToolcraftControlSchema["label"], ) => string; getControlValue: (control: ToolcraftControlSchema) => unknown; headerKeyframeTarget: string | null; maybeUpsertControlKeyframe: ( control: ToolcraftControlSchema, label: string, value: unknown, ) => void; sectionHasOnlyColorFields: boolean; setControlValue: ( target: string, value: unknown, label?: string, meta?: ControlChangeMeta, ) => void; shouldShowColorFieldLabel: CompoundShouldShowColorFieldLabel; withKeyframeLabelAction: CompoundControlKeyframeWrap; }; export function renderCompoundColorGroup({ entries, getControlName, getControlValue, headerKeyframeTarget, maybeUpsertControlKeyframe, sectionHasOnlyColorFields, setControlValue, shouldShowColorFieldLabel, withKeyframeLabelAction, }: CompoundColorGroupRenderArgs): React.JSX.Element | null { const colorInputs = entries.map(([id, control]) => { const name = getControlName(id, control.label); const value = getControlValue(control); const colorValue = asColorValue(value); return { hex: colorValue.hex, name, onValueChange: (nextValue, meta) => { setControlValue(control.target, nextValue, name, meta); maybeUpsertControlKeyframe(control, name, nextValue); }, showLabel: shouldShowColorFieldLabel({ control, sectionHasOnlyColorFields, }), } satisfies ColorControlInput; }); const [firstInput, secondInput] = colorInputs; if (!firstInput) { return null; } if (!secondInput) { const firstEntry = entries[0]; const firstControl = firstEntry?.[1]; const firstValue = firstControl ? getControlValue(firstControl) : undefined; return firstControl ? ( withKeyframeLabelAction({ children: ( ), control: firstControl, disableAction: firstControl.target === headerKeyframeTarget, name: firstInput.name, providerKey: firstInput.name, value: firstValue, }) as React.JSX.Element ) : ( ); } return ( ); } export function renderCompoundControl({ commit, commitWithLabel, control, id, name, sectionHasOnlyColorFields, shouldShowColorFieldLabel, usesHeaderKeyframeAction, value, withKeyframeLabelAction, }: CompoundControlRenderArgs): React.ReactNode | null { switch (control.type) { case "channelMixer": { const channelMixerName = name; return withKeyframeLabelAction({ children: ( commitWithLabel(channelMixerName)(nextValue.values) } values={ isRecord(value) ? (value as ChannelMixerValues) : defaultChannelMixerValues } /> ), control, disableAction: false, labelActionName: channelMixerName, name, providerKey: id, value, }); } case "color": { const colorValue = asColorValue(value); return withKeyframeLabelAction({ children: ( ), control, disableAction: usesHeaderKeyframeAction, name, providerKey: id, value, }); } case "colorOpacity": { const colorOpacityValue = asColorOpacityValue(value); return withKeyframeLabelAction({ children: ( ), control, disableAction: usesHeaderKeyframeAction, name, providerKey: id, value: colorOpacityValue, }); } case "curves": { const curvesName = control.label === false ? "Curves" : name; return withKeyframeLabelAction({ children: ( ), control, disableAction: false, labelActionName: curvesName, name: curvesName, providerKey: id, value, }); } case "gradient": { const gradientValue = asGradientValue(value); return withKeyframeLabelAction({ children: ( ), control, disableAction: usesHeaderKeyframeAction, name, providerKey: id, value, }); } case "fontPicker": { const fontPickerValue = asFontPickerValue(value); return withKeyframeLabelAction({ children: ( ), control, disableAction: usesHeaderKeyframeAction, name, providerKey: id, value: fontPickerValue, }); } case "imagePicker": return ( ); case "palette": return withKeyframeLabelAction({ children: ( ["defaultValue"]) : undefined } key={id} onValueChange={commit} value={ isRecord(value) ? (value as React.ComponentProps["value"]) : undefined } /> ), control, disableAction: usesHeaderKeyframeAction, name, providerKey: id, value, }); default: return null; } }