sv5ui 0.0.1 → 1.1.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 (200) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +167 -62
  3. package/dist/Accordion/Accordion.svelte +196 -0
  4. package/dist/Accordion/Accordion.svelte.d.ts +6 -0
  5. package/dist/Accordion/accordion.types.d.ts +225 -0
  6. package/dist/Accordion/accordion.types.js +1 -0
  7. package/dist/Accordion/accordion.variants.d.ts +88 -0
  8. package/dist/Accordion/accordion.variants.js +28 -0
  9. package/dist/Accordion/index.d.ts +2 -0
  10. package/dist/Accordion/index.js +1 -0
  11. package/dist/Alert/Alert.svelte +120 -120
  12. package/dist/Avatar/Avatar.svelte +88 -70
  13. package/dist/AvatarGroup/AvatarGroup.svelte +64 -66
  14. package/dist/Badge/Badge.svelte +7 -3
  15. package/dist/Badge/badge.variants.js +21 -7
  16. package/dist/Breadcrumb/Breadcrumb.svelte +88 -0
  17. package/dist/Breadcrumb/Breadcrumb.svelte.d.ts +5 -0
  18. package/dist/Breadcrumb/breadcrumb.types.d.ts +62 -0
  19. package/dist/Breadcrumb/breadcrumb.types.js +1 -0
  20. package/dist/Breadcrumb/breadcrumb.variants.d.ts +128 -0
  21. package/dist/Breadcrumb/breadcrumb.variants.js +49 -0
  22. package/dist/Breadcrumb/index.d.ts +2 -0
  23. package/dist/Breadcrumb/index.js +1 -0
  24. package/dist/Button/Button.svelte +121 -103
  25. package/dist/Button/button.types.d.ts +0 -5
  26. package/dist/Calendar/Calendar.svelte +292 -0
  27. package/dist/Calendar/Calendar.svelte.d.ts +6 -0
  28. package/dist/Calendar/calendar.types.d.ts +99 -0
  29. package/dist/Calendar/calendar.types.js +1 -0
  30. package/dist/Calendar/calendar.variants.d.ts +553 -0
  31. package/dist/Calendar/calendar.variants.js +367 -0
  32. package/dist/Calendar/index.d.ts +2 -0
  33. package/dist/Calendar/index.js +1 -0
  34. package/dist/Card/Card.svelte +53 -53
  35. package/dist/Checkbox/Checkbox.svelte +138 -0
  36. package/dist/Checkbox/Checkbox.svelte.d.ts +6 -0
  37. package/dist/Checkbox/checkbox.types.d.ts +86 -0
  38. package/dist/Checkbox/checkbox.types.js +1 -0
  39. package/dist/Checkbox/checkbox.variants.d.ts +358 -0
  40. package/dist/Checkbox/checkbox.variants.js +140 -0
  41. package/dist/Checkbox/index.d.ts +2 -0
  42. package/dist/Checkbox/index.js +1 -0
  43. package/dist/Chip/chip.variants.js +20 -4
  44. package/dist/Container/Container.svelte +1 -7
  45. package/dist/ContextMenu/ContextMenu.svelte +334 -0
  46. package/dist/ContextMenu/ContextMenu.svelte.d.ts +6 -0
  47. package/dist/ContextMenu/context-menu.types.d.ts +260 -0
  48. package/dist/ContextMenu/context-menu.types.js +1 -0
  49. package/dist/ContextMenu/context-menu.variants.d.ts +393 -0
  50. package/dist/ContextMenu/context-menu.variants.js +176 -0
  51. package/dist/ContextMenu/index.d.ts +2 -0
  52. package/dist/ContextMenu/index.js +1 -0
  53. package/dist/Drawer/Drawer.svelte +200 -0
  54. package/dist/Drawer/Drawer.svelte.d.ts +6 -0
  55. package/dist/Drawer/drawer.types.d.ts +75 -0
  56. package/dist/Drawer/drawer.types.js +1 -0
  57. package/dist/Drawer/drawer.variants.d.ts +193 -0
  58. package/dist/Drawer/drawer.variants.js +139 -0
  59. package/dist/Drawer/index.d.ts +2 -0
  60. package/dist/Drawer/index.js +1 -0
  61. package/dist/DropdownMenu/DropdownMenu.svelte +371 -0
  62. package/dist/DropdownMenu/DropdownMenu.svelte.d.ts +6 -0
  63. package/dist/DropdownMenu/dropdown-menu.types.d.ts +266 -0
  64. package/dist/DropdownMenu/dropdown-menu.types.js +1 -0
  65. package/dist/DropdownMenu/dropdown-menu.variants.d.ts +463 -0
  66. package/dist/DropdownMenu/dropdown-menu.variants.js +192 -0
  67. package/dist/DropdownMenu/index.d.ts +2 -0
  68. package/dist/DropdownMenu/index.js +1 -0
  69. package/dist/Empty/Empty.svelte +83 -83
  70. package/dist/FieldGroup/FieldGroup.svelte +48 -0
  71. package/dist/FieldGroup/FieldGroup.svelte.d.ts +5 -0
  72. package/dist/FieldGroup/field-group.types.d.ts +33 -0
  73. package/dist/FieldGroup/field-group.types.js +1 -0
  74. package/dist/FieldGroup/field-group.variants.d.ts +116 -0
  75. package/dist/FieldGroup/field-group.variants.js +49 -0
  76. package/dist/FieldGroup/index.d.ts +2 -0
  77. package/dist/FieldGroup/index.js +1 -0
  78. package/dist/FormField/FormField.svelte +128 -0
  79. package/dist/FormField/FormField.svelte.d.ts +5 -0
  80. package/dist/FormField/form-field.types.d.ts +90 -0
  81. package/dist/FormField/form-field.types.js +1 -0
  82. package/dist/FormField/form-field.variants.d.ts +313 -0
  83. package/dist/FormField/form-field.variants.js +74 -0
  84. package/dist/FormField/index.d.ts +2 -0
  85. package/dist/FormField/index.js +1 -0
  86. package/dist/Input/Input.svelte +174 -0
  87. package/dist/Input/Input.svelte.d.ts +5 -0
  88. package/dist/Input/index.d.ts +2 -0
  89. package/dist/Input/index.js +1 -0
  90. package/dist/Input/input.types.d.ts +92 -0
  91. package/dist/Input/input.types.js +1 -0
  92. package/dist/Input/input.variants.d.ts +413 -0
  93. package/dist/Input/input.variants.js +406 -0
  94. package/dist/Kbd/Kbd.svelte +35 -35
  95. package/dist/Kbd/kbd.variants.js +65 -13
  96. package/dist/Kbd/useKbd.svelte.js +13 -3
  97. package/dist/Link/Link.svelte +122 -117
  98. package/dist/Modal/Modal.svelte +197 -0
  99. package/dist/Modal/Modal.svelte.d.ts +5 -0
  100. package/dist/Modal/index.d.ts +2 -0
  101. package/dist/Modal/index.js +1 -0
  102. package/dist/Modal/modal.types.d.ts +129 -0
  103. package/dist/Modal/modal.types.js +1 -0
  104. package/dist/Modal/modal.variants.d.ts +208 -0
  105. package/dist/Modal/modal.variants.js +71 -0
  106. package/dist/Pagination/Pagination.svelte +198 -0
  107. package/dist/Pagination/Pagination.svelte.d.ts +6 -0
  108. package/dist/Pagination/index.d.ts +2 -0
  109. package/dist/Pagination/index.js +1 -0
  110. package/dist/Pagination/pagination.types.d.ts +169 -0
  111. package/dist/Pagination/pagination.types.js +1 -0
  112. package/dist/Pagination/pagination.variants.d.ts +598 -0
  113. package/dist/Pagination/pagination.variants.js +145 -0
  114. package/dist/Popover/Popover.svelte +125 -0
  115. package/dist/Popover/Popover.svelte.d.ts +6 -0
  116. package/dist/Popover/index.d.ts +2 -0
  117. package/dist/Popover/index.js +1 -0
  118. package/dist/Popover/popover.types.d.ts +52 -0
  119. package/dist/Popover/popover.types.js +1 -0
  120. package/dist/Popover/popover.variants.d.ts +123 -0
  121. package/dist/Popover/popover.variants.js +41 -0
  122. package/dist/Progress/Progress.svelte +99 -89
  123. package/dist/Progress/progress.variants.js +16 -8
  124. package/dist/RadioGroup/RadioGroup.svelte +175 -0
  125. package/dist/RadioGroup/RadioGroup.svelte.d.ts +6 -0
  126. package/dist/RadioGroup/index.d.ts +2 -0
  127. package/dist/RadioGroup/index.js +1 -0
  128. package/dist/RadioGroup/radio-group.types.d.ts +96 -0
  129. package/dist/RadioGroup/radio-group.types.js +1 -0
  130. package/dist/RadioGroup/radio-group.variants.d.ts +453 -0
  131. package/dist/RadioGroup/radio-group.variants.js +163 -0
  132. package/dist/Select/Select.svelte +383 -0
  133. package/dist/Select/Select.svelte.d.ts +6 -0
  134. package/dist/Select/index.d.ts +2 -0
  135. package/dist/Select/index.js +1 -0
  136. package/dist/Select/select.types.d.ts +221 -0
  137. package/dist/Select/select.types.js +1 -0
  138. package/dist/Select/select.variants.d.ts +713 -0
  139. package/dist/Select/select.variants.js +482 -0
  140. package/dist/Separator/Separator.svelte +5 -1
  141. package/dist/Skeleton/Skeleton.svelte +25 -31
  142. package/dist/Slideover/Slideover.svelte +191 -0
  143. package/dist/Slideover/Slideover.svelte.d.ts +5 -0
  144. package/dist/Slideover/index.d.ts +2 -0
  145. package/dist/Slideover/index.js +1 -0
  146. package/dist/Slideover/slideover.types.d.ts +128 -0
  147. package/dist/Slideover/slideover.types.js +1 -0
  148. package/dist/Slideover/slideover.variants.d.ts +203 -0
  149. package/dist/Slideover/slideover.variants.js +140 -0
  150. package/dist/Switch/Switch.svelte +157 -0
  151. package/dist/Switch/Switch.svelte.d.ts +6 -0
  152. package/dist/Switch/index.d.ts +2 -0
  153. package/dist/Switch/index.js +1 -0
  154. package/dist/Switch/switch.types.d.ts +75 -0
  155. package/dist/Switch/switch.types.js +1 -0
  156. package/dist/Switch/switch.variants.d.ts +433 -0
  157. package/dist/Switch/switch.variants.js +171 -0
  158. package/dist/Tabs/Tabs.svelte +189 -0
  159. package/dist/Tabs/Tabs.svelte.d.ts +6 -0
  160. package/dist/Tabs/index.d.ts +2 -0
  161. package/dist/Tabs/index.js +1 -0
  162. package/dist/Tabs/tabs.types.d.ts +205 -0
  163. package/dist/Tabs/tabs.types.js +1 -0
  164. package/dist/Tabs/tabs.variants.d.ts +298 -0
  165. package/dist/Tabs/tabs.variants.js +249 -0
  166. package/dist/Textarea/Textarea.svelte +196 -0
  167. package/dist/Textarea/Textarea.svelte.d.ts +5 -0
  168. package/dist/Textarea/index.d.ts +2 -0
  169. package/dist/Textarea/index.js +1 -0
  170. package/dist/Textarea/textarea.types.d.ts +103 -0
  171. package/dist/Textarea/textarea.types.js +1 -0
  172. package/dist/Textarea/textarea.variants.d.ts +403 -0
  173. package/dist/Textarea/textarea.variants.js +404 -0
  174. package/dist/ThemeModeButton/ThemeModeButton.svelte +73 -0
  175. package/dist/ThemeModeButton/ThemeModeButton.svelte.d.ts +5 -0
  176. package/dist/ThemeModeButton/index.d.ts +2 -0
  177. package/dist/ThemeModeButton/index.js +1 -0
  178. package/dist/ThemeModeButton/theme-mode-button.types.d.ts +64 -0
  179. package/dist/ThemeModeButton/theme-mode-button.types.js +1 -0
  180. package/dist/ThemeModeButton/theme-mode-button.variants.d.ts +21 -0
  181. package/dist/ThemeModeButton/theme-mode-button.variants.js +17 -0
  182. package/dist/Timeline/Timeline.svelte +4 -2
  183. package/dist/Timeline/timeline.variants.js +96 -16
  184. package/dist/Tooltip/Tooltip.svelte +147 -0
  185. package/dist/Tooltip/Tooltip.svelte.d.ts +6 -0
  186. package/dist/Tooltip/TooltipTestWrapper.svelte +11 -0
  187. package/dist/Tooltip/TooltipTestWrapper.svelte.d.ts +4 -0
  188. package/dist/Tooltip/index.d.ts +2 -0
  189. package/dist/Tooltip/index.js +1 -0
  190. package/dist/Tooltip/tooltip.types.d.ts +56 -0
  191. package/dist/Tooltip/tooltip.types.js +1 -0
  192. package/dist/Tooltip/tooltip.variants.d.ts +133 -0
  193. package/dist/Tooltip/tooltip.variants.js +44 -0
  194. package/dist/User/User.svelte +94 -94
  195. package/dist/config.d.ts +2 -0
  196. package/dist/config.js +3 -1
  197. package/dist/index.d.ts +21 -0
  198. package/dist/index.js +21 -0
  199. package/dist/theme.css +599 -410
  200. package/package.json +106 -104
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 ndlabdev
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2025 ndlabdev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,124 +1,229 @@
1
- # SV5UI
1
+ <p align="center">
2
+ <img src="https://img.shields.io/badge/sv5ui-Svelte_5_UI-ff3e00?style=for-the-badge&logo=svelte&logoColor=white" alt="SV5UI" />
3
+ </p>
2
4
 
3
- A modern, fully-typed Svelte 5 UI component library built with Tailwind CSS 4.
5
+ <h1 align="center">SV5UI</h1>
4
6
 
5
- [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
6
- [![npm version](https://img.shields.io/npm/v/sv5ui.svg)](https://www.npmjs.com/package/sv5ui)
7
+ <p align="center">
8
+ A modern, fully-typed UI component library for Svelte 5.<br/>
9
+ Built with Tailwind CSS 4, OKLCH color tokens, and accessible headless primitives.
10
+ </p>
7
11
 
8
- ## Features
12
+ <p align="center">
13
+ <a href="https://www.npmjs.com/package/sv5ui"><img src="https://img.shields.io/npm/v/sv5ui.svg?style=flat-square&colorA=18181b&colorB=ff3e00" alt="npm version" /></a>
14
+ <a href="https://github.com/ndlabdev/sv5ui/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/sv5ui.svg?style=flat-square&colorA=18181b&colorB=ff3e00" alt="license" /></a>
15
+ <a href="https://www.npmjs.com/package/sv5ui"><img src="https://img.shields.io/npm/dm/sv5ui.svg?style=flat-square&colorA=18181b&colorB=ff3e00" alt="downloads" /></a>
16
+ </p>
9
17
 
10
- - **Svelte 5** - Built with runes, snippets, and the latest Svelte 5 features
11
- - **Tailwind CSS 4** - Utility-first styling with [Tailwind Variants](https://www.tailwind-variants.org/) for type-safe composable variants
12
- - **OKLCH Colors** - Semantic color tokens with light/dark mode support
13
- - **Fully Typed** - Complete TypeScript support with strict mode
14
- - **Accessible** - Built on [Bits UI](https://bits-ui.com) headless primitives
15
- - **Customizable** - Global config system to override default variants and slot styles
18
+ ---
19
+
20
+ ## Highlights
21
+
22
+ - **Svelte 5** Built with runes, snippets, and the latest reactivity model
23
+ - **Tailwind CSS 4** Utility-first styling with [Tailwind Variants](https://www.tailwind-variants.org/) for type-safe, composable variants
24
+ - **Fully Typed** — Strict TypeScript with exported prop types for every component
25
+ - **Accessible** — Built on [Bits UI](https://bits-ui.com) and [Vaul Svelte](https://vaul-svelte.com) headless primitives
26
+ - **200,000+ Icons** — First-class [Iconify](https://iconify.design) integration
27
+ - **Customizable** — Global config system + per-instance slot overrides
16
28
 
17
29
  ## Installation
18
30
 
19
31
  ```bash
20
32
  npm install sv5ui
33
+ # or
34
+ pnpm add sv5ui
21
35
  ```
22
36
 
23
- Peer dependencies: `svelte >= 5.0.0`, `tailwindcss >= 4.0.0`
37
+ **Peer dependencies:** `svelte >= 5.0.0`, `tailwindcss >= 4.0.0`
24
38
 
25
39
  ## Quick Start
26
40
 
41
+ **1. Import the theme**
42
+
27
43
  ```css
28
44
  /* layout.css */
29
45
  @import 'sv5ui/theme.css';
30
- @source "../../node_modules/sv5ui/dist";
31
46
  ```
32
47
 
48
+ **2. Use components**
49
+
33
50
  ```svelte
34
51
  <script>
35
- import { Button, Alert, Avatar, Badge } from 'sv5ui'
52
+ import { Button, Avatar, Badge, Tooltip } from 'sv5ui'
36
53
  </script>
37
54
 
38
- <Button variant="solid" color="primary">Click me</Button>
39
- <Alert title="Heads up!" description="Something happened." color="info" variant="soft" />
40
- <Avatar src="/photo.jpg" alt="John Doe" size="lg" />
41
- <Badge label="New" color="success" />
55
+ <Tooltip text="Edit profile">
56
+ <Button variant="soft" color="primary" leadingIcon="lucide:edit">Edit</Button>
57
+ </Tooltip>
58
+
59
+ <Avatar src="/photo.jpg" alt="Jane Doe" size="lg" />
60
+ <Badge label="Online" color="success" variant="soft" />
42
61
  ```
43
62
 
44
63
  ## Components
45
64
 
46
- | Component | Description |
47
- |-----------|-------------|
48
- | **Alert** | Notification banners with actions and close support |
49
- | **Avatar** | User avatar with image fallback and auto-generated initials |
50
- | **AvatarGroup** | Grouped avatars with overflow count |
51
- | **Badge** | Status indicators and tags |
52
- | **Button** | Interactive button with loading, icon, and block modes |
53
- | **Card** | Content container with header/body/footer slots |
54
- | **Chip** | Compact notification indicators with positioning |
55
- | **Container** | Responsive layout wrapper with max-width constraints |
56
- | **Icon** | Iconify wrapper with 200,000+ icons |
57
- | **Kbd** | Keyboard key display with automatic symbol mapping |
58
- | **Link** | Smart navigation with active state detection |
59
- | **Progress** | Determinate/indeterminate progress bars with step mode |
60
- | **Separator** | Dividers with optional label, icon, or avatar content |
61
- | **Timeline** | Sequence/step visualization with states |
62
-
63
- > Browse the interactive docs by running `pnpm dev` and opening [localhost:5173](http://localhost:5173).
65
+ ### General
66
+
67
+ | Component | Description |
68
+ | :--------------------------------------------- | :--------------------------------------------------------------------------------- |
69
+ | [**Button**](src/lib/Button) | Versatile button with 6 variants, loading state, icons, and avatar support |
70
+ | [**Link**](src/lib/Link) | Smart anchor with automatic active-state detection based on current route |
71
+ | [**Icon**](src/lib/Icon) | Iconify wrapper render any of 200,000+ icons by name |
72
+ | [**Kbd**](src/lib/Kbd) | Keyboard shortcut display with OS-aware symbol mapping |
73
+ | [**ThemeModeButton**](src/lib/ThemeModeButton) | Light/dark mode toggle button with customizable icons and mode-watcher integration |
74
+
75
+ ### Layout
76
+
77
+ | Component | Description |
78
+ | :--------------------------------- | :--------------------------------------------------------------- |
79
+ | [**Card**](src/lib/Card) | Content container with header, body, and footer slots |
80
+ | [**Container**](src/lib/Container) | Responsive max-width wrapper for page content |
81
+ | [**Separator**](src/lib/Separator) | Horizontal/vertical divider with optional label, icon, or avatar |
82
+
83
+ ### Data Display
84
+
85
+ | Component | Description |
86
+ | :------------------------------------- | :--------------------------------------------------------------------- |
87
+ | [**Avatar**](src/lib/Avatar) | Profile image with auto-generated initials fallback |
88
+ | [**AvatarGroup**](src/lib/AvatarGroup) | Stacked avatars with overflow count |
89
+ | [**Badge**](src/lib/Badge) | Status indicators and tags in 4 variants and 8 colors |
90
+ | [**Chip**](src/lib/Chip) | Notification dot indicator with configurable positioning |
91
+ | [**User**](src/lib/User) | User profile display combining avatar, name, and description |
92
+ | [**Timeline**](src/lib/Timeline) | Step/sequence visualization with completed, active, and pending states |
93
+ | [**Skeleton**](src/lib/Skeleton) | Animated loading placeholder |
94
+ | [**Empty**](src/lib/Empty) | Empty state with icon, description, and action slots |
95
+
96
+ ### Feedback
97
+
98
+ | Component | Description |
99
+ | :------------------------------- | :------------------------------------------------------------------- |
100
+ | [**Alert**](src/lib/Alert) | Notification banner with icon, actions, and dismissible support |
101
+ | [**Progress**](src/lib/Progress) | Determinate/indeterminate progress bar with step mode and animations |
102
+
103
+ ### Navigation
104
+
105
+ | Component | Description |
106
+ | :----------------------------------- | :----------------------------------------------------------------------------- |
107
+ | [**Breadcrumb**](src/lib/Breadcrumb) | Hierarchical navigation trail with icons, custom separators, and snippet slots |
108
+ | [**Tabs**](src/lib/Tabs) | Tabbed interface with content panels and configurable orientation |
109
+ | [**Pagination**](src/lib/Pagination) | Page navigation with first/prev/next/last controls and ellipsis |
110
+
111
+ ### Overlay
112
+
113
+ | Component | Description |
114
+ | :--------------------------------------- | :------------------------------------------------------------------------ |
115
+ | [**Modal**](src/lib/Modal) | Accessible dialog with overlay, focus trap, and scroll lock |
116
+ | [**Slideover**](src/lib/Slideover) | Side panel sliding from any edge with inset mode |
117
+ | [**Drawer**](src/lib/Drawer) | Draggable bottom/side sheet with snap points |
118
+ | [**Tooltip**](src/lib/Tooltip) | Hover tooltip with arrow, keyboard shortcut display, and portal rendering |
119
+ | [**Popover**](src/lib/Popover) | Floating interactive content panel with focus management |
120
+ | [**Accordion**](src/lib/Accordion) | Expandable sections with single or multiple open modes |
121
+ | [**DropdownMenu**](src/lib/DropdownMenu) | Triggered floating menu with items, groups, separators, and sub-menus |
122
+ | [**ContextMenu**](src/lib/ContextMenu) | Right-click context menu with items, colors, and keyboard navigation |
123
+
124
+ ### Form
125
+
126
+ | Component | Description |
127
+ | :----------------------------------- | :------------------------------------------------------------------------------------------------------ |
128
+ | [**Input**](src/lib/Input) | Text input with 5 variants, icons, avatar, loading state, and FormField integration |
129
+ | [**Textarea**](src/lib/Textarea) | Multi-line text input with 5 variants, icons, autoresize with maxrows, and FormField integration |
130
+ | [**Select**](src/lib/Select) | Dropdown select with 5 variants, icons, avatars, groups, descriptions, and FormField support |
131
+ | [**Switch**](src/lib/Switch) | Toggle switch with 8 colors, 5 sizes, checked/unchecked icons, loading state, and FormField integration |
132
+ | [**Checkbox**](src/lib/Checkbox) | Checkbox with 8 colors, 5 sizes, indeterminate state, custom icons, and FormField integration |
133
+ | [**RadioGroup**](src/lib/RadioGroup) | Radio group for single-selection with items API, legend, orientation, and FormField integration |
134
+ | [**FormField**](src/lib/FormField) | Form control wrapper providing label, description, hint, help, and error handling |
135
+ | [**FieldGroup**](src/lib/FieldGroup) | Groups buttons and inputs with seamless borders and shared size/orientation context |
136
+ | [**Calendar**](src/lib/Calendar) | Date picker calendar with single, multiple, and range selection modes |
64
137
 
65
138
  ## Theming
66
139
 
67
- SV5UI uses OKLCH color space with semantic tokens. Light and dark modes work automatically.
140
+ SV5UI uses **OKLCH color space** with semantic tokens. Light and dark modes work out of the box.
141
+
142
+ ### Color Tokens
68
143
 
69
- **Available color tokens:** `primary`, `secondary`, `tertiary`, `success`, `warning`, `error`, `info`, `surface`
144
+ Each color provides a set of related tokens for surfaces, text, and containers:
70
145
 
71
- **Dark mode** via `.dark` class or `prefers-color-scheme`, managed through [mode-watcher](https://github.com/svecosystem/mode-watcher).
146
+ ```
147
+ --color-{name} Main color
148
+ --color-on-{name} Contrast text on main color
149
+ --color-{name}-container Lighter background variant
150
+ --color-on-{name}-container Text on container background
151
+ ```
72
152
 
73
- **Custom colors** by overriding CSS variables:
153
+ **Available colors:** `primary` · `secondary` · `tertiary` · `success` · `warning` · `error` · `info` · `surface`
154
+
155
+ ### Dark Mode
156
+
157
+ Supported via `.dark` class on `<html>` or `prefers-color-scheme` media query, managed with [mode-watcher](https://github.com/svecosystem/mode-watcher).
158
+
159
+ ### Custom Colors
160
+
161
+ Override any token with CSS variables:
74
162
 
75
163
  ```css
76
164
  :root {
77
- --color-primary: oklch(0.55 0.25 270);
78
- --color-secondary: oklch(0.45 0.15 240);
165
+ --color-primary: oklch(0.55 0.25 270);
166
+ --color-secondary: oklch(0.45 0.15 240);
79
167
  }
80
168
  ```
81
169
 
82
170
  ## Customization
83
171
 
84
- ### Per-instance overrides
172
+ ### Per-instance — `ui` prop
85
173
 
86
- Override slot styles on any component via the `ui` prop:
174
+ Override slot classes directly on any component:
87
175
 
88
176
  ```svelte
89
- <Button ui={{ base: 'rounded-full', label: 'font-bold uppercase' }}>
90
- Custom
91
- </Button>
177
+ <Button ui={{ base: 'rounded-full shadow-lg', label: 'font-bold uppercase' }}>Custom</Button>
92
178
  ```
93
179
 
94
- ### Global defaults
180
+ ### Global — `defineConfig`
95
181
 
96
- Use `defineConfig` to set library-wide defaults:
182
+ Set library-wide defaults for variants, slots, and icons:
97
183
 
98
184
  ```typescript
99
185
  import { defineConfig } from 'sv5ui'
100
186
 
101
187
  defineConfig({
102
- button: {
103
- defaultVariants: { variant: 'outline', size: 'lg' },
104
- slots: { base: 'shadow-md' }
105
- },
106
- icons: { loading: 'svg-spinners:ring-resize' }
188
+ button: {
189
+ defaultVariants: { variant: 'outline', size: 'lg' },
190
+ slots: { base: 'shadow-md' }
191
+ },
192
+ avatar: {
193
+ defaultVariants: { size: 'lg' },
194
+ slots: { root: 'ring-2 ring-primary' }
195
+ },
196
+ icons: {
197
+ loading: 'lucide:loader',
198
+ close: 'lucide:x'
199
+ }
107
200
  })
108
201
  ```
109
202
 
110
203
  ## Development
111
204
 
112
205
  ```bash
113
- pnpm install # Install dependencies
114
- pnpm dev # Start dev server
115
- pnpm test # Run tests
116
- pnpm check # Type check
117
- pnpm prepack # Build library
118
- pnpm lint # Lint
119
- pnpm format # Format
206
+ pnpm install # Install dependencies
207
+ pnpm dev # Dev server at localhost:5173
208
+ pnpm test # Run unit tests
209
+ pnpm check # TypeScript check
210
+ pnpm prepack # Build library package
211
+ pnpm lint # Lint
212
+ pnpm format # Format code
120
213
  ```
121
214
 
215
+ > Run `pnpm dev` and open [localhost:5173](http://localhost:5173) to browse the interactive component demos.
216
+
217
+ ## Tech Stack
218
+
219
+ | Layer | Technology |
220
+ | :--------- | :-------------------------------------------------------------------------------------------------- |
221
+ | Framework | [Svelte 5](https://svelte.dev) + [SvelteKit](https://svelte.dev/docs/kit) |
222
+ | Styling | [Tailwind CSS 4](https://tailwindcss.com) + [Tailwind Variants](https://www.tailwind-variants.org/) |
223
+ | Primitives | [Bits UI](https://bits-ui.com) · [Vaul Svelte](https://vaul-svelte.com) |
224
+ | Icons | [Iconify](https://iconify.design) (200,000+ icons) |
225
+ | Testing | [Vitest](https://vitest.dev) + [Playwright](https://playwright.dev) |
226
+
122
227
  ## License
123
228
 
124
- [MIT](LICENSE)
229
+ [MIT](LICENSE) &copy; [ndlabdev](https://github.com/ndlabdev)
@@ -0,0 +1,196 @@
1
+ <script lang="ts" module>
2
+ import type { AccordionProps, AccordionItem } from './accordion.types.js'
3
+
4
+ export type Props = AccordionProps
5
+ </script>
6
+
7
+ <script lang="ts">
8
+ import { Accordion } from 'bits-ui'
9
+ import { slide } from 'svelte/transition'
10
+ import { accordionVariants, accordionDefaults } from './accordion.variants.js'
11
+ import { getComponentConfig } from '../config.js'
12
+ import Icon from '../Icon/Icon.svelte'
13
+
14
+ const config = getComponentConfig('accordion', accordionDefaults)
15
+
16
+ let {
17
+ items = [],
18
+ type = 'single',
19
+ value = $bindable(),
20
+ onValueChange,
21
+ disabled = false,
22
+ loop = false,
23
+ orientation = 'vertical',
24
+ forceMount = false,
25
+ trailingIcon = 'lucide:chevron-down',
26
+ ui,
27
+ class: className,
28
+ leading,
29
+ label: labelSlot,
30
+ trailing,
31
+ content: contentSlot,
32
+ body: bodySlot
33
+ }: Props = $props()
34
+
35
+ const variantSlots = $derived(accordionVariants({ disabled }))
36
+ const rootClass = $derived(
37
+ variantSlots.root({ class: [config.slots.root, ui?.root, className] })
38
+ )
39
+
40
+ const singleValue = $derived(typeof value === 'string' ? value : undefined)
41
+ const multipleValue = $derived(Array.isArray(value) ? value : undefined)
42
+
43
+ const slotNames = [
44
+ 'item',
45
+ 'header',
46
+ 'trigger',
47
+ 'content',
48
+ 'body',
49
+ 'leadingIcon',
50
+ 'trailingIcon',
51
+ 'label'
52
+ ] as const
53
+
54
+ type SlotName = (typeof slotNames)[number]
55
+
56
+ function getItemClasses(item: AccordionItem) {
57
+ const result = {} as Record<SlotName, string>
58
+ for (const slot of slotNames) {
59
+ const baseClass = [
60
+ config.slots[slot],
61
+ ui?.[slot],
62
+ item.ui?.[slot],
63
+ slot === 'item' ? item.class : undefined
64
+ ]
65
+ const opts =
66
+ slot === 'trigger'
67
+ ? { class: baseClass, disabled: item.disabled }
68
+ : { class: baseClass }
69
+ result[slot] = variantSlots[slot](opts)
70
+ }
71
+ return result
72
+ }
73
+
74
+ function isOpen(itemValue: string): boolean {
75
+ if (!value) return false
76
+ if (Array.isArray(value)) return value.includes(itemValue)
77
+ return value === itemValue
78
+ }
79
+
80
+ function handleSingleValueChange(newValue: string) {
81
+ value = newValue
82
+ onValueChange?.(newValue)
83
+ }
84
+
85
+ function handleMultipleValueChange(newValue: string[]) {
86
+ value = newValue
87
+ onValueChange?.(newValue)
88
+ }
89
+ </script>
90
+
91
+ {#snippet accordionItem(item: AccordionItem, index: number)}
92
+ {@const itemValue = item.value ?? String(index)}
93
+ {@const cls = getItemClasses(item)}
94
+ {@const open = isOpen(itemValue)}
95
+ <Accordion.Item value={itemValue} disabled={item.disabled} class={cls.item}>
96
+ <Accordion.Header class={cls.header}>
97
+ <Accordion.Trigger class={cls.trigger}>
98
+ {#if leading}
99
+ {@render leading({ item, index, open })}
100
+ {:else if item.icon}
101
+ <Icon name={item.icon} class={cls.leadingIcon} />
102
+ {/if}
103
+
104
+ {#if item.label || labelSlot}
105
+ <span class={cls.label}>
106
+ {#if labelSlot}
107
+ {@render labelSlot({ item, index, open })}
108
+ {:else}
109
+ {item.label}
110
+ {/if}
111
+ </span>
112
+ {/if}
113
+
114
+ {#if trailing}
115
+ {@render trailing({ item, index, open })}
116
+ {:else}
117
+ <Icon name={item.trailingIcon ?? trailingIcon} class={cls.trailingIcon} />
118
+ {/if}
119
+ </Accordion.Trigger>
120
+ </Accordion.Header>
121
+
122
+ {#if item.content || contentSlot || bodySlot}
123
+ {#if forceMount}
124
+ <Accordion.Content forceMount>
125
+ {#snippet child({ props, open: isContentOpen })}
126
+ {#if isContentOpen}
127
+ <div {...props} transition:slide={{ duration: 200 }}>
128
+ <div class={cls.content}>
129
+ {#if contentSlot}
130
+ {@render contentSlot({ item, index, open: isContentOpen })}
131
+ {:else}
132
+ <div class={cls.body}>
133
+ {#if bodySlot}
134
+ {@render bodySlot({
135
+ item,
136
+ index,
137
+ open: isContentOpen
138
+ })}
139
+ {:else}
140
+ {item.content}
141
+ {/if}
142
+ </div>
143
+ {/if}
144
+ </div>
145
+ </div>
146
+ {/if}
147
+ {/snippet}
148
+ </Accordion.Content>
149
+ {:else}
150
+ <Accordion.Content class={cls.content}>
151
+ {#if contentSlot}
152
+ {@render contentSlot({ item, index, open })}
153
+ {:else}
154
+ <div class={cls.body}>
155
+ {#if bodySlot}
156
+ {@render bodySlot({ item, index, open })}
157
+ {:else}
158
+ {item.content}
159
+ {/if}
160
+ </div>
161
+ {/if}
162
+ </Accordion.Content>
163
+ {/if}
164
+ {/if}
165
+ </Accordion.Item>
166
+ {/snippet}
167
+
168
+ {#if type === 'single'}
169
+ <Accordion.Root
170
+ type="single"
171
+ value={singleValue}
172
+ onValueChange={handleSingleValueChange}
173
+ {disabled}
174
+ {loop}
175
+ {orientation}
176
+ class={rootClass}
177
+ >
178
+ {#each items as item, index (item.value ?? index)}
179
+ {@render accordionItem(item, index)}
180
+ {/each}
181
+ </Accordion.Root>
182
+ {:else}
183
+ <Accordion.Root
184
+ type="multiple"
185
+ value={multipleValue}
186
+ onValueChange={handleMultipleValueChange}
187
+ {disabled}
188
+ {loop}
189
+ {orientation}
190
+ class={rootClass}
191
+ >
192
+ {#each items as item, index (item.value ?? index)}
193
+ {@render accordionItem(item, index)}
194
+ {/each}
195
+ </Accordion.Root>
196
+ {/if}
@@ -0,0 +1,6 @@
1
+ import type { AccordionProps } from './accordion.types.js';
2
+ export type Props = AccordionProps;
3
+ import { Accordion } from 'bits-ui';
4
+ declare const Accordion: import("svelte").Component<AccordionProps, {}, "value">;
5
+ type Accordion = ReturnType<typeof Accordion>;
6
+ export default Accordion;