Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Spikeysanju committed Nov 10, 2024
0 parents commit 5d8d972
Show file tree
Hide file tree
Showing 32 changed files with 1,364 additions and 0 deletions.
37 changes: 37 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -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}}
22 changes: 22 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -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-*
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
engine-strict=true
4 changes: 4 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Package Managers
package-lock.json
pnpm-lock.yaml
yarn.lock
15 changes: 15 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -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"
}
}
]
}
257 changes: 257 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -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
<!-- Make a droppable container -->
<div use:droppable={{ container: 'list', callbacks: { onDrop: handleDrop } }}>
{#each items as item}
<!-- Make items draggable -->
<div use:draggable={{ container: 'list', dragData: item }}>
{item}
</div>
{/each}
</div>
```

## 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
<div use:draggable={{
container: "my-list",
dragData: item,
callbacks: {
onDragStart: (state) => 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> | void;
}
}

// Usage
<div use:droppable={{
container: "my-list",
callbacks: {
onDrop: async (state) => 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
<script lang="ts">
let items = $state(['Item 1', 'Item 2', 'Item 3']);
function handleDrop(state: DragDropState) {
const { draggedItem } = state;
items = [...items, draggedItem];
}
</script>
<div use:droppable={{ container: 'list', callbacks: { onDrop: handleDrop } }}>
{#each items as item}
<div use:draggable={{ container: 'list', dragData: item }}>
{item}
</div>
{/each}
</div>
```

### Multiple Containers

```svelte
<script lang="ts">
let container1 = $state(['A', 'B']);
let container2 = $state(['C', 'D']);
function handleDrop(state: DragDropState) {
const { sourceContainer, targetContainer, draggedItem } = state;
if (sourceContainer === 'container1') {
container1 = container1.filter((i) => i !== draggedItem);
container2 = [...container2, draggedItem];
} else {
container2 = container2.filter((i) => i !== draggedItem);
container1 = [...container1, draggedItem];
}
}
</script>
<div class="flex gap-4">
<div use:droppable={{ container: 'container1', callbacks: { onDrop: handleDrop } }}>
{#each container1 as item}
<div use:draggable={{ container: 'container1', dragData: item }}>
{item}
</div>
{/each}
</div>
<div use:droppable={{ container: 'container2', callbacks: { onDrop: handleDrop } }}>
{#each container2 as item}
<div use:draggable={{ container: 'container2', dragData: item }}>
{item}
</div>
{/each}
</div>
</div>
```

### Conditional Dropping

```svelte
<script lang="ts">
function handleDragOver(state: DragDropState) {
const { draggedItem } = state;
// Prevent dropping if item doesn't meet criteria
if (!isValidItem(draggedItem)) {
return false;
}
}
</script>
<div use:droppable={{
container: "filtered",
callbacks: {
onDragOver: handleDragOver,
onDrop: handleDrop
}
}}>
```

## 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
Binary file added bun.lockb
Binary file not shown.
33 changes: 33 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -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/']
}
);
Loading

0 comments on commit 5d8d972

Please sign in to comment.