UNPKG

@vimeo/iris

Version:
333 lines (330 loc) 17.3 kB
import { c as __assign, _ as __read } from '../../../../tslib.es6-7f0e734f.js'; import React__default, { useRef, useReducer, useState, useEffect, useMemo } from 'react'; import { Calendar } from '../Calendar/Calendar.esm.js'; import { i as initialState, r as reducer, a as init } from '../../../../Calendar.state-4c10d987.js'; import { getDateFormat, formatDate, getMonthFromDate } from './DateFormat.esm.js'; import { DateRangeContainer, Menu, CalendarsContainer, CalendarHeader, DateField, CalendarsBody, CalendarsFooter, ClearButton, ApplyButton } from './DateRange.style.esm.js'; import { translations } from './translations.esm.js'; import { Input } from '../../Input/Input.esm.js'; import { withIris } from '../../../../utils/HOCs/withIris.esm.js'; import { slate } from '../../../../color/colors.esm.js'; import 'styled-components'; import '../Calendar/useDaysFromViewport.esm.js'; import '../Calendar/CalendarDay.esm.js'; import 'polished'; import '../Calendar/CalendarDayLabel.esm.js'; import '../../../../typography/Paragraph/Paragraph.esm.js'; import '../../../../typography/Paragraph/Paragraph.style.esm.js'; import '../../../../typography/Text/Text.esm.js'; import '../../../../typography/Text/Text.style.esm.js'; import '../../../../typography/typography.esm.js'; import '../../../../tokens/core.esm.js'; import '../../../../tokens/color/index.esm.js'; import '../../../../tokens/color/background/background.esm.js'; import '../../../../tokens/util/readToken.esm.js'; import '../../../../tokens/util/clamp.esm.js'; import '../../../../tokens/color/format/format.esm.js'; import '../../../../tokens/color/format/primary.esm.js'; import '../../../../tokens/color/format/secondary.esm.js'; import '../../../../tokens/color/format/tertiary.esm.js'; import '../../../../tokens/color/rainbow/rainbow.esm.js'; import '../../../../tokens/color/rainbow/conic/index.esm.js'; import '../../../../tokens/color/rainbow/conic/sm.esm.js'; import '../../../../tokens/color/rainbow/conic/xl.esm.js'; import '../../../../tokens/color/rainbow/linear/index.esm.js'; import '../../../../tokens/color/rainbow/linear/sm.esm.js'; import '../../../../tokens/color/rainbow/linear/xl.esm.js'; import '../../../../tokens/color/livestream/livestream.esm.js'; import '../../../../tokens/color/status/status.esm.js'; import '../../../../tokens/color/status/caution.esm.js'; import '../../../../tokens/color/status/negative.esm.js'; import '../../../../tokens/color/status/positive.esm.js'; import '../../../../tokens/color/stroke/stroke.esm.js'; import '../../../../tokens/color/surface/surface.esm.js'; import '../../../../tokens/color/text/text.esm.js'; import '../../../../tokens/util/round.esm.js'; import '../../../../tokens/color/upsell/upsell.esm.js'; import '../../../../tokens/color/upsell/sm.esm.js'; import '../../../../tokens/color/upsell/xl.esm.js'; import '../../../../tokens/color/upsell/new.esm.js'; import '../../../../tokens/edge/edge.esm.js'; import '../../../../tokens/space/space.esm.js'; import '../../../../tokens/typography/index.esm.js'; import '../../../../tokens/typography/size/size.esm.js'; import '../../../../typography/Text/EditableText.esm.js'; import '../../../../utils/hooks/useLayoutStyles.esm.js'; import '../../../../utils/DOM/geometry.esm.js'; import '../../../../utils/css.esm.js'; import '../../../../typography/Header/Header.esm.js'; import '../../../../typography/Header/Header.style.esm.js'; import '../../../../icons/ui/ChevronLeft.esm.js'; import '../../../../icons/ui/ChevronRight.esm.js'; import '../../../Menu/Menu.esm.js'; import '../../../Menu/Menu.style.esm.js'; import '../../../Menu/Menu.minors.esm.js'; import '../../../../icons/ui/ChevronDown.esm.js'; import '../../../Button/Button.esm.js'; import '../../../Button/Button.style.esm.js'; import '../../../Button/Button.config.esm.js'; import '../../../Button/FeaturedIcon.esm.js'; import '../../../../themes/index.esm.js'; import '../../../LoaderCircular/LoaderCircular.esm.js'; import '../../../LoaderCircular/LoaderCircular.style.esm.js'; import '../../../../utils/hooks/useDeprecate.esm.js'; import '../../../../utils/general/mergeReactRefs.esm.js'; import '../../Input/Text.esm.js'; import '../../Input/Input.style.esm.js'; import '../../Shared.esm.js'; import '../../Input/useSuggestions.esm.js'; import '../../Wrapper/Wrapper.esm.js'; import '../../../PopOver/PopOver.esm.js'; import '../../../PopOver/PopOver.style.esm.js'; import '../../../PopOver/PopOver.error.esm.js'; import '../../../../utils/hooks/usePortal_DEPRECATED/usePortal_DEPRECATED.esm.js'; import 'react-dom'; import '../../../../utils/hooks/usePortal_DEPRECATED/usePortal_DEPRECATED.style.esm.js'; import '../../../../utils/hooks/usePortal_DEPRECATED/useMountAnimations.esm.js'; import '../../../../utils/hooks/useIsomorphicEffect.esm.js'; import '../../../../utils/DOM/getComputedStyles.esm.js'; import '../../../../utils/DOM/animate.esm.js'; import '../../../../utils/events/onEvent.esm.js'; import '../../../../utils/hooks/usePortal_DEPRECATED/coordinates.esm.js'; import '../../../../utils/hooks/usePortal_DEPRECATED/Anchor.esm.js'; import '../../../../utils/hooks/useOutsideClick.esm.js'; import '../../../../utils/DOM/SSR.esm.js'; import '../../../../utils/DOM/createPortalOutlet.esm.js'; import '../../../../utils/DOM/createElement.esm.js'; import '../../Input/Mark.esm.js'; import '../../../../utils/general/generateUID.esm.js'; var DateRange = withIris(DateRangeComponent); var dateFormat = getDateFormat(); function DateRangeComponent(_a) { var className = _a.className, endInputLabel = _a.endInputLabel, forwardRef = _a.forwardRef, maxDate = _a.maxDate, minDate = _a.minDate, onChange = _a.onChange, presets = _a.presets, maxDaysSelected = _a.maxDaysSelected, startInputLabel = _a.startInputLabel, onPresetClick = _a.onPresetClick, _b = _a.translation, translation = _b === void 0 ? translations['en'] : _b, defaultValue = _a.defaultValue; var firstRender = useRef(true); var initial = defaultValue ? __assign(__assign({}, initialState), { range: defaultValue, draft: defaultValue, viewportDate: defaultValue[0] }) : initialState; var _c = __read(useReducer(reducer, initial, init), 2), state = _c[0], dispatch = _c[1]; var _d = __read(useState(''), 2), presetOption = _d[0], setPresetOption = _d[1]; // When our internal range value changes, if a callback for onChange is passed // let's call that callback with our new value. useEffect(function () { if (onChange && !firstRender.current) { onChange(state.range); } else { firstRender.current = false; } }, [state.range, onChange]); var startLabel = state.startLabel, startDateError = state.startDateError, endLabel = state.endLabel, endDateError = state.endDateError, _e = __read(state.range, 2), rangeStart = _e[0], rangeEnd = _e[1], _f = __read(state.draft, 2), draftStart = _f[0], draftEnd = _f[1], _g = __read(state.hoverDraft, 2), hoverStart = _g[0], hoverEnd = _g[1], viewportDate = state.viewportDate, open = state.open; var _h = __read(useMemo(function () { if (!maxDaysSelected || !Number.isInteger(maxDaysSelected) || !draftStart) { return [minDate, maxDate]; } var start = new Date(draftEnd ? draftEnd.getTime() : draftStart.getTime()); start.setDate(start.getDate() - maxDaysSelected); var end = new Date(draftStart.getTime()); end.setDate(end.getDate() + maxDaysSelected); if (minDate && minDate > start) { start = minDate; } if (maxDate && maxDate < end) { end = maxDate; } return [start, end]; }, [draftStart, draftEnd, minDate, maxDate, maxDaysSelected]), 2), minDateRange = _h[0], maxDateRange = _h[1]; // Get the viewport for the first calendar in our range picker. var getDateForFirstCalendar = useMemo(function () { var year = viewportDate.getFullYear(); var month = viewportDate.getMonth(); var dateForFirstCalendar = new Date(); dateForFirstCalendar.setFullYear(year, month - 1, 1); return dateForFirstCalendar; }, [viewportDate]); // Derive the value for the input that represents our start date. var startDateLabel = useMemo(function () { if (typeof startLabel === 'string') return startLabel; if (hoverStart) return formatDate(hoverStart); if (draftStart) return formatDate(draftStart); if (!open && rangeStart) return formatDate(rangeStart); return ''; }, [open, draftStart, startLabel, hoverStart, rangeStart]); // Derive the value for the input that represents our end date. var endDateLabel = useMemo(function () { if (typeof endLabel === 'string') return endLabel; if (hoverEnd) return formatDate(hoverEnd); if (draftEnd) return formatDate(draftEnd); if (!open && rangeEnd) return formatDate(rangeEnd); return ''; }, [open, draftEnd, endLabel, hoverEnd, rangeEnd]); // Callback for going to the next month in our date range picker. function handleGoForward() { var viewportDate = state.viewportDate; var payload = new Date(viewportDate.getFullYear(), viewportDate.getMonth() + 1, 1); dispatch({ type: 'CHANGE_VIEWPORT', payload: payload }); } // Callback for going to the previous month in our date range picker. function handleGoBackward() { var viewportDate = state.viewportDate; var payload = new Date(viewportDate.getFullYear(), viewportDate.getMonth() - 1, 1); dispatch({ type: 'CHANGE_VIEWPORT', payload: payload }); } function handleKeyDown(event) { event.stopPropagation(); switch (event.key) { case 'Enter': if (open) { dispatch({ type: 'SAVE' }); } else { dispatch({ type: 'OPEN' }); } break; case 'Escape': if (open) { dispatch({ type: 'CLOSE' }); } break; } } function handleClick(payload) { dispatch({ type: 'SELECT_DATE', payload: payload }); } function handleHover(payload) { dispatch({ type: 'HOVER_DATE', payload: payload }); } var handleStartChange = function (event) { dispatch({ type: 'CHANGE_START', payload: { label: event.currentTarget.value, minDate: minDateRange, }, }); }; var handleEndChange = function (event) { dispatch({ type: 'CHANGE_END', payload: { label: event.currentTarget.value, maxDate: maxDateRange, }, }); }; var handleSelectPreset = function (preset) { var payload = []; var _a = getDates(), today = _a.today, yesterday = _a.yesterday; setPresetOption(preset); dispatch({ type: 'CLEAR' }); switch (typeof preset) { case 'string': if (preset === 'today') payload.push(today); if (preset === 'yesterday') payload.push(yesterday); if (preset === 'current month') { var firstDayOfMonth = new Date(); firstDayOfMonth.setDate(1); payload.push(firstDayOfMonth); payload.push(new Date()); } if (preset === 'last month') { var firstDayOfLastMonth = new Date(); firstDayOfLastMonth.setDate(1); firstDayOfLastMonth.setMonth(firstDayOfLastMonth.getMonth() - 1); var lastDateOfLastMonth = new Date(); lastDateOfLastMonth.setDate(0); payload.push(firstDayOfLastMonth); payload.push(lastDateOfLastMonth); } break; case 'number': var date = new Date(new Date().setDate(new Date().getDate() + preset)); if (preset > 0) { payload.push(today); payload.push(date); } else { payload.push(date); payload.push(today); } break; } if (payload.length) { dispatch({ type: 'SET_DATE_FROM_PRESET', payload: payload }); } }; var getPresetLabel = function (preset) { if (typeof preset === 'number') { return preset < 0 ? translation.lastDays(Math.abs(preset)) : translation.nextDays(preset); } else if (preset === 'current month') { return getMonthFromDate(new Date(), translation); } else if (preset === 'last month') { var dateOfLastMonth = new Date(); dateOfLastMonth.setDate(1); dateOfLastMonth.setMonth(dateOfLastMonth.getMonth() - 1); return getMonthFromDate(dateOfLastMonth, translation); } else if (preset === 'today') { return translation.today; } else if (preset === 'yesterday') { return translation.yesterday; } else if (preset === 'custom') { return translation.custom; } return preset; }; // Generate the styles to pin the portal to the parent node. return (React__default.createElement(DateRangeContainer, { ref: forwardRef }, presets ? (React__default.createElement(Menu, { format: "basic", style: { borderRight: "1px solid ".concat(slate(100)) } }, React__default.createElement(Menu.Section, { title: translation.presets }, presets.map(function (preset, key) { var label = getPresetLabel(preset); return (React__default.createElement(Menu.Item, { active: presetOption === preset, key: key, onClick: function () { handleSelectPreset(preset); if (Boolean(onPresetClick)) { onPresetClick(preset); } }, style: { textTransform: 'capitalize' } }, label)); })))) : null, React__default.createElement(CalendarsContainer // hidden={!open} , { // hidden={!open} className: className }, React__default.createElement(CalendarHeader, null, React__default.createElement(DateField, null, React__default.createElement(Input, { id: "start\u2013date", label: startInputLabel || translation.startDate, value: startDateLabel, onChange: handleStartChange, onKeyDown: handleKeyDown, placeholder: dateFormat, status: startDateError ? 'negative' : 'neutral', messages: { error: startDateError } })), React__default.createElement(DateField, null, React__default.createElement(Input, { id: "end-date", label: endInputLabel || translation.endDate, value: endDateLabel, onChange: handleEndChange, onKeyDown: handleKeyDown, placeholder: dateFormat, disabled: draftStart ? false : true, status: endDateError ? 'negative' : 'neutral', messages: { error: endDateError } }))), React__default.createElement(CalendarsBody, null, React__default.createElement(Calendar, { isRange: true, backOnly: true, backOnClick: handleGoBackward, initialMonth: getDateForFirstCalendar, minDate: minDateRange, maxDate: maxDateRange, range: [draftStart, draftEnd], hoverRange: [hoverStart, hoverEnd], selectionStart: hoverStart ? hoverStart : draftStart, selectionEnd: hoverEnd ? hoverEnd : draftEnd, onClick: handleClick, onMouseEnter: handleHover, translation: translation }), React__default.createElement(Calendar, { isRange: true, forwardOnly: true, forwardOnClick: handleGoForward, initialMonth: viewportDate, minDate: minDateRange, maxDate: maxDateRange, range: [draftStart, draftEnd], hoverRange: [hoverStart, hoverEnd], selectionStart: hoverStart ? hoverStart : draftStart, selectionEnd: hoverEnd ? hoverEnd : draftEnd, onClick: handleClick, onMouseEnter: handleHover, translation: translation })), React__default.createElement(CalendarsFooter, null, React__default.createElement(ClearButton, { hidden: draftEnd === null, size: "sm", format: "primary", variant: "minimal", onClick: function () { return void dispatch({ type: 'CLEAR' }); } }, translation.clear), React__default.createElement(ApplyButton, { disabled: !draftStart || !draftEnd || startDateError !== null || endDateError !== null, size: "sm", format: "secondary", onClick: function () { return void dispatch({ type: 'SAVE' }); } }, translation.apply))))); } function getDates() { var today = new Date(); var yesterday = new Date(today); yesterday.setDate(yesterday.getDate() - 1); return { today: today, yesterday: yesterday }; } export { DateRange };