@spothero/ui 15.1.0 → 15.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -3
- package/styles/Alert/Alert.jsx +0 -45
- package/styles/Alert/Alert.spec.js +0 -85
- package/styles/AutoSuggestInput/AutoSuggestInput.jsx +0 -429
- package/styles/AutoSuggestInput/AutoSuggestInput.spec.js +0 -132
- package/styles/AutoSuggestInput/AutoSuggestItem.jsx +0 -61
- package/styles/AutoSuggestInput/AutoSuggestList.jsx +0 -85
- package/styles/Badge/Badge.jsx +0 -24
- package/styles/Badge/Badge.spec.js +0 -43
- package/styles/Chart/Chart.jsx +0 -185
- package/styles/Chart/Chart.spec.js +0 -369
- package/styles/Checkbox/Checkbox.jsx +0 -159
- package/styles/Checkbox/Checkbox.spec.js +0 -142
- package/styles/DateTime/DatePicker.jsx +0 -281
- package/styles/DateTime/DatePicker.spec.js +0 -186
- package/styles/DateTime/DatePickerCalendar.jsx +0 -170
- package/styles/DateTime/DatePickerCalendarNavigation.jsx +0 -44
- package/styles/DateTime/DatePickerCalendarWithRange.jsx +0 -218
- package/styles/DateTime/DateTimePicker.jsx +0 -266
- package/styles/DateTime/DateTimePicker.spec.js +0 -60
- package/styles/DateTime/DateTimeRangePicker.jsx +0 -629
- package/styles/DateTime/DateTimeRangePicker.spec.js +0 -425
- package/styles/DateTime/TimePicker.jsx +0 -158
- package/styles/DateTime/TimePicker.spec.js +0 -148
- package/styles/DateTime/date-time-assertions.js +0 -89
- package/styles/DateTime/index.js +0 -6
- package/styles/ErrorBoundary/ErrorBoundary.jsx +0 -76
- package/styles/ErrorBoundary/ErrorBoundary.spec.js +0 -72
- package/styles/Flyout/Flyout.jsx +0 -147
- package/styles/Flyout/Flyout.spec.js +0 -117
- package/styles/Form/Form.jsx +0 -151
- package/styles/Form/Form.spec.js +0 -148
- package/styles/Form/FormElementError.jsx +0 -18
- package/styles/Form/FormGroup.jsx +0 -32
- package/styles/Form/FormGroupError.jsx +0 -24
- package/styles/Form/index.js +0 -4
- package/styles/GooglePlacesSearchInput/GooglePlacesSearchInput.jsx +0 -215
- package/styles/GooglePlacesSearchInput/GooglePlacesSearchInput.spec.js +0 -213
- package/styles/GooglePlacesSearchInput/PoweredByGoogle.jsx +0 -43
- package/styles/GooglePlacesSearchInput/index.js +0 -2
- package/styles/HorizontalRule/HorizontalRule.jsx +0 -36
- package/styles/HorizontalRule/HorizontalRule.spec.js +0 -94
- package/styles/Label/Label.jsx +0 -22
- package/styles/Label/Label.spec.js +0 -11
- package/styles/Notification/Notification.jsx +0 -117
- package/styles/Notification/Notification.spec.js +0 -154
- package/styles/Notification/NotificationContainer.jsx +0 -90
- package/styles/Notification/NotificationPropTypes.js +0 -20
- package/styles/Notification/index.js +0 -2
- package/styles/PasswordControl/PasswordControl.jsx +0 -197
- package/styles/PasswordControl/PasswordControl.spec.js +0 -236
- package/styles/Portal/Portal.jsx +0 -65
- package/styles/Portal/Portal.spec.js +0 -45
- package/styles/PulseLoader/PulseLoader.jsx +0 -71
- package/styles/PulseLoader/PulseLoader.spec.js +0 -63
- package/styles/Radio/Radio.jsx +0 -114
- package/styles/Radio/Radio.spec.js +0 -128
- package/styles/Radio/RadioGroup.jsx +0 -105
- package/styles/Radio/index.js +0 -2
- package/styles/RenderInBody/RenderInBody.jsx +0 -56
- package/styles/RenderInBody/RenderInBody.spec.js +0 -24
- package/styles/Select/Select.jsx +0 -251
- package/styles/Select/Select.spec.js +0 -254
- package/styles/Select/SelectItemPropTypes.js +0 -19
- package/styles/Select/index.js +0 -2
- package/styles/SelectControlled/SelectControlled.jsx +0 -250
- package/styles/SelectControlled/SelectControlled.spec.js +0 -290
- package/styles/SelectControlled/index.js +0 -1
- package/styles/Sprite/Sprite.jsx +0 -16
- package/styles/Sprite/Sprite.spec.js +0 -11
- package/styles/Tabs/Tab.jsx +0 -38
- package/styles/Tabs/TabContent.jsx +0 -46
- package/styles/Tabs/TabNavigation.jsx +0 -64
- package/styles/Tabs/TabPanel.jsx +0 -30
- package/styles/Tabs/Tabs.jsx +0 -87
- package/styles/Tabs/Tabs.spec.js +0 -201
- package/styles/Tabs/index.js +0 -5
- package/styles/TextArea/TextArea.jsx +0 -137
- package/styles/TextArea/TextArea.spec.js +0 -111
- package/styles/TextInput/TextInput.jsx +0 -159
- package/styles/TextInput/TextInput.spec.js +0 -263
- package/styles/TextInput/TextInputPropTypes.js +0 -88
- package/styles/TextInput/index.js +0 -2
- package/styles/Tooltip/Tooltip.jsx +0 -230
- package/styles/Tooltip/Tooltip.spec.js +0 -170
|
@@ -1,281 +0,0 @@
|
|
|
1
|
-
import React, {Component} from 'react';
|
|
2
|
-
import PropTypes from 'prop-types';
|
|
3
|
-
import classNames from 'classnames';
|
|
4
|
-
import uuidV4 from 'uuid/v4';
|
|
5
|
-
import {document} from 'ssr-window';
|
|
6
|
-
import TetherComponent from 'react-tether';
|
|
7
|
-
import omit from 'lodash/omit';
|
|
8
|
-
import IconCalendar from '@spothero/icons/calendar';
|
|
9
|
-
import DOMUtils from '@spothero/utils/dom';
|
|
10
|
-
import DatePickerCalendar from './DatePickerCalendar';
|
|
11
|
-
import TextInput from '../TextInput/TextInput';
|
|
12
|
-
import Portal from '../Portal/Portal';
|
|
13
|
-
|
|
14
|
-
export default class DatePicker extends Component {
|
|
15
|
-
static propTypes = {
|
|
16
|
-
/** Additional class(es) to add to the component. */
|
|
17
|
-
className: PropTypes.string,
|
|
18
|
-
/** A unique ID which is used to identify this element for accessibility purposes on the client as well as the server. */
|
|
19
|
-
id: PropTypes.string.isRequired,
|
|
20
|
-
/** Additional class(es) to add to the the underlying calendar component. */
|
|
21
|
-
calendarClassName: PropTypes.string,
|
|
22
|
-
/** A unique name which is used to identify this element. If belonging to a form this is used as the key for serialization and is required. */
|
|
23
|
-
name: PropTypes.string,
|
|
24
|
-
/** A function that alters how the selected date is displayed in the input field. Takes the date in MM/DD/YYYY format and should return a string with the new format. */
|
|
25
|
-
displayFormat: PropTypes.func,
|
|
26
|
-
/** A string in the format 'MM/DD/YYYY' representing the date which should be selected. */
|
|
27
|
-
selectedDate: PropTypes.string,
|
|
28
|
-
/** Whether to show the calendar icon in the input field. */
|
|
29
|
-
useIcon: PropTypes.bool,
|
|
30
|
-
/** If using the icon, whether it should appear on the left or right side of the input field. */
|
|
31
|
-
iconPosition: PropTypes.oneOf(['left', 'right']),
|
|
32
|
-
/** Whether the DatePicker is disabled or not. */
|
|
33
|
-
disabled: PropTypes.bool,
|
|
34
|
-
/** A custom label (typically a Label component) to display above the input. */
|
|
35
|
-
label: PropTypes.element,
|
|
36
|
-
/** The placeholder text to show in the input before a selection is made. */
|
|
37
|
-
placeholder: PropTypes.string,
|
|
38
|
-
/** Whether the field should be auto focused when mounted. */
|
|
39
|
-
autoFocus: PropTypes.bool,
|
|
40
|
-
/** Whether the field should be focused when the component receives new prop of focus={true}. */
|
|
41
|
-
focus: PropTypes.bool,
|
|
42
|
-
/** Whether to disable days before today. */
|
|
43
|
-
disablePast: PropTypes.bool,
|
|
44
|
-
/** A string in the format 'MM/DD/YYYY' representing the date where days before it should be disabled in the calendar. */
|
|
45
|
-
disableBefore: PropTypes.string,
|
|
46
|
-
/** A string in the format 'MM/DD/YYYY' representing the date where days after it should be disabled in the calendar. */
|
|
47
|
-
disableAfter: PropTypes.string,
|
|
48
|
-
/** Puts the calendar in the center of the page with a shim behind it. */
|
|
49
|
-
useTetherShim: PropTypes.bool,
|
|
50
|
-
/** Whether to set the initial month to show in the calendar to the same month as the selected day falls within when a day is selected. */
|
|
51
|
-
overrideInitialMonthWithSelected: PropTypes.bool,
|
|
52
|
-
/**
|
|
53
|
-
* Function to execute when the selected date changes.
|
|
54
|
-
*
|
|
55
|
-
* @param {String} selectedDate - The selected date in the format 'MM/DD/YYYY'.
|
|
56
|
-
*/
|
|
57
|
-
onChange: PropTypes.func,
|
|
58
|
-
};
|
|
59
|
-
static defaultProps = {
|
|
60
|
-
disablePast: true,
|
|
61
|
-
useIcon: true,
|
|
62
|
-
overrideInitialMonthWithSelected: true,
|
|
63
|
-
iconPosition: 'right',
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
constructor(props) {
|
|
67
|
-
super(props);
|
|
68
|
-
|
|
69
|
-
const {id, selectedDate} = props;
|
|
70
|
-
|
|
71
|
-
if (!id) {
|
|
72
|
-
throw new Error(
|
|
73
|
-
`The prop 'id' is required to make DatePicker accessible for users using assistive technologies such as screen readers. Check the render method of DatePicker.`
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
this._TETHER_CLASS = `DatePicker-tether-${id}`;
|
|
78
|
-
|
|
79
|
-
this.state = {
|
|
80
|
-
showCalendar: false,
|
|
81
|
-
selectedDate,
|
|
82
|
-
tetherKey: uuidV4(),
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
componentDidUpdate(prevProps, prevState) {
|
|
87
|
-
const {useTetherShim, onChange} = this.props;
|
|
88
|
-
const {showCalendar, selectedDate} = this.state;
|
|
89
|
-
const {
|
|
90
|
-
showCalendar: prevShowCalendar,
|
|
91
|
-
selectedDate: prevSelectedDate,
|
|
92
|
-
} = prevState;
|
|
93
|
-
|
|
94
|
-
if (showCalendar && showCalendar !== prevShowCalendar) {
|
|
95
|
-
document.body.addEventListener('mousedown', this._onBodyClick);
|
|
96
|
-
document.body.addEventListener('touchstart', this._onBodyClick);
|
|
97
|
-
|
|
98
|
-
if (useTetherShim) {
|
|
99
|
-
DOMUtils.addClass('html', 'DatePicker-tether-shim-open');
|
|
100
|
-
}
|
|
101
|
-
} else {
|
|
102
|
-
this._removeBodyClickListener();
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (selectedDate !== prevSelectedDate && onChange) {
|
|
106
|
-
onChange(selectedDate);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
componentWillUnmount() {
|
|
111
|
-
this._removeBodyClickListener();
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
_onBodyClick = evt => {
|
|
115
|
-
if (
|
|
116
|
-
(!DOMUtils.parent(evt.target, 'FormElement-control') ||
|
|
117
|
-
!DOMUtils.parent(evt.target, `.DatePicker-${this.props.id}`)) &&
|
|
118
|
-
!DOMUtils.parent(evt.target, `.${this._TETHER_CLASS}`)
|
|
119
|
-
) {
|
|
120
|
-
this.setState({
|
|
121
|
-
showCalendar: false,
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
this.node.blur();
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
_onInputFocus = evt => {
|
|
129
|
-
this.setState({
|
|
130
|
-
showCalendar: true,
|
|
131
|
-
});
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
_onInputChange = selectedDate => {
|
|
135
|
-
this.setState({
|
|
136
|
-
selectedDate,
|
|
137
|
-
});
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
_onDateChange = selectedDate => {
|
|
141
|
-
this.setState({
|
|
142
|
-
showCalendar: false,
|
|
143
|
-
selectedDate,
|
|
144
|
-
tetherKey: uuidV4(),
|
|
145
|
-
});
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
_removeBodyClickListener() {
|
|
149
|
-
document.body.removeEventListener('mousedown', this._onBodyClick);
|
|
150
|
-
document.body.removeEventListener('touchstart', this._onBodyClick);
|
|
151
|
-
|
|
152
|
-
if (this.props.useTetherShim) {
|
|
153
|
-
DOMUtils.removeClass('html', 'DatePicker-tether-shim-open');
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Getter for the input DOM element.
|
|
159
|
-
*
|
|
160
|
-
* @public
|
|
161
|
-
* @returns {Element} - The input element.
|
|
162
|
-
*/
|
|
163
|
-
get node() {
|
|
164
|
-
return this._textInput.node;
|
|
165
|
-
}
|
|
166
|
-
render() {
|
|
167
|
-
const {
|
|
168
|
-
className,
|
|
169
|
-
id,
|
|
170
|
-
calendarClassName,
|
|
171
|
-
disabled,
|
|
172
|
-
disablePast,
|
|
173
|
-
disableBefore,
|
|
174
|
-
disableAfter,
|
|
175
|
-
label,
|
|
176
|
-
name,
|
|
177
|
-
useIcon,
|
|
178
|
-
iconPosition,
|
|
179
|
-
placeholder,
|
|
180
|
-
useTetherShim,
|
|
181
|
-
autoFocus,
|
|
182
|
-
focus,
|
|
183
|
-
overrideInitialMonthWithSelected,
|
|
184
|
-
displayFormat,
|
|
185
|
-
...attrs
|
|
186
|
-
} = this.props;
|
|
187
|
-
|
|
188
|
-
const spreadProps = omit(attrs, ['onChange']);
|
|
189
|
-
const {showCalendar, tetherKey, selectedDate} = this.state;
|
|
190
|
-
const classes = classNames(
|
|
191
|
-
'DatePicker',
|
|
192
|
-
`DatePicker-${id}`,
|
|
193
|
-
{'DatePicker-disabled': disabled},
|
|
194
|
-
className
|
|
195
|
-
);
|
|
196
|
-
const containerClasses = classNames('DatePicker-input-container', {
|
|
197
|
-
'DatePicker-input-container-with-icon': useIcon,
|
|
198
|
-
});
|
|
199
|
-
const tetherClasses = classNames(
|
|
200
|
-
'DatePicker-tether',
|
|
201
|
-
{'DatePicker-tether-centered-with-shim': useTetherShim},
|
|
202
|
-
this._TETHER_CLASS
|
|
203
|
-
);
|
|
204
|
-
const inputDisplay =
|
|
205
|
-
displayFormat && selectedDate
|
|
206
|
-
? displayFormat(selectedDate)
|
|
207
|
-
: selectedDate;
|
|
208
|
-
|
|
209
|
-
/* eslint-disable react/jsx-no-bind */
|
|
210
|
-
return (
|
|
211
|
-
<div className={classes}>
|
|
212
|
-
<div className={containerClasses}>
|
|
213
|
-
{label}
|
|
214
|
-
<TetherComponent
|
|
215
|
-
key={tetherKey}
|
|
216
|
-
className={tetherClasses}
|
|
217
|
-
attachment="top left"
|
|
218
|
-
targetAttachment="bottom left"
|
|
219
|
-
constraints={[
|
|
220
|
-
{
|
|
221
|
-
to: 'window',
|
|
222
|
-
pin: true,
|
|
223
|
-
},
|
|
224
|
-
]}
|
|
225
|
-
renderTarget={ref => {
|
|
226
|
-
return (
|
|
227
|
-
<span ref={ref}>
|
|
228
|
-
<TextInput
|
|
229
|
-
ref={node => {
|
|
230
|
-
this._textInput = node;
|
|
231
|
-
}}
|
|
232
|
-
name={name}
|
|
233
|
-
disabled={disabled}
|
|
234
|
-
defaultValue={inputDisplay}
|
|
235
|
-
onFocus={this._onInputFocus}
|
|
236
|
-
icon={
|
|
237
|
-
useIcon ? (
|
|
238
|
-
<IconCalendar className="Icon-calendar" />
|
|
239
|
-
) : null
|
|
240
|
-
}
|
|
241
|
-
iconPosition={iconPosition}
|
|
242
|
-
autoFocus={autoFocus}
|
|
243
|
-
focus={focus}
|
|
244
|
-
placeholder={placeholder}
|
|
245
|
-
readOnly
|
|
246
|
-
// TODO: Figure out why `aria-label` attribute gets removed after spreading
|
|
247
|
-
{...spreadProps}
|
|
248
|
-
/>
|
|
249
|
-
</span>
|
|
250
|
-
);
|
|
251
|
-
}}
|
|
252
|
-
renderElement={ref => {
|
|
253
|
-
return (
|
|
254
|
-
showCalendar && (
|
|
255
|
-
<DatePickerCalendar
|
|
256
|
-
ref={ref}
|
|
257
|
-
className={calendarClassName}
|
|
258
|
-
onChange={this._onDateChange}
|
|
259
|
-
selectedDate={selectedDate}
|
|
260
|
-
disablePast={disablePast}
|
|
261
|
-
disableBefore={disableBefore}
|
|
262
|
-
disableAfter={disableAfter}
|
|
263
|
-
overrideInitialMonthWithSelected={
|
|
264
|
-
overrideInitialMonthWithSelected
|
|
265
|
-
}
|
|
266
|
-
/>
|
|
267
|
-
)
|
|
268
|
-
);
|
|
269
|
-
}}
|
|
270
|
-
/>
|
|
271
|
-
{useTetherShim && showCalendar && (
|
|
272
|
-
<Portal>
|
|
273
|
-
<div className="DatePicker-calendar-shim" />
|
|
274
|
-
</Portal>
|
|
275
|
-
)}
|
|
276
|
-
</div>
|
|
277
|
-
</div>
|
|
278
|
-
);
|
|
279
|
-
/* eslint-ensable react/jsx-no-bind */
|
|
280
|
-
}
|
|
281
|
-
}
|
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
import moment from 'moment';
|
|
2
|
-
import DateTimeAssertions from './date-time-assertions';
|
|
3
|
-
|
|
4
|
-
describe('<DatePicker />', () => {
|
|
5
|
-
context('Display', () => {
|
|
6
|
-
context('Default', () => {
|
|
7
|
-
const dateTodayFormatted = moment().format('MM/DD/YYYY');
|
|
8
|
-
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
cy.visitStory('v1/DatePicker/Display', 'Default', {
|
|
11
|
-
onBeforeLoad: contentWindow => {
|
|
12
|
-
contentWindow.onDatePickerChange = selectedDate => {
|
|
13
|
-
console.log('selected date:', selectedDate); // eslint-disable-line no-console
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
cy.stub(contentWindow, 'onDatePickerChange').as(
|
|
17
|
-
'onChange'
|
|
18
|
-
);
|
|
19
|
-
},
|
|
20
|
-
})
|
|
21
|
-
.get('.FormElement-item')
|
|
22
|
-
.as('asInput');
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('Renders properly', () => {
|
|
26
|
-
cy.get('.DatePicker')
|
|
27
|
-
.should('have.class', 'DatePicker')
|
|
28
|
-
.find('.Icon-calendar');
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('Shows the calendar on focus', () => {
|
|
32
|
-
cy.get('@asInput').focus().get('.DatePicker-calendar');
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it('Populates the input with the default selected date', () => {
|
|
36
|
-
cy.get('@asInput')
|
|
37
|
-
.focus()
|
|
38
|
-
.get('.DayPicker-Day--today')
|
|
39
|
-
.click()
|
|
40
|
-
.get('@asInput')
|
|
41
|
-
.should('have.value', dateTodayFormatted);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('Disables all dates in the past', () => {
|
|
45
|
-
DateTimeAssertions.pastDatesDisabled('.FormElement-item');
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it('Fires `onChange` properly', () => {
|
|
49
|
-
cy.get('@asInput')
|
|
50
|
-
.focus()
|
|
51
|
-
.get('.DayPicker-Day--today')
|
|
52
|
-
.click()
|
|
53
|
-
.get('@onChange')
|
|
54
|
-
.should('be.calledWith', dateTodayFormatted);
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
context('Classes', () => {
|
|
59
|
-
it('Has custom class names on DatePicker and DatePickerCalendar components', () => {
|
|
60
|
-
cy.visitStory('v1/DatePicker/Display', 'Classes')
|
|
61
|
-
.get('.DatePickerClasses')
|
|
62
|
-
.should('have.class', 'DatePickerClasses')
|
|
63
|
-
.should('have.class', 'DatePickerClasses2')
|
|
64
|
-
.get('.FormElement-item')
|
|
65
|
-
.focus()
|
|
66
|
-
.get('.DatePicker-calendar')
|
|
67
|
-
.should('have.class', 'custom-calendar-class');
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
context('Name', () => {
|
|
72
|
-
it('Has name property', () => {
|
|
73
|
-
cy.visitStory('v1/DatePicker/Display', 'Name')
|
|
74
|
-
.get('.FormElement-item')
|
|
75
|
-
.should('have.attr', 'name', 'date');
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
context('Selected Date', () => {
|
|
80
|
-
it('Has pre-selected date', () => {
|
|
81
|
-
cy.visitStory('v1/DatePicker/Display', 'SelectedDate')
|
|
82
|
-
.get('.FormElement-item')
|
|
83
|
-
.should('have.value', '01/01/2040');
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
context('Display Format', () => {
|
|
88
|
-
it('Formats the date displayed based on the given format method', () => {
|
|
89
|
-
cy.visitStory('v1/DatePicker/Display', 'DisplayFormat')
|
|
90
|
-
.get('.FormElement-item')
|
|
91
|
-
.should('have.value', 'Today');
|
|
92
|
-
});
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
context('Icon', () => {
|
|
96
|
-
it('Has no icon', () => {
|
|
97
|
-
cy.visitStory('v1/DatePicker/Display', 'Icon')
|
|
98
|
-
.get('.Icon-calendar')
|
|
99
|
-
.should('not.exist');
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
context('Disabled', () => {
|
|
104
|
-
it('Has a disabled form element and does not open the calendar on focus', () => {
|
|
105
|
-
cy.visitStory('v1/DatePicker/Display', 'Disabled')
|
|
106
|
-
.get('.FormElement-item')
|
|
107
|
-
.should('have.attr', 'disabled', 'disabled');
|
|
108
|
-
});
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
context('Label', () => {
|
|
112
|
-
it('Has a label', () => {
|
|
113
|
-
cy.visitStory('v1/DatePicker/Display', 'WithLabel')
|
|
114
|
-
.get('.Label')
|
|
115
|
-
.contains('Pick a date yo');
|
|
116
|
-
});
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
context('Placeholder', () => {
|
|
120
|
-
it('Has a placeholder', () => {
|
|
121
|
-
cy.visitStory('v1/DatePicker/Display', 'Placeholder')
|
|
122
|
-
.get('.FormElement-item')
|
|
123
|
-
.should('have.attr', 'placeholder', 'Select Date');
|
|
124
|
-
});
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
context('Spread Attributes', () => {
|
|
128
|
-
it('Has "required" and "type" attributes', () => {
|
|
129
|
-
cy.visitStory('v1/DatePicker/Display', 'SpreadAttributes')
|
|
130
|
-
.get('.FormElement-item')
|
|
131
|
-
.should(formEl => {
|
|
132
|
-
expect(formEl).to.have.attr('required');
|
|
133
|
-
expect(formEl).to.have.attr('type', 'tel');
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
});
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
context('Interaction', () => {
|
|
140
|
-
context('Auto Focus', () => {
|
|
141
|
-
it('Automatically focuses the input field displaying the calendar', () => {
|
|
142
|
-
cy.visitStory('v1/DatePicker/Interaction', 'AutoFocus').get(
|
|
143
|
-
'.DatePicker-calendar'
|
|
144
|
-
);
|
|
145
|
-
});
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
context('Focus', () => {
|
|
149
|
-
it('Applies autoFocus and focus settings properly', () => {
|
|
150
|
-
cy.visitStory('v1/DatePicker/Interaction', 'Focus')
|
|
151
|
-
.get('.add-focus')
|
|
152
|
-
.click()
|
|
153
|
-
.focused()
|
|
154
|
-
.should('have.class', 'FormElement-item');
|
|
155
|
-
});
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
context('Enable/Disable Dates', () => {
|
|
159
|
-
it('Enables dates in the past when disablePast is false', () => {
|
|
160
|
-
cy.visitStory('v1/DatePicker/Interaction', 'EnablePastDates');
|
|
161
|
-
|
|
162
|
-
DateTimeAssertions.pastDatesEnabled('.FormElement-item');
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
it('Disables dates before disableBefore and after disableAfter', () => {
|
|
166
|
-
cy.visitStory(
|
|
167
|
-
'v1/DatePicker/Interaction',
|
|
168
|
-
'DisableDatesBeforeAfter'
|
|
169
|
-
);
|
|
170
|
-
|
|
171
|
-
DateTimeAssertions.datesDisabledBeforeAndAfter(
|
|
172
|
-
'.FormElement-item'
|
|
173
|
-
);
|
|
174
|
-
});
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
context('Shim', () => {
|
|
178
|
-
it('Has a calendar in the center of the page with a shim behind it', () => {
|
|
179
|
-
cy.visitStory('v1/DatePicker/Interaction', 'Shim')
|
|
180
|
-
.get('.FormElement-item')
|
|
181
|
-
.focus()
|
|
182
|
-
.get('.DatePicker-tether-centered-with-shim');
|
|
183
|
-
});
|
|
184
|
-
});
|
|
185
|
-
});
|
|
186
|
-
});
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
import isEmpty from 'lodash/isEmpty';
|
|
2
|
-
import React, {Component} from 'react';
|
|
3
|
-
import PropTypes from 'prop-types';
|
|
4
|
-
import classNames from 'classnames';
|
|
5
|
-
import moment from 'moment';
|
|
6
|
-
import DayPicker, {DateUtils as DayPickerDateUtils} from 'react-day-picker';
|
|
7
|
-
import DateUtils from '@spothero/utils/date';
|
|
8
|
-
import DatePickerCalendarNavigation from './DatePickerCalendarNavigation';
|
|
9
|
-
|
|
10
|
-
const DATE = new Date();
|
|
11
|
-
|
|
12
|
-
export default class DatePickerCalendar extends Component {
|
|
13
|
-
static propTypes = {
|
|
14
|
-
/** Additional class(es) to add to the component. */
|
|
15
|
-
className: PropTypes.string,
|
|
16
|
-
/**
|
|
17
|
-
* Function to execute when the selected date changes.
|
|
18
|
-
*
|
|
19
|
-
* @param {String} selectedDate - The selected date in the format 'MM/DD/YYYY'.
|
|
20
|
-
*/
|
|
21
|
-
onChange: PropTypes.func,
|
|
22
|
-
/** A string in the format 'MM/DD/YYYY' representing the date which should be selected on the calendar. */
|
|
23
|
-
selectedDate: PropTypes.string,
|
|
24
|
-
/** A date object representing the initial month to show on the calendar. */
|
|
25
|
-
initialMonth: PropTypes.instanceOf(Date),
|
|
26
|
-
/** Whether to disable the days on the calendar that are in the past. */
|
|
27
|
-
disablePast: PropTypes.bool,
|
|
28
|
-
/** A string in the format 'MM/DD/YYYY' representing the date where any day prior is disabled. */
|
|
29
|
-
disableBefore: PropTypes.string,
|
|
30
|
-
/** A string in the format 'MM/DD/YYYY' representing the date where any day past is disabled. */
|
|
31
|
-
disableAfter: PropTypes.string,
|
|
32
|
-
/** Whether to set the initial month to show in the calendar to the same month as the selected day falls within when a selectedDate is passed. */
|
|
33
|
-
overrideInitialMonthWithSelected: PropTypes.bool,
|
|
34
|
-
};
|
|
35
|
-
static defaultProps = {
|
|
36
|
-
selectedDate: '',
|
|
37
|
-
initialMonth: DATE,
|
|
38
|
-
disablePast: true,
|
|
39
|
-
overrideInitialMonthWithSelected: true,
|
|
40
|
-
};
|
|
41
|
-
state = {
|
|
42
|
-
selectedDate: this.props.selectedDate,
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
constructor(props) {
|
|
46
|
-
super(props);
|
|
47
|
-
|
|
48
|
-
this._weekdayTitles = ['S', 'M', 'T', 'W', 'T', 'F', 'S'];
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
_onDaySelected = (day, {selected, disabled}, evt) => {
|
|
52
|
-
if (disabled) {
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const {onChange} = this.props;
|
|
57
|
-
const selectedDate = moment(day).format('MM/DD/YYYY');
|
|
58
|
-
|
|
59
|
-
this.setState({
|
|
60
|
-
selectedDate,
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
if (onChange) {
|
|
64
|
-
onChange(selectedDate);
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
_modifierSelected = day => {
|
|
69
|
-
const {selectedDate} = this.state;
|
|
70
|
-
|
|
71
|
-
if (!isEmpty(selectedDate)) {
|
|
72
|
-
return DayPickerDateUtils.isSameDay(
|
|
73
|
-
DateUtils.getAsDate(selectedDate),
|
|
74
|
-
day
|
|
75
|
-
);
|
|
76
|
-
} else {
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
_modifierDisabled = day => {
|
|
82
|
-
const {disablePast, disableBefore, disableAfter} = this.props;
|
|
83
|
-
let isDayDisabled = false;
|
|
84
|
-
let disableDay = false;
|
|
85
|
-
|
|
86
|
-
if (disableBefore) {
|
|
87
|
-
disableDay = DateUtils.isBefore(
|
|
88
|
-
day,
|
|
89
|
-
DateUtils.getAsDate(disableBefore)
|
|
90
|
-
);
|
|
91
|
-
isDayDisabled = disableDay;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (disableAfter && !isDayDisabled) {
|
|
95
|
-
disableDay = DateUtils.isAfter(
|
|
96
|
-
day,
|
|
97
|
-
DateUtils.getAsDate(disableAfter)
|
|
98
|
-
);
|
|
99
|
-
isDayDisabled = disableDay;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
if (disablePast && !isDayDisabled) {
|
|
103
|
-
disableDay = DayPickerDateUtils.isPastDay(day);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return disableDay;
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
_renderDayMarkup = day => {
|
|
110
|
-
const m = moment(day);
|
|
111
|
-
const date = `${m.format('MM')}/${m.format('DD')}/${m.format('YYYY')}`;
|
|
112
|
-
|
|
113
|
-
return <span data-date={date}>{day.getDate()}</span>;
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
render() {
|
|
117
|
-
const {
|
|
118
|
-
className,
|
|
119
|
-
initialMonth,
|
|
120
|
-
disablePast,
|
|
121
|
-
disableBefore,
|
|
122
|
-
disableAfter,
|
|
123
|
-
overrideInitialMonthWithSelected,
|
|
124
|
-
} = this.props;
|
|
125
|
-
const {selectedDate} = this.state;
|
|
126
|
-
const classes = classNames('DatePicker-calendar', className);
|
|
127
|
-
let firstMonth = initialMonth;
|
|
128
|
-
let fromMonth = disablePast ? DATE : null;
|
|
129
|
-
let toMonth = null;
|
|
130
|
-
|
|
131
|
-
if (disableBefore) {
|
|
132
|
-
const beforeDate = DateUtils.getAsDate(disableBefore);
|
|
133
|
-
|
|
134
|
-
if (fromMonth) {
|
|
135
|
-
if (DateUtils.isAfter(beforeDate, fromMonth)) {
|
|
136
|
-
fromMonth = beforeDate;
|
|
137
|
-
}
|
|
138
|
-
} else {
|
|
139
|
-
fromMonth = beforeDate;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
firstMonth = fromMonth;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
if (disableAfter) {
|
|
146
|
-
toMonth = DateUtils.getAsDate(disableAfter);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if (selectedDate && overrideInitialMonthWithSelected) {
|
|
150
|
-
firstMonth = DateUtils.getAsDate(selectedDate);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
return (
|
|
154
|
-
<div className={classes}>
|
|
155
|
-
<DayPicker
|
|
156
|
-
selectedDays={this._modifierSelected}
|
|
157
|
-
disabledDays={this._modifierDisabled}
|
|
158
|
-
onDayClick={this._onDaySelected}
|
|
159
|
-
fromMonth={fromMonth}
|
|
160
|
-
toMonth={toMonth}
|
|
161
|
-
initialMonth={firstMonth}
|
|
162
|
-
renderDay={this._renderDayMarkup}
|
|
163
|
-
weekdaysShort={this._weekdayTitles}
|
|
164
|
-
navbarElement={<DatePickerCalendarNavigation />}
|
|
165
|
-
showOutsideDays
|
|
166
|
-
/>
|
|
167
|
-
</div>
|
|
168
|
-
);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import React, {Component} from 'react';
|
|
2
|
-
import classNames from 'classnames';
|
|
3
|
-
import {NavbarPropTypes} from 'react-day-picker';
|
|
4
|
-
import IconChevronLeft from '@spothero/icons/chevron-left';
|
|
5
|
-
import IconChevronRight from '@spothero/icons/chevron-right';
|
|
6
|
-
import Button from 'v1/components/Button/Button';
|
|
7
|
-
|
|
8
|
-
export default class DatePickerCalendarNavigation extends Component {
|
|
9
|
-
static propTypes = NavbarPropTypes;
|
|
10
|
-
|
|
11
|
-
_onPreviousClick = () => {
|
|
12
|
-
this.props.onPreviousClick();
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
_onNextClick = () => {
|
|
16
|
-
this.props.onNextClick();
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
render() {
|
|
20
|
-
const {className, showPreviousButton, showNextButton} = this.props;
|
|
21
|
-
const classes = classNames('DatePickerCalendarNavigation', className);
|
|
22
|
-
|
|
23
|
-
return (
|
|
24
|
-
<div className={classes}>
|
|
25
|
-
{showPreviousButton && (
|
|
26
|
-
<Button
|
|
27
|
-
className="DayPicker-NavButton DayPicker-NavButton--prev"
|
|
28
|
-
onClick={this._onPreviousClick}
|
|
29
|
-
>
|
|
30
|
-
<IconChevronLeft />
|
|
31
|
-
</Button>
|
|
32
|
-
)}
|
|
33
|
-
{showNextButton && (
|
|
34
|
-
<Button
|
|
35
|
-
className="DayPicker-NavButton DayPicker-NavButton--next"
|
|
36
|
-
onClick={this._onNextClick}
|
|
37
|
-
>
|
|
38
|
-
<IconChevronRight />
|
|
39
|
-
</Button>
|
|
40
|
-
)}
|
|
41
|
-
</div>
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
}
|