@vimeo/iris
Version:
Vimeo Design System
333 lines (330 loc) • 17.3 kB
JavaScript
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 };