@spothero/ui 15.0.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/v2/components/FormControl/FormControl.jsx +20 -2
- package/styles/v2/components/Radio/Radio.jsx +50 -0
- package/styles/v2/components/Radio/Radio.stories.js +155 -0
- package/styles/v2/components/Radio/RadioGroup.jsx +69 -0
- package/styles/v2/components/Radio/styles/index.js +52 -0
- package/styles/v2/components/index.js +1 -0
- package/styles/v2/components/styles.js +1 -0
- 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/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
- /package/styles/{Radio → v2/components/Radio}/index.js +0 -0
package/styles/Tabs/Tabs.spec.js
DELETED
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
describe('<Tabs />', () => {
|
|
2
|
-
context('Display', () => {
|
|
3
|
-
context('Default', () => {
|
|
4
|
-
beforeEach(() => {
|
|
5
|
-
cy.visitStory('v1/Tabs/Display', 'Default');
|
|
6
|
-
});
|
|
7
|
-
|
|
8
|
-
it('Should take in and display basic tab and panel content, with default active states and custom classes', () => {
|
|
9
|
-
cy.get('.Tabs')
|
|
10
|
-
.find('.Tab')
|
|
11
|
-
.should('have.length', 4)
|
|
12
|
-
.eq(0)
|
|
13
|
-
.should('have.class', 'Tab-active')
|
|
14
|
-
.get('.Tabs')
|
|
15
|
-
.find('.TabPanel')
|
|
16
|
-
.should('have.length', 4)
|
|
17
|
-
.eq(0)
|
|
18
|
-
.should('have.class', 'TabPanel-active')
|
|
19
|
-
// check that the mobile select component is rendered
|
|
20
|
-
.get('.Tabs')
|
|
21
|
-
.find('.TabNavigation-select')
|
|
22
|
-
.find('option')
|
|
23
|
-
.should('have.length', 4)
|
|
24
|
-
.eq(0)
|
|
25
|
-
.should('be.selected');
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('Should apply custom classes to all components', () => {
|
|
29
|
-
cy.get('.Tabs')
|
|
30
|
-
.should(
|
|
31
|
-
'have.class',
|
|
32
|
-
'custom-tab-component restaurant-menus'
|
|
33
|
-
)
|
|
34
|
-
.find('.TabNavigation')
|
|
35
|
-
.should('have.class', 'tab-nav menu-nav')
|
|
36
|
-
.get('.Tabs')
|
|
37
|
-
.find('.Tab')
|
|
38
|
-
.eq(0)
|
|
39
|
-
.should('have.class', 'menu-tab special-menu')
|
|
40
|
-
.get('.Tabs')
|
|
41
|
-
.find('.TabContent')
|
|
42
|
-
.should(
|
|
43
|
-
'have.class',
|
|
44
|
-
'tab-content-container restaurant-menus-container'
|
|
45
|
-
)
|
|
46
|
-
.get('.Tabs')
|
|
47
|
-
.find('.TabPanel')
|
|
48
|
-
.eq(3)
|
|
49
|
-
.should('have.class', 'menu-content dessert-menu-content');
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it('Should have visible Select on mobile viewport and visible tabs otherwise', () => {
|
|
53
|
-
cy.get('.Tabs')
|
|
54
|
-
.find('.TabNavigation-select')
|
|
55
|
-
.should('not.be.visible')
|
|
56
|
-
.get('.Tabs')
|
|
57
|
-
.find('.Tab')
|
|
58
|
-
.should('be.visible')
|
|
59
|
-
.viewport('iphone-6')
|
|
60
|
-
.get('.Tabs')
|
|
61
|
-
.find('.TabNavigation-select')
|
|
62
|
-
.should('be.visible')
|
|
63
|
-
.get('.Tabs')
|
|
64
|
-
.find('.Tab')
|
|
65
|
-
.should('not.be.visible');
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
context('Child Nodes', () => {
|
|
70
|
-
it('Should take in and display complex tab and panel content', () => {
|
|
71
|
-
cy.visitStory('v1/Tabs/Display', 'ChildNodes')
|
|
72
|
-
// Check that spans exist in the tab
|
|
73
|
-
.get('.Tabs')
|
|
74
|
-
.find('.Tab')
|
|
75
|
-
.eq(0)
|
|
76
|
-
.find('span.breakfast-tab')
|
|
77
|
-
.should('exist')
|
|
78
|
-
.should('contain', 'Breakfast Menu')
|
|
79
|
-
// Check that icon is in the tab
|
|
80
|
-
.get('.Tabs')
|
|
81
|
-
.find('.Tab')
|
|
82
|
-
.eq(3)
|
|
83
|
-
.find('.Icon')
|
|
84
|
-
.should('exist')
|
|
85
|
-
// Check that span/div exists in the panel
|
|
86
|
-
.get('.Tabs')
|
|
87
|
-
.find('.TabPanel')
|
|
88
|
-
.eq(0)
|
|
89
|
-
.find('span.bacon')
|
|
90
|
-
.should('exist')
|
|
91
|
-
.get('.Tabs')
|
|
92
|
-
.find('.TabPanel')
|
|
93
|
-
.eq(0)
|
|
94
|
-
.find('div.toast')
|
|
95
|
-
.should('exist')
|
|
96
|
-
// Check that ul/li exists in the panel
|
|
97
|
-
.get('.Tabs')
|
|
98
|
-
.find('.TabPanel')
|
|
99
|
-
.eq(1)
|
|
100
|
-
.find('ul')
|
|
101
|
-
.should('exist')
|
|
102
|
-
.find('li')
|
|
103
|
-
.should('have.length', 3);
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
context('Selected Index', () => {
|
|
108
|
-
it('Should display specified tab and content', () => {
|
|
109
|
-
cy.visitStory('v1/Tabs/Display', 'SelectedIndex')
|
|
110
|
-
.get('.Tabs')
|
|
111
|
-
.find('.Tab')
|
|
112
|
-
.eq(3)
|
|
113
|
-
.should('have.class', 'Tab-active')
|
|
114
|
-
.get('.Tabs')
|
|
115
|
-
.find('.TabPanel')
|
|
116
|
-
.eq(3)
|
|
117
|
-
.should('have.class', 'TabPanel-active')
|
|
118
|
-
// check that the mobile select component has the correct option selected
|
|
119
|
-
.get('.Tabs')
|
|
120
|
-
.find('.TabNavigation-select option')
|
|
121
|
-
.eq(3)
|
|
122
|
-
.should('be.selected');
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
context('Render Active Only', () => {
|
|
127
|
-
it('Should render only tab content corresponding to the active tab', () => {
|
|
128
|
-
cy.visitStory('v1/Tabs/Display', 'RenderActiveOnly')
|
|
129
|
-
.get('.Tabs')
|
|
130
|
-
.find('.TabPanel')
|
|
131
|
-
.should('have.length', 1)
|
|
132
|
-
.should('have.class', 'TabPanel-active')
|
|
133
|
-
.should('contain', 'Bacon, Eggs, and Toast')
|
|
134
|
-
.get('.Tabs')
|
|
135
|
-
.find('.Tab')
|
|
136
|
-
.eq(2)
|
|
137
|
-
.click()
|
|
138
|
-
.get('.Tabs')
|
|
139
|
-
.find('.TabPanel')
|
|
140
|
-
.should('have.length', 1)
|
|
141
|
-
.should('have.class', 'TabPanel-active')
|
|
142
|
-
.should(
|
|
143
|
-
'contain',
|
|
144
|
-
'Prime Rib, Mashed Potatoes, and Glazed Carrots'
|
|
145
|
-
);
|
|
146
|
-
});
|
|
147
|
-
});
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
context('Methods', () => {
|
|
151
|
-
context('On Select', () => {
|
|
152
|
-
beforeEach(() => {
|
|
153
|
-
cy.visitStory('v1/Tabs/Methods', 'OnSelect', {
|
|
154
|
-
onBeforeLoad: contentWindow => {
|
|
155
|
-
contentWindow.onTabSelect = evt => {
|
|
156
|
-
console.log(`onTabSelect`); // eslint-disable-line no-console
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
cy.stub(contentWindow, 'onTabSelect').as('onTabSelect');
|
|
160
|
-
},
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
it('Should be called when a tab is selected', () => {
|
|
165
|
-
cy.get('.Tabs')
|
|
166
|
-
.find('.Tab')
|
|
167
|
-
.eq(1)
|
|
168
|
-
.should('not.have.class', 'Tab-active')
|
|
169
|
-
.click()
|
|
170
|
-
.get('@onTabSelect')
|
|
171
|
-
.should('be.called')
|
|
172
|
-
// check that selecting from the mobile select component also calls @onTabSelect
|
|
173
|
-
.viewport('iphone-6')
|
|
174
|
-
.get('.Tabs')
|
|
175
|
-
// cannot use selectItem method due to rerender of TabNavigation
|
|
176
|
-
.find('.TabNavigation-select select')
|
|
177
|
-
.select('2')
|
|
178
|
-
.get('@onTabSelect')
|
|
179
|
-
.should('be.called');
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
it('Should not be called when a tab is already active', () => {
|
|
183
|
-
cy.get('.Tabs')
|
|
184
|
-
.find('.Tab')
|
|
185
|
-
.eq(0)
|
|
186
|
-
.should('have.class', 'Tab-active')
|
|
187
|
-
.click()
|
|
188
|
-
.get('@onTabSelect')
|
|
189
|
-
.should('not.be.called')
|
|
190
|
-
// check that selecting from the mobile select component does not call @onTabSelect
|
|
191
|
-
.viewport('iphone-6')
|
|
192
|
-
.get('.Tabs')
|
|
193
|
-
// cannot use selectItem method due to rerender of TabNavigation
|
|
194
|
-
.find('.TabNavigation-select select')
|
|
195
|
-
.select('0')
|
|
196
|
-
.get('@onTabSelect')
|
|
197
|
-
.should('not.be.called');
|
|
198
|
-
});
|
|
199
|
-
});
|
|
200
|
-
});
|
|
201
|
-
});
|
package/styles/Tabs/index.js
DELETED
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
import React, {Component} from 'react';
|
|
2
|
-
import PropTypes from 'prop-types';
|
|
3
|
-
import classNames from 'classnames';
|
|
4
|
-
|
|
5
|
-
export default class TextArea extends Component {
|
|
6
|
-
static propTypes = {
|
|
7
|
-
/** Additional class(es) to add to the component. */
|
|
8
|
-
className: PropTypes.string,
|
|
9
|
-
/** 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. */
|
|
10
|
-
name: PropTypes.string,
|
|
11
|
-
/** Text to display in the field before a user starts to type in the textarea. */
|
|
12
|
-
placeholder: PropTypes.string,
|
|
13
|
-
/** A custom label (typically a Label component) to display above the textarea. */
|
|
14
|
-
label: PropTypes.element,
|
|
15
|
-
/** Whether this field is required during validation. */
|
|
16
|
-
required: PropTypes.bool,
|
|
17
|
-
/** Disallows user interaction. */
|
|
18
|
-
disabled: PropTypes.bool,
|
|
19
|
-
/** Whether the textarea should be auto focused when mounted. */
|
|
20
|
-
autoFocus: PropTypes.bool,
|
|
21
|
-
/** A custom help element to place below the input. */
|
|
22
|
-
helpNode: PropTypes.node,
|
|
23
|
-
/** A custom validation error (typically a FormElementError component) to display when this component is part of a form and is invalid. */
|
|
24
|
-
error: PropTypes.element,
|
|
25
|
-
/** The default value to display in the textarea when mounted. */
|
|
26
|
-
defaultValue: PropTypes.string,
|
|
27
|
-
/** Specifies the maximum number of characters allowed. */
|
|
28
|
-
maxLength: PropTypes.number,
|
|
29
|
-
/** A custom icon (typically an Icon component) to show in the textarea. */
|
|
30
|
-
icon: PropTypes.element,
|
|
31
|
-
/**
|
|
32
|
-
* Function to execute when the textarea changes.
|
|
33
|
-
*
|
|
34
|
-
* @param {SyntheticEvent} evt - The React `SyntheticEvent`.
|
|
35
|
-
*/
|
|
36
|
-
onChange: PropTypes.func,
|
|
37
|
-
/**
|
|
38
|
-
* Function to execute when the element is marked as invalid by a validation check.
|
|
39
|
-
*
|
|
40
|
-
* @param {ValidityState} validationState - ValidityState object for more fine grained control over error handling in a parent component if desired.
|
|
41
|
-
*/
|
|
42
|
-
onInvalid: PropTypes.func,
|
|
43
|
-
};
|
|
44
|
-
state = {
|
|
45
|
-
validationState: null,
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
componentDidMount() {
|
|
49
|
-
this._textarea.addEventListener('invalid', this._onInvalid);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
componentWillUnmount() {
|
|
53
|
-
this._textarea.removeEventListener('invalid', this._onInvalid);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
_onInvalid = evt => {
|
|
57
|
-
evt.preventDefault();
|
|
58
|
-
|
|
59
|
-
const {onInvalid} = this.props;
|
|
60
|
-
const validationState = evt.currentTarget.validity;
|
|
61
|
-
|
|
62
|
-
this.setState({
|
|
63
|
-
validationState,
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
if (onInvalid) {
|
|
67
|
-
onInvalid(validationState);
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
_onChange = evt => {
|
|
72
|
-
const {onChange} = this.props;
|
|
73
|
-
|
|
74
|
-
this.setState({
|
|
75
|
-
validationState: null,
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
if (onChange) {
|
|
79
|
-
onChange(evt);
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
render() {
|
|
84
|
-
const {
|
|
85
|
-
className,
|
|
86
|
-
name,
|
|
87
|
-
label,
|
|
88
|
-
placeholder,
|
|
89
|
-
disabled,
|
|
90
|
-
required,
|
|
91
|
-
autoFocus,
|
|
92
|
-
helpNode,
|
|
93
|
-
error,
|
|
94
|
-
defaultValue,
|
|
95
|
-
maxLength,
|
|
96
|
-
icon,
|
|
97
|
-
} = this.props;
|
|
98
|
-
const {validationState} = this.state;
|
|
99
|
-
const isValid = validationState ? validationState.isValid : true;
|
|
100
|
-
const classes = classNames(
|
|
101
|
-
'TextArea',
|
|
102
|
-
'FormElement',
|
|
103
|
-
{'TextArea-with-icon': icon},
|
|
104
|
-
{'FormElement-contains-error': !isValid},
|
|
105
|
-
className
|
|
106
|
-
);
|
|
107
|
-
|
|
108
|
-
return (
|
|
109
|
-
<div className={classes}>
|
|
110
|
-
<div className="FormElement-control-container">
|
|
111
|
-
{label}
|
|
112
|
-
<div className="FormElement-control">
|
|
113
|
-
<textarea
|
|
114
|
-
ref={node => {
|
|
115
|
-
this._textarea = node;
|
|
116
|
-
}}
|
|
117
|
-
className="FormElement-item"
|
|
118
|
-
name={name}
|
|
119
|
-
placeholder={placeholder}
|
|
120
|
-
required={required}
|
|
121
|
-
disabled={disabled}
|
|
122
|
-
autoFocus={autoFocus}
|
|
123
|
-
maxLength={maxLength}
|
|
124
|
-
defaultValue={defaultValue}
|
|
125
|
-
onChange={this._onChange}
|
|
126
|
-
/>
|
|
127
|
-
{icon}
|
|
128
|
-
</div>
|
|
129
|
-
</div>
|
|
130
|
-
{helpNode && (
|
|
131
|
-
<div className="FormElement-help-text">{helpNode}</div>
|
|
132
|
-
)}
|
|
133
|
-
{!isValid && error}
|
|
134
|
-
</div>
|
|
135
|
-
);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
describe('<TextArea />', () => {
|
|
2
|
-
context('Display', () => {
|
|
3
|
-
context('Default', () => {
|
|
4
|
-
it('Should have placeholder, default value, label, help text, and custom class names', () => {
|
|
5
|
-
cy.visitStory('v1/TextArea/Display', 'Default')
|
|
6
|
-
.get('.TextArea')
|
|
7
|
-
.should('exist')
|
|
8
|
-
.and('have.class', 'custom-class1')
|
|
9
|
-
.and('have.class', 'custom-class2')
|
|
10
|
-
.find('textarea')
|
|
11
|
-
.should('have.attr', 'name', 'message')
|
|
12
|
-
.and('have.attr', 'placeholder', 'Enter Message Here')
|
|
13
|
-
.and('have.value', 'Dear Sir or Madam:')
|
|
14
|
-
.get('.TextArea')
|
|
15
|
-
.find('.Label')
|
|
16
|
-
.contains('Customer Feedback')
|
|
17
|
-
.get('.TextArea')
|
|
18
|
-
.find('.FormElement-help-text')
|
|
19
|
-
.contains('Additional help node text');
|
|
20
|
-
});
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
context('Icon', () => {
|
|
24
|
-
it('Should render with an icon', () => {
|
|
25
|
-
cy.visitStory('v1/TextArea/Display', 'Icon')
|
|
26
|
-
.get('.TextArea')
|
|
27
|
-
.find('.Icon')
|
|
28
|
-
.should('exist');
|
|
29
|
-
});
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
context('Disabled', () => {
|
|
33
|
-
it('Is disabled', () => {
|
|
34
|
-
cy.visitStory('v1/TextArea/Display', 'Disabled')
|
|
35
|
-
.get('.TextArea')
|
|
36
|
-
.find('textarea')
|
|
37
|
-
.should('be.disabled');
|
|
38
|
-
});
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
context('Auto Focus', () => {
|
|
42
|
-
it('Receives focus after rendered', () => {
|
|
43
|
-
cy.visitStory('v1/TextArea/Display', 'AutoFocus')
|
|
44
|
-
.focused()
|
|
45
|
-
.should('have.attr', 'name', 'message');
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
context('Max Length', () => {
|
|
50
|
-
it('Has maxlength attribute and does not allow more characters', () => {
|
|
51
|
-
// longstring is 143 characters long
|
|
52
|
-
const longstring =
|
|
53
|
-
'12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890AAA';
|
|
54
|
-
|
|
55
|
-
cy.visitStory('v1/TextArea/Display', 'MaxLength')
|
|
56
|
-
.get('.TextArea')
|
|
57
|
-
.find('textarea')
|
|
58
|
-
.should('have.attr', 'maxlength', '140')
|
|
59
|
-
.type(longstring, {delay: 0})
|
|
60
|
-
.should('have.value', longstring.substring(0, 140));
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
context('Methods', () => {
|
|
66
|
-
describe('On Change', () => {
|
|
67
|
-
it('Executes the method when a change is detected', () => {
|
|
68
|
-
cy.visitStory('v1/TextArea/Methods', 'Default', {
|
|
69
|
-
onBeforeLoad: contentWindow => {
|
|
70
|
-
contentWindow.onTextAreaChange = evt => {
|
|
71
|
-
console.log(`onTextAreaChange`); // eslint-disable-line no-console
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
cy.stub(contentWindow, 'onTextAreaChange').as(
|
|
75
|
-
'onTextAreaChange'
|
|
76
|
-
);
|
|
77
|
-
},
|
|
78
|
-
})
|
|
79
|
-
.get('.TextArea')
|
|
80
|
-
.find('textarea')
|
|
81
|
-
.type('I have a complaint', {delay: 0})
|
|
82
|
-
.get('@onTextAreaChange')
|
|
83
|
-
.should('be.called');
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
describe('On Invalid', () => {
|
|
88
|
-
it('Displays an error if the input is invalid', () => {
|
|
89
|
-
cy.visitStory('v1/TextArea/Methods', 'OnInvalid')
|
|
90
|
-
.get('.TextArea')
|
|
91
|
-
.find('textarea')
|
|
92
|
-
// Show error on empty field since this is required
|
|
93
|
-
.should('have.value', '')
|
|
94
|
-
.get('button[type=submit]')
|
|
95
|
-
.click()
|
|
96
|
-
.get('.TextArea')
|
|
97
|
-
.find('.FormElementError')
|
|
98
|
-
.should('exist')
|
|
99
|
-
// Don't show error on field with content
|
|
100
|
-
.get('.TextArea')
|
|
101
|
-
.find('textarea')
|
|
102
|
-
.type('I have a complaint', {delay: 0})
|
|
103
|
-
.get('button[type=submit]')
|
|
104
|
-
.click()
|
|
105
|
-
.get('.TextArea')
|
|
106
|
-
.find('.FormElementError')
|
|
107
|
-
.should('not.exist');
|
|
108
|
-
});
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
});
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
import React, {Component} from 'react';
|
|
2
|
-
import classNames from 'classnames';
|
|
3
|
-
import InputElement from 'react-input-mask';
|
|
4
|
-
import Loader from 'v1/components/Loader/Loader';
|
|
5
|
-
import TextInputPropTypes from './TextInputPropTypes';
|
|
6
|
-
|
|
7
|
-
export default class TextInput extends Component {
|
|
8
|
-
static propTypes = TextInputPropTypes;
|
|
9
|
-
static defaultProps = {
|
|
10
|
-
type: 'text',
|
|
11
|
-
maskChar: null,
|
|
12
|
-
iconPosition: 'left',
|
|
13
|
-
};
|
|
14
|
-
state = {
|
|
15
|
-
validationState: null,
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
componentDidMount() {
|
|
19
|
-
this._input
|
|
20
|
-
?.getInputDOMNode()
|
|
21
|
-
?.addEventListener('invalid', this._onInvalid);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
componentDidUpdate(prevProps, prevState) {
|
|
25
|
-
if (prevProps.focus !== this.props.focus) {
|
|
26
|
-
this._checkFocus();
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
componentWillUnmount() {
|
|
31
|
-
this._input
|
|
32
|
-
?.getInputDOMNode()
|
|
33
|
-
?.removeEventListener('invalid', this._onInvalid);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
_onInvalid = evt => {
|
|
37
|
-
evt.preventDefault();
|
|
38
|
-
|
|
39
|
-
const {onInvalid} = this.props;
|
|
40
|
-
const validationState = evt.currentTarget.validity;
|
|
41
|
-
|
|
42
|
-
this.setState({
|
|
43
|
-
validationState,
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
if (onInvalid) {
|
|
47
|
-
onInvalid(validationState);
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
_onChange = evt => {
|
|
52
|
-
const {onChange} = this.props;
|
|
53
|
-
|
|
54
|
-
this.setState({
|
|
55
|
-
validationState: null,
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
if (onChange) {
|
|
59
|
-
onChange(evt);
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
_checkFocus() {
|
|
64
|
-
if (this.props.focus) {
|
|
65
|
-
this._input?.getInputDOMNode()?.focus();
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Getter for the input DOM element.
|
|
71
|
-
*
|
|
72
|
-
* @public
|
|
73
|
-
* @returns {Element} - The input element.
|
|
74
|
-
*/
|
|
75
|
-
get node() {
|
|
76
|
-
return this._input?.getInputDOMNode();
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
render() {
|
|
80
|
-
const {
|
|
81
|
-
className,
|
|
82
|
-
name,
|
|
83
|
-
type,
|
|
84
|
-
label,
|
|
85
|
-
placeholder,
|
|
86
|
-
pattern,
|
|
87
|
-
required,
|
|
88
|
-
disabled,
|
|
89
|
-
loading,
|
|
90
|
-
autoFocus,
|
|
91
|
-
error,
|
|
92
|
-
defaultValue,
|
|
93
|
-
icon,
|
|
94
|
-
iconPosition,
|
|
95
|
-
helpNode,
|
|
96
|
-
inline,
|
|
97
|
-
readOnly,
|
|
98
|
-
maxLength,
|
|
99
|
-
min,
|
|
100
|
-
max,
|
|
101
|
-
mask,
|
|
102
|
-
maskChar,
|
|
103
|
-
additionalInputProps,
|
|
104
|
-
onFocus,
|
|
105
|
-
onBlur,
|
|
106
|
-
} = this.props;
|
|
107
|
-
const {validationState} = this.state;
|
|
108
|
-
const isValid = validationState ? validationState.valid : true;
|
|
109
|
-
const classes = classNames(
|
|
110
|
-
'TextInput',
|
|
111
|
-
'FormElement',
|
|
112
|
-
{'FormElement-inline': inline},
|
|
113
|
-
{'FormElement-with-icon': icon},
|
|
114
|
-
{'FormElement-loading': loading},
|
|
115
|
-
{[`FormElement-with-icon-${iconPosition}`]: icon},
|
|
116
|
-
{'FormElement-contains-error': !isValid},
|
|
117
|
-
className
|
|
118
|
-
);
|
|
119
|
-
|
|
120
|
-
return (
|
|
121
|
-
<div className={classes}>
|
|
122
|
-
{label}
|
|
123
|
-
<div className="FormElement-control">
|
|
124
|
-
<InputElement
|
|
125
|
-
ref={node => {
|
|
126
|
-
this._input = node;
|
|
127
|
-
}}
|
|
128
|
-
className="FormElement-item"
|
|
129
|
-
name={name}
|
|
130
|
-
type={type}
|
|
131
|
-
placeholder={placeholder}
|
|
132
|
-
disabled={disabled}
|
|
133
|
-
autoFocus={autoFocus}
|
|
134
|
-
required={required}
|
|
135
|
-
pattern={pattern}
|
|
136
|
-
maxLength={maxLength}
|
|
137
|
-
min={min}
|
|
138
|
-
max={max}
|
|
139
|
-
onChange={this._onChange}
|
|
140
|
-
onFocus={onFocus}
|
|
141
|
-
onBlur={onBlur}
|
|
142
|
-
mask={mask}
|
|
143
|
-
maskChar={maskChar}
|
|
144
|
-
alwaysShowMask={false}
|
|
145
|
-
readOnly={readOnly}
|
|
146
|
-
defaultValue={defaultValue}
|
|
147
|
-
{...additionalInputProps}
|
|
148
|
-
/>
|
|
149
|
-
{icon}
|
|
150
|
-
{loading && <Loader size={16} borderWidth={2} />}
|
|
151
|
-
</div>
|
|
152
|
-
{helpNode && (
|
|
153
|
-
<div className="FormElement-help-text">{helpNode}</div>
|
|
154
|
-
)}
|
|
155
|
-
{!isValid && error}
|
|
156
|
-
</div>
|
|
157
|
-
);
|
|
158
|
-
}
|
|
159
|
-
}
|