diff --git a/src/dom-utils.ts b/src/dom-utils.ts index 247017313..4cac479cf 100644 --- a/src/dom-utils.ts +++ b/src/dom-utils.ts @@ -6,8 +6,8 @@ export function div(): HTMLDivElement { return document.createElement('div'); } -export function isElement(value: unknown): value is Element { - return isType(value, 'Element'); +export function isElement(value: unknown): value is Element | DocumentFragment { + return ['Element', 'Fragment'].some((type) => isType(value, type)); } export function isNodeList(value: unknown): value is NodeList { diff --git a/src/types.ts b/src/types.ts index aa5bd1e46..0fabaadfc 100644 --- a/src/types.ts +++ b/src/types.ts @@ -4,7 +4,11 @@ export type BasePlacement = Popper.BasePlacement; export type Placement = Popper.Placement; -export type Content = string | Element | ((ref: Element) => Element | string); +export type Content = + | string + | Element + | DocumentFragment + | ((ref: Element) => Element | string); export type SingleTarget = Element; @@ -44,7 +48,7 @@ export interface LifecycleHooks { export interface RenderProps { allowHTML: boolean; animation: string | boolean; - arrow: boolean | string | SVGElement; + arrow: boolean | string | SVGElement | DocumentFragment; content: Content; inertia: boolean; maxWidth: number | string; diff --git a/test/integration/__snapshots__/props.test.js.snap b/test/integration/__snapshots__/props.test.js.snap index 6dfe1c426..9d184404c 100644 --- a/test/integration/__snapshots__/props.test.js.snap +++ b/test/integration/__snapshots__/props.test.js.snap @@ -1,5 +1,16 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`content DocumentFragment is injected into the tippy node 1`] = ` +
+
+`; + exports[`content Element is injected into the tippy node 1`] = `
{ }); }); + describe('DocumentFragment', () => { + it('is injected into the tippy node', () => { + const fragment = document.createDocumentFragment(); + const node = h(); + fragment.appendChild(node); + const instance = tippy(h(), {content: fragment}); + + expect(getChildren(instance.popper).content).toMatchSnapshot(); + }); + }); + describe('Function', () => { it('is injected into the tippy node', () => { const instance = tippy(h(), {content: () => 'string'}); @@ -1316,16 +1327,35 @@ describe('arrow', () => { }); describe('Element', () => { - const instance = tippy(h(), { - arrow: document.createElementNS('http://www.w3.org/2000/svg', 'svg'), + it('uses an svg', () => { + const instance = tippy(h(), { + arrow: document.createElementNS('http://www.w3.org/2000/svg', 'svg'), + }); + + expect(getChildren(instance.popper).arrow.className).toBe( + '__NAMESPACE_PREFIX__-svg-arrow' + ); + expect(getChildren(instance.popper).arrow.querySelector('svg')).not.toBe( + null + ); }); + }); - expect(getChildren(instance.popper).arrow.className).toBe( - '__NAMESPACE_PREFIX__-svg-arrow' - ); - expect(getChildren(instance.popper).arrow.querySelector('svg')).not.toBe( - null - ); + describe('Fragment', () => { + it('uses an svg', () => { + const fragment = document.createDocumentFragment(); + const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); + + fragment.appendChild(svg); + + const instance = tippy(h(), { + arrow: fragment, + }); + + expect(getChildren(instance.popper).arrow.querySelector('svg')).not.toBe( + null + ); + }); }); it('is updated correctly by .setProps()', () => { diff --git a/test/visual/tests.js b/test/visual/tests.js index 1d1bcce7c..51c4f6de6 100644 --- a/test/visual/tests.js +++ b/test/visual/tests.js @@ -40,12 +40,17 @@ window.state = { const tests = window.state.tests; tests.default = () => { + const content = document.createDocumentFragment(); + const svgA = document.createElement('svg'); + const svgB = document.createElement('svg'); + + content.appendChild(svgA); + content.appendChild(svgB); + const [instance] = tippy('#default .reference', { - content: 'Tippy', + content: 'hello', + arrow: content, interactive: true, - aria: { - expanded: false, - }, trigger: 'click', });