@connve/ui 0.0.0-stage → 0.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 (62) hide show
  1. package/LICENSE +373 -0
  2. package/README.md +92 -2
  3. package/dist/AppShell.svelte +258 -0
  4. package/dist/AppShell.svelte.d.ts +29 -0
  5. package/dist/Badge.svelte +33 -0
  6. package/dist/Badge.svelte.d.ts +9 -0
  7. package/dist/ContextBridge.svelte +18 -0
  8. package/dist/ContextBridge.svelte.d.ts +8 -0
  9. package/dist/CopyButton.svelte +57 -0
  10. package/dist/CopyButton.svelte.d.ts +11 -0
  11. package/dist/EditButton.svelte +37 -0
  12. package/dist/EditButton.svelte.d.ts +9 -0
  13. package/dist/FolderTree.svelte +116 -0
  14. package/dist/FolderTree.svelte.d.ts +42 -0
  15. package/dist/IconButton.svelte +33 -0
  16. package/dist/IconButton.svelte.d.ts +16 -0
  17. package/dist/Inspector.svelte +115 -0
  18. package/dist/Inspector.svelte.d.ts +20 -0
  19. package/dist/InspectorSection.svelte +18 -0
  20. package/dist/InspectorSection.svelte.d.ts +9 -0
  21. package/dist/ListHeader.svelte +73 -0
  22. package/dist/ListHeader.svelte.d.ts +18 -0
  23. package/dist/Loading.svelte +25 -0
  24. package/dist/Loading.svelte.d.ts +9 -0
  25. package/dist/Logo.svelte +93 -0
  26. package/dist/Logo.svelte.d.ts +9 -0
  27. package/dist/NavList.svelte +74 -0
  28. package/dist/NavList.svelte.d.ts +24 -0
  29. package/dist/PaneResizer.svelte +36 -0
  30. package/dist/PaneResizer.svelte.d.ts +7 -0
  31. package/dist/Segmented.svelte +38 -0
  32. package/dist/Segmented.svelte.d.ts +33 -0
  33. package/dist/SidePane.svelte +148 -0
  34. package/dist/SidePane.svelte.d.ts +17 -0
  35. package/dist/StateMessage.svelte +110 -0
  36. package/dist/StateMessage.svelte.d.ts +15 -0
  37. package/dist/StatusDot.svelte +32 -0
  38. package/dist/StatusDot.svelte.d.ts +10 -0
  39. package/dist/ThemeToggle.svelte +37 -0
  40. package/dist/ThemeToggle.svelte.d.ts +3 -0
  41. package/dist/focus.d.ts +2 -0
  42. package/dist/focus.js +39 -0
  43. package/dist/icons.d.ts +19 -0
  44. package/dist/icons.js +90 -0
  45. package/dist/index.d.ts +24 -0
  46. package/dist/index.js +23 -0
  47. package/dist/labels.svelte.d.ts +28 -0
  48. package/dist/labels.svelte.js +27 -0
  49. package/dist/mobile.d.ts +5 -0
  50. package/dist/mobile.js +7 -0
  51. package/dist/paneSize.svelte.d.ts +26 -0
  52. package/dist/paneSize.svelte.js +112 -0
  53. package/dist/shell.svelte.d.ts +18 -0
  54. package/dist/shell.svelte.js +20 -0
  55. package/dist/theme.css +169 -0
  56. package/dist/theme.svelte.d.ts +13 -0
  57. package/dist/theme.svelte.js +46 -0
  58. package/dist/tooltip.d.ts +3 -0
  59. package/dist/tooltip.js +7 -0
  60. package/dist/tree.d.ts +17 -0
  61. package/dist/tree.js +44 -0
  62. package/package.json +82 -5
@@ -0,0 +1,26 @@
1
+ export interface PaneBounds {
2
+ initial: number;
3
+ min: number;
4
+ max: number;
5
+ /** The pane's edge that resizes it: `right` for a pane on the left, `left` for one on the right, `top` for one at the bottom. */
6
+ edge: 'left' | 'right' | 'top';
7
+ }
8
+ export declare class PaneSize {
9
+ #private;
10
+ readonly edge: PaneBounds['edge'];
11
+ constructor(key: string, bounds: PaneBounds);
12
+ /** In pixels, within the bounds. */
13
+ get size(): number;
14
+ /** Whether a pointer is resizing the pane. */
15
+ get dragging(): boolean;
16
+ get vertical(): boolean;
17
+ get min(): number;
18
+ get max(): number;
19
+ start: (event: PointerEvent) => void;
20
+ reset: () => void;
21
+ keydown: (event: KeyboardEvent) => void;
22
+ }
23
+ /** One width for every page's side pane, so switching pages keeps the divider in place. */
24
+ export declare const sidePaneWidth: PaneSize;
25
+ /** One width for every page's inspector. */
26
+ export declare const inspectorWidth: PaneSize;
@@ -0,0 +1,112 @@
1
+ // Size of a resizable pane, remembered in this browser.
2
+ const KEY_STEP = 16;
3
+ export class PaneSize {
4
+ #size = $state(0);
5
+ #dragging = $state(false);
6
+ edge;
7
+ #bounds;
8
+ #key;
9
+ constructor(key, bounds) {
10
+ this.#key = `connve-${key}-pane-${bounds.edge === 'top' ? 'height' : 'width'}`;
11
+ this.#bounds = bounds;
12
+ this.edge = bounds.edge;
13
+ this.#size = bounds.initial;
14
+ try {
15
+ const saved = Number(localStorage.getItem(this.#key));
16
+ if (saved > 0)
17
+ this.#size = this.#clamp(saved);
18
+ }
19
+ catch {
20
+ // No storage on the server, or blocked in the browser; the initial size still works.
21
+ }
22
+ }
23
+ /** In pixels, within the bounds. */
24
+ get size() {
25
+ return this.#size;
26
+ }
27
+ /** Whether a pointer is resizing the pane. */
28
+ get dragging() {
29
+ return this.#dragging;
30
+ }
31
+ get vertical() {
32
+ return this.edge === 'top';
33
+ }
34
+ get min() {
35
+ return this.#bounds.min;
36
+ }
37
+ get max() {
38
+ return this.#bounds.max;
39
+ }
40
+ #clamp(size) {
41
+ return Math.min(this.#bounds.max, Math.max(this.#bounds.min, Math.round(size)));
42
+ }
43
+ #save() {
44
+ try {
45
+ localStorage.setItem(this.#key, String(this.#size));
46
+ }
47
+ catch {
48
+ // Not remembered, but the pane keeps its size for this visit.
49
+ }
50
+ }
51
+ /** Size change for a pointer or key moving `delta` pixels right, or down for a bottom pane. */
52
+ #grow(delta) {
53
+ return this.edge === 'right' ? delta : -delta;
54
+ }
55
+ start = (event) => {
56
+ if (event.button !== 0)
57
+ return;
58
+ const handle = event.currentTarget;
59
+ const startAt = this.vertical ? event.clientY : event.clientX;
60
+ const startSize = this.#size;
61
+ handle.setPointerCapture(event.pointerId);
62
+ this.#dragging = true;
63
+ const move = (e) => {
64
+ const at = this.vertical ? e.clientY : e.clientX;
65
+ this.#size = this.#clamp(startSize + this.#grow(at - startAt));
66
+ };
67
+ const end = () => {
68
+ this.#dragging = false;
69
+ handle.removeEventListener('pointermove', move);
70
+ handle.removeEventListener('pointerup', end);
71
+ handle.removeEventListener('pointercancel', end);
72
+ this.#save();
73
+ };
74
+ handle.addEventListener('pointermove', move);
75
+ handle.addEventListener('pointerup', end);
76
+ handle.addEventListener('pointercancel', end);
77
+ };
78
+ reset = () => {
79
+ this.#size = this.#bounds.initial;
80
+ this.#save();
81
+ };
82
+ keydown = (event) => {
83
+ if (event.key === 'Home') {
84
+ event.preventDefault();
85
+ this.reset();
86
+ return;
87
+ }
88
+ const keys = this.vertical
89
+ ? { ArrowUp: -KEY_STEP, ArrowDown: KEY_STEP }
90
+ : { ArrowLeft: -KEY_STEP, ArrowRight: KEY_STEP };
91
+ const delta = keys[event.key];
92
+ if (delta === undefined)
93
+ return;
94
+ event.preventDefault();
95
+ this.#size = this.#clamp(this.#size + this.#grow(delta));
96
+ this.#save();
97
+ };
98
+ }
99
+ /** One width for every page's side pane, so switching pages keeps the divider in place. */
100
+ export const sidePaneWidth = new PaneSize('side', {
101
+ initial: 256,
102
+ min: 200,
103
+ max: 520,
104
+ edge: 'right'
105
+ });
106
+ /** One width for every page's inspector. */
107
+ export const inspectorWidth = new PaneSize('inspector', {
108
+ initial: 480,
109
+ min: 360,
110
+ max: 800,
111
+ edge: 'left'
112
+ });
@@ -0,0 +1,18 @@
1
+ import { type Snippet } from 'svelte';
2
+ /** What a page's panes tell the `AppShell` they render in. */
3
+ export declare class ShellState {
4
+ /** The page's side pane, rendered by the shell beside the menu so it reaches the top. */
5
+ pane: Snippet<[]> | null;
6
+ /** Opens a collapsed pane from the top bar on a phone, where its rail is hidden. */
7
+ expand: {
8
+ label: string;
9
+ onclick: () => void;
10
+ } | null;
11
+ /** The top bar's button for `expand`, which takes focus back when a pane over the page closes. */
12
+ expandButton: HTMLButtonElement | null;
13
+ /** How many inspectors are open. */
14
+ inspectors: number;
15
+ }
16
+ export declare const setShell: (context: ShellState) => ShellState;
17
+ /** The enclosing `AppShell`'s state; `component` names the caller in the error when there's none. */
18
+ export declare function getShell(component: string): ShellState;
@@ -0,0 +1,20 @@
1
+ import { createContext } from 'svelte';
2
+ /** What a page's panes tell the `AppShell` they render in. */
3
+ export class ShellState {
4
+ /** The page's side pane, rendered by the shell beside the menu so it reaches the top. */
5
+ pane = $state(null);
6
+ /** Opens a collapsed pane from the top bar on a phone, where its rail is hidden. */
7
+ expand = $state(null);
8
+ /** The top bar's button for `expand`, which takes focus back when a pane over the page closes. */
9
+ expandButton = $state(null);
10
+ /** How many inspectors are open. */
11
+ inspectors = $state(0);
12
+ }
13
+ const [get, set, has] = createContext();
14
+ export const setShell = set;
15
+ /** The enclosing `AppShell`'s state; `component` names the caller in the error when there's none. */
16
+ export function getShell(component) {
17
+ if (!has())
18
+ throw new Error(`${component} must be inside an AppShell`);
19
+ return get();
20
+ }
package/dist/theme.css ADDED
@@ -0,0 +1,169 @@
1
+ /* Import after `tailwindcss` and the `daisyui` plugin. */
2
+
3
+ /* The components' own classes, for the app's Tailwind build. */
4
+ @source './';
5
+
6
+ /* Both themes set every daisyUI token: with `themes: false` nothing fills a gap.
7
+ Text colors keep at least 4.5:1 against what they sit on (WCAG AA). */
8
+
9
+ @plugin 'daisyui/theme' {
10
+ name: 'connve-light';
11
+ default: true;
12
+ prefersdark: false;
13
+ color-scheme: light;
14
+
15
+ --color-base-100: #fffef9;
16
+ --color-base-200: #eef0ea;
17
+ --color-base-300: #d9dcd4;
18
+ --color-base-content: oklch(21% 0.006 285.885);
19
+ --color-primary: #006b55;
20
+ --color-primary-content: #ffffff;
21
+ --color-secondary: #007600;
22
+ --color-secondary-content: oklch(94% 0.028 342.258);
23
+ --color-accent: #00e168;
24
+ --color-accent-content: oklch(38% 0.063 188.416);
25
+ --color-neutral: #0e271b;
26
+ --color-neutral-content: oklch(92% 0.004 286.32);
27
+ --color-info: #007cf3;
28
+ --color-info-content: oklch(29% 0.066 243.157);
29
+ --color-success: #00ffd1;
30
+ --color-success-content: oklch(37% 0.077 168.94);
31
+ --color-warning: #ff9804;
32
+ --color-warning-content: oklch(41% 0.112 45.904);
33
+ --color-error: #cf3450;
34
+ --color-error-content: oklch(27% 0.105 12.094);
35
+
36
+ --radius-selector: 0.5rem;
37
+ --radius-field: 0.25rem;
38
+ --radius-box: 0.5rem;
39
+ --size-selector: 0.25rem;
40
+ --size-field: 0.25rem;
41
+ --border: 1px;
42
+ --depth: 1;
43
+ --noise: 0;
44
+
45
+ /* The library's own tokens: text on the theme's pale tints, which mixes the
46
+ hue with the text color for contrast, and the glow behind state messages. */
47
+ --color-attention: color-mix(in oklab, var(--color-warning) 60%, var(--color-base-content));
48
+ --color-chip-success: color-mix(in oklab, var(--color-primary) 75%, var(--color-base-content));
49
+ --color-chip-warning: color-mix(in oklab, var(--color-warning) 60%, var(--color-base-content));
50
+ --color-chip-error: color-mix(in oklab, var(--color-error) 65%, var(--color-base-content));
51
+ --state-glow-opacity: 0.22;
52
+ --state-glow-blend: multiply;
53
+ --state-title: linear-gradient(120deg, #006b55 0%, #007a6e 50%, #007a3d 100%);
54
+ }
55
+
56
+ @plugin 'daisyui/theme' {
57
+ name: 'connve-dark';
58
+ prefersdark: true;
59
+ color-scheme: dark;
60
+
61
+ --color-base-100: #0e1a15;
62
+ --color-base-200: #142520;
63
+ --color-base-300: #1c2f28;
64
+ --color-base-content: #e8f0ec;
65
+ --color-primary: #00a372;
66
+ --color-primary-content: #0e1a15;
67
+ --color-secondary: #00b4a6;
68
+ --color-secondary-content: oklch(94% 0.028 342.258);
69
+ --color-accent: #00ffd1;
70
+ --color-accent-content: oklch(38% 0.063 188.416);
71
+ --color-neutral: #d4d4d4;
72
+ --color-neutral-content: #0e1a15;
73
+ --color-info: #3399ff;
74
+ --color-info-content: oklch(29% 0.066 243.157);
75
+ --color-success: #00cc99;
76
+ --color-success-content: oklch(37% 0.077 168.94);
77
+ --color-warning: #d97706;
78
+ --color-warning-content: oklch(41% 0.112 45.904);
79
+ --color-error: #ef5a72;
80
+ --color-error-content: #0e1a15;
81
+
82
+ --radius-selector: 0.5rem;
83
+ --radius-field: 0.25rem;
84
+ --radius-box: 0.5rem;
85
+ --size-selector: 0.25rem;
86
+ --size-field: 0.25rem;
87
+ --border: 1px;
88
+ --depth: 1;
89
+ --noise: 0;
90
+
91
+ /* On the dark base the hues read as they are. */
92
+ --color-attention: var(--color-warning);
93
+ --color-chip-success: var(--color-primary);
94
+ --color-chip-warning: var(--color-warning);
95
+ --color-chip-error: var(--color-error);
96
+ --state-glow-opacity: 0.28;
97
+ --state-glow-blend: screen;
98
+ --state-title: linear-gradient(120deg, #00b4a6 0%, #3fd1c4 50%, #00e168 100%);
99
+ }
100
+
101
+ /* Filter chips. Each theme sets the text color on the tints. */
102
+ @utility chip {
103
+ @apply flex h-8 items-center gap-1.5 rounded-full border border-transparent px-3 text-xs transition-colors;
104
+ }
105
+ @utility chip-sm {
106
+ @apply flex h-6 items-center gap-1.5 rounded-full border border-transparent px-2 text-xs transition-colors;
107
+ }
108
+ @utility chip-inactive {
109
+ @apply opacity-70 hover:opacity-100;
110
+ }
111
+ @utility chip-neutral {
112
+ @apply bg-base-200;
113
+ }
114
+ @utility chip-success {
115
+ @apply bg-primary/10;
116
+ color: var(--color-chip-success);
117
+ }
118
+ @utility chip-warn {
119
+ @apply bg-warning/10;
120
+ color: var(--color-chip-warning);
121
+ }
122
+ @utility chip-error {
123
+ @apply bg-error/10;
124
+ color: var(--color-chip-error);
125
+ }
126
+
127
+ /* Warning hue readable as text. */
128
+ @utility text-attention {
129
+ color: var(--color-attention);
130
+ }
131
+
132
+ /* Hides native number-input spinners so number fields match other inputs. */
133
+ @utility no-spinner {
134
+ appearance: textfield;
135
+ -moz-appearance: textfield;
136
+ &::-webkit-outer-spin-button,
137
+ &::-webkit-inner-spin-button {
138
+ -webkit-appearance: none;
139
+ margin: 0;
140
+ }
141
+ }
142
+
143
+ /* List rows read at the size of the side pane beside them. Outside any layer to beat
144
+ daisyUI's own `table-sm` size, which sits in the utilities layer; a row's own text
145
+ size then needs `!`. */
146
+ .table-sm tbody tr {
147
+ font-size: var(--text-sm);
148
+ }
149
+
150
+ /* Clickable rows, in a layer so an app's own utilities still win. */
151
+ @layer components {
152
+ tr[role='button']:focus {
153
+ outline: none;
154
+ }
155
+ /* A visible ring, since the hover background alone also marks the selected row. */
156
+ tr[role='button']:focus-visible {
157
+ @apply bg-base-200;
158
+ outline: 2px solid var(--color-primary);
159
+ outline-offset: -2px;
160
+ }
161
+ }
162
+
163
+ /* daisyUI draws a tooltip's text as generated content, which screen readers read too, after
164
+ the name the element already has. An empty alternative keeps it visual only. */
165
+ @supports (content: 'x' / '') {
166
+ .tooltip[data-tip]::before {
167
+ content: attr(data-tip) / '';
168
+ }
169
+ }
@@ -0,0 +1,13 @@
1
+ export type ThemePref = 'system' | 'light' | 'dark';
2
+ declare class Theme {
3
+ #private;
4
+ /** The viewer's choice; `system` follows the OS. */
5
+ get pref(): ThemePref;
6
+ /** Whether the dark theme shows. */
7
+ get dark(): boolean;
8
+ /** Keeps `<html data-theme>` on the shown theme; call once from the root layout, and stop it with the returned function. */
9
+ start(): () => void;
10
+ set(pref: ThemePref): void;
11
+ }
12
+ export declare const theme: Theme;
13
+ export {};
@@ -0,0 +1,46 @@
1
+ // The color theme the viewer picked, applied to `<html data-theme>`.
2
+ import { MediaQuery } from 'svelte/reactivity';
3
+ const KEY = 'connve-theme';
4
+ function isPref(value) {
5
+ return value === 'system' || value === 'light' || value === 'dark';
6
+ }
7
+ function savedPref() {
8
+ try {
9
+ const saved = localStorage.getItem(KEY);
10
+ return isPref(saved) ? saved : 'system';
11
+ }
12
+ catch {
13
+ // No storage on the server, or blocked in the browser; the theme follows the OS.
14
+ return 'system';
15
+ }
16
+ }
17
+ class Theme {
18
+ #pref = $state(savedPref());
19
+ #osDark = new MediaQuery('prefers-color-scheme: dark');
20
+ /** The viewer's choice; `system` follows the OS. */
21
+ get pref() {
22
+ return this.#pref;
23
+ }
24
+ /** Whether the dark theme shows. */
25
+ get dark() {
26
+ return this.#pref === 'system' ? this.#osDark.current : this.#pref === 'dark';
27
+ }
28
+ /** Keeps `<html data-theme>` on the shown theme; call once from the root layout, and stop it with the returned function. */
29
+ start() {
30
+ return $effect.root(() => {
31
+ $effect(() => {
32
+ document.documentElement.setAttribute('data-theme', this.dark ? 'connve-dark' : 'connve-light');
33
+ });
34
+ });
35
+ }
36
+ set(pref) {
37
+ this.#pref = pref;
38
+ try {
39
+ localStorage.setItem(KEY, pref);
40
+ }
41
+ catch {
42
+ // Not remembered, but the theme still applies for this visit.
43
+ }
44
+ }
45
+ }
46
+ export const theme = new Theme();
@@ -0,0 +1,3 @@
1
+ export type TooltipSide = 'left' | 'right' | 'top' | 'bottom';
2
+ /** daisyUI's placement classes, written out in full so Tailwind finds them. */
3
+ export declare const TOOLTIP_SIDE: Record<TooltipSide, string>;
@@ -0,0 +1,7 @@
1
+ /** daisyUI's placement classes, written out in full so Tailwind finds them. */
2
+ export const TOOLTIP_SIDE = {
3
+ left: 'tooltip-left',
4
+ right: 'tooltip-right',
5
+ top: 'tooltip-top',
6
+ bottom: 'tooltip-bottom'
7
+ };
package/dist/tree.d.ts ADDED
@@ -0,0 +1,17 @@
1
+ export interface TreeNode<T> {
2
+ name: string;
3
+ fullPath: string;
4
+ depth: number;
5
+ isFolder: boolean;
6
+ children?: TreeNode<T>[];
7
+ leaf?: T;
8
+ fileCount?: number;
9
+ }
10
+ /**
11
+ * Builds a slash-delimited path tree from a flat list; `path` returns each item's key.
12
+ * Folders come first, then names in natural order ("item2" before "item10"), and each
13
+ * folder's `fileCount` is its number of items, nested ones included. A key can name an
14
+ * item and a folder at once ("a" and "a/b"); they become two nodes. Of items with the
15
+ * same key, the first is kept.
16
+ */
17
+ export declare function buildTree<T>(items: T[], path: (item: T) => string): TreeNode<T>[];
package/dist/tree.js ADDED
@@ -0,0 +1,44 @@
1
+ const collator = new Intl.Collator(undefined, { numeric: true });
2
+ /**
3
+ * Builds a slash-delimited path tree from a flat list; `path` returns each item's key.
4
+ * Folders come first, then names in natural order ("item2" before "item10"), and each
5
+ * folder's `fileCount` is its number of items, nested ones included. A key can name an
6
+ * item and a folder at once ("a" and "a/b"); they become two nodes. Of items with the
7
+ * same key, the first is kept.
8
+ */
9
+ export function buildTree(items, path) {
10
+ const root = [];
11
+ for (const item of items) {
12
+ const parts = path(item).split('/').filter(Boolean);
13
+ let level = root;
14
+ parts.forEach((name, depth) => {
15
+ const isFolder = depth < parts.length - 1;
16
+ let node = level.find((n) => n.name === name && n.isFolder === isFolder);
17
+ if (!node) {
18
+ const fullPath = parts.slice(0, depth + 1).join('/');
19
+ node = isFolder
20
+ ? { name, fullPath, depth, isFolder, children: [] }
21
+ : { name, fullPath, depth, isFolder, leaf: item };
22
+ level.push(node);
23
+ }
24
+ level = node.children ?? [];
25
+ });
26
+ }
27
+ sortAndCount(root);
28
+ return root;
29
+ }
30
+ /** Sorts a level and its folders, sets their `fileCount`, and returns the level's item count. */
31
+ function sortAndCount(nodes) {
32
+ nodes.sort((a, b) => Number(b.isFolder) - Number(a.isFolder) || collator.compare(a.name, b.name));
33
+ let count = 0;
34
+ for (const node of nodes) {
35
+ if (node.children) {
36
+ node.fileCount = sortAndCount(node.children);
37
+ count += node.fileCount;
38
+ }
39
+ else {
40
+ count += 1;
41
+ }
42
+ }
43
+ return count;
44
+ }
package/package.json CHANGED
@@ -1,6 +1,83 @@
1
1
  {
2
- "name": "@connve/ui",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
2
+ "name": "@connve/ui",
3
+ "version": "0.1.0",
4
+ "description": "Svelte components and theme shared by the CONNVE apps.",
5
+ "license": "MPL-2.0",
6
+ "type": "module",
7
+ "keywords": [
8
+ "svelte",
9
+ "svelte5",
10
+ "components",
11
+ "tailwindcss",
12
+ "daisyui"
13
+ ],
14
+ "homepage": "https://github.com/connve/ui#readme",
15
+ "bugs": "https://github.com/connve/ui/issues",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/connve/ui.git"
19
+ },
20
+ "publishConfig": {
21
+ "access": "public"
22
+ },
23
+ "scripts": {
24
+ "dev": "vite dev",
25
+ "build": "vite build && npm run package",
26
+ "package": "svelte-kit sync && svelte-package && publint && node scripts/check-dist.js",
27
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
28
+ "test": "vitest run",
29
+ "format": "prettier --write .",
30
+ "lint": "prettier --check . && eslint .",
31
+ "icons": "node scripts/icons.js && prettier --write src/lib/icons.ts",
32
+ "prepublishOnly": "npm run package"
33
+ },
34
+ "files": [
35
+ "dist",
36
+ "!dist/**/*.test.*",
37
+ "!dist/**/*.spec.*"
38
+ ],
39
+ "sideEffects": [
40
+ "**/*.css"
41
+ ],
42
+ "svelte": "./dist/index.js",
43
+ "types": "./dist/index.d.ts",
44
+ "exports": {
45
+ ".": {
46
+ "types": "./dist/index.d.ts",
47
+ "svelte": "./dist/index.js"
48
+ },
49
+ "./theme.css": "./dist/theme.css"
50
+ },
51
+ "peerDependencies": {
52
+ "@iconify/svelte": "^5.0.0",
53
+ "daisyui": "^5.0.0",
54
+ "svelte": "^5.40.0",
55
+ "tailwindcss": "^4.0.0"
56
+ },
57
+ "devDependencies": {
58
+ "@eslint/js": "^10.0.1",
59
+ "@iconify-json/tabler": "^1.2.44",
60
+ "@iconify/svelte": "^5.2.4",
61
+ "@sveltejs/adapter-static": "^4.0.1",
62
+ "@sveltejs/kit": "^3.2.0",
63
+ "@sveltejs/package": "^3.0.2",
64
+ "@sveltejs/vite-plugin-svelte": "^7.3.1",
65
+ "@tailwindcss/vite": "^4.3.5",
66
+ "daisyui": "^5.7.50",
67
+ "eslint": "^10.14.0",
68
+ "eslint-config-prettier": "^10.1.8",
69
+ "eslint-plugin-svelte": "^3.24.1",
70
+ "globals": "^17.14.0",
71
+ "prettier": "^3.9.10",
72
+ "prettier-plugin-svelte": "^4.1.1",
73
+ "prettier-plugin-tailwindcss": "^0.8.1",
74
+ "publint": "^0.3.25",
75
+ "svelte": "^5.57.3",
76
+ "svelte-check": "^4.7.8",
77
+ "tailwindcss": "^4.3.5",
78
+ "typescript": "^6.0.3",
79
+ "typescript-eslint": "^8.72.2",
80
+ "vite": "^8.3.8",
81
+ "vitest": "^5.1.0"
82
+ }
83
+ }