yaxa-svelte 1.14.2 → 1.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/README.md +17 -5
  2. package/dist/actions/infiniteScroll.js +1 -1
  3. package/dist/admin/handler.d.ts +2 -2
  4. package/dist/admin/handler.js +2 -2
  5. package/dist/admin/hook.d.ts +3 -3
  6. package/dist/admin/hook.js +6 -6
  7. package/dist/components/ai/AiChat.svelte +30 -23
  8. package/dist/components/ai/AiThought.svelte +5 -1
  9. package/dist/components/ai/AiToolCall.svelte +5 -1
  10. package/dist/components/ai/PromptBar.svelte +41 -35
  11. package/dist/components/blocks/FAQ.svelte +1 -1
  12. package/dist/components/blocks/FAQ.svelte.d.ts +1 -1
  13. package/dist/components/blocks/FeatureGrid.svelte +1 -1
  14. package/dist/components/blocks/FeatureGrid.svelte.d.ts +1 -1
  15. package/dist/components/blocks/Testimonials.svelte +1 -1
  16. package/dist/components/blocks/Testimonials.svelte.d.ts +1 -1
  17. package/dist/components/elements/Avatar.svelte +6 -2
  18. package/dist/components/elements/Avatar.svelte.d.ts +1 -1
  19. package/dist/components/elements/AvatarGroup.svelte +5 -1
  20. package/dist/components/elements/Badge.svelte +11 -8
  21. package/dist/components/elements/Badge.svelte.d.ts +1 -1
  22. package/dist/components/elements/Button.svelte +1 -1
  23. package/dist/components/elements/Button.svelte.d.ts +1 -1
  24. package/dist/components/elements/Carousel.svelte +1 -1
  25. package/dist/components/elements/Carousel.svelte.d.ts +4 -4
  26. package/dist/components/elements/CodeBlock.svelte +1 -1
  27. package/dist/components/elements/CodeDiff.svelte +1 -1
  28. package/dist/components/elements/CodeDiff.test.js +3 -3
  29. package/dist/components/elements/DataTable.dom.test.js +1 -1
  30. package/dist/components/elements/EmptyState.svelte +1 -1
  31. package/dist/components/elements/EmptyState.svelte.d.ts +1 -1
  32. package/dist/components/elements/Icon.svelte +1 -1
  33. package/dist/components/elements/Icon.test.js +1 -1
  34. package/dist/components/elements/Kbd.svelte +69 -9
  35. package/dist/components/elements/Kbd.svelte.d.ts +4 -1
  36. package/dist/components/elements/Kbd.test.d.ts +1 -0
  37. package/dist/components/elements/Kbd.test.js +34 -0
  38. package/dist/components/elements/MetricCard.svelte +1 -1
  39. package/dist/components/elements/Progress.svelte +1 -1
  40. package/dist/components/elements/Progress.svelte.d.ts +1 -1
  41. package/dist/components/elements/Skeleton.svelte +77 -4
  42. package/dist/components/elements/Skeleton.svelte.d.ts +7 -5
  43. package/dist/components/elements/Skeleton.test.js +24 -1
  44. package/dist/components/elements/SortableList.svelte +1 -1
  45. package/dist/components/elements/Terminal.svelte +2 -2
  46. package/dist/components/elements/Terminal.svelte.d.ts +1 -1
  47. package/dist/components/elements/Timeline.svelte +1 -1
  48. package/dist/components/elements/Timeline.svelte.d.ts +1 -1
  49. package/dist/components/elements/Tree.svelte +1 -1
  50. package/dist/components/elements/Tree.svelte.d.ts +1 -1
  51. package/dist/components/elements/VirtualList.svelte +1 -1
  52. package/dist/components/elements/VirtualList.svelte.d.ts +1 -1
  53. package/dist/components/forms/Checkbox.svelte +52 -21
  54. package/dist/components/forms/Checkbox.svelte.d.ts +10 -3
  55. package/dist/components/forms/Combobox.dom.test.js +1 -1
  56. package/dist/components/forms/Combobox.svelte +1 -1
  57. package/dist/components/forms/Combobox.svelte.d.ts +1 -1
  58. package/dist/components/forms/DatePicker.svelte +1 -1
  59. package/dist/components/forms/DateRangePicker.svelte +1 -1
  60. package/dist/components/forms/Dropzone.svelte +1 -1
  61. package/dist/components/forms/Form.dom.test.js +1 -1
  62. package/dist/components/forms/FormField.svelte +2 -1
  63. package/dist/components/forms/Input.svelte +78 -20
  64. package/dist/components/forms/Input.svelte.d.ts +19 -11
  65. package/dist/components/forms/InputOTP.svelte +1 -1
  66. package/dist/components/forms/InputOTP.test.js +1 -1
  67. package/dist/components/forms/MultiSelect.svelte +1 -1
  68. package/dist/components/forms/MultiSelect.svelte.d.ts +1 -1
  69. package/dist/components/forms/NumberInput.svelte +1 -1
  70. package/dist/components/forms/NumberInput.svelte.d.ts +1 -1
  71. package/dist/components/forms/Select.svelte +1 -1
  72. package/dist/components/forms/Select.svelte.d.ts +1 -1
  73. package/dist/components/forms/Switch.svelte +35 -10
  74. package/dist/components/forms/Switch.svelte.d.ts +11 -3
  75. package/dist/components/forms/Textarea.svelte +2 -2
  76. package/dist/components/forms/Textarea.svelte.d.ts +1 -1
  77. package/dist/components/forms/ToggleGroup.svelte +2 -2
  78. package/dist/components/forms/advanced-forms.test.js +1 -1
  79. package/dist/components/layout/Card.svelte +31 -16
  80. package/dist/components/layout/Card.svelte.d.ts +17 -10
  81. package/dist/components/layout/Container.svelte +1 -1
  82. package/dist/components/layout/Container.svelte.d.ts +1 -1
  83. package/dist/components/layout/DashboardShell.svelte +1 -1
  84. package/dist/components/layout/DashboardShell.svelte.d.ts +1 -1
  85. package/dist/components/layout/Footer.svelte +2 -2
  86. package/dist/components/layout/Footer.svelte.d.ts +1 -1
  87. package/dist/components/layout/Header.svelte +4 -4
  88. package/dist/components/layout/Header.svelte.d.ts +1 -1
  89. package/dist/components/layout/ResizablePanels.svelte +1 -1
  90. package/dist/components/layout/ResizablePanels.svelte.d.ts +1 -1
  91. package/dist/components/layout/YaxaApp.svelte +4 -4
  92. package/dist/components/layout/YaxaApp.svelte.d.ts +3 -3
  93. package/dist/components/legal/LegalDocument.svelte +2 -2
  94. package/dist/components/legal/LegalDocument.svelte.d.ts +1 -1
  95. package/dist/components/navigation/Breadcrumb.svelte +36 -14
  96. package/dist/components/navigation/Breadcrumb.svelte.d.ts +11 -2
  97. package/dist/components/navigation/CommandPalette.svelte +66 -22
  98. package/dist/components/navigation/CommandPalette.svelte.d.ts +13 -2
  99. package/dist/components/navigation/Stepper.svelte +1 -1
  100. package/dist/components/navigation/Stepper.svelte.d.ts +1 -1
  101. package/dist/components/navigation/Tabs.svelte +109 -36
  102. package/dist/components/navigation/Tabs.svelte.d.ts +12 -3
  103. package/dist/components/overlays/Accordion.svelte +40 -10
  104. package/dist/components/overlays/Accordion.svelte.d.ts +11 -0
  105. package/dist/components/overlays/Alert.svelte +30 -8
  106. package/dist/components/overlays/Alert.svelte.d.ts +11 -1
  107. package/dist/components/overlays/Drawer.svelte +47 -14
  108. package/dist/components/overlays/Drawer.svelte.d.ts +14 -2
  109. package/dist/components/overlays/Modal.dom.test.js +1 -1
  110. package/dist/components/overlays/Modal.svelte +44 -12
  111. package/dist/components/overlays/Modal.svelte.d.ts +13 -2
  112. package/dist/components/overlays/NotificationCenter.svelte +1 -1
  113. package/dist/components/overlays/NotificationCenter.svelte.d.ts +1 -1
  114. package/dist/components/overlays/Slideover.svelte +1 -1
  115. package/dist/components/overlays/Slideover.svelte.d.ts +1 -1
  116. package/dist/components/overlays/Toast.svelte +4 -4
  117. package/dist/components/overlays/Toast.svelte.d.ts +2 -2
  118. package/dist/components/overlays/Toast.test.js +2 -2
  119. package/dist/components/overlays/Toaster.svelte +2 -2
  120. package/dist/components/overlays/Toaster.svelte.d.ts +1 -1
  121. package/dist/components/overlays/Tooltip.dom.test.js +1 -1
  122. package/dist/components/overlays/Tooltip.svelte +29 -10
  123. package/dist/components/overlays/Tooltip.svelte.d.ts +10 -4
  124. package/dist/components/saas/Gate.svelte +2 -2
  125. package/dist/components/saas/Gate.svelte.d.ts +1 -1
  126. package/dist/components/saas/OrgSwitcher.svelte +1 -1
  127. package/dist/components/saas/OrgSwitcher.svelte.d.ts +1 -1
  128. package/dist/components/saas/PasskeyUI.svelte +1 -1
  129. package/dist/components/saas/PasskeyUI.svelte.d.ts +1 -1
  130. package/dist/components/saas/PricingCard.svelte +17 -9
  131. package/dist/components/seo/Favicons.svelte +2 -2
  132. package/dist/components/seo/Favicons.svelte.d.ts +1 -1
  133. package/dist/components/seo/OgImage.svelte +2 -2
  134. package/dist/components/seo/OgImage.svelte.d.ts +1 -1
  135. package/dist/components/seo/Seo.svelte +3 -3
  136. package/dist/components/seo/Seo.svelte.d.ts +1 -1
  137. package/dist/components/theme/ThemeStudio.svelte +2 -2
  138. package/dist/composables/useClipboard.svelte.js +1 -1
  139. package/dist/composables/useColorMode.svelte.d.ts +1 -1
  140. package/dist/composables/useColorMode.svelte.js +1 -1
  141. package/dist/composables/useFormAction.svelte.d.ts +10 -11
  142. package/dist/composables/useFormAction.svelte.js +9 -10
  143. package/dist/composables/useGate.svelte.d.ts +1 -1
  144. package/dist/composables/useGate.svelte.js +1 -1
  145. package/dist/composables/useInfiniteScroll.svelte.js +1 -1
  146. package/dist/composables/useLocale.svelte.js +1 -1
  147. package/dist/composables/useMediaQuery.svelte.js +1 -1
  148. package/dist/composables/useShortcuts.svelte.js +1 -1
  149. package/dist/index.js +1 -1
  150. package/dist/server/auth/hook.d.ts +1 -1
  151. package/dist/server/endpoints.test.js +5 -5
  152. package/dist/server/polar/webhook.js +2 -1
  153. package/dist/server/storage/index.js +19 -5
  154. package/dist/server/storage/storage.test.js +1 -1
  155. package/dist/site/hook.d.ts +1 -1
  156. package/dist/site/schema.js +1 -1
  157. package/dist/site/sitemap-xsl.js +2 -2
  158. package/dist/styles/theme.css +294 -0
  159. package/dist/styles/yaxa.css +1 -254
  160. package/dist/testing/setup.d.ts +0 -1
  161. package/dist/testing/setup.js +1 -1
  162. package/dist/theme/theme.svelte.js +1 -1
  163. package/package.json +28 -31
package/README.md CHANGED
@@ -3,12 +3,12 @@
3
3
  # Yaxa
4
4
 
5
5
  **The Intuitive Svelte UI & Solo SaaS Library**
6
- _Nuxt UI v4 & Nuxt UI Pro Equivalent for SvelteKit 2 & 3 and Svelte 5 with Built-in SEO & SaaS Parity._
6
+ _Nuxt UI v4 & Nuxt UI Pro Equivalent for SvelteKit 2.7+ & Svelte 5 with Built-in SEO & SaaS Parity._
7
7
 
8
8
  [![npm version](https://img.shields.io/npm/v/yaxa-svelte.svg?color=CB3837&logo=npm)](https://www.npmjs.com/package/yaxa-svelte)
9
9
  [![npm downloads](https://img.shields.io/npm/dm/yaxa-svelte.svg?color=blue)](https://www.npmjs.com/package/yaxa-svelte)
10
10
  [![Svelte 5](https://img.shields.io/badge/Svelte-5.0+-FF3E00?style=flat&logo=svelte&logoColor=white)](https://svelte.dev)
11
- [![SvelteKit](https://img.shields.io/badge/SvelteKit-2%20%26%203-FF3E00?style=flat&logo=svelte&logoColor=white)](https://kit.svelte.dev)
11
+ [![SvelteKit](https://img.shields.io/badge/SvelteKit-2.7+-FF3E00?style=flat&logo=svelte&logoColor=white)](https://kit.svelte.dev)
12
12
  [![Tailwind CSS v4](https://img.shields.io/badge/Tailwind_CSS-v4.0-38B2AC?style=flat&logo=tailwind-css&logoColor=white)](https://tailwindcss.com)
13
13
  [![Bits UI](https://img.shields.io/badge/Bits_UI-v2.0-18181b?style=flat)](https://bits-ui.com)
14
14
  [![License: MIT](https://img.shields.io/badge/License-MIT-emerald.svg)](LICENSE)
@@ -21,9 +21,9 @@ _Nuxt UI v4 & Nuxt UI Pro Equivalent for SvelteKit 2 & 3 and Svelte 5 with Built
21
21
 
22
22
  ## 🌟 Overview
23
23
 
24
- **Yaxa** brings the full developer experience, visual elegance, and full-stack toolkit of **Nuxt UI** and the **Nuxt SEO + SaaS ecosystem** to **SvelteKit 2 & 3** and **Svelte 5**.
24
+ **Yaxa** brings the full developer experience, visual elegance, and full-stack toolkit of **Nuxt UI** and the **Nuxt SEO + SaaS ecosystem** to **SvelteKit 2.7+** and **Svelte 5**.
25
25
 
26
- - 🎨 **Tailwind CSS v4 Native Tokens**: Styled with `@theme` variables; harmonic radius scale (`--radius-xs` to `--radius-4xl`), chart palette tokens (`--color-chart-1` to `--color-chart-5`), and auto-adaptive scrollbars.
26
+ - 🎨 **Tailwind CSS v4 Native Tokens**: Styled with `@theme` variables; harmonic radius scale (`--radius-xs` to `--radius-4xl`), chart palette tokens (`--color-chart-1` to `--color-chart-5`), atmospheric utilities (`yaxa-grain` & `yaxa-mesh-glow`), and auto-adaptive scrollbars.
27
27
  - 🎛️ **Visual Web Theme Studio**: Interactive runtime palette designer (`/theme` and `<ThemeStudio />`) with live sandbox preview and 1-click token export.
28
28
  - 🤖 **AI-Native Primitives**: Drop-in `<AiChat>`, `<PromptBar>`, `<AiThought>`, and `<AiToolCall>` for conversational interfaces and agentic workflows.
29
29
  - 📊 **Zero-Dependency SVG Charts**: Pure Svelte 5 `<LineChart>`, `<BarChart>`, and `<DonutChart>` with responsive tooltips, curved splines, and theme-palette synchronisation.
@@ -31,7 +31,7 @@ _Nuxt UI v4 & Nuxt UI Pro Equivalent for SvelteKit 2 & 3 and Svelte 5 with Built
31
31
  - ♿ **Accessible by Default**: Headless primitives powered by **Bits UI**.
32
32
  - 🚀 **100% DRY SEO Parity**: Automate dynamic Open Graph cards (`/api/og`), environment-aware `robots.txt`, XML sitemaps with human-readable `sitemap.xsl` stylesheets, PWA manifests, and Schema.org JSON-LD from a single `src/site.config.ts`.
33
33
  - 🔐 **Batteries-Included SaaS Suite**: Pre-integrated **Better-Auth**, multi-dialect **Drizzle ORM** (Neon PostgreSQL & Turso LibSQL/SQLite), **Polar.sh** payments & webhook sync, and **Resend** transactional emails.
34
- - 🧩 **50+ Production Components**: Elements, AI primitives, charts, advanced forms (`<RichTextEditor>`, `<PhoneInput>`, `<CreditCardInput>`), layout, overlays, native `<Toast>` / `<Toaster>`, and drop-in SaaS widgets (`<AuthCard>`, `<UserMenu>`, `<PricingTable>`, `<SubscriptionCard>`).
34
+ - 🧩 **50+ Production Components**: Elements, compound `<Skeleton recipe="...">` layouts, AI primitives, charts, advanced forms (`<RichTextEditor>`, `<PhoneInput>`, `<CreditCardInput>`), layout, overlays, sliding segmented `<Tabs>`, native `<Toast>` / `<Toaster>`, and drop-in SaaS widgets (`<AuthCard>`, `<UserMenu>`, `<PricingTable>`, `<SubscriptionCard>`).
35
35
  - 🛠️ **Composable Runes**: `useAuth`, `useShortcuts`, `useClipboard`, `useColorMode`, `useToast`, `useMediaQuery`, `useDebounce`, `useIdle`, `useGate`.
36
36
 
37
37
  ---
@@ -107,6 +107,7 @@ export const siteConfig = defineSiteConfig({
107
107
 
108
108
  ### 4. Import CSS & Wrap Root Layout
109
109
 
110
+ **Option A: Turnkey Zero-Config** (Default)
110
111
  Import `yaxa-svelte/yaxa.css` and wrap your app in `<YaxaApp>`:
111
112
 
112
113
  ```svelte
@@ -124,6 +125,17 @@ Import `yaxa-svelte/yaxa.css` and wrap your app in `<YaxaApp>`:
124
125
  </YaxaApp>
125
126
  ```
126
127
 
128
+ **Option B: Optimized Tailwind CSS v4 Pipeline** (Maximum build performance & deduplication)
129
+ If your project already imports Tailwind in `src/app.css`, import the standalone theme tokens and tell Tailwind to scan Yaxa:
130
+
131
+ ```css
132
+ /* src/app.css */
133
+ @import 'tailwindcss';
134
+ @plugin '@tailwindcss/typography';
135
+ @import 'yaxa-svelte/theme.css';
136
+ @source '../node_modules/yaxa-svelte/dist/**/*.{js,svelte}';
137
+ ```
138
+
127
139
  ---
128
140
 
129
141
  ## 🛡️ 1-Line Server SEO & Auth Automation
@@ -1,4 +1,4 @@
1
- import { browser } from '$app/env';
1
+ import { browser } from '$app/environment';
2
2
  /**
3
3
  * Headless Svelte Action to trigger loading callbacks when scrolling near the edges.
4
4
  *
@@ -39,8 +39,8 @@ export declare class DrizzleAdminService {
39
39
  * Example:
40
40
  * ```ts
41
41
  * // src/routes/admin/+page.server.ts
42
- * import { db } from '../server/db/index.js';
43
- * import * as schema from '../server/db/schema-pg.js';
42
+ * import { db } from '../server/db';
43
+ * import * as schema from '../server/db/schema-pg';
44
44
  * import { createDrizzleAdmin } from 'yaxa-svelte/admin';
45
45
  *
46
46
  * export const { load, actions } = createDrizzleAdmin({ db, schema });
@@ -232,8 +232,8 @@ export class DrizzleAdminService {
232
232
  * Example:
233
233
  * ```ts
234
234
  * // src/routes/admin/+page.server.ts
235
- * import { db } from '../server/db/index.js';
236
- * import * as schema from '../server/db/schema-pg.js';
235
+ * import { db } from '../server/db';
236
+ * import * as schema from '../server/db/schema-pg';
237
237
  * import { createDrizzleAdmin } from 'yaxa-svelte/admin';
238
238
  *
239
239
  * export const { load, actions } = createDrizzleAdmin({ db, schema });
@@ -1,4 +1,4 @@
1
- import type { Handle } from '@sveltejs/kit/hooks';
1
+ import type { Handle } from '@sveltejs/kit';
2
2
  import type { YaxaAdminHookOptions } from './types';
3
3
  /**
4
4
  * Creates a SvelteKit Handle hook for zero-file route interception and automatic Drizzle admin dashboard.
@@ -8,8 +8,8 @@ import type { YaxaAdminHookOptions } from './types';
8
8
  * // src/hooks.server.ts
9
9
  * import { sequence } from '@sveltejs/kit/hooks';
10
10
  * import { createYaxaAdminHook } from 'yaxa-svelte/admin';
11
- * import { db } from '../server/db/index.js';
12
- * import * as schema from '../server/db/schema-pg.js';
11
+ * import { db } from '../server/db';
12
+ * import * as schema from '../server/db/schema-pg';
13
13
  *
14
14
  * export const handle = sequence(
15
15
  * createYaxaAdminHook({ db, schema, path: '/admin' })
@@ -9,8 +9,8 @@ import { createPresignedUploadUrl } from '../server/storage/index';
9
9
  * // src/hooks.server.ts
10
10
  * import { sequence } from '@sveltejs/kit/hooks';
11
11
  * import { createYaxaAdminHook } from 'yaxa-svelte/admin';
12
- * import { db } from '../server/db/index.js';
13
- * import * as schema from '../server/db/schema-pg.js';
12
+ * import { db } from '../server/db';
13
+ * import * as schema from '../server/db/schema-pg';
14
14
  *
15
15
  * export const handle = sequence(
16
16
  * createYaxaAdminHook({ db, schema, path: '/admin' })
@@ -172,8 +172,8 @@ function renderAdminHtml(data, title, adminPath) {
172
172
  <meta charset="utf-8" />
173
173
  <meta name="viewport" content="width=device-width, initial-scale=1" />
174
174
  <title>${title}</title>
175
- <${'script'} src="https://cdn.tailwindcss.com"></${'script'}>
176
- <${'script'}>
175
+ <script src="https://cdn.tailwindcss.com"></script>
176
+ <script>
177
177
  tailwind.config = {
178
178
  darkMode: 'class',
179
179
  theme: {
@@ -188,8 +188,8 @@ function renderAdminHtml(data, title, adminPath) {
188
188
  }
189
189
  }
190
190
  }
191
- };
192
- </${'script'}>
191
+ }
192
+ </script>
193
193
  </head>
194
194
  <body class="bg-neutral-950 text-neutral-100 antialiased min-h-screen font-sans">
195
195
  <div class="flex h-14 items-center justify-between border-b border-neutral-800 bg-neutral-900/90 px-6 backdrop-blur">
@@ -49,7 +49,8 @@
49
49
  import PromptBar from './PromptBar.svelte';
50
50
  import AiThought from './AiThought.svelte';
51
51
  import AiToolCall from './AiToolCall.svelte';
52
- import { useToast } from '../../composables/useToast.svelte.js';
52
+ import { useToast } from '../../composables/useToast.svelte';
53
+ import { cn } from '../../utils/cn';
53
54
 
54
55
  let {
55
56
  messages = [],
@@ -73,17 +74,16 @@
73
74
  const toast = useToast();
74
75
 
75
76
  function scrollToBottom(smooth = true) {
76
- if (scrollContainer && autoScroll) {
77
- scrollContainer.scrollTo({
78
- top: scrollContainer.scrollHeight,
79
- behavior: smooth ? 'smooth' : 'auto'
80
- });
81
- }
77
+ if (!scrollContainer) return;
78
+ scrollContainer.scrollTo({
79
+ top: scrollContainer.scrollHeight,
80
+ behavior: smooth ? 'smooth' : 'auto'
81
+ });
82
82
  }
83
83
 
84
84
  $effect(() => {
85
- if (messages.length > 0) {
86
- setTimeout(() => scrollToBottom(true), 50);
85
+ if (autoScroll && messages.length > 0) {
86
+ scrollToBottom(true);
87
87
  }
88
88
  });
89
89
 
@@ -96,7 +96,10 @@
96
96
  </script>
97
97
 
98
98
  <div
99
- class="flex h-full min-h-[500px] w-full flex-col overflow-hidden rounded-2xl border border-neutral-200 bg-white shadow-md dark:border-neutral-800 dark:bg-neutral-950 {className}"
99
+ class={cn(
100
+ 'flex h-full min-h-[500px] w-full flex-col overflow-hidden rounded-2xl border border-neutral-200 bg-white shadow-md dark:border-neutral-800 dark:bg-neutral-950',
101
+ className
102
+ )}
100
103
  >
101
104
  <!-- Chat Header Bar -->
102
105
  <div
@@ -117,9 +120,10 @@
117
120
  </div>
118
121
  <div class="flex items-center gap-1.5 text-[11px] text-neutral-500">
119
122
  <span
120
- class="h-1.5 w-1.5 rounded-full {loading
121
- ? 'animate-ping bg-amber-500'
122
- : 'bg-emerald-500'}"
123
+ class={cn(
124
+ 'h-1.5 w-1.5 rounded-full',
125
+ loading ? 'animate-ping bg-amber-500' : 'bg-emerald-500'
126
+ )}
123
127
  ></span>
124
128
  <span>{loading ? 'Generating response...' : 'Online & Ready'}</span>
125
129
  </div>
@@ -131,7 +135,7 @@
131
135
  <!-- Scrollable Messages Container -->
132
136
  <div
133
137
  bind:this={scrollContainer}
134
- class="yaxa-scrollbar flex-1 space-y-6 overflow-y-auto p-4 sm:p-6"
138
+ class="flex-1 yaxa-scrollbar space-y-6 overflow-y-auto p-4 sm:p-6"
135
139
  >
136
140
  {#if messages.length === 0}
137
141
  <div class="flex h-full min-h-[300px] flex-col items-center justify-center text-center">
@@ -152,7 +156,7 @@
152
156
  {#if messageSlot}
153
157
  {@render messageSlot(msg)}
154
158
  {:else}
155
- <div class="flex gap-3.5 {msg.role === 'user' ? 'justify-end' : 'justify-start'}">
159
+ <div class={cn('flex gap-3.5', msg.role === 'user' ? 'justify-end' : 'justify-start')}>
156
160
  {#if msg.role === 'assistant'}
157
161
  <Avatar
158
162
  src={assistantAvatar}
@@ -163,9 +167,10 @@
163
167
  {/if}
164
168
 
165
169
  <div
166
- class="flex max-w-[85%] flex-col gap-1 sm:max-w-[75%] {msg.role === 'user'
167
- ? 'items-end'
168
- : 'items-start'}"
170
+ class={cn(
171
+ 'flex max-w-[85%] flex-col gap-1 sm:max-w-[75%]',
172
+ msg.role === 'user' ? 'items-end' : 'items-start'
173
+ )}
169
174
  >
170
175
  <!-- Agent Reasoning / Thoughts -->
171
176
  {#if msg.thought}
@@ -184,7 +189,7 @@
184
189
  <!-- Agent Tool Invocations -->
185
190
  {#if msg.tools && msg.tools.length > 0}
186
191
  <div class="w-full space-y-2">
187
- {#each msg.tools as tool}
192
+ {#each msg.tools as tool, tIdx (tool.name + tIdx)}
188
193
  <AiToolCall
189
194
  name={tool.name}
190
195
  status={tool.status}
@@ -197,10 +202,12 @@
197
202
 
198
203
  <!-- Message Bubble -->
199
204
  <div
200
- class="relative rounded-2xl px-4 py-3 text-sm leading-relaxed shadow-xs {msg.role ===
201
- 'user'
202
- ? 'bg-primary-500 text-white dark:bg-primary-600'
203
- : 'border border-neutral-200/80 bg-neutral-50 text-neutral-900 dark:border-neutral-800/80 dark:bg-neutral-900 dark:text-neutral-100'}"
205
+ class={cn(
206
+ 'relative rounded-2xl px-4 py-3 text-sm leading-relaxed shadow-xs',
207
+ msg.role === 'user'
208
+ ? 'bg-primary-500 text-white dark:bg-primary-600'
209
+ : 'border border-neutral-200/80 bg-neutral-50 text-neutral-900 dark:border-neutral-800/80 dark:bg-neutral-900 dark:text-neutral-100'
210
+ )}
204
211
  >
205
212
  <div class="whitespace-pre-wrap">{msg.content}</div>
206
213
 
@@ -12,6 +12,7 @@
12
12
 
13
13
  <script lang="ts">
14
14
  import Icon from '../elements/Icon.svelte';
15
+ import { cn } from '../../utils/cn';
15
16
 
16
17
  let {
17
18
  duration,
@@ -29,7 +30,10 @@
29
30
  </script>
30
31
 
31
32
  <div
32
- class="my-2 overflow-hidden rounded-xl border border-neutral-200/80 bg-neutral-50/60 transition-all dark:border-neutral-800/80 dark:bg-neutral-900/40 {className}"
33
+ class={cn(
34
+ 'my-2 overflow-hidden rounded-xl border border-neutral-200/80 bg-neutral-50/60 transition-all dark:border-neutral-800/80 dark:bg-neutral-900/40',
35
+ className
36
+ )}
33
37
  >
34
38
  <!-- Header Bar -->
35
39
  <button
@@ -15,6 +15,7 @@
15
15
  <script lang="ts">
16
16
  import Icon from '../elements/Icon.svelte';
17
17
  import CodeBlock from '../elements/CodeBlock.svelte';
18
+ import { cn } from '../../utils/cn';
18
19
 
19
20
  let {
20
21
  name,
@@ -40,7 +41,10 @@
40
41
  </script>
41
42
 
42
43
  <div
43
- class="my-2.5 overflow-hidden rounded-xl border border-neutral-200 bg-white shadow-xs transition-all dark:border-neutral-800 dark:bg-neutral-900 {className}"
44
+ class={cn(
45
+ 'my-2.5 overflow-hidden rounded-xl border border-neutral-200 bg-white shadow-xs transition-all dark:border-neutral-800 dark:bg-neutral-900',
46
+ className
47
+ )}
44
48
  >
45
49
  <!-- Header Bar -->
46
50
  <button
@@ -22,9 +22,10 @@
22
22
  </script>
23
23
 
24
24
  <script lang="ts">
25
- import { autosize } from '../../actions/index.js';
25
+ import { autosize } from '../../actions';
26
26
  import Button from '../elements/Button.svelte';
27
27
  import Icon from '../elements/Icon.svelte';
28
+ import { cn } from '../../utils/cn';
28
29
 
29
30
  let {
30
31
  value = $bindable(''),
@@ -60,26 +61,12 @@
60
61
  });
61
62
 
62
63
  let showCommands = $derived(
63
- value.startsWith('/') && filteredCommands.length > 0 && dismissedQuery !== value
64
+ value.startsWith('/') &&
65
+ filteredCommands.length > 0 &&
66
+ dismissedQuery !== value &&
67
+ !value.includes(' ')
64
68
  );
65
69
 
66
- function handleSubmit() {
67
- if (loading) {
68
- if (onstop) onstop();
69
- return;
70
- }
71
-
72
- if ((!value.trim() && attachments.length === 0) || disabled) return;
73
-
74
- if (onsubmit) {
75
- onsubmit(value.trim(), [...attachments]);
76
- }
77
-
78
- value = '';
79
- attachments = [];
80
- dismissedQuery = '';
81
- }
82
-
83
70
  function handleKeydown(e: KeyboardEvent) {
84
71
  if (showCommands) {
85
72
  if (e.key === 'ArrowDown') {
@@ -95,11 +82,7 @@
95
82
  }
96
83
  if (e.key === 'Enter' || e.key === 'Tab') {
97
84
  e.preventDefault();
98
- const cmd = filteredCommands[selectedCommandIdx];
99
- if (cmd) {
100
- value = `${cmd.name} `;
101
- dismissedQuery = '';
102
- }
85
+ selectCommand(filteredCommands[selectedCommandIdx]);
103
86
  return;
104
87
  }
105
88
  if (e.key === 'Escape') {
@@ -114,14 +97,32 @@
114
97
  }
115
98
  }
116
99
 
100
+ function handleSubmit() {
101
+ if (loading) {
102
+ if (onstop) onstop();
103
+ return;
104
+ }
105
+
106
+ if ((!value.trim() && attachments.length === 0) || disabled) return;
107
+
108
+ if (onsubmit) {
109
+ onsubmit(value.trim(), attachments);
110
+ }
111
+
112
+ value = '';
113
+ attachments = [];
114
+ dismissedQuery = '';
115
+ }
116
+
117
117
  function triggerFileUpload() {
118
118
  fileInputEl?.click();
119
119
  }
120
120
 
121
121
  function handleFileChange(e: Event) {
122
122
  const target = e.target as HTMLInputElement;
123
- if (target.files && target.files.length > 0) {
123
+ if (target.files) {
124
124
  attachments = [...attachments, ...Array.from(target.files)];
125
+ target.value = '';
125
126
  }
126
127
  }
127
128
 
@@ -135,7 +136,7 @@
135
136
  }
136
137
  </script>
137
138
 
138
- <div class="relative w-full {className}">
139
+ <div class={cn('relative w-full', className)}>
139
140
  <!-- Slash Command Autocomplete Menu -->
140
141
  {#if showCommands}
141
142
  <div
@@ -144,14 +145,16 @@
144
145
  <div class="px-2.5 py-1 text-[11px] font-semibold text-neutral-400 uppercase">
145
146
  Quick Commands
146
147
  </div>
147
- {#each filteredCommands as cmd, i}
148
+ {#each filteredCommands as cmd, i (cmd.name)}
148
149
  <button
149
150
  type="button"
150
151
  onclick={() => selectCommand(cmd)}
151
- class="flex w-full items-center justify-between rounded-lg px-2.5 py-1.5 text-left text-xs transition-colors {i ===
152
- selectedCommandIdx
153
- ? 'bg-primary-50 text-primary-900 dark:bg-primary-950/60 dark:text-primary-100'
154
- : 'text-neutral-700 hover:bg-neutral-100 dark:text-neutral-300 dark:hover:bg-neutral-800/60'}"
152
+ class={cn(
153
+ 'flex w-full items-center justify-between rounded-lg px-2.5 py-1.5 text-left text-xs transition-colors',
154
+ i === selectedCommandIdx
155
+ ? 'bg-primary-50 text-primary-900 dark:bg-primary-950/60 dark:text-primary-100'
156
+ : 'text-neutral-700 hover:bg-neutral-100 dark:text-neutral-300 dark:hover:bg-neutral-800/60'
157
+ )}
155
158
  >
156
159
  <div class="flex items-center gap-2">
157
160
  <span class="font-mono font-medium">{cmd.name}</span>
@@ -180,7 +183,7 @@
180
183
  <!-- Attached Files List -->
181
184
  {#if attachments.length > 0}
182
185
  <div class="mb-2 flex flex-wrap gap-1.5 px-1.5 pt-1">
183
- {#each attachments as file, idx}
186
+ {#each attachments as file, idx (file.name + idx)}
184
187
  <div
185
188
  class="flex items-center gap-1.5 rounded-lg border border-neutral-200 bg-neutral-50 px-2 py-1 text-xs text-neutral-700 dark:border-neutral-800 dark:bg-neutral-800 dark:text-neutral-200"
186
189
  >
@@ -235,9 +238,12 @@
235
238
  audioRecording = !audioRecording;
236
239
  if (ontoggleAudio) ontoggleAudio();
237
240
  }}
238
- class="h-8 w-8 rounded-lg p-0 {audioRecording
239
- ? 'text-rose-500 hover:bg-rose-50 dark:hover:bg-rose-950/40'
240
- : 'text-neutral-500 hover:text-neutral-900 dark:text-neutral-400 dark:hover:text-white'}"
241
+ class={cn(
242
+ 'h-8 w-8 rounded-lg p-0',
243
+ audioRecording
244
+ ? 'text-rose-500 hover:bg-rose-50 dark:hover:bg-rose-950/40'
245
+ : 'text-neutral-500 hover:text-neutral-900 dark:text-neutral-400 dark:hover:text-white'
246
+ )}
241
247
  aria-label={audioRecording ? 'Stop voice recording' : 'Voice prompt'}
242
248
  title={audioRecording ? 'Stop voice recording' : 'Voice prompt'}
243
249
  >
@@ -1,5 +1,5 @@
1
1
  <script module lang="ts">
2
- import { tv, type VariantProps } from '../../utils/cn.js';
2
+ import { tv, type VariantProps } from '../../utils/cn';
3
3
 
4
4
  export interface FAQItem {
5
5
  id: string | number;
@@ -1,4 +1,4 @@
1
- import { type VariantProps } from '../../utils/cn.js';
1
+ import { type VariantProps } from '../../utils/cn';
2
2
  export interface FAQItem {
3
3
  id: string | number;
4
4
  question: string;
@@ -1,5 +1,5 @@
1
1
  <script module lang="ts">
2
- import { tv, type VariantProps } from '../../utils/cn.js';
2
+ import { tv, type VariantProps } from '../../utils/cn';
3
3
  import type { IconSource } from '../elements/Icon.svelte';
4
4
 
5
5
  export interface FeatureItem {
@@ -1,4 +1,4 @@
1
- import { type VariantProps } from '../../utils/cn.js';
1
+ import { type VariantProps } from '../../utils/cn';
2
2
  import type { IconSource } from '../elements/Icon.svelte';
3
3
  export interface FeatureItem {
4
4
  id: string | number;
@@ -1,5 +1,5 @@
1
1
  <script module lang="ts">
2
- import { tv, type VariantProps } from '../../utils/cn.js';
2
+ import { tv, type VariantProps } from '../../utils/cn';
3
3
 
4
4
  export interface TestimonialItem {
5
5
  id: string | number;
@@ -1,4 +1,4 @@
1
- import { type VariantProps } from '../../utils/cn.js';
1
+ import { type VariantProps } from '../../utils/cn';
2
2
  export interface TestimonialItem {
3
3
  id: string | number;
4
4
  quote: string;
@@ -1,5 +1,5 @@
1
1
  <script module lang="ts">
2
- import { tv, type VariantProps } from '../../utils/cn.js';
2
+ import { tv, cn, type VariantProps } from '../../utils/cn';
3
3
 
4
4
  export const avatarVariants = tv({
5
5
  base: 'relative inline-flex shrink-0 items-center justify-center font-medium select-none overflow-hidden rounded-full bg-neutral-200 text-neutral-700 dark:bg-neutral-800 dark:text-neutral-300',
@@ -100,7 +100,11 @@
100
100
 
101
101
  {#if presence}
102
102
  <span
103
- class="absolute right-0 bottom-0 rounded-full ring-white dark:ring-neutral-900 {presenceColor} {presenceSize}"
103
+ class={cn(
104
+ 'absolute right-0 bottom-0 rounded-full ring-white dark:ring-neutral-900',
105
+ presenceColor,
106
+ presenceSize
107
+ )}
104
108
  ></span>
105
109
  {/if}
106
110
  </div>
@@ -1,4 +1,4 @@
1
- import { type VariantProps } from '../../utils/cn.js';
1
+ import { type VariantProps } from '../../utils/cn';
2
2
  export declare const avatarVariants: import("tailwind-variants").TVReturnType<{
3
3
  size: {
4
4
  xs: "h-6 w-6 text-[10px]";
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from 'svelte';
3
+ import { cn } from '../../utils/cn';
3
4
 
4
5
  interface Props {
5
6
  class?: string;
@@ -10,7 +11,10 @@
10
11
  </script>
11
12
 
12
13
  <div
13
- class="inline-flex items-center -space-x-2 *:ring-2 *:ring-white dark:*:ring-neutral-900 {className}"
14
+ class={cn(
15
+ 'inline-flex items-center -space-x-2 *:ring-2 *:ring-white dark:*:ring-neutral-900',
16
+ className
17
+ )}
14
18
  >
15
19
  {#if children}
16
20
  {@render children()}
@@ -1,5 +1,5 @@
1
1
  <script module lang="ts">
2
- import { tv, type VariantProps } from '../../utils/cn.js';
2
+ import { tv, cn, type VariantProps } from '../../utils/cn';
3
3
  import type { Snippet } from 'svelte';
4
4
  import type { IconSource } from './Icon.svelte';
5
5
 
@@ -183,13 +183,16 @@
183
183
  <span class={classes}>
184
184
  {#if dot}
185
185
  <span
186
- class="h-1.5 w-1.5 rounded-full {color === 'success'
187
- ? 'bg-emerald-500'
188
- : color === 'warning'
189
- ? 'bg-amber-500'
190
- : color === 'error'
191
- ? 'bg-rose-500'
192
- : 'bg-primary-500'}"
186
+ class={cn(
187
+ 'h-1.5 w-1.5 rounded-full',
188
+ color === 'success'
189
+ ? 'bg-emerald-500'
190
+ : color === 'warning'
191
+ ? 'bg-amber-500'
192
+ : color === 'error'
193
+ ? 'bg-rose-500'
194
+ : 'bg-primary-500'
195
+ )}
193
196
  ></span>
194
197
  {/if}
195
198
 
@@ -1,4 +1,4 @@
1
- import { type VariantProps } from '../../utils/cn.js';
1
+ import { type VariantProps } from '../../utils/cn';
2
2
  import type { Snippet } from 'svelte';
3
3
  import type { IconSource } from './Icon.svelte';
4
4
  export declare const badgeVariants: import("tailwind-variants").TVReturnType<{
@@ -1,5 +1,5 @@
1
1
  <script module lang="ts">
2
- import { tv, type VariantProps } from '../../utils/cn.js';
2
+ import { tv, type VariantProps } from '../../utils/cn';
3
3
  import type { Snippet } from 'svelte';
4
4
  import type { HTMLButtonAttributes, HTMLAnchorAttributes } from 'svelte/elements';
5
5
  import type { IconSource } from './Icon.svelte';
@@ -1,4 +1,4 @@
1
- import { type VariantProps } from '../../utils/cn.js';
1
+ import { type VariantProps } from '../../utils/cn';
2
2
  import type { Snippet } from 'svelte';
3
3
  import type { IconSource } from './Icon.svelte';
4
4
  export declare const buttonVariants: import("tailwind-variants").TVReturnType<{
@@ -1,5 +1,5 @@
1
1
  <script module lang="ts">
2
- import { tv, type VariantProps } from '../../utils/cn.js';
2
+ import { tv, type VariantProps } from '../../utils/cn';
3
3
  import type { Snippet } from 'svelte';
4
4
 
5
5
  export const carouselVariants = tv({
@@ -1,10 +1,10 @@
1
- import { type VariantProps } from '../../utils/cn.js';
1
+ import { type VariantProps } from '../../utils/cn';
2
2
  import type { Snippet } from 'svelte';
3
3
  export declare const carouselVariants: import("tailwind-variants").TVReturnType<{
4
4
  [key: string]: {
5
5
  [key: string]: import("tailwind-variants").ClassValue | {
6
- viewport?: import("tailwind-variants").ClassValue;
7
6
  root?: import("tailwind-variants").ClassValue;
7
+ viewport?: import("tailwind-variants").ClassValue;
8
8
  slide?: import("tailwind-variants").ClassValue;
9
9
  controls?: import("tailwind-variants").ClassValue;
10
10
  arrowBtn?: import("tailwind-variants").ClassValue;
@@ -15,8 +15,8 @@ export declare const carouselVariants: import("tailwind-variants").TVReturnType<
15
15
  } | {
16
16
  [x: string]: {
17
17
  [x: string]: import("tailwind-variants").ClassValue | {
18
- viewport?: import("tailwind-variants").ClassValue;
19
18
  root?: import("tailwind-variants").ClassValue;
19
+ viewport?: import("tailwind-variants").ClassValue;
20
20
  slide?: import("tailwind-variants").ClassValue;
21
21
  controls?: import("tailwind-variants").ClassValue;
22
22
  arrowBtn?: import("tailwind-variants").ClassValue;
@@ -35,8 +35,8 @@ export declare const carouselVariants: import("tailwind-variants").TVReturnType<
35
35
  }, undefined, {
36
36
  [key: string]: {
37
37
  [key: string]: import("tailwind-variants").ClassValue | {
38
- viewport?: import("tailwind-variants").ClassValue;
39
38
  root?: import("tailwind-variants").ClassValue;
39
+ viewport?: import("tailwind-variants").ClassValue;
40
40
  slide?: import("tailwind-variants").ClassValue;
41
41
  controls?: import("tailwind-variants").ClassValue;
42
42
  arrowBtn?: import("tailwind-variants").ClassValue;
@@ -243,7 +243,7 @@
243
243
  <script lang="ts">
244
244
  import Button from './Button.svelte';
245
245
  import Icon from './Icon.svelte';
246
- import { useToast } from '../../composables/useToast.svelte.js';
246
+ import { useToast } from '../../composables/useToast.svelte';
247
247
 
248
248
  let {
249
249
  code,