diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..7456665
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,37 @@
+name: CI
+
+on:
+ push:
+ branches: [main]
+ pull_request:
+ branches: [main]
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: '20'
+ cache: 'npm'
+ - run: npm ci
+ - run: npm run check
+ - run: npm run lint
+ - run: npm test
+
+ publish:
+ needs: test
+ runs-on: ubuntu-latest
+ if: github.ref == 'refs/heads/main'
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: '20'
+ registry-url: 'https://registry.npmjs.org'
+ - run: npm ci
+ - run: npm run build
+ - run: npm publish
+ env:
+ NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..715b548
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,22 @@
+node_modules
+
+# Output
+.output
+.vercel
+/.svelte-kit
+/build
+/dist
+
+# OS
+.DS_Store
+Thumbs.db
+
+# Env
+.env
+.env.*
+!.env.example
+!.env.test
+
+# Vite
+vite.config.js.timestamp-*
+vite.config.ts.timestamp-*
diff --git a/.npmrc b/.npmrc
new file mode 100644
index 0000000..b6f27f1
--- /dev/null
+++ b/.npmrc
@@ -0,0 +1 @@
+engine-strict=true
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 0000000..ab78a95
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,4 @@
+# Package Managers
+package-lock.json
+pnpm-lock.yaml
+yarn.lock
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..7ebb855
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,15 @@
+{
+ "useTabs": true,
+ "singleQuote": true,
+ "trailingComma": "none",
+ "printWidth": 100,
+ "plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
+ "overrides": [
+ {
+ "files": "*.svelte",
+ "options": {
+ "parser": "svelte"
+ }
+ }
+ ]
+}
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..f13e9ec
--- /dev/null
+++ b/README.md
@@ -0,0 +1,257 @@
+# SvelteDnD
+
+A lightweight drag and drop library for Svelte 5 applications. Built with TypeScript and Svelte's new runes system.
+
+## Installation
+
+```bash
+npm install sveltednd
+```
+
+## Quick Start
+
+```typescript
+import { draggable, droppable } from 'sveltednd';
+import 'sveltednd/styles.css';
+
+// Create a list of items
+let items = $state(['Item 1', 'Item 2', 'Item 3']);
+
+// Handle drops between containers
+function handleDrop(state) {
+ const { draggedItem, sourceContainer, targetContainer } = state;
+ if (!targetContainer || sourceContainer === targetContainer) return;
+
+ items = items.filter((item) => item !== draggedItem);
+ items = [...items, draggedItem];
+}
+```
+
+```svelte
+
+
+ {#each items as item}
+
+
+ {item}
+
+ {/each}
+
+```
+
+## Core Concepts
+
+### 1. Draggable Items
+
+- Add `use:draggable` to make elements draggable
+- Specify container ID and data to transfer
+- Optional callbacks for drag start/end
+
+### 2. Droppable Containers
+
+- Add `use:droppable` to create drop zones
+- Handle drops via callbacks
+- Visual feedback during drag operations
+
+### 3. State Management
+
+- Built-in state tracking via Svelte 5 runes
+- Access current drag state via `dndState` store
+- Automatic cleanup and memory management
+
+## API Reference
+
+### Draggable Action
+
+```typescript
+interface DraggableOptions {
+ container: string; // Container identifier
+ dragData: any; // Data to transfer
+ disabled?: boolean; // Disable dragging
+ callbacks?: {
+ onDragStart?: (state: DragDropState) => void;
+ onDragEnd?: (state: DragDropState) => void;
+ }
+}
+
+// Usage
+ console.log('Started dragging', state)
+ }
+}}>
+```
+
+### Droppable Action
+
+```typescript
+interface DroppableOptions {
+ container: string; // Container identifier
+ disabled?: boolean; // Disable dropping
+ callbacks?: {
+ onDragEnter?: (state: DragDropState) => void;
+ onDragLeave?: (state: DragDropState) => void;
+ onDragOver?: (state: DragDropState) => void;
+ onDrop?: (state: DragDropState) => Promise
| void;
+ }
+}
+
+// Usage
+ handleDrop(state)
+ }
+}}>
+```
+
+### DragDropState Interface
+
+```typescript
+interface DragDropState {
+ isDragging: boolean; // Current drag status
+ draggedItem: any; // Item being dragged
+ sourceContainer: string; // Origin container ID
+ targetContainer: string | null; // Current target container ID
+}
+```
+
+## Examples
+
+### Basic List
+
+```svelte
+
+
+
+ {#each items as item}
+
+ {item}
+
+ {/each}
+
+```
+
+### Multiple Containers
+
+```svelte
+
+
+
+
+ {#each container1 as item}
+
+ {item}
+
+ {/each}
+
+
+
+ {#each container2 as item}
+
+ {item}
+
+ {/each}
+
+
+```
+
+### Conditional Dropping
+
+```svelte
+
+
+
+```
+
+## Styling
+
+The library provides CSS classes for styling drag and drop states:
+
+```css
+/* Base styles */
+.svelte-dnd-draggable {
+ cursor: grab;
+}
+
+/* Active dragging */
+.svelte-dnd-dragging {
+ opacity: 0.5;
+ cursor: grabbing;
+}
+
+/* Valid drop target */
+.svelte-dnd-drop-target {
+ outline: 2px dashed #4caf50;
+}
+
+/* Invalid drop target */
+.svelte-dnd-invalid-target {
+ outline: 2px dashed #f44336;
+}
+```
+
+## TypeScript Support
+
+The library is written in TypeScript and provides full type definitions. Use interfaces to type your dragged items:
+
+```typescript
+interface Task {
+ id: string;
+ title: string;
+}
+
+function handleDrop(state: DragDropState) {
+ const draggedTask = state.draggedItem as Task;
+ // TypeScript now knows the shape of draggedTask
+}
+```
+
+## Performance Tips
+
+1. Use unique IDs as keys in loops
+2. Keep drag data minimal
+3. Avoid expensive operations in drag callbacks
+4. Use `$derived` for computed values
+
+## License
+
+MIT
diff --git a/bun.lockb b/bun.lockb
new file mode 100755
index 0000000..7f4e3ea
Binary files /dev/null and b/bun.lockb differ
diff --git a/eslint.config.js b/eslint.config.js
new file mode 100644
index 0000000..a526565
--- /dev/null
+++ b/eslint.config.js
@@ -0,0 +1,33 @@
+import prettier from 'eslint-config-prettier';
+import js from '@eslint/js';
+import svelte from 'eslint-plugin-svelte';
+import globals from 'globals';
+import ts from 'typescript-eslint';
+
+export default ts.config(
+ js.configs.recommended,
+ ...ts.configs.recommended,
+ ...svelte.configs['flat/recommended'],
+ prettier,
+ ...svelte.configs['flat/prettier'],
+ {
+ languageOptions: {
+ globals: {
+ ...globals.browser,
+ ...globals.node
+ }
+ }
+ },
+ {
+ files: ['**/*.svelte'],
+
+ languageOptions: {
+ parserOptions: {
+ parser: ts.parser
+ }
+ }
+ },
+ {
+ ignores: ['build/', '.svelte-kit/', 'dist/']
+ }
+);
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..fd19805
--- /dev/null
+++ b/package.json
@@ -0,0 +1,75 @@
+{
+ "name": "sveltednd",
+ "version": "0.0.1",
+ "description": "A lightweight, flexible drag and drop library for Svelte 5 applications.",
+ "author": "sanju
",
+ "contributors": [
+ "sanju "
+ ],
+ "license": "MIT",
+ "keywords": [
+ "svelte",
+ "drag",
+ "drop",
+ "dnd",
+ "drag-and-drop",
+ "typescript",
+ "svelte5"
+ ],
+ "scripts": {
+ "dev": "vite dev",
+ "build": "vite build && npm run package",
+ "preview": "vite preview",
+ "package": "svelte-kit sync && svelte-package && publint",
+ "prepublishOnly": "npm run package",
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
+ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
+ "format": "prettier --write .",
+ "lint": "prettier --check . && eslint .",
+ "test:unit": "vitest",
+ "test": "npm run test:unit -- --run"
+ },
+ "files": [
+ "dist",
+ "!dist/**/*.test.*",
+ "!dist/**/*.spec.*"
+ ],
+ "sideEffects": [
+ "**/*.css"
+ ],
+ "svelte": "./dist/index.js",
+ "types": "./dist/index.d.ts",
+ "type": "module",
+ "exports": {
+ ".": {
+ "types": "./dist/index.d.ts",
+ "svelte": "./dist/index.js"
+ }
+ },
+ "peerDependencies": {
+ "svelte": "^5.0.0"
+ },
+ "devDependencies": {
+ "@sveltejs/adapter-auto": "^3.0.0",
+ "@sveltejs/kit": "^2.0.0",
+ "@sveltejs/package": "^2.0.0",
+ "@sveltejs/vite-plugin-svelte": "^4.0.0",
+ "@types/eslint": "^9.6.0",
+ "autoprefixer": "^10.4.20",
+ "eslint": "^9.7.0",
+ "eslint-config-prettier": "^9.1.0",
+ "eslint-plugin-svelte": "^2.36.0",
+ "globals": "^15.0.0",
+ "prettier": "^3.3.2",
+ "prettier-plugin-svelte": "^3.2.6",
+ "prettier-plugin-tailwindcss": "^0.6.5",
+ "publint": "^0.2.0",
+ "svelte": "^5.0.0",
+ "svelte-check": "^4.0.0",
+ "tailwindcss": "^3.4.9",
+ "typescript": "^5.0.0",
+ "typescript-eslint": "^8.0.0",
+ "vite": "^5.0.11",
+ "vitest": "^2.0.4"
+ }
+}
diff --git a/postcss.config.js b/postcss.config.js
new file mode 100644
index 0000000..0f77216
--- /dev/null
+++ b/postcss.config.js
@@ -0,0 +1,6 @@
+export default {
+ plugins: {
+ tailwindcss: {},
+ autoprefixer: {}
+ }
+};
diff --git a/src/app.css b/src/app.css
new file mode 100644
index 0000000..a31e444
--- /dev/null
+++ b/src/app.css
@@ -0,0 +1,3 @@
+@import 'tailwindcss/base';
+@import 'tailwindcss/components';
+@import 'tailwindcss/utilities';
diff --git a/src/app.d.ts b/src/app.d.ts
new file mode 100644
index 0000000..da08e6d
--- /dev/null
+++ b/src/app.d.ts
@@ -0,0 +1,13 @@
+// See https://svelte.dev/docs/kit/types#app.d.ts
+// for information about these interfaces
+declare global {
+ namespace App {
+ // interface Error {}
+ // interface Locals {}
+ // interface PageData {}
+ // interface PageState {}
+ // interface Platform {}
+ }
+}
+
+export {};
diff --git a/src/app.html b/src/app.html
new file mode 100644
index 0000000..f22aeaa
--- /dev/null
+++ b/src/app.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+ %sveltekit.head%
+
+
+ %sveltekit.body%
+
+
diff --git a/src/demo.spec.ts b/src/demo.spec.ts
new file mode 100644
index 0000000..e07cbbd
--- /dev/null
+++ b/src/demo.spec.ts
@@ -0,0 +1,7 @@
+import { describe, it, expect } from 'vitest';
+
+describe('sum test', () => {
+ it('adds 1 + 2 to equal 3', () => {
+ expect(1 + 2).toBe(3);
+ });
+});
diff --git a/src/lib/actions/draggable.ts b/src/lib/actions/draggable.ts
new file mode 100644
index 0000000..636a280
--- /dev/null
+++ b/src/lib/actions/draggable.ts
@@ -0,0 +1,49 @@
+import { dndState } from '$lib/stores/dnd.svelte.js';
+import type { DragDropOptions } from '$lib/types/index.js';
+
+export function draggable(node: HTMLElement, options: DragDropOptions) {
+ function handleDragStart(event: DragEvent) {
+ if (options.disabled) return;
+
+ // Update state using assignment (Svelte 5 style)
+ dndState.isDragging = true;
+ dndState.draggedItem = options.dragData;
+ dndState.sourceContainer = options.container;
+ dndState.targetContainer = null;
+
+ if (event.dataTransfer) {
+ event.dataTransfer.effectAllowed = 'move';
+ event.dataTransfer.setData('text/plain', JSON.stringify(options.dragData));
+ }
+
+ node.classList.add('dragging');
+ options.callbacks?.onDragStart?.(dndState);
+ }
+
+ function handleDragEnd() {
+ node.classList.remove('dragging');
+ options.callbacks?.onDragEnd?.(dndState);
+
+ // Reset state
+ dndState.isDragging = false;
+ dndState.draggedItem = null;
+ dndState.sourceContainer = '';
+ dndState.targetContainer = null;
+ }
+
+ node.draggable = !options.disabled;
+ node.addEventListener('dragstart', handleDragStart);
+ node.addEventListener('dragend', handleDragEnd);
+
+ return {
+ update(newOptions: DragDropOptions) {
+ options = newOptions;
+ node.draggable = !options.disabled;
+ },
+
+ destroy() {
+ node.removeEventListener('dragstart', handleDragStart);
+ node.removeEventListener('dragend', handleDragEnd);
+ }
+ };
+}
diff --git a/src/lib/actions/droppable.ts b/src/lib/actions/droppable.ts
new file mode 100644
index 0000000..132b40a
--- /dev/null
+++ b/src/lib/actions/droppable.ts
@@ -0,0 +1,71 @@
+import { dndState } from '$lib/stores/dnd.svelte.js';
+import type { DragDropOptions } from '$lib/types/index.js';
+
+export function droppable(node: HTMLElement, options: DragDropOptions) {
+ function handleDragEnter(event: DragEvent) {
+ if (options.disabled) return;
+ event.preventDefault();
+
+ dndState.targetContainer = options.container;
+ node.classList.add('drag-over');
+ options.callbacks?.onDragEnter?.(dndState);
+ }
+
+ function handleDragLeave(event: DragEvent) {
+ if (options.disabled) return;
+
+ const target = event.target as HTMLElement;
+ if (!node.contains(target)) {
+ dndState.targetContainer = null;
+ node.classList.remove('drag-over');
+ options.callbacks?.onDragLeave?.(dndState);
+ }
+ }
+
+ function handleDragOver(event: DragEvent) {
+ if (options.disabled) return;
+ event.preventDefault();
+
+ if (event.dataTransfer) {
+ event.dataTransfer.dropEffect = 'move';
+ }
+
+ options.callbacks?.onDragOver?.(dndState);
+ }
+
+ async function handleDrop(event: DragEvent) {
+ if (options.disabled) return;
+ event.preventDefault();
+
+ node.classList.remove('drag-over');
+
+ try {
+ if (event.dataTransfer) {
+ const dragData = JSON.parse(event.dataTransfer.getData('text/plain'));
+ dndState.draggedItem = dragData;
+ }
+
+ await options.callbacks?.onDrop?.(dndState);
+ } catch (error) {
+ console.error('Drop handling failed:', error);
+ }
+ }
+
+ node.addEventListener('dragenter', handleDragEnter);
+ node.addEventListener('dragleave', handleDragLeave);
+ node.addEventListener('dragover', handleDragOver);
+ node.addEventListener('drop', handleDrop);
+
+ return {
+ update(newOptions: DragDropOptions) {
+ options = newOptions;
+ },
+
+ destroy() {
+ node.removeEventListener('dragenter', handleDragEnter);
+ node.removeEventListener('dragleave', handleDragLeave);
+ node.removeEventListener('dragover', handleDragOver);
+ node.removeEventListener('drop', handleDrop);
+ }
+ };
+}
diff --git a/src/lib/actions/index.ts b/src/lib/actions/index.ts
new file mode 100644
index 0000000..10edd50
--- /dev/null
+++ b/src/lib/actions/index.ts
@@ -0,0 +1,2 @@
+export { draggable } from './draggable.js';
+export { droppable } from './droppable.js';
diff --git a/src/lib/index.ts b/src/lib/index.ts
new file mode 100644
index 0000000..c9450e3
--- /dev/null
+++ b/src/lib/index.ts
@@ -0,0 +1,11 @@
+// Actions
+export { draggable, droppable } from './actions/index.js';
+
+// Store
+export { dndState } from './stores/dnd.svelte.js';
+
+// Types
+export type * from './types/index.js';
+
+// Styles
+import './styles/dnd.css';
diff --git a/src/lib/stores/dnd.svelte.ts b/src/lib/stores/dnd.svelte.ts
new file mode 100644
index 0000000..4bb7456
--- /dev/null
+++ b/src/lib/stores/dnd.svelte.ts
@@ -0,0 +1,9 @@
+import type { DragDropState } from '$lib/types/index.js';
+
+// Global DnD state using Svelte 5's state rune
+export const dndState = $state({
+ isDragging: false,
+ draggedItem: null,
+ sourceContainer: '',
+ targetContainer: null
+});
diff --git a/src/lib/styles/dnd.css b/src/lib/styles/dnd.css
new file mode 100644
index 0000000..790b2be
--- /dev/null
+++ b/src/lib/styles/dnd.css
@@ -0,0 +1,37 @@
+/* Base draggable styles */
+.svelte-dnd-draggable {
+ touch-action: none; /* Prevents touch scrolling while dragging */
+ user-select: none; /* Prevents text selection during drag */
+}
+
+/* Active dragging state */
+.svelte-dnd-dragging {
+ opacity: 0.5;
+ cursor: grabbing;
+}
+
+/* Draggable hover state */
+.svelte-dnd-draggable:hover {
+ cursor: grab;
+}
+
+/* Droppable area styles */
+.svelte-dnd-droppable {
+ position: relative;
+}
+
+/* Active drop target */
+.svelte-dnd-drop-target {
+ outline: 2px dashed #4caf50;
+}
+
+/* Invalid drop target */
+.svelte-dnd-invalid-target {
+ outline: 2px dashed #f44336;
+}
+
+/* Drop preview/placeholder */
+.svelte-dnd-placeholder {
+ opacity: 0.3;
+ border: 2px dashed #9e9e9e;
+}
diff --git a/src/lib/types/index.ts b/src/lib/types/index.ts
new file mode 100644
index 0000000..6810d40
--- /dev/null
+++ b/src/lib/types/index.ts
@@ -0,0 +1,22 @@
+export interface DragDropState {
+ isDragging: boolean;
+ draggedItem: any;
+ sourceContainer: string;
+ targetContainer: string | null;
+}
+
+export interface DragDropCallbacks {
+ onDragStart?: (state: DragDropState) => void;
+ onDragEnter?: (state: DragDropState) => void;
+ onDragLeave?: (state: DragDropState) => void;
+ onDragOver?: (state: DragDropState) => void;
+ onDrop?: (state: DragDropState) => Promise | void;
+ onDragEnd?: (state: DragDropState) => void;
+}
+
+export interface DragDropOptions {
+ dragData?: any;
+ container: string;
+ disabled?: boolean;
+ callbacks?: DragDropCallbacks;
+}
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte
new file mode 100644
index 0000000..33ddc16
--- /dev/null
+++ b/src/routes/+layout.svelte
@@ -0,0 +1,60 @@
+
+
+
+
+
+ {@render children()}
+
+
+
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte
new file mode 100644
index 0000000..c5d6df7
--- /dev/null
+++ b/src/routes/+page.svelte
@@ -0,0 +1,153 @@
+
+
+
+
+
Kanban Board
+
Drag and drop tasks between columns to reorder them in the board.
+
+
+
+ {#each tasksByStatus as { status, items }}
+
+
+
+
+ {status.replace('-', ' ')}
+
+
+ {items.length}
+
+
+
+
+ {#each items as task (task.id)}
+
+
+
+ {task.title}
+
+
+ {task.priority}
+
+
+
+ {task.description}
+
+
+ {/each}
+
+
+
+ {/each}
+
+
+
+
diff --git a/src/routes/grid-sort/+page.svelte b/src/routes/grid-sort/+page.svelte
new file mode 100644
index 0000000..8d097ed
--- /dev/null
+++ b/src/routes/grid-sort/+page.svelte
@@ -0,0 +1,58 @@
+
+
+
+
+
+
Sortable List
+
Drag and drop items to reorder them in the list.
+
+
+
+ {#each cards as card, index (card.id)}
+
+
+
+ Position {index + 1}
+
+
{/each}
+
+
+
diff --git a/src/routes/horizontal-scroll/+page.svelte b/src/routes/horizontal-scroll/+page.svelte
new file mode 100644
index 0000000..199856b
--- /dev/null
+++ b/src/routes/horizontal-scroll/+page.svelte
@@ -0,0 +1,60 @@
+
+
+
+
+
Horizontal Image Gallery
+
Drag and drop images to rearrange them in the gallery.
+
+
+
+ {#each images as image, index (image.id)}
+
+
+
+
+
+ {index + 1}
+
+
+ {/each}
+
+
diff --git a/src/routes/nested/+page.svelte b/src/routes/nested/+page.svelte
new file mode 100644
index 0000000..d516678
--- /dev/null
+++ b/src/routes/nested/+page.svelte
@@ -0,0 +1,188 @@
+
+
+
+
Nested Containers
+
+
+ {#each groups as group, groupIndex (group.id)}
+
+
+
+
+
+
{group.title}
+
{group.description}
+
+
+ {group.items.length}
+
+
+
+
+
+ {#each group.items as item, itemIndex (item.id)}
+
handleItemDrop(group.id, state)
+ }
+ }}
+ >
+
+
+
{item.title}
+
+ {item.priority}
+
+
+
{item.description}
+
+
+ {/each}
+
+
+
+ {/each}
+
+
+
+
diff --git a/src/routes/simple-list/+page.svelte b/src/routes/simple-list/+page.svelte
new file mode 100644
index 0000000..4ae1274
--- /dev/null
+++ b/src/routes/simple-list/+page.svelte
@@ -0,0 +1,105 @@
+
+
+
+
+
Sortable List
+
Drag and drop items to reorder them in the list.
+
+
+
+
+
+ {#each items as item, index (item.id)}
+
+
+
+ {item.title}
+
+
+ {item.priority}
+
+
+
+ {item.description}
+
+
+ {/each}
+
+
+
+
+
+
diff --git a/static/favicon.png b/static/favicon.png
new file mode 100644
index 0000000..825b9e6
Binary files /dev/null and b/static/favicon.png differ
diff --git a/svelte.config.js b/svelte.config.js
new file mode 100644
index 0000000..1295460
--- /dev/null
+++ b/svelte.config.js
@@ -0,0 +1,18 @@
+import adapter from '@sveltejs/adapter-auto';
+import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
+
+/** @type {import('@sveltejs/kit').Config} */
+const config = {
+ // Consult https://svelte.dev/docs/kit/integrations
+ // for more information about preprocessors
+ preprocess: vitePreprocess(),
+
+ kit: {
+ // adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
+ // If your environment is not supported, or you settled on a specific environment, switch out the adapter.
+ // See https://svelte.dev/docs/kit/adapters for more information about adapters.
+ adapter: adapter()
+ }
+};
+
+export default config;
diff --git a/tailwind.config.ts b/tailwind.config.ts
new file mode 100644
index 0000000..aa4bc77
--- /dev/null
+++ b/tailwind.config.ts
@@ -0,0 +1,11 @@
+import type { Config } from 'tailwindcss';
+
+export default {
+ content: ['./src/**/*.{html,js,svelte,ts}'],
+
+ theme: {
+ extend: {}
+ },
+
+ plugins: []
+} satisfies Config;
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..6f788f1
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,15 @@
+{
+ "extends": "./.svelte-kit/tsconfig.json",
+ "compilerOptions": {
+ "allowJs": true,
+ "checkJs": true,
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "resolveJsonModule": true,
+ "skipLibCheck": true,
+ "sourceMap": true,
+ "strict": true,
+ "module": "NodeNext",
+ "moduleResolution": "NodeNext"
+ }
+}
diff --git a/vite.config.ts b/vite.config.ts
new file mode 100644
index 0000000..d76fc8a
--- /dev/null
+++ b/vite.config.ts
@@ -0,0 +1,10 @@
+import { defineConfig } from 'vitest/config';
+import { sveltekit } from '@sveltejs/kit/vite';
+
+export default defineConfig({
+ plugins: [sveltekit()],
+
+ test: {
+ include: ['src/**/*.{test,spec}.{js,ts}']
+ }
+});