# okami

> Okami Primitives React Components to build a Calendar

Latest version **0.2.5** (published 2018-09-19) · MIT license · 0 weekly downloads

## Install

```sh
npm install okami
pnpm add okami
yarn add okami
bun add okami
```

## Health

**Score 20/100 (F)** — status: abandoned.

Positive: esm support; no vulnerabilities.

Warnings: low downloads; no types; pre 1.0.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 0.2.5 |
| Published | 2018-09-19 |
| First published | 2017-09-06 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | none |
| Module format | ESM + CommonJS |
| Dependencies | 4 |
| Unpacked size | 124.1 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 19 |
| Author | wcastand |
| Maintainers | alefevre19, alexandrebodin, augustinlf, kilix_user, wcastand |
| Keywords | react, calendar, composable, primitives |

## Links

- npm: https://www.npmjs.com/package/okami
- Repository: https://github.com/Kilix/okami
- Homepage: https://github.com/Kilix/okami#readme
- Issues: https://github.com/Kilix/okami/issues
- npm.io page: https://npm.io/package/okami

## Dependencies (4)

- [date-fns](https://npm.io/package/date-fns.md) 2.0.0-alpha.1
- [debounce](https://npm.io/package/debounce.md) 1.1.0
- [recompose](https://npm.io/package/recompose.md) 0.26.0
- [pomeranian-durations](https://npm.io/package/pomeranian-durations.md) 0.2.0

## Alternatives

- [mobx-react](https://npm.io/package/mobx-react.md) — 2.8M weekly downloads
- [rc-tree](https://npm.io/package/rc-tree.md) — 2.6M weekly downloads
- [@react-oauth/google](https://npm.io/package/@react-oauth/google.md) — 1.3M weekly downloads
- [@wagmi/connectors](https://npm.io/package/@wagmi/connectors.md) — 877.0K weekly downloads
- [vee-validate](https://npm.io/package/vee-validate.md) — 836.4K weekly downloads

## Recent versions

- 0.2.5 (latest) — 2018-09-19
- 0.0.1 (alpha) — 2017-09-06
- 0.2.4 — 2018-09-05
- 0.2.3 — 2018-08-03
- 0.2.2 — 2018-08-03
- 0.2.1 — 2018-02-02
- 0.2.0 — 2018-01-29
- 0.1.8 — 2018-01-25
- 0.1.7 — 2017-10-19
- 0.1.6 — 2017-10-02
- 0.1.5 — 2017-09-14
- 0.1.4 — 2017-09-14
- 0.1.3 — 2017-09-13
- 0.1.2 — 2017-09-13
- 0.1.1 — 2017-09-13
- … 7 more at https://npm.io/package/okami/versions

## README

<h1 align="center">
  Okami
  <br>
</h1>
<p align="center" style="font-size: 1.2rem;">Primitives React Components to build a Calendar</p>

[![Build Status][build-badge]][build]
[![Code Coverage][coverage-badge]][coverage]
[![version][version-badge]][package]
[![MIT License][license-badge]][LICENSE]

## Project status
Okami is used in production, we consider evolving its API, but it works as expected!

## Introduction
It's a set of Primitives React Components to build a Calendar. Handle the logic so you can focus on UI/UX. Similar to [downshift](https://github.com/paypal/downshift) or [selectless](https://github.com/Kilix/selectless).

We use composition to construct the calendar, which simply means:

- A monthly calendar is composed of weekly calendar.
- A weekly calendar is composed of daily calendar.

This allow to have a lot fo flexibility without repeating the logic and avoid complexity.

We strongly recommend to use `okami` with [date-fns](https://date-fns.org/).

## Install

```yarn add okami```
```npm install --save okami```

## Basic Usage

For more examples, look at the storybook :)

```jsx

import React from 'react'
import frLocale from 'date-fns/locale/fr'
import { Calendar, DailyCalendar, Navigation, HoursLabels } from 'okami'

import data from './stories/data'

const Container = props =>
  <div style={{ display: 'flex', alignItems: 'stretch', justifyContent: 'center'}} {...props} />

const CalendarContainer = props =>
  <div style={{ display: 'flex', alignItems: 'stretch', justifyContent: 'flex-start', width: '100%' }} {...props} />

export default props => (
  <Calendar
    data={data}
    startingDay="monday"
    dateFormat="ddd DD/MM"
    hourFormat="HH"
    startHour="PT3H"
    endHour="PT22H"
    locale={frLocale}
  >
    <DailyCalendar showNow {...props}>
      {({calendar, dayEvents, rowHeight}) => (
        <div style={{display: 'flex', flexDirection:'column'}}>
          <div style={{display:'flex'}}>
            <Navigation dateFormat="ddd DD MMMM">
              {({next, prev, today, currentDate}) => (
                <div style={{display:'flex'}}>
                  <button onClick={today}>Today</button>
                  <button onClick={prev}>Prev day</button>
                  <button onClick={next}>Next day</button>
                  <span>{currentDate}</span>
                </div>
              )}
            </Navigation>
          </div>
          <Container>
            <div style={{paddingTop: rowHeight * (dayEvents.length + 1)}}>
              <HoursLabels renderChild={props => <span style={{height: rowHeight}} {...props} />} />
            </div>
            <CalendarContainer style={{flexDirection: 'column'}}>
              {dayEvents.map(props => <Event {...props} />)}
              {calendar.events.map(props => <Event {...props} />)}
            </CalendarContainer>
          </Container>
        </div>
      )}
    </DailyCalendar>
  </Calendar>
)

```

## Documentation

### Props Calendar

| property      | type      | required | default    | description                  |
|---------------|-----------|----------|------------|------------------------------|
| `data`        | `array`   | yes      | -          | List of events               |
| `startHour`   | `string`  | no       | PT0H       | Hour to start the calendar   |
| `endHour`     | `string`  | no       | PT24H      | Hour to end the calendar     |
| `dateFormat`  | `string`  | no       | MM/DD/YYYY | Format of the date string    |
| `hourFormat`  | `string`  | no       | HH:mm      | Format of the hour string    |
| `startingDay` | `string`  | no       | sunday     | Starting day of the week     |
| `locale`      | `object`  | no       | en         | Local from `date-fns`        |
| `rowHeight`   | `number`  | no       | 30         | Height of a row              |

To define property that will be use as duration like `startHours` or `endHour`.
We use [ISO-8601](https://fr.wikipedia.org/wiki/ISO_8601) format for durations.

Every prop passed to Calendar can be overwritten as the sub component level.

```jsx
  <Calendar
    data={data}
    startingDay="monday"
    dateFormat="ddd DD/MM"
    hourFormat="HH"
    startHour="PT3H"
    endHour="PT22H"
  >
    <MonthlyCalendar>{...}</MonthlyCalendar>
    <DailyCalendar dateFormat="DD-MM-YYYY">{...}</DailyCalendar>
  </Calendar>
```
This will use the `dateFormat` from `<Calendar>` in `<MonthlyCalendar>` but `<DailyCalendar>` will use his custom `dateFormat` when it renders.

---

### Daily Calendar

Render a day.

#### Props

| property      | type      | default      | description                        |
|---------------|-----------|--------------|------------------------------------|
| `start`       | `Date`    | `new Date()` | Day to show                        |
| `showNow`     | `boolean` | `false`      | Send props to show the time of day |

#### Child Callback Function

| property         | type       | description                                                    |
|------------------|------------|----------------------------------------------------------------|
| `calendar`       | `Object`   | events, label and date of the day                              |
| `start`          | `Date`     | date of the day                                                |
| `showNowProps`   | `Object`   | if `showNow` is true, props to the showNow container (postion) |
| `hours`          | `Array`    | Array of formatted string for hours labels                     |
| `rowHeight`      | `Number`   | Height of the row                                              |
| `dayEvents`      | `Array`    | Array of the events that last more than a day of the all day   |

**calendar**

| property | type     |
|----------|----------|
| `date`   | `Date`   |
| `events` | `Array`  |


**dayEvents**

| property | type       |
|----------|------------|
| `key`    | `event.id` |
| `event`  | `Object`   |
| `style`  | `Object`   |

The style object is passed only if the `getColumnProp` is called and we have a ref available.

| methods          | description                                   |
|------------------|-----------------------------------------------|
| `nextDay`        | Go to next day                                |
| `prevDay`        | Go to previous day                            |
| `gotoToday`      | Go to today                                   |
| `dateLabel`      | get the date formatted                        |
| `getColumnProps` | get the props for the container of the events |

**dateLabel**

Allow you to render the current day with a special format.

- dateFormat: use the convention from `date-fns` [format](https://date-fns.org/v1.28.5/docs/format)

**getColumnProps**

Allow to get the ref to your column element for calculation of the events position.

- refKey: if you're rendering a composite component, that component will need to accept a prop which it forwards to the root DOM element. Commonly, folks call this innerRef. So you'd call: getRootProps({refKey: 'innerRef'}) and your composite component would forward like: <div ref={props.innerRef} />.
By default, it will use the react default ref key

---

### Weekly Calendar

Render a week.

#### Props

| property      | type      | default      | description                        |
|---------------|-----------|--------------|------------------------------------|
| `start`       | `Date`    | `new Date()` | Day of the week to show            |
| `showNow`     | `boolean` | `false`      | Send props to show the time of day |

#### Child Callback Function

| property         | type       | description                                                    |
|------------------|------------|----------------------------------------------------------------|
| `calendar`       | `Array`    | list of day for the week                                       |
| `end`            | `Date`     | end of the week                                                |
| `start`          | `Date`     | start of the week                                              |
| `showNowProps`   | `Object`   | if `showNow` is true, props to the showNow container (postion) |
| `hours`          | `Array`    | Array of formatted string for hours labels                     |
| `rowHeight`      | `Number`   | Height of the row                                              |
| `weekEvents`     | `Array`    | Array of the events that last more than a day of the all week  |

**weekEvents**

| property | type       |
|----------|------------|
| `key`    | `event.id` |
| `event`  | `Object`   |
| `style`  | `Object`   |

The style object is passed only if the `getContainerProps` is called and we have a ref available.

| methods             | description                                   |
|---------------------|-----------------------------------------------|
| `nextWeek`          | Go to next week                               |
| `prevWeek`          | Go to previous week                           |
| `gotoToday`         | Go to today                                   |
| `dateLabel`         | get the date formatted                        |
| `getContainerProps` | get the props for the container of the events |


**dateLabel**

Allow you to render the current week with a special format.

- dateFormat: use the convention from `date-fns` [format](https://date-fns.org/v1.28.5/docs/format)

**getContainerProps**

Allow to get the ref to your column element for calculation of the events position.

- refKey: if you're rendering a composite component, that component will need to accept a prop which it forwards to the root DOM element. Commonly, folks call this innerRef. So you'd call: getRootProps({refKey: 'innerRef'}) and your composite component would forward like: <div ref={props.innerRef} />.
By default, it will use the react default ref key.

---

### Monthly Calendar

Render a month.

#### Props

| property      | type      | default      | description                        |
|---------------|-----------|--------------|------------------------------------|
| `start`       | `Date`    | `new Date()` | Date of the curent month           |

#### Child Callback Function

| property         | type       | description                                                    |
|------------------|------------|----------------------------------------------------------------|
| `calendar`       | `Array`    | List of first day of the week for the month                    |
| `end`            | `Date`     | end of the month                                               |
| `start`          | `Date`     | start of the month                                             |
| `weeks`          | `Array`    | List of the first day of week for the month                    |
| `rowHeight`      | `Number`   | Height of the row                                              |

| methods             | description                                   |
|---------------------|-----------------------------------------------|
| `nextMonth`          | Go to next month                             |
| `prevMonth`          | Go to previous month                         |
| `gotoToday`         | Go to today                                   |
| `dateLabel`         | get the date formatted                        |

**dateLabel**

Allow you to render the current month with a special format.

- dateFormat: use the convention from `date-fns` [format](https://date-fns.org/v1.28.5/docs/format)

---

### Navigation

render the navigation for the calendar and the current label. The navigation and label are based on the type.
If you use this in a `DailyCalendar`, `next()` will jump to the next day but if you use it in `MonthlyCalendar`, it will jump to the next month.
You also get access to the function to toggle weekends on the calendar.

If you force showWeekend on a sub component, don't forget to update manually this props.

#### Props
| property      | type      | description                        |
|---------------|-----------|------------------------------------|
| `dateFormat`  | `string`  | format of the date                 |

#### Child Callback Function

| property       | type       | description                                                    |
|----------------|------------|----------------------------------------------------------------|
| `type`         | `string`   | Type of calendar ('monthly', 'weekly', 'daily')                |
| `currentDate`  | `string`   | Formatted date based on type                                   |

| methods         | description                   |
|-----------------|-------------------------------|
| `next`          | Go to next based on type      |
| `prev`          | Go to previous based on type  |
| `today`         | Go to today                   |
| `toggleWeekend` | show/hide weekend on calendar |

**toggleWeekend**

Let you toggle the weekend in the calendar.
If you don't pass a pamarater, it will toggle the prop. If you pass a boolean, it will force the value.

```javascript

const showWeekend = true

toggleWeekend() // showWeekend = false
toggleWeekend(true) // showWeekend = true
toggleWeekend(true) // showWeekend = true
toggleWeekend(false) // showWeekend = false
[...]

```

---

### DaysLabels / HoursLabels

render the days/hours labels for the calendar.
You have 3 options to render those components:
 - Child Callback function : allow full control
 - `renderChild` props: pass a component that receive pre formatted props
 - The default render that let you style the `div` container.

#### Props
| property      | type                  |
|---------------|-----------------------|
| `renderChild`  | `Element|Component`  |

#### Child Callback Function

**DaysLabels**

| property       | type       | description                                                    |
|----------------|------------|----------------------------------------------------------------|
| `weeks`         | `array`   | Array of the formatted day labels                              |

**HoursLabels**

| property       | type       | description                                                    |
|----------------|------------|----------------------------------------------------------------|
| `hours`        | `array`   | Array of the formatted hour labels                              |

```jsx
  <HoursLabels>
    { hours => hours.map(h => <span>{h}</span>} }
  </HoursLabels>
```

#### `renderChild` prop

props from the HoursLabels/DaysLabels are passed down to the container and the labels are rendered with the component from `renderChild`.

```jsx
  <HoursLabels renderChild={props => <span {...props} />} />
```

#### The default render function

props from the HoursLabels/DaysLabels are passed down to the container.

```<HoursLabels />```

This is the render function used :
```jsx
<div {...props}>
  {formattedDays.map((h, idx) => (
    <div key={`day_label_${idx}`} style={{height: rowHeight}}>
      {h}
    </div>
  ))}
</div>
```
---

### Data structure

`data` is an array of objects, the object requires a few properties :

| property | type              | description                  |
|----------|-------------------|------------------------------|
| `id`     | `ID`              | Identifier of the event      |
| `title`  | `string`          | Title of the event           |
| `allDay` | `boolean | Date`  | Determine the type of event  |
| `start`  | `Date`            | Beggining of the event       |
| `end`    | `Date`            | End of the event             |

`allDay` has 3 states :
 - `true`, the event is on multiple days
 - `false`, the event is no longer than a day
 - `Date`, the event last all day

if `allDay` is a boolean, you need to provide a `start` and `end` properties.
If you want to create an event for the all day, you just put the date in `allDay`.

```javascript

// Event of 2 hours:
{
  id: 0,
  title: 'Diner',
  allDay: false,
  start : 'Wed Sep 06 2017 12:07:52 GMT+0200 (CEST)',
  end: 'Wed Sep 06 2017 14:07:52 GMT+0200 (CEST)'
}

// Event of all day:
{
  id: 0,
  title: 'Diner',
  allDay: 'Wed Sep 06 2017 12:07:52 GMT+0200 (CEST)'
}

// Event of 2 days:
{
  id: 0,
  title: 'Diner',
  allDay: true,
  start : 'Wed Sep 06 2017 12:07:52 GMT+0200 (CEST)',
  end: 'Wed Sep 08 2017 14:07:52 GMT+0200 (CEST)'
}

```


# LICENSE

 MIT


[build-badge]: https://img.shields.io/travis/Kilix/okami.svg?style=flat-square
[build]: https://travis-ci.org/Kilix/okami
[coverage-badge]: https://img.shields.io/codecov/c/github/Kilix/okami.svg?style=flat-square
[coverage]: https://codecov.io/github/Kilix/okami
[version-badge]: https://img.shields.io/npm/v/okami.svg?style=flat-square
[package]: https://www.npmjs.com/package/okami
[license-badge]: https://img.shields.io/npm/l/okami.svg?style=flat-square
[license]: https://github.com/paypal/okami/blob/master/LICENSE

---
_Source: https://npm.io/package/okami · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
