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 +60 -183
- package/dist/Table/Table.svelte +11 -0
- package/dist/Table/table.types.d.ts +3 -0
- package/dist/Table/table.variants.js +5 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,240 +1,117 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="https://img.shields.io/badge/
|
|
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
|
-
|
|
9
|
-
|
|
8
|
+
<strong>Modern UI component library for Svelte 5</strong><br/>
|
|
9
|
+
Tailwind CSS 4 · OKLCH Color Tokens · Fully Typed · 50+ Components · 7 Hooks
|
|
10
10
|
</p>
|
|
11
11
|
|
|
12
12
|
<p align="center">
|
|
13
|
-
<a href="https://
|
|
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://
|
|
18
|
-
<a href="https://
|
|
19
|
-
<a href="https://
|
|
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> ·
|
|
20
|
+
<a href="https://sv5ui.vercel.app/getting-started"><strong>Getting Started</strong></a> ·
|
|
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
|
-
##
|
|
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
|
-
#
|
|
40
|
-
|
|
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,
|
|
42
|
+
import { Button, Avatar, toast } from 'sv5ui'
|
|
59
43
|
</script>
|
|
60
44
|
|
|
61
|
-
<
|
|
62
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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
|
-
|
|
59
|
+
## Hooks
|
|
165
60
|
|
|
166
|
-
|
|
61
|
+
Reactive hooks built on Svelte 5 runes and actions.
|
|
167
62
|
|
|
168
|
-
|
|
63
|
+
```svelte
|
|
64
|
+
<script>
|
|
65
|
+
import { useMediaQuery, useClipboard, useDebounce } from 'sv5ui'
|
|
169
66
|
|
|
170
|
-
|
|
67
|
+
const isMobile = useMediaQuery('(max-width: 640px)')
|
|
68
|
+
const clipboard = useClipboard()
|
|
69
|
+
const debounce = useDebounce({ delay: 500 })
|
|
70
|
+
</script>
|
|
171
71
|
|
|
172
|
-
|
|
72
|
+
{#if isMobile.matches}
|
|
73
|
+
<MobileLayout />
|
|
74
|
+
{/if}
|
|
173
75
|
|
|
174
|
-
|
|
175
|
-
:
|
|
176
|
-
|
|
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
|
-
|
|
182
|
-
|
|
183
|
-
|
|
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
|
-
|
|
91
|
+
## Customization
|
|
186
92
|
|
|
187
93
|
```svelte
|
|
188
|
-
|
|
94
|
+
<!-- Per-instance -->
|
|
95
|
+
<Button ui={{ base: 'rounded-full shadow-lg' }}>Custom</Button>
|
|
189
96
|
```
|
|
190
97
|
|
|
191
|
-
|
|
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
|
-
|
|
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
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
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) © [ndlabdev](https://github.com/ndlabdev)
|
package/dist/Table/Table.svelte
CHANGED
|
@@ -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: {
|