sv5ui 1.5.0 → 1.5.1

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.
package/README.md CHANGED
@@ -1,240 +1,117 @@
1
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" />
2
+ <img src="https://img.shields.io/badge/SV5UI-ff3e00?style=for-the-badge&logo=svelte&logoColor=white" alt="SV5UI" />
3
3
  </p>
4
4
 
5
5
  <h1 align="center">SV5UI</h1>
6
6
 
7
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.
8
+ <strong>Modern UI component library for Svelte 5</strong><br/>
9
+ Tailwind CSS 4 &middot; OKLCH Color Tokens &middot; Fully Typed &middot; 50+ Components &middot; 7 Hooks
10
10
  </p>
11
11
 
12
12
  <p align="center">
13
- <a href="https://sv5ui.vercel.app/docs"><strong>Documentation</strong></a> · <a href="https://sv5ui.vercel.app"><strong>Live Demo</strong></a>
13
+ <a href="https://www.npmjs.com/package/sv5ui"><img src="https://img.shields.io/npm/v/sv5ui?style=flat-square&colorA=18181b&colorB=ff3e00" alt="npm" /></a>
14
+ <a href="https://www.npmjs.com/package/sv5ui"><img src="https://img.shields.io/npm/dm/sv5ui?style=flat-square&colorA=18181b&colorB=ff3e00" alt="downloads" /></a>
15
+ <a href="https://github.com/ndlabdev/sv5ui/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/sv5ui?style=flat-square&colorA=18181b&colorB=ff3e00" alt="license" /></a>
14
16
  </p>
15
17
 
16
18
  <p align="center">
17
- <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>
18
- <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>
19
- <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>
20
- <a href="https://svelte.dev"><img src="https://img.shields.io/badge/svelte-5-ff3e00?style=flat-square&logo=svelte&logoColor=white" alt="Svelte 5" /></a>
21
- <a href="https://www.typescriptlang.org"><img src="https://img.shields.io/badge/types-TypeScript-blue?style=flat-square&logo=typescript&logoColor=white" alt="TypeScript" /></a>
19
+ <a href="https://sv5ui.vercel.app"><strong>Live Demo</strong></a> &middot;
20
+ <a href="https://sv5ui.vercel.app/getting-started"><strong>Getting Started</strong></a> &middot;
21
+ <a href="https://github.com/ndlabdev/sv5ui/blob/main/CHANGELOG.md"><strong>Changelog</strong></a>
22
22
  </p>
23
23
 
24
24
  ---
25
25
 
26
- ## Highlights
27
-
28
- - **Svelte 5** — Built with runes, snippets, and the latest reactivity model
29
- - **Tailwind CSS 4** — Utility-first styling with [Tailwind Variants](https://www.tailwind-variants.org/) for type-safe, composable variants
30
- - **Fully Typed** — Strict TypeScript with exported prop types for every component
31
- - **Accessible** — Built on [Bits UI](https://bits-ui.com) and [Vaul Svelte](https://vaul-svelte.com) headless primitives
32
- - **200,000+ Icons** — First-class [Iconify](https://iconify.design) integration
33
- - **Customizable** — Global config system + per-instance slot overrides
34
-
35
- ## Installation
26
+ ## Install
36
27
 
37
28
  ```bash
38
29
  npm install sv5ui
39
- # or
40
- pnpm add sv5ui
30
+ # pnpm add sv5ui
31
+ # yarn add sv5ui
32
+ # bun add sv5ui
41
33
  ```
42
34
 
43
- **Peer dependencies:** `svelte >= 5.0.0`, `tailwindcss >= 4.0.0`
44
-
45
- ## Quick Start
46
-
47
- **1. Import the theme**
48
-
49
35
  ```css
50
36
  /* layout.css */
51
37
  @import 'sv5ui/theme.css';
52
38
  ```
53
39
 
54
- **2. Use components**
55
-
56
40
  ```svelte
57
41
  <script>
58
- import { Button, Avatar, Badge, Tooltip } from 'sv5ui'
42
+ import { Button, Avatar, toast } from 'sv5ui'
59
43
  </script>
60
44
 
61
- <Tooltip text="Edit profile">
62
- <Button variant="soft" color="primary" leadingIcon="lucide:edit">Edit</Button>
63
- </Tooltip>
64
-
65
- <Avatar src="/photo.jpg" alt="Jane Doe" size="lg" />
66
- <Badge label="Online" color="success" variant="soft" />
45
+ <Button variant="soft" color="primary" leadingIcon="lucide:edit">Edit</Button>
46
+ <Avatar src="/photo.jpg" alt="Jane" size="lg" />
67
47
  ```
68
48
 
69
- ## Components
70
-
71
- ### General
72
-
73
- | Component | Description |
74
- | :--------------------------------------------- | :--------------------------------------------------------------------------------- |
75
- | [**Button**](src/lib/Button) | Versatile button with 6 variants, loading state, icons, and avatar support |
76
- | [**Link**](src/lib/Link) | Smart anchor with automatic active-state detection based on current route |
77
- | [**Icon**](src/lib/Icon) | Iconify wrapper — render any of 200,000+ icons by name |
78
- | [**Kbd**](src/lib/Kbd) | Keyboard shortcut display with OS-aware symbol mapping |
79
- | [**ThemeModeButton**](src/lib/ThemeModeButton) | Light/dark mode toggle button with customizable icons and mode-watcher integration |
80
-
81
- ### Layout
82
-
83
- | Component | Description |
84
- | :--------------------------------- | :--------------------------------------------------------------- |
85
- | [**Card**](src/lib/Card) | Content container with header, body, and footer slots |
86
- | [**Container**](src/lib/Container) | Responsive max-width wrapper for page content |
87
- | [**Separator**](src/lib/Separator) | Horizontal/vertical divider with optional label, icon, or avatar |
88
-
89
- ### Data Display
90
-
91
- | Component | Description |
92
- | :------------------------------------- | :--------------------------------------------------------------------- |
93
- | [**Avatar**](src/lib/Avatar) | Profile image with auto-generated initials fallback |
94
- | [**AvatarGroup**](src/lib/AvatarGroup) | Stacked avatars with overflow count |
95
- | [**Badge**](src/lib/Badge) | Status indicators and tags in 4 variants and 8 colors |
96
- | [**Chip**](src/lib/Chip) | Notification dot indicator with configurable positioning |
97
- | [**User**](src/lib/User) | User profile display combining avatar, name, and description |
98
- | [**Timeline**](src/lib/Timeline) | Step/sequence visualization with completed, active, and pending states |
99
- | [**Skeleton**](src/lib/Skeleton) | Animated loading placeholder |
100
- | [**Empty**](src/lib/Empty) | Empty state with icon, description, and action slots |
101
-
102
- ### Feedback
103
-
104
- | Component | Description |
105
- | :------------------------------- | :------------------------------------------------------------------- |
106
- | [**Alert**](src/lib/Alert) | Notification banner with icon, actions, and dismissible support |
107
- | [**Progress**](src/lib/Progress) | Determinate/indeterminate progress bar with step mode and animations |
108
-
109
- ### Navigation
110
-
111
- | Component | Description |
112
- | :----------------------------------- | :----------------------------------------------------------------------------- |
113
- | [**Breadcrumb**](src/lib/Breadcrumb) | Hierarchical navigation trail with icons, custom separators, and snippet slots |
114
- | [**Tabs**](src/lib/Tabs) | Tabbed interface with content panels and configurable orientation |
115
- | [**Pagination**](src/lib/Pagination) | Page navigation with first/prev/next/last controls and ellipsis |
116
-
117
- ### Overlay
118
-
119
- | Component | Description |
120
- | :--------------------------------------- | :------------------------------------------------------------------------ |
121
- | [**Modal**](src/lib/Modal) | Accessible dialog with overlay, focus trap, and scroll lock |
122
- | [**Slideover**](src/lib/Slideover) | Side panel sliding from any edge with inset mode |
123
- | [**Drawer**](src/lib/Drawer) | Draggable bottom/side sheet with snap points |
124
- | [**Tooltip**](src/lib/Tooltip) | Hover tooltip with arrow, keyboard shortcut display, and portal rendering |
125
- | [**Popover**](src/lib/Popover) | Floating interactive content panel with focus management |
126
- | [**Accordion**](src/lib/Accordion) | Expandable sections with single or multiple open modes |
127
- | [**DropdownMenu**](src/lib/DropdownMenu) | Triggered floating menu with items, groups, separators, and sub-menus |
128
- | [**ContextMenu**](src/lib/ContextMenu) | Right-click context menu with items, colors, and keyboard navigation |
129
-
130
- ### Form
131
-
132
- | Component | Description |
133
- | :----------------------------------------- | :------------------------------------------------------------------------------------------------------ |
134
- | [**Input**](src/lib/Input) | Text input with 5 variants, icons, avatar, loading state, and FormField integration |
135
- | [**Textarea**](src/lib/Textarea) | Multi-line text input with 5 variants, icons, autoresize with maxrows, and FormField integration |
136
- | [**Select**](src/lib/Select) | Dropdown select with 5 variants, icons, avatars, groups, descriptions, and FormField support |
137
- | [**SelectMenu**](src/lib/SelectMenu) | Searchable multi-select menu with chips, groups, and FormField integration |
138
- | [**Switch**](src/lib/Switch) | Toggle switch with 8 colors, 5 sizes, checked/unchecked icons, loading state, and FormField integration |
139
- | [**Checkbox**](src/lib/Checkbox) | Checkbox with 8 colors, 5 sizes, indeterminate state, custom icons, and FormField integration |
140
- | [**CheckboxGroup**](src/lib/CheckboxGroup) | Grouped checkboxes with single/multiple selection, per-item disabled, and FormField integration |
141
- | [**RadioGroup**](src/lib/RadioGroup) | Radio group for single-selection with items API, legend, orientation, and FormField integration |
142
- | [**Slider**](src/lib/Slider) | Range slider with single/range values, step, orientation, tooltip labels, and FormField integration |
143
- | [**PinInput**](src/lib/PinInput) | PIN/OTP input with masking, numeric filtering, OTP autocomplete, and FormField integration |
144
- | [**FileUpload**](src/lib/FileUpload) | Drag-and-drop file upload with preview list, image thumbnails, accept filter, and multiple files |
145
- | [**FormField**](src/lib/FormField) | Form control wrapper providing label, description, hint, help, and error handling |
146
- | [**FieldGroup**](src/lib/FieldGroup) | Groups buttons and inputs with seamless borders and shared size/orientation context |
147
- | [**Calendar**](src/lib/Calendar) | Date picker calendar with single, multiple, and range selection modes |
148
-
149
- ## Theming
150
-
151
- SV5UI uses **OKLCH color space** with semantic tokens. Light and dark modes work out of the box.
152
-
153
- ### Color Tokens
154
-
155
- Each color provides a set of related tokens for surfaces, text, and containers:
49
+ ## Features
156
50
 
157
- ```
158
- --color-{name} Main color
159
- --color-on-{name} Contrast text on main color
160
- --color-{name}-container Lighter background variant
161
- --color-on-{name}-container Text on container background
162
- ```
51
+ - **Svelte 5** — Runes, snippets, latest reactivity
52
+ - **Tailwind CSS 4** — Utility-first with [Tailwind Variants](https://www.tailwind-variants.org/)
53
+ - **Fully Typed** Strict TypeScript, exported prop types
54
+ - **Accessible** — Built on [Bits UI](https://bits-ui.com) & [Vaul Svelte](https://vaul-svelte.com)
55
+ - **200,000+ Icons** — [Iconify](https://iconify.design) integration
56
+ - **Themeable** — OKLCH color tokens, light/dark mode, global config
57
+ - **Hooks** — 7 reactive hooks for common UI patterns
163
58
 
164
- **Available colors:** `primary` · `secondary` · `tertiary` · `success` · `warning` · `error` · `info` · `surface`
59
+ ## Hooks
165
60
 
166
- ### Dark Mode
61
+ Reactive hooks built on Svelte 5 runes and actions.
167
62
 
168
- Supported via `.dark` class on `<html>` or `prefers-color-scheme` media query, managed with [mode-watcher](https://github.com/svecosystem/mode-watcher).
63
+ ```svelte
64
+ <script>
65
+ import { useMediaQuery, useClipboard, useDebounce } from 'sv5ui'
169
66
 
170
- ### Custom Colors
67
+ const isMobile = useMediaQuery('(max-width: 640px)')
68
+ const clipboard = useClipboard()
69
+ const debounce = useDebounce({ delay: 500 })
70
+ </script>
171
71
 
172
- Override any token with CSS variables:
72
+ {#if isMobile.matches}
73
+ <MobileLayout />
74
+ {/if}
173
75
 
174
- ```css
175
- :root {
176
- --color-primary: oklch(0.55 0.25 270);
177
- --color-secondary: oklch(0.45 0.15 240);
178
- }
76
+ <Button onclick={() => clipboard.copy('Hello!')}>
77
+ {clipboard.copied ? 'Copied!' : 'Copy'}
78
+ </Button>
179
79
  ```
180
80
 
181
- ## Customization
182
-
183
- ### Per-instance — `ui` prop
81
+ | Hook | Type | Description |
82
+ | ------------------- | -------------- | ---------------------------------------------- |
83
+ | `useMediaQuery` | Runes | Reactive CSS media query tracking |
84
+ | `useClipboard` | Runes | Copy text with auto-reset state |
85
+ | `useFormField` | Context | Access FormField context from child components |
86
+ | `useDebounce` | Runes | Debounce with pending, cancel, flush |
87
+ | `useClickOutside` | Action | Detect clicks outside an element |
88
+ | `useInfiniteScroll` | Runes + Action | Auto-load on scroll with loading state |
89
+ | `useEscapeKeydown` | Action | Listen for Escape key |
184
90
 
185
- Override slot classes directly on any component:
91
+ ## Customization
186
92
 
187
93
  ```svelte
188
- <Button ui={{ base: 'rounded-full shadow-lg', label: 'font-bold uppercase' }}>Custom</Button>
94
+ <!-- Per-instance -->
95
+ <Button ui={{ base: 'rounded-full shadow-lg' }}>Custom</Button>
189
96
  ```
190
97
 
191
- ### Global — `defineConfig`
192
-
193
- Set library-wide defaults for variants, slots, and icons:
194
-
195
- ```typescript
98
+ ```ts
99
+ // Global defaults
196
100
  import { defineConfig } from 'sv5ui'
197
101
 
198
102
  defineConfig({
199
- button: {
200
- defaultVariants: { variant: 'outline', size: 'lg' },
201
- slots: { base: 'shadow-md' }
202
- },
203
- avatar: {
204
- defaultVariants: { size: 'lg' },
205
- slots: { root: 'ring-2 ring-primary' }
206
- },
207
- icons: {
208
- loading: 'lucide:loader',
209
- close: 'lucide:x'
210
- }
103
+ button: { defaultVariants: { variant: 'outline' } },
104
+ icons: { loading: 'lucide:loader' }
211
105
  })
212
106
  ```
213
107
 
214
- ## Development
215
-
216
- ```bash
217
- pnpm install # Install dependencies
218
- pnpm dev # Dev server at localhost:5173
219
- pnpm test # Run unit tests
220
- pnpm check # TypeScript check
221
- pnpm prepack # Build library package
222
- pnpm lint # Lint
223
- pnpm format # Format code
108
+ ```css
109
+ /* Custom colors */
110
+ :root {
111
+ --color-primary: oklch(0.55 0.25 270);
112
+ }
224
113
  ```
225
114
 
226
- > Run `pnpm dev` and open [localhost:5173](http://localhost:5173) to browse the interactive component demos.
227
-
228
- ## Tech Stack
229
-
230
- | Layer | Technology |
231
- | :--------- | :-------------------------------------------------------------------------------------------------- |
232
- | Framework | [Svelte 5](https://svelte.dev) + [SvelteKit](https://svelte.dev/docs/kit) |
233
- | Styling | [Tailwind CSS 4](https://tailwindcss.com) + [Tailwind Variants](https://www.tailwind-variants.org/) |
234
- | Primitives | [Bits UI](https://bits-ui.com) · [Vaul Svelte](https://vaul-svelte.com) |
235
- | Icons | [Iconify](https://iconify.design) (200,000+ icons) |
236
- | Testing | [Vitest](https://vitest.dev) + [Playwright](https://playwright.dev) |
237
-
238
115
  ## License
239
116
 
240
117
  [MIT](LICENSE) &copy; [ndlabdev](https://github.com/ndlabdev)
@@ -89,6 +89,7 @@
89
89
  striped = false,
90
90
  hoverable = config.defaultVariants.hoverable ?? true,
91
91
  sticky = false,
92
+ action,
92
93
 
93
94
  // Callbacks
94
95
  onRowClick,
@@ -112,6 +113,16 @@
112
113
  ...restProps
113
114
  }: TableProps<T> = $props()
114
115
 
116
+ // =========================================================================
117
+ // Apply Svelte action on root element
118
+ // =========================================================================
119
+ $effect(() => {
120
+ if (ref && action) {
121
+ const result = action(ref)
122
+ return () => result?.destroy?.()
123
+ }
124
+ })
125
+
115
126
  // =========================================================================
116
127
  // Change notifications — skip initial mount, fire only on subsequent changes
117
128
  // =========================================================================
@@ -1,4 +1,5 @@
1
1
  import type { Snippet } from 'svelte';
2
+ import type { Action } from 'svelte/action';
2
3
  import type { HTMLAttributes } from 'svelte/elements';
3
4
  import type { ClassNameValue } from 'tailwind-merge';
4
5
  import type { TableVariantProps, TableSlots } from './table.variants.js';
@@ -167,6 +168,8 @@ export interface TableProps<T extends Record<string, any> = Record<string, any>>
167
168
  hoverable?: boolean;
168
169
  /** Sticky header/footer. @default false */
169
170
  sticky?: boolean | 'header' | 'footer';
171
+ /** Svelte action to apply on the root scroll container (e.g. infinite scroll). */
172
+ action?: Action<HTMLElement>;
170
173
  /** Callback fired when a row is clicked. */
171
174
  onRowClick?: (row: T, index: number, event: MouseEvent) => void;
172
175
  /** Callback fired when pointer enters/leaves a row. Passes `null` on leave. */
@@ -1,7 +1,7 @@
1
1
  import { tv } from 'tailwind-variants';
2
2
  export const tableVariants = tv({
3
3
  slots: {
4
- root: 'relative w-full overflow-x-auto rounded-xl border border-outline-variant/50 bg-surface [contain:inline-size]',
4
+ root: 'relative w-full overflow-x-auto scrollbar-thin rounded-xl border border-outline-variant/50 bg-surface [contain:inline-size]',
5
5
  base: 'min-w-full',
6
6
  caption: 'sr-only',
7
7
  thead: 'relative bg-surface-container-low',
@@ -40,14 +40,14 @@ export const tableVariants = tv({
40
40
  },
41
41
  sticky: {
42
42
  true: {
43
- thead: 'sticky top-0 inset-x-0 bg-surface-container-low/95 backdrop-blur-sm z-10',
44
- tfoot: 'sticky bottom-0 inset-x-0 bg-surface-container-low/95 backdrop-blur-sm z-10'
43
+ thead: 'sticky top-0 inset-x-0 bg-surface-container-low/95 backdrop-blur-sm z-10 rounded-t-xl',
44
+ tfoot: 'sticky bottom-0 inset-x-0 bg-surface-container-low/95 backdrop-blur-sm z-10 rounded-b-xl'
45
45
  },
46
46
  header: {
47
- thead: 'sticky top-0 inset-x-0 bg-surface-container-low/95 backdrop-blur-sm z-10'
47
+ thead: 'sticky top-0 inset-x-0 bg-surface-container-low/95 backdrop-blur-sm z-10 rounded-t-xl'
48
48
  },
49
49
  footer: {
50
- tfoot: 'sticky bottom-0 inset-x-0 bg-surface-container-low/95 backdrop-blur-sm z-10'
50
+ tfoot: 'sticky bottom-0 inset-x-0 bg-surface-container-low/95 backdrop-blur-sm z-10 rounded-b-xl'
51
51
  }
52
52
  },
53
53
  striped: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sv5ui",
3
- "version": "1.5.0",
3
+ "version": "1.5.1",
4
4
  "description": "A modern Svelte 5 UI component library with Tailwind CSS",
5
5
  "author": "ndlabdev",
6
6
  "license": "MIT",