Skip to content

Commit

Permalink
✨ [feature] add DateSelect and DateRangeSelect Component.
Browse files Browse the repository at this point in the history
  • Loading branch information
lanjingling0510 committed Mar 22, 2017
1 parent 6dbfc8c commit ee36b44
Show file tree
Hide file tree
Showing 20 changed files with 373 additions and 33 deletions.
4 changes: 1 addition & 3 deletions components/autocomplete/theme.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
@import './config.css';

.menu {
box-shadow: 0 1px 6px rgba(0,0,0,.2);
border-radius: 4px;
z-index: 1050;
float: left;
Expand All @@ -15,8 +14,7 @@
color: rgba(0,0,0,.65);
background: #fff;
overflow: hidden;
min-width: 120px;
position: absolute;
width: 100%;
}

.menuItem {
Expand Down
147 changes: 147 additions & 0 deletions components/date_select/DateRangeSelect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import React, { Component, PropTypes } from 'react';
import theme from './theme.css';
import moment from 'moment';
import allRanges from './ranges.js';
import pick from 'ramda/src/pick';

const popupAlign = {
points: ['tl', 'bl'],
offset: [0, 10],
};

const factory = (Trigger, SelectInput, DateRange) => {
class DateRangeSelect extends Component {

static propTypes = {
startDate: PropTypes.object,
endDate: PropTypes.object,
minDate: PropTypes.object,
maxDate: PropTypes.object,
onChange: PropTypes.func,
ranges: PropTypes.arrayOf(
PropTypes.oneOf(['今日', '昨日', '近7日', '近30天', '近三个月', '近一年'])
),
theme: PropTypes.shape({
DaySelected: PropTypes.object,
DayInRange: PropTypes.object,
})
}

static defaultProps = {
minDate: moment('2016-03-01'),
maxDate: moment(),
ranges: ['今日', '昨日', '近7日', '近30天', '近三个月', '近一年'],
onChange: () => void 0,
}

constructor(props) {
super(props);

this.state = {
ranges: pick(props.ranges, allRanges),
startDate: 'startDate' in props ? props.startDate : moment(),
endDate: 'endDate' in props ? props.endDate : moment(),
open: false,
};

this.defaultTheme = {
DaySelected: {
background: theme.DaySelected_background,
},
DayInRange: {
background: theme.DayInRange_background,
color: theme.DayInRange_color,
},
};
}

componentWillReceiveProps(nextProps) {
if ('startDate' in nextProps) {
this.setState({ startDate: nextProps.startDate });
}

if ('endDate' in nextProps) {
this.setState({ date: nextProps.endDate });
}

if (nextProps.ranges !== this.props.ranges) {
this.setState({ ranges: pick(nextProps.ranges, allRanges) })
}
}

handleSelectToggle = () => {
this.setState({ open: !this.state.open });
}

handleRangeSelect = ({ startDate, endDate }) => {
const props = this.props;

if (!('startDate' in props)) {
this.setState({ startDate });
}

if (!('endDate' in this.props)) {
this.setState({ endDate });
}

this.handleSelectToggle();
props.onChange(startDate, endDate);
}

getDateRange = () => {
const {
theme,
minDate,
maxDate,
} = this.props;

const {
ranges,
startDate,
endDate,
} = this.state;

return (
<DateRange
lang="cn"
startDate={startDate}
endDate={endDate}
minDate={minDate}
maxDate={maxDate}
twoStepChange={true}
onChange={this.handleRangeSelect}
linkedCalendars={true}
theme={theme || this.defaultTheme}
ranges={ranges} />
);
}

render() {
const {
open,
startDate,
endDate,
} = this.state;

const dateRange = this.getDateRange();
const selectedItem = {label: startDate.format('YYYY年MM月D日') + '~' + endDate.format('YYYY年MM月D日')};

return (
<Trigger
popupAlign={popupAlign}
popupVisible={open}
onPopupVisibleChange={this.handleSelectToggle}
popup={dateRange}>
<SelectInput
selectedItem={selectedItem}
isActive={open}
onClick={this.handleSelectToggle} />
</Trigger>
);
}
}

return DateRangeSelect;
};

export {factory as dateRangeSelectFactory};
104 changes: 104 additions & 0 deletions components/date_select/DateSelect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import React, { Component, PropTypes } from 'react';
import theme from './theme.css';
import moment from 'moment';

const popupAlign = {
points: ['tl', 'bl'],
offset: [0, 10],
};

const factory = (Trigger, SelectInput, Calendar) => {
class DateSelect extends Component {

static propTypes = {
date: PropTypes.object,
minDate: PropTypes.object,
maxDate: PropTypes.object,
onChange: PropTypes.func,
theme: PropTypes.shape({
DaySelected: PropTypes.object,
})
}

static defaultProps = {
minDate: moment('2016-03-01'),
maxDate: moment(),
onChange: () => void 0,
}

constructor(props) {
super(props);

this.state = {
date: 'date' in props ? props.date : moment(),
open: false,
}

this.defaultTheme = {
DaySelected: {
background: theme.DaySelected_background
}
};
}

componentWillReceiveProps(nextProps) {
if ('date' in nextProps) {
this.setState({ date: nextProps.date });
}
}

handleSelectToggle = () => {
this.setState({ open: !this.state.open });
}

handleDateSelect = (date) => {
this.handleSelectToggle();

if (!('date' in this.props)) {
this.setState({ date });
}

this.props.onChange(date);
}

getCalendar = () => {
const {
minDate,
maxDate,
} = this.props;

return (
<Calendar
lang="cn"
date={this.state.date}
minDate={minDate}
maxDate={maxDate}
onChange={this.handleDateSelect}
theme={this.props.theme || this.defaultTheme} />
);
}

render() {
const state = this.state;
const calendar = this.getCalendar();
const selectedItem = {label: state.date.format('YYYY年MM月D日')};

return (
<Trigger
popupAlign={popupAlign}
popupVisible={state.open}
onPopupVisibleChange={this.handleSelectToggle}
popup={calendar}>
<SelectInput
selectedItem={selectedItem}
isActive={state.open}
onClick={this.handleSelectToggle} />
</Trigger>
);
}
}

return DateSelect;
};

export {factory as dateSelectFactory};
13 changes: 13 additions & 0 deletions components/date_select/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import {dateSelectFactory} from './DateSelect';
import {dateRangeSelectFactory} from './DateRangeSelect';
import { Calendar, DateRange } from 'react-date-range';

import Trigger from '../trigger';
import SelectInput from '../select_input';

const DateSelect = dateSelectFactory(Trigger, SelectInput, Calendar);
const DateRangeSelect = dateRangeSelectFactory(Trigger, SelectInput, DateRange);

export default DateSelect;
export { DateSelect };
export { DateRangeSelect };
50 changes: 50 additions & 0 deletions components/date_select/ranges.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
export default {
'今日': {
startDate(e) {
return e;
},
endDate(e) {
return e;
},
},
'昨日': {
startDate(e) {
return e.add(-1, 'days');
},
endDate(e) {
return e.add(-1, 'days');
},
},
'近7日': {
startDate(e) {
return e.add(-7, 'days');
},
endDate(e) {
return e;
},
},
'近30日': {
startDate(e) {
return e.add(-1, 'months');
},
endDate(e) {
return e;
},
},
'近三个月': {
startDate(e) {
return e.add(-3, 'months');
},
endDate(e) {
return e;
},
},
'近一年': {
startDate(e) {
return e.add(-1, 'years');
},
endDate(e) {
return e;
},
},
};
8 changes: 8 additions & 0 deletions components/date_select/theme.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
@import '../colors.css';
@import '../variables.css';

:export {
DaySelected_background: var(--color-primary);
DayInRange_background: var(--palette-cyan-200);
DayInRange_color: var(--color-white);
}
1 change: 1 addition & 0 deletions components/identifiers.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export const RIPPLE = 'CQRIPPLE';
export const ICON = 'CQICON';
export const SELECT = 'CQSELECT';
export const SELECT_INPUT = 'CQSELECTINPUT';
export const DATESELECT = 'CQDATESELECT';
export const MENU = 'CQMENU';
export const POPUP = 'CQPOPUP';
export const OVERLAY = 'CQOVERLAY';
Expand Down
4 changes: 1 addition & 3 deletions components/popup/popup.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,16 +98,14 @@ class Popup extends React.Component {
const {children, theme, active, onMouseEnter, onMouseLeave} = this.props;

const newProps = {
key: 'popup',
ref: 'popup',
onMouseEnter,
onMouseLeave,
};

const classes = classnames(theme.popup, {
[theme.active]: active});

return <div className={classes}>{React.cloneElement(children, newProps)}</div>;
return <div ref="popup" className={classes}>{React.cloneElement(children, newProps)}</div>;
}

getPopupDomNode = () => {
Expand Down
2 changes: 2 additions & 0 deletions components/popup/theme.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
opacity: 0.01;
transform: translate(0, 10px);
opacity: 0;
position: absolute;
box-shadow: 0 1px 6px rgba(0,0,0,.2);
transition:
opacity var(--animation-duration) var(--animation-curve-default),
transform var(--animation-duration) var(--animation-curve-default);
Expand Down
5 changes: 4 additions & 1 deletion components/select/Select.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,10 @@ const factory = (Trigger, SelectInput, Menu, MenuItem) => {

handleMenuItemClick = item => () => {
this.handleSelectToggle();
this.setState({ value: item.value });
if (!('value' in this.props)) {
this.setState({ value: item.value });
}

this.props.onChange(item);
}

Expand Down
Loading

0 comments on commit ee36b44

Please sign in to comment.