From db2c2b31fd2fad944c81ebd834a9b55783fa4529 Mon Sep 17 00:00:00 2001 From: sj Date: Tue, 10 Dec 2024 09:59:41 -0500 Subject: [PATCH] Added Description and a DescriptionProvider --- src/lib/checkbox/Checkbox.svelte | 9 +- src/lib/description/Description.svelte | 63 ++++++++++++++ .../description/DescriptionProvider.svelte | 71 ++++++++++++++++ src/lib/description/description.dom.test.ts | 85 +++++++++++++++++++ src/lib/field/Field.svelte | 33 +++---- src/lib/input/Input.svelte | 10 ++- src/lib/label/label.dom.test.ts | 85 +++++++++++++++++++ src/lib/select/Select.svelte | 8 +- src/lib/select/select.dom.test.ts | 4 +- src/lib/switch/Switch.svelte | 9 +- src/lib/textarea/Textarea.svelte | 4 +- src/routes/(main)/nav.svelte | 10 ++- src/routes/examples/fieldset/+page.svelte | 62 ++++++-------- src/routes/examples/select/+page.svelte | 5 +- src/routes/examples/textarea/+page.svelte | 4 +- 15 files changed, 395 insertions(+), 67 deletions(-) create mode 100644 src/lib/description/Description.svelte create mode 100644 src/lib/description/DescriptionProvider.svelte create mode 100644 src/lib/description/description.dom.test.ts create mode 100644 src/lib/label/label.dom.test.ts diff --git a/src/lib/checkbox/Checkbox.svelte b/src/lib/checkbox/Checkbox.svelte index 692af57..81f5f85 100644 --- a/src/lib/checkbox/Checkbox.svelte +++ b/src/lib/checkbox/Checkbox.svelte @@ -2,6 +2,8 @@ import type { Component, Snippet } from "svelte"; import { useId } from "$lib/internal/hooks/use-id"; import { useDisabled } from "$lib/internal/DisabledProvider.svelte"; + import { useDescribedBy } from "$lib/description/DescriptionProvider.svelte"; + import { useLabelledBy } from "$lib/label/LabelProvider.svelte"; type Props = { /** The element or component the checkbox should render as. */ @@ -70,6 +72,9 @@ toggle(); } + let describedBy = $derived(useDescribedBy()); + let labelledBy = $derived(useLabelledBy()); + let ourProps = $derived({ id, autofocus, @@ -77,8 +82,8 @@ role: "checkbox", "aria-checked": checked, // "aria-invalid": invalid, // ? "" : undefined, - // "aria-labelledby": labelledBy, - // "aria-describedby": describedBy, + "aria-labelledby": labelledBy, + "aria-describedby": describedBy, onclick, }); diff --git a/src/lib/description/Description.svelte b/src/lib/description/Description.svelte new file mode 100644 index 0000000..19aaf3d --- /dev/null +++ b/src/lib/description/Description.svelte @@ -0,0 +1,63 @@ + + +{#if typeof as === "string"} + + {@render children?.(snippetProps)} + +{:else} + {@const AsComponent = as} + + {@render children?.(snippetProps)} + +{/if} diff --git a/src/lib/description/DescriptionProvider.svelte b/src/lib/description/DescriptionProvider.svelte new file mode 100644 index 0000000..0873b3e --- /dev/null +++ b/src/lib/description/DescriptionProvider.svelte @@ -0,0 +1,71 @@ + + + + + +{@render children?.()} +{@render describedBy?.({ descriptionIds })} diff --git a/src/lib/description/description.dom.test.ts b/src/lib/description/description.dom.test.ts new file mode 100644 index 0000000..cf8c7eb --- /dev/null +++ b/src/lib/description/description.dom.test.ts @@ -0,0 +1,85 @@ +import Description from "./Description.svelte"; +import type { SvelteComponent } from "svelte"; +import { render, screen } from "@testing-library/svelte"; +import { + assertActiveElement, + assertSwitch, + getByText, + getSwitch, + getSwitchLabel, + SwitchState, +} from "../../test-utils/accessibility-assertions"; +import { click, focus, Keys, mouseEnter, press } from "../../test-utils/interactions"; + +vi.mock("../../hooks/use-id"); + +it("empty", () => { +}); + +// it('should be possible to use a DescriptionProvider without using a Description', async () => { +// function Component(props: { children: ReactNode }) { +// let [describedby, DescriptionProvider] = useDescriptions() + +// return ( +// +//
{props.children}
+//
+// ) +// } + +// function Example() { +// return No description +// } + +// let { container } = render() +// expect(container.firstChild).toMatchSnapshot() +// }) + +// it('should be possible to use a DescriptionProvider and a single Description, and have them linked', async () => { +// function Component(props: { children: ReactNode }) { +// let [describedby, DescriptionProvider] = useDescriptions() + +// return ( +// +//
{props.children}
+//
+// ) +// } + +// function Example() { +// return ( +// +// I am a description +// Contents +// +// ) +// } + +// let { container } = render() +// expect(container.firstChild).toMatchSnapshot() +// }) + +// it('should be possible to use a DescriptionProvider and multiple Description components, and have them linked', async () => { +// function Component(props: { children: ReactNode }) { +// let [describedby, DescriptionProvider] = useDescriptions() + +// return ( +// +//
{props.children}
+//
+// ) +// } + +// function Example() { +// return ( +// +// I am a description +// Contents +// I am also a description +// +// ) +// } + +// let { container } = render() +// expect(container.firstChild).toMatchSnapshot() +// }) diff --git a/src/lib/field/Field.svelte b/src/lib/field/Field.svelte index b80b0cd..ee33231 100644 --- a/src/lib/field/Field.svelte +++ b/src/lib/field/Field.svelte @@ -3,6 +3,7 @@ import { useId } from "$lib/internal/hooks/use-id"; import LabelProvider from "$lib/label/LabelProvider.svelte"; import DisabledProvider, { useDisabled } from "$lib/internal/DisabledProvider.svelte"; + import DescriptionProvider from "$lib/description/DescriptionProvider.svelte"; type Props = { /** The element or component the checkbox should render as. */ @@ -44,20 +45,22 @@ - {#if typeof as === "string"} - - {@render children?.(snippetProps)} - - {:else} - {@const AsComponent = as} - - {@render children?.(snippetProps)} - - {/if} + + {#if typeof as === "string"} + + {@render children?.(snippetProps)} + + {:else} + {@const AsComponent = as} + + {@render children?.(snippetProps)} + + {/if} + diff --git a/src/lib/input/Input.svelte b/src/lib/input/Input.svelte index 5895f21..bb91a0b 100644 --- a/src/lib/input/Input.svelte +++ b/src/lib/input/Input.svelte @@ -1,6 +1,7 @@ diff --git a/src/lib/label/label.dom.test.ts b/src/lib/label/label.dom.test.ts new file mode 100644 index 0000000..e3d9cd6 --- /dev/null +++ b/src/lib/label/label.dom.test.ts @@ -0,0 +1,85 @@ +import Label from "./Label.svelte"; +import type { SvelteComponent } from "svelte"; +import { render, screen } from "@testing-library/svelte"; +import { + assertActiveElement, + assertSwitch, + getByText, + getSwitch, + getSwitchLabel, + SwitchState, +} from "../../test-utils/accessibility-assertions"; +import { click, focus, Keys, mouseEnter, press } from "../../test-utils/interactions"; + +vi.mock("../../hooks/use-id"); + +it("empty", () => { +}); + +// it('should be possible to use a LabelProvider without using a Label', async () => { +// function Component(props: { children: ReactNode }) { +// let [labelledby, LabelProvider] = useLabels() + +// return ( +// +//
{props.children}
+//
+// ) +// } + +// function Example() { +// return No label +// } + +// let { container } = render() +// expect(container.firstChild).toMatchSnapshot() +// }) + +// it('should be possible to use a LabelProvider and a single Label, and have them linked', async () => { +// function Component(props: { children: ReactNode }) { +// let [labelledby, LabelProvider] = useLabels() + +// return ( +// +//
{props.children}
+//
+// ) +// } + +// function Example() { +// return ( +// +// +// Contents +// +// ) +// } + +// let { container } = render() +// expect(container.firstChild).toMatchSnapshot() +// }) + +// it('should be possible to use a LabelProvider and multiple Label components, and have them linked', async () => { +// function Component(props: { children: ReactNode }) { +// let [labelledby, LabelProvider] = useLabels() + +// return ( +// +//
{props.children}
+//
+// ) +// } + +// function Example() { +// return ( +// +// +// Contents +// +// +// ) +// } + +// let { container } = render() +// expect(container.firstChild).toMatchSnapshot() +// }) diff --git a/src/lib/select/Select.svelte b/src/lib/select/Select.svelte index 08cb5d6..cdde08e 100644 --- a/src/lib/select/Select.svelte +++ b/src/lib/select/Select.svelte @@ -1,8 +1,9 @@