npm package: @lightspeed/cirrus-datepicker
Description: Cirrus Datepicker Component
Author: Lightspeed
Latest version: 1.3.2

# Cirrus Date Picker

For all things Date and Time.

See [story](https://github.com/lightspeedretail/cirrus/blob/master/packages/cirrus-datepicker/story.tsx) on how to use.

## TODO

- [ ] RTL support
- [ ] Support different start of week
- [ ] DateRange with only 1 month calendar
- [ ] An actual TimePicker component

## Installation

First, make sure you have been through the [install steps](https://github.com/lightspeed/flame#installing) steps required to add Flame in your application. Although it's not required to have Flame installed to use Logo, you will need to install its peer dependencies.

If using [Yarn](https://yarnpkg.com/):

```sh
yarn add @lightspeed/cirrus-datepicker
```

Or using [npm](https://www.npmjs.com/):

```sh
npm i -S @lightspeed/cirrus-datepicker
```

## Usage

### Components

#### `<DateRange>`

| Prop            | Type                                                     | Description                                                                                                                                                                                                   |
| --------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `startDate`     | `Date`                                                   | Javascript Date representing the initially selected start date                                                                                                                                                |
| `endDate`       | `Date`                                                   | Javascript Date representing the initially selected end date                                                                                                                                                  |
| `isDateBlocked` | `(Date) => boolean`                                      | Callback function used for determining whether or not a date should be blocked                                                                                                                                |
| `onSubmit`      | `({ startDate:Date, endDate:Date }) => void`             | Callback function when clicking on the "apply" button. The selected start and end date will be sent back if all is valid                                                                                      |
| `presetDates`   | `Array<{label: string, startDate: Date, endDate: Date}>` | List of preset dates. By adding this, a small menu will be created within the calendar to automatically select the start and end date. You may add an empty object, which will automatically create a divider |
| `dateFormat`    | `String`                                                 | A Luxon compatible string format                                                                                                                                                                              |
| `translations`  | `Object`                                                 | A key value pairing for forwarding translated messages. See the Translation section for further details.                                                                                                      |
| `locale`        | `String`                                                 | Valid language locale, e.g: 'en-fr', 'en-us'. Changing this parameter will adjust some dateFormat outputs to match the target locale                                                                          |

##### Translations

When adding translations to the `DateRange`, it is important to use the right translation key for the component to pick up the string.

Here is a sample translation object:

```
{
  START_DATE_NOT_DEFINED: 'The start date is not defined',
  END_DATE_NOT_DEFINED: 'The end date is not defined',
  START_DATE_FORMAT_NOT_VALID: 'The start date is not valid',
  END_DATE_FORMAT_NOT_VALID: 'The end date is not valid',
  START_DATE_MUST_BE_BEFORE_END_DATE: 'The start date should be before the end date',
  END_DATE_MUST_BE_AFTER_START_DATE: 'The end date should be after the start date',
  START_DATE_NOT_WITHIN_RANGE: 'The start date is not within the accepted range',
  END_DATE_NOT_WITHIN_RANGE: 'The end date is not within the accepted range',
  APPLY: 'Apply',
  DAY_TITLE_FREE: (date: any) => `Choose: ${date}`,
  DAY_TITLE_SELECTED: (date: any) => `Selected. ${date}`,
  // This field is optional and will default to the dateFormat
  START_DATE_INPUT_PLACEHOLDER: 'yyyy/MM/dd';
  // This field is optional and will default to the dateFormat
  END_DATE_INPUT_PLACEHOLDER: 'yyyy/MM/dd';
}
```

##### Example Usage

```jsx
import { DateRange } from '@lightspeed/cirrus-datepicker';

const translations = {
  // ...
};

const App = () => {
  const [dates, setDates] = useState({
    startDate: new Date(2019, 6, 21),
    endDate: new Date(2019, 6, 27),
  });

  return (
    <DateRange
      startDate={dates.startDate}
      endDate={dates.endDate}
      dateFormat="yyyy/MM/dd"
      translations={translations}
      onSubmit={dates => {
        console.log(dates);
      }}
    />
  );
};
```

##### Example Usage - With Presets

```jsx
import { DateRange, createWeekPreset, createMonthPreset } from '@lightspeed/cirrus-datepicker';

const translations = {
  // ...
};

const lastWeek = createWeekPreset({ label: 'Last week', amountOfWeeks: 1, relativeStart: -1 });
const thisWeek = createWeekPreset({ label: 'This week', amountOfWeeks: 1 });

const App = () => {
  const [dates, setDates] = useState({
    startDate: new Date(2019, 6, 21),
    endDate: new Date(2019, 6, 27),
  });

  return (
    <DateRange
      startDate={dates.startDate}
      endDate={dates.endDate}
      dateFormat="yyyy/MM/dd"
      presetDates={[
        {
          label: 'Some Arbitrary Preset',
          startDate: new Date(2019, 6, 28),
          endDate: new Date(2019, 6, 29),
        },
        {
          label: 'Another Preset',
          startDate: new Date(2019, 5, 1),
          endDate: new Date(2019, 5, 14),
        },
        {}, // this makes a separator
        lastWeek,
        thisWeek,
      ]}
      translations={translations}
      onSubmit={dates => {
        console.log(dates);
      }}
    />
  );
};
```

#### `<DateRangePicker>`

| Prop            | Type                                                                   | Description                                                                                                                                                                                                   |
| --------------- | ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `startDate`     | `Date`                                                                 | Javascript Date representing the initially selected start date                                                                                                                                                |
| `endDate`       | `Date`                                                                 | Javascript Date representing the initially selected end date                                                                                                                                                  |
| `isDateBlocked` | `(Date) => boolean`                                                    | Callback function used for determining whether or not a date should be blocked                                                                                                                                |
| `onSubmit`      | `({ startDate:Date, endDate:Date }) => void`                           | Callback function when clicking on the "apply" button. The selected start and end date will be sent back if all is valid                                                                                      |
| `presetDates`   | `Array<{label: string, startDate: Date, endDate: Date}>`               | List of preset dates. By adding this, a small menu will be created within the calendar to automatically select the start and end date. You may add an empty object, which will automatically create a divider |
| `dateFormat`    | `String`                                                               | A Luxon compatible string format                                                                                                                                                                              |
| `target`        | `(targetRef: ref, toggle: () => void, isActive: boolean) => ReactNode` | Pass a custom React element as a target                                                                                                                                                                       |
| `translations`  | `Object`                                                               | A key value pairing for forwarding translated messages. See the Translation section for further details.                                                                                                      |
| `locale`        | `String`                                                               | Valid language locale, e.g: 'en-fr', 'en-us'. Changing this parameter will adjust some dateFormat outputs to match the target locale                                                                          |

##### Translations

When adding translations to the `DateRangePicker`, it is important to use the right translation key for the component to pick up the string.

Here is a sample translation object:

```
{
  START_DATE_NOT_DEFINED: 'The start date is not defined',
  END_DATE_NOT_DEFINED: 'The end date is not defined',
  START_DATE_FORMAT_NOT_VALID: 'The start date is not valid',
  END_DATE_FORMAT_NOT_VALID: 'The end date is not valid',
  START_DATE_MUST_BE_BEFORE_END_DATE: 'The start date should be before the end date',
  END_DATE_MUST_BE_AFTER_START_DATE: 'The end date should be after the start date',
  START_DATE_NOT_WITHIN_RANGE: 'The start date is not within the accepted range',
  END_DATE_NOT_WITHIN_RANGE: 'The end date is not within the accepted range',
  APPLY: 'Apply',
  DAY_TITLE_FREE: (date: any) => `Choose: ${date}`,
  DAY_TITLE_SELECTED: (date: any) => `Selected. ${date}`,
  // This field is optional and will default to the dateFormat
  START_DATE_INPUT_PLACEHOLDER: 'yyyy/MM/dd';
  // This field is optional and will default to the dateFormat
  END_DATE_INPUT_PLACEHOLDER: 'yyyy/MM/dd';
}
```

##### Example Usage

```jsx
import { DateRangePicker } from '@lightspeed/cirrus-datepicker';

const translations = {
  // ...
};

const App = () => {
  const [dates, setDates] = useState({
    startDate: new Date(2019, 6, 21),
    endDate: new Date(2019, 6, 27),
  });

  return (
    <DateRangePicker
      startDate={dates.startDate}
      endDate={dates.endDate}
      dateFormat="yyyy/MM/dd"
      translations={translations}
      onSubmit={dates => {
        console.log(dates);
      }}
    />
  );
};
```

##### Example Usage - With Presets

```jsx
import {
  DateRangePicker,
  createWeekPreset,
  createMonthPreset,
} from '@lightspeed/cirrus-datepicker';

const translations = {
  // ...
};

const lastWeek = createWeekPreset({ label: 'Last week', amountOfWeeks: 1, relativeStart: -1 });
const thisWeek = createWeekPreset({ label: 'This week', amountOfWeeks: 1 });
const thisMonth = createMonthPreset({ label: 'This month', amountOfMonths: 1 });
const nextMonth = createMonthPreset({ label: 'Next month', amountOfMonths: 1, relativeStart: 1 });

const App = () => {
  const [dates, setDates] = useState({
    startDate: new Date(2019, 6, 21),
    endDate: new Date(2019, 6, 27),
  });

  return (
    <DateRangePicker
      startDate={dates.startDate}
      endDate={dates.endDate}
      dateFormat="yyyy/MM/dd"
      presetDates={[
        {
          label: 'Some Arbitrary Preset',
          startDate: new Date(2019, 6, 28),
          endDate: new Date(2019, 6, 29),
        },
        {
          label: 'Another Preset',
          startDate: new Date(2019, 5, 1),
          endDate: new Date(2019, 5, 14),
        },
        {}, // this makes a separator
        lastWeek,
        thisWeek,
        {},
        thisMonth,
        nextMonth,
      ]}
      translations={translations}
      onSubmit={dates => {
        console.log(dates);
      }}
    />
  );
};
```

#### `<DatePicker>`

| Prop            | Type                                                        | Description                                                                                                                            |
| --------------- | ----------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `date`          | `Date`                                                      | Date representing the initially selected start date                                                                                    |
| `isDateBlocked` | `(Date) => boolean`                                         | Callback function used for determining whether or not a date should be blocked                                                         |
| `onSubmit`      | `({ date:Date }) => void`                                   | Callback function that receives an object containing the startDate end endDate selected                                                |
| `presetDates`   | `Array<{label:string, startDate: Moment, endDate: Moment}>` | List of preset dates. By adding this, a small menu will be created within the calendar to automatically select the start and end date. |
| `dateFormat`    | `String`                                                    | Luxon compatible string format                                                                                                         |
| `target`        | `func`                                                      | Pass a custom React element as a target                                                                                                |
| `translations`  | `Object`                                                    | A key value pairing for forwarding translated messages. See the Translation section for further details.                               |
| `locale`        | `String`                                                    | Valid language locale, e.g: 'en-fr', 'en-us'. Changing this parameter will adjust some dateFormat outputs to match the target locale   |

##### Translations

When adding translations to the `DatePicker`, it is important to use the right translation key for the component to pick up the string.

Here is a sample translation object:

```
{
  DATE_NOT_DEFINED: 'The date is not defined',
  DATE_NOT_VALID: 'The date is not valid',
  DATE_NOT_WITHIN_RANGE: 'The date is not within the accepted range',
  APPLY: 'Apply Button Text',
  DAY_TITLE_FREE: (date: any) => `Choose: ${date}`,
  DAY_TITLE_SELECTED: (date: any) => `Selected. ${date}`,
  // This field is optional and will default to the dateFormat
  INPUT_PLACEHOLDER: 'yyyy/MM/dd'
}
```

##### Example Usage

```jsx
import { DateRangePicker } from '@lightspeed/cirrus-datepicker';

const translations = {
  // ...
};

const App = () => {
  const [dates, setDates] = useState(new Date(2019, 6, 21));

  return (
    <DatePicker
      date={date}
      dateFormat="yyyy/MM/dd"
      translations={translations}
      onSubmit={values => {
        console.log(values);
      }}
    />
  );
};
```

#### createWeekPreset

Helper function to rapidly generate some presets used in the DateRangePicker.

| Prop            | Type     | Description                                                                                                                                                                        |
| --------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `label`         | `string` | Label of the preset                                                                                                                                                                |
| `relativeStart` | `number` | Relative start week based on today's date. By default, the value is set to 0, which represents this week. If we were to put 1, we would be selected next week as our starting week |
| `amountOfWeeks` | `number` | Amount of weeks to select when starting from the relativeStart.                                                                                                                    |

```jsx
const lastWeek = createWeekPreset({ label: 'Last week', amountOfWeeks: 1, relativeStart: -1 });
const thisWeek = createWeekPreset({ label: 'This week', amountOfWeeks: 1 });
const nextWeek = createWeekPreset({ label: 'Next week', amountOfWeeks: 1, relativeStart: 1 });
```

#### createMonthPreset

Helper function to rapidly generate some presets used in the DateRangePicker.

| Prop             | Type     | Description                                                                                                                                                                            |
| ---------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `label`          | `string` | Label of the preset                                                                                                                                                                    |
| `relativeStart`  | `number` | Relative start month based on today's date. By default, the value is set to 0, which represents this month. If we were to put 1, we would be selected next month as our starting month |
| `amountOfMonths` | `number` | Amount of months to select when starting from the relativeStart                                                                                                                        |

```jsx
const lastMonth = createMonthPreset({ label: 'Last month', amountOfMonths: 1, relativeStart: -1 });
const thisMonth = createMonthPreset({ label: 'This month', amountOfMonths: 1 });
const nextMonth = createMonthPreset({ label: 'Next month', amountOfMonths: 1, relativeStart: 1 });
```

#### `<TimeSelect>`

**Experimental Component Ahead**

| Prop          | Type                   | Description                                                                                                          |
| ------------- | ---------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `date`        | `Date`                 | Date object we wish to set the time on. By default, sets to Today                                                    |
| `minuteSteps` | `number`               | Minute selector increments. e.g: setting this to `5` will result only in minutes with multiples of 5 to be displayed |
| `format`      | `12h | 24h`            | Format of the TimeSelect. By default, `24h` is selected                                                              |
| `onChange`    | `(date: Date) => void` | Callback function that takes the entry date and returns the same date, but with the time changed                     |

##### Example Usage

```jsx
import { TimeSelect } from '@lightspeed/cirrus-datepicker';

const App = () => {
  return (
    <TimeSelect
      onChange={nextDate => {
        console.log(nextDate);
      }}
    />
  );
};
```