Skip to content

Commit

Permalink
chore: downgrade mantine to v6 (#2202)
Browse files Browse the repository at this point in the history
* chore: downgrade mantine to v6

* chore: update

* chore: add data-hidden

* chore: separate styled props

* chore: fix interaction test

* chore: update

* Create swift-elephants-reflect.md

* chore: update

* chore: update

* chore: update
  • Loading branch information
anuraghazra authored May 28, 2024
1 parent 3269642 commit d9bb522
Show file tree
Hide file tree
Showing 12 changed files with 337 additions and 104 deletions.
5 changes: 5 additions & 0 deletions .changeset/swift-elephants-reflect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@razorpay/blade": minor
---

refactor(blade): downgrade mantine to v6
6 changes: 3 additions & 3 deletions packages/blade/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,9 @@
"@table-library/react-table-library": "4.1.7",
"tinycolor2": "1.6.0",
"universal-base64": "2.1.0",
"@mantine/core": "7.8.1",
"@mantine/dates": "7.8.1",
"@mantine/hooks": "7.8.1",
"@mantine/core": "6.0.21",
"@mantine/dates": "6.0.21",
"@mantine/hooks": "6.0.21",
"dayjs": "1.11.10"
},
"devDependencies": {
Expand Down
14 changes: 9 additions & 5 deletions packages/blade/src/components/DatePicker/Calendar.web.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
import dayjs from 'dayjs';
import React from 'react';
import type { CalendarLevel } from '@mantine/dates';
import { shiftTimezone, useDatesContext, DatePicker } from '@mantine/dates';
import { useDatesContext, DatePicker } from '@mantine/dates';
import type { CalendarProps, DateSelectionType, PickerType, DateValue } from './types';
import { CalendarHeader } from './CalendarHeader';
import { CalendarGradientStyles, CalendarStyles } from './CalendarStyles';
import { useUncontrolledDates } from './useControlledDates';
import { levelToPicker, pickerToLevel, classes } from './constants';
import { shiftTimezone } from './shiftTimezone';
import { useControllableState } from '~utils/useControllable';
import { useIsMobile } from '~utils/useIsMobile';
import { throwBladeError } from '~utils/logger';
Expand Down Expand Up @@ -61,7 +62,7 @@ const Calendar = <Type extends DateSelectionType>({

const dateContext = useDatesContext();
const isMobile = useIsMobile();
const currentDate = _date ?? shiftTimezone('add', new Date(), dateContext.getTimezone());
const currentDate = _date ?? shiftTimezone('add', new Date());
const numberOfColumns = isMobile || !isRange ? 1 : 2;
const columnsToScroll = numberOfColumns;

Expand Down Expand Up @@ -140,10 +141,13 @@ const Calendar = <Type extends DateSelectionType>({
// @ts-expect-error unable to narrow props based on `type`
allowSingleDateInRange={allowSingleDateInRange}
classNames={{
levelsGroup: classes.levelsGroup,
monthLevelGroup: classes.levelsGroup,
yearLevelGroup: classes.levelsGroup,
decadeLevelGroup: classes.levelsGroup,
day: classes.dayCell,
monthsListControl: classes.monthsListControl,
yearsListControl: classes.yearsListControl,
monthsListCell: classes.yearsListControl,
yearsListCell: classes.monthsListControl,
monthCell: classes.dayCell,
calendarHeader: classes.calendarHeader,
monthRow: classes.row,
yearsListRow: classes.row,
Expand Down
63 changes: 36 additions & 27 deletions packages/blade/src/components/DatePicker/CalendarStyles.web.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -258,9 +258,12 @@ const CalendarStyles = styled(BaseBox)<{ pickerType?: PickerType }>(({ theme, pi
gap: makeSpace(theme.spacing[8]),
table: {
borderCollapse: 'collapse',
width: '100%',
width: !isDayPicker || isMobile ? '100%' : undefined,
},
'> div': {
margin: 0,
width: isMobile || !isDayPicker ? '100%' : undefined,
},
'> div': { width: isMobile || !isDayPicker ? '100%' : undefined },
th: {
flex: 1,
},
Expand Down Expand Up @@ -289,33 +292,39 @@ const CalendarStyles = styled(BaseBox)<{ pickerType?: PickerType }>(({ theme, pi
paddingBottom: makeSpace(theme.spacing[4]),
},
[`.${classes.dayCell}`]: {
cursor: 'pointer',
width: isMobile || !isDayPicker ? '100%' : makeSpace(cell.size[device]),
height: isDayPicker && isMobile ? undefined : makeSpace(cell.size[device]),
aspectRatio: isDayPicker && isMobile ? '1 / 1' : undefined,
borderRadius: theme.border.radius.medium,
backgroundColor: getIn(theme.colors, cell.background.default),
border: 'none',
...getTextStyles({ theme, variant: 'body', size: 'medium', weight: 'regular' }),
button: {
all: 'unset',
cursor: 'pointer',
width: isMobile || !isDayPicker ? '100%' : makeSpace(cell.size[device]),
height: isDayPicker && isMobile ? '100%' : makeSpace(cell.size[device]),
aspectRatio: isDayPicker && isMobile ? '1 / 1' : undefined,
borderRadius: theme.border.radius.medium,
backgroundColor: getIn(theme.colors, cell.background.default),
border: 'none',
...getTextStyles({ theme, variant: 'body', size: 'medium', weight: 'regular' }),

'&:hover': {
backgroundColor: getIn(theme.colors, cell.background.hover),
},
'&:focus-visible': getFocusRingStyles({ theme, isImportant: true }),
'&[data-disabled]': {
color: getIn(theme.colors, cell.text.disabled),
backgroundColor: getIn(theme.colors, cell.background.disabled),
cursor: 'not-allowed',
},
'&[data-outside]': {
color: theme.colors.interactive.text.gray.muted,
},
'&[data-outside]:hover': {
color: getIn(theme.colors, cell.text.default),
'&:hover': {
backgroundColor: getIn(theme.colors, cell.background.hover),
},
'&:focus-visible': getFocusRingStyles({ theme, isImportant: true }),
'&[data-disabled]': {
color: getIn(theme.colors, cell.text.disabled),
backgroundColor: getIn(theme.colors, cell.background.disabled),
cursor: 'not-allowed',
},
'&[data-hidden]': {
display: 'none',
},
'&[data-outside]': {
color: theme.colors.interactive.text.gray.muted,
},
'&[data-outside]:hover': {
color: getIn(theme.colors, cell.text.default),
},
...ranges,
...today,
...selected,
},
...ranges,
...today,
...selected,
},
};
});
Expand Down
3 changes: 2 additions & 1 deletion packages/blade/src/components/DatePicker/DateInput.web.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */
/* eslint-disable @typescript-eslint/no-explicit-any */
import React from 'react';
import { useDatesContext, getFormattedDate } from '@mantine/dates';
import { useDatesContext } from '@mantine/dates';
import type { DatePickerInputProps } from './types';
import { getFormattedDate } from './utils';
import BaseBox from '~components/Box/BaseBox';
import { ArrowRightIcon, CalendarIcon } from '~components/Icons';
import type { BaseInputProps } from '~components/Input/BaseInput';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Box } from '~components/Box';
import StoryPageWrapper from '~utils/storybook/StoryPageWrapper';
import { Sandbox } from '~utils/storybook/Sandbox';
import { Code, Text } from '~components/Typography';
import { getStyledPropsArgTypes } from '~components/Box/BaseBox/storybookArgTypes';

const propsCategory = {
BASE_PROPS: 'DatePicker Props',
Expand All @@ -30,6 +31,7 @@ export default {
component: DatePickerComponent,
tags: ['autodocs'],
argTypes: {
...getStyledPropsArgTypes(),
value: baseProp,
isOpen: baseProp,
onChange: baseProp,
Expand Down
12 changes: 6 additions & 6 deletions packages/blade/src/components/DatePicker/DatePicker.web.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable @typescript-eslint/no-explicit-any */
import { DatesProvider, shiftTimezone, useDatesContext } from '@mantine/dates';
import { DatesProvider } from '@mantine/dates';
import React from 'react';
import { FloatingFocusManager, FloatingPortal } from '@floating-ui/react';
import { useI18nContext } from '@razorpay/i18nify-react';
import { HeadlessMantineProvider } from '@mantine/core';
import { MantineProvider } from '@mantine/core';
import dayjs from 'dayjs';
import type { DatesRangeValue, DatePickerProps, DateSelectionType, PickerType } from './types';
import { Calendar } from './Calendar';
Expand All @@ -16,6 +16,7 @@ import { DatePickerInput } from './DateInput';
import { usePopup } from './usePopup';
import { CalendarFooter } from './CalendarFooter';
import { convertIntlToDayjsLocale, loadScript } from './utils';
import { shiftTimezone } from './shiftTimezone';
import BaseBox from '~components/Box/BaseBox';
import { useControllableState } from '~utils/useControllable';
import { useTheme } from '~utils';
Expand Down Expand Up @@ -64,7 +65,6 @@ const DatePicker = <Type extends DateSelectionType = 'single'>({
const { i18nState } = useI18nContext();
const _selectionType = selectionType ?? 'single';
const { theme } = useTheme();
const ctx = useDatesContext();
const isSingle = _selectionType === 'single';
const [_, forceRerender] = React.useReducer((x: number) => x + 1, 0);
const [selectedPreset, setSelectedPreset] = React.useState<DatesRangeValue | null>(null);
Expand Down Expand Up @@ -106,7 +106,7 @@ const DatePicker = <Type extends DateSelectionType = 'single'>({
onChange: (isOpen) => onOpenChange?.({ isOpen }),
});

const currentDate = shiftTimezone('add', new Date(), ctx.getTimezone());
const currentDate = shiftTimezone('add', new Date());
const [oldValue, setOldValue] = React.useState<DatesRangeValue | null>(controlledValue);

const close = React.useCallback(() => {
Expand Down Expand Up @@ -245,7 +245,7 @@ const DatePicker = <Type extends DateSelectionType = 'single'>({
}, [i18nState?.locale]);

return (
<HeadlessMantineProvider>
<MantineProvider>
<DatesProvider settings={dateProviderValue}>
<BaseBox
width="100%"
Expand Down Expand Up @@ -335,7 +335,7 @@ const DatePicker = <Type extends DateSelectionType = 'single'>({
)}
</BaseBox>
</DatesProvider>
</HeadlessMantineProvider>
</MantineProvider>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ DatePickerSingleSelectControlled.play = async () => {
// assert inputs value
await expect(input).toHaveValue(dayjs().add(5, 'day').format('DD/MM/YYYY'));
// select another date
const dateToSelect = dayjs().add(6, 'day');
const dateToSelect = dayjs().add(2, 'day');
const date = getByRole('button', { name: dateToSelect.format('DD MMMM YYYY') });
await userEvent.click(date);
// press apply button
Expand Down
49 changes: 49 additions & 0 deletions packages/blade/src/components/DatePicker/shiftTimezone.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import dayjs from 'dayjs';
import timezonePlugin from 'dayjs/plugin/timezone';
import utcPlugin from 'dayjs/plugin/utc';
import type { DateValue, DatesRangeValue } from './types';

dayjs.extend(utcPlugin);
dayjs.extend(timezonePlugin);

function getTimezoneOffset(date: Date, timezone?: string): number {
if (timezone) {
return dayjs(date).tz(timezone).utcOffset() + date.getTimezoneOffset();
}
return 0;
}

type TimeShiftDirection = 'add' | 'remove';

const updateTimezone = (
date: DateValue | undefined,
timezone?: string,
direction?: TimeShiftDirection,
): DateValue => {
if (!date) {
return null;
}
if (!timezone) {
return date;
}
let offset = getTimezoneOffset(date, timezone);
if (direction === 'remove') {
offset *= -1;
}
return dayjs(date).add(offset, 'minutes').toDate();
};

export function shiftTimezone<T extends DateValue | Date[] | DatesRangeValue | undefined>(
direction: TimeShiftDirection,
date: T,
timezone?: string,
disabled?: boolean,
): T {
if (disabled || !date) {
return date;
}
if (Array.isArray(date)) {
return date.map((d) => updateTimezone(d, timezone, direction)) as T;
}
return updateTimezone(date, timezone, direction) as T;
}
10 changes: 4 additions & 6 deletions packages/blade/src/components/DatePicker/useControlledDates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { useRef } from 'react';
import { useUncontrolled } from '@mantine/hooks';
import type { DatePickerType, DatePickerValue } from '@mantine/dates';
import { shiftTimezone, useDatesContext } from '@mantine/dates';
import { shiftTimezone } from './shiftTimezone';
import { throwBladeError } from '~utils/logger';

interface UseUncontrolledDates<Type extends DatePickerType = 'default'> {
Expand All @@ -23,16 +23,14 @@ function useUncontrolledDates<Type extends DatePickerType = 'default'>({
value,
defaultValue,
onChange,
applyTimezone = true,
}: UseUncontrolledDates<Type>) {
const storedType = useRef<Type>(type);
const ctx = useDatesContext();
const [_value, _setValue, controlled] = useUncontrolled<any>({
value: shiftTimezone('add', value, ctx.getTimezone(), !applyTimezone),
defaultValue: shiftTimezone('add', defaultValue, ctx.getTimezone(), !applyTimezone),
value: shiftTimezone('add', value),
defaultValue: shiftTimezone('add', defaultValue),
finalValue: getEmptyValue(type),
onChange: (newDate) => {
onChange?.(shiftTimezone('remove', newDate, ctx.getTimezone(), !applyTimezone));
onChange?.(shiftTimezone('remove', newDate));
},
});

Expand Down
47 changes: 46 additions & 1 deletion packages/blade/src/components/DatePicker/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
/* eslint-disable @typescript-eslint/explicit-function-return-type */
import type { DatePickerType, DatePickerValue } from '@mantine/dates';
import dayjs from 'dayjs';

const dayjs_locales = [
'af',
'ar',
Expand Down Expand Up @@ -166,4 +171,44 @@ function loadScript(src: string, callback?: () => void): void {
document.head.appendChild(localeScript);
}

export { convertIntlToDayjsLocale, loadScript };
interface DateFormatterInput {
type: DatePickerType;
date: DatePickerValue<DatePickerType>;
locale: string;
format: string;
labelSeparator: string;
}

type DateFormatter = (input: DateFormatterInput) => string;

function defaultDateFormatter({ type, date, locale, format, labelSeparator }: DateFormatterInput) {
const formatDate = (value: Date) => dayjs(value).locale(locale).format(format);

if (type === 'default') {
return date === null ? '' : formatDate(date as Date);
}

if (type === 'range' && Array.isArray(date)) {
if (date[0] && date[1]) {
return `${formatDate(date[0])} ${labelSeparator} ${formatDate(date[1])}`;
}

if (date[0]) {
return `${formatDate(date[0])} ${labelSeparator} `;
}

return '';
}

return '';
}

interface GetFormattedDateInput extends DateFormatterInput {
formatter?: DateFormatter;
}

function getFormattedDate({ formatter, ...others }: GetFormattedDateInput) {
return (formatter || defaultDateFormatter)(others);
}

export { convertIntlToDayjsLocale, loadScript, getFormattedDate };
Loading

0 comments on commit d9bb522

Please sign in to comment.