Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@rgossiaux/svelte-headlessui

Package Overview
Dependencies
Maintainers
1
Versions
16
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@rgossiaux/svelte-headlessui - npm Package Compare versions

Comparing version 1.0.0-beta.4 to 1.0.0-beta.5

components/dialog/_NestedDialog.svelte

1

components/dialog/_ManagedDialog.svelte.d.ts

@@ -7,2 +7,3 @@ import { SvelteComponentTyped } from "svelte";

onClose?: (() => void) | undefined;
buttonInside?: boolean | undefined;
buttonText?: string | null | undefined;

@@ -9,0 +10,0 @@ buttonProps?: {} | undefined;

2

hooks/use-actions.js

@@ -18,3 +18,3 @@ export function useActions(node, actions) {

if (((actions && actions.length) || 0) != actionReturns.length) {
throw new Error('You must not change the length of an actions array.');
throw new Error("You must not change the length of an actions array.");
}

@@ -21,0 +21,0 @@ if (actions) {

@@ -21,2 +21,3 @@ import type { SvelteComponent } from "svelte";

import Footer from "./Footer.svelte";
import Form from "./Form.svelte";
import H1 from "./H1.svelte";

@@ -30,2 +31,3 @@ import H2 from "./H2.svelte";

import I from "./I.svelte";
import Input from "./Input.svelte";
import Label from "./Label.svelte";

@@ -61,2 +63,3 @@ import Li from "./Li.svelte";

footer: typeof Footer;
form: typeof Form;
h1: typeof H1;

@@ -70,2 +73,3 @@ h2: typeof H2;

i: typeof I;
input: typeof Input;
label: typeof Label;

@@ -84,3 +88,3 @@ li: typeof Li;

export declare type SupportedAs = SupportedElement | SvelteComponent;
export declare function getElementComponent(name: SupportedElement): typeof A | typeof Address | typeof Article | typeof Aside | typeof B | typeof Bdi | typeof Bdo | typeof Blockquote | typeof Button | typeof Cite | typeof Code | typeof Data | typeof Datalist | typeof Dd | typeof Dl | typeof Dt | typeof Div | typeof Em | typeof Footer | typeof H1 | typeof H2 | typeof H3 | typeof H4 | typeof H5 | typeof H6 | typeof Header | typeof I | typeof Label | typeof Li | typeof Main | typeof Nav | typeof Ol | typeof P | typeof Section | typeof Span | typeof Strong | typeof Ul;
export declare function getElementComponent(name: SupportedElement): typeof A | typeof Address | typeof Article | typeof Aside | typeof B | typeof Bdi | typeof Bdo | typeof Blockquote | typeof Button | typeof Cite | typeof Code | typeof Data | typeof Datalist | typeof Dd | typeof Dl | typeof Dt | typeof Div | typeof Em | typeof Footer | typeof Form | typeof H1 | typeof H2 | typeof H3 | typeof H4 | typeof H5 | typeof H6 | typeof Header | typeof I | typeof Input | typeof Label | typeof Li | typeof Main | typeof Nav | typeof Ol | typeof P | typeof Section | typeof Span | typeof Strong | typeof Ul;
export {};

@@ -20,2 +20,3 @@ import A from "./A.svelte";

import Footer from "./Footer.svelte";
import Form from "./Form.svelte";
import H1 from "./H1.svelte";

@@ -29,2 +30,3 @@ import H2 from "./H2.svelte";

import I from "./I.svelte";
import Input from "./Input.svelte";
import Label from "./Label.svelte";

@@ -41,39 +43,41 @@ import Li from "./Li.svelte";

const components = {
"a": A,
"address": Address,
"article": Article,
"aside": Aside,
"b": B,
"bdi": Bdi,
"bdo": Bdo,
"blockquote": Blockquote,
"button": Button,
"cite": Cite,
"code": Code,
"data": Data,
"datalist": Datalist,
"dd": Dd,
"dl": Dl,
"dt": Dt,
"div": Div,
"em": Em,
"footer": Footer,
"h1": H1,
"h2": H2,
"h3": H3,
"h4": H4,
"h5": H5,
"h6": H6,
"header": Header,
"i": I,
"label": Label,
"li": Li,
"main": Main,
"nav": Nav,
"ol": Ol,
"p": P,
"section": Section,
"span": Span,
"strong": Strong,
"ul": Ul,
a: A,
address: Address,
article: Article,
aside: Aside,
b: B,
bdi: Bdi,
bdo: Bdo,
blockquote: Blockquote,
button: Button,
cite: Cite,
code: Code,
data: Data,
datalist: Datalist,
dd: Dd,
dl: Dl,
dt: Dt,
div: Div,
em: Em,
footer: Footer,
form: Form,
h1: H1,
h2: H2,
h3: H3,
h4: H4,
h5: H5,
h6: H6,
header: Header,
i: I,
input: Input,
label: Label,
li: Li,
main: Main,
nav: Nav,
ol: Ol,
p: P,
section: Section,
span: Span,
strong: Strong,
ul: Ul,
};

@@ -80,0 +84,0 @@ export function getElementComponent(name) {

@@ -1,4 +0,9 @@

import type { SvelteComponent } from 'svelte';
export declare function forwardEventsBuilder(component: SvelteComponent, except?: string[]): (node: HTMLElement | SVGElement) => {
import type { SvelteComponent } from "svelte";
declare type ForwardException = string | {
name: string;
shouldExclude: () => boolean;
};
export declare function forwardEventsBuilder(component: SvelteComponent, except?: ForwardException[]): (node: HTMLElement | SVGElement) => {
destroy: () => void;
};
export {};

@@ -1,2 +0,2 @@

import { bubble, listen, prevent_default, stop_propagation, } from 'svelte/internal';
import { bubble, listen, prevent_default, stop_propagation, } from "svelte/internal";
const MODIFIER_DIVIDER = "!";

@@ -13,11 +13,22 @@ const modifierRegex = new RegExp(`^[^${MODIFIER_DIVIDER}]+(?:${MODIFIER_DIVIDER}(?:preventDefault|stopPropagation|passive|nonpassive|capture|once|self))+$`);

let destructor = () => { };
if (except.includes(eventType)) {
// Bail out of the event forwarding and run the normal Svelte $on() code
const callbacks = (component.$$.callbacks[eventType] || (component.$$.callbacks[eventType] = []));
callbacks.push(callback);
return () => {
const index = callbacks.indexOf(callback);
if (index !== -1)
callbacks.splice(index, 1);
};
for (let exception of except) {
if (typeof exception === "string" && exception === eventType) {
// Bail out of the event forwarding and run the normal Svelte $on() code
const callbacks = component.$$.callbacks[eventType] ||
(component.$$.callbacks[eventType] = []);
callbacks.push(callback);
return () => {
const index = callbacks.indexOf(callback);
if (index !== -1)
callbacks.splice(index, 1);
};
}
if (typeof exception === "object" && exception["name"] === eventType) {
let oldCallback = callback;
callback = (...props) => {
if (!(typeof exception === "object" && exception["shouldExclude"]())) {
oldCallback(...props);
}
};
}
}

@@ -24,0 +35,0 @@ if ($on) {

@@ -18,3 +18,3 @@ {

"repository": "github:rgossiaux/svelte-headlessui",
"version": "1.0.0-beta.4",
"version": "1.0.0-beta.5",
"peerDependencies": {

@@ -21,0 +21,0 @@ "svelte": "^3.44.0"

# svelte-headlessui
This is an unofficial, complete Svelte port of the Headless UI component library (https://headlessui.dev/). It contains **fully accessible, feature-rich, unstyled** UI components.
This is an unofficial, complete Svelte port of the Headless UI component library (https://headlessui.dev/). It contains **fully accessible, feature-rich, unstyled** UI components.

@@ -9,8 +9,8 @@ ## Who is this for?

* You want unstyled yet sophisticated customizable UI components that fully follow the WAI-ARIA specs. You want a component library to handle all the messy details (keyboard navigation, focus management, aria-* attributes, and many many more), but you want to style your components yourself and not be constrained by existing design systems like Material UI.
* You want to use the commercial Tailwind UI component library (https://tailwindui.com/) in your Svelte project, and want a drop-in replacement for the React components which power Tailwind UI.
- You want unstyled yet sophisticated customizable UI components that fully follow the WAI-ARIA specs. You want a component library to handle all the messy details (keyboard navigation, focus management, aria-\* attributes, and many many more), but you want to style your components yourself and not be constrained by existing design systems like Material UI.
- You want to use the commercial Tailwind UI component library (https://tailwindui.com/) in your Svelte project, and want a drop-in replacement for the React components which power Tailwind UI.
This project is intended to keep an API as close as possible to the React API for the base Headless UI project, with only a few small differences. While one of the primary goals is to enable using Tailwind UI in a Svelte project with as little effort as possible, **neither Tailwind UI nor Tailwind CSS is required** to use these components.
This project is intended to keep an API as close as possible to the React API for the base Headless UI project, with only a few small differences. While one of the primary goals is to enable using Tailwind UI in a Svelte project with as little effort as possible, **neither Tailwind UI nor Tailwind CSS is required** to use these components.
This project is an **unofficial** port. I have no affiliation with Tailwind Labs and cannot offer commercial support for this project. With that said, I intend to keep it as up to date as possible with the upstream Headless UI project, including porting new components when they are released.
This project is an **unofficial** port. I have no affiliation with Tailwind Labs and cannot offer commercial support for this project. With that said, I intend to keep it as up to date as possible with the upstream Headless UI project, including porting new components when they are released.

@@ -26,4 +26,6 @@ ## Installation

For now, until I write separate documentation, you can refer to the [Headless UI React documentation](https://headlessui.dev/). The API is nearly identical to the React API there, with the following differences:
* Components do not have . in their names; use `ListboxButton` instead of `Listbox.Button`
* Event handlers are done Svelte-style with custom events:
- Components do not have . in their names; use `ListboxButton` instead of `Listbox.Button`
- Event handlers are done Svelte-style with custom events:
```

@@ -43,3 +45,4 @@ // React version

* Instead of render props, we use Svelte's [slot props](https://svelte.dev/tutorial/slot-props):
- Instead of render props, we use Svelte's [slot props](https://svelte.dev/tutorial/slot-props):
```

@@ -56,4 +59,6 @@ // React version

```
* When porting React code, HTML attributes use their real names instead of the camelCased React versions. In particular, use `class=` instead of `className=`.
* When porting React code, use `{#each}` instead of `.map` (don't forget to add a key!):
- When porting React code, HTML attributes use their real names instead of the camelCased React versions. In particular, use `class=` instead of `className=`.
- When porting React code, use `{#each}` instead of `.map` (don't forget to add a key!):
```

@@ -65,3 +70,3 @@ // React version

...
<!--- Svelte version --->

@@ -72,12 +77,15 @@ {#each people as person (person.id)}

```
Similarly, React's `{value && (<Component />)}` style syntax becomes `{#if value} <Component /> {/if}` in Svelte, of course.
* While the `as` prop is supported, `as={Fragment}` support is not possible due to limitations in Svelte itself. You'll have to settle for rendering a `div` or similar. Usually this won't cause any problems, especially if you are writing your own code, but if you are porting React Headless UI code that both uses `as={Fragment}` and `z-index`, your div could possibly create a new [stacking context](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context), causing the `z-index` to not work correctly. If this happens, you can fix by copying the `z-index` (and a relevant `position`) to the component that used to render as a `Fragment`.
Furthermore, specific to Svelte, you may
* Pass [actions](https://svelte.dev/tutorial/actions) to any component in this library using the `use` prop, with the syntax `use={[[action1, action1options], [action2], [action3, action3options], ...]}`, and they will be forwarded to the underlying DOM element.
* Add your own event listeners with modifiers, which will be forwarded to the underyling DOM element. Modifiers are separated with the `!` character instead of the normal `|`: `on:click!capture={(e) => ...}`
- While the `as` prop is supported, `as={Fragment}` support is not possible due to limitations in Svelte itself. You'll have to settle for rendering a `div` or similar. Usually this won't cause any problems, especially if you are writing your own code, but if you are porting React Headless UI code that both uses `as={Fragment}` and `z-index`, your div could possibly create a new [stacking context](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context), causing the `z-index` to not work correctly. If this happens, you can fix by copying the `z-index` (and a relevant `position`) to the component that used to render as a `Fragment`.
Furthermore, specific to Svelte, you may
- Pass [actions](https://svelte.dev/tutorial/actions) to any component in this library using the `use` prop, with the syntax `use={[[action1, action1options], [action2], [action3, action3options], ...]}`, and they will be forwarded to the underlying DOM element.
- Add your own event listeners with modifiers, which will be forwarded to the underyling DOM element. Modifiers are separated with the `!` character instead of the normal `|`: `on:click!capture={(e) => ...}`
## Credits
Credit for everything good about this library goes to Tailwind Labs for writing the original React/Vue versions. All bugs should be assumed to be my fault in the port (though as the codebases are so similar, bugs in upstream will likely affect this library too).
Credit for everything good about this library goes to Tailwind Labs for writing the original React/Vue versions. All bugs should be assumed to be my fault in the port (though as the codebases are so similar, bugs in upstream will likely affect this library too).

@@ -84,0 +92,0 @@ Additional thanks to https://github.com/hperrin/svelte-material-ui; this well-engineered Svelte library was the source of the action and event forwarding code, with minor modifications.

@@ -49,3 +49,3 @@ export declare function getMenuButton(): HTMLElement | null;

state: ListboxState;
orientation?: 'horizontal' | 'vertical';
orientation?: "horizontal" | "vertical";
}, listbox?: HTMLElement | null): void;

@@ -175,3 +175,3 @@ export declare function assertListboxButton(options: {

active: number;
orientation?: 'vertical' | 'horizontal';
orientation?: "vertical" | "horizontal";
}, list?: HTMLElement | null, tabs?: HTMLElement[], panels?: HTMLElement[]): void;

@@ -178,0 +178,0 @@ export declare function assertActiveElement(element: HTMLElement | null): void;

@@ -1,4 +0,4 @@

import { isFocusableElement, FocusableMode } from '../utils/focus-management';
import { isFocusableElement, FocusableMode } from "../utils/focus-management";
function assertNever(x) {
throw new Error('Unexpected object: ' + x);
throw new Error("Unexpected object: " + x);
}

@@ -36,25 +36,25 @@ // ---

// Ensure menu button have these properties
expect(button).toHaveAttribute('id');
expect(button).toHaveAttribute('aria-haspopup');
expect(button).toHaveAttribute("id");
expect(button).toHaveAttribute("aria-haspopup");
switch (options.state) {
case MenuState.Visible:
expect(button).toHaveAttribute('aria-controls');
expect(button).toHaveAttribute('aria-expanded', 'true');
expect(button).toHaveAttribute("aria-controls");
expect(button).toHaveAttribute("aria-expanded", "true");
break;
case MenuState.InvisibleHidden:
expect(button).toHaveAttribute('aria-controls');
if (button.hasAttribute('disabled')) {
expect(button).not.toHaveAttribute('aria-expanded');
expect(button).toHaveAttribute("aria-controls");
if (button.hasAttribute("disabled")) {
expect(button).not.toHaveAttribute("aria-expanded");
}
else {
expect(button).toHaveAttribute('aria-expanded', 'false');
expect(button).toHaveAttribute("aria-expanded", "false");
}
break;
case MenuState.InvisibleUnmounted:
expect(button).not.toHaveAttribute('aria-controls');
if (button.hasAttribute('disabled')) {
expect(button).not.toHaveAttribute('aria-expanded');
expect(button).not.toHaveAttribute("aria-controls");
if (button.hasAttribute("disabled")) {
expect(button).not.toHaveAttribute("aria-expanded");
}
else {
expect(button).toHaveAttribute('aria-expanded', 'false');
expect(button).toHaveAttribute("aria-expanded", "false");
}

@@ -85,4 +85,4 @@ break;

// Ensure link between button & menu is correct
expect(button).toHaveAttribute('aria-controls', menu.getAttribute('id'));
expect(menu).toHaveAttribute('aria-labelledby', button.getAttribute('id'));
expect(button).toHaveAttribute("aria-controls", menu.getAttribute("id"));
expect(menu).toHaveAttribute("aria-labelledby", button.getAttribute("id"));
}

@@ -101,3 +101,3 @@ catch (err) {

// Ensure link between menu & menu item is correct
expect(menu).toHaveAttribute('aria-activedescendant', item.getAttribute('id'));
expect(menu).toHaveAttribute("aria-activedescendant", item.getAttribute("id"));
}

@@ -114,3 +114,3 @@ catch (err) {

// Ensure we don't have an active menu
expect(menu).not.toHaveAttribute('aria-activedescendant');
expect(menu).not.toHaveAttribute("aria-activedescendant");
}

@@ -129,4 +129,4 @@ catch (err) {

assertHidden(menu);
expect(menu).toHaveAttribute('aria-labelledby');
expect(menu).toHaveAttribute('role', 'menu');
expect(menu).toHaveAttribute("aria-labelledby");
expect(menu).toHaveAttribute("role", "menu");
if (options.textContent)

@@ -142,4 +142,4 @@ expect(menu).toHaveTextContent(options.textContent);

assertVisible(menu);
expect(menu).toHaveAttribute('aria-labelledby');
expect(menu).toHaveAttribute('role', 'menu');
expect(menu).toHaveAttribute("aria-labelledby");
expect(menu).toHaveAttribute("role", "menu");
if (options.textContent)

@@ -169,7 +169,7 @@ expect(menu).toHaveTextContent(options.textContent);

// time, we just require them.
expect(item).toHaveAttribute('id');
expect(item).toHaveAttribute("id");
// Check that we have the correct values for certain attributes
expect(item).toHaveAttribute('role', 'menuitem');
if (!item.getAttribute('aria-disabled'))
expect(item).toHaveAttribute('tabindex', '-1');
expect(item).toHaveAttribute("role", "menuitem");
if (!item.getAttribute("aria-disabled"))
expect(item).toHaveAttribute("tabindex", "-1");
// Ensure menu button has the following attributes

@@ -220,3 +220,3 @@ if (options) {

export function assertListbox(options, listbox = getListbox()) {
let { orientation = 'vertical' } = options;
let { orientation = "vertical" } = options;
try {

@@ -228,5 +228,5 @@ switch (options.state) {

assertHidden(listbox);
expect(listbox).toHaveAttribute('aria-labelledby');
expect(listbox).toHaveAttribute('aria-orientation', orientation);
expect(listbox).toHaveAttribute('role', 'listbox');
expect(listbox).toHaveAttribute("aria-labelledby");
expect(listbox).toHaveAttribute("aria-orientation", orientation);
expect(listbox).toHaveAttribute("role", "listbox");
if (options.textContent)

@@ -242,5 +242,5 @@ expect(listbox).toHaveTextContent(options.textContent);

assertVisible(listbox);
expect(listbox).toHaveAttribute('aria-labelledby');
expect(listbox).toHaveAttribute('aria-orientation', orientation);
expect(listbox).toHaveAttribute('role', 'listbox');
expect(listbox).toHaveAttribute("aria-labelledby");
expect(listbox).toHaveAttribute("aria-orientation", orientation);
expect(listbox).toHaveAttribute("role", "listbox");
if (options.textContent)

@@ -269,25 +269,25 @@ expect(listbox).toHaveTextContent(options.textContent);

// Ensure menu button have these properties
expect(button).toHaveAttribute('id');
expect(button).toHaveAttribute('aria-haspopup');
expect(button).toHaveAttribute("id");
expect(button).toHaveAttribute("aria-haspopup");
switch (options.state) {
case ListboxState.Visible:
expect(button).toHaveAttribute('aria-controls');
expect(button).toHaveAttribute('aria-expanded', 'true');
expect(button).toHaveAttribute("aria-controls");
expect(button).toHaveAttribute("aria-expanded", "true");
break;
case ListboxState.InvisibleHidden:
expect(button).toHaveAttribute('aria-controls');
if (button.hasAttribute('disabled')) {
expect(button).not.toHaveAttribute('aria-expanded');
expect(button).toHaveAttribute("aria-controls");
if (button.hasAttribute("disabled")) {
expect(button).not.toHaveAttribute("aria-expanded");
}
else {
expect(button).toHaveAttribute('aria-expanded', 'false');
expect(button).toHaveAttribute("aria-expanded", "false");
}
break;
case ListboxState.InvisibleUnmounted:
expect(button).not.toHaveAttribute('aria-controls');
if (button.hasAttribute('disabled')) {
expect(button).not.toHaveAttribute('aria-expanded');
expect(button).not.toHaveAttribute("aria-controls");
if (button.hasAttribute("disabled")) {
expect(button).not.toHaveAttribute("aria-expanded");
}
else {
expect(button).toHaveAttribute('aria-expanded', 'false');
expect(button).toHaveAttribute("aria-expanded", "false");
}

@@ -316,3 +316,3 @@ break;

// Ensure menu button have these properties
expect(label).toHaveAttribute('id');
expect(label).toHaveAttribute("id");
if (options.textContent) {

@@ -341,4 +341,4 @@ expect(label).toHaveTextContent(options.textContent);

// Ensure link between button & listbox is correct
expect(button).toHaveAttribute('aria-controls', listbox.getAttribute('id'));
expect(listbox).toHaveAttribute('aria-labelledby', button.getAttribute('id'));
expect(button).toHaveAttribute("aria-controls", listbox.getAttribute("id"));
expect(listbox).toHaveAttribute("aria-labelledby", button.getAttribute("id"));
}

@@ -356,3 +356,3 @@ catch (err) {

return expect(listbox).not.toBe(null);
expect(listbox).toHaveAttribute('aria-labelledby', label.getAttribute('id'));
expect(listbox).toHaveAttribute("aria-labelledby", label.getAttribute("id"));
}

@@ -371,3 +371,3 @@ catch (err) {

// Ensure link between button & label is correct
expect(button).toHaveAttribute('aria-labelledby', `${label.id} ${button.id}`);
expect(button).toHaveAttribute("aria-labelledby", `${label.id} ${button.id}`);
}

@@ -386,3 +386,3 @@ catch (err) {

// Ensure link between listbox & listbox item is correct
expect(listbox).toHaveAttribute('aria-activedescendant', item.getAttribute('id'));
expect(listbox).toHaveAttribute("aria-activedescendant", item.getAttribute("id"));
}

@@ -399,3 +399,3 @@ catch (err) {

// Ensure we don't have an active listbox
expect(listbox).not.toHaveAttribute('aria-activedescendant');
expect(listbox).not.toHaveAttribute("aria-activedescendant");
}

@@ -410,3 +410,3 @@ catch (err) {

for (let item of items)
expect(item).not.toHaveAttribute('aria-selected');
expect(item).not.toHaveAttribute("aria-selected");
}

@@ -424,7 +424,7 @@ catch (err) {

// time, we just require them.
expect(item).toHaveAttribute('id');
expect(item).toHaveAttribute("id");
// Check that we have the correct values for certain attributes
expect(item).toHaveAttribute('role', 'option');
if (!item.getAttribute('aria-disabled'))
expect(item).toHaveAttribute('tabindex', '-1');
expect(item).toHaveAttribute("role", "option");
if (!item.getAttribute("aria-disabled"))
expect(item).toHaveAttribute("tabindex", "-1");
// Ensure listbox button has the following attributes

@@ -442,5 +442,5 @@ if (!options)

case true:
return expect(item).toHaveAttribute('aria-selected', 'true');
return expect(item).toHaveAttribute("aria-selected", "true");
case false:
return expect(item).not.toHaveAttribute('aria-selected');
return expect(item).not.toHaveAttribute("aria-selected");
default:

@@ -473,4 +473,4 @@ assertNever(options.selected);

return expect(switchElement).not.toBe(null);
expect(switchElement).toHaveAttribute('role', 'switch');
expect(switchElement).toHaveAttribute('tabindex', '0');
expect(switchElement).toHaveAttribute("role", "switch");
expect(switchElement).toHaveAttribute("tabindex", "0");
if (options.textContent) {

@@ -490,6 +490,6 @@ expect(switchElement).toHaveTextContent(options.textContent);

case SwitchState.On:
expect(switchElement).toHaveAttribute('aria-checked', 'true');
expect(switchElement).toHaveAttribute("aria-checked", "true");
break;
case SwitchState.Off:
expect(switchElement).toHaveAttribute('aria-checked', 'false');
expect(switchElement).toHaveAttribute("aria-checked", "false");
break;

@@ -528,24 +528,24 @@ default:

// Ensure disclosure button have these properties
expect(button).toHaveAttribute('id');
expect(button).toHaveAttribute("id");
switch (options.state) {
case DisclosureState.Visible:
expect(button).toHaveAttribute('aria-controls');
expect(button).toHaveAttribute('aria-expanded', 'true');
expect(button).toHaveAttribute("aria-controls");
expect(button).toHaveAttribute("aria-expanded", "true");
break;
case DisclosureState.InvisibleHidden:
expect(button).toHaveAttribute('aria-controls');
if (button.hasAttribute('disabled')) {
expect(button).not.toHaveAttribute('aria-expanded');
expect(button).toHaveAttribute("aria-controls");
if (button.hasAttribute("disabled")) {
expect(button).not.toHaveAttribute("aria-expanded");
}
else {
expect(button).toHaveAttribute('aria-expanded', 'false');
expect(button).toHaveAttribute("aria-expanded", "false");
}
break;
case DisclosureState.InvisibleUnmounted:
expect(button).not.toHaveAttribute('aria-controls');
if (button.hasAttribute('disabled')) {
expect(button).not.toHaveAttribute('aria-expanded');
expect(button).not.toHaveAttribute("aria-controls");
if (button.hasAttribute("disabled")) {
expect(button).not.toHaveAttribute("aria-expanded");
}
else {
expect(button).toHaveAttribute('aria-expanded', 'false');
expect(button).toHaveAttribute("aria-expanded", "false");
}

@@ -630,24 +630,24 @@ break;

// Ensure popover button have these properties
expect(button).toHaveAttribute('id');
expect(button).toHaveAttribute("id");
switch (options.state) {
case PopoverState.Visible:
expect(button).toHaveAttribute('aria-controls');
expect(button).toHaveAttribute('aria-expanded', 'true');
expect(button).toHaveAttribute("aria-controls");
expect(button).toHaveAttribute("aria-expanded", "true");
break;
case PopoverState.InvisibleHidden:
expect(button).toHaveAttribute('aria-controls');
if (button.hasAttribute('disabled')) {
expect(button).not.toHaveAttribute('aria-expanded');
expect(button).toHaveAttribute("aria-controls");
if (button.hasAttribute("disabled")) {
expect(button).not.toHaveAttribute("aria-expanded");
}
else {
expect(button).toHaveAttribute('aria-expanded', 'false');
expect(button).toHaveAttribute("aria-expanded", "false");
}
break;
case PopoverState.InvisibleUnmounted:
expect(button).not.toHaveAttribute('aria-controls');
if (button.hasAttribute('disabled')) {
expect(button).not.toHaveAttribute('aria-expanded');
expect(button).not.toHaveAttribute("aria-controls");
if (button.hasAttribute("disabled")) {
expect(button).not.toHaveAttribute("aria-expanded");
}
else {
expect(button).toHaveAttribute('aria-expanded', 'false');
expect(button).toHaveAttribute("aria-expanded", "false");
}

@@ -710,12 +710,13 @@ break;

return expect(element).not.toBe(null);
if (element.hasAttribute('aria-labelledby')) {
let ids = element.getAttribute('aria-labelledby').split(' ');
expect(ids.map(id => document.getElementById(id)?.textContent).join(' ')).toEqual(value);
if (element.hasAttribute("aria-labelledby")) {
let ids = element.getAttribute("aria-labelledby").split(" ");
expect(ids.map((id) => document.getElementById(id)?.textContent).join(" ")).toEqual(value);
return;
}
if (element.hasAttribute('aria-label')) {
expect(element).toHaveAttribute('aria-label', value);
if (element.hasAttribute("aria-label")) {
expect(element).toHaveAttribute("aria-label", value);
return;
}
if (element.hasAttribute('id') && document.querySelectorAll(`[for="${element.id}"]`).length > 0) {
if (element.hasAttribute("id") &&
document.querySelectorAll(`[for="${element.id}"]`).length > 0) {
expect(document.querySelector(`[for="${element.id}"]`)).toHaveTextContent(value);

@@ -730,3 +731,3 @@ return;

return expect(element).not.toBe(null);
let id = element.getAttribute('aria-describedby');
let id = element.getAttribute("aria-describedby");
expect(document.getElementById(id)?.textContent).toEqual(value);

@@ -771,4 +772,4 @@ }

assertHidden(dialog);
expect(dialog).toHaveAttribute('role', 'dialog');
expect(dialog).not.toHaveAttribute('aria-modal', 'true');
expect(dialog).toHaveAttribute("role", "dialog");
expect(dialog).not.toHaveAttribute("aria-modal", "true");
if (options.textContent)

@@ -784,4 +785,4 @@ expect(dialog).toHaveTextContent(options.textContent);

assertVisible(dialog);
expect(dialog).toHaveAttribute('role', 'dialog');
expect(dialog).toHaveAttribute('aria-modal', 'true');
expect(dialog).toHaveAttribute("role", "dialog");
expect(dialog).toHaveAttribute("aria-modal", "true");
if (options.textContent)

@@ -814,4 +815,4 @@ expect(dialog).toHaveTextContent(options.textContent);

assertHidden(title);
expect(title).toHaveAttribute('id');
expect(dialog).toHaveAttribute('aria-labelledby', title.id);
expect(title).toHaveAttribute("id");
expect(dialog).toHaveAttribute("aria-labelledby", title.id);
if (options.textContent)

@@ -829,4 +830,4 @@ expect(title).toHaveTextContent(options.textContent);

assertVisible(title);
expect(title).toHaveAttribute('id');
expect(dialog).toHaveAttribute('aria-labelledby', title.id);
expect(title).toHaveAttribute("id");
expect(dialog).toHaveAttribute("aria-labelledby", title.id);
if (options.textContent)

@@ -859,4 +860,4 @@ expect(title).toHaveTextContent(options.textContent);

assertHidden(description);
expect(description).toHaveAttribute('id');
expect(dialog).toHaveAttribute('aria-describedby', description.id);
expect(description).toHaveAttribute("id");
expect(dialog).toHaveAttribute("aria-describedby", description.id);
if (options.textContent)

@@ -874,4 +875,4 @@ expect(description).toHaveTextContent(options.textContent);

assertVisible(description);
expect(description).toHaveAttribute('id');
expect(dialog).toHaveAttribute('aria-describedby', description.id);
expect(description).toHaveAttribute("id");
expect(dialog).toHaveAttribute("aria-describedby", description.id);
if (options.textContent)

@@ -947,4 +948,4 @@ expect(description).toHaveTextContent(options.textContent);

return expect(radioGroup).not.toBe(null);
expect(label).toHaveAttribute('id');
expect(radioGroup).toHaveAttribute('aria-labelledby', label.id);
expect(label).toHaveAttribute("id");
expect(radioGroup).toHaveAttribute("aria-labelledby", label.id);
if (options.textContent)

@@ -972,42 +973,42 @@ expect(label).toHaveTextContent(options.textContent);

// ---
export function assertTabs({ active, orientation = 'horizontal', }, list = getTabList(), tabs = getTabs(), panels = getPanels()) {
export function assertTabs({ active, orientation = "horizontal", }, list = getTabList(), tabs = getTabs(), panels = getPanels()) {
try {
if (list === null)
return expect(list).not.toBe(null);
expect(list).toHaveAttribute('role', 'tablist');
expect(list).toHaveAttribute('aria-orientation', orientation);
let activeTab = tabs.find(tab => tab.dataset.headlessuiIndex === '' + active);
let activePanel = panels.find(panel => panel.dataset.headlessuiIndex === '' + active);
expect(list).toHaveAttribute("role", "tablist");
expect(list).toHaveAttribute("aria-orientation", orientation);
let activeTab = tabs.find((tab) => tab.dataset.headlessuiIndex === "" + active);
let activePanel = panels.find((panel) => panel.dataset.headlessuiIndex === "" + active);
for (let tab of tabs) {
expect(tab).toHaveAttribute('id');
expect(tab).toHaveAttribute('role', 'tab');
expect(tab).toHaveAttribute('type', 'button');
expect(tab).toHaveAttribute("id");
expect(tab).toHaveAttribute("role", "tab");
expect(tab).toHaveAttribute("type", "button");
if (tab === activeTab) {
expect(tab).toHaveAttribute('aria-selected', 'true');
expect(tab).toHaveAttribute('tabindex', '0');
expect(tab).toHaveAttribute("aria-selected", "true");
expect(tab).toHaveAttribute("tabindex", "0");
}
else {
expect(tab).toHaveAttribute('aria-selected', 'false');
expect(tab).toHaveAttribute('tabindex', '-1');
expect(tab).toHaveAttribute("aria-selected", "false");
expect(tab).toHaveAttribute("tabindex", "-1");
}
if (tab.hasAttribute('aria-controls')) {
let controlsId = tab.getAttribute('aria-controls');
if (tab.hasAttribute("aria-controls")) {
let controlsId = tab.getAttribute("aria-controls");
let panel = document.getElementById(controlsId);
expect(panel).not.toBe(null);
expect(panels).toContain(panel);
expect(panel).toHaveAttribute('aria-labelledby', tab.id);
expect(panel).toHaveAttribute("aria-labelledby", tab.id);
}
}
for (let panel of panels) {
expect(panel).toHaveAttribute('id');
expect(panel).toHaveAttribute('role', 'tabpanel');
let controlledById = panel.getAttribute('aria-labelledby');
expect(panel).toHaveAttribute("id");
expect(panel).toHaveAttribute("role", "tabpanel");
let controlledById = panel.getAttribute("aria-labelledby");
let tab = document.getElementById(controlledById);
expect(tabs).toContain(tab);
expect(tab).toHaveAttribute('aria-controls', panel.id);
expect(tab).toHaveAttribute("aria-controls", panel.id);
if (panel === activePanel) {
expect(panel).toHaveAttribute('tabindex', '0');
expect(panel).toHaveAttribute("tabindex", "0");
}
else {
expect(panel).toHaveAttribute('tabindex', '-1');
expect(panel).toHaveAttribute("tabindex", "-1");
}

@@ -1058,4 +1059,4 @@ }

return expect(element).not.toBe(null);
expect(element).toHaveAttribute('hidden');
expect(element).toHaveStyle({ display: 'none' });
expect(element).toHaveAttribute("hidden");
expect(element).toHaveStyle({ display: "none" });
}

@@ -1071,4 +1072,4 @@ catch (err) {

return expect(element).not.toBe(null);
expect(element).not.toHaveAttribute('hidden');
expect(element).not.toHaveStyle({ display: 'none' });
expect(element).not.toHaveAttribute("hidden");
expect(element).not.toHaveStyle({ display: "none" });
}

@@ -1075,0 +1076,0 @@ catch (err) {

import { tick } from "svelte";
import { fireEvent } from '@testing-library/svelte';
import { fireEvent } from "@testing-library/svelte";
export let Keys = {
Space: { key: ' ', keyCode: 32, charCode: 32 },
Enter: { key: 'Enter', keyCode: 13, charCode: 13 },
Escape: { key: 'Escape', keyCode: 27, charCode: 27 },
Backspace: { key: 'Backspace', keyCode: 8 },
ArrowLeft: { key: 'ArrowLeft', keyCode: 37 },
ArrowUp: { key: 'ArrowUp', keyCode: 38 },
ArrowRight: { key: 'ArrowRight', keyCode: 39 },
ArrowDown: { key: 'ArrowDown', keyCode: 40 },
Home: { key: 'Home', keyCode: 36 },
End: { key: 'End', keyCode: 35 },
PageUp: { key: 'PageUp', keyCode: 33 },
PageDown: { key: 'PageDown', keyCode: 34 },
Tab: { key: 'Tab', keyCode: 9, charCode: 9 },
Space: { key: " ", keyCode: 32, charCode: 32 },
Enter: { key: "Enter", keyCode: 13, charCode: 13 },
Escape: { key: "Escape", keyCode: 27, charCode: 27 },
Backspace: { key: "Backspace", keyCode: 8 },
ArrowLeft: { key: "ArrowLeft", keyCode: 37 },
ArrowUp: { key: "ArrowUp", keyCode: 38 },
ArrowRight: { key: "ArrowRight", keyCode: 39 },
ArrowDown: { key: "ArrowDown", keyCode: 40 },
Home: { key: "Home", keyCode: 36 },
End: { key: "End", keyCode: 35 },
PageUp: { key: "PageUp", keyCode: 33 },
PageDown: { key: "PageDown", keyCode: 34 },
Tab: { key: "Tab", keyCode: 9, charCode: 9 },
};

@@ -22,3 +22,3 @@ export function shift(event) {

export function word(input) {
return input.split('').map(key => ({ key }));
return input.split("").map((key) => ({ key }));
}

@@ -29,3 +29,3 @@ let Default = Symbol();

[Default]: {
keydown: new Set(['keypress']),
keydown: new Set(["keypress"]),
keypress: new Set([]),

@@ -35,13 +35,13 @@ keyup: new Set([]),

[Keys.Enter.key]: {
keydown: new Set(['keypress', 'click']),
keypress: new Set(['click']),
keydown: new Set(["keypress", "click"]),
keypress: new Set(["click"]),
keyup: new Set([]),
},
[Keys.Space.key]: {
keydown: new Set(['keypress', 'click']),
keydown: new Set(["keypress", "click"]),
keypress: new Set([]),
keyup: new Set(['click']),
keyup: new Set(["click"]),
},
[Keys.Tab.key]: {
keydown: new Set(['keypress', 'blur', 'focus']),
keydown: new Set(["keypress", "blur", "focus"]),
keypress: new Set([]),

@@ -116,4 +116,4 @@ keyup: new Set([]),

for (let action of actions) {
let checks = action.name.split('And');
if (checks.some(check => skip.has(check)))
let checks = action.name.split("And");
if (checks.some((check) => skip.has(check)))
continue;

@@ -276,20 +276,19 @@ let result = await action(element, {

let focusableSelector = [
'[contentEditable=true]',
'[tabindex]',
'a[href]',
'area[href]',
'button:not([disabled])',
'iframe',
'input:not([disabled])',
'select:not([disabled])',
'textarea:not([disabled])',
"[contentEditable=true]",
"[tabindex]",
"a[href]",
"area[href]",
"button:not([disabled])",
"iframe",
"input:not([disabled])",
"select:not([disabled])",
"textarea:not([disabled])",
]
.map(process.env.NODE_ENV === 'test'
.map(process.env.NODE_ENV === "test"
? // TODO: Remove this once JSDOM fixes the issue where an element that is
// "hidden" can be the document.activeElement, because this is not possible
// in real browsers.
// TODO: Remove this once JSDOM fixes the issue where an element that is
selector => `${selector}:not([tabindex='-1']):not([style*='display: none'])`
: selector => `${selector}:not([tabindex='-1'])`)
.join(',');
(selector) => `${selector}:not([tabindex='-1']):not([style*='display: none'])`
: (selector) => `${selector}:not([tabindex='-1'])`)
.join(",");
function getFocusableElements(container = document.body) {

@@ -296,0 +295,0 @@ if (!container)

@@ -1,2 +0,2 @@

export function suppressConsoleLogs(cb, type = 'error') {
export function suppressConsoleLogs(cb, type = "error") {
return (...args) => {

@@ -3,0 +3,0 @@ let spy = jest.spyOn(global.console, type).mockImplementation(jest.fn());

@@ -8,2 +8,4 @@ import { SvelteComponentTyped } from "svelte";

onKeydown?: HandlerType;
onSubmit?: HandlerType;
onClick?: HandlerType;
}

@@ -10,0 +12,0 @@ declare type SingleComponent = string | [SvelteComponent, ComponentProps, TestRendererProps];

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc