Merge branch 'datepicker' into 'main'

Remove react-datepicker, add a custom Datepicker component

See merge request soapbox-pub/soapbox!3169
This commit is contained in:
Alex Gleason 2024-10-19 20:52:30 +00:00
commit 1a70afe98d
13 changed files with 81 additions and 355 deletions

View File

@ -80,7 +80,6 @@
"@types/path-browserify": "^1.0.0", "@types/path-browserify": "^1.0.0",
"@types/react": "^18.3.9", "@types/react": "^18.3.9",
"@types/react-color": "^3.0.6", "@types/react-color": "^3.0.6",
"@types/react-datepicker": "^4.4.2",
"@types/react-dom": "^18.3.0", "@types/react-dom": "^18.3.0",
"@types/react-helmet": "^6.1.5", "@types/react-helmet": "^6.1.5",
"@types/react-motion": "^0.0.40", "@types/react-motion": "^0.0.40",
@ -128,7 +127,6 @@
"qrcode.react": "^3.1.0", "qrcode.react": "^3.1.0",
"react": "^18.3.1", "react": "^18.3.1",
"react-color": "^2.19.3", "react-color": "^2.19.3",
"react-datepicker": "^4.8.0",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-error-boundary": "^4.0.11", "react-error-boundary": "^4.0.11",
"react-helmet": "^6.1.0", "react-helmet": "^6.1.0",

View File

@ -1,10 +1,10 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import { defineMessages, useIntl } from 'react-intl'; import { defineMessages, useIntl } from 'react-intl';
import IconButton from 'soapbox/components/icon-button';
import { DatePicker } from 'soapbox/features/ui/util/async-components';
import { useInstance, useFeatures } from 'soapbox/hooks'; import { useInstance, useFeatures } from 'soapbox/hooks';
import { Datetime } from './ui/datetime/datetime';
const messages = defineMessages({ const messages = defineMessages({
birthdayPlaceholder: { id: 'edit_profile.fields.birthday_placeholder', defaultMessage: 'Your birthday' }, birthdayPlaceholder: { id: 'edit_profile.fields.birthday_placeholder', defaultMessage: 'Your birthday' },
previousMonth: { id: 'datepicker.previous_month', defaultMessage: 'Previous month' }, previousMonth: { id: 'datepicker.previous_month', defaultMessage: 'Previous month' },
@ -28,7 +28,7 @@ const BirthdayInput: React.FC<IBirthdayInput> = ({ value, onChange, required })
const minAge = instance.pleroma.metadata.birthday_min_age; const minAge = instance.pleroma.metadata.birthday_min_age;
const maxDate = useMemo(() => { const maxDate = useMemo(() => {
if (!supportsBirthdays) return null; if (!supportsBirthdays) return;
let maxDate = new Date(); let maxDate = new Date();
maxDate = new Date(maxDate.getTime() - minAge * 1000 * 60 * 60 * 24 + maxDate.getTimezoneOffset() * 1000 * 60); maxDate = new Date(maxDate.getTime() - minAge * 1000 * 60 * 60 * 24 + maxDate.getTimezoneOffset() * 1000 * 60);
@ -36,7 +36,7 @@ const BirthdayInput: React.FC<IBirthdayInput> = ({ value, onChange, required })
}, [minAge]); }, [minAge]);
const selected = useMemo(() => { const selected = useMemo(() => {
if (!supportsBirthdays || !value) return null; if (!supportsBirthdays || !value) return;
const date = new Date(value); const date = new Date(value);
return new Date(date.getTime() + (date.getTimezoneOffset() * 60000)); return new Date(date.getTime() + (date.getTimezoneOffset() * 60000));
@ -44,85 +44,17 @@ const BirthdayInput: React.FC<IBirthdayInput> = ({ value, onChange, required })
if (!supportsBirthdays) return null; if (!supportsBirthdays) return null;
const renderCustomHeader = ({
decreaseMonth,
increaseMonth,
prevMonthButtonDisabled,
nextMonthButtonDisabled,
decreaseYear,
increaseYear,
prevYearButtonDisabled,
nextYearButtonDisabled,
date,
}: {
decreaseMonth(): void;
increaseMonth(): void;
prevMonthButtonDisabled: boolean;
nextMonthButtonDisabled: boolean;
decreaseYear(): void;
increaseYear(): void;
prevYearButtonDisabled: boolean;
nextYearButtonDisabled: boolean;
date: Date;
}) => {
return (
<div className='flex flex-col gap-2'>
<div className='flex items-center justify-between'>
<IconButton
className='datepicker__button rtl:rotate-180'
src={require('@tabler/icons/outline/chevron-left.svg')}
onClick={decreaseMonth}
disabled={prevMonthButtonDisabled}
aria-label={intl.formatMessage(messages.previousMonth)}
title={intl.formatMessage(messages.previousMonth)}
/>
{intl.formatDate(date, { month: 'long' })}
<IconButton
className='datepicker__button rtl:rotate-180'
src={require('@tabler/icons/outline/chevron-right.svg')}
onClick={increaseMonth}
disabled={nextMonthButtonDisabled}
aria-label={intl.formatMessage(messages.nextMonth)}
title={intl.formatMessage(messages.nextMonth)}
/>
</div>
<div className='flex items-center justify-between'>
<IconButton
className='datepicker__button rtl:rotate-180'
src={require('@tabler/icons/outline/chevron-left.svg')}
onClick={decreaseYear}
disabled={prevYearButtonDisabled}
aria-label={intl.formatMessage(messages.previousYear)}
title={intl.formatMessage(messages.previousYear)}
/>
{intl.formatDate(date, { year: 'numeric' })}
<IconButton
className='datepicker__button rtl:rotate-180'
src={require('@tabler/icons/outline/chevron-right.svg')}
onClick={increaseYear}
disabled={nextYearButtonDisabled}
aria-label={intl.formatMessage(messages.nextYear)}
title={intl.formatMessage(messages.nextYear)}
/>
</div>
</div>
);
};
const handleChange = (date: Date) => onChange(date ? new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString().slice(0, 10) : ''); const handleChange = (date: Date) => onChange(date ? new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString().slice(0, 10) : '');
return ( return (
<div className='relative mt-1 rounded-md shadow-sm'> <div className='relative mt-1 rounded-md shadow-sm'>
<DatePicker <Datetime
selected={selected} value={selected ?? new Date()}
wrapperClassName='react-datepicker-wrapper'
onChange={handleChange} onChange={handleChange}
placeholderText={intl.formatMessage(messages.birthdayPlaceholder)} placeholder={intl.formatMessage(messages.birthdayPlaceholder)}
minDate={new Date('1900-01-01')} min={new Date('1900-01-01')}
maxDate={maxDate} max={maxDate}
required={required} required={required}
renderCustomHeader={renderCustomHeader}
isClearable={!required}
/> />
</div> </div>
); );

View File

@ -0,0 +1,39 @@
import React from 'react';
import Input from '../input/input';
interface DatetimeProps {
value: Date;
onChange(date: Date): void;
min?: Date;
max?: Date;
placeholder?: string;
required?: boolean;
}
/**
* Date input with time.
*/
export const Datetime: React.FC<DatetimeProps> = ({ value, onChange, min, max, ...rest }) => {
return (
<Input
type='datetime-local'
onChange={(e) => onChange(new Date(e.target.value))}
value={formatDateLocal(value)}
min={min ? formatDateLocal(min) : undefined}
max={max ? formatDateLocal(max) : undefined}
{...rest}
/>
);
};
/** Format a Date object to 'YYYY-MM-DDTHH:MM' format, used by `<input type="datetime-local">` elements. */
function formatDateLocal(date: Date): string {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
return `${year}-${month}-${day}T${hours}:${minutes}`;
}

View File

@ -17,7 +17,7 @@ const messages = defineMessages({
/** Possible theme names for an Input. */ /** Possible theme names for an Input. */
type InputThemes = 'normal' | 'search' type InputThemes = 'normal' | 'search'
interface IInput extends Pick<React.InputHTMLAttributes<HTMLInputElement>, 'maxLength' | 'onChange' | 'onBlur' | 'type' | 'autoComplete' | 'autoCorrect' | 'autoCapitalize' | 'required' | 'disabled' | 'onClick' | 'readOnly' | 'min' | 'pattern' | 'onKeyDown' | 'onKeyUp' | 'onFocus' | 'style' | 'id'> { interface IInput extends Pick<React.InputHTMLAttributes<HTMLInputElement>, 'maxLength' | 'onChange' | 'onBlur' | 'type' | 'autoComplete' | 'autoCorrect' | 'autoCapitalize' | 'required' | 'disabled' | 'onClick' | 'readOnly' | 'min' | 'max' | 'pattern' | 'onKeyDown' | 'onKeyUp' | 'onFocus' | 'style' | 'id'> {
/** Put the cursor into the input on mount. */ /** Put the cursor into the input on mount. */
autoFocus?: boolean; autoFocus?: boolean;
/** The initial text in the input. */ /** The initial text in the input. */

View File

@ -1,4 +0,0 @@
import DatePicker from 'react-datepicker';
import 'react-datepicker/dist/react-datepicker.css';
export default DatePicker;

View File

@ -1,24 +1,12 @@
import clsx from 'clsx'; import React from 'react';
import React, { Suspense } from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { setSchedule, removeSchedule } from 'soapbox/actions/compose'; import { setSchedule, removeSchedule } from 'soapbox/actions/compose';
import IconButton from 'soapbox/components/icon-button'; import IconButton from 'soapbox/components/icon-button';
import { HStack, Input, Stack, Text } from 'soapbox/components/ui'; import { HStack, Stack, Text } from 'soapbox/components/ui';
import { DatePicker } from 'soapbox/features/ui/util/async-components'; import { Datetime } from 'soapbox/components/ui/datetime/datetime';
import { useAppDispatch, useCompose } from 'soapbox/hooks'; import { useAppDispatch, useCompose } from 'soapbox/hooks';
export const isCurrentOrFutureDate = (date: Date) => {
return date && new Date().setHours(0, 0, 0, 0) <= new Date(date).setHours(0, 0, 0, 0);
};
const isFiveMinutesFromNow = (time: Date) => {
const fiveMinutesFromNow = new Date(new Date().getTime() + 300000); // now, plus five minutes (Pleroma won't schedule posts )
const selectedDate = new Date(time);
return fiveMinutesFromNow.getTime() < selectedDate.getTime();
};
const messages = defineMessages({ const messages = defineMessages({
schedule: { id: 'schedule.post_time', defaultMessage: 'Post Date/Time' }, schedule: { id: 'schedule.post_time', defaultMessage: 'Post Date/Time' },
remove: { id: 'schedule.remove', defaultMessage: 'Remove schedule' }, remove: { id: 'schedule.remove', defaultMessage: 'Remove schedule' },
@ -35,6 +23,8 @@ const ScheduleForm: React.FC<IScheduleForm> = ({ composeId }) => {
const scheduledAt = useCompose(composeId).schedule; const scheduledAt = useCompose(composeId).schedule;
const active = !!scheduledAt; const active = !!scheduledAt;
const fiveMinutesFromNow = new Date(new Date().getTime() + 300_000);
const onSchedule = (date: Date) => { const onSchedule = (date: Date) => {
dispatch(setSchedule(composeId, date)); dispatch(setSchedule(composeId, date));
}; };
@ -54,22 +44,11 @@ const ScheduleForm: React.FC<IScheduleForm> = ({ composeId }) => {
<FormattedMessage id='datepicker.hint' defaultMessage='Scheduled to post at…' /> <FormattedMessage id='datepicker.hint' defaultMessage='Scheduled to post at…' />
</Text> </Text>
<HStack space={2} alignItems='center'> <HStack space={2} alignItems='center'>
<Suspense fallback={<Input type='text' disabled />}> <Datetime
<DatePicker onChange={onSchedule}
selected={scheduledAt} value={scheduledAt}
showTimeSelect min={fiveMinutesFromNow}
dateFormat='MMMM d, yyyy h:mm aa' />
timeIntervals={15}
wrapperClassName='react-datepicker-wrapper'
onChange={onSchedule}
placeholderText={intl.formatMessage(messages.schedule)}
filterDate={isCurrentOrFutureDate}
filterTime={isFiveMinutesFromNow}
className={clsx({
'has-error': !isFiveMinutesFromNow(scheduledAt),
})}
/>
</Suspense>
<IconButton <IconButton
iconClassName='h-4 w-4' iconClassName='h-4 w-4'
className='bg-transparent text-gray-400 hover:text-gray-600' className='bg-transparent text-gray-400 hover:text-gray-600'

View File

@ -22,9 +22,9 @@ import { ADDRESS_ICONS } from 'soapbox/components/autosuggest-location';
import LocationSearch from 'soapbox/components/location-search'; import LocationSearch from 'soapbox/components/location-search';
import { checkEventComposeContent } from 'soapbox/components/modal-root'; import { checkEventComposeContent } from 'soapbox/components/modal-root';
import { Button, Form, FormGroup, HStack, Icon, IconButton, Input, Modal, Spinner, Stack, Tabs, Text, Toggle } from 'soapbox/components/ui'; import { Button, Form, FormGroup, HStack, Icon, IconButton, Input, Modal, Spinner, Stack, Tabs, Text, Toggle } from 'soapbox/components/ui';
import { Datetime } from 'soapbox/components/ui/datetime/datetime';
import AccountContainer from 'soapbox/containers/account-container'; import AccountContainer from 'soapbox/containers/account-container';
import { isCurrentOrFutureDate } from 'soapbox/features/compose/components/schedule-form'; import { ComposeEditor } from 'soapbox/features/ui/util/async-components';
import { ComposeEditor, DatePicker } from 'soapbox/features/ui/util/async-components';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks'; import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
import UploadButton from './upload-button'; import UploadButton from './upload-button';
@ -254,15 +254,10 @@ const ComposeEventModal: React.FC<IComposeEventModal> = ({ onClose }) => {
<FormGroup <FormGroup
labelText={<FormattedMessage id='compose_event.fields.start_time_label' defaultMessage='Event start date' />} labelText={<FormattedMessage id='compose_event.fields.start_time_label' defaultMessage='Event start date' />}
> >
<DatePicker <Datetime
showTimeSelect value={startTime}
dateFormat='MMMM d, yyyy h:mm aa'
timeIntervals={15}
wrapperClassName='react-datepicker-wrapper'
placeholderText={intl.formatMessage(messages.eventStartTimePlaceholder)}
filterDate={isCurrentOrFutureDate}
selected={startTime}
onChange={onChangeStartTime} onChange={onChangeStartTime}
placeholder={intl.formatMessage(messages.eventStartTimePlaceholder)}
/> />
</FormGroup> </FormGroup>
<HStack alignItems='center' space={2}> <HStack alignItems='center' space={2}>
@ -278,15 +273,10 @@ const ComposeEventModal: React.FC<IComposeEventModal> = ({ onClose }) => {
<FormGroup <FormGroup
labelText={<FormattedMessage id='compose_event.fields.end_time_label' defaultMessage='Event end date' />} labelText={<FormattedMessage id='compose_event.fields.end_time_label' defaultMessage='Event end date' />}
> >
<DatePicker <Datetime
showTimeSelect value={endTime}
dateFormat='MMMM d, yyyy h:mm aa'
timeIntervals={15}
wrapperClassName='react-datepicker-wrapper'
placeholderText={intl.formatMessage(messages.eventEndTimePlaceholder)}
filterDate={isCurrentOrFutureDate}
selected={endTime}
onChange={onChangeEndTime} onChange={onChangeEndTime}
placeholder={intl.formatMessage(messages.eventEndTimePlaceholder)}
/> />
</FormGroup> </FormGroup>
)} )}

View File

@ -4,7 +4,7 @@ import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
import { closeModal } from 'soapbox/actions/modals'; import { closeModal } from 'soapbox/actions/modals';
import { useAnnouncements } from 'soapbox/api/hooks/admin/useAnnouncements'; import { useAnnouncements } from 'soapbox/api/hooks/admin/useAnnouncements';
import { Form, FormGroup, HStack, Modal, Stack, Text, Textarea, Toggle } from 'soapbox/components/ui'; import { Form, FormGroup, HStack, Modal, Stack, Text, Textarea, Toggle } from 'soapbox/components/ui';
import { DatePicker } from 'soapbox/features/ui/util/async-components'; import { Datetime } from 'soapbox/components/ui/datetime/datetime';
import { useAppDispatch } from 'soapbox/hooks'; import { useAppDispatch } from 'soapbox/hooks';
import toast from 'soapbox/toast'; import toast from 'soapbox/toast';
@ -30,15 +30,15 @@ const EditAnnouncementModal: React.FC<IEditAnnouncementModal> = ({ onClose, anno
const intl = useIntl(); const intl = useIntl();
const [content, setContent] = useState(announcement?.content || ''); const [content, setContent] = useState(announcement?.content || '');
const [startTime, setStartTime] = useState(announcement?.starts_at ? new Date(announcement.starts_at) : null); const [startTime, setStartTime] = useState(announcement?.starts_at ? new Date(announcement.starts_at) : undefined);
const [endTime, setEndTime] = useState(announcement?.ends_at ? new Date(announcement.ends_at) : null); const [endTime, setEndTime] = useState(announcement?.ends_at ? new Date(announcement.ends_at) : undefined);
const [allDay, setAllDay] = useState(announcement?.all_day || false); const [allDay, setAllDay] = useState(announcement?.all_day || false);
const onChangeContent: React.ChangeEventHandler<HTMLTextAreaElement> = ({ target }) => setContent(target.value); const onChangeContent: React.ChangeEventHandler<HTMLTextAreaElement> = ({ target }) => setContent(target.value);
const onChangeStartTime = (date: Date | null) => setStartTime(date); const onChangeStartTime = (date: Date | undefined) => setStartTime(date);
const onChangeEndTime = (date: Date | null) => setEndTime(date); const onChangeEndTime = (date: Date | undefined) => setEndTime(date);
const onChangeAllDay: React.ChangeEventHandler<HTMLInputElement> = ({ target }) => setAllDay(target.checked); const onChangeAllDay: React.ChangeEventHandler<HTMLInputElement> = ({ target }) => setAllDay(target.checked);
@ -94,29 +94,19 @@ const EditAnnouncementModal: React.FC<IEditAnnouncementModal> = ({ onClose, anno
<FormGroup <FormGroup
labelText={<FormattedMessage id='admin.edit_announcement.fields.start_time_label' defaultMessage='Start date' />} labelText={<FormattedMessage id='admin.edit_announcement.fields.start_time_label' defaultMessage='Start date' />}
> >
<DatePicker <Datetime
showTimeSelect value={startTime ?? new Date()}
dateFormat='MMMM d, yyyy h:mm aa'
timeIntervals={15}
wrapperClassName='react-datepicker-wrapper'
placeholderText={intl.formatMessage(messages.announcementStartTimePlaceholder)}
selected={startTime}
onChange={onChangeStartTime} onChange={onChangeStartTime}
isClearable placeholder={intl.formatMessage(messages.announcementStartTimePlaceholder)}
/> />
</FormGroup> </FormGroup>
<FormGroup <FormGroup
labelText={<FormattedMessage id='admin.edit_announcement.fields.end_time_label' defaultMessage='End date' />} labelText={<FormattedMessage id='admin.edit_announcement.fields.end_time_label' defaultMessage='End date' />}
> >
<DatePicker <Datetime
showTimeSelect value={endTime ?? new Date()}
dateFormat='MMMM d, yyyy h:mm aa'
timeIntervals={15}
wrapperClassName='react-datepicker-wrapper'
placeholderText={intl.formatMessage(messages.announcementEndTimePlaceholder)}
selected={endTime}
onChange={onChangeEndTime} onChange={onChangeEndTime}
isClearable placeholder={intl.formatMessage(messages.announcementEndTimePlaceholder)}
/> />
</FormGroup> </FormGroup>
<HStack alignItems='center' space={2}> <HStack alignItems='center' space={2}>

View File

@ -120,7 +120,6 @@ export const CreateApp = lazy(() => import('soapbox/features/developers/apps/cre
export const SettingsStore = lazy(() => import('soapbox/features/developers/settings-store')); export const SettingsStore = lazy(() => import('soapbox/features/developers/settings-store'));
export const TestTimeline = lazy(() => import('soapbox/features/test-timeline')); export const TestTimeline = lazy(() => import('soapbox/features/test-timeline'));
export const ServiceWorkerInfo = lazy(() => import('soapbox/features/developers/service-worker-info')); export const ServiceWorkerInfo = lazy(() => import('soapbox/features/developers/service-worker-info'));
export const DatePicker = lazy(() => import('soapbox/features/birthdays/date-picker'));
export const CompareHistoryModal = lazy(() => import('soapbox/features/ui/components/modals/compare-history-modal')); export const CompareHistoryModal = lazy(() => import('soapbox/features/ui/components/modals/compare-history-modal'));
export const AuthTokenList = lazy(() => import('soapbox/features/auth-token-list')); export const AuthTokenList = lazy(() => import('soapbox/features/auth-token-list'));
export const FamiliarFollowersModal = lazy(() => import('soapbox/features/ui/components/modals/familiar-followers-modal')); export const FamiliarFollowersModal = lazy(() => import('soapbox/features/ui/components/modals/familiar-followers-modal'));

View File

@ -14,7 +14,6 @@ import '@fontsource/inter/700.css';
import '@fontsource/inter/900.css'; import '@fontsource/inter/900.css';
import '@fontsource/roboto-mono/400.css'; import '@fontsource/roboto-mono/400.css';
import 'line-awesome/dist/font-awesome-line-awesome/css/all.css'; import 'line-awesome/dist/font-awesome-line-awesome/css/all.css';
import 'react-datepicker/dist/react-datepicker.css';
import 'soapbox/features/nostr/keys'; import 'soapbox/features/nostr/keys';
import './iframe'; import './iframe';

View File

@ -28,4 +28,3 @@
@import 'components/icon'; @import 'components/icon';
@import 'forms'; @import 'forms';
@import 'utilities'; @import 'utilities';
@import 'components/datepicker';

View File

@ -1,150 +0,0 @@
.react-datepicker {
@apply black:bg-black dark:bg-gray-900 dark:border-gray-700 p-4 font-sans text-xs text-gray-900 dark:text-gray-300 border border-solid border-gray-200 rounded-lg;
}
.react-datepicker__input-container > input {
@apply black:bg-black dark:bg-gray-900 dark:text-gray-100 block w-full sm:text-sm border-gray-400 dark:border-gray-800 rounded-md focus:ring-primary-500 focus:border-primary-500;
&.has-error {
@apply text-red-600 border-red-600;
}
}
.react-datepicker-popper[data-placement^='bottom'] .react-datepicker__triangle::before,
.react-datepicker-popper[data-placement^='bottom'] .react-datepicker__triangle::after {
@apply border-b-white dark:border-b-gray-900 black:border-b-black;
}
.react-datepicker-popper[data-placement^='bottom'] .react-datepicker__triangle::before {
@apply border-b-gray-200 dark:border-b-gray-700;
}
.react-datepicker__header:not(.react-datepicker__header--has-time-select) {
@apply rounded-tr-lg;
}
.react-datepicker__header {
@apply bg-white black:bg-black dark:bg-gray-900 border-b-0 py-1 px-0;
}
.react-datepicker__current-month,
.react-datepicker-time__header,
.react-datepicker-year-header {
@apply text-gray-900 dark:text-gray-300 font-bold text-sm;
}
.react-datepicker__current-month {
margin-top: 2px;
}
.react-datepicker__navigation {
@apply top-4 h-8 w-8 rounded hover:bg-gray-50 dark:hover:bg-gray-900/50;
}
.react-datepicker__navigation-icon {
margin-top: -3px;
}
.react-datepicker__navigation-icon--previous::before {
right: -5px;
}
.react-datepicker__navigation-icon--next::before {
left: -5px;
}
.react-datepicker__navigation--previous {
left: 16px;
}
.react-datepicker__navigation--next {
right: 16px;
&--with-time:not(.react-datepicker__navigation--next--with-today-button) {
right: 100px;
}
}
.react-datepicker__year-read-view--down-arrow,
.react-datepicker__month-read-view--down-arrow,
.react-datepicker__month-year-read-view--down-arrow,
.react-datepicker__navigation-icon::before {
border-width: 2px 2px 0 0;
height: 7px;
width: 7px;
top: 8px;
}
.react-datepicker__header__dropdown {
@apply py-4;
}
.react-datepicker__day-names,
.react-datepicker__week {
@apply flex justify-between;
}
.react-datepicker__time {
&-container & {
@apply dark:bg-gray-900 black:bg-black;
}
}
.react-datepicker__time-container {
@apply dark:border-gray-700 black:border-gray-800;
}
.react-datepicker__day-name,
.react-datepicker__day,
.react-datepicker__time-name {
@apply text-gray-900 dark:text-gray-300;
width: 30px;
height: 30px;
line-height: 30px;
}
.react-datepicker__time-list-item--disabled,
.react-datepicker__day--disabled {
@apply text-gray-400 dark:text-gray-500;
}
.react-datepicker__day:hover,
.react-datepicker__month-text:hover,
.react-datepicker__quarter-text:hover,
.react-datepicker__year-text:hover,
.react-datepicker__time-list-item:hover {
@apply bg-gray-100 dark:bg-gray-700 rounded;
}
.react-datepicker__day--selected,
.react-datepicker__day--in-selecting-range,
.react-datepicker__day--in-range,
.react-datepicker__month-text--selected,
.react-datepicker__month-text--in-selecting-range,
.react-datepicker__month-text--in-range,
.react-datepicker__quarter-text--selected,
.react-datepicker__quarter-text--in-selecting-range,
.react-datepicker__quarter-text--in-range,
.react-datepicker__year-text--selected,
.react-datepicker__year-text--in-selecting-range,
.react-datepicker__year-text--in-range {
@apply bg-primary-600 hover:bg-primary-700 dark:bg-gray-300 dark:hover:bg-gray-200 text-white dark:text-black rounded;
}
.react-datepicker__day--keyboard-selected,
.react-datepicker__month-text--keyboard-selected,
.react-datepicker__quarter-text--keyboard-selected,
.react-datepicker__year-text--keyboard-selected {
@apply bg-primary-50 hover:bg-primary-100 dark:bg-gray-700 dark:hover:bg-gray-600 text-primary-600 dark:text-primary-400;
}
.react-datepicker__close-icon {
@apply rtl:left-0 rtl:right-auto rtl:pr-0 rtl:pl-[6px];
}
.react-datepicker__close-icon::after {
@apply bg-transparent text-gray-600 dark:text-gray-400 text-base;
font-family: 'Font Awesome 5 Free';
content: '';
font-weight: 900;
}

View File

@ -1948,11 +1948,6 @@
"@parcel/watcher-win32-ia32" "2.4.1" "@parcel/watcher-win32-ia32" "2.4.1"
"@parcel/watcher-win32-x64" "2.4.1" "@parcel/watcher-win32-x64" "2.4.1"
"@popperjs/core@^2.9.2":
version "2.11.5"
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.5.tgz#db5a11bf66bdab39569719555b0f76e138d7bd64"
integrity sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw==
"@reach/auto-id@0.18.0": "@reach/auto-id@0.18.0":
version "0.18.0" version "0.18.0"
resolved "https://registry.yarnpkg.com/@reach/auto-id/-/auto-id-0.18.0.tgz#4b97085cd1cf1360a9bedc6e9c78e97824014f0d" resolved "https://registry.yarnpkg.com/@reach/auto-id/-/auto-id-0.18.0.tgz#4b97085cd1cf1360a9bedc6e9c78e97824014f0d"
@ -2648,16 +2643,6 @@
"@types/react" "*" "@types/react" "*"
"@types/reactcss" "*" "@types/reactcss" "*"
"@types/react-datepicker@^4.4.2":
version "4.4.2"
resolved "https://registry.yarnpkg.com/@types/react-datepicker/-/react-datepicker-4.4.2.tgz#13ab25a5fff7f3da4c5380c471efd8b38f53010e"
integrity sha512-g8DhWvYmaIMLzVrIEVLXncylyImyBaoPsEUr3yR13JDaaHoebhDorqnVv4tLkNGa8SjBB8SAOQvxD5jaPNBX8A==
dependencies:
"@popperjs/core" "^2.9.2"
"@types/react" "*"
date-fns "^2.0.1"
react-popper "^2.2.5"
"@types/react-dom@^18.0.0", "@types/react-dom@^18.3.0": "@types/react-dom@^18.0.0", "@types/react-dom@^18.3.0":
version "18.3.0" version "18.3.0"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.0.tgz#0cbc818755d87066ab6ca74fbedb2547d74a82b0" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.0.tgz#0cbc818755d87066ab6ca74fbedb2547d74a82b0"
@ -3705,7 +3690,7 @@ chrome-trace-event@^1.0.2:
resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac"
integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==
classnames@^2.2.5, classnames@^2.2.6: classnames@^2.2.5:
version "2.3.1" version "2.3.1"
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e"
integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==
@ -4057,11 +4042,6 @@ data-urls@^5.0.0:
whatwg-mimetype "^4.0.0" whatwg-mimetype "^4.0.0"
whatwg-url "^14.0.0" whatwg-url "^14.0.0"
date-fns@^2.0.1, date-fns@^2.24.0:
version "2.28.0"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.28.0.tgz#9570d656f5fc13143e50c975a3b6bbeb46cd08b2"
integrity sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw==
debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.6, debug@^4.3.7: debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.6, debug@^4.3.7:
version "4.3.7" version "4.3.7"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52"
@ -7232,18 +7212,6 @@ react-color@^2.19.3:
reactcss "^1.2.0" reactcss "^1.2.0"
tinycolor2 "^1.4.1" tinycolor2 "^1.4.1"
react-datepicker@^4.8.0:
version "4.8.0"
resolved "https://registry.yarnpkg.com/react-datepicker/-/react-datepicker-4.8.0.tgz#11b8918d085a1ce4781eee4c8e4641b3cd592010"
integrity sha512-u69zXGHMpxAa4LeYR83vucQoUCJQ6m/WBsSxmUMu/M8ahTSVMMyiyQzauHgZA2NUr9y0FUgOAix71hGYUb6tvg==
dependencies:
"@popperjs/core" "^2.9.2"
classnames "^2.2.6"
date-fns "^2.24.0"
prop-types "^15.7.2"
react-onclickoutside "^6.12.0"
react-popper "^2.2.5"
react-dom@^18.3.1: react-dom@^18.3.1:
version "18.3.1" version "18.3.1"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4"
@ -7275,7 +7243,7 @@ react-event-listener@^0.6.0:
prop-types "^15.6.0" prop-types "^15.6.0"
warning "^4.0.1" warning "^4.0.1"
react-fast-compare@^3.0.1, react-fast-compare@^3.1.1: react-fast-compare@^3.1.1:
version "3.2.0" version "3.2.0"
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb" resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb"
integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==
@ -7349,11 +7317,6 @@ react-motion@^0.5.2:
prop-types "^15.5.8" prop-types "^15.5.8"
raf "^3.1.0" raf "^3.1.0"
react-onclickoutside@^6.12.0:
version "6.12.1"
resolved "https://registry.yarnpkg.com/react-onclickoutside/-/react-onclickoutside-6.12.1.tgz#92dddd28f55e483a1838c5c2930e051168c1e96b"
integrity sha512-a5Q7CkWznBRUWPmocCvE8b6lEYw1s6+opp/60dCunhO+G6E4tDTO2Sd2jKE+leEnnrLAE2Wj5DlDHNqj5wPv1Q==
react-overlays@^0.9.0: react-overlays@^0.9.0:
version "0.9.3" version "0.9.3"
resolved "https://registry.yarnpkg.com/react-overlays/-/react-overlays-0.9.3.tgz#5bac8c1e9e7e057a125181dee2d784864dd62902" resolved "https://registry.yarnpkg.com/react-overlays/-/react-overlays-0.9.3.tgz#5bac8c1e9e7e057a125181dee2d784864dd62902"
@ -7366,14 +7329,6 @@ react-overlays@^0.9.0:
react-transition-group "^2.2.1" react-transition-group "^2.2.1"
warning "^3.0.0" warning "^3.0.0"
react-popper@^2.2.5:
version "2.3.0"
resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-2.3.0.tgz#17891c620e1320dce318bad9fede46a5f71c70ba"
integrity sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==
dependencies:
react-fast-compare "^3.0.1"
warning "^4.0.2"
react-property@2.0.2: react-property@2.0.2:
version "2.0.2" version "2.0.2"
resolved "https://registry.yarnpkg.com/react-property/-/react-property-2.0.2.tgz#d5ac9e244cef564880a610bc8d868bd6f60fdda6" resolved "https://registry.yarnpkg.com/react-property/-/react-property-2.0.2.tgz#d5ac9e244cef564880a610bc8d868bd6f60fdda6"
@ -8938,7 +8893,7 @@ warning@^3.0.0:
dependencies: dependencies:
loose-envify "^1.0.0" loose-envify "^1.0.0"
warning@^4.0.0, warning@^4.0.1, warning@^4.0.2: warning@^4.0.0, warning@^4.0.1:
version "4.0.3" version "4.0.3"
resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3"
integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==