From 1be498acf00ec0793de99fbb64cb7f40850b64be Mon Sep 17 00:00:00 2001 From: anuraghazra Date: Mon, 20 May 2024 16:24:03 +0530 Subject: [PATCH 1/3] feat: add selected state for month/year cell --- .../DatePicker/CalendarStyles.web.tsx | 66 +++++++++++++------ .../components/DatePicker/DatePicker.web.tsx | 31 +++++++-- .../blade/src/components/DatePicker/types.ts | 2 + .../components/DatePicker/useDatesState.ts | 3 +- 4 files changed, 74 insertions(+), 28 deletions(-) diff --git a/packages/blade/src/components/DatePicker/CalendarStyles.web.tsx b/packages/blade/src/components/DatePicker/CalendarStyles.web.tsx index a110a5b4b1d..d841eaa862e 100644 --- a/packages/blade/src/components/DatePicker/CalendarStyles.web.tsx +++ b/packages/blade/src/components/DatePicker/CalendarStyles.web.tsx @@ -6,7 +6,7 @@ import { classes } from './constants'; import BaseBox from '~components/Box/BaseBox'; import getTextStyles from '~components/Typography/Text/getTextStyles'; import { size } from '~tokens/global'; -import { makeSpace } from '~utils'; +import { makeBorderSize, makeSpace } from '~utils'; import getIn from '~utils/lodashButBetter/get'; import { useIsMobile } from '~utils/useIsMobile'; @@ -46,17 +46,31 @@ const todayCell = { } as const; const selectedCell = { - background: { - default: 'interactive.background.primary.default', - hover: 'interactive.background.primary.highlighted', - }, - border: { - default: 'interactive.border.primary.default', - hover: 'interactive.border.primary.faded', + day: { + background: { + default: 'interactive.background.primary.default', + hover: 'interactive.background.primary.highlighted', + }, + border: { + default: 'interactive.border.primary.default', + hover: 'interactive.border.primary.faded', + }, + text: { + default: 'interactive.text.onPrimary.normal', + hover: 'interactive.text.onPrimary.normal', + }, }, - text: { - default: 'interactive.text.onPrimary.normal', - hover: 'interactive.text.onPrimary.normal', + month: { + background: { + default: 'transparent', + hover: 'interactive.background.primary.faded', + }, + border: { + default: 'interactive.border.primary.default', + }, + text: { + default: 'interactive.text.primary.normal', + }, }, } as const; @@ -186,21 +200,33 @@ const CalendarStyles = styled(BaseBox)<{ pickerType?: PickerType }>(({ theme, pi const selected = { '&[data-selected]': { - backgroundColor: getIn(theme.colors, selectedCell.background.default), - outlineColor: getIn(theme.colors, selectedCell.border.default), - color: getIn(theme.colors, selectedCell.text.default), + '&[data-celltype="day"]': { + backgroundColor: getIn(theme.colors, selectedCell.day.background.default), + outlineColor: getIn(theme.colors, selectedCell.day.border.default), + color: getIn(theme.colors, selectedCell.day.text.default), + ':hover': { + backgroundColor: getIn(theme.colors, selectedCell.day.background.hover), + color: getIn(theme.colors, selectedCell.day.text.hover), + }, + }, + '&[data-celltype="month"], &[data-celltype="year"]': { + backgroundColor: 'transparent', + outlineStyle: 'solid', + outlineWidth: makeBorderSize(theme.border.width.thin), + outlineOffset: makeSpace(-theme.border.width.thin), + outlineColor: getIn(theme.colors, selectedCell.month.border.default), + color: getIn(theme.colors, selectedCell.month.text.default), + ':hover': { + backgroundColor: getIn(theme.colors, selectedCell.month.background.hover), + }, + }, ':before': { - backgroundColor: getIn(theme.colors, selectedCell.text.default), + backgroundColor: getIn(theme.colors, selectedCell.day.text.default), }, }, '&[data-selected] [data-date]': { background: 'none !important', }, - '&[data-selected]:hover': { - backgroundColor: getIn(theme.colors, selectedCell.background.hover), - outlineColor: 'red', - color: getIn(theme.colors, selectedCell.text.hover), - }, } as const; const ranges = { diff --git a/packages/blade/src/components/DatePicker/DatePicker.web.tsx b/packages/blade/src/components/DatePicker/DatePicker.web.tsx index 4ac1b7590f4..ab6c1f6c3c0 100644 --- a/packages/blade/src/components/DatePicker/DatePicker.web.tsx +++ b/packages/blade/src/components/DatePicker/DatePicker.web.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { FloatingFocusManager, FloatingPortal } from '@floating-ui/react'; import { Calendar } from './Calendar'; import { PresetSideBar } from './QuickSelection/PresetSideBar'; -import type { DatePickerProps, DateSelectionType } from './types'; +import type { DatePickerProps, DateSelectionType, PickerType } from './types'; import { useDatesState } from './useDatesState'; import { DatePickerInput } from './DateInput'; import { usePopup } from './usePopup'; @@ -45,6 +45,9 @@ const DatePicker = ({ successText, validationState, size, + defaultPicker = 'day', + picker, + onPickerChange, ...props }: DatePickerProps): React.ReactElement => { const _selectionType = selectionType ?? 'single'; @@ -54,6 +57,15 @@ const DatePicker = ({ const [_, forceRerenderBottomSheet] = React.useReducer((x: number) => x + 1, 0); const [selectedPreset, setSelectedPreset] = React.useState(null); + + const [_picker, setPicker] = useControllableState({ + defaultValue: defaultPicker, + value: picker, + onChange: (picker) => { + onPickerChange?.(picker); + }, + }); + const { onDateChange, onRootMouseLeave, @@ -63,7 +75,7 @@ const DatePicker = ({ controlledValue, setControlledValue, } = useDatesState({ - level: 'day', + level: _picker, type: isSingle ? 'default' : 'range', allowDeselect: false, allowSingleDateInRange, @@ -163,10 +175,14 @@ const DatePicker = ({ __onDayClick={(_event, date) => { onDateChange(date); }} + getMonthControlProps={(date) => { + return getControlProps(date); + }} + getYearControlProps={(date) => { + return getControlProps(date); + }} getDayProps={(date) => { - return { - ...getControlProps(date), - }; + return getControlProps(date); }} onMonthSelect={(date) => { props?.onMonthSelect?.(date); @@ -184,8 +200,9 @@ const DatePicker = ({ props?.onPrevious?.(date); forceRerenderBottomSheet(); }} - onPickerChange={(date) => { - props?.onPickerChange?.(date); + picker={_picker} + onPickerChange={(picker) => { + setPicker(() => picker); forceRerenderBottomSheet(); }} /> diff --git a/packages/blade/src/components/DatePicker/types.ts b/packages/blade/src/components/DatePicker/types.ts index b421882b9d0..197db003362 100644 --- a/packages/blade/src/components/DatePicker/types.ts +++ b/packages/blade/src/components/DatePicker/types.ts @@ -29,6 +29,8 @@ type CalendarProps = Pick< | '__onDayMouseEnter' | '__onDayClick' | 'getDayProps' + | 'getYearControlProps' + | 'getMonthControlProps' | 'onMouseLeave' | 'value' | 'defaultValue' diff --git a/packages/blade/src/components/DatePicker/useDatesState.ts b/packages/blade/src/components/DatePicker/useDatesState.ts index 734a0200f47..78680466b47 100644 --- a/packages/blade/src/components/DatePicker/useDatesState.ts +++ b/packages/blade/src/components/DatePicker/useDatesState.ts @@ -142,11 +142,12 @@ export function useDatesState({ firstInRange: isFirstInRange(date), lastInRange: isLastInRange(date), 'data-autofocus': (!!_value[0] && dayjs(_value[0]).isSame(date, level)) || undefined, + 'data-celltype': level, }; } const selected = dayjs(_value).isSame(date, level); - return { selected, 'data-autofocus': selected || undefined }; + return { selected, 'data-autofocus': selected || undefined, 'data-celltype': level }; }; const onHoveredDateChange = type === 'range' && pickedDate ? setHoveredDate : () => {}; From 2d4e8cbb34653ce7d9e9b294a01d33b79c1dfab5 Mon Sep 17 00:00:00 2001 From: anuraghazra Date: Mon, 20 May 2024 16:30:45 +0530 Subject: [PATCH 2/3] chore: simplify gradient logic --- .../components/DatePicker/Calendar.web.tsx | 6 ----- .../DatePicker/CalendarStyles.web.tsx | 25 ++++--------------- .../components/DatePicker/useDatesState.ts | 8 +++++- 3 files changed, 12 insertions(+), 27 deletions(-) diff --git a/packages/blade/src/components/DatePicker/Calendar.web.tsx b/packages/blade/src/components/DatePicker/Calendar.web.tsx index 0882877c17a..1931e5008f4 100644 --- a/packages/blade/src/components/DatePicker/Calendar.web.tsx +++ b/packages/blade/src/components/DatePicker/Calendar.web.tsx @@ -12,7 +12,6 @@ import { levelToPicker, pickerToLevel } from './utils'; import { classes } from './constants'; import { useControllableState } from '~utils/useControllable'; import { useIsMobile } from '~utils/useIsMobile'; -import BaseBox from '~components/Box/BaseBox'; import { throwBladeError } from '~utils/logger'; const Calendar = ({ @@ -152,11 +151,6 @@ const Calendar = ({ firstDayOfWeek={firstDayOfWeek} // @ts-expect-error unable to narrow props based on `type` allowSingleDateInRange={allowSingleDateInRange} - renderDay={(date) => { - return ( - {date.getDate()} - ); - }} classNames={{ levelsGroup: classes.levelsGroup, day: classes.dayCell, diff --git a/packages/blade/src/components/DatePicker/CalendarStyles.web.tsx b/packages/blade/src/components/DatePicker/CalendarStyles.web.tsx index d841eaa862e..34c97c45974 100644 --- a/packages/blade/src/components/DatePicker/CalendarStyles.web.tsx +++ b/packages/blade/src/components/DatePicker/CalendarStyles.web.tsx @@ -112,15 +112,6 @@ const CalendarGradientStyles = styled(BaseBox)<{ date: Date; isRange: boolean }> const calendar2FirstGradient = `${cal2.month()}-${cal2FirstDay.date()}`; const calendar2LastGradient = `${cal2.month()}-${cal2LastDay.date()}`; - const gradientCell = { - pointerEvents: 'none', - position: 'relative', - width: 'inherit', - height: 'inherit', - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - } as const; const gradientBefore = { content: '""', position: 'absolute', @@ -128,6 +119,7 @@ const CalendarGradientStyles = styled(BaseBox)<{ date: Date; isRange: boolean }> top: 0, bottom: 0, right: 0, + pointerEvents: 'none', } as const; const rightGradient = { ...gradientBefore, @@ -148,21 +140,17 @@ const CalendarGradientStyles = styled(BaseBox)<{ date: Date; isRange: boolean }> return { [`.${classes.dayCell}`]: { - [`&[data-in-range]:not(&[data-first-in-range]) [data-date="${calendar1FirstGradient}"]`]: { - ...gradientCell, + [`&[data-in-range]:not(&[data-first-in-range])[data-date="${calendar1FirstGradient}"]`]: { '&:before': cal1IsFirstDayStartOfTheWeek ? {} : rightGradient, }, - [`&[data-in-range]:not(&[data-last-in-range]) [data-date="${calendar1LastGradient}"]`]: { - ...gradientCell, + [`&[data-in-range]:not(&[data-last-in-range])[data-date="${calendar1LastGradient}"]`]: { '&:before': cal1IsLastDayEndOfTheWeek ? {} : leftGradient, }, // Second calendar column - [`&[data-in-range]:not(&[data-first-in-range]) [data-date="${calendar2FirstGradient}"]`]: { - ...gradientCell, + [`&[data-in-range]:not(&[data-first-in-range])[data-date="${calendar2FirstGradient}"]`]: { '&:before': cal2IsFirstDayStartOfTheWeek ? {} : rightGradient, }, - [`&[data-in-range]:not(&[data-last-in-range]) [data-date="${calendar2LastGradient}"]`]: { - ...gradientCell, + [`&[data-in-range]:not(&[data-last-in-range])[data-date="${calendar2LastGradient}"]`]: { '&:before': cal2IsLastDayEndOfTheWeek ? {} : leftGradient, }, }, @@ -224,9 +212,6 @@ const CalendarStyles = styled(BaseBox)<{ pickerType?: PickerType }>(({ theme, pi backgroundColor: getIn(theme.colors, selectedCell.day.text.default), }, }, - '&[data-selected] [data-date]': { - background: 'none !important', - }, } as const; const ranges = { diff --git a/packages/blade/src/components/DatePicker/useDatesState.ts b/packages/blade/src/components/DatePicker/useDatesState.ts index 78680466b47..146de855d97 100644 --- a/packages/blade/src/components/DatePicker/useDatesState.ts +++ b/packages/blade/src/components/DatePicker/useDatesState.ts @@ -143,11 +143,17 @@ export function useDatesState({ lastInRange: isLastInRange(date), 'data-autofocus': (!!_value[0] && dayjs(_value[0]).isSame(date, level)) || undefined, 'data-celltype': level, + 'data-date': `${date.getMonth()}-${date.getDate()}`, }; } const selected = dayjs(_value).isSame(date, level); - return { selected, 'data-autofocus': selected || undefined, 'data-celltype': level }; + return { + selected, + 'data-autofocus': selected || undefined, + 'data-celltype': level, + 'data-date': `${date.getMonth()}-${date.getDate()}`, + }; }; const onHoveredDateChange = type === 'range' && pickedDate ? setHoveredDate : () => {}; From 31e087fba71c808d70f27e7d3e5ee932df7d3668 Mon Sep 17 00:00:00 2001 From: anuraghazra Date: Mon, 20 May 2024 16:32:41 +0530 Subject: [PATCH 3/3] chore: fix footer --- .../src/components/DatePicker/CalendarFooter.web.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/blade/src/components/DatePicker/CalendarFooter.web.tsx b/packages/blade/src/components/DatePicker/CalendarFooter.web.tsx index 26c3e6f6e26..3891da96704 100644 --- a/packages/blade/src/components/DatePicker/CalendarFooter.web.tsx +++ b/packages/blade/src/components/DatePicker/CalendarFooter.web.tsx @@ -16,7 +16,13 @@ const CalendarFooter = ({ return ( {isMobile ? null : } - +