'use client' import { useCallback, useEffect, useRef, type CompositionEvent, type ReactNode } from 'react' import { RatioSelector, StylePresetSelector, StyleSelector } from '@/components/selectors/RatioStyleSelectors' import { resolveTextareaTargetHeight } from '@/lib/ui/textarea-height' interface StoryInputComposerOption { value: string label: string recommended?: boolean } interface StoryInputComposerStylePresetOption { value: string label: string description: string } interface StoryInputComposerProps { value: string onValueChange: (value: string) => void placeholder: string minRows: number disabled?: boolean maxHeightViewportRatio?: number topRight?: ReactNode footer?: ReactNode secondaryActions?: ReactNode primaryAction: ReactNode videoRatio: string onVideoRatioChange: (value: string) => void ratioOptions: StoryInputComposerOption[] getRatioUsage?: (ratio: string) => string artStyle: string onArtStyleChange: (value: string) => void styleOptions: StoryInputComposerOption[] stylePresetValue: string onStylePresetChange: (value: string) => void stylePresetOptions: readonly StoryInputComposerStylePresetOption[] onCompositionStart?: () => void onCompositionEnd?: (event: CompositionEvent) => void textareaClassName?: string } export default function StoryInputComposer({ value, onValueChange, placeholder, minRows, disabled = false, maxHeightViewportRatio = 0.5, topRight, footer, secondaryActions, primaryAction, videoRatio, onVideoRatioChange, ratioOptions, getRatioUsage, artStyle, onArtStyleChange, styleOptions, stylePresetValue, onStylePresetChange, stylePresetOptions, onCompositionStart, onCompositionEnd, textareaClassName, }: StoryInputComposerProps) { const textareaRef = useRef(null) const textareaMinHeightRef = useRef(null) const autoResizeTextarea = useCallback(() => { const el = textareaRef.current if (!el || typeof window === 'undefined') return const maxHeight = window.innerHeight * maxHeightViewportRatio const oldHeight = el.offsetHeight const oldScrollTop = el.scrollTop if (textareaMinHeightRef.current === null && oldHeight > 0) { textareaMinHeightRef.current = oldHeight } const minHeight = textareaMinHeightRef.current ?? oldHeight el.style.transition = 'none' el.style.height = 'auto' const scrollHeight = el.scrollHeight const targetHeight = resolveTextareaTargetHeight({ minHeight, maxHeight, scrollHeight, }) el.style.height = `${oldHeight}px` el.scrollTop = oldScrollTop requestAnimationFrame(() => { el.scrollTop = oldScrollTop el.style.transition = 'height 200ms ease-out' el.style.height = `${targetHeight}px` el.style.overflowY = scrollHeight > maxHeight ? 'auto' : 'hidden' }) }, [maxHeightViewportRatio]) useEffect(() => { autoResizeTextarea() }, [value, autoResizeTextarea]) return (
{topRight && (
{topRight}
)}