@girardmedia/bootspring 3.3.2 → 3.4.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 (171) hide show
  1. package/assets/agents/accessibility-auditor.md +39 -0
  2. package/assets/agents/api-designer.md +40 -0
  3. package/assets/agents/auth-implementer.md +64 -0
  4. package/assets/agents/bug-hunter.md +42 -0
  5. package/assets/agents/bundle-analyzer.md +40 -0
  6. package/assets/agents/cache-optimizer.md +55 -0
  7. package/assets/agents/changelog-writer.md +55 -0
  8. package/assets/agents/ci-cd-builder.md +40 -0
  9. package/assets/agents/code-explainer.md +39 -0
  10. package/assets/agents/code-reviewer.md +39 -0
  11. package/assets/agents/cost-optimizer.md +57 -0
  12. package/assets/agents/cron-scheduler.md +51 -0
  13. package/assets/agents/data-seeder.md +56 -0
  14. package/assets/agents/database-architect.md +40 -0
  15. package/assets/agents/dependency-updater.md +40 -0
  16. package/assets/agents/deploy-checker.md +40 -0
  17. package/assets/agents/docker-optimizer.md +40 -0
  18. package/assets/agents/documentation-writer.md +40 -0
  19. package/assets/agents/email-builder.md +55 -0
  20. package/assets/agents/env-setup.md +40 -0
  21. package/assets/agents/error-handler.md +40 -0
  22. package/assets/agents/eslint-fixer.md +46 -0
  23. package/assets/agents/feature-flagger.md +69 -0
  24. package/assets/agents/git-detective.md +39 -0
  25. package/assets/agents/graphql-builder.md +60 -0
  26. package/assets/agents/incident-responder.md +59 -0
  27. package/assets/agents/log-analyzer.md +39 -0
  28. package/assets/agents/migration-planner.md +41 -0
  29. package/assets/agents/monorepo-navigator.md +39 -0
  30. package/assets/agents/nextjs-expert.md +57 -0
  31. package/assets/agents/notification-builder.md +56 -0
  32. package/assets/agents/onboarding-guide.md +39 -0
  33. package/assets/agents/performance-profiler.md +40 -0
  34. package/assets/agents/prisma-expert.md +57 -0
  35. package/assets/agents/rate-limiter.md +58 -0
  36. package/assets/agents/react-expert.md +58 -0
  37. package/assets/agents/refactorer.md +42 -0
  38. package/assets/agents/regex-builder.md +46 -0
  39. package/assets/agents/release-manager.md +40 -0
  40. package/assets/agents/s3-manager.md +58 -0
  41. package/assets/agents/schema-validator.md +40 -0
  42. package/assets/agents/search-builder.md +62 -0
  43. package/assets/agents/security-auditor.md +39 -0
  44. package/assets/agents/sitemap-generator.md +53 -0
  45. package/assets/agents/stripe-integrator.md +59 -0
  46. package/assets/agents/tailwind-expert.md +55 -0
  47. package/assets/agents/tech-debt-tracker.md +39 -0
  48. package/assets/agents/test-writer.md +42 -0
  49. package/assets/agents/type-fixer.md +45 -0
  50. package/assets/agents/webhook-builder.md +54 -0
  51. package/assets/rules/cpp.md +53 -0
  52. package/assets/rules/css.md +52 -0
  53. package/assets/rules/go.md +50 -0
  54. package/assets/rules/html.md +52 -0
  55. package/assets/rules/java.md +51 -0
  56. package/assets/rules/kotlin.md +50 -0
  57. package/assets/rules/php.md +51 -0
  58. package/assets/rules/python.md +51 -0
  59. package/assets/rules/ruby.md +51 -0
  60. package/assets/rules/rust.md +49 -0
  61. package/assets/rules/shell.md +52 -0
  62. package/assets/rules/sql.md +49 -0
  63. package/assets/rules/swift.md +50 -0
  64. package/assets/rules/typescript.md +52 -0
  65. package/assets/rules/yaml-json.md +51 -0
  66. package/assets/skills/accessibility.md +210 -0
  67. package/assets/skills/agent-patterns.md +387 -0
  68. package/assets/skills/ai-integration.md +263 -0
  69. package/assets/skills/animation-patterns.md +224 -0
  70. package/assets/skills/api-design.md +218 -0
  71. package/assets/skills/api-gateway.md +341 -0
  72. package/assets/skills/api-versioning.md +226 -0
  73. package/assets/skills/astro-patterns.md +233 -0
  74. package/assets/skills/auth-patterns.md +248 -0
  75. package/assets/skills/aws-patterns.md +171 -0
  76. package/assets/skills/background-jobs.md +162 -0
  77. package/assets/skills/browser-extensions.md +309 -0
  78. package/assets/skills/caching-patterns.md +253 -0
  79. package/assets/skills/ci-cd.md +251 -0
  80. package/assets/skills/cli-development.md +296 -0
  81. package/assets/skills/code-review.md +185 -0
  82. package/assets/skills/cron-patterns.md +327 -0
  83. package/assets/skills/data-fetching.md +231 -0
  84. package/assets/skills/database-migrations.md +346 -0
  85. package/assets/skills/database-patterns.md +219 -0
  86. package/assets/skills/debugging.md +281 -0
  87. package/assets/skills/design-system.md +289 -0
  88. package/assets/skills/django-patterns.md +182 -0
  89. package/assets/skills/docker-patterns.md +235 -0
  90. package/assets/skills/e2e-testing.md +287 -0
  91. package/assets/skills/edge-computing.md +268 -0
  92. package/assets/skills/electron-patterns.md +266 -0
  93. package/assets/skills/email-templates.md +206 -0
  94. package/assets/skills/error-handling.md +265 -0
  95. package/assets/skills/event-driven.md +232 -0
  96. package/assets/skills/express-patterns.md +239 -0
  97. package/assets/skills/fastapi-patterns.md +198 -0
  98. package/assets/skills/feature-flags.md +212 -0
  99. package/assets/skills/figma-to-code.md +298 -0
  100. package/assets/skills/file-upload.md +228 -0
  101. package/assets/skills/forms-patterns.md +264 -0
  102. package/assets/skills/gcp-patterns.md +189 -0
  103. package/assets/skills/git-workflow.md +187 -0
  104. package/assets/skills/golang-patterns.md +185 -0
  105. package/assets/skills/graphql-patterns.md +244 -0
  106. package/assets/skills/i18n-patterns.md +172 -0
  107. package/assets/skills/image-processing.md +350 -0
  108. package/assets/skills/java-springboot.md +226 -0
  109. package/assets/skills/kotlin-patterns.md +207 -0
  110. package/assets/skills/kubernetes-patterns.md +326 -0
  111. package/assets/skills/laravel-patterns.md +261 -0
  112. package/assets/skills/llm-fine-tuning.md +335 -0
  113. package/assets/skills/load-testing.md +303 -0
  114. package/assets/skills/logging-observability.md +228 -0
  115. package/assets/skills/markdown-processing.md +318 -0
  116. package/assets/skills/mcp-server-patterns.md +292 -0
  117. package/assets/skills/microservices.md +272 -0
  118. package/assets/skills/migration-patterns.md +239 -0
  119. package/assets/skills/mongodb-patterns.md +189 -0
  120. package/assets/skills/monorepo-patterns.md +287 -0
  121. package/assets/skills/nextjs-app-router.md +237 -0
  122. package/assets/skills/notification-patterns.md +348 -0
  123. package/assets/skills/oauth-patterns.md +246 -0
  124. package/assets/skills/payment-integration.md +222 -0
  125. package/assets/skills/pdf-generation.md +307 -0
  126. package/assets/skills/performance-optimization.md +277 -0
  127. package/assets/skills/php-patterns.md +210 -0
  128. package/assets/skills/prisma-patterns.md +241 -0
  129. package/assets/skills/prompt-engineering.md +193 -0
  130. package/assets/skills/pwa-patterns.md +247 -0
  131. package/assets/skills/python-patterns.md +158 -0
  132. package/assets/skills/python-testing.md +172 -0
  133. package/assets/skills/queue-patterns.md +295 -0
  134. package/assets/skills/rag-patterns.md +159 -0
  135. package/assets/skills/rate-limiting.md +319 -0
  136. package/assets/skills/react-components.md +201 -0
  137. package/assets/skills/react-native-patterns.md +299 -0
  138. package/assets/skills/real-time-patterns.md +181 -0
  139. package/assets/skills/redis-patterns.md +188 -0
  140. package/assets/skills/refactoring.md +218 -0
  141. package/assets/skills/regex-patterns.md +191 -0
  142. package/assets/skills/remix-patterns.md +262 -0
  143. package/assets/skills/responsive-design.md +199 -0
  144. package/assets/skills/ruby-rails-patterns.md +178 -0
  145. package/assets/skills/rust-patterns.md +211 -0
  146. package/assets/skills/search-patterns.md +227 -0
  147. package/assets/skills/security-hardening.md +237 -0
  148. package/assets/skills/seo-patterns.md +179 -0
  149. package/assets/skills/serverless-patterns.md +223 -0
  150. package/assets/skills/sql-optimization.md +154 -0
  151. package/assets/skills/state-management.md +254 -0
  152. package/assets/skills/storybook-patterns.md +330 -0
  153. package/assets/skills/svelte-patterns.md +258 -0
  154. package/assets/skills/swift-patterns.md +227 -0
  155. package/assets/skills/tailwind-patterns.md +272 -0
  156. package/assets/skills/tdd-workflow.md +199 -0
  157. package/assets/skills/terraform-patterns.md +270 -0
  158. package/assets/skills/testing-react.md +240 -0
  159. package/assets/skills/testing-vitest.md +232 -0
  160. package/assets/skills/typescript-strict.md +159 -0
  161. package/assets/skills/video-processing.md +340 -0
  162. package/assets/skills/vue-patterns.md +247 -0
  163. package/assets/skills/web-workers.md +327 -0
  164. package/assets/skills/webhooks-patterns.md +283 -0
  165. package/assets/skills/websocket-patterns.md +306 -0
  166. package/dist/cli/index.js +941 -958
  167. package/dist/core/index.d.ts +341 -11
  168. package/dist/core.js +58 -95
  169. package/dist/mcp/index.d.ts +33 -1
  170. package/dist/mcp-server.js +177 -255
  171. package/package.json +4 -1
@@ -0,0 +1,330 @@
1
+ ---
2
+ name: storybook-patterns
3
+ description: Storybook patterns for CSF3 stories, args, decorators, play functions, visual regression testing, and addon configuration.
4
+ ---
5
+
6
+ # Storybook Patterns
7
+
8
+ ## When to Use
9
+ Use Storybook to develop, document, and test UI components in isolation. These patterns cover Component Story Format 3 (CSF3), args-based stories, decorators for context providers, play functions for interaction testing, and visual regression testing. Storybook is essential when building a component library, onboarding new developers, or establishing visual QA workflows.
10
+
11
+ ## How It Works
12
+
13
+ ### CSF3 Story Structure
14
+
15
+ ```typescript
16
+ // components/Button/Button.stories.tsx
17
+ import type { Meta, StoryObj } from '@storybook/react';
18
+ import { Button } from './Button';
19
+
20
+ const meta = {
21
+ title: 'Components/Button',
22
+ component: Button,
23
+ parameters: {
24
+ layout: 'centered',
25
+ docs: {
26
+ description: { component: 'Primary UI button with multiple variants and sizes.' },
27
+ },
28
+ },
29
+ argTypes: {
30
+ variant: {
31
+ control: 'select',
32
+ options: ['primary', 'secondary', 'ghost', 'danger'],
33
+ description: 'Visual style variant',
34
+ table: { defaultValue: { summary: 'primary' } },
35
+ },
36
+ size: {
37
+ control: 'radio',
38
+ options: ['sm', 'md', 'lg'],
39
+ },
40
+ disabled: { control: 'boolean' },
41
+ loading: { control: 'boolean' },
42
+ onClick: { action: 'clicked' },
43
+ },
44
+ tags: ['autodocs'],
45
+ } satisfies Meta<typeof Button>;
46
+
47
+ export default meta;
48
+ type Story = StoryObj<typeof meta>;
49
+
50
+ export const Primary: Story = {
51
+ args: { children: 'Button', variant: 'primary', size: 'md' },
52
+ };
53
+
54
+ export const Secondary: Story = {
55
+ args: { children: 'Button', variant: 'secondary' },
56
+ };
57
+
58
+ export const Loading: Story = {
59
+ args: { children: 'Saving...', loading: true },
60
+ };
61
+
62
+ export const Disabled: Story = {
63
+ args: { children: 'Unavailable', disabled: true },
64
+ };
65
+ ```
66
+
67
+ ### Composite Stories (All Variants)
68
+
69
+ ```typescript
70
+ export const AllVariants: Story = {
71
+ render: () => (
72
+ <div className="flex flex-col gap-4">
73
+ <div className="flex gap-2 items-center">
74
+ {(['primary', 'secondary', 'ghost', 'danger'] as const).map((variant) => (
75
+ <Button key={variant} variant={variant}>{variant}</Button>
76
+ ))}
77
+ </div>
78
+ <div className="flex gap-2 items-center">
79
+ {(['sm', 'md', 'lg'] as const).map((size) => (
80
+ <Button key={size} size={size}>Size {size}</Button>
81
+ ))}
82
+ </div>
83
+ </div>
84
+ ),
85
+ parameters: { controls: { disable: true } },
86
+ };
87
+
88
+ export const DarkMode: Story = {
89
+ args: { children: 'Dark Mode', variant: 'primary' },
90
+ decorators: [
91
+ (Story) => (
92
+ <div className="dark bg-gray-900 p-8 rounded-lg">
93
+ <Story />
94
+ </div>
95
+ ),
96
+ ],
97
+ };
98
+ ```
99
+
100
+ ### Decorators (Context Providers)
101
+
102
+ ```typescript
103
+ // .storybook/preview.tsx
104
+ import type { Preview } from '@storybook/react';
105
+ import { ThemeProvider } from '../src/providers/ThemeProvider';
106
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
107
+ import '../src/styles/globals.css';
108
+
109
+ const queryClient = new QueryClient({
110
+ defaultOptions: { queries: { retry: false, staleTime: Infinity } },
111
+ });
112
+
113
+ const preview: Preview = {
114
+ decorators: [
115
+ // Theme provider wrapper
116
+ (Story, context) => (
117
+ <ThemeProvider defaultTheme={context.globals.theme ?? 'light'}>
118
+ <Story />
119
+ </ThemeProvider>
120
+ ),
121
+ // React Query provider
122
+ (Story) => (
123
+ <QueryClientProvider client={queryClient}>
124
+ <Story />
125
+ </QueryClientProvider>
126
+ ),
127
+ // Layout padding
128
+ (Story) => (
129
+ <div className="p-4">
130
+ <Story />
131
+ </div>
132
+ ),
133
+ ],
134
+ globalTypes: {
135
+ theme: {
136
+ description: 'Global theme',
137
+ toolbar: {
138
+ title: 'Theme',
139
+ icon: 'circlehollow',
140
+ items: ['light', 'dark'],
141
+ dynamicTitle: true,
142
+ },
143
+ },
144
+ },
145
+ parameters: {
146
+ actions: { argTypesRegex: '^on[A-Z].*' },
147
+ controls: { matchers: { color: /(background|color)$/i, date: /Date$/i } },
148
+ },
149
+ };
150
+
151
+ export default preview;
152
+ ```
153
+
154
+ ### Play Functions (Interaction Testing)
155
+
156
+ ```typescript
157
+ // components/LoginForm/LoginForm.stories.tsx
158
+ import { within, userEvent, expect, waitFor } from '@storybook/test';
159
+
160
+ export const FilledForm: Story = {
161
+ play: async ({ canvasElement }) => {
162
+ const canvas = within(canvasElement);
163
+
164
+ // Type into email field
165
+ const emailInput = canvas.getByLabelText('Email');
166
+ await userEvent.clear(emailInput);
167
+ await userEvent.type(emailInput, 'user@example.com');
168
+
169
+ // Type into password field
170
+ const passwordInput = canvas.getByLabelText('Password');
171
+ await userEvent.clear(passwordInput);
172
+ await userEvent.type(passwordInput, 'SecurePass123');
173
+
174
+ // Verify values
175
+ expect(emailInput).toHaveValue('user@example.com');
176
+ expect(passwordInput).toHaveValue('SecurePass123');
177
+ },
178
+ };
179
+
180
+ export const SubmitWithValidation: Story = {
181
+ play: async ({ canvasElement }) => {
182
+ const canvas = within(canvasElement);
183
+
184
+ // Submit empty form
185
+ const submitButton = canvas.getByRole('button', { name: /sign in/i });
186
+ await userEvent.click(submitButton);
187
+
188
+ // Check validation errors
189
+ await waitFor(() => {
190
+ expect(canvas.getByText('Email is required')).toBeInTheDocument();
191
+ });
192
+
193
+ // Fill and submit
194
+ await userEvent.type(canvas.getByLabelText('Email'), 'user@example.com');
195
+ await userEvent.type(canvas.getByLabelText('Password'), 'SecurePass123');
196
+ await userEvent.click(submitButton);
197
+
198
+ // Verify errors cleared
199
+ await waitFor(() => {
200
+ expect(canvas.queryByText('Email is required')).not.toBeInTheDocument();
201
+ });
202
+ },
203
+ };
204
+ ```
205
+
206
+ ### MSW Integration (Mocked API)
207
+
208
+ ```typescript
209
+ // components/UserProfile/UserProfile.stories.tsx
210
+ import { http, HttpResponse } from 'msw';
211
+
212
+ export const WithData: Story = {
213
+ parameters: {
214
+ msw: {
215
+ handlers: [
216
+ http.get('/api/user/profile', () =>
217
+ HttpResponse.json({
218
+ name: 'Jane Doe',
219
+ email: 'jane@example.com',
220
+ avatar: 'https://placekitten.com/200/200',
221
+ })
222
+ ),
223
+ ],
224
+ },
225
+ },
226
+ };
227
+
228
+ export const Loading: Story = {
229
+ parameters: {
230
+ msw: {
231
+ handlers: [
232
+ http.get('/api/user/profile', async () => {
233
+ await new Promise((r) => setTimeout(r, 999999)); // never resolves
234
+ return HttpResponse.json({});
235
+ }),
236
+ ],
237
+ },
238
+ },
239
+ };
240
+
241
+ export const Error: Story = {
242
+ parameters: {
243
+ msw: {
244
+ handlers: [
245
+ http.get('/api/user/profile', () =>
246
+ HttpResponse.json({ error: 'Unauthorized' }, { status: 401 })
247
+ ),
248
+ ],
249
+ },
250
+ },
251
+ };
252
+ ```
253
+
254
+ ### Visual Regression with Chromatic
255
+
256
+ ```typescript
257
+ // .storybook/main.ts
258
+ import type { StorybookConfig } from '@storybook/react-vite';
259
+
260
+ const config: StorybookConfig = {
261
+ stories: ['../src/**/*.stories.@(ts|tsx)'],
262
+ addons: [
263
+ '@storybook/addon-essentials',
264
+ '@storybook/addon-interactions',
265
+ '@storybook/addon-a11y',
266
+ '@chromatic-com/storybook',
267
+ ],
268
+ framework: '@storybook/react-vite',
269
+ };
270
+
271
+ export default config;
272
+ ```
273
+
274
+ ```yaml
275
+ # .github/workflows/chromatic.yml
276
+ name: Visual Tests
277
+ on: push
278
+ jobs:
279
+ chromatic:
280
+ runs-on: ubuntu-latest
281
+ steps:
282
+ - uses: actions/checkout@v4
283
+ with: { fetch-depth: 0 }
284
+ - uses: actions/setup-node@v4
285
+ with: { node-version: 20, cache: npm }
286
+ - run: npm ci
287
+ - uses: chromaui/action@latest
288
+ with:
289
+ projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
290
+ exitOnceUploaded: true
291
+ ```
292
+
293
+ ### Accessibility Testing Addon
294
+
295
+ ```typescript
296
+ // Per-story a11y configuration
297
+ export const AccessibleButton: Story = {
298
+ args: { children: 'Click me', variant: 'primary' },
299
+ parameters: {
300
+ a11y: {
301
+ config: {
302
+ rules: [
303
+ { id: 'color-contrast', enabled: true },
304
+ { id: 'button-name', enabled: true },
305
+ ],
306
+ },
307
+ },
308
+ },
309
+ };
310
+ ```
311
+
312
+ ## Examples
313
+
314
+ | Story Type | Purpose | Key Feature |
315
+ |------------|---------|-------------|
316
+ | Args-based | Default prop permutations | Controls panel auto-generated |
317
+ | Composite render | All variants at once | Visual comparison grid |
318
+ | Play function | Interaction simulation | Click, type, assert in browser |
319
+ | MSW handler | API state simulation | Loading, success, error states |
320
+ | Chromatic snapshot | Visual regression | Pixel-diff on every PR |
321
+
322
+ ## Checklist
323
+ - [ ] Stories use CSF3 format with `satisfies Meta<typeof Component>`
324
+ - [ ] `argTypes` defined for every configurable prop with descriptions
325
+ - [ ] `tags: ['autodocs']` enabled for automatic documentation generation
326
+ - [ ] Decorators provide all necessary context (theme, router, query client)
327
+ - [ ] Play functions test critical interaction flows with assertions
328
+ - [ ] MSW handlers mock all API states (success, loading, error)
329
+ - [ ] `@storybook/addon-a11y` enabled for accessibility violation detection
330
+ - [ ] Visual regression testing configured (Chromatic or Percy) in CI
@@ -0,0 +1,258 @@
1
+ ---
2
+ name: svelte-patterns
3
+ description: Svelte patterns for reactivity, stores, actions, transitions, SvelteKit routing, and load functions.
4
+ ---
5
+
6
+ # Svelte Patterns
7
+
8
+ ## When to Use
9
+
10
+ Apply these patterns when building Svelte 4/5 or SvelteKit applications. Use this
11
+ skill for understanding Svelte's reactivity model, creating and using stores,
12
+ adding DOM behavior with actions, animating with transitions, and structuring
13
+ SvelteKit routes with load functions.
14
+
15
+ ## How It Works
16
+
17
+ ### Reactivity
18
+
19
+ Svelte's reactivity is compile-time. In Svelte 4, use `$:` for reactive
20
+ declarations. In Svelte 5 (runes), use `$state`, `$derived`, and `$effect`.
21
+
22
+ ```svelte
23
+ <!-- Svelte 5 (runes) -->
24
+ <script lang="ts">
25
+ let count = $state(0)
26
+ let doubled = $derived(count * 2)
27
+ let items = $state<string[]>([])
28
+
29
+ $effect(() => {
30
+ console.log(`Count changed to ${count}`)
31
+ // cleanup returned automatically on re-run
32
+ return () => console.log('cleaning up')
33
+ })
34
+
35
+ function addItem(text: string) {
36
+ items.push(text) // mutations tracked automatically with runes
37
+ }
38
+ </script>
39
+
40
+ <button onclick={() => count++}>
41
+ {count} (doubled: {doubled})
42
+ </button>
43
+ ```
44
+
45
+ ```svelte
46
+ <!-- Svelte 4 (legacy reactive) -->
47
+ <script lang="ts">
48
+ let count = 0
49
+ $: doubled = count * 2
50
+ $: if (count > 10) {
51
+ console.log('count is high')
52
+ }
53
+ </script>
54
+ ```
55
+
56
+ ### Stores
57
+
58
+ Use writable stores for shared state. Use derived stores for computed values.
59
+ Use readable stores for external data sources. Subscribe with `$store` syntax.
60
+
61
+ ```typescript
62
+ // stores/auth.ts
63
+ import { writable, derived } from 'svelte/store'
64
+
65
+ interface User { id: string; name: string; role: string }
66
+
67
+ export const currentUser = writable<User | null>(null)
68
+ export const isAuthenticated = derived(currentUser, $user => $user !== null)
69
+ export const isAdmin = derived(currentUser, $user => $user?.role === 'admin')
70
+
71
+ export function login(credentials: Credentials) {
72
+ return api.login(credentials).then(user => {
73
+ currentUser.set(user)
74
+ })
75
+ }
76
+
77
+ export function logout() {
78
+ currentUser.set(null)
79
+ }
80
+ ```
81
+
82
+ ```svelte
83
+ <script>
84
+ import { currentUser, isAuthenticated, logout } from '$lib/stores/auth'
85
+ </script>
86
+
87
+ {#if $isAuthenticated}
88
+ <p>Welcome, {$currentUser.name}</p>
89
+ <button onclick={logout}>Logout</button>
90
+ {:else}
91
+ <a href="/login">Sign in</a>
92
+ {/if}
93
+ ```
94
+
95
+ ### Actions
96
+
97
+ Actions add reusable DOM behavior to elements. Use them for click-outside
98
+ detection, tooltips, focus traps, and intersection observers.
99
+
100
+ ```typescript
101
+ // actions/clickOutside.ts
102
+ export function clickOutside(node: HTMLElement, callback: () => void) {
103
+ function handleClick(event: MouseEvent) {
104
+ if (!node.contains(event.target as Node)) {
105
+ callback()
106
+ }
107
+ }
108
+
109
+ document.addEventListener('click', handleClick, true)
110
+
111
+ return {
112
+ destroy() {
113
+ document.removeEventListener('click', handleClick, true)
114
+ }
115
+ }
116
+ }
117
+
118
+ // actions/lazyLoad.ts
119
+ export function lazyLoad(node: HTMLImageElement) {
120
+ const observer = new IntersectionObserver((entries) => {
121
+ entries.forEach(entry => {
122
+ if (entry.isIntersecting) {
123
+ const src = node.dataset.src
124
+ if (src) node.src = src
125
+ observer.unobserve(node)
126
+ }
127
+ })
128
+ })
129
+ observer.observe(node)
130
+ return { destroy: () => observer.disconnect() }
131
+ }
132
+ ```
133
+
134
+ ```svelte
135
+ <div use:clickOutside={() => menuOpen = false}>
136
+ <DropdownMenu bind:open={menuOpen} />
137
+ </div>
138
+
139
+ <img use:lazyLoad data-src="/large-image.jpg" alt="Lazy loaded" />
140
+ ```
141
+
142
+ ### Transitions
143
+
144
+ Svelte has built-in transition directives. Use `transition:` for enter+leave,
145
+ `in:` and `out:` for separate control. Combine with `animate:flip` for list
146
+ reordering.
147
+
148
+ ```svelte
149
+ <script>
150
+ import { fade, slide, fly } from 'svelte/transition'
151
+ import { flip } from 'svelte/animate'
152
+
153
+ let items = $state([...])
154
+ let visible = $state(true)
155
+ </script>
156
+
157
+ {#if visible}
158
+ <div transition:fade={{ duration: 200 }}>
159
+ Fades in and out
160
+ </div>
161
+ {/if}
162
+
163
+ {#each items as item (item.id)}
164
+ <div
165
+ animate:flip={{ duration: 300 }}
166
+ in:fly={{ y: 20, duration: 200 }}
167
+ out:fade={{ duration: 150 }}
168
+ >
169
+ {item.text}
170
+ </div>
171
+ {/each}
172
+ ```
173
+
174
+ ### SvelteKit Routing
175
+
176
+ File-based routing with `+page.svelte`, `+layout.svelte`, `+page.server.ts`.
177
+ Use `+page.ts` for universal load, `+page.server.ts` for server-only load.
178
+
179
+ ```
180
+ routes/
181
+ +layout.svelte # root layout
182
+ +page.svelte # home page
183
+ projects/
184
+ +page.svelte # /projects
185
+ +page.server.ts # server load for /projects
186
+ [id]/
187
+ +page.svelte # /projects/:id
188
+ +page.ts # universal load
189
+ +error.svelte # error boundary
190
+ ```
191
+
192
+ ### Load Functions
193
+
194
+ Use `load` functions to fetch data before rendering. Return data as plain objects.
195
+ Use `depends` for invalidation. Throw `error()` for error pages.
196
+
197
+ ```typescript
198
+ // routes/projects/[id]/+page.server.ts
199
+ import { error } from '@sveltejs/kit'
200
+ import type { PageServerLoad } from './$types'
201
+
202
+ export const load: PageServerLoad = async ({ params, locals }) => {
203
+ const project = await db.project.findUnique({
204
+ where: { id: params.id, ownerId: locals.userId }
205
+ })
206
+
207
+ if (!project) {
208
+ throw error(404, 'Project not found')
209
+ }
210
+
211
+ return {
212
+ project,
213
+ tasks: await db.task.findMany({ where: { projectId: params.id } })
214
+ }
215
+ }
216
+ ```
217
+
218
+ ```svelte
219
+ <!-- routes/projects/[id]/+page.svelte -->
220
+ <script lang="ts">
221
+ import type { PageData } from './$types'
222
+ let { data }: { data: PageData } = $props()
223
+ </script>
224
+
225
+ <h1>{data.project.name}</h1>
226
+ {#each data.tasks as task}
227
+ <TaskCard {task} />
228
+ {/each}
229
+ ```
230
+
231
+ ## Examples
232
+
233
+ **Pattern: Form action with progressive enhancement**
234
+ ```typescript
235
+ // +page.server.ts
236
+ export const actions = {
237
+ default: async ({ request }) => {
238
+ const data = await request.formData()
239
+ const name = data.get('name') as string
240
+ if (!name) return fail(400, { name, missing: true })
241
+ await db.project.create({ data: { name } })
242
+ throw redirect(303, '/projects')
243
+ }
244
+ }
245
+ ```
246
+
247
+ ## Checklist
248
+
249
+ - [ ] Svelte 5 runes (`$state`, `$derived`, `$effect`) over `$:` reactive statements
250
+ - [ ] Stores for shared cross-component state; `$store` for auto-subscriptions
251
+ - [ ] Actions (`use:action`) for reusable DOM behavior with proper `destroy` cleanup
252
+ - [ ] Transitions use built-in directives (`transition:`, `in:`, `out:`)
253
+ - [ ] `animate:flip` on `{#each}` blocks with keyed items for smooth reordering
254
+ - [ ] SvelteKit load functions return plain objects, throw `error()` for error pages
255
+ - [ ] Server-only data in `+page.server.ts`, universal data in `+page.ts`
256
+ - [ ] Form actions with `fail()` for validation errors, `redirect()` for success
257
+ - [ ] `$effect` cleanup functions returned for subscriptions and listeners
258
+ - [ ] `{#snippet}` blocks (Svelte 5) for reusable template fragments