├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── .prettierignore
├── .prettierrc
├── LICENSE
├── README.md
├── package-lock.json
├── package.json
├── rollup.config.js
├── src
├── MoveResize
│ └── index.svelte
├── index.svelte
└── utils
│ ├── container.js
│ ├── helper.js
│ ├── item.js
│ ├── matrix.js
│ └── other.js
└── www
├── .gitignore
├── .nowignore
├── now.json
├── package-lock.json
├── package.json
├── rollup.config.js
├── src
├── client.js
├── components
│ ├── Footer.svelte
│ ├── Nav.svelte
│ └── Ribbon.svelte
├── routes
│ ├── _layout.svelte
│ ├── examples
│ │ ├── add_remove.svx
│ │ ├── autoscroll.svx
│ │ ├── basic.svx
│ │ ├── custom-dragger.svx
│ │ ├── custom-resizer.svx
│ │ ├── events.svx
│ │ ├── fast-start.svx
│ │ ├── fill-space.svx
│ │ ├── fixed.svx
│ │ ├── gap.svx
│ │ ├── github.js
│ │ ├── index.svx
│ │ ├── local-storage.svx
│ │ ├── min_max.svx
│ │ ├── responsive-local-storage.svx
│ │ └── responsive.svx
│ ├── features.svelte
│ ├── index.svelte
│ └── usage.svx
├── server.js
├── service-worker.js
└── template.html
└── static
├── favicon.png
├── global.css
├── logo-192.png
├── logo-512.png
└── manifest.json
/.eslintignore:
--------------------------------------------------------------------------------
1 | public/
2 | *.svelte
3 | index.js
4 | index.mjs
5 | www/
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "env": {
3 | "browser": true,
4 | "es6": true,
5 | "node": true
6 | },
7 | "extends": "eslint:recommended",
8 | "globals": {
9 | "Atomics": "readonly",
10 | "SharedArrayBuffer": "readonly"
11 | },
12 | "parserOptions": {
13 | "ecmaVersion": 2019,
14 | "sourceType": "module"
15 | },
16 | "rules": {
17 | },
18 | };
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (https://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # TypeScript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 |
60 | # next.js build output
61 | .next
62 |
63 | build/
64 | less.exe.stackdump
65 |
66 | # www
67 | www/__sapper__/
68 | www/src/components/svelte-grid/
69 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | www/src/routes/usage.svelte
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "useTabs": false,
3 | "printWidth": 300,
4 | "tabWidth": 2,
5 | "semi": true,
6 | "trailingComma": "all",
7 | "singleQuote": false
8 | }
9 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Vahe
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # svelte-grid
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | 
21 |
22 | ## About
23 |
24 | - 100% Svelte (or vanillajs) - no jQuery, no 3rd party dependencies
25 | - Compatible with Sapper (SSR Svelte)
26 | - Draggable widgets
27 | - Resizable widgets
28 | - Static widgets
29 | - Layout can be serialized and restored
30 | - Responsive breakpoints
31 | - Limit the minimum and maximum width / height when resizing
32 | - Provide helper functions
33 | - Custom dragging
34 | - Grid gap
35 | - Soft autoscroll
36 |
37 | ## Installation
38 |
39 | **via NPM**
40 |
41 | ```code
42 | npm i svelte-grid --save-dev
43 | ```
44 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "svelte-grid",
3 | "version": "5.1.2",
4 | "description": "A responsive, draggable and resizable grid layout, for Svelte.",
5 | "svelte": "src/index.svelte",
6 | "module": "build/index.mjs",
7 | "main": "build/index.js",
8 | "scripts": {
9 | "test": "echo \"Error: no test specified\" && exit 1",
10 | "lint": "eslint .",
11 | "pretty": "prettier --config .prettierrc --write --svelte-sort-order styles-markup-scripts \"rollup.config.js\" \"package.json\" \"src/**/*.js\" \"www/src/**/**/*.svelte\" \"*.md\" \"src/*.svelte\" \"src/**/*.svelte\" ",
12 | "build": "node_modules/.bin/rollup -c",
13 | "go": "npm-run-all pretty build"
14 | },
15 | "repository": {
16 | "type": "git",
17 | "url": "git+https://github.com/vaheqelyan/svelte-grid.git"
18 | },
19 | "keywords": [
20 | "svelte",
21 | "grid",
22 | "drag",
23 | "draggable",
24 | "resize",
25 | "resizable",
26 | "fluid",
27 | "responsive"
28 | ],
29 | "author": "Vahe Araqelyan ",
30 | "license": "MIT",
31 | "bugs": {
32 | "url": "https://github.com/vaheqelyan/svelte-grid/issues"
33 | },
34 | "homepage": "https://github.com/vaheqelyan/svelte-grid#readme",
35 | "devDependencies": {
36 | "@rollup/plugin-commonjs": "^17.0.0",
37 | "eslint": "^7.13.0",
38 | "npm-run-all": "^4.1.5",
39 | "prettier": "^2.2.0",
40 | "prettier-plugin-svelte": "^1.4.1",
41 | "rollup": "^2.33.3",
42 | "rollup-plugin-node-resolve": "^5.2.0",
43 | "rollup-plugin-svelte": "^6.1.1",
44 | "svelte": "^3.30.0"
45 | },
46 | "files": [
47 | "src",
48 | "build"
49 | ]
50 | }
51 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import svelte from "rollup-plugin-svelte";
2 | import resolve from "rollup-plugin-node-resolve";
3 | import commonjs from "@rollup/plugin-commonjs";
4 | import pkg from "./package.json";
5 |
6 | const name = pkg.name
7 | .replace(/^(@\S+\/)?(svelte-)?(\S+)/, "$3")
8 | .replace(/^\w/, (m) => m.toUpperCase())
9 | .replace(/-\w/g, (m) => m[1].toUpperCase());
10 |
11 | export default [
12 | {
13 | input: "src/index.svelte",
14 | output: [
15 | { file: pkg.module, format: "es" },
16 | { file: pkg.main, format: "umd", name },
17 | ],
18 | plugins: [svelte(), resolve(), commonjs()],
19 | },
20 | {
21 | input: "./src/utils/helper.js",
22 | output: [
23 | { file: "build/helper/index.mjs", format: "es" },
24 | { file: "build/helper/index.js", format: "umd", name: "gridHelper" },
25 | ],
26 | },
27 | ];
28 |
--------------------------------------------------------------------------------
/src/MoveResize/index.svelte:
--------------------------------------------------------------------------------
1 |
59 |
60 |
67 |
68 | {#if resizable && !item.customResizer}
69 |
70 | {/if}
71 |
72 |
73 | {#if active || trans}
74 |
75 | {/if}
76 |
77 |
334 |
--------------------------------------------------------------------------------
/src/index.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 | {#if xPerPx || !fastStart}
10 | {#each items as item, i (item.id)}
11 |
34 | {#if item[getComputedCols]}
35 |
36 | {/if}
37 |
38 | {/each}
39 | {/if}
40 |
41 |
42 |
166 |
--------------------------------------------------------------------------------
/src/utils/container.js:
--------------------------------------------------------------------------------
1 | import { getRowsCount } from "./other.js";
2 |
3 | export function getContainerHeight(items, yPerPx, cols) {
4 | return getRowsCount(items, cols) * yPerPx;
5 | }
6 |
--------------------------------------------------------------------------------
/src/utils/helper.js:
--------------------------------------------------------------------------------
1 | import { makeMatrixFromItems } from "../utils/matrix.js";
2 | import { findFreeSpaceForItem, normalize, adjust } from "../utils/item.js";
3 | import { getRowsCount } from "./other.js";
4 |
5 | function makeItem(item) {
6 | const { min = { w: 1, h: 1 }, max } = item;
7 | return {
8 | fixed: false,
9 | resizable: !item.fixed,
10 | draggable: !item.fixed,
11 | customDragger: false,
12 | customResizer: false,
13 | min: {
14 | w: Math.max(1, min.w),
15 | h: Math.max(1, min.h),
16 | },
17 | max: { ...max },
18 | ...item,
19 | };
20 | }
21 |
22 | const gridHelp = {
23 | normalize(items, col) {
24 | const rows = getRowsCount(items, col);
25 | return normalize(items, col, rows);
26 | },
27 |
28 | adjust(items, col) {
29 | return adjust(items, col);
30 | },
31 |
32 | item(obj) {
33 | return makeItem(obj);
34 | },
35 |
36 | findSpace(item, items, cols) {
37 | let matrix = makeMatrixFromItems(items, getRowsCount(items, cols), cols);
38 |
39 | let position = findFreeSpaceForItem(matrix, item[cols]);
40 | return position;
41 | },
42 | };
43 |
44 | export default gridHelp;
45 |
--------------------------------------------------------------------------------
/src/utils/item.js:
--------------------------------------------------------------------------------
1 | import { makeMatrix, makeMatrixFromItemsIgnore, findCloseBlocks, findItemsById, makeMatrixFromItems } from "./matrix.js";
2 | import { getRowsCount } from "./other.js";
3 |
4 | export function getItemById(id, items) {
5 | return items.find((value) => value.id === id);
6 | }
7 |
8 | export function findFreeSpaceForItem(matrix, item) {
9 | const cols = matrix[0].length;
10 | const w = Math.min(cols, item.w);
11 | let xNtime = cols - w;
12 | let getMatrixRows = matrix.length;
13 |
14 | for (var i = 0; i < getMatrixRows; i++) {
15 | const row = matrix[i];
16 | for (var j = 0; j < xNtime + 1; j++) {
17 | const sliceA = row.slice(j, j + w);
18 | const empty = sliceA.every((val) => val === undefined);
19 | if (empty) {
20 | const isEmpty = matrix.slice(i, i + item.h).every((a) => a.slice(j, j + w).every((n) => n === undefined));
21 |
22 | if (isEmpty) {
23 | return { y: i, x: j };
24 | }
25 | }
26 | }
27 | }
28 |
29 | return {
30 | y: getMatrixRows,
31 | x: 0,
32 | };
33 | }
34 |
35 | const getItem = (item, col) => {
36 | return { ...item[col], id: item.id };
37 | };
38 |
39 | const updateItem = (elements, active, position, col) => {
40 | return elements.map((value) => {
41 | if (value.id === active.id) {
42 | return { ...value, [col]: { ...value[col], ...position } };
43 | }
44 | return value;
45 | });
46 | };
47 |
48 | export function moveItemsAroundItem(active, items, cols, original) {
49 | // Get current item from the breakpoint
50 | const activeItem = getItem(active, cols);
51 | const ids = items.map((value) => value.id).filter((value) => value !== activeItem.id);
52 |
53 | const els = items.filter((value) => value.id !== activeItem.id);
54 |
55 | // Update items
56 | let newItems = updateItem(items, active, activeItem, cols);
57 |
58 | let matrix = makeMatrixFromItemsIgnore(newItems, ids, getRowsCount(newItems, cols), cols);
59 | let tempItems = newItems;
60 |
61 | // Exclude resolved elements ids in array
62 | let exclude = [];
63 |
64 | els.forEach((item) => {
65 | // Find position for element
66 | let position = findFreeSpaceForItem(matrix, item[cols]);
67 | // Exclude item
68 | exclude.push(item.id);
69 |
70 | tempItems = updateItem(tempItems, item, position, cols);
71 |
72 | // Recreate ids of elements
73 | let getIgnoreItems = ids.filter((value) => exclude.indexOf(value) === -1);
74 |
75 | // Update matrix for next iteration
76 | matrix = makeMatrixFromItemsIgnore(tempItems, getIgnoreItems, getRowsCount(tempItems, cols), cols);
77 | });
78 |
79 | // Return result
80 | return tempItems;
81 | }
82 |
83 | export function moveItem(active, items, cols, original) {
84 | // Get current item from the breakpoint
85 | const item = getItem(active, cols);
86 |
87 | // Create matrix from the items expect the active
88 | let matrix = makeMatrixFromItemsIgnore(items, [item.id], getRowsCount(items, cols), cols);
89 | // Getting the ids of items under active Array
90 | const closeBlocks = findCloseBlocks(items, matrix, item);
91 | // Getting the objects of items under active Array