@dxlbnl/ui 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +94 -0
- package/dist/components/cards/Card.stories.svelte +82 -0
- package/dist/components/cards/Card.stories.svelte.d.ts +19 -0
- package/dist/components/cards/Card.svelte +28 -0
- package/dist/components/cards/Card.svelte.d.ts +12 -0
- package/dist/components/cards/NoteCard.stories.svelte +94 -0
- package/dist/components/cards/NoteCard.stories.svelte.d.ts +19 -0
- package/dist/components/cards/NoteCard.svelte +89 -0
- package/dist/components/cards/NoteCard.svelte.d.ts +18 -0
- package/dist/components/cards/ProductCard.stories.svelte +98 -0
- package/dist/components/cards/ProductCard.stories.svelte.d.ts +19 -0
- package/dist/components/cards/ProductCard.svelte +150 -0
- package/dist/components/cards/ProductCard.svelte.d.ts +22 -0
- package/dist/components/cards/ProjectCard.stories.svelte +88 -0
- package/dist/components/cards/ProjectCard.stories.svelte.d.ts +19 -0
- package/dist/components/cards/ProjectCard.svelte +109 -0
- package/dist/components/cards/ProjectCard.svelte.d.ts +20 -0
- package/dist/components/cards/index.d.ts +4 -0
- package/dist/components/cards/index.js +4 -0
- package/dist/components/data/Accordion.stories.svelte +316 -0
- package/dist/components/data/Accordion.stories.svelte.d.ts +19 -0
- package/dist/components/data/Accordion.svelte +23 -0
- package/dist/components/data/Accordion.svelte.d.ts +9 -0
- package/dist/components/data/AccordionItem.svelte +112 -0
- package/dist/components/data/AccordionItem.svelte.d.ts +11 -0
- package/dist/components/data/Table.composition.stories.svelte +67 -0
- package/dist/components/data/Table.composition.stories.svelte.d.ts +19 -0
- package/dist/components/data/Table.stories.svelte +137 -0
- package/dist/components/data/Table.stories.svelte.d.ts +19 -0
- package/dist/components/data/Table.svelte +83 -0
- package/dist/components/data/Table.svelte.d.ts +14 -0
- package/dist/components/data/Tabs.stories.svelte +386 -0
- package/dist/components/data/Tabs.stories.svelte.d.ts +19 -0
- package/dist/components/data/Tabs.svelte +142 -0
- package/dist/components/data/Tabs.svelte.d.ts +19 -0
- package/dist/components/data/index.d.ts +4 -0
- package/dist/components/data/index.js +4 -0
- package/dist/components/feedback/Modal.stories.svelte +192 -0
- package/dist/components/feedback/Modal.stories.svelte.d.ts +4 -0
- package/dist/components/feedback/Modal.svelte +185 -0
- package/dist/components/feedback/Modal.svelte.d.ts +19 -0
- package/dist/components/feedback/Toast.stories.svelte +203 -0
- package/dist/components/feedback/Toast.stories.svelte.d.ts +19 -0
- package/dist/components/feedback/Toast.svelte +109 -0
- package/dist/components/feedback/Toast.svelte.d.ts +15 -0
- package/dist/components/feedback/ToastRegion.stories.svelte +193 -0
- package/dist/components/feedback/ToastRegion.stories.svelte.d.ts +19 -0
- package/dist/components/feedback/ToastRegion.svelte +102 -0
- package/dist/components/feedback/ToastRegion.svelte.d.ts +9 -0
- package/dist/components/feedback/index.d.ts +3 -0
- package/dist/components/feedback/index.js +3 -0
- package/dist/components/forms/Checkbox.stories.svelte +103 -0
- package/dist/components/forms/Checkbox.stories.svelte.d.ts +19 -0
- package/dist/components/forms/Checkbox.svelte +150 -0
- package/dist/components/forms/Checkbox.svelte.d.ts +11 -0
- package/dist/components/forms/Field.stories.svelte +113 -0
- package/dist/components/forms/Field.stories.svelte.d.ts +19 -0
- package/dist/components/forms/Field.svelte +77 -0
- package/dist/components/forms/Field.svelte.d.ts +17 -0
- package/dist/components/forms/Input.stories.svelte +58 -0
- package/dist/components/forms/Input.stories.svelte.d.ts +19 -0
- package/dist/components/forms/Input.svelte +64 -0
- package/dist/components/forms/Input.svelte.d.ts +9 -0
- package/dist/components/forms/InputWrap.composition.stories.svelte +32 -0
- package/dist/components/forms/InputWrap.composition.stories.svelte.d.ts +19 -0
- package/dist/components/forms/InputWrap.stories.svelte +53 -0
- package/dist/components/forms/InputWrap.stories.svelte.d.ts +19 -0
- package/dist/components/forms/InputWrap.svelte +128 -0
- package/dist/components/forms/InputWrap.svelte.d.ts +21 -0
- package/dist/components/forms/Radio.stories.svelte +70 -0
- package/dist/components/forms/Radio.stories.svelte.d.ts +19 -0
- package/dist/components/forms/Radio.svelte +109 -0
- package/dist/components/forms/Radio.svelte.d.ts +9 -0
- package/dist/components/forms/RadioGroup.stories.svelte +115 -0
- package/dist/components/forms/RadioGroup.stories.svelte.d.ts +19 -0
- package/dist/components/forms/RadioGroup.svelte +116 -0
- package/dist/components/forms/RadioGroup.svelte.d.ts +24 -0
- package/dist/components/forms/Select.stories.svelte +168 -0
- package/dist/components/forms/Select.stories.svelte.d.ts +19 -0
- package/dist/components/forms/Select.svelte +262 -0
- package/dist/components/forms/Select.svelte.d.ts +23 -0
- package/dist/components/forms/Switch.stories.svelte +86 -0
- package/dist/components/forms/Switch.stories.svelte.d.ts +19 -0
- package/dist/components/forms/Switch.svelte +113 -0
- package/dist/components/forms/Switch.svelte.d.ts +11 -0
- package/dist/components/forms/Textarea.stories.svelte +40 -0
- package/dist/components/forms/Textarea.stories.svelte.d.ts +19 -0
- package/dist/components/forms/Textarea.svelte +66 -0
- package/dist/components/forms/Textarea.svelte.d.ts +9 -0
- package/dist/components/forms/field-context.d.ts +7 -0
- package/dist/components/forms/field-context.js +1 -0
- package/dist/components/forms/index.d.ts +9 -0
- package/dist/components/forms/index.js +9 -0
- package/dist/components/layout/Container.stories.svelte +67 -0
- package/dist/components/layout/Container.stories.svelte.d.ts +19 -0
- package/dist/components/layout/Container.svelte +52 -0
- package/dist/components/layout/Container.svelte.d.ts +14 -0
- package/dist/components/layout/Grid.stories.svelte +109 -0
- package/dist/components/layout/Grid.stories.svelte.d.ts +19 -0
- package/dist/components/layout/Grid.svelte +54 -0
- package/dist/components/layout/Grid.svelte.d.ts +19 -0
- package/dist/components/layout/Inline.stories.svelte +136 -0
- package/dist/components/layout/Inline.stories.svelte.d.ts +19 -0
- package/dist/components/layout/Inline.svelte +46 -0
- package/dist/components/layout/Inline.svelte.d.ts +19 -0
- package/dist/components/layout/Prose.stories.svelte +423 -0
- package/dist/components/layout/Prose.stories.svelte.d.ts +19 -0
- package/dist/components/layout/Prose.svelte +176 -0
- package/dist/components/layout/Prose.svelte.d.ts +12 -0
- package/dist/components/layout/Rule.stories.svelte +80 -0
- package/dist/components/layout/Rule.stories.svelte.d.ts +19 -0
- package/dist/components/layout/Rule.svelte +33 -0
- package/dist/components/layout/Rule.svelte.d.ts +9 -0
- package/dist/components/layout/Spread.stories.svelte +118 -0
- package/dist/components/layout/Spread.stories.svelte.d.ts +19 -0
- package/dist/components/layout/Spread.svelte +38 -0
- package/dist/components/layout/Spread.svelte.d.ts +16 -0
- package/dist/components/layout/Stack.stories.svelte +90 -0
- package/dist/components/layout/Stack.stories.svelte.d.ts +19 -0
- package/dist/components/layout/Stack.svelte +37 -0
- package/dist/components/layout/Stack.svelte.d.ts +16 -0
- package/dist/components/layout/index.d.ts +7 -0
- package/dist/components/layout/index.js +7 -0
- package/dist/components/navigation/Breadcrumb.stories.svelte +122 -0
- package/dist/components/navigation/Breadcrumb.stories.svelte.d.ts +19 -0
- package/dist/components/navigation/Breadcrumb.svelte +70 -0
- package/dist/components/navigation/Breadcrumb.svelte.d.ts +13 -0
- package/dist/components/navigation/Nav.stories.svelte +323 -0
- package/dist/components/navigation/Nav.stories.svelte.d.ts +19 -0
- package/dist/components/navigation/Nav.svelte +257 -0
- package/dist/components/navigation/Nav.svelte.d.ts +21 -0
- package/dist/components/navigation/index.d.ts +2 -0
- package/dist/components/navigation/index.js +2 -0
- package/dist/components/patterns/ActivityRow.stories.svelte +45 -0
- package/dist/components/patterns/ActivityRow.stories.svelte.d.ts +19 -0
- package/dist/components/patterns/ActivityRow.svelte +69 -0
- package/dist/components/patterns/ActivityRow.svelte.d.ts +16 -0
- package/dist/components/patterns/Alert.stories.svelte +63 -0
- package/dist/components/patterns/Alert.stories.svelte.d.ts +19 -0
- package/dist/components/patterns/Alert.svelte +91 -0
- package/dist/components/patterns/Alert.svelte.d.ts +16 -0
- package/dist/components/patterns/CtaBlock.stories.svelte +62 -0
- package/dist/components/patterns/CtaBlock.stories.svelte.d.ts +19 -0
- package/dist/components/patterns/CtaBlock.svelte +80 -0
- package/dist/components/patterns/CtaBlock.svelte.d.ts +16 -0
- package/dist/components/patterns/KvList.stories.svelte +48 -0
- package/dist/components/patterns/KvList.stories.svelte.d.ts +19 -0
- package/dist/components/patterns/KvList.svelte +65 -0
- package/dist/components/patterns/KvList.svelte.d.ts +15 -0
- package/dist/components/patterns/PageHero.stories.svelte +62 -0
- package/dist/components/patterns/PageHero.stories.svelte.d.ts +19 -0
- package/dist/components/patterns/PageHero.svelte +62 -0
- package/dist/components/patterns/PageHero.svelte.d.ts +14 -0
- package/dist/components/patterns/ProgressBar.stories.svelte +83 -0
- package/dist/components/patterns/ProgressBar.stories.svelte.d.ts +19 -0
- package/dist/components/patterns/ProgressBar.svelte +71 -0
- package/dist/components/patterns/ProgressBar.svelte.d.ts +13 -0
- package/dist/components/patterns/SectionFoot.stories.svelte +37 -0
- package/dist/components/patterns/SectionFoot.stories.svelte.d.ts +19 -0
- package/dist/components/patterns/SectionFoot.svelte +70 -0
- package/dist/components/patterns/SectionFoot.svelte.d.ts +15 -0
- package/dist/components/patterns/SectionHead.stories.svelte +67 -0
- package/dist/components/patterns/SectionHead.stories.svelte.d.ts +19 -0
- package/dist/components/patterns/SectionHead.svelte +54 -0
- package/dist/components/patterns/SectionHead.svelte.d.ts +14 -0
- package/dist/components/patterns/StatCard.stories.svelte +59 -0
- package/dist/components/patterns/StatCard.stories.svelte.d.ts +19 -0
- package/dist/components/patterns/StatCard.svelte +57 -0
- package/dist/components/patterns/StatCard.svelte.d.ts +15 -0
- package/dist/components/patterns/index.d.ts +9 -0
- package/dist/components/patterns/index.js +9 -0
- package/dist/components/primitives/Button.stories.svelte +132 -0
- package/dist/components/primitives/Button.stories.svelte.d.ts +19 -0
- package/dist/components/primitives/Button.svelte +142 -0
- package/dist/components/primitives/Button.svelte.d.ts +16 -0
- package/dist/components/primitives/Heading.stories.svelte +137 -0
- package/dist/components/primitives/Heading.stories.svelte.d.ts +19 -0
- package/dist/components/primitives/Heading.svelte +107 -0
- package/dist/components/primitives/Heading.svelte.d.ts +23 -0
- package/dist/components/primitives/Led.stories.svelte +63 -0
- package/dist/components/primitives/Led.stories.svelte.d.ts +19 -0
- package/dist/components/primitives/Led.svelte +65 -0
- package/dist/components/primitives/Led.svelte.d.ts +11 -0
- package/dist/components/primitives/TagPill.stories.svelte +90 -0
- package/dist/components/primitives/TagPill.stories.svelte.d.ts +19 -0
- package/dist/components/primitives/TagPill.svelte +44 -0
- package/dist/components/primitives/TagPill.svelte.d.ts +9 -0
- package/dist/components/primitives/Text.stories.svelte +252 -0
- package/dist/components/primitives/Text.stories.svelte.d.ts +19 -0
- package/dist/components/primitives/Text.svelte +101 -0
- package/dist/components/primitives/Text.svelte.d.ts +25 -0
- package/dist/components/primitives/index.d.ts +5 -0
- package/dist/components/primitives/index.js +5 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +10 -0
- package/dist/stores/toast.d.ts +19 -0
- package/dist/stores/toast.js +22 -0
- package/dist/storybook-utils.d.ts +11 -0
- package/dist/storybook-utils.js +29 -0
- package/dist/tokens/ColorSwatch.svelte +73 -0
- package/dist/tokens/ColorSwatch.svelte.d.ts +10 -0
- package/dist/tokens/layout.css +144 -0
- package/dist/tokens/patterns.css +281 -0
- package/dist/tokens/tokens.css +96 -0
- package/dist/tokens/tokens.stories.svelte +107 -0
- package/dist/tokens/tokens.stories.svelte.d.ts +18 -0
- package/dist/tokens/typography.css +159 -0
- package/package.json +62 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
import { defineMeta } from "@storybook/addon-svelte-csf";
|
|
3
|
+
import { expect, within } from "storybook/test";
|
|
4
|
+
import Rule from "./Rule.svelte";
|
|
5
|
+
import Stack from "./Stack.svelte";
|
|
6
|
+
import { resolveTokenFgColor } from "../../storybook-utils.js";
|
|
7
|
+
|
|
8
|
+
const { Story } = defineMeta({
|
|
9
|
+
title: "Layout/Rule",
|
|
10
|
+
tags: ["autodocs"],
|
|
11
|
+
});
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<Story name="All Variants"
|
|
15
|
+
play={async ({ canvasElement }) => {
|
|
16
|
+
const hrs = canvasElement.querySelectorAll("hr");
|
|
17
|
+
await expect(hrs.length).toBe(3);
|
|
18
|
+
|
|
19
|
+
const [solid, dashed, strong] = Array.from(hrs) as HTMLElement[];
|
|
20
|
+
|
|
21
|
+
// Solid variant
|
|
22
|
+
const solidStyle = getComputedStyle(solid);
|
|
23
|
+
await expect(solidStyle.borderTopStyle).toBe("solid");
|
|
24
|
+
await expect(solidStyle.borderTopWidth).toBe("1px");
|
|
25
|
+
const ruleColor = resolveTokenFgColor("--rule");
|
|
26
|
+
await expect(solidStyle.borderTopColor).toBe(ruleColor);
|
|
27
|
+
|
|
28
|
+
// Dashed variant
|
|
29
|
+
const dashedStyle = getComputedStyle(dashed);
|
|
30
|
+
await expect(dashedStyle.borderTopStyle).toBe("dashed");
|
|
31
|
+
await expect(dashedStyle.borderTopWidth).toBe("1px");
|
|
32
|
+
await expect(dashedStyle.borderTopColor).toBe(ruleColor);
|
|
33
|
+
|
|
34
|
+
// Strong variant — same style but different color from solid
|
|
35
|
+
const strongStyle = getComputedStyle(strong);
|
|
36
|
+
await expect(strongStyle.borderTopStyle).toBe("solid");
|
|
37
|
+
const ruleStrongColor = resolveTokenFgColor("--rule-strong");
|
|
38
|
+
await expect(strongStyle.borderTopColor).toBe(ruleStrongColor);
|
|
39
|
+
await expect(strongStyle.borderTopColor).not.toBe(ruleColor);
|
|
40
|
+
}}>
|
|
41
|
+
<Stack gap="md">
|
|
42
|
+
<span>Solid (default)</span>
|
|
43
|
+
<Rule variant="solid" />
|
|
44
|
+
<span>Dashed</span>
|
|
45
|
+
<Rule variant="dashed" />
|
|
46
|
+
<span>Strong</span>
|
|
47
|
+
<Rule variant="strong" />
|
|
48
|
+
</Stack>
|
|
49
|
+
</Story>
|
|
50
|
+
|
|
51
|
+
<Story name="In Context"
|
|
52
|
+
play={async ({ canvasElement }) => {
|
|
53
|
+
const hr = within(canvasElement).getAllByRole("separator")[0];
|
|
54
|
+
await expect(hr).toBeVisible();
|
|
55
|
+
const style = getComputedStyle(hr);
|
|
56
|
+
await expect(style.marginTop).toBe("0px");
|
|
57
|
+
await expect(style.marginBottom).toBe("0px");
|
|
58
|
+
await expect(style.marginLeft).toBe("0px");
|
|
59
|
+
await expect(style.marginRight).toBe("0px");
|
|
60
|
+
// aria-hidden forwarded via ...rest
|
|
61
|
+
const hiddenHr = canvasElement.querySelector("[data-testid='rule-hidden']") as HTMLElement;
|
|
62
|
+
await expect(hiddenHr.getAttribute("aria-hidden")).toBe("true");
|
|
63
|
+
}}>
|
|
64
|
+
<Stack gap="md">
|
|
65
|
+
<h3>Section Heading</h3>
|
|
66
|
+
<Rule />
|
|
67
|
+
<p>Body text below the rule. The rule carries no margin of its own — spacing comes from the Stack gap.</p>
|
|
68
|
+
<Rule aria-hidden="true" data-testid="rule-hidden" />
|
|
69
|
+
</Stack>
|
|
70
|
+
</Story>
|
|
71
|
+
|
|
72
|
+
<Story name="With Margin Override"
|
|
73
|
+
play={async ({ canvasElement }) => {
|
|
74
|
+
const hr = canvasElement.querySelector("hr")!;
|
|
75
|
+
const style = getComputedStyle(hr);
|
|
76
|
+
await expect(style.marginTop).toBe("24px");
|
|
77
|
+
await expect(style.marginBottom).toBe("24px");
|
|
78
|
+
}}>
|
|
79
|
+
<Rule style="margin-top: 24px; margin-bottom: 24px" />
|
|
80
|
+
</Story>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import Rule from "./Rule.svelte";
|
|
2
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
3
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
4
|
+
$$bindings?: Bindings;
|
|
5
|
+
} & Exports;
|
|
6
|
+
(internal: unknown, props: {
|
|
7
|
+
$$events?: Events;
|
|
8
|
+
$$slots?: Slots;
|
|
9
|
+
}): Exports & {
|
|
10
|
+
$set?: any;
|
|
11
|
+
$on?: any;
|
|
12
|
+
};
|
|
13
|
+
z_$$bindings?: Bindings;
|
|
14
|
+
}
|
|
15
|
+
declare const Rule: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
16
|
+
[evt: string]: CustomEvent<any>;
|
|
17
|
+
}, {}, {}, string>;
|
|
18
|
+
type Rule = InstanceType<typeof Rule>;
|
|
19
|
+
export default Rule;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements'
|
|
3
|
+
|
|
4
|
+
type RuleVariant = 'solid' | 'dashed' | 'strong'
|
|
5
|
+
|
|
6
|
+
interface Props extends HTMLAttributes<HTMLHRElement> {
|
|
7
|
+
variant?: RuleVariant
|
|
8
|
+
[key: string]: unknown
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
let { variant = 'solid', ...rest }: Props = $props()
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<hr class="rule" data-variant={variant} {...rest} />
|
|
15
|
+
|
|
16
|
+
<style>
|
|
17
|
+
.rule {
|
|
18
|
+
border: none;
|
|
19
|
+
margin: 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.rule[data-variant="solid"] {
|
|
23
|
+
border-top: 1px solid var(--rule);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.rule[data-variant="dashed"] {
|
|
27
|
+
border-top: 1px dashed var(--rule);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.rule[data-variant="strong"] {
|
|
31
|
+
border-top: 1px solid var(--rule-strong);
|
|
32
|
+
}
|
|
33
|
+
</style>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
2
|
+
type RuleVariant = 'solid' | 'dashed' | 'strong';
|
|
3
|
+
interface Props extends HTMLAttributes<HTMLHRElement> {
|
|
4
|
+
variant?: RuleVariant;
|
|
5
|
+
[key: string]: unknown;
|
|
6
|
+
}
|
|
7
|
+
declare const Rule: import("svelte").Component<Props, {}, "">;
|
|
8
|
+
type Rule = ReturnType<typeof Rule>;
|
|
9
|
+
export default Rule;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
import { defineMeta } from "@storybook/addon-svelte-csf";
|
|
3
|
+
import { expect, within } from "storybook/test";
|
|
4
|
+
import Spread from "./Spread.svelte";
|
|
5
|
+
import Button from "../primitives/Button.svelte";
|
|
6
|
+
import Led from "../primitives/Led.svelte";
|
|
7
|
+
import TagPill from "../primitives/TagPill.svelte";
|
|
8
|
+
|
|
9
|
+
const { Story } = defineMeta({
|
|
10
|
+
title: "Layout/Spread",
|
|
11
|
+
component: Spread,
|
|
12
|
+
tags: ["autodocs"],
|
|
13
|
+
});
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<Story name="Section Header" args={{ "aria-label": "test-label" }}
|
|
17
|
+
play={async ({ canvasElement }) => {
|
|
18
|
+
const root = canvasElement.firstElementChild as HTMLElement;
|
|
19
|
+
await expect(root).toBeVisible();
|
|
20
|
+
const style = getComputedStyle(root);
|
|
21
|
+
await expect(style.display).toBe("flex");
|
|
22
|
+
await expect(style.justifyContent).toBe("space-between");
|
|
23
|
+
// aria-label forwarded via ...rest
|
|
24
|
+
await expect(root.getAttribute("aria-label")).toBe("test-label");
|
|
25
|
+
}}>
|
|
26
|
+
<span class="mono-label">System Status</span>
|
|
27
|
+
<Button variant="ghost">View All →</Button>
|
|
28
|
+
</Story>
|
|
29
|
+
|
|
30
|
+
<Story name="Led Status Bar"
|
|
31
|
+
play={async ({ canvasElement }) => {
|
|
32
|
+
const root = canvasElement.firstElementChild as HTMLElement;
|
|
33
|
+
await expect(root).toBeVisible();
|
|
34
|
+
const style = getComputedStyle(root);
|
|
35
|
+
await expect(style.justifyContent).toBe("space-between");
|
|
36
|
+
// After B25: bare <Spread> with no gap prop defaults to none → 0px
|
|
37
|
+
const gap = style.gap || style.columnGap;
|
|
38
|
+
await expect(gap === "0px" || gap === "0").toBe(true);
|
|
39
|
+
}}>
|
|
40
|
+
<span style="display: flex; align-items: center; gap: 8px;">
|
|
41
|
+
<Led color="ok" aria-label="Status: ok" />
|
|
42
|
+
<span>All systems nominal</span>
|
|
43
|
+
</span>
|
|
44
|
+
<TagPill variant="amber">Live</TagPill>
|
|
45
|
+
</Story>
|
|
46
|
+
|
|
47
|
+
<Story name="With Gap"
|
|
48
|
+
play={async ({ canvasElement }) => {
|
|
49
|
+
const root = canvasElement.firstElementChild!;
|
|
50
|
+
await expect(getComputedStyle(root).display).toBe("flex");
|
|
51
|
+
await expect(getComputedStyle(root).justifyContent).toBe("space-between");
|
|
52
|
+
// After B25: bare <Spread> with no gap prop defaults to none → 0px
|
|
53
|
+
const gap = getComputedStyle(root).gap || getComputedStyle(root).columnGap;
|
|
54
|
+
await expect(gap === "0px" || gap === "0").toBe(true);
|
|
55
|
+
}}>
|
|
56
|
+
<span class="mono-label">Left Item</span>
|
|
57
|
+
<span class="mono-label">Center Item</span>
|
|
58
|
+
<span class="mono-label">Right Item</span>
|
|
59
|
+
</Story>
|
|
60
|
+
|
|
61
|
+
<Story name="Vertical Stack" args={{ as: "section", "aria-label": "stack-region" }}
|
|
62
|
+
play={async ({ canvasElement }) => {
|
|
63
|
+
const root = canvasElement.firstElementChild!;
|
|
64
|
+
await expect(root.tagName).toBe("SECTION");
|
|
65
|
+
await expect(getComputedStyle(root).display).toBe("flex");
|
|
66
|
+
await expect(root.getAttribute("aria-label")).toBe("stack-region");
|
|
67
|
+
}}>
|
|
68
|
+
<span>Item A</span>
|
|
69
|
+
<span>Item B</span>
|
|
70
|
+
</Story>
|
|
71
|
+
|
|
72
|
+
<!-- AC-2 / AC-3: default gap (no prop) and explicit gap="none" both resolve to 0px -->
|
|
73
|
+
<Story name="Gap None" args={{ gap: "none" }}
|
|
74
|
+
play={async ({ canvasElement }) => {
|
|
75
|
+
const root = canvasElement.firstElementChild as HTMLElement;
|
|
76
|
+
await expect(root).toBeVisible();
|
|
77
|
+
const gap = getComputedStyle(root).gap || getComputedStyle(root).columnGap;
|
|
78
|
+
await expect(gap === "0px" || gap === "0").toBe(true);
|
|
79
|
+
}}>
|
|
80
|
+
<span>Left</span>
|
|
81
|
+
<span>Right</span>
|
|
82
|
+
</Story>
|
|
83
|
+
|
|
84
|
+
<!-- AC-5: gap="sm" → var(--u2) → 16px -->
|
|
85
|
+
<Story name="Gap Sm" args={{ gap: "sm" }}
|
|
86
|
+
play={async ({ canvasElement }) => {
|
|
87
|
+
const root = canvasElement.firstElementChild as HTMLElement;
|
|
88
|
+
await expect(root).toBeVisible();
|
|
89
|
+
const gap = getComputedStyle(root).gap || getComputedStyle(root).columnGap;
|
|
90
|
+
await expect(gap.includes("16px")).toBe(true);
|
|
91
|
+
}}>
|
|
92
|
+
<span>Left</span>
|
|
93
|
+
<span>Right</span>
|
|
94
|
+
</Story>
|
|
95
|
+
|
|
96
|
+
<!-- AC-6: gap="md" → var(--u3) → 24px -->
|
|
97
|
+
<Story name="Gap Md" args={{ gap: "md" }}
|
|
98
|
+
play={async ({ canvasElement }) => {
|
|
99
|
+
const root = canvasElement.firstElementChild as HTMLElement;
|
|
100
|
+
await expect(root).toBeVisible();
|
|
101
|
+
const gap = getComputedStyle(root).gap || getComputedStyle(root).columnGap;
|
|
102
|
+
await expect(gap.includes("24px")).toBe(true);
|
|
103
|
+
}}>
|
|
104
|
+
<span>Left</span>
|
|
105
|
+
<span>Right</span>
|
|
106
|
+
</Story>
|
|
107
|
+
|
|
108
|
+
<!-- AC-7: gap="lg" → var(--u4) → 32px -->
|
|
109
|
+
<Story name="Gap Lg" args={{ gap: "lg" }}
|
|
110
|
+
play={async ({ canvasElement }) => {
|
|
111
|
+
const root = canvasElement.firstElementChild as HTMLElement;
|
|
112
|
+
await expect(root).toBeVisible();
|
|
113
|
+
const gap = getComputedStyle(root).gap || getComputedStyle(root).columnGap;
|
|
114
|
+
await expect(gap.includes("32px")).toBe(true);
|
|
115
|
+
}}>
|
|
116
|
+
<span>Left</span>
|
|
117
|
+
<span>Right</span>
|
|
118
|
+
</Story>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import Spread from "./Spread.svelte";
|
|
2
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
3
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
4
|
+
$$bindings?: Bindings;
|
|
5
|
+
} & Exports;
|
|
6
|
+
(internal: unknown, props: {
|
|
7
|
+
$$events?: Events;
|
|
8
|
+
$$slots?: Slots;
|
|
9
|
+
}): Exports & {
|
|
10
|
+
$set?: any;
|
|
11
|
+
$on?: any;
|
|
12
|
+
};
|
|
13
|
+
z_$$bindings?: Bindings;
|
|
14
|
+
}
|
|
15
|
+
declare const Spread: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
16
|
+
[evt: string]: CustomEvent<any>;
|
|
17
|
+
}, {}, {}, string>;
|
|
18
|
+
type Spread = InstanceType<typeof Spread>;
|
|
19
|
+
export default Spread;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { ClassValue } from 'svelte/elements'
|
|
3
|
+
import type { Snippet } from 'svelte'
|
|
4
|
+
|
|
5
|
+
type GapSize = 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl'
|
|
6
|
+
|
|
7
|
+
interface Props {
|
|
8
|
+
/** HTML element to render as. @default 'div' */
|
|
9
|
+
as?: string
|
|
10
|
+
/** Space between children. @default 'none' */
|
|
11
|
+
gap?: GapSize
|
|
12
|
+
children?: Snippet
|
|
13
|
+
class?: ClassValue | null
|
|
14
|
+
style?: string | null
|
|
15
|
+
[key: string]: unknown
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let { as = 'div', gap = 'none', children, class: klass = '', ...rest }: Props = $props()
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<svelte:element this={as} class={['spread', klass]} data-gap={gap} {...rest}>
|
|
22
|
+
{@render children?.()}
|
|
23
|
+
</svelte:element>
|
|
24
|
+
|
|
25
|
+
<style>
|
|
26
|
+
.spread {
|
|
27
|
+
display: flex;
|
|
28
|
+
align-items: center;
|
|
29
|
+
justify-content: space-between;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.spread[data-gap="none"] { gap: 0; }
|
|
33
|
+
.spread[data-gap="xs"] { gap: var(--u); }
|
|
34
|
+
.spread[data-gap="sm"] { gap: var(--u2); }
|
|
35
|
+
.spread[data-gap="md"] { gap: var(--u3); }
|
|
36
|
+
.spread[data-gap="lg"] { gap: var(--u4); }
|
|
37
|
+
.spread[data-gap="xl"] { gap: var(--u5); }
|
|
38
|
+
</style>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ClassValue } from 'svelte/elements';
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
type GapSize = 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
4
|
+
interface Props {
|
|
5
|
+
/** HTML element to render as. @default 'div' */
|
|
6
|
+
as?: string;
|
|
7
|
+
/** Space between children. @default 'none' */
|
|
8
|
+
gap?: GapSize;
|
|
9
|
+
children?: Snippet;
|
|
10
|
+
class?: ClassValue | null;
|
|
11
|
+
style?: string | null;
|
|
12
|
+
[key: string]: unknown;
|
|
13
|
+
}
|
|
14
|
+
declare const Spread: import("svelte").Component<Props, {}, "">;
|
|
15
|
+
type Spread = ReturnType<typeof Spread>;
|
|
16
|
+
export default Spread;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
import { defineMeta } from "@storybook/addon-svelte-csf";
|
|
3
|
+
import { expect, within } from "storybook/test";
|
|
4
|
+
import Stack from "./Stack.svelte";
|
|
5
|
+
import Button from "../primitives/Button.svelte";
|
|
6
|
+
import TagPill from "../primitives/TagPill.svelte";
|
|
7
|
+
|
|
8
|
+
const { Story } = defineMeta({
|
|
9
|
+
title: "Layout/Stack",
|
|
10
|
+
component: Stack,
|
|
11
|
+
tags: ["autodocs"],
|
|
12
|
+
});
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<Story name="Default Stack" args={{ gap: "sm", "aria-label": "test-label" }}
|
|
16
|
+
play={async ({ canvasElement }) => {
|
|
17
|
+
const root = canvasElement.firstElementChild as HTMLElement;
|
|
18
|
+
await expect(root).toBeVisible();
|
|
19
|
+
const style = getComputedStyle(root);
|
|
20
|
+
await expect(style.display).toBe("flex");
|
|
21
|
+
await expect(style.flexDirection).toBe("column");
|
|
22
|
+
// gap="sm" → var(--u2) → 16px
|
|
23
|
+
const gap = style.gap || style.columnGap;
|
|
24
|
+
await expect(gap.includes("16px")).toBe(true);
|
|
25
|
+
// aria-label forwarded via ...rest
|
|
26
|
+
await expect(root.getAttribute("aria-label")).toBe("test-label");
|
|
27
|
+
}}>
|
|
28
|
+
<Button variant="ghost">View All Hardware →</Button>
|
|
29
|
+
<Button variant="ghost">View Projects →</Button>
|
|
30
|
+
<Button variant="ghost">Read the Docs →</Button>
|
|
31
|
+
</Story>
|
|
32
|
+
|
|
33
|
+
<Story name="Large Gap" args={{ gap: "lg" }}
|
|
34
|
+
play={async ({ canvasElement }) => {
|
|
35
|
+
const root = canvasElement.firstElementChild as HTMLElement;
|
|
36
|
+
const style = getComputedStyle(root);
|
|
37
|
+
const gap = style.gap || style.rowGap;
|
|
38
|
+
await expect(gap.includes("32px")).toBe(true);
|
|
39
|
+
}}>
|
|
40
|
+
<TagPill variant="amber">Featured</TagPill>
|
|
41
|
+
<TagPill>Utility</TagPill>
|
|
42
|
+
</Story>
|
|
43
|
+
|
|
44
|
+
<Story name="Small Gap" args={{ gap: "xs" }}
|
|
45
|
+
play={async ({ canvasElement }) => {
|
|
46
|
+
const root = canvasElement.firstElementChild as HTMLElement;
|
|
47
|
+
const style = getComputedStyle(root);
|
|
48
|
+
const gap = style.gap || style.rowGap;
|
|
49
|
+
await expect(gap.includes("8px")).toBe(true);
|
|
50
|
+
}}>
|
|
51
|
+
<span>Item 1</span>
|
|
52
|
+
<span>Item 2</span>
|
|
53
|
+
<span>Item 3</span>
|
|
54
|
+
<span>Item 4</span>
|
|
55
|
+
</Story>
|
|
56
|
+
|
|
57
|
+
<Story name="As Section" args={{ as: "section", gap: "md" }}
|
|
58
|
+
play={async ({ canvasElement }) => {
|
|
59
|
+
const root = canvasElement.firstElementChild as HTMLElement;
|
|
60
|
+
await expect(root.tagName).toBe("SECTION");
|
|
61
|
+
// AC-16 / AC-9: gap="md" → var(--u3) → 24px (fixed from erroneous 16px)
|
|
62
|
+
const style = getComputedStyle(root);
|
|
63
|
+
const gap = style.gap || style.rowGap;
|
|
64
|
+
await expect(gap.includes("24px")).toBe(true);
|
|
65
|
+
}}>
|
|
66
|
+
<h2>Section Title</h2>
|
|
67
|
+
<p>Section content paragraph text goes here.</p>
|
|
68
|
+
</Story>
|
|
69
|
+
|
|
70
|
+
<Story name="None Gap" args={{ gap: "none" }}
|
|
71
|
+
play={async ({ canvasElement }) => {
|
|
72
|
+
const root = canvasElement.firstElementChild as HTMLElement;
|
|
73
|
+
const style = getComputedStyle(root);
|
|
74
|
+
const gap = style.gap || style.rowGap;
|
|
75
|
+
await expect(gap === "0px" || gap === "0").toBe(true);
|
|
76
|
+
}}>
|
|
77
|
+
<Button variant="ghost">A</Button>
|
|
78
|
+
<Button variant="ghost">B</Button>
|
|
79
|
+
</Story>
|
|
80
|
+
|
|
81
|
+
<Story name="XL Gap" args={{ gap: "xl" }}
|
|
82
|
+
play={async ({ canvasElement }) => {
|
|
83
|
+
const root = canvasElement.firstElementChild as HTMLElement;
|
|
84
|
+
const style = getComputedStyle(root);
|
|
85
|
+
const gap = style.gap || style.rowGap;
|
|
86
|
+
await expect(gap.includes("40px")).toBe(true);
|
|
87
|
+
}}>
|
|
88
|
+
<Button variant="ghost">Top</Button>
|
|
89
|
+
<Button variant="ghost">Bottom</Button>
|
|
90
|
+
</Story>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import Stack from "./Stack.svelte";
|
|
2
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
3
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
4
|
+
$$bindings?: Bindings;
|
|
5
|
+
} & Exports;
|
|
6
|
+
(internal: unknown, props: {
|
|
7
|
+
$$events?: Events;
|
|
8
|
+
$$slots?: Slots;
|
|
9
|
+
}): Exports & {
|
|
10
|
+
$set?: any;
|
|
11
|
+
$on?: any;
|
|
12
|
+
};
|
|
13
|
+
z_$$bindings?: Bindings;
|
|
14
|
+
}
|
|
15
|
+
declare const Stack: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
16
|
+
[evt: string]: CustomEvent<any>;
|
|
17
|
+
}, {}, {}, string>;
|
|
18
|
+
type Stack = InstanceType<typeof Stack>;
|
|
19
|
+
export default Stack;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { ClassValue } from 'svelte/elements'
|
|
3
|
+
import type { Snippet } from 'svelte'
|
|
4
|
+
|
|
5
|
+
type GapSize = 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl'
|
|
6
|
+
|
|
7
|
+
interface Props {
|
|
8
|
+
/** HTML element to render as. @default 'div' */
|
|
9
|
+
as?: string
|
|
10
|
+
/** Space between children. @default 'sm' */
|
|
11
|
+
gap?: GapSize
|
|
12
|
+
children?: Snippet
|
|
13
|
+
class?: ClassValue | null
|
|
14
|
+
style?: string | null
|
|
15
|
+
[key: string]: unknown
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let { as = 'div', gap = 'sm', children, class: klass = '', ...rest }: Props = $props()
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<svelte:element this={as} class={['stack', klass]} data-gap={gap} {...rest}>
|
|
22
|
+
{@render children?.()}
|
|
23
|
+
</svelte:element>
|
|
24
|
+
|
|
25
|
+
<style>
|
|
26
|
+
.stack {
|
|
27
|
+
display: flex;
|
|
28
|
+
flex-direction: column;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.stack[data-gap="none"] { gap: 0; }
|
|
32
|
+
.stack[data-gap="xs"] { gap: var(--u); }
|
|
33
|
+
.stack[data-gap="sm"] { gap: var(--u2); }
|
|
34
|
+
.stack[data-gap="md"] { gap: var(--u3); }
|
|
35
|
+
.stack[data-gap="lg"] { gap: var(--u4); }
|
|
36
|
+
.stack[data-gap="xl"] { gap: var(--u5); }
|
|
37
|
+
</style>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ClassValue } from 'svelte/elements';
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
type GapSize = 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
4
|
+
interface Props {
|
|
5
|
+
/** HTML element to render as. @default 'div' */
|
|
6
|
+
as?: string;
|
|
7
|
+
/** Space between children. @default 'sm' */
|
|
8
|
+
gap?: GapSize;
|
|
9
|
+
children?: Snippet;
|
|
10
|
+
class?: ClassValue | null;
|
|
11
|
+
style?: string | null;
|
|
12
|
+
[key: string]: unknown;
|
|
13
|
+
}
|
|
14
|
+
declare const Stack: import("svelte").Component<Props, {}, "">;
|
|
15
|
+
type Stack = ReturnType<typeof Stack>;
|
|
16
|
+
export default Stack;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { default as Stack } from './Stack.svelte';
|
|
2
|
+
export { default as Inline } from './Inline.svelte';
|
|
3
|
+
export { default as Spread } from './Spread.svelte';
|
|
4
|
+
export { default as Grid } from './Grid.svelte';
|
|
5
|
+
export { default as Container } from './Container.svelte';
|
|
6
|
+
export { default as Rule } from './Rule.svelte';
|
|
7
|
+
export { default as Prose } from './Prose.svelte';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { default as Stack } from './Stack.svelte';
|
|
2
|
+
export { default as Inline } from './Inline.svelte';
|
|
3
|
+
export { default as Spread } from './Spread.svelte';
|
|
4
|
+
export { default as Grid } from './Grid.svelte';
|
|
5
|
+
export { default as Container } from './Container.svelte';
|
|
6
|
+
export { default as Rule } from './Rule.svelte';
|
|
7
|
+
export { default as Prose } from './Prose.svelte';
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
import { defineMeta } from "@storybook/addon-svelte-csf";
|
|
3
|
+
import { expect, within } from "storybook/test";
|
|
4
|
+
import Breadcrumb from "./Breadcrumb.svelte";
|
|
5
|
+
|
|
6
|
+
const { Story } = defineMeta({
|
|
7
|
+
title: "Navigation/Breadcrumb",
|
|
8
|
+
component: Breadcrumb,
|
|
9
|
+
tags: ["autodocs"],
|
|
10
|
+
});
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<!-- AC 25: Default story — 3-crumb trail -->
|
|
14
|
+
<Story
|
|
15
|
+
name="Default"
|
|
16
|
+
args={{
|
|
17
|
+
crumbs: [
|
|
18
|
+
{ label: "Home", href: "/" },
|
|
19
|
+
{ label: "Catalogue", href: "/catalogue" },
|
|
20
|
+
{ label: "Conduit PDX-2", href: "/catalogue/conduit-pdx2" },
|
|
21
|
+
],
|
|
22
|
+
}}
|
|
23
|
+
play={async ({ canvasElement }) => {
|
|
24
|
+
// AC 5 / AC 25: <nav> with aria-label="breadcrumb" is present
|
|
25
|
+
const nav = within(canvasElement).getByRole("navigation", {
|
|
26
|
+
name: "breadcrumb",
|
|
27
|
+
});
|
|
28
|
+
await expect(nav).toBeVisible();
|
|
29
|
+
|
|
30
|
+
// AC 6: direct child is <ol>
|
|
31
|
+
const ol = nav.querySelector("ol");
|
|
32
|
+
await expect(ol).not.toBeNull();
|
|
33
|
+
await expect(ol!.tagName).toBe("OL");
|
|
34
|
+
|
|
35
|
+
// AC 8 / AC 25: exactly 3 <li> elements
|
|
36
|
+
const items = ol!.querySelectorAll("li");
|
|
37
|
+
await expect(items.length).toBe(3);
|
|
38
|
+
|
|
39
|
+
// AC 11 / AC 25: "Home" does NOT have aria-current
|
|
40
|
+
const homeLink = within(canvasElement).getByRole("link", { name: "Home" });
|
|
41
|
+
await expect(homeLink).not.toHaveAttribute("aria-current");
|
|
42
|
+
|
|
43
|
+
// AC 11 / AC 25: "Catalogue" does NOT have aria-current
|
|
44
|
+
const catalogueLink = within(canvasElement).getByRole("link", {
|
|
45
|
+
name: "Catalogue",
|
|
46
|
+
});
|
|
47
|
+
await expect(catalogueLink).not.toHaveAttribute("aria-current");
|
|
48
|
+
|
|
49
|
+
// AC 10 / AC 25: last crumb "Conduit PDX-2" has aria-current="page"
|
|
50
|
+
const currentLink = within(canvasElement).getByRole("link", {
|
|
51
|
+
name: "Conduit PDX-2",
|
|
52
|
+
});
|
|
53
|
+
await expect(currentLink).toHaveAttribute("aria-current", "page");
|
|
54
|
+
|
|
55
|
+
// AC 12 / AC 25: exactly 2 aria-hidden separator elements
|
|
56
|
+
const separators = canvasElement.querySelectorAll('[aria-hidden="true"]');
|
|
57
|
+
await expect(separators.length).toBe(2);
|
|
58
|
+
|
|
59
|
+
// AC 9: "Home" link href is "/"
|
|
60
|
+
await expect(homeLink).toHaveAttribute("href", "/");
|
|
61
|
+
|
|
62
|
+
// AC 9: "Catalogue" link href is "/catalogue"
|
|
63
|
+
await expect(catalogueLink).toHaveAttribute("href", "/catalogue");
|
|
64
|
+
}}
|
|
65
|
+
/>
|
|
66
|
+
|
|
67
|
+
<!-- AC 26: Root Only — single crumb -->
|
|
68
|
+
<Story
|
|
69
|
+
name="Root Only"
|
|
70
|
+
args={{
|
|
71
|
+
crumbs: [{ label: "Home", href: "/" }],
|
|
72
|
+
}}
|
|
73
|
+
play={async ({ canvasElement }) => {
|
|
74
|
+
// AC 5: <nav> with aria-label="breadcrumb" is present
|
|
75
|
+
const nav = within(canvasElement).getByRole("navigation", {
|
|
76
|
+
name: "breadcrumb",
|
|
77
|
+
});
|
|
78
|
+
await expect(nav).toBeVisible();
|
|
79
|
+
|
|
80
|
+
// AC 15 / AC 26: exactly 1 <li> element
|
|
81
|
+
const items = canvasElement.querySelectorAll("li");
|
|
82
|
+
await expect(items.length).toBe(1);
|
|
83
|
+
|
|
84
|
+
// AC 13 / AC 26: single crumb has aria-current="page"
|
|
85
|
+
const homeLink = within(canvasElement).getByRole("link", { name: "Home" });
|
|
86
|
+
await expect(homeLink).toHaveAttribute("aria-current", "page");
|
|
87
|
+
|
|
88
|
+
// AC 14 / AC 26: zero separator elements
|
|
89
|
+
const separators = canvasElement.querySelectorAll('[aria-hidden="true"]');
|
|
90
|
+
await expect(separators.length).toBe(0);
|
|
91
|
+
}}
|
|
92
|
+
/>
|
|
93
|
+
|
|
94
|
+
<!-- AC 27: Two Crumbs — intermediate depth -->
|
|
95
|
+
<Story
|
|
96
|
+
name="Two Crumbs"
|
|
97
|
+
args={{
|
|
98
|
+
crumbs: [
|
|
99
|
+
{ label: "Home", href: "/" },
|
|
100
|
+
{ label: "Projects", href: "/projects" },
|
|
101
|
+
],
|
|
102
|
+
}}
|
|
103
|
+
play={async ({ canvasElement }) => {
|
|
104
|
+
// AC 27: exactly 2 <li> elements
|
|
105
|
+
const items = canvasElement.querySelectorAll("li");
|
|
106
|
+
await expect(items.length).toBe(2);
|
|
107
|
+
|
|
108
|
+
// AC 27: "Home" does NOT have aria-current
|
|
109
|
+
const homeLink = within(canvasElement).getByRole("link", { name: "Home" });
|
|
110
|
+
await expect(homeLink).not.toHaveAttribute("aria-current");
|
|
111
|
+
|
|
112
|
+
// AC 27: "Projects" has aria-current="page"
|
|
113
|
+
const projectsLink = within(canvasElement).getByRole("link", {
|
|
114
|
+
name: "Projects",
|
|
115
|
+
});
|
|
116
|
+
await expect(projectsLink).toHaveAttribute("aria-current", "page");
|
|
117
|
+
|
|
118
|
+
// AC 27: exactly 1 separator element
|
|
119
|
+
const separators = canvasElement.querySelectorAll('[aria-hidden="true"]');
|
|
120
|
+
await expect(separators.length).toBe(1);
|
|
121
|
+
}}
|
|
122
|
+
/>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import Breadcrumb from "./Breadcrumb.svelte";
|
|
2
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
3
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
4
|
+
$$bindings?: Bindings;
|
|
5
|
+
} & Exports;
|
|
6
|
+
(internal: unknown, props: {
|
|
7
|
+
$$events?: Events;
|
|
8
|
+
$$slots?: Slots;
|
|
9
|
+
}): Exports & {
|
|
10
|
+
$set?: any;
|
|
11
|
+
$on?: any;
|
|
12
|
+
};
|
|
13
|
+
z_$$bindings?: Bindings;
|
|
14
|
+
}
|
|
15
|
+
declare const Breadcrumb: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
16
|
+
[evt: string]: CustomEvent<any>;
|
|
17
|
+
}, {}, {}, string>;
|
|
18
|
+
type Breadcrumb = InstanceType<typeof Breadcrumb>;
|
|
19
|
+
export default Breadcrumb;
|