From 693f1af7618d5c5c4dc2d7537dd92ca595e0b173 Mon Sep 17 00:00:00 2001 From: Valerii Sidorenko Date: Fri, 23 Aug 2024 19:27:40 +0200 Subject: [PATCH] feat(Calendar): add isWeekend prop --- src/components/Calendar/README.md | 1 + .../Calendar/__stories__/Calendar.stories.tsx | 19 +++++++++++++++++++ src/components/CalendarView/Calendar.scss | 2 +- src/components/CalendarView/hooks/types.ts | 2 ++ .../CalendarView/hooks/useCalendarState.ts | 10 ++++++++-- src/components/RangeCalendar/README.md | 1 + .../__stories__/RangeCalendar.stories.tsx | 19 +++++++++++++++++++ src/components/utils/dates.ts | 4 ++++ 8 files changed, 55 insertions(+), 3 deletions(-) diff --git a/src/components/Calendar/README.md b/src/components/Calendar/README.md index 63c61fe..f4a831a 100644 --- a/src/components/Calendar/README.md +++ b/src/components/Calendar/README.md @@ -191,6 +191,7 @@ LANDING_BLOCK--> | [focusedValue](#focused-value) | Set the default view of uncontrolled component which includes this value | `DateTime` `null` | | | id | The control's `id` attribute | `string` | | | isDateUnavailable | Callback that is called for each date of the calendar. If it returns true, then the date is unavailable. | `((date: DateTime) => boolean)` | | +| isWeekend | Callback that is called for each date of the calendar. If it returns true, then the date is weekend. | `((date: DateTime) => boolean)` | | | [maxValue](#min-and-max-value) | The maximum allowed date that a user may select. | `DateTime` | | | [minValue](#min-and-max-value) | The minimum allowed date that a user may select. | `DateTime` | | | [mode](#mode) | Defines the time interval that `Calendar` should display in colttrolled way. | `days` `months` `quarters` `years` | | diff --git a/src/components/Calendar/__stories__/Calendar.stories.tsx b/src/components/Calendar/__stories__/Calendar.stories.tsx index 077514d..11de802 100644 --- a/src/components/Calendar/__stories__/Calendar.stories.tsx +++ b/src/components/Calendar/__stories__/Calendar.stories.tsx @@ -42,6 +42,7 @@ export const Default = { ? dateTimeParse(args.defaultFocusedValue, {timeZone}) : undefined, isDateUnavailable: getIsDateUnavailable(args.isDateUnavailable as unknown as string), + isWeekend: getIsWeekend(args.isWeekend as unknown as string), }; return ; }, @@ -96,6 +97,12 @@ export const Default = { type: 'radio', }, }, + isWeekend: { + options: ['default', 'none', 'Friday and Saturday'], + control: { + type: 'radio', + }, + }, timeZone: timeZoneControl, }, } satisfies Story; @@ -126,6 +133,18 @@ function getIsDateUnavailable(variant: string) { return undefined; } +function getIsWeekend(variant: string) { + if (variant === 'Friday and Saturday') { + return (date: DateTime) => [5, 6].includes(date.day()); + } + + if (variant === 'none') { + return () => false; + } + + return undefined; +} + export const Custom: Story = { ...Default, render: function Custom(args) { diff --git a/src/components/CalendarView/Calendar.scss b/src/components/CalendarView/Calendar.scss index 6c06426..6d1a604 100644 --- a/src/components/CalendarView/Calendar.scss +++ b/src/components/CalendarView/Calendar.scss @@ -286,7 +286,7 @@ $block: '.#{variables.$ns}calendar'; content: ''; border-radius: 50%; - background-color: var(--g-color-text-primary); + background-color: currentColor; transform: translateY(8px); } diff --git a/src/components/CalendarView/hooks/types.ts b/src/components/CalendarView/hooks/types.ts index 877e535..c389068 100644 --- a/src/components/CalendarView/hooks/types.ts +++ b/src/components/CalendarView/hooks/types.ts @@ -11,6 +11,8 @@ export interface CalendarStateOptionsBase extends InputBase { maxValue?: DateTime; /** Callback that is called for each date of the calendar. If it returns true, then the date is unavailable. */ isDateUnavailable?: (date: DateTime) => boolean; + /** Callback that is called for each date of the calendar. If it returns true, then the date is weekend. */ + isWeekend?: (date: DateTime) => boolean; /** * Which timezone use to show values. Example: 'default', 'system', 'Europe/Amsterdam'. * @default The timezone of the `value` or `defaultValue` or `focusedValue` or `defaultFocusedValue`, 'default' otherwise. diff --git a/src/components/CalendarView/hooks/useCalendarState.ts b/src/components/CalendarView/hooks/useCalendarState.ts index a8b4f36..2c6fa3c 100644 --- a/src/components/CalendarView/hooks/useCalendarState.ts +++ b/src/components/CalendarView/hooks/useCalendarState.ts @@ -5,7 +5,7 @@ import type {DateTime} from '@gravity-ui/date-utils'; import {useControlledState} from '@gravity-ui/uikit'; import type {ValueBase} from '../../types'; -import {constrainValue, createPlaceholderValue, mergeDateTime} from '../../utils/dates'; +import {constrainValue, createPlaceholderValue, isWeekend, mergeDateTime} from '../../utils/dates'; import {useDefaultTimeZone} from '../../utils/useDefaultTimeZone'; import {calendarLayouts} from '../utils'; @@ -231,7 +231,13 @@ export function useCalendarState(props: CalendarStateOptions): CalendarState { return this.disabled || this.isInvalid(date); }, isWeekend(date: DateTime) { - return this.mode === 'days' && [0, 6].includes(date.day()); + if (this.mode !== 'days') { + return false; + } + if (typeof props.isWeekend === 'function') { + return props.isWeekend(date); + } + return isWeekend(date); }, isCurrent(date: DateTime) { return dateTime({timeZone}).isSame(date, this.mode); diff --git a/src/components/RangeCalendar/README.md b/src/components/RangeCalendar/README.md index 20b1fe5..1ad7fa3 100644 --- a/src/components/RangeCalendar/README.md +++ b/src/components/RangeCalendar/README.md @@ -215,6 +215,7 @@ LANDING_BLOCK--> | [focusedValue](#focused-value) | Set the default view of uncontrolled component which includes this value | `DateTime` `null` | | | id | The control's `id` attribute | `string` | | | isDateUnavailable | Callback that is called for each date of the calendar. If it returns true, then the date is unavailable. | `((date: DateTime) => boolean)` | | +| isWeekend | Callback that is called for each date of the calendar. If it returns true, then the date is weekend. | `((date: DateTime) => boolean)` | | | [maxValue](#min-and-max-value) | The maximum allowed date that a user may select. | `DateTime` | | | [minValue](#min-and-max-value) | The minimum allowed date that a user may select. | `DateTime` | | | [mode](#mode) | Defines the time interval that `RangeCalendar` should display in colttrolled way. | `days` `months` `quarters` `years` | | diff --git a/src/components/RangeCalendar/__stories__/RangeCalendar.stories.tsx b/src/components/RangeCalendar/__stories__/RangeCalendar.stories.tsx index 279fa17..2f60119 100644 --- a/src/components/RangeCalendar/__stories__/RangeCalendar.stories.tsx +++ b/src/components/RangeCalendar/__stories__/RangeCalendar.stories.tsx @@ -39,6 +39,7 @@ export const Default = { ? dateTimeParse(args.defaultFocusedValue, {timeZone}) : undefined, isDateUnavailable: getIsDateUnavailable(args.isDateUnavailable as unknown as string), + isWeekend: getIsWeekend(args.isWeekend as unknown as string), }; const [value, setValue] = React.useState | null>(null); @@ -100,6 +101,12 @@ export const Default = { type: 'radio', }, }, + isWeekend: { + options: ['default', 'none', 'Friday and Saturday'], + control: { + type: 'radio', + }, + }, timeZone: timeZoneControl, }, } satisfies Story; @@ -130,6 +137,18 @@ function getIsDateUnavailable(variant: string) { return undefined; } +function getIsWeekend(variant: string) { + if (variant === 'Friday and Saturday') { + return (date: DateTime) => [5, 6].includes(date.day()); + } + + if (variant === 'none') { + return () => false; + } + + return undefined; +} + export const Custom: Story = { ...Default, render: function Custom(args) { diff --git a/src/components/utils/dates.ts b/src/components/utils/dates.ts index 6092c52..6f2abf1 100644 --- a/src/components/utils/dates.ts +++ b/src/components/utils/dates.ts @@ -1,6 +1,10 @@ import {dateTime} from '@gravity-ui/date-utils'; import type {DateTime} from '@gravity-ui/date-utils'; +export function isWeekend(date: DateTime) { + return [0, 6].includes(date.day()); +} + export interface PlaceholderValueOptions { placeholderValue?: DateTime; timeZone?: string;