import React, { useMemo } from 'react' import { AnyRecord, IJSX, StyledComponentProps, useCompositionStyles } from '@codeleap/styles' import { MobileStyleRegistry } from '../../Registry' import { useStylesFor } from '../../hooks' import { CalendarInputProps } from './types' import { Calendar } from '../Calendar' import { TextInput } from '../TextInput' import { useInputBase } from '../InputBase' import { fields } from '@codeleap/form' import { dateUtils } from '@codeleap/utils' import { InputOverlay, inputOverlayManager } from '../InputOverlay' export * from './styles' export * from './types' /** * The calendar overlay is managed by `inputOverlayManager`, not local state — this means only * one CalendarInput can be open at a time application-wide when `autoClosePeersCalendars` is true. * Setting `overlay={false}` renders the calendar inline in the document flow instead. */ export const CalendarInput = (props: CalendarInputProps) => { const { style, value, onValueChange, disabled, gap, calendarPosition, rightIcon, leftIcon, autoClosePeersCalendars, field, format, overlay, calendarProps, ...textInputProps } = { ...CalendarInput.defaultProps, ...props } const styles = useStylesFor(CalendarInput.styleRegistryName, style) const compositionStyles = useCompositionStyles(['calendar', 'input'], styles) const { inputValue, onInputValueChange, } = useInputBase(field, fields.date as any, { value, onValueChange }) const { isOpen, toggle, id } = inputOverlayManager.use() /** * For range mode, an incomplete selection (only start date chosen) intentionally shows an empty * string so the TextInput doesn't display a partial "start - " label. */ const formattedValue = useMemo(() => { if (!inputValue) return '' if (Array.isArray(inputValue)) { const filled = inputValue.filter(Boolean) if (filled.length < inputValue.length) return '' return filled.map((v) => dateUtils.removeTimezoneAndFormat(v, format)).join(' - ') } return dateUtils.removeTimezoneAndFormat(inputValue, format) }, [inputValue, format]) return ( } > inputValue} onPress={disabled ? undefined : toggle} innerWrapperProps={{ rippleDisabled: true, }} focused={isOpen} leftIcon={!leftIcon ? null : { ...leftIcon, onPress: toggle, }} rightIcon={!rightIcon ? null : { ...rightIcon, onPress: toggle, }} /> ) } CalendarInput.styleRegistryName = 'CalendarInput' CalendarInput.elements = ['wrapper', 'calendar', 'input'] CalendarInput.rootElement = 'wrapper' CalendarInput.withVariantTypes = (styles: S) => { return CalendarInput as (props: StyledComponentProps) => IJSX } CalendarInput.defaultProps = { gap: 8, calendarPosition: 'left', autoClosePeersCalendars: false, format: 'DD/MM/YYYY', overlay: true, } as Partial MobileStyleRegistry.registerComponent(CalendarInput)