@spothero/ui 15.1.0 → 15.1.2
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/CHANGELOG.md +0 -18
- package/package.json +2 -3
- package/styles/v2/components/Modal/styles/dialogContainer.js +0 -1
- package/styles/v2/components/Radio/Radio.jsx +1 -1
- package/styles/v2/components/Radio/RadioGroup.jsx +1 -1
- package/v2/index.js +1 -1
- package/v2/index.js.map +1 -1
- 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,148 +0,0 @@
|
|
|
1
|
-
import DateTimeAssertions from './date-time-assertions';
|
|
2
|
-
|
|
3
|
-
describe('<TimePicker />', () => {
|
|
4
|
-
context('Display', () => {
|
|
5
|
-
context('Default', () => {
|
|
6
|
-
beforeEach(() => {
|
|
7
|
-
cy.visitStory('v1/TimePicker/Display', 'Default', {
|
|
8
|
-
onBeforeLoad: contentWindow => {
|
|
9
|
-
contentWindow.onTimePickerChange = selectedTime => {
|
|
10
|
-
console.log('selected time:', selectedTime); // eslint-disable-line no-console
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
cy.stub(contentWindow, 'onTimePickerChange').as(
|
|
14
|
-
'onChange'
|
|
15
|
-
);
|
|
16
|
-
},
|
|
17
|
-
})
|
|
18
|
-
.get('.Select')
|
|
19
|
-
.as('asSelect');
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it('Renders properly', () => {
|
|
23
|
-
cy.get('.TimePicker')
|
|
24
|
-
.should('have.class', 'TimePicker')
|
|
25
|
-
.find('.Icon-clock')
|
|
26
|
-
.get('select')
|
|
27
|
-
.children()
|
|
28
|
-
.should('have.length', 48);
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('Populates the input with the default selected time', () => {
|
|
32
|
-
cy.get('@asSelect')
|
|
33
|
-
.find('.FormElement-item')
|
|
34
|
-
.should('have.value', '12:00 AM');
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('Fires `onChange` properly', () => {
|
|
38
|
-
cy.selectItem({alias: 'asSelect', value: '03:00 AM'})
|
|
39
|
-
.get('@onChange')
|
|
40
|
-
.should('be.calledWith', '03:00 AM');
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
context('Classes', () => {
|
|
45
|
-
it('Has custom class names', () => {
|
|
46
|
-
cy.visitStory('v1/TimePicker/Display', 'Classes')
|
|
47
|
-
.get('.TimePickerClasses')
|
|
48
|
-
.should('have.class', 'TimePickerClasses')
|
|
49
|
-
.should('have.class', 'TimePickerClasses2');
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
context('Name', () => {
|
|
54
|
-
it('Has name property', () => {
|
|
55
|
-
cy.visitStory('v1/TimePicker/Display', 'Name')
|
|
56
|
-
.get('.FormElement-item')
|
|
57
|
-
.should('have.attr', 'name', 'time');
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
context('Selected Time', () => {
|
|
62
|
-
it('Has pre-selected time', () => {
|
|
63
|
-
cy.visitStory('v1/TimePicker/Display', 'SelectedTime')
|
|
64
|
-
.get('.FormElement-item')
|
|
65
|
-
.should('have.value', '11:30 AM');
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
context('Display Format', () => {
|
|
70
|
-
it('Has proper display formatting applied while retaining the proper value', () => {
|
|
71
|
-
cy.visitStory('v1/TimePicker/Display', 'DisplayFormat')
|
|
72
|
-
.get('.FormElement-item')
|
|
73
|
-
.should('have.value', '07:30 AM')
|
|
74
|
-
.select('08:30 AM')
|
|
75
|
-
.find(':selected')
|
|
76
|
-
.contains('8:30 AM');
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
context('Icon', () => {
|
|
81
|
-
it('Has no icon', () => {
|
|
82
|
-
cy.visitStory('v1/TimePicker/Display', 'Icon')
|
|
83
|
-
.get('.Icon-calendar')
|
|
84
|
-
.should('not.exist');
|
|
85
|
-
});
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
context('Disabled', () => {
|
|
89
|
-
it('Has a disabled form element and does not call the onFocus callback on focus', () => {
|
|
90
|
-
cy.visitStory('v1/TimePicker/Display', 'Disabled')
|
|
91
|
-
.get('.FormElement-item')
|
|
92
|
-
.should('have.attr', 'disabled', 'disabled');
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
context('Label', () => {
|
|
97
|
-
it('Has a label', () => {
|
|
98
|
-
cy.visitStory('v1/TimePicker/Display', 'WithLabel')
|
|
99
|
-
.get('.Label')
|
|
100
|
-
.contains('Pick a time yo');
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
context('Placeholder', () => {
|
|
105
|
-
it('Has a placeholder first option with empty value', () => {
|
|
106
|
-
cy.visitStory('v1/TimePicker/Display', 'Placeholder')
|
|
107
|
-
.get('option')
|
|
108
|
-
.first()
|
|
109
|
-
.should('have.attr', 'value', '')
|
|
110
|
-
.contains('Select Time');
|
|
111
|
-
});
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
context('Spread Attributes', () => {
|
|
115
|
-
it('Has "required" and "type" attributes', () => {
|
|
116
|
-
cy.visitStory('v1/TimePicker/Display', 'SpreadAttributes')
|
|
117
|
-
.get('.FormElement-item')
|
|
118
|
-
.should(formEl => {
|
|
119
|
-
expect(formEl).to.have.attr('required');
|
|
120
|
-
expect(formEl).to.have.attr('type', 'tel');
|
|
121
|
-
expect(formEl).not.to.have.attr('displayformat');
|
|
122
|
-
});
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
context('Interaction', () => {
|
|
128
|
-
context('Step', () => {
|
|
129
|
-
it('Time options in dropdown reflect the step value multiplier', () => {
|
|
130
|
-
cy.visitStory('v1/TimePicker/Interaction', 'Step')
|
|
131
|
-
.get('select')
|
|
132
|
-
.children()
|
|
133
|
-
.should('have.length', 24);
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
context('Disable Times', () => {
|
|
138
|
-
it('Disables times before disableBefore and after disableAfter', () => {
|
|
139
|
-
cy.visitStory(
|
|
140
|
-
'v1/TimePicker/Interaction',
|
|
141
|
-
'DisableTimesBeforeAfter'
|
|
142
|
-
);
|
|
143
|
-
|
|
144
|
-
DateTimeAssertions.timesDisabledBeforeAndAfter('select', false);
|
|
145
|
-
});
|
|
146
|
-
});
|
|
147
|
-
});
|
|
148
|
-
});
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
const DateTimeAssertions = {
|
|
2
|
-
pastDatesDisabled(inputSelector) {
|
|
3
|
-
cy.get(inputSelector)
|
|
4
|
-
.focus()
|
|
5
|
-
.get('.DayPicker-Day--today')
|
|
6
|
-
.then($todayElement => {
|
|
7
|
-
if ($todayElement.prev().length) {
|
|
8
|
-
return $todayElement.prev();
|
|
9
|
-
} else {
|
|
10
|
-
return $todayElement.parent().prev().children().last();
|
|
11
|
-
}
|
|
12
|
-
})
|
|
13
|
-
.then($prevDay => {
|
|
14
|
-
cy.wrap($prevDay).should(
|
|
15
|
-
'have.class',
|
|
16
|
-
'DayPicker-Day--disabled'
|
|
17
|
-
);
|
|
18
|
-
});
|
|
19
|
-
},
|
|
20
|
-
|
|
21
|
-
pastDatesEnabled(inputSelector) {
|
|
22
|
-
cy.get(inputSelector)
|
|
23
|
-
.focus()
|
|
24
|
-
.get('.DayPicker-Day--today')
|
|
25
|
-
.then($todayElement => {
|
|
26
|
-
if ($todayElement.prev().length) {
|
|
27
|
-
return $todayElement.prev();
|
|
28
|
-
} else {
|
|
29
|
-
return $todayElement.parent().prev().children().last();
|
|
30
|
-
}
|
|
31
|
-
})
|
|
32
|
-
.then($prevDay => {
|
|
33
|
-
cy.wrap($prevDay).should(
|
|
34
|
-
'not.have.class',
|
|
35
|
-
'DayPicker-Day--disabled'
|
|
36
|
-
);
|
|
37
|
-
});
|
|
38
|
-
},
|
|
39
|
-
|
|
40
|
-
datesDisabledBeforeAndAfter(inputSelector) {
|
|
41
|
-
cy.get(inputSelector)
|
|
42
|
-
.focus()
|
|
43
|
-
.get('.DayPicker-Day--today')
|
|
44
|
-
.then($todayElement => {
|
|
45
|
-
// if previous child element exists return it
|
|
46
|
-
// if not, return the last child element from the previous calendar row
|
|
47
|
-
if ($todayElement.prev().length) {
|
|
48
|
-
return $todayElement.prev();
|
|
49
|
-
} else {
|
|
50
|
-
return $todayElement.parent().prev().children().last();
|
|
51
|
-
}
|
|
52
|
-
})
|
|
53
|
-
.then($prevDay => {
|
|
54
|
-
cy.wrap($prevDay).should(
|
|
55
|
-
'have.class',
|
|
56
|
-
'DayPicker-Day--disabled'
|
|
57
|
-
);
|
|
58
|
-
})
|
|
59
|
-
.get('.DayPicker-Day--today')
|
|
60
|
-
.then($todayElement => {
|
|
61
|
-
// if next child element exists return it
|
|
62
|
-
// if not, return the first child element from the next calendar row
|
|
63
|
-
if ($todayElement.next().length) {
|
|
64
|
-
return $todayElement.next();
|
|
65
|
-
} else {
|
|
66
|
-
return $todayElement.parent().next().children().first();
|
|
67
|
-
}
|
|
68
|
-
})
|
|
69
|
-
.then($nextDay => {
|
|
70
|
-
cy.wrap($nextDay)
|
|
71
|
-
.should('have.class', 'DayPicker-Day--disabled')
|
|
72
|
-
.get('.DayPicker-Day--today')
|
|
73
|
-
.click();
|
|
74
|
-
});
|
|
75
|
-
},
|
|
76
|
-
|
|
77
|
-
timesDisabledBeforeAndAfter(inputSelector, hasPlaceholder = true) {
|
|
78
|
-
cy.get(inputSelector)
|
|
79
|
-
.find('option')
|
|
80
|
-
.eq(hasPlaceholder ? 1 : 0)
|
|
81
|
-
.should('have.attr', 'value', '11:00 AM')
|
|
82
|
-
.get(inputSelector)
|
|
83
|
-
.find('option')
|
|
84
|
-
.last()
|
|
85
|
-
.should('have.attr', 'value', '01:00 PM');
|
|
86
|
-
},
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
export default DateTimeAssertions;
|
package/styles/DateTime/index.js
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export {default as DatePicker} from './DatePicker';
|
|
2
|
-
export {default as TimePicker} from './TimePicker';
|
|
3
|
-
export {default as DateTimePicker} from './DateTimePicker';
|
|
4
|
-
export {default as DatePickerCalendar} from './DatePickerCalendar';
|
|
5
|
-
export {default as DateTimeRangePicker} from './DateTimeRangePicker';
|
|
6
|
-
export {default as DatePickerCalendarWithRange} from './DatePickerCalendarWithRange';
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import PropTypes from 'prop-types';
|
|
2
|
-
import classNames from 'classnames';
|
|
3
|
-
import React, {Component} from 'react';
|
|
4
|
-
import SentryUtils from '@spothero/utils/sentry';
|
|
5
|
-
|
|
6
|
-
export default class ErrorBoundary extends Component {
|
|
7
|
-
static propTypes = {
|
|
8
|
-
/** Additional class(es) to add to the component -- only shows on error catch. */
|
|
9
|
-
className: PropTypes.string,
|
|
10
|
-
/** The node to display when the component does not have any errors. */
|
|
11
|
-
children: PropTypes.node.isRequired,
|
|
12
|
-
/** A custom node to display in place of the default error messaging. */
|
|
13
|
-
errorComponent: PropTypes.element,
|
|
14
|
-
/** Whether or not to report error to Sentry. */
|
|
15
|
-
reportToSentry: PropTypes.bool,
|
|
16
|
-
/**
|
|
17
|
-
* Function to execute when the an error is caught.
|
|
18
|
-
*
|
|
19
|
-
* @param {Object} error - The error object.
|
|
20
|
-
* @param {Object} info - Extra info provided by React.
|
|
21
|
-
*/
|
|
22
|
-
onError: PropTypes.func,
|
|
23
|
-
};
|
|
24
|
-
static defaultProps = {
|
|
25
|
-
reportToSentry: true,
|
|
26
|
-
};
|
|
27
|
-
state = {
|
|
28
|
-
error: null,
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
componentDidCatch(error, info) {
|
|
32
|
-
const {reportToSentry, onError} = this.props;
|
|
33
|
-
|
|
34
|
-
this.setState({
|
|
35
|
-
error,
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
if (onError) {
|
|
39
|
-
onError(error, info);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (reportToSentry) {
|
|
43
|
-
SentryUtils.addData(info);
|
|
44
|
-
SentryUtils.sendMessage({
|
|
45
|
-
message: error.message,
|
|
46
|
-
level: 'error',
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
render() {
|
|
52
|
-
const {children, className, errorComponent} = this.props;
|
|
53
|
-
const {error} = this.state;
|
|
54
|
-
const classes = classNames('ErrorBoundary', className);
|
|
55
|
-
|
|
56
|
-
if (error) {
|
|
57
|
-
return (
|
|
58
|
-
<div className={classes}>
|
|
59
|
-
{errorComponent}
|
|
60
|
-
{!errorComponent && (
|
|
61
|
-
<div className="ErrorBoundary-content">
|
|
62
|
-
<div className="ErrorBoundary-info">
|
|
63
|
-
An error has occurred.
|
|
64
|
-
</div>
|
|
65
|
-
<div className="ErrorBoundary-info">
|
|
66
|
-
Please refresh the page and try again.
|
|
67
|
-
</div>
|
|
68
|
-
</div>
|
|
69
|
-
)}
|
|
70
|
-
</div>
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return children;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
describe('<ErrorBoundary />', () => {
|
|
2
|
-
beforeEach(() => {
|
|
3
|
-
cy.on('uncaught:exception', () => {
|
|
4
|
-
return false;
|
|
5
|
-
});
|
|
6
|
-
});
|
|
7
|
-
|
|
8
|
-
context('Display', () => {
|
|
9
|
-
context('Default', () => {
|
|
10
|
-
it('Handles JS Error with default error messaging', () => {
|
|
11
|
-
cy.visitStory('v1/ErrorBoundary/Display', 'Default')
|
|
12
|
-
.get('.Button')
|
|
13
|
-
.click()
|
|
14
|
-
.get('.ErrorBoundary-info')
|
|
15
|
-
.eq(0)
|
|
16
|
-
.should('contain.text', 'An error has occurred.')
|
|
17
|
-
.get('.ErrorBoundary-info')
|
|
18
|
-
.eq(1)
|
|
19
|
-
.should(
|
|
20
|
-
'contain.text',
|
|
21
|
-
'Please refresh the page and try again.'
|
|
22
|
-
);
|
|
23
|
-
});
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
context('Custom Error Component', () => {
|
|
27
|
-
it('Handles JS Error with custom error messaging', () => {
|
|
28
|
-
cy.visitStory('v1/ErrorBoundary/Display', 'CustomError')
|
|
29
|
-
.get('.Button')
|
|
30
|
-
.click()
|
|
31
|
-
.get('.ErrorBoundary')
|
|
32
|
-
.should('contain.text', 'Something went wrong!');
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
context('Methods', () => {
|
|
38
|
-
context('onError', () => {
|
|
39
|
-
it('Calls onError upon catching error', () => {
|
|
40
|
-
cy.visitStory('v1/ErrorBoundary/Methods', 'OnError', {
|
|
41
|
-
onBeforeLoad: contentWindow => {
|
|
42
|
-
contentWindow.onError = evt => {
|
|
43
|
-
console.log('onError'); // eslint-disable-line no-console
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
cy.stub(contentWindow, 'onError').as('onError');
|
|
47
|
-
},
|
|
48
|
-
})
|
|
49
|
-
.get('.Button')
|
|
50
|
-
.click()
|
|
51
|
-
.get('@onError')
|
|
52
|
-
.should(
|
|
53
|
-
'be.calledWithMatch',
|
|
54
|
-
error => {
|
|
55
|
-
return (
|
|
56
|
-
error.message &&
|
|
57
|
-
error.message.includes(
|
|
58
|
-
'I crashed the component!'
|
|
59
|
-
)
|
|
60
|
-
);
|
|
61
|
-
},
|
|
62
|
-
info => {
|
|
63
|
-
return (
|
|
64
|
-
info.componentStack &&
|
|
65
|
-
info.componentStack.includes('ErrorBoundary')
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
);
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
|
-
});
|
package/styles/Flyout/Flyout.jsx
DELETED
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
import isString from 'lodash/isString';
|
|
2
|
-
import React, {Component} from 'react';
|
|
3
|
-
import PropTypes from 'prop-types';
|
|
4
|
-
import classNames from 'classnames';
|
|
5
|
-
import IconTimes from '@spothero/icons/times';
|
|
6
|
-
import DOMUtils from '@spothero/utils/dom';
|
|
7
|
-
import Button from 'v1/components/Button/Button';
|
|
8
|
-
import Portal from '../Portal/Portal';
|
|
9
|
-
|
|
10
|
-
export default class Flyout extends Component {
|
|
11
|
-
static propTypes = {
|
|
12
|
-
/** Additional class(es) to add to the component. */
|
|
13
|
-
className: PropTypes.string,
|
|
14
|
-
/** The content to insert into the flyout. */
|
|
15
|
-
children: PropTypes.node.isRequired,
|
|
16
|
-
/** The title to include at the top of the flyout. */
|
|
17
|
-
title: PropTypes.node.isRequired,
|
|
18
|
-
/**
|
|
19
|
-
* A function to execute after the flyout has been hidden. Use this to manage state in a parent component to remove the flyout from the DOM (see examples).
|
|
20
|
-
*
|
|
21
|
-
* @param {*} args - Any arguments that were passed to `hide()` to retrieve in the callback.
|
|
22
|
-
*/
|
|
23
|
-
onHidden: PropTypes.func,
|
|
24
|
-
/** Whether to close the Flyout when the shim is clicked. */
|
|
25
|
-
closeOnShimClick: PropTypes.bool,
|
|
26
|
-
/** Whether to allow the background to scroll or not. **/
|
|
27
|
-
isBackgroundScrollable: PropTypes.bool,
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
static defaultProps = {
|
|
31
|
-
closeOnShimClick: true,
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
componentDidMount() {
|
|
35
|
-
const {isBackgroundScrollable} = this.props;
|
|
36
|
-
|
|
37
|
-
setTimeout(() => {
|
|
38
|
-
this._isAnimating = true;
|
|
39
|
-
|
|
40
|
-
if (!isBackgroundScrollable) {
|
|
41
|
-
DOMUtils.addClass('html', 'Flyout-no-scroll');
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
DOMUtils.addClass(this._flyout, 'Flyout-active');
|
|
45
|
-
|
|
46
|
-
window.transitionEnd(this._flyout).bind(() => {
|
|
47
|
-
window.transitionEnd(this._flyout).unbind();
|
|
48
|
-
|
|
49
|
-
this._isAnimating = false;
|
|
50
|
-
});
|
|
51
|
-
}, 100);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
componentWillUnmount() {
|
|
55
|
-
this._removeClasses();
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
_onCloseClick = evt => {
|
|
59
|
-
if (this._isAnimating) {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
this.hide();
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
_removeClasses() {
|
|
67
|
-
DOMUtils.removeClass('html', 'Flyout-open Flyout-no-scroll');
|
|
68
|
-
DOMUtils.removeClass(this._flyout, 'Flyout-active');
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Hides the Flyout programmatically.
|
|
73
|
-
*
|
|
74
|
-
* @public
|
|
75
|
-
* @param {*} args - The arguments to pass to the onHidden callback in cases where you may need access to something not available in Flyout itself.
|
|
76
|
-
* @returns {void}
|
|
77
|
-
*/
|
|
78
|
-
hide(...args) {
|
|
79
|
-
this._isAnimating = true;
|
|
80
|
-
|
|
81
|
-
const {onHidden} = this.props;
|
|
82
|
-
|
|
83
|
-
this._removeClasses();
|
|
84
|
-
|
|
85
|
-
window.transitionEnd(this._flyout).bind(() => {
|
|
86
|
-
window.transitionEnd(this._flyout).unbind();
|
|
87
|
-
|
|
88
|
-
this._isAnimating = false;
|
|
89
|
-
|
|
90
|
-
if (onHidden) {
|
|
91
|
-
onHidden(...args);
|
|
92
|
-
}
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
render() {
|
|
97
|
-
const {
|
|
98
|
-
title,
|
|
99
|
-
children,
|
|
100
|
-
// eslint-disable-next-line no-unused-vars
|
|
101
|
-
onHidden,
|
|
102
|
-
className,
|
|
103
|
-
closeOnShimClick,
|
|
104
|
-
// eslint-disable-next-line no-unused-vars
|
|
105
|
-
isBackgroundScrollable,
|
|
106
|
-
...props
|
|
107
|
-
} = this.props;
|
|
108
|
-
|
|
109
|
-
const classes = classNames('Flyout-container', className);
|
|
110
|
-
|
|
111
|
-
return (
|
|
112
|
-
<Portal className="Flyout">
|
|
113
|
-
<div className={classes}>
|
|
114
|
-
{closeOnShimClick && (
|
|
115
|
-
<div
|
|
116
|
-
className="Flyout-shim"
|
|
117
|
-
onClick={this._onCloseClick}
|
|
118
|
-
/>
|
|
119
|
-
)}
|
|
120
|
-
<div
|
|
121
|
-
ref={node => {
|
|
122
|
-
this._flyout = node;
|
|
123
|
-
}}
|
|
124
|
-
className="Flyout-wrapper"
|
|
125
|
-
{...props}
|
|
126
|
-
>
|
|
127
|
-
<div className="Flyout-heading">
|
|
128
|
-
{isString(title) ? (
|
|
129
|
-
<h1 className="heading-sm">{title}</h1>
|
|
130
|
-
) : (
|
|
131
|
-
title
|
|
132
|
-
)}
|
|
133
|
-
<Button
|
|
134
|
-
className="Flyout-close"
|
|
135
|
-
aria-label="Close Flyout"
|
|
136
|
-
onClick={this._onCloseClick}
|
|
137
|
-
>
|
|
138
|
-
<IconTimes />
|
|
139
|
-
</Button>
|
|
140
|
-
</div>
|
|
141
|
-
<div className="Flyout-content">{children}</div>
|
|
142
|
-
</div>
|
|
143
|
-
</div>
|
|
144
|
-
</Portal>
|
|
145
|
-
);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
const animationTimeout = 300;
|
|
2
|
-
|
|
3
|
-
describe('<Flyout />', () => {
|
|
4
|
-
context('Display', () => {
|
|
5
|
-
context('Default', () => {
|
|
6
|
-
beforeEach(() => {
|
|
7
|
-
cy.visitStory('v1/Flyout/Display', 'Default')
|
|
8
|
-
.get('.Button')
|
|
9
|
-
.click()
|
|
10
|
-
.wait(animationTimeout);
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
it('Renders properly', () => {
|
|
14
|
-
cy.get('.Flyout')
|
|
15
|
-
// check to make sure the parent is the body
|
|
16
|
-
.parent()
|
|
17
|
-
.then($el => {
|
|
18
|
-
expect($el.prop('tagName').toLowerCase()).to.eq('body');
|
|
19
|
-
})
|
|
20
|
-
.get('.Flyout-wrapper')
|
|
21
|
-
.should('have.class', 'Flyout-active')
|
|
22
|
-
.contains('This is the flyout content.')
|
|
23
|
-
// confirm other default elements exist
|
|
24
|
-
.get('.Flyout-shim')
|
|
25
|
-
.get('.Flyout-heading')
|
|
26
|
-
.get('.Flyout-content')
|
|
27
|
-
.get('.Flyout-close')
|
|
28
|
-
.get('html')
|
|
29
|
-
.should('have.class', 'Flyout-no-scroll');
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('Closes when close is clicked', () => {
|
|
33
|
-
cy.get('.Flyout-close')
|
|
34
|
-
.click()
|
|
35
|
-
.wait(animationTimeout)
|
|
36
|
-
.get('.Flyout')
|
|
37
|
-
.should('not.exist');
|
|
38
|
-
});
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
context('Custom Title', () => {
|
|
42
|
-
it('Renders properly', () => {
|
|
43
|
-
cy.visitStory('v1/Flyout/Display', 'CustomTitle')
|
|
44
|
-
.get('.Button')
|
|
45
|
-
.click()
|
|
46
|
-
.wait(animationTimeout)
|
|
47
|
-
// check for custom title
|
|
48
|
-
.get('.FlyoutTitle')
|
|
49
|
-
.contains('Custom Flyout Title')
|
|
50
|
-
// confirm close still exists
|
|
51
|
-
.get('.Flyout-close');
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
context('Close on shim click prop', () => {
|
|
56
|
-
it('Does not render shim that controls background closing click when prop is false', () => {
|
|
57
|
-
cy.visitStory('v1/Flyout/Display', 'CloseOnShimClickFalse')
|
|
58
|
-
.get('.Button')
|
|
59
|
-
.click()
|
|
60
|
-
.wait(animationTimeout)
|
|
61
|
-
.get('.Flyout-shim')
|
|
62
|
-
.should('not.exist');
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('Closes when shim is clicked with default prop value', () => {
|
|
66
|
-
cy.visitStory('v1/Flyout/Display', 'Default')
|
|
67
|
-
.get('.Button')
|
|
68
|
-
.click()
|
|
69
|
-
.wait(animationTimeout)
|
|
70
|
-
.get('.Flyout-shim')
|
|
71
|
-
.click()
|
|
72
|
-
.wait(animationTimeout)
|
|
73
|
-
.get('.Flyout')
|
|
74
|
-
.should('not.exist');
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
context('Background scrollable', () => {
|
|
79
|
-
it('Default isBackgroundScrollable false does not have scrollable background', () => {
|
|
80
|
-
cy.visitStory('v1/Flyout/Display', 'Default')
|
|
81
|
-
.get('.Button')
|
|
82
|
-
.click()
|
|
83
|
-
.wait(animationTimeout)
|
|
84
|
-
.get('html')
|
|
85
|
-
.should('have.class', 'Flyout-no-scroll');
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
it('Setting isBackgroundScrollable to true will allow the background to scroll', () => {
|
|
89
|
-
cy.visitStory('v1/Flyout/Display', 'BackgroundScrollable')
|
|
90
|
-
.get('.Button')
|
|
91
|
-
.click()
|
|
92
|
-
.wait(animationTimeout + 100)
|
|
93
|
-
.window()
|
|
94
|
-
.scrollTo(0, 500)
|
|
95
|
-
.then(win => {
|
|
96
|
-
expect(win.scrollY).to.be.greaterThan(499);
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
context('Methods', () => {
|
|
103
|
-
context('Hide', () => {
|
|
104
|
-
it('Calling hide() will hide the flyout', () => {
|
|
105
|
-
cy.visitStory('v1/Flyout/Methods', 'Hide')
|
|
106
|
-
.get('.Button')
|
|
107
|
-
.click()
|
|
108
|
-
.wait(animationTimeout)
|
|
109
|
-
.get('.Flyout-hide')
|
|
110
|
-
.click()
|
|
111
|
-
.wait(animationTimeout)
|
|
112
|
-
.get('.Flyout')
|
|
113
|
-
.should('not.exist');
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
|
-
});
|
|
117
|
-
});
|