@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,263 +0,0 @@
1
- describe('<TextInput />', () => {
2
- context('Display', () => {
3
- context('Default', () => {
4
- it('Should have placeholder, default value, label, help text, and custom class names', () => {
5
- cy.visitStory('v1/TextInput/Display', 'Default')
6
- .get('.TextInput')
7
- .should('exist')
8
- .and('have.class', 'custom-class1')
9
- .and('have.class', 'custom-class2')
10
- .find('input')
11
- .should('have.attr', 'name', 'license-plate')
12
- .and('have.attr', 'placeholder', 'License Plate')
13
- .and('have.value', 'ECTO-1')
14
- .get('.TextInput')
15
- .find('.Label')
16
- .contains('Add new license plate')
17
- .get('.TextInput')
18
- .find('.FormElement-help-text')
19
- .contains('Additional help node text');
20
- });
21
- });
22
-
23
- context('Disabled', () => {
24
- it('Is disabled', () => {
25
- cy.visitStory('v1/TextInput/Display', 'Disabled')
26
- .get('.TextInput')
27
- .find('input')
28
- .should('be.disabled');
29
- });
30
- });
31
-
32
- context('Read Only', () => {
33
- it('Is read only', () => {
34
- cy.visitStory('v1/TextInput/Display', 'ReadOnly')
35
- .get('.TextInput')
36
- .find('input')
37
- .should('have.attr', 'readonly');
38
- });
39
- });
40
-
41
- context('Icon', () => {
42
- it('Should render with an icon', () => {
43
- cy.visitStory('v1/TextInput/Display', 'Icon')
44
- .get('.TextInput')
45
- .should('have.class', 'FormElement-with-icon-right')
46
- .find('.Icon')
47
- .should('exist');
48
- });
49
- });
50
-
51
- context('Loading', () => {
52
- it('Should render with a loading spinner', () => {
53
- cy.visitStory('v1/TextInput/Display', 'Loading')
54
- .get('.TextInput')
55
- .find('.Loader')
56
- .should('exist');
57
- });
58
- });
59
-
60
- context('Inline', () => {
61
- it('Should render with inline styling', () => {
62
- cy.visitStory('v1/TextInput/Display', 'Inline')
63
- .get('.TextInput')
64
- .should('have.class', 'FormElement-inline');
65
- });
66
- });
67
-
68
- context('Auto Focus', () => {
69
- it('Receives focus after rendered', () => {
70
- cy.visitStory('v1/TextInput/Display', 'AutoFocus')
71
- .focused()
72
- .should('have.attr', 'name', 'license-plate');
73
- });
74
- });
75
- });
76
-
77
- context('Formatting', () => {
78
- describe('Mask', () => {
79
- it('Applies a mask over the input text', () => {
80
- cy.visitStory('v1/TextInput/Formatting', 'Mask')
81
- .get('.TextInput')
82
- .find('input')
83
- .click()
84
- .should('have.value', '+X-XXX-XXX-XXXX')
85
- .type('12345678899', {delay: 0})
86
- .blur()
87
- .should('have.value', '+1-234-567-8899');
88
- });
89
- });
90
-
91
- describe('Pattern', () => {
92
- it('Has pattern attribute and ensures the input text follows the specified regex pattern', () => {
93
- cy.visitStory('v1/TextInput/Formatting', 'Pattern')
94
- .get('.TextInput')
95
- .find('input')
96
- .should('have.attr', 'pattern', '[A-Za-z0-9]+')
97
- // should show error since value does not follow pattern
98
- .type('OÜTAT!M&', {delay: 0})
99
- .get('button[type=submit]')
100
- .click()
101
- .get('.TextInput')
102
- .find('.FormElementError')
103
- .should('exist')
104
- // should not show error since value follows pattern
105
- .get('.TextInput')
106
- .find('input')
107
- .clear()
108
- .type('oUtAT1M3', {delay: 0})
109
- .get('button[type=submit]')
110
- .click()
111
- .get('.TextInput')
112
- .find('.FormElementError')
113
- .should('not.exist');
114
- });
115
- });
116
-
117
- context('Max Length', () => {
118
- it('Has maxlength attribute and does not allow more characters', () => {
119
- // longstring is 53 characters long
120
- const longstring =
121
- 'myusernamemyusernamemyusernamemyusernamemyusernameabc';
122
-
123
- cy.visitStory('v1/TextInput/Formatting', 'MaxLength')
124
- .get('.TextInput')
125
- .find('input')
126
- .should('have.attr', 'maxlength', '50')
127
- .type(longstring, {delay: 0})
128
- .should('have.value', longstring.substring(0, 50));
129
- });
130
- });
131
-
132
- context('Min Max', () => {
133
- it('Has min and max attributes and does not consider input outside that range valid', () => {
134
- cy.visitStory('v1/TextInput/Formatting', 'MinMax')
135
- .get('.TextInput')
136
- .find('input')
137
- .should('have.attr', 'min', '1')
138
- .should('have.attr', 'max', '100')
139
- // should show error since value is below min
140
- .type('0', {delay: 0})
141
- .get('button[type=submit]')
142
- .click()
143
- .get('.TextInput')
144
- .find('.FormElementError')
145
- .should('exist')
146
- // should not show error since value is in range
147
- .get('.TextInput')
148
- .find('input')
149
- .clear()
150
- .type('42', {delay: 0})
151
- .get('button[type=submit]')
152
- .click()
153
- .get('.TextInput')
154
- .find('.FormElementError')
155
- .should('not.exist')
156
- // should show error since value is above max
157
- .get('.TextInput')
158
- .find('input')
159
- .clear()
160
- .type('4200', {delay: 0})
161
- .get('button[type=submit]')
162
- .click()
163
- .get('.TextInput')
164
- .find('.FormElementError')
165
- .should('exist');
166
- });
167
- });
168
- });
169
-
170
- context('Methods', () => {
171
- describe('On Change', () => {
172
- it('Executes the method when a change is detected', () => {
173
- cy.visitStory('v1/TextInput/Methods', 'OnChange', {
174
- onBeforeLoad: contentWindow => {
175
- contentWindow.onTextInputChange = evt => {
176
- console.log(`onTextInputChange`); // eslint-disable-line no-console
177
- };
178
-
179
- cy.stub(contentWindow, 'onTextInputChange').as(
180
- 'onTextInputChange'
181
- );
182
- },
183
- })
184
- .get('.TextInput')
185
- .find('input')
186
- .type('OUTATIME', {delay: 0})
187
- .get('@onTextInputChange')
188
- .should('be.called');
189
- });
190
- });
191
-
192
- describe('On Focus', () => {
193
- it('Executes the method when input is focused on', () => {
194
- cy.visitStory('v1/TextInput/Methods', 'OnFocus', {
195
- onBeforeLoad: contentWindow => {
196
- contentWindow.onTextInputFocus = evt => {
197
- console.log(`onTextInputFocus`); // eslint-disable-line no-console
198
- };
199
-
200
- cy.stub(contentWindow, 'onTextInputFocus').as(
201
- 'onTextInputFocus'
202
- );
203
- },
204
- })
205
- .get('.TextInput')
206
- .find('input')
207
- .focus()
208
- .get('@onTextInputFocus')
209
- .should('be.called');
210
- });
211
- });
212
-
213
- describe('On Blur', () => {
214
- it('Executes the method when input loses focus', () => {
215
- cy.visitStory('v1/TextInput/Methods', 'OnBlur', {
216
- onBeforeLoad: contentWindow => {
217
- contentWindow.onTextInputBlur = evt => {
218
- console.log(`onTextInputBlur`); // eslint-disable-line no-console
219
- };
220
-
221
- cy.stub(contentWindow, 'onTextInputBlur').as(
222
- 'onTextInputBlur'
223
- );
224
- },
225
- })
226
- .get('.TextInput')
227
- .find('input')
228
- .focus()
229
- .get('@onTextInputBlur')
230
- .should('not.be.called')
231
- .get('.TextInput')
232
- .find('input')
233
- .blur()
234
- .get('@onTextInputBlur')
235
- .should('be.called');
236
- });
237
- });
238
-
239
- describe('On Invalid', () => {
240
- it('Displays an error if the input is invalid', () => {
241
- cy.visitStory('v1/TextInput/Methods', 'OnInvalid')
242
- .get('.TextInput')
243
- .find('input')
244
- // Show error on empty field since this is required
245
- .should('have.value', '')
246
- .get('button[type=submit]')
247
- .click()
248
- .get('.TextInput')
249
- .find('.FormElementError')
250
- .should('exist')
251
- // Don't show error on field with content
252
- .get('.TextInput')
253
- .find('input')
254
- .type('MY PRSHE', {delay: 0})
255
- .get('button[type=submit]')
256
- .click()
257
- .get('.TextInput')
258
- .find('.FormElementError')
259
- .should('not.exist');
260
- });
261
- });
262
- });
263
- });
@@ -1,88 +0,0 @@
1
- import PropTypes from 'prop-types';
2
-
3
- const TextInputPropTypes = {
4
- /** Additional class(es) to add to the component. */
5
- className: PropTypes.string,
6
- /** 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. */
7
- name: PropTypes.string,
8
- /** What HTML input type the underlying input should be set to. */
9
- type: PropTypes.oneOf([
10
- 'text',
11
- 'password',
12
- 'date',
13
- 'email',
14
- 'time',
15
- 'tel',
16
- 'search',
17
- 'number',
18
- 'hidden',
19
- ]),
20
- /** Text to display in the field before a user starts to type in the input. */
21
- placeholder: PropTypes.string,
22
- /** A custom label (typically a Label component) to display above the input. */
23
- label: PropTypes.element,
24
- /** A regular expression that the input value is checked against for validation. */
25
- pattern: PropTypes.string,
26
- /** Whether this field is required during validation. */
27
- required: PropTypes.bool,
28
- /** Disallows user interaction. */
29
- disabled: PropTypes.bool,
30
- /** Whether to show a loading animation inside of the component. */
31
- loading: PropTypes.bool,
32
- /** Whether the field should be auto focused when mounted. */
33
- autoFocus: PropTypes.bool,
34
- /** Whether the field should be focused when the component receives new props. */
35
- focus: PropTypes.bool,
36
- /** A custom validation error (typically a FormElementError component) to display when this component is part of a form and is invalid. */
37
- error: PropTypes.element,
38
- /** The default value to display in the input when mounted. */
39
- defaultValue: PropTypes.string,
40
- /** A custom icon (typically an Icon component) to show in the input field. */
41
- icon: PropTypes.element,
42
- /** If an icon is provided, whether it should appear on the left or right side of the input field. */
43
- iconPosition: PropTypes.oneOf(['left', 'right']),
44
- /** A custom help element to place below the input. */
45
- helpNode: PropTypes.node,
46
- /** Applies proper styling to display this field inline in a form. */
47
- inline: PropTypes.bool,
48
- /** Specifies that the input field is read-only. */
49
- readOnly: PropTypes.bool,
50
- /** Specifies the maximum number of characters allowed. */
51
- maxLength: PropTypes.number,
52
- /** Specifies the minimum value when type is `date` or `number`. */
53
- min: PropTypes.number,
54
- /** Specifies the maximum value when type is `date` or `number`. */
55
- max: PropTypes.number,
56
- /** A string to use as a mask. See <a href="https://github.com/sanniassin/react-input-mask#mask--string" target="_blank">react-input-mask</a>. */
57
- mask: PropTypes.string,
58
- /** Character to cover unfilled editable parts of mask. See <a href="https://github.com/sanniassin/react-input-mask#maskchar--string" target="_blank">react-input-mask</a>. */
59
- maskChar: PropTypes.string,
60
- /** Additional props to pass to the input element */
61
- additionalInputProps: PropTypes.object,
62
- /**
63
- * Function to execute when the input changes.
64
- *
65
- * @param {SyntheticEvent} evt - The React `SyntheticEvent`.
66
- */
67
- onChange: PropTypes.func,
68
- /**
69
- * Function to execute when the input is focused.
70
- *
71
- * @param {SyntheticEvent} evt - The React `SyntheticEvent`.
72
- */
73
- onFocus: PropTypes.func,
74
- /**
75
- * Function to execute when the input loses focused.
76
- *
77
- * @param {SyntheticEvent} evt - The React `SyntheticEvent`.
78
- */
79
- onBlur: PropTypes.func,
80
- /**
81
- * Function to execute when the element is marked as invalid by a validation check.
82
- *
83
- * @param {ValidityState} validationState - ValidityState object for more fine grained control over error handling in a parent component if desired.
84
- */
85
- onInvalid: PropTypes.func,
86
- };
87
-
88
- export default TextInputPropTypes;
@@ -1,2 +0,0 @@
1
- export {default as TextInput} from './TextInput';
2
- export {default as TextInputPropTypes} from './TextInputPropTypes';
@@ -1,230 +0,0 @@
1
- import bind from 'lodash/bind';
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 Tooltip extends Component {
11
- static propTypes = {
12
- /** Additional class(es) to add to the component. */
13
- className: PropTypes.string,
14
- /** Additional class(es) to add to the containing Portal component. */
15
- containerClassName: PropTypes.string,
16
- /** The markup node to insert into the tooltip. */
17
- children: PropTypes.node.isRequired,
18
- /** Where to position the tooltip in relation to the triggering element. */
19
- position: PropTypes.oneOf(['top', 'right', 'bottom', 'left']),
20
- /** Whether to show the close button or not. */
21
- showClose: PropTypes.bool,
22
- /** The selector (.foo, #foo, etc...) for the element to attach the tooltip to. */
23
- triggerSelector: PropTypes.string.isRequired,
24
- /** Whether to reposition the tooltip when it moves, be it via window resize or scrolling or whatever moves it. */
25
- updateOnMove: PropTypes.bool,
26
- /** The offset of the tooltip from the triggering element. This is based on what the position is set to (`top` offsets up, etc). */
27
- tipOffset: PropTypes.number,
28
- /** Whether to automatically adjust the tooltip if its off the left or right side of the screen. */
29
- adjustArrow: PropTypes.bool,
30
- /** Whether to close the tooltip if the body outside of it is clicked. */
31
- closeOnBodyClick: PropTypes.bool,
32
- /** A function to execute after the tooltip has been hidden. Use this to manage state in a parent component to remove the tooltip from the DOM (see examples). */
33
- onHidden: PropTypes.func.isRequired,
34
- };
35
- static defaultProps = {
36
- position: 'top',
37
- showClose: true,
38
- tipOffset: 0,
39
- adjustArrow: true,
40
- };
41
-
42
- constructor(props) {
43
- super(props);
44
-
45
- this._isArrowAdjusted = false;
46
- }
47
-
48
- componentDidMount() {
49
- const {triggerSelector, updateOnMove, closeOnBodyClick} = this.props;
50
-
51
- this._trigger = DOMUtils.el(triggerSelector);
52
- this._positionTooltip();
53
-
54
- DOMUtils.addClass(this._container, 'Tooltip-showing');
55
-
56
- if (updateOnMove) {
57
- this._container.style.position = 'fixed';
58
-
59
- this._scrollInterval = setInterval(
60
- bind(this._positionTooltip, this),
61
- 100
62
- );
63
- }
64
-
65
- if (closeOnBodyClick) {
66
- document.addEventListener('click', this._onCloseClick, {
67
- capture: true,
68
- });
69
- }
70
- }
71
-
72
- componentWillUnmount() {
73
- const {updateOnMove, closeOnBodyClick} = this.props;
74
-
75
- if (updateOnMove) {
76
- clearInterval(this._scrollInterval);
77
- }
78
-
79
- if (closeOnBodyClick) {
80
- document.removeEventListener('click', this._onCloseClick);
81
- }
82
- }
83
-
84
- _onCloseClick = evt => {
85
- this.hide();
86
- };
87
-
88
- _positionTooltip() {
89
- if (!this._trigger) {
90
- return;
91
- }
92
-
93
- const {position, tipOffset, updateOnMove, adjustArrow} = this.props;
94
- const {
95
- top: clientTop,
96
- left: clientLeft,
97
- right: clientRight,
98
- bottom: clientBottom,
99
- width,
100
- height,
101
- } = this._trigger.getBoundingClientRect();
102
- const tooltipWidth = this._container.offsetWidth;
103
- const tooltipHeight = this._container.offsetHeight;
104
- const {
105
- top: documentTop,
106
- left: documentLeft,
107
- } = DOMUtils.getDocumentOffset(this._trigger);
108
- const top = updateOnMove ? clientTop : documentTop;
109
- const right = updateOnMove ? clientRight : documentLeft + width;
110
- const bottom = updateOnMove ? clientBottom : documentTop + height;
111
- const left = updateOnMove ? clientLeft : documentLeft;
112
- const containerMid =
113
- position === 'top' || position === 'bottom'
114
- ? tooltipWidth / 2
115
- : tooltipHeight / 2;
116
- const bodyWidth = document.body.clientWidth;
117
- const adjuster = 5;
118
- let newTop = 0;
119
- let newLeft = 0;
120
-
121
- switch (position) {
122
- case 'top':
123
- newTop = top - tooltipHeight - tipOffset;
124
- newLeft = left + width / 2 - containerMid;
125
- break;
126
-
127
- case 'right':
128
- newTop = top + height / 2 - containerMid;
129
- newLeft = right + tipOffset;
130
- break;
131
-
132
- case 'bottom':
133
- newTop = bottom + tipOffset;
134
- newLeft = left + width / 2 - containerMid;
135
- break;
136
-
137
- case 'left':
138
- newTop = top + height / 2 - containerMid;
139
- newLeft = left - tooltipWidth - tipOffset;
140
- break;
141
- }
142
-
143
- // adjust tooltip position if off the left side of the screen
144
- let adjustedLeft = newLeft < 0 ? adjuster : newLeft;
145
-
146
- // adjust tooltip position if off the right side of the screen
147
- if (tooltipWidth > bodyWidth - adjustedLeft) {
148
- adjustedLeft = bodyWidth - tooltipWidth - adjuster;
149
- }
150
-
151
- this._container.style.top = `${newTop}px`;
152
- this._container.style.left = `${adjustedLeft}px`;
153
-
154
- if (
155
- adjustArrow &&
156
- !this._isArrowAdjusted &&
157
- adjustedLeft !== newLeft &&
158
- (position === 'top' || position === 'bottom')
159
- ) {
160
- this._arrow.style.left = `${
161
- this._arrow.getBoundingClientRect().left +
162
- (newLeft - adjustedLeft)
163
- }px`;
164
-
165
- this._isArrowAdjusted = true;
166
- }
167
- }
168
-
169
- /**
170
- * Hides the Tooltip programmatically and fires the `onHidden` callback when done.
171
- *
172
- * @public
173
- * @returns {void}
174
- */
175
- hide() {
176
- if (DOMUtils.hasClass(this._container, 'Tooltip-showing')) {
177
- DOMUtils.removeClass(this._container, 'Tooltip-showing');
178
-
179
- setTimeout(() => {
180
- this.props.onHidden();
181
- }, 250);
182
- }
183
- }
184
-
185
- render() {
186
- const {
187
- className,
188
- containerClassName,
189
- position,
190
- showClose,
191
- children,
192
- } = this.props;
193
- const classes = classNames(
194
- 'Tooltip',
195
- `Tooltip-${position}`,
196
- {'Tooltip-no-close': !showClose},
197
- className
198
- );
199
-
200
- return (
201
- <Portal className={containerClassName}>
202
- <div
203
- ref={node => {
204
- this._container = node;
205
- }}
206
- className={classes}
207
- role="tooltip"
208
- >
209
- <div
210
- ref={node => {
211
- this._arrow = node;
212
- }}
213
- className="Tooltip-arrow"
214
- />
215
- <div className="Tooltip-content">
216
- {children}
217
- {showClose && (
218
- <Button
219
- className="Tooltip-close"
220
- onClick={this._onCloseClick}
221
- >
222
- <IconTimes />
223
- </Button>
224
- )}
225
- </div>
226
- </div>
227
- </Portal>
228
- );
229
- }
230
- }