Calendar refactoring
parent
5f62ce283a
commit
18a51d8d26
|
@ -0,0 +1,29 @@
|
|||
css = require './style'
|
||||
dateUtils = require '../date_utils'
|
||||
|
||||
module.exports = React.createClass
|
||||
displayName: 'Day',
|
||||
|
||||
propTypes:
|
||||
day : React.PropTypes.number
|
||||
onClick : React.PropTypes.func
|
||||
selectedDate : React.PropTypes.object
|
||||
viewDate : React.PropTypes.object
|
||||
|
||||
_dayStyle: ->
|
||||
marginLeft: "#{dateUtils.firstWeekDay(@props.viewDate) * 100/7}%"
|
||||
|
||||
_isSelected: () ->
|
||||
isSameYear = @props.viewDate.getFullYear() == @props.selectedDate.getFullYear()
|
||||
isSameMonth = @props.viewDate.getMonth() == @props.selectedDate.getMonth()
|
||||
isSameDay = @props.day == @props.selectedDate.getDate()
|
||||
isSameYear && isSameMonth && isSameDay
|
||||
|
||||
render: ->
|
||||
className = " #{css.day}"
|
||||
className += " active" if @_isSelected()
|
||||
dayStyle = @_dayStyle() if @props.day == 1
|
||||
|
||||
<div className={className} style={dayStyle}>
|
||||
<span onClick={@props.onClick}>{ @props.day }</span>
|
||||
</div>
|
|
@ -1,9 +1,12 @@
|
|||
CTG = React.addons.CSSTransitionGroup
|
||||
css = require './style'
|
||||
FontIcon = require '../font_icon'
|
||||
dateUtils = require '../date_utils'
|
||||
|
||||
CTG = React.addons.CSSTransitionGroup
|
||||
FontIcon = require '../font_icon'
|
||||
Month = require './month'
|
||||
|
||||
module.exports = React.createClass
|
||||
displayName: 'Calendar',
|
||||
|
||||
# -- States & Properties
|
||||
propTypes:
|
||||
|
@ -21,8 +24,10 @@ module.exports = React.createClass
|
|||
selectedDate: @props.selectedDate
|
||||
viewDate: @props.viewDate
|
||||
|
||||
# -- Lifecycle
|
||||
componentDidUpdate: (prevProps, prevState) ->
|
||||
@props.onChange? @ if prevState.selectedDate.getTime() != @state.selectedDate.getTime()
|
||||
if prevState.selectedDate.getTime() != @state.selectedDate.getTime() && @props.onChange
|
||||
@props.onChange? @
|
||||
|
||||
# -- Events
|
||||
onDayClick: (event) ->
|
||||
|
@ -31,7 +36,7 @@ module.exports = React.createClass
|
|||
newDate.setDate(day)
|
||||
@setState selectedDate: newDate
|
||||
|
||||
# -- Handle month increment and decrement
|
||||
# -- Public methods
|
||||
incrementViewMonth: ->
|
||||
@setState
|
||||
viewDate: dateUtils.addMonths(@state.viewDate, 1)
|
||||
|
@ -42,58 +47,19 @@ module.exports = React.createClass
|
|||
viewDate: dateUtils.addMonths(@state.viewDate, -1)
|
||||
direction: 'left'
|
||||
|
||||
# -- Render helpers
|
||||
isDaySelected: (day) ->
|
||||
isSameYear = @state.viewDate.getFullYear() == @state.selectedDate.getFullYear()
|
||||
isSameMonth = @state.viewDate.getMonth() == @state.selectedDate.getMonth()
|
||||
isSameDay = day == @state.selectedDate.getDate()
|
||||
if isSameYear && isSameMonth && isSameDay then 'active' else ''
|
||||
getValue: ->
|
||||
@state.selectedDate
|
||||
|
||||
# -- Render
|
||||
render: ->
|
||||
<div className={"#{css.root} #{@state.direction}"}>
|
||||
|
||||
{# Controllers to move to prev and next month }
|
||||
<FontIcon className={css.prevMonth} value='chevron_left' onClick={@decrementViewMonth} />
|
||||
<FontIcon className={css.nextMonth} value='chevron_right' onClick={@incrementViewMonth} />
|
||||
|
||||
{# Calendar itself }
|
||||
<FontIcon className={css.prev} value='chevron_left' onClick={@decrementViewMonth} />
|
||||
<FontIcon className={css.next} value='chevron_right' onClick={@incrementViewMonth} />
|
||||
<CTG transitionName='slide-horizontal'>
|
||||
<div key={@state.viewDate.getMonth()}>
|
||||
<div className={css.title}>
|
||||
{"#{dateUtils.monthInWords(@state.viewDate)}, #{@state.viewDate.getFullYear()}"}
|
||||
</div>
|
||||
|
||||
<div className={css.calendar}>
|
||||
<div className={css.calendarWeekDays}>
|
||||
{
|
||||
for i in [0..6]
|
||||
<span className={css.calendarWeekDay}
|
||||
key={"dw#{i}"}>
|
||||
{dateUtils.weekDayInWords(i).charAt(0)}
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
<div className={css.calendarBody}>
|
||||
<span key={"d1"}
|
||||
onClick={@onDayClick}
|
||||
className={css.calendarBodyDay + ' ' + @isDaySelected(1)}
|
||||
style={marginLeft: "#{dateUtils.firstWeekDay(@state.viewDate) * 100/7}%"}>
|
||||
1
|
||||
</span>
|
||||
{
|
||||
for i in [2..dateUtils.daysInMonth(@state.viewDate)]
|
||||
<span key={"d#{i}"}
|
||||
onClick={@onDayClick}
|
||||
className={css.calendarBodyDay + ' ' + @isDaySelected(i)}>
|
||||
{i}
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Month
|
||||
key={@state.viewDate.getMonth()}
|
||||
viewDate={@state.viewDate}
|
||||
selectedDate={@state.selectedDate}
|
||||
onDayClick={@onDayClick} />
|
||||
</CTG>
|
||||
</div>
|
||||
|
||||
getValue: ->
|
||||
@state.selectedDate
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
css = require './style'
|
||||
Day = require './day'
|
||||
util = require '../date_utils'
|
||||
|
||||
module.exports = React.createClass
|
||||
displayName: 'Month',
|
||||
|
||||
propTypes:
|
||||
onDayClick : React.PropTypes.func
|
||||
selectedDate : React.PropTypes.object
|
||||
viewDate : React.PropTypes.object
|
||||
|
||||
render: ->
|
||||
<div>
|
||||
<span>{ util.monthInWords(@props.viewDate)}, {@props.viewDate.getFullYear() }</span>
|
||||
<div className={css.week}>
|
||||
{ <span key={"dw#{i}"}>{ util.weekDayInWords(i).charAt(0) }</span> for i in [0..6] }
|
||||
</div>
|
||||
<div className={css.days}>
|
||||
{ for i in [1..util.daysInMonth(@props.viewDate)]
|
||||
<Day key={"d#{i}"}
|
||||
day={i}
|
||||
onClick={@props.onDayClick}
|
||||
selectedDate={@props.selectedDate}
|
||||
viewDate={@props.viewDate} /> }
|
||||
</div>
|
||||
</div>
|
|
@ -1,94 +1,78 @@
|
|||
@import '../constants'
|
||||
|
||||
// -- Calendar sizes
|
||||
monthHeight = 38px
|
||||
dayWidth = 38px
|
||||
innerPadding = 10px
|
||||
dayHeight = dayWidth
|
||||
calendarWidth = dayWidth * 7
|
||||
calendarHeight = dayHeight * 7
|
||||
totalHeight = monthHeight + calendarHeight + innerPadding * 2
|
||||
totalWidth = calendarWidth + innerPadding * 2
|
||||
ROW_HEIGHT = 40px
|
||||
TOTAL_HEIGHT = ROW_HEIGHT * 8
|
||||
|
||||
:local(.root)
|
||||
border-radius : 3px
|
||||
height : totalHeight
|
||||
background : WHITE
|
||||
height : TOTAL_HEIGHT
|
||||
font-size : 14px
|
||||
overflow : hidden
|
||||
position : relative
|
||||
line-height : ROW_HEIGHT
|
||||
text-align : center
|
||||
width : totalWidth
|
||||
|
||||
// -- Prev and next controls
|
||||
:local(.prevMonth), :local(.nextMonth)
|
||||
:local(.prev), :local(.next)
|
||||
cursor : pointer
|
||||
height : monthHeight
|
||||
line-height : monthHeight
|
||||
height : ROW_HEIGHT
|
||||
line-height : ROW_HEIGHT
|
||||
opacity : .7
|
||||
position : absolute
|
||||
text-align : center
|
||||
top : innerPadding
|
||||
width : dayWidth
|
||||
z-index : 2
|
||||
top : 0
|
||||
width : ROW_HEIGHT
|
||||
z-index : Z_INDEX_HIGH
|
||||
|
||||
:local(.prevMonth)
|
||||
left : innerPadding
|
||||
:local(.prev)
|
||||
left : 0
|
||||
|
||||
:local(.nextMonth)
|
||||
right : innerPadding
|
||||
:local(.next)
|
||||
right : 0
|
||||
|
||||
// -- Calendar
|
||||
:local(.title)
|
||||
font-size : 14px
|
||||
left : innerPadding
|
||||
line-height : monthHeight
|
||||
position : absolute
|
||||
right : innerPadding
|
||||
top : innerPadding
|
||||
|
||||
:local(.calendar)
|
||||
bottom : innerPadding
|
||||
font-size : 12px
|
||||
left : innerPadding
|
||||
position : absolute
|
||||
right : innerPadding
|
||||
top : monthHeight + innerPadding
|
||||
|
||||
:local(.calendarWeekDays)
|
||||
:local(.week)
|
||||
display : flex
|
||||
flex-wrap : wrap
|
||||
height : dayHeight
|
||||
line-height : dayHeight
|
||||
font-size : 13px
|
||||
height : ROW_HEIGHT
|
||||
line-height : ROW_HEIGHT
|
||||
opacity : .5
|
||||
|
||||
:local(.calendarWeekDay)
|
||||
flex : 0 0 (100/7)%
|
||||
> span
|
||||
flex : 0 0 (100/7)%
|
||||
|
||||
:local(.calendarBody)
|
||||
:local(.days)
|
||||
display : flex
|
||||
flex-wrap : wrap
|
||||
font-size : 13px
|
||||
|
||||
:local(.calendarBodyDay)
|
||||
border-radius : 50%
|
||||
cursor : pointer
|
||||
:local(.day)
|
||||
flex : 0 0 (100/7)%
|
||||
height : dayHeight
|
||||
line-height : dayHeight
|
||||
padding : 2px
|
||||
|
||||
&:hover:not(.active)
|
||||
> span
|
||||
border-radius : 50%
|
||||
cursor : pointer
|
||||
display : inline-block
|
||||
height : ROW_HEIGHT
|
||||
line-height : ROW_HEIGHT
|
||||
width : ROW_HEIGHT
|
||||
|
||||
&:hover:not(.active) > span
|
||||
background : lighten(ACCENT, 65%)
|
||||
color : white
|
||||
color : WHITE
|
||||
|
||||
&.active
|
||||
&.active > span
|
||||
background : ACCENT
|
||||
color : white
|
||||
color : WHITE
|
||||
|
||||
// -- Slide transitions
|
||||
// -- Transitions
|
||||
:local(.root) .slide-horizontal-enter, :local(.root) .slide-horizontal-leave
|
||||
transition : all .5s
|
||||
|
||||
// -- Slide horizontal transition left to right
|
||||
:local(.root).right
|
||||
.slide-horizontal-enter
|
||||
position : absolute
|
||||
transform : translateX(100%)
|
||||
opacity : 0
|
||||
|
||||
|
@ -100,9 +84,9 @@ totalWidth = calendarWidth + innerPadding * 2
|
|||
transform : translateX(-100%)
|
||||
opacity : 0
|
||||
|
||||
// -- Slide horizontal transition right to left
|
||||
:local(.root).left
|
||||
.slide-horizontal-enter
|
||||
position : absolute
|
||||
transform : translateX(-100%)
|
||||
opacity : 0
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
module.exports =
|
||||
daysInMonth: (date) ->
|
||||
(new Date(date.getFullYear(), date.getMonth(), 0)).getDate()
|
||||
(new Date(date.getFullYear(), date.getMonth() + 1, 0)).getDate()
|
||||
|
||||
firstWeekDay: (date) ->
|
||||
(new Date(date.getFullYear(), date.getMonth(), 1)).getDay()
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
localCSS = require './style'
|
||||
|
||||
module.exports = React.createClass
|
||||
displayName: 'FontIcon',
|
||||
|
||||
# -- States & Properties
|
||||
propTypes:
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
Calendar = require '../../components/calendar'
|
||||
|
||||
module.exports = React.createClass
|
||||
displayName: 'TestCalendar',
|
||||
|
||||
render: ->
|
||||
<Calendar />
|
||||
|
|
Loading…
Reference in New Issue