svelora 3.0.11 → 3.0.12

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.
@@ -1,21 +1,39 @@
1
1
  <script lang="ts" module>export {};
2
2
  </script>
3
3
 
4
- <script lang="ts">import Icon from "@iconify/svelte";
4
+ <script lang="ts">import Iconify from "@iconify/svelte";
5
5
  import { twMerge } from "tailwind-merge";
6
+ import { getComponentConfig, iconsDefaults } from "../config.js";
7
+ const config = getComponentConfig("icons", iconsDefaults);
6
8
  let { name, size = 24, color, flipH = false, flipV = false, rotate = 0, class: className, ...restProps } = $props();
7
9
  const flip = $derived(flipH && flipV ? "horizontal,vertical" : flipH ? "horizontal" : flipV ? "vertical" : undefined);
8
10
  const rotateValue = $derived(rotate ? rotate / 90 : undefined);
9
11
  const iconClass = $derived(twMerge("shrink-0", className));
12
+ const provider = $derived(config.provider ?? "iconify");
13
+ // Automatically map "lucide:bell" to "icon-[lucide--bell]" if using tailwind provider
14
+ const tailwindClass = $derived(name.startsWith("icon-") || name.startsWith("i-") ? name : `icon-[${name.replace(":", "--")}]`);
15
+ // Resolve size value for inline styles
16
+ const sizeStyle = $derived(typeof size === "number" ? `${size}px` : size);
10
17
  </script>
11
18
 
12
- <Icon
13
- icon={name}
14
- width={size}
15
- height={size}
16
- {color}
17
- {flip}
18
- rotate={rotateValue}
19
- class={iconClass}
20
- {...restProps}
21
- />
19
+ {#if provider === 'tailwind'}
20
+ <span
21
+ class={twMerge(tailwindClass, iconClass)}
22
+ style:width={sizeStyle}
23
+ style:height={sizeStyle}
24
+ style:color={color}
25
+ style:transform={rotateValue ? `rotate(${rotateValue * 90}deg)` : undefined}
26
+ {...(restProps as any)}
27
+ ></span>
28
+ {:else}
29
+ <Iconify
30
+ icon={name}
31
+ width={size}
32
+ height={size}
33
+ {color}
34
+ {flip}
35
+ rotate={rotateValue}
36
+ class={iconClass}
37
+ {...restProps}
38
+ />
39
+ {/if}
@@ -1,6 +1,5 @@
1
1
  import type { IconProps } from './icon.types.js';
2
2
  export type Props = IconProps;
3
- import Icon from '@iconify/svelte';
4
3
  declare const Icon: import("svelte").Component<IconProps, {}, "">;
5
4
  type Icon = ReturnType<typeof Icon>;
6
5
  export default Icon;
package/dist/config.d.ts CHANGED
@@ -32,6 +32,7 @@ import type { FontsConfig } from './Fonts/fonts.types.js';
32
32
  * Default icons used across components
33
33
  */
34
34
  export declare const iconsDefaults: {
35
+ provider: "iconify" | "tailwind";
35
36
  loading: string;
36
37
  chevronDown: string;
37
38
  chevronLeft: string;
package/dist/config.js CHANGED
@@ -32,6 +32,7 @@
32
32
  * Default icons used across components
33
33
  */
34
34
  export const iconsDefaults = {
35
+ provider: 'iconify',
35
36
  loading: 'lucide:loader-2',
36
37
  chevronDown: 'lucide:chevron-down',
37
38
  chevronLeft: 'lucide:chevron-left',
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "version": 1,
3
3
  "packageName": "svelora",
4
- "packageVersion": "3.0.11",
5
- "generatedAt": "2026-06-26T17:54:14.673Z",
4
+ "packageVersion": "3.0.12",
5
+ "generatedAt": "2026-06-27T01:43:31.166Z",
6
6
  "slugs": {
7
7
  "components": [
8
8
  "button",
@@ -114,7 +114,7 @@
114
114
  "card": "<script lang=\"ts\">\n import { Card, Button, Icon, Avatar } from '$lib/index.js'\n</script>\n\n<div class=\"space-y-8\">\n <div class=\"space-y-2\">\n <h1 class=\"text-2xl font-bold\">Card</h1>\n <p class=\"text-on-surface-variant\">\n Container component for grouping related content with optional header and footer.\n </p>\n </div>\n\n <!-- Variants -->\n <section class=\"space-y-3\">\n <h2 id=\"Variants\" class=\"text-lg font-semibold\">\n<a href=\"#Variants\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Variants\n </a>\n</h2>\n <div class=\"grid gap-4 md:grid-cols-2\">\n <Card variant=\"outline\">\n {#snippet header()}\n <h3 class=\"font-semibold\">Outline (Default)</h3>\n {/snippet}\n <p class=\"text-on-surface-variant\">Card with border and background.</p>\n </Card>\n\n <Card variant=\"soft\">\n {#snippet header()}\n <h3 class=\"font-semibold\">Soft</h3>\n {/snippet}\n <p class=\"text-on-surface-variant\">Card with subtle background.</p>\n </Card>\n\n <Card variant=\"subtle\">\n {#snippet header()}\n <h3 class=\"font-semibold\">Subtle</h3>\n {/snippet}\n <p class=\"text-on-surface-variant\">Card with background and border.</p>\n </Card>\n\n <Card variant=\"solid\">\n {#snippet header()}\n <h3 class=\"font-semibold\">Solid</h3>\n {/snippet}\n <p class=\"opacity-90\">Card with inverted colors.</p>\n </Card>\n </div>\n </section>\n\n <!-- With Header and Footer -->\n <section class=\"space-y-3\">\n <h2 id=\"With-Header--Footer\" class=\"text-lg font-semibold\">\n<a href=\"#With-Header--Footer\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n With Header & Footer\n </a>\n</h2>\n <div class=\"grid gap-4 md:grid-cols-2\">\n <Card>\n {#snippet header()}\n <div class=\"flex items-center justify-between\">\n <h3 class=\"font-semibold\">Card Title</h3>\n <Button\n variant=\"ghost\"\n color=\"secondary\"\n icon=\"lucide:more-horizontal\"\n square\n size=\"sm\"\n />\n </div>\n {/snippet}\n <p class=\"text-on-surface-variant\">\n This is the card body content. You can put any content here.\n </p>\n {#snippet footer()}\n <div class=\"flex justify-end gap-2\">\n <Button variant=\"ghost\" color=\"secondary\" label=\"Cancel\" size=\"sm\" />\n <Button variant=\"solid\" color=\"primary\" label=\"Save\" size=\"sm\" />\n </div>\n {/snippet}\n </Card>\n\n <Card variant=\"soft\">\n {#snippet header()}\n <div class=\"flex items-center gap-3\">\n <Avatar src=\"https://i.pravatar.cc/150?img=5\" alt=\"John Doe\" size=\"md\" />\n <div>\n <h3 class=\"font-semibold\">John Doe</h3>\n <p class=\"text-sm text-on-surface-variant\">Software Engineer</p>\n </div>\n </div>\n {/snippet}\n <p class=\"text-on-surface-variant\">\n Building awesome things with Svelte and TypeScript.\n </p>\n {#snippet footer()}\n <div class=\"flex gap-2\">\n <Button\n variant=\"soft\"\n color=\"primary\"\n leadingIcon=\"lucide:mail\"\n label=\"Contact\"\n size=\"sm\"\n />\n <Button\n variant=\"ghost\"\n color=\"secondary\"\n leadingIcon=\"lucide:user-plus\"\n label=\"Follow\"\n size=\"sm\"\n />\n </div>\n {/snippet}\n </Card>\n </div>\n </section>\n\n <!-- Body Only -->\n <section class=\"space-y-3\">\n <h2 id=\"Body-Only\" class=\"text-lg font-semibold\">\n<a href=\"#Body-Only\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Body Only\n </a>\n</h2>\n <div class=\"grid gap-4 md:grid-cols-3\">\n <Card>\n <div class=\"text-center\">\n <Icon name=\"lucide:folder\" size=\"32\" class=\"mx-auto text-primary\" />\n <h4 class=\"mt-2 font-medium\">Documents</h4>\n <p class=\"text-sm text-on-surface-variant\">24 files</p>\n </div>\n </Card>\n\n <Card variant=\"soft\">\n <div class=\"text-center\">\n <Icon name=\"lucide:image\" size=\"32\" class=\"mx-auto text-success\" />\n <h4 class=\"mt-2 font-medium\">Images</h4>\n <p class=\"text-sm text-on-surface-variant\">128 files</p>\n </div>\n </Card>\n\n <Card variant=\"subtle\">\n <div class=\"text-center\">\n <Icon name=\"lucide:music\" size=\"32\" class=\"mx-auto text-tertiary\" />\n <h4 class=\"mt-2 font-medium\">Music</h4>\n <p class=\"text-sm text-on-surface-variant\">56 files</p>\n </div>\n </Card>\n </div>\n </section>\n\n <!-- Custom Styling -->\n <section class=\"space-y-3\">\n <h2 id=\"Custom-Styling\" class=\"text-lg font-semibold\">\n<a href=\"#Custom-Styling\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Custom Styling\n </a>\n</h2>\n <div class=\"grid gap-4 md:grid-cols-2\">\n <Card class=\"border-l-4 border-l-primary\">\n {#snippet header()}\n <h3 class=\"font-semibold text-primary\">Accent Border</h3>\n {/snippet}\n <p class=\"text-on-surface-variant\">Card with left accent border.</p>\n </Card>\n\n <Card\n class=\"shadow-lg\"\n ui={{ header: 'bg-primary text-on-primary', body: 'bg-primary-container' }}\n >\n {#snippet header()}\n <h3 class=\"font-semibold\">Custom Slots</h3>\n {/snippet}\n <p class=\"text-on-primary-container\">\n Card with custom header and body styles via ui prop.\n </p>\n </Card>\n </div>\n </section>\n\n <!-- As Different Element -->\n <section class=\"space-y-3\">\n <h2 id=\"As-Different-Element\" class=\"text-lg font-semibold\">\n<a href=\"#As-Different-Element\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n As Different Element\n </a>\n</h2>\n <Card as=\"article\" variant=\"soft\">\n {#snippet header()}\n <h3 class=\"font-semibold\">Article Card</h3>\n <p class=\"text-sm text-on-surface-variant\">Rendered as &lt;article&gt; element</p>\n {/snippet}\n <p class=\"text-on-surface-variant\">\n Use the <code class=\"rounded bg-surface-container-highest px-1\">as</code> prop to render\n as different HTML elements for better semantics.\n </p>\n </Card>\n </section>\n</div>\n",
115
115
  "container": "<script lang=\"ts\">\n import { Container } from '$lib/index.js'\n</script>\n\n<div class=\"space-y-8\">\n <div class=\"space-y-2\">\n <h1 class=\"text-2xl font-bold\">Container</h1>\n <p class=\"text-on-surface-variant\">\n Layout component that centers and constrains content width with responsive padding.\n </p>\n </div>\n\n <!-- Basic -->\n <section class=\"space-y-3\">\n <h2 id=\"Basic\" class=\"text-lg font-semibold\">\n<a href=\"#Basic\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Basic\n </a>\n</h2>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <Container class=\"rounded-lg bg-primary-container/30 py-4 text-center\">\n <p class=\"text-on-primary-container\">\n Content is centered with max-w-7xl and responsive padding.\n </p>\n </Container>\n </div>\n </section>\n\n <!-- Semantic Elements -->\n <section class=\"space-y-3\">\n <h2 id=\"Semantic-Elements\" class=\"text-lg font-semibold\">\n<a href=\"#Semantic-Elements\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Semantic Elements\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the <code class=\"rounded bg-surface-container-highest px-1\">as</code> prop to render as\n different HTML elements.\n </p>\n <div class=\"space-y-3 rounded-lg bg-surface-container-high p-4\">\n <Container as=\"section\" class=\"rounded-lg bg-secondary-container/30 py-3 text-center\">\n <p class=\"text-sm text-on-secondary-container\">Rendered as &lt;section&gt;</p>\n </Container>\n <Container as=\"main\" class=\"rounded-lg bg-tertiary-container/30 py-3 text-center\">\n <p class=\"text-sm text-on-tertiary-container\">Rendered as &lt;main&gt;</p>\n </Container>\n <Container as=\"article\" class=\"rounded-lg bg-success-container/30 py-3 text-center\">\n <p class=\"text-sm text-on-success-container\">Rendered as &lt;article&gt;</p>\n </Container>\n <Container as=\"nav\" class=\"rounded-lg bg-info-container/30 py-3 text-center\">\n <p class=\"text-sm text-on-info-container\">Rendered as &lt;nav&gt;</p>\n </Container>\n </div>\n </section>\n\n <!-- UI Slot Overrides -->\n <section class=\"space-y-3\">\n <h2 id=\"UI-Slot-Overrides\" class=\"text-lg font-semibold\">\n<a href=\"#UI-Slot-Overrides\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n UI Slot Overrides\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Override the default max-width and padding using the <code\n class=\"rounded bg-surface-container-highest px-1\">ui</code\n > prop.\n </p>\n <div class=\"space-y-3 rounded-lg bg-surface-container-high p-4\">\n <Container\n ui={{ root: 'max-w-sm' }}\n class=\"rounded-lg bg-warning-container/30 py-3 text-center\"\n >\n <p class=\"text-sm text-on-warning-container\">max-w-sm</p>\n </Container>\n <Container\n ui={{ root: 'max-w-xl' }}\n class=\"rounded-lg bg-primary-container/30 py-3 text-center\"\n >\n <p class=\"text-sm text-on-primary-container\">max-w-xl</p>\n </Container>\n <Container\n ui={{ root: 'max-w-3xl' }}\n class=\"rounded-lg bg-secondary-container/30 py-3 text-center\"\n >\n <p class=\"text-sm text-on-secondary-container\">max-w-3xl</p>\n </Container>\n <Container class=\"rounded-lg bg-tertiary-container/30 py-3 text-center\">\n <p class=\"text-sm text-on-tertiary-container\">max-w-7xl (default)</p>\n </Container>\n </div>\n </section>\n\n <!-- Custom Class -->\n <section class=\"space-y-3\">\n <h2 id=\"Custom-Class\" class=\"text-lg font-semibold\">\n<a href=\"#Custom-Class\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Custom Class\n </a>\n</h2>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <Container class=\"rounded-xl border border-outline-variant bg-surface-container p-6\">\n <h3 class=\"mb-2 font-medium\">Card-like Container</h3>\n <p class=\"text-sm text-on-surface-variant\">\n Combine Container with custom classes to create card-like layouts with\n consistent max-width.\n </p>\n </Container>\n </div>\n </section>\n\n <!-- Real World Examples -->\n <section class=\"space-y-3\">\n <h2 id=\"Real-World-Examples\" class=\"text-lg font-semibold\">\n<a href=\"#Real-World-Examples\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Real World Examples\n </a>\n</h2>\n <div class=\"space-y-6 rounded-lg bg-surface-container-high p-4\">\n <!-- Page Layout -->\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium text-on-surface-variant\">Page Header</p>\n <Container\n as=\"header\"\n class=\"rounded-lg border border-outline-variant bg-surface-container py-4\"\n >\n <div class=\"flex items-center justify-between\">\n <span class=\"font-bold text-primary\">Logo</span>\n <div class=\"flex gap-4 text-sm text-on-surface-variant\">\n <span>Home</span>\n <span>About</span>\n <span>Contact</span>\n </div>\n </div>\n </Container>\n </div>\n\n <!-- Content Section -->\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium text-on-surface-variant\">Content Section</p>\n <Container\n as=\"section\"\n ui={{ root: 'max-w-3xl' }}\n class=\"rounded-lg border border-outline-variant bg-surface-container py-6\"\n >\n <h3 class=\"mb-2 text-lg font-semibold\">Article Title</h3>\n <p class=\"text-sm text-on-surface-variant\">\n A narrow container is ideal for long-form content like blog posts and\n articles, keeping the line length readable and comfortable.\n </p>\n </Container>\n </div>\n\n <!-- Footer -->\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium text-on-surface-variant\">Footer</p>\n <Container\n as=\"footer\"\n class=\"rounded-lg border border-outline-variant bg-surface-container py-4\"\n >\n <div class=\"flex items-center justify-between text-sm text-on-surface-variant\">\n <span>&copy; 2026 Svelora</span>\n <div class=\"flex gap-4\">\n <span>Privacy</span>\n <span>Terms</span>\n </div>\n </div>\n </Container>\n </div>\n </div>\n </section>\n</div>\n",
116
116
  "resizable": "<script lang=\"ts\">\n import { Resizable } from '$lib/index.js'\n</script>\n\n<div class=\"space-y-8\">\n <div class=\"space-y-2\">\n <h1 class=\"text-2xl font-bold\">Resizable</h1>\n <p class=\"text-on-surface-variant\">\n A simple container that allows users to resize its dimensions.\n </p>\n </div>\n\n <!-- Usage -->\n <section class=\"space-y-3\">\n <h2 id=\"Usage\" class=\"text-lg font-semibold\">\n<a href=\"#Usage\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Usage\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Wrap your content in a <code class=\"rounded bg-surface-container-highest px-1\">Resizable</code> component. By default, it can be resized in both directions.\n </p>\n <div class=\"rounded-lg bg-surface-container-high p-4 flex justify-center\">\n <Resizable direction=\"both\" class=\"min-h-32 min-w-32 h-48 w-48 rounded-lg border border-outline-variant bg-surface overflow-hidden\">\n <div class=\"flex h-full items-center justify-center p-6 text-center text-sm text-on-surface-variant\">\n Drag the bottom-right corner to resize\n </div>\n </Resizable>\n </div>\n </section>\n\n <!-- Horizontal & Vertical -->\n <section class=\"space-y-3\">\n <h2 id=\"Horizontal--Vertical\" class=\"text-lg font-semibold\">\n<a href=\"#Horizontal--Vertical\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Horizontal & Vertical\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the <code class=\"rounded bg-surface-container-highest px-1\">direction</code> prop to restrict resizing to either <code class=\"rounded bg-surface-container-highest px-1\">horizontal</code> or <code class=\"rounded bg-surface-container-highest px-1\">vertical</code>.\n </p>\n <div class=\"rounded-lg bg-surface-container-high p-4 flex gap-4 justify-center flex-wrap\">\n <Resizable direction=\"horizontal\" class=\"min-h-32 min-w-32 h-32 w-48 rounded-lg border border-outline-variant bg-surface overflow-hidden\">\n <div class=\"flex h-full items-center justify-center p-4 font-semibold\">\n Horizontal\n </div>\n </Resizable>\n \n <Resizable direction=\"vertical\" class=\"min-h-32 min-w-32 h-48 w-32 rounded-lg border border-outline-variant bg-surface overflow-hidden\">\n <div class=\"flex h-full items-center justify-center p-4 font-semibold\">\n Vertical\n </div>\n </Resizable>\n </div>\n </section>\n</div>\n",
117
- "modal": "<script lang=\"ts\">\n import { Modal, Button, Badge, Icon, Separator } from '$lib/index.js'\n\n let basicOpen = $state(false)\n let fullscreenOpen = $state(false)\n let scrollableOpen = $state(false)\n let scrollableFullscreenOpen = $state(false)\n let noCloseOpen = $state(false)\n let noOverlayOpen = $state(false)\n let noTransitionOpen = $state(false)\n let nonDismissibleOpen = $state(false)\n let slotsOpen = $state(false)\n let actionsOpen = $state(false)\n let customContentOpen = $state(false)\n let callbacksOpen = $state(false)\n let callbackLog = $state<string[]>([])\n let uiOverrideOpen = $state(false)\n let programmaticOpen = $state(false)\n\n let confirmOpen = $state(false)\n let formOpen = $state(false)\n let alertOpen = $state(false)\n let imageOpen = $state(false)\n\n let sizeOpens = $state<Record<string, boolean>>({\n sm: false,\n md: false,\n lg: false,\n xl: false,\n full: false\n })\n let transitionOpens = $state<Record<string, boolean>>({\n scale: false,\n fade: false,\n slide: false,\n none: false\n })\n\n function logCallback(name: string) {\n callbackLog = [...callbackLog.slice(-4), `${new Date().toLocaleTimeString()} — ${name}`]\n }\n</script>\n\n<div class=\"space-y-8\">\n <div class=\"space-y-2\">\n <h1 class=\"text-2xl font-bold\">Modal</h1>\n <p class=\"text-on-surface-variant\">\n A modal dialog component built on bits-ui Dialog. Supports transitions, fullscreen,\n scrollable mode, dismissible control, and full slot customization.\n </p>\n </div>\n\n <!-- Basic -->\n <section class=\"space-y-3\">\n <h2 id=\"Basic\" class=\"text-lg font-semibold\">\n<a href=\"#Basic\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Basic\n </a>\n</h2>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <Modal\n bind:open={basicOpen}\n title=\"Basic Modal\"\n description=\"This is a basic modal with title, description, body and footer.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Open Modal\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n A centered modal dialog. Click the X, press Escape, or click outside to\n close.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button label=\"Cancel\" variant=\"outline\" onclick={() => (basicOpen = false)} />\n <Button\n label=\"Confirm\"\n variant=\"solid\"\n color=\"primary\"\n onclick={() => (basicOpen = false)}\n />\n {/snippet}\n </Modal>\n </div>\n </section>\n\n <!-- Fullscreen -->\n <section class=\"space-y-3\">\n <h2 id=\"Fullscreen\" class=\"text-lg font-semibold\">\n<a href=\"#Fullscreen\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Fullscreen\n </a>\n</h2>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <Modal\n bind:open={fullscreenOpen}\n fullscreen\n title=\"Fullscreen Modal\"\n description=\"This modal takes up the entire screen.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Open Fullscreen\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n Covers the entire viewport. Useful for complex forms or media viewers.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (fullscreenOpen = false)}\n />\n {/snippet}\n </Modal>\n </div>\n </section>\n\n <!-- Scrollable -->\n <section class=\"space-y-3\">\n <h2 id=\"Scrollable\" class=\"text-lg font-semibold\">\n<a href=\"#Scrollable\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Scrollable\n </a>\n</h2>\n <div class=\"flex flex-wrap gap-3 rounded-lg bg-surface-container-high p-4\">\n <Modal\n bind:open={scrollableOpen}\n scrollable\n title=\"Scrollable Modal\"\n description=\"The entire modal scrolls within the overlay.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Scrollable\" />\n {/snippet}\n {#snippet body()}\n <div class=\"space-y-3\">\n {#each Array.from({ length: 20 }, (_, i) => i) as i (i)}\n <div class=\"rounded-md bg-surface-container p-3\">\n <p class=\"text-sm text-on-surface-variant\">Content item {i + 1}</p>\n </div>\n {/each}\n </div>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (scrollableOpen = false)}\n />\n {/snippet}\n </Modal>\n\n <Modal\n bind:open={scrollableFullscreenOpen}\n scrollable\n fullscreen\n title=\"Scrollable + Fullscreen\"\n description=\"Full viewport with scrollable content.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Scrollable + Fullscreen\" />\n {/snippet}\n {#snippet body()}\n <div class=\"space-y-3\">\n {#each Array.from({ length: 30 }, (_, i) => i) as i (i)}\n <div class=\"rounded-md bg-surface-container p-3\">\n <p class=\"text-sm text-on-surface-variant\">Content item {i + 1}</p>\n </div>\n {/each}\n </div>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (scrollableFullscreenOpen = false)}\n />\n {/snippet}\n </Modal>\n </div>\n </section>\n\n <!-- Options -->\n <section class=\"space-y-3\">\n <h2 id=\"Options\" class=\"text-lg font-semibold\">\n<a href=\"#Options\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Options\n </a>\n</h2>\n <div class=\"flex flex-wrap gap-3 rounded-lg bg-surface-container-high p-4\">\n <Modal\n bind:open={noTransitionOpen}\n transition={false}\n title=\"No Transition\"\n description=\"Appears instantly without animation.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"No Transition\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">Modal opens and closes without animation.</p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (noTransitionOpen = false)}\n />\n {/snippet}\n </Modal>\n\n <Modal\n bind:open={noCloseOpen}\n close={false}\n title=\"No Close Button\"\n description=\"Close button is hidden.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"No Close Button\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">Use the footer button or Escape to close.</p>\n {/snippet}\n {#snippet footer()}\n <Button label=\"Close\" variant=\"outline\" onclick={() => (noCloseOpen = false)} />\n {/snippet}\n </Modal>\n\n <Modal\n bind:open={noOverlayOpen}\n overlay={false}\n title=\"No Overlay\"\n description=\"Background is visible.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"No Overlay\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">No backdrop overlay behind the modal.</p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (noOverlayOpen = false)}\n />\n {/snippet}\n </Modal>\n </div>\n </section>\n\n <!-- Non-Dismissible -->\n <section class=\"space-y-3\">\n <h2 id=\"Non-Dismissible\" class=\"text-lg font-semibold\">\n<a href=\"#Non-Dismissible\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Non-Dismissible\n </a>\n</h2>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <Modal\n bind:open={nonDismissibleOpen}\n dismissible={false}\n title=\"Non-Dismissible\"\n description=\"Must use the close button.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Open (Non-Dismissible)\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n Clicking outside or pressing Escape won't close this modal.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"solid\"\n color=\"primary\"\n onclick={() => (nonDismissibleOpen = false)}\n />\n {/snippet}\n </Modal>\n </div>\n </section>\n\n <!-- Slots -->\n <section class=\"space-y-3\">\n <h2 id=\"Slots\" class=\"text-lg font-semibold\">\n<a href=\"#Slots\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Slots\n </a>\n</h2>\n <div class=\"flex flex-wrap gap-3 rounded-lg bg-surface-container-high p-4\">\n <!-- Custom header -->\n <Modal bind:open={slotsOpen}>\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Custom Header\" />\n {/snippet}\n {#snippet header()}\n <div class=\"flex items-center gap-3 p-4 sm:px-6\">\n <div\n class=\"flex size-10 items-center justify-center rounded-full bg-primary text-on-primary\"\n >\n <Icon name=\"lucide:settings\" size=\"20\" />\n </div>\n <div>\n <h3 class=\"font-semibold text-on-surface\">Custom Header</h3>\n <p class=\"text-sm text-on-surface-variant\">With icon and layout</p>\n </div>\n </div>\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n The header slot replaces the default title, description, and close button.\n </p>\n {/snippet}\n {#snippet footer()}\n <div class=\"flex gap-2\">\n <Button\n label=\"Cancel\"\n variant=\"outline\"\n onclick={() => (slotsOpen = false)}\n />\n <Button\n label=\"Save\"\n variant=\"solid\"\n color=\"primary\"\n onclick={() => (slotsOpen = false)}\n />\n </div>\n {/snippet}\n </Modal>\n\n <!-- Actions slot -->\n <Modal\n bind:open={actionsOpen}\n title=\"User Profile\"\n description=\"Manage your account settings.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Actions Slot\" />\n {/snippet}\n {#snippet actions()}\n <Badge variant=\"soft\" color=\"success\" size=\"xs\" label=\"Active\" />\n <Badge variant=\"soft\" color=\"info\" size=\"xs\" label=\"Pro\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n The actions slot renders between the title/description and the close button.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button label=\"Close\" variant=\"outline\" onclick={() => (actionsOpen = false)} />\n {/snippet}\n </Modal>\n\n <!-- Full content slot -->\n <Modal bind:open={customContentOpen} title=\"Custom Content\">\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Content Slot\" />\n {/snippet}\n {#snippet content()}\n <div class=\"flex flex-col items-center gap-4 p-6\">\n <div\n class=\"flex size-16 items-center justify-center rounded-full bg-success/10\"\n >\n <Icon name=\"lucide:check-circle\" size=\"32\" class=\"text-success\" />\n </div>\n <h3 class=\"text-xl font-semibold text-on-surface\">Payment Successful</h3>\n <p class=\"text-center text-on-surface-variant\">\n The content slot replaces the entire inner layout.\n </p>\n <Button\n label=\"Done\"\n variant=\"solid\"\n color=\"primary\"\n onclick={() => (customContentOpen = false)}\n />\n </div>\n {/snippet}\n </Modal>\n </div>\n </section>\n\n <!-- Lifecycle Callbacks -->\n <section class=\"space-y-3\">\n <h2 id=\"Lifecycle-Callbacks\" class=\"text-lg font-semibold\">\n<a href=\"#Lifecycle-Callbacks\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Lifecycle Callbacks\n </a>\n</h2>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <div class=\"mb-3 space-y-1\">\n {#if callbackLog.length === 0}\n <p class=\"text-sm text-on-surface-variant italic\">\n Open/close the modal to see callback logs...\n </p>\n {/if}\n {#each callbackLog as log, i (i)}\n <p class=\"font-mono text-xs text-on-surface-variant\">{log}</p>\n {/each}\n </div>\n <Modal\n bind:open={callbacksOpen}\n onOpenChange={(v) => logCallback(`onOpenChange(${v})`)}\n onOpenChangeComplete={(v) => logCallback(`onOpenChangeComplete(${v})`)}\n title=\"Callback Demo\"\n description=\"Check the log above.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Open (With Callbacks)\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n Open, close, and watch the callback log update.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (callbacksOpen = false)}\n />\n {/snippet}\n </Modal>\n </div>\n </section>\n\n <!-- Programmatic Control -->\n <section class=\"space-y-3\">\n <h2 id=\"Programmatic-Control\" class=\"text-lg font-semibold\">\n<a href=\"#Programmatic-Control\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Programmatic Control\n </a>\n</h2>\n <div class=\"flex gap-3 rounded-lg bg-surface-container-high p-4\">\n <Button\n variant=\"outline\"\n label=\"Open Programmatically\"\n onclick={() => (programmaticOpen = true)}\n />\n <Modal\n bind:open={programmaticOpen}\n title=\"Programmatic Modal\"\n description=\"Opened without a trigger slot.\"\n >\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n This modal has no trigger. It was opened by setting open = true externally.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (programmaticOpen = false)}\n />\n {/snippet}\n </Modal>\n </div>\n </section>\n\n <!-- UI Overrides -->\n <section class=\"space-y-3\">\n <h2 id=\"UI-Slot-Overrides\" class=\"text-lg font-semibold\">\n<a href=\"#UI-Slot-Overrides\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n UI Slot Overrides\n </a>\n</h2>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <Modal\n bind:open={uiOverrideOpen}\n title=\"Styled Modal\"\n description=\"Custom styles via the ui prop.\"\n ui={{\n content: 'bg-primary-container',\n title: 'text-on-primary-container',\n description: 'text-on-primary-container/70',\n header: 'border-on-primary-container/10'\n }}\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Open Styled Modal\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-primary-container/80\">\n This modal overrides content, title, description, and header slot classes.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (uiOverrideOpen = false)}\n />\n {/snippet}\n </Modal>\n </div>\n </section>\n\n <Separator />\n\n <!-- Real World Examples -->\n <section class=\"space-y-3\">\n <h2 id=\"Real-World-Examples\" class=\"text-lg font-semibold\">\n<a href=\"#Real-World-Examples\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Real World Examples\n </a>\n</h2>\n <div class=\"grid gap-4 sm:grid-cols-2\">\n <!-- Confirmation Dialog -->\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <p class=\"mb-3 text-sm font-medium\">Confirmation Dialog</p>\n <Modal bind:open={confirmOpen} dismissible={false} close={false}>\n {#snippet children({ props })}\n <Button\n {...props}\n variant=\"outline\"\n leadingIcon=\"lucide:trash-2\"\n label=\"Delete Item\"\n color=\"error\"\n class=\"w-full\"\n />\n {/snippet}\n {#snippet content()}\n <div class=\"flex flex-col items-center gap-4 p-6 text-center\">\n <div\n class=\"flex size-14 items-center justify-center rounded-full bg-error/10\"\n >\n <Icon name=\"lucide:alert-triangle\" size=\"28\" class=\"text-error\" />\n </div>\n <h3 class=\"text-lg font-semibold text-on-surface\">Delete this item?</h3>\n <p class=\"text-sm text-on-surface-variant\">\n This action is permanent and cannot be undone.\n </p>\n <div class=\"flex w-full gap-2\">\n <Button\n label=\"Cancel\"\n variant=\"outline\"\n class=\"flex-1\"\n onclick={() => (confirmOpen = false)}\n />\n <Button\n label=\"Delete\"\n variant=\"solid\"\n color=\"error\"\n class=\"flex-1\"\n onclick={() => (confirmOpen = false)}\n />\n </div>\n </div>\n {/snippet}\n </Modal>\n </div>\n\n <!-- Form Modal -->\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <p class=\"mb-3 text-sm font-medium\">Form Modal</p>\n <Modal\n bind:open={formOpen}\n title=\"Create Project\"\n description=\"Fill in the details to create a new project.\"\n >\n {#snippet children({ props })}\n <Button\n {...props}\n variant=\"outline\"\n leadingIcon=\"lucide:plus\"\n label=\"New Project\"\n class=\"w-full\"\n />\n {/snippet}\n {#snippet body()}\n <div class=\"space-y-4\">\n <div>\n <label\n for=\"project-name\"\n class=\"mb-1 block text-sm font-medium text-on-surface\"\n >Project Name</label\n >\n <input\n id=\"project-name\"\n type=\"text\"\n placeholder=\"My Project\"\n class=\"w-full rounded-md border border-outline-variant bg-surface px-3 py-2 text-sm text-on-surface placeholder:text-on-surface-variant/50 focus:border-primary focus:ring-1 focus:ring-primary focus:outline-none\"\n />\n </div>\n <div>\n <label\n for=\"project-desc\"\n class=\"mb-1 block text-sm font-medium text-on-surface\"\n >Description</label\n >\n <textarea\n id=\"project-desc\"\n rows=\"3\"\n placeholder=\"Describe your project...\"\n class=\"w-full rounded-md border border-outline-variant bg-surface px-3 py-2 text-sm text-on-surface placeholder:text-on-surface-variant/50 focus:border-primary focus:ring-1 focus:ring-primary focus:outline-none\"\n ></textarea>\n </div>\n </div>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Cancel\"\n variant=\"outline\"\n onclick={() => (formOpen = false)}\n />\n <Button\n label=\"Create\"\n variant=\"solid\"\n color=\"primary\"\n onclick={() => (formOpen = false)}\n />\n {/snippet}\n </Modal>\n </div>\n\n <!-- Alert Modal -->\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <p class=\"mb-3 text-sm font-medium\">Alert Modal</p>\n <Modal\n bind:open={alertOpen}\n title=\"Session Expired\"\n description=\"Your session has timed out due to inactivity.\"\n dismissible={false}\n >\n {#snippet children({ props })}\n <Button\n {...props}\n variant=\"outline\"\n leadingIcon=\"lucide:clock\"\n label=\"Session Alert\"\n class=\"w-full\"\n />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n Please sign in again to continue using the application.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Sign In\"\n variant=\"solid\"\n color=\"primary\"\n class=\"w-full\"\n onclick={() => (alertOpen = false)}\n />\n {/snippet}\n </Modal>\n </div>\n\n <!-- Image Preview -->\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <p class=\"mb-3 text-sm font-medium\">Image Preview</p>\n <Modal bind:open={imageOpen} close={{ color: 'surface', size: 'md' }}>\n {#snippet children({ props })}\n <Button\n {...props}\n variant=\"outline\"\n leadingIcon=\"lucide:image\"\n label=\"View Image\"\n class=\"w-full\"\n />\n {/snippet}\n {#snippet content()}\n <div class=\"p-2\">\n <img\n src=\"https://picsum.photos/800/600\"\n alt=\"Preview\"\n class=\"w-full rounded-md\"\n />\n <p class=\"mt-2 text-center text-sm text-on-surface-variant\">\n Photo from Picsum\n </p>\n </div>\n {/snippet}\n </Modal>\n </div>\n </div>\n </section>\n\n <Separator />\n\n <section>\n <h2 id=\"Size\" class=\"mb-3 text-lg font-semibold\">\n<a href=\"#Size\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Size\n </a>\n</h2>\n <p class=\"mb-4 text-sm text-on-surface-variant\">\n Use <code>size</code> to control the modal width: <code>sm</code> /\n <code>md</code> (default) / <code>lg</code> / <code>xl</code> /\n <code>full</code>. The legacy <code>fullscreen</code> prop is kept as an alias for\n <code>size=\"full\"</code>.\n </p>\n <div class=\"flex flex-wrap gap-2\">\n {#each ['sm', 'md', 'lg', 'xl', 'full'] as const as s (s)}\n <Modal\n bind:open={sizeOpens[s]}\n size={s}\n title={`Size: ${s}`}\n description=\"Resize your browser to see how the modal width scales.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label={`size=\"${s}\"`} />\n {/snippet}\n {#snippet body()}\n <p class=\"text-sm text-on-surface-variant\">\n Current size is <code>{s}</code>.\n </p>\n {/snippet}\n </Modal>\n {/each}\n </div>\n </section>\n\n <Separator />\n\n <section>\n <h2 id=\"Transition\" class=\"mb-3 text-lg font-semibold\">\n<a href=\"#Transition\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Transition\n </a>\n</h2>\n <p class=\"mb-4 text-sm text-on-surface-variant\">\n Pick how the modal animates in and out. Default is <code>scale</code>; pass\n <code>fade</code>, <code>slide</code>, or <code>none</code> to override. Boolean\n <code>true</code> / <code>false</code> still work as legacy aliases.\n </p>\n <div class=\"flex flex-wrap gap-2\">\n {#each ['scale', 'fade', 'slide', 'none'] as const as t (t)}\n <Modal\n bind:open={transitionOpens[t]}\n transition={t}\n title={`Transition: ${t}`}\n description=\"Open and close to see the animation.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label={`transition=\"${t}\"`} />\n {/snippet}\n </Modal>\n {/each}\n </div>\n </section>\n</div>\n",
117
+ "modal": "<script lang=\"ts\">\n import { Modal, Button, Badge, Icon, Separator } from '$lib/index.js'\n\n let basicOpen = $state(false)\n let fullscreenOpen = $state(false)\n let scrollableBodyOpen = $state(false)\n let scrollableOpen = $state(false)\n let scrollableFullscreenOpen = $state(false)\n let noCloseOpen = $state(false)\n let noOverlayOpen = $state(false)\n let noTransitionOpen = $state(false)\n let nonDismissibleOpen = $state(false)\n let slotsOpen = $state(false)\n let actionsOpen = $state(false)\n let customContentOpen = $state(false)\n let callbacksOpen = $state(false)\n let callbackLog = $state<string[]>([])\n let uiOverrideOpen = $state(false)\n let programmaticOpen = $state(false)\n\n let confirmOpen = $state(false)\n let formOpen = $state(false)\n let alertOpen = $state(false)\n let imageOpen = $state(false)\n\n let sizeOpens = $state<Record<string, boolean>>({\n sm: false,\n md: false,\n lg: false,\n xl: false,\n full: false\n })\n let transitionOpens = $state<Record<string, boolean>>({\n scale: false,\n fade: false,\n slide: false,\n none: false\n })\n\n function logCallback(name: string) {\n callbackLog = [...callbackLog.slice(-4), `${new Date().toLocaleTimeString()} — ${name}`]\n }\n</script>\n\n<div class=\"space-y-8\">\n <div class=\"space-y-2\">\n <h1 class=\"text-2xl font-bold\">Modal</h1>\n <p class=\"text-on-surface-variant\">\n A modal dialog component built on bits-ui Dialog. Supports transitions, fullscreen,\n scrollable mode, dismissible control, and full slot customization.\n </p>\n </div>\n\n <!-- Basic -->\n <section class=\"space-y-3\">\n <h2 id=\"Basic\" class=\"text-lg font-semibold\">\n<a href=\"#Basic\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Basic\n </a>\n</h2>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <Modal\n bind:open={basicOpen}\n title=\"Basic Modal\"\n description=\"This is a basic modal with title, description, body and footer.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Open Modal\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n A centered modal dialog. Click the X, press Escape, or click outside to\n close.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button label=\"Cancel\" variant=\"outline\" onclick={() => (basicOpen = false)} />\n <Button\n label=\"Confirm\"\n variant=\"solid\"\n color=\"primary\"\n onclick={() => (basicOpen = false)}\n />\n {/snippet}\n </Modal>\n </div>\n </section>\n\n <!-- Fullscreen -->\n <section class=\"space-y-3\">\n <h2 id=\"Fullscreen\" class=\"text-lg font-semibold\">\n<a href=\"#Fullscreen\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Fullscreen\n </a>\n</h2>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <Modal\n bind:open={fullscreenOpen}\n fullscreen\n title=\"Fullscreen Modal\"\n description=\"This modal takes up the entire screen.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Open Fullscreen\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n Covers the entire viewport. Useful for complex forms or media viewers.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (fullscreenOpen = false)}\n />\n {/snippet}\n </Modal>\n </div>\n </section>\n\n <!-- Scrollable -->\n <section class=\"space-y-3\">\n <h2 id=\"Scrollable\" class=\"text-lg font-semibold\">\n <a href=\"#Scrollable\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Scrollable\n </a>\n </h2>\n <p class=\"text-sm text-on-surface-variant\">\n By default, long content scrolls <strong>inside the modal body</strong> while the header and footer remain fixed. If you prefer the <em>entire modal</em> to scroll along with the overlay, you can use the <code class=\"rounded bg-surface-container-highest px-1\">scrollable</code> property.\n </p>\n <div class=\"flex flex-wrap gap-3 rounded-lg bg-surface-container-high p-4\">\n <!-- Scrollable Body (Default) -->\n <Modal\n bind:open={scrollableBodyOpen}\n title=\"Scrollable Body (Default)\"\n description=\"The header and footer stay fixed. Only the body scrolls.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Scrollable Body\" />\n {/snippet}\n {#snippet body()}\n <div class=\"space-y-3\">\n {#each Array.from({ length: 20 }, (_, i) => i) as i (i)}\n <div class=\"rounded-md bg-surface-container p-3\">\n <p class=\"text-sm text-on-surface-variant\">Content item {i + 1}</p>\n </div>\n {/each}\n </div>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (scrollableBodyOpen = false)}\n />\n {/snippet}\n </Modal>\n\n <!-- Scrollable Overlay -->\n <Modal\n bind:open={scrollableOpen}\n scrollable\n title=\"Scrollable Overlay\"\n description=\"The entire modal scrolls within the overlay.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Scrollable Overlay\" />\n {/snippet}\n {#snippet body()}\n <div class=\"space-y-3\">\n {#each Array.from({ length: 20 }, (_, i) => i) as i (i)}\n <div class=\"rounded-md bg-surface-container p-3\">\n <p class=\"text-sm text-on-surface-variant\">Content item {i + 1}</p>\n </div>\n {/each}\n </div>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (scrollableOpen = false)}\n />\n {/snippet}\n </Modal>\n\n <Modal\n bind:open={scrollableFullscreenOpen}\n scrollable\n fullscreen\n title=\"Scrollable + Fullscreen\"\n description=\"Full viewport with scrollable content.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Scrollable + Fullscreen\" />\n {/snippet}\n {#snippet body()}\n <div class=\"space-y-3\">\n {#each Array.from({ length: 30 }, (_, i) => i) as i (i)}\n <div class=\"rounded-md bg-surface-container p-3\">\n <p class=\"text-sm text-on-surface-variant\">Content item {i + 1}</p>\n </div>\n {/each}\n </div>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (scrollableFullscreenOpen = false)}\n />\n {/snippet}\n </Modal>\n </div>\n </section>\n\n <!-- Options -->\n <section class=\"space-y-3\">\n <h2 id=\"Options\" class=\"text-lg font-semibold\">\n<a href=\"#Options\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Options\n </a>\n</h2>\n <div class=\"flex flex-wrap gap-3 rounded-lg bg-surface-container-high p-4\">\n <Modal\n bind:open={noTransitionOpen}\n transition={false}\n title=\"No Transition\"\n description=\"Appears instantly without animation.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"No Transition\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">Modal opens and closes without animation.</p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (noTransitionOpen = false)}\n />\n {/snippet}\n </Modal>\n\n <Modal\n bind:open={noCloseOpen}\n close={false}\n title=\"No Close Button\"\n description=\"Close button is hidden.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"No Close Button\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">Use the footer button or Escape to close.</p>\n {/snippet}\n {#snippet footer()}\n <Button label=\"Close\" variant=\"outline\" onclick={() => (noCloseOpen = false)} />\n {/snippet}\n </Modal>\n\n <Modal\n bind:open={noOverlayOpen}\n overlay={false}\n title=\"No Overlay\"\n description=\"Background is visible.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"No Overlay\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">No backdrop overlay behind the modal.</p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (noOverlayOpen = false)}\n />\n {/snippet}\n </Modal>\n </div>\n </section>\n\n <!-- Non-Dismissible -->\n <section class=\"space-y-3\">\n <h2 id=\"Non-Dismissible\" class=\"text-lg font-semibold\">\n<a href=\"#Non-Dismissible\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Non-Dismissible\n </a>\n</h2>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <Modal\n bind:open={nonDismissibleOpen}\n dismissible={false}\n title=\"Non-Dismissible\"\n description=\"Must use the close button.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Open (Non-Dismissible)\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n Clicking outside or pressing Escape won't close this modal.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"solid\"\n color=\"primary\"\n onclick={() => (nonDismissibleOpen = false)}\n />\n {/snippet}\n </Modal>\n </div>\n </section>\n\n <!-- Slots -->\n <section class=\"space-y-3\">\n <h2 id=\"Slots\" class=\"text-lg font-semibold\">\n<a href=\"#Slots\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Slots\n </a>\n</h2>\n <div class=\"flex flex-wrap gap-3 rounded-lg bg-surface-container-high p-4\">\n <!-- Custom header -->\n <Modal bind:open={slotsOpen}>\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Custom Header\" />\n {/snippet}\n {#snippet header()}\n <div class=\"flex items-center gap-3 p-4 sm:px-6\">\n <div\n class=\"flex size-10 items-center justify-center rounded-full bg-primary text-on-primary\"\n >\n <Icon name=\"lucide:settings\" size=\"20\" />\n </div>\n <div>\n <h3 class=\"font-semibold text-on-surface\">Custom Header</h3>\n <p class=\"text-sm text-on-surface-variant\">With icon and layout</p>\n </div>\n </div>\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n The header slot replaces the default title, description, and close button.\n </p>\n {/snippet}\n {#snippet footer()}\n <div class=\"flex gap-2\">\n <Button\n label=\"Cancel\"\n variant=\"outline\"\n onclick={() => (slotsOpen = false)}\n />\n <Button\n label=\"Save\"\n variant=\"solid\"\n color=\"primary\"\n onclick={() => (slotsOpen = false)}\n />\n </div>\n {/snippet}\n </Modal>\n\n <!-- Actions slot -->\n <Modal\n bind:open={actionsOpen}\n title=\"User Profile\"\n description=\"Manage your account settings.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Actions Slot\" />\n {/snippet}\n {#snippet actions()}\n <Badge variant=\"soft\" color=\"success\" size=\"xs\" label=\"Active\" />\n <Badge variant=\"soft\" color=\"info\" size=\"xs\" label=\"Pro\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n The actions slot renders between the title/description and the close button.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button label=\"Close\" variant=\"outline\" onclick={() => (actionsOpen = false)} />\n {/snippet}\n </Modal>\n\n <!-- Full content slot -->\n <Modal bind:open={customContentOpen} title=\"Custom Content\">\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Content Slot\" />\n {/snippet}\n {#snippet content()}\n <div class=\"flex flex-col items-center gap-4 p-6\">\n <div\n class=\"flex size-16 items-center justify-center rounded-full bg-success/10\"\n >\n <Icon name=\"lucide:check-circle\" size=\"32\" class=\"text-success\" />\n </div>\n <h3 class=\"text-xl font-semibold text-on-surface\">Payment Successful</h3>\n <p class=\"text-center text-on-surface-variant\">\n The content slot replaces the entire inner layout.\n </p>\n <Button\n label=\"Done\"\n variant=\"solid\"\n color=\"primary\"\n onclick={() => (customContentOpen = false)}\n />\n </div>\n {/snippet}\n </Modal>\n </div>\n </section>\n\n <!-- Lifecycle Callbacks -->\n <section class=\"space-y-3\">\n <h2 id=\"Lifecycle-Callbacks\" class=\"text-lg font-semibold\">\n<a href=\"#Lifecycle-Callbacks\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Lifecycle Callbacks\n </a>\n</h2>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <div class=\"mb-3 space-y-1\">\n {#if callbackLog.length === 0}\n <p class=\"text-sm text-on-surface-variant italic\">\n Open/close the modal to see callback logs...\n </p>\n {/if}\n {#each callbackLog as log, i (i)}\n <p class=\"font-mono text-xs text-on-surface-variant\">{log}</p>\n {/each}\n </div>\n <Modal\n bind:open={callbacksOpen}\n onOpenChange={(v) => logCallback(`onOpenChange(${v})`)}\n onOpenChangeComplete={(v) => logCallback(`onOpenChangeComplete(${v})`)}\n title=\"Callback Demo\"\n description=\"Check the log above.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Open (With Callbacks)\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n Open, close, and watch the callback log update.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (callbacksOpen = false)}\n />\n {/snippet}\n </Modal>\n </div>\n </section>\n\n <!-- Programmatic Control -->\n <section class=\"space-y-3\">\n <h2 id=\"Programmatic-Control\" class=\"text-lg font-semibold\">\n<a href=\"#Programmatic-Control\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Programmatic Control\n </a>\n</h2>\n <div class=\"flex gap-3 rounded-lg bg-surface-container-high p-4\">\n <Button\n variant=\"outline\"\n label=\"Open Programmatically\"\n onclick={() => (programmaticOpen = true)}\n />\n <Modal\n bind:open={programmaticOpen}\n title=\"Programmatic Modal\"\n description=\"Opened without a trigger slot.\"\n >\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n This modal has no trigger. It was opened by setting open = true externally.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (programmaticOpen = false)}\n />\n {/snippet}\n </Modal>\n </div>\n </section>\n\n <!-- UI Overrides -->\n <section class=\"space-y-3\">\n <h2 id=\"UI-Slot-Overrides\" class=\"text-lg font-semibold\">\n<a href=\"#UI-Slot-Overrides\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n UI Slot Overrides\n </a>\n</h2>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <Modal\n bind:open={uiOverrideOpen}\n title=\"Styled Modal\"\n description=\"Custom styles via the ui prop.\"\n ui={{\n content: 'bg-primary-container',\n title: 'text-on-primary-container',\n description: 'text-on-primary-container/70',\n header: 'border-on-primary-container/10'\n }}\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Open Styled Modal\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-primary-container/80\">\n This modal overrides content, title, description, and header slot classes.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (uiOverrideOpen = false)}\n />\n {/snippet}\n </Modal>\n </div>\n </section>\n\n <Separator />\n\n <!-- Real World Examples -->\n <section class=\"space-y-3\">\n <h2 id=\"Real-World-Examples\" class=\"text-lg font-semibold\">\n<a href=\"#Real-World-Examples\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Real World Examples\n </a>\n</h2>\n <div class=\"grid gap-4 sm:grid-cols-2\">\n <!-- Confirmation Dialog -->\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <p class=\"mb-3 text-sm font-medium\">Confirmation Dialog</p>\n <Modal bind:open={confirmOpen} dismissible={false} close={false}>\n {#snippet children({ props })}\n <Button\n {...props}\n variant=\"outline\"\n leadingIcon=\"lucide:trash-2\"\n label=\"Delete Item\"\n color=\"error\"\n class=\"w-full\"\n />\n {/snippet}\n {#snippet content()}\n <div class=\"flex flex-col items-center gap-4 p-6 text-center\">\n <div\n class=\"flex size-14 items-center justify-center rounded-full bg-error/10\"\n >\n <Icon name=\"lucide:alert-triangle\" size=\"28\" class=\"text-error\" />\n </div>\n <h3 class=\"text-lg font-semibold text-on-surface\">Delete this item?</h3>\n <p class=\"text-sm text-on-surface-variant\">\n This action is permanent and cannot be undone.\n </p>\n <div class=\"flex w-full gap-2\">\n <Button\n label=\"Cancel\"\n variant=\"outline\"\n class=\"flex-1\"\n onclick={() => (confirmOpen = false)}\n />\n <Button\n label=\"Delete\"\n variant=\"solid\"\n color=\"error\"\n class=\"flex-1\"\n onclick={() => (confirmOpen = false)}\n />\n </div>\n </div>\n {/snippet}\n </Modal>\n </div>\n\n <!-- Form Modal -->\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <p class=\"mb-3 text-sm font-medium\">Form Modal</p>\n <Modal\n bind:open={formOpen}\n title=\"Create Project\"\n description=\"Fill in the details to create a new project.\"\n >\n {#snippet children({ props })}\n <Button\n {...props}\n variant=\"outline\"\n leadingIcon=\"lucide:plus\"\n label=\"New Project\"\n class=\"w-full\"\n />\n {/snippet}\n {#snippet body()}\n <div class=\"space-y-4\">\n <div>\n <label\n for=\"project-name\"\n class=\"mb-1 block text-sm font-medium text-on-surface\"\n >Project Name</label\n >\n <input\n id=\"project-name\"\n type=\"text\"\n placeholder=\"My Project\"\n class=\"w-full rounded-md border border-outline-variant bg-surface px-3 py-2 text-sm text-on-surface placeholder:text-on-surface-variant/50 focus:border-primary focus:ring-1 focus:ring-primary focus:outline-none\"\n />\n </div>\n <div>\n <label\n for=\"project-desc\"\n class=\"mb-1 block text-sm font-medium text-on-surface\"\n >Description</label\n >\n <textarea\n id=\"project-desc\"\n rows=\"3\"\n placeholder=\"Describe your project...\"\n class=\"w-full rounded-md border border-outline-variant bg-surface px-3 py-2 text-sm text-on-surface placeholder:text-on-surface-variant/50 focus:border-primary focus:ring-1 focus:ring-primary focus:outline-none\"\n ></textarea>\n </div>\n </div>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Cancel\"\n variant=\"outline\"\n onclick={() => (formOpen = false)}\n />\n <Button\n label=\"Create\"\n variant=\"solid\"\n color=\"primary\"\n onclick={() => (formOpen = false)}\n />\n {/snippet}\n </Modal>\n </div>\n\n <!-- Alert Modal -->\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <p class=\"mb-3 text-sm font-medium\">Alert Modal</p>\n <Modal\n bind:open={alertOpen}\n title=\"Session Expired\"\n description=\"Your session has timed out due to inactivity.\"\n dismissible={false}\n >\n {#snippet children({ props })}\n <Button\n {...props}\n variant=\"outline\"\n leadingIcon=\"lucide:clock\"\n label=\"Session Alert\"\n class=\"w-full\"\n />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n Please sign in again to continue using the application.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Sign In\"\n variant=\"solid\"\n color=\"primary\"\n class=\"w-full\"\n onclick={() => (alertOpen = false)}\n />\n {/snippet}\n </Modal>\n </div>\n\n <!-- Image Preview -->\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <p class=\"mb-3 text-sm font-medium\">Image Preview</p>\n <Modal bind:open={imageOpen} close={{ color: 'surface', size: 'md' }}>\n {#snippet children({ props })}\n <Button\n {...props}\n variant=\"outline\"\n leadingIcon=\"lucide:image\"\n label=\"View Image\"\n class=\"w-full\"\n />\n {/snippet}\n {#snippet content()}\n <div class=\"p-2\">\n <img\n src=\"https://picsum.photos/800/600\"\n alt=\"Preview\"\n class=\"w-full rounded-md\"\n />\n <p class=\"mt-2 text-center text-sm text-on-surface-variant\">\n Photo from Picsum\n </p>\n </div>\n {/snippet}\n </Modal>\n </div>\n </div>\n </section>\n\n <Separator />\n\n <section>\n <h2 id=\"Size\" class=\"mb-3 text-lg font-semibold\">\n<a href=\"#Size\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Size\n </a>\n</h2>\n <p class=\"mb-4 text-sm text-on-surface-variant\">\n Use <code>size</code> to control the modal width: <code>sm</code> /\n <code>md</code> (default) / <code>lg</code> / <code>xl</code> /\n <code>full</code>. The legacy <code>fullscreen</code> prop is kept as an alias for\n <code>size=\"full\"</code>.\n </p>\n <div class=\"flex flex-wrap gap-2\">\n {#each ['sm', 'md', 'lg', 'xl', 'full'] as const as s (s)}\n <Modal\n bind:open={sizeOpens[s]}\n size={s}\n title={`Size: ${s}`}\n description=\"Resize your browser to see how the modal width scales.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label={`size=\"${s}\"`} />\n {/snippet}\n {#snippet body()}\n <p class=\"text-sm text-on-surface-variant\">\n Current size is <code>{s}</code>.\n </p>\n {/snippet}\n </Modal>\n {/each}\n </div>\n </section>\n\n <Separator />\n\n <section>\n <h2 id=\"Transition\" class=\"mb-3 text-lg font-semibold\">\n<a href=\"#Transition\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Transition\n </a>\n</h2>\n <p class=\"mb-4 text-sm text-on-surface-variant\">\n Pick how the modal animates in and out. Default is <code>scale</code>; pass\n <code>fade</code>, <code>slide</code>, or <code>none</code> to override. Boolean\n <code>true</code> / <code>false</code> still work as legacy aliases.\n </p>\n <div class=\"flex flex-wrap gap-2\">\n {#each ['scale', 'fade', 'slide', 'none'] as const as t (t)}\n <Modal\n bind:open={transitionOpens[t]}\n transition={t}\n title={`Transition: ${t}`}\n description=\"Open and close to see the animation.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label={`transition=\"${t}\"`} />\n {/snippet}\n </Modal>\n {/each}\n </div>\n </section>\n</div>\n",
118
118
  "navigation-menu": "<script lang=\"ts\">\n import { NavigationMenu, Separator } from '$lib/index.js'\n import type { NavigationMenuItemType } from '$lib/index.js'\n\n // --- Basic Navbar (1D Array) ---\n const basicLinks: NavigationMenuItemType[] = [\n { label: 'Home', href: '/', icon: 'lucide:home', active: true },\n { label: 'Components', href: '/docs/components/button', icon: 'lucide:box' },\n { label: 'Changelog', href: '/changelog', badge: 'v3.0.7', badgeColor: 'info' }\n ]\n\n // --- Unified Navbar (2D Array) ---\n const unifiedLinks: NavigationMenuItemType[][] = [\n [\n { label: 'Dashboard', icon: 'lucide:layout-dashboard', href: '/dashboard' },\n {\n label: 'Products',\n icon: 'lucide:shopping-bag',\n items: [\n { type: 'item', label: 'All Products', icon: 'lucide:package' },\n { type: 'item', label: 'Categories', icon: 'lucide:tags' },\n { type: 'separator' },\n { type: 'item', label: 'Add New Product', icon: 'lucide:plus', kbds: ['meta', 'P'] }\n ]\n }\n ],\n [\n { label: 'GitHub', icon: 'simple-icons:github', href: 'https://github.com/asphum/svelora', target: '_blank', badge: 'v3' },\n {\n label: 'Settings',\n icon: 'lucide:settings',\n items: [\n { type: 'item', label: 'Profile', icon: 'lucide:user' },\n { type: 'item', label: 'Preferences', icon: 'lucide:sliders' }\n ]\n }\n ]\n ]\n\n // --- Vertical Sidebar Links ---\n const sidebarLinks: NavigationMenuItemType[] = [\n { label: 'Overview', icon: 'lucide:layout-dashboard', href: '/dashboard' },\n {\n label: 'Analytics',\n icon: 'lucide:bar-chart-2',\n defaultOpen: true,\n items: [\n { type: 'item', label: 'Reports', icon: 'lucide:file-text' },\n { type: 'item', label: 'Traffic', icon: 'lucide:activity' }\n ]\n },\n {\n label: 'Settings',\n icon: 'lucide:settings',\n items: [\n { type: 'item', label: 'Profile', icon: 'lucide:user' },\n { type: 'item', label: 'Billing', icon: 'lucide:credit-card' }\n ]\n }\n ]\n\n // --- Tree Sidebar Links ---\n const treeLinks: NavigationMenuItemType[] = [\n { label: 'Overview', icon: 'lucide:layout-dashboard', href: '/dashboard' },\n {\n label: 'Analytics',\n icon: 'lucide:bar-chart-2',\n badge: 2,\n defaultOpen: true,\n items: [\n { type: 'item', label: 'Reports', icon: 'lucide:file-text', active: true },\n { type: 'item', label: 'Traffic', icon: 'lucide:activity' }\n ]\n },\n {\n label: 'Settings',\n icon: 'lucide:settings',\n badge: 3,\n items: [\n { type: 'item', label: 'Profile', icon: 'lucide:user' },\n { type: 'item', label: 'Preferences', icon: 'lucide:sliders' },\n { type: 'item', label: 'Billing', icon: 'lucide:credit-card' }\n ]\n }\n ]\n</script>\n\n<div class=\"space-y-8\">\n <div class=\"space-y-2\">\n <h1 class=\"text-2xl font-bold\">Navigation Menu</h1>\n <p class=\"text-on-surface-variant\">\n A unified navigation component that supports both horizontal and vertical orientations.\n </p>\n </div>\n\n <!-- Basic Navbar -->\n <section class=\"space-y-3\">\n <h2 id=\"Basic-Navigation\" class=\"text-lg font-semibold\">\n<a href=\"#Basic-Navigation\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Basic Navigation\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n A simple 1D list of links. Use the <code class=\"rounded bg-surface-container-highest px-1\">items</code> prop to define your navigation.\n </p>\n <div class=\"rounded-lg border border-outline-variant bg-surface-container-lowest p-6 flex flex-col gap-4\">\n <div class=\"w-full bg-surface border border-outline-variant rounded-xl shadow-sm px-4 py-2 flex items-center justify-between\">\n <span class=\"font-bold text-lg mr-8\">Brand</span>\n <NavigationMenu items={basicLinks} class=\"flex-1\" />\n </div>\n </div>\n </section>\n\n <Separator />\n\n <!-- 2D Array Grouping -->\n <section class=\"space-y-3\">\n <h2 id=\"Grouping-2D-Arrays\" class=\"text-lg font-semibold\">\n<a href=\"#Grouping-2D-Arrays\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Grouping (2D Arrays)\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Pass a 2D array (<code class=\"rounded bg-surface-container-highest px-1\">items=[ [leftItems], [rightItems] ]</code>) to easily group links on opposite sides of the navbar.\n </p>\n <div class=\"rounded-lg border border-outline-variant bg-surface-container-lowest p-6\">\n <div class=\"w-full bg-surface border border-outline-variant rounded-xl shadow-sm px-4 py-2 flex items-center\">\n <NavigationMenu items={unifiedLinks} />\n </div>\n </div>\n </section>\n\n <Separator />\n\n <!-- Vertical Orientation (Accordion) -->\n <section class=\"space-y-3\">\n <h2 id=\"Vertical-Sidebar--Accordion\" class=\"text-lg font-semibold\">\n<a href=\"#Vertical-Sidebar--Accordion\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Vertical (Sidebar & Accordion)\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Set <code class=\"rounded bg-surface-container-highest px-1\">orientation=\"vertical\"</code> to render as a sidebar menu. Nested sub-menus will automatically render as smoothly expanding accordions! Add <code class=\"rounded bg-surface-container-highest px-1\">accordion=\"true\"</code> to restrict opening to one group at a time.\n </p>\n <div class=\"rounded-lg border border-outline-variant bg-surface-container-lowest p-6 flex gap-8\">\n <div class=\"w-64 bg-surface border border-outline-variant rounded-xl shadow-sm p-3 flex flex-col items-start\">\n <p class=\"text-xs font-semibold text-on-surface-variant px-3 mb-2 uppercase tracking-wider\">Multi-Open</p>\n <NavigationMenu items={sidebarLinks} orientation=\"vertical\" variant=\"ghost\" />\n </div>\n \n <div class=\"w-64 bg-surface border border-outline-variant rounded-xl shadow-sm p-3 flex flex-col items-start\">\n <p class=\"text-xs font-semibold text-on-surface-variant px-3 mb-2 uppercase tracking-wider\">Strict Accordion</p>\n <NavigationMenu items={sidebarLinks} orientation=\"vertical\" variant=\"ghost\" accordion />\n </div>\n </div>\n </section>\n\n <Separator />\n\n <!-- Tree Style (Lines & Badges) -->\n <section class=\"space-y-3\">\n <h2 id=\"Tree-Style\" class=\"text-lg font-semibold\">\n<a href=\"#Tree-Style\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n \n Tree Style\n \n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Set <code class=\"rounded bg-surface-container-highest px-1\">tree=\"true\"</code> to render connecting lines for nested sub-menus. This style pairs well with badges indicating the number of child items!\n </p>\n <div class=\"rounded-lg border border-outline-variant bg-surface-container-lowest p-6 flex gap-8\">\n <div class=\"w-64 bg-surface border border-outline-variant rounded-xl shadow-sm p-3 flex flex-col items-start\">\n <p class=\"text-xs font-semibold text-on-surface-variant px-3 mb-2 uppercase tracking-wider\">With Lines & Badges</p>\n <NavigationMenu items={treeLinks} orientation=\"vertical\" variant=\"ghost\" tree accordion />\n </div>\n </div>\n </section>\n\n <Separator />\n\n <!-- Auto-Active State -->\n <section class=\"space-y-3\">\n <h2 id=\"Auto-Active-State\" class=\"text-lg font-semibold\">\n <a href=\"#Auto-Active-State\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Auto-Active State\n </a>\n </h2>\n <p class=\"text-sm text-on-surface-variant\">\n NavigationMenu automatically detects the current URL and highlights matching links! It features a powerful Longest Prefix Match algorithm and supports exact/prefix matching out of the box.\n </p>\n \n <div class=\"space-y-4 mt-4\">\n <div class=\"rounded-lg border border-outline-variant bg-surface-container-lowest p-6\">\n <h3 class=\"text-sm font-semibold mb-2\">Exact Match (Default)</h3>\n <p class=\"text-sm text-on-surface-variant mb-4\">By default, <code class=\"rounded bg-surface-container-highest px-1\">exact: true</code> is assumed. The item will only be active if the current URL matches its <code class=\"rounded bg-surface-container-highest px-1\">href</code> perfectly.</p>\n </div>\n\n <div class=\"rounded-lg border border-outline-variant bg-surface-container-lowest p-6\">\n <h3 class=\"text-sm font-semibold mb-2\">Prefix Match</h3>\n <p class=\"text-sm text-on-surface-variant mb-4\">Set <code class=\"rounded bg-surface-container-highest px-1\">exact: false</code> on an item to make it active whenever the URL starts with its <code class=\"rounded bg-surface-container-highest px-1\">href</code>. Great for top-level navigation tabs!</p>\n </div>\n\n <div class=\"rounded-lg border border-outline-variant bg-surface-container-lowest p-6\">\n <h3 class=\"text-sm font-semibold mb-2\">Advanced: Match Pattern</h3>\n <p class=\"text-sm text-on-surface-variant mb-4\">If your <code class=\"rounded bg-surface-container-highest px-1\">href</code> points to a deep subpage (like <code class=\"text-primary\">/docs/components/button</code>) but you want it to act as the parent tab for the whole section, use <code class=\"rounded bg-surface-container-highest px-1\">matchPattern</code> to tell the menu what URL to match against!</p>\n </div>\n </div>\n </section>\n</div>\n",
119
119
  "scroll-area": "<script lang=\"ts\">\n import { ScrollArea, Separator } from '$lib/index.js'\n</script>\n\n<div class=\"space-y-8\">\n <div class=\"space-y-2\">\n <h1 class=\"text-2xl font-bold\">ScrollArea</h1>\n <p class=\"text-on-surface-variant\">\n Augments native scroll functionality for custom, cross-browser styling.\n </p>\n </div>\n\n <!-- Usage -->\n <section class=\"space-y-3\">\n <h2 id=\"Usage\" class=\"text-lg font-semibold\">\n<a href=\"#Usage\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Usage\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Wrap any content in a <code class=\"rounded bg-surface-container-highest px-1\">ScrollArea</code> and provide it with a fixed height.\n </p>\n <div class=\"rounded-lg bg-surface-container-high p-4 flex justify-center\">\n <ScrollArea class=\"h-72 w-full max-w-sm rounded-lg border border-outline-variant bg-surface p-4\">\n <div class=\"space-y-4\">\n <h4 class=\"text-sm font-semibold\">Svelora Components</h4>\n <Separator />\n {#each Array(50) as _, i}\n <div class=\"text-sm text-on-surface-variant\">Component {i + 1}</div>\n {#if i !== 49}\n <Separator />\n {/if}\n {/each}\n </div>\n </ScrollArea>\n </div>\n </section>\n\n <!-- Horizontal -->\n <section class=\"space-y-3\">\n <h2 id=\"Horizontal-Scrolling\" class=\"text-lg font-semibold\">\n<a href=\"#Horizontal-Scrolling\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Horizontal Scrolling\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Set <code class=\"rounded bg-surface-container-highest px-1\">orientation=\"horizontal\"</code> or <code class=\"rounded bg-surface-container-highest px-1\">orientation=\"both\"</code> to enable horizontal scrollbars.\n </p>\n <div class=\"rounded-lg bg-surface-container-high p-4 flex justify-center\">\n <ScrollArea orientation=\"horizontal\" class=\"w-full max-w-lg rounded-lg border border-outline-variant bg-surface p-4 whitespace-nowrap\">\n <div class=\"flex gap-4\">\n {#each Array(10) as _, i}\n <div class=\"h-32 w-32 shrink-0 rounded-md bg-surface-container-highest flex items-center justify-center font-bold text-on-surface-variant\">\n Item {i + 1}\n </div>\n {/each}\n </div>\n </ScrollArea>\n </div>\n </section>\n</div>\n",
120
120
  "search": "<script lang=\"ts\">\n import { Search, Separator, CodeBlock, Badge } from '$lib/index.js'\n import type { CommandGroup } from '$lib/index.js'\n import { quickExample } from './quick-example.js'\n\n const searchGroups: CommandGroup[] = [\n {\n id: 'pages',\n label: 'Pages',\n items: [\n { value: 'home', label: 'Home', icon: 'lucide:home', keywords: ['start', 'main'] },\n { value: 'dashboard', label: 'Dashboard', icon: 'lucide:layout-dashboard' },\n { value: 'settings', label: 'Settings', icon: 'lucide:settings', keywords: ['preferences', 'options'] }\n ]\n },\n {\n id: 'actions',\n label: 'Actions',\n items: [\n { value: 'new-file', label: 'New File', icon: 'lucide:file-plus' },\n { value: 'invite', label: 'Invite Users', icon: 'lucide:user-plus' }\n ]\n }\n ]\n\n let selectedValue = $state<string | null>(null)\n let inputValue = $state('')\n</script>\n\n<div class=\"space-y-8\">\n <div class=\"space-y-2\">\n <h1 class=\"text-2xl font-bold\">Search</h1>\n <p class=\"text-on-surface-variant\">\n A flexible search component that can act as a standard input, an icon button, or a global command palette modal (⌘K).\n </p>\n </div>\n\n <!-- Quick Example -->\n <section class=\"space-y-3\">\n <h2 id=\"Quick-Start\" class=\"text-lg font-semibold\">\n<a href=\"#Quick-Start\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Quick Start\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use <code class=\"rounded bg-surface-container-highest px-1\">variant=\"modal\"</code> to create a \"fake\" input that triggers a global search modal. This is the modern best practice for application search.\n </p>\n <div class=\"rounded-lg border border-outline-variant bg-surface-container-lowest p-6 flex flex-col items-center gap-6\">\n <div class=\"w-full max-w-sm\">\n <Search \n variant=\"modal\" \n groups={searchGroups} \n kbd={['meta', 'K']} \n placeholder=\"Search documentation...\" \n onSelect={(val) => selectedValue = val}\n />\n </div>\n {#if selectedValue}\n <div class=\"flex items-center gap-2\">\n <span class=\"text-sm text-on-surface-variant\">You selected:</span>\n <Badge color=\"success\" label={selectedValue} />\n </div>\n {/if}\n </div>\n <CodeBlock code={quickExample} />\n </section>\n\n <Separator />\n\n <!-- Variant: Input -->\n <section class=\"space-y-3\">\n <h2 id=\"Standard-Input\" class=\"text-lg font-semibold\">\n<a href=\"#Standard-Input\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Standard Input\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use <code class=\"rounded bg-surface-container-highest px-1\">variant=\"input\"</code> (default) for a standard text input. You can still pass <code class=\"rounded bg-surface-container-highest px-1\">kbd</code> to show a keyboard shortcut visual.\n </p>\n <div class=\"rounded-lg border border-outline-variant bg-surface-container-lowest p-6 flex flex-col items-center gap-4\">\n <div class=\"w-full max-w-sm\">\n <Search \n variant=\"input\" \n bind:value={inputValue}\n placeholder=\"Search standard input...\" \n kbd={['/']}\n />\n </div>\n <p class=\"text-sm text-on-surface-variant\">Value: {inputValue || 'empty'}</p>\n </div>\n </section>\n\n <Separator />\n\n <!-- Variant: Button -->\n <section class=\"space-y-3\">\n <h2 id=\"Icon-Button\" class=\"text-lg font-semibold\">\n<a href=\"#Icon-Button\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Icon Button\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use <code class=\"rounded bg-surface-container-highest px-1\">variant=\"button\"</code> for an icon-only trigger that opens the command modal. Great for mobile navbars.\n </p>\n <div class=\"rounded-lg border border-outline-variant bg-surface-container-lowest p-6 flex justify-center\">\n <div class=\"flex items-center gap-4 bg-surface px-4 py-2 rounded-full border border-outline-variant shadow-sm\">\n <span class=\"font-bold text-lg\">My App</span>\n <div class=\"flex-1\"></div>\n <Search \n variant=\"button\" \n groups={searchGroups} \n />\n </div>\n </div>\n </section>\n</div>\n",
@@ -169,7 +169,7 @@
169
169
  "command": "<script lang=\"ts\">\n import { Command, Separator, Badge, Kbd, Button, Popover, Modal, Drawer } from '$lib/index.js'\n import type { CommandGroup } from '$lib/index.js'\n\n // --- Basic groups ---\n const basicGroups: CommandGroup[] = [\n {\n id: 'suggestions',\n label: 'Suggestions',\n items: [\n { value: 'calendar', label: 'Calendar', icon: 'lucide:calendar' },\n { value: 'search-emoji', label: 'Search Emoji', icon: 'lucide:smile' },\n { value: 'calculator', label: 'Calculator', icon: 'lucide:calculator' }\n ]\n },\n {\n id: 'settings',\n label: 'Settings',\n items: [\n {\n value: 'profile',\n label: 'Profile',\n icon: 'lucide:user',\n description: 'Manage your profile settings'\n },\n {\n value: 'billing',\n label: 'Billing',\n icon: 'lucide:credit-card',\n description: 'View billing information'\n },\n {\n value: 'preferences',\n label: 'Preferences',\n icon: 'lucide:settings',\n description: 'Configure app preferences'\n }\n ]\n }\n ]\n\n // --- Groups with disabled items ---\n const disabledGroups: CommandGroup[] = [\n {\n id: 'actions',\n label: 'Actions',\n items: [\n { value: 'new-file', label: 'New File', icon: 'lucide:file-plus' },\n { value: 'new-folder', label: 'New Folder', icon: 'lucide:folder-plus' },\n {\n value: 'delete',\n label: 'Delete (disabled)',\n icon: 'lucide:trash-2',\n disabled: true\n },\n {\n value: 'archive',\n label: 'Archive (disabled)',\n icon: 'lucide:archive',\n disabled: true\n }\n ]\n }\n ]\n\n // --- Keywords for search ---\n const keywordGroups: CommandGroup[] = [\n {\n id: 'navigation',\n label: 'Navigation',\n items: [\n {\n value: 'home',\n label: 'Home',\n icon: 'lucide:home',\n keywords: ['dashboard', 'main', 'start']\n },\n {\n value: 'docs',\n label: 'Documentation',\n icon: 'lucide:book-open',\n keywords: ['help', 'guide', 'manual']\n },\n {\n value: 'components',\n label: 'Components',\n icon: 'lucide:blocks',\n keywords: ['ui', 'elements', 'widgets']\n }\n ]\n }\n ]\n\n // --- External filtering ---\n let externalSearch = $state('')\n const allCountries = [\n { value: 'us', label: 'United States', icon: 'circle-flags:us' },\n { value: 'gb', label: 'United Kingdom', icon: 'circle-flags:gb' },\n { value: 'fr', label: 'France', icon: 'circle-flags:fr' },\n { value: 'de', label: 'Germany', icon: 'circle-flags:de' },\n { value: 'jp', label: 'Japan', icon: 'circle-flags:jp' },\n { value: 'kr', label: 'South Korea', icon: 'circle-flags:kr' },\n { value: 'vn', label: 'Vietnam', icon: 'circle-flags:vn' },\n { value: 'br', label: 'Brazil', icon: 'circle-flags:br' },\n { value: 'au', label: 'Australia', icon: 'circle-flags:au' },\n { value: 'ca', label: 'Canada', icon: 'circle-flags:ca' }\n ]\n const filteredCountries = $derived(\n externalSearch\n ? allCountries.filter((c) =>\n c.label.toLowerCase().includes(externalSearch.toLowerCase())\n )\n : allCountries\n )\n const externalGroups = $derived<CommandGroup[]>([\n {\n id: 'countries',\n label: externalSearch\n ? `Results for \"${externalSearch}\" (${filteredCountries.length})`\n : `All countries (${allCountries.length})`,\n items: filteredCountries\n }\n ])\n\n // --- onSelect callback ---\n let lastSelected = $state('')\n const callbackGroups: CommandGroup[] = [\n {\n id: 'fruits',\n label: 'Fruits',\n items: [\n {\n value: 'apple',\n label: 'Apple',\n icon: 'lucide:apple',\n onSelect: () => (lastSelected = 'Apple')\n },\n {\n value: 'banana',\n label: 'Banana',\n icon: 'lucide:banana',\n onSelect: () => (lastSelected = 'Banana')\n },\n {\n value: 'grape',\n label: 'Grape',\n icon: 'lucide:grape',\n onSelect: () => (lastSelected = 'Grape')\n }\n ]\n }\n ]\n\n // --- Multiple groups ---\n const multiGroups: CommandGroup[] = [\n {\n id: 'general',\n label: 'General',\n items: [\n {\n value: 'appearance',\n label: 'Appearance',\n icon: 'lucide:paintbrush',\n description: 'Change theme and colors'\n },\n {\n value: 'language',\n label: 'Language',\n icon: 'lucide:globe',\n description: 'Select preferred language'\n }\n ]\n },\n {\n id: 'account',\n label: 'Account',\n items: [\n {\n value: 'security',\n label: 'Security',\n icon: 'lucide:shield',\n description: 'Password and 2FA'\n },\n {\n value: 'notifications',\n label: 'Notifications',\n icon: 'lucide:bell',\n description: 'Email and push alerts'\n }\n ]\n },\n {\n id: 'developer',\n label: 'Developer',\n items: [\n {\n value: 'api-keys',\n label: 'API Keys',\n icon: 'lucide:key',\n description: 'Manage API credentials'\n },\n {\n value: 'webhooks',\n label: 'Webhooks',\n icon: 'lucide:webhook',\n description: 'Configure webhook endpoints'\n }\n ]\n }\n ]\n</script>\n\n<div class=\"mx-auto max-w-3xl space-y-12 p-8\">\n <div>\n <h1 class=\"text-2xl font-bold\">Command</h1>\n <p class=\"mt-1 text-on-surface-variant\">\n A command menu with search filtering and keyboard navigation.\n </p>\n </div>\n\n <Separator />\n\n <!-- Basic -->\n <section class=\"space-y-3\">\n <h2 id=\"Basic\" class=\"text-lg font-semibold\">\n<a href=\"#Basic\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Basic\n </a>\n</h2>\n <div class=\"rounded-lg border border-outline-variant shadow-md\">\n <Command groups={basicGroups} placeholder=\"Type a command or search...\" />\n </div>\n </section>\n\n <Separator />\n\n <!-- With descriptions -->\n <section class=\"space-y-3\">\n <h2 id=\"Items-with-Descriptions\" class=\"text-lg font-semibold\">\n<a href=\"#Items-with-Descriptions\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Items with Descriptions\n </a>\n</h2>\n <div class=\"rounded-lg border border-outline-variant shadow-md\">\n <Command groups={multiGroups} placeholder=\"Search settings...\" />\n </div>\n </section>\n\n <Separator />\n\n <!-- Disabled items -->\n <section class=\"space-y-3\">\n <h2 id=\"Disabled-Items\" class=\"text-lg font-semibold\">\n<a href=\"#Disabled-Items\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Disabled Items\n </a>\n</h2>\n <div class=\"rounded-lg border border-outline-variant shadow-md\">\n <Command groups={disabledGroups} placeholder=\"Search actions...\" />\n </div>\n </section>\n\n <Separator />\n\n <!-- Keywords search -->\n <section class=\"space-y-3\">\n <h2 id=\"Keywords-search-help-ui-dashboard\" class=\"text-lg font-semibold\">\n<a href=\"#Keywords-search-help-ui-dashboard\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Keywords (search \"help\", \"ui\", \"dashboard\")\n </a>\n</h2>\n <div class=\"rounded-lg border border-outline-variant shadow-md\">\n <Command groups={keywordGroups} placeholder=\"Try searching help or dashboard...\" />\n </div>\n </section>\n\n <Separator />\n\n <!-- onSelect callback -->\n <section class=\"space-y-3\">\n <h2 id=\"onSelect-Callback\" class=\"text-lg font-semibold\">\n<a href=\"#onSelect-Callback\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n onSelect Callback\n </a>\n</h2>\n <div class=\"flex items-center gap-2\">\n <span class=\"text-sm text-on-surface-variant\">Last selected:</span>\n <Badge label={lastSelected || 'None'} color={lastSelected ? 'success' : 'surface'} />\n </div>\n <div class=\"rounded-lg border border-outline-variant shadow-md\">\n <Command groups={callbackGroups} placeholder=\"Select a fruit...\" />\n </div>\n </section>\n\n <Separator />\n\n <!-- Loading -->\n <section class=\"space-y-3\">\n <h2 id=\"Loading-State\" class=\"text-lg font-semibold\">\n<a href=\"#Loading-State\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Loading State\n </a>\n</h2>\n <div class=\"rounded-lg border border-outline-variant shadow-md\">\n <Command groups={[]} loading placeholder=\"Fetching results...\" />\n </div>\n </section>\n\n <Separator />\n\n <!-- Empty state -->\n <section class=\"space-y-3\">\n <h2 id=\"Empty-State\" class=\"text-lg font-semibold\">\n<a href=\"#Empty-State\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Empty State\n </a>\n</h2>\n <div class=\"rounded-lg border border-outline-variant shadow-md\">\n <Command\n groups={[{ id: 'empty', items: [] }]}\n emptyText=\"Nothing here yet.\"\n placeholder=\"Search...\"\n />\n </div>\n </section>\n\n <Separator />\n\n <!-- Custom empty slot -->\n <section class=\"space-y-3\">\n <h2 id=\"Custom-Empty-Slot\" class=\"text-lg font-semibold\">\n<a href=\"#Custom-Empty-Slot\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Custom Empty Slot\n </a>\n</h2>\n <div class=\"rounded-lg border border-outline-variant shadow-md\">\n <Command groups={basicGroups} placeholder=\"Search something that doesn't exist...\">\n {#snippet empty({ search })}\n <div class=\"flex flex-col items-center gap-2 py-6\">\n <span class=\"text-2xl\">🔍</span>\n <span class=\"text-sm text-on-surface-variant\">\n {search ? `No results for \"${search}\"` : 'Start typing to search'}\n </span>\n </div>\n {/snippet}\n </Command>\n </div>\n </section>\n\n <Separator />\n\n <!-- Sizes -->\n <section class=\"space-y-3\">\n <h2 id=\"Sizes\" class=\"text-lg font-semibold\">\n<a href=\"#Sizes\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Sizes\n </a>\n</h2>\n {#each ['xs', 'sm', 'md', 'lg', 'xl'] as const as s (s)}\n <div>\n <p class=\"mb-1 text-xs font-medium text-on-surface-variant\">{s}</p>\n <div class=\"rounded-lg border border-outline-variant shadow-md\">\n <Command\n size={s}\n groups={[\n {\n id: 'size-demo',\n label: 'Actions',\n items: [\n { value: 'copy', label: 'Copy', icon: 'lucide:copy' },\n { value: 'paste', label: 'Paste', icon: 'lucide:clipboard' }\n ]\n }\n ]}\n placeholder=\"Size {s}...\"\n />\n </div>\n </div>\n {/each}\n </section>\n\n <Separator />\n\n <!-- Custom UI slots -->\n <section class=\"space-y-3\">\n <h2 id=\"Custom-UI-Slots\" class=\"text-lg font-semibold\">\n<a href=\"#Custom-UI-Slots\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Custom UI Slots\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Available ui slots: root, input, list, empty, loading, group, groupHeading, groupItems,\n separator, item, itemIcon, itemLabel, itemDescription, itemTrailing\n </p>\n <div class=\"space-y-4\">\n <div>\n <p class=\"mb-1 text-xs font-medium text-on-surface-variant\">\n Custom background + rounded items + uppercase headings\n </p>\n <Command\n groups={basicGroups}\n placeholder=\"Styled command...\"\n ui={{\n root: 'rounded-lg border border-outline-variant shadow-md bg-surface-container-low',\n item: 'rounded-lg',\n groupHeading: 'uppercase tracking-wider text-primary'\n }}\n />\n </div>\n <div>\n <p class=\"mb-1 text-xs font-medium text-on-surface-variant\">\n Custom selected item color + item icon color\n </p>\n <div class=\"rounded-lg border border-outline-variant shadow-md\">\n <Command\n groups={basicGroups}\n placeholder=\"Custom highlight...\"\n ui={{\n item: 'data-[selected]:bg-primary/10 data-[selected]:text-primary',\n itemIcon: 'text-primary'\n }}\n />\n </div>\n </div>\n <div>\n <p class=\"mb-1 text-xs font-medium text-on-surface-variant\">\n Custom list max height (scrollable)\n </p>\n <div class=\"rounded-lg border border-outline-variant shadow-md\">\n <Command\n groups={multiGroups}\n placeholder=\"Scroll to see more...\"\n ui={{\n list: 'max-h-48'\n }}\n />\n </div>\n </div>\n </div>\n </section>\n\n <Separator />\n\n <!-- Footer slot -->\n <section class=\"space-y-3\">\n <h2 id=\"Footer-Slot\" class=\"text-lg font-semibold\">\n<a href=\"#Footer-Slot\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Footer Slot\n </a>\n</h2>\n <div class=\"rounded-lg border border-outline-variant shadow-md\">\n <Command groups={basicGroups} placeholder=\"Search...\">\n {#snippet footer()}\n <div\n class=\"flex items-center justify-between px-3 py-2 text-xs text-on-surface-variant\"\n >\n <div class=\"flex items-center gap-2\">\n <span class=\"flex items-center gap-1\"\n ><Kbd value=\"↑\" size=\"sm\" /><Kbd value=\"↓\" size=\"sm\" /> Navigate</span\n >\n <span class=\"flex items-center gap-1\"\n ><Kbd value=\"↵\" size=\"sm\" /> Select</span\n >\n </div>\n <span class=\"flex items-center gap-1\"\n ><Kbd value=\"Esc\" size=\"sm\" /> Close</span\n >\n </div>\n {/snippet}\n </Command>\n </div>\n </section>\n\n <Separator />\n\n <!-- shouldFilter=false -->\n <section class=\"space-y-3\">\n <h2 id=\"External-Filtering-shouldFilterfalse\" class=\"text-lg font-semibold\">\n<a href=\"#External-Filtering-shouldFilterfalse\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n External Filtering (shouldFilter=false)\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Built-in filter is disabled. The search term is bound via\n <code class=\"rounded bg-surface-container-highest px-1 py-0.5 text-xs\">bind:search</code\n >\n and filtering is handled externally.\n </p>\n <div class=\"rounded-lg border border-outline-variant shadow-md\">\n <Command\n shouldFilter={false}\n bind:search={externalSearch}\n groups={externalGroups}\n placeholder=\"Search countries...\"\n />\n </div>\n </section>\n\n <Separator />\n\n <!-- Inside Popover -->\n <section class=\"space-y-3\">\n <h2 id=\"Inside-Popover\" class=\"text-lg font-semibold\">\n<a href=\"#Inside-Popover\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Inside Popover\n </a>\n</h2>\n <Popover>\n <Button variant=\"outline\" leadingIcon=\"lucide:search\">Open Command...</Button>\n {#snippet content()}\n <Command\n groups={basicGroups}\n placeholder=\"Search...\"\n ui={{ list: 'max-h-64' }}\n class=\"w-80\"\n />\n {/snippet}\n </Popover>\n </section>\n\n <Separator />\n\n <!-- Inside Modal -->\n <section class=\"space-y-3\">\n <h2 id=\"Inside-Modal\" class=\"text-lg font-semibold\">\n<a href=\"#Inside-Modal\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Inside Modal\n </a>\n</h2>\n <Modal>\n <Button variant=\"outline\" leadingIcon=\"lucide:search\">\n Search...\n <Kbd value=\"meta\" size=\"sm\" />\n <Kbd value=\"K\" size=\"sm\" />\n </Button>\n {#snippet content()}\n <Command groups={multiGroups} placeholder=\"Search settings...\" />\n {/snippet}\n </Modal>\n </section>\n\n <Separator />\n\n <!-- Inside Drawer -->\n <section class=\"space-y-3\">\n <h2 id=\"Inside-Drawer\" class=\"text-lg font-semibold\">\n<a href=\"#Inside-Drawer\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Inside Drawer\n </a>\n</h2>\n <Drawer handle={false}>\n <Button variant=\"outline\" leadingIcon=\"lucide:terminal\">Open Command Drawer</Button>\n {#snippet content()}\n <Command groups={multiGroups} placeholder=\"Search settings...\" />\n {/snippet}\n </Drawer>\n </section>\n</div>\n",
170
170
  "context-menu": "<script lang=\"ts\">\n import {\n ContextMenu,\n Separator,\n type ContextMenuItem,\n type ContextMenuRadioGroup\n } from '$lib/index.js'\n\n let showStatusBar = $state(true)\n let showActivityBar = $state(false)\n let showPanel = $state(true)\n let selectedTheme = $state('system')\n\n const basicItems: ContextMenuItem[] = [\n { label: 'Back', icon: 'lucide:arrow-left', kbds: ['alt', 'left'] },\n { label: 'Forward', icon: 'lucide:arrow-right', kbds: ['alt', 'right'], disabled: true },\n { label: 'Reload', icon: 'lucide:refresh-cw', kbds: ['meta', 'r'] },\n { type: 'separator' },\n { label: 'Save As...', icon: 'lucide:save', kbds: ['meta', 's'] },\n { label: 'Print...', icon: 'lucide:printer', kbds: ['meta', 'p'] }\n ]\n\n const coloredItems: ContextMenuItem[] = [\n { label: 'Edit', icon: 'lucide:pencil' },\n { label: 'Duplicate', icon: 'lucide:copy' },\n { type: 'separator' },\n { label: 'Archive', icon: 'lucide:archive', color: 'warning' },\n { label: 'Delete', icon: 'lucide:trash-2', color: 'error' }\n ]\n\n const checkboxItems: ContextMenuItem[] = $derived([\n { type: 'label', label: 'Appearance' },\n {\n type: 'checkbox',\n label: 'Status Bar',\n checked: showStatusBar,\n closeOnSelect: false,\n onCheckedChange: (v: boolean) => (showStatusBar = v)\n },\n {\n type: 'checkbox',\n label: 'Activity Bar',\n checked: showActivityBar,\n closeOnSelect: false,\n onCheckedChange: (v: boolean) => (showActivityBar = v)\n },\n {\n type: 'checkbox',\n label: 'Panel',\n checked: showPanel,\n closeOnSelect: false,\n onCheckedChange: (v: boolean) => (showPanel = v)\n }\n ])\n\n const radioItems: ContextMenuItem[] = [\n { type: 'label', label: 'Theme' },\n { type: 'radio', label: 'Light', value: 'light' },\n { type: 'radio', label: 'Dark', value: 'dark' },\n { type: 'radio', label: 'System', value: 'system' }\n ]\n\n const radioGroups: ContextMenuRadioGroup[] = $derived([\n {\n name: 'theme',\n value: selectedTheme,\n onValueChange: (v: string) => (selectedTheme = v)\n }\n ])\n\n const submenuItems: ContextMenuItem[] = [\n { label: 'Cut', icon: 'lucide:scissors', kbds: ['meta', 'x'] },\n { label: 'Copy', icon: 'lucide:copy', kbds: ['meta', 'c'] },\n { label: 'Paste', icon: 'lucide:clipboard', kbds: ['meta', 'v'] },\n { type: 'separator' },\n {\n type: 'sub',\n label: 'More Tools',\n icon: 'lucide:wrench',\n items: [\n { label: 'Save Page As...', kbds: ['meta', 's'] },\n { label: 'Create Shortcut...' },\n { label: 'Name Window...' },\n { type: 'separator' },\n { label: 'Developer Tools', kbds: ['meta', 'alt', 'i'] }\n ]\n },\n {\n type: 'sub',\n label: 'Share',\n icon: 'lucide:share-2',\n items: [\n { label: 'Email', icon: 'lucide:mail' },\n { label: 'Message', icon: 'lucide:message-square' },\n { type: 'separator' },\n { label: 'Copy Link', icon: 'lucide:link' }\n ]\n }\n ]\n\n const fullItems: ContextMenuItem[] = $derived([\n { label: 'Cut', icon: 'lucide:scissors', kbds: ['meta', 'x'] },\n { label: 'Copy', icon: 'lucide:copy', kbds: ['meta', 'c'] },\n { label: 'Paste', icon: 'lucide:clipboard', kbds: ['meta', 'v'] },\n { type: 'separator' },\n { type: 'label', label: 'View' },\n {\n type: 'checkbox',\n label: 'Show Bookmarks',\n checked: showStatusBar,\n onCheckedChange: (v: boolean) => (showStatusBar = v)\n },\n {\n type: 'checkbox',\n label: 'Show Full URLs',\n checked: showActivityBar,\n onCheckedChange: (v: boolean) => (showActivityBar = v)\n },\n { type: 'separator' },\n {\n type: 'sub',\n label: 'More Tools',\n icon: 'lucide:wrench',\n items: [\n { label: 'Save Page As...', kbds: ['meta', 's'] },\n { label: 'Create Shortcut...' },\n { type: 'separator' },\n { label: 'Developer Tools', kbds: ['meta', 'alt', 'i'] }\n ]\n },\n { type: 'separator' },\n { label: 'Delete', icon: 'lucide:trash-2', color: 'error', kbds: ['delete'] }\n ])\n\n const triggerClass =\n 'flex items-center justify-center rounded-lg border-2 border-dashed border-outline-variant bg-surface-container-low text-on-surface-variant transition-colors hover:border-primary/50 hover:bg-surface-container cursor-context-menu select-none'\n</script>\n\n<div class=\"space-y-8\">\n <div class=\"space-y-2\">\n <h1 class=\"text-2xl font-bold\">ContextMenu</h1>\n <p class=\"text-on-surface-variant\">\n Display a menu of actions or options triggered by right-click. Built on bits-ui\n ContextMenu primitive.\n </p>\n </div>\n\n <!-- Basic -->\n <section class=\"space-y-3\">\n <h2 id=\"Basic\" class=\"text-lg font-semibold\">\n<a href=\"#Basic\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Basic\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Right-click on the area below to open a context menu with icons and keyboard shortcuts.\n </p>\n <ContextMenu items={basicItems}>\n <div class=\"{triggerClass} h-36 w-full\">\n <span class=\"text-sm\">Right-click here</span>\n </div>\n </ContextMenu>\n </section>\n\n <!-- Colored Items -->\n <section class=\"space-y-3\">\n <h2 id=\"Colored-Items\" class=\"text-lg font-semibold\">\n<a href=\"#Colored-Items\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Colored Items\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">color</code>\n prop on items for semantic coloring.\n </p>\n <ContextMenu items={coloredItems}>\n <div class=\"{triggerClass} h-36 w-full\">\n <span class=\"text-sm\">Right-click for colored items</span>\n </div>\n </ContextMenu>\n </section>\n\n <!-- Checkbox Items -->\n <section class=\"space-y-3\">\n <h2 id=\"Checkbox-Items\" class=\"text-lg font-semibold\">\n<a href=\"#Checkbox-Items\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Checkbox Items\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">Toggle boolean states with checkbox items.</p>\n <div class=\"flex items-start gap-4 rounded-lg bg-surface-container-high p-4\">\n <ContextMenu items={checkboxItems} class=\"flex-1\">\n <div class=\"{triggerClass} h-36 w-full\">\n <span class=\"text-sm\">Right-click for checkboxes</span>\n </div>\n </ContextMenu>\n <div class=\"text-sm text-on-surface-variant\">\n <p>Status Bar: <code class=\"text-primary\">{showStatusBar}</code></p>\n <p>Activity Bar: <code class=\"text-primary\">{showActivityBar}</code></p>\n <p>Panel: <code class=\"text-primary\">{showPanel}</code></p>\n </div>\n </div>\n </section>\n\n <!-- Radio Items -->\n <section class=\"space-y-3\">\n <h2 id=\"Radio-Items\" class=\"text-lg font-semibold\">\n<a href=\"#Radio-Items\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Radio Items\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">Single selection with radio items and groups.</p>\n <div class=\"flex items-start gap-4 rounded-lg bg-surface-container-high p-4\">\n <ContextMenu items={radioItems} {radioGroups} class=\"flex-1\">\n <div class=\"{triggerClass} h-36 w-full\">\n <span class=\"text-sm\">Right-click for radio selection</span>\n </div>\n </ContextMenu>\n <div class=\"text-sm text-on-surface-variant\">\n Selected: <code class=\"text-primary\">{selectedTheme}</code>\n </div>\n </div>\n </section>\n\n <!-- Submenus -->\n <section class=\"space-y-3\">\n <h2 id=\"Submenus\" class=\"text-lg font-semibold\">\n<a href=\"#Submenus\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Submenus\n </a>\n</h2>\n <ContextMenu items={submenuItems}>\n <div class=\"{triggerClass} h-36 w-full\">\n <span class=\"text-sm\">Right-click for submenus</span>\n </div>\n </ContextMenu>\n </section>\n\n <!-- Sizes -->\n <section class=\"space-y-3\">\n <h2 id=\"Sizes\" class=\"text-lg font-semibold\">\n<a href=\"#Sizes\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Sizes\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Control the menu size with the\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">size</code>\n prop.\n </p>\n <div class=\"grid gap-4 md:grid-cols-3\">\n {#each [{ size: 'xs' as const, label: 'XS' }, { size: 'sm' as const, label: 'SM' }, { size: 'md' as const, label: 'MD (default)' }, { size: 'lg' as const, label: 'LG' }, { size: 'xl' as const, label: 'XL' }] as item (item.size)}\n <ContextMenu items={basicItems.slice(0, 5)} size={item.size}>\n <div class=\"{triggerClass} h-28\">\n <span class=\"text-xs\">{item.label}</span>\n </div>\n </ContextMenu>\n {/each}\n </div>\n </section>\n\n <!-- Custom Header/Footer -->\n <section class=\"space-y-3\">\n <h2 id=\"Custom-HeaderFooter\" class=\"text-lg font-semibold\">\n<a href=\"#Custom-HeaderFooter\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Custom Header/Footer\n </a>\n</h2>\n <ContextMenu items={basicItems.slice(0, 4)}>\n <div class=\"{triggerClass} h-36 w-full\">\n <span class=\"text-sm\">Right-click for header/footer</span>\n </div>\n {#snippet header()}\n <div class=\"px-3 py-2\">\n <p class=\"text-sm font-medium\">John Doe</p>\n <p class=\"text-xs text-on-surface-variant\">john@example.com</p>\n </div>\n <Separator />\n {/snippet}\n {#snippet footer({ close })}\n <Separator />\n <div class=\"p-1\">\n <button\n class=\"flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-sm text-error hover:bg-error-container hover:text-on-error-container\"\n onclick={close}\n >\n Log out\n </button>\n </div>\n {/snippet}\n </ContextMenu>\n </section>\n\n <!-- Custom Content -->\n <section class=\"space-y-3\">\n <h2 id=\"Custom-Content\" class=\"text-lg font-semibold\">\n<a href=\"#Custom-Content\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Custom Content\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">content</code>\n slot for fully custom context menu content.\n </p>\n <ContextMenu>\n <div class=\"{triggerClass} h-36 w-full\">\n <span class=\"text-sm\">Right-click for custom content</span>\n </div>\n {#snippet content({ close })}\n <div class=\"p-4\">\n <p class=\"mb-3 text-sm font-medium\">Choose a color</p>\n <div class=\"grid grid-cols-5 gap-2\">\n {#each ['bg-red-500', 'bg-orange-500', 'bg-yellow-500', 'bg-green-500', 'bg-teal-500', 'bg-blue-500', 'bg-indigo-500', 'bg-purple-500', 'bg-pink-500', 'bg-gray-500'] as color (color)}\n <button\n class=\"size-8 rounded-full {color} transition-all hover:ring-2 hover:ring-outline hover:ring-offset-2\"\n aria-label=\"Select {color\n .replace('bg-', '')\n .replace('-500', '')} color\"\n onclick={close}\n ></button>\n {/each}\n </div>\n </div>\n {/snippet}\n </ContextMenu>\n </section>\n\n <!-- UI Overrides -->\n <section class=\"space-y-3\">\n <h2 id=\"UI-Overrides\" class=\"text-lg font-semibold\">\n<a href=\"#UI-Overrides\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n UI Overrides\n </a>\n</h2>\n <div class=\"grid gap-4 sm:grid-cols-2\">\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium text-on-surface-variant\">Primary theme</p>\n <ContextMenu\n items={basicItems.slice(0, 4)}\n ui={{\n content: 'bg-primary text-on-primary ring-primary/50',\n item: 'data-[highlighted]:bg-on-primary/20',\n separator: 'bg-on-primary/20'\n }}\n >\n <div class=\"{triggerClass} h-28\">\n <span class=\"text-sm\">Primary Style</span>\n </div>\n </ContextMenu>\n </div>\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium text-on-surface-variant\">Custom rounding</p>\n <ContextMenu\n items={basicItems.slice(0, 4)}\n ui={{ content: 'rounded-xl shadow-2xl' }}\n >\n <div class=\"{triggerClass} h-28\">\n <span class=\"text-sm\">Custom Rounding</span>\n </div>\n </ContextMenu>\n </div>\n </div>\n </section>\n\n <Separator />\n\n <!-- Real World Examples -->\n <section class=\"space-y-6\">\n <h2 id=\"Real-World-Examples\" class=\"text-lg font-semibold\">\n<a href=\"#Real-World-Examples\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Real World Examples\n </a>\n</h2>\n\n <div class=\"space-y-4\">\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium\">Browser Context Menu</p>\n <ContextMenu items={fullItems}>\n <div class=\"{triggerClass} h-48 w-full\">\n <div class=\"text-center\">\n <p class=\"text-sm font-medium text-on-surface\">Interactive Area</p>\n <p class=\"mt-1 text-xs text-on-surface-variant\">\n Right-click anywhere in this area\n </p>\n </div>\n </div>\n </ContextMenu>\n </div>\n </div>\n </section>\n</div>\n",
171
171
  "drawer": "<script lang=\"ts\">\n import { Drawer, Button, Badge, Icon, Separator } from '$lib/index.js'\n\n let basicOpen = $state(false)\n let directionOpen = $state<Record<string, boolean>>({\n top: false,\n right: false,\n bottom: false,\n left: false\n })\n let insetOpen = $state<Record<string, boolean>>({\n top: false,\n right: false,\n bottom: false,\n left: false\n })\n let noHandleOpen = $state(false)\n let handleOnlyOpen = $state(false)\n let noOverlayOpen = $state(false)\n let scaleBackgroundOpen = $state(false)\n let nonDismissibleOpen = $state(false)\n let snapOpen = $state(false)\n let snapControlledOpen = $state(false)\n let activeSnap = $state<number | string | null>(0.25)\n let nestedOuterOpen = $state(false)\n let nestedInnerOpen = $state(false)\n let slotsOpen = $state(false)\n let customContentOpen = $state(false)\n let callbacksOpen = $state(false)\n let callbackLog = $state<string[]>([])\n let uiOverrideOpen = $state(false)\n let programmaticOpen = $state(false)\n\n let settingsOpen = $state(false)\n let notificationsOpen = $state(false)\n let filterOpen = $state(false)\n let confirmOpen = $state(false)\n\n const directions = ['top', 'right', 'bottom', 'left'] as const\n\n function logCallback(name: string) {\n callbackLog = [...callbackLog.slice(-4), `${new Date().toLocaleTimeString()} — ${name}`]\n }\n</script>\n\n<div class=\"space-y-8\">\n <div class=\"space-y-2\">\n <h1 class=\"text-2xl font-bold\">Drawer</h1>\n <p class=\"text-on-surface-variant\">\n A draggable drawer component built on vaul-svelte. Supports swipe-to-dismiss, snap\n points, nested drawers, all 4 directions, and full slot customization.\n </p>\n </div>\n\n <!-- Basic -->\n <section class=\"space-y-3\">\n <h2 id=\"Basic\" class=\"text-lg font-semibold\">\n<a href=\"#Basic\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Basic\n </a>\n</h2>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <Drawer\n bind:open={basicOpen}\n title=\"Basic Drawer\"\n description=\"This is a basic drawer with title, description, body and footer.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Open Drawer\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n Slides up from the bottom by default. Swipe down or click the overlay to\n close.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button label=\"Close\" variant=\"outline\" onclick={() => (basicOpen = false)} />\n {/snippet}\n </Drawer>\n </div>\n </section>\n\n <!-- Directions -->\n <section class=\"space-y-3\">\n <h2 id=\"Directions\" class=\"text-lg font-semibold\">\n<a href=\"#Directions\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Directions\n </a>\n</h2>\n <div class=\"flex flex-wrap gap-3 rounded-lg bg-surface-container-high p-4\">\n {#each directions as dir (dir)}\n <Drawer\n bind:open={directionOpen[dir]}\n direction={dir}\n title=\"{dir.charAt(0).toUpperCase() + dir.slice(1)} Drawer\"\n description=\"Opens from the {dir}.\"\n >\n {#snippet children({ props })}\n <Button\n {...props}\n variant=\"outline\"\n label={dir.charAt(0).toUpperCase() + dir.slice(1)}\n />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n Drawer from the <strong>{dir}</strong>. Swipe towards the edge to\n dismiss.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (directionOpen[dir] = false)}\n />\n {/snippet}\n </Drawer>\n {/each}\n </div>\n </section>\n\n <!-- Inset -->\n <section class=\"space-y-3\">\n <h2 id=\"Inset\" class=\"text-lg font-semibold\">\n<a href=\"#Inset\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Inset\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Inset drawers have rounded corners and are offset from screen edges.\n </p>\n <div class=\"flex flex-wrap gap-3 rounded-lg bg-surface-container-high p-4\">\n {#each directions as dir (dir)}\n <Drawer\n bind:open={insetOpen[dir]}\n inset\n direction={dir}\n title=\"Inset {dir.charAt(0).toUpperCase() + dir.slice(1)}\"\n description=\"Inset + {dir} direction.\"\n >\n {#snippet children({ props })}\n <Button\n {...props}\n variant=\"soft\"\n size=\"sm\"\n label=\"Inset {dir.charAt(0).toUpperCase() + dir.slice(1)}\"\n />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n Inset mode combined with <strong>{dir}</strong> direction.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (insetOpen[dir] = false)}\n />\n {/snippet}\n </Drawer>\n {/each}\n </div>\n </section>\n\n <!-- Handle Options -->\n <section class=\"space-y-3\">\n <h2 id=\"Handle-Options\" class=\"text-lg font-semibold\">\n<a href=\"#Handle-Options\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Handle Options\n </a>\n</h2>\n <div class=\"flex flex-wrap gap-3 rounded-lg bg-surface-container-high p-4\">\n <Drawer\n bind:open={noHandleOpen}\n handle={false}\n title=\"No Handle\"\n description=\"Handle is hidden.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"No Handle\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">No drag handle visible. Still swipeable.</p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (noHandleOpen = false)}\n />\n {/snippet}\n </Drawer>\n\n <Drawer\n bind:open={handleOnlyOpen}\n handleOnly\n title=\"Handle Only\"\n description=\"Only the handle can be dragged.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Handle Only\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n Content area is not draggable — only the handle responds to drag.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (handleOnlyOpen = false)}\n />\n {/snippet}\n </Drawer>\n </div>\n </section>\n\n <!-- Overlay & Modal -->\n <section class=\"space-y-3\">\n <h2 id=\"Overlay--Modal\" class=\"text-lg font-semibold\">\n<a href=\"#Overlay--Modal\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Overlay & Modal\n </a>\n</h2>\n <div class=\"flex flex-wrap gap-3 rounded-lg bg-surface-container-high p-4\">\n <Drawer\n bind:open={noOverlayOpen}\n overlay={false}\n modal={false}\n title=\"Non-Modal\"\n description=\"No overlay, background is interactive.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Non-Modal\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n No overlay. You can still interact with the page behind.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (noOverlayOpen = false)}\n />\n {/snippet}\n </Drawer>\n\n <Drawer\n bind:open={scaleBackgroundOpen}\n shouldScaleBackground\n title=\"Scale Background\"\n description=\"Background scales down when opened.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Scale Background\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n The page content behind scales down, creating a layered depth effect.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (scaleBackgroundOpen = false)}\n />\n {/snippet}\n </Drawer>\n </div>\n </section>\n\n <!-- Non-Dismissible -->\n <section class=\"space-y-3\">\n <h2 id=\"Non-Dismissible\" class=\"text-lg font-semibold\">\n<a href=\"#Non-Dismissible\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Non-Dismissible\n </a>\n</h2>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <Drawer\n bind:open={nonDismissibleOpen}\n dismissible={false}\n title=\"Non-Dismissible\"\n description=\"You must use the close button.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Open (Non-Dismissible)\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n Try swiping or clicking outside — the drawer will not close.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close Drawer\"\n variant=\"solid\"\n color=\"primary\"\n onclick={() => (nonDismissibleOpen = false)}\n />\n {/snippet}\n </Drawer>\n </div>\n </section>\n\n <!-- Snap Points -->\n <section class=\"space-y-3\">\n <h2 id=\"Snap-Points\" class=\"text-lg font-semibold\">\n<a href=\"#Snap-Points\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Snap Points\n </a>\n</h2>\n <div class=\"flex flex-wrap gap-3 rounded-lg bg-surface-container-high p-4\">\n <Drawer\n bind:open={snapOpen}\n snapPoints={[0.25, 0.5, 1]}\n fadeFromIndex={1}\n title=\"Snap Points\"\n description=\"Snaps at 25%, 50%, 100%.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"3 Snap Points\" />\n {/snippet}\n {#snippet body()}\n <div class=\"space-y-2\">\n <p class=\"text-on-surface-variant\">\n Drag between 25%, 50%, and 100% heights.\n </p>\n {#each Array.from({ length: 12 }, (_, i) => i) as i (i)}\n <div class=\"rounded-md bg-surface-container p-3\">\n <p class=\"text-sm text-on-surface-variant\">Item {i + 1}</p>\n </div>\n {/each}\n </div>\n {/snippet}\n </Drawer>\n\n <Drawer\n bind:open={snapControlledOpen}\n snapPoints={[0.25, 0.5, 1]}\n fadeFromIndex={1}\n bind:activeSnapPoint={activeSnap}\n title=\"Controlled Snap\"\n description=\"Active: {activeSnap}\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Controlled Snap\" />\n {/snippet}\n {#snippet body()}\n <div class=\"space-y-3\">\n <p class=\"text-on-surface-variant\">\n Active snap point: <strong>{activeSnap}</strong>\n </p>\n <div class=\"flex gap-2\">\n <Button\n size=\"sm\"\n variant=\"soft\"\n label=\"25%\"\n onclick={() => (activeSnap = 0.25)}\n />\n <Button\n size=\"sm\"\n variant=\"soft\"\n label=\"50%\"\n onclick={() => (activeSnap = 0.5)}\n />\n <Button\n size=\"sm\"\n variant=\"soft\"\n label=\"100%\"\n onclick={() => (activeSnap = 1)}\n />\n </div>\n </div>\n {/snippet}\n </Drawer>\n </div>\n </section>\n\n <!-- Nested Drawers -->\n <section class=\"space-y-3\">\n <h2 id=\"Nested-Drawers\" class=\"text-lg font-semibold\">\n<a href=\"#Nested-Drawers\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Nested Drawers\n </a>\n</h2>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <Drawer\n bind:open={nestedOuterOpen}\n title=\"Outer Drawer\"\n description=\"This is the parent drawer.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Open Nested\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n Click below to open a child drawer on top of this one.\n </p>\n <div class=\"mt-3\">\n <Drawer\n bind:open={nestedInnerOpen}\n nested\n title=\"Inner Drawer\"\n description=\"Nested child drawer.\"\n >\n {#snippet children({ props })}\n <Button\n {...props}\n variant=\"solid\"\n color=\"primary\"\n label=\"Open Inner Drawer\"\n />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n This is the nested drawer. Closing it returns to the outer\n drawer.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close Inner\"\n variant=\"outline\"\n onclick={() => (nestedInnerOpen = false)}\n />\n {/snippet}\n </Drawer>\n </div>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (nestedOuterOpen = false)}\n />\n {/snippet}\n </Drawer>\n </div>\n </section>\n\n <!-- Slots -->\n <section class=\"space-y-3\">\n <h2 id=\"Slots\" class=\"text-lg font-semibold\">\n<a href=\"#Slots\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Slots\n </a>\n</h2>\n <div class=\"flex flex-wrap gap-3 rounded-lg bg-surface-container-high p-4\">\n <!-- Custom header -->\n <Drawer bind:open={slotsOpen}>\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Custom Header\" />\n {/snippet}\n {#snippet header()}\n <div class=\"flex items-center gap-3\">\n <div\n class=\"flex size-10 items-center justify-center rounded-full bg-primary text-on-primary\"\n >\n <Icon name=\"lucide:settings\" size=\"20\" />\n </div>\n <div>\n <h3 class=\"font-semibold text-on-surface\">Custom Header</h3>\n <p class=\"text-sm text-on-surface-variant\">With icon and layout</p>\n </div>\n </div>\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n The header slot replaces the default title + description.\n </p>\n {/snippet}\n {#snippet footer()}\n <div class=\"flex gap-2\">\n <Button\n label=\"Cancel\"\n variant=\"outline\"\n class=\"flex-1\"\n onclick={() => (slotsOpen = false)}\n />\n <Button\n label=\"Confirm\"\n variant=\"solid\"\n color=\"primary\"\n class=\"flex-1\"\n onclick={() => (slotsOpen = false)}\n />\n </div>\n {/snippet}\n </Drawer>\n\n <!-- Full content slot -->\n <Drawer bind:open={customContentOpen} title=\"Custom Content\">\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Content Slot\" />\n {/snippet}\n {#snippet content()}\n <div class=\"flex flex-col items-center gap-4 p-6\">\n <div\n class=\"flex size-16 items-center justify-center rounded-full bg-success/10\"\n >\n <Icon name=\"lucide:check-circle\" size=\"32\" class=\"text-success\" />\n </div>\n <h3 class=\"text-xl font-semibold text-on-surface\">Payment Successful</h3>\n <p class=\"text-center text-on-surface-variant\">\n The content slot replaces the entire inner layout.\n </p>\n <Button\n label=\"Done\"\n variant=\"solid\"\n color=\"primary\"\n onclick={() => (customContentOpen = false)}\n />\n </div>\n {/snippet}\n </Drawer>\n </div>\n </section>\n\n <!-- Lifecycle Callbacks -->\n <section class=\"space-y-3\">\n <h2 id=\"Lifecycle-Callbacks\" class=\"text-lg font-semibold\">\n<a href=\"#Lifecycle-Callbacks\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Lifecycle Callbacks\n </a>\n</h2>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <div class=\"mb-3 space-y-1\">\n {#if callbackLog.length === 0}\n <p class=\"text-sm text-on-surface-variant italic\">\n Open/close the drawer to see callback logs...\n </p>\n {/if}\n {#each callbackLog as log, i (i)}\n <p class=\"font-mono text-xs text-on-surface-variant\">{log}</p>\n {/each}\n </div>\n <Drawer\n bind:open={callbacksOpen}\n onOpenChange={(v) => logCallback(`onOpenChange(${v})`)}\n onClose={() => logCallback('onClose()')}\n onAnimationEnd={(v) => logCallback(`onAnimationEnd(open=${v})`)}\n title=\"Callback Demo\"\n description=\"Check the log above.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Open (With Callbacks)\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n Open, close, and watch the callback log update.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (callbacksOpen = false)}\n />\n {/snippet}\n </Drawer>\n </div>\n </section>\n\n <!-- Programmatic Control -->\n <section class=\"space-y-3\">\n <h2 id=\"Programmatic-Control\" class=\"text-lg font-semibold\">\n<a href=\"#Programmatic-Control\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Programmatic Control\n </a>\n</h2>\n <div class=\"flex gap-3 rounded-lg bg-surface-container-high p-4\">\n <Button\n variant=\"outline\"\n label=\"Open Programmatically\"\n onclick={() => (programmaticOpen = true)}\n />\n <Drawer\n bind:open={programmaticOpen}\n title=\"Programmatic Drawer\"\n description=\"Opened without a trigger slot.\"\n >\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n This drawer has no trigger. It was opened by setting open = true externally.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (programmaticOpen = false)}\n />\n {/snippet}\n </Drawer>\n </div>\n </section>\n\n <!-- UI Overrides -->\n <section class=\"space-y-3\">\n <h2 id=\"UI-Slot-Overrides\" class=\"text-lg font-semibold\">\n<a href=\"#UI-Slot-Overrides\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n UI Slot Overrides\n </a>\n</h2>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <Drawer\n bind:open={uiOverrideOpen}\n title=\"Styled Drawer\"\n description=\"Custom styles via the ui prop.\"\n ui={{\n content: 'bg-primary-container',\n title: 'text-on-primary-container',\n description: 'text-on-primary-container/70',\n handle: 'bg-on-primary-container/40',\n container: 'gap-3'\n }}\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Open Styled Drawer\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-primary-container/80\">\n This drawer overrides content, title, description, handle, and container\n slot classes.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (uiOverrideOpen = false)}\n />\n {/snippet}\n </Drawer>\n </div>\n </section>\n\n <Separator />\n\n <!-- Real World Examples -->\n <section class=\"space-y-3\">\n <h2 id=\"Real-World-Examples\" class=\"text-lg font-semibold\">\n<a href=\"#Real-World-Examples\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Real World Examples\n </a>\n</h2>\n <div class=\"grid gap-4 sm:grid-cols-2\">\n <!-- Mobile Settings -->\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <p class=\"mb-3 text-sm font-medium\">Mobile Settings Panel</p>\n <Drawer bind:open={settingsOpen} title=\"Settings\">\n {#snippet children({ props })}\n <Button\n {...props}\n variant=\"outline\"\n leadingIcon=\"lucide:settings\"\n label=\"Settings\"\n class=\"w-full\"\n />\n {/snippet}\n {#snippet body()}\n <div class=\"space-y-4\">\n {#each [{ icon: 'lucide:user', label: 'Account', desc: 'Manage your profile' }, { icon: 'lucide:bell', label: 'Notifications', desc: 'Push, email, SMS' }, { icon: 'lucide:shield', label: 'Privacy', desc: 'Data and permissions' }, { icon: 'lucide:palette', label: 'Appearance', desc: 'Theme and display' }, { icon: 'lucide:globe', label: 'Language', desc: 'English (US)' }] as item (item.label)}\n <button\n class=\"flex w-full items-center gap-3 rounded-lg p-2 text-left transition-colors hover:bg-surface-container\"\n >\n <div\n class=\"flex size-10 items-center justify-center rounded-full bg-surface-container-highest\"\n >\n <Icon\n name={item.icon}\n size=\"18\"\n class=\"text-on-surface-variant\"\n />\n </div>\n <div class=\"flex-1\">\n <p class=\"text-sm font-medium text-on-surface\">\n {item.label}\n </p>\n <p class=\"text-xs text-on-surface-variant\">{item.desc}</p>\n </div>\n <Icon\n name=\"lucide:chevron-right\"\n size=\"16\"\n class=\"text-on-surface-variant\"\n />\n </button>\n {/each}\n </div>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Sign Out\"\n variant=\"soft\"\n color=\"error\"\n leadingIcon=\"lucide:log-out\"\n class=\"w-full\"\n onclick={() => (settingsOpen = false)}\n />\n {/snippet}\n </Drawer>\n </div>\n\n <!-- Notifications -->\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <p class=\"mb-3 text-sm font-medium\">Notifications Drawer</p>\n <Drawer bind:open={notificationsOpen} direction=\"right\">\n {#snippet children({ props })}\n <Button\n {...props}\n variant=\"outline\"\n leadingIcon=\"lucide:bell\"\n label=\"Notifications\"\n class=\"w-full\"\n />\n {/snippet}\n {#snippet header()}\n <div class=\"flex items-center justify-between\">\n <h3 class=\"text-lg font-semibold text-on-surface\">Notifications</h3>\n <Badge variant=\"solid\" color=\"error\" size=\"xs\" label=\"3 new\" />\n </div>\n {/snippet}\n {#snippet body()}\n <div class=\"space-y-3\">\n {#each [{ title: 'New message', desc: 'John sent you a message', time: '2m ago', unread: true }, { title: 'Build completed', desc: 'Pipeline #482 passed', time: '15m ago', unread: true }, { title: 'Review requested', desc: 'PR #31 needs review', time: '1h ago', unread: true }, { title: 'Deploy finished', desc: 'v2.4.0 deployed to prod', time: '3h ago', unread: false }] as n (n.title)}\n <div\n class=\"flex gap-3 rounded-lg p-2 {n.unread\n ? 'bg-primary/5'\n : ''}\"\n >\n <div\n class=\"mt-0.5 size-2 shrink-0 rounded-full {n.unread\n ? 'bg-primary'\n : 'bg-transparent'}\"\n ></div>\n <div class=\"flex-1\">\n <p class=\"text-sm font-medium text-on-surface\">{n.title}</p>\n <p class=\"text-xs text-on-surface-variant\">{n.desc}</p>\n <p class=\"mt-1 text-xs text-on-surface-variant/60\">\n {n.time}\n </p>\n </div>\n </div>\n {/each}\n </div>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Mark all as read\"\n variant=\"ghost\"\n color=\"primary\"\n class=\"w-full\"\n onclick={() => (notificationsOpen = false)}\n />\n {/snippet}\n </Drawer>\n </div>\n\n <!-- Filter Drawer -->\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <p class=\"mb-3 text-sm font-medium\">Filter (Snap Points)</p>\n <Drawer\n bind:open={filterOpen}\n snapPoints={[0.4, 0.75, 1]}\n fadeFromIndex={1}\n title=\"Filters\"\n description=\"Refine your search results.\"\n >\n {#snippet children({ props })}\n <Button\n {...props}\n variant=\"outline\"\n leadingIcon=\"lucide:filter\"\n label=\"Filters\"\n class=\"w-full\"\n />\n {/snippet}\n {#snippet body()}\n <div class=\"space-y-4\">\n <div>\n <p class=\"mb-2 text-sm font-medium text-on-surface\">Category</p>\n <div class=\"flex flex-wrap gap-2\">\n {#each ['All', 'Electronics', 'Clothing', 'Books', 'Home'] as cat (cat)}\n <Button\n size=\"xs\"\n variant={cat === 'All' ? 'solid' : 'outline'}\n color={cat === 'All' ? 'primary' : 'secondary'}\n label={cat}\n />\n {/each}\n </div>\n </div>\n <Separator />\n <div>\n <p class=\"mb-2 text-sm font-medium text-on-surface\">Price Range</p>\n <div class=\"flex flex-wrap gap-2\">\n {#each ['Under $25', '$25-$50', '$50-$100', '$100+'] as price (price)}\n <Button\n size=\"xs\"\n variant=\"outline\"\n color=\"secondary\"\n label={price}\n />\n {/each}\n </div>\n </div>\n </div>\n {/snippet}\n {#snippet footer()}\n <div class=\"flex gap-2\">\n <Button\n label=\"Reset\"\n variant=\"outline\"\n class=\"flex-1\"\n onclick={() => (filterOpen = false)}\n />\n <Button\n label=\"Apply Filters\"\n variant=\"solid\"\n color=\"primary\"\n class=\"flex-1\"\n onclick={() => (filterOpen = false)}\n />\n </div>\n {/snippet}\n </Drawer>\n </div>\n\n <!-- Confirmation Drawer -->\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <p class=\"mb-3 text-sm font-medium\">Confirmation (Non-Dismissible)</p>\n <Drawer bind:open={confirmOpen} dismissible={false} handle={false}>\n {#snippet children({ props })}\n <Button\n {...props}\n variant=\"outline\"\n leadingIcon=\"lucide:trash-2\"\n label=\"Delete Account\"\n color=\"error\"\n class=\"w-full\"\n />\n {/snippet}\n {#snippet content()}\n <div class=\"flex flex-col items-center gap-4 p-6 text-center\">\n <div\n class=\"flex size-14 items-center justify-center rounded-full bg-error/10\"\n >\n <Icon name=\"lucide:alert-triangle\" size=\"28\" class=\"text-error\" />\n </div>\n <h3 class=\"text-lg font-semibold text-on-surface\">Delete Account?</h3>\n <p class=\"text-sm text-on-surface-variant\">\n This action is permanent and cannot be undone.\n </p>\n <div class=\"flex w-full gap-2\">\n <Button\n label=\"Cancel\"\n variant=\"outline\"\n class=\"flex-1\"\n onclick={() => (confirmOpen = false)}\n />\n <Button\n label=\"Delete\"\n variant=\"solid\"\n color=\"error\"\n class=\"flex-1\"\n onclick={() => (confirmOpen = false)}\n />\n </div>\n </div>\n {/snippet}\n </Drawer>\n </div>\n </div>\n </section>\n</div>\n",
172
- "dropdown-menu": "<script lang=\"ts\">\n import {\n DropdownMenu,\n Button,\n Separator,\n type DropdownMenuItem,\n type DropdownMenuRadioGroup\n } from '$lib/index.js'\n\n let controlledOpen = $state(false)\n let showStatusBar = $state(true)\n let showActivityBar = $state(false)\n let showPanel = $state(true)\n let selectedTheme = $state('system')\n let clickCount = $state(0)\n let option1 = $state(false)\n let option2 = $state(false)\n let option3 = $state(false)\n\n const basicItems: DropdownMenuItem[] = [\n { label: 'New File', icon: 'lucide:file-plus', kbds: ['meta', 'n'] },\n { label: 'New Window', icon: 'lucide:window', kbds: ['meta', 'shift', 'n'] },\n { type: 'separator' },\n { label: 'Open File...', icon: 'lucide:folder-open', kbds: ['meta', 'o'] },\n { label: 'Save', icon: 'lucide:save', kbds: ['meta', 's'] },\n { type: 'separator' },\n { label: 'Exit', icon: 'lucide:log-out' }\n ]\n\n const coloredItems: DropdownMenuItem[] = [\n { label: 'Edit', icon: 'lucide:pencil' },\n { label: 'Duplicate', icon: 'lucide:copy' },\n { type: 'separator' },\n { label: 'Archive', icon: 'lucide:archive', color: 'warning' },\n { label: 'Delete', icon: 'lucide:trash-2', color: 'error' }\n ]\n\n const checkboxItems: DropdownMenuItem[] = $derived([\n { type: 'label', label: 'Appearance' },\n {\n type: 'checkbox',\n label: 'Status Bar',\n checked: showStatusBar,\n onCheckedChange: (v: boolean) => (showStatusBar = v)\n },\n {\n type: 'checkbox',\n label: 'Activity Bar',\n checked: showActivityBar,\n onCheckedChange: (v: boolean) => (showActivityBar = v)\n },\n {\n type: 'checkbox',\n label: 'Panel',\n checked: showPanel,\n onCheckedChange: (v: boolean) => (showPanel = v)\n }\n ])\n\n const radioItems: DropdownMenuItem[] = [\n { type: 'label', label: 'Theme' },\n { type: 'radio', label: 'Light', value: 'light' },\n { type: 'radio', label: 'Dark', value: 'dark' },\n { type: 'radio', label: 'System', value: 'system' }\n ]\n\n const radioGroups: DropdownMenuRadioGroup[] = $derived([\n {\n name: 'theme',\n value: selectedTheme,\n onValueChange: (v: string) => (selectedTheme = v)\n }\n ])\n\n const closeOnSelectItems: DropdownMenuItem[] = $derived([\n {\n label: 'Click me (stays open)',\n icon: 'lucide:hand-metal',\n closeOnSelect: false,\n onSelect: () => clickCount++\n },\n {\n label: 'Me too (stays open)',\n icon: 'lucide:hand-metal',\n closeOnSelect: false,\n onSelect: () => clickCount++\n },\n { type: 'separator' },\n {\n label: 'Click me (closes menu)',\n icon: 'lucide:log-out',\n onSelect: () => clickCount++\n }\n ])\n\n const checkboxCloseOnSelectItems: DropdownMenuItem[] = $derived([\n { type: 'label', label: 'Select Multiple' },\n {\n type: 'checkbox',\n label: 'Option 1',\n checked: option1,\n closeOnSelect: false,\n onCheckedChange: (v: boolean) => (option1 = v)\n },\n {\n type: 'checkbox',\n label: 'Option 2',\n checked: option2,\n closeOnSelect: false,\n onCheckedChange: (v: boolean) => (option2 = v)\n },\n {\n type: 'checkbox',\n label: 'Option 3',\n checked: option3,\n closeOnSelect: false,\n onCheckedChange: (v: boolean) => (option3 = v)\n }\n ])\n\n const submenuItems: DropdownMenuItem[] = [\n { label: 'Back', icon: 'lucide:arrow-left', kbds: ['meta', '['] },\n { label: 'Forward', icon: 'lucide:arrow-right', kbds: ['meta', ']'], disabled: true },\n { label: 'Reload', icon: 'lucide:refresh-cw', kbds: ['meta', 'r'] },\n { type: 'separator' },\n {\n type: 'sub',\n label: 'More Tools',\n icon: 'lucide:wrench',\n items: [\n { label: 'Save Page As...', kbds: ['meta', 's'] },\n { label: 'Create Shortcut...' },\n { label: 'Name Window...' },\n { type: 'separator' },\n { label: 'Developer Tools', kbds: ['meta', 'alt', 'i'] }\n ]\n }\n ]\n\n const profileItems: DropdownMenuItem[] = [\n { type: 'label', label: 'My Account' },\n { label: 'Profile', icon: 'lucide:user', kbds: ['meta', 'p'] },\n { label: 'Billing', icon: 'lucide:credit-card', kbds: ['meta', 'b'] },\n { label: 'Settings', icon: 'lucide:settings', kbds: ['meta', ','] },\n { type: 'separator' },\n { label: 'Team', icon: 'lucide:users' },\n {\n type: 'sub',\n label: 'Invite users',\n icon: 'lucide:user-plus',\n items: [\n { label: 'Email', icon: 'lucide:mail' },\n { label: 'Message', icon: 'lucide:message-square' },\n { type: 'separator' },\n { label: 'More...', icon: 'lucide:plus-circle' }\n ]\n },\n { label: 'New Team', icon: 'lucide:plus', kbds: ['meta', 't'] },\n { type: 'separator' },\n { label: 'GitHub', icon: 'lucide:github' },\n { label: 'Support', icon: 'lucide:life-buoy' },\n { label: 'API', icon: 'lucide:cloud', disabled: true },\n { type: 'separator' },\n { label: 'Log out', icon: 'lucide:log-out', kbds: ['meta', 'shift', 'q'] }\n ]\n</script>\n\n<div class=\"space-y-8\">\n <div class=\"space-y-2\">\n <h1 class=\"text-2xl font-bold\">DropdownMenu</h1>\n <p class=\"text-on-surface-variant\">\n Display a menu of actions or options triggered by a button. Built on bits-ui\n DropdownMenu primitive.\n </p>\n </div>\n\n <!-- Basic -->\n <section class=\"space-y-3\">\n <h2 id=\"Basic\" class=\"text-lg font-semibold\">\n<a href=\"#Basic\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Basic\n </a>\n</h2>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <DropdownMenu items={basicItems}>\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\">\n File\n <span class=\"ml-2 text-xs opacity-60\">Alt+F</span>\n </Button>\n {/snippet}\n </DropdownMenu>\n </div>\n </section>\n\n <!-- Positions -->\n <section class=\"space-y-3\">\n <h2 id=\"Positions\" class=\"text-lg font-semibold\">\n<a href=\"#Positions\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Positions\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Control dropdown placement with the\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">side</code>\n prop.\n </p>\n <div\n class=\"flex flex-wrap items-center justify-center gap-8 rounded-lg bg-surface-container-high p-8\"\n >\n {#each [{ side: 'top' as const, label: 'Top' }, { side: 'right' as const, label: 'Right' }, { side: 'bottom' as const, label: 'Bottom' }, { side: 'left' as const, label: 'Left' }] as item (item.side)}\n <DropdownMenu items={basicItems.slice(0, 4)} side={item.side}>\n {#snippet children({ props })}\n <Button {...props} variant=\"soft\">{item.label}</Button>\n {/snippet}\n </DropdownMenu>\n {/each}\n </div>\n </section>\n\n <!-- Sizes -->\n <section class=\"space-y-3\">\n <h2 id=\"Sizes\" class=\"text-lg font-semibold\">\n<a href=\"#Sizes\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Sizes\n </a>\n</h2>\n <div class=\"flex flex-wrap items-center gap-4 rounded-lg bg-surface-container-high p-4\">\n {#each [{ size: 'xs' as const, label: 'XS' }, { size: 'sm' as const, label: 'SM' }, { size: 'md' as const, label: 'MD' }, { size: 'lg' as const, label: 'LG' }, { size: 'xl' as const, label: 'XL' }] as item (item.size)}\n <DropdownMenu items={basicItems.slice(0, 4)} size={item.size}>\n {#snippet children({ props })}\n <Button {...props} size={item.size} variant=\"outline\">{item.label}</Button>\n {/snippet}\n </DropdownMenu>\n {/each}\n </div>\n </section>\n\n <!-- Colored Items -->\n <section class=\"space-y-3\">\n <h2 id=\"Colored-Items\" class=\"text-lg font-semibold\">\n<a href=\"#Colored-Items\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Colored Items\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">color</code>\n prop on items for semantic coloring.\n </p>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <DropdownMenu items={coloredItems}>\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" icon=\"lucide:more-horizontal\"\n >Actions</Button\n >\n {/snippet}\n </DropdownMenu>\n </div>\n </section>\n\n <!-- Checkbox Items -->\n <section class=\"space-y-3\">\n <h2 id=\"Checkbox-Items\" class=\"text-lg font-semibold\">\n<a href=\"#Checkbox-Items\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Checkbox Items\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">Toggle boolean states with checkbox items.</p>\n <div class=\"flex flex-wrap items-center gap-4 rounded-lg bg-surface-container-high p-4\">\n <DropdownMenu items={checkboxItems}>\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" icon=\"lucide:layout\">View</Button>\n {/snippet}\n </DropdownMenu>\n <div class=\"text-sm text-on-surface-variant\">\n <p>Status Bar: <code class=\"text-primary\">{showStatusBar}</code></p>\n <p>Activity Bar: <code class=\"text-primary\">{showActivityBar}</code></p>\n <p>Panel: <code class=\"text-primary\">{showPanel}</code></p>\n </div>\n </div>\n </section>\n\n <!-- Radio Items -->\n <section class=\"space-y-3\">\n <h2 id=\"Radio-Items\" class=\"text-lg font-semibold\">\n<a href=\"#Radio-Items\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Radio Items\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">Single selection with radio items and groups.</p>\n <div class=\"flex flex-wrap items-center gap-4 rounded-lg bg-surface-container-high p-4\">\n <DropdownMenu items={radioItems} {radioGroups}>\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" icon=\"lucide:sun-moon\">Theme</Button>\n {/snippet}\n </DropdownMenu>\n <div class=\"text-sm text-on-surface-variant\">\n Selected: <code class=\"text-primary\">{selectedTheme}</code>\n </div>\n </div>\n </section>\n\n <!-- Submenus -->\n <section class=\"space-y-3\">\n <h2 id=\"Submenus\" class=\"text-lg font-semibold\">\n<a href=\"#Submenus\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Submenus\n </a>\n</h2>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <DropdownMenu items={submenuItems}>\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" icon=\"lucide:menu\">Navigate</Button>\n {/snippet}\n </DropdownMenu>\n </div>\n </section>\n\n <!-- Close On Select -->\n <section class=\"space-y-3\">\n <h2 id=\"Close-On-Select\" class=\"text-lg font-semibold\">\n<a href=\"#Close-On-Select\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Close On Select\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\"\n >closeOnSelect: false</code\n >\n to keep the menu open after clicking an item.\n </p>\n <div class=\"flex flex-wrap items-center gap-4 rounded-lg bg-surface-container-high p-4\">\n <DropdownMenu items={closeOnSelectItems}>\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" icon=\"lucide:mouse-pointer-click\"\n >Actions</Button\n >\n {/snippet}\n </DropdownMenu>\n <DropdownMenu items={checkboxCloseOnSelectItems}>\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" icon=\"lucide:check-square\"\n >Multi-Select</Button\n >\n {/snippet}\n </DropdownMenu>\n <div class=\"text-sm text-on-surface-variant\">\n <p>Click count: <code class=\"text-primary\">{clickCount}</code></p>\n <p>Options: <code class=\"text-primary\">[{option1}, {option2}, {option3}]</code></p>\n </div>\n </div>\n </section>\n\n <!-- Controlled -->\n <section class=\"space-y-3\">\n <h2 id=\"Controlled\" class=\"text-lg font-semibold\">\n<a href=\"#Controlled\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Controlled\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Control dropdown visibility programmatically with\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">open</code>\n binding.\n </p>\n <div class=\"grid gap-4 sm:grid-cols-2\">\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium text-on-surface-variant\">Observe click state</p>\n <div class=\"flex items-center gap-4 rounded-lg bg-surface-container-high p-4\">\n <DropdownMenu items={basicItems.slice(0, 4)} bind:open={controlledOpen}>\n {#snippet children({ props })}\n <Button {...props} variant={controlledOpen ? 'solid' : 'outline'}>\n Click me\n </Button>\n {/snippet}\n </DropdownMenu>\n <span class=\"text-sm text-on-surface-variant\">\n open: <code class=\"text-primary\">{controlledOpen}</code>\n </span>\n </div>\n </div>\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium text-on-surface-variant\">Toggle programmatically</p>\n <div class=\"flex items-center gap-4 rounded-lg bg-surface-container-high p-4\">\n <DropdownMenu items={basicItems.slice(0, 4)} open={controlledOpen}>\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\">Target</Button>\n {/snippet}\n </DropdownMenu>\n <Button variant=\"soft\" onclick={() => (controlledOpen = !controlledOpen)}>\n {controlledOpen ? 'Close' : 'Open'}\n </Button>\n </div>\n </div>\n </div>\n </section>\n\n <!-- Custom Header/Footer -->\n <section class=\"space-y-3\">\n <h2 id=\"Custom-HeaderFooter\" class=\"text-lg font-semibold\">\n<a href=\"#Custom-HeaderFooter\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Custom Header/Footer\n </a>\n</h2>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <DropdownMenu items={basicItems.slice(0, 4)}>\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" icon=\"lucide:user-circle\">Account</Button>\n {/snippet}\n {#snippet header()}\n <div class=\"px-3 py-2\">\n <p class=\"text-sm font-medium\">John Doe</p>\n <p class=\"text-xs text-on-surface-variant\">john@example.com</p>\n </div>\n <Separator />\n {/snippet}\n {#snippet footer({ close })}\n <Separator />\n <div class=\"p-1\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n class=\"w-full justify-start\"\n icon=\"lucide:log-out\"\n color=\"error\"\n onclick={close}\n >\n Log out\n </Button>\n </div>\n {/snippet}\n </DropdownMenu>\n </div>\n </section>\n\n <!-- Custom Content -->\n <section class=\"space-y-3\">\n <h2 id=\"Custom-Content\" class=\"text-lg font-semibold\">\n<a href=\"#Custom-Content\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Custom Content\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">content</code>\n slot for fully custom dropdown content.\n </p>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <DropdownMenu>\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" icon=\"lucide:palette\">Colors</Button>\n {/snippet}\n {#snippet content({ close })}\n <div class=\"p-4\">\n <p class=\"mb-3 text-sm font-medium\">Choose a color</p>\n <div class=\"grid grid-cols-5 gap-2\">\n {#each ['bg-red-500', 'bg-orange-500', 'bg-yellow-500', 'bg-green-500', 'bg-teal-500', 'bg-blue-500', 'bg-indigo-500', 'bg-purple-500', 'bg-pink-500', 'bg-gray-500'] as color (color)}\n <button\n class=\"size-8 rounded-full {color} transition-all hover:ring-2 hover:ring-outline hover:ring-offset-2\"\n aria-label=\"Select {color\n .replace('bg-', '')\n .replace('-500', '')} color\"\n onclick={close}\n ></button>\n {/each}\n </div>\n </div>\n {/snippet}\n </DropdownMenu>\n </div>\n </section>\n\n <!-- UI Slot Overrides -->\n <section class=\"space-y-3\">\n <h2 id=\"UI-Slot-Overrides\" class=\"text-lg font-semibold\">\n<a href=\"#UI-Slot-Overrides\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n UI Slot Overrides\n </a>\n</h2>\n <div class=\"grid gap-4 sm:grid-cols-2\">\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium text-on-surface-variant\">Primary theme</p>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <DropdownMenu\n items={basicItems.slice(0, 4)}\n ui={{\n content: 'bg-primary text-on-primary ring-primary/50',\n item: 'data-[highlighted]:bg-on-primary/20',\n separator: 'bg-on-primary/20'\n }}\n >\n {#snippet children({ props })}\n <Button {...props}>Primary Style</Button>\n {/snippet}\n </DropdownMenu>\n </div>\n </div>\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium text-on-surface-variant\">Custom rounding</p>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <DropdownMenu\n items={basicItems.slice(0, 4)}\n ui={{ content: 'rounded-xl shadow-2xl' }}\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\">Rounded</Button>\n {/snippet}\n </DropdownMenu>\n </div>\n </div>\n </div>\n </section>\n\n <Separator />\n\n <!-- Real World Examples -->\n <section class=\"space-y-6\">\n <h2 id=\"Real-World-Examples\" class=\"text-lg font-semibold\">\n<a href=\"#Real-World-Examples\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Real World Examples\n </a>\n</h2>\n\n <div class=\"grid gap-4 md:grid-cols-2\">\n <!-- Profile Menu -->\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium\">Profile Menu</p>\n <div\n class=\"flex items-center justify-center rounded-lg bg-surface-container-high p-6\"\n >\n <DropdownMenu items={profileItems}>\n {#snippet children({ props })}\n <Button {...props} icon=\"lucide:chevron-down\" trailing>\n <span class=\"flex items-center gap-2\">\n <span\n class=\"flex size-6 items-center justify-center rounded-full bg-primary text-xs text-on-primary\"\n >\n JD\n </span>\n shadcn\n </span>\n </Button>\n {/snippet}\n </DropdownMenu>\n </div>\n </div>\n\n <!-- Context Menu Style -->\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium\">Right-Click Style</p>\n <div\n class=\"flex items-center justify-center rounded-lg bg-surface-container-high p-6\"\n >\n <DropdownMenu items={coloredItems} arrow align=\"center\">\n {#snippet children({ props })}\n <Button\n {...props}\n variant=\"outline\"\n icon=\"lucide:more-vertical\"\n square\n aria-label=\"More options\"\n />\n {/snippet}\n </DropdownMenu>\n </div>\n </div>\n </div>\n </section>\n</div>\n",
172
+ "dropdown-menu": "<script lang=\"ts\">\n import {\n DropdownMenu,\n Button,\n Separator,\n Badge,\n Icon,\n type DropdownMenuItem,\n type DropdownMenuRadioGroup\n } from '$lib/index.js'\n\n let controlledOpen = $state(false)\n let showStatusBar = $state(true)\n let showActivityBar = $state(false)\n let showPanel = $state(true)\n let selectedTheme = $state('system')\n let clickCount = $state(0)\n let option1 = $state(false)\n let option2 = $state(false)\n let option3 = $state(false)\n\n const notificationItems: DropdownMenuItem[] = [\n { type: 'label', label: 'Notifications' },\n { type: 'separator' },\n { label: 'Svelora v3.0.11 is out!', icon: 'lucide:rocket' },\n { label: 'New component: BentoGrid', icon: 'lucide:layout-grid' },\n { label: 'System maintenance scheduled', icon: 'lucide:wrench' },\n { type: 'separator' },\n { label: 'Mark all as read', icon: 'lucide:check-check' }\n ]\n\n const basicItems: DropdownMenuItem[] = [\n { label: 'New File', icon: 'lucide:file-plus', kbds: ['meta', 'n'] },\n { label: 'New Window', icon: 'lucide:window', kbds: ['meta', 'shift', 'n'] },\n { type: 'separator' },\n { label: 'Open File...', icon: 'lucide:folder-open', kbds: ['meta', 'o'] },\n { label: 'Save', icon: 'lucide:save', kbds: ['meta', 's'] },\n { type: 'separator' },\n { label: 'Exit', icon: 'lucide:log-out' }\n ]\n\n const coloredItems: DropdownMenuItem[] = [\n { label: 'Edit', icon: 'lucide:pencil' },\n { label: 'Duplicate', icon: 'lucide:copy' },\n { type: 'separator' },\n { label: 'Archive', icon: 'lucide:archive', color: 'warning' },\n { label: 'Delete', icon: 'lucide:trash-2', color: 'error' }\n ]\n\n const checkboxItems: DropdownMenuItem[] = $derived([\n { type: 'label', label: 'Appearance' },\n {\n type: 'checkbox',\n label: 'Status Bar',\n checked: showStatusBar,\n onCheckedChange: (v: boolean) => (showStatusBar = v)\n },\n {\n type: 'checkbox',\n label: 'Activity Bar',\n checked: showActivityBar,\n onCheckedChange: (v: boolean) => (showActivityBar = v)\n },\n {\n type: 'checkbox',\n label: 'Panel',\n checked: showPanel,\n onCheckedChange: (v: boolean) => (showPanel = v)\n }\n ])\n\n const radioItems: DropdownMenuItem[] = [\n { type: 'label', label: 'Theme' },\n { type: 'radio', label: 'Light', value: 'light' },\n { type: 'radio', label: 'Dark', value: 'dark' },\n { type: 'radio', label: 'System', value: 'system' }\n ]\n\n const radioGroups: DropdownMenuRadioGroup[] = $derived([\n {\n name: 'theme',\n value: selectedTheme,\n onValueChange: (v: string) => (selectedTheme = v)\n }\n ])\n\n const closeOnSelectItems: DropdownMenuItem[] = $derived([\n {\n label: 'Click me (stays open)',\n icon: 'lucide:hand-metal',\n closeOnSelect: false,\n onSelect: () => clickCount++\n },\n {\n label: 'Me too (stays open)',\n icon: 'lucide:hand-metal',\n closeOnSelect: false,\n onSelect: () => clickCount++\n },\n { type: 'separator' },\n {\n label: 'Click me (closes menu)',\n icon: 'lucide:log-out',\n onSelect: () => clickCount++\n }\n ])\n\n const checkboxCloseOnSelectItems: DropdownMenuItem[] = $derived([\n { type: 'label', label: 'Select Multiple' },\n {\n type: 'checkbox',\n label: 'Option 1',\n checked: option1,\n closeOnSelect: false,\n onCheckedChange: (v: boolean) => (option1 = v)\n },\n {\n type: 'checkbox',\n label: 'Option 2',\n checked: option2,\n closeOnSelect: false,\n onCheckedChange: (v: boolean) => (option2 = v)\n },\n {\n type: 'checkbox',\n label: 'Option 3',\n checked: option3,\n closeOnSelect: false,\n onCheckedChange: (v: boolean) => (option3 = v)\n }\n ])\n\n const submenuItems: DropdownMenuItem[] = [\n { label: 'Back', icon: 'lucide:arrow-left', kbds: ['meta', '['] },\n { label: 'Forward', icon: 'lucide:arrow-right', kbds: ['meta', ']'], disabled: true },\n { label: 'Reload', icon: 'lucide:refresh-cw', kbds: ['meta', 'r'] },\n { type: 'separator' },\n {\n type: 'sub',\n label: 'More Tools',\n icon: 'lucide:wrench',\n items: [\n { label: 'Save Page As...', kbds: ['meta', 's'] },\n { label: 'Create Shortcut...' },\n { label: 'Name Window...' },\n { type: 'separator' },\n { label: 'Developer Tools', kbds: ['meta', 'alt', 'i'] }\n ]\n }\n ]\n\n const profileItems: DropdownMenuItem[] = [\n { type: 'label', label: 'My Account' },\n { label: 'Profile', icon: 'lucide:user', kbds: ['meta', 'p'] },\n { label: 'Billing', icon: 'lucide:credit-card', kbds: ['meta', 'b'] },\n { label: 'Settings', icon: 'lucide:settings', kbds: ['meta', ','] },\n { type: 'separator' },\n { label: 'Team', icon: 'lucide:users' },\n {\n type: 'sub',\n label: 'Invite users',\n icon: 'lucide:user-plus',\n items: [\n { label: 'Email', icon: 'lucide:mail' },\n { label: 'Message', icon: 'lucide:message-square' },\n { type: 'separator' },\n { label: 'More...', icon: 'lucide:plus-circle' }\n ]\n },\n { label: 'New Team', icon: 'lucide:plus', kbds: ['meta', 't'] },\n { type: 'separator' },\n { label: 'GitHub', icon: 'lucide:github' },\n { label: 'Support', icon: 'lucide:life-buoy' },\n { label: 'API', icon: 'lucide:cloud', disabled: true },\n { type: 'separator' },\n { label: 'Log out', icon: 'lucide:log-out', kbds: ['meta', 'shift', 'q'] }\n ]\n</script>\n\n<div class=\"space-y-8\">\n <div class=\"space-y-2\">\n <h1 class=\"text-2xl font-bold\">DropdownMenu</h1>\n <p class=\"text-on-surface-variant\">\n Display a menu of actions or options triggered by a button. Built on bits-ui\n DropdownMenu primitive.\n </p>\n </div>\n\n <!-- Basic -->\n <section class=\"space-y-3\">\n <h2 id=\"Basic\" class=\"text-lg font-semibold\">\n<a href=\"#Basic\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Basic\n </a>\n</h2>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <DropdownMenu items={basicItems}>\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\">\n File\n <span class=\"ml-2 text-xs opacity-60\">Alt+F</span>\n </Button>\n {/snippet}\n </DropdownMenu>\n </div>\n </section>\n\n <!-- Positions -->\n <section class=\"space-y-3\">\n <h2 id=\"Positions\" class=\"text-lg font-semibold\">\n<a href=\"#Positions\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Positions\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Control dropdown placement with the\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">side</code>\n prop.\n </p>\n <div\n class=\"flex flex-wrap items-center justify-center gap-8 rounded-lg bg-surface-container-high p-8\"\n >\n {#each [{ side: 'top' as const, label: 'Top' }, { side: 'right' as const, label: 'Right' }, { side: 'bottom' as const, label: 'Bottom' }, { side: 'left' as const, label: 'Left' }] as item (item.side)}\n <DropdownMenu items={basicItems.slice(0, 4)} side={item.side}>\n {#snippet children({ props })}\n <Button {...props} variant=\"soft\">{item.label}</Button>\n {/snippet}\n </DropdownMenu>\n {/each}\n </div>\n </section>\n\n <!-- Sizes -->\n <section class=\"space-y-3\">\n <h2 id=\"Sizes\" class=\"text-lg font-semibold\">\n<a href=\"#Sizes\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Sizes\n </a>\n</h2>\n <div class=\"flex flex-wrap items-center gap-4 rounded-lg bg-surface-container-high p-4\">\n {#each [{ size: 'xs' as const, label: 'XS' }, { size: 'sm' as const, label: 'SM' }, { size: 'md' as const, label: 'MD' }, { size: 'lg' as const, label: 'LG' }, { size: 'xl' as const, label: 'XL' }] as item (item.size)}\n <DropdownMenu items={basicItems.slice(0, 4)} size={item.size}>\n {#snippet children({ props })}\n <Button {...props} size={item.size} variant=\"outline\">{item.label}</Button>\n {/snippet}\n </DropdownMenu>\n {/each}\n </div>\n </section>\n\n <!-- Colored Items -->\n <section class=\"space-y-3\">\n <h2 id=\"Colored-Items\" class=\"text-lg font-semibold\">\n<a href=\"#Colored-Items\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Colored Items\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">color</code>\n prop on items for semantic coloring.\n </p>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <DropdownMenu items={coloredItems}>\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" icon=\"lucide:more-horizontal\"\n >Actions</Button\n >\n {/snippet}\n </DropdownMenu>\n </div>\n </section>\n\n <!-- Checkbox Items -->\n <section class=\"space-y-3\">\n <h2 id=\"Checkbox-Items\" class=\"text-lg font-semibold\">\n<a href=\"#Checkbox-Items\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Checkbox Items\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">Toggle boolean states with checkbox items.</p>\n <div class=\"flex flex-wrap items-center gap-4 rounded-lg bg-surface-container-high p-4\">\n <DropdownMenu items={checkboxItems}>\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" icon=\"lucide:layout\">View</Button>\n {/snippet}\n </DropdownMenu>\n <div class=\"text-sm text-on-surface-variant\">\n <p>Status Bar: <code class=\"text-primary\">{showStatusBar}</code></p>\n <p>Activity Bar: <code class=\"text-primary\">{showActivityBar}</code></p>\n <p>Panel: <code class=\"text-primary\">{showPanel}</code></p>\n </div>\n </div>\n </section>\n\n <!-- Radio Items -->\n <section class=\"space-y-3\">\n <h2 id=\"Radio-Items\" class=\"text-lg font-semibold\">\n<a href=\"#Radio-Items\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Radio Items\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">Single selection with radio items and groups.</p>\n <div class=\"flex flex-wrap items-center gap-4 rounded-lg bg-surface-container-high p-4\">\n <DropdownMenu items={radioItems} {radioGroups}>\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" icon=\"lucide:sun-moon\">Theme</Button>\n {/snippet}\n </DropdownMenu>\n <div class=\"text-sm text-on-surface-variant\">\n Selected: <code class=\"text-primary\">{selectedTheme}</code>\n </div>\n </div>\n </section>\n\n <!-- Submenus -->\n <section class=\"space-y-3\">\n <h2 id=\"Submenus\" class=\"text-lg font-semibold\">\n<a href=\"#Submenus\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Submenus\n </a>\n</h2>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <DropdownMenu items={submenuItems}>\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" icon=\"lucide:menu\">Navigate</Button>\n {/snippet}\n </DropdownMenu>\n </div>\n </section>\n\n <!-- Close On Select -->\n <section class=\"space-y-3\">\n <h2 id=\"Close-On-Select\" class=\"text-lg font-semibold\">\n<a href=\"#Close-On-Select\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Close On Select\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\"\n >closeOnSelect: false</code\n >\n to keep the menu open after clicking an item.\n </p>\n <div class=\"flex flex-wrap items-center gap-4 rounded-lg bg-surface-container-high p-4\">\n <DropdownMenu items={closeOnSelectItems}>\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" icon=\"lucide:mouse-pointer-click\"\n >Actions</Button\n >\n {/snippet}\n </DropdownMenu>\n <DropdownMenu items={checkboxCloseOnSelectItems}>\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" icon=\"lucide:check-square\"\n >Multi-Select</Button\n >\n {/snippet}\n </DropdownMenu>\n <div class=\"text-sm text-on-surface-variant\">\n <p>Click count: <code class=\"text-primary\">{clickCount}</code></p>\n <p>Options: <code class=\"text-primary\">[{option1}, {option2}, {option3}]</code></p>\n </div>\n </div>\n </section>\n\n <!-- Controlled -->\n <section class=\"space-y-3\">\n <h2 id=\"Controlled\" class=\"text-lg font-semibold\">\n<a href=\"#Controlled\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Controlled\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Control dropdown visibility programmatically with\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">open</code>\n binding.\n </p>\n <div class=\"grid gap-4 sm:grid-cols-2\">\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium text-on-surface-variant\">Observe click state</p>\n <div class=\"flex items-center gap-4 rounded-lg bg-surface-container-high p-4\">\n <DropdownMenu items={basicItems.slice(0, 4)} bind:open={controlledOpen}>\n {#snippet children({ props })}\n <Button {...props} variant={controlledOpen ? 'solid' : 'outline'}>\n Click me\n </Button>\n {/snippet}\n </DropdownMenu>\n <span class=\"text-sm text-on-surface-variant\">\n open: <code class=\"text-primary\">{controlledOpen}</code>\n </span>\n </div>\n </div>\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium text-on-surface-variant\">Toggle programmatically</p>\n <div class=\"flex items-center gap-4 rounded-lg bg-surface-container-high p-4\">\n <DropdownMenu items={basicItems.slice(0, 4)} open={controlledOpen}>\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\">Target</Button>\n {/snippet}\n </DropdownMenu>\n <Button variant=\"soft\" onclick={() => (controlledOpen = !controlledOpen)}>\n {controlledOpen ? 'Close' : 'Open'}\n </Button>\n </div>\n </div>\n </div>\n </section>\n\n <!-- Custom Header/Footer -->\n <section class=\"space-y-3\">\n <h2 id=\"Custom-HeaderFooter\" class=\"text-lg font-semibold\">\n<a href=\"#Custom-HeaderFooter\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Custom Header/Footer\n </a>\n</h2>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <DropdownMenu items={basicItems.slice(0, 4)}>\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" icon=\"lucide:user-circle\">Account</Button>\n {/snippet}\n {#snippet header()}\n <div class=\"px-3 py-2\">\n <p class=\"text-sm font-medium\">John Doe</p>\n <p class=\"text-xs text-on-surface-variant\">john@example.com</p>\n </div>\n <Separator />\n {/snippet}\n {#snippet footer({ close })}\n <Separator />\n <div class=\"p-1\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n class=\"w-full justify-start\"\n icon=\"lucide:log-out\"\n color=\"error\"\n onclick={close}\n >\n Log out\n </Button>\n </div>\n {/snippet}\n </DropdownMenu>\n </div>\n </section>\n\n <!-- Custom Content -->\n <section class=\"space-y-3\">\n <h2 id=\"Custom-Content\" class=\"text-lg font-semibold\">\n<a href=\"#Custom-Content\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Custom Content\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">content</code>\n slot for fully custom dropdown content.\n </p>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <DropdownMenu>\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" icon=\"lucide:palette\">Colors</Button>\n {/snippet}\n {#snippet content({ close })}\n <div class=\"p-4\">\n <p class=\"mb-3 text-sm font-medium\">Choose a color</p>\n <div class=\"grid grid-cols-5 gap-2\">\n {#each ['bg-red-500', 'bg-orange-500', 'bg-yellow-500', 'bg-green-500', 'bg-teal-500', 'bg-blue-500', 'bg-indigo-500', 'bg-purple-500', 'bg-pink-500', 'bg-gray-500'] as color (color)}\n <button\n class=\"size-8 rounded-full {color} transition-all hover:ring-2 hover:ring-outline hover:ring-offset-2\"\n aria-label=\"Select {color\n .replace('bg-', '')\n .replace('-500', '')} color\"\n onclick={close}\n ></button>\n {/each}\n </div>\n </div>\n {/snippet}\n </DropdownMenu>\n </div>\n </section>\n\n <!-- UI Slot Overrides -->\n <section class=\"space-y-3\">\n <h2 id=\"UI-Slot-Overrides\" class=\"text-lg font-semibold\">\n<a href=\"#UI-Slot-Overrides\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n UI Slot Overrides\n </a>\n</h2>\n <div class=\"grid gap-4 sm:grid-cols-2\">\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium text-on-surface-variant\">Primary theme</p>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <DropdownMenu\n items={basicItems.slice(0, 4)}\n ui={{\n content: 'bg-primary text-on-primary ring-primary/50',\n item: 'data-[highlighted]:bg-on-primary/20',\n separator: 'bg-on-primary/20'\n }}\n >\n {#snippet children({ props })}\n <Button {...props}>Primary Style</Button>\n {/snippet}\n </DropdownMenu>\n </div>\n </div>\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium text-on-surface-variant\">Custom rounding</p>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <DropdownMenu\n items={basicItems.slice(0, 4)}\n ui={{ content: 'rounded-xl shadow-2xl' }}\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\">Rounded</Button>\n {/snippet}\n </DropdownMenu>\n </div>\n </div>\n </div>\n </section>\n\n <Separator />\n\n <!-- Real World Examples -->\n <section class=\"space-y-6\">\n <h2 id=\"Real-World-Examples\" class=\"text-lg font-semibold\">\n<a href=\"#Real-World-Examples\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Real World Examples\n </a>\n</h2>\n\n <div class=\"grid gap-4 md:grid-cols-2\">\n <!-- Profile Menu -->\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium\">Profile Menu</p>\n <div\n class=\"flex items-center justify-center rounded-lg bg-surface-container-high p-6\"\n >\n <DropdownMenu items={profileItems}>\n {#snippet children({ props })}\n <Button {...props} icon=\"lucide:chevron-down\" trailing>\n <span class=\"flex items-center gap-2\">\n <span\n class=\"flex size-6 items-center justify-center rounded-full bg-primary text-xs text-on-primary\"\n >\n JD\n </span>\n shadcn\n </span>\n </Button>\n {/snippet}\n </DropdownMenu>\n </div>\n </div>\n\n <!-- Context Menu Style -->\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium\">Right-Click Style</p>\n <div\n class=\"flex items-center justify-center rounded-lg bg-surface-container-high p-6\"\n >\n <DropdownMenu items={coloredItems} arrow align=\"center\">\n {#snippet children({ props })}\n <Button\n {...props}\n variant=\"outline\"\n icon=\"lucide:more-vertical\"\n square\n aria-label=\"More options\"\n />\n {/snippet}\n </DropdownMenu>\n </div>\n </div>\n\n <!-- Notification Bell -->\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium\">Notification Bell</p>\n <div\n class=\"flex items-center justify-center rounded-lg bg-surface-container-high p-6\"\n >\n <DropdownMenu items={notificationItems} arrow align=\"end\">\n {#snippet children({ props })}\n <Button\n {...props}\n variant=\"ghost\"\n square\n class=\"relative\"\n aria-label=\"Notifications\"\n >\n <Icon name=\"lucide:bell\" size=\"20\" />\n <Badge \n size=\"sm\" \n color=\"error\"\n class=\"absolute top-1 right-1 size-2 p-0\" \n />\n </Button>\n {/snippet}\n </DropdownMenu>\n </div>\n </div>\n </div>\n </section>\n</div>\n",
173
173
  "popover": "<script lang=\"ts\">\n import { Popover, Button, Badge, Icon, Separator } from '$lib/index.js'\n\n let controlledOpen = $state(false)\n</script>\n\n<div class=\"space-y-8\">\n <div class=\"space-y-2\">\n <h1 class=\"text-2xl font-bold\">Popover</h1>\n <p class=\"text-on-surface-variant\">\n Display rich content in a floating panel triggered by click. Built on bits-ui Popover\n primitive.\n </p>\n </div>\n\n <!-- Basic -->\n <section class=\"space-y-3\">\n <h2 id=\"Basic\" class=\"text-lg font-semibold\">\n<a href=\"#Basic\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Basic\n </a>\n</h2>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <Popover>\n <Button variant=\"outline\">Click me</Button>\n {#snippet content()}\n <div class=\"w-72 p-4\">\n <p class=\"text-sm font-medium\">Popover Content</p>\n <p class=\"mt-1 text-sm text-on-surface-variant\">\n This is a simple popover with some informational text.\n </p>\n </div>\n {/snippet}\n </Popover>\n </div>\n </section>\n\n <!-- Positions -->\n <section class=\"space-y-3\">\n <h2 id=\"Positions\" class=\"text-lg font-semibold\">\n<a href=\"#Positions\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Positions\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Control popover placement with the\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">side</code>\n prop.\n </p>\n <div\n class=\"flex flex-wrap items-center justify-center gap-8 rounded-lg bg-surface-container-high p-8\"\n >\n {#each [{ side: 'top' as const, label: 'Top' }, { side: 'right' as const, label: 'Right' }, { side: 'bottom' as const, label: 'Bottom' }, { side: 'left' as const, label: 'Left' }] as item (item.side)}\n <Popover side={item.side}>\n <Button variant=\"soft\">{item.label}</Button>\n {#snippet content()}\n <div class=\"p-3\">\n <p class=\"text-sm\">Popover on {item.side}</p>\n </div>\n {/snippet}\n </Popover>\n {/each}\n </div>\n </section>\n\n <!-- Alignment -->\n <section class=\"space-y-3\">\n <h2 id=\"Alignment\" class=\"text-lg font-semibold\">\n<a href=\"#Alignment\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Alignment\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Control alignment with the\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">align</code>\n prop.\n </p>\n <div\n class=\"flex flex-wrap items-center justify-center gap-8 rounded-lg bg-surface-container-high p-8\"\n >\n {#each [{ align: 'start' as const, label: 'Start' }, { align: 'center' as const, label: 'Center' }, { align: 'end' as const, label: 'End' }] as item (item.align)}\n <Popover side=\"bottom\" align={item.align}>\n <Button variant=\"outline\">{item.label}</Button>\n {#snippet content()}\n <div class=\"w-48 p-3\">\n <p class=\"text-sm\">Aligned to {item.align}</p>\n </div>\n {/snippet}\n </Popover>\n {/each}\n </div>\n </section>\n\n <!-- Arrow -->\n <section class=\"space-y-3\">\n <h2 id=\"Arrow\" class=\"text-lg font-semibold\">\n<a href=\"#Arrow\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Arrow\n </a>\n</h2>\n <div class=\"grid gap-4 sm:grid-cols-2\">\n {#each [{ side: 'top' as const, label: 'Top' }, { side: 'right' as const, label: 'Right' }, { side: 'bottom' as const, label: 'Bottom' }, { side: 'left' as const, label: 'Left' }] as item (item.side)}\n <div\n class=\"flex items-center justify-center rounded-lg bg-surface-container-high p-6\"\n >\n <Popover arrow side={item.side}>\n <Button>{item.label}</Button>\n {#snippet content()}\n <div class=\"p-3\">\n <p class=\"text-sm\">Content with arrow</p>\n </div>\n {/snippet}\n </Popover>\n </div>\n {/each}\n </div>\n </section>\n\n <!-- Close Action -->\n <section class=\"space-y-3\">\n <h2 id=\"Close-Action\" class=\"text-lg font-semibold\">\n<a href=\"#Close-Action\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Close Action\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n The\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">content</code>\n snippet exposes a\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">close</code>\n function to programmatically dismiss the popover.\n </p>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <Popover>\n <Button variant=\"outline\">Confirm Action</Button>\n {#snippet content({ close })}\n <div class=\"w-72 p-4\">\n <div class=\"flex items-center justify-between\">\n <p class=\"font-medium\">Confirm Action</p>\n <Button\n icon=\"lucide:x\"\n square\n variant=\"ghost\"\n size=\"xs\"\n onclick={close}\n />\n </div>\n <p class=\"mt-2 text-sm text-on-surface-variant\">\n Are you sure you want to proceed with this action?\n </p>\n <div class=\"mt-4 flex justify-end gap-2\">\n <Button variant=\"outline\" size=\"sm\" onclick={close}>Cancel</Button>\n <Button size=\"sm\" onclick={close}>Confirm</Button>\n </div>\n </div>\n {/snippet}\n </Popover>\n </div>\n </section>\n\n <!-- Controlled -->\n <section class=\"space-y-3\">\n <h2 id=\"Controlled\" class=\"text-lg font-semibold\">\n<a href=\"#Controlled\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Controlled\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Control popover visibility programmatically with\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">open</code>\n binding.\n </p>\n <div class=\"grid gap-4 sm:grid-cols-2\">\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium text-on-surface-variant\">Observe click state</p>\n <div class=\"flex items-center gap-4 rounded-lg bg-surface-container-high p-4\">\n <Popover bind:open={controlledOpen}>\n <Button variant={controlledOpen ? 'solid' : 'outline'}>Click me</Button>\n {#snippet content()}\n <div class=\"w-64 p-4\">\n <p class=\"text-sm\">Controlled popover content</p>\n </div>\n {/snippet}\n </Popover>\n <span class=\"text-sm text-on-surface-variant\">\n open: <code class=\"text-primary\">{controlledOpen}</code>\n </span>\n </div>\n </div>\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium text-on-surface-variant\">Toggle programmatically</p>\n <div class=\"flex items-center gap-4 rounded-lg bg-surface-container-high p-4\">\n <Popover open={controlledOpen}>\n <Button variant=\"outline\">Target</Button>\n {#snippet content()}\n <div class=\"w-64 p-4\">\n <p class=\"text-sm\">Programmatic popover</p>\n </div>\n {/snippet}\n </Popover>\n <Button variant=\"soft\" onclick={() => (controlledOpen = !controlledOpen)}>\n {controlledOpen ? 'Close' : 'Open'}\n </Button>\n </div>\n </div>\n </div>\n </section>\n\n <!-- Non-dismissible -->\n <section class=\"space-y-3\">\n <h2 id=\"Non-dismissible\" class=\"text-lg font-semibold\">\n<a href=\"#Non-dismissible\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Non-dismissible\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Prevent dismissing by clicking outside or pressing Escape.\n </p>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <Popover dismissible={false}>\n <Button variant=\"outline\">Non-dismissible</Button>\n {#snippet content({ close })}\n <div class=\"w-72 p-4\">\n <p class=\"text-sm font-medium\">Cannot dismiss by clicking outside</p>\n <p class=\"mt-1 text-sm text-on-surface-variant\">\n You must use the close button to dismiss this popover.\n </p>\n <div class=\"mt-3 flex justify-end\">\n <Button size=\"sm\" onclick={close}>Got it</Button>\n </div>\n </div>\n {/snippet}\n </Popover>\n </div>\n </section>\n\n <!-- UI Slot Overrides -->\n <section class=\"space-y-3\">\n <h2 id=\"UI-Slot-Overrides\" class=\"text-lg font-semibold\">\n<a href=\"#UI-Slot-Overrides\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n UI Slot Overrides\n </a>\n</h2>\n <div class=\"grid gap-4 sm:grid-cols-2\">\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium text-on-surface-variant\">Custom rounding</p>\n <div\n class=\"flex items-center justify-center rounded-lg bg-surface-container-high p-6\"\n >\n <Popover ui={{ content: 'rounded-xl shadow-2xl' }}>\n <Button variant=\"outline\">Rounded</Button>\n {#snippet content()}\n <div class=\"w-64 p-4\">\n <p class=\"text-sm\">Extra rounded with larger shadow.</p>\n </div>\n {/snippet}\n </Popover>\n </div>\n </div>\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium text-on-surface-variant\">No ring border</p>\n <div\n class=\"flex items-center justify-center rounded-lg bg-surface-container-high p-6\"\n >\n <Popover ui={{ content: 'ring-0 shadow-xl' }}>\n <Button variant=\"outline\">No Ring</Button>\n {#snippet content()}\n <div class=\"w-64 p-4\">\n <p class=\"text-sm\">Ring removed, shadow only.</p>\n </div>\n {/snippet}\n </Popover>\n </div>\n </div>\n </div>\n </section>\n\n <Separator />\n\n <!-- Real World Examples -->\n <section class=\"space-y-6\">\n <h2 id=\"Real-World-Examples\" class=\"text-lg font-semibold\">\n<a href=\"#Real-World-Examples\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Real World Examples\n </a>\n</h2>\n\n <div class=\"grid gap-4 md:grid-cols-2\">\n <!-- User Profile Card -->\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium\">User Profile Card</p>\n <div\n class=\"flex items-center justify-center rounded-lg bg-surface-container-high p-6\"\n >\n <Popover>\n <Button variant=\"soft\" icon=\"lucide:user\">Profile</Button>\n {#snippet content()}\n <div class=\"w-72\">\n <div class=\"p-4\">\n <div class=\"flex items-center gap-3\">\n <div\n class=\"flex size-10 items-center justify-center rounded-full bg-primary text-on-primary\"\n >\n <Icon name=\"lucide:user\" size=\"20\" />\n </div>\n <div>\n <p class=\"font-medium\">John Doe</p>\n <p class=\"text-sm text-on-surface-variant\">\n john@example.com\n </p>\n </div>\n </div>\n <Separator class=\"my-3\" />\n <div class=\"flex gap-4 text-sm text-on-surface-variant\">\n <span\n ><strong class=\"text-on-surface\">128</strong> posts</span\n >\n <span\n ><strong class=\"text-on-surface\">1.2k</strong> followers</span\n >\n </div>\n </div>\n <Separator />\n <div class=\"p-2\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n class=\"w-full justify-start\"\n icon=\"lucide:settings\">Settings</Button\n >\n <Button\n variant=\"ghost\"\n size=\"sm\"\n class=\"w-full justify-start\"\n icon=\"lucide:log-out\"\n color=\"error\">Sign out</Button\n >\n </div>\n </div>\n {/snippet}\n </Popover>\n </div>\n </div>\n\n <!-- Share Menu -->\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium\">Share Menu</p>\n <div\n class=\"flex items-center justify-center rounded-lg bg-surface-container-high p-6\"\n >\n <Popover>\n <Button variant=\"outline\" icon=\"lucide:share-2\">Share</Button>\n {#snippet content({ close })}\n <div class=\"w-56 p-2\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n class=\"w-full justify-start\"\n icon=\"lucide:link\"\n onclick={close}>Copy link</Button\n >\n <Button\n variant=\"ghost\"\n size=\"sm\"\n class=\"w-full justify-start\"\n icon=\"lucide:twitter\"\n onclick={close}>Twitter</Button\n >\n <Button\n variant=\"ghost\"\n size=\"sm\"\n class=\"w-full justify-start\"\n icon=\"lucide:facebook\"\n onclick={close}>Facebook</Button\n >\n <Button\n variant=\"ghost\"\n size=\"sm\"\n class=\"w-full justify-start\"\n icon=\"lucide:mail\"\n onclick={close}>Email</Button\n >\n </div>\n {/snippet}\n </Popover>\n </div>\n </div>\n\n <!-- Notification Panel -->\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium\">Notification Panel</p>\n <div\n class=\"flex items-center justify-center rounded-lg bg-surface-container-high p-6\"\n >\n <Popover>\n <Button variant=\"outline\" icon=\"lucide:bell\">Notifications</Button>\n {#snippet content()}\n <div class=\"w-80\">\n <div class=\"flex items-center justify-between p-4 pb-2\">\n <p class=\"font-medium\">Notifications</p>\n <Badge label=\"3 new\" size=\"xs\" color=\"primary\" />\n </div>\n <div class=\"divide-y divide-outline-variant\">\n <div class=\"flex gap-3 p-4\">\n <div\n class=\"flex size-8 shrink-0 items-center justify-center rounded-full bg-primary/10 text-primary\"\n >\n <Icon name=\"lucide:message-circle\" size=\"16\" />\n </div>\n <div>\n <p class=\"text-sm\">New comment on your post</p>\n <p class=\"text-xs text-on-surface-variant\">\n 2 minutes ago\n </p>\n </div>\n </div>\n <div class=\"flex gap-3 p-4\">\n <div\n class=\"flex size-8 shrink-0 items-center justify-center rounded-full bg-success/10 text-success\"\n >\n <Icon name=\"lucide:user-plus\" size=\"16\" />\n </div>\n <div>\n <p class=\"text-sm\">New follower: Jane Smith</p>\n <p class=\"text-xs text-on-surface-variant\">\n 1 hour ago\n </p>\n </div>\n </div>\n </div>\n </div>\n {/snippet}\n </Popover>\n </div>\n </div>\n\n <!-- Filter Panel -->\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium\">Filter Panel</p>\n <div\n class=\"flex items-center justify-center rounded-lg bg-surface-container-high p-6\"\n >\n <Popover>\n <Button variant=\"outline\" icon=\"lucide:filter\">Filters</Button>\n {#snippet content({ close })}\n <div class=\"w-72\">\n <div class=\"p-4\">\n <p class=\"font-medium\">Filter Results</p>\n </div>\n <Separator />\n <div class=\"space-y-3 p-4\">\n <div>\n <p class=\"text-sm font-medium\">Status</p>\n <div class=\"mt-1 flex gap-2\">\n <Badge label=\"Active\" color=\"success\" />\n <Badge label=\"Pending\" color=\"warning\" />\n <Badge label=\"Closed\" color=\"error\" />\n </div>\n </div>\n <div>\n <p class=\"text-sm font-medium\">Priority</p>\n <div class=\"mt-1 flex gap-2\">\n <Badge label=\"High\" />\n <Badge label=\"Medium\" />\n <Badge label=\"Low\" />\n </div>\n </div>\n </div>\n <Separator />\n <div class=\"flex justify-end gap-2 p-3\">\n <Button variant=\"ghost\" size=\"sm\" onclick={close}>Reset</Button>\n <Button size=\"sm\" onclick={close}>Apply</Button>\n </div>\n </div>\n {/snippet}\n </Popover>\n </div>\n </div>\n </div>\n </section>\n</div>\n",
174
174
  "slideover": "<script lang=\"ts\">\n import { Slideover, Button, Badge, Icon, Separator } from '$lib/index.js'\n\n // --- State ---\n let basicOpen = $state(false)\n let leftOpen = $state(false)\n let topOpen = $state(false)\n let bottomOpen = $state(false)\n let insetRightOpen = $state(false)\n let insetLeftOpen = $state(false)\n let insetTopOpen = $state(false)\n let insetBottomOpen = $state(false)\n let noCloseOpen = $state(false)\n let noOverlayOpen = $state(false)\n let noTransitionOpen = $state(false)\n let nonDismissibleOpen = $state(false)\n let slotsOpen = $state(false)\n let customContentOpen = $state(false)\n let titleSlotOpen = $state(false)\n let actionsOpen = $state(false)\n let callbacksOpen = $state(false)\n let callbackLog = $state<string[]>([])\n let noPortalOpen = $state(false)\n let uiOverrideOpen = $state(false)\n let programmaticOpen = $state(false)\n\n // Real-world demos\n let filtersOpen = $state(false)\n let settingsOpen = $state(false)\n let cartOpen = $state(false)\n let notificationsOpen = $state(false)\n\n let sizeOpens = $state<Record<string, boolean>>({\n sm: false,\n md: false,\n lg: false,\n xl: false,\n full: false\n })\n let transitionOpens = $state<Record<string, boolean>>({\n slide: false,\n fade: false,\n scale: false,\n none: false\n })\n\n function logCallback(name: string) {\n callbackLog = [...callbackLog.slice(-4), `${new Date().toLocaleTimeString()} — ${name}`]\n }\n</script>\n\n<div class=\"space-y-8\">\n <div class=\"space-y-2\">\n <h1 class=\"text-2xl font-bold\">Slideover</h1>\n <p class=\"text-on-surface-variant\">\n A slideover panel component built on top of bits-ui Dialog. Slides in from any side with\n support for transitions, inset mode, dismissible control, and full slot customization.\n </p>\n </div>\n\n <!-- ==================== SIDE VARIANTS ==================== -->\n <section class=\"space-y-3\">\n <h2 id=\"Side-Variants\" class=\"text-lg font-semibold\">\n<a href=\"#Side-Variants\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Side Variants\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Control which side the slideover appears from with the\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">side</code> prop.\n </p>\n <div class=\"flex flex-wrap gap-3 rounded-lg bg-surface-container-high p-4\">\n <Slideover\n bind:open={basicOpen}\n side=\"right\"\n title=\"Right Slideover\"\n description=\"Slides in from the right (default).\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Right\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n This panel slides in from the right side (default).\n </p>\n {/snippet}\n {#snippet footer()}\n <Button label=\"Close\" variant=\"outline\" onclick={() => (basicOpen = false)} />\n {/snippet}\n </Slideover>\n\n <Slideover\n bind:open={leftOpen}\n side=\"left\"\n title=\"Left Slideover\"\n description=\"Slides in from the left.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Left\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">This panel slides in from the left side.</p>\n {/snippet}\n {#snippet footer()}\n <Button label=\"Close\" variant=\"outline\" onclick={() => (leftOpen = false)} />\n {/snippet}\n </Slideover>\n\n <Slideover\n bind:open={topOpen}\n side=\"top\"\n title=\"Top Slideover\"\n description=\"Slides down from the top.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Top\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">This panel slides down from the top.</p>\n {/snippet}\n {#snippet footer()}\n <Button label=\"Close\" variant=\"outline\" onclick={() => (topOpen = false)} />\n {/snippet}\n </Slideover>\n\n <Slideover\n bind:open={bottomOpen}\n side=\"bottom\"\n title=\"Bottom Slideover\"\n description=\"Slides up from the bottom.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Bottom\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">This panel slides up from the bottom.</p>\n {/snippet}\n {#snippet footer()}\n <Button label=\"Close\" variant=\"outline\" onclick={() => (bottomOpen = false)} />\n {/snippet}\n </Slideover>\n </div>\n </section>\n\n <!-- ==================== INSET MODE ==================== -->\n <section class=\"space-y-3\">\n <h2 id=\"Inset-Mode\" class=\"text-lg font-semibold\">\n<a href=\"#Inset-Mode\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Inset Mode\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Enable <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\"\n >inset</code\n > mode to add margins and rounded corners to the slideover.\n </p>\n <div class=\"flex flex-wrap gap-3 rounded-lg bg-surface-container-high p-4\">\n <Slideover\n bind:open={insetRightOpen}\n inset\n title=\"Inset Right\"\n description=\"Inset mode with rounded corners.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Inset (Right)\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n This slideover has margins and rounded corners, giving it a floating\n appearance.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (insetRightOpen = false)}\n />\n {/snippet}\n </Slideover>\n\n <Slideover\n bind:open={insetLeftOpen}\n side=\"left\"\n inset\n title=\"Inset Left\"\n description=\"Inset mode from the left side.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Inset (Left)\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n Inset mode from the left with floating panel appearance.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (insetLeftOpen = false)}\n />\n {/snippet}\n </Slideover>\n\n <Slideover\n bind:open={insetTopOpen}\n side=\"top\"\n inset\n title=\"Inset Top\"\n description=\"Inset mode from the top.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Inset (Top)\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n Inset mode from the top with floating panel appearance.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (insetTopOpen = false)}\n />\n {/snippet}\n </Slideover>\n\n <Slideover\n bind:open={insetBottomOpen}\n side=\"bottom\"\n inset\n title=\"Inset Bottom\"\n description=\"Inset mode from the bottom.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Inset (Bottom)\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n Inset mode from the bottom with floating panel appearance.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (insetBottomOpen = false)}\n />\n {/snippet}\n </Slideover>\n </div>\n </section>\n\n <!-- ==================== TRANSITION ==================== -->\n <section class=\"space-y-3\">\n <h2 id=\"Transition\" class=\"text-lg font-semibold\">\n<a href=\"#Transition\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Transition\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Animations are enabled by default. Set\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\"\n >transition=&#123;false&#125;</code\n >\n to disable.\n </p>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <Slideover\n bind:open={noTransitionOpen}\n transition={false}\n title=\"No Transition\"\n description=\"This slideover appears and disappears instantly.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"No Transition\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n No slide or fade animation — the slideover snaps open and closed.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (noTransitionOpen = false)}\n />\n {/snippet}\n </Slideover>\n </div>\n </section>\n\n <!-- ==================== CLOSE BUTTON ==================== -->\n <section class=\"space-y-3\">\n <h2 id=\"Close-Button\" class=\"text-lg font-semibold\">\n<a href=\"#Close-Button\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Close Button\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Hide the close button with <code\n class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\"\n >close=&#123;false&#125;</code\n >.\n </p>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <Slideover\n bind:open={noCloseOpen}\n close={false}\n title=\"No Close Button\"\n description=\"The X button is hidden.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"No Close Button\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n There's no X button. Use the footer button or Escape key to close.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"solid\"\n color=\"primary\"\n onclick={() => (noCloseOpen = false)}\n />\n {/snippet}\n </Slideover>\n </div>\n </section>\n\n <!-- ==================== OVERLAY ==================== -->\n <section class=\"space-y-3\">\n <h2 id=\"Overlay\" class=\"text-lg font-semibold\">\n<a href=\"#Overlay\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Overlay\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Hide the overlay with <code\n class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\"\n >overlay=&#123;false&#125;</code\n >.\n </p>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <Slideover\n bind:open={noOverlayOpen}\n overlay={false}\n title=\"No Overlay\"\n description=\"The backdrop is hidden.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"No Overlay\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n The slideover has no backdrop overlay. The page content behind is fully\n visible.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (noOverlayOpen = false)}\n />\n {/snippet}\n </Slideover>\n </div>\n </section>\n\n <!-- ==================== NON-DISMISSIBLE ==================== -->\n <section class=\"space-y-3\">\n <h2 id=\"Non-Dismissible\" class=\"text-lg font-semibold\">\n<a href=\"#Non-Dismissible\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Non-Dismissible\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Set <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\"\n >dismissible=&#123;false&#125;</code\n >\n to prevent closing by clicking outside or pressing Escape.\n </p>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <Slideover\n bind:open={nonDismissibleOpen}\n dismissible={false}\n close={false}\n title=\"Non-Dismissible\"\n description=\"You must use the button to close.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Open (Non-Dismissible)\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n Try clicking outside or pressing Escape — the slideover will not close.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"I Understand\"\n variant=\"solid\"\n color=\"primary\"\n onclick={() => (nonDismissibleOpen = false)}\n />\n {/snippet}\n </Slideover>\n </div>\n </section>\n\n <!-- ==================== SLOTS ==================== -->\n <section class=\"space-y-3\">\n <h2 id=\"Slots\" class=\"text-lg font-semibold\">\n<a href=\"#Slots\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Slots\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Customize every part: <code\n class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">header</code\n >,\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">titleSlot</code\n >,\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\"\n >descriptionSlot</code\n >,\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">actions</code>,\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">body</code>,\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">footer</code>,\n or replace all with\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">content</code>.\n </p>\n <div class=\"flex flex-wrap gap-3 rounded-lg bg-surface-container-high p-4\">\n <!-- Custom header slot -->\n <Slideover bind:open={slotsOpen}>\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Custom Header\" />\n {/snippet}\n {#snippet header()}\n <div class=\"flex items-center gap-3 p-4 sm:px-6\">\n <div\n class=\"flex size-10 items-center justify-center rounded-full bg-primary text-on-primary\"\n >\n <Icon name=\"lucide:settings\" size=\"20\" />\n </div>\n <div>\n <h3 class=\"font-semibold text-on-surface\">Custom Header</h3>\n <p class=\"text-sm text-on-surface-variant\">With icon and layout</p>\n </div>\n </div>\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n The <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\"\n >header</code\n > slot replaces the default title + description + close button with fully custom\n markup.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button label=\"Cancel\" variant=\"outline\" onclick={() => (slotsOpen = false)} />\n <Button\n label=\"Confirm\"\n variant=\"solid\"\n color=\"primary\"\n onclick={() => (slotsOpen = false)}\n />\n {/snippet}\n </Slideover>\n\n <!-- Custom title/description slots -->\n <Slideover bind:open={titleSlotOpen}>\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Custom Title/Desc\" />\n {/snippet}\n {#snippet titleSlot()}\n <span class=\"flex items-center gap-2\">\n <Icon name=\"lucide:sparkles\" size=\"16\" class=\"text-warning\" />\n Rich Title with Icon\n </span>\n {/snippet}\n {#snippet descriptionSlot()}\n <span>\n Description with <Badge\n variant=\"soft\"\n color=\"info\"\n size=\"xs\"\n label=\"badge\"\n />\n </span>\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\"\n >titleSlot</code\n >\n and\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\"\n >descriptionSlot</code\n >\n let you customize just the title/description while keeping the default header\n layout.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (titleSlotOpen = false)}\n />\n {/snippet}\n </Slideover>\n\n <!-- Actions slot -->\n <Slideover\n bind:open={actionsOpen}\n title=\"User Profile\"\n description=\"Manage your account settings.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Actions Slot\" />\n {/snippet}\n {#snippet actions()}\n <Badge variant=\"soft\" color=\"success\" size=\"xs\" label=\"Active\" />\n <Badge variant=\"soft\" color=\"info\" size=\"xs\" label=\"Pro\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n The <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\"\n >actions</code\n >\n slot renders between the title/description and the close button in the header.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button label=\"Close\" variant=\"outline\" onclick={() => (actionsOpen = false)} />\n {/snippet}\n </Slideover>\n\n <!-- Full content slot -->\n <Slideover bind:open={customContentOpen} title=\"Custom Content\">\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Content Slot\" />\n {/snippet}\n {#snippet content()}\n <div class=\"flex h-full flex-col items-center justify-center gap-4 p-6\">\n <div\n class=\"flex size-16 items-center justify-center rounded-full bg-success/10\"\n >\n <Icon name=\"lucide:check-circle\" size=\"32\" class=\"text-success\" />\n </div>\n <h3 class=\"text-xl font-semibold text-on-surface\">Action Complete</h3>\n <p class=\"text-center text-on-surface-variant\">\n The <code\n class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\"\n >content</code\n > slot replaces the entire inner layout (header + body + footer).\n </p>\n <Button\n label=\"Done\"\n variant=\"solid\"\n color=\"primary\"\n onclick={() => (customContentOpen = false)}\n />\n </div>\n {/snippet}\n </Slideover>\n </div>\n </section>\n\n <!-- ==================== CALLBACKS ==================== -->\n <section class=\"space-y-3\">\n <h2 id=\"Lifecycle-Callbacks\" class=\"text-lg font-semibold\">\n<a href=\"#Lifecycle-Callbacks\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Lifecycle Callbacks\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\"\n >onOpenChange</code\n >\n and\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\"\n >onOpenChangeComplete</code\n >.\n </p>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <div class=\"mb-3 space-y-1\">\n {#if callbackLog.length === 0}\n <p class=\"text-sm text-on-surface-variant italic\">\n Open/close the slideover to see callback logs...\n </p>\n {/if}\n {#each callbackLog as log, i (i)}\n <p class=\"font-mono text-xs text-on-surface-variant\">{log}</p>\n {/each}\n </div>\n <Slideover\n bind:open={callbacksOpen}\n onOpenChange={(v) => logCallback(`onOpenChange(${v})`)}\n onOpenChangeComplete={(v) => logCallback(`onOpenChangeComplete(${v})`)}\n title=\"Callback Demo\"\n description=\"Check the log above.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Open (With Callbacks)\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n Open, close, and watch the callback log update in real-time.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (callbacksOpen = false)}\n />\n {/snippet}\n </Slideover>\n </div>\n </section>\n\n <!-- ==================== NO PORTAL ==================== -->\n <section class=\"space-y-3\">\n <h2 id=\"Without-Portal\" class=\"text-lg font-semibold\">\n<a href=\"#Without-Portal\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Without Portal\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Set\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\"\n >portal=&#123;false&#125;</code\n >\n to render inline instead of being portalled to the body.\n </p>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <Slideover\n bind:open={noPortalOpen}\n portal={false}\n title=\"No Portal\"\n description=\"Rendered inline, not in a portal.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Open (No Portal)\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n This slideover is rendered inline in the DOM.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (noPortalOpen = false)}\n />\n {/snippet}\n </Slideover>\n </div>\n </section>\n\n <!-- ==================== PROGRAMMATIC ==================== -->\n <section class=\"space-y-3\">\n <h2 id=\"Programmatic-Control\" class=\"text-lg font-semibold\">\n<a href=\"#Programmatic-Control\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Programmatic Control\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Control the slideover without a trigger by binding\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">open</code> externally.\n </p>\n <div class=\"flex gap-3 rounded-lg bg-surface-container-high p-4\">\n <Button\n variant=\"outline\"\n label=\"Open Programmatically\"\n onclick={() => (programmaticOpen = true)}\n />\n <Slideover\n bind:open={programmaticOpen}\n title=\"Programmatic Slideover\"\n description=\"Opened without a trigger slot.\"\n >\n {#snippet body()}\n <p class=\"text-on-surface-variant\">\n This slideover has no children slot. It was opened by setting\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\"\n >open = true</code\n > externally.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (programmaticOpen = false)}\n />\n {/snippet}\n </Slideover>\n </div>\n </section>\n\n <!-- ==================== UI OVERRIDES ==================== -->\n <section class=\"space-y-3\">\n <h2 id=\"UI-Prop-Style-Overrides\" class=\"text-lg font-semibold\">\n<a href=\"#UI-Prop-Style-Overrides\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n UI Prop (Style Overrides)\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Override individual slot styles via the\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">ui</code> prop.\n </p>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <Slideover\n bind:open={uiOverrideOpen}\n title=\"Styled Slideover\"\n description=\"Custom styles via the ui prop.\"\n ui={{\n content: 'bg-primary-container',\n title: 'text-on-primary-container',\n description: 'text-on-primary-container/70'\n }}\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label=\"Open Styled Slideover\" />\n {/snippet}\n {#snippet body()}\n <p class=\"text-on-primary-container/80\">\n This slideover overrides\n <code\n class=\"rounded bg-on-primary-container/10 px-1.5 py-0.5 text-xs text-on-primary-container\"\n >content</code\n >,\n <code\n class=\"rounded bg-on-primary-container/10 px-1.5 py-0.5 text-xs text-on-primary-container\"\n >title</code\n >, and\n <code\n class=\"rounded bg-on-primary-container/10 px-1.5 py-0.5 text-xs text-on-primary-container\"\n >description</code\n > slot classes.\n </p>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Close\"\n variant=\"outline\"\n onclick={() => (uiOverrideOpen = false)}\n />\n {/snippet}\n </Slideover>\n </div>\n </section>\n\n <Separator />\n\n <!-- ==================== REAL WORLD EXAMPLES ==================== -->\n <section class=\"space-y-3\">\n <h2 id=\"Real-World-Examples\" class=\"text-lg font-semibold\">\n<a href=\"#Real-World-Examples\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Real World Examples\n </a>\n</h2>\n\n <div class=\"grid gap-4 sm:grid-cols-2\">\n <!-- Filters Panel -->\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <p class=\"mb-3 text-sm font-medium\">Filters Panel</p>\n <Slideover\n bind:open={filtersOpen}\n side=\"left\"\n title=\"Filters\"\n description=\"Refine your search results.\"\n >\n {#snippet children({ props })}\n <Button\n {...props}\n variant=\"outline\"\n leadingIcon=\"lucide:sliders-horizontal\"\n label=\"Filters\"\n class=\"w-full\"\n />\n {/snippet}\n {#snippet body()}\n <div class=\"space-y-6\">\n <div>\n <h4 class=\"mb-3 text-sm font-medium text-on-surface\">Category</h4>\n <div class=\"space-y-2\">\n {#each ['Electronics', 'Clothing', 'Home & Garden', 'Sports'] as category (category)}\n <label class=\"flex items-center gap-2\">\n <input\n type=\"checkbox\"\n class=\"rounded border-outline-variant text-primary focus:ring-primary\"\n />\n <span class=\"text-sm text-on-surface-variant\"\n >{category}</span\n >\n </label>\n {/each}\n </div>\n </div>\n <div>\n <h4 class=\"mb-3 text-sm font-medium text-on-surface\">\n Price Range\n </h4>\n <div class=\"flex gap-2\">\n <input\n type=\"number\"\n placeholder=\"Min\"\n class=\"w-full rounded-md border border-outline-variant bg-surface px-3 py-2 text-sm\"\n />\n <input\n type=\"number\"\n placeholder=\"Max\"\n class=\"w-full rounded-md border border-outline-variant bg-surface px-3 py-2 text-sm\"\n />\n </div>\n </div>\n <div>\n <h4 class=\"mb-3 text-sm font-medium text-on-surface\">Rating</h4>\n <div class=\"space-y-2\">\n {#each [4, 3, 2, 1] as stars (stars)}\n <label class=\"flex items-center gap-2\">\n <input\n type=\"radio\"\n name=\"rating\"\n class=\"border-outline-variant text-primary focus:ring-primary\"\n />\n <span\n class=\"flex items-center gap-1 text-sm text-on-surface-variant\"\n >\n {stars}+ <Icon\n name=\"lucide:star\"\n size=\"14\"\n class=\"text-warning\"\n />\n </span>\n </label>\n {/each}\n </div>\n </div>\n </div>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Reset\"\n variant=\"outline\"\n onclick={() => (filtersOpen = false)}\n />\n <Button\n label=\"Apply Filters\"\n variant=\"solid\"\n color=\"primary\"\n onclick={() => (filtersOpen = false)}\n />\n {/snippet}\n </Slideover>\n </div>\n\n <!-- Settings Panel -->\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <p class=\"mb-3 text-sm font-medium\">Settings Panel</p>\n <Slideover\n bind:open={settingsOpen}\n inset\n title=\"Settings\"\n description=\"Customize your experience.\"\n >\n {#snippet children({ props })}\n <Button\n {...props}\n variant=\"outline\"\n leadingIcon=\"lucide:settings\"\n label=\"Settings\"\n class=\"w-full\"\n />\n {/snippet}\n {#snippet body()}\n <div class=\"space-y-6\">\n <div class=\"flex items-center justify-between\">\n <div>\n <p class=\"font-medium text-on-surface\">Dark Mode</p>\n <p class=\"text-sm text-on-surface-variant\">Enable dark theme</p>\n </div>\n <input\n type=\"checkbox\"\n class=\"rounded border-outline-variant text-primary focus:ring-primary\"\n />\n </div>\n <div class=\"flex items-center justify-between\">\n <div>\n <p class=\"font-medium text-on-surface\">Notifications</p>\n <p class=\"text-sm text-on-surface-variant\">\n Receive push notifications\n </p>\n </div>\n <input\n type=\"checkbox\"\n checked\n class=\"rounded border-outline-variant text-primary focus:ring-primary\"\n />\n </div>\n <div class=\"flex items-center justify-between\">\n <div>\n <p class=\"font-medium text-on-surface\">Sound Effects</p>\n <p class=\"text-sm text-on-surface-variant\">\n Play sounds for actions\n </p>\n </div>\n <input\n type=\"checkbox\"\n class=\"rounded border-outline-variant text-primary focus:ring-primary\"\n />\n </div>\n <div>\n <p class=\"mb-2 font-medium text-on-surface\">Language</p>\n <select\n class=\"w-full rounded-md border border-outline-variant bg-surface px-3 py-2 text-sm\"\n >\n <option>English</option>\n <option>Spanish</option>\n <option>French</option>\n <option>German</option>\n </select>\n </div>\n </div>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Cancel\"\n variant=\"outline\"\n onclick={() => (settingsOpen = false)}\n />\n <Button\n label=\"Save Changes\"\n variant=\"solid\"\n color=\"primary\"\n onclick={() => (settingsOpen = false)}\n />\n {/snippet}\n </Slideover>\n </div>\n\n <!-- Shopping Cart -->\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <p class=\"mb-3 text-sm font-medium\">Shopping Cart</p>\n <Slideover\n bind:open={cartOpen}\n title=\"Shopping Cart\"\n description=\"3 items in your cart\"\n >\n {#snippet children({ props })}\n <Button\n {...props}\n variant=\"outline\"\n leadingIcon=\"lucide:shopping-cart\"\n label=\"Cart (3)\"\n class=\"w-full\"\n />\n {/snippet}\n {#snippet body()}\n <div class=\"space-y-4\">\n {#each [{ name: 'Wireless Headphones', price: '$199.99', qty: 1 }, { name: 'USB-C Cable', price: '$19.99', qty: 2 }, { name: 'Phone Case', price: '$29.99', qty: 1 }] as item (item.name)}\n <div\n class=\"flex items-center gap-3 rounded-lg bg-surface-container p-3\"\n >\n <div\n class=\"size-12 rounded-md bg-surface-container-highest\"\n ></div>\n <div class=\"flex-1\">\n <p class=\"font-medium text-on-surface\">{item.name}</p>\n <p class=\"text-sm text-on-surface-variant\">\n Qty: {item.qty}\n </p>\n </div>\n <p class=\"font-medium text-on-surface\">{item.price}</p>\n </div>\n {/each}\n <div class=\"border-t border-outline-variant pt-4\">\n <div class=\"flex justify-between\">\n <span class=\"text-on-surface-variant\">Subtotal</span>\n <span class=\"font-medium text-on-surface\">$269.96</span>\n </div>\n <div class=\"mt-1 flex justify-between\">\n <span class=\"text-on-surface-variant\">Shipping</span>\n <span class=\"font-medium text-on-surface\">$9.99</span>\n </div>\n <div\n class=\"mt-2 flex justify-between border-t border-outline-variant pt-2\"\n >\n <span class=\"font-semibold text-on-surface\">Total</span>\n <span class=\"font-semibold text-on-surface\">$279.95</span>\n </div>\n </div>\n </div>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Continue Shopping\"\n variant=\"outline\"\n onclick={() => (cartOpen = false)}\n />\n <Button\n label=\"Checkout\"\n variant=\"solid\"\n color=\"primary\"\n onclick={() => (cartOpen = false)}\n />\n {/snippet}\n </Slideover>\n </div>\n\n <!-- Notifications Panel -->\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <p class=\"mb-3 text-sm font-medium\">Notifications Panel</p>\n <Slideover\n bind:open={notificationsOpen}\n title=\"Notifications\"\n description=\"You have 5 unread notifications\"\n >\n {#snippet children({ props })}\n <Button\n {...props}\n variant=\"outline\"\n leadingIcon=\"lucide:bell\"\n label=\"Notifications\"\n class=\"w-full\"\n />\n {/snippet}\n {#snippet body()}\n <div class=\"space-y-3\">\n {#each [{ icon: 'lucide:package', title: 'Order shipped', desc: 'Your order #1234 has been shipped', time: '2m ago', color: 'text-info' }, { icon: 'lucide:user-plus', title: 'New follower', desc: 'John Doe started following you', time: '1h ago', color: 'text-primary' }, { icon: 'lucide:message-circle', title: 'New comment', desc: 'Sarah commented on your post', time: '3h ago', color: 'text-success' }, { icon: 'lucide:heart', title: 'Post liked', desc: 'Your post received 100 likes', time: '5h ago', color: 'text-error' }, { icon: 'lucide:calendar', title: 'Event reminder', desc: 'Team meeting in 30 minutes', time: '1d ago', color: 'text-warning' }] as notif (notif.title)}\n <div class=\"flex gap-3 rounded-lg bg-surface-container p-3\">\n <div\n class={`flex size-10 shrink-0 items-center justify-center rounded-full bg-surface-container-highest ${notif.color}`}\n >\n <Icon name={notif.icon} size=\"18\" />\n </div>\n <div class=\"flex-1\">\n <p class=\"font-medium text-on-surface\">{notif.title}</p>\n <p class=\"text-sm text-on-surface-variant\">{notif.desc}</p>\n <p class=\"mt-1 text-xs text-on-surface-variant\">\n {notif.time}\n </p>\n </div>\n </div>\n {/each}\n </div>\n {/snippet}\n {#snippet footer()}\n <Button\n label=\"Mark all as read\"\n variant=\"outline\"\n class=\"w-full\"\n onclick={() => (notificationsOpen = false)}\n />\n {/snippet}\n </Slideover>\n </div>\n </div>\n </section>\n\n <Separator />\n\n <section>\n <h2 id=\"Size\" class=\"mb-3 text-lg font-semibold\">\n<a href=\"#Size\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Size\n </a>\n</h2>\n <p class=\"mb-4 text-sm text-on-surface-variant\">\n Use <code>size</code> to control the panel along its axis.\n <code>left</code> / <code>right</code> change <code>max-width</code>;\n <code>top</code> / <code>bottom</code> change <code>max-height</code>. Available values:\n <code>sm</code>\n / <code>md</code> (default) / <code>lg</code> /\n <code>xl</code> / <code>full</code>.\n </p>\n <div class=\"flex flex-wrap gap-2\">\n {#each ['sm', 'md', 'lg', 'xl', 'full'] as const as s (s)}\n <Slideover\n bind:open={sizeOpens[s]}\n size={s}\n title={`Size: ${s}`}\n description={`right side, size=\"${s}\"`}\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label={`size=\"${s}\"`} />\n {/snippet}\n {#snippet body()}\n <p class=\"text-sm text-on-surface-variant\">\n Current size is <code>{s}</code>.\n </p>\n {/snippet}\n </Slideover>\n {/each}\n </div>\n </section>\n\n <Separator />\n\n <section>\n <h2 id=\"Transition\" class=\"mb-3 text-lg font-semibold\">\n<a href=\"#Transition\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Transition\n </a>\n</h2>\n <p class=\"mb-4 text-sm text-on-surface-variant\">\n Pick the entrance/exit animation. Default is <code>slide</code> (side-aware); pass\n <code>fade</code>, <code>scale</code>, or <code>none</code> to override. Boolean\n <code>true</code> / <code>false</code> still work as legacy aliases.\n </p>\n <div class=\"flex flex-wrap gap-2\">\n {#each ['slide', 'fade', 'scale', 'none'] as const as t (t)}\n <Slideover\n bind:open={transitionOpens[t]}\n transition={t}\n title={`Transition: ${t}`}\n description=\"Open and close to see the animation.\"\n >\n {#snippet children({ props })}\n <Button {...props} variant=\"outline\" label={`transition=\"${t}\"`} />\n {/snippet}\n </Slideover>\n {/each}\n </div>\n </section>\n</div>\n",
175
175
  "tooltip": "<script lang=\"ts\">\n import { Tooltip, Button, Badge, Icon, Separator } from '$lib/index.js'\n\n let controlledOpen = $state(false)\n</script>\n\n<div class=\"space-y-8\">\n <div class=\"space-y-2\">\n <h1 class=\"text-2xl font-bold\">Tooltip</h1>\n <p class=\"text-on-surface-variant\">\n Display brief, informative text on hover or focus. Built on bits-ui Tooltip primitive.\n </p>\n </div>\n\n <!-- Basic -->\n <section class=\"space-y-3\">\n <h2 id=\"Basic\" class=\"text-lg font-semibold\">\n<a href=\"#Basic\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Basic\n </a>\n</h2>\n <div class=\"flex flex-wrap gap-4 rounded-lg bg-surface-container-high p-4\">\n <Tooltip text=\"This is a tooltip\">\n <Button variant=\"outline\">Hover me</Button>\n </Tooltip>\n\n <Tooltip text=\"Tooltip for icon button\">\n <Button icon=\"lucide:settings\" square variant=\"ghost\" />\n </Tooltip>\n\n <Tooltip text=\"Information tooltip\">\n <Badge label=\"Hover for info\" color=\"info\" />\n </Tooltip>\n </div>\n </section>\n\n <!-- Positions -->\n <section class=\"space-y-3\">\n <h2 id=\"Positions\" class=\"text-lg font-semibold\">\n<a href=\"#Positions\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Positions\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Control tooltip placement with the\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">side</code>\n prop.\n </p>\n <div\n class=\"flex flex-wrap items-center justify-center gap-8 rounded-lg bg-surface-container-high p-8\"\n >\n <Tooltip text=\"I appear on top\" side=\"top\">\n <Button variant=\"soft\">Top</Button>\n </Tooltip>\n\n <Tooltip text=\"I appear on the right\" side=\"right\">\n <Button variant=\"soft\">Right</Button>\n </Tooltip>\n\n <Tooltip text=\"I appear on the bottom\" side=\"bottom\">\n <Button variant=\"soft\">Bottom</Button>\n </Tooltip>\n\n <Tooltip text=\"I appear on the left\" side=\"left\">\n <Button variant=\"soft\">Left</Button>\n </Tooltip>\n </div>\n </section>\n\n <!-- Alignment -->\n <section class=\"space-y-3\">\n <h2 id=\"Alignment\" class=\"text-lg font-semibold\">\n<a href=\"#Alignment\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Alignment\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Control alignment with the\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">align</code>\n prop.\n </p>\n <div\n class=\"flex flex-wrap items-center justify-center gap-8 rounded-lg bg-surface-container-high p-8\"\n >\n <Tooltip text=\"Aligned to start\" side=\"bottom\" align=\"start\">\n <Button variant=\"outline\">Start</Button>\n </Tooltip>\n\n <Tooltip text=\"Aligned to center\" side=\"bottom\" align=\"center\">\n <Button variant=\"outline\">Center</Button>\n </Tooltip>\n\n <Tooltip text=\"Aligned to end\" side=\"bottom\" align=\"end\">\n <Button variant=\"outline\">End</Button>\n </Tooltip>\n </div>\n </section>\n\n <!-- Arrow -->\n <section class=\"space-y-3\">\n <h2 id=\"Arrow\" class=\"text-lg font-semibold\">\n<a href=\"#Arrow\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Arrow\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Add an arrow pointing to the trigger element with the\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">arrow</code>\n prop.\n </p>\n <div class=\"grid gap-4 sm:grid-cols-2\">\n {#each [{ side: 'top' as const, label: 'Top' }, { side: 'right' as const, label: 'Right' }, { side: 'bottom' as const, label: 'Bottom' }, { side: 'left' as const, label: 'Left' }] as item (item.side)}\n <div\n class=\"flex items-center justify-center rounded-lg bg-surface-container-high p-6\"\n >\n <Tooltip text=\"Arrow on {item.side}\" arrow side={item.side}>\n <Button>{item.label}</Button>\n </Tooltip>\n </div>\n {/each}\n </div>\n </section>\n\n <!-- Keyboard Shortcuts -->\n <section class=\"space-y-3\">\n <h2 id=\"Keyboard-Shortcuts\" class=\"text-lg font-semibold\">\n<a href=\"#Keyboard-Shortcuts\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Keyboard Shortcuts\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Display keyboard shortcuts alongside text using the\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">kbds</code>\n prop.\n </p>\n <div class=\"flex flex-wrap gap-4 rounded-lg bg-surface-container-high p-4\">\n <Tooltip text=\"Search\" kbds={['meta', 'k']}>\n <Button icon=\"lucide:search\" variant=\"outline\">Search</Button>\n </Tooltip>\n\n <Tooltip text=\"Save changes\" kbds={['meta', 's']}>\n <Button icon=\"lucide:save\" variant=\"soft\">Save</Button>\n </Tooltip>\n\n <Tooltip text=\"Undo action\" kbds={['meta', 'z']}>\n <Button icon=\"lucide:undo\" variant=\"ghost\">Undo</Button>\n </Tooltip>\n\n <Tooltip text=\"Open command palette\" kbds={['meta', 'shift', 'p']}>\n <Button icon=\"lucide:terminal\" variant=\"outline\">Command</Button>\n </Tooltip>\n </div>\n </section>\n\n <!-- Delay Duration -->\n <section class=\"space-y-3\">\n <h2 id=\"Delay-Duration\" class=\"text-lg font-semibold\">\n<a href=\"#Delay-Duration\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Delay Duration\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Control how long to wait before showing the tooltip.\n </p>\n <div class=\"flex flex-wrap gap-4 rounded-lg bg-surface-container-high p-4\">\n <Tooltip text=\"Instant (0ms)\" delayDuration={0}>\n <Button variant=\"outline\">No Delay</Button>\n </Tooltip>\n\n <Tooltip text=\"Fast (200ms)\" delayDuration={200}>\n <Button variant=\"outline\">200ms</Button>\n </Tooltip>\n\n <Tooltip text=\"Slow (500ms)\" delayDuration={500}>\n <Button variant=\"outline\">500ms</Button>\n </Tooltip>\n\n <Tooltip text=\"Very slow (1s)\" delayDuration={1000}>\n <Button variant=\"outline\">1 second</Button>\n </Tooltip>\n </div>\n </section>\n\n <!-- Controlled -->\n <section class=\"space-y-3\">\n <h2 id=\"Controlled\" class=\"text-lg font-semibold\">\n<a href=\"#Controlled\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Controlled\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Control tooltip visibility programmatically with\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">open</code>\n binding.\n </p>\n <div class=\"grid gap-4 sm:grid-cols-2\">\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium text-on-surface-variant\">Observe hover state</p>\n <div class=\"flex items-center gap-4 rounded-lg bg-surface-container-high p-4\">\n <Tooltip text=\"Hover to see state change\" bind:open={controlledOpen}>\n <Button variant={controlledOpen ? 'solid' : 'outline'}>Hover me</Button>\n </Tooltip>\n <span class=\"text-sm text-on-surface-variant\">\n open: <code class=\"text-primary\">{controlledOpen}</code>\n </span>\n </div>\n </div>\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium text-on-surface-variant\">Toggle programmatically</p>\n <div class=\"flex items-center gap-4 rounded-lg bg-surface-container-high p-4\">\n <Tooltip text=\"Programmatic tooltip\" open={controlledOpen}>\n <Button variant=\"outline\">Target</Button>\n </Tooltip>\n <Button variant=\"soft\" onclick={() => (controlledOpen = !controlledOpen)}>\n {controlledOpen ? 'Hide' : 'Show'}\n </Button>\n </div>\n </div>\n </div>\n </section>\n\n <!-- Disabled -->\n <section class=\"space-y-3\">\n <h2 id=\"Disabled\" class=\"text-lg font-semibold\">\n<a href=\"#Disabled\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Disabled\n </a>\n</h2>\n <div class=\"flex flex-wrap gap-4 rounded-lg bg-surface-container-high p-4\">\n <Tooltip text=\"This won't show\" disabled>\n <Button>Tooltip Disabled</Button>\n </Tooltip>\n\n <Tooltip text=\"This will show\">\n <Button variant=\"soft\">Tooltip Enabled</Button>\n </Tooltip>\n </div>\n </section>\n\n <!-- Custom Content Snippet -->\n <section class=\"space-y-3\">\n <h2 id=\"Custom-Content\" class=\"text-lg font-semibold\">\n<a href=\"#Custom-Content\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Custom Content\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">content</code>\n snippet for rich tooltip content.\n </p>\n <div class=\"flex flex-wrap gap-4 rounded-lg bg-surface-container-high p-4\">\n <Tooltip>\n <Button variant=\"soft\" icon=\"lucide:user\">User Info</Button>\n {#snippet content()}\n <div class=\"flex items-center gap-2\">\n <Icon name=\"lucide:user-circle\" size=\"16\" />\n <span>John Doe</span>\n <Badge label=\"Admin\" size=\"xs\" color=\"success\" />\n </div>\n {/snippet}\n </Tooltip>\n\n <Tooltip arrow>\n <Button variant=\"soft\" icon=\"lucide:info\">Details</Button>\n {#snippet content()}\n <div class=\"flex flex-col gap-1\">\n <span class=\"font-medium\">Server Status</span>\n <span class=\"text-inverse-on-surface/80\">All systems operational</span>\n </div>\n {/snippet}\n </Tooltip>\n\n <Tooltip>\n <Button icon=\"lucide:palette\" variant=\"outline\">Colors</Button>\n {#snippet content()}\n <div class=\"flex gap-1\">\n <span class=\"size-4 rounded-full bg-red-500\"></span>\n <span class=\"size-4 rounded-full bg-yellow-500\"></span>\n <span class=\"size-4 rounded-full bg-green-500\"></span>\n <span class=\"size-4 rounded-full bg-blue-500\"></span>\n </div>\n {/snippet}\n </Tooltip>\n </div>\n </section>\n\n <!-- Hoverable Content -->\n <section class=\"space-y-3\">\n <h2 id=\"Hoverable-Content\" class=\"text-lg font-semibold\">\n<a href=\"#Hoverable-Content\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Hoverable Content\n </a>\n</h2>\n <p class=\"text-sm text-on-surface-variant\">\n By default, users can hover over tooltip content. Disable with\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\"\n >disableHoverableContent</code\n >.\n </p>\n <div class=\"flex flex-wrap gap-4 rounded-lg bg-surface-container-high p-4\">\n <Tooltip text=\"You can hover over this tooltip\" delayDuration={0}>\n <Button variant=\"outline\">Hoverable (default)</Button>\n </Tooltip>\n\n <Tooltip\n text=\"This closes immediately when you leave trigger\"\n disableHoverableContent\n delayDuration={0}\n >\n <Button variant=\"outline\">Not Hoverable</Button>\n </Tooltip>\n </div>\n </section>\n\n <!-- UI Slot Overrides -->\n <section class=\"space-y-3\">\n <h2 id=\"UI-Slot-Overrides\" class=\"text-lg font-semibold\">\n<a href=\"#UI-Slot-Overrides\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n UI Slot Overrides\n </a>\n</h2>\n <div class=\"grid gap-4 sm:grid-cols-2\">\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium text-on-surface-variant\">Primary style</p>\n <div\n class=\"flex items-center justify-center rounded-lg bg-surface-container-high p-6\"\n >\n <Tooltip\n text=\"Custom styled tooltip\"\n ui={{ content: 'bg-primary text-on-primary rounded-full px-4' }}\n >\n <Button>Primary</Button>\n </Tooltip>\n </div>\n </div>\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium text-on-surface-variant\">Error style</p>\n <div\n class=\"flex items-center justify-center rounded-lg bg-surface-container-high p-6\"\n >\n <Tooltip text=\"Error styled\" ui={{ content: 'bg-error text-on-error' }}>\n <Button color=\"error\" variant=\"soft\">Error</Button>\n </Tooltip>\n </div>\n </div>\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium text-on-surface-variant\">Success style</p>\n <div\n class=\"flex items-center justify-center rounded-lg bg-surface-container-high p-6\"\n >\n <Tooltip text=\"Success message\" ui={{ content: 'bg-success text-on-success' }}>\n <Button color=\"success\" variant=\"soft\">Success</Button>\n </Tooltip>\n </div>\n </div>\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium text-on-surface-variant\">Large size</p>\n <div\n class=\"flex items-center justify-center rounded-lg bg-surface-container-high p-6\"\n >\n <Tooltip text=\"Large tooltip\" ui={{ content: 'text-sm px-4 py-2' }}>\n <Button variant=\"outline\">Large</Button>\n </Tooltip>\n </div>\n </div>\n </div>\n </section>\n\n <Separator />\n\n <!-- Real World Examples -->\n <section class=\"space-y-6\">\n <h2 id=\"Real-World-Examples\" class=\"text-lg font-semibold\">\n<a href=\"#Real-World-Examples\" class=\"group relative inline-flex items-center no-underline hover:underline focus:outline-none focus-visible:underline w-fit\">\n <span class=\"absolute -left-5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100 text-primary/60 font-normal text-base leading-none\" aria-hidden=\"true\">#</span>\n Real World Examples\n </a>\n</h2>\n\n <div class=\"grid gap-4 md:grid-cols-2\">\n <!-- Editor Toolbar -->\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium\">Editor Toolbar</p>\n <div class=\"flex items-center gap-1 rounded-lg bg-surface-container-high p-2\">\n <Tooltip text=\"Bold\" kbds={['meta', 'b']}>\n <Button icon=\"lucide:bold\" square variant=\"ghost\" size=\"sm\" />\n </Tooltip>\n <Tooltip text=\"Italic\" kbds={['meta', 'i']}>\n <Button icon=\"lucide:italic\" square variant=\"ghost\" size=\"sm\" />\n </Tooltip>\n <Tooltip text=\"Underline\" kbds={['meta', 'u']}>\n <Button icon=\"lucide:underline\" square variant=\"ghost\" size=\"sm\" />\n </Tooltip>\n <div class=\"mx-1 h-6 w-px bg-outline-variant\"></div>\n <Tooltip text=\"Align Left\">\n <Button icon=\"lucide:align-left\" square variant=\"ghost\" size=\"sm\" />\n </Tooltip>\n <Tooltip text=\"Align Center\">\n <Button icon=\"lucide:align-center\" square variant=\"ghost\" size=\"sm\" />\n </Tooltip>\n <Tooltip text=\"Align Right\">\n <Button icon=\"lucide:align-right\" square variant=\"ghost\" size=\"sm\" />\n </Tooltip>\n <div class=\"mx-1 h-6 w-px bg-outline-variant\"></div>\n <Tooltip text=\"Insert Link\" kbds={['meta', 'k']}>\n <Button icon=\"lucide:link\" square variant=\"ghost\" size=\"sm\" />\n </Tooltip>\n </div>\n </div>\n\n <!-- Social Actions -->\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium\">Social Actions</p>\n <div class=\"flex items-center gap-2 rounded-lg bg-surface-container-high p-4\">\n <Tooltip text=\"Like this post\">\n <Button icon=\"lucide:heart\" variant=\"ghost\" size=\"sm\">128</Button>\n </Tooltip>\n <Tooltip text=\"Leave a comment\">\n <Button icon=\"lucide:message-circle\" variant=\"ghost\" size=\"sm\">24</Button>\n </Tooltip>\n <Tooltip text=\"Share this post\">\n <Button icon=\"lucide:share-2\" variant=\"ghost\" size=\"sm\">Share</Button>\n </Tooltip>\n <Tooltip text=\"Save to bookmarks\">\n <Button icon=\"lucide:bookmark\" variant=\"ghost\" size=\"sm\" square />\n </Tooltip>\n </div>\n </div>\n\n <!-- Status Indicators -->\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium\">Status Indicators</p>\n <div class=\"flex items-center gap-4 rounded-lg bg-surface-container-high p-4\">\n <Tooltip text=\"Server is healthy and responding\">\n <span class=\"flex items-center gap-2\">\n <span class=\"size-3 rounded-full bg-success\"></span>\n <span class=\"text-sm\">API Server</span>\n </span>\n </Tooltip>\n <Tooltip text=\"High CPU usage detected\">\n <span class=\"flex items-center gap-2\">\n <span class=\"size-3 rounded-full bg-warning\"></span>\n <span class=\"text-sm\">Worker Node</span>\n </span>\n </Tooltip>\n <Tooltip text=\"Service unavailable\">\n <span class=\"flex items-center gap-2\">\n <span class=\"size-3 rounded-full bg-error\"></span>\n <span class=\"text-sm\">Database</span>\n </span>\n </Tooltip>\n </div>\n </div>\n\n <!-- Truncated Content -->\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium\">Truncated Content</p>\n <div class=\"flex flex-col gap-2 rounded-lg bg-surface-container-high p-4\">\n <Tooltip\n text=\"This is the full title of a very long document that would normally be truncated in the UI\"\n >\n <p class=\"w-64 truncate text-sm\">\n This is the full title of a very long document that would normally be\n truncated in the UI\n </p>\n </Tooltip>\n <Tooltip text=\"user@example.com, admin@company.org, support@helpdesk.io\">\n <p class=\"w-48 truncate text-sm text-on-surface-variant\">\n user@example.com, admin@company.org, support@helpdesk.io\n </p>\n </Tooltip>\n </div>\n </div>\n </div>\n </section>\n</div>\n",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelora",
3
- "version": "3.0.11",
3
+ "version": "3.0.12",
4
4
  "description": "Modern primitive-based UI component library for Svelte 5",
5
5
  "packageManager": "bun@1.3.14",
6
6
  "author": "asphum",