├── .npmignore ├── .babelrc ├── demo ├── .babelrc ├── src │ ├── main.js │ ├── util.js │ ├── Icon.vue │ └── App.vue ├── deploy.js ├── index.html ├── package.json └── webpack.config.js ├── .gitignore ├── src ├── index.js ├── util.js ├── mixins │ └── window_size.js ├── GridItem.vue └── Grid.vue ├── LICENSE ├── package.json ├── webpack.config.js ├── README.md └── dist └── index.js /.npmignore: -------------------------------------------------------------------------------- 1 | demo 2 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-2"], 3 | "comments": false 4 | } 5 | -------------------------------------------------------------------------------- /demo/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env"] 4 | ], 5 | "plugins": ["transform-object-rest-spread"] 6 | } 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | npm-debug.log 4 | package-lock.json 5 | yarn-error.log 6 | demo/dist 7 | *.map 8 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import Grid from './Grid.vue' 2 | 3 | export default { 4 | install (Vue) { 5 | Vue.component('Grid', Grid) 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/util.js: -------------------------------------------------------------------------------- 1 | const distance = (x1, y1, x2, y2) => { 2 | return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)) 3 | } 4 | 5 | export default { distance } 6 | -------------------------------------------------------------------------------- /demo/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import Grid from 'plugin' 4 | 5 | Vue.use(Grid) 6 | 7 | new Vue({ 8 | el: '#app', 9 | render: h => h(App) 10 | }) 11 | -------------------------------------------------------------------------------- /demo/deploy.js: -------------------------------------------------------------------------------- 1 | var ghpages = require('gh-pages'); 2 | var path = require('path'); 3 | 4 | ghpages.publish('dist', function(err) { 5 | console.log('Github Pages deployment done.') 6 | 7 | if (err) { 8 | console.log(err) 9 | } 10 | }); 11 | -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vue.js Grid 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /demo/src/util.js: -------------------------------------------------------------------------------- 1 | export const randomInt = (fr, to) => { 2 | return Math.round(fr + Math.random() * to) 3 | } 4 | 5 | export const generateRGBColors = (count) => { 6 | return Array.apply(null, new Array(count)).map((none, i) => { 7 | return { 8 | r: randomInt(0, 255), 9 | g: randomInt(0, 255), 10 | b: randomInt(0, 255) 11 | } 12 | }) 13 | } 14 | 15 | export default { 16 | randomInt, 17 | generateRGBColors 18 | } 19 | -------------------------------------------------------------------------------- /src/mixins/window_size.js: -------------------------------------------------------------------------------- 1 | export default { 2 | data () { 3 | return { 4 | windowHeight: 0, 5 | windowWidth: 0 6 | } 7 | }, 8 | created () { 9 | window.addEventListener('resize', this.getWindowSize) 10 | this.getWindowSize() 11 | }, 12 | mounted () { 13 | this.getWindowSize() 14 | }, 15 | beforeDestroy () { 16 | window.removeEventListener('resize', this.getWindowSize) 17 | }, 18 | 19 | methods: { 20 | getWindowSize () { 21 | if (this.$el) { 22 | this.windowHeight = this.$el.clientHeight 23 | this.windowWidth = this.$el.clientWidth 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "version": "1.0.0", 4 | "scripts": { 5 | "dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot", 6 | "build": "cross-env NODE_ENV=production webpack --progress --hide-modules", 7 | "deploy": "npm run build && node ./deploy.js" 8 | }, 9 | "dependencies": { 10 | "vue": "^2.0.0" 11 | }, 12 | "devDependencies": { 13 | "babel-core": "^6.0.0", 14 | "babel-loader": "^6.0.0", 15 | "babel-plugin-transform-object-rest-spread": "^6.26.0", 16 | "babel-preset-env": "^1.6.0", 17 | "babel-preset-latest": "^6.0.0", 18 | "cross-env": "^3.0.0", 19 | "css-loader": "^0.25.0", 20 | "file-loader": "^0.9.0", 21 | "gh-pages": "^1.0.0", 22 | "html-webpack-plugin": "^2.30.1", 23 | "install": "^0.10.1", 24 | "node-sass": "^4.5.0", 25 | "npm": "^6.13.4", 26 | "sass-loader": "^5.0.1", 27 | "vue-loader": "^11.1.4", 28 | "vue-template-compiler": "^2.2.1", 29 | "webpack": "^2.2.0", 30 | "webpack-dev-server": "^2.2.0" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Yev Vlasenko 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 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-js-grid", 3 | "description": "Vue.js responsive grid plugin", 4 | "version": "1.0.1", 5 | "author": "euvl ", 6 | "private": false, 7 | "scripts": { 8 | "build": "cross-env NODE_ENV=production webpack --progress --hide-modules" 9 | }, 10 | "main": "dist/index.js", 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/euvl/vue-js-grid.git" 14 | }, 15 | "bugs": { 16 | "url": "https://github.com/euvl/vue-js-grid/issues" 17 | }, 18 | "keywords": [ 19 | "vue" 20 | ], 21 | "devDependencies": { 22 | "babel-core": "^6.0.0", 23 | "babel-loader": "^6.0.0", 24 | "babel-preset-latest": "^6.0.0", 25 | "babel-preset-stage-2": "^6.24.1", 26 | "cross-env": "^3.0.0", 27 | "css-loader": "^0.25.0", 28 | "file-loader": "^0.9.0", 29 | "node-sass": "^4.5.0", 30 | "sass-loader": "^5.0.1", 31 | "uglifyjs-webpack-plugin": "^0.4.6", 32 | "vue": "^2.0.0", 33 | "vue-loader": "^11.1.4", 34 | "vue-template-compiler": "^2.0.0", 35 | "webpack": "^2.2.0", 36 | "webpack-dev-server": "^2.2.0" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack = require('webpack') 3 | var UglifyJSPlugin = require('uglifyjs-webpack-plugin'); 4 | 5 | module.exports = { 6 | entry: './src/index.js', 7 | output: { 8 | path: path.resolve(__dirname, './dist'), 9 | publicPath: '/dist/', 10 | filename: 'index.js', 11 | library:'vue-js-grid', 12 | libraryTarget: 'umd' 13 | }, 14 | module: { 15 | rules: [ 16 | { 17 | test: /\.vue$/, 18 | loader: 'vue-loader' 19 | // , 20 | // options: { 21 | // loaders: { 22 | // 'scss': 'vue-style-loader!css-loader!sass-loader' 23 | // } 24 | // } 25 | }, 26 | { 27 | test: /\.js$/, 28 | loader: 'babel-loader', 29 | exclude: /node_modules/ 30 | } 31 | ] 32 | }, 33 | performance: { 34 | hints: false 35 | }, 36 | devtool: '#source-map', 37 | plugins: [ 38 | new webpack.DefinePlugin({ 39 | 'process.env': { 40 | NODE_ENV: '"production"' 41 | } 42 | }), 43 | new UglifyJSPlugin({ 44 | mangle: false, 45 | beautify: true 46 | }) 47 | ] 48 | } 49 | -------------------------------------------------------------------------------- /demo/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack = require('webpack') 3 | var HtmlWebpackPlugin = require('html-webpack-plugin') 4 | 5 | module.exports = { 6 | entry: './src/main.js', 7 | output: { 8 | path: path.resolve(__dirname, './dist'), 9 | publicPath: '/dist/', 10 | filename: 'build.js' 11 | }, 12 | module: { 13 | rules: [ 14 | { 15 | test: /\.vue$/, 16 | loader: 'vue-loader', 17 | options: { 18 | loaders: { 19 | 'scss': 'vue-style-loader!css-loader!sass-loader', 20 | } 21 | } 22 | }, 23 | { 24 | test: /\.js$/, 25 | loader: 'babel-loader', 26 | exclude: /node_modules/ 27 | } 28 | ] 29 | }, 30 | resolve: { 31 | alias: { 32 | 'vue$': 'vue/dist/vue.esm.js', 33 | 'plugin': path.resolve(__dirname, '../dist/index.js') 34 | } 35 | }, 36 | devServer: { 37 | // contentBase: path.join(__dirname, 'dist'), 38 | historyApiFallback: true, 39 | noInfo: true 40 | }, 41 | performance: { 42 | hints: false 43 | }, 44 | devtool: '#eval-source-map' 45 | } 46 | 47 | if (process.env.NODE_ENV === 'production') { 48 | module.exports.output.publicPath = '.' 49 | module.exports.devtool = '#source-map' 50 | // http://vue-loader.vuejs.org/en/workflow/production.html 51 | module.exports.plugins = (module.exports.plugins || []).concat([ 52 | new webpack.DefinePlugin({ 53 | 'process.env': { 54 | NODE_ENV: '"production"' 55 | } 56 | }), 57 | new webpack.optimize.UglifyJsPlugin({ 58 | sourceMap: true, 59 | compress: { 60 | warnings: false 61 | } 62 | }), 63 | new webpack.LoaderOptionsPlugin({ 64 | minimize: true 65 | }), 66 | new HtmlWebpackPlugin({ 67 | template: './index.html' 68 | }) 69 | ]) 70 | } 71 | -------------------------------------------------------------------------------- /demo/src/Icon.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 60 | 61 | 118 | -------------------------------------------------------------------------------- /demo/src/App.vue: -------------------------------------------------------------------------------- 1 | 52 | 53 | 105 | 106 | 124 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Vue.js Grid ( Experiment ) 2 | 3 | ## ⚠️ This an experement and not a production-ready plugin 4 | 5 | [![npm version](https://badge.fury.io/js/vue-js-grid.svg)](https://badge.fury.io/js/vue-js-grid) 6 | [![npm](https://img.shields.io/npm/dm/vue-js-grid.svg)](https://www.npmjs.com/package/vue-js-grid) 7 | 8 | #### Fixed size grid for Vue.js 9 | 10 | This is very a first version of the plugin. If you find any bugs and/or want to contribute, feel free to create issues, PRs, or reach me out on twitter! 👍 🚀 11 | 12 | Thanks! 13 | 14 |

15 | 16 |

17 | 18 | ### Install 19 | ``` 20 | npm install --save vue-js-grid 21 | ``` 22 | 23 | ```js 24 | import Vue from 'vue' 25 | import Grid from 'vue-js-grid' 26 | 27 | Vue.use(Grid) 28 | ``` 29 | 30 | ### Usage 31 | 32 | ```js 33 | data () { 34 | return { 35 | items: [ 36 | 'a', 37 | 'b', 38 | 'c' 39 | ] 40 | } 41 | ``` 42 | 43 | ```vue 44 | 50 | 53 | 54 | ``` 55 | #### [Codesandbox Demo](https://codesandbox.io/s/j23p2opkk3) 56 | 57 | Plugin does **NOT** modify the source data array. 58 | 59 | 1. Every time permutation is performed you will get a new sorted array in event (`items`). 60 | 2. The same works for removing elements, you will get a new "cleaned" array in your `@remove` event handler. 61 | 3. Currently there is no way to extend data array after event handling. But hopefully I'll come up with a clean way to do it in nearest future. 62 | 63 | ### Props 64 | 65 | | Name | Type | Default | Description | 66 | | --- | --- | --- | --- | 67 | | `items` | Array | `[]` | Initial array of items | 68 | | `cellWidth` | Number | `80` | Cell width | 69 | | `cellHeight` | Number | `80` | Cell height | 70 | | `draggable` | Boolean | `false` | Flag that will let you drag grid's cells | 71 | | `dragDelay` | Number | `0` | @TODO | 72 | | `sortable` | Boolean | `false` | Flag that will let you reorder grid's cells; requires `draggable` to be `true` | 73 | | `center` | Boolean | `false` | @TODO | 74 | 75 | ### Events 76 | 77 | | Name | Description | 78 | | --- | --- | 79 | | `@change` | Occurs on every action that involves reordering array or changing its length | 80 | | `@remove` | Occurs when an element is deleted through template | 81 | | `@click` | Occurs when cell is clicked | 82 | | `@sort` | Occurs when array item order is changed manually | 83 | 84 | ### Cell template 85 | 86 | Cell template is used to get access to list data, indexing, and sorting params generated by plugin. 87 | 88 | Template's scope contains: 89 | 90 | * `props.item`: list item value 91 | * `props.index`: initial index of the item 92 | * `props.sort`: current index of the item after sorting 93 | * `props.remove()`: method that removes the item from the array and resort list. 94 | 95 | Example: 96 | 97 | ```vue 98 | 103 | ``` 104 | 105 | ### Why do I need this? 106 | 107 | A good example of using a plugin would be rending macOS' `Launchpad` or `Dock`. Check out a demo for a solid example of how the plugin behaves & feels. 108 | 109 | Demo: https://euvl.github.io/vue-js-grid/ 110 | 111 | ### Roadmap 112 | 113 | 1. Add element insertion 114 | 2. Add tests 115 | -------------------------------------------------------------------------------- /src/GridItem.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 216 | 217 | 236 | -------------------------------------------------------------------------------- /src/Grid.vue: -------------------------------------------------------------------------------- 1 | 27 | 239 | 246 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | !function(root, factory) { 2 | "object" == typeof exports && "object" == typeof module ? module.exports = factory() : "function" == typeof define && define.amd ? define([], factory) : "object" == typeof exports ? exports["vue-js-grid"] = factory() : root["vue-js-grid"] = factory(); 3 | }(this, function() { 4 | return function(modules) { 5 | function __webpack_require__(moduleId) { 6 | if (installedModules[moduleId]) return installedModules[moduleId].exports; 7 | var module = installedModules[moduleId] = { 8 | i: moduleId, 9 | l: !1, 10 | exports: {} 11 | }; 12 | return modules[moduleId].call(module.exports, module, module.exports, __webpack_require__), 13 | module.l = !0, module.exports; 14 | } 15 | var installedModules = {}; 16 | return __webpack_require__.m = modules, __webpack_require__.c = installedModules, 17 | __webpack_require__.i = function(value) { 18 | return value; 19 | }, __webpack_require__.d = function(exports, name, getter) { 20 | __webpack_require__.o(exports, name) || Object.defineProperty(exports, name, { 21 | configurable: !1, 22 | enumerable: !0, 23 | get: getter 24 | }); 25 | }, __webpack_require__.n = function(module) { 26 | var getter = module && module.__esModule ? function() { 27 | return module.default; 28 | } : function() { 29 | return module; 30 | }; 31 | return __webpack_require__.d(getter, "a", getter), getter; 32 | }, __webpack_require__.o = function(object, property) { 33 | return Object.prototype.hasOwnProperty.call(object, property); 34 | }, __webpack_require__.p = "/dist/", __webpack_require__(__webpack_require__.s = 6); 35 | }([ function(module, exports) { 36 | module.exports = function() { 37 | var list = []; 38 | return list.toString = function() { 39 | for (var result = [], i = 0; i < this.length; i++) { 40 | var item = this[i]; 41 | item[2] ? result.push("@media " + item[2] + "{" + item[1] + "}") : result.push(item[1]); 42 | } 43 | return result.join(""); 44 | }, list.i = function(modules, mediaQuery) { 45 | "string" == typeof modules && (modules = [ [ null, modules, "" ] ]); 46 | for (var alreadyImportedModules = {}, i = 0; i < this.length; i++) { 47 | var id = this[i][0]; 48 | "number" == typeof id && (alreadyImportedModules[id] = !0); 49 | } 50 | for (i = 0; i < modules.length; i++) { 51 | var item = modules[i]; 52 | "number" == typeof item[0] && alreadyImportedModules[item[0]] || (mediaQuery && !item[2] ? item[2] = mediaQuery : mediaQuery && (item[2] = "(" + item[2] + ") and (" + mediaQuery + ")"), 53 | list.push(item)); 54 | } 55 | }, list; 56 | }; 57 | }, function(module, exports) { 58 | module.exports = function(rawScriptExports, compiledTemplate, scopeId, cssModules) { 59 | var esModule, scriptExports = rawScriptExports = rawScriptExports || {}, type = typeof rawScriptExports.default; 60 | "object" !== type && "function" !== type || (esModule = rawScriptExports, scriptExports = rawScriptExports.default); 61 | var options = "function" == typeof scriptExports ? scriptExports.options : scriptExports; 62 | if (compiledTemplate && (options.render = compiledTemplate.render, options.staticRenderFns = compiledTemplate.staticRenderFns), 63 | scopeId && (options._scopeId = scopeId), cssModules) { 64 | var computed = Object.create(options.computed || null); 65 | Object.keys(cssModules).forEach(function(key) { 66 | var module = cssModules[key]; 67 | computed[key] = function() { 68 | return module; 69 | }; 70 | }), options.computed = computed; 71 | } 72 | return { 73 | esModule: esModule, 74 | exports: scriptExports, 75 | options: options 76 | }; 77 | }; 78 | }, function(module, exports, __webpack_require__) { 79 | function addStylesToDom(styles) { 80 | for (var i = 0; i < styles.length; i++) { 81 | var item = styles[i], domStyle = stylesInDom[item.id]; 82 | if (domStyle) { 83 | domStyle.refs++; 84 | for (var j = 0; j < domStyle.parts.length; j++) domStyle.parts[j](item.parts[j]); 85 | for (;j < item.parts.length; j++) domStyle.parts.push(addStyle(item.parts[j])); 86 | domStyle.parts.length > item.parts.length && (domStyle.parts.length = item.parts.length); 87 | } else { 88 | for (var parts = [], j = 0; j < item.parts.length; j++) parts.push(addStyle(item.parts[j])); 89 | stylesInDom[item.id] = { 90 | id: item.id, 91 | refs: 1, 92 | parts: parts 93 | }; 94 | } 95 | } 96 | } 97 | function createStyleElement() { 98 | var styleElement = document.createElement("style"); 99 | return styleElement.type = "text/css", head.appendChild(styleElement), styleElement; 100 | } 101 | function addStyle(obj) { 102 | var update, remove, styleElement = document.querySelector('style[data-vue-ssr-id~="' + obj.id + '"]'); 103 | if (styleElement) { 104 | if (isProduction) return noop; 105 | styleElement.parentNode.removeChild(styleElement); 106 | } 107 | if (isOldIE) { 108 | var styleIndex = singletonCounter++; 109 | styleElement = singletonElement || (singletonElement = createStyleElement()), update = applyToSingletonTag.bind(null, styleElement, styleIndex, !1), 110 | remove = applyToSingletonTag.bind(null, styleElement, styleIndex, !0); 111 | } else styleElement = createStyleElement(), update = applyToTag.bind(null, styleElement), 112 | remove = function() { 113 | styleElement.parentNode.removeChild(styleElement); 114 | }; 115 | return update(obj), function(newObj) { 116 | if (newObj) { 117 | if (newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap) return; 118 | update(obj = newObj); 119 | } else remove(); 120 | }; 121 | } 122 | function applyToSingletonTag(styleElement, index, remove, obj) { 123 | var css = remove ? "" : obj.css; 124 | if (styleElement.styleSheet) styleElement.styleSheet.cssText = replaceText(index, css); else { 125 | var cssNode = document.createTextNode(css), childNodes = styleElement.childNodes; 126 | childNodes[index] && styleElement.removeChild(childNodes[index]), childNodes.length ? styleElement.insertBefore(cssNode, childNodes[index]) : styleElement.appendChild(cssNode); 127 | } 128 | } 129 | function applyToTag(styleElement, obj) { 130 | var css = obj.css, media = obj.media, sourceMap = obj.sourceMap; 131 | if (media && styleElement.setAttribute("media", media), sourceMap && (css += "\n/*# sourceURL=" + sourceMap.sources[0] + " */", 132 | css += "\n/*# sourceMappingURL=data:application/json;base64," + btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))) + " */"), 133 | styleElement.styleSheet) styleElement.styleSheet.cssText = css; else { 134 | for (;styleElement.firstChild; ) styleElement.removeChild(styleElement.firstChild); 135 | styleElement.appendChild(document.createTextNode(css)); 136 | } 137 | } 138 | var hasDocument = "undefined" != typeof document; 139 | if ("undefined" != typeof DEBUG && DEBUG && !hasDocument) throw new Error("vue-style-loader cannot be used in a non-browser environment. Use { target: 'node' } in your Webpack config to indicate a server-rendering environment."); 140 | var listToStyles = __webpack_require__(15), stylesInDom = {}, head = hasDocument && (document.head || document.getElementsByTagName("head")[0]), singletonElement = null, singletonCounter = 0, isProduction = !1, noop = function() {}, isOldIE = "undefined" != typeof navigator && /msie [6-9]\b/.test(navigator.userAgent.toLowerCase()); 141 | module.exports = function(parentId, list, _isProduction) { 142 | isProduction = _isProduction; 143 | var styles = listToStyles(parentId, list); 144 | return addStylesToDom(styles), function(newList) { 145 | for (var mayRemove = [], i = 0; i < styles.length; i++) { 146 | var item = styles[i], domStyle = stylesInDom[item.id]; 147 | domStyle.refs--, mayRemove.push(domStyle); 148 | } 149 | newList ? (styles = listToStyles(parentId, newList), addStylesToDom(styles)) : styles = []; 150 | for (var i = 0; i < mayRemove.length; i++) { 151 | var domStyle = mayRemove[i]; 152 | if (0 === domStyle.refs) { 153 | for (var j = 0; j < domStyle.parts.length; j++) domStyle.parts[j](); 154 | delete stylesInDom[domStyle.id]; 155 | } 156 | } 157 | }; 158 | }; 159 | var replaceText = function() { 160 | var textStore = []; 161 | return function(index, replacement) { 162 | return textStore[index] = replacement, textStore.filter(Boolean).join("\n"); 163 | }; 164 | }(); 165 | }, function(module, exports, __webpack_require__) { 166 | __webpack_require__(13); 167 | var Component = __webpack_require__(1)(__webpack_require__(4), __webpack_require__(11), null, null); 168 | module.exports = Component.exports; 169 | }, function(module, exports, __webpack_require__) { 170 | "use strict"; 171 | function _interopRequireDefault(obj) { 172 | return obj && obj.__esModule ? obj : { 173 | default: obj 174 | }; 175 | } 176 | Object.defineProperty(exports, "__esModule", { 177 | value: !0 178 | }); 179 | var _extends = Object.assign || function(target) { 180 | for (var i = 1; i < arguments.length; i++) { 181 | var source = arguments[i]; 182 | for (var key in source) Object.prototype.hasOwnProperty.call(source, key) && (target[key] = source[key]); 183 | } 184 | return target; 185 | }, _window_size = __webpack_require__(7), _window_size2 = _interopRequireDefault(_window_size), _GridItem = __webpack_require__(10), _GridItem2 = _interopRequireDefault(_GridItem); 186 | exports.default = { 187 | name: "Grid", 188 | mixins: [ _window_size2.default ], 189 | components: { 190 | GridItem: _GridItem2.default 191 | }, 192 | props: { 193 | items: { 194 | type: Array, 195 | default: function() { 196 | return []; 197 | } 198 | }, 199 | gridWidth: { 200 | type: Number, 201 | default: -1 202 | }, 203 | cellWidth: { 204 | type: Number, 205 | default: 80 206 | }, 207 | cellHeight: { 208 | type: Number, 209 | default: 80 210 | }, 211 | draggable: { 212 | type: Boolean, 213 | default: !1 214 | }, 215 | dragDelay: { 216 | type: Number, 217 | default: 0 218 | }, 219 | sortable: { 220 | type: Boolean, 221 | default: !1 222 | }, 223 | center: { 224 | type: Boolean, 225 | default: !1 226 | } 227 | }, 228 | data: function() { 229 | return { 230 | list: [] 231 | }; 232 | }, 233 | watch: { 234 | items: { 235 | handler: function() { 236 | var nextItems = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []; 237 | this.list = nextItems.map(function(item, index) { 238 | return { 239 | item: item, 240 | index: index, 241 | sort: index 242 | }; 243 | }); 244 | }, 245 | immediate: !0 246 | } 247 | }, 248 | computed: { 249 | gridResponsiveWidth: function() { 250 | return this.gridWidth < 0 ? this.windowWidth : Math.min(this.windowWidth, this.gridWidth); 251 | }, 252 | height: function() { 253 | return Math.ceil(this.list.length / this.rowCount) * this.cellHeight; 254 | }, 255 | style: function() { 256 | return { 257 | height: this.height + "px" 258 | }; 259 | }, 260 | rowCount: function() { 261 | return Math.floor(this.gridResponsiveWidth / this.cellWidth); 262 | }, 263 | rowShift: function() { 264 | if (this.center) { 265 | var contentWidth = this.list.length * this.cellWidth, rowShift = contentWidth < this.gridResponsiveWidth ? (this.gridResponsiveWidth - contentWidth) / 2 : this.gridResponsiveWidth % this.cellWidth / 2; 266 | return Math.floor(rowShift); 267 | } 268 | return 0; 269 | } 270 | }, 271 | methods: { 272 | wrapEvent: function() { 273 | var other = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; 274 | return _extends({ 275 | datetime: Date.now(), 276 | items: this.getListClone() 277 | }, other); 278 | }, 279 | getListClone: function() { 280 | return this.list.slice(0).sort(function(a, b) { 281 | return a.sort - b.sort; 282 | }); 283 | }, 284 | removeItem: function(_ref) { 285 | var index = _ref.index, removeItem = this.list.find(function(v) { 286 | return v.index === index; 287 | }), removeItemSort = removeItem.sort; 288 | this.list = this.list.filter(function(v) { 289 | return v.index !== index; 290 | }).map(function(v) { 291 | var sort = v.sort > removeItemSort ? v.sort - 1 : v.sort; 292 | return _extends({}, v, { 293 | sort: sort 294 | }); 295 | }), this.$emit("remove", this.wrapEvent({ 296 | index: index 297 | })); 298 | }, 299 | onDragStart: function(event) { 300 | this.$emit("dragstart", this.wrapEvent(event)); 301 | }, 302 | onDragEnd: function(event) { 303 | this.$emit("dragend", this.wrapEvent(event)); 304 | }, 305 | click: function(event) { 306 | this.$emit("click", this.wrapEvent(event)); 307 | }, 308 | onDrag: function(event) { 309 | this.sortable && this.sortList(event.index, event.gridPosition), this.$emit("drag", this.wrapEvent({ 310 | event: event 311 | })); 312 | }, 313 | sortList: function(itemIndex, gridPosition) { 314 | var targetItem = this.list.find(function(item) { 315 | return item.index === itemIndex; 316 | }), targetItemSort = targetItem.sort; 317 | gridPosition = Math.max(gridPosition, 0), gridPosition = Math.min(gridPosition, this.list.length - 1), 318 | targetItemSort !== gridPosition && (this.list = this.list.map(function(item) { 319 | if (item.index === targetItem.index) return _extends({}, item, { 320 | sort: gridPosition 321 | }); 322 | var sort = item.sort; 323 | return targetItemSort > gridPosition && sort <= targetItemSort && sort >= gridPosition ? _extends({}, item, { 324 | sort: sort + 1 325 | }) : targetItemSort < gridPosition && sort >= targetItemSort && sort <= gridPosition ? _extends({}, item, { 326 | sort: sort - 1 327 | }) : item; 328 | }), this.$emit("sort", this.wrapEvent())); 329 | } 330 | } 331 | }; 332 | }, function(module, exports, __webpack_require__) { 333 | "use strict"; 334 | Object.defineProperty(exports, "__esModule", { 335 | value: !0 336 | }); 337 | exports.default = { 338 | name: "GridItem", 339 | props: { 340 | index: { 341 | type: Number 342 | }, 343 | sort: { 344 | type: Number 345 | }, 346 | cellWidth: { 347 | type: Number 348 | }, 349 | cellHeight: { 350 | type: Number 351 | }, 352 | rowCount: { 353 | type: Number 354 | }, 355 | rowShift: { 356 | type: Number, 357 | default: 0 358 | }, 359 | draggable: { 360 | type: Boolean 361 | }, 362 | dragDelay: { 363 | type: Number, 364 | default: 0 365 | } 366 | }, 367 | data: function() { 368 | return { 369 | animate: !0, 370 | dragging: !1, 371 | shiftStartX: 0, 372 | shiftStartY: 0, 373 | mouseMoveStartX: 0, 374 | mouseMoveStartY: 0, 375 | shiftX: 0, 376 | shiftY: 0, 377 | timer: null, 378 | zIndex: 1 379 | }; 380 | }, 381 | mounted: function() { 382 | var _this = this; 383 | this.$refs.self.addEventListener("transitionend", function(event) { 384 | _this.dragging || (_this.zIndex = 1); 385 | }, !1); 386 | }, 387 | computed: { 388 | className: function() { 389 | return [ "v-grid-item-wrapper", { 390 | "v-grid-item-animate": this.animate, 391 | "v-grid-item-dragging": this.dragging 392 | } ]; 393 | }, 394 | style: function() { 395 | var zIndex = this.zIndex, cellWidth = this.cellWidth, cellHeight = this.cellHeight, top = this.top; 396 | return { 397 | zIndex: zIndex, 398 | width: cellWidth + "px", 399 | height: cellHeight + "px", 400 | transform: "translate3d(" + this.left + "px, " + top + "px, 0)" 401 | }; 402 | }, 403 | left: function() { 404 | return this.dragging ? this.shiftX : this.rowShift + this.sort % this.rowCount * this.cellWidth; 405 | }, 406 | top: function() { 407 | return this.dragging ? this.shiftY : Math.floor(this.sort / this.rowCount) * this.cellHeight; 408 | } 409 | }, 410 | methods: { 411 | wrapEvent: function(event) { 412 | return { 413 | event: event, 414 | index: this.index, 415 | sort: this.sort 416 | }; 417 | }, 418 | dragStart: function(event) { 419 | var e = event.touches ? event.touches[0] : event; 420 | this.zIndex = 2, this.shiftX = this.shiftStartX = this.left, this.shiftY = this.shiftStartY = this.top, 421 | this.mouseMoveStartX = e.pageX, this.mouseMoveStartY = e.pageY, this.animate = !1, 422 | this.dragging = !0, document.addEventListener("mousemove", this.documentMouseMove), 423 | document.addEventListener("touchmove", this.documentMouseMove), this.$emit("dragstart", this.wrapEvent(event)); 424 | }, 425 | drag: function(event) { 426 | var e = event.touches ? event.touches[0] : event, distanceX = e.pageX - this.mouseMoveStartX, distanceY = e.pageY - this.mouseMoveStartY; 427 | this.shiftX = distanceX + this.shiftStartX, this.shiftY = distanceY + this.shiftStartY; 428 | var gridX = Math.round(this.shiftX / this.cellWidth), gridY = Math.round(this.shiftY / this.cellHeight); 429 | gridX = Math.min(gridX, this.rowCount - 1), gridY = Math.max(gridY, 0); 430 | var gridPosition = gridX + gridY * this.rowCount, $event = { 431 | event: event, 432 | distanceX: distanceX, 433 | distanceY: distanceY, 434 | positionX: this.shiftX, 435 | positionY: this.shiftY, 436 | index: this.index, 437 | gridX: gridX, 438 | gridY: gridY, 439 | gridPosition: gridPosition 440 | }; 441 | this.$emit("drag", $event); 442 | }, 443 | mousedown: function(event) { 444 | var _this2 = this; 445 | this.draggable && (this.timer = setTimeout(function() { 446 | _this2.dragStart(event); 447 | }, this.dragDelay), document.addEventListener("mouseup", this.documentMouseUp), 448 | document.addEventListener("touchend", this.documentMouseUp)); 449 | }, 450 | documentMouseMove: function(event) { 451 | this.draggable && this.dragging && this.drag(event); 452 | }, 453 | documentMouseUp: function(event) { 454 | this.timer && (clearTimeout(this.timer), this.timer = null); 455 | var dx = this.shiftStartX - this.shiftX, dy = this.shiftStartY - this.shiftY, distance = Math.sqrt(dx * dx + dy * dy); 456 | this.animate = !0, this.dragging = !1, this.mouseMoveStartX = 0, this.mouseMoveStartY = 0, 457 | this.shiftStartX = 0, this.shiftStartY = 0, document.removeEventListener("mousemove", this.documentMouseMove), 458 | document.removeEventListener("touchmove", this.documentMouseMove), document.removeEventListener("mouseup", this.documentMouseUp), 459 | document.removeEventListener("touchend", this.documentMouseUp); 460 | var $event = this.wrapEvent(event); 461 | distance < 4 && this.$emit("click", $event), this.$emit("dragend", $event); 462 | } 463 | } 464 | }; 465 | }, function(module, exports, __webpack_require__) { 466 | "use strict"; 467 | Object.defineProperty(exports, "__esModule", { 468 | value: !0 469 | }); 470 | var _Grid = __webpack_require__(3), _Grid2 = function(obj) { 471 | return obj && obj.__esModule ? obj : { 472 | default: obj 473 | }; 474 | }(_Grid); 475 | exports.default = { 476 | install: function(Vue) { 477 | Vue.component("Grid", _Grid2.default); 478 | } 479 | }; 480 | }, function(module, exports, __webpack_require__) { 481 | "use strict"; 482 | Object.defineProperty(exports, "__esModule", { 483 | value: !0 484 | }), exports.default = { 485 | data: function() { 486 | return { 487 | windowHeight: 0, 488 | windowWidth: 0 489 | }; 490 | }, 491 | created: function() { 492 | window.addEventListener("resize", this.getWindowSize), this.getWindowSize(); 493 | }, 494 | mounted: function() { 495 | this.getWindowSize(); 496 | }, 497 | beforeDestroy: function() { 498 | window.removeEventListener("resize", this.getWindowSize); 499 | }, 500 | methods: { 501 | getWindowSize: function() { 502 | this.$el && (this.windowHeight = this.$el.clientHeight, this.windowWidth = this.$el.clientWidth); 503 | } 504 | } 505 | }; 506 | }, function(module, exports, __webpack_require__) { 507 | exports = module.exports = __webpack_require__(0)(), exports.push([ module.i, ".v-grid{display:block;position:relative;width:100%}", "" ]); 508 | }, function(module, exports, __webpack_require__) { 509 | exports = module.exports = __webpack_require__(0)(), exports.push([ module.i, ".v-grid-item-wrapper{display:block;position:absolute;box-sizing:border-box;left:0;top:0;user-select:none;transform:translateZ(0);z-index:1}.v-grid-item-animate{transition:transform .8s ease}", "" ]); 510 | }, function(module, exports, __webpack_require__) { 511 | __webpack_require__(14); 512 | var Component = __webpack_require__(1)(__webpack_require__(5), __webpack_require__(12), null, null); 513 | module.exports = Component.exports; 514 | }, function(module, exports) { 515 | module.exports = { 516 | render: function() { 517 | var _vm = this, _h = _vm.$createElement, _c = _vm._self._c || _h; 518 | return _c("div", { 519 | staticClass: "v-grid", 520 | style: _vm.style 521 | }, _vm._l(_vm.list, function(v) { 522 | return _c("GridItem", { 523 | key: v.index, 524 | attrs: { 525 | index: v.index, 526 | sort: v.sort, 527 | draggable: _vm.draggable, 528 | "drag-delay": _vm.dragDelay, 529 | "row-count": _vm.rowCount, 530 | "cell-width": _vm.cellWidth, 531 | "cell-height": _vm.cellHeight, 532 | "window-width": _vm.windowWidth, 533 | "row-shift": _vm.rowShift 534 | }, 535 | on: { 536 | dragstart: _vm.onDragStart, 537 | dragend: _vm.onDragEnd, 538 | drag: _vm.onDrag, 539 | click: _vm.click 540 | } 541 | }, [ _vm._t("cell", null, { 542 | item: v.item, 543 | index: v.index, 544 | sort: v.sort, 545 | remove: function() { 546 | _vm.removeItem(v); 547 | } 548 | }) ], 2); 549 | })); 550 | }, 551 | staticRenderFns: [] 552 | }; 553 | }, function(module, exports) { 554 | module.exports = { 555 | render: function() { 556 | var _vm = this, _h = _vm.$createElement; 557 | return (_vm._self._c || _h)("div", { 558 | ref: "self", 559 | class: _vm.className, 560 | style: _vm.style, 561 | on: { 562 | mousedown: _vm.mousedown, 563 | touchstart: function($event) { 564 | return $event.stopPropagation(), _vm.mousedown($event); 565 | } 566 | } 567 | }, [ _vm._t("default") ], 2); 568 | }, 569 | staticRenderFns: [] 570 | }; 571 | }, function(module, exports, __webpack_require__) { 572 | var content = __webpack_require__(8); 573 | "string" == typeof content && (content = [ [ module.i, content, "" ] ]), content.locals && (module.exports = content.locals); 574 | __webpack_require__(2)("105852af", content, !0); 575 | }, function(module, exports, __webpack_require__) { 576 | var content = __webpack_require__(9); 577 | "string" == typeof content && (content = [ [ module.i, content, "" ] ]), content.locals && (module.exports = content.locals); 578 | __webpack_require__(2)("38de0bc4", content, !0); 579 | }, function(module, exports) { 580 | module.exports = function(parentId, list) { 581 | for (var styles = [], newStyles = {}, i = 0; i < list.length; i++) { 582 | var item = list[i], id = item[0], css = item[1], media = item[2], sourceMap = item[3], part = { 583 | id: parentId + ":" + i, 584 | css: css, 585 | media: media, 586 | sourceMap: sourceMap 587 | }; 588 | newStyles[id] ? newStyles[id].parts.push(part) : styles.push(newStyles[id] = { 589 | id: id, 590 | parts: [ part ] 591 | }); 592 | } 593 | return styles; 594 | }; 595 | } ]); 596 | }); --------------------------------------------------------------------------------