Skip to content
This repository was archived by the owner on Nov 9, 2024. It is now read-only.

Commit b0ca959

Browse files
authored
Fix className prop (#57)
* Fix className prop * Remove unused demo code * Consistency * Add whitespace check and test
1 parent de3937c commit b0ca959

File tree

5 files changed

+62
-38
lines changed

5 files changed

+62
-38
lines changed

.eslintrc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
},
2020
"extends": ["eslint:recommended", "plugin:react/recommended", "prettier"],
2121
"rules": {
22-
"react/no-find-dom-node": "off",
23-
"react/prop-types": "off"
22+
"react/prop-types": "off",
23+
"no-unused-vars": ["error", { "ignoreRestSiblings": true }]
2424
}
2525
}

demo/index.js

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -117,19 +117,19 @@ class ComponentChild extends React.Component {
117117
class App extends React.Component {
118118
state = {
119119
arrow: false,
120-
customClass: ''
120+
customClass: 'hello',
121121
}
122122

123123
toggleArrow = () => {
124124
this.setState(state => ({
125-
arrow: !state.arrow
125+
arrow: !state.arrow,
126126
}))
127127
}
128128

129-
updateCustomClass = (e) => {
130-
this.setState({
131-
customClass: e.target.value
132-
})
129+
componentDidMount() {
130+
setTimeout(() => {
131+
this.setState({ customClass: 'bye' })
132+
}, 500)
133133
}
134134

135135
render() {
@@ -174,8 +174,7 @@ class App extends React.Component {
174174
</Tippy>
175175

176176
<h1>Other</h1>
177-
<input type="text" placeholder="Enter class" onChange={this.updateCustomClass}/>
178-
<Tippy placement="bottom" className={this.state.customClass}>
177+
<Tippy trigger="click" className={this.state.customClass}>
179178
<button>Custom class</button>
180179
</Tippy>
181180
</main>

src/Tippy.js

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import React, {
33
cloneElement,
44
useState,
55
useRef,
6-
useEffect,
76
useLayoutEffect,
87
} from 'react'
98
import { createPortal } from 'react-dom'
@@ -32,20 +31,15 @@ function Tippy(props) {
3231
options.trigger = 'manual'
3332
}
3433

35-
useEffect(() => {
34+
useLayoutEffect(() => {
3635
instanceRef.current = tippy(targetRef.current, options)
3736

38-
const { onCreate, isEnabled, isVisible, className } = props
37+
const { onCreate, isEnabled, isVisible } = props
3938

4039
if (onCreate) {
4140
onCreate(instanceRef.current)
4241
}
4342

44-
if (className) {
45-
const { tooltip } = instanceRef.current.popperChildren
46-
updateClassName(tooltip, 'add', props.className)
47-
}
48-
4943
if (isEnabled === false) {
5044
instanceRef.current.disable()
5145
}
@@ -86,15 +80,12 @@ function Tippy(props) {
8680
})
8781

8882
useLayoutEffect(() => {
89-
if (!isMounted) {
90-
return
91-
}
92-
93-
const { tooltip } = instanceRef.current.popperChildren
94-
updateClassName(tooltip, 'add', props.className)
95-
96-
return () => {
97-
updateClassName(tooltip, 'remove', props.className)
83+
if (props.className) {
84+
const { tooltip } = instanceRef.current.popperChildren
85+
updateClassName(tooltip, 'add', props.className)
86+
return () => {
87+
updateClassName(tooltip, 'remove', props.className)
88+
}
9889
}
9990
}, [props.className])
10091

src/utils.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
export function getNativeTippyProps(props) {
2-
// eslint-disable-next-line no-unused-vars
3-
const { children, onCreate, isVisible, isEnabled, className, ...nativeProps } = props
2+
const {
3+
children,
4+
onCreate,
5+
isVisible,
6+
isEnabled,
7+
className,
8+
...nativeProps
9+
} = props
410
return nativeProps
511
}
612

test/Tippy.test.js

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,27 +52,55 @@ describe('<Tippy />', () => {
5252
expect(instance.popper.querySelector('strong')).not.toBeNull()
5353
})
5454

55-
test('custom class name get added to DOM', () => {
55+
test('props.className: single name is added to tooltip', () => {
5656
const className = 'hello'
5757
const { container } = render(
58-
<Tippy content="tip content" className={className}>
58+
<Tippy content="tooltip" className={className}>
5959
<button />
6060
</Tippy>,
6161
)
62-
const tip = container.querySelector('button')._tippy
63-
expect(tip.popper.querySelector(`.${className}`)).not.toBeNull()
62+
const instance = container.querySelector('button')._tippy
63+
expect(instance.popper.querySelector(`.${className}`)).not.toBeNull()
6464
})
6565

66-
test('custom class name get added to DOM', () => {
66+
test('props.className: multiple names are added to tooltip', () => {
6767
const classNames = 'hello world'
6868
const { container } = render(
69-
<Tippy content="tip content" className={classNames}>
69+
<Tippy content="tooltip" className={classNames}>
70+
<button />
71+
</Tippy>,
72+
)
73+
const instance = container.querySelector('button')._tippy
74+
expect(instance.popper.querySelector('.hello')).not.toBeNull()
75+
expect(instance.popper.querySelector('.world')).not.toBeNull()
76+
})
77+
78+
test('props.className: extra whitespace is ignored', () => {
79+
const className = ' hello world '
80+
const { container } = render(
81+
<Tippy content="tooltip" className={className}>
82+
<button />
83+
</Tippy>,
84+
)
85+
const { tooltip } = container.querySelector('button')._tippy.popperChildren
86+
expect(tooltip.className).toBe('tippy-tooltip dark-theme hello world')
87+
})
88+
89+
test('props.className: updating does not leave stale className behind', () => {
90+
const { container, rerender } = render(
91+
<Tippy content="tooltip" className="one">
92+
<button />
93+
</Tippy>,
94+
)
95+
const { tooltip } = container.querySelector('button')._tippy.popperChildren
96+
expect(tooltip.classList.contains('one')).toBe(true)
97+
rerender(
98+
<Tippy content="tooltip" className="two">
7099
<button />
71100
</Tippy>,
72101
)
73-
const tip = container.querySelector('button')._tippy
74-
expect(tip.popper.querySelector('.hello')).not.toBeNull()
75-
expect(tip.popper.querySelector('.world')).not.toBeNull()
102+
expect(tooltip.classList.contains('one')).toBe(false)
103+
expect(tooltip.classList.contains('two')).toBe(true)
76104
})
77105

78106
test('unmount destroys the tippy instance and allows garbage collection', () => {

0 commit comments

Comments
 (0)