From 868f8fa1b19b81108cb90881a0635c54d2500f71 Mon Sep 17 00:00:00 2001 From: Carbon Copy Date: Wed, 2 Oct 2019 04:16:31 +1000 Subject: [PATCH] Add className support to --- index.d.ts | 1 + src/Tippy.js | 19 +++------ src/TippySingleton.js | 29 ++++++++++--- src/hooks.js | 22 +++++++--- test/TippySingleton.test.js | 85 ++++++++++++++++++++++++++++++++++--- 5 files changed, 126 insertions(+), 30 deletions(-) diff --git a/index.d.ts b/index.d.ts index 7c62399..0a866ed 100644 --- a/index.d.ts +++ b/index.d.ts @@ -17,6 +17,7 @@ export const tippy: typeof tippyCore; export interface TippySingletonProps extends Partial { children: Array>; + className?: string; } export const TippySingleton: React.FunctionComponent; diff --git a/src/Tippy.js b/src/Tippy.js index 29dfd72..44a45ae 100644 --- a/src/Tippy.js +++ b/src/Tippy.js @@ -2,8 +2,12 @@ import React, {forwardRef, cloneElement, useState} from 'react'; import PropTypes from 'prop-types'; import {createPortal} from 'react-dom'; import tippy from 'tippy.js'; -import {preserveRef, ssrSafeCreateDiv, updateClassName} from './utils'; -import {useInstance, useIsomorphicLayoutEffect} from './hooks'; +import {preserveRef, ssrSafeCreateDiv} from './utils'; +import { + useInstance, + useIsomorphicLayoutEffect, + useUpdateClassName, +} from './hooks'; export function Tippy({ children, @@ -83,16 +87,7 @@ export function Tippy({ } }); - // UPDATE className - useIsomorphicLayoutEffect(() => { - if (className) { - const {tooltip} = component.instance.popperChildren; - updateClassName(tooltip, 'add', className); - return () => { - updateClassName(tooltip, 'remove', className); - }; - } - }, [className]); + useUpdateClassName(component, className); return ( <> diff --git a/src/TippySingleton.js b/src/TippySingleton.js index 134930d..76ec679 100644 --- a/src/TippySingleton.js +++ b/src/TippySingleton.js @@ -1,23 +1,36 @@ import {Children, cloneElement} from 'react'; import PropTypes from 'prop-types'; import {createSingleton} from 'tippy.js'; -import {useIsomorphicLayoutEffect, useInstance} from './hooks'; +import { + useIsomorphicLayoutEffect, + useInstance, + useUpdateClassName, +} from './hooks'; -export default function TippySingleton({children, ...props}) { +export default function TippySingleton({ + children, + className, + ignoreAttributes = true, + ...restOfNativeProps +}) { const component = useInstance({ instances: [], renders: 1, }); + const props = { + ignoreAttributes, + ...restOfNativeProps, + }; + useIsomorphicLayoutEffect(() => { const {instances} = component; - const singleton = createSingleton(instances, props); + const instance = createSingleton(instances, props); - component.singleton = singleton; + component.instance = instance; return () => { - singleton.destroy(); - + instance.destroy(); component.instances = instances.filter(i => !i.state.isDestroyed); }; }, [children.length]); @@ -28,9 +41,11 @@ export default function TippySingleton({children, ...props}) { return; } - component.singleton.setProps(props); + component.instance.setProps(props); }); + useUpdateClassName(component, className); + return Children.map(children, child => { return cloneElement(child, { enabled: false, diff --git a/src/hooks.js b/src/hooks.js index 85eafc3..4e1db51 100644 --- a/src/hooks.js +++ b/src/hooks.js @@ -1,6 +1,22 @@ -import {isBrowser} from './utils'; +import {isBrowser, updateClassName} from './utils'; import {useLayoutEffect, useEffect, useRef} from 'react'; +export const useIsomorphicLayoutEffect = isBrowser + ? useLayoutEffect + : useEffect; + +export function useUpdateClassName(component, className) { + useIsomorphicLayoutEffect(() => { + const {tooltip} = component.instance.popperChildren; + if (className) { + updateClassName(tooltip, 'add', className); + return () => { + updateClassName(tooltip, 'remove', className); + }; + } + }, [className]); +} + export function useInstance(initialValue) { // Using refs instead of state as it's recommended to not store imperative // values in state due to memory problems in React(?) @@ -13,7 +29,3 @@ export function useInstance(initialValue) { return ref.current; } - -export const useIsomorphicLayoutEffect = isBrowser - ? useLayoutEffect - : useEffect; diff --git a/test/TippySingleton.test.js b/test/TippySingleton.test.js index c1d72ce..9249470 100644 --- a/test/TippySingleton.test.js +++ b/test/TippySingleton.test.js @@ -1,5 +1,5 @@ import React from 'react'; -import Tippy, {TippySingleton} from '../src'; +import Tippy, {TippySingleton as TippySingletonBase} from '../src'; import {render, cleanup} from '@testing-library/react'; jest.useFakeTimers(); @@ -7,6 +7,12 @@ jest.useFakeTimers(); afterEach(cleanup); describe('', () => { + let instance; + + function TippySingleton(props) { + return (instance = i)} />; + } + it('renders without crashing', () => { render( @@ -106,11 +112,11 @@ describe('', () => { ); }); - it('uses `onCreate` prop', () => { - const spy = jest.fn(); + test('props.className: single name is added to tooltip', () => { + const className = 'hello'; render( - +