okami v0.2.5
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 or 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.
Install
yarn add okami
npm install --save okami
Basic Usage
For more examples, look at the storybook :)
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 format for durations.
Every prop passed to Calendar can be overwritten as the sub component level.
<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-fnsformat
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: . 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-fnsformat
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: . 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-fnsformat
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.
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
renderChildprops: pass a component that receive pre formatted props- The default render that let you style the
divcontainer.
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 |
<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.
<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 :
<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 daysfalse, the event is no longer than a dayDate, 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.
// 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
7 years ago
7 years ago
7 years ago
7 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago