@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.
Files changed (94) hide show
  1. package/package.json +2 -3
  2. package/styles/v2/components/FormControl/FormControl.jsx +20 -2
  3. package/styles/v2/components/Radio/Radio.jsx +50 -0
  4. package/styles/v2/components/Radio/Radio.stories.js +155 -0
  5. package/styles/v2/components/Radio/RadioGroup.jsx +69 -0
  6. package/styles/v2/components/Radio/styles/index.js +52 -0
  7. package/styles/v2/components/index.js +1 -0
  8. package/styles/v2/components/styles.js +1 -0
  9. package/v2/index.js +1 -1
  10. package/v2/index.js.map +1 -1
  11. package/styles/Alert/Alert.jsx +0 -45
  12. package/styles/Alert/Alert.spec.js +0 -85
  13. package/styles/AutoSuggestInput/AutoSuggestInput.jsx +0 -429
  14. package/styles/AutoSuggestInput/AutoSuggestInput.spec.js +0 -132
  15. package/styles/AutoSuggestInput/AutoSuggestItem.jsx +0 -61
  16. package/styles/AutoSuggestInput/AutoSuggestList.jsx +0 -85
  17. package/styles/Badge/Badge.jsx +0 -24
  18. package/styles/Badge/Badge.spec.js +0 -43
  19. package/styles/Chart/Chart.jsx +0 -185
  20. package/styles/Chart/Chart.spec.js +0 -369
  21. package/styles/Checkbox/Checkbox.jsx +0 -159
  22. package/styles/Checkbox/Checkbox.spec.js +0 -142
  23. package/styles/DateTime/DatePicker.jsx +0 -281
  24. package/styles/DateTime/DatePicker.spec.js +0 -186
  25. package/styles/DateTime/DatePickerCalendar.jsx +0 -170
  26. package/styles/DateTime/DatePickerCalendarNavigation.jsx +0 -44
  27. package/styles/DateTime/DatePickerCalendarWithRange.jsx +0 -218
  28. package/styles/DateTime/DateTimePicker.jsx +0 -266
  29. package/styles/DateTime/DateTimePicker.spec.js +0 -60
  30. package/styles/DateTime/DateTimeRangePicker.jsx +0 -629
  31. package/styles/DateTime/DateTimeRangePicker.spec.js +0 -425
  32. package/styles/DateTime/TimePicker.jsx +0 -158
  33. package/styles/DateTime/TimePicker.spec.js +0 -148
  34. package/styles/DateTime/date-time-assertions.js +0 -89
  35. package/styles/DateTime/index.js +0 -6
  36. package/styles/ErrorBoundary/ErrorBoundary.jsx +0 -76
  37. package/styles/ErrorBoundary/ErrorBoundary.spec.js +0 -72
  38. package/styles/Flyout/Flyout.jsx +0 -147
  39. package/styles/Flyout/Flyout.spec.js +0 -117
  40. package/styles/Form/Form.jsx +0 -151
  41. package/styles/Form/Form.spec.js +0 -148
  42. package/styles/Form/FormElementError.jsx +0 -18
  43. package/styles/Form/FormGroup.jsx +0 -32
  44. package/styles/Form/FormGroupError.jsx +0 -24
  45. package/styles/Form/index.js +0 -4
  46. package/styles/GooglePlacesSearchInput/GooglePlacesSearchInput.jsx +0 -215
  47. package/styles/GooglePlacesSearchInput/GooglePlacesSearchInput.spec.js +0 -213
  48. package/styles/GooglePlacesSearchInput/PoweredByGoogle.jsx +0 -43
  49. package/styles/GooglePlacesSearchInput/index.js +0 -2
  50. package/styles/HorizontalRule/HorizontalRule.jsx +0 -36
  51. package/styles/HorizontalRule/HorizontalRule.spec.js +0 -94
  52. package/styles/Label/Label.jsx +0 -22
  53. package/styles/Label/Label.spec.js +0 -11
  54. package/styles/Notification/Notification.jsx +0 -117
  55. package/styles/Notification/Notification.spec.js +0 -154
  56. package/styles/Notification/NotificationContainer.jsx +0 -90
  57. package/styles/Notification/NotificationPropTypes.js +0 -20
  58. package/styles/Notification/index.js +0 -2
  59. package/styles/PasswordControl/PasswordControl.jsx +0 -197
  60. package/styles/PasswordControl/PasswordControl.spec.js +0 -236
  61. package/styles/Portal/Portal.jsx +0 -65
  62. package/styles/Portal/Portal.spec.js +0 -45
  63. package/styles/PulseLoader/PulseLoader.jsx +0 -71
  64. package/styles/PulseLoader/PulseLoader.spec.js +0 -63
  65. package/styles/Radio/Radio.jsx +0 -114
  66. package/styles/Radio/Radio.spec.js +0 -128
  67. package/styles/Radio/RadioGroup.jsx +0 -105
  68. package/styles/RenderInBody/RenderInBody.jsx +0 -56
  69. package/styles/RenderInBody/RenderInBody.spec.js +0 -24
  70. package/styles/Select/Select.jsx +0 -251
  71. package/styles/Select/Select.spec.js +0 -254
  72. package/styles/Select/SelectItemPropTypes.js +0 -19
  73. package/styles/Select/index.js +0 -2
  74. package/styles/SelectControlled/SelectControlled.jsx +0 -250
  75. package/styles/SelectControlled/SelectControlled.spec.js +0 -290
  76. package/styles/SelectControlled/index.js +0 -1
  77. package/styles/Sprite/Sprite.jsx +0 -16
  78. package/styles/Sprite/Sprite.spec.js +0 -11
  79. package/styles/Tabs/Tab.jsx +0 -38
  80. package/styles/Tabs/TabContent.jsx +0 -46
  81. package/styles/Tabs/TabNavigation.jsx +0 -64
  82. package/styles/Tabs/TabPanel.jsx +0 -30
  83. package/styles/Tabs/Tabs.jsx +0 -87
  84. package/styles/Tabs/Tabs.spec.js +0 -201
  85. package/styles/Tabs/index.js +0 -5
  86. package/styles/TextArea/TextArea.jsx +0 -137
  87. package/styles/TextArea/TextArea.spec.js +0 -111
  88. package/styles/TextInput/TextInput.jsx +0 -159
  89. package/styles/TextInput/TextInput.spec.js +0 -263
  90. package/styles/TextInput/TextInputPropTypes.js +0 -88
  91. package/styles/TextInput/index.js +0 -2
  92. package/styles/Tooltip/Tooltip.jsx +0 -230
  93. package/styles/Tooltip/Tooltip.spec.js +0 -170
  94. /package/styles/{Radio → v2/components/Radio}/index.js +0 -0
@@ -1,290 +0,0 @@
1
- describe('<SelectControlled />', () => {
2
- context('Display', () => {
3
- context('Default', () => {
4
- it('Renders select and options', () => {
5
- cy.visitStory('v1/SelectControlled/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/SelectControlled/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/SelectControlled/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/SelectControlled/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/SelectControlled/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/SelectControlled/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/SelectControlled/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/SelectControlled/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('With Value', () => {
156
- it('Renders with specified value selected', () => {
157
- cy.visitStory('v1/SelectControlled/Display', 'WithValue')
158
- .get('option:selected')
159
- .contains('Option 2')
160
- .should('have.value', 'Option 2');
161
- });
162
-
163
- it('Changes specified value', () => {
164
- cy.visitStory('v1/SelectControlled/Display', 'WithValue')
165
- .get('select')
166
- .select('Option 4')
167
- .get('option:selected')
168
- .contains('Option 4')
169
- .should('have.value', 'Option 4');
170
- });
171
- });
172
- });
173
-
174
- context('Methods', () => {
175
- context('OnChange', () => {
176
- it('OnChange method functions properly', () => {
177
- cy.visitStory('v1/SelectControlled/Methods', 'OnChange', {
178
- onBeforeLoad: contentWindow => {
179
- contentWindow.onSelectChange = ({label, value}) => {
180
- console.log('onSelectChange'); // eslint-disable-line no-console
181
- };
182
-
183
- cy.stub(contentWindow, 'onSelectChange').as(
184
- 'selectChange'
185
- );
186
- },
187
- })
188
- // fill form
189
- .get('.Select')
190
- .as('item')
191
- .selectItem({alias: 'item', value: 'Option 2'})
192
- // calls the onChange method
193
- .get('@selectChange')
194
- .should('be.calledWith', {
195
- label: 'Option 2',
196
- value: 'Option 2',
197
- });
198
- });
199
-
200
- context('With Value', () => {
201
- it('OnChange method functions properly', () => {
202
- cy.visitStory('v1/SelectControlled/Display', 'WithValue', {
203
- onBeforeLoad: contentWindow => {
204
- contentWindow.onSelectChange = ({label, value}) => {
205
- console.log('onSelectChange'); // eslint-disable-line no-console
206
- };
207
-
208
- cy.stub(contentWindow, 'onSelectChange').as(
209
- 'selectChange'
210
- );
211
- },
212
- })
213
- // fill form
214
- .get('.Select')
215
- .as('item')
216
- .selectItem({alias: 'item', value: 'Option 2'})
217
- // calls the onChange method
218
- .get('@selectChange')
219
- .should('be.calledWith', {
220
- label: 'Option 2',
221
- value: 'Option 2',
222
- });
223
- });
224
- });
225
- });
226
-
227
- context('OnFocus', () => {
228
- it('OnFocus method functions properly', () => {
229
- cy.visitStory('v1/SelectControlled/Methods', 'OnFocus', {
230
- onBeforeLoad: contentWindow => {
231
- contentWindow.onSelectFocus = evt => {
232
- console.log('onSelectFocus'); // eslint-disable-line no-console
233
- };
234
-
235
- cy.stub(contentWindow, 'onSelectFocus').as(
236
- 'selectFocus'
237
- );
238
- },
239
- })
240
- // fill form
241
- .get('.Select')
242
- .as('item')
243
- .selectItem({alias: 'item', value: 'Option 2'})
244
- // calls the onFocus method
245
- .get('@selectFocus')
246
- .should('be.called');
247
- });
248
- });
249
-
250
- context('OnInvalid', () => {
251
- it('OnInvalid method functions properly and form is submitted when valid', () => {
252
- cy.visitStory('v1/SelectControlled/Methods', 'OnInvalid', {
253
- onBeforeLoad: contentWindow => {
254
- contentWindow.onSelectFormSubmit = evt => {
255
- console.log('onSelectFormSubmit'); // eslint-disable-line no-console
256
- };
257
-
258
- contentWindow.onSelectInvalid = validationState => {
259
- console.log('onSelectInvalid'); // eslint-disable-line no-console
260
- };
261
-
262
- cy.stub(contentWindow, 'onSelectFormSubmit').as(
263
- 'selectFormSubmit'
264
- );
265
-
266
- cy.stub(contentWindow, 'onSelectInvalid').as(
267
- 'selectInvalid'
268
- );
269
- },
270
- })
271
- .get('.SelectMethods-submit')
272
- .click()
273
- // check validity
274
- .get('@selectInvalid')
275
- .should('be.called')
276
- // fill form
277
- .get('.Select')
278
- .as('item')
279
- .selectItem({alias: 'item', value: 'Option 2'})
280
- // submit after item is selected
281
- .get('.SelectMethods-submit')
282
- .click()
283
- .get('@selectFormSubmit')
284
- .should('be.calledWith', {
285
- select: 'Option 2',
286
- });
287
- });
288
- });
289
- });
290
- });
@@ -1 +0,0 @@
1
- export {default as SelectControlled} from './SelectControlled';
@@ -1,16 +0,0 @@
1
- import React from 'react';
2
- import PropTypes from 'prop-types';
3
- import classNames from 'classnames';
4
-
5
- const Sprite = ({className, name}) => {
6
- const classes = classNames('Sprite', `sprite-${name}`, className);
7
-
8
- return <i className={classes} />;
9
- };
10
-
11
- Sprite.propTypes = {
12
- className: PropTypes.string,
13
- name: PropTypes.string.isRequired,
14
- };
15
-
16
- export default Sprite;
@@ -1,11 +0,0 @@
1
- describe('<Sprite />', () => {
2
- context('Display', () => {
3
- context('Name', () => {
4
- it('Renders properly', () => {
5
- cy.visitStory('v1/Sprite/Display', 'Default')
6
- .get('.Sprite')
7
- .should('have.class', 'sprite-test');
8
- });
9
- });
10
- });
11
- });
@@ -1,38 +0,0 @@
1
- import React, {Component} from 'react';
2
- import PropTypes from 'prop-types';
3
- import classNames from 'classnames';
4
- import Button from 'v1/components/Button/Button';
5
-
6
- export default class Tab extends Component {
7
- static propTypes = {
8
- /** Additional class(es) to add to the component. */
9
- className: PropTypes.string,
10
- /** The content to render inside of the tab. */
11
- children: PropTypes.node.isRequired,
12
- /** The label to put in the dropdown when the tabs are on small viewports. Not used in this component but gets read in TabNavigation to create the dropdown. */
13
- label: PropTypes.string.isRequired, // eslint-disable-line react/no-unused-prop-types
14
- /** Whether this tab should be active. Automatically passed from TabNavigation, do not set manually. */
15
- active: PropTypes.bool,
16
- /** The method to call when this tab is clicked. Automatically passed from TabNavigation, do not set manually. */
17
- onTabClick: PropTypes.func,
18
- /** The index that corresponds to this tab. Automatically passed from TabNavigation, do not set manually. */
19
- index: PropTypes.number,
20
- };
21
-
22
- _onClick = evt => {
23
- const {index, onTabClick} = this.props;
24
-
25
- onTabClick(index);
26
- };
27
-
28
- render() {
29
- const {className, children, active} = this.props;
30
- const classes = classNames('Tab', {'Tab-active': active}, className);
31
-
32
- return (
33
- <Button className={classes} role="tab" onClick={this._onClick}>
34
- {children}
35
- </Button>
36
- );
37
- }
38
- }
@@ -1,46 +0,0 @@
1
- import React, {Children, cloneElement} from 'react';
2
- import PropTypes from 'prop-types';
3
- import classNames from 'classnames';
4
-
5
- const TabContent = ({className, children, selectedIndex, renderActiveOnly}) => {
6
- const classes = classNames('TabContent', className);
7
-
8
- return (
9
- <div className={classes}>
10
- {Children.map(children, (panel, i) => {
11
- if (panel) {
12
- if (renderActiveOnly) {
13
- if (selectedIndex === i) {
14
- return cloneElement(panel, {
15
- active: true,
16
- index: i,
17
- });
18
- } else {
19
- return null;
20
- }
21
- } else {
22
- return cloneElement(panel, {
23
- active: selectedIndex === i,
24
- index: i,
25
- });
26
- }
27
- }
28
- })}
29
- </div>
30
- );
31
- };
32
-
33
- TabContent.propTypes = {
34
- /** Additional class(es) to add to the component. */
35
- className: PropTypes.string,
36
- /** Children should only be made up of TabPanel components or a false boolean value when a condition to render the TabPanel is false. */
37
- children: PropTypes.arrayOf(
38
- PropTypes.oneOfType([PropTypes.element, PropTypes.bool])
39
- ).isRequired,
40
- /** The selected tab index. Automatically passed from Tabs, do not set manually. */
41
- selectedIndex: PropTypes.number,
42
- /** Whether to only render the active tab's content or all content for every tab in the DOM. */
43
- renderActiveOnly: PropTypes.bool,
44
- };
45
-
46
- export default TabContent;
@@ -1,64 +0,0 @@
1
- import React, {PureComponent, Children, cloneElement} from 'react';
2
- import PropTypes from 'prop-types';
3
- import classNames from 'classnames';
4
- import Select from '../Select/Select';
5
-
6
- export default class TabNavigation extends PureComponent {
7
- static propTypes = {
8
- /** Additional class(es) to add to the component. */
9
- className: PropTypes.string,
10
- /** Children should only be made up of Tab components or a false boolean value when a condition to render the Tab is false. */
11
- children: PropTypes.arrayOf(
12
- PropTypes.oneOfType([PropTypes.element, PropTypes.bool])
13
- ).isRequired,
14
- /** The selected tab index. Automatically passed from Tabs, do not set manually. */
15
- selectedIndex: PropTypes.number,
16
- /** The method to call when a tab is clicked. Automatically passed from Tabs, do not set manually. */
17
- onTabClick: PropTypes.func,
18
- };
19
-
20
- constructor(props) {
21
- super(props);
22
-
23
- this._selectItems = Children.map(props.children, (tab, i) => {
24
- if (tab) {
25
- return {
26
- label: tab.props.label,
27
- value: i.toString(),
28
- };
29
- }
30
- });
31
- }
32
-
33
- _onSelectChange = ({value}) => {
34
- this.props.onTabClick(parseInt(value, 10));
35
- };
36
-
37
- render() {
38
- const {className, children, selectedIndex, onTabClick} = this.props;
39
- const classes = classNames('TabNavigation', className);
40
-
41
- return (
42
- <div className={classes} role="tablist">
43
- <div className="TabNavigation-links">
44
- {Children.map(children, (tab, i) => {
45
- if (tab) {
46
- return cloneElement(tab, {
47
- active: selectedIndex === i,
48
- index: i,
49
- onTabClick,
50
- });
51
- }
52
- })}
53
- </div>
54
- <Select
55
- key={new Date()}
56
- className="TabNavigation-select"
57
- defaultValue={selectedIndex.toString()}
58
- items={this._selectItems}
59
- onChange={this._onSelectChange}
60
- />
61
- </div>
62
- );
63
- }
64
- }
@@ -1,30 +0,0 @@
1
- import React from 'react';
2
- import PropTypes from 'prop-types';
3
- import classNames from 'classnames';
4
-
5
- const TabPanel = ({className, children, index, active}) => {
6
- const classes = classNames(
7
- 'TabPanel',
8
- {'TabPanel-active': active},
9
- className
10
- );
11
-
12
- return (
13
- <div className={classes} role="tabpanel">
14
- {children}
15
- </div>
16
- );
17
- };
18
-
19
- TabPanel.propTypes = {
20
- /** Additional class(es) to add to the component. */
21
- className: PropTypes.string,
22
- /** The content to render inside of the tab. */
23
- children: PropTypes.node.isRequired,
24
- /** Whether this panel should be active. Automatically passed from TabContent, do not set manually. */
25
- active: PropTypes.bool,
26
- /** The index that corresponds to this panel. Automatically passed from TabContainer, do not set manually. */
27
- index: PropTypes.number,
28
- };
29
-
30
- export default TabPanel;
@@ -1,87 +0,0 @@
1
- import React, {Children, Component, cloneElement} from 'react';
2
- import PropTypes from 'prop-types';
3
- import classNames from 'classnames';
4
-
5
- export default class Tabs extends Component {
6
- static propTypes = {
7
- /** Additional class(es) to add to the component. */
8
- className: PropTypes.string,
9
- /** The index of the selected tab, 0 based. */
10
- selectedIndex: PropTypes.number,
11
- /**
12
- * A function to execute when a tab is selected.
13
- *
14
- * @param {Number} selectedIndex - The currently selected tab index.
15
- */
16
- onSelect: PropTypes.func,
17
- /** Children should only be made up of TabNavigation (with nested Tab) and TabContent (with nested TabPanel) components. The number of nested components for each should be equal to each other. */
18
- children: PropTypes.arrayOf(PropTypes.element).isRequired,
19
- };
20
- static defaultProps = {
21
- selectedIndex: 0,
22
- };
23
- state = {
24
- selectedIndex: this.props.selectedIndex,
25
- };
26
-
27
- constructor(props) {
28
- super(props);
29
-
30
- const {numTabs, numPanels} = this._getNumItems();
31
-
32
- if (numTabs !== numPanels) {
33
- throw new Error(
34
- 'The number of Tab components must correspond to the number of TabPanel components provided.'
35
- );
36
- }
37
- }
38
-
39
- componentDidUpdate(prevProps, prevState) {
40
- const {onSelect} = this.props;
41
- const {selectedIndex} = this.state;
42
-
43
- if (prevState.selectedIndex !== selectedIndex && onSelect) {
44
- onSelect(selectedIndex);
45
- }
46
- }
47
-
48
- _getNumItems() {
49
- const {children} = this.props;
50
-
51
- return {
52
- numTabs: Children.count(children[0].props.children),
53
- numPanels: Children.count(children[1].props.children),
54
- };
55
- }
56
-
57
- _selectTab = index => {
58
- this.setState({
59
- selectedIndex: index,
60
- });
61
- };
62
-
63
- _renderNavigation(nav) {
64
- return cloneElement(nav, {
65
- selectedIndex: this.state.selectedIndex,
66
- onTabClick: this._selectTab,
67
- });
68
- }
69
-
70
- _renderContent(content) {
71
- return cloneElement(content, {
72
- selectedIndex: this.state.selectedIndex,
73
- });
74
- }
75
-
76
- render() {
77
- const {className, children} = this.props;
78
- const classes = classNames('Tabs', className);
79
-
80
- return (
81
- <div className={classes}>
82
- {this._renderNavigation(children[0])}
83
- {this._renderContent(children[1])}
84
- </div>
85
- );
86
- }
87
- }