Skip to content

Commit 9844a6c

Browse files
authored
feat: add borderClass prop to allow a custom border class [skip-ci]
feat: add borderClass prop to allow a custom border class
2 parents d99b3e8 + 53792a0 commit 9844a6c

File tree

7 files changed

+67
-44
lines changed

7 files changed

+67
-44
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ Notes:
8080
| delayUpdate | data-delay-update | Number | | `<p data-tip="tooltip" data-delay-update='1000'></p>` or `<ReactTooltip delayUpdate={1000} />` Sets a delay in calling getContent if the tooltip is already shown and you mouse over another target |
8181
| insecure | null | Bool | true, false | Whether to inject the style header into the page dynamically (violates CSP style-src but is a convenient default) |
8282
| border | data-border | Bool | true, false | Add one pixel white border |
83+
| borderClass | data-border-class | String | e.g. custom-border-class | A custom class name to use for the border - enabled by the `border` prop |
8384
| textColor | data-text-color | String | e.g. red | Popup text color |
8485
| backgroundColor | data-background-color | String | e.g. yellow | Popup background color |
8586
| borderColor | data-border-color | String | e.g. green | Popup border color - enabled by the `border` value |

example/src/App.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ export default class App extends Component {
316316
<div className="side">
317317
<a
318318
data-for="custom-color"
319-
data-tip="That is one weird arrow (and a border)!"
319+
data-tip="That is one weird arrow (and a border with custom class name)!"
320320
>
321321
V(^-^)V
322322
</a>
@@ -325,6 +325,7 @@ export default class App extends Component {
325325
className="custom-color"
326326
place="right"
327327
border
328+
borderClass="custom-border-class"
328329
textColor="#5F4B8BFF"
329330
backgroundColor="#E69A8DFF"
330331
borderColor="darkgreen"

react-tooltip.d.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ export interface TooltipProps {
3030
multiline?: boolean;
3131
// Add 1px white border
3232
border?: boolean;
33+
// A custom class name to use for the border
34+
borderClass?: string;
3335
// Popup text color
3436
textColor?: string;
3537
// Popup background color
@@ -74,7 +76,7 @@ export interface TooltipProps {
7476
afterHide?: VoidFunc;
7577
// Callback to override the tooltip position
7678
overridePosition?: (
77-
position: { left: number; top: number; },
79+
position: { left: number; top: number },
7880
currentEvent: Event,
7981
currentTarget: EventTarget,
8082
// node is the ref argument, and the wrapper
@@ -83,8 +85,8 @@ export interface TooltipProps {
8385
place: Place,
8486
desiredPlace: Place,
8587
effect: Effect,
86-
offset: Offset,
87-
) => ({ left: number; top: number; });
88+
offset: Offset
89+
) => { left: number; top: number };
8890
// Manually disable the tooltip behavior
8991
disable?: boolean;
9092
// Hide the tooltip when scrolling;
@@ -94,7 +96,7 @@ export interface TooltipProps {
9496
// default = true
9597
resizeHide?: boolean;
9698
// The tooltip parent component;
97-
// default = 'div'
99+
// default = 'div'
98100
wrapper?: 'div' | 'span';
99101
// Listen to body events vs. individual events
100102
bodyMode?: boolean;
@@ -112,7 +114,7 @@ export interface TooltipProps {
112114
// You can overview demo examples here: https://bddeu.csb.app
113115
export default class ReactTooltip extends React.Component<TooltipProps> {
114116
// static methods
115-
static show: (target: Element) => {};
116-
static hide: (target?: Element) => {};
117-
static rebuild: () => {};
117+
static show: (target: Element) => {};
118+
static hide: (target?: Element) => {};
119+
static rebuild: () => {};
118120
}

src/decorators/bodyMode.js

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44
import { checkStatus } from './customEvent';
55

6-
const makeProxy = e => {
6+
const makeProxy = (e) => {
77
const proxy = {};
88
for (const key in e) {
99
if (typeof e[key] === 'function') {
@@ -15,7 +15,7 @@ const makeProxy = e => {
1515
return proxy;
1616
};
1717

18-
const bodyListener = function(callback, options, e) {
18+
const bodyListener = function (callback, options, e) {
1919
const { respectEffect = false, customEvent = false } = options;
2020
const { id } = this.props;
2121

@@ -54,28 +54,24 @@ const bodyListener = function(callback, options, e) {
5454

5555
const findCustomEvents = (targetArray, dataAttribute) => {
5656
const events = {};
57-
targetArray.forEach(target => {
57+
targetArray.forEach((target) => {
5858
const event = target.getAttribute(dataAttribute);
59-
if (event) event.split(' ').forEach(event => (events[event] = true));
59+
if (event) event.split(' ').forEach((event) => (events[event] = true));
6060
});
6161

6262
return events;
6363
};
6464

6565
const getBody = () => document.getElementsByTagName('body')[0];
6666

67-
export default function(target) {
68-
target.prototype.isBodyMode = function() {
67+
export default function (target) {
68+
target.prototype.isBodyMode = function () {
6969
return !!this.props.bodyMode;
7070
};
7171

72-
target.prototype.bindBodyListener = function(targetArray) {
73-
const {
74-
event,
75-
eventOff,
76-
possibleCustomEvents,
77-
possibleCustomEventsOff
78-
} = this.state;
72+
target.prototype.bindBodyListener = function (targetArray) {
73+
const { event, eventOff, possibleCustomEvents, possibleCustomEventsOff } =
74+
this.state;
7975
const body = getBody();
8076

8177
const customEvents = findCustomEvents(targetArray, 'data-event');
@@ -85,10 +81,10 @@ export default function(target) {
8581
if (eventOff != null) customEventsOff[eventOff] = true;
8682
possibleCustomEvents
8783
.split(' ')
88-
.forEach(event => (customEvents[event] = true));
84+
.forEach((event) => (customEvents[event] = true));
8985
possibleCustomEventsOff
9086
.split(' ')
91-
.forEach(event => (customEventsOff[event] = true));
87+
.forEach((event) => (customEventsOff[event] = true));
9288

9389
this.unbindBodyListener(body);
9490

@@ -104,7 +100,7 @@ export default function(target) {
104100
for (const event in customEvents) {
105101
listeners[event] = bodyListener.bind(
106102
this,
107-
e => {
103+
(e) => {
108104
const targetEventOff =
109105
e.currentTarget.getAttribute('data-event-off') || eventOff;
110106
checkStatus.call(this, targetEventOff, e);
@@ -122,7 +118,7 @@ export default function(target) {
122118
}
123119
};
124120

125-
target.prototype.unbindBodyListener = function(body) {
121+
target.prototype.unbindBodyListener = function (body) {
126122
body = body || getBody();
127123

128124
const listeners = this.bodyModeListeners;

src/index.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class ReactTooltip extends React.Component {
4444
padding: PropTypes.string,
4545
multiline: PropTypes.bool,
4646
border: PropTypes.bool,
47+
borderClass: PropTypes.string,
4748
textColor: PropTypes.string,
4849
backgroundColor: PropTypes.string,
4950
borderColor: PropTypes.string,
@@ -97,6 +98,7 @@ class ReactTooltip extends React.Component {
9798
effect: props.effect || 'float', // float or fixed
9899
show: false,
99100
border: false,
101+
borderClass: 'border',
100102
customColors: {},
101103
offset: {},
102104
padding: props.padding,
@@ -507,6 +509,10 @@ class ReactTooltip extends React.Component {
507509
(target.getAttribute('data-border')
508510
? target.getAttribute('data-border') === 'true'
509511
: self.props.border) || false,
512+
borderClass:
513+
target.getAttribute('data-border-class') ||
514+
self.props.borderClass ||
515+
'border',
510516
extraClass:
511517
target.getAttribute('data-class') ||
512518
self.props.class ||
@@ -791,7 +797,7 @@ class ReactTooltip extends React.Component {
791797
'__react_component_tooltip' +
792798
` ${this.state.uuid}` +
793799
(this.state.show && !disable && !isEmptyTip ? ' show' : '') +
794-
(this.state.border ? ' border' : '') +
800+
(this.state.border ? ' ' + this.state.borderClass : '') +
795801
` place-${this.state.place}` + // top, bottom, left, right
796802
` type-${this.hasCustomColors() ? 'custom' : this.state.type}` + // dark, success, warning, error, info, light, custom
797803
(this.props.delayUpdate ? ' allow_hover' : '') +

src/utils/getPosition.js

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* - `newState` {Object}
1515
* - `position` {Object} {left: {Number}, top: {Number}}
1616
*/
17-
export default function(e, target, node, place, desiredPlace, effect, offset) {
17+
export default function (e, target, node, place, desiredPlace, effect, offset) {
1818
const { width: tipWidth, height: tipHeight } = getDimensions(node);
1919

2020
const { width: targetWidth, height: targetHeight } = getDimensions(target);
@@ -35,19 +35,19 @@ export default function(e, target, node, place, desiredPlace, effect, offset) {
3535
const { parentTop, parentLeft } = getParent(node);
3636

3737
// Get the edge offset of the tooltip
38-
const getTipOffsetLeft = place => {
38+
const getTipOffsetLeft = (place) => {
3939
const offsetX = defaultOffset[place].l;
4040
return mouseX + offsetX + extraOffsetX;
4141
};
42-
const getTipOffsetRight = place => {
42+
const getTipOffsetRight = (place) => {
4343
const offsetX = defaultOffset[place].r;
4444
return mouseX + offsetX + extraOffsetX;
4545
};
46-
const getTipOffsetTop = place => {
46+
const getTipOffsetTop = (place) => {
4747
const offsetY = defaultOffset[place].t;
4848
return mouseY + offsetY + extraOffsetY;
4949
};
50-
const getTipOffsetBottom = place => {
50+
const getTipOffsetBottom = (place) => {
5151
const offsetY = defaultOffset[place].b;
5252
return mouseY + offsetY + extraOffsetY;
5353
};
@@ -66,15 +66,15 @@ export default function(e, target, node, place, desiredPlace, effect, offset) {
6666
// |
6767
// Bottom side
6868
//
69-
const outsideLeft = p => getTipOffsetLeft(p) < 0;
70-
const outsideRight = p => getTipOffsetRight(p) > windowWidth;
71-
const outsideTop = p => getTipOffsetTop(p) < 0;
72-
const outsideBottom = p => getTipOffsetBottom(p) > windowHeight;
69+
const outsideLeft = (p) => getTipOffsetLeft(p) < 0;
70+
const outsideRight = (p) => getTipOffsetRight(p) > windowWidth;
71+
const outsideTop = (p) => getTipOffsetTop(p) < 0;
72+
const outsideBottom = (p) => getTipOffsetBottom(p) > windowHeight;
7373

7474
// Check whether the tooltip with orientation p is completely inside the client window
75-
const outside = p =>
75+
const outside = (p) =>
7676
outsideLeft(p) || outsideRight(p) || outsideTop(p) || outsideBottom(p);
77-
const inside = p => !outside(p);
77+
const inside = (p) => !outside(p);
7878

7979
const placeIsInside = {
8080
top: inside('top'),
@@ -119,7 +119,7 @@ export default function(e, target, node, place, desiredPlace, effect, offset) {
119119
};
120120
}
121121

122-
const getDimensions = node => {
122+
const getDimensions = (node) => {
123123
const { height, width } = node.getBoundingClientRect();
124124
return {
125125
height: parseInt(height, 10),
@@ -132,9 +132,8 @@ const getCurrentOffset = (e, currentTarget, effect) => {
132132
const boundingClientRect = currentTarget.getBoundingClientRect();
133133
const targetTop = boundingClientRect.top;
134134
const targetLeft = boundingClientRect.left;
135-
const { width: targetWidth, height: targetHeight } = getDimensions(
136-
currentTarget
137-
);
135+
const { width: targetWidth, height: targetHeight } =
136+
getDimensions(currentTarget);
138137

139138
if (effect === 'float') {
140139
return {
@@ -221,7 +220,7 @@ const getDefaultPosition = (
221220
};
222221

223222
// Consider additional offset into position calculation
224-
const calculateOffset = offset => {
223+
const calculateOffset = (offset) => {
225224
let extraOffsetX = 0;
226225
let extraOffsetY = 0;
227226

@@ -244,7 +243,7 @@ const calculateOffset = offset => {
244243
};
245244

246245
// Get the offset of the parent elements
247-
const getParent = currentTarget => {
246+
const getParent = (currentTarget) => {
248247
let currentParent = currentTarget;
249248
while (currentParent) {
250249
const computedStyle = window.getComputedStyle(currentParent);

test/index.spec.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,21 @@ describe('Tooltip', () => {
170170
arrowColor: '#222',
171171
borderColor: 'blue'
172172
}
173+
],
174+
[
175+
{
176+
border: true,
177+
borderClass: 'custom-border-class',
178+
borderColor: '#414141'
179+
},
180+
{
181+
borderColor: '#414141',
182+
borderClass: 'custom-border-class',
183+
popupType: 'type-custom',
184+
textColor: '#fff',
185+
background: '#222',
186+
arrowColor: '#222'
187+
}
173188
]
174189
]).it('Popup color generation - show', (props, res) => {
175190
render(
@@ -184,10 +199,13 @@ describe('Tooltip', () => {
184199
);
185200

186201
const tooltip = document.getElementById('colorSpec');
202+
203+
const expectedBorderClass = res.borderClass || 'border';
204+
187205
expect(tooltip.className).to.match(
188206
new RegExp(
189207
'__react_component_tooltip [a-zA-Z0-9-]+ show' +
190-
(props.border ? ' border ' : ' ') +
208+
(props.border ? ` ${expectedBorderClass} ` : ' ') +
191209
'place-top ' +
192210
res.popupType,
193211
'i'

0 commit comments

Comments
 (0)