@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
|
@@ -1,254 +0,0 @@
|
|
|
1
|
-
describe('<Select />', () => {
|
|
2
|
-
context('Display', () => {
|
|
3
|
-
context('Default', () => {
|
|
4
|
-
it('Renders select and options', () => {
|
|
5
|
-
cy.visitStory('v1/Select/Display', 'Default')
|
|
6
|
-
// make sure it's a Select component
|
|
7
|
-
.get('.SelectDefault')
|
|
8
|
-
.should('have.class', 'Select')
|
|
9
|
-
// make sure dropdown exists
|
|
10
|
-
.get('.Select-dropdown-icon')
|
|
11
|
-
.should('exist')
|
|
12
|
-
// make sure options are what we expect
|
|
13
|
-
.get('option')
|
|
14
|
-
.eq(0)
|
|
15
|
-
.should('have.value', 'Option 1')
|
|
16
|
-
.get('option')
|
|
17
|
-
.eq(4)
|
|
18
|
-
.should('have.value', 'Option 5');
|
|
19
|
-
});
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
context('With Optional Props', () => {
|
|
23
|
-
it('Renders proper elements based on optional props', () => {
|
|
24
|
-
cy.visitStory('v1/Select/Display', 'WithProps', {
|
|
25
|
-
onBeforeLoad: contentWindow => {
|
|
26
|
-
contentWindow.onSelectFormSubmit = evt => {
|
|
27
|
-
console.log('onSelectFormSubmit'); // eslint-disable-line no-console
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
cy.stub(contentWindow, 'onSelectFormSubmit').as(
|
|
31
|
-
'selectFormSubmit'
|
|
32
|
-
);
|
|
33
|
-
},
|
|
34
|
-
})
|
|
35
|
-
// make sure select is required
|
|
36
|
-
.get('.SelectWithProps select.FormElement-item')
|
|
37
|
-
.should('have.attr', 'required')
|
|
38
|
-
// make sure select is rendered inline
|
|
39
|
-
.get('.SelectWithProps')
|
|
40
|
-
.should('have.class', 'FormElement-inline')
|
|
41
|
-
// make sure label renders properly
|
|
42
|
-
.get('.SelectWithProps .Label')
|
|
43
|
-
.contains('Select Dropdown')
|
|
44
|
-
// make sure placeholder renders properly
|
|
45
|
-
.get('option')
|
|
46
|
-
.eq(0)
|
|
47
|
-
.contains('Please select an item')
|
|
48
|
-
.should('have.attr', 'disabled', 'disabled')
|
|
49
|
-
// make sure Select-icon renders
|
|
50
|
-
.get('.Select-icon > .Icon')
|
|
51
|
-
.should('have.class', 'Icon-info')
|
|
52
|
-
// make sure help node renders
|
|
53
|
-
.get('.FormElement-help-text')
|
|
54
|
-
.contains(
|
|
55
|
-
'This is where some helpful information might appear.'
|
|
56
|
-
)
|
|
57
|
-
// after submit without selected, make sure error shows
|
|
58
|
-
.get('.SelectWithProps-submit')
|
|
59
|
-
.click()
|
|
60
|
-
.get('@selectFormSubmit')
|
|
61
|
-
.should('be.calledWith', null)
|
|
62
|
-
.get('.SelectWithProps')
|
|
63
|
-
.should('have.class', 'FormElement-contains-error')
|
|
64
|
-
.get('.FormElementError')
|
|
65
|
-
.contains('Please select an option');
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
context('Disabled', () => {
|
|
70
|
-
it('Has disabled attribute', () => {
|
|
71
|
-
cy.visitStory('v1/Select/Display', 'Disabled')
|
|
72
|
-
.get('.Select .FormElement-item')
|
|
73
|
-
.should('have.attr', 'disabled', 'disabled');
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
context('With Option Groups', () => {
|
|
78
|
-
it('Renders select with option groups', () => {
|
|
79
|
-
cy.visitStory('v1/Select/Display', 'WithOptionGroups')
|
|
80
|
-
// make sure optgroup exists and has options
|
|
81
|
-
.get('optgroup')
|
|
82
|
-
.eq(0)
|
|
83
|
-
.should('have.attr', 'label', 'Option Group A')
|
|
84
|
-
.get('optgroup')
|
|
85
|
-
.eq(1)
|
|
86
|
-
.should('have.attr', 'label', 'Option Group B')
|
|
87
|
-
.get('option')
|
|
88
|
-
.eq(0)
|
|
89
|
-
.should('have.value', 'Option A')
|
|
90
|
-
.get('option')
|
|
91
|
-
.eq(4)
|
|
92
|
-
.should('have.value', 'Option E');
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
context('With Mixed Options', () => {
|
|
97
|
-
it('Renders select with mixed items and option groups', () => {
|
|
98
|
-
cy.visitStory('v1/Select/Display', 'WithMixedOptions')
|
|
99
|
-
// Check optgroups are rendered
|
|
100
|
-
.get('optgroup')
|
|
101
|
-
.should('have.length', 2)
|
|
102
|
-
.get('optgroup')
|
|
103
|
-
.eq(0)
|
|
104
|
-
.should('have.attr', 'label', 'Option Group A')
|
|
105
|
-
.get('optgroup')
|
|
106
|
-
.eq(1)
|
|
107
|
-
.should('have.attr', 'label', 'Option Group B')
|
|
108
|
-
// Check options have the right values
|
|
109
|
-
.get('option')
|
|
110
|
-
.should('have.length', 15)
|
|
111
|
-
.get('option')
|
|
112
|
-
.eq(1)
|
|
113
|
-
.should('have.value', 'Option B')
|
|
114
|
-
.get('option')
|
|
115
|
-
.eq(4)
|
|
116
|
-
.should('have.value', 'Option E')
|
|
117
|
-
.get('option')
|
|
118
|
-
.eq(8)
|
|
119
|
-
.should('have.value', 'Option I')
|
|
120
|
-
.get('option')
|
|
121
|
-
.eq(11)
|
|
122
|
-
.should('have.value', 'Option 2');
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
context('Loading', () => {
|
|
127
|
-
it('Has loader', () => {
|
|
128
|
-
cy.visitStory('v1/Select/Display', 'Loading')
|
|
129
|
-
.get('.Loader')
|
|
130
|
-
.should('exist')
|
|
131
|
-
.parent()
|
|
132
|
-
.parent()
|
|
133
|
-
.should('have.class', 'Select');
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
context('Custom Icon', () => {
|
|
138
|
-
it('Has a custom dropdown icon', () => {
|
|
139
|
-
cy.visitStory('v1/Select/Display', 'WithCustomIcon')
|
|
140
|
-
.get('.Select-dropdown-icon')
|
|
141
|
-
.should('have.class', 'Icon-settings');
|
|
142
|
-
});
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
context('Default Value', () => {
|
|
146
|
-
it('Renders with default value selected', () => {
|
|
147
|
-
cy.visitStory('v1/Select/Display', 'WithDefaultValue')
|
|
148
|
-
// make sure default value is selected
|
|
149
|
-
.get('option:selected')
|
|
150
|
-
.contains('Option 3')
|
|
151
|
-
.should('have.value', 'Option 3');
|
|
152
|
-
});
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
context('Spread Additional Attributes', () => {
|
|
156
|
-
it('Renders with default value selected', () => {
|
|
157
|
-
cy.visitStory('v1/Select/Display', 'SpreadAdditionalProps')
|
|
158
|
-
.get('#my-search-field')
|
|
159
|
-
.should('have.attr', 'aria-label', 'Your search');
|
|
160
|
-
});
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
context('Methods', () => {
|
|
165
|
-
context('OnChange', () => {
|
|
166
|
-
it('OnChange method functions properly', () => {
|
|
167
|
-
cy.visitStory('v1/Select/Methods', 'OnChange', {
|
|
168
|
-
onBeforeLoad: contentWindow => {
|
|
169
|
-
contentWindow.onSelectChange = ({label, value}) => {
|
|
170
|
-
console.log('onSelectChange'); // eslint-disable-line no-console
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
cy.stub(contentWindow, 'onSelectChange').as(
|
|
174
|
-
'selectChange'
|
|
175
|
-
);
|
|
176
|
-
},
|
|
177
|
-
})
|
|
178
|
-
// fill form
|
|
179
|
-
.get('.Select')
|
|
180
|
-
.as('item')
|
|
181
|
-
.selectItem({alias: 'item', value: 'Option 2'})
|
|
182
|
-
// calls the onChange method
|
|
183
|
-
.get('@selectChange')
|
|
184
|
-
.should('be.calledWith', {
|
|
185
|
-
label: 'Option 2',
|
|
186
|
-
value: 'Option 2',
|
|
187
|
-
});
|
|
188
|
-
});
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
context('OnFocus', () => {
|
|
192
|
-
it('OnFocus method functions properly', () => {
|
|
193
|
-
cy.visitStory('v1/Select/Methods', 'OnFocus', {
|
|
194
|
-
onBeforeLoad: contentWindow => {
|
|
195
|
-
contentWindow.onSelectFocus = evt => {
|
|
196
|
-
console.log('onSelectFocus'); // eslint-disable-line no-console
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
cy.stub(contentWindow, 'onSelectFocus').as(
|
|
200
|
-
'selectFocus'
|
|
201
|
-
);
|
|
202
|
-
},
|
|
203
|
-
})
|
|
204
|
-
// fill form
|
|
205
|
-
.get('.Select')
|
|
206
|
-
.as('item')
|
|
207
|
-
.selectItem({alias: 'item', value: 'Option 2'})
|
|
208
|
-
// calls the onFocus method
|
|
209
|
-
.get('@selectFocus')
|
|
210
|
-
.should('be.called');
|
|
211
|
-
});
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
context('OnInvalid', () => {
|
|
215
|
-
it('OnInvalid method functions properly and form is submitted when valid', () => {
|
|
216
|
-
cy.visitStory('v1/Select/Methods', 'OnInvalid', {
|
|
217
|
-
onBeforeLoad: contentWindow => {
|
|
218
|
-
contentWindow.onSelectFormSubmit = evt => {
|
|
219
|
-
console.log('onSelectFormSubmit'); // eslint-disable-line no-console
|
|
220
|
-
};
|
|
221
|
-
|
|
222
|
-
contentWindow.onSelectInvalid = validationState => {
|
|
223
|
-
console.log('onSelectInvalid'); // eslint-disable-line no-console
|
|
224
|
-
};
|
|
225
|
-
|
|
226
|
-
cy.stub(contentWindow, 'onSelectFormSubmit').as(
|
|
227
|
-
'selectFormSubmit'
|
|
228
|
-
);
|
|
229
|
-
|
|
230
|
-
cy.stub(contentWindow, 'onSelectInvalid').as(
|
|
231
|
-
'selectInvalid'
|
|
232
|
-
);
|
|
233
|
-
},
|
|
234
|
-
})
|
|
235
|
-
.get('.SelectMethods-submit')
|
|
236
|
-
.click()
|
|
237
|
-
// check validity
|
|
238
|
-
.get('@selectInvalid')
|
|
239
|
-
.should('be.called')
|
|
240
|
-
// fill form
|
|
241
|
-
.get('.Select')
|
|
242
|
-
.as('item')
|
|
243
|
-
.selectItem({alias: 'item', value: 'Option 2'})
|
|
244
|
-
// submit after item is selected
|
|
245
|
-
.get('.SelectMethods-submit')
|
|
246
|
-
.click()
|
|
247
|
-
.get('@selectFormSubmit')
|
|
248
|
-
.should('be.calledWith', {
|
|
249
|
-
select: 'Option 2',
|
|
250
|
-
});
|
|
251
|
-
});
|
|
252
|
-
});
|
|
253
|
-
});
|
|
254
|
-
});
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import PropTypes from 'prop-types';
|
|
2
|
-
|
|
3
|
-
export const SelectItemPropTypes = {
|
|
4
|
-
/** The label to display visually in the Select. */
|
|
5
|
-
label: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
|
6
|
-
/** The value to return when a selection is made. */
|
|
7
|
-
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
|
8
|
-
/** Whether the option is disabled. */
|
|
9
|
-
disabled: PropTypes.bool,
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export const OptgroupPropTypes = {
|
|
13
|
-
/** The optgroup label within the list of options */
|
|
14
|
-
label: PropTypes.string,
|
|
15
|
-
/** An array of options with label/value pairs */
|
|
16
|
-
optgroup: PropTypes.arrayOf(PropTypes.shape(SelectItemPropTypes)),
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export default SelectItemPropTypes;
|
package/styles/Select/index.js
DELETED
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
import isEmpty from 'lodash/isEmpty';
|
|
2
|
-
import React, {Component, cloneElement} from 'react';
|
|
3
|
-
import PropTypes from 'prop-types';
|
|
4
|
-
import cn from 'classnames';
|
|
5
|
-
import IconChevronDown from '@spothero/icons/chevron-down';
|
|
6
|
-
import DOMUtils from '@spothero/utils/dom';
|
|
7
|
-
import Loader from 'v1/components/Loader/Loader';
|
|
8
|
-
// import {
|
|
9
|
-
// SelectItemPropTypes,
|
|
10
|
-
// OptgroupPropTypes
|
|
11
|
-
// } from './SelectItemPropTypes';
|
|
12
|
-
|
|
13
|
-
export default class SelectControlled extends Component {
|
|
14
|
-
static propTypes = {
|
|
15
|
-
/** Additional class(es) to add to the component. */
|
|
16
|
-
className: PropTypes.string,
|
|
17
|
-
/** 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. */
|
|
18
|
-
name: PropTypes.string,
|
|
19
|
-
/** A custom label (typically a Label component) to display above the select. */
|
|
20
|
-
label: PropTypes.element,
|
|
21
|
-
/** Adds an initial, unselectable item to display in the dropdown. */
|
|
22
|
-
placeholder: PropTypes.string,
|
|
23
|
-
/** Whether this field is required during validation. */
|
|
24
|
-
required: PropTypes.bool,
|
|
25
|
-
/** Disallows user interaction. */
|
|
26
|
-
disabled: PropTypes.bool,
|
|
27
|
-
/** Whether to show a loading animation inside of the component. */
|
|
28
|
-
loading: PropTypes.bool,
|
|
29
|
-
/** An array of options or an array of option groups */
|
|
30
|
-
items: PropTypes.array.isRequired,
|
|
31
|
-
// items: PropTypes.oneOfType([
|
|
32
|
-
// PropTypes.arrayOf(PropTypes.shape(SelectItemPropTypes)),
|
|
33
|
-
// PropTypes.arrayOf(PropTypes.shape(OptgroupPropTypes))
|
|
34
|
-
// ]).isRequired,
|
|
35
|
-
/** A custom help element to place below the select. */
|
|
36
|
-
helpNode: PropTypes.node,
|
|
37
|
-
/** Applies proper styling to display this field inline in a form. */
|
|
38
|
-
inline: PropTypes.bool,
|
|
39
|
-
/** A custom icon (typically an Icon component) to show instead of the default arrow dropdown icon. */
|
|
40
|
-
dropdownIcon: PropTypes.element,
|
|
41
|
-
/** A custom icon (typically an Icon component) to show in the select field. */
|
|
42
|
-
icon: PropTypes.element,
|
|
43
|
-
/** If an icon is provided, whether it should appear on the left or right side of the input field. */
|
|
44
|
-
iconPosition: PropTypes.oneOf(['left', 'right']),
|
|
45
|
-
/** The default value to display in the select when mounted. */
|
|
46
|
-
defaultValue: PropTypes.string,
|
|
47
|
-
/** Value to display in the select when used as a controlled form element. Cannot be used with `defaultValue`. */
|
|
48
|
-
value: PropTypes.string,
|
|
49
|
-
/** A custom validation error (typically a FormElementError component) to display when this component is part of a form and is invalid. */
|
|
50
|
-
error: PropTypes.element,
|
|
51
|
-
/**
|
|
52
|
-
* Function to execute when the select changes.
|
|
53
|
-
*
|
|
54
|
-
* @param {Object} item - The value/label pair of the selection.
|
|
55
|
-
*/
|
|
56
|
-
onChange: PropTypes.func,
|
|
57
|
-
/**
|
|
58
|
-
* Function to execute when the select is focused.
|
|
59
|
-
*
|
|
60
|
-
* @param {SyntheticEvent} evt - The React `SyntheticEvent`.
|
|
61
|
-
*/
|
|
62
|
-
onFocus: PropTypes.func,
|
|
63
|
-
/**
|
|
64
|
-
* Function to execute when the element is marked as invalid by a validation check.
|
|
65
|
-
*
|
|
66
|
-
* @param {ValidityState} validationState - ValidityState object for more fine grained control over error handling in a parent component if desired.
|
|
67
|
-
*/
|
|
68
|
-
onInvalid: PropTypes.func,
|
|
69
|
-
};
|
|
70
|
-
static defaultProps = {
|
|
71
|
-
iconPosition: 'left',
|
|
72
|
-
};
|
|
73
|
-
state = {
|
|
74
|
-
validationState: null,
|
|
75
|
-
};
|
|
76
|
-
_isFirstRender = true;
|
|
77
|
-
|
|
78
|
-
componentDidMount() {
|
|
79
|
-
// if a placeholder is present on first render, we want to use this for setting the placeholder class to avoid a flash
|
|
80
|
-
// in the coloring of the placeholder text in the field on initial load
|
|
81
|
-
this._isFirstRender = false;
|
|
82
|
-
this._select.addEventListener('invalid', this._onInvalid);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
componentDidUpdate(prevProps, prevState, snapshot) {
|
|
86
|
-
this._checkIfDisabledSelected();
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
componentWillUnmount() {
|
|
90
|
-
this._select.removeEventListener('invalid', this._onInvalid);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
_onInvalid = evt => {
|
|
94
|
-
evt.preventDefault();
|
|
95
|
-
|
|
96
|
-
const {onInvalid} = this.props;
|
|
97
|
-
const validationState = evt.currentTarget.validity;
|
|
98
|
-
|
|
99
|
-
this.setState({
|
|
100
|
-
validationState,
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
if (onInvalid) {
|
|
104
|
-
onInvalid(validationState);
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
_onChange = evt => {
|
|
109
|
-
const {items, onChange} = this.props;
|
|
110
|
-
const selectedItem = items
|
|
111
|
-
.reduce((options, {optgroup, ...item}) => {
|
|
112
|
-
return optgroup
|
|
113
|
-
? [...options, ...optgroup]
|
|
114
|
-
: [...options, item];
|
|
115
|
-
}, [])
|
|
116
|
-
.find(({value}) => value === evt.target.value);
|
|
117
|
-
|
|
118
|
-
this.setState({
|
|
119
|
-
validationState: null,
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
if (onChange) {
|
|
123
|
-
onChange(selectedItem);
|
|
124
|
-
}
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
_checkIfDisabledSelected() {
|
|
128
|
-
// if a disabled option is selected at first, make it the same color as placeholder as thats typically why its selected
|
|
129
|
-
if (isEmpty(this._select.value)) {
|
|
130
|
-
DOMUtils.addClass(this._select, 'FormElement-item-placeholder');
|
|
131
|
-
} else {
|
|
132
|
-
DOMUtils.removeClass(this._select, 'FormElement-item-placeholder');
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
_renderOptgroup = ({label, optgroup}) => {
|
|
137
|
-
return (
|
|
138
|
-
<optgroup key={label} label={label}>
|
|
139
|
-
{optgroup.map(this._renderItem)}
|
|
140
|
-
</optgroup>
|
|
141
|
-
);
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
_renderItem = ({disabled = false, label = '', value = ''}, i) => {
|
|
145
|
-
return (
|
|
146
|
-
<option key={i} value={value} disabled={disabled}>
|
|
147
|
-
{label}
|
|
148
|
-
</option>
|
|
149
|
-
);
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Getter for the select DOM element.
|
|
154
|
-
*
|
|
155
|
-
* @public
|
|
156
|
-
* @returns {Element} - The select element.
|
|
157
|
-
*/
|
|
158
|
-
get node() {
|
|
159
|
-
return this._select;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
render() {
|
|
163
|
-
const {
|
|
164
|
-
className,
|
|
165
|
-
name,
|
|
166
|
-
items,
|
|
167
|
-
disabled,
|
|
168
|
-
loading,
|
|
169
|
-
error,
|
|
170
|
-
helpNode,
|
|
171
|
-
label,
|
|
172
|
-
dropdownIcon,
|
|
173
|
-
icon,
|
|
174
|
-
iconPosition,
|
|
175
|
-
required,
|
|
176
|
-
inline,
|
|
177
|
-
defaultValue,
|
|
178
|
-
placeholder,
|
|
179
|
-
onFocus,
|
|
180
|
-
value,
|
|
181
|
-
} = this.props;
|
|
182
|
-
const {validationState} = this.state;
|
|
183
|
-
const isValid = validationState ? validationState.valid : true;
|
|
184
|
-
const containerClasses = cn(
|
|
185
|
-
'Select',
|
|
186
|
-
'FormElement',
|
|
187
|
-
{'FormElement-inline': inline},
|
|
188
|
-
{'FormElement-with-icon': icon},
|
|
189
|
-
{[`FormElement-with-icon-${iconPosition}`]: icon},
|
|
190
|
-
{'FormElement-contains-error': !isValid},
|
|
191
|
-
className
|
|
192
|
-
);
|
|
193
|
-
const itemClasses = cn('FormElement-item', {
|
|
194
|
-
'FormElement-item-placeholder':
|
|
195
|
-
placeholder && !defaultValue && this._isFirstRender,
|
|
196
|
-
});
|
|
197
|
-
const customIconClasses = cn(
|
|
198
|
-
'Select-dropdown-icon',
|
|
199
|
-
dropdownIcon ? dropdownIcon.props.className : null
|
|
200
|
-
);
|
|
201
|
-
const newDefaultValue =
|
|
202
|
-
placeholder && !defaultValue ? '' : defaultValue;
|
|
203
|
-
|
|
204
|
-
return (
|
|
205
|
-
<div className={containerClasses}>
|
|
206
|
-
{label}
|
|
207
|
-
<div className="FormElement-control">
|
|
208
|
-
<select
|
|
209
|
-
ref={node => {
|
|
210
|
-
this._select = node;
|
|
211
|
-
}}
|
|
212
|
-
className={itemClasses}
|
|
213
|
-
name={name}
|
|
214
|
-
required={required}
|
|
215
|
-
disabled={disabled}
|
|
216
|
-
defaultValue={newDefaultValue}
|
|
217
|
-
onFocus={onFocus}
|
|
218
|
-
onChange={this._onChange}
|
|
219
|
-
value={value}
|
|
220
|
-
>
|
|
221
|
-
{placeholder && (
|
|
222
|
-
<option value="" disabled>
|
|
223
|
-
{placeholder}
|
|
224
|
-
</option>
|
|
225
|
-
)}
|
|
226
|
-
{items.map((item, i) => {
|
|
227
|
-
return item.optgroup
|
|
228
|
-
? this._renderOptgroup(item)
|
|
229
|
-
: this._renderItem(item, i);
|
|
230
|
-
})}
|
|
231
|
-
</select>
|
|
232
|
-
{loading ? (
|
|
233
|
-
<Loader size={16} borderWidth={2} />
|
|
234
|
-
) : dropdownIcon ? (
|
|
235
|
-
cloneElement(dropdownIcon, {
|
|
236
|
-
className: customIconClasses,
|
|
237
|
-
})
|
|
238
|
-
) : (
|
|
239
|
-
<IconChevronDown className="Select-dropdown-icon" />
|
|
240
|
-
)}
|
|
241
|
-
<span className="Select-icon">{icon}</span>
|
|
242
|
-
</div>
|
|
243
|
-
{helpNode && (
|
|
244
|
-
<div className="FormElement-help-text">{helpNode}</div>
|
|
245
|
-
)}
|
|
246
|
-
{!isValid && error}
|
|
247
|
-
</div>
|
|
248
|
-
);
|
|
249
|
-
}
|
|
250
|
-
}
|