This repository has no description
1<script module lang="ts">
2 import { tv, type VariantProps } from "tailwind-variants";
3
4 export const error = tv({
5 slots: {
6 root: "overflow-hidden rounded-sm border border-border-danger bg-background-danger-subtle text-foreground-danger dark:border-border-danger/60 dark:bg-background-danger-subtle/20",
7 header: "flex items-center gap-2",
8 icon: "shrink-0",
9 label: "min-w-0",
10 toggle:
11 "flex w-full items-center gap-2 border-t border-border-danger text-foreground-danger transition-colors hover:text-foreground-danger-strong dark:border-border-danger/60",
12 chevron: "shrink-0 transition-transform",
13 body: "border-t border-border-danger font-mono text-foreground-danger-strong dark:border-border-danger/60"
14 },
15 variants: {
16 size: {
17 small: {
18 header: "px-3 py-2 typography-paragraph-small",
19 icon: "size-4",
20 toggle: "px-3 py-2 typography-paragraph-small",
21 chevron: "size-4",
22 body: "px-3 py-2 typography-paragraph-small"
23 },
24 large: {
25 header: "px-4 py-3 typography-paragraph-large",
26 icon: "size-5",
27 toggle: "px-4 py-3 typography-paragraph-small",
28 chevron: "size-4",
29 body: "px-4 py-3 typography-paragraph-small"
30 }
31 }
32 },
33 defaultVariants: {
34 size: "small"
35 }
36 });
37
38 export type ErrorVariants = VariantProps<typeof error>;
39</script>
40
41<script lang="ts">
42 import type { Snippet } from "svelte";
43 import type { HTMLAttributes } from "svelte/elements";
44 import OctagonAlert from "$icon/octagon-alert";
45 import ChevronRight from "$icon/chevron-right";
46
47 interface Props extends Omit<HTMLAttributes<HTMLDivElement>, "class" | "children"> {
48 /** The error message shown next to the icon; renders nothing when absent. */
49 label?: string;
50 size?: ErrorVariants["size"];
51 class?: string;
52 /** Optional collapsible content revealed by a "Show code" toggle. */
53 children?: Snippet;
54 }
55
56 let { label, size = "small", class: className, children, ...rest }: Props = $props();
57
58 let open = $state(false);
59 $effect(() => {
60 if (!label) open = false;
61 });
62
63 const classes = $derived(error({ size }));
64</script>
65
66{#if label}
67 <div class={classes.root({ class: className })} role="alert" {...rest}>
68 <div class={classes.header()}>
69 <OctagonAlert class={classes.icon()} aria-hidden="true" />
70 <span class={classes.label()}>{label}</span>
71 </div>
72
73 {#if children}
74 <button type="button" class={classes.toggle()} onclick={() => (open = !open)}>
75 <ChevronRight class="{classes.chevron()} {open ? 'rotate-90' : ''}" aria-hidden="true" />
76 <span>Show code</span>
77 </button>
78 {#if open}
79 <div class={classes.body()}>
80 {@render children()}
81 </div>
82 {/if}
83 {/if}
84 </div>
85{/if}