diff --git a/README.md b/README.md index 151ba7294..1512166d4 100755 --- a/README.md +++ b/README.md @@ -80,6 +80,7 @@ Notes: | delayUpdate | data-delay-update | Number | | `

` or `` Sets a delay in calling getContent if the tooltip is already shown and you mouse over another target | | insecure | null | Bool | true, false | Whether to inject the style header into the page dynamically (violates CSP style-src but is a convenient default) | | border | data-border | Bool | true, false | Add one pixel white border | +| borderClass | data-border-class | String | e.g. custom-border-class | A custom class name to use for the border - enabled by the `border` prop | | textColor | data-text-color | String | e.g. red | Popup text color | | backgroundColor | data-background-color | String | e.g. yellow | Popup background color | | borderColor | data-border-color | String | e.g. green | Popup border color - enabled by the `border` value | diff --git a/example/src/App.js b/example/src/App.js index 1bc42f062..8da0f070f 100644 --- a/example/src/App.js +++ b/example/src/App.js @@ -316,7 +316,7 @@ export default class App extends Component {
V(^-^)V @@ -325,6 +325,7 @@ export default class App extends Component { className="custom-color" place="right" border + borderClass="custom-border-class" textColor="#5F4B8BFF" backgroundColor="#E69A8DFF" borderColor="darkgreen" diff --git a/react-tooltip.d.ts b/react-tooltip.d.ts index 0c0a84efe..f496646a3 100644 --- a/react-tooltip.d.ts +++ b/react-tooltip.d.ts @@ -30,6 +30,8 @@ export interface TooltipProps { multiline?: boolean; // Add 1px white border border?: boolean; + // A custom class name to use for the border + borderClass?: string; // Popup text color textColor?: string; // Popup background color @@ -74,7 +76,7 @@ export interface TooltipProps { afterHide?: VoidFunc; // Callback to override the tooltip position overridePosition?: ( - position: { left: number; top: number; }, + position: { left: number; top: number }, currentEvent: Event, currentTarget: EventTarget, // node is the ref argument, and the wrapper @@ -83,8 +85,8 @@ export interface TooltipProps { place: Place, desiredPlace: Place, effect: Effect, - offset: Offset, - ) => ({ left: number; top: number; }); + offset: Offset + ) => { left: number; top: number }; // Manually disable the tooltip behavior disable?: boolean; // Hide the tooltip when scrolling; @@ -94,7 +96,7 @@ export interface TooltipProps { // default = true resizeHide?: boolean; // The tooltip parent component; - // default = 'div' + // default = 'div' wrapper?: 'div' | 'span'; // Listen to body events vs. individual events bodyMode?: boolean; @@ -112,7 +114,7 @@ export interface TooltipProps { // You can overview demo examples here: https://bddeu.csb.app export default class ReactTooltip extends React.Component { // static methods - static show: (target: Element) => {}; - static hide: (target?: Element) => {}; - static rebuild: () => {}; + static show: (target: Element) => {}; + static hide: (target?: Element) => {}; + static rebuild: () => {}; } diff --git a/src/decorators/bodyMode.js b/src/decorators/bodyMode.js index a845a5f5b..fc713cd02 100644 --- a/src/decorators/bodyMode.js +++ b/src/decorators/bodyMode.js @@ -3,7 +3,7 @@ */ import { checkStatus } from './customEvent'; -const makeProxy = e => { +const makeProxy = (e) => { const proxy = {}; for (const key in e) { if (typeof e[key] === 'function') { @@ -15,7 +15,7 @@ const makeProxy = e => { return proxy; }; -const bodyListener = function(callback, options, e) { +const bodyListener = function (callback, options, e) { const { respectEffect = false, customEvent = false } = options; const { id } = this.props; @@ -54,9 +54,9 @@ const bodyListener = function(callback, options, e) { const findCustomEvents = (targetArray, dataAttribute) => { const events = {}; - targetArray.forEach(target => { + targetArray.forEach((target) => { const event = target.getAttribute(dataAttribute); - if (event) event.split(' ').forEach(event => (events[event] = true)); + if (event) event.split(' ').forEach((event) => (events[event] = true)); }); return events; @@ -64,18 +64,14 @@ const findCustomEvents = (targetArray, dataAttribute) => { const getBody = () => document.getElementsByTagName('body')[0]; -export default function(target) { - target.prototype.isBodyMode = function() { +export default function (target) { + target.prototype.isBodyMode = function () { return !!this.props.bodyMode; }; - target.prototype.bindBodyListener = function(targetArray) { - const { - event, - eventOff, - possibleCustomEvents, - possibleCustomEventsOff - } = this.state; + target.prototype.bindBodyListener = function (targetArray) { + const { event, eventOff, possibleCustomEvents, possibleCustomEventsOff } = + this.state; const body = getBody(); const customEvents = findCustomEvents(targetArray, 'data-event'); @@ -85,10 +81,10 @@ export default function(target) { if (eventOff != null) customEventsOff[eventOff] = true; possibleCustomEvents .split(' ') - .forEach(event => (customEvents[event] = true)); + .forEach((event) => (customEvents[event] = true)); possibleCustomEventsOff .split(' ') - .forEach(event => (customEventsOff[event] = true)); + .forEach((event) => (customEventsOff[event] = true)); this.unbindBodyListener(body); @@ -104,7 +100,7 @@ export default function(target) { for (const event in customEvents) { listeners[event] = bodyListener.bind( this, - e => { + (e) => { const targetEventOff = e.currentTarget.getAttribute('data-event-off') || eventOff; checkStatus.call(this, targetEventOff, e); @@ -122,7 +118,7 @@ export default function(target) { } }; - target.prototype.unbindBodyListener = function(body) { + target.prototype.unbindBodyListener = function (body) { body = body || getBody(); const listeners = this.bodyModeListeners; diff --git a/src/index.js b/src/index.js index 616d0d167..e31129e7d 100755 --- a/src/index.js +++ b/src/index.js @@ -44,6 +44,7 @@ class ReactTooltip extends React.Component { padding: PropTypes.string, multiline: PropTypes.bool, border: PropTypes.bool, + borderClass: PropTypes.string, textColor: PropTypes.string, backgroundColor: PropTypes.string, borderColor: PropTypes.string, @@ -97,6 +98,7 @@ class ReactTooltip extends React.Component { effect: props.effect || 'float', // float or fixed show: false, border: false, + borderClass: 'border', customColors: {}, offset: {}, padding: props.padding, @@ -507,6 +509,10 @@ class ReactTooltip extends React.Component { (target.getAttribute('data-border') ? target.getAttribute('data-border') === 'true' : self.props.border) || false, + borderClass: + target.getAttribute('data-border-class') || + self.props.borderClass || + 'border', extraClass: target.getAttribute('data-class') || self.props.class || @@ -791,7 +797,7 @@ class ReactTooltip extends React.Component { '__react_component_tooltip' + ` ${this.state.uuid}` + (this.state.show && !disable && !isEmptyTip ? ' show' : '') + - (this.state.border ? ' border' : '') + + (this.state.border ? ' ' + this.state.borderClass : '') + ` place-${this.state.place}` + // top, bottom, left, right ` type-${this.hasCustomColors() ? 'custom' : this.state.type}` + // dark, success, warning, error, info, light, custom (this.props.delayUpdate ? ' allow_hover' : '') + diff --git a/src/utils/getPosition.js b/src/utils/getPosition.js index 6f72cc833..5c2bc1b70 100755 --- a/src/utils/getPosition.js +++ b/src/utils/getPosition.js @@ -14,7 +14,7 @@ * - `newState` {Object} * - `position` {Object} {left: {Number}, top: {Number}} */ -export default function(e, target, node, place, desiredPlace, effect, offset) { +export default function (e, target, node, place, desiredPlace, effect, offset) { const { width: tipWidth, height: tipHeight } = getDimensions(node); const { width: targetWidth, height: targetHeight } = getDimensions(target); @@ -35,19 +35,19 @@ export default function(e, target, node, place, desiredPlace, effect, offset) { const { parentTop, parentLeft } = getParent(node); // Get the edge offset of the tooltip - const getTipOffsetLeft = place => { + const getTipOffsetLeft = (place) => { const offsetX = defaultOffset[place].l; return mouseX + offsetX + extraOffsetX; }; - const getTipOffsetRight = place => { + const getTipOffsetRight = (place) => { const offsetX = defaultOffset[place].r; return mouseX + offsetX + extraOffsetX; }; - const getTipOffsetTop = place => { + const getTipOffsetTop = (place) => { const offsetY = defaultOffset[place].t; return mouseY + offsetY + extraOffsetY; }; - const getTipOffsetBottom = place => { + const getTipOffsetBottom = (place) => { const offsetY = defaultOffset[place].b; return mouseY + offsetY + extraOffsetY; }; @@ -66,15 +66,15 @@ export default function(e, target, node, place, desiredPlace, effect, offset) { // | // Bottom side // - const outsideLeft = p => getTipOffsetLeft(p) < 0; - const outsideRight = p => getTipOffsetRight(p) > windowWidth; - const outsideTop = p => getTipOffsetTop(p) < 0; - const outsideBottom = p => getTipOffsetBottom(p) > windowHeight; + const outsideLeft = (p) => getTipOffsetLeft(p) < 0; + const outsideRight = (p) => getTipOffsetRight(p) > windowWidth; + const outsideTop = (p) => getTipOffsetTop(p) < 0; + const outsideBottom = (p) => getTipOffsetBottom(p) > windowHeight; // Check whether the tooltip with orientation p is completely inside the client window - const outside = p => + const outside = (p) => outsideLeft(p) || outsideRight(p) || outsideTop(p) || outsideBottom(p); - const inside = p => !outside(p); + const inside = (p) => !outside(p); const placeIsInside = { top: inside('top'), @@ -119,7 +119,7 @@ export default function(e, target, node, place, desiredPlace, effect, offset) { }; } -const getDimensions = node => { +const getDimensions = (node) => { const { height, width } = node.getBoundingClientRect(); return { height: parseInt(height, 10), @@ -132,9 +132,8 @@ const getCurrentOffset = (e, currentTarget, effect) => { const boundingClientRect = currentTarget.getBoundingClientRect(); const targetTop = boundingClientRect.top; const targetLeft = boundingClientRect.left; - const { width: targetWidth, height: targetHeight } = getDimensions( - currentTarget - ); + const { width: targetWidth, height: targetHeight } = + getDimensions(currentTarget); if (effect === 'float') { return { @@ -221,7 +220,7 @@ const getDefaultPosition = ( }; // Consider additional offset into position calculation -const calculateOffset = offset => { +const calculateOffset = (offset) => { let extraOffsetX = 0; let extraOffsetY = 0; @@ -244,7 +243,7 @@ const calculateOffset = offset => { }; // Get the offset of the parent elements -const getParent = currentTarget => { +const getParent = (currentTarget) => { let currentParent = currentTarget; while (currentParent) { const computedStyle = window.getComputedStyle(currentParent); diff --git a/test/index.spec.js b/test/index.spec.js index 419bb76aa..cd4f5e63b 100644 --- a/test/index.spec.js +++ b/test/index.spec.js @@ -170,6 +170,21 @@ describe('Tooltip', () => { arrowColor: '#222', borderColor: 'blue' } + ], + [ + { + border: true, + borderClass: 'custom-border-class', + borderColor: '#414141' + }, + { + borderColor: '#414141', + borderClass: 'custom-border-class', + popupType: 'type-custom', + textColor: '#fff', + background: '#222', + arrowColor: '#222' + } ] ]).it('Popup color generation - show', (props, res) => { render( @@ -184,10 +199,13 @@ describe('Tooltip', () => { ); const tooltip = document.getElementById('colorSpec'); + + const expectedBorderClass = res.borderClass || 'border'; + expect(tooltip.className).to.match( new RegExp( '__react_component_tooltip [a-zA-Z0-9-]+ show' + - (props.border ? ' border ' : ' ') + + (props.border ? ` ${expectedBorderClass} ` : ' ') + 'place-top ' + res.popupType, 'i'