-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
336 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,44 +1,239 @@ | ||
import { fireEvent, render, screen } from '@testing-library/svelte/svelte5'; | ||
import { describe, expect, it } from 'vitest'; | ||
import { describe, expect, it, vi } from 'vitest'; | ||
import App from './App.test.svelte'; | ||
|
||
describe('useDismiss', () => { | ||
it('dismisses on outside pointerdown', async () => { | ||
render(App, { open: true }); | ||
describe('default', () => { | ||
it('does dismiss on outside pointerdown', async () => { | ||
render(App, { open: true }); | ||
|
||
expect(screen.queryByTestId('floating')).toBeInTheDocument(); | ||
expect(screen.queryByTestId('floating')).toBeInTheDocument(); | ||
|
||
await fireEvent.pointerDown(document); | ||
await fireEvent.pointerDown(document); | ||
|
||
expect(screen.queryByTestId('floating')).not.toBeInTheDocument(); | ||
expect(screen.queryByTestId('floating')).not.toBeInTheDocument(); | ||
}); | ||
|
||
it('does dismiss on `Escape` key press', async () => { | ||
render(App, { open: true }); | ||
|
||
expect(screen.queryByTestId('floating')).toBeInTheDocument(); | ||
|
||
await fireEvent.keyDown(document, { key: 'Escape' }); | ||
|
||
expect(screen.queryByTestId('floating')).not.toBeInTheDocument(); | ||
}); | ||
}); | ||
|
||
describe('enabled', () => { | ||
it('does dismiss when set to `true`', async () => { | ||
render(App, { open: true, enabled: true }); | ||
|
||
expect(screen.queryByTestId('floating')).toBeInTheDocument(); | ||
|
||
await fireEvent.pointerDown(document); | ||
|
||
expect(screen.queryByTestId('floating')).not.toBeInTheDocument(); | ||
}); | ||
|
||
it('does not dismiss when set to `false`', async () => { | ||
render(App, { open: true, enabled: false }); | ||
|
||
expect(screen.queryByTestId('floating')).toBeInTheDocument(); | ||
|
||
await fireEvent.pointerDown(document); | ||
|
||
expect(screen.queryByTestId('floating')).toBeInTheDocument(); | ||
}); | ||
}); | ||
|
||
describe('escapeKey', () => { | ||
it('does dismiss on `Escape` key press when set to `true`', async () => { | ||
render(App, { open: true, escapeKey: true }); | ||
|
||
expect(screen.queryByTestId('floating')).toBeInTheDocument(); | ||
|
||
await fireEvent.keyDown(document, { key: 'Escape' }); | ||
|
||
expect(screen.queryByTestId('floating')).not.toBeInTheDocument(); | ||
}); | ||
|
||
it('does not dismiss on `Escape` key press when set to `false`', async () => { | ||
render(App, { open: true, escapeKey: false }); | ||
|
||
expect(screen.queryByTestId('floating')).toBeInTheDocument(); | ||
|
||
await fireEvent.keyDown(document, { key: 'Escape' }); | ||
|
||
expect(screen.queryByTestId('floating')).toBeInTheDocument(); | ||
}); | ||
}); | ||
|
||
describe('outsidePress', () => { | ||
describe('boolean', () => { | ||
it('does dismiss on outside press when set to `true`', async () => { | ||
render(App, { open: true, outsidePress: true }); | ||
|
||
expect(screen.queryByTestId('floating')).toBeInTheDocument(); | ||
|
||
await fireEvent.pointerDown(document); | ||
|
||
expect(screen.queryByTestId('floating')).not.toBeInTheDocument(); | ||
}); | ||
|
||
it('does not dismiss on outside press when set to `false`', async () => { | ||
render(App, { open: true, outsidePress: false }); | ||
|
||
expect(screen.queryByTestId('floating')).toBeInTheDocument(); | ||
|
||
await fireEvent.pointerDown(document); | ||
|
||
expect(screen.queryByTestId('floating')).toBeInTheDocument(); | ||
}); | ||
}); | ||
describe('function', () => { | ||
it('does dismiss on outside press when the function returns `true`', async () => { | ||
render(App, { open: true, outsidePress: () => true }); | ||
|
||
expect(screen.queryByTestId('floating')).toBeInTheDocument(); | ||
|
||
await fireEvent.pointerDown(document); | ||
|
||
expect(screen.queryByTestId('floating')).not.toBeInTheDocument(); | ||
}); | ||
|
||
it('does not dismiss on outside press when the function returns `false`', async () => { | ||
render(App, { open: true, outsidePress: () => false }); | ||
|
||
expect(screen.queryByTestId('floating')).toBeInTheDocument(); | ||
|
||
await fireEvent.pointerDown(document); | ||
|
||
expect(screen.queryByTestId('floating')).toBeInTheDocument(); | ||
}); | ||
|
||
it('passes the corresponding event as argument', async () => { | ||
const outsidePress = vi.fn(); | ||
render(App, { open: true, outsidePress }); | ||
|
||
expect(outsidePress).not.toHaveBeenCalled(); | ||
|
||
const pointerdownEvent = new Event('pointerdown'); | ||
|
||
await fireEvent.pointerDown(document, { event: pointerdownEvent }); | ||
|
||
expect(outsidePress).toHaveBeenCalled(); | ||
|
||
expect(outsidePress.mock.calls[0][0]).toBe(pointerdownEvent); | ||
}); | ||
}); | ||
}); | ||
it('dismisses on `Escape` key press', async () => { | ||
render(App, { open: true }); | ||
|
||
expect(screen.queryByTestId('floating')).toBeInTheDocument(); | ||
describe('outsidePressEvent', () => { | ||
it('does dismiss on outside `pointerdown` event when set to `pointerdown`', async () => { | ||
render(App, { open: true, outsidePress: true, outsidePressEvent: 'pointerdown' }); | ||
|
||
expect(screen.queryByTestId('floating')).toBeInTheDocument(); | ||
|
||
await fireEvent.pointerDown(document); | ||
|
||
expect(screen.queryByTestId('floating')).not.toBeInTheDocument(); | ||
}); | ||
|
||
await fireEvent.keyDown(document, { key: 'Escape' }); | ||
it('does dismiss on outside `mousedown` event when set to `mousedown`', async () => { | ||
render(App, { open: true, outsidePress: true, outsidePressEvent: 'mousedown' }); | ||
|
||
expect(screen.queryByTestId('floating')).not.toBeInTheDocument(); | ||
expect(screen.queryByTestId('floating')).toBeInTheDocument(); | ||
|
||
await fireEvent.mouseDown(document); | ||
|
||
expect(screen.queryByTestId('floating')).not.toBeInTheDocument(); | ||
}); | ||
|
||
it('does dismiss on outside `click` event when set to `click`', async () => { | ||
render(App, { open: true, outsidePress: true, outsidePressEvent: 'click' }); | ||
|
||
expect(screen.queryByTestId('floating')).toBeInTheDocument(); | ||
|
||
await fireEvent.click(document); | ||
|
||
expect(screen.queryByTestId('floating')).not.toBeInTheDocument(); | ||
}); | ||
}); | ||
|
||
it('dismisses on reference press', async () => { | ||
render(App, { open: true, referencePress: true }); | ||
describe('referencePress', () => { | ||
it('does dismiss on reference press when set to `true`', async () => { | ||
render(App, { open: true, referencePress: true }); | ||
|
||
expect(screen.queryByTestId('floating')).toBeInTheDocument(); | ||
|
||
await fireEvent.pointerDown(screen.getByTestId('reference')); | ||
|
||
expect(screen.queryByTestId('floating')).not.toBeInTheDocument(); | ||
}); | ||
|
||
expect(screen.queryByTestId('floating')).toBeInTheDocument(); | ||
it('does not dismiss on reference press when set to `false`', async () => { | ||
render(App, { open: true, referencePress: false }); | ||
|
||
await fireEvent.pointerDown(screen.getByTestId('reference')); | ||
expect(screen.queryByTestId('floating')).toBeInTheDocument(); | ||
|
||
expect(screen.queryByTestId('floating')).not.toBeInTheDocument(); | ||
await fireEvent.pointerDown(screen.getByTestId('reference')); | ||
|
||
expect(screen.queryByTestId('floating')).toBeInTheDocument(); | ||
}); | ||
}); | ||
|
||
describe('referencePressEvent', () => { | ||
it('does dismiss on reference `pointerdown` event when set to `pointerdown`', async () => { | ||
render(App, { open: true, referencePress: true, referencePressEvent: 'pointerdown' }); | ||
|
||
expect(screen.queryByTestId('floating')).toBeInTheDocument(); | ||
|
||
await fireEvent.pointerDown(screen.getByTestId('reference')); | ||
|
||
expect(screen.queryByTestId('floating')).not.toBeInTheDocument(); | ||
}); | ||
|
||
it('does dismiss on reference `mousedown` event when set to `mousedown`', async () => { | ||
render(App, { open: true, referencePress: true, referencePressEvent: 'mousedown' }); | ||
|
||
expect(screen.queryByTestId('floating')).toBeInTheDocument(); | ||
|
||
await fireEvent.mouseDown(screen.getByTestId('reference')); | ||
|
||
expect(screen.queryByTestId('floating')).not.toBeInTheDocument(); | ||
}); | ||
|
||
it('does dismiss on reference `click` event when set to `click`', async () => { | ||
render(App, { open: true, referencePress: true, referencePressEvent: 'click' }); | ||
|
||
expect(screen.queryByTestId('floating')).toBeInTheDocument(); | ||
|
||
await fireEvent.click(screen.getByTestId('reference')); | ||
|
||
expect(screen.queryByTestId('floating')).not.toBeInTheDocument(); | ||
}); | ||
}); | ||
|
||
it('dismisses on ancestor scroll', async () => { | ||
render(App, { open: true, ancestorScroll: true }); | ||
describe('ancestorScroll', () => { | ||
it('does dismiss on ancestor scroll when set to `true`', async () => { | ||
render(App, { open: true, ancestorScroll: true }); | ||
|
||
expect(screen.queryByTestId('floating')).toBeInTheDocument(); | ||
|
||
await fireEvent.scroll(window); | ||
|
||
expect(screen.queryByTestId('floating')).not.toBeInTheDocument(); | ||
}); | ||
|
||
it('does not dismiss on ancestor scroll when set to `false`', async () => { | ||
render(App, { open: true, ancestorScroll: false }); | ||
|
||
expect(screen.queryByTestId('floating')).toBeInTheDocument(); | ||
expect(screen.queryByTestId('floating')).toBeInTheDocument(); | ||
|
||
await fireEvent.scroll(window); | ||
await fireEvent.scroll(window); | ||
|
||
expect(screen.queryByTestId('floating')).not.toBeInTheDocument(); | ||
expect(screen.queryByTestId('floating')).toBeInTheDocument(); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
<script lang="ts"> | ||
import CodeBlock from '$docs/components/CodeBlock/CodeBlock.svelte'; | ||
import ExampleRaw from './Example.svelte?raw'; | ||
import Table from '$docs/components/Table/Table.svelte'; | ||
import { tableOptions } from './data.js'; | ||
</script> | ||
|
||
<div class="space-y-10"> | ||
<!-- Header --> | ||
<header class="card card-gradient space-y-8"> | ||
<h1 class="h1"><span>useDismiss</span></h1> | ||
<p> | ||
Closes the floating element when a dismissal is requested — by default, when the user presses | ||
the <kbd class="kbd">escape</kbd> key or outside of the floating element with their pointer. | ||
</p> | ||
<CodeBlock lang="ts" code={`import { useDismiss } from '@skeletonlabs/floating-ui-svelte';`} /> | ||
</header> | ||
<!-- Usage --> | ||
<section class="space-y-8"> | ||
<h2 class="h2">Usage</h2> | ||
<CodeBlock code={ExampleRaw} lang="svelte" /> | ||
</section> | ||
<!-- Table: Options --> | ||
<section class="space-y-8"> | ||
<h2 class="h2">Options</h2> | ||
<Table data={tableOptions} /> | ||
</section> | ||
<!-- Compare --> | ||
<section class="space-y-8"> | ||
<h2 class="h2">Compare</h2> | ||
<!-- prettier-ignore --> | ||
<p> | ||
Compare to <a class="anchor" href="https://floating-ui.com/docs/useDismiss" target="_blank">Floating UI React</a>. | ||
</p> | ||
</section> | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
<script lang="ts"> | ||
import { useFloating, useInteractions, useDismiss } from '@skeletonlabs/floating-ui-svelte'; | ||
const floating = useFloating(); | ||
const click = useDismiss(floating.context); | ||
const interactions = useInteractions([click]); | ||
</script> | ||
|
||
<!-- Reference Element --> | ||
<button bind:this={floating.elements.reference} {...interactions.getReferenceProps()}> | ||
Reference | ||
</button> | ||
|
||
<!-- Floating Element --> | ||
<div | ||
bind:this={floating.elements.floating} | ||
style={floating.floatingStyles} | ||
{...interactions.getFloatingProps()} | ||
> | ||
Tooltip | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// Hook: useDismiss | ||
|
||
import type { TableData } from '$docs/types.js'; | ||
|
||
// Options | ||
export const tableOptions: TableData[] = [ | ||
{ | ||
property: `enabled`, | ||
description: `Whether the Hook is enabled, including all internal Effects and event handlers.`, | ||
type: `boolean`, | ||
default: `true`, | ||
}, | ||
{ | ||
property: `escapeKey`, | ||
description: `Whether to dismiss the floating element upon pressing the \`esc\` key.`, | ||
type: `boolean`, | ||
default: `true`, | ||
}, | ||
{ | ||
property: `referencePress`, | ||
description: `Whether to dismiss the floating element upon pressing the reference element. You likely want to ensure the \`move\` option in the \`useHover()\` Hook has been disabled when this is in use.`, | ||
type: `boolean`, | ||
default: `false`, | ||
}, | ||
{ | ||
property: `referencePressEvent`, | ||
description: `The type of event to use to determine a “press”.`, | ||
type: `'pointerdown' | 'mousedown' | 'click'`, | ||
default: `'pointerdown'`, | ||
}, | ||
{ | ||
property: `outsidePress`, | ||
description: `Whether to dismiss the floating element upon pressing outside of the floating element.`, | ||
type: `boolean | ((event: MouseEvent) => boolean)`, | ||
default: `true`, | ||
}, | ||
{ | ||
property: `outsidePressEvent`, | ||
description: `The type of event to use to determine an outside “press”.`, | ||
type: `'pointerdown' | 'mousedown' | 'click'`, | ||
default: `'pointerdown'`, | ||
}, | ||
{ | ||
property: `ancestorScroll`, | ||
description: `Whether to dismiss the floating element upon scrolling an overflow ancestor.`, | ||
type: `boolean`, | ||
default: `false`, | ||
}, | ||
{ | ||
property: `bubbles`, | ||
description: `Determines whether event listeners bubble upwards through a tree of floating elements.`, | ||
type: `boolean | { escapeKey?: boolean; outsidePress?: boolean }`, | ||
default: `undefined`, | ||
}, | ||
{ | ||
property: `capture`, | ||
description: `Determines whether to use capture phase event listeners.`, | ||
type: `boolean | { escapeKey?: boolean; outsidePress?: boolean }`, | ||
default: `undefined`, | ||
}, | ||
]; |