svelora 3.0.4 → 3.0.5

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.
@@ -26,6 +26,7 @@ const leadingIconName = $derived(spinLeading ? loadingIcon : leadingIcon || (!tr
26
26
  const trailingIconName = $derived(spinTrailing ? loadingIcon : trailingIcon || (trailing ? icon : undefined));
27
27
  const resolvedColor = $derived(active && activeColor ? activeColor : color);
28
28
  const resolvedVariant = $derived(active && activeVariant ? activeVariant : variant);
29
+ const isLink = $derived(!!href);
29
30
  const classes = $derived.by(() => {
30
31
  const slots = buttonVariants({
31
32
  variant: resolvedVariant,
@@ -72,38 +73,69 @@ function handleClick(e) {
72
73
  }
73
74
  </script>
74
75
 
75
- <Link
76
- {...restProps}
77
- bind:ref
78
- {href}
79
- {type}
80
- {external}
81
- {active}
82
- {exact}
83
- {activeClass}
84
- {inactiveClass}
85
- raw
86
- disabled={disabled || isLoading}
87
- class={classes.base}
88
- onclick={handleClick}
89
- >
90
- {#if leadingSlot}
91
- {@render leadingSlot()}
92
- {:else if isLeading && leadingIconName}
93
- <Icon name={leadingIconName} class={classes.leadingIcon} />
94
- {:else if avatar}
95
- <Avatar {...avatar} size={classes.leadingAvatarSize} class={classes.leadingAvatar} />
96
- {/if}
76
+ {#if isLink}
77
+ <Link
78
+ {...restProps}
79
+ bind:ref
80
+ {href}
81
+ {type}
82
+ {external}
83
+ {active}
84
+ {exact}
85
+ {activeClass}
86
+ {inactiveClass}
87
+ raw
88
+ disabled={disabled || isLoading}
89
+ class={classes.base}
90
+ onclick={handleClick}
91
+ >
92
+ {#if leadingSlot}
93
+ {@render leadingSlot()}
94
+ {:else if isLeading && leadingIconName}
95
+ <Icon name={leadingIconName} class={classes.leadingIcon} />
96
+ {:else if avatar}
97
+ <Avatar {...avatar} size={classes.leadingAvatarSize} class={classes.leadingAvatar} />
98
+ {/if}
97
99
 
98
- {#if label}
99
- <span class={classes.label}>{label}</span>
100
- {:else if children}
101
- <span class={classes.label}>{@render children()}</span>
102
- {/if}
100
+ {#if label}
101
+ <span class={classes.label}>{label}</span>
102
+ {:else if children}
103
+ <span class={classes.label}>{@render children()}</span>
104
+ {/if}
103
105
 
104
- {#if trailingSlot}
105
- {@render trailingSlot()}
106
- {:else if isTrailing && trailingIconName}
107
- <Icon name={trailingIconName} class={classes.trailingIcon} />
108
- {/if}
109
- </Link>
106
+ {#if trailingSlot}
107
+ {@render trailingSlot()}
108
+ {:else if isTrailing && trailingIconName}
109
+ <Icon name={trailingIconName} class={classes.trailingIcon} />
110
+ {/if}
111
+ </Link>
112
+ {:else}
113
+ <button
114
+ {...restProps}
115
+ bind:this={ref}
116
+ type={type ?? 'button'}
117
+ disabled={disabled || isLoading}
118
+ class={classes.base}
119
+ onclick={handleClick}
120
+ >
121
+ {#if leadingSlot}
122
+ {@render leadingSlot()}
123
+ {:else if isLeading && leadingIconName}
124
+ <Icon name={leadingIconName} class={classes.leadingIcon} />
125
+ {:else if avatar}
126
+ <Avatar {...avatar} size={classes.leadingAvatarSize} class={classes.leadingAvatar} />
127
+ {/if}
128
+
129
+ {#if label}
130
+ <span class={classes.label}>{label}</span>
131
+ {:else if children}
132
+ <span class={classes.label}>{@render children()}</span>
133
+ {/if}
134
+
135
+ {#if trailingSlot}
136
+ {@render trailingSlot()}
137
+ {:else if isTrailing && trailingIconName}
138
+ <Icon name={trailingIconName} class={classes.trailingIcon} />
139
+ {/if}
140
+ </button>
141
+ {/if}
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "version": 1,
3
3
  "packageName": "svelora",
4
- "packageVersion": "3.0.4",
5
- "generatedAt": "2026-06-23T23:37:07.305Z",
4
+ "packageVersion": "3.0.5",
5
+ "generatedAt": "2026-06-24T07:18:01.854Z",
6
6
  "slugs": {
7
7
  "components": [
8
8
  "button",
@@ -73,7 +73,7 @@
73
73
  ]
74
74
  },
75
75
  "pages": {
76
- "button": "<script lang=\"ts\">\n import { Button, Icon } from '$lib/index.js'\n\n const variants = ['solid', 'outline', 'soft', 'subtle', 'ghost', 'link'] as const\n const colors = [\n 'primary',\n 'secondary',\n 'tertiary',\n 'success',\n 'warning',\n 'error',\n 'info',\n 'surface'\n ] as const\n const sizes = ['xs', 'sm', 'md', 'lg', 'xl'] as const\n</script>\n\n<div class=\"space-y-8\">\n <div class=\"space-y-2\">\n <h1 class=\"text-2xl font-bold\">Button</h1>\n <p class=\"text-on-surface-variant\">\n Use the Button component to trigger actions or navigate with\n <code class=\"rounded bg-surface-container-highest px-1\">href</code>. Supports multiple\n variants, colors, sizes, icons, avatars, and loading states.\n </p>\n </div>\n\n <!-- Usage -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Usage</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the <code class=\"rounded bg-surface-container-highest px-1\">label</code> prop or the default\n slot to set the button text.\n </p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n <Button label=\"Button\" />\n </div>\n </section>\n\n <!-- Variant -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Variant</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the <code class=\"rounded bg-surface-container-highest px-1\">variant</code> prop to\n change the visual style. Defaults to\n <code class=\"rounded bg-surface-container-highest px-1\">solid</code>.\n </p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n {#each variants as variant (variant)}\n <Button {variant} label={variant[0].toUpperCase() + variant.slice(1)} />\n {/each}\n </div>\n </section>\n\n <!-- Color -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Color</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the <code class=\"rounded bg-surface-container-highest px-1\">color</code> prop to\n change the color scheme. Defaults to\n <code class=\"rounded bg-surface-container-highest px-1\">primary</code>.\n </p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n {#each colors as color (color)}\n <Button {color} label={color[0].toUpperCase() + color.slice(1)} />\n {/each}\n </div>\n </section>\n\n <!-- Variant x Color Matrix -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Variant & Color Matrix</h2>\n <div class=\"overflow-x-auto\">\n <table class=\"w-full\">\n <thead>\n <tr class=\"border-b border-outline-variant\">\n <th class=\"px-2 py-3 text-left text-sm font-medium text-on-surface-variant\"\n >Variant</th\n >\n {#each colors as color (color)}\n <th\n class=\"px-2 py-3 text-center text-sm font-medium text-on-surface-variant capitalize\"\n >{color}</th\n >\n {/each}\n </tr>\n </thead>\n <tbody>\n {#each variants as variant (variant)}\n <tr class=\"border-b border-outline-variant/50\">\n <td\n class=\"px-2 py-3 text-sm font-medium text-on-surface-variant capitalize\"\n >{variant}</td\n >\n {#each colors as color (color)}\n <td class=\"px-2 py-3 text-center\">\n <Button {variant} {color} label=\"Button\" />\n </td>\n {/each}\n </tr>\n {/each}\n </tbody>\n </table>\n </div>\n </section>\n\n <!-- Size -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Size</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the <code class=\"rounded bg-surface-container-highest px-1\">size</code> prop to\n change the dimensions. Defaults to\n <code class=\"rounded bg-surface-container-highest px-1\">md</code>.\n </p>\n <div class=\"flex flex-wrap items-end gap-3 rounded-lg bg-surface-container-high p-4\">\n {#each sizes as size (size)}\n <Button {size} label={size.toUpperCase()} />\n {/each}\n </div>\n </section>\n\n <!-- Icon -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Icon</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the <code class=\"rounded bg-surface-container-highest px-1\">icon</code> prop to\n display an icon in the button. By default the icon is placed on the leading side. Use\n the\n <code class=\"rounded bg-surface-container-highest px-1\">trailing</code> prop to move it to\n the trailing side.\n </p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n <Button icon=\"lucide:rocket\" label=\"Launch\" />\n <Button icon=\"lucide:arrow-right\" trailing label=\"Next\" />\n </div>\n </section>\n\n <!-- Leading & Trailing Icon -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Leading & Trailing Icon</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use <code class=\"rounded bg-surface-container-highest px-1\">leadingIcon</code> and\n <code class=\"rounded bg-surface-container-highest px-1\">trailingIcon</code> to display icons\n on both sides simultaneously.\n </p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n <Button leadingIcon=\"lucide:plus\" label=\"Add Item\" />\n <Button\n variant=\"outline\"\n color=\"secondary\"\n trailingIcon=\"lucide:arrow-right\"\n label=\"Next\"\n />\n <Button\n variant=\"soft\"\n color=\"success\"\n leadingIcon=\"lucide:check\"\n trailingIcon=\"lucide:chevron-down\"\n label=\"Confirm\"\n />\n </div>\n </section>\n\n <!-- Square (Icon Only) -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Square</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the <code class=\"rounded bg-surface-container-highest px-1\">square</code> prop to\n force equal width and height — ideal for icon-only buttons. When only\n <code class=\"rounded bg-surface-container-highest px-1\">icon</code> is provided without\n <code class=\"rounded bg-surface-container-highest px-1\">label</code>, the button is\n automatically treated as icon-only.\n </p>\n <div class=\"flex flex-wrap items-end gap-3 rounded-lg bg-surface-container-high p-4\">\n {#each sizes as size (size)}\n <Button {size} icon=\"lucide:plus\" square />\n {/each}\n <span class=\"mx-2 text-on-surface-variant\">|</span>\n <Button variant=\"outline\" color=\"secondary\" icon=\"lucide:settings\" square />\n <Button variant=\"soft\" color=\"success\" icon=\"lucide:check\" square />\n <Button variant=\"subtle\" color=\"warning\" icon=\"lucide:alert-triangle\" square />\n <Button variant=\"ghost\" color=\"error\" icon=\"lucide:x\" square />\n </div>\n </section>\n\n <!-- Avatar -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Avatar</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the <code class=\"rounded bg-surface-container-highest px-1\">avatar</code> prop to\n display an avatar before the label. Takes precedence over\n <code class=\"rounded bg-surface-container-highest px-1\">leadingIcon</code>.\n </p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n <Button\n variant=\"soft\"\n avatar={{ src: 'https://i.pravatar.cc/150?img=1', alt: 'John' }}\n label=\"John Doe\"\n />\n <Button\n variant=\"outline\"\n color=\"secondary\"\n avatar={{ src: 'https://i.pravatar.cc/150?img=2', alt: 'Jane' }}\n label=\"Jane Smith\"\n />\n <Button variant=\"solid\" color=\"tertiary\" avatar={{ alt: 'New' }} label=\"New User\" />\n <Button\n variant=\"ghost\"\n color=\"secondary\"\n avatar={{ src: 'https://i.pravatar.cc/150?img=5', alt: 'User' }}\n label=\"Profile\"\n trailingIcon=\"lucide:chevron-down\"\n />\n </div>\n\n <p class=\"text-sm text-on-surface-variant\">\n The avatar size automatically adapts to the button size.\n </p>\n <div class=\"flex flex-wrap items-end gap-3 rounded-lg bg-surface-container-high p-4\">\n {#each sizes as size (size)}\n <Button\n variant=\"soft\"\n {size}\n avatar={{ src: 'https://i.pravatar.cc/150?img=3', alt: 'User' }}\n label={size.toUpperCase()}\n />\n {/each}\n </div>\n </section>\n\n <!-- Loading -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Loading</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the <code class=\"rounded bg-surface-container-highest px-1\">loading</code> prop to\n show a loading spinner and disable the button. The spinner replaces the leading icon by\n default. Use\n <code class=\"rounded bg-surface-container-highest px-1\">trailing</code> to place it on the\n trailing side.\n </p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n <Button loading label=\"Loading...\" />\n <Button variant=\"outline\" color=\"secondary\" loading label=\"Processing\" />\n <Button variant=\"soft\" color=\"success\" loading icon=\"lucide:loader-2\" square />\n <Button variant=\"solid\" color=\"info\" loading trailing label=\"Uploading\" />\n </div>\n </section>\n\n <!-- Loading Auto -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Loading Auto</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the <code class=\"rounded bg-surface-container-highest px-1\">loadingAuto</code> prop\n to automatically show loading state while the\n <code class=\"rounded bg-surface-container-highest px-1\">onclick</code> handler's Promise is\n pending. The button is disabled until the Promise resolves or rejects.\n </p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n <Button\n loadingAuto\n label=\"Save (2s)\"\n leadingIcon=\"lucide:save\"\n onclick={() => new Promise((r) => setTimeout(r, 2000))}\n />\n <Button\n variant=\"outline\"\n color=\"secondary\"\n loadingAuto\n label=\"Submit (3s)\"\n onclick={() => new Promise((r) => setTimeout(r, 3000))}\n />\n <Button\n variant=\"soft\"\n color=\"error\"\n loadingAuto\n label=\"Delete (1s)\"\n leadingIcon=\"lucide:trash-2\"\n onclick={() => new Promise((r) => setTimeout(r, 1000))}\n />\n </div>\n </section>\n\n <!-- Disabled -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Disabled</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the <code class=\"rounded bg-surface-container-highest px-1\">disabled</code> prop to disable\n the button and prevent interaction.\n </p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n {#each variants as variant (variant)}\n <Button {variant} disabled label=\"Disabled\" />\n {/each}\n </div>\n </section>\n\n <!-- Block -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Block</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the <code class=\"rounded bg-surface-container-highest px-1\">block</code> prop to stretch\n the button to fill the full width of its container.\n </p>\n <div class=\"space-y-2 rounded-lg bg-surface-container-high p-4\">\n <Button block label=\"Full Width Button\" />\n <Button\n variant=\"outline\"\n color=\"secondary\"\n block\n leadingIcon=\"lucide:mail\"\n trailingIcon=\"lucide:arrow-right\"\n label=\"Send Email\"\n />\n </div>\n </section>\n\n <!-- As Link -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">As Link</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the <code class=\"rounded bg-surface-container-highest px-1\">href</code> prop to\n render as an anchor element. External URLs are auto-detected with\n <code class=\"rounded bg-surface-container-highest px-1\">target=\"_blank\"</code> and\n <code class=\"rounded bg-surface-container-highest px-1\">rel=\"noopener noreferrer\"</code\n >. Use the\n <code class=\"rounded bg-surface-container-highest px-1\">external</code> prop to force this\n behavior on internal paths.\n </p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n <Button href=\"/link\" label=\"Internal Link\" />\n <Button\n variant=\"outline\"\n color=\"secondary\"\n href=\"https://svelte.dev\"\n label=\"External Link\"\n trailingIcon=\"lucide:external-link\"\n />\n <Button\n variant=\"soft\"\n color=\"info\"\n href=\"/button\"\n label=\"Current Page\"\n leadingIcon=\"lucide:link\"\n />\n <Button variant=\"ghost\" color=\"error\" href=\"/about\" disabled label=\"Disabled Link\" />\n </div>\n </section>\n\n <!-- Type -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Type</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the <code class=\"rounded bg-surface-container-highest px-1\">type</code> prop to set\n the button type attribute. Defaults to\n <code class=\"rounded bg-surface-container-highest px-1\">button</code>. Only applies when\n rendering as a &lt;button&gt; element (no\n <code class=\"rounded bg-surface-container-highest px-1\">href</code>).\n </p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n <Button label=\"Button (default)\" />\n <Button variant=\"outline\" color=\"success\" type=\"submit\" label=\"Submit\" />\n <Button variant=\"ghost\" color=\"secondary\" type=\"reset\" label=\"Reset\" />\n </div>\n </section>\n\n <!-- Active Color & Variant -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Active Color & Variant</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use\n <code class=\"rounded bg-surface-container-highest px-1\">activeColor</code> and\n <code class=\"rounded bg-surface-container-highest px-1\">activeVariant</code> to change\n the button appearance when\n <code class=\"rounded bg-surface-container-highest px-1\">active</code> is true. Falls\n back to the default\n <code class=\"rounded bg-surface-container-highest px-1\">color</code> and\n <code class=\"rounded bg-surface-container-highest px-1\">variant</code> when inactive.\n </p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n <Button\n variant=\"ghost\"\n color=\"secondary\"\n active\n activeColor=\"primary\"\n activeVariant=\"solid\"\n label=\"Dashboard\"\n leadingIcon=\"lucide:home\"\n />\n <Button\n variant=\"ghost\"\n color=\"secondary\"\n label=\"Settings\"\n leadingIcon=\"lucide:settings\"\n />\n <Button\n variant=\"ghost\"\n color=\"secondary\"\n active\n activeColor=\"error\"\n activeVariant=\"soft\"\n label=\"Alerts\"\n leadingIcon=\"lucide:bell\"\n />\n <Button variant=\"ghost\" color=\"secondary\" label=\"Profile\" leadingIcon=\"lucide:user\" />\n </div>\n </section>\n\n <!-- Children Slot -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Children</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the default slot to render custom content inside the button instead of the\n <code class=\"rounded bg-surface-container-highest px-1\">label</code> prop.\n </p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n <Button>\n <Icon name=\"lucide:sparkles\" size=\"16\" />\n <span>Custom Content</span>\n </Button>\n <Button variant=\"outline\" color=\"tertiary\">\n <span class=\"font-bold\">Bold</span>\n <span class=\"font-light\">& Light</span>\n </Button>\n </div>\n </section>\n\n <!-- Leading & Trailing Slots -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Leading & Trailing Slots</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use <code class=\"rounded bg-surface-container-highest px-1\">leadingSlot</code> and\n <code class=\"rounded bg-surface-container-highest px-1\">trailingSlot</code> for fully\n custom leading/trailing content. They take precedence over\n <code class=\"rounded bg-surface-container-highest px-1\">avatar</code> and icon props.\n </p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n {#snippet statusSlot()}\n <span class=\"relative flex size-2\">\n <span\n class=\"absolute inline-flex size-full animate-ping rounded-full bg-success opacity-75\"\n ></span>\n <span class=\"relative inline-flex size-2 rounded-full bg-success\"></span>\n </span>\n {/snippet}\n <Button variant=\"outline\" color=\"success\" leadingSlot={statusSlot} label=\"Online\" />\n\n {#snippet badgeSlot()}\n <span\n class=\"flex size-5 items-center justify-center rounded-full bg-error text-xs font-bold text-on-error\"\n >3</span\n >\n {/snippet}\n <Button\n variant=\"ghost\"\n color=\"secondary\"\n leadingIcon=\"lucide:bell\"\n trailingSlot={badgeSlot}\n label=\"Notifications\"\n />\n\n {#snippet kbdSlot()}\n <kbd\n class=\"rounded border border-outline-variant bg-surface-container px-1.5 py-0.5 font-mono text-xs text-on-surface-variant\"\n >&#8984;K</kbd\n >\n {/snippet}\n <Button\n variant=\"outline\"\n color=\"secondary\"\n leadingIcon=\"lucide:search\"\n trailingSlot={kbdSlot}\n label=\"Search\"\n />\n </div>\n </section>\n\n <!-- UI -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">UI</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the <code class=\"rounded bg-surface-container-highest px-1\">ui</code> prop to\n override classes for specific slots:\n <code class=\"rounded bg-surface-container-highest px-1\">base</code>,\n <code class=\"rounded bg-surface-container-highest px-1\">label</code>,\n <code class=\"rounded bg-surface-container-highest px-1\">leadingIcon</code>,\n <code class=\"rounded bg-surface-container-highest px-1\">trailingIcon</code>,\n <code class=\"rounded bg-surface-container-highest px-1\">leadingAvatar</code>.\n </p>\n\n <p class=\"text-xs font-medium text-on-surface-variant uppercase\">Base slot</p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n <Button label=\"Pill Button\" class=\"rounded-full\" />\n <Button\n color=\"tertiary\"\n label=\"With Shadow\"\n ui={{ base: 'shadow-lg shadow-tertiary/30' }}\n />\n <Button\n label=\"Gradient\"\n ui={{\n base: 'bg-linear-to-r from-primary to-tertiary hover:from-primary/90 hover:to-tertiary/90'\n }}\n />\n <Button\n variant=\"outline\"\n color=\"warning\"\n label=\"Dashed Border\"\n ui={{ base: 'border-2 border-dashed ring-0' }}\n />\n </div>\n\n <p class=\"text-xs font-medium text-on-surface-variant uppercase\">Label slot</p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n <Button label=\"Uppercase\" ui={{ label: 'uppercase tracking-wider' }} />\n <Button\n variant=\"outline\"\n color=\"secondary\"\n label=\"Italic Text\"\n ui={{ label: 'italic' }}\n />\n <Button variant=\"soft\" color=\"success\" label=\"monospace\" ui={{ label: 'font-mono' }} />\n <Button\n variant=\"ghost\"\n label=\"Gradient Text\"\n ui={{\n label: 'bg-linear-to-r from-primary to-tertiary bg-clip-text text-transparent'\n }}\n />\n </div>\n\n <p class=\"text-xs font-medium text-on-surface-variant uppercase\">Icon slots</p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n <Button\n variant=\"outline\"\n color=\"secondary\"\n leadingIcon=\"lucide:settings\"\n label=\"Hover Rotate\"\n ui={{ leadingIcon: 'transition-transform duration-300 group-hover:rotate-90' }}\n class=\"group\"\n />\n <Button\n variant=\"soft\"\n color=\"success\"\n leadingIcon=\"lucide:bell\"\n label=\"Bouncing\"\n ui={{ leadingIcon: 'animate-bounce' }}\n />\n <Button\n variant=\"outline\"\n color=\"secondary\"\n leadingIcon=\"lucide:heart\"\n label=\"Colored Icon\"\n ui={{ leadingIcon: 'text-error' }}\n />\n <Button\n variant=\"solid\"\n color=\"info\"\n trailingIcon=\"lucide:arrow-right\"\n label=\"Hover Slide\"\n ui={{ trailingIcon: 'transition-transform duration-200 group-hover:translate-x-1' }}\n class=\"group\"\n />\n </div>\n </section>\n\n <!-- Examples -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Examples</h2>\n\n <!-- Action Bar -->\n <div class=\"space-y-2 rounded-lg bg-surface-container-high p-4\">\n <p class=\"text-xs font-medium text-on-surface-variant uppercase\">Action bar</p>\n <div class=\"flex items-center gap-2\">\n <Button leadingIcon=\"lucide:save\" label=\"Save\" />\n <Button variant=\"outline\" color=\"secondary\" label=\"Cancel\" />\n <div class=\"flex-1\"></div>\n <Button variant=\"ghost\" color=\"error\" leadingIcon=\"lucide:trash-2\" label=\"Delete\" />\n </div>\n </div>\n\n <!-- Navigation -->\n <div class=\"space-y-2 rounded-lg bg-surface-container-high p-4\">\n <p class=\"text-xs font-medium text-on-surface-variant uppercase\">Navigation</p>\n <div class=\"flex items-center gap-1\">\n <Button\n variant=\"ghost\"\n color=\"secondary\"\n active\n activeColor=\"primary\"\n activeVariant=\"soft\"\n href=\"/button\"\n label=\"Dashboard\"\n leadingIcon=\"lucide:home\"\n />\n <Button\n variant=\"ghost\"\n color=\"secondary\"\n href=\"/link\"\n label=\"Links\"\n leadingIcon=\"lucide:link\"\n />\n <Button\n variant=\"ghost\"\n color=\"secondary\"\n href=\"/settings\"\n label=\"Settings\"\n leadingIcon=\"lucide:settings\"\n />\n </div>\n </div>\n\n <!-- Social Buttons -->\n <div class=\"space-y-2 rounded-lg bg-surface-container-high p-4\">\n <p class=\"text-xs font-medium text-on-surface-variant uppercase\">Social buttons</p>\n <div class=\"flex items-center gap-2\">\n <Button variant=\"soft\" color=\"info\" leadingIcon=\"mdi:twitter\" label=\"Tweet\" />\n <Button variant=\"soft\" leadingIcon=\"mdi:facebook\" label=\"Share\" />\n <Button variant=\"soft\" color=\"tertiary\" leadingIcon=\"mdi:linkedin\" label=\"Post\" />\n </div>\n </div>\n\n <!-- Pagination -->\n <div class=\"space-y-2 rounded-lg bg-surface-container-high p-4\">\n <p class=\"text-xs font-medium text-on-surface-variant uppercase\">Pagination</p>\n <div class=\"flex items-center gap-1\">\n <Button variant=\"ghost\" color=\"secondary\" icon=\"lucide:chevron-left\" square />\n <Button variant=\"ghost\" color=\"secondary\" label=\"1\" />\n <Button variant=\"solid\" label=\"2\" />\n <Button variant=\"ghost\" color=\"secondary\" label=\"3\" />\n <Button variant=\"ghost\" color=\"secondary\" label=\"...\" />\n <Button variant=\"ghost\" color=\"secondary\" label=\"10\" />\n <Button variant=\"ghost\" color=\"secondary\" icon=\"lucide:chevron-right\" square />\n </div>\n </div>\n </section>\n</div>\n",
76
+ "button": "<script lang=\"ts\">\n import { Button, Icon } from '$lib/index.js'\n\n const variants = ['solid', 'outline', 'soft', 'subtle', 'ghost', 'link'] as const\n const colors = [\n 'primary',\n 'secondary',\n 'tertiary',\n 'success',\n 'warning',\n 'error',\n 'info',\n 'surface'\n ] as const\n const sizes = ['xs', 'sm', 'md', 'lg', 'xl'] as const\n</script>\n\n<div class=\"space-y-8\">\n <div class=\"space-y-2\">\n <h1 class=\"text-2xl font-bold\">Button</h1>\n <p class=\"text-on-surface-variant\">\n Use the Button component to trigger actions or navigate with\n <code class=\"rounded bg-surface-container-highest px-1\">href</code>. Supports multiple\n variants, colors, sizes, icons, avatars, and loading states.\n </p>\n <div\n class=\"rounded-lg border border-outline-variant bg-surface-container-high px-4 py-3 text-sm text-on-surface-variant\"\n >\n <strong class=\"text-on-surface\">Mode guide:</strong>\n omit <code class=\"rounded bg-surface-container-highest px-1\">href</code> for a native\n <code class=\"rounded bg-surface-container-highest px-1\">&lt;button&gt;</code> with form\n attributes like\n <code class=\"rounded bg-surface-container-highest px-1\">type</code>,\n <code class=\"rounded bg-surface-container-highest px-1\">formaction</code>, and\n <code class=\"rounded bg-surface-container-highest px-1\">formmethod</code>. Add\n <code class=\"rounded bg-surface-container-highest px-1\">href</code> to render an anchor\n for navigation instead.\n </div>\n </div>\n\n <!-- Usage -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Usage</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the <code class=\"rounded bg-surface-container-highest px-1\">label</code> prop or the default\n slot to set the button text.\n </p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n <Button label=\"Button\" />\n </div>\n </section>\n\n <!-- Variant -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Variant</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the <code class=\"rounded bg-surface-container-highest px-1\">variant</code> prop to\n change the visual style. Defaults to\n <code class=\"rounded bg-surface-container-highest px-1\">solid</code>.\n </p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n {#each variants as variant (variant)}\n <Button {variant} label={variant[0].toUpperCase() + variant.slice(1)} />\n {/each}\n </div>\n </section>\n\n <!-- Color -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Color</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the <code class=\"rounded bg-surface-container-highest px-1\">color</code> prop to\n change the color scheme. Defaults to\n <code class=\"rounded bg-surface-container-highest px-1\">primary</code>.\n </p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n {#each colors as color (color)}\n <Button {color} label={color[0].toUpperCase() + color.slice(1)} />\n {/each}\n </div>\n </section>\n\n <!-- Variant x Color Matrix -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Variant & Color Matrix</h2>\n <div class=\"overflow-x-auto\">\n <table class=\"w-full\">\n <thead>\n <tr class=\"border-b border-outline-variant\">\n <th class=\"px-2 py-3 text-left text-sm font-medium text-on-surface-variant\"\n >Variant</th\n >\n {#each colors as color (color)}\n <th\n class=\"px-2 py-3 text-center text-sm font-medium text-on-surface-variant capitalize\"\n >{color}</th\n >\n {/each}\n </tr>\n </thead>\n <tbody>\n {#each variants as variant (variant)}\n <tr class=\"border-b border-outline-variant/50\">\n <td\n class=\"px-2 py-3 text-sm font-medium text-on-surface-variant capitalize\"\n >{variant}</td\n >\n {#each colors as color (color)}\n <td class=\"px-2 py-3 text-center\">\n <Button {variant} {color} label=\"Button\" />\n </td>\n {/each}\n </tr>\n {/each}\n </tbody>\n </table>\n </div>\n </section>\n\n <!-- Size -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Size</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the <code class=\"rounded bg-surface-container-highest px-1\">size</code> prop to\n change the dimensions. Defaults to\n <code class=\"rounded bg-surface-container-highest px-1\">md</code>.\n </p>\n <div class=\"flex flex-wrap items-end gap-3 rounded-lg bg-surface-container-high p-4\">\n {#each sizes as size (size)}\n <Button {size} label={size.toUpperCase()} />\n {/each}\n </div>\n </section>\n\n <!-- Icon -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Icon</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the <code class=\"rounded bg-surface-container-highest px-1\">icon</code> prop to\n display an icon in the button. By default the icon is placed on the leading side. Use\n the\n <code class=\"rounded bg-surface-container-highest px-1\">trailing</code> prop to move it to\n the trailing side.\n </p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n <Button icon=\"lucide:rocket\" label=\"Launch\" />\n <Button icon=\"lucide:arrow-right\" trailing label=\"Next\" />\n </div>\n </section>\n\n <!-- Leading & Trailing Icon -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Leading & Trailing Icon</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use <code class=\"rounded bg-surface-container-highest px-1\">leadingIcon</code> and\n <code class=\"rounded bg-surface-container-highest px-1\">trailingIcon</code> to display icons\n on both sides simultaneously.\n </p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n <Button leadingIcon=\"lucide:plus\" label=\"Add Item\" />\n <Button\n variant=\"outline\"\n color=\"secondary\"\n trailingIcon=\"lucide:arrow-right\"\n label=\"Next\"\n />\n <Button\n variant=\"soft\"\n color=\"success\"\n leadingIcon=\"lucide:check\"\n trailingIcon=\"lucide:chevron-down\"\n label=\"Confirm\"\n />\n </div>\n </section>\n\n <!-- Square (Icon Only) -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Square</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the <code class=\"rounded bg-surface-container-highest px-1\">square</code> prop to\n force equal width and height — ideal for icon-only buttons. When only\n <code class=\"rounded bg-surface-container-highest px-1\">icon</code> is provided without\n <code class=\"rounded bg-surface-container-highest px-1\">label</code>, the button is\n automatically treated as icon-only.\n </p>\n <div class=\"flex flex-wrap items-end gap-3 rounded-lg bg-surface-container-high p-4\">\n {#each sizes as size (size)}\n <Button {size} icon=\"lucide:plus\" square />\n {/each}\n <span class=\"mx-2 text-on-surface-variant\">|</span>\n <Button variant=\"outline\" color=\"secondary\" icon=\"lucide:settings\" square />\n <Button variant=\"soft\" color=\"success\" icon=\"lucide:check\" square />\n <Button variant=\"subtle\" color=\"warning\" icon=\"lucide:alert-triangle\" square />\n <Button variant=\"ghost\" color=\"error\" icon=\"lucide:x\" square />\n </div>\n </section>\n\n <!-- Avatar -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Avatar</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the <code class=\"rounded bg-surface-container-highest px-1\">avatar</code> prop to\n display an avatar before the label. Takes precedence over\n <code class=\"rounded bg-surface-container-highest px-1\">leadingIcon</code>.\n </p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n <Button\n variant=\"soft\"\n avatar={{ src: 'https://i.pravatar.cc/150?img=1', alt: 'John' }}\n label=\"John Doe\"\n />\n <Button\n variant=\"outline\"\n color=\"secondary\"\n avatar={{ src: 'https://i.pravatar.cc/150?img=2', alt: 'Jane' }}\n label=\"Jane Smith\"\n />\n <Button variant=\"solid\" color=\"tertiary\" avatar={{ alt: 'New' }} label=\"New User\" />\n <Button\n variant=\"ghost\"\n color=\"secondary\"\n avatar={{ src: 'https://i.pravatar.cc/150?img=5', alt: 'User' }}\n label=\"Profile\"\n trailingIcon=\"lucide:chevron-down\"\n />\n </div>\n\n <p class=\"text-sm text-on-surface-variant\">\n The avatar size automatically adapts to the button size.\n </p>\n <div class=\"flex flex-wrap items-end gap-3 rounded-lg bg-surface-container-high p-4\">\n {#each sizes as size (size)}\n <Button\n variant=\"soft\"\n {size}\n avatar={{ src: 'https://i.pravatar.cc/150?img=3', alt: 'User' }}\n label={size.toUpperCase()}\n />\n {/each}\n </div>\n </section>\n\n <!-- Loading -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Loading</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the <code class=\"rounded bg-surface-container-highest px-1\">loading</code> prop to\n show a loading spinner and disable the button. The spinner replaces the leading icon by\n default. Use\n <code class=\"rounded bg-surface-container-highest px-1\">trailing</code> to place it on the\n trailing side.\n </p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n <Button loading label=\"Loading...\" />\n <Button variant=\"outline\" color=\"secondary\" loading label=\"Processing\" />\n <Button variant=\"soft\" color=\"success\" loading icon=\"lucide:loader-2\" square />\n <Button variant=\"solid\" color=\"info\" loading trailing label=\"Uploading\" />\n </div>\n </section>\n\n <!-- Loading Auto -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Loading Auto</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the <code class=\"rounded bg-surface-container-highest px-1\">loadingAuto</code> prop\n to automatically show loading state while the\n <code class=\"rounded bg-surface-container-highest px-1\">onclick</code> handler's Promise is\n pending. The button is disabled until the Promise resolves or rejects.\n </p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n <Button\n loadingAuto\n label=\"Save (2s)\"\n leadingIcon=\"lucide:save\"\n onclick={() => new Promise((r) => setTimeout(r, 2000))}\n />\n <Button\n variant=\"outline\"\n color=\"secondary\"\n loadingAuto\n label=\"Submit (3s)\"\n onclick={() => new Promise((r) => setTimeout(r, 3000))}\n />\n <Button\n variant=\"soft\"\n color=\"error\"\n loadingAuto\n label=\"Delete (1s)\"\n leadingIcon=\"lucide:trash-2\"\n onclick={() => new Promise((r) => setTimeout(r, 1000))}\n />\n </div>\n </section>\n\n <!-- Disabled -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Disabled</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the <code class=\"rounded bg-surface-container-highest px-1\">disabled</code> prop to disable\n the button and prevent interaction.\n </p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n {#each variants as variant (variant)}\n <Button {variant} disabled label=\"Disabled\" />\n {/each}\n </div>\n </section>\n\n <!-- Block -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Block</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the <code class=\"rounded bg-surface-container-highest px-1\">block</code> prop to stretch\n the button to fill the full width of its container.\n </p>\n <div class=\"space-y-2 rounded-lg bg-surface-container-high p-4\">\n <Button block label=\"Full Width Button\" />\n <Button\n variant=\"outline\"\n color=\"secondary\"\n block\n leadingIcon=\"lucide:mail\"\n trailingIcon=\"lucide:arrow-right\"\n label=\"Send Email\"\n />\n </div>\n </section>\n\n <!-- As Link -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">As Link</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the <code class=\"rounded bg-surface-container-highest px-1\">href</code> prop to\n render as an anchor element. External URLs are auto-detected with\n <code class=\"rounded bg-surface-container-highest px-1\">target=\"_blank\"</code> and\n <code class=\"rounded bg-surface-container-highest px-1\">rel=\"noopener noreferrer\"</code\n >. Use the\n <code class=\"rounded bg-surface-container-highest px-1\">external</code> prop to force this\n behavior on internal paths.\n </p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n <Button href=\"/link\" label=\"Internal Link\" />\n <Button\n variant=\"outline\"\n color=\"secondary\"\n href=\"https://svelte.dev\"\n label=\"External Link\"\n trailingIcon=\"lucide:external-link\"\n />\n <Button\n variant=\"soft\"\n color=\"info\"\n href=\"/button\"\n label=\"Current Page\"\n leadingIcon=\"lucide:link\"\n />\n <Button variant=\"ghost\" color=\"error\" href=\"/about\" disabled label=\"Disabled Link\" />\n </div>\n </section>\n\n <!-- Type -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Type</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the <code class=\"rounded bg-surface-container-highest px-1\">type</code> prop to set\n the button type attribute. Defaults to\n <code class=\"rounded bg-surface-container-highest px-1\">button</code>. Only applies when\n rendering as a &lt;button&gt; element (no\n <code class=\"rounded bg-surface-container-highest px-1\">href</code>).\n </p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n <Button label=\"Button (default)\" />\n <Button variant=\"outline\" color=\"success\" type=\"submit\" label=\"Submit\" />\n <Button variant=\"ghost\" color=\"secondary\" type=\"reset\" label=\"Reset\" />\n </div>\n </section>\n\n <!-- Native Form -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Native Form Submit</h2>\n <p class=\"text-sm text-on-surface-variant\">\n When <code class=\"rounded bg-surface-container-highest px-1\">href</code> is omitted,\n <code class=\"rounded bg-surface-container-highest px-1\">Button</code> renders a native\n <code class=\"rounded bg-surface-container-highest px-1\">&lt;button&gt;</code> element. This\n means browser form semantics such as\n <code class=\"rounded bg-surface-container-highest px-1\">type</code>,\n <code class=\"rounded bg-surface-container-highest px-1\">formaction</code>, and\n <code class=\"rounded bg-surface-container-highest px-1\">formmethod</code> work as expected.\n </p>\n <form class=\"space-y-3 rounded-lg bg-surface-container-high p-4\" onsubmit={(event) => event.preventDefault()}>\n <div class=\"grid gap-3 sm:grid-cols-2\">\n <label class=\"grid gap-1 text-sm\">\n <span class=\"text-on-surface-variant\">Phone</span>\n <input\n class=\"rounded-lg border border-outline-variant bg-surface px-3 py-2\"\n placeholder=\"081-234-5678\"\n />\n </label>\n <label class=\"grid gap-1 text-sm\">\n <span class=\"text-on-surface-variant\">Code</span>\n <input\n class=\"rounded-lg border border-outline-variant bg-surface px-3 py-2\"\n placeholder=\"123456\"\n />\n </label>\n </div>\n <div class=\"flex flex-wrap gap-3\">\n <Button\n type=\"submit\"\n formaction=\"?/sendOtp\"\n formmethod=\"post\"\n variant=\"outline\"\n color=\"secondary\"\n label=\"Send Code\"\n />\n <Button\n type=\"submit\"\n formaction=\"?/login\"\n formmethod=\"post\"\n label=\"Sign In\"\n />\n </div>\n </form>\n </section>\n\n <!-- Mode Notes -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Mode Notes</h2>\n <div class=\"overflow-x-auto rounded-lg bg-surface-container-high p-4\">\n <table class=\"w-full text-sm\">\n <thead>\n <tr class=\"border-b border-outline-variant text-left text-on-surface-variant\">\n <th class=\"px-2 py-2 font-medium\">Mode</th>\n <th class=\"px-2 py-2 font-medium\">Rendered element</th>\n <th class=\"px-2 py-2 font-medium\">Use for</th>\n <th class=\"px-2 py-2 font-medium\">Important props</th>\n </tr>\n </thead>\n <tbody>\n <tr class=\"border-b border-outline-variant/50 align-top\">\n <td class=\"px-2 py-3 font-medium text-on-surface\">Button mode</td>\n <td class=\"px-2 py-3\">\n <code class=\"rounded bg-surface-container-highest px-1\"\n >&lt;button&gt;</code\n >\n </td>\n <td class=\"px-2 py-3\">Actions, submit, reset, and native form behavior</td>\n <td class=\"px-2 py-3\">\n <code class=\"rounded bg-surface-container-highest px-1\">type</code>,\n <code class=\"rounded bg-surface-container-highest px-1\">name</code>,\n <code class=\"rounded bg-surface-container-highest px-1\">value</code>,\n <code class=\"rounded bg-surface-container-highest px-1\">formaction</code>,\n <code class=\"rounded bg-surface-container-highest px-1\">formmethod</code>\n </td>\n </tr>\n <tr class=\"align-top\">\n <td class=\"px-2 py-3 font-medium text-on-surface\">Link mode</td>\n <td class=\"px-2 py-3\">\n <code class=\"rounded bg-surface-container-highest px-1\">&lt;a&gt;</code>\n </td>\n <td class=\"px-2 py-3\">Navigation to internal or external destinations</td>\n <td class=\"px-2 py-3\">\n <code class=\"rounded bg-surface-container-highest px-1\">href</code>,\n <code class=\"rounded bg-surface-container-highest px-1\">target</code>,\n <code class=\"rounded bg-surface-container-highest px-1\">rel</code>,\n <code class=\"rounded bg-surface-container-highest px-1\">download</code>\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </section>\n\n <!-- Active Color & Variant -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Active Color & Variant</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use\n <code class=\"rounded bg-surface-container-highest px-1\">activeColor</code> and\n <code class=\"rounded bg-surface-container-highest px-1\">activeVariant</code> to change\n the button appearance when\n <code class=\"rounded bg-surface-container-highest px-1\">active</code> is true. Falls\n back to the default\n <code class=\"rounded bg-surface-container-highest px-1\">color</code> and\n <code class=\"rounded bg-surface-container-highest px-1\">variant</code> when inactive.\n </p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n <Button\n variant=\"ghost\"\n color=\"secondary\"\n active\n activeColor=\"primary\"\n activeVariant=\"solid\"\n label=\"Dashboard\"\n leadingIcon=\"lucide:home\"\n />\n <Button\n variant=\"ghost\"\n color=\"secondary\"\n label=\"Settings\"\n leadingIcon=\"lucide:settings\"\n />\n <Button\n variant=\"ghost\"\n color=\"secondary\"\n active\n activeColor=\"error\"\n activeVariant=\"soft\"\n label=\"Alerts\"\n leadingIcon=\"lucide:bell\"\n />\n <Button variant=\"ghost\" color=\"secondary\" label=\"Profile\" leadingIcon=\"lucide:user\" />\n </div>\n </section>\n\n <!-- Children Slot -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Children</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the default slot to render custom content inside the button instead of the\n <code class=\"rounded bg-surface-container-highest px-1\">label</code> prop.\n </p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n <Button>\n <Icon name=\"lucide:sparkles\" size=\"16\" />\n <span>Custom Content</span>\n </Button>\n <Button variant=\"outline\" color=\"tertiary\">\n <span class=\"font-bold\">Bold</span>\n <span class=\"font-light\">& Light</span>\n </Button>\n </div>\n </section>\n\n <!-- Leading & Trailing Slots -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Leading & Trailing Slots</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use <code class=\"rounded bg-surface-container-highest px-1\">leadingSlot</code> and\n <code class=\"rounded bg-surface-container-highest px-1\">trailingSlot</code> for fully\n custom leading/trailing content. They take precedence over\n <code class=\"rounded bg-surface-container-highest px-1\">avatar</code> and icon props.\n </p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n {#snippet statusSlot()}\n <span class=\"relative flex size-2\">\n <span\n class=\"absolute inline-flex size-full animate-ping rounded-full bg-success opacity-75\"\n ></span>\n <span class=\"relative inline-flex size-2 rounded-full bg-success\"></span>\n </span>\n {/snippet}\n <Button variant=\"outline\" color=\"success\" leadingSlot={statusSlot} label=\"Online\" />\n\n {#snippet badgeSlot()}\n <span\n class=\"flex size-5 items-center justify-center rounded-full bg-error text-xs font-bold text-on-error\"\n >3</span\n >\n {/snippet}\n <Button\n variant=\"ghost\"\n color=\"secondary\"\n leadingIcon=\"lucide:bell\"\n trailingSlot={badgeSlot}\n label=\"Notifications\"\n />\n\n {#snippet kbdSlot()}\n <kbd\n class=\"rounded border border-outline-variant bg-surface-container px-1.5 py-0.5 font-mono text-xs text-on-surface-variant\"\n >&#8984;K</kbd\n >\n {/snippet}\n <Button\n variant=\"outline\"\n color=\"secondary\"\n leadingIcon=\"lucide:search\"\n trailingSlot={kbdSlot}\n label=\"Search\"\n />\n </div>\n </section>\n\n <!-- UI -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">UI</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use the <code class=\"rounded bg-surface-container-highest px-1\">ui</code> prop to\n override classes for specific slots:\n <code class=\"rounded bg-surface-container-highest px-1\">base</code>,\n <code class=\"rounded bg-surface-container-highest px-1\">label</code>,\n <code class=\"rounded bg-surface-container-highest px-1\">leadingIcon</code>,\n <code class=\"rounded bg-surface-container-highest px-1\">trailingIcon</code>,\n <code class=\"rounded bg-surface-container-highest px-1\">leadingAvatar</code>.\n </p>\n\n <p class=\"text-xs font-medium text-on-surface-variant uppercase\">Base slot</p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n <Button label=\"Pill Button\" class=\"rounded-full\" />\n <Button\n color=\"tertiary\"\n label=\"With Shadow\"\n ui={{ base: 'shadow-lg shadow-tertiary/30' }}\n />\n <Button\n label=\"Gradient\"\n ui={{\n base: 'bg-linear-to-r from-primary to-tertiary hover:from-primary/90 hover:to-tertiary/90'\n }}\n />\n <Button\n variant=\"outline\"\n color=\"warning\"\n label=\"Dashed Border\"\n ui={{ base: 'border-2 border-dashed ring-0' }}\n />\n </div>\n\n <p class=\"text-xs font-medium text-on-surface-variant uppercase\">Label slot</p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n <Button label=\"Uppercase\" ui={{ label: 'uppercase tracking-wider' }} />\n <Button\n variant=\"outline\"\n color=\"secondary\"\n label=\"Italic Text\"\n ui={{ label: 'italic' }}\n />\n <Button variant=\"soft\" color=\"success\" label=\"monospace\" ui={{ label: 'font-mono' }} />\n <Button\n variant=\"ghost\"\n label=\"Gradient Text\"\n ui={{\n label: 'bg-linear-to-r from-primary to-tertiary bg-clip-text text-transparent'\n }}\n />\n </div>\n\n <p class=\"text-xs font-medium text-on-surface-variant uppercase\">Icon slots</p>\n <div class=\"flex flex-wrap items-center gap-3 rounded-lg bg-surface-container-high p-4\">\n <Button\n variant=\"outline\"\n color=\"secondary\"\n leadingIcon=\"lucide:settings\"\n label=\"Hover Rotate\"\n ui={{ leadingIcon: 'transition-transform duration-300 group-hover:rotate-90' }}\n class=\"group\"\n />\n <Button\n variant=\"soft\"\n color=\"success\"\n leadingIcon=\"lucide:bell\"\n label=\"Bouncing\"\n ui={{ leadingIcon: 'animate-bounce' }}\n />\n <Button\n variant=\"outline\"\n color=\"secondary\"\n leadingIcon=\"lucide:heart\"\n label=\"Colored Icon\"\n ui={{ leadingIcon: 'text-error' }}\n />\n <Button\n variant=\"solid\"\n color=\"info\"\n trailingIcon=\"lucide:arrow-right\"\n label=\"Hover Slide\"\n ui={{ trailingIcon: 'transition-transform duration-200 group-hover:translate-x-1' }}\n class=\"group\"\n />\n </div>\n </section>\n\n <!-- Examples -->\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Examples</h2>\n\n <!-- Action Bar -->\n <div class=\"space-y-2 rounded-lg bg-surface-container-high p-4\">\n <p class=\"text-xs font-medium text-on-surface-variant uppercase\">Action bar</p>\n <div class=\"flex items-center gap-2\">\n <Button leadingIcon=\"lucide:save\" label=\"Save\" />\n <Button variant=\"outline\" color=\"secondary\" label=\"Cancel\" />\n <div class=\"flex-1\"></div>\n <Button variant=\"ghost\" color=\"error\" leadingIcon=\"lucide:trash-2\" label=\"Delete\" />\n </div>\n </div>\n\n <!-- Navigation -->\n <div class=\"space-y-2 rounded-lg bg-surface-container-high p-4\">\n <p class=\"text-xs font-medium text-on-surface-variant uppercase\">Navigation</p>\n <div class=\"flex items-center gap-1\">\n <Button\n variant=\"ghost\"\n color=\"secondary\"\n active\n activeColor=\"primary\"\n activeVariant=\"soft\"\n href=\"/button\"\n label=\"Dashboard\"\n leadingIcon=\"lucide:home\"\n />\n <Button\n variant=\"ghost\"\n color=\"secondary\"\n href=\"/link\"\n label=\"Links\"\n leadingIcon=\"lucide:link\"\n />\n <Button\n variant=\"ghost\"\n color=\"secondary\"\n href=\"/settings\"\n label=\"Settings\"\n leadingIcon=\"lucide:settings\"\n />\n </div>\n </div>\n\n <!-- Social Buttons -->\n <div class=\"space-y-2 rounded-lg bg-surface-container-high p-4\">\n <p class=\"text-xs font-medium text-on-surface-variant uppercase\">Social buttons</p>\n <div class=\"flex items-center gap-2\">\n <Button variant=\"soft\" color=\"info\" leadingIcon=\"mdi:twitter\" label=\"Tweet\" />\n <Button variant=\"soft\" leadingIcon=\"mdi:facebook\" label=\"Share\" />\n <Button variant=\"soft\" color=\"tertiary\" leadingIcon=\"mdi:linkedin\" label=\"Post\" />\n </div>\n </div>\n\n <!-- Pagination -->\n <div class=\"space-y-2 rounded-lg bg-surface-container-high p-4\">\n <p class=\"text-xs font-medium text-on-surface-variant uppercase\">Pagination</p>\n <div class=\"flex items-center gap-1\">\n <Button variant=\"ghost\" color=\"secondary\" icon=\"lucide:chevron-left\" square />\n <Button variant=\"ghost\" color=\"secondary\" label=\"1\" />\n <Button variant=\"solid\" label=\"2\" />\n <Button variant=\"ghost\" color=\"secondary\" label=\"3\" />\n <Button variant=\"ghost\" color=\"secondary\" label=\"...\" />\n <Button variant=\"ghost\" color=\"secondary\" label=\"10\" />\n <Button variant=\"ghost\" color=\"secondary\" icon=\"lucide:chevron-right\" square />\n </div>\n </div>\n </section>\n</div>\n",
77
77
  "code-block": "<script lang=\"ts\">\n import { CodeBlock } from '$lib/index.js'\n import { renderHighlightedCode } from '$lib/docs/code-block.js'\n\n const sampleCode = `<script lang=\"ts\">\n import { Button } from 'svelora';\n<` + `/script>\n\n<Button label=\"Hello\" />`\n\n const sampleTs = `type User = { _id: string; name: string }\n\nconst user: User = { _id: 'u_1', name: 'Jane' }\nconsole.log(user)`\n\n let shikiHtml = $state('')\n let isDarkMode = $state(true)\n\n $effect(() => {\n if (typeof document === 'undefined') return\n\n const root = document.documentElement\n const updateMode = () => {\n isDarkMode = root.classList.contains('dark')\n }\n\n updateMode()\n\n const observer = new MutationObserver(() => {\n updateMode()\n })\n\n observer.observe(root, { attributes: true, attributeFilter: ['class'] })\n return () => observer.disconnect()\n })\n\n $effect(() => {\n const darkMode = isDarkMode\n let cancelled = false\n\n void renderHighlightedCode(sampleCode, darkMode).then((html) => {\n if (cancelled) return\n shikiHtml = html\n })\n\n return () => {\n cancelled = true\n }\n })\n</script>\n\n<div class=\"space-y-8\">\n <div class=\"space-y-2\">\n <h1 class=\"text-2xl font-bold\">CodeBlock</h1>\n <p class=\"text-on-surface-variant\">\n Display code snippets with a consistent header, copy button, and theme-aware styling.\n </p>\n </div>\n\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Basic</h2>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <CodeBlock title=\"Code\" code={sampleTs} />\n </div>\n </section>\n\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">With highlighted HTML</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Provide pre-highlighted HTML (for example, from Shiki) via the <code>html</code> prop.\n </p>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <CodeBlock code={sampleCode} html={shikiHtml} />\n </div>\n </section>\n\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Variants</h2>\n <div class=\"grid gap-3 md:grid-cols-2\">\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <CodeBlock title=\"outline\" variant=\"outline\" code={sampleTs} />\n </div>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <CodeBlock title=\"soft\" variant=\"soft\" code={sampleTs} />\n </div>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <CodeBlock title=\"subtle\" variant=\"subtle\" code={sampleTs} />\n </div>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <CodeBlock title=\"solid\" variant=\"solid\" code={sampleTs} />\n </div>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <CodeBlock title=\"ghost\" variant=\"ghost\" code={sampleTs} />\n </div>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <CodeBlock title=\"none\" variant=\"none\" code={sampleTs} />\n </div>\n </div>\n </section>\n\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Sizes</h2>\n <div class=\"grid gap-3 md:grid-cols-3\">\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <CodeBlock title=\"sm\" size=\"sm\" code={sampleTs} />\n </div>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <CodeBlock title=\"md\" size=\"md\" code={sampleTs} />\n </div>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <CodeBlock title=\"lg\" size=\"lg\" code={sampleTs} />\n </div>\n </div>\n </section>\n\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Copy controls</h2>\n <div class=\"grid gap-3 md:grid-cols-2\">\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <CodeBlock title=\"copyable=false\" code={sampleTs} copyable={false} />\n </div>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <CodeBlock title=\"custom copyText\" code=\"Visible code\" copyText=\"Copied text\" />\n </div>\n </div>\n </section>\n</div>\n\n",
78
78
  "field-group": "<script lang=\"ts\">\n import { Button, Input, FieldGroup, Separator } from '$lib/index.js'\n\n const sizes = ['xs', 'sm', 'md', 'lg', 'xl'] as const\n</script>\n\n<div class=\"space-y-8\">\n <h1 class=\"text-2xl font-bold text-on-surface\">FieldGroup</h1>\n\n <!-- Basic Usage -->\n <section class=\"space-y-4\">\n <h2 class=\"text-lg font-semibold text-on-surface\">Basic Usage</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Wrap multiple <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\"\n >Button</code\n >\n within a\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\"\n >FieldGroup</code\n > to group them together.\n </p>\n <FieldGroup>\n <Button label=\"Action\" />\n <Button label=\"Action\" />\n <Button label=\"Action\" />\n </FieldGroup>\n </section>\n\n <!-- Orientation -->\n <section class=\"space-y-4\">\n <h2 class=\"text-lg font-semibold text-on-surface\">Orientation</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\"\n >orientation</code\n > to change the layout direction.\n </p>\n <div class=\"flex flex-wrap items-start gap-6\">\n <div class=\"space-y-2\">\n <p class=\"text-xs text-on-surface-variant\">horizontal (default)</p>\n <FieldGroup orientation=\"horizontal\">\n <Button label=\"Left\" />\n <Button label=\"Center\" />\n <Button label=\"Right\" />\n </FieldGroup>\n </div>\n <div class=\"space-y-2\">\n <p class=\"text-xs text-on-surface-variant\">vertical</p>\n <FieldGroup orientation=\"vertical\">\n <Button label=\"Top\" />\n <Button label=\"Middle\" />\n <Button label=\"Bottom\" />\n </FieldGroup>\n </div>\n </div>\n </section>\n\n <!-- Size -->\n <section class=\"space-y-4\">\n <h2 class=\"text-lg font-semibold text-on-surface\">Size</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Use <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">size</code> to\n set the size of all child components.\n </p>\n <div class=\"flex flex-wrap items-end gap-6\">\n {#each sizes as size (size)}\n <div class=\"flex flex-col items-center gap-2\">\n <FieldGroup {size}>\n <Button label=\"Action\" />\n <Button label=\"Action\" />\n <Button label=\"Action\" />\n </FieldGroup>\n <span class=\"text-xs text-on-surface-variant\">{size}</span>\n </div>\n {/each}\n </div>\n </section>\n\n <!-- Variants -->\n <section class=\"space-y-4\">\n <h2 class=\"text-lg font-semibold text-on-surface\">With Variants</h2>\n <p class=\"text-sm text-on-surface-variant\">\n FieldGroup works with different button variants.\n </p>\n <div class=\"flex flex-wrap items-center gap-6\">\n <FieldGroup>\n <Button variant=\"outline\" color=\"surface\" label=\"Left\" />\n <Button variant=\"outline\" color=\"surface\" label=\"Center\" />\n <Button variant=\"outline\" color=\"surface\" label=\"Right\" />\n </FieldGroup>\n\n <FieldGroup>\n <Button variant=\"soft\" label=\"Left\" />\n <Button variant=\"soft\" label=\"Center\" />\n <Button variant=\"soft\" label=\"Right\" />\n </FieldGroup>\n\n <FieldGroup>\n <Button variant=\"subtle\" label=\"Left\" />\n <Button variant=\"subtle\" label=\"Center\" />\n <Button variant=\"subtle\" label=\"Right\" />\n </FieldGroup>\n </div>\n </section>\n\n <!-- With Icons -->\n <section class=\"space-y-4\">\n <h2 class=\"text-lg font-semibold text-on-surface\">With Icons</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Icon-only button groups for toolbar-style layouts.\n </p>\n <div class=\"flex flex-wrap items-center gap-6\">\n <FieldGroup>\n <Button icon=\"lucide:align-left\" variant=\"outline\" color=\"surface\" />\n <Button icon=\"lucide:align-center\" variant=\"outline\" color=\"surface\" />\n <Button icon=\"lucide:align-right\" variant=\"outline\" color=\"surface\" />\n <Button icon=\"lucide:align-justify\" variant=\"outline\" color=\"surface\" />\n </FieldGroup>\n\n <FieldGroup>\n <Button icon=\"lucide:bold\" variant=\"outline\" color=\"surface\" />\n <Button icon=\"lucide:italic\" variant=\"outline\" color=\"surface\" />\n <Button icon=\"lucide:underline\" variant=\"outline\" color=\"surface\" />\n <Button icon=\"lucide:strikethrough\" variant=\"outline\" color=\"surface\" />\n </FieldGroup>\n </div>\n </section>\n\n <!-- Vertical with Icons -->\n <section class=\"space-y-4\">\n <h2 class=\"text-lg font-semibold text-on-surface\">Vertical with Icons</h2>\n <div class=\"flex flex-wrap items-start gap-6\">\n <FieldGroup orientation=\"vertical\">\n <Button icon=\"lucide:zoom-in\" variant=\"outline\" color=\"surface\" />\n <Button icon=\"lucide:zoom-out\" variant=\"outline\" color=\"surface\" />\n <Button icon=\"lucide:rotate-cw\" variant=\"outline\" color=\"surface\" />\n </FieldGroup>\n\n <FieldGroup orientation=\"vertical\">\n <Button leadingIcon=\"lucide:home\" label=\"Home\" variant=\"soft\" />\n <Button leadingIcon=\"lucide:settings\" label=\"Settings\" variant=\"soft\" />\n <Button leadingIcon=\"lucide:user\" label=\"Profile\" variant=\"soft\" />\n </FieldGroup>\n </div>\n </section>\n\n <!-- With Input -->\n <section class=\"space-y-4\">\n <h2 class=\"text-lg font-semibold text-on-surface\">With Input</h2>\n <p class=\"text-sm text-on-surface-variant\">\n Combine <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\"\n >Input</code\n >\n and\n <code class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">Button</code> in\n a FieldGroup.\n </p>\n <div class=\"flex flex-wrap items-start gap-6\">\n <FieldGroup>\n <Input leadingIcon=\"lucide:search\" placeholder=\"Search...\" />\n <Button label=\"Search\" />\n </FieldGroup>\n\n <FieldGroup>\n <Input placeholder=\"Enter email\" type=\"email\" />\n <Button label=\"Subscribe\" variant=\"solid\" color=\"primary\" />\n </FieldGroup>\n </div>\n </section>\n\n <!-- With Input (Vertical) -->\n <section class=\"space-y-4\">\n <h2 class=\"text-lg font-semibold text-on-surface\">With Input (Vertical)</h2>\n <div class=\"flex flex-wrap items-start gap-6\">\n <div class=\"w-72\">\n <FieldGroup orientation=\"vertical\">\n <Input placeholder=\"First name\" />\n <Input placeholder=\"Last name\" />\n <Input placeholder=\"Email\" type=\"email\" />\n </FieldGroup>\n </div>\n\n <div class=\"w-72\">\n <FieldGroup orientation=\"vertical\">\n <Input leadingIcon=\"lucide:user\" placeholder=\"Username\" />\n <Input leadingIcon=\"lucide:lock\" placeholder=\"Password\" type=\"password\" />\n <Button label=\"Sign in\" block />\n </FieldGroup>\n </div>\n </div>\n </section>\n\n <!-- Input + Button Sizes -->\n <section class=\"space-y-4\">\n <h2 class=\"text-lg font-semibold text-on-surface\">Input + Button Sizes</h2>\n <p class=\"text-sm text-on-surface-variant\">\n FieldGroup propagates <code\n class=\"rounded bg-surface-container-highest px-1.5 py-0.5 text-xs\">size</code\n > to all children.\n </p>\n <div class=\"flex flex-wrap items-end gap-6\">\n {#each sizes as size (size)}\n <div class=\"flex flex-col items-center gap-2\">\n <FieldGroup {size}>\n <Input placeholder=\"Search...\" />\n <Button icon=\"lucide:search\" />\n </FieldGroup>\n <span class=\"text-xs text-on-surface-variant\">{size}</span>\n </div>\n {/each}\n </div>\n </section>\n\n <Separator />\n\n <!-- Real World Examples -->\n <section class=\"space-y-4\">\n <h2 class=\"text-lg font-semibold text-on-surface\">Real World Examples</h2>\n\n <div class=\"space-y-6\">\n <div>\n <p class=\"mb-2 text-xs text-on-surface-variant\">Text editor toolbar</p>\n <div class=\"flex flex-wrap items-center gap-3\">\n <FieldGroup>\n <Button icon=\"lucide:bold\" variant=\"outline\" color=\"surface\" size=\"sm\" />\n <Button icon=\"lucide:italic\" variant=\"outline\" color=\"surface\" size=\"sm\" />\n <Button\n icon=\"lucide:underline\"\n variant=\"outline\"\n color=\"surface\"\n size=\"sm\"\n />\n </FieldGroup>\n <FieldGroup>\n <Button\n icon=\"lucide:align-left\"\n variant=\"outline\"\n color=\"surface\"\n size=\"sm\"\n />\n <Button\n icon=\"lucide:align-center\"\n variant=\"outline\"\n color=\"surface\"\n size=\"sm\"\n />\n <Button\n icon=\"lucide:align-right\"\n variant=\"outline\"\n color=\"surface\"\n size=\"sm\"\n />\n </FieldGroup>\n <FieldGroup>\n <Button icon=\"lucide:list\" variant=\"outline\" color=\"surface\" size=\"sm\" />\n <Button\n icon=\"lucide:list-ordered\"\n variant=\"outline\"\n color=\"surface\"\n size=\"sm\"\n />\n </FieldGroup>\n </div>\n </div>\n\n <div>\n <p class=\"mb-2 text-xs text-on-surface-variant\">Login form</p>\n <div class=\"w-80\">\n <FieldGroup orientation=\"vertical\">\n <Input leadingIcon=\"lucide:mail\" placeholder=\"Email\" type=\"email\" />\n <Input leadingIcon=\"lucide:lock\" placeholder=\"Password\" type=\"password\" />\n <Button label=\"Sign in\" variant=\"solid\" color=\"primary\" block />\n </FieldGroup>\n </div>\n </div>\n\n <div>\n <p class=\"mb-2 text-xs text-on-surface-variant\">Search with filter</p>\n <FieldGroup>\n <Button label=\"All\" variant=\"outline\" color=\"surface\" />\n <Input leadingIcon=\"lucide:search\" placeholder=\"Search products...\" />\n <Button icon=\"lucide:sliders-horizontal\" variant=\"outline\" color=\"surface\" />\n </FieldGroup>\n </div>\n </div>\n </section>\n</div>\n",
79
79
  "fonts": "<script lang=\"ts\">\n import { Card, CodeBlock, Fonts, defaultFontFamilies, fontsDefaults } from '$lib/index.js'\n import { renderHighlightedCode } from '$lib/docs/code-block.js'\n import type { FontDefinition } from '$lib/index.js'\n\n const googleFamilies: FontDefinition[] = [\n {\n name: 'Inter',\n variable: '--font-sans-family',\n weights: [400, 500, 600, 700]\n },\n {\n name: 'Poppins',\n variable: '--font-heading-family',\n weights: [600, 700]\n },\n {\n name: 'JetBrains Mono',\n variable: '--font-mono-family',\n weights: [400, 500, 700]\n }\n ]\n\n const defaultPresetCode = `<Fonts />`\n\n const defaultPresetItems = [\n {\n variable: '--font-sans-family',\n family: 'Inter',\n weights: '400, 500, 600, 700',\n utility: 'font-sans'\n },\n {\n variable: '--font-heading-family',\n family: 'Inter',\n weights: '400, 500, 600, 700',\n utility: 'font-heading'\n },\n {\n variable: '--font-mono-family',\n family: 'JetBrains Mono',\n weights: '400, 500, 700',\n utility: 'font-mono'\n }\n ] as const\n\n const localSetupSteps = [\n 'Add your files under `static/fonts/*` so they are served from the app root.',\n 'Map each file with `provider: \"local\"` and `sources` entries for the weights/styles you need.',\n 'Bind the family to a CSS variable such as `--font-sarabun-family`.',\n 'Use the mapped variable through utility classes like `font-sarabun`, `font-heading`, or `font-mono`.'\n ] as const\n\n const localLayoutCode = `<script lang=\"ts\">\n import 'svelora/theme.css';\n import { Fonts } from 'svelora';\n\n let { children } = $props();\n<` + `/script>\n\n<Fonts\n families={[\n {\n provider: 'local',\n name: 'Sarabun',\n variable: '--font-sarabun-family',\n sources: [\n { src: '/fonts/Sarabun-Regular.woff2', format: 'woff2', weight: 400 },\n { src: '/fonts/Sarabun-Medium.woff2', format: 'woff2', weight: 500 },\n { src: '/fonts/Sarabun-Bold.woff2', format: 'woff2', weight: 700 }\n ]\n }\n ]}\n/>\n\n<main class=\"font-sarabun\">\n {@render children?.()}\n</main>`\n\n const familyReference = [\n {\n name: 'provider',\n type: `'google' | 'local'`,\n description: 'Selects whether the family loads from Google Fonts or local assets.'\n },\n {\n name: 'name',\n type: 'string',\n description: 'Font family name used in the request or `@font-face` declaration.'\n },\n {\n name: 'variable',\n type: '`--${string}`',\n description: 'CSS custom property that stores the generated font-family stack.'\n },\n {\n name: 'fallback',\n type: 'string',\n description: 'Optional fallback stack appended after the primary font family.'\n },\n {\n name: 'weights',\n type: 'number[]',\n description: 'Google-only list of weights to request.'\n },\n {\n name: 'styles',\n type: `('normal' | 'italic')[]`,\n description: 'Google-only styles to request.'\n },\n {\n name: 'sources',\n type: 'LocalFontSource[]',\n description: 'Local-only file definitions used to build `@font-face` rules.'\n }\n ] as const\n\n const optionsReference = [\n {\n name: 'families',\n type: 'FontDefinition[]',\n description: 'Complete list of families managed by the provider.'\n },\n {\n name: 'display',\n type: `'auto' | 'block' | 'swap' | 'fallback' | 'optional'`,\n description: 'Controls `font-display` for Google requests and local `@font-face` output.'\n },\n {\n name: 'preconnect',\n type: 'boolean',\n description: 'Adds preconnect links for Google Fonts when enabled.'\n }\n ] as const\n\n const localSourceReference = [\n {\n name: 'src',\n type: 'string',\n description: 'Public URL to the local font file, for example `/fonts/Sarabun-Regular.woff2`.'\n },\n {\n name: 'format',\n type: `'woff2' | 'woff' | 'truetype' | 'opentype' | 'embedded-opentype' | 'svg'`,\n description: 'Optional format hint used in `@font-face`.'\n },\n {\n name: 'weight',\n type: 'number | `${number} ${number}`',\n description: 'Single weight or variable font range.'\n },\n {\n name: 'style',\n type: `'normal' | 'italic'`,\n description: 'Font style for the source entry.'\n },\n {\n name: 'unicodeRange',\n type: 'string',\n description: 'Optional unicode-range for partial subsets.'\n }\n ] as const\n\n const localProviderCode = `<Fonts\n families={[\n {\n provider: 'local',\n name: 'Sarabun',\n variable: '--font-sarabun-family',\n sources: [\n { src: '/fonts/Sarabun-Regular.woff2', format: 'woff2', weight: 400 },\n { src: '/fonts/Sarabun-Bold.woff2', format: 'woff2', weight: 700 }\n ]\n }\n ]}\n/>`\n\n const mixedProviderCode = `<Fonts\n families={[\n { name: 'Inter', variable: '--font-sans-family', weights: [400, 500, 600, 700] },\n { name: 'Poppins', variable: '--font-heading-family', weights: [600, 700] },\n {\n provider: 'local',\n name: 'Sarabun',\n variable: '--font-sarabun-family',\n sources: [{ src: '/fonts/Sarabun-Regular.woff2', format: 'woff2', weight: 400 }]\n }\n ]}\n/>`\n\n const configCode = `import { defineConfig } from 'svelora';\n\ndefineConfig({\n fonts: {\n families: [\n { name: 'Inter', variable: '--font-sans-family', weights: [400, 500, 600, 700] },\n { name: 'Poppins', variable: '--font-heading-family', weights: [600, 700] },\n {\n provider: 'local',\n name: 'Sarabun',\n variable: '--font-sarabun-family',\n sources: [\n { src: '/fonts/Sarabun-Regular.woff2', format: 'woff2', weight: 400 },\n { src: '/fonts/Sarabun-Bold.woff2', format: 'woff2', weight: 700 }\n ]\n }\n ]\n }\n});`\n\n const layoutCode = `<script lang=\"ts\">\n import 'svelora/theme.css';\n import { Fonts, ModeWatcher } from 'svelora';\n\n let { children } = $props();\n<` + `/script>\n\n<Fonts />\n<ModeWatcher />\n{@render children?.()}`\n\n const disableDefaultsCode = `import { defineConfig } from 'svelora';\n\ndefineConfig({\n fonts: false\n});`\n\n let isDarkMode = $state(true)\n let defaultPresetHtml = $state('')\n let localProviderHtml = $state('')\n let localLayoutHtml = $state('')\n let mixedProviderHtml = $state('')\n let configHtml = $state('')\n let layoutHtml = $state('')\n let disableDefaultsHtml = $state('')\n\n $effect(() => {\n if (typeof document === 'undefined') return\n\n const root = document.documentElement\n const updateMode = () => {\n isDarkMode = root.classList.contains('dark')\n }\n\n updateMode()\n\n const observer = new MutationObserver(() => {\n updateMode()\n })\n\n observer.observe(root, { attributes: true, attributeFilter: ['class'] })\n return () => observer.disconnect()\n })\n\n $effect(() => {\n const darkMode = isDarkMode\n let cancelled = false\n\n const tasks = [\n renderHighlightedCode(defaultPresetCode, darkMode).then((html) => {\n if (!cancelled) defaultPresetHtml = html\n }),\n renderHighlightedCode(localProviderCode, darkMode).then((html) => {\n if (!cancelled) localProviderHtml = html\n }),\n renderHighlightedCode(localLayoutCode, darkMode).then((html) => {\n if (!cancelled) localLayoutHtml = html\n }),\n renderHighlightedCode(mixedProviderCode, darkMode).then((html) => {\n if (!cancelled) mixedProviderHtml = html\n }),\n renderHighlightedCode(configCode, darkMode).then((html) => {\n if (!cancelled) configHtml = html\n }),\n renderHighlightedCode(layoutCode, darkMode).then((html) => {\n if (!cancelled) layoutHtml = html\n }),\n renderHighlightedCode(disableDefaultsCode, darkMode).then((html) => {\n if (!cancelled) disableDefaultsHtml = html\n })\n ]\n\n void Promise.all(tasks)\n\n return () => {\n cancelled = true\n }\n })\n</script>\n\n<div class=\"space-y-8\">\n <div class=\"space-y-2\">\n <h1 class=\"text-2xl font-bold\">Fonts</h1>\n <p class=\"text-on-surface-variant\">\n A unified font provider for Svelora that supports both Google Fonts and local font files\n through the same `fonts.families` API.\n </p>\n </div>\n\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Default Preset</h2>\n <p class=\"text-sm text-on-surface-variant\">\n If you render `<Fonts />` without props or custom config, Svelora uses the built-in preset\n below. The current default display is `{fontsDefaults.display}` with preconnect set to\n `{fontsDefaults.preconnect ? 'true' : 'false'}`.\n </p>\n <CodeBlock title=\"Default Preset\" code={defaultPresetCode} html={defaultPresetHtml} />\n <div class=\"grid gap-4 md:grid-cols-3\">\n {#each defaultPresetItems as item (item.variable)}\n <Card class=\"border border-outline-variant/70\">\n <div class=\"space-y-2\">\n <p class=\"font-mono text-xs text-on-surface-variant\">{item.variable}</p>\n <h3 class=\"text-base font-semibold\">{item.family}</h3>\n <p class=\"text-sm text-on-surface-variant\">Weights: {item.weights}</p>\n <p class=\"text-sm text-on-surface-variant\">Utility: `{item.utility}`</p>\n </div>\n </Card>\n {/each}\n </div>\n <p class=\"text-sm text-on-surface-variant\">\n The preset is sourced from `defaultFontFamilies` and currently includes\n `{defaultFontFamilies.length}` families.\n </p>\n </section>\n\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Google Provider</h2>\n <div class=\"rounded-lg bg-surface-container-high p-4\">\n <Fonts families={googleFamilies} />\n <h3 class=\"font-heading text-2xl font-semibold\">Poppins heading</h3>\n <p>Inter body copy is mapped to `--font-sans-family`.</p>\n <p class=\"font-mono mt-2 text-sm\">const provider = 'google';</p>\n </div>\n </section>\n\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Local Provider</h2>\n <CodeBlock title=\"Local Provider\" code={localProviderCode} html={localProviderHtml} />\n <p class=\"text-sm text-on-surface-variant\">\n Put your font files under `static/fonts/*`, map them to a CSS variable, then use utility\n classes like `font-sarabun` across the project.\n </p>\n </section>\n\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Local Font Setup</h2>\n <div class=\"grid gap-3 md:grid-cols-2\">\n {#each localSetupSteps as step, index (`${index}-${step}`)}\n <Card class=\"border border-outline-variant/70\">\n <div class=\"space-y-2\">\n <p class=\"text-sm font-medium text-primary\">Step {index + 1}</p>\n <p class=\"text-sm text-on-surface-variant\">{step}</p>\n </div>\n </Card>\n {/each}\n </div>\n <CodeBlock title=\"Local Font Setup\" code={localLayoutCode} html={localLayoutHtml} />\n </section>\n\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Mixed Providers</h2>\n <CodeBlock title=\"Mixed Providers\" code={mixedProviderCode} html={mixedProviderHtml} />\n <p class=\"text-sm text-on-surface-variant\">\n Mix Google fonts for global typography with local assets for brand or language-specific\n families in the same provider.\n </p>\n </section>\n\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Using Global Config</h2>\n <CodeBlock title=\"defineConfig()\" code={configCode} html={configHtml} />\n <CodeBlock title=\"+layout.svelte\" code={layoutCode} html={layoutHtml} />\n </section>\n\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">Disable Defaults</h2>\n <CodeBlock title=\"Disable Defaults\" code={disableDefaultsCode} html={disableDefaultsHtml} />\n <p class=\"text-sm text-on-surface-variant\">\n Set `fonts: false` when you want to fully manage font loading yourself.\n </p>\n </section>\n\n <section class=\"space-y-3\">\n <h2 class=\"text-lg font-semibold\">API Reference</h2>\n <div class=\"grid gap-4 lg:grid-cols-2\">\n <Card class=\"border border-outline-variant/70\">\n <div class=\"space-y-4\">\n <h3 class=\"text-base font-semibold\">Fonts Options</h3>\n <div class=\"space-y-3\">\n {#each optionsReference as item (item.name)}\n <div class=\"border-b border-outline-variant/60 pb-3 last:border-b-0 last:pb-0\">\n <p class=\"font-mono text-xs text-on-surface-variant\">{item.name}</p>\n <p class=\"mt-1 text-sm font-medium\">{item.type}</p>\n <p class=\"mt-1 text-sm text-on-surface-variant\">{item.description}</p>\n </div>\n {/each}\n </div>\n </div>\n </Card>\n <Card class=\"border border-outline-variant/70\">\n <div class=\"space-y-4\">\n <h3 class=\"text-base font-semibold\">Font Definition</h3>\n <div class=\"space-y-3\">\n {#each familyReference as item (item.name)}\n <div class=\"border-b border-outline-variant/60 pb-3 last:border-b-0 last:pb-0\">\n <p class=\"font-mono text-xs text-on-surface-variant\">{item.name}</p>\n <p class=\"mt-1 text-sm font-medium\">{item.type}</p>\n <p class=\"mt-1 text-sm text-on-surface-variant\">{item.description}</p>\n </div>\n {/each}\n </div>\n </div>\n </Card>\n </div>\n <Card class=\"border border-outline-variant/70\">\n <div class=\"space-y-4\">\n <h3 class=\"text-base font-semibold\">Local Font Source</h3>\n <div class=\"grid gap-3 md:grid-cols-2\">\n {#each localSourceReference as item (item.name)}\n <div class=\"rounded-xl border border-outline-variant/60 p-4\">\n <p class=\"font-mono text-xs text-on-surface-variant\">{item.name}</p>\n <p class=\"mt-1 text-sm font-medium\">{item.type}</p>\n <p class=\"mt-1 text-sm text-on-surface-variant\">{item.description}</p>\n </div>\n {/each}\n </div>\n </div>\n </Card>\n </section>\n</div>\n",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelora",
3
- "version": "3.0.4",
3
+ "version": "3.0.5",
4
4
  "description": "Modern primitive-based UI component library for Svelte 5",
5
5
  "packageManager": "bun@1.3.14",
6
6
  "author": "asphum",
@@ -224,9 +224,9 @@
224
224
  "@types/node": "^26.0.0",
225
225
  "@vitest/browser-playwright": "^4.1.9",
226
226
  "joi": "^18.2.3",
227
- "playwright": "^1.61.0",
227
+ "playwright": "^1.61.1",
228
228
  "publint": "^0.3.21",
229
- "svelte": "^5.56.3",
229
+ "svelte": "^5.56.4",
230
230
  "svelte-check": "^4.7.0",
231
231
  "tailwindcss": "^4.3.1",
232
232
  "tiptap-markdown": "^0.9.0",