├── .prettierrc.json ├── .github ├── FUNDING.yml └── workflows │ ├── release.yml │ └── bundle-check.yml ├── .vscode └── extensions.json ├── readme └── demo.gif ├── public └── favicon.ico ├── lib └── main.ts ├── src ├── assets │ └── logo.png ├── main.ts ├── env.d.ts ├── components │ ├── HelloWorld.vue │ └── Sortable.vue ├── App.vue └── examples │ └── WithStore.vue ├── renovate.json ├── tsconfig.node.json ├── vite.site.config.ts ├── .prettierignore ├── .gitignore ├── .npmignore ├── .eslintrc.js ├── index.html ├── tsconfig.dist.json ├── tsconfig.site.json ├── vite.config.ts ├── LICENSE ├── package.json ├── README.md └── pnpm-lock.yaml /.prettierrc.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: MaxLeiter 2 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["Vue.volar"] 3 | } 4 | -------------------------------------------------------------------------------- /readme/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaxLeiter/sortablejs-vue3/HEAD/readme/demo.gif -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaxLeiter/sortablejs-vue3/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /lib/main.ts: -------------------------------------------------------------------------------- 1 | import Sortable from "../src/components/Sortable.vue"; 2 | 3 | export { Sortable }; 4 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaxLeiter/sortablejs-vue3/HEAD/src/assets/logo.png -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from "vue"; 2 | import App from "./App.vue"; 3 | 4 | const app = createApp(App); 5 | 6 | app.mount("#app"); 7 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": ["group:allNonMajor", "config:base"] 4 | } 5 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "esnext", 5 | "moduleResolution": "node" 6 | }, 7 | "include": ["vite.config.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /vite.site.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import vue from "@vitejs/plugin-vue"; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [vue()], 7 | }); 8 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | dist-ssr 4 | *.local 5 | 6 | # Editor directories and files 7 | .vscode/* 8 | !.vscode/extensions.json 9 | .idea 10 | .DS_Store 11 | *.suo 12 | *.ntvs* 13 | *.njsproj 14 | *.sln 15 | *.sw? 16 | 17 | .vercel 18 | 19 | # Custom 20 | sortablejs-*.tgz 21 | -------------------------------------------------------------------------------- /src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | declare module "*.vue" { 4 | import type { DefineComponent } from "vue"; 5 | // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types 6 | const component: DefineComponent<{}, {}, any>; 7 | export default component; 8 | } 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | 26 | .vercel 27 | 28 | # Custom 29 | sortablejs-*.tgz 30 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # .gitignore, because npm ignores it if this file is present. 2 | # Logs 3 | logs 4 | *.log 5 | npm-debug.log* 6 | yarn-debug.log* 7 | yarn-error.log* 8 | pnpm-debug.log* 9 | lerna-debug.log* 10 | 11 | node_modules 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | 26 | .vercel 27 | 28 | # Custom 29 | sortablejs-*.tgz 30 | 31 | # Specific to ignoring when packaging 32 | .github 33 | 34 | readme 35 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | require("@rushstack/eslint-patch/modern-module-resolution"); 2 | 3 | module.exports = { 4 | env: { 5 | node: true, 6 | }, 7 | extends: [ 8 | "eslint:recommended", 9 | "plugin:vue/vue3-recommended", 10 | "@vue/eslint-config-typescript", 11 | "prettier", 12 | ], 13 | parser: "vue-eslint-parser", 14 | parserOptions: { 15 | parser: "@typescript-eslint/parser", 16 | sourceType: "module", 17 | }, 18 | rules: { 19 | // override/add rules settings here, such as: 20 | // 'vue/no-unused-vars': 'error' 21 | }, 22 | }; 23 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | sortablejs-vue3 8 | 9 | 10 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - v* 7 | workflow_dispatch: 8 | 9 | jobs: 10 | release: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v3 14 | - uses: actions/setup-node@v3 15 | with: 16 | node-version: "18" 17 | registry-url: "https://registry.npmjs.org" 18 | - uses: pnpm/action-setup@v2 19 | name: Install pnpm 20 | with: 21 | version: 8 22 | run_install: false 23 | - run: pnpm i 24 | - run: pnpm build 25 | - run: pnpm publish 26 | env: 27 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 28 | -------------------------------------------------------------------------------- /tsconfig.dist.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "useDefineForClassFields": true, 5 | "module": "esnext", 6 | "moduleResolution": "node", 7 | "strict": true, 8 | "jsx": "preserve", 9 | "sourceMap": true, 10 | "resolveJsonModule": true, 11 | "isolatedModules": true, 12 | "esModuleInterop": true, 13 | "lib": ["esnext", "dom"], 14 | "skipLibCheck": true, 15 | "baseUrl": "./", 16 | "rootDir": "./", 17 | "declaration": true, 18 | "outDir": "dist", 19 | "allowSyntheticDefaultImports": true 20 | }, 21 | "files": ["lib/main.ts", "src/components/Sortable.vue"], 22 | "references": [{ "path": "./tsconfig.node.json" }] 23 | } 24 | -------------------------------------------------------------------------------- /tsconfig.site.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "useDefineForClassFields": true, 5 | "module": "esnext", 6 | "moduleResolution": "node", 7 | "strict": true, 8 | "jsx": "preserve", 9 | "sourceMap": true, 10 | "resolveJsonModule": true, 11 | "isolatedModules": true, 12 | "esModuleInterop": true, 13 | "lib": ["esnext", "dom"], 14 | "skipLibCheck": true, 15 | "baseUrl": "./", 16 | "rootDir": "./", 17 | "declaration": true, 18 | "outDir": "dist", 19 | "allowSyntheticDefaultImports": true 20 | }, 21 | "include": ["src/**/*.ts", "src/**/*.vue", "lib/**/*.ts"], 22 | "references": [{ "path": "./tsconfig.node.json" }] 23 | } 24 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import vue from "@vitejs/plugin-vue"; 3 | import * as path from "path"; 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [vue()], 8 | resolve: { 9 | dedupe: ["vue"], 10 | preserveSymlinks: false, 11 | }, 12 | logLevel: "info", 13 | build: { 14 | target: "esnext", 15 | minify: "terser", 16 | lib: { 17 | entry: path.resolve(__dirname, "lib/main.ts"), 18 | name: "SortableJS-Vue3", 19 | fileName: (format) => `sortablejs-vue3.${format}.js`, 20 | }, 21 | rollupOptions: { 22 | // make sure to externalize deps that shouldn't be bundled 23 | // into your library 24 | external: ["vue", "sortablejs"], 25 | output: { 26 | // Provide global variables to use in the UMD build 27 | // for externalized deps 28 | globals: { 29 | vue: "Vue", 30 | sortablejs: "Sortable", 31 | }, 32 | }, 33 | }, 34 | }, 35 | }); 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Max Leiter 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/bundle-check.yml: -------------------------------------------------------------------------------- 1 | name: Bundle Size Check 2 | 3 | on: 4 | workflow_dispatch: 5 | pull_request: 6 | branches: 7 | - main 8 | 9 | jobs: 10 | bundle-size: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v3 15 | 16 | - name: Set up Node.js 17 | uses: actions/setup-node@v3 18 | with: 19 | node-version: 16 20 | 21 | - name: Install pnpm 22 | run: npm install -g pnpm 23 | 24 | - name: Install dependencies 25 | run: pnpm install 26 | 27 | - name: Build project 28 | run: pnpm run build 29 | 30 | - name: Calculate bundle size 31 | id: bundle-size 32 | run: | 33 | SIZE=$(du -s dist | awk '{print $1}') 34 | echo "Bundle size: $SIZE bytes" 35 | echo "::set-output name=size::$SIZE" 36 | 37 | - name: Store bundle size as artifact 38 | uses: actions/upload-artifact@v3 39 | with: 40 | name: bundle-size 41 | path: | 42 | dist/ 43 | !dist/**/*.map 44 | 45 | - name: Add bundle size comment 46 | uses: peter-evans/create-or-update-comment@v2.1.1 47 | with: 48 | token: ${{ secrets.GITHUB_TOKEN }} 49 | issue-number: ${{ github.event.pull_request.number }} 50 | body: | 51 | 📦 **Bundle size:** The bundle size increased by ${{ steps.bundle-size.outputs.size }} bytes. 52 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sortablejs-vue3", 3 | "version": "1.3.0", 4 | "author": { 5 | "email": "maxwell.leiter@gmail.com", 6 | "name": "Max Leiter", 7 | "url": "https://maxleiter.com" 8 | }, 9 | "funding": { 10 | "type": "individual", 11 | "url": "https://github.com/sponsors/MaxLeiter/" 12 | }, 13 | "license": "MIT", 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/maxleiter/sortablejs-vue3" 17 | }, 18 | "scripts": { 19 | "dev": "vite", 20 | "build": "vite build && vue-tsc --emitDeclarationOnly --project tsconfig.dist.json && mv dist/lib dist/types && rm -rf dist/favicon.ico", 21 | "build:site": "vue-tsc --noEmit --project tsconfig.site.json && vite --config vite.site.config.ts build", 22 | "preview": "vite preview", 23 | "lint": "pnpm prettier --write '**/*.{ts,vue,json}'" 24 | }, 25 | "types": "./dist/types/main.d.ts", 26 | "files": [ 27 | "dist" 28 | ], 29 | "main": "./dist/sortablejs-vue3.umd.js", 30 | "module": "./dist/sortablejs-vue3.es.js", 31 | "exports": { 32 | ".": { 33 | "types": "./dist/types/main.d.ts", 34 | "import": "./dist/sortablejs-vue3.es.js", 35 | "require": "./dist/sortablejs-vue3.umd.js" 36 | } 37 | }, 38 | "dependencies": { 39 | "sortablejs": "^1.15.0", 40 | "vue": "^3.3.7" 41 | }, 42 | "peerDependencies": { 43 | "sortablejs": "^1.15.0", 44 | "vue": "^3.2.25" 45 | }, 46 | "devDependencies": { 47 | "@types/node": "18.14.2", 48 | "@types/sortablejs": "1.15.4", 49 | "@vitejs/plugin-vue": "4.4.0", 50 | "eslint-config-prettier": "^9.0.0", 51 | "prettier": "3.0.3", 52 | "terser": "5.22.0", 53 | "typescript": "5.2.2", 54 | "vite": "4.5.0", 55 | "vue-component-type-helpers": "^2.1.6", 56 | "vue-tsc": "1.8.22" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 139 | 140 | 186 | 187 | 212 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 80 | 81 | 190 | -------------------------------------------------------------------------------- /src/components/Sortable.vue: -------------------------------------------------------------------------------- 1 | 156 | 157 | 170 | -------------------------------------------------------------------------------- /src/examples/WithStore.vue: -------------------------------------------------------------------------------- 1 | 99 | 100 | 126 | 127 | 173 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SortableJS-vue3 2 | 3 | [Demo](https://sortablejs-vue3.maxleiter.com) | [npm](https://www.npmjs.com/package/sortablejs-vue3) 4 | 5 | ![GIF of the demo being used](./readme/demo.gif) 6 | 7 | This is a thin wrapper around the great [SortableJS](https://github.com/SortableJS/Sortable) library. I had many issues migrating from Vue.Draggable to vue.draggable.next, and after briefly investigating I decided that it was too complicated and a smaller solution was the answer. This wrapper attempts to keep you as close to Sortable as possible. 8 | 9 | ### Why not use \? 10 | 11 | - `Vue.Draggable` only supports Vue 2 12 | - `vue.draggable.next` uses the Options API, has multiple open (and afaict useful) pull requests, and had weird bugs/side-effects when I tried and used it 13 | - `shopify/draggable` and [`vue-shopify-dragable`](https://github.com/zjffun/vue-shopify-draggable) seemed promising but they don't supported nested components 14 | 15 | ## Usage 16 | 17 | You can see a demo with more complete code at [https://sortablejs-vue3.maxleiter.com](https://sortablejs-vue3.maxleiter.com). 18 | 19 | 1. Install the package: 20 | 21 | ```bash 22 | pnpm add sortablejs-vue3 sortablejs 23 | ``` 24 | 25 | or 26 | 27 | ```bash 28 | npm install sortablejs-vue3 sortablejs 29 | ``` 30 | 31 | 2. Import the component in your `