@mantine/dates
Version:
Calendars, date and time pickers based on Mantine components
1 lines • 16.5 kB
Source Map (JSON)
{"version":3,"file":"DateInput.mjs","names":["classes"],"sources":["../../../src/components/DateInput/DateInput.tsx"],"sourcesContent":["import dayjs from 'dayjs';\nimport { useEffect, useRef, useState } from 'react';\nimport {\n __BaseInputProps,\n __InputStylesNames,\n Box,\n BoxProps,\n ClearSectionMode,\n ElementProps,\n factory,\n Factory,\n getFontSize,\n Input,\n InputVariant,\n MantineSize,\n Popover,\n PopoverProps,\n StylesApiProps,\n UnstyledButton,\n useInputProps,\n useStyles,\n} from '@mantine/core';\nimport { useClickOutside, useDidUpdate } from '@mantine/hooks';\nimport { useUncontrolledDates } from '../../hooks';\nimport { CalendarLevel, DateStringValue, DateValue } from '../../types';\nimport { Calendar, CalendarBaseProps, CalendarStylesNames, pickCalendarProps } from '../Calendar';\nimport { DatePickerPreset } from '../DatePicker';\nimport { useDatesContext } from '../DatesProvider';\nimport { DecadeLevelSettings } from '../DecadeLevel';\nimport { HiddenDatesInput } from '../HiddenDatesInput';\nimport { isSameMonth } from '../Month';\nimport { MonthLevelSettings } from '../MonthLevel';\nimport { YearLevelSettings } from '../YearLevel';\nimport { dateStringParser } from './date-string-parser/date-string-parser';\nimport { isDateValid } from './is-date-valid/is-date-valid';\nimport classes from './DateInput.module.css';\n\nexport type DateInputStylesNames =\n | __InputStylesNames\n | CalendarStylesNames\n | 'presetsRoot'\n | 'presetsList'\n | 'presetButton';\n\nexport interface DateInputProps\n extends\n BoxProps,\n Omit<__BaseInputProps, 'size'>,\n CalendarBaseProps,\n DecadeLevelSettings,\n YearLevelSettings,\n MonthLevelSettings,\n StylesApiProps<DateInputFactory>,\n ElementProps<'input', 'size' | 'value' | 'defaultValue' | 'onChange'> {\n /** A function to parse user input and convert it to date string value */\n dateParser?: (value: string) => DateStringValue | Date | null;\n\n /** Controlled component value */\n value?: DateValue | Date;\n\n /** Uncontrolled component default value */\n defaultValue?: DateValue | Date;\n\n /** Called when value changes */\n onChange?: (value: DateStringValue | null) => void;\n\n /** Props passed down to the `Popover` component */\n popoverProps?: Partial<Omit<PopoverProps, 'children'>>;\n\n /** If set, clear button is displayed in the `rightSection` when the component has value. Ignored if `rightSection` prop is set. @default false */\n clearable?: boolean;\n\n /** Determines how the clear button and rightSection are rendered @default 'both' */\n clearSectionMode?: ClearSectionMode;\n\n /** Props passed down to the clear button */\n clearButtonProps?: React.ComponentProps<'button'>;\n\n /** `dayjs` format to display input value, `\"MMMM D, YYYY\"` by default */\n valueFormat?: string;\n\n /** If set to `true`, the time part of the value is preserved. Set this to `true` when `valueFormat` includes time (e.g. `\"YYYY-MM-DD HH:mm\"`). @default false */\n withTime?: boolean;\n\n /** If set to `false`, invalid user input is preserved and is not corrected on blur */\n fixOnBlur?: boolean;\n\n /** If set, the value can be deselected by deleting everything from the input or by clicking the selected date in the dropdown. By default, `true` if `clearable` prop is set, `false` otherwise. */\n allowDeselect?: boolean;\n\n /** Max level that user can go up to @default 'decade' */\n maxLevel?: CalendarLevel;\n\n /** Initial displayed level (uncontrolled) */\n defaultLevel?: CalendarLevel;\n\n /** Current displayed level (controlled) */\n level?: CalendarLevel;\n\n /** Called when the level changes */\n onLevelChange?: (level: CalendarLevel) => void;\n\n /** Predefined values to pick from */\n presets?: DatePickerPreset<'default'>[];\n}\n\nexport type DateInputFactory = Factory<{\n props: DateInputProps;\n ref: HTMLInputElement;\n stylesNames: DateInputStylesNames;\n variant: InputVariant;\n}>;\n\nconst defaultProps = {\n valueFormat: 'MMMM D, YYYY',\n fixOnBlur: true,\n size: 'sm',\n} satisfies Partial<DateInputProps>;\n\nexport const DateInput = factory<DateInputFactory>((_props) => {\n const props = useInputProps('DateInput', defaultProps, _props);\n const {\n inputProps,\n wrapperProps,\n value,\n defaultValue,\n onChange,\n clearable,\n clearSectionMode,\n clearButtonProps,\n popoverProps,\n getDayProps,\n locale,\n valueFormat,\n withTime,\n dateParser,\n minDate,\n maxDate,\n fixOnBlur,\n onFocus,\n onBlur,\n onClick,\n onKeyDown,\n readOnly,\n name,\n form,\n rightSection,\n unstyled,\n classNames,\n styles,\n allowDeselect,\n date,\n defaultDate,\n onDateChange,\n getMonthControlProps,\n getYearControlProps,\n disabled,\n presets,\n ...rest\n } = props;\n\n const getStyles = useStyles<DateInputFactory>({\n name: 'DateInput',\n classes,\n props: props as unknown as DateInputProps,\n classNames,\n styles,\n unstyled,\n attributes: wrapperProps.attributes,\n });\n\n const _wrapperRef = useRef<HTMLDivElement>(null);\n const _dropdownRef = useRef<HTMLDivElement>(null);\n const [dropdownOpened, setDropdownOpened] = useState(false);\n const { calendarProps, others } = pickCalendarProps(rest);\n const ctx = useDatesContext();\n const defaultDateParser = (val: string): DateStringValue | null => {\n const parsedDate = dayjs(val, valueFormat, ctx.getLocale(locale)).toDate();\n return Number.isNaN(parsedDate.getTime())\n ? dateStringParser(val)\n : dayjs(parsedDate).format(withTime ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD');\n };\n\n const _dateParser = dateParser || defaultDateParser;\n const _allowDeselect = allowDeselect !== undefined ? allowDeselect : clearable;\n\n const formatValue = (val: DateStringValue) =>\n val ? dayjs(val).locale(ctx.getLocale(locale)).format(valueFormat) : '';\n\n const [_value, setValue, controlled] = useUncontrolledDates({\n type: 'default',\n value,\n defaultValue,\n onChange,\n withTime,\n });\n\n const [_date, setDate] = useUncontrolledDates({\n type: 'default',\n value: date,\n defaultValue: defaultValue || defaultDate,\n onChange: onDateChange as any,\n });\n\n useEffect(() => {\n if (controlled && value !== null) {\n setDate(value);\n }\n }, [controlled, value]);\n\n const [inputValue, setInputValue] = useState(formatValue(_value));\n\n useEffect(() => {\n setInputValue(formatValue(_value));\n }, [ctx.getLocale(locale)]);\n\n const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n const val = event.currentTarget.value;\n setInputValue(val);\n setDropdownOpened(true);\n\n if (val.trim() === '' && (allowDeselect || clearable)) {\n setValue(null);\n } else {\n const dateValue = _dateParser(val);\n if (dateValue && isDateValid({ date: dateValue, minDate, maxDate })) {\n setValue(dateValue);\n setDate(dateValue);\n }\n }\n };\n\n const handleInputBlur = (event: React.FocusEvent<HTMLInputElement>) => {\n onBlur?.(event);\n setDropdownOpened(false);\n fixOnBlur && setInputValue(formatValue(_value));\n };\n\n const handleInputFocus = (event: React.FocusEvent<HTMLInputElement>) => {\n onFocus?.(event);\n setDropdownOpened(true);\n };\n\n const handleInputClick = (event: React.MouseEvent<HTMLInputElement>) => {\n onClick?.(event);\n setDropdownOpened(true);\n };\n\n const handleInputKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n if (event.key === 'Escape') {\n setDropdownOpened(false);\n }\n onKeyDown?.(event);\n };\n\n const _getDayProps = (day: DateStringValue) => ({\n ...getDayProps?.(day),\n selected: dayjs(_value).isSame(day, 'day'),\n onClick: (event: any) => {\n getDayProps?.(day).onClick?.(event);\n\n const val = _allowDeselect ? (dayjs(_value).isSame(day, 'day') ? null : day) : day;\n setValue(val);\n !controlled && val && setInputValue(formatValue(val));\n setDropdownOpened(false);\n },\n });\n\n const handlePresetSelect = (val: DateStringValue | null) => {\n setValue(val);\n if (val) {\n setDate(val);\n }\n if (!controlled) {\n setInputValue(val ? formatValue(val) : '');\n }\n setDropdownOpened(false);\n };\n\n const presetButtons = presets?.map((preset, index) => (\n <UnstyledButton\n key={index}\n {...getStyles('presetButton')}\n onClick={() => handlePresetSelect(preset.value)}\n onMouseDown={(event) => event.preventDefault()}\n >\n {preset.label}\n </UnstyledButton>\n ));\n\n const clearButton = (\n <Input.ClearButton\n onClick={() => {\n setValue(null);\n !controlled && setInputValue('');\n setDropdownOpened(false);\n }}\n unstyled={unstyled}\n {...clearButtonProps}\n />\n );\n\n const _clearable = clearable && !!_value && !readOnly && !disabled;\n\n useDidUpdate(() => {\n _value !== undefined && !dropdownOpened && setInputValue(formatValue(_value));\n }, [_value]);\n\n useClickOutside(() => setDropdownOpened(false), undefined, [\n _wrapperRef.current,\n _dropdownRef.current,\n ]);\n\n const calendar = (\n <Calendar\n __staticSelector=\"DateInput\"\n {...calendarProps}\n classNames={classNames}\n styles={styles}\n unstyled={unstyled}\n __preventFocus\n minDate={minDate}\n maxDate={maxDate}\n locale={locale}\n getDayProps={_getDayProps}\n size={inputProps.size as MantineSize}\n date={_date}\n onDateChange={setDate}\n getMonthControlProps={(date) => ({\n selected: typeof _value === 'string' ? isSameMonth(date, _value) : false,\n ...getMonthControlProps?.(date),\n })}\n getYearControlProps={(date) => ({\n selected: typeof _value === 'string' ? dayjs(date).isSame(_value, 'year') : false,\n ...getYearControlProps?.(date),\n })}\n attributes={wrapperProps.attributes}\n />\n );\n\n return (\n <>\n <Input.Wrapper {...wrapperProps} __staticSelector=\"DateInput\" ref={_wrapperRef}>\n <Popover\n opened={dropdownOpened}\n trapFocus={false}\n position=\"bottom-start\"\n disabled={readOnly || disabled}\n withRoles={false}\n unstyled={unstyled}\n {...popoverProps}\n >\n <Popover.Target>\n <Input\n data-dates-input\n data-read-only={readOnly || undefined}\n autoComplete=\"off\"\n value={inputValue}\n onChange={handleInputChange}\n onBlur={handleInputBlur}\n onFocus={handleInputFocus}\n onClick={handleInputClick}\n onKeyDown={handleInputKeyDown}\n readOnly={readOnly}\n rightSection={rightSection}\n __clearSection={clearButton}\n __clearable={_clearable}\n __clearSectionMode={clearSectionMode}\n {...inputProps}\n {...others}\n disabled={disabled}\n __staticSelector=\"DateInput\"\n />\n </Popover.Target>\n <Popover.Dropdown\n onMouseDown={(event) => event.preventDefault()}\n data-dates-dropdown\n ref={_dropdownRef}\n >\n {presets ? (\n <Box\n {...getStyles('presetsRoot', {\n style: { '--preset-font-size': getFontSize(inputProps.size) },\n })}\n >\n <div {...getStyles('presetsList')}>{presetButtons}</div>\n {calendar}\n </Box>\n ) : (\n calendar\n )}\n </Popover.Dropdown>\n </Popover>\n </Input.Wrapper>\n <HiddenDatesInput name={name} form={form} value={_value} type=\"default\" withTime={withTime} />\n </>\n );\n});\n\nDateInput.classes = { ...Input.classes, ...Calendar.classes, ...classes };\nDateInput.displayName = '@mantine/dates/DateInput';\n\nexport namespace DateInput {\n export type Props = DateInputProps;\n export type StylesNames = DateInputStylesNames;\n export type Factory = DateInputFactory;\n}\n"],"mappings":"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"}