@svelte-atoms/core 1.0.0-alpha.31 → 1.0.0-alpha.32

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 (136) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +289 -853
  3. package/dist/attachments/index.d.ts +1 -0
  4. package/dist/attachments/index.js +1 -0
  5. package/dist/components/accordion/accordion-root.svelte +65 -65
  6. package/dist/components/accordion/accordion.stories.svelte +70 -70
  7. package/dist/components/accordion/item/accordion-item-body.svelte +44 -44
  8. package/dist/components/accordion/item/accordion-item-header.svelte +51 -51
  9. package/dist/components/accordion/item/accordion-item-indicator.svelte +51 -51
  10. package/dist/components/accordion/item/accordion-item-root.svelte +66 -66
  11. package/dist/components/alert/alert-close-button.svelte +66 -66
  12. package/dist/components/alert/alert-description.svelte +42 -42
  13. package/dist/components/alert/alert-root.svelte +68 -68
  14. package/dist/components/atom/html-atom.svelte +26 -194
  15. package/dist/components/atom/types.d.ts +3 -2
  16. package/dist/components/atom/utils.d.ts +37 -0
  17. package/dist/components/atom/utils.js +208 -0
  18. package/dist/components/breadcrumb/breadcrumb-item.svelte +1 -1
  19. package/dist/components/breadcrumb/breadcrumb-separator.svelte +5 -1
  20. package/dist/components/breadcrumb/breadcrumb.stories.svelte +16 -16
  21. package/dist/components/calendar/calendar-day.svelte +101 -101
  22. package/dist/components/checkbox/checkbox.svelte +159 -159
  23. package/dist/components/collapsible/bond.svelte.js +2 -1
  24. package/dist/components/collapsible/collapsible-body.svelte +3 -2
  25. package/dist/components/collapsible/motion.svelte.d.ts +6 -0
  26. package/dist/components/collapsible/motion.svelte.js +15 -0
  27. package/dist/components/combobox/atoms.d.ts +3 -3
  28. package/dist/components/combobox/atoms.js +3 -3
  29. package/dist/components/combobox/bond.svelte.d.ts +6 -6
  30. package/dist/components/combobox/bond.svelte.js +3 -26
  31. package/dist/components/combobox/combobox-control.svelte +52 -52
  32. package/dist/components/combobox/{compobox-item.svelte → combobox-item.svelte} +62 -68
  33. package/dist/components/combobox/combobox-item.svelte.d.ts +12 -0
  34. package/dist/components/combobox/combobox.stories.svelte +50 -0
  35. package/dist/components/combobox/combobox.stories.svelte.d.ts +3 -0
  36. package/dist/components/datagrid/tr/datagrid-tr.svelte +90 -90
  37. package/dist/components/date-picker/bond.svelte.d.ts +15 -5
  38. package/dist/components/date-picker/bond.svelte.js +5 -11
  39. package/dist/components/date-picker/date-picker-calendar.svelte +67 -67
  40. package/dist/components/dialog/bond.svelte.js +5 -20
  41. package/dist/components/dialog/dialog-content.svelte +44 -44
  42. package/dist/components/dialog/dialog-root.svelte +91 -91
  43. package/dist/components/drawer/bond.svelte.d.ts +18 -16
  44. package/dist/components/drawer/bond.svelte.js +8 -18
  45. package/dist/components/drawer/drawer-content.svelte +49 -49
  46. package/dist/components/drawer/drawer-root.svelte +5 -4
  47. package/dist/components/drawer/drawer.stories.svelte +141 -144
  48. package/dist/components/drawer/motion.js +1 -1
  49. package/dist/components/dropdown/atoms.d.ts +1 -1
  50. package/dist/components/dropdown/atoms.js +1 -1
  51. package/dist/components/dropdown/bond.svelte.d.ts +21 -22
  52. package/dist/components/dropdown/bond.svelte.js +29 -53
  53. package/dist/components/dropdown/dropdown-root.svelte +65 -59
  54. package/dist/components/dropdown/dropdown-values.svelte +17 -17
  55. package/dist/components/dropdown/dropdown-values.svelte.d.ts +1 -2
  56. package/dist/components/dropdown/dropdown.stories.svelte +83 -80
  57. package/dist/components/dropdown/index.d.ts +1 -0
  58. package/dist/components/dropdown/index.js +1 -0
  59. package/dist/components/dropdown/item/attachments.svelte.d.ts +2 -2
  60. package/dist/components/dropdown/item/attachments.svelte.js +2 -2
  61. package/dist/components/dropdown/item/controller.svelte.d.ts +34 -0
  62. package/dist/components/dropdown/item/controller.svelte.js +82 -0
  63. package/dist/components/dropdown/item/dropdown-item.svelte +109 -102
  64. package/dist/components/dropdown/item/dropdown-item.svelte.d.ts +13 -28
  65. package/dist/components/dropdown/item/index.d.ts +3 -0
  66. package/dist/components/dropdown/item/index.js +3 -0
  67. package/dist/components/dropdown/item/types.d.ts +29 -0
  68. package/dist/components/dropdown/item/types.js +1 -0
  69. package/dist/components/list/list-item.svelte +20 -20
  70. package/dist/components/menu/atoms.d.ts +8 -3
  71. package/dist/components/menu/atoms.js +8 -3
  72. package/dist/components/menu/bond.svelte.d.ts +54 -0
  73. package/dist/components/menu/bond.svelte.js +132 -0
  74. package/dist/components/menu/index.d.ts +1 -0
  75. package/dist/components/menu/index.js +1 -0
  76. package/dist/components/menu/item/controller.svelte.d.ts +26 -0
  77. package/dist/components/menu/item/controller.svelte.js +69 -0
  78. package/dist/components/menu/item/index.d.ts +2 -0
  79. package/dist/components/menu/item/index.js +2 -0
  80. package/dist/components/menu/item/menu-item.svelte +103 -0
  81. package/dist/components/menu/item/menu-item.svelte.d.ts +31 -0
  82. package/dist/components/menu/item/types.d.ts +62 -0
  83. package/dist/components/menu/item/types.js +1 -0
  84. package/dist/components/menu/{menu-list.svelte → menu-content.svelte} +40 -40
  85. package/dist/components/menu/{menu-list.svelte.d.ts → menu-content.svelte.d.ts} +3 -3
  86. package/dist/components/menu/menu-root.svelte +15 -0
  87. package/dist/components/menu/menu-root.svelte.d.ts +8 -0
  88. package/dist/components/menu/menu.stories.svelte +33 -33
  89. package/dist/components/menu/types.d.ts +0 -7
  90. package/dist/components/popover/bond.svelte.d.ts +11 -14
  91. package/dist/components/popover/bond.svelte.js +27 -44
  92. package/dist/components/popover/popover-content.svelte +137 -137
  93. package/dist/components/popover/popover.stories.svelte +37 -49
  94. package/dist/components/portal/active-portal.svelte +29 -29
  95. package/dist/components/portal/portal-root.svelte +76 -76
  96. package/dist/components/portal/teleport.svelte +49 -49
  97. package/dist/components/radio/radio.svelte +109 -109
  98. package/dist/components/root/index.d.ts +1 -0
  99. package/dist/components/root/index.js +1 -0
  100. package/dist/components/root/l0-portal.svelte +8 -0
  101. package/dist/components/root/l0-portal.svelte.d.ts +26 -0
  102. package/dist/components/root/l1-portal.svelte +7 -0
  103. package/dist/components/root/l1-portal.svelte.d.ts +26 -0
  104. package/dist/components/root/root.css +119 -119
  105. package/dist/components/root/root.svelte +17 -18
  106. package/dist/components/root/root.svelte.d.ts +2 -6
  107. package/dist/components/root/toasts-portal.svelte +7 -0
  108. package/dist/components/root/toasts-portal.svelte.d.ts +26 -0
  109. package/dist/components/root/types.d.ts +17 -0
  110. package/dist/components/sidebar/motion.svelte.js +3 -3
  111. package/dist/components/sidebar/sidebar-content.svelte +40 -40
  112. package/dist/components/textarea/textarea-input.svelte +9 -9
  113. package/dist/components/textarea/textarea-root.svelte +9 -9
  114. package/dist/components/tooltip/tooltip-trigger.svelte +39 -39
  115. package/dist/components/tree/index.d.ts +1 -0
  116. package/dist/components/tree/index.js +1 -0
  117. package/dist/components/tree/motion.svelte.d.ts +6 -0
  118. package/dist/components/tree/motion.svelte.js +14 -0
  119. package/dist/components/tree/tree-body.svelte +4 -3
  120. package/dist/context/preset.svelte.d.ts +3 -1
  121. package/dist/icons/icon-copy.svelte +6 -6
  122. package/dist/utils/dom.svelte.d.ts +2 -0
  123. package/dist/utils/dom.svelte.js +21 -0
  124. package/dist/utils/function.d.ts +1 -1
  125. package/dist/utils/promise.svelte.d.ts +5 -0
  126. package/dist/utils/promise.svelte.js +20 -0
  127. package/package.json +4 -2
  128. package/dist/components/combobox/compobox-item.svelte.d.ts +0 -34
  129. package/dist/components/combobox/compobox.stories.svelte +0 -51
  130. package/dist/components/combobox/compobox.stories.svelte.d.ts +0 -3
  131. package/dist/components/dropdown/item/bond.svelte.d.ts +0 -42
  132. package/dist/components/dropdown/item/bond.svelte.js +0 -99
  133. package/dist/components/menu/menu-item.svelte +0 -69
  134. package/dist/components/menu/menu-item.svelte.d.ts +0 -37
  135. package/dist/utils/markdown-to-llm.d.ts +0 -28
  136. package/dist/utils/markdown-to-llm.js +0 -76
package/README.md CHANGED
@@ -1,853 +1,289 @@
1
- # ⚛️ @svelte-atoms/core | Svelte 5 UI Library
2
-
3
- > A modern, modular, and accessible Svelte 5 UI component library built with composability at its core.
4
-
5
- Core UI is a comprehensive Svelte component library that provides fundamental building blocks ("atoms") for creating sophisticated, interactive design systems. Each component is designed with accessibility, type safety, and developer experience in mind. Built with Svelte 5 runes for optimal reactivity and performance.
6
-
7
- [![npm version](https://img.shields.io/npm/v/@svelte-atoms/core.svg)](https://www.npmjs.com/package/@svelte-atoms/core)
8
- [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/svelte-atoms/core)
9
- [![license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
10
-
11
- ---
12
-
13
- ## Features
14
-
15
- ### 🧱 **Bond Architecture**
16
-
17
- Self-contained state management classes that encapsulate component logic and DOM interactions. Bonds communicate through Svelte's context API using standardized `Bond.get()` / `Bond.set()` methods, enabling parent-child relationships without prop drilling.
18
-
19
- ### ♿ **Accessibility First**
20
-
21
- Every component includes proper ARIA attributes, keyboard navigation, and focus management out of the box.
22
-
23
- ### 🔧 **Highly Extensible**
24
-
25
- Easily extend components with custom behaviors, animations, and styling while maintaining the core functionality.
26
-
27
- ### 🎯 **Type Safety**
28
-
29
- Fully written in TypeScript with comprehensive type definitions for a robust development experience.
30
-
31
- ### **Reactive by Design**
32
-
33
- Leverages Svelte's fine-grained reactivity system for optimal performance and smooth user interactions.
34
-
35
- ### 🎨 **Headless & Stylable**
36
-
37
- Components are headless by default, giving you complete control over styling while providing sensible defaults.
38
-
39
- ### 🧩 **Composable**
40
-
41
- Build complex UIs by combining simple, reusable components. Each component is designed to work seamlessly with others through the Bond pattern and context API. Create sophisticated features like multi-level dropdowns, nested accordions, or custom form controls by composing atomic components together.
42
-
43
- ---
44
-
45
- ## 📦 Available Components
46
-
47
- Our comprehensive collection of UI components with implementation status:
48
-
49
- ### Layout & Navigation
50
-
51
- | Component | Description | Status |
52
- | ----------------------------------------------- | ---------------------------- | ------ |
53
- | [**Accordion**](docs/components/accordion.md) | Collapsible content sections | ✅ |
54
- | [**Breadcrumb**](docs/components/breadcrumb.md) | Navigation hierarchy | ✅ |
55
- | [**Sidebar**](docs/components/sidebar.md) | Collapsible side navigation | ✅ |
56
- | [**Tabs**](docs/components/tabs.md) | Tabbed interfaces | ✅ |
57
- | [**Tree**](docs/components/tree.md) | Hierarchical data structures | ✅ |
58
- | **Stepper** | Multi-step process indicator | ❌ |
59
- | **Pagination** | Page navigation controls | ❌ |
60
-
61
- ### Forms & Input
62
-
63
- | Component | Description | Status |
64
- | ------------------------------------------- | ------------------------------------ | ------ |
65
- | [**Button**](docs/components/button.md) | Interactive buttons with variants | ✅ |
66
- | [**Checkbox**](docs/components/checkbox.md) | Multi-select inputs | ✅ |
67
- | [**Combobox**](docs/components/combobox.md) | Searchable select inputs | ✅ |
68
- | [**Input**](docs/components/input.md) | Text input fields | ✅ |
69
- | [**Radio**](docs/components/radio.md) | Single-select inputs | ✅ |
70
- | **Slider** | Range input controls | ❌ |
71
- | **Switch** | Toggle controls | ❌ |
72
- | [**Textarea**](docs/components/textarea.md) | Multi-line text inputs | ✅ |
73
- | [**Form**](docs/components/form.md) | Form validation and state management | ✅ |
74
- | **DatePicker** | Date selection component | ✅ |
75
- | **TimePicker** | Time selection component | ❌ |
76
- | **FileUpload** | File upload component | ❌ |
77
- | **ColorPicker** | Color selection component | ❌ |
78
- | **Rating** | Star rating component | ❌ |
79
-
80
- ### Data Display
81
-
82
- | Component | Description | Status |
83
- | ------------------------------------------- | --------------------------- | ------ |
84
- | [**Avatar**](docs/components/avatar.md) | User profile images | ✅ |
85
- | [**Badge**](docs/components/badge.md) | Status indicators | ✅ |
86
- | [**DataGrid**](docs/components/datagrid.md) | Advanced data tables | ✅ |
87
- | [**Divider**](docs/components/divider.md) | Content separators | ✅ |
88
- | [**Icon**](docs/components/icon.md) | Scalable icons | ✅ |
89
- | [**Label**](docs/components/label.md) | Form labels | ✅ |
90
- | [**Link**](docs/components/link.md) | Navigation links | ✅ |
91
- | [**List**](docs/components/list.md) | Structured lists | ✅ |
92
- | [**Card**](docs/components/card.md) | Content containers | ✅ |
93
- | **Table** | Simple data tables | ❌ |
94
- | **Chip** | Compact information display | ❌ |
95
- | **Progress** | Progress indicators | ❌ |
96
- | **Skeleton** | Loading placeholders | ❌ |
97
- | **Timeline** | Event timeline display | ❌ |
98
- | **Calendar** | Date display component | ✅ |
99
- | **QRCode** | QR code generator | ✅ |
100
-
101
- ### Overlays & Feedback
102
-
103
- | Component | Description | Status |
104
- | ------------------------------------------------- | ------------------------ | ------ |
105
- | [**Dialog**](docs/components/dialog.md) | Modal dialogs | ✅ |
106
- | [**Dropdown**](docs/components/dropdown.md) | Contextual menus | ✅ |
107
- | [**Popover**](docs/components/popover.md) | Contextual information | ✅ |
108
- | [**Toast**](docs/components/toast.md) | Notification messages | ✅ |
109
- | [**Tooltip**](docs/components/tooltip.md) | Contextual hints | ✅ |
110
- | [**ContextMenu**](docs/components/contextmenu.md) | Right-click menus | ✅ |
111
- | [**Drawer**](docs/components/drawer.md) | Slide-out panels | ✅ |
112
- | [**Alert**](docs/components/alert.md) | Alert messages | ✅ |
113
- | **Banner** | Full-width notifications | ❌ |
114
- | **Spotlight** | Feature highlighting | ❌ |
115
-
116
- ### Utilities & Layout
117
-
118
- | Component | Description | Status |
119
- | ------------------------------------------------- | ----------------------------------- | ------ |
120
- | [**Portal**](docs/components/portal.md) | Declare a portal anywhere in DOM | ✅ |
121
- | **Teleport** | Render content in a specific portal | ✅ |
122
- | **Root** | Application root container | ✅ |
123
- | [**Layer**](docs/components/layer.md) | Layer management utility | ✅ |
124
- | [**Collapsible**](docs/components/collapsible.md) | Generic collapsible wrapper | ✅ |
125
- | **Container** | Layout container | ✅ |
126
- | [**Scrollable**](docs/components/scrollable.md) | Custom scrollbar component | ✅ |
127
- | [**Stack**](docs/components/stack.md) | Flexible layout stacking component | ✅ |
128
- | **Spacer** | Space management utility | ❌ |
129
- | **VirtualList** | Virtual scrolling list | ❌ |
130
-
131
- ---
132
-
133
- ## 🏗️ Architecture
134
-
135
- The library is organized into distinct layers for maximum maintainability and extensibility:
136
-
137
- ```
138
- src/lib/
139
- ├── components/ # 30+ Core UI components
140
- ├── shared/ # Base classes (Bond, BondState) and utilities
141
- ├── helpers/ # Helper functions and components
142
- ├── attachments/ # DOM attachment utilities
143
- ├── runes/ # Reactive utilities (Svelte 5 runes)
144
- ├── types/ # TypeScript type definitions
145
- └── utils/ # General utility functions
146
- ```
147
-
148
- ### Bond Pattern
149
-
150
- Each component follows a consistent Bond pattern:
151
-
152
- - **Bond Class**: Manages component state and DOM interactions
153
- - **BondState Class**: Holds reactive component state using Svelte 5 runes
154
- - **Context Methods**: Static `CONTEXT_KEY`, `get()`, and `set()` methods for component communication
155
- - **Component Files**: Svelte components that use the Bond for behavior
156
-
157
- ```typescript
158
- class MyComponentBond extends Bond<MyComponentBondState> {
159
- static CONTEXT_KEY = '@atoms/context/my-component';
160
-
161
- static get(): MyComponentBond | undefined {
162
- return getContext(MyComponentBond.CONTEXT_KEY);
163
- }
164
-
165
- static set(bond: MyComponentBond): MyComponentBond {
166
- return setContext(MyComponentBond.CONTEXT_KEY, bond);
167
- }
168
- }
169
- ```
170
-
171
- ---
172
-
173
- ## 🚀 Quick Start
174
-
175
- ### Installation
176
-
177
- ```bash
178
- # npm
179
- npm install @svelte-atoms/core
180
-
181
- # yarn
182
- yarn install @svelte-atoms/core
183
-
184
- # pnpm
185
- pnpm add @svelte-atoms/core
186
-
187
- # bun
188
- bun add @svelte-atoms/core
189
- ```
190
-
191
- ### Basic Usage
192
-
193
- ```svelte
194
- <script lang="ts">
195
- import { Button, Dialog, Input } from '@svelte-atoms/core';
196
- import '@svelte-atoms/tw';
197
-
198
- let dialogOpen = $state(false);
199
- let inputValue = '';
200
- </script>
201
-
202
- <!-- Simple Button -->
203
- <Button onclick={() => (dialogOpen = true)}>Open Dialog</Button>
204
-
205
- <!-- Dialog with Input -->
206
- <Dialog.Root bind:open={dialogOpen}>
207
- <Dialog.Content>
208
- <Dialog.Header>
209
- <Dialog.Title>Enter your name</Dialog.Title>
210
- </Dialog.Header>
211
- <Dialog.Body>
212
- <Input.Root>
213
- <Input.Value bind:value={inputValue} placeholder="Your name...">
214
- </Input.Root>
215
- </Dialog.Body>
216
- <Dialog.Footer>
217
- <Button.Root onclick={() => (dialogOpen = false)}>Cancel</Button.Root>
218
- <Button.Root variant="primary" onclick={() => (dialogOpen = false)}>Confirm</Button.Root>
219
- </Dialog.Footer>
220
- </Dialog.Content>
221
- </Dialog.Root>
222
- ```
223
-
224
- ### Advanced Usage with Bonds
225
-
226
- For more control, you can use the Bond system directly:
227
-
228
- ```svelte
229
- <script lang="ts">
230
- import { DialogBond, DialogBondState } from '@svelte-atoms/core/dialog';
231
-
232
- const { open = false, disable = false } = $props();
233
-
234
- const bondProps = defineState(
235
- [
236
- defineProperty(
237
- 'open',
238
- () => open,
239
- (v) => (open = v)
240
- ),
241
- defineProperty('disable', () => disable)
242
- ],
243
- {
244
- // Other props
245
- }
246
- );
247
-
248
- // Create dialog state
249
- const dialogState = new DialogBondState(() => bondProps);
250
-
251
- // Create dialog bond
252
- // Make available via context
253
- const dialogBond = new DialogBond(dialogState).share();
254
- </script>
255
-
256
- <div {...dialogBond.root()}>
257
- <button {...dialogBond.trigger()} onclick={() => dialogBond.state.toggle()}>
258
- Toggle Dialog
259
- </button>
260
-
261
- {#if open}
262
- <div {...dialogBond.overlay()}>
263
- <div {...dialogBond.content()}>
264
- <h2 {...dialogBond.title()}>Dialog Title</h2>
265
- <p>Dialog content goes here...</p>
266
- <button onclick={() => dialogBond.state.close()}>Close</button>
267
- </div>
268
- </div>
269
- {/if}
270
- </div>
271
- ```
272
-
273
- ### Advanced Usage With Composition
274
-
275
- This example demonstrates the power of component composition by combining `Dropdown`, `Input`, and animation capabilities to create a searchable multi-select dropdown with smooth transitions:
276
-
277
- ```svelte
278
- <script lang="ts">
279
- import { Dropdown, Input, Root, filter } from '@svelte-atoms/core';
280
- import { flip } from 'svelte/animate';
281
-
282
- // Sample data
283
- let data = [
284
- { id: 1, value: 'apple', text: 'Apple' },
285
- { id: 2, value: 'banana', text: 'Banana' },
286
- { id: 3, value: 'cherry', text: 'Cherry' },
287
- { id: 4, value: 'date', text: 'Date' },
288
- { id: 5, value: 'elderberry', text: 'Elderberry' }
289
- ];
290
-
291
- let open = $state(false);
292
- // Filter items based on search query
293
- const dd = filter(
294
- () => data,
295
- (query, item) => item.text.toLowerCase().includes(query.toLowerCase())
296
- );
297
- </script>
298
-
299
- <Root class="items-center justify-center p-4">
300
- <!-- Multi-select dropdown with search functionality -->
301
- <Dropdown.Root
302
- bind:open
303
- multiple
304
- keys={data.map((item) => item.value)}
305
- onquerychange={(q) => (dd.query = q)}
306
- >
307
- {#snippet children({ dropdown })}
308
- <!-- Compose Dropdown.Trigger with Input.Root for a custom trigger -->
309
- <Dropdown.Trigger
310
- base={Input.Root}
311
- class="h-auto min-h-12 max-w-sm min-w-sm items-center gap-2 rounded-sm px-4 transition-colors duration-200"
312
- onclick={(ev) => {
313
- ev.preventDefault();
314
-
315
- dropdown.state.open();
316
- }}
317
- >
318
- <!-- Display selected values with animation -->
319
- {#each dropdown?.state?.selectedItems ?? [] as item (item.id)}
320
- <div animate:flip={{ duration: 200 }}>
321
- <ADropdown.Value value={item.value} class="text-foreground/80">
322
- {item.text}
323
- </ADropdown.Value>
324
- </div>
325
- {/each}
326
-
327
- <!-- Inline search input within the trigger -->
328
- <Dropdown.Query class="flex-1 px-1" placeholder="Search for fruits..." />
329
- </Dropdown.Trigger>
330
-
331
- <!-- Dropdown list with filtered items -->
332
- <Dropdown.List>
333
- {#each dd.current as item (item.id)}
334
- <div animate:flip={{ duration: 200 }}>
335
- <Dropdown.Item value={item.value}>{item.text}</Dropdown.Item>
336
- </div>
337
- {/each}
338
- </Dropdown.List>
339
- {/snippet}
340
- </Dropdown.Root>
341
- </Root>
342
- ```
343
-
344
- **Key composition features demonstrated:**
345
-
346
- - **Component Fusion**: Using `base={Input.Root}` to compose Dropdown.Trigger with Input styling and behavior
347
- - **Snippet Patterns**: Accessing internal state through snippets for custom rendering
348
- - **Reactive Filtering**: Combining search query state with reactive effects for real-time filtering
349
- - **Smooth Animations**: Using Svelte's `flip` animation for seamless list transitions
350
- - **Multi-Select State**: Managing complex selection state through the Bond pattern
351
-
352
- ### Creating Custom Variants
353
-
354
- @svelte-atoms/core provides a powerful variant system using `defineVariants()` that allows you to create type-safe, reusable component variations with support for compound variants, defaults, and bond state integration.
355
-
356
- #### Basic Variant Definition
357
-
358
- ```typescript
359
- import { defineVariants, type VariantPropsType } from '@svelte-atoms/core/utils';
360
-
361
- const buttonVariants = defineVariants({
362
- class: 'inline-flex items-center justify-center rounded-md font-medium transition-colors',
363
- variants: {
364
- variant: {
365
- primary: 'bg-blue-500 text-white hover:bg-blue-600',
366
- secondary: 'bg-gray-200 text-gray-900 hover:bg-gray-300',
367
- ghost: 'hover:bg-gray-100'
368
- },
369
- size: {
370
- sm: 'h-8 px-3 text-sm',
371
- md: 'h-10 px-4',
372
- lg: 'h-12 px-6 text-lg'
373
- }
374
- },
375
- compounds: [
376
- {
377
- variant: 'primary',
378
- size: 'lg',
379
- class: 'shadow-md font-semibold'
380
- }
381
- ],
382
- defaults: {
383
- variant: 'primary',
384
- size: 'md'
385
- }
386
- });
387
-
388
- // Extract type-safe props
389
- type ButtonVariantProps = VariantPropsType<typeof buttonVariants>;
390
- ```
391
-
392
- #### Local vs Global Variants
393
-
394
- **Local Variants** - Define variants directly in your component:
395
-
396
- ```svelte
397
- <script lang="ts">
398
- import { HtmlAtom } from '@svelte-atoms/core';
399
- import { defineVariants, type VariantPropsType } from '@svelte-atoms/core/utils';
400
-
401
- const buttonVariants = defineVariants({
402
- class: 'rounded-md font-medium',
403
- variants: {
404
- variant: {
405
- primary: 'bg-blue-500 text-white',
406
- secondary: 'bg-gray-500 text-white'
407
- },
408
- size: {
409
- sm: 'px-2 py-1 text-sm',
410
- md: 'px-4 py-2 text-base'
411
- }
412
- },
413
- defaults: {
414
- variant: 'primary',
415
- size: 'md'
416
- }
417
- });
418
-
419
- type ButtonProps = VariantPropsType<typeof buttonVariants> & {
420
- disabled?: boolean;
421
- class?: string;
422
- };
423
-
424
- let { variant, size, disabled = false, class: klass = '', ...props }: ButtonProps = $props();
425
-
426
- const variantProps = $derived(buttonVariants(null, { variant, size }));
427
- </script>
428
-
429
- <HtmlAtom
430
- as="button"
431
- variants={variantProps}
432
- {disabled}
433
- class={[variantProps.class, klass]}
434
- {...props}
435
- >
436
- {@render children?.()}
437
- </HtmlAtom>
438
- ```
439
-
440
- **Global Variants** - Define variants in your theme/preset configuration:
441
-
442
- ```typescript
443
- // +layout.svelte or theme configuration
444
- import { setPreset } from '@svelte-atoms/core/context';
445
-
446
- setPreset({
447
- button: () => ({
448
- class: 'inline-flex items-center justify-center rounded-md font-medium transition-colors',
449
- variants: {
450
- variant: {
451
- default: {
452
- class: 'bg-primary text-primary-foreground hover:bg-primary/90'
453
- },
454
- destructive: {
455
- class: 'bg-destructive text-destructive-foreground hover:bg-destructive/90'
456
- },
457
- outline: {
458
- class: 'border border-input bg-background hover:bg-accent'
459
- }
460
- },
461
- size: {
462
- default: 'h-10 px-4 py-2',
463
- sm: 'h-9 px-3',
464
- lg: 'h-11 px-8'
465
- }
466
- },
467
- compounds: [
468
- {
469
- variant: 'default',
470
- size: 'lg',
471
- class: 'text-base font-semibold'
472
- }
473
- ],
474
- defaults: {
475
- variant: 'default',
476
- size: 'default'
477
- }
478
- })
479
- });
480
- ```
481
-
482
- #### Extending Global Variants
483
-
484
- Combine global presets with local extensions:
485
-
486
- ```svelte
487
- <script lang="ts">
488
- import { HtmlAtom } from '@svelte-atoms/core';
489
- import { defineVariants } from '@svelte-atoms/core/utils';
490
-
491
- // Extend preset variants with local additions
492
- const extendedVariants = defineVariants({
493
- variants: {
494
- variant: {
495
- // Add new variants not in preset
496
- gradient: {
497
- class: 'bg-gradient-to-r from-purple-500 to-pink-500 text-white'
498
- },
499
- neon: {
500
- class: 'bg-black text-green-400 border-2 border-green-400'
501
- }
502
- },
503
- // Add new variant dimension
504
- animated: {
505
- true: 'animate-pulse',
506
- false: ''
507
- }
508
- },
509
- defaults: {
510
- animated: false
511
- }
512
- });
513
-
514
- let { variant, size, animated, ...props } = $props();
515
- </script>
516
-
517
- <HtmlAtom
518
- preset="button"
519
- variants={extendedVariants}
520
- as="button"
521
- {variant}
522
- {size}
523
- {animated}
524
- {...props}
525
- >
526
- {@render children?.()}
527
- </HtmlAtom>
528
- ```
529
-
530
- #### Bond-Reactive Variants
531
-
532
- Variants can react to component state through the Bond pattern:
533
-
534
- ```typescript
535
- const accordionVariants = defineVariants({
536
- class: 'border rounded-md transition-all',
537
- variants: {
538
- state: {
539
- open: (bond) => ({
540
- class: bond?.state?.isOpen ? 'bg-blue-50 border-blue-200' : 'bg-white',
541
- 'aria-expanded': bond?.state?.isOpen,
542
- 'data-state': bond?.state?.isOpen ? 'open' : 'closed'
543
- })
544
- }
545
- }
546
- });
547
-
548
- // Usage with bond
549
- const bond = AccordionBond.get();
550
- const variantProps = $derived(accordionVariants(bond, { state: 'open' }));
551
- ```
552
-
553
- **Variant Features:**
554
-
555
- - ✅ **Type Safety** - Automatic TypeScript inference
556
- - ✅ **Compound Variants** - Apply styles when multiple conditions match
557
- - ✅ **Default Values** - Specify fallback variant values
558
- - ✅ **Bond Integration** - Access component state for reactive styling
559
- - ✅ **Return Attributes** - Not just classes, any HTML attributes
560
- - ✅ **Extensible** - Combine global presets with local variants
561
-
562
- ---
563
-
564
- ## 📖 Documentation
565
-
566
- ### Component Examples
567
-
568
- #### Dropdown with Multiple Selection
569
-
570
- ```svelte
571
- <script lang="ts">
572
- import { Dropdown } from '@svelte-atoms/core';
573
-
574
- let selectedValues = ['option1'];
575
- const options = [
576
- { value: 'option1', label: 'Option 1' },
577
- { value: 'option2', label: 'Option 2' },
578
- { value: 'option3', label: 'Option 3' }
579
- ];
580
- </script>
581
-
582
- <Dropdown.Root multiple bind:values={selectedValues}>
583
- <!-- Access internal bond -->
584
- {#snippet children({ dropdown })}
585
- <Dropdown.Trigger>
586
- Select options ({selectedValues.length} selected)
587
- </Dropdown.Trigger>
588
-
589
- <Dropdown.Content>
590
- {#each options as option}
591
- <Dropdown.Item value={option.value}>
592
- {option.label}
593
- </Dropdown.Item>
594
- {/each}
595
- </Dropdown.Content>
596
- {/snippet}
597
- </Dropdown.Root>
598
- ```
599
-
600
- #### Form with Validation
601
-
602
- ```svelte
603
- <script lang="ts">
604
- import { Form, Input, Button } from '@svelte-atoms/core';
605
- import { z } from 'zod';
606
-
607
- const schema = z.object({
608
- email: z.string().email('Invalid email address'),
609
- password: z.string().min(8, 'Password must be at least 8 characters')
610
- });
611
-
612
- let formData = { email: '', password: '' };
613
- let errors = {};
614
- </script>
615
-
616
- <Form {schema} bind:value={formData} bind:errors>
617
- <Field name="email">
618
- <Field.Label>Email</Field.Label>
619
- <Field.Control>
620
- <Input.Root type="email" placeholder="Enter your email" bind:value={formData.email} />
621
- </Field.Control>
622
- {#if errors.email}
623
- <Form.Error>{errors.email}</Form.Error>
624
- {/if}
625
- </.Field>
626
-
627
- <Field name="password">
628
- <Field.Label>Password</Field.Label>
629
- <Field.Control>
630
- <Input.Root
631
- type="password"
632
- placeholder="Enter your password"
633
- bind:value={formData.password}
634
- />
635
- </Field.Control>
636
- {#if errors.password}
637
- <Field.Error>{errors.password}</Field.Error>
638
- {/if}
639
- </.Field>
640
-
641
- <Button type="submit">Submit</Button>
642
- </Form>
643
- ```
644
-
645
- #### Data Grid with Sorting and Selection
646
-
647
- ```svelte
648
- <script lang="ts">
649
- import { DataGrid, Checkbox } from '@svelte-atoms/core';
650
-
651
- let data = [
652
- { id: 1, name: 'John Doe', email: 'john@example.com', role: 'Admin' },
653
- { id: 2, name: 'Jane Smith', email: 'jane@example.com', role: 'User' },
654
- { id: 3, name: 'Bob Johnson', email: 'bob@example.com', role: 'Editor' }
655
- ];
656
-
657
- let selectedRows = [];
658
- </script>
659
-
660
- <DataGrid.Root {data} bind:selectedRows multiple>
661
- <DataGrid.Header>
662
- <DataGrid.Tr>
663
- <DataGrid.Th>
664
- <Checkbox />
665
- </DataGrid.Th>
666
- <DataGrid.Th sortable="name">Name</DataGrid.Th>
667
- <DataGrid.Th sortable="email">Email</DataGrid.Th>
668
- <DataGrid.Th>Role</DataGrid.Th>
669
- </DataGrid.Tr>
670
- </DataGrid.Header>
671
-
672
- <DataGrid.Body>
673
- {#each data as row}
674
- <DataGrid.Tr value={row.id}>
675
- <DataGrid.Td>
676
- <Checkbox.Root value={row.id} />
677
- </DataGrid.Td>
678
- <DataGrid.Td>{row.name}</DataGrid.Td>
679
- <DataGrid.Td>{row.email}</DataGrid.Td>
680
- <DataGrid.Td>{row.role}</DataGrid.Td>
681
- </DataGrid.Tr>
682
- {/each}
683
- </DataGrid.Body>
684
- </DataGrid.Root>
685
- ```
686
-
687
- ---
688
-
689
- ## 🎨 Styling
690
-
691
- @svelte-atoms/core is completely headless, giving you full control over styling. Here are some approaches:
692
-
693
- ### Using Vanilla CSS
694
-
695
- ```css
696
- /* Default button styles */
697
- .btn {
698
- @apply rounded-md px-4 py-2 font-medium transition-colors;
699
- }
700
-
701
- .btn-primary {
702
- @apply bg-blue-600 text-white hover:bg-blue-700;
703
- }
704
-
705
- .btn-secondary {
706
- @apply bg-gray-200 text-gray-900 hover:bg-gray-300;
707
- }
708
- ```
709
-
710
- ### Using Tailwind CSS
711
-
712
- ```svelte
713
- <Button class="rounded-md bg-blue-600 px-4 py-2 text-white hover:bg-blue-700">Styled Button</Button>
714
- ```
715
-
716
- ---
717
-
718
- ## 🧪 Development
719
-
720
- ### Setup
721
-
722
- 1. **Clone the repository:**
723
-
724
- ```bash
725
- git clone https://github.com/ryu-man/svelte-atoms.git
726
- cd svelte-atoms
727
- ```
728
-
729
- 2. **Install dependencies:**
730
-
731
- ```bash
732
- bun install
733
- ```
734
-
735
- 3. **Start development server:**
736
-
737
- ```bash
738
- bun dev
739
- ```
740
-
741
- 4. **Run Storybook:**
742
- ```bash
743
- bun run storybook:dev
744
- ```
745
-
746
- ### Building
747
-
748
- ```bash
749
- # Build library
750
- bun run build
751
-
752
- # Build Storybook
753
- bun run storybook:build
754
- ```
755
-
756
- ---
757
-
758
- <!-- ## 🤝 Contributing
759
-
760
- We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details. -->
761
-
762
- <!-- ### Development Workflow
763
-
764
- 1. Fork the repository
765
- 2. Create a feature branch: `git checkout -b feature/amazing-feature`
766
- 3. Make your changes and add tests
767
- 4. Run the test suite: `bun test`
768
- 5. Commit your changes: `git commit -m 'Add amazing feature'`
769
- 6. Push to the branch: `git push origin feature/amazing-feature`
770
- 7. Open a Pull Request -->
771
-
772
- ### Creating New Components
773
-
774
- When adding new components, follow these guidelines:
775
-
776
- 1. **Create the bond structure:**
777
-
778
- ```
779
- src/lib/atoms/my-component/
780
- ├── bond.svelte.ts # Core bond logic (Bond + BondState classes)
781
- ├── index.ts # Public exports
782
- ├── atoms.ts # Component exports
783
- ├── my-component-root.svelte # Use namespace pattern when building complex component
784
- ├── my-component-content.svelte
785
- └── README.md # Component documentation
786
- ```
787
-
788
- 2. **Implement accessibility features:**
789
- - ARIA attributes
790
- - Keyboard navigation
791
- - Focus management
792
- - Screen reader support
793
-
794
- 3. **Add comprehensive tests:**
795
- - Unit tests for bond logic
796
- - Component integration tests
797
- - Accessibility tests
798
-
799
- 4. **Create Storybook stories:**
800
- - Basic usage examples
801
- - Advanced configurations
802
- - Interactive demos
803
-
804
- ---
805
-
806
- ## 📚 Resources
807
-
808
- - **[Documentation](https://svelte-atoms.dev)** - Comprehensive documentation
809
- - **[Storybook](https://storybook.svelte-atoms.dev/)** - Interactive component documentation
810
- - **[GitHub](https://github.com/ryu-man/svelte-atoms)** - Source code and issues
811
- - **[@svelte-atoms/alchemist](../alchimist)** - Data visualization companion library
812
-
813
- ---
814
-
815
- ## 🗺️ Roadmap
816
-
817
- ### v1.0.0 (Current - Alpha)
818
-
819
- - ✅ Bond architecture with Svelte 5 runes
820
- - ✅ 35+ essential components
821
- - ✅ TypeScript support
822
- - ✅ Accessibility features
823
- - ✅ Storybook documentation
824
- - ✅ Standardized context pattern
825
-
826
- ---
827
-
828
- ## 📄 License
829
-
830
- MIT License - see the [LICENSE](LICENSE) file for details.
831
-
832
- ---
833
-
834
- ## 🙏 Acknowledgements
835
-
836
- - [Svelte](https://svelte.dev/) - The amazing framework that powers this library
837
- - [Motion](https://motion.dev/) - For handling internal default animations
838
- - [Floating UI](https://floating-ui.com/) - For advanced positioning logic
839
- - [Tailwind CSS](https://tailwindcss.com/) - For styling
840
- - [Storybook](https://storybook.js.org/) - For component documentation and testing
841
- - [Vitest](https://vitest.dev/) - For fast and reliable testing
842
- - [Playwright](https://playwright.dev/) - For end-to-end testing
843
-
844
- ---
845
-
846
- <div align="center">
847
- <p>Built with ❤️ by the Svelte Atoms team</p>
848
- <!-- <p>
849
- <a href="https://github.com/ryu-man/svelte-atoms">GitHub</a> •
850
- <a href="https://svelte-atoms.dev">Documentation</a> •
851
- <a href="https://storybook.svelte-atoms.dev">Storybook</a>
852
- </p> -->
853
- </div>
1
+ # @svelte-atoms/core
2
+
3
+ > A modern, modular, and accessible Svelte 5 UI component library built with composability at its core.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@svelte-atoms/core.svg)](https://www.npmjs.com/package/@svelte-atoms/core)
6
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/svelte-atoms/core)
7
+ [![license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
8
+
9
+ ## Features
10
+
11
+ - **Bond Architecture** - Self-contained state management with context-based communication
12
+ - **Accessible** - ARIA attributes, keyboard navigation, and focus management included
13
+ - **Type Safe** - Full TypeScript support with comprehensive type definitions
14
+ - **Headless** - Complete styling control with sensible defaults
15
+ - **Composable** - Build complex UIs by combining simple, reusable components
16
+ - **Svelte 5 Runes** - Optimized reactivity and performance
17
+
18
+ ## Documentation
19
+
20
+ - **[Documentation](https://sacore.netlify.app/)** - Complete guides, API references, and examples
21
+ - **[Storybook](https://statuesque-boba-0fb888.netlify.app/)** - Interactive component playground
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ npm install @svelte-atoms/core
27
+ ```
28
+
29
+ ## Usage
30
+
31
+ ### Basic Example
32
+
33
+ ```svelte
34
+ <script lang="ts">
35
+ import { Button, Dialog, Input } from '@svelte-atoms/core';
36
+
37
+ let dialogOpen = $state(false);
38
+ let inputValue = '';
39
+ </script>
40
+
41
+ <Button onclick={() => (dialogOpen = true)}>Open Dialog</Button>
42
+
43
+ <Dialog.Root bind:open={dialogOpen}>
44
+ <Dialog.Content>
45
+ <Dialog.Header>
46
+ <Dialog.Title>Enter your name</Dialog.Title>
47
+ </Dialog.Header>
48
+ <Dialog.Body>
49
+ <Input.Root>
50
+ <Input.Control bind:value={inputValue} placeholder="Your name..." />
51
+ </Input.Root>
52
+ </Dialog.Body>
53
+ <Dialog.Footer>
54
+ <Button onclick={() => (dialogOpen = false)}>Cancel</Button>
55
+ <Button variant="primary" onclick={() => (dialogOpen = false)}>Confirm</Button>
56
+ </Dialog.Footer>
57
+ </Dialog.Content>
58
+ </Dialog.Root>
59
+ ```
60
+
61
+ ### Composable Components
62
+
63
+ Combine components to create complex UIs:
64
+
65
+ ```svelte
66
+ <script lang="ts">
67
+ import { Dropdown, Input, Root, filter } from '@svelte-atoms/core';
68
+ import { flip } from 'svelte/animate';
69
+
70
+ let data = [
71
+ { id: 1, value: 'apple', text: 'Apple' },
72
+ { id: 2, value: 'banana', text: 'Banana' },
73
+ { id: 3, value: 'cherry', text: 'Cherry' }
74
+ ];
75
+
76
+ let open = $state(false);
77
+ const dd = filter(
78
+ () => data,
79
+ (query, item) => item.text.toLowerCase().includes(query.toLowerCase())
80
+ );
81
+ </script>
82
+
83
+ <Dropdown.Root
84
+ bind:open
85
+ multiple
86
+ keys={data.map((item) => item.value)}
87
+ onquerychange={(q) => (dd.query = q)}
88
+ >
89
+ {#snippet children({ dropdown })}
90
+ <Dropdown.Trigger
91
+ base={Input.Root}
92
+ onclick={(ev) => {
93
+ ev.preventDefault();
94
+ dropdown.state.open();
95
+ }}
96
+ >
97
+ {#each dropdown?.state?.selectedItems ?? [] as item (item.id)}
98
+ <div animate:flip={{ duration: 200 }}>
99
+ <Dropdown.Value value={item.value}>{item.text}</Dropdown.Value>
100
+ </div>
101
+ {/each}
102
+ <Dropdown.Query placeholder="Search..." />
103
+ </Dropdown.Trigger>
104
+
105
+ <Dropdown.Content>
106
+ {#each dd.current as item (item.id)}
107
+ <div animate:flip={{ duration: 200 }}>
108
+ <Dropdown.Item value={item.value}>{item.text}</Dropdown.Item>
109
+ </div>
110
+ {/each}
111
+ </Dropdown.Content>
112
+ {/snippet}
113
+ </Dropdown.Root>
114
+ ```
115
+
116
+ ### Extensibility with `as` and `base` Props
117
+
118
+ Transform components into any element or wrap them with custom logic:
119
+
120
+ ```svelte
121
+ <script lang="ts">
122
+ import { Button, Popover, Input } from '@svelte-atoms/core';
123
+ </script>
124
+
125
+ <!-- Use Button as Popover trigger -->
126
+ <Popover.Root>
127
+ <Popover.Trigger base={Button} variant="outline">Open Popover</Popover.Trigger>
128
+ <Popover.Content class="p-4">
129
+ <h4 class="font-semibold">Settings</h4>
130
+ <p class="text-sm">Configure your preferences here.</p>
131
+ </Popover.Content>
132
+ </Popover.Root>
133
+
134
+ <!-- Use Input.Root as Popover trigger -->
135
+ <Popover.Root>
136
+ <Popover.Trigger base={Input.Root}>
137
+ <Input.Control placeholder="Click to open popover..." readonly />
138
+ </Popover.Trigger>
139
+ <Popover.Content class="p-4">
140
+ <p class="text-sm">Popover triggered by an input field</p>
141
+ </Popover.Content>
142
+ </Popover.Root>
143
+ ```
144
+
145
+ ### Working with Animations
146
+
147
+ Seamlessly integrate with Svelte's animation system:
148
+
149
+ ```svelte
150
+ <script lang="ts">
151
+ import { List, Button } from '@svelte-atoms/core';
152
+ import { flip } from 'svelte/animate';
153
+ import { slide } from 'svelte/transition';
154
+
155
+ let items = $state([
156
+ { id: 1, text: 'Task 1' },
157
+ { id: 2, text: 'Task 2' },
158
+ { id: 3, text: 'Task 3' }
159
+ ]);
160
+
161
+ function removeItem(id: number) {
162
+ items = items.filter((item) => item.id !== id);
163
+ }
164
+ </script>
165
+
166
+ <List.Root>
167
+ {#each items as item (item.id)}
168
+ <div animate:flip={{ duration: 300 }}>
169
+ <List.Item>
170
+ <span>{item.text}</span>
171
+ <Button size="sm" onclick={() => removeItem(item.id)}>Remove</Button>
172
+ </List.Item>
173
+ </div>
174
+ {/each}
175
+ </List.Root>
176
+ ```
177
+
178
+ Advanced animation with lifecycle hooks using Motion:
179
+
180
+ ```svelte
181
+ <script lang="ts">
182
+ import { Dialog, Button, toTransitionConfig } from '@svelte-atoms/core';
183
+ import { animate } from 'motion';
184
+
185
+ let open = $state(false);
186
+ </script>
187
+
188
+ <Button onclick={() => (open = true)}>Open Dialog</Button>
189
+
190
+ <Dialog.Root bind:open>
191
+ <Dialog.Overlay
192
+ initial={(node) => {
193
+ node.style.opacity = '0';
194
+ }}
195
+ enter={(node) => {
196
+ const duration = 0.2;
197
+ const animation = animate(node, { opacity: 1 }, { duration });
198
+ return { duration };
199
+ }}
200
+ exit={(node) => {
201
+ const duration = 0.1;
202
+ const animation = animate(node, { opacity: 0 }, { duration: 0.1 });
203
+ return { duration };
204
+ }}
205
+ />
206
+ <Dialog.Content
207
+ initial={(node) => {
208
+ node.style.opacity = '0';
209
+ node.style.scale = '0.95';
210
+ }}
211
+ enter={(node) => {
212
+ const duration = 0.3;
213
+ const animation = animate(node, { opacity: 1, scale: 1 }, { duration, easing: 'ease-out' });
214
+ return { duration };
215
+ }}
216
+ exit={(node) => {
217
+ const animation = animate(node, { opacity: 0, scale: 0.95 }, { duration, easing: 'ease-in' });
218
+ return { duration };
219
+ }}
220
+ >
221
+ <Dialog.Header>
222
+ <Dialog.Title>Animated Dialog</Dialog.Title>
223
+ </Dialog.Header>
224
+ <Dialog.Body>
225
+ <p>This dialog animates with custom Motion transitions using lifecycle hooks.</p>
226
+ </Dialog.Body>
227
+ <Dialog.Footer>
228
+ <Button onclick={() => (open = false)}>Close</Button>
229
+ </Dialog.Footer>
230
+ </Dialog.Content>
231
+ </Dialog.Root>
232
+ ```
233
+
234
+ ### Styling with Variants
235
+
236
+ Variants can be created locally at component level or globally in the preset configuration:
237
+
238
+ ```typescript
239
+ import { defineVariants } from '@svelte-atoms/core/utils';
240
+
241
+ const buttonVariants = defineVariants({
242
+ class: 'inline-flex items-center justify-center rounded-md font-medium',
243
+ variants: {
244
+ variant: {
245
+ primary: 'bg-blue-500 text-white hover:bg-blue-600',
246
+ secondary: 'bg-gray-200 text-gray-900 hover:bg-gray-300'
247
+ },
248
+ size: {
249
+ sm: 'h-8 px-3 text-sm',
250
+ md: 'h-10 px-4',
251
+ lg: 'h-12 px-6 text-lg'
252
+ }
253
+ },
254
+ defaults: {
255
+ variant: 'primary',
256
+ size: 'md'
257
+ }
258
+ });
259
+ ```
260
+
261
+ ## Development
262
+
263
+ ```bash
264
+ # Clone repository
265
+ git clone https://github.com/svelte-atoms/core.git
266
+ cd svelte-atoms
267
+
268
+ # Install dependencies
269
+ bun install
270
+
271
+ # Start dev server
272
+ bun dev
273
+
274
+ # Run tests
275
+ bun test
276
+
277
+ # Build library
278
+ bun run build
279
+ ```
280
+
281
+ ## License
282
+
283
+ MIT License - see [LICENSE](LICENSE) file for details.
284
+
285
+ ---
286
+
287
+ <div align="center">
288
+ <p>Built with ❤️ by the Svelte Atoms team</p>
289
+ </div>