From 6ef0d5f8377d50d8efde86291f67c92c790b66f0 Mon Sep 17 00:00:00 2001 From: ibogdanov Date: Thu, 11 Feb 2016 14:41:07 -0800 Subject: [PATCH 01/13] progress --- .../SLDSCalendar/SLDSCalendarDay/index.js | 174 +++++++++++++ .../SLDSCalendar/SLDSCalendarWeek/index.js | 89 +++++++ .../SLDSTimepicker/SLDSCalendar/index.js | 245 ++++++++++++++++++ .../SLDSDatePicker/SLDSDatePickerNav/index.js | 123 +++++++++ .../SLDSTimepicker/SLDSDatePicker/index.js | 177 +++++++++++++ .../SLDSTimepicker/SLDSYearSelector/index.js | 66 +++++ components/SLDSTimepicker/index.jsx | 231 +++++++++++++++++ components/index.js | 2 + demo/index.js | 2 + demo/pages/TimePickerSection.js | 58 +++++ demo/pages/index.jsx | 2 + 11 files changed, 1169 insertions(+) create mode 100644 components/SLDSTimepicker/SLDSCalendar/SLDSCalendarDay/index.js create mode 100644 components/SLDSTimepicker/SLDSCalendar/SLDSCalendarWeek/index.js create mode 100644 components/SLDSTimepicker/SLDSCalendar/index.js create mode 100644 components/SLDSTimepicker/SLDSDatePicker/SLDSDatePickerNav/index.js create mode 100644 components/SLDSTimepicker/SLDSDatePicker/index.js create mode 100644 components/SLDSTimepicker/SLDSYearSelector/index.js create mode 100644 components/SLDSTimepicker/index.jsx create mode 100644 demo/pages/TimePickerSection.js diff --git a/components/SLDSTimepicker/SLDSCalendar/SLDSCalendarDay/index.js b/components/SLDSTimepicker/SLDSCalendar/SLDSCalendarDay/index.js new file mode 100644 index 0000000000..aa69615a43 --- /dev/null +++ b/components/SLDSTimepicker/SLDSCalendar/SLDSCalendarDay/index.js @@ -0,0 +1,174 @@ +/* +Copyright (c) 2015, salesforce.com, inc. All rights reserved. +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +'use strict'; + +import React from 'react'; +import {KEYS,EventUtil,DateUtil} from '../../../utils'; + +module.exports = React.createClass({ + + getDefaultProps () { + return { + + displayedDate:new Date(), + + selectedDate:new Date(), + + calendarHasFocus: false, + + onSelectDate (date) { + console.log('onSelectDate should be defined ',date); + }, + + onClick (index) { + console.log('onClick should be defined ',index); + }, + + onMoveFocus (delta){ + console.log('onMoveFocus should be defined ',delta); + }, + + onBlur (relatedTarget){ + console.log('onBlur should be defined ',relatedTarget); + }, + + onFocus (index, height) { + console.log('onFocus should be defined ',index,height); + }, + + onCancel () { + console.log('onCancel should be defined'); + } + + }; + }, + + handleClick (event) { + if(this.props.onSelectDate){ + this.props.onSelectDate(this.props.date); + } + if(event.nativeEvent){ + event.nativeEvent.stopImmediatePropagation(); + event.nativeEvent.preventDefault(); + } + }, + + handleToPrevDay(){ + if(this.props.onPrevDay){ + this.props.onPrevDay(this.props.date); + } + }, + + handleToNextDay(){ + if(this.props.onNextDay){ + this.props.onNextDay(this.props.date); + } + }, + + handleToPrevWeek(){ + if(this.props.onPrevWeek){ + this.props.onPrevWeek(this.props.date); + } + }, + + handleToNextWeek(){ + if(this.props.onNextWeek){ + this.props.onNextWeek(this.props.date); + } + }, + + handleKeyDown(event) { + if(event.keyCode){ + if(event.keyCode === KEYS.ENTER || + event.keyCode === KEYS.SPACE ){ + EventUtil.trapEvent(event); + if(this.props.onSelectDate){ + this.props.onSelectDate(this.props.date); + } + } + else if(event.keyCode === KEYS.ESCAPE){ + EventUtil.trapEvent(event); + if(this.props.onCancel){ + this.props.onCancel(); + } + } + else if(event.keyCode === KEYS.TAB){ +/* + if(!event.shiftKey){ + EventUtil.trapEvent(event); + if(this.props.onCancel){ + this.props.onCancel(); + } + } +*/ + } + else if(event.keyCode === KEYS.RIGHT){ + EventUtil.trapEvent(event); + this.handleToNextDay(); + } + else if(event.keyCode === KEYS.LEFT){ + EventUtil.trapEvent(event); + this.handleToPrevDay(); + } + else if(event.keyCode === KEYS.RIGHT){ + EventUtil.trapEvent(event); + this.handleToNextDay(); + } + else if(event.keyCode === KEYS.UP){ + EventUtil.trapEvent(event); + this.handleToPrevWeek(); + } + else if(event.keyCode === KEYS.DOWN){ + EventUtil.trapEvent(event); + this.handleToNextWeek(); + } + else{ + EventUtil.trapEvent(event); + } + } + }, + + setFocus () { + if(this.isMounted() && this.props.calendarHasFocus){ + this.getDOMNode().focus(); + } + }, + + render () { + + const isCurrentMonth = DateUtil.isSameMonth(this.props.date,this.props.displayedDate); + const isToday = DateUtil.isToday(this.props.date); + const isSelectedDay = DateUtil.isSameDay(this.props.date,this.props.selectedDate); + const isFirstDayOfMonth = DateUtil.isFirstDayOfMonth(this.props.date); + + return ( + + + {this.props.date.getDate()} + + + ); + }, + + componentDidUpdate (prevProps) { + if(this.props.focused && !prevProps.focused){ + this.setFocus(); + } + } + +}); diff --git a/components/SLDSTimepicker/SLDSCalendar/SLDSCalendarWeek/index.js b/components/SLDSTimepicker/SLDSCalendar/SLDSCalendarWeek/index.js new file mode 100644 index 0000000000..1b9b2a79b2 --- /dev/null +++ b/components/SLDSTimepicker/SLDSCalendar/SLDSCalendarWeek/index.js @@ -0,0 +1,89 @@ +/* +Copyright (c) 2015, salesforce.com, inc. All rights reserved. +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +'use strict'; + +import React from 'react'; + +import Day from '../SLDSCalendarDay/index'; +import {DateUtil} from '../../../utils'; + + +module.exports = React.createClass({ + + getDefaultProps () { + return { + displayedDate:new Date(), + selectedDate:new Date() + }; + }, + + handleSelectDate (day) { + if(this.props.onSelectDate){ + this.props.onSelectDate(day); + } + }, + + handleCancel () { + if(this.props.onCancel){ + this.props.onCancel(); + } + }, + + handlePrevDay (date) { + if(this.props.onPrevDay){ + this.props.onPrevDay(date); + } + }, + + handleNextDay (date) { + if(this.props.onNextDay){ + this.props.onNextDay(date); + } + }, + + handlePrevWeek (date) { + if(this.props.onPrevWeek){ + this.props.onPrevWeek(date); + } + }, + + handleNextWeek (date) { + if(this.props.onNextWeek){ + this.props.onNextWeek(date); + } + }, + + render: function() { + let days = []; + let date = this.props.date; + for (var i = 0; i < 7; i++) { + days.push(); + date = DateUtil.addDays(date,1); + } + + return + {days} + + } +}); diff --git a/components/SLDSTimepicker/SLDSCalendar/index.js b/components/SLDSTimepicker/SLDSCalendar/index.js new file mode 100644 index 0000000000..c42195188b --- /dev/null +++ b/components/SLDSTimepicker/SLDSCalendar/index.js @@ -0,0 +1,245 @@ +/* +Copyright (c) 2015, salesforce.com, inc. All rights reserved. +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +'use strict'; + +import React from 'react'; +import Week from './SLDSCalendarWeek/index'; +import {EventUtil, DateUtil, KEYS} from '../../utils'; + +module.exports = React.createClass({ + + displayName: 'SLDSCalendar', + + getDefaultProps () { + return { + displayedDate:new Date(), + selectedDate:new Date(), + weekDayLabels:['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'], + abbrWeekDayLabels:['S','M','T','W','T','F','S'], + todayLabel:'Today', + onSelectDate (date) { + console.log('onSelectDate should be defined ',date); + }, + + onCancel () { + console.log('onCancel should be defined'); + } + + }; + }, + + getInitialState () { + return { + highlightedDate: DateUtil.firstDayOfMonth(this.props.displayedDate), + hasFocus: false, + todayFocus: false, + }; + }, + + handleSelectDate (day) { + this.setState({selected:day}); + if(this.props.onSelectDate){ + this.props.onSelectDate(day); + } + }, + + handleCancel () { + if(this.props.onCancel){ + this.props.onCancel(); + } + }, + + handleChangeDisplayedDate (date) { + if(this.props.onChange){ + this.props.onChange(date); + } + }, + + handlePrevDay (date) { + const prevDate = DateUtil.addDays(date,-1); + if(!DateUtil.isSameMonth(prevDate,date)){ + this.handleChangeDisplayedDate(prevDate); + } + else{ + this.setState({highlightedDate:prevDate}); + } + }, + + handleNextDay (date) { + const nextDate = DateUtil.addDays(date,1); + if(!DateUtil.isSameMonth(nextDate,date)){ + this.handleChangeDisplayedDate(nextDate); + } + else{ + this.setState({highlightedDate:nextDate}); + } + }, + + handlePrevWeek (date) { + const prevDate = DateUtil.addDays(date,-7); + if(!DateUtil.isSameMonth(prevDate,date)){ + this.handleChangeDisplayedDate(prevDate); + } + else{ + this.setState({highlightedDate:prevDate}); + } + }, + + handleNextWeek (date) { + const nextDate = DateUtil.addDays(date,7); + if(!DateUtil.isSameMonth(nextDate,date)){ + this.handleChangeDisplayedDate(nextDate); + } + else{ + this.setState({highlightedDate:nextDate}); + } + }, + + handleTodaySelect () { + this.handleSelectDate(new Date()); + }, + + handleFocus () { + if(!this.state.todayFocus){ + this.setState({hasFocus:true}); + } + }, + + handleBlur () { + this.setState({hasFocus:false}); + }, + + handleTodayFocus () { + this.state.todayFocus = true; + }, + + handleTodayBlur () { + this.state.todayFocus = false; + }, + + handleKeyDown(event) { + if(event.keyCode){ + if(event.keyCode === KEYS.TAB){ + if(!event.shiftKey){ + EventUtil.trapEvent(event); + if(this.props.onCancel){ + this.props.onCancel(); + } + } + } + } + }, + + render () { + return (
+ + + + + + + + + + + + + + {this.renderWeeks()} + {this.renderToday()} + +
+ {this.props.abbrWeekDayLabels[0]} + + {this.props.abbrWeekDayLabels[1]} + + {this.props.abbrWeekDayLabels[2]} + + {this.props.abbrWeekDayLabels[3]} + + {this.props.abbrWeekDayLabels[4]} + + {this.props.abbrWeekDayLabels[5]} + + {this.props.abbrWeekDayLabels[6]} +
+
); + }, + + renderToday () { + return + + + {this.props.todayLabel} + + + ; + }, + + renderWeeks () { + const firstDayOfMonth = DateUtil.firstDayOfMonth(this.props.displayedDate); + + let date = firstDayOfMonth; + if(firstDayOfMonth.getDay()>0){ + const prevWeek = DateUtil.addWeeks(firstDayOfMonth,-1); + const nextSunday = DateUtil.nearestWeekDay(prevWeek,0); + date = nextSunday; + } + + let weeks = []; + let done = false; + + + let monthIndex = date.getMonth(); + let count = 0; + while (!done) { + weeks.push(); + date = DateUtil.addWeeks(date,1); + done = count++ > 2 && monthIndex !== date.getMonth(); + monthIndex = date.getMonth(); + } + var extra = 0; + while(weeks.length < 6){ + weeks.push( ); + } + + return weeks; + }, + + componentDidUpdate (prevProps) { + if( !DateUtil.isEqual(this.props.displayedDate,prevProps.displayedDate) ){ + this.setState({highlightedDate:this.props.displayedDate}); + } + } + +}); \ No newline at end of file diff --git a/components/SLDSTimepicker/SLDSDatePicker/SLDSDatePickerNav/index.js b/components/SLDSTimepicker/SLDSDatePicker/SLDSDatePickerNav/index.js new file mode 100644 index 0000000000..f9e553fd2a --- /dev/null +++ b/components/SLDSTimepicker/SLDSDatePicker/SLDSDatePickerNav/index.js @@ -0,0 +1,123 @@ +/* +Copyright (c) 2015, salesforce.com, inc. All rights reserved. +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +'use strict'; + +import React from 'react'; +import SLDSSelectYear from '../../SLDSYearSelector/index'; +import ButtonIcon from './../../../SLDSIcon/ButtonIcon'; +import {DateUtil, EventUtil, KEYS} from './../../../utils'; + +module.exports = React.createClass( { + + getDefaultProps (){ + return { + displayedDate:new Date(), + monthLabels:['January','February','March','April','May','June','July','August','September','October','November','December'], + onChangeMonth (){ + console.log('onChangeMonth should be defined'); + } + }; + }, + + handleClick (event){ + event.preventDefault(); + event.stopPropagation(); + }, + + handleChange (displayedDate){ + if(this.props.onChange){ + this.props.onChange(displayedDate); + } + }, + + handleCancel(){ + if(this.props.onCancel){ + this.props.onCancel(); + } + }, + + previousMonth (){ + if(this.props.displayedDate && this.handleChange){ + this.handleChange(DateUtil.addMonths(this.props.displayedDate,-1)); + } + + }, + + componentDidMount () { + }, + + nextMonth (){ + if(this.props.displayedDate && this.handleChange){ + this.handleChange(DateUtil.addMonths(this.props.displayedDate,1)); + } + }, + + handleYearSelect (displayedDate) { + if(this.props.onChange){ + this.props.onChange(displayedDate); + } + }, + + handleKeyDown (event) { + if(event.keyCode === KEYS.TAB){ + if(event.shiftKey){ + EventUtil.trapEvent(event); + this.handleCancel(); + } + } + }, + + getMonthLabel(){ + return this.props.monthLabels[new Date(this.props.displayedDate).getMonth()]; + }, + + render() { + return ( + +
+
+
+ +
+ +

{this.getMonthLabel()}

+
+ +
+
+
+ +
+
+ + ); + } +}); + diff --git a/components/SLDSTimepicker/SLDSDatePicker/index.js b/components/SLDSTimepicker/SLDSDatePicker/index.js new file mode 100644 index 0000000000..28554c5ec3 --- /dev/null +++ b/components/SLDSTimepicker/SLDSDatePicker/index.js @@ -0,0 +1,177 @@ +/* +Copyright (c) 2015, salesforce.com, inc. All rights reserved. +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +'use strict'; + +import React from 'react'; +import Calendar from '../SLDSCalendar/index'; +import SLDSDatePickerNav from './SLDSDatePickerNav/index'; +import {EventUtil} from './../../utils'; + +import {KEYS} from '../../utils'; + + +module.exports = React.createClass( { + + getDefaultProps () { + return { + selectedDate:new Date(), + value:new Date(), + onChange (date) { + console.log('onChange should be defined ',date); + }, + + onDisplayedDateChange (date) { + console.log('onDisplayedDateChange should be defined ',date); + }, + + onClose () { + console.log('onClose should be defined'); + }, + + }; + }, + + getInitialState () { + return { + displayedDate: this.props.selectedDate, + isFocused: false, + isClosing: false + }; + }, + + handleKeyDown(event) { + if(event.keyCode){ + if(event.keyCode === KEYS.ESCAPE){ + if(this.props.onClose){ + this.props.onClose(); + } + } + else if(event.keyCode === KEYS.SPACE){ + + } + else if(event.keyCode === KEYS.ENTER){ + + } + else if(event.keyCode === KEYS.TAB){ + } + else if(event.keyCode === KEYS.ESCAPE){ + } + else{ + EventUtil.trapEvent(event); + } + } + }, + + handleClickOutside (e) { + e.preventDefault(); + e.stopPropagation(); + if(this.props.onClose){ + this.props.onClose(); + } + }, + + handleDisplayedDateChange (displayedDate){ + if(this.props.onDisplayedDateChange){ + this.props.onDisplayedDateChange(displayedDate); + } + this.setState({displayedDate:displayedDate}); + }, + + handleSelectDate (selectedDate){ + if(this.props.onChange){ + this.props.onChange(selectedDate); + } + }, + + handleCancel () { + if(this.props.onClose){ + this.props.onClose(); + } + }, + + handleBGClick(event) { + if(event.nativeEvent){ + event.nativeEvent.preventDefault(); + } + }, + + handleFocus () { + this.setState({isFocused:true}); + }, + + handleBlur () { + this.setState({isFocused:false}); + }, + + render() { + + return ( +
+
+ + + Go to previous month + Go to next month +
+ +
+ ); + }, + + componentDidUpdate (prevProps, prevState) { + if(!this.state.isFocused && prevState.isFocused){ + this.setState({isClosing:true}); + + setTimeout ( () => { + + if(this.isMounted()){ + if(this.state.isClosing){ + if(this.state.isFocused){ + this.setState({isClosing:false}); + } + else{ + if(this.props.onClose){ + this.props.onClose(); + } + } + } + } + + + }); + + } + + } +}); + diff --git a/components/SLDSTimepicker/SLDSYearSelector/index.js b/components/SLDSTimepicker/SLDSYearSelector/index.js new file mode 100644 index 0000000000..2b773477d7 --- /dev/null +++ b/components/SLDSTimepicker/SLDSYearSelector/index.js @@ -0,0 +1,66 @@ +/* +Copyright (c) 2015, salesforce.com, inc. All rights reserved. +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +'use strict'; + +import React from 'react'; +import SLDSMenuPicklist from '../../SLDSMenuPicklist'; + +module.exports = React.createClass( { + + displayName: 'SLDSYearSelector', + + getDefaultProps (){ + return { + displayedDate:new Date(), + relativeYearFrom:-5, + relativeYearTo:5, + onChange (displayedDate){ + console.log('onChange should be defined: ',displayedDate); + } + }; + }, + + getOptions () { + const now = new Date(); + const fromYear = now.getFullYear()+this.props.relativeYearFrom; + const toYear = now.getFullYear()+this.props.relativeYearTo; + let opts = []; + + for (let year = fromYear; year < toYear; year++){ + opts.push({label:year,value:year}); + } + return opts; + }, + + handleSelect(selectedValue){ + if(selectedValue){ + if(this.props.onChange){ + this.props.onChange(new Date(this.props.displayedDate.setFullYear(parseInt(selectedValue.value)))); + } + } + }, + + render() { + return ( +
+ + +
+ ); + } +}); diff --git a/components/SLDSTimepicker/index.jsx b/components/SLDSTimepicker/index.jsx new file mode 100644 index 0000000000..fe285f3929 --- /dev/null +++ b/components/SLDSTimepicker/index.jsx @@ -0,0 +1,231 @@ +/* +Copyright (c) 2015, salesforce.com, inc. All rights reserved. +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +'use strict'; + +import React from 'react'; +import ReactDOM from 'react-dom'; +import SLDSPopover from '../SLDSPopover'; +import SLDSDatePicker from './SLDSDatePicker/index'; +import InputIcon from '../SLDSIcon/InputIcon'; + +import {KEYS,EventUtil} from '../utils'; + +const displayName = 'SLDSTimepicker'; +const propTypes = { + abbrWeekDayLabels: React.PropTypes.array, + + /** + * Date formatting function + */ + formatter: React.PropTypes.func, + + monthLabels: React.PropTypes.array, + + /** + * Parsing date string into Date + */ + parser: React.PropTypes.func, + + relativeYearFrom: React.PropTypes.number, + + relativeYearTo: React.PropTypes.number, + + todayLabel: React.PropTypes.string, + + /** + * Date + */ + value: React.PropTypes.instanceOf(Date), + + strValue: React.PropTypes.string, + + weekDayLabels: React.PropTypes.array, + + +}; +const defaultProps = { + abbrWeekDayLabels: ['S','M','T','W','T','F','S'], + formatter (date) { + if(date){ + return (date.getMonth()+1) + + '/'+date.getDate() + + '/'+date.getFullYear(); + } + }, + monthLabels: [ + 'January','February','March', + 'April','May','June','July', + 'August','September','October', + 'November','December' + ], + onDateChange (date) { + console.log('onDateChange should be defined'); + }, + parser (str) { + return new Date(str); + }, + placeholder: 'Pick a Date', + relativeYearFrom: -5, + relativeYearTo: 5, + todayLabel: 'Today', + value: null, + weekDayLabels: [ + 'Sunday','Monday','Tuesday', + 'Wednesday','Thursday','Friday', + 'Saturday' + ], +}; + +module.exports = React.createClass({ + + displayName: displayName, + + propTypes: propTypes, + + getDefaultProps(){ + return defaultProps; + }, + + getInitialState(){ + return { + isOpen:false, + value:this.props.value, + strValue:this.props.strValue + }; + }, + + handleChange(date) { + this.setState({ + value:date, + strValue:this.props.formatter(date), + isOpen:false + }); + if(this.props.onDateChange){ + this.props.onDateChange(date); + } + }, + + handleClose() { + this.setState({isOpen:false}); + this.setFocus(); + }, + + handleClick() { + this.setState({isOpen:true}); + }, + + handleFocus() { +// this.setState({isOpen:true}) + }, + + handleBlur() { +// this.setState({isOpen:false}) + }, + + setFocus () { + if(this.isMounted()){ + ReactDOM.findDOMNode(this.refs.date).focus(); + } + }, + + parseDate(strValue) { + const d = this.props.parser(strValue); + if ( Object.prototype.toString.call(d) === "[object Date]" ) { + if ( !isNaN( d.getTime() ) ) { + return d; + } + } + return new Date(); + }, + + popover() { + if(this.state && this.state.isOpen){ + const date = this.state.strValue?this.parseDate(this.state.strValue):this.state.value; + return + + ; + } + return ; + }, + + handleInputChange() { + const string = ReactDOM.findDOMNode(this.refs.date).value; + if(string){ + this.setState({ + strValue:string + }); + if(this.props.onDateChange){ + const d = this.props.parser(string) + this.props.onDateChange(d); + } + } + else{ + this.setState({ + isOpen:false + }); + } + }, + + handleKeyDown(event) { + if (event.keyCode){ + if (event.keyCode === KEYS.ENTER || + event.keyCode === KEYS.SPACE || + event.keyCode === KEYS.DOWN || + event.keyCode === KEYS.UP){ + EventUtil.trapEvent(event); + + this.setState({ + isOpen:true + }); + } + } + }, + + getInputIcon(){ + return ; + }, + + render() { + return ( +
+ +
+
+ + { this.getInputIcon() } + +
+
+ {this.popover()} +
+ ); + } +}); diff --git a/components/index.js b/components/index.js index 940287fdc5..0b8cad78a0 100644 --- a/components/index.js +++ b/components/index.js @@ -21,6 +21,7 @@ import SLDSModalTrigger from './SLDSModal/trigger'; import SLDSNotification from './SLDSNotification'; import SLDSPopoverTooltip from './SLDSPopoverTooltip'; import SLDSDatepickerSingleSelect from './SLDSDatepickerSingleSelect'; +import SLDSTimepicker from './SLDSTimepicker'; import SLDSSettings from './SLDSSettings'; import SLDSUtilityIcon from './SLDSUtilityIcon'; @@ -37,6 +38,7 @@ module.exports = { SLDSModalTrigger: SLDSModalTrigger, SLDSNotification: SLDSNotification, SLDSPopoverTooltip: SLDSPopoverTooltip, + SLDSTimepicker: SLDSTimepicker, SLDSSettings: SLDSSettings, SLDSUtilityIcon: SLDSUtilityIcon, }; diff --git a/demo/index.js b/demo/index.js index 9eb6ddbf68..404000682a 100644 --- a/demo/index.js +++ b/demo/index.js @@ -17,6 +17,7 @@ import ButtonStatefulSection from './pages/ButtonStatefulSection'; import ButtonGroupSection from './pages/ButtonGroupSection'; import DateInputSection from './pages/DateInputSection'; import DatePickerSingleSelectSection from './pages/DatePickerSingleSelectSection'; +import TimePickerSection from './pages/TimePickerSection'; import DropdownBaseSection from './pages/DropdownSection'; import IconSection from './pages/IconSection'; import LookupSection from './pages/LookupSection'; @@ -37,6 +38,7 @@ const routes = ( + diff --git a/demo/pages/TimePickerSection.js b/demo/pages/TimePickerSection.js new file mode 100644 index 0000000000..854c964a7c --- /dev/null +++ b/demo/pages/TimePickerSection.js @@ -0,0 +1,58 @@ +/* +Copyright (c) 2015, salesforce.com, inc. All rights reserved. +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +import React from 'react'; +import CodeMirror from 'demo/CodeMirror'; +import Samples from 'demo/Samples'; +import PropTable from 'demo/PropTable'; +import DOCS from 'docs'; +import ComponentHeader from 'demo/pages/components/componentHeader'; + +const displayName = "DatepickerSingleSelectSection"; +const propTypes = {}; +const defaultProps = {}; + +class DatepickerSingleSelectSection extends React.Component { + + constructor(props) { + super(props); + this.state = {}; + } + + getDescription() { + const desc = DOCS["DatepickerSingleSelect"].description; + return {__html: desc }; + } + + render(){ + const docs = DOCS["DatepickerSingleSelect"] ? true : false; + return ( +
+ TIMEPICKER + +
+ {docs ?

: null} +

+ +
+ +
+ +
+ ); + } + +} + +DatepickerSingleSelectSection.displayName = displayName; +DatepickerSingleSelectSection.propTypes = propTypes; +DatepickerSingleSelectSection.defaultProps = defaultProps; + +module.exports = DatepickerSingleSelectSection; + diff --git a/demo/pages/index.jsx b/demo/pages/index.jsx index 2bb011aea0..fc55f6133f 100644 --- a/demo/pages/index.jsx +++ b/demo/pages/index.jsx @@ -69,6 +69,8 @@ module.exports = React.createClass( {
  • Modal
  • Notification
  • PopoverTooltip
  • +
  • TimePicker
  • + From 79511a01a53fa9f7d908bec0cef819097154d7c0 Mon Sep 17 00:00:00 2001 From: ibogdanov Date: Thu, 11 Feb 2016 15:10:15 -0800 Subject: [PATCH 02/13] progess --- components/SLDSTimepicker/index.jsx | 4 ++-- demo/CodeMirror.jsx | 3 +-- demo/Samples.js | 1 + demo/code-snippets/TimepickerExample.js | 6 ++++++ demo/index.js | 2 +- demo/pages/TimePickerSection.js | 4 ++-- 6 files changed, 13 insertions(+), 7 deletions(-) create mode 100644 demo/code-snippets/TimepickerExample.js diff --git a/components/SLDSTimepicker/index.jsx b/components/SLDSTimepicker/index.jsx index fe285f3929..5d0102a430 100644 --- a/components/SLDSTimepicker/index.jsx +++ b/components/SLDSTimepicker/index.jsx @@ -71,7 +71,7 @@ const defaultProps = { parser (str) { return new Date(str); }, - placeholder: 'Pick a Date', + placeholder: 'Pick Time', relativeYearFrom: -5, relativeYearTo: 5, todayLabel: 'Today', @@ -199,7 +199,7 @@ module.exports = React.createClass({ }, getInputIcon(){ - return ; + return ; }, render() { diff --git a/demo/CodeMirror.jsx b/demo/CodeMirror.jsx index aeb1f3866d..561f46a7fd 100644 --- a/demo/CodeMirror.jsx +++ b/demo/CodeMirror.jsx @@ -9,7 +9,6 @@ const ReactDOM = require('react-dom'); const classNames = require('classnames'); const trim = require('lodash.trim'); - const SLDSButton = require('../components/SLDSButton'); const SLDSButtonStateful = require('../components/SLDSButtonStateful'); const SLDSButtonGroup = require('../components/SLDSButtonGroup'); @@ -22,7 +21,7 @@ const SLDSModal = require('../components/SLDSModal'); const SLDSNotification = require('../components/SLDSNotification'); const SLDSPopoverTooltip = require('../components/SLDSPopoverTooltip'); const SLDSDatepickerSingleSelect = require('../components/SLDSDatepickerSingleSelect'); - +const SLDSTimepicker = require('../components/SLDSTimepicker'); const displayName = 'CodeMirror'; const propTypes = { diff --git a/demo/Samples.js b/demo/Samples.js index 16b81d3c2a..535c54d567 100644 --- a/demo/Samples.js +++ b/demo/Samples.js @@ -22,6 +22,7 @@ const Samples = { Tooltips2: require('fs').readFileSync('demo/code-snippets/TooltipExamples2.js', 'utf8'), Tooltips3: require('fs').readFileSync('demo/code-snippets/TooltipExamples3.js', 'utf8'), DatepickerSingleSelect: require('fs').readFileSync('demo/code-snippets/DateInputExample-1.js', 'utf8'), + Timepicker: require('fs').readFileSync('demo/code-snippets/TimepickerExample.js', 'utf8'), }; module.exports = Samples; diff --git a/demo/code-snippets/TimepickerExample.js b/demo/code-snippets/TimepickerExample.js new file mode 100644 index 0000000000..8c7fac03f9 --- /dev/null +++ b/demo/code-snippets/TimepickerExample.js @@ -0,0 +1,6 @@ +
    TIMEPICKER!
    +>> onDateChange ', date); + }} +/> \ No newline at end of file diff --git a/demo/index.js b/demo/index.js index 404000682a..7cf6632ab5 100644 --- a/demo/index.js +++ b/demo/index.js @@ -38,7 +38,7 @@ const routes = ( - + diff --git a/demo/pages/TimePickerSection.js b/demo/pages/TimePickerSection.js index 854c964a7c..0c9fcf594f 100644 --- a/demo/pages/TimePickerSection.js +++ b/demo/pages/TimePickerSection.js @@ -34,14 +34,14 @@ class DatepickerSingleSelectSection extends React.Component { const docs = DOCS["DatepickerSingleSelect"] ? true : false; return (
    - TIMEPICKER + TIME PICKER
    {docs ?

    : null}

    - +
    From 2305769edd00610724c90a726be9f461c7e60fb1 Mon Sep 17 00:00:00 2001 From: ibogdanov Date: Thu, 11 Feb 2016 15:25:59 -0800 Subject: [PATCH 03/13] progress --- components/SLDSTimepicker/index.jsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/SLDSTimepicker/index.jsx b/components/SLDSTimepicker/index.jsx index 5d0102a430..f0b6626d09 100644 --- a/components/SLDSTimepicker/index.jsx +++ b/components/SLDSTimepicker/index.jsx @@ -14,6 +14,7 @@ import ReactDOM from 'react-dom'; import SLDSPopover from '../SLDSPopover'; import SLDSDatePicker from './SLDSDatePicker/index'; import InputIcon from '../SLDSIcon/InputIcon'; +import SLDSYearSelector from './SLDSYearSelector/index'; import {KEYS,EventUtil} from '../utils'; @@ -149,6 +150,7 @@ module.exports = React.createClass({ if(this.state && this.state.isOpen){ const date = this.state.strValue?this.parseDate(this.state.strValue):this.state.value; return +{/* +*/} +
    TIME SELECTOR
    ; } return ; From 732c4395a4b32abbbc72362b47eace4dd19b509c Mon Sep 17 00:00:00 2001 From: ibogdanov Date: Thu, 11 Feb 2016 17:08:07 -0800 Subject: [PATCH 04/13] progress --- components/SLDSMenuList/ListItem.jsx | 193 ++++++++++++++++++++++ components/SLDSMenuList/ListItemLabel.jsx | 54 ++++++ components/SLDSMenuList/index.jsx | 183 ++++++++++++++++++++ components/SLDSMenuPicklist/index.jsx | 6 +- components/SLDSTimepicker/index.jsx | 25 +++ 5 files changed, 457 insertions(+), 4 deletions(-) create mode 100644 components/SLDSMenuList/ListItem.jsx create mode 100644 components/SLDSMenuList/ListItemLabel.jsx create mode 100644 components/SLDSMenuList/index.jsx diff --git a/components/SLDSMenuList/ListItem.jsx b/components/SLDSMenuList/ListItem.jsx new file mode 100644 index 0000000000..48b667ec2e --- /dev/null +++ b/components/SLDSMenuList/ListItem.jsx @@ -0,0 +1,193 @@ +/* +Copyright (c) 2015, salesforce.com, inc. All rights reserved. +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +import React from 'react'; +import ReactDOM from 'react-dom'; + +import KEYS from '../utils/KEYS'; +import EventUtil from '../utils/EventUtil'; +import ListItemLabelRenderer from './ListItemLabel'; + +const displayName = "SLDSList-Item"; +const propTypes = { + data: React.PropTypes.object, + checkmark: React.PropTypes.bool, + index: React.PropTypes.number, + inverted: React.PropTypes.bool, + isHighlighted: React.PropTypes.bool, + isSelected: React.PropTypes.bool, + label: React.PropTypes.string, + labelRenderer: React.PropTypes.func, + value: React.PropTypes.any, + onBlur: React.PropTypes.func, + onClick: React.PropTypes.func, + onFocus: React.PropTypes.func, + onMoveFocus: React.PropTypes.func, + onSelect: React.PropTypes.func, +}; +const defaultProps = { + data: {}, + index: 0, + inverted: false, + isHighlighted: false, + isSelected: false, + label: '', + labelRenderer: ListItemLabelRenderer, + onBlur (relatedTarget){ + console.log('onBlur should be defined ',relatedTarget); + }, + onClick (index) { + console.log('onClick should be defined ',index); + }, + onFocus (index, height) { + console.log('onFocus should be defined ',index,height); + }, + onMoveFocus (delta){ + console.log('onMoveFocus should be defined ',delta); + }, + onSelect (index) { + console.log('onSelect should be defined ',index); + }, + value: null, +}; + +class SLDSListItem extends React.Component { + handleClick (e) { + e.preventDefault(); + e.stopPropagation(); + if(this.props.onSelect){ + this.props.onSelect(this.props.index); + } + } + + handleMouseDown (e) { + if(e.nativeEvent){ + e.nativeEvent.preventDefault(); + e.nativeEvent.stopImmediatePropagation(); + } + e.preventDefault(); + } + + componentDidMount(){ + if(this.props.isHighlighted){ + this.setFocus(); + } + } + + componentDidUpdate( prevProps, prevState) { + if(!prevProps.isHighlighted && this.props.isHighlighted){ + this.setFocus(); + } + } + + setFocus () { + if(!this.props.isHover){ + ReactDOM.findDOMNode(this.refs.link).focus(); + } + } + + handleKeyDown(event) { + if(event.keyCode){ + if(event.keyCode === KEYS.DOWN){ + EventUtil.trapEvent(event); + if(this.props.onMoveFocus){ + this.props.onMoveFocus(1); + } + } + else if(event.keyCode === KEYS.UP){ + EventUtil.trapEvent(event); + if(this.props.onMoveFocus){ + this.props.onMoveFocus(-1); + } + } + else if(event.keyCode === KEYS.ENTER || + event.keyCode === KEYS.SPACE ){ + EventUtil.trapEvent(event); + if(this.props.onSelect){ + this.props.onSelect(this.props.index); + } + } + else if(event.keyCode === KEYS.ESCAPE){ + EventUtil.trapEvent(event); + if(this.props.onCancel){ + this.props.onCancel(); + } + } + else if(event.keyCode === KEYS.TAB){ + } + else{ + EventUtil.trapEvent(event); + const ch = String.fromCharCode(event.keyCode); + if(this.props.onSearch){ + this.props.onSearch(this.props.index,ch); + } + } + } + } + + handleBlur(e) { + if(this.props.onBlur){ + this.props.onBlur(this.props.index, e.relatedTarget); + } + } + + handleFocus () { + const height = ReactDOM.findDOMNode(this).offsetHeight; + if(height && this.props.onFocus){ + this.props.onFocus(this.props.index,height); + } + } + + getLabel () { + const LabelComp = this.props.labelRenderer; + return ; + } + + render () { + let isSelected = this.props.isSelected ? " slds-is-selected" : ""; + return ( +
  • + + {this.getLabel()} + +
  • + ); + } +} + +SLDSListItem.displayName = displayName; +SLDSListItem.propTypes = propTypes; +SLDSListItem.defaultProps = defaultProps; + +module.exports = SLDSListItem; + diff --git a/components/SLDSMenuList/ListItemLabel.jsx b/components/SLDSMenuList/ListItemLabel.jsx new file mode 100644 index 0000000000..7341857efe --- /dev/null +++ b/components/SLDSMenuList/ListItemLabel.jsx @@ -0,0 +1,54 @@ +/* +Copyright (c) 2015, salesforce.com, inc. All rights reserved. +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +import React from 'react'; +import SLDSIcon from '../SLDSIcon'; + +const displayName = "SLDSList-Item-Label"; +const propTypes = { + data: React.PropTypes.object, + index: React.PropTypes.number, + inverted: React.PropTypes.bool, + isHighlighted: React.PropTypes.bool, + isSelected: React.PropTypes.bool, + label: React.PropTypes.string, + value: React.PropTypes.string, +}; +const defaultProps = { + data: {}, + index: 0, + inverted: false, + isHighlighted: false, + isSelected: false, + label: '', + value: null, +}; + +class SLDSListItemLabel extends React.Component { + + constructor(props) { + super(props); + this.state = {}; + } + render() { + return ( +

    + {this.props.checkmark ? : null} + {this.props.label} +

    + ) + } +} + +SLDSListItemLabel.displayName = displayName; +SLDSListItemLabel.propTypes = propTypes; +SLDSListItemLabel.defaultProps = defaultProps; + +module.exports = SLDSListItemLabel; + diff --git a/components/SLDSMenuList/index.jsx b/components/SLDSMenuList/index.jsx new file mode 100644 index 0000000000..dba9cb8227 --- /dev/null +++ b/components/SLDSMenuList/index.jsx @@ -0,0 +1,183 @@ +/* +Copyright (c) 2015, salesforce.com, inc. All rights reserved. +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +import React from 'react'; +import ReactDOM from 'react-dom'; + +import ListItem from "./ListItem"; +import EventUtil from '../utils/EventUtil'; + +const displayName = "SLDSList"; +const propTypes = { + className: React.PropTypes.string, + checkmark: React.PropTypes.bool, + highlightedIndex: React.PropTypes.number, + itemRenderer: React.PropTypes.func, + options: React.PropTypes.array, + onCancel: React.PropTypes.func, + onListBlur: React.PropTypes.func, + onListItemBlur: React.PropTypes.func, + onMoveFocus: React.PropTypes.func, + onSelect: React.PropTypes.func, + selectedIndex: React.PropTypes.number, +}; +const defaultProps = { + className: '', + highlightedIndex: 0, + itemRenderer: null, + options: [], + onCancel: (delta)=>{ + console.log("onCancel should be overwritten"); + }, + onListBlur: () => { + console.log("onListBlur should be overwritten"); + }, + onListItemBlur: (listItemIndex)=>{ + console.log("onListItemBlur should be overwritten"); + }, + onMoveFocus: (delta)=>{ + console.log("onMoveFocus should be overwritten"); + }, + onSelect: (index)=>{ + console.log("onSelect should be overwritten"); + }, + selectedIndex: -1, +}; + +class SLDSList extends React.Component { + handleMouseDown (event) { + EventUtil.trapImmediate(event); + } + + handleClick (e) { + if(e.nativeEvent){ + e.nativeEvent.preventDefault(); + e.nativeEvent.stopImmediatePropagation(); + } + e.preventDefault(); + } + + handleUpdateHighlighted (nextIndex) { + if(this.props.onUpdateHighlighted){ + this.props.onUpdateHighlighted(nextIndex); + } + } + + handleListItemBlur (index, relatedTarget) { + if(this.props.onListItemBlur){ + this.props.onListItemBlur(index); + } + this.setState({lastBlurredIndex:index}); + } + + handleMoveFocus (delta) { + let newHighlightedIndex = this.props.highlightedIndex + delta; + if(newHighlightedIndex < 0){ + newHighlightedIndex = this.props.options.length - 1; + } + else if(newHighlightedIndex >= this.props.options.length){ + newHighlightedIndex = 0; + } + if(this.props.onUpdateHighlighted){ + this.props.onUpdateHighlighted(newHighlightedIndex); + } + } + + handleCancel () { + if(this.props.onCancel){ + this.props.onCancel(); + } + } + + handleSelect (index) { + if(this.props.onSelect){ + this.props.onSelect(index); + } + } + + handleItemFocus (itemIndex, itemHeight) { + if(this.refs.scroll){ + ReactDOM.findDOMNode(this.refs.scroll).scrollTop = itemIndex * itemHeight; + } + } + + handleSearch (index, ch) { + const searchChar = ch.toLowerCase(); + for(let i=index+1;i{ + return ( + + ); + }); + } + + render () { + return ( +
      + {this.getItems()} +
    + ); + } +} + +SLDSList.displayName = displayName; +SLDSList.propTypes = propTypes; +SLDSList.defaultProps = defaultProps; + +module.exports = SLDSList; + diff --git a/components/SLDSMenuPicklist/index.jsx b/components/SLDSMenuPicklist/index.jsx index a2dca9852a..7e4a56ab83 100644 --- a/components/SLDSMenuPicklist/index.jsx +++ b/components/SLDSMenuPicklist/index.jsx @@ -14,9 +14,8 @@ import isEqual from "lodash.isequal"; import SLDSPopover from "../SLDSPopover"; import {KEYS, EventUtil} from "../utils"; import SLDSIcon from "../SLDSIcon"; -import List from "./List"; -import ListItem from "./ListItem"; -import ListItemLabel from "./ListItemLabel"; +import List from "../SLDSMenuList"; +import ListItemLabel from "../SLDSMenuList/ListItemLabel"; const displayName = "SLDSMenuPicklist"; const propTypes = { @@ -298,6 +297,5 @@ SLDSMenuPicklist.propTypes = propTypes; SLDSMenuPicklist.defaultProps = defaultProps; module.exports = SLDSMenuPicklist; -module.exports.ListItem = ListItem; module.exports.ListItemLabel = ListItemLabel; diff --git a/components/SLDSTimepicker/index.jsx b/components/SLDSTimepicker/index.jsx index f0b6626d09..927ea21191 100644 --- a/components/SLDSTimepicker/index.jsx +++ b/components/SLDSTimepicker/index.jsx @@ -15,6 +15,8 @@ import SLDSPopover from '../SLDSPopover'; import SLDSDatePicker from './SLDSDatePicker/index'; import InputIcon from '../SLDSIcon/InputIcon'; import SLDSYearSelector from './SLDSYearSelector/index'; +import SLDSMenuPicklist from '../SLDSMenuPicklist/index'; + import {KEYS,EventUtil} from '../utils'; @@ -146,6 +148,18 @@ module.exports = React.createClass({ return new Date(); }, + getOptions () { + const now = new Date(); + const fromYear = now.getFullYear()-5; + const toYear = now.getFullYear()+5; + let opts = []; + + for (let year = fromYear; year < toYear; year++){ + opts.push({label:year,value:year}); + } + return opts; + }, + popover() { if(this.state && this.state.isOpen){ const date = this.state.strValue?this.parseDate(this.state.strValue):this.state.value; @@ -163,7 +177,18 @@ module.exports = React.createClass({ relativeYearTo={this.props.relativeYearTo} selectedDate={date?date:new Date()} /> */} +{/*
    TIME SELECTOR
    +*/} + ; } return ; From f44d686cd238488598df85cde4d74e425e9e3ecb Mon Sep 17 00:00:00 2001 From: ibogdanov Date: Thu, 11 Feb 2016 17:51:58 -0800 Subject: [PATCH 05/13] progress --- .../List.jsx | 0 components/SLDSMenuList/index.jsx | 319 +++++++++++------- components/SLDSMenuPicklist/ListItem.jsx | 193 ----------- components/SLDSMenuPicklist/ListItemLabel.jsx | 54 --- components/SLDSMenuPicklist/index.jsx | 2 +- components/SLDSTimepicker/index.jsx | 59 ++-- 6 files changed, 228 insertions(+), 399 deletions(-) rename components/{SLDSMenuPicklist => SLDSMenuList}/List.jsx (100%) delete mode 100644 components/SLDSMenuPicklist/ListItem.jsx delete mode 100644 components/SLDSMenuPicklist/ListItemLabel.jsx diff --git a/components/SLDSMenuPicklist/List.jsx b/components/SLDSMenuList/List.jsx similarity index 100% rename from components/SLDSMenuPicklist/List.jsx rename to components/SLDSMenuList/List.jsx diff --git a/components/SLDSMenuList/index.jsx b/components/SLDSMenuList/index.jsx index dba9cb8227..c05d017093 100644 --- a/components/SLDSMenuList/index.jsx +++ b/components/SLDSMenuList/index.jsx @@ -7,177 +7,238 @@ Neither the name of salesforce.com, inc. nor the names of its contributors may b THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import React from 'react'; -import ReactDOM from 'react-dom'; +import React from "react"; +import ReactDOM from "react-dom"; +import isEqual from "lodash.isequal"; -import ListItem from "./ListItem"; -import EventUtil from '../utils/EventUtil'; +import {KEYS, EventUtil} from "../utils"; +import SLDSIcon from "../SLDSIcon"; +import List from "./List"; +import ListItemLabel from "./ListItemLabel"; -const displayName = "SLDSList"; +const displayName = "SLDSMenuList"; const propTypes = { className: React.PropTypes.string, + /** + * If true, renders checkmark icon on the selected Menu Item. + */ checkmark: React.PropTypes.bool, - highlightedIndex: React.PropTypes.number, - itemRenderer: React.PropTypes.func, - options: React.PropTypes.array, - onCancel: React.PropTypes.func, - onListBlur: React.PropTypes.func, - onListItemBlur: React.PropTypes.func, - onMoveFocus: React.PropTypes.func, + disabled: React.PropTypes.bool, + label: React.PropTypes.string, + /** + * Custom element that overrides the default Menu Item component. + */ + listItemRenderer: React.PropTypes.node, + /** + * If true, component renders specifically to work inside Modal. + */ + modal: React.PropTypes.bool, + onClick: React.PropTypes.func, onSelect: React.PropTypes.func, - selectedIndex: React.PropTypes.number, + /** + * Menu item data. + */ + options: React.PropTypes.array.isRequired, + placeholder: React.PropTypes.string, + required: React.PropTypes.bool, + /** + * Current selected item. + */ + value: React.PropTypes.node, }; const defaultProps = { - className: '', - highlightedIndex: 0, - itemRenderer: null, - options: [], - onCancel: (delta)=>{ - console.log("onCancel should be overwritten"); - }, - onListBlur: () => { - console.log("onListBlur should be overwritten"); - }, - onListItemBlur: (listItemIndex)=>{ - console.log("onListItemBlur should be overwritten"); - }, - onMoveFocus: (delta)=>{ - console.log("onMoveFocus should be overwritten"); - }, - onSelect: (index)=>{ - console.log("onSelect should be overwritten"); - }, - selectedIndex: -1, + disabled: false, + modal: true, + required: false, + placeholder: "Select an Option", + checkmark: true }; -class SLDSList extends React.Component { - handleMouseDown (event) { - EventUtil.trapImmediate(event); +/** + * The SLDSMenuPicklist component is a variant of the Ligtning Design System Menu component. + */ +class SLDSMenuPicklist extends React.Component { + constructor(props) { + super(props); + this.state = { + highlightedIndex: 0, + isOpen: false, + isFocused: false, + lastBlurredIndex: -1, + lastBlurredTimeStamp: -1, + selectedIndex: this.getIndexByValue(this.props.value), + /* triggerId is the id of the element that triggers the Menu to open. + * Need this for aria-labelledby on
      in Menu for accessibility. */ + triggerId: this.props.label ? this.props.label.replace(/\s+/g, '') + '_Button': 'Picklist_Button', + }; } - handleClick (e) { - if(e.nativeEvent){ - e.nativeEvent.preventDefault(); - e.nativeEvent.stopImmediatePropagation(); - } - e.preventDefault(); + componentWillUnmount(){ + this.isUnmounting = true; } - handleUpdateHighlighted (nextIndex) { - if(this.props.onUpdateHighlighted){ - this.props.onUpdateHighlighted(nextIndex); + componentDidUpdate( prevProps, prevState) { + if(this.state.lastBlurredTimeStamp !== prevState.lastBlurredTimeStamp){ + if(this.state.lastBlurredIndex === this.state.highlightedIndex){ + this.handleClose(); + } + } + if(this.state.selectedIndex !== prevState.selectedIndex){ + this.handleClose(); + } + else if(this.state.isFocused && !prevState.isFocused){ + this.setState({isOpen: false}); + } + else if(!this.state.isFocused && prevState.isFocused){ + if(this.refs.list){ + if(!this.isUnmounting && this.refs.list){ + if(ReactDOM.findDOMNode(this.refs.list).contains(document.activeElement)){ + return; + } + this.setState({isOpen: false}) + } + } } - } - handleListItemBlur (index, relatedTarget) { - if(this.props.onListItemBlur){ - this.props.onListItemBlur(index); + if(this.props.value !== prevProps.value || + !isEqual(this.props.options, prevProps.options)){ + var newSelectedIndex = this.getIndexByValue(this.props.value); + if (newSelectedIndex !== this.state.selectedIndex) { + this.handleSelect(newSelectedIndex); + } } - this.setState({lastBlurredIndex:index}); } - handleMoveFocus (delta) { - let newHighlightedIndex = this.props.highlightedIndex + delta; - if(newHighlightedIndex < 0){ - newHighlightedIndex = this.props.options.length - 1; - } - else if(newHighlightedIndex >= this.props.options.length){ - newHighlightedIndex = 0; - } - if(this.props.onUpdateHighlighted){ - this.props.onUpdateHighlighted(newHighlightedIndex); + getIndexByValue(value){ + let foundIndex = -1; + if(this.props.options && this.props.options.length){ + this.props.options.some((element, index, array)=>{ + if(element && element.value === value){ + foundIndex = index; + return true; + } + return false; + }); } + return foundIndex; } - handleCancel () { - if(this.props.onCancel){ - this.props.onCancel(); + getValueByIndex(index){ + const option = this.props.options[index]; + if(option){ + return this.props.options[index]; } } - handleSelect (index) { + handleSelect(index) { + this.setState({selectedIndex: index}) + this.setFocus(); if(this.props.onSelect){ - this.props.onSelect(index); + this.props.onSelect(this.getValueByIndex(index)); } } - handleItemFocus (itemIndex, itemHeight) { - if(this.refs.scroll){ - ReactDOM.findDOMNode(this.refs.scroll).scrollTop = itemIndex * itemHeight; + handleClose() { + this.setState({isOpen: false}); + } + + handleClick() { + if(!this.state.isOpen){ + this.setState({isOpen: true}); + if(this.props.onClick) this.props.onClick(); + } + else{ + this.handleClose(); } } - handleSearch (index, ch) { - const searchChar = ch.toLowerCase(); - for(let i=index+1;i{ - return ( - - ); + handleUpdateHighlighted(nextIndex){ + this.setState({highlightedIndex: nextIndex}); + } + + handleListBlur(){ + this.setState({isOpen: false}); + } + + handleCancel () { + this.setFocus(); + } + + getListItemRenderer() { + return this.props.listItemRenderer?this.props.listItemRenderer:ListItemLabel; + } + + getPlaceholder() { + const option = this.props.options[this.state.selectedIndex]; + return (option && option.label)?option.label:this.props.placeholder; + } + + handleListItemBlur (index, relatedTarget) { + this.setState({ + lastBlurredIndex: index, + lastBlurredTimeStamp: Date.now() }); } - render () { - return ( -
        - {this.getItems()} -
      - ); + render() { + return ; } + } -SLDSList.displayName = displayName; -SLDSList.propTypes = propTypes; -SLDSList.defaultProps = defaultProps; -module.exports = SLDSList; +SLDSMenuPicklist.displayName = displayName; +SLDSMenuPicklist.propTypes = propTypes; +SLDSMenuPicklist.defaultProps = defaultProps; + +module.exports = SLDSMenuPicklist; +module.exports.ListItemLabel = ListItemLabel; diff --git a/components/SLDSMenuPicklist/ListItem.jsx b/components/SLDSMenuPicklist/ListItem.jsx deleted file mode 100644 index 48b667ec2e..0000000000 --- a/components/SLDSMenuPicklist/ListItem.jsx +++ /dev/null @@ -1,193 +0,0 @@ -/* -Copyright (c) 2015, salesforce.com, inc. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - - -import React from 'react'; -import ReactDOM from 'react-dom'; - -import KEYS from '../utils/KEYS'; -import EventUtil from '../utils/EventUtil'; -import ListItemLabelRenderer from './ListItemLabel'; - -const displayName = "SLDSList-Item"; -const propTypes = { - data: React.PropTypes.object, - checkmark: React.PropTypes.bool, - index: React.PropTypes.number, - inverted: React.PropTypes.bool, - isHighlighted: React.PropTypes.bool, - isSelected: React.PropTypes.bool, - label: React.PropTypes.string, - labelRenderer: React.PropTypes.func, - value: React.PropTypes.any, - onBlur: React.PropTypes.func, - onClick: React.PropTypes.func, - onFocus: React.PropTypes.func, - onMoveFocus: React.PropTypes.func, - onSelect: React.PropTypes.func, -}; -const defaultProps = { - data: {}, - index: 0, - inverted: false, - isHighlighted: false, - isSelected: false, - label: '', - labelRenderer: ListItemLabelRenderer, - onBlur (relatedTarget){ - console.log('onBlur should be defined ',relatedTarget); - }, - onClick (index) { - console.log('onClick should be defined ',index); - }, - onFocus (index, height) { - console.log('onFocus should be defined ',index,height); - }, - onMoveFocus (delta){ - console.log('onMoveFocus should be defined ',delta); - }, - onSelect (index) { - console.log('onSelect should be defined ',index); - }, - value: null, -}; - -class SLDSListItem extends React.Component { - handleClick (e) { - e.preventDefault(); - e.stopPropagation(); - if(this.props.onSelect){ - this.props.onSelect(this.props.index); - } - } - - handleMouseDown (e) { - if(e.nativeEvent){ - e.nativeEvent.preventDefault(); - e.nativeEvent.stopImmediatePropagation(); - } - e.preventDefault(); - } - - componentDidMount(){ - if(this.props.isHighlighted){ - this.setFocus(); - } - } - - componentDidUpdate( prevProps, prevState) { - if(!prevProps.isHighlighted && this.props.isHighlighted){ - this.setFocus(); - } - } - - setFocus () { - if(!this.props.isHover){ - ReactDOM.findDOMNode(this.refs.link).focus(); - } - } - - handleKeyDown(event) { - if(event.keyCode){ - if(event.keyCode === KEYS.DOWN){ - EventUtil.trapEvent(event); - if(this.props.onMoveFocus){ - this.props.onMoveFocus(1); - } - } - else if(event.keyCode === KEYS.UP){ - EventUtil.trapEvent(event); - if(this.props.onMoveFocus){ - this.props.onMoveFocus(-1); - } - } - else if(event.keyCode === KEYS.ENTER || - event.keyCode === KEYS.SPACE ){ - EventUtil.trapEvent(event); - if(this.props.onSelect){ - this.props.onSelect(this.props.index); - } - } - else if(event.keyCode === KEYS.ESCAPE){ - EventUtil.trapEvent(event); - if(this.props.onCancel){ - this.props.onCancel(); - } - } - else if(event.keyCode === KEYS.TAB){ - } - else{ - EventUtil.trapEvent(event); - const ch = String.fromCharCode(event.keyCode); - if(this.props.onSearch){ - this.props.onSearch(this.props.index,ch); - } - } - } - } - - handleBlur(e) { - if(this.props.onBlur){ - this.props.onBlur(this.props.index, e.relatedTarget); - } - } - - handleFocus () { - const height = ReactDOM.findDOMNode(this).offsetHeight; - if(height && this.props.onFocus){ - this.props.onFocus(this.props.index,height); - } - } - - getLabel () { - const LabelComp = this.props.labelRenderer; - return ; - } - - render () { - let isSelected = this.props.isSelected ? " slds-is-selected" : ""; - return ( -
    • - - {this.getLabel()} - -
    • - ); - } -} - -SLDSListItem.displayName = displayName; -SLDSListItem.propTypes = propTypes; -SLDSListItem.defaultProps = defaultProps; - -module.exports = SLDSListItem; - diff --git a/components/SLDSMenuPicklist/ListItemLabel.jsx b/components/SLDSMenuPicklist/ListItemLabel.jsx deleted file mode 100644 index 7341857efe..0000000000 --- a/components/SLDSMenuPicklist/ListItemLabel.jsx +++ /dev/null @@ -1,54 +0,0 @@ -/* -Copyright (c) 2015, salesforce.com, inc. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -import React from 'react'; -import SLDSIcon from '../SLDSIcon'; - -const displayName = "SLDSList-Item-Label"; -const propTypes = { - data: React.PropTypes.object, - index: React.PropTypes.number, - inverted: React.PropTypes.bool, - isHighlighted: React.PropTypes.bool, - isSelected: React.PropTypes.bool, - label: React.PropTypes.string, - value: React.PropTypes.string, -}; -const defaultProps = { - data: {}, - index: 0, - inverted: false, - isHighlighted: false, - isSelected: false, - label: '', - value: null, -}; - -class SLDSListItemLabel extends React.Component { - - constructor(props) { - super(props); - this.state = {}; - } - render() { - return ( -

      - {this.props.checkmark ? : null} - {this.props.label} -

      - ) - } -} - -SLDSListItemLabel.displayName = displayName; -SLDSListItemLabel.propTypes = propTypes; -SLDSListItemLabel.defaultProps = defaultProps; - -module.exports = SLDSListItemLabel; - diff --git a/components/SLDSMenuPicklist/index.jsx b/components/SLDSMenuPicklist/index.jsx index 7e4a56ab83..ca0ecf3735 100644 --- a/components/SLDSMenuPicklist/index.jsx +++ b/components/SLDSMenuPicklist/index.jsx @@ -14,7 +14,7 @@ import isEqual from "lodash.isequal"; import SLDSPopover from "../SLDSPopover"; import {KEYS, EventUtil} from "../utils"; import SLDSIcon from "../SLDSIcon"; -import List from "../SLDSMenuList"; +import List from "../SLDSMenuList/List"; import ListItemLabel from "../SLDSMenuList/ListItemLabel"; const displayName = "SLDSMenuPicklist"; diff --git a/components/SLDSTimepicker/index.jsx b/components/SLDSTimepicker/index.jsx index 927ea21191..37f6075b28 100644 --- a/components/SLDSTimepicker/index.jsx +++ b/components/SLDSTimepicker/index.jsx @@ -16,7 +16,8 @@ import SLDSDatePicker from './SLDSDatePicker/index'; import InputIcon from '../SLDSIcon/InputIcon'; import SLDSYearSelector from './SLDSYearSelector/index'; import SLDSMenuPicklist from '../SLDSMenuPicklist/index'; - +import SLDSMenuList from '../SLDSMenuList'; +import ListItemLabel from '../SLDSMenuList/ListItemLabel'; import {KEYS,EventUtil} from '../utils'; @@ -148,18 +149,43 @@ module.exports = React.createClass({ return new Date(); }, - getOptions () { - const now = new Date(); - const fromYear = now.getFullYear()-5; - const toYear = now.getFullYear()+5; - let opts = []; + getOptions() { + return [ + {label: "A Option Option Super Super Long", value: "A0", title: "Greg"}, + {label: "B Option", value: "B0"}, + {label: "C Option", value: "C0"}, + {label: "D Option", value: "D0"}, + {label: "E Option", value: "E0"}, + {label: "A1 Option", value: "A1"}, + {label: "B2 Option", value: "B1"}, + {label: "C2 Option", value: "C1"}, + {label: "D2 Option", value: "D1"}, + {label: "E2 Option Super Super Long", value: "E1"}, + ]; + }, - for (let year = fromYear; year < toYear; year++){ - opts.push({label:year,value:year}); - } - return opts; + getListItemRenderer() { + return this.props.listItemRenderer?this.props.listItemRenderer:ListItemLabel; + }, + + getPopoverContent() { + return ; }, + popover() { if(this.state && this.state.isOpen){ const date = this.state.strValue?this.parseDate(this.state.strValue):this.state.value; @@ -177,18 +203,7 @@ module.exports = React.createClass({ relativeYearTo={this.props.relativeYearTo} selectedDate={date?date:new Date()} /> */} -{/* -
      TIME SELECTOR
      -*/} - + { this.getPopoverContent() } ; } return ; From 573a2266f88db61604bf5cb6b3883975418570ac Mon Sep 17 00:00:00 2001 From: ibogdanov Date: Thu, 11 Feb 2016 18:11:58 -0800 Subject: [PATCH 06/13] more cleanup --- components/SLDSMenuList/index.jsx | 73 ++++------------------------- components/SLDSTimepicker/index.jsx | 15 ++++-- 2 files changed, 20 insertions(+), 68 deletions(-) diff --git a/components/SLDSMenuList/index.jsx b/components/SLDSMenuList/index.jsx index c05d017093..e99e76311f 100644 --- a/components/SLDSMenuList/index.jsx +++ b/components/SLDSMenuList/index.jsx @@ -63,7 +63,6 @@ class SLDSMenuPicklist extends React.Component { this.state = { highlightedIndex: 0, isOpen: false, - isFocused: false, lastBlurredIndex: -1, lastBlurredTimeStamp: -1, selectedIndex: this.getIndexByValue(this.props.value), @@ -86,19 +85,6 @@ class SLDSMenuPicklist extends React.Component { if(this.state.selectedIndex !== prevState.selectedIndex){ this.handleClose(); } - else if(this.state.isFocused && !prevState.isFocused){ - this.setState({isOpen: false}); - } - else if(!this.state.isFocused && prevState.isFocused){ - if(this.refs.list){ - if(!this.isUnmounting && this.refs.list){ - if(ReactDOM.findDOMNode(this.refs.list).contains(document.activeElement)){ - return; - } - this.setState({isOpen: false}) - } - } - } if(this.props.value !== prevProps.value || !isEqual(this.props.options, prevProps.options)){ @@ -132,23 +118,15 @@ class SLDSMenuPicklist extends React.Component { handleSelect(index) { this.setState({selectedIndex: index}) - this.setFocus(); if(this.props.onSelect){ this.props.onSelect(this.getValueByIndex(index)); } } handleClose() { - this.setState({isOpen: false}); - } - - handleClick() { - if(!this.state.isOpen){ - this.setState({isOpen: true}); - if(this.props.onClick) this.props.onClick(); - } - else{ - this.handleClose(); + console.log('!!! handleClose !!!'); + if(this.props.onCancel){ + this.props.onCancel(); } } @@ -156,58 +134,26 @@ class SLDSMenuPicklist extends React.Component { EventUtil.trapImmediate(event); } - handleBlur(e) { - this.setState({isFocused: false}); - } - - handleFocus() { - this.setState({isFocused: true}); - } - - setFocus() { - if(!this.isUnmounting){ - ReactDOM.findDOMNode(this.refs.triggerbutton).focus(); - } - } - - handleKeyDown(event) { - if (event.keyCode){ - if (event.keyCode === KEYS.ENTER || - event.keyCode === KEYS.SPACE || - event.keyCode === KEYS.DOWN || - event.keyCode === KEYS.UP){ - EventUtil.trapEvent(event); - - this.setState({ - isOpen: true, - highlightedIndex: 0 - }); - - } - } - } - handleUpdateHighlighted(nextIndex){ this.setState({highlightedIndex: nextIndex}); } handleListBlur(){ - this.setState({isOpen: false}); + if(this.props.onListBlur){ + this.props.onListBlur(); + } } handleCancel () { - this.setFocus(); + if(this.props.onCancel){ + this.props.onCancel(); + } } getListItemRenderer() { return this.props.listItemRenderer?this.props.listItemRenderer:ListItemLabel; } - getPlaceholder() { - const option = this.props.options[this.state.selectedIndex]; - return (option && option.label)?option.label:this.props.placeholder; - } - handleListItemBlur (index, relatedTarget) { this.setState({ lastBlurredIndex: index, @@ -228,7 +174,6 @@ class SLDSMenuPicklist extends React.Component { options={this.props.options} ref="list" selectedIndex={this.state.selectedIndex} - triggerId={this.state.triggerId} />; } diff --git a/components/SLDSTimepicker/index.jsx b/components/SLDSTimepicker/index.jsx index 37f6075b28..6d32e52463 100644 --- a/components/SLDSTimepicker/index.jsx +++ b/components/SLDSTimepicker/index.jsx @@ -168,15 +168,22 @@ module.exports = React.createClass({ return this.props.listItemRenderer?this.props.listItemRenderer:ListItemLabel; }, + handleSelect(value) { + console.log('!!! value: ',value); + this.handleClose(); + }, + + handleCancel(){ + this.handleClose(); + }, + getPopoverContent() { return Date: Thu, 11 Feb 2016 18:25:02 -0800 Subject: [PATCH 07/13] more cleanup --- components/SLDSMenuList/index.jsx | 46 ++++------------------------- components/SLDSTimepicker/index.jsx | 7 ++--- 2 files changed, 8 insertions(+), 45 deletions(-) diff --git a/components/SLDSMenuList/index.jsx b/components/SLDSMenuList/index.jsx index e99e76311f..6551da9246 100644 --- a/components/SLDSMenuList/index.jsx +++ b/components/SLDSMenuList/index.jsx @@ -23,7 +23,6 @@ const propTypes = { * If true, renders checkmark icon on the selected Menu Item. */ checkmark: React.PropTypes.bool, - disabled: React.PropTypes.bool, label: React.PropTypes.string, /** * Custom element that overrides the default Menu Item component. @@ -32,25 +31,14 @@ const propTypes = { /** * If true, component renders specifically to work inside Modal. */ - modal: React.PropTypes.bool, onClick: React.PropTypes.func, onSelect: React.PropTypes.func, /** * Menu item data. */ options: React.PropTypes.array.isRequired, - placeholder: React.PropTypes.string, - required: React.PropTypes.bool, - /** - * Current selected item. - */ - value: React.PropTypes.node, }; const defaultProps = { - disabled: false, - modal: true, - required: false, - placeholder: "Select an Option", checkmark: true }; @@ -65,11 +53,12 @@ class SLDSMenuPicklist extends React.Component { isOpen: false, lastBlurredIndex: -1, lastBlurredTimeStamp: -1, - selectedIndex: this.getIndexByValue(this.props.value), + selectedIndex: this.props.selectedIndex, /* triggerId is the id of the element that triggers the Menu to open. * Need this for aria-labelledby on
        in Menu for accessibility. */ triggerId: this.props.label ? this.props.label.replace(/\s+/g, '') + '_Button': 'Picklist_Button', }; + } componentWillUnmount(){ @@ -86,45 +75,22 @@ class SLDSMenuPicklist extends React.Component { this.handleClose(); } - if(this.props.value !== prevProps.value || + if(this.props.selectedIndex !== prevProps.selectedIndex || !isEqual(this.props.options, prevProps.options)){ - var newSelectedIndex = this.getIndexByValue(this.props.value); - if (newSelectedIndex !== this.state.selectedIndex) { - this.handleSelect(newSelectedIndex); + if (this.props.selectedIndex !== this.state.selectedIndex) { + this.handleSelect(this.props.selectedIndex); } } } - getIndexByValue(value){ - let foundIndex = -1; - if(this.props.options && this.props.options.length){ - this.props.options.some((element, index, array)=>{ - if(element && element.value === value){ - foundIndex = index; - return true; - } - return false; - }); - } - return foundIndex; - } - - getValueByIndex(index){ - const option = this.props.options[index]; - if(option){ - return this.props.options[index]; - } - } - handleSelect(index) { this.setState({selectedIndex: index}) if(this.props.onSelect){ - this.props.onSelect(this.getValueByIndex(index)); + this.props.onSelect(index); } } handleClose() { - console.log('!!! handleClose !!!'); if(this.props.onCancel){ this.props.onCancel(); } diff --git a/components/SLDSTimepicker/index.jsx b/components/SLDSTimepicker/index.jsx index 6d32e52463..13cfb23946 100644 --- a/components/SLDSTimepicker/index.jsx +++ b/components/SLDSTimepicker/index.jsx @@ -179,16 +179,13 @@ module.exports = React.createClass({ getPopoverContent() { return ; }, From b3be162ade9da2d717cf1c80d4414171e545dd5c Mon Sep 17 00:00:00 2001 From: ibogdanov Date: Fri, 12 Feb 2016 00:21:49 -0800 Subject: [PATCH 08/13] progress --- .../SLDSCalendar/SLDSCalendarDay/index.js | 174 ------------- .../SLDSCalendar/SLDSCalendarWeek/index.js | 89 ------- .../SLDSTimepicker/SLDSCalendar/index.js | 245 ------------------ .../SLDSDatePicker/SLDSDatePickerNav/index.js | 123 --------- .../SLDSTimepicker/SLDSDatePicker/index.js | 177 ------------- .../SLDSTimepicker/SLDSYearSelector/index.js | 66 ----- components/SLDSTimepicker/index.jsx | 126 +++++---- 7 files changed, 70 insertions(+), 930 deletions(-) delete mode 100644 components/SLDSTimepicker/SLDSCalendar/SLDSCalendarDay/index.js delete mode 100644 components/SLDSTimepicker/SLDSCalendar/SLDSCalendarWeek/index.js delete mode 100644 components/SLDSTimepicker/SLDSCalendar/index.js delete mode 100644 components/SLDSTimepicker/SLDSDatePicker/SLDSDatePickerNav/index.js delete mode 100644 components/SLDSTimepicker/SLDSDatePicker/index.js delete mode 100644 components/SLDSTimepicker/SLDSYearSelector/index.js diff --git a/components/SLDSTimepicker/SLDSCalendar/SLDSCalendarDay/index.js b/components/SLDSTimepicker/SLDSCalendar/SLDSCalendarDay/index.js deleted file mode 100644 index aa69615a43..0000000000 --- a/components/SLDSTimepicker/SLDSCalendar/SLDSCalendarDay/index.js +++ /dev/null @@ -1,174 +0,0 @@ -/* -Copyright (c) 2015, salesforce.com, inc. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -'use strict'; - -import React from 'react'; -import {KEYS,EventUtil,DateUtil} from '../../../utils'; - -module.exports = React.createClass({ - - getDefaultProps () { - return { - - displayedDate:new Date(), - - selectedDate:new Date(), - - calendarHasFocus: false, - - onSelectDate (date) { - console.log('onSelectDate should be defined ',date); - }, - - onClick (index) { - console.log('onClick should be defined ',index); - }, - - onMoveFocus (delta){ - console.log('onMoveFocus should be defined ',delta); - }, - - onBlur (relatedTarget){ - console.log('onBlur should be defined ',relatedTarget); - }, - - onFocus (index, height) { - console.log('onFocus should be defined ',index,height); - }, - - onCancel () { - console.log('onCancel should be defined'); - } - - }; - }, - - handleClick (event) { - if(this.props.onSelectDate){ - this.props.onSelectDate(this.props.date); - } - if(event.nativeEvent){ - event.nativeEvent.stopImmediatePropagation(); - event.nativeEvent.preventDefault(); - } - }, - - handleToPrevDay(){ - if(this.props.onPrevDay){ - this.props.onPrevDay(this.props.date); - } - }, - - handleToNextDay(){ - if(this.props.onNextDay){ - this.props.onNextDay(this.props.date); - } - }, - - handleToPrevWeek(){ - if(this.props.onPrevWeek){ - this.props.onPrevWeek(this.props.date); - } - }, - - handleToNextWeek(){ - if(this.props.onNextWeek){ - this.props.onNextWeek(this.props.date); - } - }, - - handleKeyDown(event) { - if(event.keyCode){ - if(event.keyCode === KEYS.ENTER || - event.keyCode === KEYS.SPACE ){ - EventUtil.trapEvent(event); - if(this.props.onSelectDate){ - this.props.onSelectDate(this.props.date); - } - } - else if(event.keyCode === KEYS.ESCAPE){ - EventUtil.trapEvent(event); - if(this.props.onCancel){ - this.props.onCancel(); - } - } - else if(event.keyCode === KEYS.TAB){ -/* - if(!event.shiftKey){ - EventUtil.trapEvent(event); - if(this.props.onCancel){ - this.props.onCancel(); - } - } -*/ - } - else if(event.keyCode === KEYS.RIGHT){ - EventUtil.trapEvent(event); - this.handleToNextDay(); - } - else if(event.keyCode === KEYS.LEFT){ - EventUtil.trapEvent(event); - this.handleToPrevDay(); - } - else if(event.keyCode === KEYS.RIGHT){ - EventUtil.trapEvent(event); - this.handleToNextDay(); - } - else if(event.keyCode === KEYS.UP){ - EventUtil.trapEvent(event); - this.handleToPrevWeek(); - } - else if(event.keyCode === KEYS.DOWN){ - EventUtil.trapEvent(event); - this.handleToNextWeek(); - } - else{ - EventUtil.trapEvent(event); - } - } - }, - - setFocus () { - if(this.isMounted() && this.props.calendarHasFocus){ - this.getDOMNode().focus(); - } - }, - - render () { - - const isCurrentMonth = DateUtil.isSameMonth(this.props.date,this.props.displayedDate); - const isToday = DateUtil.isToday(this.props.date); - const isSelectedDay = DateUtil.isSameDay(this.props.date,this.props.selectedDate); - const isFirstDayOfMonth = DateUtil.isFirstDayOfMonth(this.props.date); - - return ( - - - {this.props.date.getDate()} - - - ); - }, - - componentDidUpdate (prevProps) { - if(this.props.focused && !prevProps.focused){ - this.setFocus(); - } - } - -}); diff --git a/components/SLDSTimepicker/SLDSCalendar/SLDSCalendarWeek/index.js b/components/SLDSTimepicker/SLDSCalendar/SLDSCalendarWeek/index.js deleted file mode 100644 index 1b9b2a79b2..0000000000 --- a/components/SLDSTimepicker/SLDSCalendar/SLDSCalendarWeek/index.js +++ /dev/null @@ -1,89 +0,0 @@ -/* -Copyright (c) 2015, salesforce.com, inc. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -'use strict'; - -import React from 'react'; - -import Day from '../SLDSCalendarDay/index'; -import {DateUtil} from '../../../utils'; - - -module.exports = React.createClass({ - - getDefaultProps () { - return { - displayedDate:new Date(), - selectedDate:new Date() - }; - }, - - handleSelectDate (day) { - if(this.props.onSelectDate){ - this.props.onSelectDate(day); - } - }, - - handleCancel () { - if(this.props.onCancel){ - this.props.onCancel(); - } - }, - - handlePrevDay (date) { - if(this.props.onPrevDay){ - this.props.onPrevDay(date); - } - }, - - handleNextDay (date) { - if(this.props.onNextDay){ - this.props.onNextDay(date); - } - }, - - handlePrevWeek (date) { - if(this.props.onPrevWeek){ - this.props.onPrevWeek(date); - } - }, - - handleNextWeek (date) { - if(this.props.onNextWeek){ - this.props.onNextWeek(date); - } - }, - - render: function() { - let days = []; - let date = this.props.date; - for (var i = 0; i < 7; i++) { - days.push(); - date = DateUtil.addDays(date,1); - } - - return - {days} - - } -}); diff --git a/components/SLDSTimepicker/SLDSCalendar/index.js b/components/SLDSTimepicker/SLDSCalendar/index.js deleted file mode 100644 index c42195188b..0000000000 --- a/components/SLDSTimepicker/SLDSCalendar/index.js +++ /dev/null @@ -1,245 +0,0 @@ -/* -Copyright (c) 2015, salesforce.com, inc. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -'use strict'; - -import React from 'react'; -import Week from './SLDSCalendarWeek/index'; -import {EventUtil, DateUtil, KEYS} from '../../utils'; - -module.exports = React.createClass({ - - displayName: 'SLDSCalendar', - - getDefaultProps () { - return { - displayedDate:new Date(), - selectedDate:new Date(), - weekDayLabels:['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'], - abbrWeekDayLabels:['S','M','T','W','T','F','S'], - todayLabel:'Today', - onSelectDate (date) { - console.log('onSelectDate should be defined ',date); - }, - - onCancel () { - console.log('onCancel should be defined'); - } - - }; - }, - - getInitialState () { - return { - highlightedDate: DateUtil.firstDayOfMonth(this.props.displayedDate), - hasFocus: false, - todayFocus: false, - }; - }, - - handleSelectDate (day) { - this.setState({selected:day}); - if(this.props.onSelectDate){ - this.props.onSelectDate(day); - } - }, - - handleCancel () { - if(this.props.onCancel){ - this.props.onCancel(); - } - }, - - handleChangeDisplayedDate (date) { - if(this.props.onChange){ - this.props.onChange(date); - } - }, - - handlePrevDay (date) { - const prevDate = DateUtil.addDays(date,-1); - if(!DateUtil.isSameMonth(prevDate,date)){ - this.handleChangeDisplayedDate(prevDate); - } - else{ - this.setState({highlightedDate:prevDate}); - } - }, - - handleNextDay (date) { - const nextDate = DateUtil.addDays(date,1); - if(!DateUtil.isSameMonth(nextDate,date)){ - this.handleChangeDisplayedDate(nextDate); - } - else{ - this.setState({highlightedDate:nextDate}); - } - }, - - handlePrevWeek (date) { - const prevDate = DateUtil.addDays(date,-7); - if(!DateUtil.isSameMonth(prevDate,date)){ - this.handleChangeDisplayedDate(prevDate); - } - else{ - this.setState({highlightedDate:prevDate}); - } - }, - - handleNextWeek (date) { - const nextDate = DateUtil.addDays(date,7); - if(!DateUtil.isSameMonth(nextDate,date)){ - this.handleChangeDisplayedDate(nextDate); - } - else{ - this.setState({highlightedDate:nextDate}); - } - }, - - handleTodaySelect () { - this.handleSelectDate(new Date()); - }, - - handleFocus () { - if(!this.state.todayFocus){ - this.setState({hasFocus:true}); - } - }, - - handleBlur () { - this.setState({hasFocus:false}); - }, - - handleTodayFocus () { - this.state.todayFocus = true; - }, - - handleTodayBlur () { - this.state.todayFocus = false; - }, - - handleKeyDown(event) { - if(event.keyCode){ - if(event.keyCode === KEYS.TAB){ - if(!event.shiftKey){ - EventUtil.trapEvent(event); - if(this.props.onCancel){ - this.props.onCancel(); - } - } - } - } - }, - - render () { - return (
        - - - - - - - - - - - - - - {this.renderWeeks()} - {this.renderToday()} - -
        - {this.props.abbrWeekDayLabels[0]} - - {this.props.abbrWeekDayLabels[1]} - - {this.props.abbrWeekDayLabels[2]} - - {this.props.abbrWeekDayLabels[3]} - - {this.props.abbrWeekDayLabels[4]} - - {this.props.abbrWeekDayLabels[5]} - - {this.props.abbrWeekDayLabels[6]} -
        -
        ); - }, - - renderToday () { - return - - - {this.props.todayLabel} - - - ; - }, - - renderWeeks () { - const firstDayOfMonth = DateUtil.firstDayOfMonth(this.props.displayedDate); - - let date = firstDayOfMonth; - if(firstDayOfMonth.getDay()>0){ - const prevWeek = DateUtil.addWeeks(firstDayOfMonth,-1); - const nextSunday = DateUtil.nearestWeekDay(prevWeek,0); - date = nextSunday; - } - - let weeks = []; - let done = false; - - - let monthIndex = date.getMonth(); - let count = 0; - while (!done) { - weeks.push(); - date = DateUtil.addWeeks(date,1); - done = count++ > 2 && monthIndex !== date.getMonth(); - monthIndex = date.getMonth(); - } - var extra = 0; - while(weeks.length < 6){ - weeks.push( ); - } - - return weeks; - }, - - componentDidUpdate (prevProps) { - if( !DateUtil.isEqual(this.props.displayedDate,prevProps.displayedDate) ){ - this.setState({highlightedDate:this.props.displayedDate}); - } - } - -}); \ No newline at end of file diff --git a/components/SLDSTimepicker/SLDSDatePicker/SLDSDatePickerNav/index.js b/components/SLDSTimepicker/SLDSDatePicker/SLDSDatePickerNav/index.js deleted file mode 100644 index f9e553fd2a..0000000000 --- a/components/SLDSTimepicker/SLDSDatePicker/SLDSDatePickerNav/index.js +++ /dev/null @@ -1,123 +0,0 @@ -/* -Copyright (c) 2015, salesforce.com, inc. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -'use strict'; - -import React from 'react'; -import SLDSSelectYear from '../../SLDSYearSelector/index'; -import ButtonIcon from './../../../SLDSIcon/ButtonIcon'; -import {DateUtil, EventUtil, KEYS} from './../../../utils'; - -module.exports = React.createClass( { - - getDefaultProps (){ - return { - displayedDate:new Date(), - monthLabels:['January','February','March','April','May','June','July','August','September','October','November','December'], - onChangeMonth (){ - console.log('onChangeMonth should be defined'); - } - }; - }, - - handleClick (event){ - event.preventDefault(); - event.stopPropagation(); - }, - - handleChange (displayedDate){ - if(this.props.onChange){ - this.props.onChange(displayedDate); - } - }, - - handleCancel(){ - if(this.props.onCancel){ - this.props.onCancel(); - } - }, - - previousMonth (){ - if(this.props.displayedDate && this.handleChange){ - this.handleChange(DateUtil.addMonths(this.props.displayedDate,-1)); - } - - }, - - componentDidMount () { - }, - - nextMonth (){ - if(this.props.displayedDate && this.handleChange){ - this.handleChange(DateUtil.addMonths(this.props.displayedDate,1)); - } - }, - - handleYearSelect (displayedDate) { - if(this.props.onChange){ - this.props.onChange(displayedDate); - } - }, - - handleKeyDown (event) { - if(event.keyCode === KEYS.TAB){ - if(event.shiftKey){ - EventUtil.trapEvent(event); - this.handleCancel(); - } - } - }, - - getMonthLabel(){ - return this.props.monthLabels[new Date(this.props.displayedDate).getMonth()]; - }, - - render() { - return ( - -
        -
        -
        - -
        - -

        {this.getMonthLabel()}

        -
        - -
        -
        -
        - -
        -
        - - ); - } -}); - diff --git a/components/SLDSTimepicker/SLDSDatePicker/index.js b/components/SLDSTimepicker/SLDSDatePicker/index.js deleted file mode 100644 index 28554c5ec3..0000000000 --- a/components/SLDSTimepicker/SLDSDatePicker/index.js +++ /dev/null @@ -1,177 +0,0 @@ -/* -Copyright (c) 2015, salesforce.com, inc. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -'use strict'; - -import React from 'react'; -import Calendar from '../SLDSCalendar/index'; -import SLDSDatePickerNav from './SLDSDatePickerNav/index'; -import {EventUtil} from './../../utils'; - -import {KEYS} from '../../utils'; - - -module.exports = React.createClass( { - - getDefaultProps () { - return { - selectedDate:new Date(), - value:new Date(), - onChange (date) { - console.log('onChange should be defined ',date); - }, - - onDisplayedDateChange (date) { - console.log('onDisplayedDateChange should be defined ',date); - }, - - onClose () { - console.log('onClose should be defined'); - }, - - }; - }, - - getInitialState () { - return { - displayedDate: this.props.selectedDate, - isFocused: false, - isClosing: false - }; - }, - - handleKeyDown(event) { - if(event.keyCode){ - if(event.keyCode === KEYS.ESCAPE){ - if(this.props.onClose){ - this.props.onClose(); - } - } - else if(event.keyCode === KEYS.SPACE){ - - } - else if(event.keyCode === KEYS.ENTER){ - - } - else if(event.keyCode === KEYS.TAB){ - } - else if(event.keyCode === KEYS.ESCAPE){ - } - else{ - EventUtil.trapEvent(event); - } - } - }, - - handleClickOutside (e) { - e.preventDefault(); - e.stopPropagation(); - if(this.props.onClose){ - this.props.onClose(); - } - }, - - handleDisplayedDateChange (displayedDate){ - if(this.props.onDisplayedDateChange){ - this.props.onDisplayedDateChange(displayedDate); - } - this.setState({displayedDate:displayedDate}); - }, - - handleSelectDate (selectedDate){ - if(this.props.onChange){ - this.props.onChange(selectedDate); - } - }, - - handleCancel () { - if(this.props.onClose){ - this.props.onClose(); - } - }, - - handleBGClick(event) { - if(event.nativeEvent){ - event.nativeEvent.preventDefault(); - } - }, - - handleFocus () { - this.setState({isFocused:true}); - }, - - handleBlur () { - this.setState({isFocused:false}); - }, - - render() { - - return ( -
        -
        - - - Go to previous month - Go to next month -
        - -
        - ); - }, - - componentDidUpdate (prevProps, prevState) { - if(!this.state.isFocused && prevState.isFocused){ - this.setState({isClosing:true}); - - setTimeout ( () => { - - if(this.isMounted()){ - if(this.state.isClosing){ - if(this.state.isFocused){ - this.setState({isClosing:false}); - } - else{ - if(this.props.onClose){ - this.props.onClose(); - } - } - } - } - - - }); - - } - - } -}); - diff --git a/components/SLDSTimepicker/SLDSYearSelector/index.js b/components/SLDSTimepicker/SLDSYearSelector/index.js deleted file mode 100644 index 2b773477d7..0000000000 --- a/components/SLDSTimepicker/SLDSYearSelector/index.js +++ /dev/null @@ -1,66 +0,0 @@ -/* -Copyright (c) 2015, salesforce.com, inc. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -'use strict'; - -import React from 'react'; -import SLDSMenuPicklist from '../../SLDSMenuPicklist'; - -module.exports = React.createClass( { - - displayName: 'SLDSYearSelector', - - getDefaultProps (){ - return { - displayedDate:new Date(), - relativeYearFrom:-5, - relativeYearTo:5, - onChange (displayedDate){ - console.log('onChange should be defined: ',displayedDate); - } - }; - }, - - getOptions () { - const now = new Date(); - const fromYear = now.getFullYear()+this.props.relativeYearFrom; - const toYear = now.getFullYear()+this.props.relativeYearTo; - let opts = []; - - for (let year = fromYear; year < toYear; year++){ - opts.push({label:year,value:year}); - } - return opts; - }, - - handleSelect(selectedValue){ - if(selectedValue){ - if(this.props.onChange){ - this.props.onChange(new Date(this.props.displayedDate.setFullYear(parseInt(selectedValue.value)))); - } - } - }, - - render() { - return ( -
        - - -
        - ); - } -}); diff --git a/components/SLDSTimepicker/index.jsx b/components/SLDSTimepicker/index.jsx index 13cfb23946..c2b564aae2 100644 --- a/components/SLDSTimepicker/index.jsx +++ b/components/SLDSTimepicker/index.jsx @@ -12,10 +12,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND import React from 'react'; import ReactDOM from 'react-dom'; import SLDSPopover from '../SLDSPopover'; -import SLDSDatePicker from './SLDSDatePicker/index'; import InputIcon from '../SLDSIcon/InputIcon'; -import SLDSYearSelector from './SLDSYearSelector/index'; -import SLDSMenuPicklist from '../SLDSMenuPicklist/index'; import SLDSMenuList from '../SLDSMenuList'; import ListItemLabel from '../SLDSMenuList/ListItemLabel'; @@ -23,15 +20,12 @@ import {KEYS,EventUtil} from '../utils'; const displayName = 'SLDSTimepicker'; const propTypes = { - abbrWeekDayLabels: React.PropTypes.array, /** - * Date formatting function + * Time formatting function */ formatter: React.PropTypes.func, - monthLabels: React.PropTypes.array, - /** * Parsing date string into Date */ @@ -55,20 +49,11 @@ const propTypes = { }; const defaultProps = { - abbrWeekDayLabels: ['S','M','T','W','T','F','S'], formatter (date) { if(date){ - return (date.getMonth()+1) + - '/'+date.getDate() + - '/'+date.getFullYear(); + return date.toLocaleTimeString(navigator.language, {hour: '2-digit', minute:'2-digit'}); } }, - monthLabels: [ - 'January','February','March', - 'April','May','June','July', - 'August','September','October', - 'November','December' - ], onDateChange (date) { console.log('onDateChange should be defined'); }, @@ -101,7 +86,8 @@ module.exports = React.createClass({ return { isOpen:false, value:this.props.value, - strValue:this.props.strValue + strValue:this.props.strValue, + options:this.getOptions() }; }, @@ -150,26 +136,47 @@ module.exports = React.createClass({ }, getOptions() { - return [ - {label: "A Option Option Super Super Long", value: "A0", title: "Greg"}, - {label: "B Option", value: "B0"}, - {label: "C Option", value: "C0"}, - {label: "D Option", value: "D0"}, - {label: "E Option", value: "E0"}, - {label: "A1 Option", value: "A1"}, - {label: "B2 Option", value: "B1"}, - {label: "C2 Option", value: "C1"}, - {label: "D2 Option", value: "D1"}, - {label: "E2 Option Super Super Long", value: "E1"}, - ]; + const d = new Date(); + let options = []; + d.setHours(0); + d.setMinutes(0); + d.setSeconds(0); + d.setMilliseconds(0); + const curDate = new Date(d); + while(d.getDate() === curDate.getDate()){ + const formatted = this.props.formatter(curDate); + options.push({ + label:formatted, + value:formatted + }); + curDate.setMinutes(curDate.getMinutes()+30); + } + return options; }, getListItemRenderer() { return this.props.listItemRenderer?this.props.listItemRenderer:ListItemLabel; }, - handleSelect(value) { - console.log('!!! value: ',value); + getValueByIndex(index){ + const option = this.state.options[index]; + if(option){ + return this.state.options[index]; + } + }, + + handleSelect(index) { + + const value = this.getValueByIndex(index); + + this.setState({ + value:value.value, + strValue:value.label, + isOpen:false + }); + if(this.props.onChange){ + this.props.onChange(date); + } this.handleClose(); }, @@ -183,34 +190,41 @@ module.exports = React.createClass({ itemRenderer={this.getListItemRenderer()} onCancel={this.handleCancel} onSelect={this.handleSelect} - options={this.getOptions()} + options={this.state.options} ref="list" - selectedIndex={3} + triggerId={this.state.triggerId} />; }, + getSimplePopover() { + return ( + !this.props.disabled && this.state.isOpen? +
        + {this.getPopoverContent()} +
        :null + ); + }, - popover() { - if(this.state && this.state.isOpen){ - const date = this.state.strValue?this.parseDate(this.state.strValue):this.state.value; - return -{/* - -*/} - { this.getPopoverContent() } - ; - } - return ; + getModalPopover() { + return ( + !this.props.disabled && this.state.isOpen? + + {this.getPopoverContent()} + :null + ); }, handleInputChange() { @@ -272,7 +286,7 @@ module.exports = React.createClass({ onFocus={this.handleFocus}/> - {this.popover()} + {this.props.modal?this.getModalPopover():this.getSimplePopover()} ); } From 537ef7210bdd3180247bf3e059fe46e8968b5c7f Mon Sep 17 00:00:00 2001 From: ibogdanov Date: Fri, 12 Feb 2016 00:44:13 -0800 Subject: [PATCH 09/13] progress --- components/SLDSTimepicker/index.jsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/components/SLDSTimepicker/index.jsx b/components/SLDSTimepicker/index.jsx index c2b564aae2..cb6dff27fd 100644 --- a/components/SLDSTimepicker/index.jsx +++ b/components/SLDSTimepicker/index.jsx @@ -57,8 +57,10 @@ const defaultProps = { onDateChange (date) { console.log('onDateChange should be defined'); }, - parser (str) { - return new Date(str); + parser (timeStr) { + const date = new Date(); + const dateStr = date.toLocaleString(navigator.language, {year: 'numeric', month: 'numeric', day: 'numeric'}); + return new Date(dateStr+' '+timeStr); }, placeholder: 'Pick Time', relativeYearFrom: -5, @@ -234,7 +236,7 @@ module.exports = React.createClass({ strValue:string }); if(this.props.onDateChange){ - const d = this.props.parser(string) + const d = this.props.parser(string); this.props.onDateChange(d); } } From 2e9b0ffd684b64568bf847f6478e9763a4731a51 Mon Sep 17 00:00:00 2001 From: ibogdanov Date: Fri, 12 Feb 2016 12:05:34 -0800 Subject: [PATCH 10/13] cleanup --- demo/code-snippets/TimepickerExample.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/demo/code-snippets/TimepickerExample.js b/demo/code-snippets/TimepickerExample.js index 8c7fac03f9..82e383b8f7 100644 --- a/demo/code-snippets/TimepickerExample.js +++ b/demo/code-snippets/TimepickerExample.js @@ -1,6 +1,5 @@ -
        TIMEPICKER!
        >> onDateChange ', date); + onDateChange = {function(date, inputStr){ + console.log('>>> onDateChange ', date, ' inputStr: ',inputStr); }} /> \ No newline at end of file From 47dbec25bac0403956cbac43fd375934aeb60ccb Mon Sep 17 00:00:00 2001 From: ibogdanov Date: Fri, 12 Feb 2016 12:11:37 -0800 Subject: [PATCH 11/13] docs build --- demo/docs/components.json | 112 +++++++++++++++++++++++++++++++- demo/pages/TimePickerSection.js | 1 - scripts/component-docs.js | 1 + 3 files changed, 112 insertions(+), 2 deletions(-) diff --git a/demo/docs/components.json b/demo/docs/components.json index ffe6aac576..b586340413 100644 --- a/demo/docs/components.json +++ b/demo/docs/components.json @@ -1319,7 +1319,7 @@ "required": false, "description": "Date formatting function", "defaultValue": { - "value": "function(date) {\n return (date.getMonth()+1) +\n '/'+date.getDate() +\n '/'+date.getFullYear();\n}", + "value": "function(date) {\n if(date){\n return (date.getMonth()+1) +\n '/'+date.getDate() +\n '/'+date.getFullYear();\n }\n}", "computed": false } }, @@ -1390,6 +1390,13 @@ "computed": false } }, + "strValue": { + "type": { + "name": "string" + }, + "required": false, + "description": "" + }, "weekDayLabels": { "type": { "name": "array" @@ -1414,5 +1421,108 @@ } } } + }, + "SLDSTimepicker": { + "description": "", + "displayName": "SLDSTimepicker", + "props": { + "formatter": { + "type": { + "name": "func" + }, + "required": false, + "description": "Time formatting function", + "defaultValue": { + "value": "function(date) {\n if(date){\n return date.toLocaleTimeString(navigator.language, {hour: '2-digit', minute:'2-digit'});\n }\n}", + "computed": false + } + }, + "parser": { + "type": { + "name": "func" + }, + "required": false, + "description": "Parsing date string into Date", + "defaultValue": { + "value": "function(timeStr) {\n const date = new Date();\n const dateStr = date.toLocaleString(navigator.language, {year: 'numeric', month: 'numeric', day: 'numeric'});\n return new Date(dateStr+' '+timeStr);\n}", + "computed": false + } + }, + "relativeYearFrom": { + "type": { + "name": "number" + }, + "required": false, + "description": "", + "defaultValue": { + "value": "-5", + "computed": false + } + }, + "relativeYearTo": { + "type": { + "name": "number" + }, + "required": false, + "description": "", + "defaultValue": { + "value": "5", + "computed": false + } + }, + "todayLabel": { + "type": { + "name": "string" + }, + "required": false, + "description": "", + "defaultValue": { + "value": "'Today'", + "computed": false + } + }, + "value": { + "type": { + "name": "instanceOf", + "value": "Date" + }, + "required": false, + "description": "Date", + "defaultValue": { + "value": "null", + "computed": false + } + }, + "strValue": { + "type": { + "name": "string" + }, + "required": false, + "description": "" + }, + "weekDayLabels": { + "type": { + "name": "array" + }, + "required": false, + "description": "", + "defaultValue": { + "value": "[\n 'Sunday','Monday','Tuesday',\n 'Wednesday','Thursday','Friday',\n 'Saturday'\n]", + "computed": false + } + }, + "onDateChange": { + "defaultValue": { + "value": "function(date) {\n console.log('onDateChange should be defined');\n}", + "computed": false + } + }, + "placeholder": { + "defaultValue": { + "value": "'Pick Time'", + "computed": false + } + } + } } } \ No newline at end of file diff --git a/demo/pages/TimePickerSection.js b/demo/pages/TimePickerSection.js index 0c9fcf594f..f488ebfd76 100644 --- a/demo/pages/TimePickerSection.js +++ b/demo/pages/TimePickerSection.js @@ -34,7 +34,6 @@ class DatepickerSingleSelectSection extends React.Component { const docs = DOCS["DatepickerSingleSelect"] ? true : false; return (
        - TIME PICKER
        {docs ?

        : null} diff --git a/scripts/component-docs.js b/scripts/component-docs.js index fae7bd46ba..dea34a3624 100644 --- a/scripts/component-docs.js +++ b/scripts/component-docs.js @@ -14,6 +14,7 @@ var componentNames = [ 'SLDSNotification', 'SLDSPopoverTooltip', 'SLDSDatepickerSingleSelect', + 'SLDSTimepicker', //'SLDSGrid', //'SLDSUtilityIcon', ]; From daf3d2c8e956e626a9fe59a39ee661a0c752c8c9 Mon Sep 17 00:00:00 2001 From: ibogdanov Date: Fri, 12 Feb 2016 12:35:09 -0800 Subject: [PATCH 12/13] props cleanup --- components/SLDSMenuList/ListItemLabel.jsx | 2 +- components/SLDSTimepicker/index.jsx | 67 +++++++---------------- demo/docs/components.json | 44 --------------- demo/pages/TimePickerSection.js | 6 +- 4 files changed, 25 insertions(+), 94 deletions(-) diff --git a/components/SLDSMenuList/ListItemLabel.jsx b/components/SLDSMenuList/ListItemLabel.jsx index 7341857efe..00df703f41 100644 --- a/components/SLDSMenuList/ListItemLabel.jsx +++ b/components/SLDSMenuList/ListItemLabel.jsx @@ -18,7 +18,7 @@ const propTypes = { isHighlighted: React.PropTypes.bool, isSelected: React.PropTypes.bool, label: React.PropTypes.string, - value: React.PropTypes.string, + value: React.PropTypes.any, }; const defaultProps = { data: {}, diff --git a/components/SLDSTimepicker/index.jsx b/components/SLDSTimepicker/index.jsx index cb6dff27fd..bbdaf5ba78 100644 --- a/components/SLDSTimepicker/index.jsx +++ b/components/SLDSTimepicker/index.jsx @@ -31,20 +31,15 @@ const propTypes = { */ parser: React.PropTypes.func, - relativeYearFrom: React.PropTypes.number, - - relativeYearTo: React.PropTypes.number, - - todayLabel: React.PropTypes.string, - /** * Date */ value: React.PropTypes.instanceOf(Date), + stepInMinutes: React.PropTypes.number, + strValue: React.PropTypes.string, - weekDayLabels: React.PropTypes.array, }; @@ -63,15 +58,8 @@ const defaultProps = { return new Date(dateStr+' '+timeStr); }, placeholder: 'Pick Time', - relativeYearFrom: -5, - relativeYearTo: 5, - todayLabel: 'Today', value: null, - weekDayLabels: [ - 'Sunday','Monday','Tuesday', - 'Wednesday','Thursday','Friday', - 'Saturday' - ], + stepInMinutes: 30 }; module.exports = React.createClass({ @@ -93,14 +81,14 @@ module.exports = React.createClass({ }; }, - handleChange(date) { + handleChange(date, strValue) { this.setState({ value:date, - strValue:this.props.formatter(date), + strValue:strValue, isOpen:false }); if(this.props.onDateChange){ - this.props.onDateChange(date); + this.props.onDateChange(date, strValue); } }, @@ -149,9 +137,9 @@ module.exports = React.createClass({ const formatted = this.props.formatter(curDate); options.push({ label:formatted, - value:formatted + value:new Date(curDate) }); - curDate.setMinutes(curDate.getMinutes()+30); + curDate.setMinutes(curDate.getMinutes()+this.props.stepInMinutes); } return options; }, @@ -168,16 +156,9 @@ module.exports = React.createClass({ }, handleSelect(index) { - - const value = this.getValueByIndex(index); - - this.setState({ - value:value.value, - strValue:value.label, - isOpen:false - }); - if(this.props.onChange){ - this.props.onChange(date); + const val = this.getValueByIndex(index); + if(val && val.value){ + this.handleChange(val.value, val.label); } this.handleClose(); }, @@ -231,28 +212,22 @@ module.exports = React.createClass({ handleInputChange() { const string = ReactDOM.findDOMNode(this.refs.date).value; - if(string){ - this.setState({ - strValue:string - }); - if(this.props.onDateChange){ - const d = this.props.parser(string); - this.props.onDateChange(d); - } - } - else{ - this.setState({ - isOpen:false - }); + this.setState({ + strValue:string + }); + if(this.props.onDateChange){ + const d = this.props.parser(string); + this.props.onDateChange(d, string); } }, handleKeyDown(event) { if (event.keyCode){ - if (event.keyCode === KEYS.ENTER || - event.keyCode === KEYS.SPACE || + const isShift = !!event.shiftKey; + if (!isShift && (event.keyCode === KEYS.ENTER || +// event.keyCode === KEYS.SPACE || event.keyCode === KEYS.DOWN || - event.keyCode === KEYS.UP){ + event.keyCode === KEYS.UP)){ EventUtil.trapEvent(event); this.setState({ diff --git a/demo/docs/components.json b/demo/docs/components.json index b586340413..1fde82104f 100644 --- a/demo/docs/components.json +++ b/demo/docs/components.json @@ -1448,39 +1448,6 @@ "computed": false } }, - "relativeYearFrom": { - "type": { - "name": "number" - }, - "required": false, - "description": "", - "defaultValue": { - "value": "-5", - "computed": false - } - }, - "relativeYearTo": { - "type": { - "name": "number" - }, - "required": false, - "description": "", - "defaultValue": { - "value": "5", - "computed": false - } - }, - "todayLabel": { - "type": { - "name": "string" - }, - "required": false, - "description": "", - "defaultValue": { - "value": "'Today'", - "computed": false - } - }, "value": { "type": { "name": "instanceOf", @@ -1500,17 +1467,6 @@ "required": false, "description": "" }, - "weekDayLabels": { - "type": { - "name": "array" - }, - "required": false, - "description": "", - "defaultValue": { - "value": "[\n 'Sunday','Monday','Tuesday',\n 'Wednesday','Thursday','Friday',\n 'Saturday'\n]", - "computed": false - } - }, "onDateChange": { "defaultValue": { "value": "function(date) {\n console.log('onDateChange should be defined');\n}", diff --git a/demo/pages/TimePickerSection.js b/demo/pages/TimePickerSection.js index f488ebfd76..96b3d0b44a 100644 --- a/demo/pages/TimePickerSection.js +++ b/demo/pages/TimePickerSection.js @@ -31,10 +31,10 @@ class DatepickerSingleSelectSection extends React.Component { } render(){ - const docs = DOCS["DatepickerSingleSelect"] ? true : false; + const docs = DOCS["Timepicker"] ? true : false; return (

        - +
        {docs ?

        : null}

        @@ -42,7 +42,7 @@ class DatepickerSingleSelectSection extends React.Component {
        - +
        ); } From a2fc8a23a56388fd508d96fcde63053f14fad78d Mon Sep 17 00:00:00 2001 From: ibogdanov Date: Fri, 12 Feb 2016 12:38:36 -0800 Subject: [PATCH 13/13] update docs --- demo/docs/components.json | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/demo/docs/components.json b/demo/docs/components.json index 1fde82104f..e59e6ca501 100644 --- a/demo/docs/components.json +++ b/demo/docs/components.json @@ -1460,6 +1460,17 @@ "computed": false } }, + "stepInMinutes": { + "type": { + "name": "number" + }, + "required": false, + "description": "", + "defaultValue": { + "value": "30", + "computed": false + } + }, "strValue": { "type": { "name": "string"