Skip to content

Commit

Permalink
[datetime2] feat: DateInput3 using react-day-picker v8 (#6370)
Browse files Browse the repository at this point in the history
  • Loading branch information
adidahiya committed Sep 7, 2023
1 parent bdeff6e commit 5f40f68
Show file tree
Hide file tree
Showing 14 changed files with 1,904 additions and 32 deletions.
8 changes: 4 additions & 4 deletions packages/datetime/src/common/dateFormatProps.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,18 @@ export interface DateFormatProps {

/**
* Function to render a JavaScript `Date` to a string.
* Optional `locale` argument comes directly from the prop on this component:
* Optional `localeCode` argument comes directly from the prop on this component:
* if the prop is defined, then the argument will be too.
*/
formatDate(date: Date, locale?: string): string;
formatDate(date: Date, localeCode?: string): string;

/**
* Function to deserialize user input text to a JavaScript `Date` object.
* Return `false` if the string is an invalid date.
* Return `null` to represent the absence of a date.
* Optional `locale` argument comes directly from the prop on this component.
* Optional `localeCode` argument comes directly from the prop on this component.
*/
parseDate(str: string, locale?: string): Date | false | null;
parseDate(str: string, localeCode?: string): Date | false | null;
}

export function getFormattedDateString(
Expand Down
14 changes: 14 additions & 0 deletions packages/datetime/src/common/dateUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,3 +239,17 @@ export function get24HourFrom12Hour(hour: number, isPm: boolean): number {
export function isToday(date: Date): boolean {
return isSameDay(date, new Date());
}

export function hasMonthChanged(prevDate: Date | null, nextDate: Date | null) {
return (prevDate == null) !== (nextDate == null) || nextDate?.getMonth() !== prevDate?.getMonth();
}

export function hasTimeChanged(prevDate: Date | null, nextDate: Date | null) {
return (
(prevDate == null) !== (nextDate == null) ||
nextDate?.getHours() !== prevDate?.getHours() ||
nextDate?.getMinutes() !== prevDate?.getMinutes() ||
nextDate?.getSeconds() !== prevDate?.getSeconds() ||
nextDate?.getMilliseconds() !== prevDate?.getMilliseconds()
);
}
16 changes: 1 addition & 15 deletions packages/datetime/src/components/date-input/dateInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import {

import { Classes, DateFormatProps, DatePickerBaseProps } from "../../common";
import type { DatetimePopoverProps } from "../../common/datetimePopoverProps";
import { isDateValid, isDayInRange } from "../../common/dateUtils";
import { hasMonthChanged, hasTimeChanged, isDateValid, isDayInRange } from "../../common/dateUtils";
import * as Errors from "../../common/errors";
import { getCurrentTimezone } from "../../common/getTimezone";
import { UTC_TIME } from "../../common/timezoneItems";
Expand Down Expand Up @@ -677,17 +677,3 @@ function getKeyboardFocusableElements(popoverContentRef: React.MutableRefObject<
elements.shift();
return elements;
}

function hasMonthChanged(prevDate: Date | null, nextDate: Date | null) {
return (prevDate == null) !== (nextDate == null) || nextDate?.getMonth() !== prevDate?.getMonth();
}

function hasTimeChanged(prevDate: Date | null, nextDate: Date | null) {
return (
(prevDate == null) !== (nextDate == null) ||
nextDate?.getHours() !== prevDate?.getHours() ||
nextDate?.getMinutes() !== prevDate?.getMinutes() ||
nextDate?.getSeconds() !== prevDate?.getSeconds() ||
nextDate?.getMilliseconds() !== prevDate?.getMilliseconds()
);
}
121 changes: 121 additions & 0 deletions packages/datetime2/src/components/date-input3/date-input3.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
---
tag: new
---

@# DateInput3

<div class="@ns-callout @ns-intent-primary @ns-icon-info-sign @ns-callout-has-body-content">
<h5 class="@ns-heading">

Migrating from [DateInput](#datetime/date-input)?

</h5>

__DateInput3__ is a replacement for DateInput and will replace it in Blueprint v6.
You are encouraged to use this new API now to ease the transition to the next major version of Blueprint.
See the [react-day-picker v8 migration guide](https://github.com/palantir/blueprint/wiki/react-day-picker-8-migration)
on the wiki.

</div>

__DateInput3__ has the same functionality as [DateInput](#datetime/date-input) but uses
[react-day-picker v8](https://react-day-picker.js.org/) instead of [v7](https://react-day-picker-v7.netlify.app/)
to render its calendar. It renders an interactive [__InputGroup__](#core/components/input-group)
which, when focussed, displays a [__DatePicker3__](#datetime2/date-picker3) inside a
[__Popover__](#core/components/popover). It optionally renders a [__TimezoneSelect__](#datetime/timezone-select)
on the right side of the InputGroup which allows users to change the timezone of the selected date.

@reactExample DateInput3Example

@## Usage

__DateInput3__ supports both controlled and uncontrolled usage. You can control
the selected date by setting the `value` prop, or use the component in
uncontrolled mode and specify an initial date by setting `defaultValue`.
Use the `onChange` prop callback to listen for changes to the selected day and
the `onError` prop to react to invalid dates entered in the text input.

This component uses ISO strings to represent timestamp values in the `value` & `defaultValue` props
and the `onChange` callback.

@## Props interface

In addition to top-level __DateInput3__ props, you may forward some props to `<DayPicker mode="single">` to customize
react-day-picker's behavior via `dayPickerProps` (the full list is
[documented here](https://react-day-picker.js.org/api/interfaces/DayPickerSingleProps)).

Shortcuts and modifiers are also configurable via the same API as [__DatePicker3__](#datetime2/date-picker3); see those
docs for more info.

@interface DateInput3Props

@## Date formatting

__DateInput3__ requires two important props for parsing and formatting dates. These are essentially the plumbing
between the text input and __DatePicker3__.

- `formatDate(date: Date, localeCode?: string)` receives the current `Date` and returns a string representation of it.
The result of this function becomes the input value when it is not being edited.
- `parseDate(str: string, localeCode?: string)` receives text inputted by the user and converts it to a `Date` object.
The returned `Date` becomes the next value of the component.

The optional `locale` argument to these functions is the value of the `locale` prop set on the component.

Note that we still use JS `Date` here instead of ISO strings &mdash; this makes it easy to delegate to
third party libraries like __date-fns__.

A simple implementation using built-in browser methods could look like this:

```tsx
import { DateInput3 } from "@blueprintjs/datetime2";
import { useCallback, useState } from "react";

function Example() {
const [dateValue, setDateValue] = useState<string>(null);
const handleChange = useCallback(setDateValue, []);
const formatDate = useCallback((date: Date) => date.toLocaleString(), []);
const parseDate = useCallback((str: string) => new Date(str), []);

return (
<DateInput3
formatDate={formatDate}
onChange={handleChange}
parseDate={parseDate}
placeholder="M/D/YYYY"
value={dateValue}
/>
);
}
```

An implementation using __date-fns__ could look like this:

```tsx
import { DateInput3 } from "@blueprintjs/datetime2";
import { format, parse } from "date-fns";
import { useCallback, useState } from "react";

const today = new Date();
const dateFnsFormat = "yyyy-MM-dd HH:mm:ss";

function Example() {
const [dateValue, setDateValue] = useState<string>(null);
const handleChange = useCallback(setDateValue, []);
const formatDate = useCallback((date: Date) => format(date, dateFnsFormat), []);
const parseDate = useCallback((str: string) => parse(str, dateFnsFormat, today), []);

return (
<DateInput3
formatDate={formatDate}
onChange={handleChange}
parseDate={parseDate}
placeholder={dateFnsFormat}
value={dateValue}
/>
);
}
```

@## Localization

See the [__DatePicker3__ localization docs](#datetime2/date-picker3.localization).
Loading

1 comment on commit 5f40f68

@adidahiya
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[datetime2] feat: DateInput3 using react-day-picker v8 (#6370)

Build artifact links for this commit: documentation | landing | table | demo

This is an automated comment from the deploy-preview CircleCI job.

Please sign in to comment.