diff --git a/package.json b/package.json
index 0efb59b..34fb6e9 100644
--- a/package.json
+++ b/package.json
@@ -22,6 +22,7 @@
},
"homepage": "https://github.com/devex-web-frontend/dx-components#readme",
"devDependencies": {
+ "moment": "^2.15.0",
"@kadira/storybook": "2.1.1",
"autoprefixer": "^6.3.6",
"babel-core": "^6.10.4",
@@ -92,7 +93,6 @@
"dependencies": {
"bower": "^1.7.9",
"classnames": "^2.2.5",
- "moment": "^2.15.0",
"react": "^15.3.0",
"react-css-themr": "~1.4.0",
"react-dom": "^15.3.0",
diff --git a/src/components/Button/Button.jsx b/src/components/Button/Button.jsx
index 2d10d04..dfa3fc9 100644
--- a/src/components/Button/Button.jsx
+++ b/src/components/Button/Button.jsx
@@ -3,6 +3,10 @@ import classnames from 'classnames';
import {PURE} from 'dx-util/src/react/pure';
import {themr} from 'react-css-themr';
+export const BUTTON_THEME = {
+ container: React.PropTypes.string
+};
+
export const BUTTON = Symbol('Button');
@PURE
@@ -10,9 +14,7 @@ export const BUTTON = Symbol('Button');
export default class Button extends React.Component {
static propTypes = {
children: React.PropTypes.node,
- theme: React.PropTypes.shape({
- container: React.PropTypes.string
- }),
+ theme: React.PropTypes.shape(BUTTON_THEME),
type: React.PropTypes.string,
isDisabled: React.PropTypes.bool,
isPrimary: React.PropTypes.bool,
diff --git a/src/components/Calendar/Calendar.constants.js b/src/components/Calendar/Calendar.constants.js
index 4d01eae..1a87771 100644
--- a/src/components/Calendar/Calendar.constants.js
+++ b/src/components/Calendar/Calendar.constants.js
@@ -1,5 +1,4 @@
import React from 'react';
-
export const CALENDAR_THEME = {
container: React.PropTypes.string,
header: React.PropTypes.string,
@@ -10,6 +9,7 @@ export const CALENDAR_THEME = {
monthHeader: React.PropTypes.string,
monthHeader__day: React.PropTypes.string,
week: React.PropTypes.string,
+ dayContainer: React.PropTypes.string,
day: React.PropTypes.string,
day_disabled: React.PropTypes.string,
day_current: React.PropTypes.string,
diff --git a/src/components/Calendar/Calendar.demo.styl b/src/components/Calendar/Calendar.demo.styl
index 8d30663..3276870 100644
--- a/src/components/Calendar/Calendar.demo.styl
+++ b/src/components/Calendar/Calendar.demo.styl
@@ -1,12 +1,27 @@
@require "./Calendar.styl";
-
.container {
+ padding: 0;
+ display: inline-block;
font-size: 12px;
color: #fff;
background-color: #3d3b39;
+ padding-bottom: 5px;
+}
+
+.monthHeader {
+ &__day {
+ width: 25px;
+ }
}
+.dayContainer {
+ width: 25px;
+ position: relative;
+}
+
.header {
+ text-align: center;
+ vertical-align: middle;
border-bottom: 1px solid rgba(255, 255, 255, 0.15);
padding: 10px 0;
font-weight: bold;
@@ -19,6 +34,7 @@
.changeMonth {
&__container {
+ background: transparent;
border: none;
box-shadow: none;
vertical-align: top;
@@ -36,14 +52,16 @@
}
}
-.month {
- padding-bottom: 5px;
+.week {
+ width: 100%;
}
.monthHeader {
- margin: 6px 0 12px;
-
&__day {
+ text-align: center;
+ vertical-align: middle;
+ box-sizing: border-box;
+ padding: 10px 0;
font-size: 10px;
line-height: 8px;
color: darken(#fff, 30);
@@ -52,10 +70,15 @@
}
}
-.week {
+.dayContainer {
+ text-align: center;
}
.day {
+ box-sizing: border-box;
+ display: inline-block;
+ cursor: pointer;
+ margin: 0 10px 2px;
line-height: 8px;
padding: 5px;
user-select: none;
@@ -77,4 +100,4 @@
&_disabled {
color: #7c7b7b;
}
-}
\ No newline at end of file
+}
diff --git a/src/components/Calendar/Calendar.jsx b/src/components/Calendar/Calendar.jsx
index 6aa3456..b0ac68f 100644
--- a/src/components/Calendar/Calendar.jsx
+++ b/src/components/Calendar/Calendar.jsx
@@ -1,12 +1,11 @@
import React from 'react';
import {themr} from 'react-css-themr';
-import moment from 'moment';
import Month from './Month';
import {PURE} from 'dx-util/src/react/react';
import ButtonIcon from '../ButtonIcon/ButtonIcon';
import {MEMOIZE} from 'dx-util/src/function/function';
import {CALENDAR_THEME} from './Calendar.constants';
-import noop from '../../util/func/noop';
+import {addMonths} from '../../util/func/date';
export const CALENDAR = Symbol('Calendar');
@@ -14,37 +13,40 @@ export const CALENDAR = Symbol('Calendar');
@themr(CALENDAR)
export default class Calendar extends React.Component {
static propTypes = {
- value: React.PropTypes.string.isRequired, // ISO - "2016-09-20T15:30:39.298Z"
- headerDateFormat: React.PropTypes.string,
+ value: React.PropTypes.instanceOf(Date),
+ min: React.PropTypes.instanceOf(Date),
+ max: React.PropTypes.instanceOf(Date),
+
+ /**
+ * Used to change the first day of week.
+ * It varies from Saturday to Monday between different locales.
+ * The allowed range is 0 (Sunday) to 6 (Saturday). The default is 1, Monday, as per ISO 8601.
+ */
+ firstDayOfWeek: React.PropTypes.number,
+ headerDateFormatter: React.PropTypes.func,
+ headerDayFormatter: React.PropTypes.func,
+ dayFormatter: React.PropTypes.func,
headerDayFormat: React.PropTypes.string,
dayFormat: React.PropTypes.string,
onChange: React.PropTypes.func,
- min: React.PropTypes.string, // ISO
- max: React.PropTypes.string, // ISO
previousMonthIcon: React.PropTypes.string,
nextMonthIcon: React.PropTypes.string,
+ theme: React.PropTypes.shape(CALENDAR_THEME),
locale: React.PropTypes.string,
- theme: React.PropTypes.shape(CALENDAR_THEME)
+ Month: React.PropTypes.func,
+ CalendarHeader: React.PropTypes.func,
+ Day: React.PropTypes.func
}
static defaultProps = {
- onChange: noop,
- min: null,
- max: null,
- headerDateFormat: 'MMM YYYY',
- dayFormat: 'D',
- headerDayFormat: 'ddd',
- locale: 'en'
+ Month,
+ CalendarHeader,
+ locale: 'en',
+ ...Month.defaultProps
}
state = {
- displayedDate: moment(this.props.value)
- }
-
- componentWillReceiveProps(newProps) {
- this.setState({
- displayedDate: moment(newProps.value)
- });
+ displayedDate: this.props.value
}
render() {
@@ -52,18 +54,83 @@ export default class Calendar extends React.Component {
theme,
onChange,
min,
+ locale,
max,
- headerDateFormat,
- headerDayFormat,
- dayFormat,
previousMonthIcon,
nextMonthIcon,
- locale,
- value
+ Month,
+ Day,
+ value,
+ firstDayOfWeek,
+ headerDateFormatter: originalHeaderDateFormatter,
+ headerDayFormatter: originalHeaderDayFormatter,
+ dayFormatter: originalDayFormatter
} = this.props;
- const displayedDate = this.state.displayedDate.locale(locale);
- const headerDate = displayedDate.format(headerDateFormat);
+ const headerDayFormatter = value => {
+ return originalHeaderDayFormatter(value, locale);
+ };
+
+ const dayFormatter = value => {
+ return originalDayFormatter(value, locale);
+ };
+
+ const headerDateFormatter = value => {
+ return originalHeaderDateFormatter(value, locale);
+ };
+
+ const {displayedDate} = this.state;
+
+ return (
+
+
+ {
+
+
+ }
+
+ );
+ }
+
+ onChangeDisplayedDate = displayedDate => {
+ this.setState({
+ displayedDate
+ });
+ }
+}
+
+class CalendarHeader extends React.Component {
+ static propTypes = {
+ value: React.PropTypes.instanceOf(Date),
+ onChange: React.PropTypes.func,
+ locale: React.PropTypes.string,
+ headerDateFormatter: React.PropTypes.func,
+ previousMonthIcon: React.PropTypes.string,
+ nextMonthIcon: React.PropTypes.string,
+ theme: React.PropTypes.shape(CALENDAR_THEME),
+ }
+
+ render() {
+ const {
+ theme,
+ value,
+ headerDateFormatter,
+ previousMonthIcon,
+ nextMonthIcon,
+ } = this.props;
const changeMonthBtnTheme = {
container: theme.changeMonth__container,
@@ -71,34 +138,20 @@ export default class Calendar extends React.Component {
};
return (
-
-
-
- {headerDate}
-
-
-
+
+
+
+ {headerDateFormatter ? headerDateFormatter(value) : value}
+
+
);
}
@MEMOIZE
onChangeMonth = step => () => {
- this.setState({
- displayedDate: this.state.displayedDate.clone().add(step, 'months')
- });
+ const {value, onChange} = this.props;
+ const newValue = addMonths(value, step);
+ onChange && onChange(newValue);
}
}
\ No newline at end of file
diff --git a/src/components/Calendar/Calendar.page.jsx b/src/components/Calendar/Calendar.page.jsx
new file mode 100644
index 0000000..810f169
--- /dev/null
+++ b/src/components/Calendar/Calendar.page.jsx
@@ -0,0 +1,118 @@
+import React from 'react';
+import {PURE} from 'dx-util/src/react/pure';
+import Demo from '../../demo/Demo.jsx';
+import {FORMATTER} from '../DatePicker/DatePicker.page';
+import Day from './Day.jsx';
+import Calendar from './Calendar.jsx';
+import stateful from '../../util/react/stateful';
+import {storiesOf} from '@kadira/storybook';
+
+import nextMonthIcon from '../DatePicker/resources/icon-move-right.svg';
+import previousMonthIcon from '../DatePicker/resources/icon-move-left.svg';
+import css from './Calendar.page.styl';
+
+const formatter = FORMATTER.INTL;
+
+const headerDateFormatter = formatter.headerDate;
+const headerDayFormatter = formatter.headerDay;
+const dayFormatter = formatter.day;
+
+const Stateful = stateful()(Calendar);
+
+const EVENTS = {
+ [new Date(2016, 9, 1)]: [
+ {
+ type: 'holiday',
+ title: 'test'
+ }, {
+ type: 'birthday',
+ title: 'test'
+ }
+ ],
+ [new Date(2016, 9, 10)]: [
+ {
+ type: 'holiday',
+ title: 'test'
+ }
+ ]
+};
+
+class DayWithEvent extends Day {
+ _renderEvents(events) {
+ return events.map((event, i) => {
+ console.log(css, event.type, css[event.type]);
+ return (
+
+ );
+ });
+ }
+ renderInnerContent() {
+ const {
+ dayFormatter,
+ value,
+ } = this.props;
+ const events = EVENTS[value];
+ return (
+
+ {events && (
{this._renderEvents(events)}
)}
+ {dayFormatter ? dayFormatter(value) : value}
+
+ );
+ }
+}
+
+@PURE
+class CalendarPage extends React.Component {
+
+ state = {
+ value: new Date(2016, 9, 16)
+ }
+
+ render() {
+ return (
+
+
+
+
+
+
+
+ );
+ }
+
+ onChnage = value => {
+ this.setState({
+ value
+ });
+ }
+}
+
+storiesOf('Calendar', module).add('Default', () => );
\ No newline at end of file
diff --git a/src/components/Calendar/Calendar.page.styl b/src/components/Calendar/Calendar.page.styl
new file mode 100644
index 0000000..19fd897
--- /dev/null
+++ b/src/components/Calendar/Calendar.page.styl
@@ -0,0 +1,21 @@
+$eventSize = 5px;
+.events {
+ position: absolute;
+ right: -($eventSize + 1px);
+ top: 0;
+ width: $eventSize;
+}
+
+.event {
+ width: $eventSize;
+ box-sizing: border-box;
+ height: @width;
+}
+
+.holiday {
+ background: #7f7d7d;
+}
+
+.birthday {
+ background: #fff;
+}
\ No newline at end of file
diff --git a/src/components/Calendar/Calendar.styl b/src/components/Calendar/Calendar.styl
index 4796935..78b1b1e 100644
--- a/src/components/Calendar/Calendar.styl
+++ b/src/components/Calendar/Calendar.styl
@@ -1,64 +1,51 @@
-.container {
- padding: 0;
-}
-
.header {
user-select: none;
- text-align: center;
- vertical-align: middle;
&__text {
cursor: default;
}
}
-.changeMonth {
- &__container {
- background: transparent;
+.monthHeader {
+ &__day {
+ user-select: none;
+ cursor: default;
+ }
+}
+
+.day {
+ user-select: none;
+
+ &_disabled {
+ cursor: default;
}
+}
+.changeMonth {
&__icon {
fill: inherit;
}
}
+// css table
.month {
+ display: table;
+ table-layout: fixed;
+}
+
+.week,
+.monthHeader {
+ display: table-row;
}
.monthHeader {
&__day {
- display: inline-block;
- text-align: center;
+ display: table-cell;
vertical-align: middle;
- box-sizing: border-box;
- margin: 0 10px 0;
- width: 25px;
- user-select: none;
- cursor: default;
}
}
-.week {
- width: 100%;
-}
-
-.day {
- box-sizing: border-box;
- display: inline-block;
- text-align: center;
+.dayContainer {
+ display: table-cell;
vertical-align: middle;
- cursor: pointer;
- margin: 0 10px 2px;
- width: 25px;
- user-select: none;
-
- &_selected {
- }
-
- &_current {
- }
-
- &_disabled {
- cursor: default;
- }
}
\ No newline at end of file
diff --git a/src/components/Calendar/Day.jsx b/src/components/Calendar/Day.jsx
index a5e0b96..27a957a 100644
--- a/src/components/Calendar/Day.jsx
+++ b/src/components/Calendar/Day.jsx
@@ -1,61 +1,45 @@
import React from 'react';
import {PURE} from 'dx-util/src/react/react';
-import moment from 'moment';
-import {CALENDAR_THEME} from './Calendar.constants';
-import Button from '../Button/Button';
-import noop from '../../util/func/noop';
-import classnames from 'classnames';
+import Button, {BUTTON_THEME} from '../Button/Button';
@PURE
export default class Day extends React.Component {
static propTypes = {
- value: React.PropTypes.instanceOf(moment).isRequired,
+ value: React.PropTypes.instanceOf(Date).isRequired,
onChange: React.PropTypes.func,
- dayFormat: React.PropTypes.string.isRequired,
+ dayFormatter: React.PropTypes.func,
isDisabled: React.PropTypes.bool,
- isCurrent: React.PropTypes.bool,
- isSelected: React.PropTypes.bool,
- theme: React.PropTypes.shape(CALENDAR_THEME)
+ theme: React.PropTypes.shape(BUTTON_THEME)
}
- static defaultProps = {
- onChange: noop,
- isDisabled: false,
- isCurrent: false,
- isSelected: false
+ renderInnerContent() {
+ const {
+ dayFormatter,
+ value,
+ } = this.props;
+ return dayFormatter ? dayFormatter(value) : value;
}
render() {
const {
theme,
- value,
- dayFormat,
- isCurrent,
isDisabled,
- isSelected
} = this.props;
- const btnTheme = {
- container: classnames(theme.day, {
- [theme.day_disabled]: isDisabled,
- [theme.day_current]: isCurrent && !isDisabled,
- [theme.day_selected]: isSelected && !isDisabled
- })
- };
-
return (
-