All the logic you need to quickly build a custom calendar or date-picker for any framework or plain vanilla JavaScript.
- Generates data to populate a grid
- Split your events by date
- Supports fill or fitted weeks (filled weeks always shows 6 weeks)
- Supports before and after date
- Supports start of week
- Supports range selection
- Supports disabling certains days
- Supports disabling days of the week
const options = {
  firstDay: 1 // Monday
}
let calendar = create(Date.now(), options)
const nextMonth = () => {
  calendar = create(calendar.next, options)
}
const prevMonth = () => {
  calendar = create(calendar.prev, options)
}
Sample output from calling create()
```
{
  config: {
    after: null,
    before: null,
    fillWeek: true,
    firstDay: 1,
    now: 2021-09-05T16:00:00.000Z,
    selection: null
  },
  next: 2021-09-30T16:00:00.000Z,
  prev: 2021-07-31T16:00:00.000Z,
  current: 2021-08-31T16:00:00.000Z,
  start: 2021-08-31T16:00:00.000Z,
  end: 2021-09-29T16:00:00.000Z,
  days: [
    {
      date: 2021-08-29T16:00:00.000Z,
      day: 30,
      dayOfWeek: 1,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: false
    },
    {
      date: 2021-08-30T16:00:00.000Z,
      day: 31,
      dayOfWeek: 2,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: false
    },
    {
      date: 2021-08-31T16:00:00.000Z,
      day: 1,
      dayOfWeek: 3,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: true
    },
    {
      date: 2021-09-01T16:00:00.000Z,
      day: 2,
      dayOfWeek: 4,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: true
    },
    {
      date: 2021-09-02T16:00:00.000Z,
      day: 3,
      dayOfWeek: 5,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: true
    },
    {
      date: 2021-09-03T16:00:00.000Z,
      day: 4,
      dayOfWeek: 6,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: true
    },
    {
      date: 2021-09-04T16:00:00.000Z,
      day: 5,
      dayOfWeek: 0,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: true
    },
    {
      date: 2021-09-05T16:00:00.000Z,
      day: 6,
      dayOfWeek: 1,
      isToday: true,
      selection: null,
      state: 'valid',
      inMonth: true
    },
    {
      date: 2021-09-06T16:00:00.000Z,
      day: 7,
      dayOfWeek: 2,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: true
    },
    {
      date: 2021-09-07T16:00:00.000Z,
      day: 8,
      dayOfWeek: 3,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: true
    },
    {
      date: 2021-09-08T16:00:00.000Z,
      day: 9,
      dayOfWeek: 4,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: true
    },
    {
      date: 2021-09-09T16:00:00.000Z,
      day: 10,
      dayOfWeek: 5,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: true
    },
    {
      date: 2021-09-10T16:00:00.000Z,
      day: 11,
      dayOfWeek: 6,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: true
    },
    {
      date: 2021-09-11T16:00:00.000Z,
      day: 12,
      dayOfWeek: 0,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: true
    },
    {
      date: 2021-09-12T16:00:00.000Z,
      day: 13,
      dayOfWeek: 1,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: true
    },
    {
      date: 2021-09-13T16:00:00.000Z,
      day: 14,
      dayOfWeek: 2,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: true
    },
    {
      date: 2021-09-14T16:00:00.000Z,
      day: 15,
      dayOfWeek: 3,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: true
    },
    {
      date: 2021-09-15T16:00:00.000Z,
      day: 16,
      dayOfWeek: 4,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: true
    },
    {
      date: 2021-09-16T16:00:00.000Z,
      day: 17,
      dayOfWeek: 5,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: true
    },
    {
      date: 2021-09-17T16:00:00.000Z,
      day: 18,
      dayOfWeek: 6,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: true
    },
    {
      date: 2021-09-18T16:00:00.000Z,
      day: 19,
      dayOfWeek: 0,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: true
    },
    {
      date: 2021-09-19T16:00:00.000Z,
      day: 20,
      dayOfWeek: 1,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: true
    },
    {
      date: 2021-09-20T16:00:00.000Z,
      day: 21,
      dayOfWeek: 2,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: true
    },
    {
      date: 2021-09-21T16:00:00.000Z,
      day: 22,
      dayOfWeek: 3,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: true
    },
    {
      date: 2021-09-22T16:00:00.000Z,
      day: 23,
      dayOfWeek: 4,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: true
    },
    {
      date: 2021-09-23T16:00:00.000Z,
      day: 24,
      dayOfWeek: 5,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: true
    },
    {
      date: 2021-09-24T16:00:00.000Z,
      day: 25,
      dayOfWeek: 6,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: true
    },
    {
      date: 2021-09-25T16:00:00.000Z,
      day: 26,
      dayOfWeek: 0,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: true
    },
    {
      date: 2021-09-26T16:00:00.000Z,
      day: 27,
      dayOfWeek: 1,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: true
    },
    {
      date: 2021-09-27T16:00:00.000Z,
      day: 28,
      dayOfWeek: 2,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: true
    },
    {
      date: 2021-09-28T16:00:00.000Z,
      day: 29,
      dayOfWeek: 3,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: true
    },
    {
      date: 2021-09-29T16:00:00.000Z,
      day: 30,
      dayOfWeek: 4,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: true
    },
    {
      date: 2021-09-30T16:00:00.000Z,
      day: 1,
      dayOfWeek: 5,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: false
    },
    {
      date: 2021-10-01T16:00:00.000Z,
      day: 2,
      dayOfWeek: 6,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: false
    },
    {
      date: 2021-10-02T16:00:00.000Z,
      day: 3,
      dayOfWeek: 0,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: false
    },
    {
      date: 2021-10-03T16:00:00.000Z,
      day: 4,
      dayOfWeek: 1,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: false
    },
    {
      date: 2021-10-04T16:00:00.000Z,
      day: 5,
      dayOfWeek: 2,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: false
    },
    {
      date: 2021-10-05T16:00:00.000Z,
      day: 6,
      dayOfWeek: 3,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: false
    },
    {
      date: 2021-10-06T16:00:00.000Z,
      day: 7,
      dayOfWeek: 4,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: false
    },
    {
      date: 2021-10-07T16:00:00.000Z,
      day: 8,
      dayOfWeek: 5,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: false
    },
    {
      date: 2021-10-08T16:00:00.000Z,
      day: 9,
      dayOfWeek: 6,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: false
    },
    {
      date: 2021-10-09T16:00:00.000Z,
      day: 10,
      dayOfWeek: 0,
      isToday: false,
      selection: null,
      state: 'valid',
      inMonth: false
    }
  ],
  now: 2021-09-05T16:00:00.000Z
}
```
Note that the
- monthin- CalendarDateis 1-based and that,
- dayis what is called 'date' in the Date APi.
type CalendarDate =
  | { year: number; month: number; day?: number }
  | string
  | number
  | Date;
interface CalendarEvent<T = any> {
  label: string,
  date: Date
  value?: T
}
type CalendarBuilderOptions = {
  /**
   * The first day of the week
   *
   * Default: 0
   */
  firstDay: number;
  /**
   * Add a fill week to the end even if not needed. This is useful to avoid
   * "flicker" when some months are 4-6 weeks only.
   *
   * Default: true
   */
  fillWeek: boolean;
  /**
   * Mark dates before this time invalid (excluding)
   *
   * E.g. after = 2021-05-29, then first valid date is 2021-05-30.
   */
  after: CalendarDate;
  /**
   * Mark dates after this time invalid (excluding)
   *
   * E.g. before = 2021-05-29, then last valid date is 2021-05-28.
   */
  before: CalendarDate;
  /**
   * Mark days in this range as selected. The selection state of the day may
   * vary if it is the first, last, middle, or only day in the selection.
   */
  selection: [CalendarDate, CalendarDate];
  /**
   * Optionally pas in date for when is 'now'.
   */
  now: CalendarDate;
  /**
   * Disable days of the week
   */
  disableDaysOfWeek: number[];
  /**
   * Disable specific days
   */
  disableDays: CalendarDate[];
  /**
   * Events to "bucket". Will distribute an array of events into the
     event-bucket on each of the calendar days.
   */
  events: CalendarEvent[];
};






