├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .npmignore ├── .prettierrc ├── .travis.yml ├── README.md ├── dist ├── index.css ├── index.js ├── index.js.map ├── index.modern.js └── index.modern.js.map ├── example ├── README.md ├── build │ ├── asset-manifest.json │ ├── favicon.ico │ ├── index.html │ ├── manifest.json │ ├── precache-manifest.ea604c983aa76268e777666df9decb6d.js │ ├── service-worker.js │ └── static │ │ ├── css │ │ ├── main.4c7e5384.chunk.css │ │ └── main.4c7e5384.chunk.css.map │ │ └── js │ │ ├── 2.bb6f2584.chunk.js │ │ ├── 2.bb6f2584.chunk.js.LICENSE.txt │ │ ├── 2.bb6f2584.chunk.js.map │ │ ├── main.f9efcd66.chunk.js │ │ ├── main.f9efcd66.chunk.js.LICENSE.txt │ │ ├── main.f9efcd66.chunk.js.map │ │ ├── runtime-main.3e8c9496.js │ │ └── runtime-main.3e8c9496.js.map ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ └── manifest.json └── src │ ├── App.js │ ├── App.test.js │ ├── index.css │ ├── index.js │ └── mock │ └── index.js ├── package-lock.json ├── package.json └── src ├── .eslintrc ├── components ├── card.jsx ├── cardListDragPreview.jsx ├── dragLayer.jsx ├── groupItem.jsx └── layout.jsx ├── styles.module.css ├── test ├── case-collision.js └── index.test.js └── utils ├── collision.js ├── compact.js ├── index.js └── utils.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | build/ 2 | dist/ 3 | node_modules/ 4 | .snapshots/ 5 | *.min.js -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": [ 4 | "standard", 5 | "standard-react", 6 | "plugin:prettier/recommended", 7 | "prettier/standard", 8 | "prettier/react" 9 | ], 10 | "env": { 11 | "node": true 12 | }, 13 | "parserOptions": { 14 | "ecmaVersion": 2020, 15 | "ecmaFeatures": { 16 | "legacyDecorators": true, 17 | "jsx": true 18 | } 19 | }, 20 | "settings": { 21 | "react": { 22 | "version": "16" 23 | } 24 | }, 25 | "rules": { 26 | "space-before-function-paren": 0, 27 | "react/prop-types": 0, 28 | "react/jsx-handler-names": 0, 29 | "react/jsx-fragments": 0, 30 | "react/no-unused-prop-types": 0, 31 | "import/export": 0 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # See https://help.github.com/ignore-files/ for more about ignoring files. 3 | 4 | # dependencies 5 | node_modules 6 | 7 | # builds 8 | # build 9 | # dist 10 | .rpt2_cache 11 | 12 | # misc 13 | .DS_Store 14 | .env 15 | .env.local 16 | .env.development.local 17 | .env.test.local 18 | .env.production.local 19 | 20 | npm-debug.log* 21 | yarn-debug.log* 22 | yarn-error.log* 23 | example/package-lock.json -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | example 2 | .git 3 | CVS 4 | .svn 5 | .hg 6 | .lock-wscript 7 | .wafpickle-N 8 | .*.swp 9 | .DS_Store 10 | ._* 11 | npm-debug.log 12 | .npmrc 13 | node_modules 14 | config.gypi 15 | *.orig 16 | package-lock.json -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "jsxSingleQuote": true, 4 | "semi": false, 5 | "tabWidth": 2, 6 | "bracketSpacing": true, 7 | "jsxBracketSameLine": false, 8 | "arrowParens": "always", 9 | "trailingComma": "none" 10 | } 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 12 4 | - 10 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-grid-layout-between 2 | 3 | > A draggable and resizable grid layout with responsive breakpoints , can between two or more Layouts, for React. Based on [React-DnD](https://github.com/react-dnd/react-dnd). 4 | 5 | ![react 16.8.6](https://img.shields.io/badge/react-%5E16.8.6-brightgreen.svg) 6 | ![npm 6.9.0](https://img.shields.io/badge/npm-v6.9.0-blue.svg) 7 | ![react-dnd](https://img.shields.io/badge/reactDnD-%5E2.6.0-7289da.svg) 8 | [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) 9 | 10 | ![picgif](https://user-images.githubusercontent.com/5847281/90307968-0387f780-df0e-11ea-9a19-8d6192ccbe67.gif) 11 | 12 | Live Demo : http://demo.sunxinfei.com/ 13 | 14 | ## Install 15 | 16 | ```bash 17 | npm install --save react-grid-layout-between 18 | ``` 19 | 20 | ## Usage 21 | 22 | ```jsx 23 | import React, { Component } from 'react' 24 | 25 | import GridLayout from 'react-grid-layout-between' 26 | import 'react-grid-layout-between/dist/index.css' 27 | 28 | class Example extends Component { 29 | render() { 30 | return 31 | } 32 | } 33 | ``` 34 | 35 | Features: 36 | - [x] get `` component 37 | 38 | - [x] DnD widgets between layouts 39 | 40 | - [x] 100% React 41 | 42 | - [x] Draggable widgets 43 | 44 | - [x] Configurable packing: horizontal, vertical 45 | 46 | - [x] Bounds checking for dragging 47 | 48 | - [x] Responsive breakpoints 49 | 50 | - [x] Separate layouts per responsive breakpoint 51 | 52 | - [x] Grid Items placed using CSS Transforms 53 | 54 | - [x] Drag Custom Preview 55 | 56 | - [ ] Drag widgets colliseion by gravity center 57 | 58 | - [ ] Static widgets 59 | 60 | - [ ] Resizable widgets 61 | 62 | - [ ] Support touchable device [Issue](https://github.com/SunXinFei/react-grid-layout-between/issues/9) 63 | 64 | bugs: 65 | - [x] ~~when 2x2 or 1x2 collosion bug for horizontal~~ 66 | 67 | ## License 68 | 69 | MIT © [SunXinFei](https://github.com/SunXinFei) 70 | -------------------------------------------------------------------------------- /dist/index.css: -------------------------------------------------------------------------------- 1 | .rglb_group-item { 2 | width: 100%; 3 | margin-bottom: 10px; 4 | cursor: move; 5 | position: relative; 6 | transition: all 0.2s ease-out; 7 | } 8 | .rglb_group-item .group-item-container { 9 | padding: 20px; 10 | } 11 | .rglb_group-item .group-item-container #card-container .card-shadow { 12 | background: rgba(15, 15, 15, 0.3); 13 | position: absolute; 14 | border-radius: 3px; 15 | transition: all 0.2s ease-out; 16 | } 17 | .rglb_group-item .group-item-container #card-container .card { 18 | background: #fff; 19 | position: absolute; 20 | border: 1px solid #f1f1f1; 21 | border-radius: 3px; 22 | transition: all 0.2s ease-out; 23 | } 24 | .rglb_group-item .group-item-container #card-container .card .card-footer { 25 | display: flex; 26 | justify-content: space-between; 27 | position: absolute; 28 | height: 35px; 29 | width: 100%; 30 | padding: 7px 8px; 31 | bottom: 0; 32 | background: #f2f2f2; 33 | } 34 | .rglb_group-item .group-item-container #card-container .card .card-footer .card-delete { 35 | font-size: 19px; 36 | line-height: 21px; 37 | cursor: pointer; 38 | } 39 | 40 | .rglb_custom-layer { 41 | position: fixed; 42 | pointer-events: none; 43 | z-index: 100; 44 | left: -20px; 45 | top: -20px; 46 | } 47 | .rglb_custom-layer .custom-layer-card-list .layer-card { 48 | width: 135px; 49 | height: 135px; 50 | border: 1px solid #cccccc; 51 | background: #fff; 52 | position: absolute; 53 | display: flex; 54 | align-items: center; 55 | justify-content: center; 56 | } 57 | .rglb_custom-layer .custom-layer-card-list .layer-card .layer-card-span { 58 | position: absolute; 59 | border-radius: 50%; 60 | width: 30px; 61 | height: 30px; 62 | display: inline-block; 63 | text-align: center; 64 | line-height: 30px; 65 | } -------------------------------------------------------------------------------- /dist/index.modern.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import HTML5Backend, { getEmptyImage } from 'react-dnd-html5-backend'; 3 | import { DragSource, DropTarget, DragLayer, DragDropContext } from 'react-dnd'; 4 | import _ from 'lodash'; 5 | 6 | function _extends() { 7 | _extends = Object.assign || function (target) { 8 | for (var i = 1; i < arguments.length; i++) { 9 | var source = arguments[i]; 10 | 11 | for (var key in source) { 12 | if (Object.prototype.hasOwnProperty.call(source, key)) { 13 | target[key] = source[key]; 14 | } 15 | } 16 | } 17 | 18 | return target; 19 | }; 20 | 21 | return _extends.apply(this, arguments); 22 | } 23 | 24 | function _inheritsLoose(subClass, superClass) { 25 | subClass.prototype = Object.create(superClass.prototype); 26 | subClass.prototype.constructor = subClass; 27 | subClass.__proto__ = superClass; 28 | } 29 | 30 | var collision = function collision(a, b) { 31 | if (a.gridx === b.gridx && a.gridy === b.gridy && a.width === b.width && a.height === b.height) { 32 | return true; 33 | } 34 | 35 | if (a.gridx + a.width <= b.gridx) return false; 36 | if (a.gridx >= b.gridx + b.width) return false; 37 | if (a.gridy + a.height <= b.gridy) return false; 38 | if (a.gridy >= b.gridy + b.height) return false; 39 | return true; 40 | }; 41 | var getFirstCollison = function getFirstCollison(layout, item) { 42 | for (var i = 0, length = layout.length; i < length; i++) { 43 | if (collision(layout[i], item)) { 44 | return layout[i]; 45 | } 46 | } 47 | 48 | return null; 49 | }; 50 | var layoutCheck = function () { 51 | var _layoutCheck = function _layoutCheck(layout, layoutItem, cardID, fristItemID, compactType) { 52 | if (compactType === void 0) { 53 | compactType = 'vertical'; 54 | } 55 | 56 | var keyArr = []; 57 | var movedItem = []; 58 | var axis = compactType === 'vertical' ? 'gridy' : 'gridx'; 59 | var newlayout = layout.map(function (item, index) { 60 | if (item.id !== cardID) { 61 | if (collision(item, layoutItem)) { 62 | keyArr.push(item.id); 63 | var offsetXY = item[axis] + 1; 64 | var widthOrHeight = axis === 'gridx' ? item.width : item.height; 65 | 66 | if (layoutItem[axis] > item[axis] && layoutItem[axis] < item[axis] + widthOrHeight) { 67 | offsetXY = item[axis]; 68 | } 69 | 70 | var newItem = _extends({}, item); 71 | 72 | newItem[axis] = offsetXY; 73 | movedItem.push(newItem); 74 | return newItem; 75 | } 76 | } else if (fristItemID === cardID) { 77 | return _extends({}, item, layoutItem); 78 | } 79 | 80 | return item; 81 | }); 82 | 83 | for (var c = 0, length = movedItem.length; c < length; c++) { 84 | newlayout = _layoutCheck(newlayout, movedItem[c], keyArr[c], fristItemID, compactType); 85 | } 86 | 87 | return newlayout; 88 | }; 89 | 90 | return _layoutCheck; 91 | }(); 92 | 93 | var setPropertyValueForCards = function setPropertyValueForCards(groups, property, value) { 94 | _.forEach(groups, function (g, index) { 95 | _.forEach(g.cards, function (a) { 96 | a[property] = value; 97 | }); 98 | }); 99 | }; 100 | var calColWidth = function calColWidth(containerWidth, col, containerPadding, margin) { 101 | if (margin) { 102 | return (containerWidth - containerPadding[0] * 2 - margin[0] * (col + 1)) / col; 103 | } 104 | 105 | return (containerWidth - containerPadding[0] * 2 - 0 * (col + 1)) / col; 106 | }; 107 | var calColCount = function calColCount(defaultCalWidth, containerWidth, containerPadding, margin) { 108 | if (margin) { 109 | return Math.floor((containerWidth - containerPadding[0] * 2 - margin[0]) / (defaultCalWidth + margin[0])); 110 | } 111 | }; 112 | var layoutBottom = function layoutBottom(layout) { 113 | var max = 0; 114 | var bottomY; 115 | 116 | for (var i = 0, len = layout.length; i < len; i++) { 117 | bottomY = layout[i].gridy + layout[i].height; 118 | if (bottomY > max) max = bottomY; 119 | } 120 | 121 | return max; 122 | }; 123 | var layoutHorizontalRowLength = function layoutHorizontalRowLength(layout) { 124 | var max = 0; 125 | var rowX; 126 | 127 | for (var i = 0, len = layout.length; i < len; i++) { 128 | rowX = layout[i].gridx + layout[i].width; 129 | if (rowX > max) max = rowX; 130 | } 131 | 132 | return max; 133 | }; 134 | var getContainerMaxHeight = function getContainerMaxHeight(cards, rowHeight, margin) { 135 | var resultRow = layoutBottom(cards); 136 | return resultRow * rowHeight + (resultRow - 1) * margin[1] + 2 * margin[1]; 137 | }; 138 | var calGridItemPosition = function calGridItemPosition(gridx, gridy, margin, rowHeight, calWidth) { 139 | var x = Math.round(gridx * calWidth + margin[0] * (gridx + 1)); 140 | var y = Math.round(gridy * rowHeight + margin[1] * (gridy + 1)); 141 | return { 142 | x: x, 143 | y: y 144 | }; 145 | }; 146 | var checkInContainer = function checkInContainer(gridX, gridY, col, w) { 147 | if (gridX + w > col - 1) gridX = col - w; 148 | if (gridX < 0) gridX = 0; 149 | if (gridY < 0) gridY = 0; 150 | return { 151 | gridX: gridX, 152 | gridY: gridY 153 | }; 154 | }; 155 | var calGridXY = function calGridXY(x, y, cardWidth, margin, containerWidth, col, rowHeight) { 156 | var gridX = Math.floor(x / containerWidth * col); 157 | var gridY = Math.floor(y / (rowHeight + (margin ? margin[1] : 0))); 158 | return checkInContainer(gridX, gridY, col, cardWidth); 159 | }; 160 | var calWHtoPx = function calWHtoPx(w, h, margin, rowHeight, calWidth) { 161 | var wPx = Math.round(w * calWidth + (w - 1) * margin[0]); 162 | var hPx = Math.round(h * rowHeight + (h - 1) * margin[1]); 163 | return { 164 | wPx: wPx, 165 | hPx: hPx 166 | }; 167 | }; 168 | var noop = function noop() {}; 169 | 170 | var utils = { 171 | __proto__: null, 172 | setPropertyValueForCards: setPropertyValueForCards, 173 | calColWidth: calColWidth, 174 | calColCount: calColCount, 175 | layoutBottom: layoutBottom, 176 | layoutHorizontalRowLength: layoutHorizontalRowLength, 177 | getContainerMaxHeight: getContainerMaxHeight, 178 | calGridItemPosition: calGridItemPosition, 179 | checkInContainer: checkInContainer, 180 | calGridXY: calGridXY, 181 | calWHtoPx: calWHtoPx, 182 | noop: noop 183 | }; 184 | 185 | var sortLayout = function sortLayout(layout) { 186 | return [].concat(layout).sort(function (a, b) { 187 | if (a.gridy > b.gridy || a.gridy === b.gridy && a.gridx > b.gridx) { 188 | return 1; 189 | } else if (a.gridy === b.gridy && a.gridx === b.gridx) { 190 | return 0; 191 | } 192 | 193 | return -1; 194 | }); 195 | }; 196 | 197 | var compactItem = function compactItem(finishedLayout, item) { 198 | var newItem = _extends({}, item); 199 | 200 | if (finishedLayout.length === 0) { 201 | return _extends({}, newItem, { 202 | gridy: 0 203 | }); 204 | } 205 | 206 | while (true) { 207 | var FirstCollison = getFirstCollison(finishedLayout, newItem); 208 | 209 | if (FirstCollison) { 210 | newItem.gridy = FirstCollison.gridy + FirstCollison.height; 211 | return newItem; 212 | } 213 | 214 | newItem.gridy--; 215 | if (newItem.gridy < 0) return _extends({}, newItem, { 216 | gridy: 0 217 | }); 218 | } 219 | }; 220 | 221 | var compactLayout = function compactLayout(layout, movingItem) { 222 | var sorted = sortLayout(layout); 223 | var compareList = []; 224 | var needCompact = Array(layout.length); 225 | 226 | for (var i = 0, length = sorted.length; i < length; i++) { 227 | var finished = compactItem(compareList, sorted[i]); 228 | compareList.push(finished); 229 | needCompact[i] = finished; 230 | } 231 | 232 | return needCompact; 233 | }; 234 | 235 | var getSpaceArea = function getSpaceArea(finishedLayout, item, cols) { 236 | var newItem = _extends({}, item); 237 | 238 | if (finishedLayout.length === 0) { 239 | return newItem; 240 | } 241 | 242 | var FirstCollison = getFirstCollison(finishedLayout, newItem); 243 | 244 | if (FirstCollison) { 245 | newItem.gridx++; 246 | 247 | if (newItem.gridx + item.width > cols) { 248 | newItem.gridx = 0; 249 | newItem.gridy++; 250 | } 251 | 252 | return getSpaceArea(finishedLayout, newItem, cols); 253 | } else { 254 | return newItem; 255 | } 256 | }; 257 | 258 | var compactLayoutHorizontal = function compactLayoutHorizontal(layout, cols, movingCardID) { 259 | var sorted = sortLayout(layout); 260 | var compareList = []; 261 | var needCompact = Array(layout.length); 262 | var arr = []; 263 | var moveCard; 264 | 265 | for (var i = 0; i < sorted.length; i++) { 266 | if (movingCardID === sorted[i].id) { 267 | moveCard = sorted[i]; 268 | continue; 269 | } 270 | 271 | arr.push(sorted[i]); 272 | } 273 | 274 | if (moveCard) { 275 | moveCard.gridy = Math.min(layoutBottom(arr), moveCard.gridy); 276 | } 277 | 278 | for (var _i = 0; _i < sorted.length; _i++) { 279 | if (movingCardID !== sorted[_i].id) { 280 | sorted[_i].gridy = 0; 281 | sorted[_i].gridx = 0; 282 | } 283 | } 284 | 285 | for (var _i2 = 0, length = sorted.length; _i2 < length; _i2++) { 286 | var finished = getSpaceArea(compareList, sorted[_i2], cols); 287 | compareList.push(finished); 288 | needCompact[_i2] = finished; 289 | } 290 | 291 | return needCompact; 292 | }; 293 | 294 | var noteSource = { 295 | beginDrag: function beginDrag(props, monitor, component) { 296 | var dragCard = props.card; 297 | dragCard.isShadow = true; 298 | props.updateShadowCard(dragCard); 299 | return { 300 | id: props.id, 301 | type: props.type 302 | }; 303 | }, 304 | endDrag: function endDrag(props, monitor, component) { 305 | if (!monitor.didDrop()) { 306 | var groups = props.groups; 307 | groups = _.cloneDeep(groups); 308 | utils.setPropertyValueForCards(groups, 'isShadow', false); 309 | props.updateShadowCard({}); 310 | props.updateGroupList(groups); 311 | } 312 | } 313 | }; 314 | 315 | var Item = /*#__PURE__*/function (_Component) { 316 | _inheritsLoose(Item, _Component); 317 | 318 | function Item() { 319 | return _Component.apply(this, arguments) || this; 320 | } 321 | 322 | var _proto = Item.prototype; 323 | 324 | _proto.shouldComponentUpdate = function shouldComponentUpdate(nextProps, nextState) { 325 | if (!_.isEqual(this.props.layout, nextProps.layout)) { 326 | return true; 327 | } 328 | 329 | if (this.props.gridx !== nextProps.gridx || this.props.gridy !== nextProps.gridy) { 330 | return true; 331 | } 332 | 333 | if (this.props.isShadow !== nextProps.isShadow) { 334 | return true; 335 | } 336 | 337 | return false; 338 | }; 339 | 340 | _proto.componentDidMount = function componentDidMount() { 341 | this.props.connectDragPreview(getEmptyImage(), { 342 | captureDraggingState: true 343 | }); 344 | }; 345 | 346 | _proto.render = function render() { 347 | var _this$props = this.props, 348 | connectDragSource = _this$props.connectDragSource, 349 | gridx = _this$props.gridx, 350 | gridy = _this$props.gridy, 351 | width = _this$props.width, 352 | height = _this$props.height, 353 | isShadow = _this$props.isShadow, 354 | id = _this$props.id; 355 | var _this$props$layout = this.props.layout, 356 | margin = _this$props$layout.margin, 357 | rowHeight = _this$props$layout.rowHeight, 358 | calWidth = _this$props$layout.calWidth; 359 | 360 | var _utils$calGridItemPos = utils.calGridItemPosition(gridx, gridy, margin, rowHeight, calWidth), 361 | x = _utils$calGridItemPos.x, 362 | y = _utils$calGridItemPos.y; 363 | 364 | var _utils$calWHtoPx = utils.calWHtoPx(width, height, margin, rowHeight, calWidth), 365 | wPx = _utils$calWHtoPx.wPx, 366 | hPx = _utils$calWHtoPx.hPx; 367 | 368 | var cardDom; 369 | 370 | if (isShadow) { 371 | cardDom = /*#__PURE__*/React.createElement("div", { 372 | className: "card-shadow", 373 | style: { 374 | width: wPx, 375 | height: hPx, 376 | transform: "translate(" + x + "px, " + y + "px)" 377 | } 378 | }); 379 | } else { 380 | cardDom = /*#__PURE__*/React.createElement("div", { 381 | className: "card", 382 | style: { 383 | width: wPx, 384 | height: hPx, 385 | opacity: 1, 386 | transform: "translate(" + x + "px, " + y + "px)" 387 | } 388 | }, id); 389 | } 390 | 391 | return connectDragSource(cardDom); 392 | }; 393 | 394 | return Item; 395 | }(Component); 396 | 397 | function collectSource(connect, monitor) { 398 | return { 399 | connectDragSource: connect.dragSource(), 400 | connectDragPreview: connect.dragPreview(), 401 | isDragging: monitor.isDragging() 402 | }; 403 | } 404 | 405 | var dragDropItem = DragSource('item', noteSource, collectSource)(Item); 406 | 407 | var ReactDOM = require('react-dom'); 408 | var groupItemTarget = { 409 | hover: function hover(props, monitor, component) { 410 | var dragItem = monitor.getItem(); 411 | 412 | if (dragItem.type === 'group') { 413 | var dragIndex = monitor.getItem().index; 414 | var hoverIndex = props.index; 415 | 416 | if (dragIndex === hoverIndex) { 417 | return; 418 | } 419 | 420 | var hoverBoundingRect = ReactDOM.findDOMNode(component).getBoundingClientRect(); 421 | var hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2; 422 | var clientOffset = monitor.getClientOffset(); 423 | var hoverClientY = clientOffset.y - hoverBoundingRect.top; 424 | 425 | if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) { 426 | return; 427 | } 428 | 429 | if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) { 430 | return; 431 | } 432 | 433 | props.moveGroupItem(dragIndex, hoverIndex); 434 | monitor.getItem().index = hoverIndex; 435 | } else if (dragItem.type === 'card') { 436 | var hoverItem = props; 437 | 438 | var _monitor$getClientOff = monitor.getClientOffset(), 439 | x = _monitor$getClientOff.x, 440 | y = _monitor$getClientOff.y; 441 | 442 | var groupItemBoundingRect = ReactDOM.findDOMNode(component).getBoundingClientRect(); 443 | var groupItemX = groupItemBoundingRect.left; 444 | var groupItemY = groupItemBoundingRect.top; 445 | props.moveCardInGroupItem(dragItem, hoverItem, x - groupItemX, y - groupItemY); 446 | } 447 | }, 448 | drop: function drop(props, monitor, component) { 449 | var dragItem = monitor.getItem(); 450 | var dropItem = props; 451 | 452 | if (dragItem.type === 'card') { 453 | props.onCardDropInGroupItem(dragItem, dropItem); 454 | } 455 | } 456 | }; 457 | 458 | var Demo = /*#__PURE__*/function (_Component) { 459 | _inheritsLoose(Demo, _Component); 460 | 461 | function Demo(props) { 462 | var _this; 463 | 464 | _this = _Component.call(this, props) || this; 465 | _this.state = {}; 466 | return _this; 467 | } 468 | 469 | var _proto = Demo.prototype; 470 | 471 | _proto.componentDidMount = function componentDidMount() { 472 | var clientWidth; 473 | var containerDom = document.querySelector('#card-container'); 474 | 475 | if (containerDom) { 476 | clientWidth = containerDom.clientWidth; 477 | } 478 | 479 | if (this.props.layout.containerWidth !== clientWidth) { 480 | this.props.handleLoad(); 481 | } 482 | }; 483 | 484 | _proto.createCards = function createCards(cards, groupID, groups) { 485 | var _this2 = this; 486 | 487 | var itemDoms = []; 488 | 489 | _.forEach(cards, function (c, i) { 490 | itemDoms.push( /*#__PURE__*/React.createElement(dragDropItem, { 491 | dragCardID: -1, 492 | type: 'card', 493 | groups: groups, 494 | card: c, 495 | id: c.id, 496 | index: i, 497 | gridx: c.gridx, 498 | gridy: c.gridy, 499 | width: c.width, 500 | height: c.height, 501 | isShadow: c.isShadow, 502 | key: groupID + "_" + c.id, 503 | layout: _this2.props.layout, 504 | updateShadowCard: _this2.props.updateShadowCard, 505 | updateGroupList: _this2.props.updateGroupList 506 | })); 507 | }); 508 | 509 | return itemDoms; 510 | }; 511 | 512 | _proto.render = function render() { 513 | var _this$props = this.props, 514 | connectDropTarget = _this$props.connectDropTarget, 515 | isOver = _this$props.isOver, 516 | id = _this$props.id, 517 | cards = _this$props.cards, 518 | defaultLayout = _this$props.defaultLayout, 519 | layout = _this$props.layout, 520 | groups = _this$props.groups; 521 | var containerHeight = utils.getContainerMaxHeight(cards, layout.rowHeight, layout.margin); 522 | return connectDropTarget( /*#__PURE__*/React.createElement("div", { 523 | className: "rglb_group-item" 524 | }, /*#__PURE__*/React.createElement("div", { 525 | className: "group-item-container", 526 | style: { 527 | background: isOver ? 'rgb(204, 204, 204)' : 'rgba(79,86,98,.1)' 528 | } 529 | }, /*#__PURE__*/React.createElement("section", { 530 | id: "card-container", 531 | style: { 532 | height: containerHeight > defaultLayout.containerHeight ? containerHeight : defaultLayout.containerHeight 533 | } 534 | }, this.createCards(cards, id, groups))))); 535 | }; 536 | 537 | return Demo; 538 | }(Component); 539 | 540 | function collectTarget(connect, monitor) { 541 | return { 542 | connectDropTarget: connect.dropTarget(), 543 | isOver: monitor.isOver() 544 | }; 545 | } 546 | 547 | var Container = DropTarget('item', groupItemTarget, collectTarget)(Demo); 548 | 549 | var CardListDragPreview = /*#__PURE__*/function (_Component) { 550 | _inheritsLoose(CardListDragPreview, _Component); 551 | 552 | function CardListDragPreview() { 553 | return _Component.apply(this, arguments) || this; 554 | } 555 | 556 | var _proto = CardListDragPreview.prototype; 557 | 558 | _proto.render = function render() { 559 | var _this$props = this.props, 560 | cardListLength = _this$props.cardListLength, 561 | cardId = _this$props.cardId; 562 | var divDom = []; 563 | 564 | for (var index = 0; index < cardListLength; index++) { 565 | if (index === cardListLength - 1) { 566 | var myIndex = index >= 3 ? 3 : index; 567 | divDom.push( /*#__PURE__*/React.createElement("div", { 568 | key: index, 569 | className: "layer-card", 570 | style: { 571 | left: myIndex * 5 + "px", 572 | top: myIndex * 5 + "px" 573 | } 574 | }, /*#__PURE__*/React.createElement("span", { 575 | className: "layer-card-span" 576 | }, cardId), /*#__PURE__*/React.createElement("img", { 577 | src: "https://reactjs.org/logo-180x180.png", 578 | alt: "logo", 579 | width: "107", 580 | height: "113" 581 | }))); 582 | } else if (index < 3) { 583 | divDom.push( /*#__PURE__*/React.createElement("div", { 584 | key: index, 585 | className: "layer-card", 586 | style: { 587 | left: index * 5 + "px", 588 | top: index * 5 + "px" 589 | } 590 | })); 591 | } 592 | } 593 | 594 | return /*#__PURE__*/React.createElement("div", { 595 | className: "custom-layer-card-list" 596 | }, divDom); 597 | }; 598 | 599 | return CardListDragPreview; 600 | }(Component); 601 | 602 | var CumDragLayer = /*#__PURE__*/function (_Component) { 603 | _inheritsLoose(CumDragLayer, _Component); 604 | 605 | function CumDragLayer() { 606 | var _this; 607 | 608 | for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { 609 | args[_key] = arguments[_key]; 610 | } 611 | 612 | _this = _Component.call.apply(_Component, [this].concat(args)) || this; 613 | 614 | _this.getItemStyles = function () { 615 | var clientOffset = _this.props.clientOffset; 616 | 617 | if (!clientOffset) { 618 | return { 619 | display: 'none' 620 | }; 621 | } 622 | 623 | var x = clientOffset.x, 624 | y = clientOffset.y; 625 | var transform = "translate(" + x + "px, " + y + "px)"; 626 | return { 627 | transform: transform, 628 | WebkitTransform: transform 629 | }; 630 | }; 631 | 632 | return _this; 633 | } 634 | 635 | var _proto = CumDragLayer.prototype; 636 | 637 | _proto.renderItem = function renderItem(type, item) { 638 | switch (type) { 639 | case 'item': 640 | return /*#__PURE__*/React.createElement(CardListDragPreview, { 641 | cardListLength: 1, 642 | cardId: item.id 643 | }); 644 | 645 | default: 646 | return null; 647 | } 648 | }; 649 | 650 | _proto.shouldComponentUpdate = function shouldComponentUpdate(nextProps, nextState) { 651 | var _this$props$item, _this$props$item2; 652 | 653 | if (((_this$props$item = this.props.item) === null || _this$props$item === void 0 ? void 0 : _this$props$item.type) === 'card' && this.props.isDragging !== nextProps.isDragging) { 654 | return true; 655 | } 656 | 657 | if (((_this$props$item2 = this.props.item) === null || _this$props$item2 === void 0 ? void 0 : _this$props$item2.type) === 'card' && this.props.currentOffset !== nextProps.currentOffset) { 658 | if (nextProps.currentOffset && Math.pow(Math.pow(this.props.clientOffset.x - nextProps.clientOffset.x, 2) + Math.pow(this.props.clientOffset.y - nextProps.clientOffset.y, 2), 0.5) > 1.5) { 659 | return true; 660 | } 661 | } 662 | 663 | return false; 664 | }; 665 | 666 | _proto.render = function render() { 667 | var _this$props = this.props, 668 | item = _this$props.item, 669 | itemType = _this$props.itemType, 670 | isDragging = _this$props.isDragging; 671 | 672 | if (!isDragging || item.type !== 'card') { 673 | return null; 674 | } 675 | 676 | if (navigator.userAgent.indexOf('MSIE') > -1 || navigator.userAgent.indexOf('Trident') > -1 || navigator.userAgent.indexOf('Edge') > -1) { 677 | return null; 678 | } 679 | 680 | return /*#__PURE__*/React.createElement("div", { 681 | className: "rglb_custom-layer" 682 | }, /*#__PURE__*/React.createElement("div", { 683 | style: this.getItemStyles() 684 | }, this.renderItem(itemType, item))); 685 | }; 686 | 687 | return CumDragLayer; 688 | }(Component); 689 | 690 | function collect(monitor) { 691 | return { 692 | item: monitor.getItem(), 693 | itemType: monitor.getItemType(), 694 | currentOffset: monitor.getSourceClientOffset(), 695 | clientOffset: monitor.getClientOffset(), 696 | isDragging: monitor.isDragging() 697 | }; 698 | } 699 | 700 | var CustomDragLayer = DragLayer(collect)(CumDragLayer); 701 | 702 | function createCommonjsModule(fn, module) { 703 | return module = { exports: {} }, fn(module, module.exports), module.exports; 704 | } 705 | 706 | /** @license React v16.13.1 707 | * react-is.production.min.js 708 | * 709 | * Copyright (c) Facebook, Inc. and its affiliates. 710 | * 711 | * This source code is licensed under the MIT license found in the 712 | * LICENSE file in the root directory of this source tree. 713 | */ 714 | var b="function"===typeof Symbol&&Symbol.for,c=b?Symbol.for("react.element"):60103,d=b?Symbol.for("react.portal"):60106,e=b?Symbol.for("react.fragment"):60107,f=b?Symbol.for("react.strict_mode"):60108,g=b?Symbol.for("react.profiler"):60114,h=b?Symbol.for("react.provider"):60109,k=b?Symbol.for("react.context"):60110,l=b?Symbol.for("react.async_mode"):60111,m=b?Symbol.for("react.concurrent_mode"):60111,n=b?Symbol.for("react.forward_ref"):60112,p=b?Symbol.for("react.suspense"):60113,q=b? 715 | Symbol.for("react.suspense_list"):60120,r=b?Symbol.for("react.memo"):60115,t=b?Symbol.for("react.lazy"):60116,v=b?Symbol.for("react.block"):60121,w=b?Symbol.for("react.fundamental"):60117,x=b?Symbol.for("react.responder"):60118,y=b?Symbol.for("react.scope"):60119; 716 | function z(a){if("object"===typeof a&&null!==a){var u=a.$$typeof;switch(u){case c:switch(a=a.type,a){case l:case m:case e:case g:case f:case p:return a;default:switch(a=a&&a.$$typeof,a){case k:case n:case t:case r:case h:return a;default:return u}}case d:return u}}}function A(a){return z(a)===m}var AsyncMode=l;var ConcurrentMode=m;var ContextConsumer=k;var ContextProvider=h;var Element=c;var ForwardRef=n;var Fragment=e;var Lazy=t;var Memo=r;var Portal=d; 717 | var Profiler=g;var StrictMode=f;var Suspense=p;var isAsyncMode=function(a){return A(a)||z(a)===l};var isConcurrentMode=A;var isContextConsumer=function(a){return z(a)===k};var isContextProvider=function(a){return z(a)===h};var isElement=function(a){return "object"===typeof a&&null!==a&&a.$$typeof===c};var isForwardRef=function(a){return z(a)===n};var isFragment=function(a){return z(a)===e};var isLazy=function(a){return z(a)===t}; 718 | var isMemo=function(a){return z(a)===r};var isPortal=function(a){return z(a)===d};var isProfiler=function(a){return z(a)===g};var isStrictMode=function(a){return z(a)===f};var isSuspense=function(a){return z(a)===p}; 719 | var isValidElementType=function(a){return "string"===typeof a||"function"===typeof a||a===e||a===m||a===g||a===f||a===p||a===q||"object"===typeof a&&null!==a&&(a.$$typeof===t||a.$$typeof===r||a.$$typeof===h||a.$$typeof===k||a.$$typeof===n||a.$$typeof===w||a.$$typeof===x||a.$$typeof===y||a.$$typeof===v)};var typeOf=z; 720 | 721 | var reactIs_production_min = { 722 | AsyncMode: AsyncMode, 723 | ConcurrentMode: ConcurrentMode, 724 | ContextConsumer: ContextConsumer, 725 | ContextProvider: ContextProvider, 726 | Element: Element, 727 | ForwardRef: ForwardRef, 728 | Fragment: Fragment, 729 | Lazy: Lazy, 730 | Memo: Memo, 731 | Portal: Portal, 732 | Profiler: Profiler, 733 | StrictMode: StrictMode, 734 | Suspense: Suspense, 735 | isAsyncMode: isAsyncMode, 736 | isConcurrentMode: isConcurrentMode, 737 | isContextConsumer: isContextConsumer, 738 | isContextProvider: isContextProvider, 739 | isElement: isElement, 740 | isForwardRef: isForwardRef, 741 | isFragment: isFragment, 742 | isLazy: isLazy, 743 | isMemo: isMemo, 744 | isPortal: isPortal, 745 | isProfiler: isProfiler, 746 | isStrictMode: isStrictMode, 747 | isSuspense: isSuspense, 748 | isValidElementType: isValidElementType, 749 | typeOf: typeOf 750 | }; 751 | 752 | var reactIs_development = createCommonjsModule(function (module, exports) { 753 | 754 | 755 | 756 | if (process.env.NODE_ENV !== "production") { 757 | (function() { 758 | 759 | // The Symbol used to tag the ReactElement-like types. If there is no native Symbol 760 | // nor polyfill, then a plain number is used for performance. 761 | var hasSymbol = typeof Symbol === 'function' && Symbol.for; 762 | var REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for('react.element') : 0xeac7; 763 | var REACT_PORTAL_TYPE = hasSymbol ? Symbol.for('react.portal') : 0xeaca; 764 | var REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for('react.fragment') : 0xeacb; 765 | var REACT_STRICT_MODE_TYPE = hasSymbol ? Symbol.for('react.strict_mode') : 0xeacc; 766 | var REACT_PROFILER_TYPE = hasSymbol ? Symbol.for('react.profiler') : 0xead2; 767 | var REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for('react.provider') : 0xeacd; 768 | var REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for('react.context') : 0xeace; // TODO: We don't use AsyncMode or ConcurrentMode anymore. They were temporary 769 | // (unstable) APIs that have been removed. Can we remove the symbols? 770 | 771 | var REACT_ASYNC_MODE_TYPE = hasSymbol ? Symbol.for('react.async_mode') : 0xeacf; 772 | var REACT_CONCURRENT_MODE_TYPE = hasSymbol ? Symbol.for('react.concurrent_mode') : 0xeacf; 773 | var REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0; 774 | var REACT_SUSPENSE_TYPE = hasSymbol ? Symbol.for('react.suspense') : 0xead1; 775 | var REACT_SUSPENSE_LIST_TYPE = hasSymbol ? Symbol.for('react.suspense_list') : 0xead8; 776 | var REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3; 777 | var REACT_LAZY_TYPE = hasSymbol ? Symbol.for('react.lazy') : 0xead4; 778 | var REACT_BLOCK_TYPE = hasSymbol ? Symbol.for('react.block') : 0xead9; 779 | var REACT_FUNDAMENTAL_TYPE = hasSymbol ? Symbol.for('react.fundamental') : 0xead5; 780 | var REACT_RESPONDER_TYPE = hasSymbol ? Symbol.for('react.responder') : 0xead6; 781 | var REACT_SCOPE_TYPE = hasSymbol ? Symbol.for('react.scope') : 0xead7; 782 | 783 | function isValidElementType(type) { 784 | return typeof type === 'string' || typeof type === 'function' || // Note: its typeof might be other than 'symbol' or 'number' if it's a polyfill. 785 | type === REACT_FRAGMENT_TYPE || type === REACT_CONCURRENT_MODE_TYPE || type === REACT_PROFILER_TYPE || type === REACT_STRICT_MODE_TYPE || type === REACT_SUSPENSE_TYPE || type === REACT_SUSPENSE_LIST_TYPE || typeof type === 'object' && type !== null && (type.$$typeof === REACT_LAZY_TYPE || type.$$typeof === REACT_MEMO_TYPE || type.$$typeof === REACT_PROVIDER_TYPE || type.$$typeof === REACT_CONTEXT_TYPE || type.$$typeof === REACT_FORWARD_REF_TYPE || type.$$typeof === REACT_FUNDAMENTAL_TYPE || type.$$typeof === REACT_RESPONDER_TYPE || type.$$typeof === REACT_SCOPE_TYPE || type.$$typeof === REACT_BLOCK_TYPE); 786 | } 787 | 788 | function typeOf(object) { 789 | if (typeof object === 'object' && object !== null) { 790 | var $$typeof = object.$$typeof; 791 | 792 | switch ($$typeof) { 793 | case REACT_ELEMENT_TYPE: 794 | var type = object.type; 795 | 796 | switch (type) { 797 | case REACT_ASYNC_MODE_TYPE: 798 | case REACT_CONCURRENT_MODE_TYPE: 799 | case REACT_FRAGMENT_TYPE: 800 | case REACT_PROFILER_TYPE: 801 | case REACT_STRICT_MODE_TYPE: 802 | case REACT_SUSPENSE_TYPE: 803 | return type; 804 | 805 | default: 806 | var $$typeofType = type && type.$$typeof; 807 | 808 | switch ($$typeofType) { 809 | case REACT_CONTEXT_TYPE: 810 | case REACT_FORWARD_REF_TYPE: 811 | case REACT_LAZY_TYPE: 812 | case REACT_MEMO_TYPE: 813 | case REACT_PROVIDER_TYPE: 814 | return $$typeofType; 815 | 816 | default: 817 | return $$typeof; 818 | } 819 | 820 | } 821 | 822 | case REACT_PORTAL_TYPE: 823 | return $$typeof; 824 | } 825 | } 826 | 827 | return undefined; 828 | } // AsyncMode is deprecated along with isAsyncMode 829 | 830 | var AsyncMode = REACT_ASYNC_MODE_TYPE; 831 | var ConcurrentMode = REACT_CONCURRENT_MODE_TYPE; 832 | var ContextConsumer = REACT_CONTEXT_TYPE; 833 | var ContextProvider = REACT_PROVIDER_TYPE; 834 | var Element = REACT_ELEMENT_TYPE; 835 | var ForwardRef = REACT_FORWARD_REF_TYPE; 836 | var Fragment = REACT_FRAGMENT_TYPE; 837 | var Lazy = REACT_LAZY_TYPE; 838 | var Memo = REACT_MEMO_TYPE; 839 | var Portal = REACT_PORTAL_TYPE; 840 | var Profiler = REACT_PROFILER_TYPE; 841 | var StrictMode = REACT_STRICT_MODE_TYPE; 842 | var Suspense = REACT_SUSPENSE_TYPE; 843 | var hasWarnedAboutDeprecatedIsAsyncMode = false; // AsyncMode should be deprecated 844 | 845 | function isAsyncMode(object) { 846 | { 847 | if (!hasWarnedAboutDeprecatedIsAsyncMode) { 848 | hasWarnedAboutDeprecatedIsAsyncMode = true; // Using console['warn'] to evade Babel and ESLint 849 | 850 | console['warn']('The ReactIs.isAsyncMode() alias has been deprecated, ' + 'and will be removed in React 17+. Update your code to use ' + 'ReactIs.isConcurrentMode() instead. It has the exact same API.'); 851 | } 852 | } 853 | 854 | return isConcurrentMode(object) || typeOf(object) === REACT_ASYNC_MODE_TYPE; 855 | } 856 | function isConcurrentMode(object) { 857 | return typeOf(object) === REACT_CONCURRENT_MODE_TYPE; 858 | } 859 | function isContextConsumer(object) { 860 | return typeOf(object) === REACT_CONTEXT_TYPE; 861 | } 862 | function isContextProvider(object) { 863 | return typeOf(object) === REACT_PROVIDER_TYPE; 864 | } 865 | function isElement(object) { 866 | return typeof object === 'object' && object !== null && object.$$typeof === REACT_ELEMENT_TYPE; 867 | } 868 | function isForwardRef(object) { 869 | return typeOf(object) === REACT_FORWARD_REF_TYPE; 870 | } 871 | function isFragment(object) { 872 | return typeOf(object) === REACT_FRAGMENT_TYPE; 873 | } 874 | function isLazy(object) { 875 | return typeOf(object) === REACT_LAZY_TYPE; 876 | } 877 | function isMemo(object) { 878 | return typeOf(object) === REACT_MEMO_TYPE; 879 | } 880 | function isPortal(object) { 881 | return typeOf(object) === REACT_PORTAL_TYPE; 882 | } 883 | function isProfiler(object) { 884 | return typeOf(object) === REACT_PROFILER_TYPE; 885 | } 886 | function isStrictMode(object) { 887 | return typeOf(object) === REACT_STRICT_MODE_TYPE; 888 | } 889 | function isSuspense(object) { 890 | return typeOf(object) === REACT_SUSPENSE_TYPE; 891 | } 892 | 893 | exports.AsyncMode = AsyncMode; 894 | exports.ConcurrentMode = ConcurrentMode; 895 | exports.ContextConsumer = ContextConsumer; 896 | exports.ContextProvider = ContextProvider; 897 | exports.Element = Element; 898 | exports.ForwardRef = ForwardRef; 899 | exports.Fragment = Fragment; 900 | exports.Lazy = Lazy; 901 | exports.Memo = Memo; 902 | exports.Portal = Portal; 903 | exports.Profiler = Profiler; 904 | exports.StrictMode = StrictMode; 905 | exports.Suspense = Suspense; 906 | exports.isAsyncMode = isAsyncMode; 907 | exports.isConcurrentMode = isConcurrentMode; 908 | exports.isContextConsumer = isContextConsumer; 909 | exports.isContextProvider = isContextProvider; 910 | exports.isElement = isElement; 911 | exports.isForwardRef = isForwardRef; 912 | exports.isFragment = isFragment; 913 | exports.isLazy = isLazy; 914 | exports.isMemo = isMemo; 915 | exports.isPortal = isPortal; 916 | exports.isProfiler = isProfiler; 917 | exports.isStrictMode = isStrictMode; 918 | exports.isSuspense = isSuspense; 919 | exports.isValidElementType = isValidElementType; 920 | exports.typeOf = typeOf; 921 | })(); 922 | } 923 | }); 924 | 925 | var reactIs = createCommonjsModule(function (module) { 926 | 927 | if (process.env.NODE_ENV === 'production') { 928 | module.exports = reactIs_production_min; 929 | } else { 930 | module.exports = reactIs_development; 931 | } 932 | }); 933 | 934 | /* 935 | object-assign 936 | (c) Sindre Sorhus 937 | @license MIT 938 | */ 939 | /* eslint-disable no-unused-vars */ 940 | var getOwnPropertySymbols = Object.getOwnPropertySymbols; 941 | var hasOwnProperty = Object.prototype.hasOwnProperty; 942 | var propIsEnumerable = Object.prototype.propertyIsEnumerable; 943 | 944 | function toObject(val) { 945 | if (val === null || val === undefined) { 946 | throw new TypeError('Object.assign cannot be called with null or undefined'); 947 | } 948 | 949 | return Object(val); 950 | } 951 | 952 | function shouldUseNative() { 953 | try { 954 | if (!Object.assign) { 955 | return false; 956 | } 957 | 958 | // Detect buggy property enumeration order in older V8 versions. 959 | 960 | // https://bugs.chromium.org/p/v8/issues/detail?id=4118 961 | var test1 = new String('abc'); // eslint-disable-line no-new-wrappers 962 | test1[5] = 'de'; 963 | if (Object.getOwnPropertyNames(test1)[0] === '5') { 964 | return false; 965 | } 966 | 967 | // https://bugs.chromium.org/p/v8/issues/detail?id=3056 968 | var test2 = {}; 969 | for (var i = 0; i < 10; i++) { 970 | test2['_' + String.fromCharCode(i)] = i; 971 | } 972 | var order2 = Object.getOwnPropertyNames(test2).map(function (n) { 973 | return test2[n]; 974 | }); 975 | if (order2.join('') !== '0123456789') { 976 | return false; 977 | } 978 | 979 | // https://bugs.chromium.org/p/v8/issues/detail?id=3056 980 | var test3 = {}; 981 | 'abcdefghijklmnopqrst'.split('').forEach(function (letter) { 982 | test3[letter] = letter; 983 | }); 984 | if (Object.keys(Object.assign({}, test3)).join('') !== 985 | 'abcdefghijklmnopqrst') { 986 | return false; 987 | } 988 | 989 | return true; 990 | } catch (err) { 991 | // We don't expect any of the above to throw, but better to be safe. 992 | return false; 993 | } 994 | } 995 | 996 | var objectAssign = shouldUseNative() ? Object.assign : function (target, source) { 997 | var from; 998 | var to = toObject(target); 999 | var symbols; 1000 | 1001 | for (var s = 1; s < arguments.length; s++) { 1002 | from = Object(arguments[s]); 1003 | 1004 | for (var key in from) { 1005 | if (hasOwnProperty.call(from, key)) { 1006 | to[key] = from[key]; 1007 | } 1008 | } 1009 | 1010 | if (getOwnPropertySymbols) { 1011 | symbols = getOwnPropertySymbols(from); 1012 | for (var i = 0; i < symbols.length; i++) { 1013 | if (propIsEnumerable.call(from, symbols[i])) { 1014 | to[symbols[i]] = from[symbols[i]]; 1015 | } 1016 | } 1017 | } 1018 | } 1019 | 1020 | return to; 1021 | }; 1022 | 1023 | /** 1024 | * Copyright (c) 2013-present, Facebook, Inc. 1025 | * 1026 | * This source code is licensed under the MIT license found in the 1027 | * LICENSE file in the root directory of this source tree. 1028 | */ 1029 | 1030 | var ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED'; 1031 | 1032 | var ReactPropTypesSecret_1 = ReactPropTypesSecret; 1033 | 1034 | var printWarning = function() {}; 1035 | 1036 | if (process.env.NODE_ENV !== 'production') { 1037 | var ReactPropTypesSecret$1 = ReactPropTypesSecret_1; 1038 | var loggedTypeFailures = {}; 1039 | var has = Function.call.bind(Object.prototype.hasOwnProperty); 1040 | 1041 | printWarning = function(text) { 1042 | var message = 'Warning: ' + text; 1043 | if (typeof console !== 'undefined') { 1044 | console.error(message); 1045 | } 1046 | try { 1047 | // --- Welcome to debugging React --- 1048 | // This error was thrown as a convenience so that you can use this stack 1049 | // to find the callsite that caused this warning to fire. 1050 | throw new Error(message); 1051 | } catch (x) {} 1052 | }; 1053 | } 1054 | 1055 | /** 1056 | * Assert that the values match with the type specs. 1057 | * Error messages are memorized and will only be shown once. 1058 | * 1059 | * @param {object} typeSpecs Map of name to a ReactPropType 1060 | * @param {object} values Runtime values that need to be type-checked 1061 | * @param {string} location e.g. "prop", "context", "child context" 1062 | * @param {string} componentName Name of the component for error messages. 1063 | * @param {?Function} getStack Returns the component stack. 1064 | * @private 1065 | */ 1066 | function checkPropTypes(typeSpecs, values, location, componentName, getStack) { 1067 | if (process.env.NODE_ENV !== 'production') { 1068 | for (var typeSpecName in typeSpecs) { 1069 | if (has(typeSpecs, typeSpecName)) { 1070 | var error; 1071 | // Prop type validation may throw. In case they do, we don't want to 1072 | // fail the render phase where it didn't fail before. So we log it. 1073 | // After these have been cleaned up, we'll let them throw. 1074 | try { 1075 | // This is intentionally an invariant that gets caught. It's the same 1076 | // behavior as without this statement except with a better message. 1077 | if (typeof typeSpecs[typeSpecName] !== 'function') { 1078 | var err = Error( 1079 | (componentName || 'React class') + ': ' + location + ' type `' + typeSpecName + '` is invalid; ' + 1080 | 'it must be a function, usually from the `prop-types` package, but received `' + typeof typeSpecs[typeSpecName] + '`.' 1081 | ); 1082 | err.name = 'Invariant Violation'; 1083 | throw err; 1084 | } 1085 | error = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, ReactPropTypesSecret$1); 1086 | } catch (ex) { 1087 | error = ex; 1088 | } 1089 | if (error && !(error instanceof Error)) { 1090 | printWarning( 1091 | (componentName || 'React class') + ': type specification of ' + 1092 | location + ' `' + typeSpecName + '` is invalid; the type checker ' + 1093 | 'function must return `null` or an `Error` but returned a ' + typeof error + '. ' + 1094 | 'You may have forgotten to pass an argument to the type checker ' + 1095 | 'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' + 1096 | 'shape all require an argument).' 1097 | ); 1098 | } 1099 | if (error instanceof Error && !(error.message in loggedTypeFailures)) { 1100 | // Only monitor this failure once because there tends to be a lot of the 1101 | // same error. 1102 | loggedTypeFailures[error.message] = true; 1103 | 1104 | var stack = getStack ? getStack() : ''; 1105 | 1106 | printWarning( 1107 | 'Failed ' + location + ' type: ' + error.message + (stack != null ? stack : '') 1108 | ); 1109 | } 1110 | } 1111 | } 1112 | } 1113 | } 1114 | 1115 | /** 1116 | * Resets warning cache when testing. 1117 | * 1118 | * @private 1119 | */ 1120 | checkPropTypes.resetWarningCache = function() { 1121 | if (process.env.NODE_ENV !== 'production') { 1122 | loggedTypeFailures = {}; 1123 | } 1124 | }; 1125 | 1126 | var checkPropTypes_1 = checkPropTypes; 1127 | 1128 | var has$1 = Function.call.bind(Object.prototype.hasOwnProperty); 1129 | var printWarning$1 = function() {}; 1130 | 1131 | if (process.env.NODE_ENV !== 'production') { 1132 | printWarning$1 = function(text) { 1133 | var message = 'Warning: ' + text; 1134 | if (typeof console !== 'undefined') { 1135 | console.error(message); 1136 | } 1137 | try { 1138 | // --- Welcome to debugging React --- 1139 | // This error was thrown as a convenience so that you can use this stack 1140 | // to find the callsite that caused this warning to fire. 1141 | throw new Error(message); 1142 | } catch (x) {} 1143 | }; 1144 | } 1145 | 1146 | function emptyFunctionThatReturnsNull() { 1147 | return null; 1148 | } 1149 | 1150 | var factoryWithTypeCheckers = function(isValidElement, throwOnDirectAccess) { 1151 | /* global Symbol */ 1152 | var ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator; 1153 | var FAUX_ITERATOR_SYMBOL = '@@iterator'; // Before Symbol spec. 1154 | 1155 | /** 1156 | * Returns the iterator method function contained on the iterable object. 1157 | * 1158 | * Be sure to invoke the function with the iterable as context: 1159 | * 1160 | * var iteratorFn = getIteratorFn(myIterable); 1161 | * if (iteratorFn) { 1162 | * var iterator = iteratorFn.call(myIterable); 1163 | * ... 1164 | * } 1165 | * 1166 | * @param {?object} maybeIterable 1167 | * @return {?function} 1168 | */ 1169 | function getIteratorFn(maybeIterable) { 1170 | var iteratorFn = maybeIterable && (ITERATOR_SYMBOL && maybeIterable[ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]); 1171 | if (typeof iteratorFn === 'function') { 1172 | return iteratorFn; 1173 | } 1174 | } 1175 | 1176 | /** 1177 | * Collection of methods that allow declaration and validation of props that are 1178 | * supplied to React components. Example usage: 1179 | * 1180 | * var Props = require('ReactPropTypes'); 1181 | * var MyArticle = React.createClass({ 1182 | * propTypes: { 1183 | * // An optional string prop named "description". 1184 | * description: Props.string, 1185 | * 1186 | * // A required enum prop named "category". 1187 | * category: Props.oneOf(['News','Photos']).isRequired, 1188 | * 1189 | * // A prop named "dialog" that requires an instance of Dialog. 1190 | * dialog: Props.instanceOf(Dialog).isRequired 1191 | * }, 1192 | * render: function() { ... } 1193 | * }); 1194 | * 1195 | * A more formal specification of how these methods are used: 1196 | * 1197 | * type := array|bool|func|object|number|string|oneOf([...])|instanceOf(...) 1198 | * decl := ReactPropTypes.{type}(.isRequired)? 1199 | * 1200 | * Each and every declaration produces a function with the same signature. This 1201 | * allows the creation of custom validation functions. For example: 1202 | * 1203 | * var MyLink = React.createClass({ 1204 | * propTypes: { 1205 | * // An optional string or URI prop named "href". 1206 | * href: function(props, propName, componentName) { 1207 | * var propValue = props[propName]; 1208 | * if (propValue != null && typeof propValue !== 'string' && 1209 | * !(propValue instanceof URI)) { 1210 | * return new Error( 1211 | * 'Expected a string or an URI for ' + propName + ' in ' + 1212 | * componentName 1213 | * ); 1214 | * } 1215 | * } 1216 | * }, 1217 | * render: function() {...} 1218 | * }); 1219 | * 1220 | * @internal 1221 | */ 1222 | 1223 | var ANONYMOUS = '<>'; 1224 | 1225 | // Important! 1226 | // Keep this list in sync with production version in `./factoryWithThrowingShims.js`. 1227 | var ReactPropTypes = { 1228 | array: createPrimitiveTypeChecker('array'), 1229 | bool: createPrimitiveTypeChecker('boolean'), 1230 | func: createPrimitiveTypeChecker('function'), 1231 | number: createPrimitiveTypeChecker('number'), 1232 | object: createPrimitiveTypeChecker('object'), 1233 | string: createPrimitiveTypeChecker('string'), 1234 | symbol: createPrimitiveTypeChecker('symbol'), 1235 | 1236 | any: createAnyTypeChecker(), 1237 | arrayOf: createArrayOfTypeChecker, 1238 | element: createElementTypeChecker(), 1239 | elementType: createElementTypeTypeChecker(), 1240 | instanceOf: createInstanceTypeChecker, 1241 | node: createNodeChecker(), 1242 | objectOf: createObjectOfTypeChecker, 1243 | oneOf: createEnumTypeChecker, 1244 | oneOfType: createUnionTypeChecker, 1245 | shape: createShapeTypeChecker, 1246 | exact: createStrictShapeTypeChecker, 1247 | }; 1248 | 1249 | /** 1250 | * inlined Object.is polyfill to avoid requiring consumers ship their own 1251 | * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is 1252 | */ 1253 | /*eslint-disable no-self-compare*/ 1254 | function is(x, y) { 1255 | // SameValue algorithm 1256 | if (x === y) { 1257 | // Steps 1-5, 7-10 1258 | // Steps 6.b-6.e: +0 != -0 1259 | return x !== 0 || 1 / x === 1 / y; 1260 | } else { 1261 | // Step 6.a: NaN == NaN 1262 | return x !== x && y !== y; 1263 | } 1264 | } 1265 | /*eslint-enable no-self-compare*/ 1266 | 1267 | /** 1268 | * We use an Error-like object for backward compatibility as people may call 1269 | * PropTypes directly and inspect their output. However, we don't use real 1270 | * Errors anymore. We don't inspect their stack anyway, and creating them 1271 | * is prohibitively expensive if they are created too often, such as what 1272 | * happens in oneOfType() for any type before the one that matched. 1273 | */ 1274 | function PropTypeError(message) { 1275 | this.message = message; 1276 | this.stack = ''; 1277 | } 1278 | // Make `instanceof Error` still work for returned errors. 1279 | PropTypeError.prototype = Error.prototype; 1280 | 1281 | function createChainableTypeChecker(validate) { 1282 | if (process.env.NODE_ENV !== 'production') { 1283 | var manualPropTypeCallCache = {}; 1284 | var manualPropTypeWarningCount = 0; 1285 | } 1286 | function checkType(isRequired, props, propName, componentName, location, propFullName, secret) { 1287 | componentName = componentName || ANONYMOUS; 1288 | propFullName = propFullName || propName; 1289 | 1290 | if (secret !== ReactPropTypesSecret_1) { 1291 | if (throwOnDirectAccess) { 1292 | // New behavior only for users of `prop-types` package 1293 | var err = new Error( 1294 | 'Calling PropTypes validators directly is not supported by the `prop-types` package. ' + 1295 | 'Use `PropTypes.checkPropTypes()` to call them. ' + 1296 | 'Read more at http://fb.me/use-check-prop-types' 1297 | ); 1298 | err.name = 'Invariant Violation'; 1299 | throw err; 1300 | } else if (process.env.NODE_ENV !== 'production' && typeof console !== 'undefined') { 1301 | // Old behavior for people using React.PropTypes 1302 | var cacheKey = componentName + ':' + propName; 1303 | if ( 1304 | !manualPropTypeCallCache[cacheKey] && 1305 | // Avoid spamming the console because they are often not actionable except for lib authors 1306 | manualPropTypeWarningCount < 3 1307 | ) { 1308 | printWarning$1( 1309 | 'You are manually calling a React.PropTypes validation ' + 1310 | 'function for the `' + propFullName + '` prop on `' + componentName + '`. This is deprecated ' + 1311 | 'and will throw in the standalone `prop-types` package. ' + 1312 | 'You may be seeing this warning due to a third-party PropTypes ' + 1313 | 'library. See https://fb.me/react-warning-dont-call-proptypes ' + 'for details.' 1314 | ); 1315 | manualPropTypeCallCache[cacheKey] = true; 1316 | manualPropTypeWarningCount++; 1317 | } 1318 | } 1319 | } 1320 | if (props[propName] == null) { 1321 | if (isRequired) { 1322 | if (props[propName] === null) { 1323 | return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required ' + ('in `' + componentName + '`, but its value is `null`.')); 1324 | } 1325 | return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required in ' + ('`' + componentName + '`, but its value is `undefined`.')); 1326 | } 1327 | return null; 1328 | } else { 1329 | return validate(props, propName, componentName, location, propFullName); 1330 | } 1331 | } 1332 | 1333 | var chainedCheckType = checkType.bind(null, false); 1334 | chainedCheckType.isRequired = checkType.bind(null, true); 1335 | 1336 | return chainedCheckType; 1337 | } 1338 | 1339 | function createPrimitiveTypeChecker(expectedType) { 1340 | function validate(props, propName, componentName, location, propFullName, secret) { 1341 | var propValue = props[propName]; 1342 | var propType = getPropType(propValue); 1343 | if (propType !== expectedType) { 1344 | // `propValue` being instance of, say, date/regexp, pass the 'object' 1345 | // check, but we can offer a more precise error message here rather than 1346 | // 'of type `object`'. 1347 | var preciseType = getPreciseType(propValue); 1348 | 1349 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + preciseType + '` supplied to `' + componentName + '`, expected ') + ('`' + expectedType + '`.')); 1350 | } 1351 | return null; 1352 | } 1353 | return createChainableTypeChecker(validate); 1354 | } 1355 | 1356 | function createAnyTypeChecker() { 1357 | return createChainableTypeChecker(emptyFunctionThatReturnsNull); 1358 | } 1359 | 1360 | function createArrayOfTypeChecker(typeChecker) { 1361 | function validate(props, propName, componentName, location, propFullName) { 1362 | if (typeof typeChecker !== 'function') { 1363 | return new PropTypeError('Property `' + propFullName + '` of component `' + componentName + '` has invalid PropType notation inside arrayOf.'); 1364 | } 1365 | var propValue = props[propName]; 1366 | if (!Array.isArray(propValue)) { 1367 | var propType = getPropType(propValue); 1368 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected an array.')); 1369 | } 1370 | for (var i = 0; i < propValue.length; i++) { 1371 | var error = typeChecker(propValue, i, componentName, location, propFullName + '[' + i + ']', ReactPropTypesSecret_1); 1372 | if (error instanceof Error) { 1373 | return error; 1374 | } 1375 | } 1376 | return null; 1377 | } 1378 | return createChainableTypeChecker(validate); 1379 | } 1380 | 1381 | function createElementTypeChecker() { 1382 | function validate(props, propName, componentName, location, propFullName) { 1383 | var propValue = props[propName]; 1384 | if (!isValidElement(propValue)) { 1385 | var propType = getPropType(propValue); 1386 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected a single ReactElement.')); 1387 | } 1388 | return null; 1389 | } 1390 | return createChainableTypeChecker(validate); 1391 | } 1392 | 1393 | function createElementTypeTypeChecker() { 1394 | function validate(props, propName, componentName, location, propFullName) { 1395 | var propValue = props[propName]; 1396 | if (!reactIs.isValidElementType(propValue)) { 1397 | var propType = getPropType(propValue); 1398 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected a single ReactElement type.')); 1399 | } 1400 | return null; 1401 | } 1402 | return createChainableTypeChecker(validate); 1403 | } 1404 | 1405 | function createInstanceTypeChecker(expectedClass) { 1406 | function validate(props, propName, componentName, location, propFullName) { 1407 | if (!(props[propName] instanceof expectedClass)) { 1408 | var expectedClassName = expectedClass.name || ANONYMOUS; 1409 | var actualClassName = getClassName(props[propName]); 1410 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + actualClassName + '` supplied to `' + componentName + '`, expected ') + ('instance of `' + expectedClassName + '`.')); 1411 | } 1412 | return null; 1413 | } 1414 | return createChainableTypeChecker(validate); 1415 | } 1416 | 1417 | function createEnumTypeChecker(expectedValues) { 1418 | if (!Array.isArray(expectedValues)) { 1419 | if (process.env.NODE_ENV !== 'production') { 1420 | if (arguments.length > 1) { 1421 | printWarning$1( 1422 | 'Invalid arguments supplied to oneOf, expected an array, got ' + arguments.length + ' arguments. ' + 1423 | 'A common mistake is to write oneOf(x, y, z) instead of oneOf([x, y, z]).' 1424 | ); 1425 | } else { 1426 | printWarning$1('Invalid argument supplied to oneOf, expected an array.'); 1427 | } 1428 | } 1429 | return emptyFunctionThatReturnsNull; 1430 | } 1431 | 1432 | function validate(props, propName, componentName, location, propFullName) { 1433 | var propValue = props[propName]; 1434 | for (var i = 0; i < expectedValues.length; i++) { 1435 | if (is(propValue, expectedValues[i])) { 1436 | return null; 1437 | } 1438 | } 1439 | 1440 | var valuesString = JSON.stringify(expectedValues, function replacer(key, value) { 1441 | var type = getPreciseType(value); 1442 | if (type === 'symbol') { 1443 | return String(value); 1444 | } 1445 | return value; 1446 | }); 1447 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of value `' + String(propValue) + '` ' + ('supplied to `' + componentName + '`, expected one of ' + valuesString + '.')); 1448 | } 1449 | return createChainableTypeChecker(validate); 1450 | } 1451 | 1452 | function createObjectOfTypeChecker(typeChecker) { 1453 | function validate(props, propName, componentName, location, propFullName) { 1454 | if (typeof typeChecker !== 'function') { 1455 | return new PropTypeError('Property `' + propFullName + '` of component `' + componentName + '` has invalid PropType notation inside objectOf.'); 1456 | } 1457 | var propValue = props[propName]; 1458 | var propType = getPropType(propValue); 1459 | if (propType !== 'object') { 1460 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected an object.')); 1461 | } 1462 | for (var key in propValue) { 1463 | if (has$1(propValue, key)) { 1464 | var error = typeChecker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret_1); 1465 | if (error instanceof Error) { 1466 | return error; 1467 | } 1468 | } 1469 | } 1470 | return null; 1471 | } 1472 | return createChainableTypeChecker(validate); 1473 | } 1474 | 1475 | function createUnionTypeChecker(arrayOfTypeCheckers) { 1476 | if (!Array.isArray(arrayOfTypeCheckers)) { 1477 | process.env.NODE_ENV !== 'production' ? printWarning$1('Invalid argument supplied to oneOfType, expected an instance of array.') : void 0; 1478 | return emptyFunctionThatReturnsNull; 1479 | } 1480 | 1481 | for (var i = 0; i < arrayOfTypeCheckers.length; i++) { 1482 | var checker = arrayOfTypeCheckers[i]; 1483 | if (typeof checker !== 'function') { 1484 | printWarning$1( 1485 | 'Invalid argument supplied to oneOfType. Expected an array of check functions, but ' + 1486 | 'received ' + getPostfixForTypeWarning(checker) + ' at index ' + i + '.' 1487 | ); 1488 | return emptyFunctionThatReturnsNull; 1489 | } 1490 | } 1491 | 1492 | function validate(props, propName, componentName, location, propFullName) { 1493 | for (var i = 0; i < arrayOfTypeCheckers.length; i++) { 1494 | var checker = arrayOfTypeCheckers[i]; 1495 | if (checker(props, propName, componentName, location, propFullName, ReactPropTypesSecret_1) == null) { 1496 | return null; 1497 | } 1498 | } 1499 | 1500 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`.')); 1501 | } 1502 | return createChainableTypeChecker(validate); 1503 | } 1504 | 1505 | function createNodeChecker() { 1506 | function validate(props, propName, componentName, location, propFullName) { 1507 | if (!isNode(props[propName])) { 1508 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`, expected a ReactNode.')); 1509 | } 1510 | return null; 1511 | } 1512 | return createChainableTypeChecker(validate); 1513 | } 1514 | 1515 | function createShapeTypeChecker(shapeTypes) { 1516 | function validate(props, propName, componentName, location, propFullName) { 1517 | var propValue = props[propName]; 1518 | var propType = getPropType(propValue); 1519 | if (propType !== 'object') { 1520 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type `' + propType + '` ' + ('supplied to `' + componentName + '`, expected `object`.')); 1521 | } 1522 | for (var key in shapeTypes) { 1523 | var checker = shapeTypes[key]; 1524 | if (!checker) { 1525 | continue; 1526 | } 1527 | var error = checker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret_1); 1528 | if (error) { 1529 | return error; 1530 | } 1531 | } 1532 | return null; 1533 | } 1534 | return createChainableTypeChecker(validate); 1535 | } 1536 | 1537 | function createStrictShapeTypeChecker(shapeTypes) { 1538 | function validate(props, propName, componentName, location, propFullName) { 1539 | var propValue = props[propName]; 1540 | var propType = getPropType(propValue); 1541 | if (propType !== 'object') { 1542 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type `' + propType + '` ' + ('supplied to `' + componentName + '`, expected `object`.')); 1543 | } 1544 | // We need to check all keys in case some are required but missing from 1545 | // props. 1546 | var allKeys = objectAssign({}, props[propName], shapeTypes); 1547 | for (var key in allKeys) { 1548 | var checker = shapeTypes[key]; 1549 | if (!checker) { 1550 | return new PropTypeError( 1551 | 'Invalid ' + location + ' `' + propFullName + '` key `' + key + '` supplied to `' + componentName + '`.' + 1552 | '\nBad object: ' + JSON.stringify(props[propName], null, ' ') + 1553 | '\nValid keys: ' + JSON.stringify(Object.keys(shapeTypes), null, ' ') 1554 | ); 1555 | } 1556 | var error = checker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret_1); 1557 | if (error) { 1558 | return error; 1559 | } 1560 | } 1561 | return null; 1562 | } 1563 | 1564 | return createChainableTypeChecker(validate); 1565 | } 1566 | 1567 | function isNode(propValue) { 1568 | switch (typeof propValue) { 1569 | case 'number': 1570 | case 'string': 1571 | case 'undefined': 1572 | return true; 1573 | case 'boolean': 1574 | return !propValue; 1575 | case 'object': 1576 | if (Array.isArray(propValue)) { 1577 | return propValue.every(isNode); 1578 | } 1579 | if (propValue === null || isValidElement(propValue)) { 1580 | return true; 1581 | } 1582 | 1583 | var iteratorFn = getIteratorFn(propValue); 1584 | if (iteratorFn) { 1585 | var iterator = iteratorFn.call(propValue); 1586 | var step; 1587 | if (iteratorFn !== propValue.entries) { 1588 | while (!(step = iterator.next()).done) { 1589 | if (!isNode(step.value)) { 1590 | return false; 1591 | } 1592 | } 1593 | } else { 1594 | // Iterator will provide entry [k,v] tuples rather than values. 1595 | while (!(step = iterator.next()).done) { 1596 | var entry = step.value; 1597 | if (entry) { 1598 | if (!isNode(entry[1])) { 1599 | return false; 1600 | } 1601 | } 1602 | } 1603 | } 1604 | } else { 1605 | return false; 1606 | } 1607 | 1608 | return true; 1609 | default: 1610 | return false; 1611 | } 1612 | } 1613 | 1614 | function isSymbol(propType, propValue) { 1615 | // Native Symbol. 1616 | if (propType === 'symbol') { 1617 | return true; 1618 | } 1619 | 1620 | // falsy value can't be a Symbol 1621 | if (!propValue) { 1622 | return false; 1623 | } 1624 | 1625 | // 19.4.3.5 Symbol.prototype[@@toStringTag] === 'Symbol' 1626 | if (propValue['@@toStringTag'] === 'Symbol') { 1627 | return true; 1628 | } 1629 | 1630 | // Fallback for non-spec compliant Symbols which are polyfilled. 1631 | if (typeof Symbol === 'function' && propValue instanceof Symbol) { 1632 | return true; 1633 | } 1634 | 1635 | return false; 1636 | } 1637 | 1638 | // Equivalent of `typeof` but with special handling for array and regexp. 1639 | function getPropType(propValue) { 1640 | var propType = typeof propValue; 1641 | if (Array.isArray(propValue)) { 1642 | return 'array'; 1643 | } 1644 | if (propValue instanceof RegExp) { 1645 | // Old webkits (at least until Android 4.0) return 'function' rather than 1646 | // 'object' for typeof a RegExp. We'll normalize this here so that /bla/ 1647 | // passes PropTypes.object. 1648 | return 'object'; 1649 | } 1650 | if (isSymbol(propType, propValue)) { 1651 | return 'symbol'; 1652 | } 1653 | return propType; 1654 | } 1655 | 1656 | // This handles more types than `getPropType`. Only used for error messages. 1657 | // See `createPrimitiveTypeChecker`. 1658 | function getPreciseType(propValue) { 1659 | if (typeof propValue === 'undefined' || propValue === null) { 1660 | return '' + propValue; 1661 | } 1662 | var propType = getPropType(propValue); 1663 | if (propType === 'object') { 1664 | if (propValue instanceof Date) { 1665 | return 'date'; 1666 | } else if (propValue instanceof RegExp) { 1667 | return 'regexp'; 1668 | } 1669 | } 1670 | return propType; 1671 | } 1672 | 1673 | // Returns a string that is postfixed to a warning about an invalid type. 1674 | // For example, "undefined" or "of type array" 1675 | function getPostfixForTypeWarning(value) { 1676 | var type = getPreciseType(value); 1677 | switch (type) { 1678 | case 'array': 1679 | case 'object': 1680 | return 'an ' + type; 1681 | case 'boolean': 1682 | case 'date': 1683 | case 'regexp': 1684 | return 'a ' + type; 1685 | default: 1686 | return type; 1687 | } 1688 | } 1689 | 1690 | // Returns class name of the object, if any. 1691 | function getClassName(propValue) { 1692 | if (!propValue.constructor || !propValue.constructor.name) { 1693 | return ANONYMOUS; 1694 | } 1695 | return propValue.constructor.name; 1696 | } 1697 | 1698 | ReactPropTypes.checkPropTypes = checkPropTypes_1; 1699 | ReactPropTypes.resetWarningCache = checkPropTypes_1.resetWarningCache; 1700 | ReactPropTypes.PropTypes = ReactPropTypes; 1701 | 1702 | return ReactPropTypes; 1703 | }; 1704 | 1705 | function emptyFunction() {} 1706 | function emptyFunctionWithReset() {} 1707 | emptyFunctionWithReset.resetWarningCache = emptyFunction; 1708 | 1709 | var factoryWithThrowingShims = function() { 1710 | function shim(props, propName, componentName, location, propFullName, secret) { 1711 | if (secret === ReactPropTypesSecret_1) { 1712 | // It is still safe when called from React. 1713 | return; 1714 | } 1715 | var err = new Error( 1716 | 'Calling PropTypes validators directly is not supported by the `prop-types` package. ' + 1717 | 'Use PropTypes.checkPropTypes() to call them. ' + 1718 | 'Read more at http://fb.me/use-check-prop-types' 1719 | ); 1720 | err.name = 'Invariant Violation'; 1721 | throw err; 1722 | } shim.isRequired = shim; 1723 | function getShim() { 1724 | return shim; 1725 | } // Important! 1726 | // Keep this list in sync with production version in `./factoryWithTypeCheckers.js`. 1727 | var ReactPropTypes = { 1728 | array: shim, 1729 | bool: shim, 1730 | func: shim, 1731 | number: shim, 1732 | object: shim, 1733 | string: shim, 1734 | symbol: shim, 1735 | 1736 | any: shim, 1737 | arrayOf: getShim, 1738 | element: shim, 1739 | elementType: shim, 1740 | instanceOf: getShim, 1741 | node: shim, 1742 | objectOf: getShim, 1743 | oneOf: getShim, 1744 | oneOfType: getShim, 1745 | shape: getShim, 1746 | exact: getShim, 1747 | 1748 | checkPropTypes: emptyFunctionWithReset, 1749 | resetWarningCache: emptyFunction 1750 | }; 1751 | 1752 | ReactPropTypes.PropTypes = ReactPropTypes; 1753 | 1754 | return ReactPropTypes; 1755 | }; 1756 | 1757 | var propTypes = createCommonjsModule(function (module) { 1758 | /** 1759 | * Copyright (c) 2013-present, Facebook, Inc. 1760 | * 1761 | * This source code is licensed under the MIT license found in the 1762 | * LICENSE file in the root directory of this source tree. 1763 | */ 1764 | 1765 | if (process.env.NODE_ENV !== 'production') { 1766 | var ReactIs = reactIs; 1767 | 1768 | // By explicitly using `prop-types` you are opting into new development behavior. 1769 | // http://fb.me/prop-types-in-prod 1770 | var throwOnDirectAccess = true; 1771 | module.exports = factoryWithTypeCheckers(ReactIs.isElement, throwOnDirectAccess); 1772 | } else { 1773 | // By explicitly using `prop-types` you are opting into new production behavior. 1774 | // http://fb.me/prop-types-in-prod 1775 | module.exports = factoryWithThrowingShims(); 1776 | } 1777 | }); 1778 | 1779 | var resizeWaiter = false; 1780 | 1781 | var MyContent = /*#__PURE__*/function (_Component) { 1782 | _inheritsLoose(MyContent, _Component); 1783 | 1784 | function MyContent(props) { 1785 | var _this; 1786 | 1787 | _this = _Component.call(this, props) || this; 1788 | 1789 | _this.handleLoad = function () { 1790 | if (!resizeWaiter) { 1791 | resizeWaiter = true; 1792 | setTimeout(function () { 1793 | console.info('resize!'); 1794 | resizeWaiter = false; 1795 | var clientWidth; 1796 | var containerDom = document.querySelector('#card-container'); 1797 | 1798 | if (containerDom) { 1799 | clientWidth = containerDom.clientWidth; 1800 | } else { 1801 | var firstAddButton = document.querySelector('#first-add'); 1802 | 1803 | if (firstAddButton) { 1804 | clientWidth = firstAddButton.clientWidth - 10; 1805 | } else { 1806 | return; 1807 | } 1808 | } 1809 | 1810 | var defaultCalWidth = _this.state.defaultLayout.calWidth; 1811 | var _this$state$layout = _this.state.layout, 1812 | containerPadding = _this$state$layout.containerPadding, 1813 | margin = _this$state$layout.margin; 1814 | 1815 | var layout = _.cloneDeep(_this.state.layout); 1816 | 1817 | var windowWidth = window.innerWidth - 60 * 2; 1818 | var col = utils.calColCount(defaultCalWidth, windowWidth, containerPadding, margin); 1819 | var calWidth = utils.calColWidth(clientWidth, col, containerPadding, margin); 1820 | var groups = _this.state.groups; 1821 | groups = _.cloneDeep(groups); 1822 | 1823 | _.forEach(groups, function (g) { 1824 | var compactedLayout = compactLayoutHorizontal(g.cards, col); 1825 | g.cards = compactedLayout; 1826 | }); 1827 | 1828 | layout.calWidth = layout.rowHeight = calWidth; 1829 | layout.col = col; 1830 | layout.containerWidth = clientWidth; 1831 | 1832 | _this.updateGroupList(groups); 1833 | 1834 | _this.updateLayout(layout); 1835 | }, 500); 1836 | } 1837 | }; 1838 | 1839 | _this.moveCardInGroupItem = function (dragItem, hoverItem, x, y) { 1840 | var groups = _this.state.groups; 1841 | var shadowCard = _this.state.shadowCard; 1842 | var _this$state$layout2 = _this.state.layout, 1843 | margin = _this$state$layout2.margin, 1844 | containerWidth = _this$state$layout2.containerWidth, 1845 | col = _this$state$layout2.col, 1846 | rowHeight = _this$state$layout2.rowHeight; 1847 | 1848 | var _utils$calGridXY = utils.calGridXY(x, y, shadowCard.width, margin, containerWidth, col, rowHeight), 1849 | gridX = _utils$calGridXY.gridX, 1850 | gridY = _utils$calGridXY.gridY; 1851 | 1852 | if (gridX === shadowCard.gridx && gridY === shadowCard.gridy) { 1853 | return; 1854 | } 1855 | 1856 | var groupIndex = hoverItem.index; 1857 | 1858 | _.forEach(groups, function (g, index) { 1859 | _.remove(g.cards, function (a) { 1860 | return a.isShadow === true; 1861 | }); 1862 | }); 1863 | 1864 | shadowCard = _extends({}, shadowCard, { 1865 | gridx: gridX, 1866 | gridy: gridY 1867 | }); 1868 | groups[groupIndex].cards.push(shadowCard); 1869 | var newlayout = layoutCheck(groups[groupIndex].cards, shadowCard, shadowCard.id, shadowCard.id, _this.props.compactType); 1870 | var compactedLayout; 1871 | 1872 | if (_this.props.compactType === 'horizontal') { 1873 | compactedLayout = compactLayoutHorizontal(newlayout, _this.state.layout.col, shadowCard.id); 1874 | } else if (_this.props.compactType === 'vertical') { 1875 | compactedLayout = compactLayout(newlayout); 1876 | } 1877 | 1878 | groups[groupIndex].cards = compactedLayout; 1879 | 1880 | _this.updateShadowCard(shadowCard); 1881 | 1882 | _this.updateGroupList(groups); 1883 | }; 1884 | 1885 | _this.onCardDropInGroupItem = function (dragItem, dropItem) { 1886 | var groups = _this.state.groups; 1887 | groups = _.cloneDeep(groups); 1888 | utils.setPropertyValueForCards(groups, 'isShadow', false); 1889 | 1890 | _.forEach(groups, function (g, i) { 1891 | if (_this.props.compactType === 'horizontal') { 1892 | var compactedLayout = compactLayoutHorizontal(groups[i].cards, _this.state.layout.col); 1893 | g.cards = compactedLayout; 1894 | } else if (_this.props.compactType === 'vertical') { 1895 | var _compactedLayout = compactLayout(groups[i].cards); 1896 | 1897 | g.cards = _compactedLayout; 1898 | } 1899 | }); 1900 | 1901 | _this.updateGroupList(groups); 1902 | 1903 | _this.updateShadowCard({}); 1904 | }; 1905 | 1906 | _this.updateGroupList = function (groups) { 1907 | _this.setState({ 1908 | groups: groups 1909 | }); 1910 | }; 1911 | 1912 | _this.updateShadowCard = function (shadowCard) { 1913 | _this.setState({ 1914 | shadowCard: shadowCard 1915 | }); 1916 | }; 1917 | 1918 | _this.updateLayout = function (layout) { 1919 | _this.setState({ 1920 | layout: layout 1921 | }); 1922 | 1923 | _this.props.onLayoutChange(layout); 1924 | }; 1925 | 1926 | _this.state = { 1927 | defaultLayout: { 1928 | containerWidth: 1200, 1929 | containerHeight: 300, 1930 | calWidth: 175, 1931 | rowHeight: 175, 1932 | col: 6, 1933 | margin: [10, 10], 1934 | containerPadding: [0, 0] 1935 | }, 1936 | layout: props.layout, 1937 | shadowCard: {}, 1938 | groups: props.groups 1939 | }; 1940 | return _this; 1941 | } 1942 | 1943 | var _proto = MyContent.prototype; 1944 | 1945 | _proto.componentWillUnmount = function componentWillUnmount() { 1946 | window.removeEventListener('resize', this.handleLoad); 1947 | }; 1948 | 1949 | _proto.componentDidMount = function componentDidMount() { 1950 | window.addEventListener('resize', this.handleLoad); 1951 | }; 1952 | 1953 | _proto.initGroupItem = function initGroupItem(groups) { 1954 | var _this2 = this; 1955 | 1956 | console.log(groups, 'groups'); 1957 | var itemDoms = []; 1958 | itemDoms = groups.map(function (g, i) { 1959 | return /*#__PURE__*/React.createElement(Container, { 1960 | key: g.id, 1961 | id: g.id, 1962 | type: g.type, 1963 | index: i, 1964 | cards: g.cards, 1965 | length: groups.length, 1966 | groups: groups, 1967 | moveCardInGroupItem: _this2.moveCardInGroupItem, 1968 | onDrop: _this2.onDrop, 1969 | onCardDropInGroupItem: _this2.onCardDropInGroupItem, 1970 | layout: _this2.state.layout, 1971 | defaultLayout: _this2.state.defaultLayout, 1972 | updateShadowCard: _this2.updateShadowCard, 1973 | updateGroupList: _this2.updateGroupList, 1974 | handleLoad: _this2.handleLoad 1975 | }); 1976 | }); 1977 | return itemDoms; 1978 | }; 1979 | 1980 | _proto.render = function render() { 1981 | var groups = this.state.groups; 1982 | return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(CustomDragLayer, null), this.initGroupItem(groups)); 1983 | }; 1984 | 1985 | return MyContent; 1986 | }(Component); 1987 | 1988 | MyContent.defaultProps = { 1989 | compactType: 'vertical', 1990 | layout: { 1991 | containerWidth: 1200, 1992 | containerHeight: 300, 1993 | calWidth: 175, 1994 | rowHeight: 175, 1995 | col: 6, 1996 | margin: [10, 10], 1997 | containerPadding: [0, 0] 1998 | }, 1999 | onLayoutChange: utils.noop 2000 | }; 2001 | MyContent.propTypes = { 2002 | compactType: propTypes.string, 2003 | layout: propTypes.object, 2004 | onLayoutChange: propTypes.func 2005 | }; 2006 | var layout = DragDropContext(HTML5Backend)(MyContent); 2007 | 2008 | export default layout; 2009 | //# sourceMappingURL=index.modern.js.map 2010 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | ## react-grid-layout-between 2 | This example was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 3 | 4 | It is linked to the react-grid-layout-between package in the parent directory for development purposes. 5 | 6 | You can run `npm install` and then `npm start` to test your package. 7 | 8 | 9 | ## License 10 | 11 | MIT © [SunXinFei](https://github.com/SunXinFei) 12 | 13 | 14 | -------------------------------------------------------------------------------- /example/build/asset-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": { 3 | "main.css": "./static/css/main.4c7e5384.chunk.css", 4 | "main.js": "./static/js/main.f9efcd66.chunk.js", 5 | "main.js.map": "./static/js/main.f9efcd66.chunk.js.map", 6 | "runtime-main.js": "./static/js/runtime-main.3e8c9496.js", 7 | "runtime-main.js.map": "./static/js/runtime-main.3e8c9496.js.map", 8 | "static/js/2.bb6f2584.chunk.js": "./static/js/2.bb6f2584.chunk.js", 9 | "static/js/2.bb6f2584.chunk.js.map": "./static/js/2.bb6f2584.chunk.js.map", 10 | "index.html": "./index.html", 11 | "precache-manifest.ea604c983aa76268e777666df9decb6d.js": "./precache-manifest.ea604c983aa76268e777666df9decb6d.js", 12 | "service-worker.js": "./service-worker.js", 13 | "static/css/main.4c7e5384.chunk.css.map": "./static/css/main.4c7e5384.chunk.css.map", 14 | "static/js/2.bb6f2584.chunk.js.LICENSE.txt": "./static/js/2.bb6f2584.chunk.js.LICENSE.txt", 15 | "static/js/main.f9efcd66.chunk.js.LICENSE.txt": "./static/js/main.f9efcd66.chunk.js.LICENSE.txt" 16 | }, 17 | "entrypoints": [ 18 | "static/js/runtime-main.3e8c9496.js", 19 | "static/js/2.bb6f2584.chunk.js", 20 | "static/css/main.4c7e5384.chunk.css", 21 | "static/js/main.f9efcd66.chunk.js" 22 | ] 23 | } -------------------------------------------------------------------------------- /example/build/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunXinFei/react-grid-layout-between/f21dd8d2cffa85714e17b136b721d9a0dfd13bb6/example/build/favicon.ico -------------------------------------------------------------------------------- /example/build/index.html: -------------------------------------------------------------------------------- 1 | react-grid-layout-between
-------------------------------------------------------------------------------- /example/build/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "react-grid-layout-between", 3 | "name": "react-grid-layout-between", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /example/build/precache-manifest.ea604c983aa76268e777666df9decb6d.js: -------------------------------------------------------------------------------- 1 | self.__precacheManifest = (self.__precacheManifest || []).concat([ 2 | { 3 | "revision": "cdf39dbcac8caceff20b47d0e4b00984", 4 | "url": "./index.html" 5 | }, 6 | { 7 | "revision": "23b0c0f9a80dd72d8d0d", 8 | "url": "./static/css/main.4c7e5384.chunk.css" 9 | }, 10 | { 11 | "revision": "5f89045671eada697a0a", 12 | "url": "./static/js/2.bb6f2584.chunk.js" 13 | }, 14 | { 15 | "revision": "0681588f00131025cfee96b3ab466f09", 16 | "url": "./static/js/2.bb6f2584.chunk.js.LICENSE.txt" 17 | }, 18 | { 19 | "revision": "23b0c0f9a80dd72d8d0d", 20 | "url": "./static/js/main.f9efcd66.chunk.js" 21 | }, 22 | { 23 | "revision": "6fce53c7c7713ebf61712cc2929746fa", 24 | "url": "./static/js/main.f9efcd66.chunk.js.LICENSE.txt" 25 | }, 26 | { 27 | "revision": "137666024723832e4266", 28 | "url": "./static/js/runtime-main.3e8c9496.js" 29 | } 30 | ]); -------------------------------------------------------------------------------- /example/build/service-worker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Welcome to your Workbox-powered service worker! 3 | * 4 | * You'll need to register this file in your web app and you should 5 | * disable HTTP caching for this file too. 6 | * See https://goo.gl/nhQhGp 7 | * 8 | * The rest of the code is auto-generated. Please don't update this file 9 | * directly; instead, make changes to your Workbox build configuration 10 | * and re-run your build process. 11 | * See https://goo.gl/2aRDsh 12 | */ 13 | 14 | importScripts("https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js"); 15 | 16 | importScripts( 17 | "./precache-manifest.ea604c983aa76268e777666df9decb6d.js" 18 | ); 19 | 20 | self.addEventListener('message', (event) => { 21 | if (event.data && event.data.type === 'SKIP_WAITING') { 22 | self.skipWaiting(); 23 | } 24 | }); 25 | 26 | workbox.core.clientsClaim(); 27 | 28 | /** 29 | * The workboxSW.precacheAndRoute() method efficiently caches and responds to 30 | * requests for URLs in the manifest. 31 | * See https://goo.gl/S9QRab 32 | */ 33 | self.__precacheManifest = [].concat(self.__precacheManifest || []); 34 | workbox.precaching.precacheAndRoute(self.__precacheManifest, {}); 35 | 36 | workbox.routing.registerNavigationRoute(workbox.precaching.getCacheKeyForURL("./index.html"), { 37 | 38 | blacklist: [/^\/_/,/\/[^\/?]+\.[^\/]+$/], 39 | }); 40 | -------------------------------------------------------------------------------- /example/build/static/css/main.4c7e5384.chunk.css: -------------------------------------------------------------------------------- 1 | body{margin:0;padding:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","Roboto","Oxygen","Ubuntu","Cantarell","Fira Sans","Droid Sans","Helvetica Neue",sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}code{font-family:source-code-pro,Menlo,Monaco,Consolas,"Courier New",monospace}.rglb_group-item{width:100%;margin-bottom:10px;cursor:move;position:relative;transition:all .2s ease-out}.rglb_group-item .group-item-container{padding:20px}.rglb_group-item .group-item-container #card-container .card-shadow{background:rgba(15,15,15,.3);position:absolute;border-radius:3px;transition:all .2s ease-out}.rglb_group-item .group-item-container #card-container .card{background:#fff;position:absolute;border:1px solid #f1f1f1;border-radius:3px;transition:all .2s ease-out}.rglb_group-item .group-item-container #card-container .card .card-footer{display:flex;justify-content:space-between;position:absolute;height:35px;width:100%;padding:7px 8px;bottom:0;background:#f2f2f2}.rglb_group-item .group-item-container #card-container .card .card-footer .card-delete{font-size:19px;line-height:21px;cursor:pointer}.rglb_custom-layer{position:fixed;pointer-events:none;z-index:100;left:-20px;top:-20px}.rglb_custom-layer .custom-layer-card-list .layer-card{width:135px;height:135px;border:1px solid #ccc;background:#fff;position:absolute;display:flex;align-items:center;justify-content:center}.rglb_custom-layer .custom-layer-card-list .layer-card .layer-card-span{position:absolute;border-radius:50%;width:30px;height:30px;display:inline-block;text-align:center;line-height:30px} 2 | /*# sourceMappingURL=main.4c7e5384.chunk.css.map */ -------------------------------------------------------------------------------- /example/build/static/css/main.4c7e5384.chunk.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["index.css"],"names":[],"mappings":"AAAA,KACE,QAAS,CACT,SAAU,CACV,mJAEY,CACZ,kCAAmC,CACnC,iCACF,CAEA,KACE,yEAEF,CAbA,iBACE,UAAW,CACX,kBAAmB,CACnB,WAAY,CACZ,iBAAkB,CAClB,2BACF,CACA,uCACE,YACF,CACA,oEACE,4BAAiC,CACjC,iBAAkB,CAClB,iBAAkB,CAClB,2BACF,CACA,6DACE,eAAgB,CAChB,iBAAkB,CAClB,wBAAyB,CACzB,iBAAkB,CAClB,2BACF,CACA,0EACE,YAAa,CACb,6BAA8B,CAC9B,iBAAkB,CAClB,WAAY,CACZ,UAAW,CACX,eAAgB,CAChB,QAAS,CACT,kBACF,CACA,uFACE,cAAe,CACf,gBAAiB,CACjB,cACF,CAEA,mBACE,cAAe,CACf,mBAAoB,CACpB,WAAY,CACZ,UAAW,CACX,SACF,CACA,uDACE,WAAY,CACZ,YAAa,CACb,qBAAyB,CACzB,eAAgB,CAChB,iBAAkB,CAClB,YAAa,CACb,kBAAmB,CACnB,sBACF,CACA,wEACE,iBAAkB,CAClB,iBAAkB,CAClB,UAAW,CACX,WAAY,CACZ,oBAAqB,CACrB,iBAAkB,CAClB,gBACF","file":"main.4c7e5384.chunk.css","sourcesContent":[".rglb_group-item {\n width: 100%;\n margin-bottom: 10px;\n cursor: move;\n position: relative;\n transition: all 0.2s ease-out;\n}\n.rglb_group-item .group-item-container {\n padding: 20px;\n}\n.rglb_group-item .group-item-container #card-container .card-shadow {\n background: rgba(15, 15, 15, 0.3);\n position: absolute;\n border-radius: 3px;\n transition: all 0.2s ease-out;\n}\n.rglb_group-item .group-item-container #card-container .card {\n background: #fff;\n position: absolute;\n border: 1px solid #f1f1f1;\n border-radius: 3px;\n transition: all 0.2s ease-out;\n}\n.rglb_group-item .group-item-container #card-container .card .card-footer {\n display: flex;\n justify-content: space-between;\n position: absolute;\n height: 35px;\n width: 100%;\n padding: 7px 8px;\n bottom: 0;\n background: #f2f2f2;\n}\n.rglb_group-item .group-item-container #card-container .card .card-footer .card-delete {\n font-size: 19px;\n line-height: 21px;\n cursor: pointer;\n}\n\n.rglb_custom-layer {\n position: fixed;\n pointer-events: none;\n z-index: 100;\n left: -20px;\n top: -20px;\n}\n.rglb_custom-layer .custom-layer-card-list .layer-card {\n width: 135px;\n height: 135px;\n border: 1px solid #cccccc;\n background: #fff;\n position: absolute;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.rglb_custom-layer .custom-layer-card-list .layer-card .layer-card-span {\n position: absolute;\n border-radius: 50%;\n width: 30px;\n height: 30px;\n display: inline-block;\n text-align: center;\n line-height: 30px;\n}"]} -------------------------------------------------------------------------------- /example/build/static/js/2.bb6f2584.chunk.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /* 2 | object-assign 3 | (c) Sindre Sorhus 4 | @license MIT 5 | */ 6 | 7 | /*! 8 | Mock - 模拟请求 & 模拟数据 9 | https://github.com/nuysoft/Mock 10 | 墨智 mozhi.gyy@taobao.com nuysoft@gmail.com 11 | */ 12 | 13 | /** 14 | * @license 15 | * Lodash 16 | * Copyright OpenJS Foundation and other contributors 17 | * Released under MIT license 18 | * Based on Underscore.js 1.8.3 19 | * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors 20 | */ 21 | 22 | /** @license React v0.19.1 23 | * scheduler.production.min.js 24 | * 25 | * Copyright (c) Facebook, Inc. and its affiliates. 26 | * 27 | * This source code is licensed under the MIT license found in the 28 | * LICENSE file in the root directory of this source tree. 29 | */ 30 | 31 | /** @license React v16.13.1 32 | * react-dom.production.min.js 33 | * 34 | * Copyright (c) Facebook, Inc. and its affiliates. 35 | * 36 | * This source code is licensed under the MIT license found in the 37 | * LICENSE file in the root directory of this source tree. 38 | */ 39 | 40 | /** @license React v16.13.1 41 | * react.production.min.js 42 | * 43 | * Copyright (c) Facebook, Inc. and its affiliates. 44 | * 45 | * This source code is licensed under the MIT license found in the 46 | * LICENSE file in the root directory of this source tree. 47 | */ 48 | -------------------------------------------------------------------------------- /example/build/static/js/main.f9efcd66.chunk.js: -------------------------------------------------------------------------------- 1 | /*! For license information please see main.f9efcd66.chunk.js.LICENSE.txt */ 2 | (this["webpackJsonpreact-grid-layout-between-example"]=this["webpackJsonpreact-grid-layout-between-example"]||[]).push([[0],{182:function(t,e,r){},183:function(t,e,r){"use strict";r.r(e);r(65);var n=r(0),o=r.n(n),a=r(36),i=r.n(a),c=r(21),u=r(37),d=r.n(u),s=r(9),p=r(2),l=r.n(p);function f(){return(f=Object.assign||function(t){for(var e=1;e=e.gridx+e.width)&&(!(t.gridy+t.height<=e.gridy)&&!(t.gridy>=e.gridy+e.height)))},y=function(t,e){for(var r=0,n=t.length;rt[u]&&r[u]r&&(r=e);return r},w=function(t,e,r,n){return t+n>r-1&&(t=r-n),t<0&&(t=0),e<0&&(e=0),{gridX:t,gridY:e}},b={__proto__:null,setPropertyValueForCards:function(t,e,r){l.a.forEach(t,(function(t,n){l.a.forEach(t.cards,(function(t){t[e]=r}))}))},calColWidth:function(t,e,r,n){return n?(t-2*r[0]-n[0]*(e+1))/e:(t-2*r[0]-0*(e+1))/e},calColCount:function(t,e,r,n){if(n)return Math.floor((e-2*r[0]-n[0])/(t+n[0]))},layoutBottom:v,layoutHorizontalRowLength:function(t){for(var e,r=0,n=0,o=t.length;nr&&(r=e);return r},getContainerMaxHeight:function(t,e,r){var n=v(t);return n*e+(n-1)*r[1]+2*r[1]},calGridItemPosition:function(t,e,r,n,o){return{x:Math.round(t*o+r[0]*(t+1)),y:Math.round(e*n+r[1]*(e+1))}},checkInContainer:w,calGridXY:function(t,e,r,n,o,a,i){var c=Math.floor(t/o*a),u=Math.floor(e/(i+(n?n[1]:0)));return w(c,u,a,r)},calWHtoPx:function(t,e,r,n,o){return{wPx:Math.round(t*o+(t-1)*r[0]),hPx:Math.round(e*n+(e-1)*r[1])}},noop:function(){}},x=function(t){return[].concat(t).sort((function(t,e){return t.gridy>e.gridy||t.gridy===e.gridy&&t.gridx>e.gridx?1:t.gridy===e.gridy&&t.gridx===e.gridx?0:-1}))},C=function(t,e){var r=f({},e);if(0===t.length)return f({},r,{gridy:0});for(;;){var n=y(t,r);if(n)return r.gridy=n.gridy+n.height,r;if(r.gridy--,r.gridy<0)return f({},r,{gridy:0})}},S=function(t,e){for(var r=x(t),n=[],o=Array(t.length),a=0,i=r.length;an&&(o.gridx=0,o.gridy++),t(e,o,n)):o},E=function(t,e,r){for(var n,o=x(t),a=[],i=Array(t.length),c=[],u=0;ua&&u>c)return;t.moveGroupItem(o,a),e.getItem().index=a}else if("card"===n.type){var d=t,s=e.getClientOffset(),p=s.x,l=s.y,f=L.findDOMNode(r).getBoundingClientRect(),g=f.left,h=f.top;t.moveCardInGroupItem(n,d,p-g,l-h)}},drop:function(t,e,r){var n=e.getItem(),o=t;"card"===n.type&&t.onCardDropInGroupItem(n,o)}},T=function(t){function e(e){var r;return(r=t.call(this,e)||this).state={},r}g(e,t);var r=e.prototype;return r.componentDidMount=function(){var t,e=document.querySelector("#card-container");e&&(t=e.clientWidth),this.props.layout.containerWidth!==t&&this.props.handleLoad()},r.createCards=function(t,e,r){var n=this,a=[];return l.a.forEach(t,(function(t,i){a.push(o.a.createElement(D,{dragCardID:-1,type:"card",groups:r,card:t,id:t.id,index:i,gridx:t.gridx,gridy:t.gridy,width:t.width,height:t.height,isShadow:t.isShadow,key:e+"_"+t.id,layout:n.props.layout,updateShadowCard:n.props.updateShadowCard,updateGroupList:n.props.updateGroupList}))})),a},r.render=function(){var t=this.props,e=t.connectDropTarget,r=t.isOver,n=t.id,a=t.cards,i=t.defaultLayout,c=t.layout,u=t.groups,d=b.getContainerMaxHeight(a,c.rowHeight,c.margin);return e(o.a.createElement("div",{className:"rglb_group-item"},o.a.createElement("div",{className:"group-item-container",style:{background:r?"rgb(204, 204, 204)":"rgba(79,86,98,.1)"}},o.a.createElement("section",{id:"card-container",style:{height:d>i.containerHeight?d:i.containerHeight}},this.createCards(a,n,u)))))},e}(n.Component);var M=Object(s.DropTarget)("item",P,(function(t,e){return{connectDropTarget:t.dropTarget(),isOver:e.isOver()}}))(T),_=function(t){function e(){return t.apply(this,arguments)||this}return g(e,t),e.prototype.render=function(){for(var t=this.props,e=t.cardListLength,r=t.cardId,n=[],a=0;a=3?3:a;n.push(o.a.createElement("div",{key:a,className:"layer-card",style:{left:5*i+"px",top:5*i+"px"}},o.a.createElement("span",{className:"layer-card-span"},r),o.a.createElement("img",{src:"https://reactjs.org/logo-180x180.png",alt:"logo",width:"107",height:"113"})))}else a<3&&n.push(o.a.createElement("div",{key:a,className:"layer-card",style:{left:5*a+"px",top:5*a+"px"}}));return o.a.createElement("div",{className:"custom-layer-card-list"},n)},e}(n.Component),W=function(t){function e(){for(var e,r=arguments.length,n=new Array(r),o=0;o1.5)},r.render=function(){var t=this.props,e=t.item,r=t.itemType;return t.isDragging&&"card"===e.type?navigator.userAgent.indexOf("MSIE")>-1||navigator.userAgent.indexOf("Trident")>-1||navigator.userAgent.indexOf("Edge")>-1?null:o.a.createElement("div",{className:"rglb_custom-layer"},o.a.createElement("div",{style:this.getItemStyles()},this.renderItem(r,e))):null},e}(n.Component);var G=Object(s.DragLayer)((function(t){return{item:t.getItem(),itemType:t.getItemType(),currentOffset:t.getSourceClientOffset(),clientOffset:t.getClientOffset(),isDragging:t.isDragging()}}))(W);function $(t,e){return t(e={exports:{}},e.exports),e.exports}var k="function"===typeof Symbol&&Symbol.for,H=k?Symbol.for("react.element"):60103,N=k?Symbol.for("react.portal"):60106,z=k?Symbol.for("react.fragment"):60107,F=k?Symbol.for("react.strict_mode"):60108,R=k?Symbol.for("react.profiler"):60114,A=k?Symbol.for("react.provider"):60109,q=k?Symbol.for("react.context"):60110,B=k?Symbol.for("react.async_mode"):60111,V=k?Symbol.for("react.concurrent_mode"):60111,U=k?Symbol.for("react.forward_ref"):60112,X=k?Symbol.for("react.suspense"):60113,Y=k?Symbol.for("react.suspense_list"):60120,J=k?Symbol.for("react.memo"):60115,K=k?Symbol.for("react.lazy"):60116,Q=k?Symbol.for("react.block"):60121,Z=k?Symbol.for("react.fundamental"):60117,tt=k?Symbol.for("react.responder"):60118,et=k?Symbol.for("react.scope"):60119;function rt(t){if("object"===typeof t&&null!==t){var e=t.$$typeof;switch(e){case H:switch(t=t.type){case B:case V:case z:case R:case F:case X:return t;default:switch(t=t&&t.$$typeof){case q:case U:case K:case J:case A:return t;default:return e}}case N:return e}}}function nt(t){return rt(t)===V}var ot={AsyncMode:B,ConcurrentMode:V,ContextConsumer:q,ContextProvider:A,Element:H,ForwardRef:U,Fragment:z,Lazy:K,Memo:J,Portal:N,Profiler:R,StrictMode:F,Suspense:X,isAsyncMode:function(t){return nt(t)||rt(t)===B},isConcurrentMode:nt,isContextConsumer:function(t){return rt(t)===q},isContextProvider:function(t){return rt(t)===A},isElement:function(t){return"object"===typeof t&&null!==t&&t.$$typeof===H},isForwardRef:function(t){return rt(t)===U},isFragment:function(t){return rt(t)===z},isLazy:function(t){return rt(t)===K},isMemo:function(t){return rt(t)===J},isPortal:function(t){return rt(t)===N},isProfiler:function(t){return rt(t)===R},isStrictMode:function(t){return rt(t)===F},isSuspense:function(t){return rt(t)===X},isValidElementType:function(t){return"string"===typeof t||"function"===typeof t||t===z||t===V||t===R||t===F||t===X||t===Y||"object"===typeof t&&null!==t&&(t.$$typeof===K||t.$$typeof===J||t.$$typeof===A||t.$$typeof===q||t.$$typeof===U||t.$$typeof===Z||t.$$typeof===tt||t.$$typeof===et||t.$$typeof===Q)},typeOf:rt},at=($((function(t,e){0})),$((function(t){t.exports=ot})),Object.getOwnPropertySymbols),it=Object.prototype.hasOwnProperty,ct=Object.prototype.propertyIsEnumerable;function ut(t){if(null===t||void 0===t)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(t)}(function(){try{if(!Object.assign)return!1;var t=new String("abc");if(t[5]="de","5"===Object.getOwnPropertyNames(t)[0])return!1;for(var e={},r=0;r<10;r++)e["_"+String.fromCharCode(r)]=r;if("0123456789"!==Object.getOwnPropertyNames(e).map((function(t){return e[t]})).join(""))return!1;var n={};return"abcdefghijklmnopqrst".split("").forEach((function(t){n[t]=t})),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},n)).join("")}catch(o){return!1}})()&&Object.assign;var dt="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED";function st(t,e,r,n,o){}st.resetWarningCache=function(){0};Function.call.bind(Object.prototype.hasOwnProperty);function pt(){}function lt(){}lt.resetWarningCache=pt;var ft=$((function(t){t.exports=function(){function t(t,e,r,n,o,a){if(a!==dt){var i=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw i.name="Invariant Violation",i}}function e(){return t}t.isRequired=t;var r={array:t,bool:t,func:t,number:t,object:t,string:t,symbol:t,any:t,arrayOf:e,element:t,elementType:t,instanceOf:e,node:t,objectOf:e,oneOf:e,oneOfType:e,shape:e,exact:e,checkPropTypes:lt,resetWarningCache:pt};return r.PropTypes=r,r}()})),gt=!1,ht=function(t){function e(e){var r;return(r=t.call(this,e)||this).handleLoad=function(){gt||(gt=!0,setTimeout((function(){var t;console.info("resize!"),gt=!1;var e=document.querySelector("#card-container");if(e)t=e.clientWidth;else{var n=document.querySelector("#first-add");if(!n)return;t=n.clientWidth-10}var o=r.state.defaultLayout.calWidth,a=r.state.layout,i=a.containerPadding,c=a.margin,u=l.a.cloneDeep(r.state.layout),d=window.innerWidth-120,s=b.calColCount(o,d,i,c),p=b.calColWidth(t,s,i,c),f=r.state.groups;f=l.a.cloneDeep(f),l.a.forEach(f,(function(t){var e=E(t.cards,s);t.cards=e})),u.calWidth=u.rowHeight=p,u.col=s,u.containerWidth=t,r.updateGroupList(f),r.updateLayout(u)}),500))},r.moveCardInGroupItem=function(t,e,n,o){var a=r.state.groups,i=r.state.shadowCard,c=r.state.layout,u=c.margin,d=c.containerWidth,s=c.col,p=c.rowHeight,g=b.calGridXY(n,o,i.width,u,d,s,p),h=g.gridX,y=g.gridY;if(h!==i.gridx||y!==i.gridy){var v=e.index;l.a.forEach(a,(function(t,e){l.a.remove(t.cards,(function(t){return!0===t.isShadow}))})),i=f({},i,{gridx:h,gridy:y}),a[v].cards.push(i);var w,x=m(a[v].cards,i,i.id,i.id,r.props.compactType);"horizontal"===r.props.compactType?w=E(x,r.state.layout.col,i.id):"vertical"===r.props.compactType&&(w=S(x)),a[v].cards=w,r.updateShadowCard(i),r.updateGroupList(a)}},r.onCardDropInGroupItem=function(t,e){var n=r.state.groups;n=l.a.cloneDeep(n),b.setPropertyValueForCards(n,"isShadow",!1),l.a.forEach(n,(function(t,e){if("horizontal"===r.props.compactType){var o=E(n[e].cards,r.state.layout.col);t.cards=o}else if("vertical"===r.props.compactType){var a=S(n[e].cards);t.cards=a}})),r.updateGroupList(n),r.updateShadowCard({})},r.updateGroupList=function(t){r.setState({groups:t})},r.updateShadowCard=function(t){r.setState({shadowCard:t})},r.updateLayout=function(t){r.setState({layout:t}),r.props.onLayoutChange(t)},r.state={defaultLayout:{containerWidth:1200,containerHeight:300,calWidth:175,rowHeight:175,col:6,margin:[10,10],containerPadding:[0,0]},layout:e.layout,shadowCard:{},groups:e.groups},r}g(e,t);var r=e.prototype;return r.componentWillUnmount=function(){window.removeEventListener("resize",this.handleLoad)},r.componentDidMount=function(){window.addEventListener("resize",this.handleLoad)},r.initGroupItem=function(t){var e=this;console.log(t,"groups");return t.map((function(r,n){return o.a.createElement(M,{key:r.id,id:r.id,type:r.type,index:n,cards:r.cards,length:t.length,groups:t,moveCardInGroupItem:e.moveCardInGroupItem,onDrop:e.onDrop,onCardDropInGroupItem:e.onCardDropInGroupItem,layout:e.state.layout,defaultLayout:e.state.defaultLayout,updateShadowCard:e.updateShadowCard,updateGroupList:e.updateGroupList,handleLoad:e.handleLoad})}))},r.render=function(){var t=this.state.groups;return o.a.createElement("div",null,o.a.createElement(G,null),this.initGroupItem(t))},e}(n.Component);ht.defaultProps={compactType:"vertical",layout:{containerWidth:1200,containerHeight:300,calWidth:175,rowHeight:175,col:6,margin:[10,10],containerPadding:[0,0]},onLayoutChange:b.noop},ht.propTypes={compactType:ft.string,layout:ft.object,onLayoutChange:ft.func};var yt=Object(s.DragDropContext)(d.a)(ht),mt=(r(182),r(39)),vt=r(38),wt=r.n(vt),bt=[Object(mt.a)({id:0,type:"group"},wt.a.mock({"cards|15":[{"id|+1":0,gridx:0,gridy:0,"width|1-2":1,"height|1-2":1,type:"card",isShadow:!1}]})),Object(mt.a)({id:1,type:"group"},wt.a.mock({"cards|20":[{"id|+1":100,gridx:0,gridy:0,"width|1-2":1,"height|1-2":1,type:"card",isShadow:!1}]}))],xt=function(){var t=Object(n.useState)("horizontal"),e=Object(c.a)(t,2),r=e[0],a=e[1],i=Object(n.useState)({containerWidth:1200,containerHeight:300,calWidth:175,rowHeight:175,col:6,margin:[10,10],containerPadding:[0,0]}),u=Object(c.a)(i,1)[0],d=Object(n.useState)(u.col),s=Object(c.a)(d,2),p=s[0],l=s[1];return o.a.createElement("div",null,o.a.createElement("div",{style:{margin:"10px"}},o.a.createElement("a",{target:"_blank",href:"https://github.com/SunXinFei/react-grid-layout-between"},"View project on GitHub")),o.a.createElement("div",{style:{margin:"10px 10px 0"}},"Current Breakpoint: ",p," columns "),o.a.createElement("button",{style:{height:"30px",margin:"10px"},onClick:function(){a("horizontal"===r?"vertical":"horizontal")}},"Change Compaction Type: ",o.a.createElement("b",null,r)),o.a.createElement(yt,{groups:bt,compactType:r,layout:u,onLayoutChange:function(t){l(t.col)}}))};i.a.render(o.a.createElement(xt,null),document.getElementById("root"))},64:function(t,e,r){t.exports=r(183)},65:function(t,e,r){}},[[64,1,2]]]); 3 | //# sourceMappingURL=main.f9efcd66.chunk.js.map -------------------------------------------------------------------------------- /example/build/static/js/main.f9efcd66.chunk.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /** @license React v16.13.1 2 | * react-is.production.min.js 3 | * 4 | * Copyright (c) Facebook, Inc. and its affiliates. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE file in the root directory of this source tree. 8 | */ 9 | -------------------------------------------------------------------------------- /example/build/static/js/runtime-main.3e8c9496.js: -------------------------------------------------------------------------------- 1 | !function(e){function t(t){for(var n,l,a=t[0],i=t[1],p=t[2],c=0,s=[];c0.2%", 27 | "not dead", 28 | "not ie <= 11", 29 | "not op_mini all" 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /example/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunXinFei/react-grid-layout-between/f21dd8d2cffa85714e17b136b721d9a0dfd13bb6/example/public/favicon.ico -------------------------------------------------------------------------------- /example/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 12 | 16 | 17 | 18 | 27 | react-grid-layout-between 28 | 29 | 30 | 31 | 34 |
35 | 36 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /example/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "react-grid-layout-between", 3 | "name": "react-grid-layout-between", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /example/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | 3 | import GridLayout from 'react-grid-layout-between' 4 | import 'react-grid-layout-between/dist/index.css' 5 | import mockData from './mock' 6 | 7 | const App = () => { 8 | const [compactType, setCompactType] = useState('horizontal'); 9 | const [layout] = useState({ 10 | containerWidth: 1200, 11 | containerHeight: 300, 12 | calWidth: 175, 13 | rowHeight: 175, 14 | col: 6, 15 | margin: [10, 10], 16 | containerPadding: [0, 0] 17 | }); 18 | const [col, setCol] = useState(layout.col); 19 | 20 | const changeCompactType = () => { 21 | setCompactType(compactType === "horizontal" 22 | ? "vertical" 23 | : "horizontal") 24 | } 25 | 26 | const onLayoutChange = (layout) =>{ 27 | setCol(layout.col) 28 | } 29 | return ( 30 |
31 | 34 |
Current Breakpoint: {col} columns
35 | 36 | 37 |
38 | ) 39 | } 40 | 41 | export default App 42 | -------------------------------------------------------------------------------- /example/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import App from './App' 4 | it('renders without crashing', () => { 5 | const div = document.createElement('div') 6 | ReactDOM.render(, div) 7 | ReactDOM.unmountComponentAtNode(div) 8 | }) 9 | -------------------------------------------------------------------------------- /example/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 5 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 6 | sans-serif; 7 | -webkit-font-smoothing: antialiased; 8 | -moz-osx-font-smoothing: grayscale; 9 | } 10 | 11 | code { 12 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 13 | monospace; 14 | } 15 | -------------------------------------------------------------------------------- /example/src/index.js: -------------------------------------------------------------------------------- 1 | import './index.css' 2 | 3 | import React from 'react' 4 | import ReactDOM from 'react-dom' 5 | import App from './App' 6 | 7 | ReactDOM.render(, document.getElementById('root')) 8 | -------------------------------------------------------------------------------- /example/src/mock/index.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs'; 2 | export default [ 3 | { 4 | id: 0, 5 | type: 'group', 6 | ...(() => 7 | Mock.mock({ 8 | 'cards|15': [ 9 | { 10 | 'id|+1': 0, 11 | gridx: 0, 12 | gridy: 0, 13 | 'width|1-2': 1, 14 | 'height|1-2': 1, 15 | type: 'card', 16 | isShadow: false 17 | }, 18 | ], 19 | }))(), 20 | }, 21 | { 22 | id: 1, 23 | type: 'group', 24 | ...(() => 25 | Mock.mock({ 26 | 'cards|20': [ 27 | { 28 | 'id|+1': 100, 29 | gridx: 0, 30 | gridy: 0, 31 | 'width|1-2': 1, 32 | 'height|1-2': 1, 33 | type: 'card', 34 | isShadow: false 35 | }, 36 | ], 37 | }))(), 38 | } 39 | ] -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-grid-layout-between", 3 | "version": "1.0.0", 4 | "description": "A draggable grid layout , can between two or more Layouts, for React.", 5 | "author": "SunXinFei", 6 | "license": "MIT", 7 | "repository": "SunXinFei/react-grid-layout-between", 8 | "main": "dist/index.js", 9 | "module": "dist/index.modern.js", 10 | "source": "src/components/layout.jsx", 11 | "engines": { 12 | "node": ">=10" 13 | }, 14 | "scripts": { 15 | "build": "microbundle-crl --no-compress --format modern,cjs --css-modules false", 16 | "start": "microbundle-crl watch --no-compress --format modern,cjs --css-modules false", 17 | "prepare": "run-s build", 18 | "test": "run-s test:unit test:lint test:build", 19 | "test:build": "run-s build", 20 | "test:lint": "eslint . --fix", 21 | "test:unit": "cross-env CI=1 react-scripts test --env=jsdom", 22 | "test:watch": "react-scripts test --env=jsdom", 23 | "predeploy": "cd example && npm install && npm run build", 24 | "deploy": "gh-pages -d example/build" 25 | }, 26 | "peerDependencies": { 27 | "react": "^16.0.0" 28 | }, 29 | "devDependencies": { 30 | "microbundle-crl": "^0.13.10", 31 | "babel-eslint": "^10.0.3", 32 | "cross-env": "^7.0.2", 33 | "eslint": "^6.8.0", 34 | "eslint-config-prettier": "^6.7.0", 35 | "eslint-config-standard": "^14.1.0", 36 | "eslint-config-standard-react": "^9.2.0", 37 | "eslint-plugin-import": "^2.18.2", 38 | "eslint-plugin-node": "^11.0.0", 39 | "eslint-plugin-prettier": "^3.1.1", 40 | "eslint-plugin-promise": "^4.2.1", 41 | "eslint-plugin-react": "^7.17.0", 42 | "eslint-plugin-standard": "^4.0.1", 43 | "gh-pages": "^2.2.0", 44 | "npm-run-all": "^4.1.5", 45 | "prettier": "^2.0.4", 46 | "react": "^16.13.1", 47 | "react-dom": "^16.13.1", 48 | "react-scripts": "^3.4.1" 49 | }, 50 | "files": [ 51 | "dist" 52 | ], 53 | "dependencies": { 54 | "lodash": "^4.17.20", 55 | "react-dnd": "^2.6.0", 56 | "react-dnd-html5-backend": "^2.6.0" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "jest": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/components/card.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { DragSource } from 'react-dnd'; 3 | import { getEmptyImage } from 'react-dnd-html5-backend'; 4 | import utils from '../utils'; 5 | import _ from 'lodash'; 6 | 7 | const noteSource = { 8 | //开始拖拽,设置isShadow属性,shadowCard对象,更新groups 9 | beginDrag(props, monitor, component) { 10 | let dragCard = props.card; 11 | 12 | dragCard.isShadow = true; 13 | props.updateShadowCard(dragCard); 14 | 15 | return { id: props.id, type: props.type }; 16 | }, 17 | //结束拖拽,设置isShadow属性,shadowCard对象,更新groups 18 | endDrag(props, monitor, component) { 19 | //判断是否正常走了drop事件 20 | if (!monitor.didDrop()) { 21 | let { groups } = props; 22 | groups = _.cloneDeep(groups); 23 | utils.setPropertyValueForCards(groups, 'isShadow', false); 24 | props.updateShadowCard({}); 25 | props.updateGroupList(groups); 26 | } 27 | } 28 | }; 29 | class Item extends Component { 30 | //依靠前后props中shadowCard状态(前为空对象,后为有对象)来判断是否为beginDrag状态,来阻止dom刷新 31 | shouldComponentUpdate(nextProps, nextState) { 32 | //全等判断值为false,使用isEqual判断 33 | if (!_.isEqual(this.props.layout, nextProps.layout)) { 34 | return true; 35 | } 36 | if (this.props.gridx !== nextProps.gridx || this.props.gridy !== nextProps.gridy) { 37 | return true; 38 | } 39 | if (this.props.isShadow !== nextProps.isShadow) { 40 | return true; 41 | } 42 | return false; 43 | } 44 | componentDidMount() { 45 | // Use empty image as a drag preview so browsers don't draw it 46 | // and we can draw whatever we want on the custom drag layer instead. 47 | this.props.connectDragPreview(getEmptyImage(), { 48 | // IE fallback: specify that we'd rather screenshot the node 49 | // when it already knows it's being dragged so we can hide it with CSS. 50 | captureDraggingState: true 51 | }); 52 | } 53 | render() { 54 | const { connectDragSource, gridx, gridy, width, height, isShadow, id } = this.props; 55 | const { margin, rowHeight, calWidth } = this.props.layout; 56 | const { x, y } = utils.calGridItemPosition(gridx, gridy, margin, rowHeight, calWidth); 57 | const { wPx, hPx } = utils.calWHtoPx(width, height, margin, rowHeight, calWidth); 58 | let cardDom; 59 | //是否为拖拽中的阴影卡片 60 | if (isShadow) { 61 | cardDom = (
70 |
71 | ) 72 | } else { 73 | cardDom = ( 74 |
83 | {id} 84 |
85 | ); 86 | } 87 | return connectDragSource(cardDom); 88 | } 89 | } 90 | function collectSource(connect, monitor) { 91 | return { 92 | // Call this function inside render() 93 | // to let React DnD handle the drag events: 94 | connectDragSource: connect.dragSource(), 95 | connectDragPreview: connect.dragPreview(), 96 | // You can ask the monitor about the current drag state: 97 | isDragging: monitor.isDragging() 98 | }; 99 | } 100 | const dragDropItem = DragSource('item', noteSource, collectSource)(Item); 101 | export default dragDropItem; 102 | -------------------------------------------------------------------------------- /src/components/cardListDragPreview.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | //拖拽预览组件类 3 | export default class CardListDragPreview extends Component { 4 | render() { 5 | const { cardListLength, cardId } = this.props; 6 | let divDom = []; 7 | for (let index = 0; index < cardListLength; index++) { 8 | //第一个显示layer的dom,需要显示图片 9 | if (index === cardListLength - 1) { 10 | const myIndex = index >= 3 ? 3 : index; 11 | divDom.push( 12 |
17 | {cardId} 18 | logo 24 |
25 | ); 26 | } else if (index < 3) {//layer的dom最多显示四个 27 | divDom.push( 28 |
29 | ); 30 | } 31 | } 32 | return
{divDom}
; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/components/dragLayer.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { DragLayer } from 'react-dnd'; 3 | import CardListDragPreview from './cardListDragPreview'; 4 | 5 | //拖拽的layer组件类 6 | class CumDragLayer extends Component { 7 | //如果是item类型,返回preview组件 8 | renderItem(type, item) { 9 | switch (type) { 10 | case 'item': 11 | return ; 12 | default: 13 | return null; 14 | } 15 | } 16 | 17 | getItemStyles = () => { 18 | const { clientOffset } = this.props; 19 | 20 | if (!clientOffset) { 21 | return { 22 | display: 'none' 23 | }; 24 | } 25 | let { x, y } = clientOffset; 26 | const transform = `translate(${x}px, ${y}px)`; 27 | return { 28 | transform, 29 | WebkitTransform: transform 30 | }; 31 | }; 32 | 33 | shouldComponentUpdate(nextProps, nextState) { 34 | if (this.props.item?.type === 'card' && this.props.isDragging !== nextProps.isDragging) { 35 | return true; 36 | } 37 | if (this.props.item?.type === 'card' && 38 | this.props.currentOffset !== nextProps.currentOffset 39 | ) { 40 | //如果两次移动的直线距离大于1.5px 41 | if ( 42 | nextProps.currentOffset && 43 | Math.pow( 44 | Math.pow(this.props.clientOffset.x - nextProps.clientOffset.x, 2) + 45 | Math.pow(this.props.clientOffset.y - nextProps.clientOffset.y, 2), 46 | 0.5 47 | ) > 1.5 48 | ) { 49 | return true; 50 | } 51 | } 52 | return false; 53 | } 54 | render() { 55 | const { item, itemType, isDragging } = this.props; 56 | if (!isDragging || item.type !== 'card') { 57 | return null; 58 | } 59 | //IE浏览器去掉拖拽预览 60 | if (navigator.userAgent.indexOf('MSIE') > -1 || 61 | navigator.userAgent.indexOf('Trident') > -1 || 62 | navigator.userAgent.indexOf('Edge') > -1) { 63 | return null; 64 | } 65 | return ( 66 |
67 |
{this.renderItem(itemType, item)}
68 |
69 | ); 70 | } 71 | } 72 | 73 | function collect(monitor) { 74 | return { 75 | item: monitor.getItem(), 76 | itemType: monitor.getItemType(), 77 | currentOffset: monitor.getSourceClientOffset(), 78 | clientOffset: monitor.getClientOffset(), 79 | isDragging: monitor.isDragging() 80 | } 81 | } 82 | 83 | export default DragLayer(collect)(CumDragLayer); 84 | -------------------------------------------------------------------------------- /src/components/groupItem.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | // drag && drop 3 | import { DropTarget } from 'react-dnd'; 4 | const ReactDOM = require('react-dom'); 5 | import Card from './card'; 6 | import utils from '../utils'; 7 | import _ from 'lodash'; 8 | 9 | const groupItemTarget = { 10 | hover(props, monitor, component) { 11 | const dragItem = monitor.getItem(); 12 | if (dragItem.type === 'group') { 13 | //组hover到组 14 | const dragIndex = monitor.getItem().index; 15 | const hoverIndex = props.index; 16 | 17 | if (dragIndex === hoverIndex) { 18 | return; 19 | } 20 | 21 | const hoverBoundingRect = ReactDOM.findDOMNode(component).getBoundingClientRect(); 22 | 23 | const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2; 24 | 25 | const clientOffset = monitor.getClientOffset(); 26 | 27 | const hoverClientY = clientOffset.y - hoverBoundingRect.top; 28 | 29 | if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) { 30 | return; 31 | } 32 | 33 | if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) { 34 | return; 35 | } 36 | 37 | props.moveGroupItem(dragIndex, hoverIndex); 38 | 39 | monitor.getItem().index = hoverIndex; 40 | } else if (dragItem.type === 'card') { 41 | //卡片到组 42 | const hoverItem = props; 43 | const { x, y } = monitor.getClientOffset(); 44 | const groupItemBoundingRect = ReactDOM.findDOMNode(component).getBoundingClientRect(); 45 | const groupItemX = groupItemBoundingRect.left; 46 | const groupItemY = groupItemBoundingRect.top; 47 | props.moveCardInGroupItem(dragItem, hoverItem, x - groupItemX, y - groupItemY); 48 | } 49 | }, 50 | drop(props, monitor, component) { 51 | const dragItem = monitor.getItem(); 52 | const dropItem = props; 53 | if (dragItem.type === 'card') {//释放的分组内的卡片 54 | props.onCardDropInGroupItem(dragItem, dropItem); 55 | } 56 | } 57 | }; 58 | 59 | class Demo extends Component { 60 | constructor(props) { 61 | super(props); 62 | this.state = {}; 63 | } 64 | componentDidMount() { 65 | let clientWidth; 66 | const containerDom = document.querySelector('#card-container'); 67 | if (containerDom) { 68 | clientWidth = containerDom.clientWidth; 69 | } 70 | if (this.props.layout.containerWidth !== clientWidth) { 71 | this.props.handleLoad(); 72 | } 73 | } 74 | //创建卡片 75 | createCards(cards, groupID, groups) { 76 | let itemDoms = []; 77 | _.forEach(cards, (c, i) => { 78 | itemDoms.push( 79 | 96 | ); 97 | }); 98 | return itemDoms; 99 | } 100 | 101 | render() { 102 | const { 103 | connectDropTarget, 104 | isOver, 105 | id, 106 | cards, 107 | defaultLayout, 108 | layout, 109 | groups 110 | } = this.props; 111 | const containerHeight = utils.getContainerMaxHeight(cards, layout.rowHeight, layout.margin); 112 | return connectDropTarget( 113 |
114 |
118 |
defaultLayout.containerHeight 123 | ? containerHeight 124 | : defaultLayout.containerHeight 125 | }} 126 | > 127 | {this.createCards(cards, id, groups)} 128 |
129 |
130 |
131 | ); 132 | } 133 | } 134 | function collectTarget(connect, monitor) { 135 | return { 136 | connectDropTarget: connect.dropTarget(), 137 | isOver: monitor.isOver() 138 | } 139 | } 140 | const Container = DropTarget('item', groupItemTarget, collectTarget)(Demo); 141 | export default Container; 142 | -------------------------------------------------------------------------------- /src/components/layout.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import HTML5Backend from 'react-dnd-html5-backend'; 3 | import { DragDropContext } from 'react-dnd'; 4 | import _ from 'lodash'; 5 | //自定义组件 6 | import { layoutCheck } from '../utils/collision'; 7 | import { compactLayout, compactLayoutHorizontal } from '../utils/compact'; 8 | import utils from '../utils'; 9 | import GroupItem from './groupItem'; 10 | import CustomDragLayer from './dragLayer'; 11 | import PropTypes from 'prop-types' 12 | import styles from '../styles.module.css'; 13 | 14 | let resizeWaiter = false; 15 | 16 | class MyContent extends Component { 17 | constructor(props) { 18 | super(props); 19 | this.state = { 20 | defaultLayout: { 21 | containerWidth: 1200, 22 | containerHeight: 300, 23 | calWidth: 175, 24 | rowHeight: 175, 25 | col: 6, 26 | margin: [10, 10], 27 | containerPadding: [0, 0] 28 | }, 29 | layout: props.layout, 30 | shadowCard: {}, 31 | groups: props.groups 32 | }; 33 | } 34 | componentWillUnmount() { 35 | window.removeEventListener('resize', this.handleLoad); 36 | } 37 | componentDidMount() { 38 | window.addEventListener('resize', this.handleLoad); 39 | } 40 | // 当页面加载完成,获得卡片容器宽度,并自动排列卡片 41 | handleLoad = () => { 42 | if (!resizeWaiter) { 43 | resizeWaiter = true; 44 | setTimeout(() => { 45 | console.info('resize!'); 46 | resizeWaiter = false; 47 | let clientWidth; 48 | const containerDom = document.querySelector('#card-container'); 49 | if (containerDom) { 50 | clientWidth = containerDom.clientWidth; 51 | } else { 52 | const firstAddButton = document.querySelector('#first-add'); 53 | if (firstAddButton) { 54 | clientWidth = firstAddButton.clientWidth - 10; 55 | } else { 56 | return; 57 | } 58 | } 59 | const defaultCalWidth = this.state.defaultLayout.calWidth; 60 | const { containerPadding, margin } = this.state.layout; 61 | let layout = _.cloneDeep(this.state.layout); 62 | const windowWidth = window.innerWidth - 60 * 2; 63 | const col = utils.calColCount(defaultCalWidth, windowWidth, containerPadding, margin); 64 | const calWidth = utils.calColWidth(clientWidth, col, containerPadding, margin); 65 | 66 | let { groups } = this.state; 67 | groups = _.cloneDeep(groups); 68 | _.forEach(groups, (g) => { 69 | let compactedLayout = compactLayoutHorizontal(g.cards, col); 70 | g.cards = compactedLayout; 71 | }); 72 | 73 | layout.calWidth = layout.rowHeight = calWidth; 74 | layout.col = col; 75 | layout.containerWidth = clientWidth; 76 | this.updateGroupList(groups); 77 | this.updateLayout(layout); 78 | }, 500); 79 | } 80 | } 81 | /* 82 | * 关于卡片在组内的操作 83 | */ 84 | /** 85 | * 拖拽中卡片在组上移动 86 | * @param {Object} dragItem 拖拽中的对象 87 | * @param {Object} hoverItem 拖拽中鼠标悬浮的对象 88 | * @param {Number} x 当前元素所在的网页的x轴位置,单位为px 89 | * @param {Number} y 当前元素所在的网页的y轴位置,单位为px 90 | **/ 91 | moveCardInGroupItem = (dragItem, hoverItem, x, y) => { 92 | let groups = this.state.groups; 93 | let shadowCard = this.state.shadowCard; 94 | const { margin, containerWidth, col, rowHeight } = this.state.layout; 95 | //计算当前所在的网格坐标 96 | const { gridX, gridY } = utils.calGridXY(x, y, shadowCard.width, margin, containerWidth, col, rowHeight); 97 | if (gridX === shadowCard.gridx && gridY === shadowCard.gridy) { 98 | return; 99 | } 100 | let groupIndex = hoverItem.index; 101 | //先判断组内是否存在相同的卡片 102 | // const cardid = shadowCard.id; 103 | // const isContain = utils.checkCardContainInGroup(groups[groupIndex], cardid); 104 | // if (isContain) { 105 | // return; 106 | // } 107 | 108 | //删除阴影的卡片 109 | _.forEach(groups, (g, index) => { 110 | _.remove(g.cards, (a) => { 111 | return a.isShadow === true; 112 | }); 113 | }); 114 | 115 | shadowCard = { ...shadowCard, gridx: gridX, gridy: gridY }; 116 | //添加阴影的卡片 117 | groups[groupIndex].cards.push(shadowCard); 118 | //获得当前分组内最新的layout布局 119 | const newlayout = layoutCheck( 120 | groups[groupIndex].cards, 121 | shadowCard, 122 | shadowCard.id, 123 | shadowCard.id, 124 | this.props.compactType 125 | ); 126 | //压缩当前分组内的layout布局 127 | let compactedLayout; 128 | if (this.props.compactType === 'horizontal') { 129 | compactedLayout = compactLayoutHorizontal(newlayout, this.state.layout.col, shadowCard.id); 130 | } else if (this.props.compactType === 'vertical') { 131 | compactedLayout = compactLayout(newlayout, shadowCard); 132 | } 133 | //更新group对象 134 | groups[groupIndex].cards = compactedLayout; 135 | this.updateShadowCard(shadowCard); 136 | this.updateGroupList(groups); 137 | }; 138 | /** 139 | * 释放卡片到分组 140 | * @param {Object} dragItem 拖拽的卡片对象 141 | * @param {Object} dropItem 释放的目标组对象 142 | **/ 143 | onCardDropInGroupItem = (dragItem, dropItem) => { 144 | let { groups } = this.state; 145 | groups = _.cloneDeep(groups); 146 | //将所有分组内的阴影卡片设为非阴影 147 | utils.setPropertyValueForCards(groups, 'isShadow', false); 148 | //目标组内重新横向压缩布局,由于跨组,故须全部压缩 149 | _.forEach(groups, (g, i) => { 150 | if (this.props.compactType === 'horizontal') { 151 | let compactedLayout = compactLayoutHorizontal(groups[i].cards, this.state.layout.col); 152 | g.cards = compactedLayout; 153 | } else if (this.props.compactType === 'vertical') { 154 | let compactedLayout = compactLayout(groups[i].cards); 155 | g.cards = compactedLayout; 156 | } 157 | 158 | }); 159 | this.updateGroupList(groups); 160 | this.updateShadowCard({}); 161 | }; 162 | //初始化组 163 | initGroupItem(groups) { 164 | console.log(groups,'groups') 165 | let itemDoms = []; 166 | itemDoms = groups.map((g, i) => { 167 | return ( 168 | 185 | ); 186 | }); 187 | return itemDoms; 188 | } 189 | //更新分组数据 190 | updateGroupList = (groups) => { 191 | this.setState({ groups }); 192 | } 193 | //更新阴影卡片 194 | updateShadowCard = (shadowCard) => { 195 | this.setState({ shadowCard }); 196 | } 197 | //更新布局 198 | updateLayout = (layout) => { 199 | this.setState({ layout }); 200 | this.props.onLayoutChange(layout); 201 | } 202 | render() { 203 | const { groups } = this.state; 204 | return ( 205 |
206 | 207 | {this.initGroupItem(groups)} 208 |
209 | 210 | ); 211 | } 212 | } 213 | 214 | MyContent.defaultProps = { 215 | compactType: 'vertical',//('vertical' | 'horizontal') 216 | layout: { 217 | containerWidth: 1200, 218 | containerHeight: 300, 219 | calWidth: 175, 220 | rowHeight: 175, 221 | col: 6, 222 | margin: [10, 10], 223 | containerPadding: [0, 0] 224 | }, 225 | onLayoutChange: utils.noop 226 | } 227 | MyContent.propTypes = { 228 | compactType: PropTypes.string, 229 | layout: PropTypes.object, 230 | onLayoutChange: PropTypes.func 231 | } 232 | 233 | export default DragDropContext(HTML5Backend)(MyContent); -------------------------------------------------------------------------------- /src/styles.module.css: -------------------------------------------------------------------------------- 1 | .rglb_group-item { 2 | width: 100%; 3 | margin-bottom: 10px; 4 | cursor: move; 5 | position: relative; 6 | transition: all 0.2s ease-out; 7 | } 8 | .rglb_group-item .group-item-container { 9 | padding: 20px; 10 | } 11 | .rglb_group-item .group-item-container #card-container .card-shadow { 12 | background: rgba(15, 15, 15, 0.3); 13 | position: absolute; 14 | border-radius: 3px; 15 | transition: all 0.2s ease-out; 16 | } 17 | .rglb_group-item .group-item-container #card-container .card { 18 | background: #fff; 19 | position: absolute; 20 | border: 1px solid #f1f1f1; 21 | border-radius: 3px; 22 | transition: all 0.2s ease-out; 23 | } 24 | .rglb_group-item .group-item-container #card-container .card .card-footer { 25 | display: flex; 26 | justify-content: space-between; 27 | position: absolute; 28 | height: 35px; 29 | width: 100%; 30 | padding: 7px 8px; 31 | bottom: 0; 32 | background: #f2f2f2; 33 | } 34 | .rglb_group-item .group-item-container #card-container .card .card-footer .card-delete { 35 | font-size: 19px; 36 | line-height: 21px; 37 | cursor: pointer; 38 | } 39 | 40 | .rglb_custom-layer { 41 | position: fixed; 42 | pointer-events: none; 43 | z-index: 100; 44 | left: -20px; 45 | top: -20px; 46 | } 47 | .rglb_custom-layer .custom-layer-card-list .layer-card { 48 | width: 135px; 49 | height: 135px; 50 | border: 1px solid #cccccc; 51 | background: #fff; 52 | position: absolute; 53 | display: flex; 54 | align-items: center; 55 | justify-content: center; 56 | } 57 | .rglb_custom-layer .custom-layer-card-list .layer-card .layer-card-span { 58 | position: absolute; 59 | border-radius: 50%; 60 | width: 30px; 61 | height: 30px; 62 | display: inline-block; 63 | text-align: center; 64 | line-height: 30px; 65 | } -------------------------------------------------------------------------------- /src/test/case-collision.js: -------------------------------------------------------------------------------- 1 | /** 2 | *碰撞检测方法的测试用例 3 | */ 4 | 5 | /** 6 | * (0,0) 宽2 高1 7 | * (1,0) 宽1 高1 8 | */ 9 | const testData1 = { 10 | test: { 11 | a: { 12 | gridx: 0, 13 | gridy: 0, 14 | width: 2, 15 | height: 1 16 | }, 17 | b: { 18 | gridx: 1, 19 | gridy: 0, 20 | width: 1, 21 | height: 1 22 | } 23 | }, 24 | expect: true 25 | } 26 | /** 27 | * (0,0) 宽1 高1 28 | * (1,0) 宽1 高1 29 | */ 30 | const testData2 = { 31 | test: { 32 | a: { 33 | gridx: 0, 34 | gridy: 0, 35 | width: 1, 36 | height: 1 37 | }, 38 | b: { 39 | gridx: 1, 40 | gridy: 0, 41 | width: 1, 42 | height: 1 43 | } 44 | }, 45 | expect: false 46 | } 47 | /** 48 | * (0,0) 宽1 高2 49 | * (0,1) 宽1 高1 50 | * 碰撞 解决issue:when 2x2 or 1x2 collosion bug for horizontal 51 | */ 52 | const testData3 = { 53 | test: { 54 | a: { 55 | gridx: 0, 56 | gridy: 0, 57 | width: 1, 58 | height: 2 59 | }, 60 | b: { 61 | gridx: 0, 62 | gridy: 1, 63 | width: 1, 64 | height: 1 65 | } 66 | }, 67 | expect: true 68 | } 69 | 70 | export default [testData1, testData2, testData3] 71 | -------------------------------------------------------------------------------- /src/test/index.test.js: -------------------------------------------------------------------------------- 1 | import { collision } from '../utils/collision' 2 | import Cases2Collision from './case-collision' 3 | 4 | test('collision interface', () => { 5 | Cases2Collision.forEach((caseData, i) => { 6 | console.log(`collision${i + 1}`) 7 | const { a, b } = caseData.test 8 | expect(collision(a, b)).toEqual(caseData.expect) 9 | }) 10 | }) 11 | -------------------------------------------------------------------------------- /src/utils/collision.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 碰撞检测 3 | * @param {Object} a 4 | * @param {Object} b 5 | * @returns {Boolean} 是否碰撞 6 | */ 7 | export const collision = (a, b) => { 8 | if ( 9 | a.gridx === b.gridx && 10 | a.gridy === b.gridy && 11 | a.width === b.width && 12 | a.height === b.height 13 | ) { 14 | return true 15 | } 16 | if (a.gridx + a.width <= b.gridx) return false // a处于b的左方 17 | if (a.gridx >= b.gridx + b.width) return false // a处于b的右方 18 | if (a.gridy + a.height <= b.gridy) return false // a处于b的上方 19 | if (a.gridy >= b.gridy + b.height) return false // a处于b的下方 20 | return true 21 | } 22 | /** 23 | * 获取layout中,item第一个碰撞到的物体 24 | * @param {Array} layout 25 | * @param {Object} item 26 | * @returns {Object||null} 被碰撞的item或者null 27 | */ 28 | export const getFirstCollison = (layout, item) => { 29 | for (let i = 0, length = layout.length; i < length; i++) { 30 | if (collision(layout[i], item)) { 31 | return layout[i] 32 | } 33 | } 34 | return null 35 | } 36 | /** 37 | * 布局检测,递归检测移动过的item和其他item有没有碰撞,如果有Y坐标下移/X坐标右移 38 | * @param {Array} layout 39 | * @param {Object} layoutItem 40 | * @param {String} cardID 41 | * @param {String} fristItemID 42 | * @param {String} compactType ('vertical' | 'horizontal') = 'vertical'; 43 | * @returns {Object||null} 被碰撞的item或者null 44 | */ 45 | export const layoutCheck = (function () { 46 | const _layoutCheck = function ( 47 | layout, 48 | layoutItem, 49 | cardID, 50 | fristItemID, 51 | compactType = 'vertical' 52 | ) { 53 | const keyArr = [] 54 | const movedItem = [] 55 | const axis = compactType === 'vertical' ? 'gridy' : 'gridx' 56 | 57 | let newlayout = layout.map((item, index) => { 58 | if (item.id !== cardID) { 59 | if (collision(item, layoutItem)) { 60 | // 碰撞检测,是否有方块和当前卡片有位置碰撞 61 | keyArr.push(item.id) 62 | let offsetXY = item[axis] + 1 63 | // 移动模块位于循环检测方块中 64 | const widthOrHeight = axis === 'gridx' ? item.width : item.height 65 | // 判断当前卡片的坐标和目标卡片加上宽度/高度是否有重叠,防止重叠产生 66 | // 在vertical情况下,是判断类似拖拽(0,1)宽1高1的方块与(0,0)宽1高2的纵向长方形,此时的交叠,纵向长方形保持不动, 67 | // 在horizontal情况下,是判断类似拖拽(1,0)宽1高1的方块与(0,0)宽2高1的横向长方形,此时的交叠,横向长方形保持不动, 68 | if ( 69 | layoutItem[axis] > item[axis] && 70 | layoutItem[axis] < item[axis] + widthOrHeight 71 | ) { 72 | offsetXY = item[axis] 73 | } 74 | const newItem = { ...item } 75 | newItem[axis] = offsetXY 76 | movedItem.push(newItem) 77 | return newItem 78 | } 79 | } else if (fristItemID === cardID) { 80 | return { ...item, ...layoutItem } 81 | } 82 | return item 83 | }) 84 | // 循环所有移动过的卡片,通过碰撞检测影响的相关卡片,全部进行横坐标/纵坐标偏移 85 | for (let c = 0, length = movedItem.length; c < length; c++) { 86 | newlayout = _layoutCheck( 87 | newlayout, 88 | movedItem[c], 89 | keyArr[c], 90 | fristItemID, 91 | compactType 92 | ) 93 | } 94 | 95 | return newlayout 96 | } 97 | return _layoutCheck 98 | })() 99 | -------------------------------------------------------------------------------- /src/utils/compact.js: -------------------------------------------------------------------------------- 1 | import { getFirstCollison } from './collision' 2 | import { layoutBottom } from './utils' 3 | /** 4 | * 布局的item排序,按照gridx由小到大,gridy由小到大 5 | * @param {Array} layout 布局的数组 6 | * @returns {Array} 新的排序后的layout 7 | */ 8 | const sortLayout = (layout) => { 9 | return [].concat(layout).sort((a, b) => { 10 | if (a.gridy > b.gridy || (a.gridy === b.gridy && a.gridx > b.gridx)) { 11 | return 1 12 | } else if (a.gridy === b.gridy && a.gridx === b.gridx) { 13 | return 0 14 | } 15 | return -1 16 | }) 17 | } 18 | /** 19 | * 压缩单个元素,使得每一个元素都会紧挨着边界或者相邻的元素 20 | * @param {Array} finishedLayout 压缩完的元素会放进这里来,用来对比之后的每一个元素是否需要压缩 21 | * @param {Object} item 22 | * @returns {Object} item 返回新的坐标位置的item 23 | */ 24 | const compactItem = (finishedLayout, item) => { 25 | const newItem = { ...item } 26 | if (finishedLayout.length === 0) { 27 | return { ...newItem, gridy: 0 } 28 | } 29 | 30 | while (true) { 31 | const FirstCollison = getFirstCollison(finishedLayout, newItem) 32 | if (FirstCollison) { 33 | newItem.gridy = FirstCollison.gridy + FirstCollison.height 34 | return newItem 35 | } 36 | newItem.gridy-- 37 | if (newItem.gridy < 0) return { ...newItem, gridy: 0 } // 碰到边界,gridy设为0 38 | } 39 | } 40 | /** 41 | * 纵向压缩vertical,使得每一个元素都会紧挨着边界或者相邻的元素 42 | * @param {Array} layout 43 | * @param {Object} movingItem 44 | * @returns {Array} layout 最新layout布局 45 | */ 46 | export const compactLayout = function (layout, movingItem) { 47 | const sorted = sortLayout(layout) 48 | const compareList = [] 49 | const needCompact = Array(layout.length) 50 | 51 | for (let i = 0, length = sorted.length; i < length; i++) { 52 | const finished = compactItem(compareList, sorted[i]) 53 | compareList.push(finished) 54 | needCompact[i] = finished 55 | } 56 | return needCompact 57 | } 58 | /** 59 | * 获取空闲卡片放置区域 60 | * @param {Array} finishedLayout 61 | * @param {Object} item 62 | * @param {Int} cols 63 | * @returns {Object} 卡片放置位置 64 | */ 65 | const getSpaceArea = (finishedLayout, item, cols) => { 66 | const newItem = { ...item } 67 | if (finishedLayout.length === 0) { 68 | return newItem 69 | } 70 | 71 | const FirstCollison = getFirstCollison(finishedLayout, newItem) 72 | if (FirstCollison) { 73 | newItem.gridx++ 74 | if (newItem.gridx + item.width > cols) { 75 | newItem.gridx = 0 76 | newItem.gridy++ 77 | } 78 | return getSpaceArea(finishedLayout, newItem, cols) 79 | } else { 80 | return newItem 81 | } 82 | } 83 | 84 | /** 85 | * horizontal compact Layout Version2.1 86 | * 横向压缩 2.1版本 87 | * 先将卡片按照x和y排序, 88 | * 放置一个卡片,从0,0开始检测是否碰撞或超过边界,如果碰撞,则grix=0,y+1,再次检测是否碰撞 89 | * 需优化的地方:如果移动中的卡片坐标应该一直在一个区域范围内,而不应该任意位置拖拽 90 | * @param {Array} layout 91 | * @param {Int} cols 92 | * @param {Object} movingCardID 移动中的元素id 93 | * @returns {Array} 最新layout布局 94 | */ 95 | export const compactLayoutHorizontal = function (layout, cols, movingCardID) { 96 | const sorted = sortLayout(layout) 97 | const compareList = [] 98 | const needCompact = Array(layout.length) 99 | const arr = [] 100 | let moveCard 101 | // 进行坐标重置,移动中的卡片除外 102 | for (let i = 0; i < sorted.length; i++) { 103 | if (movingCardID === sorted[i].id) { 104 | moveCard = sorted[i] 105 | continue 106 | } 107 | arr.push(sorted[i]) 108 | } 109 | // 获得当前组内的最大的y值,并赋值给移动卡片,防止分组Y值无限变大 110 | if (moveCard) { 111 | moveCard.gridy = Math.min(layoutBottom(arr), moveCard.gridy) 112 | } 113 | // 将非移动的卡片进行坐标重置 114 | for (let i = 0; i < sorted.length; i++) { 115 | if (movingCardID !== sorted[i].id) { 116 | sorted[i].gridy = 0 117 | sorted[i].gridx = 0 118 | } 119 | } 120 | // 进行重新放置,移动中卡片除外 121 | for (let i = 0, length = sorted.length; i < length; i++) { 122 | const finished = getSpaceArea(compareList, sorted[i], cols) 123 | compareList.push(finished) 124 | needCompact[i] = finished 125 | } 126 | return needCompact 127 | } 128 | 129 | /** 130 | * horizontal compact Layout Version2.0 131 | * 横向压缩 2.0版本 132 | * 先将卡片按照x和y排序, 133 | * 放置一个卡片,从0,0开始检测是否碰撞或超过边界,如果碰撞,则grix=0,y+1,再次检测是否碰撞 134 | * @param {Array} layout 135 | * @param {Int} cols 136 | * @returns {layout} 最新layout布局 137 | */ 138 | // export const compactLayoutHorizontal = function(layout, cols) { 139 | // let sorted = sortLayout(layout); 140 | // const compareList = []; 141 | // const needCompact = Array(layout.length); 142 | 143 | // for (let i = 0; i < sorted.length; i++) { 144 | // sorted[i].gridy = 0; 145 | // sorted[i].gridx = 0; 146 | // } 147 | // let rowCount = 0; 148 | // for (let i = 0, length = sorted.length; i < length; i++) { 149 | // let finished = getSpaceArea(compareList, sorted[i], cols); 150 | // compareList.push(finished); 151 | // needCompact[i] = finished; 152 | // } 153 | // return needCompact; 154 | // }; 155 | -------------------------------------------------------------------------------- /src/utils/index.js: -------------------------------------------------------------------------------- 1 | import * as utils from './utils' 2 | 3 | export default utils 4 | -------------------------------------------------------------------------------- /src/utils/utils.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash' 2 | /** 3 | * 以组为单位,设置卡片属性值 4 | * @param {Array} groups 5 | * @param {String} property 6 | * @param {*} value 7 | */ 8 | export const setPropertyValueForCards = (groups, property, value) => { 9 | _.forEach(groups, (g, index) => { 10 | _.forEach(g.cards, (a) => { 11 | a[property] = value 12 | }) 13 | }) 14 | } 15 | 16 | /** 17 | * 已知放置格子数量, 计算容器的每一个格子多大 18 | * @param {Number} containerWidth 19 | * @param {Number} col 20 | * @param {Number} containerPadding 21 | * @param {Number} margin 22 | * @returns {Number} 单元格大小 23 | */ 24 | export const calColWidth = (containerWidth, col, containerPadding, margin) => { 25 | if (margin) { 26 | return ( 27 | (containerWidth - containerPadding[0] * 2 - margin[0] * (col + 1)) / col 28 | ) 29 | } 30 | return (containerWidth - containerPadding[0] * 2 - 0 * (col + 1)) / col 31 | } 32 | 33 | /** 34 | * 已知格子大小,计算容器一行放置格子数量 35 | * @param {Number} defaultCalWidth 36 | * @param {Number} containerWidth 37 | * @param {Number} containerPadding 38 | * @param {Number} margin 39 | * @returns {Number} 每行单元格数量 40 | */ 41 | export const calColCount = ( 42 | defaultCalWidth, 43 | containerWidth, 44 | containerPadding, 45 | margin 46 | ) => { 47 | if (margin) { 48 | return Math.floor( 49 | (containerWidth - containerPadding[0] * 2 - margin[0]) / 50 | (defaultCalWidth + margin[0]) 51 | ) 52 | } 53 | } 54 | 55 | /** 56 | * 获得当前layout中最底单元格的Y坐标 57 | * @param {Array} layout 58 | * @returns {Number} 最底单元格Y坐标 59 | */ 60 | export const layoutBottom = (layout) => { 61 | let max = 0 62 | let bottomY 63 | for (let i = 0, len = layout.length; i < len; i++) { 64 | bottomY = layout[i].gridy + layout[i].height 65 | if (bottomY > max) max = bottomY 66 | } 67 | return max 68 | } 69 | 70 | /** 71 | * 计算横向的长度 72 | * @param {Array} layout 73 | * @returns {Number} 最大长度 74 | */ 75 | export const layoutHorizontalRowLength = (layout) => { 76 | let max = 0 77 | let rowX 78 | for (let i = 0, len = layout.length; i < len; i++) { 79 | rowX = layout[i].gridx + layout[i].width 80 | if (rowX > max) max = rowX 81 | } 82 | return max 83 | } 84 | /** 85 | * 计算卡片容器的最大高度 86 | * @param {Array} cards 87 | * @param {Number} rowHeight 88 | * @param {Number} margin 89 | * @returns {Number} 容器高度 90 | */ 91 | export const getContainerMaxHeight = (cards, rowHeight, margin) => { 92 | const resultRow = layoutBottom(cards) 93 | return resultRow * rowHeight + (resultRow - 1) * margin[1] + 2 * margin[1] 94 | } 95 | 96 | /** 97 | * 给予一个grid的位置,算出元素具体的在容器中位置在哪里,单位是px 98 | * @param {Number} gridx 99 | * @param {Number} gridy 100 | * @param {Number} margin 101 | * @param {Number} rowHeight 102 | * @param {Number} calWidth 103 | * @returns {Object} 包含x,y坐标的对象 104 | */ 105 | export const calGridItemPosition = ( 106 | gridx, 107 | gridy, 108 | margin, 109 | rowHeight, 110 | calWidth 111 | ) => { 112 | const x = Math.round(gridx * calWidth + margin[0] * (gridx + 1)) 113 | const y = Math.round(gridy * rowHeight + margin[1] * (gridy + 1)) 114 | return { 115 | x: x, 116 | y: y 117 | } 118 | } 119 | /** 120 | * 防止元素溢出容器 121 | * @param {Int} gridX 122 | * @param {Int} gridY 123 | * @param {Int} col 124 | * @param {Int} w 卡片宽度 125 | * @returns {Object} gridX,gridY的单元格坐标对象 126 | */ 127 | export const checkInContainer = (gridX, gridY, col, w) => { 128 | if (gridX + w > col - 1) gridX = col - w // 右边界 129 | if (gridX < 0) gridX = 0 // 左边界 130 | if (gridY < 0) gridY = 0 // 上边界 131 | return { gridX, gridY } 132 | } 133 | /** 134 | * 通过坐标x,y像素值计算所在的单元格坐标 135 | * @param {Number} x 136 | * @param {Number} y 137 | * @param {Number} cardWidth 138 | * @param {Number} margin 139 | * @param {Number} containerWidth 140 | * @param {Number} col 141 | * @param {Number} rowHeight 142 | * @returns {Object} 包含gridx和gridy的单元格坐标的对象 143 | */ 144 | export const calGridXY = ( 145 | x, 146 | y, 147 | cardWidth, 148 | margin, 149 | containerWidth, 150 | col, 151 | rowHeight 152 | ) => { 153 | // 坐标转换成格子的时候,向下取整,无须计算margin 154 | const gridX = Math.floor((x / containerWidth) * col) 155 | const gridY = Math.floor(y / (rowHeight + (margin ? margin[1] : 0))) 156 | // 防止卡片溢出容器 157 | return checkInContainer(gridX, gridY, col, cardWidth) 158 | } 159 | 160 | /** 161 | * 宽和高计算成为px 162 | * @param {Number} w 163 | * @param {Number} h 164 | * @param {Number} margin 165 | * @param {Number} rowHeight 166 | * @param {Number} cardWidth 167 | * @returns {Object} 包含wPx, hPx的对象 168 | */ 169 | export const calWHtoPx = (w, h, margin, rowHeight, calWidth) => { 170 | const wPx = Math.round(w * calWidth + (w - 1) * margin[0]) 171 | const hPx = Math.round(h * rowHeight + (h - 1) * margin[1]) 172 | return { wPx, hPx } 173 | } 174 | 175 | export const noop = () => {} 176 | --------------------------------------------------------------------------------