Added logging, changed some directory structure

This commit is contained in:
2018-01-13 21:33:40 -05:00
parent f079a5f067
commit 8e72ffb917
73656 changed files with 35284 additions and 53718 deletions

View File

@@ -0,0 +1,7 @@
{
"presets": [
["es2015", {"loose": true}],
"stage-1",
"react"
]
}

View File

@@ -0,0 +1 @@
node_modules/**/*

View File

@@ -0,0 +1,50 @@
{
"root": true,
"parser": "babel-eslint",
"plugins": [
"react"
],
"extends": "eslint:recommended",
"rules": {
"strict": 0,
"quotes": [0, "single"],
"curly": [1, "multi-line"],
"camelcase": 0,
"comma-dangle": 0,
"dot-notation": 0,
"jsx-quotes": [1, "prefer-double"], // use double quotes in jsx
"no-alert": 2,
"no-console": 2,
"no-debugger": 2,
"no-use-before-define": [1, "nofunc"],
"no-underscore-dangle": 0,
"no-unused-vars": [1, {
"argsIgnorePattern": "^((prev|next)(State|Props)|e|_.*)$",
"vars": "local",
"varsIgnorePattern": "(debug|^_)"
}],
"new-cap": 0,
"prefer-const": 1,
"react/jsx-boolean-value": [1, "always"], // forces `var={true}` instead of `var`
"react/jsx-curly-spacing": [1, "never"], // don't allow `var={ 1 }`
"react/jsx-no-duplicate-props": 1, // prevent <foo name="bar" name="baz" />
"react/jsx-no-undef": 2, // warn when using undefined components (why is this not default?)
"react/jsx-uses-react": 1, // marks `React` as consumed by any jsx el (squelched unused)
"react/jsx-uses-vars": 1, // marks any vars in jsx as used
"react/jsx-wrap-multilines": 1, // require parens around multiline jsx
"semi": [1, "always"]
},
env: {
"browser": true,
"node": true,
"es6": true
},
"ecmaFeatures": {
"jsx": true
},
"globals": {
// For Flow
"$PropertyType",
"$Exact"
}
}

View File

@@ -0,0 +1,22 @@
[version]
0.55.0
[ignore]
.*test
/build
[include]
./lib
index.js
[libs]
interfaces/
[options]
suppress_comment=\\(.\\|\n\\)*\\s*\\$FlowFixMe.*
suppress_comment=\\(.\\|\n\\)*\\s*\\$FlowBug.*
suppress_comment=\\(.\\|\n\\)*\\s*\\$FlowIgnore.*
suppress_comment=\\(.\\|\n\\)*\\s*\\$FlowNewLine.*
suppress_comment=\\(.\\|\n\\)*\\s*\\$FlowIssue
esproposal.class_instance_fields=enable
esproposal.class_static_fields=enable

View File

@@ -0,0 +1,8 @@
language: node_js
node_js:
- "6"
- "7"
script:
- make build test
cache: yarn

View File

@@ -0,0 +1,489 @@
# Changelog
0.15.2 (Sep 5, 2017)
----
- Fix missed `import *`
- Dependency updates
0.15.1 (Sep 5, 2017)
----
- Fix React PropTypes & createClass warnings
- See https://github.com/facebook/react/issues/10583
0.15.0 (Aug 21, 2017)
----
- Package upgrades, including Webpack 3
- Flow typedef upgrades for the 0.53 rework
- Add faulty key value in duplicate key error message (#602)
0.14.7 (Jul 14, 2017)
----
- Fixed a dragging bug when the grid container is scrollable. Thanks @chultquist.
- Ref: https://github.com/STRML/react-grid-layout/pull/555
0.14.6 (Apr 19, 2017)
----
- Fixed a bad publish (connectivity issue).
0.14.5 (Apr 19, 2017)
----
- Moved to `prop-types` package to avoid React.PropTypes deprecation in 15.5. Thanks @inverts!
0.14.4 (Mar 9, 2017)
----
#### Fixes:
- Typecheck in `WidthProvider` to satisfy Flow (and technically, this could be a Text node)
##### Dev:
- Update Flow
0.14.3 (Feb 22, 2017)
----
#### Fixes:
- Reverted #499; `msTransform` is indeed correct. See [discussion](https://github.com/STRML/react-grid-layout/pull/499#issuecomment-281703069).
0.14.2 (Feb 22, 2017)
----
#### Fixes:
- Fixed use of `MSTranform` for IE. Thanks @dvoaviarison (#499)
- Fix generation of source maps, which was temporarily broken by the webpack 2 upgrade.
#### Internal:
- Update development dependencies and babel version.
0.14.1 (Feb 20, 2017)
----
#### Fixes:
- Fixed a minor Flow type issue when a `classnames` typedef is present.
- Fixed a scoping issue when running `make build-example`.
0.14.0 (Feb 13, 2017)
-----
#### Features:
- New test suite - thanks @nikolas
- Dev Dependency updates
- Committed yarn.lock
- Added `react-draggable` classname to draggable grid items.
0.13.9 (Oct 13, 2016)
-----
#### Fixes:
- Fixed sorting of layout items, which could be different in IE if two items have the same x & y coordinate.
- See [#369](https://github.com/STRML/react-grid-layout/issues/369).
0.13.8 (Oct 13, 2016)
-----
#### Fixes:
- Fixed breakage introduced in `0.13.7` when items are added without a layout or `data-grid` property.
- See [#368](https://github.com/STRML/react-grid-layout/issues/368).
0.13.7 (Oct 3, 2016)
-----
#### Fixes:
- Fixed an error during layout sync if children was a keyed fragment or had nested arrays.
- Fixed `onLayoutChange` being called when layout didn't change.
- Fixed some issues with input layout items being modified in-place rather than cloned.
- Minor typos.
0.13.6 (Sep 26, 2016)
-----
#### Fixes:
- Fixed missing HTMLElement in `onResize*` callbacks.
0.13.5 (Sep 9, 2016)
-----
#### Fixes:
- Fixed a few Flow typing errors in `WidthProvider`.
0.13.4 (Sep 9, 2016)
-----
#### Fixes:
- Fixed potential call to `ReactDOM.findDOMNode(this)` after unmount of `WidthProvider`.
- Fixed an issue where layout items using `data-grid` could rearrange on mount depending on how they were ordered.
- See [#342](https://github.com/STRML/react-grid-layout/pull/342) for reference.
0.13.3 (Aug 31, 2016)
-----
#### Fixes:
- Fixed `lodash.isequal` import, which was ruined by case-insensitive HFS+ *shakes fist*
0.13.2 (Aug 31, 2016)
-----
#### Fixes:
- Diffing children in order to regenerate the layout now diffs the `key` props and their order.
- This will catch more changes, such as sorting, addition, and removal.
- Only pass `className` and `style` to WidthProvider. Other props were not intended to be supported.
- I'm aware this could be a breaking change if you were relying on this bad behavior. If so, please
use your own `WidthProvider`-style HOC.
- `babel-plugin-transform-flow-comments` had limited support for defining types like transpiled classes.
- This has been updated to instead copy source to `.js.flow` files, which preserves all type information.
0.13.1 (Aug 16, 2016)
-----
#### Fixes:
- Fix remaining `propTypes` warnings.
0.13.0 (Aug 3, 2016)
-----
#### Changed:
- Due to a change in React 15.2, passing the `_grid` property on DOM children generates an error.
To compensate, we now error on the same and suggest using `data-grid` instead. Simply change any use of
`_grid` to `data-grid`, or add your properties to the layout.
#### Fixes:
- Fix React 15.3 warning re: propTypes.
0.12.7 (Jun 29, 2016)
-----
- Prevent extraenous rerenders in `<ResponsiveReactGridLayout>` by using deep equality on layouts.
0.12.6 (Jun 5, 2016)
-----
- Fix blindingly obvious bug where mounted isn't set to true. Smack forehead.
0.12.5 (Jun 3, 2016)
-----
- Fixes for server rendering checksum failures.
0.12.4 (May 22, 2016)
-----
- Update to React-Draggable v2. Fixes: #241, #239, #24
- v2 contains a number of bugfixes & enhancements for touchscreens, multitouch, and scrolling containers.
0.12.3 (May 3, 2016)
-----
- Bugfix: Rendering with new `breakpoints`/`cols` does not refresh the layout.
Fixes #208 - thanks @damienleroux
0.12.2 (May 1, 2016)
------
- Bugfix: Fix warning about undefined `useCSSTransforms` when server-rendering.
0.12.1 (Apr 19, 2016)
------
- Bugfix: Don't set `layout` twice on width change. See #217 - thanks @damienleroux
- Enhancement: Add Flow type comments
0.12.0 (Apr 14, 2016)
------
- `<ReactGridLayout>` will no longer animate so severely on mount. See #212.
- If you are using `<WidthProvider>`, you may notice that the container's width still shunts on mount.
If you like, you may delay mounting by setting `measureBeforeMount={true}` on the wrapped element. This
will eliminate the mounting animation completely.
- If you enjoyed the old animation, set `useCSSTransforms={this.state.mounted}` and toggle the mounting
flag. See `0-showcase.jsx` for an example.
- Set more permissive version ranges for `<Draggable>` and `<Resizable>` dependencies, as they are now stable
and will only introduce breaking changes on major version ticks.
0.11.3 (Apr 8, 2016)
------
- Officially support React v15.
0.11.2 (Apr 6, 2016)
------
- Bugfix: Draggable cancel selectors, see #203 - thanks @RiiD
- README fixes, thanks @bravo-kernel & @ro-savage
0.11.1
------
- Bugfix: `<ResponsiveReactGridLayout>` was using stale data when synchronizing children with the layout
on a breakpoint change.
0.11.0
------
This release contains potentially breaking changes so I have updated the minor version (as per semver).
**Breaking Changes**:
- Layout items now have a fixed set of properties. Other properties will *not* be merged into the `<GridItem>`, such
as `className`. To set a `className` on a child, set it on the child directly and it will be merged.
This allows us to make better assumptions about the layout and use a faster cloning mechanism.
- Setting individual `handle` and `cancel` selectors per item is no longer supported. If you need this, please
open a ticket and let me know your use case.
Other changes:
- Bugfix: `<ResponsiveReactGridLayout>` `onLayoutChange` callback data could still be stale.
- Bugfix: Range error when building layout solely from `_grid` properties.
- This broke a lot of usage and thus `0.10.11` and `0.10.10` have been unpublished.
- Removed redundant `isPlaceholder` property from `<GridItem>`.
- README updates to clarify layout/_grid usage.
0.10.11
-------
- Bugfix: `layouts` param on `<ResponsiveReactGridLayout>`'s `onLayoutChange` could have stale data
for the current breakpoint.
0.10.10
-------
- Performance: Prevent V8 deopt in a few methods and add fast layout item cloning.
0.10.9
------
- Bugfix: Typo in children comparison in CWRP. See #169.
- Bugfix: Missing babel-preset-es2015 in dev.
0.10.8
------
- Rebuild using [ES2015 Loose Mode](https://babeljs.algolia.com/docs/advanced/loose/).
0.10.7
------
- Bugfix: `className` and `style` props on grid children were being incorrectly dropped, a holdover
from when `cloneWithProps()` used to do this merging for us. They are now merged.
0.10.6
------
- Bugfix: If both `props.layout` and `props.children.length` change in the same tick,
props.layout would be clobbered. See #162
0.10.5
------
- Bugfix/Enhancement: Margins were causing subtle error in some of the positioning calculations. This has
been fixed.
0.10.4
------
- Bugfix: Container height was calculated as less than expected due to improper addition of margin.
0.10.3
------
- Bugfix: Round item positions even if they're currently resizing or dragging (#158, regression of #141)
- Bugfix: Fix a positioning bug when margins are 0 (#160)
0.10.2
------
- Bugfix: <RGL> would synchronize children with layout if the layout in props didn't match the state;
this was meant to be a hook for the developer to supply a new layout. The incorrect check could cause the
layout to reset if the parent rerendered. The check is now between the layout in nextProps and props.
- Bugfix: Fixed a lot of resizing layout bugs; most of the fixes are in react-resizable.
- Bugfix: Fixed incorrect typecheck on LayoutItem.i.
- Bugfix: Make onLayoutChange fire appropriately (#155).
- Bugfix: Fix `<ResponsiveGridLayout>` not properly reverting when sizing the page up (#154).
- Remove unused `offsetX` and `offsetY` from layouts.
- Dependency updates.
0.10.1
------
- Hotfix for default export incompatibility caused by Babel 6.
0.10.0
------
This long-awaited release provides React 0.14 compatibility and a rewrite of the underlying
`<Draggable>` functionality.
**Breaking changes:**
- `ListensToWidth` replaced with `WidthProvider` which must wrap
`<ResponsiveReactGridLayout>` and `<ReactGridLayout>` to provide width data. See doc for example.
- Prop `initialWidth` renamed to `width`.
- Grid Layout keys must be type of string now.
Other changes:
- *Finally* compatible with React 0.14! Big thanks to @menelike for his help.
- Upgraded to Babel 6.
- Full typechecking via Flow.
- Lots of misc bugfixes.
- See beta releases below for more details.
0.10.0-beta1
------------
- Fixed a React import bug on ListensToWidth.jsx (#130; thanks @mrblueblue)
0.10.0-beta0
------------
*This release is unstable!*
- React 0.14 compatibility.
- This release includes a rewrite of much of the project in ES6/7 style with Flow typing.
- This release brings us onto mainline (1.x) react-draggable and react-resizable, eliminating
the previous github dependency.
- 0.10.0 is not yet complete. Use this release at your own risk.
Known bugs:
- The placeholder box does not properly follow the mouse and stays pinned to the active drag.
0.9.2
-----
- Update `react-draggable` to `v0.8.0` to fix IE11 issues (#29).
0.9.1
-----
- Update `react-draggable` to `v0.7.3` to fix a bounds bug (#56).
0.9.0
-----
- Move off `react-draggable` fork to mainline `v0.7.2`. Incremented minor (major in the case of
npm's `^`, since we are pre-v1) version in case of unforeseen conflicts.
0.8.3
-----
- Add `verticalCompact` toggle.
0.8.2
-----
- Fix a crash when initializing with no children.
0.8.1
-----
- Fixed React 0.13 warning about `isMounted()`.
- Update to babel 5.
- Added browser build for use with a `<script>` tag or in RequireJS builds.
- Pinned react-draggable version in anticipation of React 0.13 update.
0.8.0
-----
- Changed signature on resize/drag callbacks to allow dynamic max/min W/H per item.
- Fixed bug in `useCSSTransforms`.
- Documentation and example fixes.
0.7.1
-----
- Added callbacks for resize and drag start/active/stop.
0.7.0
-----
**Breaking changes:**
- `ReactGridLayout.props.handle` renamed to `ReactGridLayout.props.draggableHandle`.
> This version contains a CSS update. This fixes a visual bug where you may see items quickly reset position
and animate back to their original position on load, when you are using CSS transforms. To fix this bug,
copy the rules from css/styles.css into your stylesheet.
Other changes:
- Fixed #19 (bad new item placement with css transforms).
- Fixed some placement inconsistencies while RGL is mounting, with css transforms and percentages.
- Fixed a duplicate className bug.
0.6.2
-----
- Fix #21 (error when passing only a single child).
- Add GridItem.props.cancel.
- Use React addons directly to save file size.
- Allow setting draggable/resizable per grid item, as well as existing `static` property.
- Use object.assign to set `_grid` properties so we can more easily merge PRs in the future.
0.6.1
-----
- Fixed #8 (current layout was not properly being stored when provided via _grid props).
0.6.0
-----
- Optionally use CSS transforms for placement, fallback on position top/left.
- Allow parent to set responsive breakpoint directly.
0.5.2
-----
- Fix Responsive import for node users
0.5.1
-----
- Add support for min/max dimension attributes.
- Example tweak
0.5.0
-----
- Refactoring and demo tweaks. Update README with new params.
- Add showcase example, tweak template
- Refactor: Responsive Grid Layout is a separate element
- Auto-generate examples from template rather than edit them individually.
0.4.0
-----
- Force lodash into commons chunk
- More tweaks to grid collisions. This should fix bad swaps once and for all.
- Set unused:"vars" in lint.
- Add responsive localstorage example and `initialLayouts` support.
- Fix localstorage example comment.
- Rework responsive layouts, identify child elements by key rather than index. Added 2 new examples.
- Fixup GridItem resizing feel a bit.
< 0.4.0
-------
- Early development versions, too many changes to list.

21
goTorrentWebUI/node_modules/react-grid-layout/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 Samuel Reed
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

415
goTorrentWebUI/node_modules/react-grid-layout/README.md generated vendored Normal file
View File

@@ -0,0 +1,415 @@
# React-Grid-Layout
[![travis build](https://travis-ci.org/STRML/react-grid-layout.svg?branch=master)](https://travis-ci.org/STRML/react-grid-layout)
[![npm package](https://img.shields.io/npm/v/react-grid-layout.svg?style=flat-square)](https://www.npmjs.org/package/react-grid-layout)
[![npm downloads](https://img.shields.io/npm/dt/react-grid-layout.svg?maxAge=2592000)]()
React-Grid-Layout is a grid layout system much like [Packery](http://packery.metafizzy.co/) or
[Gridster](http://dsmorse.github.io/gridster.js/), for React.
Unlike those systems, it is responsive and supports breakpoints. Breakpoint layouts can be provided by the user
or autogenerated.
RGL is React-only and does not require jQuery.
![BitMEX UI](http://i.imgur.com/oo1NT6c.gif)
> GIF from production usage on [BitMEX.com](https://www.bitmex.com)
[**[Demo](https://strml.github.io/react-grid-layout/examples/0-showcase.html) | [Changelog](/CHANGELOG.md) | [WebpackBin Editable demo](http://www.webpackbin.com/EJF48h_rz)**]
## Table of Contents
- [Demos](#demos)
- [Features](#features)
- [Installation](#installation)
- [Usage](#usage)
- [Responsive Usage](#responsive-usage)
- [Providing Grid Width](#providing-grid-width)
- [Grid Layout Props](#grid-layout-props)
- [Responsive Grid Layout Props](#responsive-grid-layout-props)
- [Grid Item Props](#grid-item-props)
- [Contribute](#contribute)
- [TODO List](#todo-list)
## Demos
1. [Showcase](https://strml.github.io/react-grid-layout/examples/0-showcase.html)
1. [Basic](https://strml.github.io/react-grid-layout/examples/1-basic.html)
1. [No Dragging/Resizing (Layout Only)](https://strml.github.io/react-grid-layout/examples/2-no-dragging.html)
1. [Messy Layout Autocorrect](https://strml.github.io/react-grid-layout/examples/3-messy.html)
1. [Layout Defined on Children](https://strml.github.io/react-grid-layout/examples/4-grid-property.html)
1. [Static Elements](https://strml.github.io/react-grid-layout/examples/5-static-elements.html)
1. [Adding/Removing Elements](https://strml.github.io/react-grid-layout/examples/6-dynamic-add-remove.html)
1. [Saving Layout to LocalStorage](https://strml.github.io/react-grid-layout/examples/7-localstorage.html)
1. [Saving a Responsive Layout to LocalStorage](https://strml.github.io/react-grid-layout/examples/8-localstorage-responsive.html)
1. [Minimum and Maximum Width/Height](https://strml.github.io/react-grid-layout/examples/9-min-max-wh.html)
1. [Dynamic Minimum and Maximum Width/Height](https://strml.github.io/react-grid-layout/examples/10-dynamic-min-max-wh.html)
1. [No Vertical Compacting (Free Movement)](https://strml.github.io/react-grid-layout/examples/11-no-vertical-compact.html)
#### Projects based on React-Grid-Layout
- [BitMEX](https://www.bitmex.com/)
- [AWS CloudFront Dashboards](https://aws.amazon.com/blogs/aws/cloudwatch-dashboards-create-use-customized-metrics-views/)
- [Metabase](http://www.metabase.com/)
- [HubSpot](http://www.hubspot.com)
- [ComNetViz](http://www.grotto-networking.com/ComNetViz/ComNetViz.html)
- [Stoplight](https://app.stoplight.io)
- [Reflect](https://reflect.io)
- [ez-Dashing](https://github.com/ylacaute/ez-Dashing)
*Know of others? Create a PR to let me know!*
## Features
* 100% React - no jQuery
* Compatible with server-rendered apps
* Draggable widgets
* Resizable widgets
* Static widgets
* Configurable packing: horizontal, vertical, or off
* Bounds checking for dragging and resizing
* Widgets may be added or removed without rebuilding grid
* Layout can be serialized and restored
* Responsive breakpoints
* Separate layouts per responsive breakpoint
* Grid Items placed using CSS Transforms
* Performance: [on](http://i.imgur.com/FTogpLp.jpg) / [off](http://i.imgur.com/gOveMm8.jpg), note paint (green) as % of time
|Version | Compatibility |
|----------------|------------------|
| >= 0.11.3 | React 0.14 & v15 |
| >= 0.10.0 | React 0.14 |
| 0.8. - 0.9.2 | React 0.13 |
| < 0.8 | React 0.12 |
## Installation
Install the React-Grid-Layout [package](https://www.npmjs.org/package/react-grid-layout) package using [npm](https://www.npmjs.com/):
```bash
npm install react-grid-layout
```
Include the following stylesheets in your application:
```
/node_modules/react-grid-layout/css/styles.css
/node_modules/react-resizable/css/styles.css
```
## Usage
Use ReactGridLayout like any other component. The following example below will
produce a grid with three items where:
- users will not be able to drag or resize item `a`
- item `b` will be restricted to a minimum width of 2 grid blocks and a maximum width of 4 grid blocks
- users will be able to freely drag and resize item `c`
```javascript
var ReactGridLayout = require('react-grid-layout');
var MyFirstGrid = React.createClass({
render: function() {
// layout is an array of objects, see the demo for more complete usage
var layout = [
{i: 'a', x: 0, y: 0, w: 1, h: 2, static: true},
{i: 'b', x: 1, y: 0, w: 3, h: 2, minW: 2, maxW: 4},
{i: 'c', x: 4, y: 0, w: 1, h: 2}
];
return (
<ReactGridLayout className="layout" layout={layout} cols={12} rowHeight={30} width={1200}>
<div key="a">a</div>
<div key="b">b</div>
<div key="c">c</div>
</ReactGridLayout>
)
}
});
```
You may also choose to set layout properties directly on the children:
```javascript
var ReactGridLayout = require('react-grid-layout');
var MyFirstGrid = React.createClass({
render: function () {
return (
<ReactGridLayout className="layout" cols={12} rowHeight={30} width={1200}>
<div key="a" data-grid={{x: 0, y: 0, w: 1, h: 2, static: true}}>a</div>
<div key="b" data-grid={{x: 1, y: 0, w: 3, h: 2, minW: 2, maxW: 4}}>b</div>
<div key="c" data-grid={{x: 4, y: 0, w: 1, h: 2}}>c</div>
</ReactGridLayout>
)
}
});
```
### Usage without Browserify/Webpack
A module usable in a `<script>` tag is included [here](/dist/react-grid-layout.min.js). It uses a UMD shim and
excludes `React`, so it must be otherwise available in your application, either via RequireJS or on `window.React`.
### Responsive Usage
To make RGL responsive, use the `<ResponsiveReactGridLayout>` element:
```javascript
var ResponsiveReactGridLayout = require('react-grid-layout').Responsive;
//...
render: function() {
// {lg: layout1, md: layout2, ...}
var layouts = getLayoutsFromSomewhere();
return (
<ResponsiveReactGridLayout className="layout" layouts={layouts}
breakpoints={{lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0}}
cols={{lg: 12, md: 10, sm: 6, xs: 4, xxs: 2}}>
<div key="1">1</div>
<div key="2">2</div>
<div key="3">3</div>
</ResponsiveReactGridLayout>
)
}
```
When in responsive mode, you should supply at least one breakpoint via the `layouts` property.
When using `layouts`, it is best to supply as many breakpoints as possible, especially the largest one.
If the largest is provided, RGL will attempt to interpolate the rest.
You will also need to provide a `width`, when using `<ResponsiveReactGridLayout>` it is suggested you use the HOC
`WidthProvider` as per the instructions below.
For the time being, it is not possible to supply responsive mappings via the `data-grid` property on individual
items, but that is coming soon.
### Providing Grid Width
Both `<ResponsiveReactGridLayout>` and `<ReactGridLayout>` take `width` to calculate
positions on drag events. In simple cases a HOC `WidthProvider` can be used to automatically determine
width upon initialization and window resize events.
```javascript
import {Responsive, WidthProvider} from 'react-grid-layout';
const ResponsiveReactGridLayout = WidthProvider(Responsive);
//...
render() {
// {lg: layout1, md: layout2, ...}
var layouts = getLayoutsFromSomewhere();
return (
<ResponsiveReactGridLayout className="layout" layouts={layouts}
breakpoints={{lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0}}
cols={{lg: 12, md: 10, sm: 6, xs: 4, xxs: 2}}>
<div key="1">1</div>
<div key="2">2</div>
<div key="3">3</div>
</ResponsiveReactGridLayout>
)
}
```
This allows you to easily replace `WidthProvider` with your own Provider HOC if you need more sophisticated logic.
`WidthProvider` accepts a single prop, `measureBeforeMount`. If `true`, `WidthProvider` will measure the
container's width before mounting children. Use this if you'd like to completely eliminate any resizing animation
on application/component mount.
Have a more complicated layout? `WidthProvider` [is very simple](/lib/components/WidthProvider.jsx) and only
listens to window `'resize'` events. If you need more power and flexibility, try the
[SizeMe React HOC](https://github.com/ctrlplusb/react-sizeme) as an alternative to WidthProvider.
### Grid Layout Props
RGL supports the following properties (see the source for the final word on this):
```javascript
//
// Basic props
//
// This allows setting the initial width on the server side.
// This is required unless using the HOC <WidthProvider> or similar
width: number,
// If true, the container height swells and contracts to fit contents
autoSize: ?boolean = true,
// Number of columns in this layout.
cols: ?number = 12,
// A CSS selector for tags that will not be draggable.
// For example: draggableCancel:'.MyNonDraggableAreaClassName'
// If you forget the leading . it will not work.
draggableCancel: ?string = '',
// A CSS selector for tags that will act as the draggable handle.
// For example: draggableHandle:'.MyDragHandleClassName'
// If you forget the leading . it will not work.
draggableHandle: ?string = '',
// If true, the layout will compact vertically
verticalCompact: ?boolean = true,
// Compaction type.
compactType: ?('vertical' | 'horizontal') = 'vertical';
// Layout is an array of object with the format:
// {x: number, y: number, w: number, h: number}
// The index into the layout must match the key used on each item component.
// If you choose to use custom keys, you can specify that key in the layout
// array objects like so:
// {i: string, x: number, y: number, w: number, h: number}
layout: ?array = null, // If not provided, use data-grid props on children
// Margin between items [x, y] in px.
margin: ?[number, number] = [10, 10],
// Padding inside the container [x, y] in px
containerPadding: ?[number, number] = margin,
// Rows have a static height, but you can change this based on breakpoints
// if you like.
rowHeight: ?number = 150,
//
// Flags
//
isDraggable: ?boolean = true,
isResizable: ?boolean = true,
// Uses CSS3 translate() instead of position top/left.
// This makes about 6x faster paint performance
useCSSTransforms: ?boolean = true,
// If true, grid items won't change position when being
// dragged over.
preventCollision: ?boolean = false;
//
// Callbacks
//
// Callback so you can save the layout.
// Calls back with (currentLayout) after every drag or resize stop.
onLayoutChange: (layout: Layout) => void,
//
// All callbacks below have signature (layout, oldItem, newItem, placeholder, e, element).
// 'start' and 'stop' callbacks pass `undefined` for 'placeholder'.
//
type ItemCallback = (layout: Layout, oldItem: LayoutItem, newItem: LayoutItem,
placeholder: LayoutItem, e: MouseEvent, element: HTMLElement) => void;
// Calls when drag starts.
onDragStart: ItemCallback,
// Calls on each drag movement.
onDrag: ItemCallback,
// Calls when drag is complete.
onDragStop: ItemCallback,
// Calls when resize starts.
onResizeStart: ItemCallback,
// Calls when resize movement happens.
onResize: ItemCallback,
// Calls when resize is complete.
onResizeStop: ItemCallback
```
### Responsive Grid Layout Props
The responsive grid layout can be used instead. It supports all of the props above, excepting `layout`.
The new properties and changes are:
```javascript
// {name: pxVal}, e.g. {lg: 1200, md: 996, sm: 768, xs: 480}
// Breakpoint names are arbitrary but must match in the cols and layouts objects.
breakpoints: ?Object = {lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0},
// # of cols. This is a breakpoint -> cols map, e.g. {lg: 12, md: 10, ...}
cols: ?Object = {lg: 12, md: 10, sm: 6, xs: 4, xxs: 2},
// layouts is an object mapping breakpoints to layouts.
// e.g. {lg: Layout, md: Layout, ...}
layouts: {[key: $Keys<breakpoints>]: Layout}
//
// Callbacks
//
// Calls back with breakpoint and new # cols
onBreakpointChange: (newBreakpoint: string, newCols: number) => void,
// Callback so you can save the layout.
// AllLayouts are keyed by breakpoint.
onLayoutChange: (currentLayout: Layout, allLayouts: {[key: $Keys<breakpoints>]: Layout}) => void,
// Callback when the width changes, so you can modify the layout as needed.
onWidthChange: (containerWidth: number, margin: [number, number], cols: number, containerPadding: [number, number]) => void;
```
### Grid Item Props
RGL supports the following properties on grid items or layout items. When initializing a grid,
build a layout array (as in the first example above), or attach this object as the `data-grid` property
to each of your child elements (as in the second example).
Note that if a grid item is provided but incomplete (missing one of `x, y, w, or h`), an error
will be thrown so you can correct your layout.
If no properties are provided for a grid item, one will be generated with a width and height of `1`.
You can set minimums and maximums for each dimension. This is for resizing; it of course has no effect if resizing
is disabled. Errors will be thrown if your mins and maxes overlap incorrectly, or your initial dimensions
are out of range.
Any `<GridItem>` properties defined directly will take precedence over globally-set options. For
example, if the layout has the property `isDraggable: false`, but the grid item has the prop `isDraggable: true`, the item
will be draggable.
```javascript
{
// A string corresponding to the component key
i: string,
// These are all in grid units, not pixels
x: number,
y: number,
w: number,
h: number,
minW: ?number = 0,
maxW: ?number = Infinity,
minH: ?number = 0,
maxH: ?number = Infinity,
// If true, equal to `isDraggable: false, isResizable: false`.
static: ?boolean = false,
// If false, will not be draggable. Overrides `static`.
isDraggable: ?boolean = true,
// If false, will not be resizable. Overrides `static`.
isResizable: ?boolean = true
}
```
## Contribute
If you have a feature request, please add it as an issue or make a pull request.
If you have a bug to report, please reproduce the bug in [WebpackBin](http://www.webpackbin.com/VymTE3zWG) to help
us easily isolate it.
## TODO List
- [x] Basic grid layout
- [x] Fluid grid layout
- [x] Grid packing
- [x] Draggable grid items
- [x] Live grid packing while dragging
- [x] Resizable grid items
- [x] Layouts per responsive breakpoint
- [x] Define grid attributes on children themselves (`data-grid` key)
- [x] Static elements
- [x] Persistent id per item for predictable localstorage restores, even when # items changes
- [x] Min/max w/h per item
- [ ] Resizable handles on other corners
- [ ] Configurable w/h per breakpoint

View File

@@ -0,0 +1,502 @@
'use strict';
exports.__esModule = true;
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _propTypes = require('prop-types');
var _propTypes2 = _interopRequireDefault(_propTypes);
var _reactDraggable = require('react-draggable');
var _reactResizable = require('react-resizable');
var _utils = require('./utils');
var _classnames = require('classnames');
var _classnames2 = _interopRequireDefault(_classnames);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
/**
* An individual item within a ReactGridLayout.
*/
var GridItem = function (_React$Component) {
_inherits(GridItem, _React$Component);
function GridItem() {
var _temp, _this, _ret;
_classCallCheck(this, GridItem);
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return _ret = (_temp = (_this = _possibleConstructorReturn(this, _React$Component.call.apply(_React$Component, [this].concat(args))), _this), _this.state = {
resizing: null,
dragging: null,
className: ''
}, _temp), _possibleConstructorReturn(_this, _ret);
}
// Helper for generating column width
GridItem.prototype.calcColWidth = function calcColWidth() {
var _props = this.props,
margin = _props.margin,
containerPadding = _props.containerPadding,
containerWidth = _props.containerWidth,
cols = _props.cols;
return (containerWidth - margin[0] * (cols - 1) - containerPadding[0] * 2) / cols;
};
/**
* Return position on the page given an x, y, w, h.
* left, top, width, height are all in pixels.
* @param {Number} x X coordinate in grid units.
* @param {Number} y Y coordinate in grid units.
* @param {Number} w W coordinate in grid units.
* @param {Number} h H coordinate in grid units.
* @return {Object} Object containing coords.
*/
GridItem.prototype.calcPosition = function calcPosition(x, y, w, h, state) {
var _props2 = this.props,
margin = _props2.margin,
containerPadding = _props2.containerPadding,
rowHeight = _props2.rowHeight;
var colWidth = this.calcColWidth();
var out = {
left: Math.round((colWidth + margin[0]) * x + containerPadding[0]),
top: Math.round((rowHeight + margin[1]) * y + containerPadding[1]),
// 0 * Infinity === NaN, which causes problems with resize constraints;
// Fix this if it occurs.
// Note we do it here rather than later because Math.round(Infinity) causes deopt
width: w === Infinity ? w : Math.round(colWidth * w + Math.max(0, w - 1) * margin[0]),
height: h === Infinity ? h : Math.round(rowHeight * h + Math.max(0, h - 1) * margin[1])
};
if (state && state.resizing) {
out.width = Math.round(state.resizing.width);
out.height = Math.round(state.resizing.height);
}
if (state && state.dragging) {
out.top = Math.round(state.dragging.top);
out.left = Math.round(state.dragging.left);
}
return out;
};
/**
* Translate x and y coordinates from pixels to grid units.
* @param {Number} top Top position (relative to parent) in pixels.
* @param {Number} left Left position (relative to parent) in pixels.
* @return {Object} x and y in grid units.
*/
GridItem.prototype.calcXY = function calcXY(top, left) {
var _props3 = this.props,
margin = _props3.margin,
cols = _props3.cols,
rowHeight = _props3.rowHeight,
w = _props3.w,
h = _props3.h,
maxRows = _props3.maxRows;
var colWidth = this.calcColWidth();
// left = colWidth * x + margin * (x + 1)
// l = cx + m(x+1)
// l = cx + mx + m
// l - m = cx + mx
// l - m = x(c + m)
// (l - m) / (c + m) = x
// x = (left - margin) / (coldWidth + margin)
var x = Math.round((left - margin[0]) / (colWidth + margin[0]));
var y = Math.round((top - margin[1]) / (rowHeight + margin[1]));
// Capping
x = Math.max(Math.min(x, cols - w), 0);
y = Math.max(Math.min(y, maxRows - h), 0);
return { x: x, y: y };
};
/**
* Given a height and width in pixel values, calculate grid units.
* @param {Number} height Height in pixels.
* @param {Number} width Width in pixels.
* @return {Object} w, h as grid units.
*/
GridItem.prototype.calcWH = function calcWH(_ref) {
var height = _ref.height,
width = _ref.width;
var _props4 = this.props,
margin = _props4.margin,
maxRows = _props4.maxRows,
cols = _props4.cols,
rowHeight = _props4.rowHeight,
x = _props4.x,
y = _props4.y;
var colWidth = this.calcColWidth();
// width = colWidth * w - (margin * (w - 1))
// ...
// w = (width + margin) / (colWidth + margin)
var w = Math.round((width + margin[0]) / (colWidth + margin[0]));
var h = Math.round((height + margin[1]) / (rowHeight + margin[1]));
// Capping
w = Math.max(Math.min(w, cols - x), 0);
h = Math.max(Math.min(h, maxRows - y), 0);
return { w: w, h: h };
};
/**
* This is where we set the grid item's absolute placement. It gets a little tricky because we want to do it
* well when server rendering, and the only way to do that properly is to use percentage width/left because
* we don't know exactly what the browser viewport is.
* Unfortunately, CSS Transforms, which are great for performance, break in this instance because a percentage
* left is relative to the item itself, not its container! So we cannot use them on the server rendering pass.
*
* @param {Object} pos Position object with width, height, left, top.
* @return {Object} Style object.
*/
GridItem.prototype.createStyle = function createStyle(pos) {
var _props5 = this.props,
usePercentages = _props5.usePercentages,
containerWidth = _props5.containerWidth,
useCSSTransforms = _props5.useCSSTransforms;
var style = void 0;
// CSS Transforms support (default)
if (useCSSTransforms) {
style = (0, _utils.setTransform)(pos);
}
// top,left (slow)
else {
style = (0, _utils.setTopLeft)(pos);
// This is used for server rendering.
if (usePercentages) {
style.left = (0, _utils.perc)(pos.left / containerWidth);
style.width = (0, _utils.perc)(pos.width / containerWidth);
}
}
return style;
};
/**
* Mix a Draggable instance into a child.
* @param {Element} child Child element.
* @return {Element} Child wrapped in Draggable.
*/
GridItem.prototype.mixinDraggable = function mixinDraggable(child) {
return _react2.default.createElement(
_reactDraggable.DraggableCore,
{
onStart: this.onDragHandler('onDragStart'),
onDrag: this.onDragHandler('onDrag'),
onStop: this.onDragHandler('onDragStop'),
handle: this.props.handle,
cancel: ".react-resizable-handle" + (this.props.cancel ? "," + this.props.cancel : "") },
child
);
};
/**
* Mix a Resizable instance into a child.
* @param {Element} child Child element.
* @param {Object} position Position object (pixel values)
* @return {Element} Child wrapped in Resizable.
*/
GridItem.prototype.mixinResizable = function mixinResizable(child, position) {
var _props6 = this.props,
cols = _props6.cols,
x = _props6.x,
minW = _props6.minW,
minH = _props6.minH,
maxW = _props6.maxW,
maxH = _props6.maxH;
// This is the max possible width - doesn't go to infinity because of the width of the window
var maxWidth = this.calcPosition(0, 0, cols - x, 0).width;
// Calculate min/max constraints using our min & maxes
var mins = this.calcPosition(0, 0, minW, minH);
var maxes = this.calcPosition(0, 0, maxW, maxH);
var minConstraints = [mins.width, mins.height];
var maxConstraints = [Math.min(maxes.width, maxWidth), Math.min(maxes.height, Infinity)];
return _react2.default.createElement(
_reactResizable.Resizable,
{
width: position.width,
height: position.height,
minConstraints: minConstraints,
maxConstraints: maxConstraints,
onResizeStop: this.onResizeHandler('onResizeStop'),
onResizeStart: this.onResizeHandler('onResizeStart'),
onResize: this.onResizeHandler('onResize') },
child
);
};
/**
* Wrapper around drag events to provide more useful data.
* All drag events call the function with the given handler name,
* with the signature (index, x, y).
*
* @param {String} handlerName Handler name to wrap.
* @return {Function} Handler function.
*/
GridItem.prototype.onDragHandler = function onDragHandler(handlerName) {
var _this2 = this;
return function (e, _ref2) {
var node = _ref2.node,
deltaX = _ref2.deltaX,
deltaY = _ref2.deltaY;
var handler = _this2.props[handlerName];
if (!handler) return;
var newPosition = { top: 0, left: 0 };
// Get new XY
switch (handlerName) {
case 'onDragStart':
{
// ToDo this wont work on nested parents
var parentRect = node.offsetParent.getBoundingClientRect();
var clientRect = node.getBoundingClientRect();
newPosition.left = clientRect.left - parentRect.left + node.offsetParent.scrollLeft;
newPosition.top = clientRect.top - parentRect.top + node.offsetParent.scrollTop;
_this2.setState({ dragging: newPosition });
break;
}
case 'onDrag':
if (!_this2.state.dragging) throw new Error('onDrag called before onDragStart.');
newPosition.left = _this2.state.dragging.left + deltaX;
newPosition.top = _this2.state.dragging.top + deltaY;
_this2.setState({ dragging: newPosition });
break;
case 'onDragStop':
if (!_this2.state.dragging) throw new Error('onDragEnd called before onDragStart.');
newPosition.left = _this2.state.dragging.left;
newPosition.top = _this2.state.dragging.top;
_this2.setState({ dragging: null });
break;
default:
throw new Error('onDragHandler called with unrecognized handlerName: ' + handlerName);
}
var _calcXY = _this2.calcXY(newPosition.top, newPosition.left),
x = _calcXY.x,
y = _calcXY.y;
handler.call(_this2, _this2.props.i, x, y, { e: e, node: node, newPosition: newPosition });
};
};
/**
* Wrapper around drag events to provide more useful data.
* All drag events call the function with the given handler name,
* with the signature (index, x, y).
*
* @param {String} handlerName Handler name to wrap.
* @return {Function} Handler function.
*/
GridItem.prototype.onResizeHandler = function onResizeHandler(handlerName) {
var _this3 = this;
return function (e, _ref3) {
var node = _ref3.node,
size = _ref3.size;
var handler = _this3.props[handlerName];
if (!handler) return;
var _props7 = _this3.props,
cols = _props7.cols,
x = _props7.x,
i = _props7.i,
maxW = _props7.maxW,
minW = _props7.minW,
maxH = _props7.maxH,
minH = _props7.minH;
// Get new XY
var _calcWH = _this3.calcWH(size),
w = _calcWH.w,
h = _calcWH.h;
// Cap w at numCols
w = Math.min(w, cols - x);
// Ensure w is at least 1
w = Math.max(w, 1);
// Min/max capping
w = Math.max(Math.min(w, maxW), minW);
h = Math.max(Math.min(h, maxH), minH);
_this3.setState({ resizing: handlerName === 'onResizeStop' ? null : size });
handler.call(_this3, i, w, h, { e: e, node: node, size: size });
};
};
GridItem.prototype.render = function render() {
var _props8 = this.props,
x = _props8.x,
y = _props8.y,
w = _props8.w,
h = _props8.h,
isDraggable = _props8.isDraggable,
isResizable = _props8.isResizable,
useCSSTransforms = _props8.useCSSTransforms;
var pos = this.calcPosition(x, y, w, h, this.state);
var child = _react2.default.Children.only(this.props.children);
// Create the child element. We clone the existing element but modify its className and style.
var newChild = _react2.default.cloneElement(child, {
className: (0, _classnames2.default)('react-grid-item', child.props.className, this.props.className, {
static: this.props.static,
resizing: Boolean(this.state.resizing),
'react-draggable': isDraggable,
'react-draggable-dragging': Boolean(this.state.dragging),
cssTransforms: useCSSTransforms
}),
// We can set the width and height on the child, but unfortunately we can't set the position.
style: _extends({}, this.props.style, child.props.style, this.createStyle(pos))
});
// Resizable support. This is usually on but the user can toggle it off.
if (isResizable) newChild = this.mixinResizable(newChild, pos);
// Draggable support. This is always on, except for with placeholders.
if (isDraggable) newChild = this.mixinDraggable(newChild);
return newChild;
};
return GridItem;
}(_react2.default.Component);
GridItem.propTypes = {
// Children must be only a single element
children: _propTypes2.default.element,
// General grid attributes
cols: _propTypes2.default.number.isRequired,
containerWidth: _propTypes2.default.number.isRequired,
rowHeight: _propTypes2.default.number.isRequired,
margin: _propTypes2.default.array.isRequired,
maxRows: _propTypes2.default.number.isRequired,
containerPadding: _propTypes2.default.array.isRequired,
// These are all in grid units
x: _propTypes2.default.number.isRequired,
y: _propTypes2.default.number.isRequired,
w: _propTypes2.default.number.isRequired,
h: _propTypes2.default.number.isRequired,
// All optional
minW: function minW(props, propName) {
var value = props[propName];
if (typeof value !== 'number') return new Error('minWidth not Number');
if (value > props.w || value > props.maxW) return new Error('minWidth larger than item width/maxWidth');
},
maxW: function maxW(props, propName) {
var value = props[propName];
if (typeof value !== 'number') return new Error('maxWidth not Number');
if (value < props.w || value < props.minW) return new Error('maxWidth smaller than item width/minWidth');
},
minH: function minH(props, propName) {
var value = props[propName];
if (typeof value !== 'number') return new Error('minHeight not Number');
if (value > props.h || value > props.maxH) return new Error('minHeight larger than item height/maxHeight');
},
maxH: function maxH(props, propName) {
var value = props[propName];
if (typeof value !== 'number') return new Error('maxHeight not Number');
if (value < props.h || value < props.minH) return new Error('maxHeight smaller than item height/minHeight');
},
// ID is nice to have for callbacks
i: _propTypes2.default.string.isRequired,
// Functions
onDragStop: _propTypes2.default.func,
onDragStart: _propTypes2.default.func,
onDrag: _propTypes2.default.func,
onResizeStop: _propTypes2.default.func,
onResizeStart: _propTypes2.default.func,
onResize: _propTypes2.default.func,
// Flags
isDraggable: _propTypes2.default.bool.isRequired,
isResizable: _propTypes2.default.bool.isRequired,
static: _propTypes2.default.bool,
// Use CSS transforms instead of top/left
useCSSTransforms: _propTypes2.default.bool.isRequired,
// Others
className: _propTypes2.default.string,
// Selector for draggable handle
handle: _propTypes2.default.string,
// Selector for draggable cancel (see react-draggable)
cancel: _propTypes2.default.string
};
GridItem.defaultProps = {
className: '',
cancel: '',
handle: '',
minH: 1,
minW: 1,
maxH: Infinity,
maxW: Infinity
};
exports.default = GridItem;

View File

@@ -0,0 +1,430 @@
// @flow
import React from 'react';
import PropTypes from 'prop-types';
import {DraggableCore} from 'react-draggable';
import {Resizable} from 'react-resizable';
import {perc, setTopLeft, setTransform} from './utils';
import classNames from 'classnames';
import type {Element as ReactElement, Node as ReactNode} from 'react';
import type {ReactDraggableCallbackData, GridDragEvent, GridResizeEvent, Position} from './utils';
type PartialPosition = {top: number, left: number};
type GridItemCallback<Data: GridDragEvent | GridResizeEvent> = (i: string, w: number, h: number, Data) => void;
type State = {
resizing: ?{width: number, height: number},
dragging: ?{top: number, left: number},
className: string
};
type Props = {
children: ReactElement<any>,
cols: number,
containerWidth: number,
margin: [number, number],
containerPadding: [number, number],
rowHeight: number,
maxRows: number,
isDraggable: boolean,
isResizable: boolean,
static?: boolean,
useCSSTransforms?: boolean,
usePercentages?: boolean,
className: string,
style?: Object,
// Draggability
cancel: string,
handle: string,
x: number,
y: number,
w: number,
h: number,
minW: number,
maxW: number,
minH: number,
maxH: number,
i: string,
onDrag?: GridItemCallback<GridDragEvent>,
onDragStart?: GridItemCallback<GridDragEvent>,
onDragStop?: GridItemCallback<GridDragEvent>,
onResize?: GridItemCallback<GridResizeEvent>,
onResizeStart?: GridItemCallback<GridResizeEvent>,
onResizeStop?: GridItemCallback<GridResizeEvent>,
};
/**
* An individual item within a ReactGridLayout.
*/
export default class GridItem extends React.Component<Props, State> {
static propTypes = {
// Children must be only a single element
children: PropTypes.element,
// General grid attributes
cols: PropTypes.number.isRequired,
containerWidth: PropTypes.number.isRequired,
rowHeight: PropTypes.number.isRequired,
margin: PropTypes.array.isRequired,
maxRows: PropTypes.number.isRequired,
containerPadding: PropTypes.array.isRequired,
// These are all in grid units
x: PropTypes.number.isRequired,
y: PropTypes.number.isRequired,
w: PropTypes.number.isRequired,
h: PropTypes.number.isRequired,
// All optional
minW: function (props, propName) {
const value = props[propName];
if (typeof value !== 'number') return new Error('minWidth not Number');
if (value > props.w || value > props.maxW) return new Error('minWidth larger than item width/maxWidth');
},
maxW: function (props, propName) {
const value = props[propName];
if (typeof value !== 'number') return new Error('maxWidth not Number');
if (value < props.w || value < props.minW) return new Error('maxWidth smaller than item width/minWidth');
},
minH: function (props, propName) {
const value = props[propName];
if (typeof value !== 'number') return new Error('minHeight not Number');
if (value > props.h || value > props.maxH) return new Error('minHeight larger than item height/maxHeight');
},
maxH: function (props, propName) {
const value = props[propName];
if (typeof value !== 'number') return new Error('maxHeight not Number');
if (value < props.h || value < props.minH) return new Error('maxHeight smaller than item height/minHeight');
},
// ID is nice to have for callbacks
i: PropTypes.string.isRequired,
// Functions
onDragStop: PropTypes.func,
onDragStart: PropTypes.func,
onDrag: PropTypes.func,
onResizeStop: PropTypes.func,
onResizeStart: PropTypes.func,
onResize: PropTypes.func,
// Flags
isDraggable: PropTypes.bool.isRequired,
isResizable: PropTypes.bool.isRequired,
static: PropTypes.bool,
// Use CSS transforms instead of top/left
useCSSTransforms: PropTypes.bool.isRequired,
// Others
className: PropTypes.string,
// Selector for draggable handle
handle: PropTypes.string,
// Selector for draggable cancel (see react-draggable)
cancel: PropTypes.string
};
static defaultProps = {
className: '',
cancel: '',
handle: '',
minH: 1,
minW: 1,
maxH: Infinity,
maxW: Infinity,
};
state: State = {
resizing: null,
dragging: null,
className: ''
};
// Helper for generating column width
calcColWidth(): number {
const {margin, containerPadding, containerWidth, cols} = this.props;
return (containerWidth - (margin[0] * (cols - 1)) - (containerPadding[0] * 2)) / cols;
}
/**
* Return position on the page given an x, y, w, h.
* left, top, width, height are all in pixels.
* @param {Number} x X coordinate in grid units.
* @param {Number} y Y coordinate in grid units.
* @param {Number} w W coordinate in grid units.
* @param {Number} h H coordinate in grid units.
* @return {Object} Object containing coords.
*/
calcPosition(x: number, y: number, w: number, h: number, state: ?Object): Position {
const {margin, containerPadding, rowHeight} = this.props;
const colWidth = this.calcColWidth();
const out = {
left: Math.round((colWidth + margin[0]) * x + containerPadding[0]),
top: Math.round((rowHeight + margin[1]) * y + containerPadding[1]),
// 0 * Infinity === NaN, which causes problems with resize constraints;
// Fix this if it occurs.
// Note we do it here rather than later because Math.round(Infinity) causes deopt
width: w === Infinity ? w : Math.round(colWidth * w + Math.max(0, w - 1) * margin[0]),
height: h === Infinity ? h : Math.round(rowHeight * h + Math.max(0, h - 1) * margin[1])
};
if (state && state.resizing) {
out.width = Math.round(state.resizing.width);
out.height = Math.round(state.resizing.height);
}
if (state && state.dragging) {
out.top = Math.round(state.dragging.top);
out.left = Math.round(state.dragging.left);
}
return out;
}
/**
* Translate x and y coordinates from pixels to grid units.
* @param {Number} top Top position (relative to parent) in pixels.
* @param {Number} left Left position (relative to parent) in pixels.
* @return {Object} x and y in grid units.
*/
calcXY(top: number, left: number): {x: number, y: number} {
const {margin, cols, rowHeight, w, h, maxRows} = this.props;
const colWidth = this.calcColWidth();
// left = colWidth * x + margin * (x + 1)
// l = cx + m(x+1)
// l = cx + mx + m
// l - m = cx + mx
// l - m = x(c + m)
// (l - m) / (c + m) = x
// x = (left - margin) / (coldWidth + margin)
let x = Math.round((left - margin[0]) / (colWidth + margin[0]));
let y = Math.round((top - margin[1]) / (rowHeight + margin[1]));
// Capping
x = Math.max(Math.min(x, cols - w), 0);
y = Math.max(Math.min(y, maxRows - h), 0);
return {x, y};
}
/**
* Given a height and width in pixel values, calculate grid units.
* @param {Number} height Height in pixels.
* @param {Number} width Width in pixels.
* @return {Object} w, h as grid units.
*/
calcWH({height, width}: {height: number, width: number}): {w: number, h: number} {
const {margin, maxRows, cols, rowHeight, x, y} = this.props;
const colWidth = this.calcColWidth();
// width = colWidth * w - (margin * (w - 1))
// ...
// w = (width + margin) / (colWidth + margin)
let w = Math.round((width + margin[0]) / (colWidth + margin[0]));
let h = Math.round((height + margin[1]) / (rowHeight + margin[1]));
// Capping
w = Math.max(Math.min(w, cols - x), 0);
h = Math.max(Math.min(h, maxRows - y), 0);
return {w, h};
}
/**
* This is where we set the grid item's absolute placement. It gets a little tricky because we want to do it
* well when server rendering, and the only way to do that properly is to use percentage width/left because
* we don't know exactly what the browser viewport is.
* Unfortunately, CSS Transforms, which are great for performance, break in this instance because a percentage
* left is relative to the item itself, not its container! So we cannot use them on the server rendering pass.
*
* @param {Object} pos Position object with width, height, left, top.
* @return {Object} Style object.
*/
createStyle(pos: Position): {[key: string]: ?string} {
const {usePercentages, containerWidth, useCSSTransforms} = this.props;
let style;
// CSS Transforms support (default)
if (useCSSTransforms) {
style = setTransform(pos);
}
// top,left (slow)
else {
style = setTopLeft(pos);
// This is used for server rendering.
if (usePercentages) {
style.left = perc(pos.left / containerWidth);
style.width = perc(pos.width / containerWidth);
}
}
return style;
}
/**
* Mix a Draggable instance into a child.
* @param {Element} child Child element.
* @return {Element} Child wrapped in Draggable.
*/
mixinDraggable(child: ReactElement<any>): ReactElement<any> {
return (
<DraggableCore
onStart={this.onDragHandler('onDragStart')}
onDrag={this.onDragHandler('onDrag')}
onStop={this.onDragHandler('onDragStop')}
handle={this.props.handle}
cancel={".react-resizable-handle" + (this.props.cancel ? "," + this.props.cancel : "")}>
{child}
</DraggableCore>
);
}
/**
* Mix a Resizable instance into a child.
* @param {Element} child Child element.
* @param {Object} position Position object (pixel values)
* @return {Element} Child wrapped in Resizable.
*/
mixinResizable(child: ReactElement<any>, position: Position): ReactElement<any> {
const {cols, x, minW, minH, maxW, maxH} = this.props;
// This is the max possible width - doesn't go to infinity because of the width of the window
const maxWidth = this.calcPosition(0, 0, cols - x, 0).width;
// Calculate min/max constraints using our min & maxes
const mins = this.calcPosition(0, 0, minW, minH);
const maxes = this.calcPosition(0, 0, maxW, maxH);
const minConstraints = [mins.width, mins.height];
const maxConstraints = [Math.min(maxes.width, maxWidth), Math.min(maxes.height, Infinity)];
return (
<Resizable
width={position.width}
height={position.height}
minConstraints={minConstraints}
maxConstraints={maxConstraints}
onResizeStop={this.onResizeHandler('onResizeStop')}
onResizeStart={this.onResizeHandler('onResizeStart')}
onResize={this.onResizeHandler('onResize')}>
{child}
</Resizable>
);
}
/**
* Wrapper around drag events to provide more useful data.
* All drag events call the function with the given handler name,
* with the signature (index, x, y).
*
* @param {String} handlerName Handler name to wrap.
* @return {Function} Handler function.
*/
onDragHandler(handlerName:string) {
return (e:Event, {node, deltaX, deltaY}: ReactDraggableCallbackData) => {
const handler = this.props[handlerName];
if (!handler) return;
const newPosition: PartialPosition = {top: 0, left: 0};
// Get new XY
switch (handlerName) {
case 'onDragStart': {
// ToDo this wont work on nested parents
const parentRect = node.offsetParent.getBoundingClientRect();
const clientRect = node.getBoundingClientRect();
newPosition.left = clientRect.left - parentRect.left + node.offsetParent.scrollLeft;
newPosition.top = clientRect.top - parentRect.top + node.offsetParent.scrollTop;
this.setState({dragging: newPosition});
break;
}
case 'onDrag':
if (!this.state.dragging) throw new Error('onDrag called before onDragStart.');
newPosition.left = this.state.dragging.left + deltaX;
newPosition.top = this.state.dragging.top + deltaY;
this.setState({dragging: newPosition});
break;
case 'onDragStop':
if (!this.state.dragging) throw new Error('onDragEnd called before onDragStart.');
newPosition.left = this.state.dragging.left;
newPosition.top = this.state.dragging.top;
this.setState({dragging: null});
break;
default:
throw new Error('onDragHandler called with unrecognized handlerName: ' + handlerName);
}
const {x, y} = this.calcXY(newPosition.top, newPosition.left);
handler.call(this, this.props.i, x, y, {e, node, newPosition});
};
}
/**
* Wrapper around drag events to provide more useful data.
* All drag events call the function with the given handler name,
* with the signature (index, x, y).
*
* @param {String} handlerName Handler name to wrap.
* @return {Function} Handler function.
*/
onResizeHandler(handlerName: string) {
return (e:Event, {node, size}: {node: HTMLElement, size: Position}) => {
const handler = this.props[handlerName];
if (!handler) return;
const {cols, x, i, maxW, minW, maxH, minH} = this.props;
// Get new XY
let {w, h} = this.calcWH(size);
// Cap w at numCols
w = Math.min(w, cols - x);
// Ensure w is at least 1
w = Math.max(w, 1);
// Min/max capping
w = Math.max(Math.min(w, maxW), minW);
h = Math.max(Math.min(h, maxH), minH);
this.setState({resizing: handlerName === 'onResizeStop' ? null : size});
handler.call(this, i, w, h, {e, node, size});
};
}
render(): ReactNode {
const {x, y, w, h, isDraggable, isResizable, useCSSTransforms} = this.props;
const pos = this.calcPosition(x, y, w, h, this.state);
const child = React.Children.only(this.props.children);
// Create the child element. We clone the existing element but modify its className and style.
let newChild = React.cloneElement(child, {
className: classNames('react-grid-item', child.props.className, this.props.className, {
static: this.props.static,
resizing: Boolean(this.state.resizing),
'react-draggable': isDraggable,
'react-draggable-dragging': Boolean(this.state.dragging),
cssTransforms: useCSSTransforms
}),
// We can set the width and height on the child, but unfortunately we can't set the position.
style: {...this.props.style, ...child.props.style, ...this.createStyle(pos)}
});
// Resizable support. This is usually on but the user can toggle it off.
if (isResizable) newChild = this.mixinResizable(newChild, pos);
// Draggable support. This is always on, except for with placeholders.
if (isDraggable) newChild = this.mixinDraggable(newChild);
return newChild;
}
}

View File

@@ -0,0 +1,579 @@
'use strict';
exports.__esModule = true;
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _propTypes = require('prop-types');
var _propTypes2 = _interopRequireDefault(_propTypes);
var _lodash = require('lodash.isequal');
var _lodash2 = _interopRequireDefault(_lodash);
var _classnames = require('classnames');
var _classnames2 = _interopRequireDefault(_classnames);
var _utils = require('./utils');
var _GridItem = require('./GridItem');
var _GridItem2 = _interopRequireDefault(_GridItem);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var noop = function noop() {};
// Types
// End Types
/**
* A reactive, fluid grid layout with draggable, resizable components.
*/
var ReactGridLayout = function (_React$Component) {
_inherits(ReactGridLayout, _React$Component);
// TODO publish internal ReactClass displayName transform
function ReactGridLayout(props, context) {
_classCallCheck(this, ReactGridLayout);
var _this = _possibleConstructorReturn(this, _React$Component.call(this, props, context));
_initialiseProps.call(_this);
(0, _utils.autoBindHandlers)(_this, ['onDragStart', 'onDrag', 'onDragStop', 'onResizeStart', 'onResize', 'onResizeStop']);
return _this;
}
ReactGridLayout.prototype.componentDidMount = function componentDidMount() {
this.setState({ mounted: true });
// Possibly call back with layout on mount. This should be done after correcting the layout width
// to ensure we don't rerender with the wrong width.
this.onLayoutMaybeChanged(this.state.layout, this.props.layout);
};
ReactGridLayout.prototype.componentWillReceiveProps = function componentWillReceiveProps(nextProps) {
var newLayoutBase = void 0;
// Legacy support for compactType
// Allow parent to set layout directly.
if (!(0, _lodash2.default)(nextProps.layout, this.props.layout) || nextProps.compactType !== this.props.compactType) {
newLayoutBase = nextProps.layout;
}
// If children change, also regenerate the layout. Use our state
// as the base in case because it may be more up to date than
// what is in props.
else if (!(0, _utils.childrenEqual)(this.props.children, nextProps.children)) {
newLayoutBase = this.state.layout;
}
// We need to regenerate the layout.
if (newLayoutBase) {
var newLayout = (0, _utils.synchronizeLayoutWithChildren)(newLayoutBase, nextProps.children, nextProps.cols, this.compactType(nextProps));
var _oldLayout = this.state.layout;
this.setState({ layout: newLayout });
this.onLayoutMaybeChanged(newLayout, _oldLayout);
}
};
/**
* Calculates a pixel value for the container.
* @return {String} Container height in pixels.
*/
ReactGridLayout.prototype.containerHeight = function containerHeight() {
if (!this.props.autoSize) return;
var nbRow = (0, _utils.bottom)(this.state.layout);
var containerPaddingY = this.props.containerPadding ? this.props.containerPadding[1] : this.props.margin[1];
return nbRow * this.props.rowHeight + (nbRow - 1) * this.props.margin[1] + containerPaddingY * 2 + 'px';
};
ReactGridLayout.prototype.compactType = function compactType(props) {
if (!props) props = this.props;
return props.verticalCompact === false ? null : props.compactType;
};
/**
* When dragging starts
* @param {String} i Id of the child
* @param {Number} x X position of the move
* @param {Number} y Y position of the move
* @param {Event} e The mousedown event
* @param {Element} node The current dragging DOM element
*/
ReactGridLayout.prototype.onDragStart = function onDragStart(i, x, y, _ref) {
var e = _ref.e,
node = _ref.node;
var layout = this.state.layout;
var l = (0, _utils.getLayoutItem)(layout, i);
if (!l) return;
this.setState({ oldDragItem: (0, _utils.cloneLayoutItem)(l), oldLayout: this.state.layout });
this.props.onDragStart(layout, l, l, null, e, node);
};
/**
* Each drag movement create a new dragelement and move the element to the dragged location
* @param {String} i Id of the child
* @param {Number} x X position of the move
* @param {Number} y Y position of the move
* @param {Event} e The mousedown event
* @param {Element} node The current dragging DOM element
*/
ReactGridLayout.prototype.onDrag = function onDrag(i, x, y, _ref2) {
var e = _ref2.e,
node = _ref2.node;
var oldDragItem = this.state.oldDragItem;
var layout = this.state.layout;
var cols = this.props.cols;
var l = (0, _utils.getLayoutItem)(layout, i);
if (!l) return;
// Create placeholder (display only)
var placeholder = {
w: l.w, h: l.h, x: l.x, y: l.y, placeholder: true, i: i
};
// Move the element to the dragged location.
var isUserAction = true;
layout = (0, _utils.moveElement)(layout, l, x, y, isUserAction, this.props.preventCollision, this.compactType(), cols);
this.props.onDrag(layout, oldDragItem, l, placeholder, e, node);
this.setState({
layout: (0, _utils.compact)(layout, this.compactType(), cols),
activeDrag: placeholder
});
};
/**
* When dragging stops, figure out which position the element is closest to and update its x and y.
* @param {String} i Index of the child.
* @param {Number} x X position of the move
* @param {Number} y Y position of the move
* @param {Event} e The mousedown event
* @param {Element} node The current dragging DOM element
*/
ReactGridLayout.prototype.onDragStop = function onDragStop(i, x, y, _ref3) {
var e = _ref3.e,
node = _ref3.node;
var oldDragItem = this.state.oldDragItem;
var layout = this.state.layout;
var _props = this.props,
cols = _props.cols,
preventCollision = _props.preventCollision;
var l = (0, _utils.getLayoutItem)(layout, i);
if (!l) return;
// Move the element here
var isUserAction = true;
layout = (0, _utils.moveElement)(layout, l, x, y, isUserAction, preventCollision, this.compactType(), cols);
this.props.onDragStop(layout, oldDragItem, l, null, e, node);
// Set state
var newLayout = (0, _utils.compact)(layout, this.compactType(), cols);
var oldLayout = this.state.oldLayout;
this.setState({
activeDrag: null,
layout: newLayout,
oldDragItem: null,
oldLayout: null
});
this.onLayoutMaybeChanged(newLayout, oldLayout);
};
ReactGridLayout.prototype.onLayoutMaybeChanged = function onLayoutMaybeChanged(newLayout, oldLayout) {
if (!oldLayout) oldLayout = this.state.layout;
if (!(0, _lodash2.default)(oldLayout, newLayout)) {
this.props.onLayoutChange(newLayout);
}
};
ReactGridLayout.prototype.onResizeStart = function onResizeStart(i, w, h, _ref4) {
var e = _ref4.e,
node = _ref4.node;
var layout = this.state.layout;
var l = (0, _utils.getLayoutItem)(layout, i);
if (!l) return;
this.setState({
oldResizeItem: (0, _utils.cloneLayoutItem)(l),
oldLayout: this.state.layout
});
this.props.onResizeStart(layout, l, l, null, e, node);
};
ReactGridLayout.prototype.onResize = function onResize(i, w, h, _ref5) {
var e = _ref5.e,
node = _ref5.node;
var _state = this.state,
layout = _state.layout,
oldResizeItem = _state.oldResizeItem;
var _props2 = this.props,
cols = _props2.cols,
preventCollision = _props2.preventCollision;
var l = (0, _utils.getLayoutItem)(layout, i);
if (!l) return;
// Short circuit if there is a collision in no rearrangement mode.
if (preventCollision && (0, _utils.getFirstCollision)(layout, _extends({}, l, { w: w, h: h }))) {
return;
}
// Set new width and height.
l.w = w;
l.h = h;
// Create placeholder element (display only)
var placeholder = {
w: w, h: h, x: l.x, y: l.y, static: true, i: i
};
this.props.onResize(layout, oldResizeItem, l, placeholder, e, node);
// Re-compact the layout and set the drag placeholder.
this.setState({
layout: (0, _utils.compact)(layout, this.compactType(), cols),
activeDrag: placeholder
});
};
ReactGridLayout.prototype.onResizeStop = function onResizeStop(i, w, h, _ref6) {
var e = _ref6.e,
node = _ref6.node;
var _state2 = this.state,
layout = _state2.layout,
oldResizeItem = _state2.oldResizeItem;
var cols = this.props.cols;
var l = (0, _utils.getLayoutItem)(layout, i);
this.props.onResizeStop(layout, oldResizeItem, l, null, e, node);
// Set state
var newLayout = (0, _utils.compact)(layout, this.compactType(), cols);
var oldLayout = this.state.oldLayout;
this.setState({
activeDrag: null,
layout: newLayout,
oldResizeItem: null,
oldLayout: null
});
this.onLayoutMaybeChanged(newLayout, oldLayout);
};
/**
* Create a placeholder object.
* @return {Element} Placeholder div.
*/
ReactGridLayout.prototype.placeholder = function placeholder() {
var activeDrag = this.state.activeDrag;
if (!activeDrag) return null;
var _props3 = this.props,
width = _props3.width,
cols = _props3.cols,
margin = _props3.margin,
containerPadding = _props3.containerPadding,
rowHeight = _props3.rowHeight,
maxRows = _props3.maxRows,
useCSSTransforms = _props3.useCSSTransforms;
// {...this.state.activeDrag} is pretty slow, actually
return _react2.default.createElement(
_GridItem2.default,
{
w: activeDrag.w,
h: activeDrag.h,
x: activeDrag.x,
y: activeDrag.y,
i: activeDrag.i,
className: 'react-grid-placeholder',
containerWidth: width,
cols: cols,
margin: margin,
containerPadding: containerPadding || margin,
maxRows: maxRows,
rowHeight: rowHeight,
isDraggable: false,
isResizable: false,
useCSSTransforms: useCSSTransforms },
_react2.default.createElement('div', null)
);
};
/**
* Given a grid item, set its style attributes & surround in a <Draggable>.
* @param {Element} child React element.
* @return {Element} Element wrapped in draggable and properly placed.
*/
ReactGridLayout.prototype.processGridItem = function processGridItem(child) {
if (!child.key) return;
var l = (0, _utils.getLayoutItem)(this.state.layout, String(child.key));
if (!l) return null;
var _props4 = this.props,
width = _props4.width,
cols = _props4.cols,
margin = _props4.margin,
containerPadding = _props4.containerPadding,
rowHeight = _props4.rowHeight,
maxRows = _props4.maxRows,
isDraggable = _props4.isDraggable,
isResizable = _props4.isResizable,
useCSSTransforms = _props4.useCSSTransforms,
draggableCancel = _props4.draggableCancel,
draggableHandle = _props4.draggableHandle;
var mounted = this.state.mounted;
// Parse 'static'. Any properties defined directly on the grid item will take precedence.
var draggable = Boolean(!l.static && isDraggable && (l.isDraggable || l.isDraggable == null));
var resizable = Boolean(!l.static && isResizable && (l.isResizable || l.isResizable == null));
return _react2.default.createElement(
_GridItem2.default,
{
containerWidth: width,
cols: cols,
margin: margin,
containerPadding: containerPadding || margin,
maxRows: maxRows,
rowHeight: rowHeight,
cancel: draggableCancel,
handle: draggableHandle,
onDragStop: this.onDragStop,
onDragStart: this.onDragStart,
onDrag: this.onDrag,
onResizeStart: this.onResizeStart,
onResize: this.onResize,
onResizeStop: this.onResizeStop,
isDraggable: draggable,
isResizable: resizable,
useCSSTransforms: useCSSTransforms && mounted,
usePercentages: !mounted,
w: l.w,
h: l.h,
x: l.x,
y: l.y,
i: l.i,
minH: l.minH,
minW: l.minW,
maxH: l.maxH,
maxW: l.maxW,
'static': l.static
},
child
);
};
ReactGridLayout.prototype.render = function render() {
var _this2 = this;
var _props5 = this.props,
className = _props5.className,
style = _props5.style;
var mergedStyle = _extends({
height: this.containerHeight()
}, style);
return _react2.default.createElement(
'div',
{ className: (0, _classnames2.default)('react-grid-layout', className), style: mergedStyle },
// $FlowIgnore: Appears to think map calls back w/array
_react2.default.Children.map(this.props.children, function (child) {
return _this2.processGridItem(child);
}),
this.placeholder()
);
};
return ReactGridLayout;
}(_react2.default.Component);
ReactGridLayout.displayName = "ReactGridLayout";
ReactGridLayout.propTypes = {
//
// Basic props
//
className: _propTypes2.default.string,
style: _propTypes2.default.object,
// This can be set explicitly. If it is not set, it will automatically
// be set to the container width. Note that resizes will *not* cause this to adjust.
// If you need that behavior, use WidthProvider.
width: _propTypes2.default.number,
// If true, the container height swells and contracts to fit contents
autoSize: _propTypes2.default.bool,
// # of cols.
cols: _propTypes2.default.number,
// A selector that will not be draggable.
draggableCancel: _propTypes2.default.string,
// A selector for the draggable handler
draggableHandle: _propTypes2.default.string,
// Deprecated
verticalCompact: function verticalCompact(props) {
if (props.verticalCompact === false && process.env.NODE_ENV !== 'production') {
console.warn( // eslint-disable-line no-console
'`verticalCompact` on <ReactGridLayout> is deprecated and will be removed soon. ' + 'Use `compactType`: "horizontal" | "vertical" | null.');
}
},
// Choose vertical or hotizontal compaction
compactType: _propTypes2.default.oneOf(['vertical', 'horizontal']),
// layout is an array of object with the format:
// {x: Number, y: Number, w: Number, h: Number, i: String}
layout: function layout(props) {
var layout = props.layout;
// I hope you're setting the data-grid property on the grid items
if (layout === undefined) return;
(0, _utils.validateLayout)(layout, 'layout');
},
//
// Grid Dimensions
//
// Margin between items [x, y] in px
margin: _propTypes2.default.arrayOf(_propTypes2.default.number),
// Padding inside the container [x, y] in px
containerPadding: _propTypes2.default.arrayOf(_propTypes2.default.number),
// Rows have a static height, but you can change this based on breakpoints if you like
rowHeight: _propTypes2.default.number,
// Default Infinity, but you can specify a max here if you like.
// Note that this isn't fully fleshed out and won't error if you specify a layout that
// extends beyond the row capacity. It will, however, not allow users to drag/resize
// an item past the barrier. They can push items beyond the barrier, though.
// Intentionally not documented for this reason.
maxRows: _propTypes2.default.number,
//
// Flags
//
isDraggable: _propTypes2.default.bool,
isResizable: _propTypes2.default.bool,
// If true, grid items won't change position when being dragged over.
preventCollision: _propTypes2.default.bool,
// Use CSS transforms instead of top/left
useCSSTransforms: _propTypes2.default.bool,
//
// Callbacks
//
// Callback so you can save the layout. Calls after each drag & resize stops.
onLayoutChange: _propTypes2.default.func,
// Calls when drag starts. Callback is of the signature (layout, oldItem, newItem, placeholder, e, ?node).
// All callbacks below have the same signature. 'start' and 'stop' callbacks omit the 'placeholder'.
onDragStart: _propTypes2.default.func,
// Calls on each drag movement.
onDrag: _propTypes2.default.func,
// Calls when drag is complete.
onDragStop: _propTypes2.default.func,
//Calls when resize starts.
onResizeStart: _propTypes2.default.func,
// Calls when resize movement happens.
onResize: _propTypes2.default.func,
// Calls when resize is complete.
onResizeStop: _propTypes2.default.func,
//
// Other validations
//
// Children must not have duplicate keys.
children: function children(props, propName, _componentName) {
var children = props[propName];
// Check children keys for duplicates. Throw if found.
var keys = {};
_react2.default.Children.forEach(children, function (child) {
if (keys[child.key]) {
throw new Error("Duplicate child key \"" + child.key + "\" found! This will cause problems in ReactGridLayout.");
}
keys[child.key] = true;
});
}
};
ReactGridLayout.defaultProps = {
autoSize: true,
cols: 12,
className: '',
rowHeight: 150,
maxRows: Infinity, // infinite vertical growth
layout: [],
margin: [10, 10],
isDraggable: true,
isResizable: true,
useCSSTransforms: true,
verticalCompact: true,
compactType: 'vertical',
preventCollision: false,
onLayoutChange: noop,
onDragStart: noop,
onDrag: noop,
onDragStop: noop,
onResizeStart: noop,
onResize: noop,
onResizeStop: noop
};
var _initialiseProps = function _initialiseProps() {
this.state = {
activeDrag: null,
layout: (0, _utils.synchronizeLayoutWithChildren)(this.props.layout, this.props.children, this.props.cols,
// Legacy support for verticalCompact: false
this.compactType()),
mounted: false,
oldDragItem: null,
oldLayout: null,
oldResizeItem: null
};
};
exports.default = ReactGridLayout;

View File

@@ -0,0 +1,517 @@
// @flow
import React from 'react';
import PropTypes from 'prop-types';
import isEqual from 'lodash.isequal';
import classNames from 'classnames';
import {autoBindHandlers, bottom, childrenEqual, cloneLayoutItem, compact, getLayoutItem, moveElement,
synchronizeLayoutWithChildren, validateLayout, getFirstCollision} from './utils';
import GridItem from './GridItem';
import type {ChildrenArray as ReactChildrenArray, Element as ReactElement} from 'react';
const noop = function() {};
// Types
import type {EventCallback, CompactType, GridResizeEvent, GridDragEvent, Layout, LayoutItem} from './utils';
type State = {
activeDrag: ?LayoutItem,
layout: Layout,
mounted: boolean,
oldDragItem: ?LayoutItem,
oldLayout: ?Layout,
oldResizeItem: ?LayoutItem
};
export type Props = {
className: string,
style: Object,
width: number,
autoSize: boolean,
cols: number,
draggableCancel: string,
draggableHandle: string,
verticalCompact: boolean,
compactType: ?('horizontal' | 'vertical'),
layout: Layout,
margin: [number, number],
containerPadding: [number, number],
rowHeight: number,
maxRows: number,
isDraggable: boolean,
isResizable: boolean,
preventCollision: boolean,
useCSSTransforms: boolean,
// Callbacks
onLayoutChange: (Layout) => void,
onDrag: EventCallback,
onDragStart: EventCallback,
onDragStop: EventCallback,
onResize: EventCallback,
onResizeStart: EventCallback,
onResizeStop: EventCallback,
children: ReactChildrenArray<ReactElement<any>>,
};
// End Types
/**
* A reactive, fluid grid layout with draggable, resizable components.
*/
export default class ReactGridLayout extends React.Component<Props, State> {
// TODO publish internal ReactClass displayName transform
static displayName = "ReactGridLayout";
static propTypes = {
//
// Basic props
//
className: PropTypes.string,
style: PropTypes.object,
// This can be set explicitly. If it is not set, it will automatically
// be set to the container width. Note that resizes will *not* cause this to adjust.
// If you need that behavior, use WidthProvider.
width: PropTypes.number,
// If true, the container height swells and contracts to fit contents
autoSize: PropTypes.bool,
// # of cols.
cols: PropTypes.number,
// A selector that will not be draggable.
draggableCancel: PropTypes.string,
// A selector for the draggable handler
draggableHandle: PropTypes.string,
// Deprecated
verticalCompact: function(props) {
if (props.verticalCompact === false && process.env.NODE_ENV !== 'production') {
console.warn( // eslint-disable-line no-console
'`verticalCompact` on <ReactGridLayout> is deprecated and will be removed soon. ' +
'Use `compactType`: "horizontal" | "vertical" | null.');
}
},
// Choose vertical or hotizontal compaction
compactType: PropTypes.oneOf(['vertical', 'horizontal']),
// layout is an array of object with the format:
// {x: Number, y: Number, w: Number, h: Number, i: String}
layout: function (props) {
var layout = props.layout;
// I hope you're setting the data-grid property on the grid items
if (layout === undefined) return;
validateLayout(layout, 'layout');
},
//
// Grid Dimensions
//
// Margin between items [x, y] in px
margin: PropTypes.arrayOf(PropTypes.number),
// Padding inside the container [x, y] in px
containerPadding: PropTypes.arrayOf(PropTypes.number),
// Rows have a static height, but you can change this based on breakpoints if you like
rowHeight: PropTypes.number,
// Default Infinity, but you can specify a max here if you like.
// Note that this isn't fully fleshed out and won't error if you specify a layout that
// extends beyond the row capacity. It will, however, not allow users to drag/resize
// an item past the barrier. They can push items beyond the barrier, though.
// Intentionally not documented for this reason.
maxRows: PropTypes.number,
//
// Flags
//
isDraggable: PropTypes.bool,
isResizable: PropTypes.bool,
// If true, grid items won't change position when being dragged over.
preventCollision: PropTypes.bool,
// Use CSS transforms instead of top/left
useCSSTransforms: PropTypes.bool,
//
// Callbacks
//
// Callback so you can save the layout. Calls after each drag & resize stops.
onLayoutChange: PropTypes.func,
// Calls when drag starts. Callback is of the signature (layout, oldItem, newItem, placeholder, e, ?node).
// All callbacks below have the same signature. 'start' and 'stop' callbacks omit the 'placeholder'.
onDragStart: PropTypes.func,
// Calls on each drag movement.
onDrag: PropTypes.func,
// Calls when drag is complete.
onDragStop: PropTypes.func,
//Calls when resize starts.
onResizeStart: PropTypes.func,
// Calls when resize movement happens.
onResize: PropTypes.func,
// Calls when resize is complete.
onResizeStop: PropTypes.func,
//
// Other validations
//
// Children must not have duplicate keys.
children: function (props, propName, _componentName) {
var children = props[propName];
// Check children keys for duplicates. Throw if found.
var keys = {};
React.Children.forEach(children, function (child) {
if (keys[child.key]) {
throw new Error("Duplicate child key \"" + child.key + "\" found! This will cause problems in ReactGridLayout.");
}
keys[child.key] = true;
});
}
};
static defaultProps = {
autoSize: true,
cols: 12,
className: '',
rowHeight: 150,
maxRows: Infinity, // infinite vertical growth
layout: [],
margin: [10, 10],
isDraggable: true,
isResizable: true,
useCSSTransforms: true,
verticalCompact: true,
compactType: 'vertical',
preventCollision: false,
onLayoutChange: noop,
onDragStart: noop,
onDrag: noop,
onDragStop: noop,
onResizeStart: noop,
onResize: noop,
onResizeStop: noop
};
state: State = {
activeDrag: null,
layout: synchronizeLayoutWithChildren(this.props.layout, this.props.children, this.props.cols,
// Legacy support for verticalCompact: false
this.compactType()),
mounted: false,
oldDragItem: null,
oldLayout: null,
oldResizeItem: null,
};
constructor(props: Props, context: any): void {
super(props, context);
autoBindHandlers(this, ['onDragStart', 'onDrag', 'onDragStop', 'onResizeStart', 'onResize', 'onResizeStop']);
}
componentDidMount() {
this.setState({mounted: true});
// Possibly call back with layout on mount. This should be done after correcting the layout width
// to ensure we don't rerender with the wrong width.
this.onLayoutMaybeChanged(this.state.layout, this.props.layout);
}
componentWillReceiveProps(nextProps: Props) {
let newLayoutBase;
// Legacy support for compactType
// Allow parent to set layout directly.
if (!isEqual(nextProps.layout, this.props.layout) || nextProps.compactType !== this.props.compactType) {
newLayoutBase = nextProps.layout;
}
// If children change, also regenerate the layout. Use our state
// as the base in case because it may be more up to date than
// what is in props.
else if (!childrenEqual(this.props.children, nextProps.children)) {
newLayoutBase = this.state.layout;
}
// We need to regenerate the layout.
if (newLayoutBase) {
const newLayout = synchronizeLayoutWithChildren(newLayoutBase, nextProps.children,
nextProps.cols, this.compactType(nextProps));
const oldLayout = this.state.layout;
this.setState({layout: newLayout});
this.onLayoutMaybeChanged(newLayout, oldLayout);
}
}
/**
* Calculates a pixel value for the container.
* @return {String} Container height in pixels.
*/
containerHeight() {
if (!this.props.autoSize) return;
const nbRow = bottom(this.state.layout);
const containerPaddingY = this.props.containerPadding ? this.props.containerPadding[1] : this.props.margin[1];
return nbRow * this.props.rowHeight + (nbRow - 1) * this.props.margin[1] + containerPaddingY * 2 + 'px';
}
compactType(props: ?Object): CompactType {
if (!props) props = this.props;
return props.verticalCompact === false ? null : props.compactType;
}
/**
* When dragging starts
* @param {String} i Id of the child
* @param {Number} x X position of the move
* @param {Number} y Y position of the move
* @param {Event} e The mousedown event
* @param {Element} node The current dragging DOM element
*/
onDragStart(i:string, x:number, y:number, {e, node}: GridDragEvent) {
const {layout} = this.state;
var l = getLayoutItem(layout, i);
if (!l) return;
this.setState({oldDragItem: cloneLayoutItem(l), oldLayout: this.state.layout});
this.props.onDragStart(layout, l, l, null, e, node);
}
/**
* Each drag movement create a new dragelement and move the element to the dragged location
* @param {String} i Id of the child
* @param {Number} x X position of the move
* @param {Number} y Y position of the move
* @param {Event} e The mousedown event
* @param {Element} node The current dragging DOM element
*/
onDrag(i:string, x:number, y:number, {e, node}: GridDragEvent) {
const {oldDragItem} = this.state;
let {layout} = this.state;
const {cols} = this.props;
var l = getLayoutItem(layout, i);
if (!l) return;
// Create placeholder (display only)
var placeholder = {
w: l.w, h: l.h, x: l.x, y: l.y, placeholder: true, i: i
};
// Move the element to the dragged location.
const isUserAction = true;
layout = moveElement(layout, l, x, y, isUserAction, this.props.preventCollision, this.compactType(), cols);
this.props.onDrag(layout, oldDragItem, l, placeholder, e, node);
this.setState({
layout: compact(layout, this.compactType(), cols),
activeDrag: placeholder
});
}
/**
* When dragging stops, figure out which position the element is closest to and update its x and y.
* @param {String} i Index of the child.
* @param {Number} x X position of the move
* @param {Number} y Y position of the move
* @param {Event} e The mousedown event
* @param {Element} node The current dragging DOM element
*/
onDragStop(i:string, x:number, y:number, {e, node}: GridDragEvent) {
const {oldDragItem} = this.state;
let {layout} = this.state;
const {cols, preventCollision} = this.props;
const l = getLayoutItem(layout, i);
if (!l) return;
// Move the element here
const isUserAction = true;
layout = moveElement(layout, l, x, y, isUserAction, preventCollision, this.compactType(), cols);
this.props.onDragStop(layout, oldDragItem, l, null, e, node);
// Set state
const newLayout = compact(layout, this.compactType(), cols);
const {oldLayout} = this.state;
this.setState({
activeDrag: null,
layout: newLayout,
oldDragItem: null,
oldLayout: null,
});
this.onLayoutMaybeChanged(newLayout, oldLayout);
}
onLayoutMaybeChanged(newLayout: Layout, oldLayout: ?Layout) {
if (!oldLayout) oldLayout = this.state.layout;
if (!isEqual(oldLayout, newLayout)) {
this.props.onLayoutChange(newLayout);
}
}
onResizeStart(i:string, w:number, h:number, {e, node}: GridResizeEvent) {
const {layout} = this.state;
var l = getLayoutItem(layout, i);
if (!l) return;
this.setState({
oldResizeItem: cloneLayoutItem(l),
oldLayout: this.state.layout
});
this.props.onResizeStart(layout, l, l, null, e, node);
}
onResize(i:string, w:number, h:number, {e, node}: GridResizeEvent) {
const {layout, oldResizeItem} = this.state;
const {cols, preventCollision} = this.props;
var l = getLayoutItem(layout, i);
if (!l) return;
// Short circuit if there is a collision in no rearrangement mode.
if (preventCollision && getFirstCollision(layout, {...l, w, h})) {
return;
}
// Set new width and height.
l.w = w;
l.h = h;
// Create placeholder element (display only)
var placeholder = {
w: w, h: h, x: l.x, y: l.y, static: true, i: i
};
this.props.onResize(layout, oldResizeItem, l, placeholder, e, node);
// Re-compact the layout and set the drag placeholder.
this.setState({
layout: compact(layout, this.compactType(), cols),
activeDrag: placeholder
});
}
onResizeStop(i:string, w:number, h:number, {e, node}: GridResizeEvent) {
const {layout, oldResizeItem} = this.state;
const {cols} = this.props;
var l = getLayoutItem(layout, i);
this.props.onResizeStop(layout, oldResizeItem, l, null, e, node);
// Set state
const newLayout = compact(layout, this.compactType(), cols);
const {oldLayout} = this.state;
this.setState({
activeDrag: null,
layout: newLayout,
oldResizeItem: null,
oldLayout: null
});
this.onLayoutMaybeChanged(newLayout, oldLayout);
}
/**
* Create a placeholder object.
* @return {Element} Placeholder div.
*/
placeholder(): ?ReactElement<any> {
const {activeDrag} = this.state;
if (!activeDrag) return null;
const {width, cols, margin, containerPadding, rowHeight, maxRows, useCSSTransforms} = this.props;
// {...this.state.activeDrag} is pretty slow, actually
return (
<GridItem
w={activeDrag.w}
h={activeDrag.h}
x={activeDrag.x}
y={activeDrag.y}
i={activeDrag.i}
className="react-grid-placeholder"
containerWidth={width}
cols={cols}
margin={margin}
containerPadding={containerPadding || margin}
maxRows={maxRows}
rowHeight={rowHeight}
isDraggable={false}
isResizable={false}
useCSSTransforms={useCSSTransforms}>
<div />
</GridItem>
);
}
/**
* Given a grid item, set its style attributes & surround in a <Draggable>.
* @param {Element} child React element.
* @return {Element} Element wrapped in draggable and properly placed.
*/
processGridItem(child: ReactElement<any>): ?ReactElement<any> {
if (!child.key) return;
const l = getLayoutItem(this.state.layout, String(child.key));
if (!l) return null;
const {width, cols, margin, containerPadding, rowHeight,
maxRows, isDraggable, isResizable, useCSSTransforms,
draggableCancel, draggableHandle} = this.props;
const {mounted} = this.state;
// Parse 'static'. Any properties defined directly on the grid item will take precedence.
const draggable = Boolean(!l.static && isDraggable && (l.isDraggable || l.isDraggable == null));
const resizable = Boolean(!l.static && isResizable && (l.isResizable || l.isResizable == null));
return (
<GridItem
containerWidth={width}
cols={cols}
margin={margin}
containerPadding={containerPadding || margin}
maxRows={maxRows}
rowHeight={rowHeight}
cancel={draggableCancel}
handle={draggableHandle}
onDragStop={this.onDragStop}
onDragStart={this.onDragStart}
onDrag={this.onDrag}
onResizeStart={this.onResizeStart}
onResize={this.onResize}
onResizeStop={this.onResizeStop}
isDraggable={draggable}
isResizable={resizable}
useCSSTransforms={useCSSTransforms && mounted}
usePercentages={!mounted}
w={l.w}
h={l.h}
x={l.x}
y={l.y}
i={l.i}
minH={l.minH}
minW={l.minW}
maxH={l.maxH}
maxW={l.maxW}
static={l.static}
>
{child}
</GridItem>
);
}
render() {
const {className, style} = this.props;
const mergedStyle = {
height: this.containerHeight(),
...style
};
return (
<div className={classNames('react-grid-layout', className)} style={mergedStyle}>
{
// $FlowIgnore: Appears to think map calls back w/array
React.Children.map(this.props.children, (child) => this.processGridItem(child))
}
{this.placeholder()}
</div>
);
}
}

View File

@@ -0,0 +1,228 @@
'use strict';
exports.__esModule = true;
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _propTypes = require('prop-types');
var _propTypes2 = _interopRequireDefault(_propTypes);
var _lodash = require('lodash.isequal');
var _lodash2 = _interopRequireDefault(_lodash);
var _utils = require('./utils');
var _responsiveUtils = require('./responsiveUtils');
var _ReactGridLayout = require('./ReactGridLayout');
var _ReactGridLayout2 = _interopRequireDefault(_ReactGridLayout);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var noop = function noop() {};
var type = function type(obj) {
return Object.prototype.toString.call(obj);
};
var ResponsiveReactGridLayout = function (_React$Component) {
_inherits(ResponsiveReactGridLayout, _React$Component);
function ResponsiveReactGridLayout() {
var _temp, _this, _ret;
_classCallCheck(this, ResponsiveReactGridLayout);
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return _ret = (_temp = (_this = _possibleConstructorReturn(this, _React$Component.call.apply(_React$Component, [this].concat(args))), _this), _this.state = _this.generateInitialState(), _this.onLayoutChange = function (layout) {
var _extends2;
_this.props.onLayoutChange(layout, _extends({}, _this.props.layouts, (_extends2 = {}, _extends2[_this.state.breakpoint] = layout, _extends2)));
}, _temp), _possibleConstructorReturn(_this, _ret);
}
// This should only include propTypes needed in this code; RGL itself
// will do validation of the rest props passed to it.
ResponsiveReactGridLayout.prototype.generateInitialState = function generateInitialState() {
var _props = this.props,
width = _props.width,
breakpoints = _props.breakpoints,
layouts = _props.layouts,
cols = _props.cols;
var breakpoint = (0, _responsiveUtils.getBreakpointFromWidth)(breakpoints, width);
var colNo = (0, _responsiveUtils.getColsFromBreakpoint)(breakpoint, cols);
// verticalCompact compatibility, now deprecated
var compactType = this.props.verticalCompact === false ? null : this.props.compactType;
// Get the initial layout. This can tricky; we try to generate one however possible if one doesn't exist
// for this layout.
var initialLayout = (0, _responsiveUtils.findOrGenerateResponsiveLayout)(layouts, breakpoints, breakpoint, breakpoint, colNo, compactType);
return {
layout: initialLayout,
breakpoint: breakpoint,
cols: colNo
};
};
ResponsiveReactGridLayout.prototype.componentWillReceiveProps = function componentWillReceiveProps(nextProps) {
// Allow parent to set width or breakpoint directly.
if (nextProps.width != this.props.width || nextProps.breakpoint !== this.props.breakpoint || !(0, _lodash2.default)(nextProps.breakpoints, this.props.breakpoints) || !(0, _lodash2.default)(nextProps.cols, this.props.cols)) {
this.onWidthChange(nextProps);
}
// Allow parent to set layouts directly.
else if (!(0, _lodash2.default)(nextProps.layouts, this.props.layouts)) {
var _state = this.state,
_breakpoint = _state.breakpoint,
_cols = _state.cols;
// Since we're setting an entirely new layout object, we must generate a new responsive layout
// if one does not exist.
var newLayout = (0, _responsiveUtils.findOrGenerateResponsiveLayout)(nextProps.layouts, nextProps.breakpoints, _breakpoint, _breakpoint, _cols, nextProps.compactType);
this.setState({ layout: newLayout });
}
};
// wrap layouts so we do not need to pass layouts to child
/**
* When the width changes work through breakpoints and reset state with the new width & breakpoint.
* Width changes are necessary to figure out the widget widths.
*/
ResponsiveReactGridLayout.prototype.onWidthChange = function onWidthChange(nextProps) {
var breakpoints = nextProps.breakpoints,
cols = nextProps.cols,
layouts = nextProps.layouts,
compactType = nextProps.compactType;
var newBreakpoint = nextProps.breakpoint || (0, _responsiveUtils.getBreakpointFromWidth)(nextProps.breakpoints, nextProps.width);
var lastBreakpoint = this.state.breakpoint;
// Breakpoint change
if (lastBreakpoint !== newBreakpoint || this.props.breakpoints !== breakpoints || this.props.cols !== cols) {
// Preserve the current layout if the current breakpoint is not present in the next layouts.
if (!(lastBreakpoint in layouts)) layouts[lastBreakpoint] = (0, _utils.cloneLayout)(this.state.layout);
// Find or generate a new layout.
var newCols = (0, _responsiveUtils.getColsFromBreakpoint)(newBreakpoint, cols);
var _layout = (0, _responsiveUtils.findOrGenerateResponsiveLayout)(layouts, breakpoints, newBreakpoint, lastBreakpoint, newCols, compactType);
// This adds missing items.
_layout = (0, _utils.synchronizeLayoutWithChildren)(_layout, nextProps.children, newCols, compactType);
// Store the new layout.
layouts[newBreakpoint] = _layout;
// callbacks
this.props.onLayoutChange(_layout, layouts);
this.props.onBreakpointChange(newBreakpoint, newCols);
this.props.onWidthChange(nextProps.width, nextProps.margin, newCols, nextProps.containerPadding);
this.setState({ breakpoint: newBreakpoint, layout: _layout, cols: newCols });
}
};
ResponsiveReactGridLayout.prototype.render = function render() {
// eslint-disable-next-line no-unused-vars
var _props2 = this.props,
breakpoint = _props2.breakpoint,
breakpoints = _props2.breakpoints,
cols = _props2.cols,
layouts = _props2.layouts,
onBreakpointChange = _props2.onBreakpointChange,
onLayoutChange = _props2.onLayoutChange,
onWidthChange = _props2.onWidthChange,
other = _objectWithoutProperties(_props2, ['breakpoint', 'breakpoints', 'cols', 'layouts', 'onBreakpointChange', 'onLayoutChange', 'onWidthChange']);
return _react2.default.createElement(_ReactGridLayout2.default, _extends({}, other, {
onLayoutChange: this.onLayoutChange,
layout: this.state.layout,
cols: this.state.cols
}));
};
return ResponsiveReactGridLayout;
}(_react2.default.Component);
ResponsiveReactGridLayout.propTypes = {
//
// Basic props
//
// Optional, but if you are managing width yourself you may want to set the breakpoint
// yourself as well.
breakpoint: _propTypes2.default.string,
// {name: pxVal}, e.g. {lg: 1200, md: 996, sm: 768, xs: 480}
breakpoints: _propTypes2.default.object,
// # of cols. This is a breakpoint -> cols map
cols: _propTypes2.default.object,
// layouts is an object mapping breakpoints to layouts.
// e.g. {lg: Layout, md: Layout, ...}
layouts: function layouts(props, propName) {
if (type(props[propName]) !== '[object Object]') {
throw new Error('Layout property must be an object. Received: ' + type(props[propName]));
}
Object.keys(props[propName]).forEach(function (key) {
if (!(key in props.breakpoints)) {
throw new Error('Each key in layouts must align with a key in breakpoints.');
}
(0, _utils.validateLayout)(props.layouts[key], 'layouts.' + key);
});
},
// The width of this component.
// Required in this propTypes stanza because generateInitialState() will fail without it.
width: _propTypes2.default.number.isRequired,
//
// Callbacks
//
// Calls back with breakpoint and new # cols
onBreakpointChange: _propTypes2.default.func,
// Callback so you can save the layout.
// Calls back with (currentLayout, allLayouts). allLayouts are keyed by breakpoint.
onLayoutChange: _propTypes2.default.func,
// Calls back with (containerWidth, margin, cols, containerPadding)
onWidthChange: _propTypes2.default.func
};
ResponsiveReactGridLayout.defaultProps = {
breakpoints: { lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 },
cols: { lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 },
layouts: {},
onBreakpointChange: noop,
onLayoutChange: noop,
onWidthChange: noop
};
exports.default = ResponsiveReactGridLayout;

View File

@@ -0,0 +1,200 @@
// @flow
import React from 'react';
import PropTypes from 'prop-types';
import isEqual from 'lodash.isequal';
import {cloneLayout, synchronizeLayoutWithChildren, validateLayout} from './utils';
import {getBreakpointFromWidth, getColsFromBreakpoint, findOrGenerateResponsiveLayout} from './responsiveUtils';
import ReactGridLayout from './ReactGridLayout';
import type {Props as RGLProps} from './ReactGridLayout';
import type {Layout} from './utils';
const noop = function(){};
const type = (obj) => Object.prototype.toString.call(obj);
type State = {
layout: Layout,
breakpoint: string,
cols: number
};
type Props<Breakpoint: string = string> = {
...$Exact<RGLProps>,
// Responsive config
breakpoint: Breakpoint,
breakpoints: {[key: Breakpoint]: number},
cols: {[key: Breakpoint]: number},
layouts: {[key: Breakpoint]: Layout},
width: number,
// Callbacks
onBreakpointChange: (Breakpoint, cols: number) => void,
onLayoutChange: (Layout, {[key: Breakpoint]: Layout}) => void,
onWidthChange:
(containerWidth: number, margin: [number, number], cols: number, containerPadding: [number, number]) => void
};
export default class ResponsiveReactGridLayout extends React.Component<Props<>, State> {
// This should only include propTypes needed in this code; RGL itself
// will do validation of the rest props passed to it.
static propTypes = {
//
// Basic props
//
// Optional, but if you are managing width yourself you may want to set the breakpoint
// yourself as well.
breakpoint: PropTypes.string,
// {name: pxVal}, e.g. {lg: 1200, md: 996, sm: 768, xs: 480}
breakpoints: PropTypes.object,
// # of cols. This is a breakpoint -> cols map
cols: PropTypes.object,
// layouts is an object mapping breakpoints to layouts.
// e.g. {lg: Layout, md: Layout, ...}
layouts(props, propName) {
if (type(props[propName]) !== '[object Object]') {
throw new Error('Layout property must be an object. Received: ' + type(props[propName]));
}
Object.keys(props[propName]).forEach((key) => {
if (!(key in props.breakpoints)) {
throw new Error('Each key in layouts must align with a key in breakpoints.');
}
validateLayout(props.layouts[key], 'layouts.' + key);
});
},
// The width of this component.
// Required in this propTypes stanza because generateInitialState() will fail without it.
width: PropTypes.number.isRequired,
//
// Callbacks
//
// Calls back with breakpoint and new # cols
onBreakpointChange: PropTypes.func,
// Callback so you can save the layout.
// Calls back with (currentLayout, allLayouts). allLayouts are keyed by breakpoint.
onLayoutChange: PropTypes.func,
// Calls back with (containerWidth, margin, cols, containerPadding)
onWidthChange: PropTypes.func
};
static defaultProps = {
breakpoints: {lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0},
cols: {lg: 12, md: 10, sm: 6, xs: 4, xxs: 2},
layouts: {},
onBreakpointChange: noop,
onLayoutChange: noop,
onWidthChange: noop,
};
state = this.generateInitialState();
generateInitialState(): State {
const {width, breakpoints, layouts, cols} = this.props;
const breakpoint = getBreakpointFromWidth(breakpoints, width);
const colNo = getColsFromBreakpoint(breakpoint, cols);
// verticalCompact compatibility, now deprecated
const compactType = this.props.verticalCompact === false ? null : this.props.compactType;
// Get the initial layout. This can tricky; we try to generate one however possible if one doesn't exist
// for this layout.
const initialLayout = findOrGenerateResponsiveLayout(layouts, breakpoints, breakpoint,
breakpoint, colNo, compactType);
return {
layout: initialLayout,
breakpoint: breakpoint,
cols: colNo
};
}
componentWillReceiveProps(nextProps: Props<*>) {
// Allow parent to set width or breakpoint directly.
if (
nextProps.width != this.props.width
|| nextProps.breakpoint !== this.props.breakpoint
|| !isEqual(nextProps.breakpoints, this.props.breakpoints)
|| !isEqual(nextProps.cols, this.props.cols)
) {
this.onWidthChange(nextProps);
}
// Allow parent to set layouts directly.
else if (!isEqual(nextProps.layouts, this.props.layouts)) {
const {breakpoint, cols} = this.state;
// Since we're setting an entirely new layout object, we must generate a new responsive layout
// if one does not exist.
const newLayout = findOrGenerateResponsiveLayout(
nextProps.layouts, nextProps.breakpoints,
breakpoint, breakpoint, cols, nextProps.compactType
);
this.setState({layout: newLayout});
}
}
// wrap layouts so we do not need to pass layouts to child
onLayoutChange = (layout: Layout) => {
this.props.onLayoutChange(layout, {...this.props.layouts, [this.state.breakpoint]: layout});
};
/**
* When the width changes work through breakpoints and reset state with the new width & breakpoint.
* Width changes are necessary to figure out the widget widths.
*/
onWidthChange(nextProps: Props<*>) {
const {breakpoints, cols, layouts, compactType} = nextProps;
const newBreakpoint = nextProps.breakpoint || getBreakpointFromWidth(nextProps.breakpoints, nextProps.width);
const lastBreakpoint = this.state.breakpoint;
// Breakpoint change
if (lastBreakpoint !== newBreakpoint || this.props.breakpoints !== breakpoints || this.props.cols !== cols) {
// Preserve the current layout if the current breakpoint is not present in the next layouts.
if (!(lastBreakpoint in layouts)) layouts[lastBreakpoint] = cloneLayout(this.state.layout);
// Find or generate a new layout.
const newCols: number = getColsFromBreakpoint(newBreakpoint, cols);
let layout = findOrGenerateResponsiveLayout(layouts, breakpoints, newBreakpoint,
lastBreakpoint, newCols, compactType);
// This adds missing items.
layout = synchronizeLayoutWithChildren(layout, nextProps.children, newCols, compactType);
// Store the new layout.
layouts[newBreakpoint] = layout;
// callbacks
this.props.onLayoutChange(layout, layouts);
this.props.onBreakpointChange(newBreakpoint, newCols);
this.props.onWidthChange(nextProps.width, nextProps.margin, newCols, nextProps.containerPadding);
this.setState({breakpoint: newBreakpoint, layout: layout, cols: newCols});
}
}
render() {
// eslint-disable-next-line no-unused-vars
const {breakpoint, breakpoints, cols, layouts, onBreakpointChange, onLayoutChange, onWidthChange,
...other} = this.props;
return (
<ReactGridLayout
{...other}
onLayoutChange={this.onLayoutChange}
layout={this.state.layout}
cols={this.state.cols}
/>
);
}
}

View File

@@ -0,0 +1,87 @@
'use strict';
exports.__esModule = true;
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _propTypes = require('prop-types');
var _propTypes2 = _interopRequireDefault(_propTypes);
var _reactDom = require('react-dom');
var _reactDom2 = _interopRequireDefault(_reactDom);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
/*
* A simple HOC that provides facility for listening to container resizes.
*/
var WidthProvider = function WidthProvider(ComposedComponent) {
var _class, _temp2;
return _temp2 = _class = function (_React$Component) {
_inherits(_class, _React$Component);
function _class() {
var _temp, _this, _ret;
_classCallCheck(this, _class);
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return _ret = (_temp = (_this = _possibleConstructorReturn(this, _React$Component.call.apply(_React$Component, [this].concat(args))), _this), _this.state = {
width: 1280
}, _this.mounted = false, _this.onWindowResize = function (_event) {
if (!_this.mounted) return;
var node = _reactDom2.default.findDOMNode(_this); // Flow casts this to Text | Element
if (node instanceof HTMLElement) _this.setState({ width: node.offsetWidth });
}, _temp), _possibleConstructorReturn(_this, _ret);
}
_class.prototype.componentDidMount = function componentDidMount() {
this.mounted = true;
window.addEventListener('resize', this.onWindowResize);
// Call to properly set the breakpoint and resize the elements.
// Note that if you're doing a full-width element, this can get a little wonky if a scrollbar
// appears because of the grid. In that case, fire your own resize event, or set `overflow: scroll` on your body.
this.onWindowResize();
};
_class.prototype.componentWillUnmount = function componentWillUnmount() {
this.mounted = false;
window.removeEventListener('resize', this.onWindowResize);
};
_class.prototype.render = function render() {
if (this.props.measureBeforeMount && !this.mounted) {
return _react2.default.createElement('div', { className: this.props.className, style: this.props.style });
}
return _react2.default.createElement(ComposedComponent, _extends({}, this.props, this.state));
};
return _class;
}(_react2.default.Component), _class.defaultProps = {
measureBeforeMount: false
}, _class.propTypes = {
// If true, will not render children until mounted. Useful for getting the exact width before
// rendering, to prevent any unsightly resizing.
measureBeforeMount: _propTypes2.default.bool
}, _temp2;
};
exports.default = WidthProvider;

View File

@@ -0,0 +1,69 @@
// @flow
import React from "react";
import PropTypes from 'prop-types';
import ReactDOM from 'react-dom';
import type {ComponentType as ReactComponentType} from 'react';
type Props = {
className?: string,
measureBeforeMount: boolean,
style?: Object,
};
type State = {
width: number
};
/*
* A simple HOC that provides facility for listening to container resizes.
*/
type ProviderT = (ComposedComponent: ReactComponentType<any>) => ReactComponentType<any>;
const WidthProvider: ProviderT = (ComposedComponent) => class extends React.Component<Props, State> {
static defaultProps = {
measureBeforeMount: false
};
static propTypes = {
// If true, will not render children until mounted. Useful for getting the exact width before
// rendering, to prevent any unsightly resizing.
measureBeforeMount: PropTypes.bool
};
state: State = {
width: 1280
};
mounted: boolean = false;
componentDidMount() {
this.mounted = true;
window.addEventListener('resize', this.onWindowResize);
// Call to properly set the breakpoint and resize the elements.
// Note that if you're doing a full-width element, this can get a little wonky if a scrollbar
// appears because of the grid. In that case, fire your own resize event, or set `overflow: scroll` on your body.
this.onWindowResize();
}
componentWillUnmount() {
this.mounted = false;
window.removeEventListener('resize', this.onWindowResize);
}
onWindowResize = (_event: ?Event) => {
if (!this.mounted) return;
const node = ReactDOM.findDOMNode(this); // Flow casts this to Text | Element
if (node instanceof HTMLElement) this.setState({width: node.offsetWidth});
}
render() {
if (this.props.measureBeforeMount && !this.mounted) {
return <div className={this.props.className} style={this.props.style} />;
}
return <ComposedComponent {...this.props} {...this.state} />;
}
};
export default WidthProvider;

View File

@@ -0,0 +1,87 @@
'use strict';
exports.__esModule = true;
exports.getBreakpointFromWidth = getBreakpointFromWidth;
exports.getColsFromBreakpoint = getColsFromBreakpoint;
exports.findOrGenerateResponsiveLayout = findOrGenerateResponsiveLayout;
exports.sortBreakpoints = sortBreakpoints;
var _utils = require('./utils');
/**
* Given a width, find the highest breakpoint that matches is valid for it (width > breakpoint).
*
* @param {Object} breakpoints Breakpoints object (e.g. {lg: 1200, md: 960, ...})
* @param {Number} width Screen width.
* @return {String} Highest breakpoint that is less than width.
*/
function getBreakpointFromWidth(breakpoints, width) {
var sorted = sortBreakpoints(breakpoints);
var matching = sorted[0];
for (var i = 1, len = sorted.length; i < len; i++) {
var breakpointName = sorted[i];
if (width > breakpoints[breakpointName]) matching = breakpointName;
}
return matching;
}
/**
* Given a breakpoint, get the # of cols set for it.
* @param {String} breakpoint Breakpoint name.
* @param {Object} cols Map of breakpoints to cols.
* @return {Number} Number of cols.
*/
function getColsFromBreakpoint(breakpoint, cols) {
if (!cols[breakpoint]) {
throw new Error("ResponsiveReactGridLayout: `cols` entry for breakpoint " + breakpoint + " is missing!");
}
return cols[breakpoint];
}
/**
* Given existing layouts and a new breakpoint, find or generate a new layout.
*
* This finds the layout above the new one and generates from it, if it exists.
*
* @param {Object} layouts Existing layouts.
* @param {Array} breakpoints All breakpoints.
* @param {String} breakpoint New breakpoint.
* @param {String} breakpoint Last breakpoint (for fallback).
* @param {Number} cols Column count at new breakpoint.
* @param {Boolean} verticalCompact Whether or not to compact the layout
* vertically.
* @return {Array} New layout.
*/
function findOrGenerateResponsiveLayout(layouts, breakpoints, breakpoint, lastBreakpoint, cols, compactType) {
// If it already exists, just return it.
if (layouts[breakpoint]) return (0, _utils.cloneLayout)(layouts[breakpoint]);
// Find or generate the next layout
var layout = layouts[lastBreakpoint];
var breakpointsSorted = sortBreakpoints(breakpoints);
var breakpointsAbove = breakpointsSorted.slice(breakpointsSorted.indexOf(breakpoint));
for (var i = 0, len = breakpointsAbove.length; i < len; i++) {
var b = breakpointsAbove[i];
if (layouts[b]) {
layout = layouts[b];
break;
}
}
layout = (0, _utils.cloneLayout)(layout || []); // clone layout so we don't modify existing items
return (0, _utils.compact)((0, _utils.correctBounds)(layout, { cols: cols }), compactType, cols);
}
/**
* Given breakpoints, return an array of breakpoints sorted by width. This is usually
* e.g. ['xxs', 'xs', 'sm', ...]
*
* @param {Object} breakpoints Key/value pair of breakpoint names to widths.
* @return {Array} Sorted breakpoints.
*/
function sortBreakpoints(breakpoints) {
var keys = Object.keys(breakpoints);
return keys.sort(function (a, b) {
return breakpoints[a] - breakpoints[b];
});
}

View File

@@ -0,0 +1,87 @@
// @flow
import {cloneLayout, compact, correctBounds} from './utils';
import type {CompactType, Layout} from './utils';
export type ResponsiveLayout = {lg?: Layout, md?: Layout, sm?: Layout, xs?: Layout, xxs?: Layout};
type Breakpoint = string;
type Breakpoints = {lg?: number, md?: number, sm?: number, xs?: number, xxs?: number};
/**
* Given a width, find the highest breakpoint that matches is valid for it (width > breakpoint).
*
* @param {Object} breakpoints Breakpoints object (e.g. {lg: 1200, md: 960, ...})
* @param {Number} width Screen width.
* @return {String} Highest breakpoint that is less than width.
*/
export function getBreakpointFromWidth(breakpoints: Breakpoints, width: number): Breakpoint {
const sorted = sortBreakpoints(breakpoints);
let matching = sorted[0];
for (let i = 1, len = sorted.length; i < len; i++) {
const breakpointName = sorted[i];
if (width > breakpoints[breakpointName]) matching = breakpointName;
}
return matching;
}
/**
* Given a breakpoint, get the # of cols set for it.
* @param {String} breakpoint Breakpoint name.
* @param {Object} cols Map of breakpoints to cols.
* @return {Number} Number of cols.
*/
export function getColsFromBreakpoint(breakpoint: Breakpoint, cols: Breakpoints): number {
if (!cols[breakpoint]) {
throw new Error("ResponsiveReactGridLayout: `cols` entry for breakpoint " + breakpoint + " is missing!");
}
return cols[breakpoint];
}
/**
* Given existing layouts and a new breakpoint, find or generate a new layout.
*
* This finds the layout above the new one and generates from it, if it exists.
*
* @param {Object} layouts Existing layouts.
* @param {Array} breakpoints All breakpoints.
* @param {String} breakpoint New breakpoint.
* @param {String} breakpoint Last breakpoint (for fallback).
* @param {Number} cols Column count at new breakpoint.
* @param {Boolean} verticalCompact Whether or not to compact the layout
* vertically.
* @return {Array} New layout.
*/
export function findOrGenerateResponsiveLayout(layouts: ResponsiveLayout, breakpoints: Breakpoints,
breakpoint: Breakpoint, lastBreakpoint: Breakpoint,
cols: number, compactType: CompactType): Layout {
// If it already exists, just return it.
if (layouts[breakpoint]) return cloneLayout(layouts[breakpoint]);
// Find or generate the next layout
let layout = layouts[lastBreakpoint];
const breakpointsSorted = sortBreakpoints(breakpoints);
const breakpointsAbove = breakpointsSorted.slice(breakpointsSorted.indexOf(breakpoint));
for (let i = 0, len = breakpointsAbove.length; i < len; i++) {
const b = breakpointsAbove[i];
if (layouts[b]) {
layout = layouts[b];
break;
}
}
layout = cloneLayout(layout || []); // clone layout so we don't modify existing items
return compact(correctBounds(layout, {cols: cols}), compactType, cols);
}
/**
* Given breakpoints, return an array of breakpoints sorted by width. This is usually
* e.g. ['xxs', 'xs', 'sm', ...]
*
* @param {Object} breakpoints Key/value pair of breakpoint names to widths.
* @return {Array} Sorted breakpoints.
*/
export function sortBreakpoints(breakpoints: Breakpoints): Array<Breakpoint> {
const keys: Array<string> = Object.keys(breakpoints);
return keys.sort(function(a, b) {
return breakpoints[a] - breakpoints[b];
});
}

View File

@@ -0,0 +1,511 @@
'use strict';
exports.__esModule = true;
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
exports.bottom = bottom;
exports.cloneLayout = cloneLayout;
exports.cloneLayoutItem = cloneLayoutItem;
exports.childrenEqual = childrenEqual;
exports.collides = collides;
exports.compact = compact;
exports.compactItem = compactItem;
exports.correctBounds = correctBounds;
exports.getLayoutItem = getLayoutItem;
exports.getFirstCollision = getFirstCollision;
exports.getAllCollisions = getAllCollisions;
exports.getStatics = getStatics;
exports.moveElement = moveElement;
exports.moveElementAwayFromCollision = moveElementAwayFromCollision;
exports.perc = perc;
exports.setTransform = setTransform;
exports.setTopLeft = setTopLeft;
exports.sortLayoutItems = sortLayoutItems;
exports.sortLayoutItemsByRowCol = sortLayoutItemsByRowCol;
exports.sortLayoutItemsByColRow = sortLayoutItemsByColRow;
exports.synchronizeLayoutWithChildren = synchronizeLayoutWithChildren;
exports.validateLayout = validateLayout;
exports.autoBindHandlers = autoBindHandlers;
var _lodash = require('lodash.isequal');
var _lodash2 = _interopRequireDefault(_lodash);
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// All callbacks are of the signature (layout, oldItem, newItem, placeholder, e).
var isProduction = process.env.NODE_ENV === 'production';
/**
* Return the bottom coordinate of the layout.
*
* @param {Array} layout Layout array.
* @return {Number} Bottom coordinate.
*/
function bottom(layout) {
var max = 0,
bottomY = void 0;
for (var _i = 0, len = layout.length; _i < len; _i++) {
bottomY = layout[_i].y + layout[_i].h;
if (bottomY > max) max = bottomY;
}
return max;
}
function cloneLayout(layout) {
var newLayout = Array(layout.length);
for (var _i2 = 0, len = layout.length; _i2 < len; _i2++) {
newLayout[_i2] = cloneLayoutItem(layout[_i2]);
}
return newLayout;
}
// Fast path to cloning, since this is monomorphic
function cloneLayoutItem(layoutItem) {
return {
w: layoutItem.w, h: layoutItem.h, x: layoutItem.x, y: layoutItem.y, i: layoutItem.i,
minW: layoutItem.minW, maxW: layoutItem.maxW, minH: layoutItem.minH, maxH: layoutItem.maxH,
moved: Boolean(layoutItem.moved), static: Boolean(layoutItem.static),
// These can be null
isDraggable: layoutItem.isDraggable, isResizable: layoutItem.isResizable
};
}
/**
* Comparing React `children` is a bit difficult. This is a good way to compare them.
* This will catch differences in keys, order, and length.
*/
function childrenEqual(a, b) {
// $FlowIgnore: Appears to think map calls back w/array
return (0, _lodash2.default)(_react2.default.Children.map(a, function (c) {
return c.key;
}), _react2.default.Children.map(b, function (c) {
return c.key;
}));
}
/**
* Given two layoutitems, check if they collide.
*/
function collides(l1, l2) {
if (l1 === l2) return false; // same element
if (l1.x + l1.w <= l2.x) return false; // l1 is left of l2
if (l1.x >= l2.x + l2.w) return false; // l1 is right of l2
if (l1.y + l1.h <= l2.y) return false; // l1 is above l2
if (l1.y >= l2.y + l2.h) return false; // l1 is below l2
return true; // boxes overlap
}
/**
* Given a layout, compact it. This involves going down each y coordinate and removing gaps
* between items.
*
* @param {Array} layout Layout.
* @param {Boolean} verticalCompact Whether or not to compact the layout
* vertically.
* @return {Array} Compacted Layout.
*/
function compact(layout, compactType, cols) {
// Statics go in the compareWith array right away so items flow around them.
var compareWith = getStatics(layout);
// We go through the items by row and column.
var sorted = sortLayoutItems(layout, compactType);
// Holding for new items.
var out = Array(layout.length);
for (var _i3 = 0, len = sorted.length; _i3 < len; _i3++) {
var l = cloneLayoutItem(sorted[_i3]);
// Don't move static elements
if (!l.static) {
l = compactItem(compareWith, l, compactType, cols);
// Add to comparison array. We only collide with items before this one.
// Statics are already in this array.
compareWith.push(l);
}
// Add to output array to make sure they still come out in the right order.
out[layout.indexOf(sorted[_i3])] = l;
// Clear moved flag, if it exists.
l.moved = false;
}
return out;
}
/**
* Compact an item in the layout.
*/
function compactItem(compareWith, l, compactType, cols) {
var compactV = compactType === 'vertical';
var compactH = compactType === 'horizontal';
if (compactV) {
// Bottom 'y' possible is the bottom of the layout.
// This allows you to do nice stuff like specify {y: Infinity}
// This is here because the layout must be sorted in order to get the correct bottom `y`.
l.y = Math.min(bottom(compareWith), l.y);
// Move the element up as far as it can go without colliding.
while (l.y > 0 && !getFirstCollision(compareWith, l)) {
l.y--;
}
} else if (compactH) {
l.y = Math.min(bottom(compareWith), l.y);
// Move the element left as far as it can go without colliding.
while (l.x > 0 && !getFirstCollision(compareWith, l)) {
l.x--;
}
}
// Move it down, and keep moving it down if it's colliding.
var collides = void 0;
while (collides = getFirstCollision(compareWith, l)) {
if (compactH) {
l.x = collides.x + collides.w;
} else {
l.y = collides.y + collides.h;
}
// Since we can't grow without bounds horizontally, if we've overflown, let's move it down and try again.
if (compactH && l.x + l.w > cols) {
l.x = cols - l.w;
l.y++;
}
}
return l;
}
/**
* Given a layout, make sure all elements fit within its bounds.
*
* @param {Array} layout Layout array.
* @param {Number} bounds Number of columns.
*/
function correctBounds(layout, bounds) {
var collidesWith = getStatics(layout);
for (var _i4 = 0, len = layout.length; _i4 < len; _i4++) {
var l = layout[_i4];
// Overflows right
if (l.x + l.w > bounds.cols) l.x = bounds.cols - l.w;
// Overflows left
if (l.x < 0) {
l.x = 0;
l.w = bounds.cols;
}
if (!l.static) collidesWith.push(l);else {
// If this is static and collides with other statics, we must move it down.
// We have to do something nicer than just letting them overlap.
while (getFirstCollision(collidesWith, l)) {
l.y++;
}
}
}
return layout;
}
/**
* Get a layout item by ID. Used so we can override later on if necessary.
*
* @param {Array} layout Layout array.
* @param {String} id ID
* @return {LayoutItem} Item at ID.
*/
function getLayoutItem(layout, id) {
for (var _i5 = 0, len = layout.length; _i5 < len; _i5++) {
if (layout[_i5].i === id) return layout[_i5];
}
}
/**
* Returns the first item this layout collides with.
* It doesn't appear to matter which order we approach this from, although
* perhaps that is the wrong thing to do.
*
* @param {Object} layoutItem Layout item.
* @return {Object|undefined} A colliding layout item, or undefined.
*/
function getFirstCollision(layout, layoutItem) {
for (var _i6 = 0, len = layout.length; _i6 < len; _i6++) {
if (collides(layout[_i6], layoutItem)) return layout[_i6];
}
}
function getAllCollisions(layout, layoutItem) {
return layout.filter(function (l) {
return collides(l, layoutItem);
});
}
/**
* Get all static elements.
* @param {Array} layout Array of layout objects.
* @return {Array} Array of static layout items..
*/
function getStatics(layout) {
return layout.filter(function (l) {
return l.static;
});
}
/**
* Move an element. Responsible for doing cascading movements of other elements.
*
* @param {Array} layout Full layout to modify.
* @param {LayoutItem} l element to move.
* @param {Number} [x] X position in grid units.
* @param {Number} [y] Y position in grid units.
* @param {Boolean} [isUserAction] If true, designates that the item we're moving is
* being dragged/resized by the user.
*/
function moveElement(layout, l, x, y, isUserAction, preventCollision, compactType, cols) {
if (l.static) return layout;
// Short-circuit if nothing to do.
if (l.y === y && l.x === x) return layout;
var oldX = l.x;
var oldY = l.y;
var movingUp = y && l.y > y;
// This is quite a bit faster than extending the object
if (typeof x === 'number') l.x = x;
if (typeof y === 'number') l.y = y;
l.moved = true;
// If this collides with anything, move it.
// When doing this comparison, we have to sort the items we compare with
// to ensure, in the case of multiple collisions, that we're getting the
// nearest collision.
var sorted = sortLayoutItems(layout, compactType);
if (movingUp) sorted = sorted.reverse();
var collisions = getAllCollisions(sorted, l);
// There was a collision; abort
if (preventCollision && collisions.length) {
l.x = oldX;
l.y = oldY;
l.moved = false;
return layout;
}
// Move each item that collides away from this element.
for (var _i7 = 0, len = collisions.length; _i7 < len; _i7++) {
var collision = collisions[_i7];
// console.log('resolving collision between', l.i, 'at', l.y, 'and', collision.i, 'at', collision.y);
// Short circuit so we can't infinite loop
if (collision.moved) continue;
// This makes it feel a bit more precise by waiting to swap for just a bit when moving up.
if (l.y > collision.y && l.y - collision.y > collision.h / 4) continue;
if (l.x > collision.x && l.x - collision.x > collision.w / 4) continue;
// Don't move static items - we have to move *this* element away
if (collision.static) {
layout = moveElementAwayFromCollision(layout, collision, l, isUserAction, compactType, cols);
} else {
layout = moveElementAwayFromCollision(layout, l, collision, isUserAction, compactType, cols);
}
}
return layout;
}
/**
* This is where the magic needs to happen - given a collision, move an element away from the collision.
* We attempt to move it up if there's room, otherwise it goes below.
*
* @param {Array} layout Full layout to modify.
* @param {LayoutItem} collidesWith Layout item we're colliding with.
* @param {LayoutItem} itemToMove Layout item we're moving.
* @param {Boolean} [isUserAction] If true, designates that the item we're moving is being dragged/resized
* by the user.
*/
function moveElementAwayFromCollision(layout, collidesWith, itemToMove, isUserAction, compactType, cols) {
var compactH = compactType === 'horizontal';
var compactV = compactType === 'vertical';
var preventCollision = false; // we're already colliding
// If there is enough space above the collision to put this element, move it there.
// We only do this on the main collision as this can get funky in cascades and cause
// unwanted swapping behavior.
if (isUserAction) {
// Make a mock item so we don't modify the item here, only modify in moveElement.
var fakeItem = {
x: compactH ? Math.max(collidesWith.x - itemToMove.w, 0) : itemToMove.x,
y: !compactH ? Math.max(collidesWith.y - itemToMove.h, 0) : itemToMove.y,
w: itemToMove.w,
h: itemToMove.h,
i: '-1'
};
if (!getFirstCollision(layout, fakeItem)) {
return moveElement(layout, itemToMove, compactH ? fakeItem.x : undefined, compactV ? fakeItem.y + 1 : undefined, isUserAction, preventCollision, compactType, cols);
}
}
// Previously this was optimized to move below the collision directly, but this can cause problems
// with cascading moves, as an item may actually leapflog a collision and cause a reversal in order.
return moveElement(layout, itemToMove, compactH ? itemToMove.x + 1 : undefined, compactV ? itemToMove.y + 1 : undefined, isUserAction, preventCollision, compactType, cols);
}
/**
* Helper to convert a number to a percentage string.
*
* @param {Number} num Any number
* @return {String} That number as a percentage.
*/
function perc(num) {
return num * 100 + '%';
}
function setTransform(_ref) {
var top = _ref.top,
left = _ref.left,
width = _ref.width,
height = _ref.height;
// Replace unitless items with px
var translate = 'translate(' + left + 'px,' + top + 'px)';
return {
transform: translate,
WebkitTransform: translate,
MozTransform: translate,
msTransform: translate,
OTransform: translate,
width: width + 'px',
height: height + 'px',
position: 'absolute'
};
}
function setTopLeft(_ref2) {
var top = _ref2.top,
left = _ref2.left,
width = _ref2.width,
height = _ref2.height;
return {
top: top + 'px',
left: left + 'px',
width: width + 'px',
height: height + 'px',
position: 'absolute'
};
}
/**
* Get layout items sorted from top left to right and down.
*
* @return {Array} Array of layout objects.
* @return {Array} Layout, sorted static items first.
*/
function sortLayoutItems(layout, compactType) {
if (compactType === 'horizontal') return sortLayoutItemsByColRow(layout);else return sortLayoutItemsByRowCol(layout);
}
function sortLayoutItemsByRowCol(layout) {
return [].concat(layout).sort(function (a, b) {
if (a.y > b.y || a.y === b.y && a.x > b.x) {
return 1;
} else if (a.y === b.y && a.x === b.x) {
// Without this, we can get different sort results in IE vs. Chrome/FF
return 0;
}
return -1;
});
}
function sortLayoutItemsByColRow(layout) {
return [].concat(layout).sort(function (a, b) {
if (a.x > b.x || a.x === b.x && a.y > b.y) {
return 1;
}
return -1;
});
}
/**
* Generate a layout using the initialLayout and children as a template.
* Missing entries will be added, extraneous ones will be truncated.
*
* @param {Array} initialLayout Layout passed in through props.
* @param {String} breakpoint Current responsive breakpoint.
* @param {?String} compact Compaction option.
* @return {Array} Working layout.
*/
function synchronizeLayoutWithChildren(initialLayout, children, cols, compactType) {
initialLayout = initialLayout || [];
// Generate one layout item per child.
var layout = [];
_react2.default.Children.forEach(children, function (child, i) {
// Don't overwrite if it already exists.
var exists = getLayoutItem(initialLayout, String(child.key));
if (exists) {
layout[i] = cloneLayoutItem(exists);
} else {
if (!isProduction && child.props._grid) {
console.warn('`_grid` properties on children have been deprecated as of React 15.2. ' + // eslint-disable-line
'Please use `data-grid` or add your properties directly to the `layout`.');
}
var g = child.props['data-grid'] || child.props._grid;
// Hey, this item has a data-grid property, use it.
if (g) {
if (!isProduction) {
validateLayout([g], 'ReactGridLayout.children');
}
layout[i] = cloneLayoutItem(_extends({}, g, { i: child.key }));
} else {
// Nothing provided: ensure this is added to the bottom
layout[i] = cloneLayoutItem({ w: 1, h: 1, x: 0, y: bottom(layout), i: String(child.key) });
}
}
});
// Correct the layout.
layout = correctBounds(layout, { cols: cols });
layout = compact(layout, compactType, cols);
return layout;
}
/**
* Validate a layout. Throws errors.
*
* @param {Array} layout Array of layout items.
* @param {String} [contextName] Context name for errors.
* @throw {Error} Validation error.
*/
function validateLayout(layout, contextName) {
contextName = contextName || "Layout";
var subProps = ['x', 'y', 'w', 'h'];
if (!Array.isArray(layout)) throw new Error(contextName + " must be an array!");
for (var _i8 = 0, len = layout.length; _i8 < len; _i8++) {
var item = layout[_i8];
for (var j = 0; j < subProps.length; j++) {
if (typeof item[subProps[j]] !== 'number') {
throw new Error('ReactGridLayout: ' + contextName + '[' + _i8 + '].' + subProps[j] + ' must be a number!');
}
}
if (item.i && typeof item.i !== 'string') {
throw new Error('ReactGridLayout: ' + contextName + '[' + _i8 + '].i must be a string!');
}
if (item.static !== undefined && typeof item.static !== 'boolean') {
throw new Error('ReactGridLayout: ' + contextName + '[' + _i8 + '].static must be a boolean!');
}
}
}
// Flow can't really figure this out, so we just use Object
function autoBindHandlers(el, fns) {
fns.forEach(function (key) {
return el[key] = el[key].bind(el);
});
}

View File

@@ -0,0 +1,505 @@
// @flow
import isEqual from 'lodash.isequal';
import React from 'react';
import type {ChildrenArray as ReactChildrenArray, Element as ReactElement} from 'react';
export type LayoutItem = {
w: number, h: number, x: number, y: number, i: string,
minW?: number, minH?: number, maxW?: number, maxH?: number,
moved?: boolean, static?: boolean,
isDraggable?: ?boolean, isResizable?: ?boolean
};
export type Layout = Array<LayoutItem>;
export type Position = {left: number, top: number, width: number, height: number};
export type ReactDraggableCallbackData = {
node: HTMLElement,
x: number, y: number,
deltaX: number, deltaY: number,
lastX: number, lastY: number
};
export type PartialPosition = {left: number, top: number};
export type Size = {width: number, height: number};
export type GridDragEvent = {e: Event, node: HTMLElement, newPosition: PartialPosition};
export type GridResizeEvent = {e: Event, node: HTMLElement, size: Size};
type REl = ReactElement<any>;
export type ReactChildren = ReactChildrenArray<REl>;
// All callbacks are of the signature (layout, oldItem, newItem, placeholder, e).
export type EventCallback =
(Layout, oldItem: ?LayoutItem, newItem: ?LayoutItem, placeholder: ?LayoutItem, Event, ?HTMLElement) => void;
export type CompactType = ?('horizontal' | 'vertical');
const isProduction = process.env.NODE_ENV === 'production';
/**
* Return the bottom coordinate of the layout.
*
* @param {Array} layout Layout array.
* @return {Number} Bottom coordinate.
*/
export function bottom(layout: Layout): number {
let max = 0, bottomY;
for (let i = 0, len = layout.length; i < len; i++) {
bottomY = layout[i].y + layout[i].h;
if (bottomY > max) max = bottomY;
}
return max;
}
export function cloneLayout(layout: Layout): Layout {
const newLayout = Array(layout.length);
for (let i = 0, len = layout.length; i < len; i++) {
newLayout[i] = cloneLayoutItem(layout[i]);
}
return newLayout;
}
// Fast path to cloning, since this is monomorphic
export function cloneLayoutItem(layoutItem: LayoutItem): LayoutItem {
return {
w: layoutItem.w, h: layoutItem.h, x: layoutItem.x, y: layoutItem.y, i: layoutItem.i,
minW: layoutItem.minW, maxW: layoutItem.maxW, minH: layoutItem.minH, maxH: layoutItem.maxH,
moved: Boolean(layoutItem.moved), static: Boolean(layoutItem.static),
// These can be null
isDraggable: layoutItem.isDraggable, isResizable: layoutItem.isResizable
};
}
/**
* Comparing React `children` is a bit difficult. This is a good way to compare them.
* This will catch differences in keys, order, and length.
*/
export function childrenEqual(a: ReactChildren, b: ReactChildren): boolean {
// $FlowIgnore: Appears to think map calls back w/array
return isEqual(React.Children.map(a, (c) => c.key), React.Children.map(b, (c) => c.key));
}
/**
* Given two layoutitems, check if they collide.
*/
export function collides(l1: LayoutItem, l2: LayoutItem): boolean {
if (l1 === l2) return false; // same element
if (l1.x + l1.w <= l2.x) return false; // l1 is left of l2
if (l1.x >= l2.x + l2.w) return false; // l1 is right of l2
if (l1.y + l1.h <= l2.y) return false; // l1 is above l2
if (l1.y >= l2.y + l2.h) return false; // l1 is below l2
return true; // boxes overlap
}
/**
* Given a layout, compact it. This involves going down each y coordinate and removing gaps
* between items.
*
* @param {Array} layout Layout.
* @param {Boolean} verticalCompact Whether or not to compact the layout
* vertically.
* @return {Array} Compacted Layout.
*/
export function compact(layout: Layout, compactType: CompactType, cols: number): Layout {
// Statics go in the compareWith array right away so items flow around them.
const compareWith = getStatics(layout);
// We go through the items by row and column.
const sorted = sortLayoutItems(layout, compactType);
// Holding for new items.
const out = Array(layout.length);
for (let i = 0, len = sorted.length; i < len; i++) {
let l = cloneLayoutItem(sorted[i]);
// Don't move static elements
if (!l.static) {
l = compactItem(compareWith, l, compactType, cols);
// Add to comparison array. We only collide with items before this one.
// Statics are already in this array.
compareWith.push(l);
}
// Add to output array to make sure they still come out in the right order.
out[layout.indexOf(sorted[i])] = l;
// Clear moved flag, if it exists.
l.moved = false;
}
return out;
}
/**
* Compact an item in the layout.
*/
export function compactItem(compareWith: Layout, l: LayoutItem, compactType: CompactType, cols: number): LayoutItem {
const compactV = compactType === 'vertical';
const compactH = compactType === 'horizontal';
if (compactV) {
// Bottom 'y' possible is the bottom of the layout.
// This allows you to do nice stuff like specify {y: Infinity}
// This is here because the layout must be sorted in order to get the correct bottom `y`.
l.y = Math.min(bottom(compareWith), l.y);
// Move the element up as far as it can go without colliding.
while (l.y > 0 && !getFirstCollision(compareWith, l)) {
l.y--;
}
} else if (compactH) {
l.y = Math.min(bottom(compareWith), l.y);
// Move the element left as far as it can go without colliding.
while (l.x > 0 && !getFirstCollision(compareWith, l)) {
l.x--;
}
}
// Move it down, and keep moving it down if it's colliding.
let collides;
while((collides = getFirstCollision(compareWith, l))) {
if (compactH) {
l.x = collides.x + collides.w;
} else {
l.y = collides.y + collides.h;
}
// Since we can't grow without bounds horizontally, if we've overflown, let's move it down and try again.
if (compactH && l.x + l.w > cols) {
l.x = cols - l.w;
l.y++;
}
}
return l;
}
/**
* Given a layout, make sure all elements fit within its bounds.
*
* @param {Array} layout Layout array.
* @param {Number} bounds Number of columns.
*/
export function correctBounds(layout: Layout, bounds: {cols: number}): Layout {
const collidesWith = getStatics(layout);
for (let i = 0, len = layout.length; i < len; i++) {
const l = layout[i];
// Overflows right
if (l.x + l.w > bounds.cols) l.x = bounds.cols - l.w;
// Overflows left
if (l.x < 0) {
l.x = 0;
l.w = bounds.cols;
}
if (!l.static) collidesWith.push(l);
else {
// If this is static and collides with other statics, we must move it down.
// We have to do something nicer than just letting them overlap.
while(getFirstCollision(collidesWith, l)) {
l.y++;
}
}
}
return layout;
}
/**
* Get a layout item by ID. Used so we can override later on if necessary.
*
* @param {Array} layout Layout array.
* @param {String} id ID
* @return {LayoutItem} Item at ID.
*/
export function getLayoutItem(layout: Layout, id: string): ?LayoutItem {
for (let i = 0, len = layout.length; i < len; i++) {
if (layout[i].i === id) return layout[i];
}
}
/**
* Returns the first item this layout collides with.
* It doesn't appear to matter which order we approach this from, although
* perhaps that is the wrong thing to do.
*
* @param {Object} layoutItem Layout item.
* @return {Object|undefined} A colliding layout item, or undefined.
*/
export function getFirstCollision(layout: Layout, layoutItem: LayoutItem): ?LayoutItem {
for (let i = 0, len = layout.length; i < len; i++) {
if (collides(layout[i], layoutItem)) return layout[i];
}
}
export function getAllCollisions(layout: Layout, layoutItem: LayoutItem): Array<LayoutItem> {
return layout.filter((l) => collides(l, layoutItem));
}
/**
* Get all static elements.
* @param {Array} layout Array of layout objects.
* @return {Array} Array of static layout items..
*/
export function getStatics(layout: Layout): Array<LayoutItem> {
return layout.filter((l) => l.static);
}
/**
* Move an element. Responsible for doing cascading movements of other elements.
*
* @param {Array} layout Full layout to modify.
* @param {LayoutItem} l element to move.
* @param {Number} [x] X position in grid units.
* @param {Number} [y] Y position in grid units.
* @param {Boolean} [isUserAction] If true, designates that the item we're moving is
* being dragged/resized by the user.
*/
export function moveElement(layout: Layout, l: LayoutItem, x: ?number, y: ?number,
isUserAction: ?boolean, preventCollision: ?boolean,
compactType: CompactType, cols: number): Layout {
if (l.static) return layout;
// Short-circuit if nothing to do.
if (l.y === y && l.x === x) return layout;
const oldX = l.x;
const oldY = l.y;
const movingUp = y && l.y > y;
// This is quite a bit faster than extending the object
if (typeof x === 'number') l.x = x;
if (typeof y === 'number') l.y = y;
l.moved = true;
// If this collides with anything, move it.
// When doing this comparison, we have to sort the items we compare with
// to ensure, in the case of multiple collisions, that we're getting the
// nearest collision.
let sorted = sortLayoutItems(layout, compactType);
if (movingUp) sorted = sorted.reverse();
const collisions = getAllCollisions(sorted, l);
// There was a collision; abort
if (preventCollision && collisions.length) {
l.x = oldX;
l.y = oldY;
l.moved = false;
return layout;
}
// Move each item that collides away from this element.
for (let i = 0, len = collisions.length; i < len; i++) {
const collision = collisions[i];
// console.log('resolving collision between', l.i, 'at', l.y, 'and', collision.i, 'at', collision.y);
// Short circuit so we can't infinite loop
if (collision.moved) continue;
// This makes it feel a bit more precise by waiting to swap for just a bit when moving up.
if (l.y > collision.y && l.y - collision.y > collision.h / 4) continue;
if (l.x > collision.x && l.x - collision.x > collision.w / 4) continue;
// Don't move static items - we have to move *this* element away
if (collision.static) {
layout = moveElementAwayFromCollision(layout, collision, l, isUserAction, compactType, cols);
} else {
layout = moveElementAwayFromCollision(layout, l, collision, isUserAction, compactType, cols);
}
}
return layout;
}
/**
* This is where the magic needs to happen - given a collision, move an element away from the collision.
* We attempt to move it up if there's room, otherwise it goes below.
*
* @param {Array} layout Full layout to modify.
* @param {LayoutItem} collidesWith Layout item we're colliding with.
* @param {LayoutItem} itemToMove Layout item we're moving.
* @param {Boolean} [isUserAction] If true, designates that the item we're moving is being dragged/resized
* by the user.
*/
export function moveElementAwayFromCollision(layout: Layout, collidesWith: LayoutItem, itemToMove: LayoutItem,
isUserAction: ?boolean, compactType: CompactType, cols: number): Layout {
const compactH = compactType === 'horizontal';
const compactV = compactType === 'vertical';
const preventCollision = false; // we're already colliding
// If there is enough space above the collision to put this element, move it there.
// We only do this on the main collision as this can get funky in cascades and cause
// unwanted swapping behavior.
if (isUserAction) {
// Make a mock item so we don't modify the item here, only modify in moveElement.
const fakeItem: LayoutItem = {
x: compactH ? Math.max(collidesWith.x - itemToMove.w, 0) : itemToMove.x,
y: !compactH ? Math.max(collidesWith.y - itemToMove.h, 0) : itemToMove.y,
w: itemToMove.w,
h: itemToMove.h,
i: '-1'
};
if (!getFirstCollision(layout, fakeItem)) {
return moveElement(
layout,
itemToMove,
compactH ? fakeItem.x : undefined,
compactV ? fakeItem.y + 1 : undefined,
isUserAction,
preventCollision,
compactType,
cols
);
}
}
// Previously this was optimized to move below the collision directly, but this can cause problems
// with cascading moves, as an item may actually leapflog a collision and cause a reversal in order.
return moveElement(
layout,
itemToMove,
compactH ? itemToMove.x + 1 : undefined,
compactV ? itemToMove.y + 1 : undefined,
isUserAction,
preventCollision,
compactType,
cols
);
}
/**
* Helper to convert a number to a percentage string.
*
* @param {Number} num Any number
* @return {String} That number as a percentage.
*/
export function perc(num: number): string {
return num * 100 + '%';
}
export function setTransform({top, left, width, height}: Position): Object {
// Replace unitless items with px
const translate = `translate(${left}px,${top}px)`;
return {
transform: translate,
WebkitTransform: translate,
MozTransform: translate,
msTransform: translate,
OTransform: translate,
width: `${width}px`,
height: `${height}px`,
position: 'absolute'
};
}
export function setTopLeft({top, left, width, height}: Position): Object {
return {
top: `${top}px`,
left: `${left}px`,
width: `${width}px`,
height: `${height}px`,
position: 'absolute'
};
}
/**
* Get layout items sorted from top left to right and down.
*
* @return {Array} Array of layout objects.
* @return {Array} Layout, sorted static items first.
*/
export function sortLayoutItems(layout: Layout, compactType: CompactType): Layout {
if (compactType === 'horizontal') return sortLayoutItemsByColRow(layout);
else return sortLayoutItemsByRowCol(layout);
}
export function sortLayoutItemsByRowCol(layout: Layout): Layout {
return [].concat(layout).sort(function(a, b) {
if (a.y > b.y || (a.y === b.y && a.x > b.x)) {
return 1;
} else if (a.y === b.y && a.x === b.x) {
// Without this, we can get different sort results in IE vs. Chrome/FF
return 0;
}
return -1;
});
}
export function sortLayoutItemsByColRow(layout: Layout): Layout {
return [].concat(layout).sort(function(a, b) {
if (a.x > b.x || (a.x === b.x && a.y > b.y)) {
return 1;
}
return -1;
});
}
/**
* Generate a layout using the initialLayout and children as a template.
* Missing entries will be added, extraneous ones will be truncated.
*
* @param {Array} initialLayout Layout passed in through props.
* @param {String} breakpoint Current responsive breakpoint.
* @param {?String} compact Compaction option.
* @return {Array} Working layout.
*/
export function synchronizeLayoutWithChildren(initialLayout: Layout, children: ReactChildren,
cols: number, compactType: CompactType): Layout {
initialLayout = initialLayout || [];
// Generate one layout item per child.
let layout: Layout = [];
React.Children.forEach(children, (child: ReactElement<any>, i: number) => {
// Don't overwrite if it already exists.
const exists = getLayoutItem(initialLayout, String(child.key));
if (exists) {
layout[i] = cloneLayoutItem(exists);
} else {
if (!isProduction && child.props._grid) {
console.warn('`_grid` properties on children have been deprecated as of React 15.2. ' + // eslint-disable-line
'Please use `data-grid` or add your properties directly to the `layout`.');
}
const g = child.props['data-grid'] || child.props._grid;
// Hey, this item has a data-grid property, use it.
if (g) {
if (!isProduction) {
validateLayout([g], 'ReactGridLayout.children');
}
layout[i] = cloneLayoutItem({...g, i: child.key});
} else {
// Nothing provided: ensure this is added to the bottom
layout[i] = cloneLayoutItem({w: 1, h: 1, x: 0, y: bottom(layout), i: String(child.key)});
}
}
});
// Correct the layout.
layout = correctBounds(layout, {cols: cols});
layout = compact(layout, compactType, cols);
return layout;
}
/**
* Validate a layout. Throws errors.
*
* @param {Array} layout Array of layout items.
* @param {String} [contextName] Context name for errors.
* @throw {Error} Validation error.
*/
export function validateLayout(layout: Layout, contextName: string): void {
contextName = contextName || "Layout";
const subProps = ['x', 'y', 'w', 'h'];
if (!Array.isArray(layout)) throw new Error(contextName + " must be an array!");
for (let i = 0, len = layout.length; i < len; i++) {
const item = layout[i];
for (let j = 0; j < subProps.length; j++) {
if (typeof item[subProps[j]] !== 'number') {
throw new Error('ReactGridLayout: ' + contextName + '[' + i + '].' + subProps[j] + ' must be a number!');
}
}
if (item.i && typeof item.i !== 'string') {
throw new Error('ReactGridLayout: ' + contextName + '[' + i + '].i must be a string!');
}
if (item.static !== undefined && typeof item.static !== 'boolean') {
throw new Error('ReactGridLayout: ' + contextName + '[' + i + '].static must be a boolean!');
}
}
}
// Flow can't really figure this out, so we just use Object
export function autoBindHandlers(el: Object, fns: Array<string>): void {
fns.forEach((key) => el[key] = el[key].bind(el));
}

View File

@@ -0,0 +1,48 @@
.react-grid-layout {
position: relative;
transition: height 200ms ease;
}
.react-grid-item {
transition: all 200ms ease;
transition-property: left, top;
}
.react-grid-item.cssTransforms {
transition-property: transform;
}
.react-grid-item.resizing {
z-index: 1;
will-change: width, height;
}
.react-grid-item.react-draggable-dragging {
transition: none;
z-index: 3;
will-change: transform;
}
.react-grid-item.react-grid-placeholder {
background: red;
opacity: 0.2;
transition-duration: 100ms;
z-index: 2;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
-o-user-select: none;
user-select: none;
}
.react-grid-item > .react-resizable-handle {
position: absolute;
width: 20px;
height: 20px;
bottom: 0;
right: 0;
background: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pg08IS0tIEdlbmVyYXRvcjogQWRvYmUgRmlyZXdvcmtzIENTNiwgRXhwb3J0IFNWRyBFeHRlbnNpb24gYnkgQWFyb24gQmVhbGwgKGh0dHA6Ly9maXJld29ya3MuYWJlYWxsLmNvbSkgLiBWZXJzaW9uOiAwLjYuMSAgLS0+DTwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DTxzdmcgaWQ9IlVudGl0bGVkLVBhZ2UlMjAxIiB2aWV3Qm94PSIwIDAgNiA2IiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZmZmZmZmMDAiIHZlcnNpb249IjEuMSINCXhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHhtbDpzcGFjZT0icHJlc2VydmUiDQl4PSIwcHgiIHk9IjBweCIgd2lkdGg9IjZweCIgaGVpZ2h0PSI2cHgiDT4NCTxnIG9wYWNpdHk9IjAuMzAyIj4NCQk8cGF0aCBkPSJNIDYgNiBMIDAgNiBMIDAgNC4yIEwgNCA0LjIgTCA0LjIgNC4yIEwgNC4yIDAgTCA2IDAgTCA2IDYgTCA2IDYgWiIgZmlsbD0iIzAwMDAwMCIvPg0JPC9nPg08L3N2Zz4=');
background-position: bottom right;
padding: 0 3px 3px 0;
background-repeat: no-repeat;
background-origin: content-box;
box-sizing: border-box;
cursor: se-resize;
}

View File

@@ -0,0 +1,5 @@
module.exports = require('./build/ReactGridLayout').default;
module.exports.utils = require('./build/utils');
module.exports.Responsive = require('./build/ResponsiveReactGridLayout').default;
module.exports.Responsive.utils = require('./build/responsiveUtils');
module.exports.WidthProvider = require('./build/components/WidthProvider').default;

View File

@@ -0,0 +1,15 @@
// flow-typed signature: 3fba12a77525f37b0492c8dab3e04f0e
// flow-typed version: 94e9f7e0a4/classnames_v2.x.x/flow_>=v0.28.x
type $npm$classnames$Classes =
string |
{[className: string]: ?boolean } |
Array<string> |
void |
null
declare module 'classnames' {
declare function exports(
...classes: Array<$npm$classnames$Classes>
): string;
}

View File

@@ -0,0 +1,15 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../loose-envify/cli.js" "$@"
ret=$?
else
node "$basedir/../loose-envify/cli.js" "$@"
ret=$?
fi
exit $ret

View File

@@ -0,0 +1,7 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\loose-envify\cli.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\loose-envify\cli.js" %*
)

View File

@@ -0,0 +1,70 @@
## 2.0.6
Version 2.0.4 adds support for React Native by clarifying in package.json that
the browser environment does not support Node.js domains.
Why this is necessary, we leave as an exercise for the user.
## 2.0.3
Version 2.0.3 fixes a bug when adjusting the capacity of the task queue.
## 2.0.1-2.02
Version 2.0.1 fixes a bug in the way redirects were expressed that affected the
function of Browserify, but which Mr would tolerate.
## 2.0.0
Version 2 of ASAP is a full rewrite with a few salient changes.
First, the ASAP source is CommonJS only and designed with [Browserify][] and
[Browserify-compatible][Mr] module loaders in mind.
[Browserify]: https://github.com/substack/node-browserify
[Mr]: https://github.com/montagejs/mr
The new version has been refactored in two dimensions.
Support for Node.js and browsers have been separated, using Browserify
redirects and ASAP has been divided into two modules.
The "raw" layer depends on the tasks to catch thrown exceptions and unravel
Node.js domains.
The full implementation of ASAP is loadable as `require("asap")` in both Node.js
and browsers.
The raw layer that lacks exception handling overhead is loadable as
`require("asap/raw")`.
The interface is the same for both layers.
Tasks are no longer required to be functions, but can rather be any object that
implements `task.call()`.
With this feature you can recycle task objects to avoid garbage collector churn
and avoid closures in general.
The implementation has been rigorously documented so that our successors can
understand the scope of the problem that this module solves and all of its
nuances, ensuring that the next generation of implementations know what details
are essential.
- [asap.js](https://github.com/kriskowal/asap/blob/master/asap.js)
- [raw.js](https://github.com/kriskowal/asap/blob/master/raw.js)
- [browser-asap.js](https://github.com/kriskowal/asap/blob/master/browser-asap.js)
- [browser-raw.js](https://github.com/kriskowal/asap/blob/master/browser-raw.js)
The new version has also been rigorously tested across a broad spectrum of
browsers, in both the window and worker context.
The following charts capture the browser test results for the most recent
release.
The first chart shows test results for ASAP running in the main window context.
The second chart shows test results for ASAP running in a web worker context.
Test results are inconclusive (grey) on browsers that do not support web
workers.
These data are captured automatically by [Continuous
Integration][].
![Browser Compatibility](http://kriskowal-asap.s3-website-us-west-2.amazonaws.com/train/integration-2/saucelabs-results-matrix.svg)
![Compatibility in Web Workers](http://kriskowal-asap.s3-website-us-west-2.amazonaws.com/train/integration-2/saucelabs-worker-results-matrix.svg)
[Continuous Integration]: https://github.com/kriskowal/asap/blob/master/CONTRIBUTING.md

View File

@@ -0,0 +1,21 @@
Copyright 20092014 Contributors. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.

View File

@@ -0,0 +1,237 @@
# ASAP
[![Build Status](https://travis-ci.org/kriskowal/asap.png?branch=master)](https://travis-ci.org/kriskowal/asap)
Promise and asynchronous observer libraries, as well as hand-rolled callback
programs and libraries, often need a mechanism to postpone the execution of a
callback until the next available event.
(See [Designing APIs for Asynchrony][Zalgo].)
The `asap` function executes a task **as soon as possible** but not before it
returns, waiting only for the completion of the current event and previously
scheduled tasks.
```javascript
asap(function () {
// ...
});
```
[Zalgo]: http://blog.izs.me/post/59142742143/designing-apis-for-asynchrony
This CommonJS package provides an `asap` module that exports a function that
executes a task function *as soon as possible*.
ASAP strives to schedule events to occur before yielding for IO, reflow,
or redrawing.
Each event receives an independent stack, with only platform code in parent
frames and the events run in the order they are scheduled.
ASAP provides a fast event queue that will execute tasks until it is
empty before yielding to the JavaScript engine's underlying event-loop.
When a task gets added to a previously empty event queue, ASAP schedules a flush
event, preferring for that event to occur before the JavaScript engine has an
opportunity to perform IO tasks or rendering, thus making the first task and
subsequent tasks semantically indistinguishable.
ASAP uses a variety of techniques to preserve this invariant on different
versions of browsers and Node.js.
By design, ASAP prevents input events from being handled until the task
queue is empty.
If the process is busy enough, this may cause incoming connection requests to be
dropped, and may cause existing connections to inform the sender to reduce the
transmission rate or stall.
ASAP allows this on the theory that, if there is enough work to do, there is no
sense in looking for trouble.
As a consequence, ASAP can interfere with smooth animation.
If your task should be tied to the rendering loop, consider using
`requestAnimationFrame` instead.
A long sequence of tasks can also effect the long running script dialog.
If this is a problem, you may be able to use ASAPs cousin `setImmediate` to
break long processes into shorter intervals and periodically allow the browser
to breathe.
`setImmediate` will yield for IO, reflow, and repaint events.
It also returns a handler and can be canceled.
For a `setImmediate` shim, consider [YuzuJS setImmediate][setImmediate].
[setImmediate]: https://github.com/YuzuJS/setImmediate
Take care.
ASAP can sustain infinite recursive calls without warning.
It will not halt from a stack overflow, and it will not consume unbounded
memory.
This is behaviorally equivalent to an infinite loop.
Just as with infinite loops, you can monitor a Node.js process for this behavior
with a heart-beat signal.
As with infinite loops, a very small amount of caution goes a long way to
avoiding problems.
```javascript
function loop() {
asap(loop);
}
loop();
```
In browsers, if a task throws an exception, it will not interrupt the flushing
of high-priority tasks.
The exception will be postponed to a later, low-priority event to avoid
slow-downs.
In Node.js, if a task throws an exception, ASAP will resume flushing only if—and
only after—the error is handled by `domain.on("error")` or
`process.on("uncaughtException")`.
## Raw ASAP
Checking for exceptions comes at a cost.
The package also provides an `asap/raw` module that exports the underlying
implementation which is faster but stalls if a task throws an exception.
This internal version of the ASAP function does not check for errors.
If a task does throw an error, it will stall the event queue unless you manually
call `rawAsap.requestFlush()` before throwing the error, or any time after.
In Node.js, `asap/raw` also runs all tasks outside any domain.
If you need a task to be bound to your domain, you will have to do it manually.
```js
if (process.domain) {
task = process.domain.bind(task);
}
rawAsap(task);
```
## Tasks
A task may be any object that implements `call()`.
A function will suffice, but closures tend not to be reusable and can cause
garbage collector churn.
Both `asap` and `rawAsap` accept task objects to give you the option of
recycling task objects or using higher callable object abstractions.
See the `asap` source for an illustration.
## Compatibility
ASAP is tested on Node.js v0.10 and in a broad spectrum of web browsers.
The following charts capture the browser test results for the most recent
release.
The first chart shows test results for ASAP running in the main window context.
The second chart shows test results for ASAP running in a web worker context.
Test results are inconclusive (grey) on browsers that do not support web
workers.
These data are captured automatically by [Continuous
Integration][].
[Continuous Integration]: https://github.com/kriskowal/asap/blob/master/CONTRIBUTING.md
![Browser Compatibility](http://kriskowal-asap.s3-website-us-west-2.amazonaws.com/train/integration-2/saucelabs-results-matrix.svg)
![Compatibility in Web Workers](http://kriskowal-asap.s3-website-us-west-2.amazonaws.com/train/integration-2/saucelabs-worker-results-matrix.svg)
## Caveats
When a task is added to an empty event queue, it is not always possible to
guarantee that the task queue will begin flushing immediately after the current
event.
However, once the task queue begins flushing, it will not yield until the queue
is empty, even if the queue grows while executing tasks.
The following browsers allow the use of [DOM mutation observers][] to access
the HTML [microtask queue][], and thus begin flushing ASAP's task queue
immediately at the end of the current event loop turn, before any rendering or
IO:
[microtask queue]: http://www.whatwg.org/specs/web-apps/current-work/multipage/webappapis.html#microtask-queue
[DOM mutation observers]: http://dom.spec.whatwg.org/#mutation-observers
- Android 44.3
- Chrome 2634
- Firefox 1429
- Internet Explorer 11
- iPad Safari 67.1
- iPhone Safari 77.1
- Safari 67
In the absense of mutation observers, there are a few browsers, and situations
like web workers in some of the above browsers, where [message channels][]
would be a useful way to avoid falling back to timers.
Message channels give direct access to the HTML [task queue][], so the ASAP
task queue would flush after any already queued rendering and IO tasks, but
without having the minimum delay imposed by timers.
However, among these browsers, Internet Explorer 10 and Safari do not reliably
dispatch messages, so they are not worth the trouble to implement.
[message channels]: http://www.whatwg.org/specs/web-apps/current-work/multipage/web-messaging.html#message-channels
[task queue]: http://www.whatwg.org/specs/web-apps/current-work/multipage/webappapis.html#concept-task
- Internet Explorer 10
- Safair 5.0-1
- Opera 11-12
In the absense of mutation observers, these browsers and the following browsers
all fall back to using `setTimeout` and `setInterval` to ensure that a `flush`
occurs.
The implementation uses both and cancels whatever handler loses the race, since
`setTimeout` tends to occasionally skip tasks in unisolated circumstances.
Timers generally delay the flushing of ASAP's task queue for four milliseconds.
- Firefox 313
- Internet Explorer 610
- iPad Safari 4.3
- Lynx 2.8.7
## Heritage
ASAP has been factored out of the [Q][] asynchronous promise library.
It originally had a naïve implementation in terms of `setTimeout`, but
[Malte Ubl][NonBlocking] provided an insight that `postMessage` might be
useful for creating a high-priority, no-delay event dispatch hack.
Since then, Internet Explorer proposed and implemented `setImmediate`.
Robert Katić began contributing to Q by measuring the performance of
the internal implementation of `asap`, paying particular attention to
error recovery.
Domenic, Robert, and Kris Kowal collectively settled on the current strategy of
unrolling the high-priority event queue internally regardless of what strategy
we used to dispatch the potentially lower-priority flush event.
Domenic went on to make ASAP cooperate with Node.js domains.
[Q]: https://github.com/kriskowal/q
[NonBlocking]: http://www.nonblocking.io/2011/06/windownexttick.html
For further reading, Nicholas Zakas provided a thorough article on [The
Case for setImmediate][NCZ].
[NCZ]: http://www.nczonline.net/blog/2013/07/09/the-case-for-setimmediate/
Embers RSVP promise implementation later [adopted][RSVP ASAP] the name ASAP but
further developed the implentation.
Particularly, The `MessagePort` implementation was abandoned due to interaction
[problems with Mobile Internet Explorer][IE Problems] in favor of an
implementation backed on the newer and more reliable DOM `MutationObserver`
interface.
These changes were back-ported into this library.
[IE Problems]: https://github.com/cujojs/when/issues/197
[RSVP ASAP]: https://github.com/tildeio/rsvp.js/blob/cddf7232546a9cf858524b75cde6f9edf72620a7/lib/rsvp/asap.js
In addition, ASAP factored into `asap` and `asap/raw`, such that `asap` remained
exception-safe, but `asap/raw` provided a tight kernel that could be used for
tasks that guaranteed that they would not throw exceptions.
This core is useful for promise implementations that capture thrown errors in
rejected promises and do not need a second safety net.
At the same time, the exception handling in `asap` was factored into separate
implementations for Node.js and browsers, using the the [Browserify][Browser
Config] `browser` property in `package.json` to instruct browser module loaders
and bundlers, including [Browserify][], [Mr][], and [Mop][], to use the
browser-only implementation.
[Browser Config]: https://gist.github.com/defunctzombie/4339901
[Browserify]: https://github.com/substack/node-browserify
[Mr]: https://github.com/montagejs/mr
[Mop]: https://github.com/montagejs/mop
## License
Copyright 2009-2014 by Contributors
MIT License (enclosed)

View File

@@ -0,0 +1,65 @@
"use strict";
var rawAsap = require("./raw");
var freeTasks = [];
/**
* Calls a task as soon as possible after returning, in its own event, with
* priority over IO events. An exception thrown in a task can be handled by
* `process.on("uncaughtException") or `domain.on("error")`, but will otherwise
* crash the process. If the error is handled, all subsequent tasks will
* resume.
*
* @param {{call}} task A callable object, typically a function that takes no
* arguments.
*/
module.exports = asap;
function asap(task) {
var rawTask;
if (freeTasks.length) {
rawTask = freeTasks.pop();
} else {
rawTask = new RawTask();
}
rawTask.task = task;
rawTask.domain = process.domain;
rawAsap(rawTask);
}
function RawTask() {
this.task = null;
this.domain = null;
}
RawTask.prototype.call = function () {
if (this.domain) {
this.domain.enter();
}
var threw = true;
try {
this.task.call();
threw = false;
// If the task throws an exception (presumably) Node.js restores the
// domain stack for the next event.
if (this.domain) {
this.domain.exit();
}
} finally {
// We use try/finally and a threw flag to avoid messing up stack traces
// when we catch and release errors.
if (threw) {
// In Node.js, uncaught exceptions are considered fatal errors.
// Re-throw them to interrupt flushing!
// Ensure that flushing continues if an uncaught exception is
// suppressed listening process.on("uncaughtException") or
// domain.on("error").
rawAsap.requestFlush();
}
// If the task threw an error, we do not want to exit the domain here.
// Exiting the domain would prevent the domain from catching the error.
this.task = null;
this.domain = null;
freeTasks.push(this);
}
};

View File

@@ -0,0 +1,66 @@
"use strict";
// rawAsap provides everything we need except exception management.
var rawAsap = require("./raw");
// RawTasks are recycled to reduce GC churn.
var freeTasks = [];
// We queue errors to ensure they are thrown in right order (FIFO).
// Array-as-queue is good enough here, since we are just dealing with exceptions.
var pendingErrors = [];
var requestErrorThrow = rawAsap.makeRequestCallFromTimer(throwFirstError);
function throwFirstError() {
if (pendingErrors.length) {
throw pendingErrors.shift();
}
}
/**
* Calls a task as soon as possible after returning, in its own event, with priority
* over other events like animation, reflow, and repaint. An error thrown from an
* event will not interrupt, nor even substantially slow down the processing of
* other events, but will be rather postponed to a lower priority event.
* @param {{call}} task A callable object, typically a function that takes no
* arguments.
*/
module.exports = asap;
function asap(task) {
var rawTask;
if (freeTasks.length) {
rawTask = freeTasks.pop();
} else {
rawTask = new RawTask();
}
rawTask.task = task;
rawAsap(rawTask);
}
// We wrap tasks with recyclable task objects. A task object implements
// `call`, just like a function.
function RawTask() {
this.task = null;
}
// The sole purpose of wrapping the task is to catch the exception and recycle
// the task object after its single use.
RawTask.prototype.call = function () {
try {
this.task.call();
} catch (error) {
if (asap.onerror) {
// This hook exists purely for testing purposes.
// Its name will be periodically randomized to break any code that
// depends on its existence.
asap.onerror(error);
} else {
// In a web browser, exceptions are not fatal. However, to avoid
// slowing down the queue of pending tasks, we rethrow the error in a
// lower priority turn.
pendingErrors.push(error);
requestErrorThrow();
}
} finally {
this.task = null;
freeTasks[freeTasks.length] = this;
}
};

View File

@@ -0,0 +1,223 @@
"use strict";
// Use the fastest means possible to execute a task in its own turn, with
// priority over other events including IO, animation, reflow, and redraw
// events in browsers.
//
// An exception thrown by a task will permanently interrupt the processing of
// subsequent tasks. The higher level `asap` function ensures that if an
// exception is thrown by a task, that the task queue will continue flushing as
// soon as possible, but if you use `rawAsap` directly, you are responsible to
// either ensure that no exceptions are thrown from your task, or to manually
// call `rawAsap.requestFlush` if an exception is thrown.
module.exports = rawAsap;
function rawAsap(task) {
if (!queue.length) {
requestFlush();
flushing = true;
}
// Equivalent to push, but avoids a function call.
queue[queue.length] = task;
}
var queue = [];
// Once a flush has been requested, no further calls to `requestFlush` are
// necessary until the next `flush` completes.
var flushing = false;
// `requestFlush` is an implementation-specific method that attempts to kick
// off a `flush` event as quickly as possible. `flush` will attempt to exhaust
// the event queue before yielding to the browser's own event loop.
var requestFlush;
// The position of the next task to execute in the task queue. This is
// preserved between calls to `flush` so that it can be resumed if
// a task throws an exception.
var index = 0;
// If a task schedules additional tasks recursively, the task queue can grow
// unbounded. To prevent memory exhaustion, the task queue will periodically
// truncate already-completed tasks.
var capacity = 1024;
// The flush function processes all tasks that have been scheduled with
// `rawAsap` unless and until one of those tasks throws an exception.
// If a task throws an exception, `flush` ensures that its state will remain
// consistent and will resume where it left off when called again.
// However, `flush` does not make any arrangements to be called again if an
// exception is thrown.
function flush() {
while (index < queue.length) {
var currentIndex = index;
// Advance the index before calling the task. This ensures that we will
// begin flushing on the next task the task throws an error.
index = index + 1;
queue[currentIndex].call();
// Prevent leaking memory for long chains of recursive calls to `asap`.
// If we call `asap` within tasks scheduled by `asap`, the queue will
// grow, but to avoid an O(n) walk for every task we execute, we don't
// shift tasks off the queue after they have been executed.
// Instead, we periodically shift 1024 tasks off the queue.
if (index > capacity) {
// Manually shift all values starting at the index back to the
// beginning of the queue.
for (var scan = 0, newLength = queue.length - index; scan < newLength; scan++) {
queue[scan] = queue[scan + index];
}
queue.length -= index;
index = 0;
}
}
queue.length = 0;
index = 0;
flushing = false;
}
// `requestFlush` is implemented using a strategy based on data collected from
// every available SauceLabs Selenium web driver worker at time of writing.
// https://docs.google.com/spreadsheets/d/1mG-5UYGup5qxGdEMWkhP6BWCz053NUb2E1QoUTU16uA/edit#gid=783724593
// Safari 6 and 6.1 for desktop, iPad, and iPhone are the only browsers that
// have WebKitMutationObserver but not un-prefixed MutationObserver.
// Must use `global` or `self` instead of `window` to work in both frames and web
// workers. `global` is a provision of Browserify, Mr, Mrs, or Mop.
/* globals self */
var scope = typeof global !== "undefined" ? global : self;
var BrowserMutationObserver = scope.MutationObserver || scope.WebKitMutationObserver;
// MutationObservers are desirable because they have high priority and work
// reliably everywhere they are implemented.
// They are implemented in all modern browsers.
//
// - Android 4-4.3
// - Chrome 26-34
// - Firefox 14-29
// - Internet Explorer 11
// - iPad Safari 6-7.1
// - iPhone Safari 7-7.1
// - Safari 6-7
if (typeof BrowserMutationObserver === "function") {
requestFlush = makeRequestCallFromMutationObserver(flush);
// MessageChannels are desirable because they give direct access to the HTML
// task queue, are implemented in Internet Explorer 10, Safari 5.0-1, and Opera
// 11-12, and in web workers in many engines.
// Although message channels yield to any queued rendering and IO tasks, they
// would be better than imposing the 4ms delay of timers.
// However, they do not work reliably in Internet Explorer or Safari.
// Internet Explorer 10 is the only browser that has setImmediate but does
// not have MutationObservers.
// Although setImmediate yields to the browser's renderer, it would be
// preferrable to falling back to setTimeout since it does not have
// the minimum 4ms penalty.
// Unfortunately there appears to be a bug in Internet Explorer 10 Mobile (and
// Desktop to a lesser extent) that renders both setImmediate and
// MessageChannel useless for the purposes of ASAP.
// https://github.com/kriskowal/q/issues/396
// Timers are implemented universally.
// We fall back to timers in workers in most engines, and in foreground
// contexts in the following browsers.
// However, note that even this simple case requires nuances to operate in a
// broad spectrum of browsers.
//
// - Firefox 3-13
// - Internet Explorer 6-9
// - iPad Safari 4.3
// - Lynx 2.8.7
} else {
requestFlush = makeRequestCallFromTimer(flush);
}
// `requestFlush` requests that the high priority event queue be flushed as
// soon as possible.
// This is useful to prevent an error thrown in a task from stalling the event
// queue if the exception handled by Node.jss
// `process.on("uncaughtException")` or by a domain.
rawAsap.requestFlush = requestFlush;
// To request a high priority event, we induce a mutation observer by toggling
// the text of a text node between "1" and "-1".
function makeRequestCallFromMutationObserver(callback) {
var toggle = 1;
var observer = new BrowserMutationObserver(callback);
var node = document.createTextNode("");
observer.observe(node, {characterData: true});
return function requestCall() {
toggle = -toggle;
node.data = toggle;
};
}
// The message channel technique was discovered by Malte Ubl and was the
// original foundation for this library.
// http://www.nonblocking.io/2011/06/windownexttick.html
// Safari 6.0.5 (at least) intermittently fails to create message ports on a
// page's first load. Thankfully, this version of Safari supports
// MutationObservers, so we don't need to fall back in that case.
// function makeRequestCallFromMessageChannel(callback) {
// var channel = new MessageChannel();
// channel.port1.onmessage = callback;
// return function requestCall() {
// channel.port2.postMessage(0);
// };
// }
// For reasons explained above, we are also unable to use `setImmediate`
// under any circumstances.
// Even if we were, there is another bug in Internet Explorer 10.
// It is not sufficient to assign `setImmediate` to `requestFlush` because
// `setImmediate` must be called *by name* and therefore must be wrapped in a
// closure.
// Never forget.
// function makeRequestCallFromSetImmediate(callback) {
// return function requestCall() {
// setImmediate(callback);
// };
// }
// Safari 6.0 has a problem where timers will get lost while the user is
// scrolling. This problem does not impact ASAP because Safari 6.0 supports
// mutation observers, so that implementation is used instead.
// However, if we ever elect to use timers in Safari, the prevalent work-around
// is to add a scroll event listener that calls for a flush.
// `setTimeout` does not call the passed callback if the delay is less than
// approximately 7 in web workers in Firefox 8 through 18, and sometimes not
// even then.
function makeRequestCallFromTimer(callback) {
return function requestCall() {
// We dispatch a timeout with a specified delay of 0 for engines that
// can reliably accommodate that request. This will usually be snapped
// to a 4 milisecond delay, but once we're flushing, there's no delay
// between events.
var timeoutHandle = setTimeout(handleTimer, 0);
// However, since this timer gets frequently dropped in Firefox
// workers, we enlist an interval handle that will try to fire
// an event 20 times per second until it succeeds.
var intervalHandle = setInterval(handleTimer, 50);
function handleTimer() {
// Whichever timer succeeds will cancel both timers and
// execute the callback.
clearTimeout(timeoutHandle);
clearInterval(intervalHandle);
callback();
}
};
}
// This is for `asap.js` only.
// Its name will be periodically randomized to break any code that depends on
// its existence.
rawAsap.makeRequestCallFromTimer = makeRequestCallFromTimer;
// ASAP was originally a nextTick shim included in Q. This was factored out
// into this ASAP package. It was later adapted to RSVP which made further
// amendments. These decisions, particularly to marginalize MessageChannel and
// to capture the MutationObserver implementation in a closure, were integrated
// back into ASAP proper.
// https://github.com/tildeio/rsvp.js/blob/cddf7232546a9cf858524b75cde6f9edf72620a7/lib/rsvp/asap.js

View File

@@ -0,0 +1,90 @@
{
"_args": [
[
"asap@2.0.6",
"C:\\Users\\deranjer\\go\\src\\github.com\\deranjer\\goTorrent\\torrent-project"
]
],
"_from": "asap@2.0.6",
"_id": "asap@2.0.6",
"_inBundle": false,
"_integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=",
"_location": "/react-grid-layout/asap",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "asap@2.0.6",
"name": "asap",
"escapedName": "asap",
"rawSpec": "2.0.6",
"saveSpec": null,
"fetchSpec": "2.0.6"
},
"_requiredBy": [
"/react-grid-layout/promise"
],
"_resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"_spec": "2.0.6",
"_where": "C:\\Users\\deranjer\\go\\src\\github.com\\deranjer\\goTorrent\\torrent-project",
"browser": {
"./asap": "./browser-asap.js",
"./asap.js": "./browser-asap.js",
"./raw": "./browser-raw.js",
"./raw.js": "./browser-raw.js",
"./test/domain.js": "./test/browser-domain.js"
},
"bugs": {
"url": "https://github.com/kriskowal/asap/issues"
},
"description": "High-priority task queue for Node.js and browsers",
"devDependencies": {
"benchmark": "^1.0.0",
"events": "^1.0.1",
"jshint": "^2.5.1",
"knox": "^0.8.10",
"mr": "^2.0.5",
"opener": "^1.3.0",
"q": "^2.0.3",
"q-io": "^2.0.3",
"saucelabs": "^0.1.1",
"wd": "^0.2.21",
"weak-map": "^1.0.5"
},
"files": [
"raw.js",
"asap.js",
"browser-raw.js",
"browser-asap.js"
],
"homepage": "https://github.com/kriskowal/asap#readme",
"keywords": [
"event",
"task",
"queue"
],
"license": "MIT",
"main": "./asap.js",
"name": "asap",
"react-native": {
"domain": false
},
"repository": {
"type": "git",
"url": "git+https://github.com/kriskowal/asap.git"
},
"scripts": {
"benchmarks": "node benchmarks",
"lint": "jshint raw.js asap.js browser-raw.js browser-asap.js $(find scripts -name '*.js' | grep -v gauntlet)",
"test": "npm run lint && npm run test-node",
"test-browser": "node scripts/publish-bundle.js test/asap-test.js | xargs opener",
"test-node": "node test/asap-test.js",
"test-publish": "node scripts/publish-bundle.js test/asap-test.js | pbcopy",
"test-saucelabs": "node scripts/saucelabs.js test/asap-test.js scripts/saucelabs-spot-configurations.json",
"test-saucelabs-all": "node scripts/saucelabs.js test/asap-test.js scripts/saucelabs-all-configurations.json",
"test-saucelabs-worker": "node scripts/saucelabs-worker-test.js scripts/saucelabs-spot-configurations.json",
"test-saucelabs-worker-all": "node scripts/saucelabs-worker-test.js scripts/saucelabs-all-configurations.json",
"test-travis": "npm run lint && npm run test-node && npm run test-saucelabs && npm run test-saucelabs-worker"
},
"version": "2.0.6"
}

View File

@@ -0,0 +1,101 @@
"use strict";
var domain; // The domain module is executed on demand
var hasSetImmediate = typeof setImmediate === "function";
// Use the fastest means possible to execute a task in its own turn, with
// priority over other events including network IO events in Node.js.
//
// An exception thrown by a task will permanently interrupt the processing of
// subsequent tasks. The higher level `asap` function ensures that if an
// exception is thrown by a task, that the task queue will continue flushing as
// soon as possible, but if you use `rawAsap` directly, you are responsible to
// either ensure that no exceptions are thrown from your task, or to manually
// call `rawAsap.requestFlush` if an exception is thrown.
module.exports = rawAsap;
function rawAsap(task) {
if (!queue.length) {
requestFlush();
flushing = true;
}
// Avoids a function call
queue[queue.length] = task;
}
var queue = [];
// Once a flush has been requested, no further calls to `requestFlush` are
// necessary until the next `flush` completes.
var flushing = false;
// The position of the next task to execute in the task queue. This is
// preserved between calls to `flush` so that it can be resumed if
// a task throws an exception.
var index = 0;
// If a task schedules additional tasks recursively, the task queue can grow
// unbounded. To prevent memory excaustion, the task queue will periodically
// truncate already-completed tasks.
var capacity = 1024;
// The flush function processes all tasks that have been scheduled with
// `rawAsap` unless and until one of those tasks throws an exception.
// If a task throws an exception, `flush` ensures that its state will remain
// consistent and will resume where it left off when called again.
// However, `flush` does not make any arrangements to be called again if an
// exception is thrown.
function flush() {
while (index < queue.length) {
var currentIndex = index;
// Advance the index before calling the task. This ensures that we will
// begin flushing on the next task the task throws an error.
index = index + 1;
queue[currentIndex].call();
// Prevent leaking memory for long chains of recursive calls to `asap`.
// If we call `asap` within tasks scheduled by `asap`, the queue will
// grow, but to avoid an O(n) walk for every task we execute, we don't
// shift tasks off the queue after they have been executed.
// Instead, we periodically shift 1024 tasks off the queue.
if (index > capacity) {
// Manually shift all values starting at the index back to the
// beginning of the queue.
for (var scan = 0, newLength = queue.length - index; scan < newLength; scan++) {
queue[scan] = queue[scan + index];
}
queue.length -= index;
index = 0;
}
}
queue.length = 0;
index = 0;
flushing = false;
}
rawAsap.requestFlush = requestFlush;
function requestFlush() {
// Ensure flushing is not bound to any domain.
// It is not sufficient to exit the domain, because domains exist on a stack.
// To execute code outside of any domain, the following dance is necessary.
var parentDomain = process.domain;
if (parentDomain) {
if (!domain) {
// Lazy execute the domain module.
// Only employed if the user elects to use domains.
domain = require("domain");
}
domain.active = process.domain = null;
}
// `setImmediate` is slower that `process.nextTick`, but `process.nextTick`
// cannot handle recursion.
// `requestFlush` will only be called recursively from `asap.js`, to resume
// flushing after an error is thrown into a domain.
// Conveniently, `setImmediate` was introduced in the same version
// `process.nextTick` started throwing recursion errors.
if (flushing && hasSetImmediate) {
setImmediate(flush);
} else {
process.nextTick(flush);
}
if (parentDomain) {
domain.active = process.domain = parentDomain;
}
}

View File

@@ -0,0 +1,21 @@
# Contributing
Thanks for your interest in classNames. Issues, PRs and suggestions welcome :)
Before working on a PR, please consider the following:
* Speed is a serious concern for this package as it is likely to be called a
significant number of times in any project that uses it. As such, new features
will only be accepted if they improve (or at least do not negatively impact)
performance.
* To demonstrate performance differences please set up a
[JSPerf](http://jsperf.com) test and link to it from your issue / PR.
* Tests must be added for any change or new feature before it will be accepted.
A benchmark utilitiy is included so that changes may be tested against the
current published version. To run the benchmarks, `npm install` in the
`./benchmarks` directory then run `npm run benchmarks` in the package root.
Please be aware though that local benchmarks are just a smoke-signal; they will
run in the v8 version that your node/iojs uses, while classNames is _most_
often run across a wide variety of browsers and browser versions.

View File

@@ -0,0 +1,81 @@
# Changelog
## v2.2.5 / 2016-05-02
* Improved performance of `dedupe` variant even further, thanks [Andres Suarez](https://github.com/zertosh)
## v2.2.4 / 2016-04-25
* Improved performance of `dedupe` variant by about 2x, thanks [Bartosz Gościński](https://github.com/bgoscinski)
## v2.2.3 / 2016-01-05
* Updated `bind` variant to use `[].join(' ')` as per the main script in 2.2.2
## v2.2.2 / 2016-01-04
* Switched from string concatenation to `[].join(' ')` for a slight performance gain in the main function.
## v2.2.1 / 2015-11-26
* Add deps parameter to the AMD module, fixes an issue using the Dojo loader, thanks [Chris Jordan](https://github.com/flipperkid)
## v2.2.0 / 2015-10-18
* added a new `bind` variant for use with [css-modules](https://github.com/css-modules/css-modules) and similar abstractions, thanks to [Kirill Yakovenko](https://github.com/blia)
## v2.1.5 / 2015-09-30
* reverted a new usage of `Object.keys` in `dedupe.js` that slipped through in the last release
## v2.1.4 / 2015-09-30
* new case added to benchmarks
* safer `hasOwnProperty` check
* AMD module is now named, so you can do the following:
```
define(["classnames"], function (classNames) {
var style = classNames("foo", "bar");
// ...
});
```
## v2.1.3 / 2015-07-02
* updated UMD wrapper to support AMD and CommonJS on the same pacge
## v2.1.2 / 2015-05-28
* added a proper UMD wrapper
## v2.1.1 / 2015-05-06
* minor performance improvement thanks to type caching
* improved benchmarking and results output
## v2.1.0 / 2015-05-05
* added alternate `dedupe` version of classNames, which is slower (10x) but ensures that if a class is added then overridden by a falsy value in a subsequent argument, it is excluded from the result.
## v2.0.0 / 2015-05-03
* performance improvement; switched to `Array.isArray` for type detection, which is much faster in modern browsers. A polyfill is now required for IE8 support, see the Readme for details.
## v1.2.2 / 2015-04-28
* license comment updates to simiplify certain build scenarios
## v1.2.1 / 2015-04-22
* added safe exporting for requireJS usage
* clarified Bower usage and instructions
## v1.2.0 / 2015-03-17
* added comprehensive support for array arguments, including nested arrays
* simplified code slightly
## Previous
Please see the git history for the details of previous versions.

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 Jed Watson
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,188 @@
Classnames
===========
[![Version](http://img.shields.io/npm/v/classnames.svg)](https://www.npmjs.org/package/classnames)
[![Build Status](https://travis-ci.org/JedWatson/classnames.svg?branch=master)](https://travis-ci.org/JedWatson/classnames)
A simple javascript utility for conditionally joining classNames together.
Install with npm or Bower.
```sh
npm install classnames
```
Use with node.js, browserify or webpack:
```js
var classNames = require('classnames');
classNames('foo', 'bar'); // => 'foo bar'
```
Alternatively, you can simply include `index.js` on your page with a standalone `<script>` tag and it will export a global `classNames` method, or define the module if you are using RequireJS.
### Project philosophy
We take the stability and performance of this package seriously, because it is run millions of times a day in browsers all around the world. Updates are thoroughly reviewed for performance impacts before being released, and we have a comprehensive test suite.
Classnames follows the [SemVer](http://semver.org/) standard for versioning.
There is also a [Changelog](https://github.com/JedWatson/classnames/blob/master/HISTORY.md).
## Usage
The `classNames` function takes any number of arguments which can be a string or object.
The argument `'foo'` is short for `{ foo: true }`. If the value of the key is falsy, it won't be included in the output.
```js
classNames('foo', 'bar'); // => 'foo bar'
classNames('foo', { bar: true }); // => 'foo bar'
classNames({ 'foo-bar': true }); // => 'foo-bar'
classNames({ 'foo-bar': false }); // => ''
classNames({ foo: true }, { bar: true }); // => 'foo bar'
classNames({ foo: true, bar: true }); // => 'foo bar'
// lots of arguments of various types
classNames('foo', { bar: true, duck: false }, 'baz', { quux: true }); // => 'foo bar baz quux'
// other falsy values are just ignored
classNames(null, false, 'bar', undefined, 0, 1, { baz: null }, ''); // => 'bar 1'
```
Arrays will be recursively flattened as per the rules above:
```js
var arr = ['b', { c: true, d: false }];
classNames('a', arr); // => 'a b c'
```
### Dynamic class names with ES2015
If you're in an environment that supports [computed keys](http://www.ecma-international.org/ecma-262/6.0/#sec-object-initializer) (available in ES2015 and Babel) you can use dynamic class names:
```js
let buttonType = 'primary';
classNames({ [`btn-${buttonType}`]: true });
```
### Usage with React.js
This package is the official replacement for `classSet`, which was originally shipped in the React.js Addons bundle.
One of its primary use cases is to make dynamic and conditional className props simpler to work with (especially more so than conditional string manipulation). So where you may have the following code to generate a `className` prop for a `<button>` in React:
```js
var Button = React.createClass({
// ...
render () {
var btnClass = 'btn';
if (this.state.isPressed) btnClass += ' btn-pressed';
else if (this.state.isHovered) btnClass += ' btn-over';
return <button className={btnClass}>{this.props.label}</button>;
}
});
```
You can express the conditional classes more simply as an object:
```js
var classNames = require('classnames');
var Button = React.createClass({
// ...
render () {
var btnClass = classNames({
'btn': true,
'btn-pressed': this.state.isPressed,
'btn-over': !this.state.isPressed && this.state.isHovered
});
return <button className={btnClass}>{this.props.label}</button>;
}
});
```
Because you can mix together object, array and string arguments, supporting optional className props is also simpler as only truthy arguments get included in the result:
```js
var btnClass = classNames('btn', this.props.className, {
'btn-pressed': this.state.isPressed,
'btn-over': !this.state.isPressed && this.state.isHovered
});
```
### Alternate `dedupe` version
There is an alternate version of `classNames` available which correctly dedupes classes and ensures that falsy classes specified in later arguments are excluded from the result set.
This version is slower (about 5x) so it is offered as an opt-in.
To use the dedupe version with node, browserify or webpack:
```js
var classNames = require('classnames/dedupe');
classNames('foo', 'foo', 'bar'); // => 'foo bar'
classNames('foo', { foo: false, bar: true }); // => 'bar'
```
For standalone (global / AMD) use, include `dedupe.js` in a `<script>` tag on your page.
### Alternate `bind` version (for [css-modules](https://github.com/css-modules/css-modules))
If you are using [css-modules](https://github.com/css-modules/css-modules), or a similar approach to abstract class "names" and the real `className` values that are actually output to the DOM, you may want to use the `bind` variant.
_Note that in ES2015 environments, it may be better to use the "dynamic class names" approach documented above._
```js
var classNames = require('classnames/bind');
var styles = {
foo: 'abc',
bar: 'def',
baz: 'xyz'
};
var cx = classNames.bind(styles);
var className = cx('foo', ['bar'], { baz: true }); // => "abc def xyz"
```
Real-world example:
```js
/* components/submit-button.js */
import { Component } from 'react';
import classNames from 'classnames/bind';
import styles from './submit-button.css';
let cx = classNames.bind(styles);
export default class SubmitButton extends Component {
render () {
let text = this.props.store.submissionInProgress ? 'Processing...' : 'Submit';
let className = cx({
base: true,
inProgress: this.props.store.submissionInProgress,
error: this.props.store.errorOccurred,
disabled: this.props.form.valid,
});
return <button className={className}>{text}</button>;
}
};
```
## Polyfills needed to support older browsers
#### `classNames >=2.0.0`
`Array.isArray`: see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray) for details about unsupported older browsers (e.g. <= IE8) and a simple polyfill.
`Object.keys`: see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys) for details about unsupported older browsers (e.g. <= IE8) and a simple polyfill. This is only used in `dedupe.js`.
## License
[MIT](LICENSE). Copyright (c) 2016 Jed Watson.

View File

@@ -0,0 +1,48 @@
/*!
Copyright (c) 2016 Jed Watson.
Licensed under the MIT License (MIT), see
http://jedwatson.github.io/classnames
*/
/* global define */
(function () {
'use strict';
var hasOwn = {}.hasOwnProperty;
function classNames () {
var classes = [];
for (var i = 0; i < arguments.length; i++) {
var arg = arguments[i];
if (!arg) continue;
var argType = typeof arg;
if (argType === 'string' || argType === 'number') {
classes.push(this && this[arg] || arg);
} else if (Array.isArray(arg)) {
classes.push(classNames.apply(this, arg));
} else if (argType === 'object') {
for (var key in arg) {
if (hasOwn.call(arg, key) && arg[key]) {
classes.push(this && this[key] || key);
}
}
}
}
return classes.join(' ');
}
if (typeof module !== 'undefined' && module.exports) {
module.exports = classNames;
} else if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) {
// register as 'classnames', consistent with npm package name
define('classnames', [], function () {
return classNames;
});
} else {
window.classNames = classNames;
}
}());

View File

@@ -0,0 +1,37 @@
{
"name": "classnames",
"version": "2.2.5",
"description": "A simple utility for conditionally joining classNames together",
"main": [
"index.js",
"bind.js",
"dedupe.js"
],
"homepage": "https://github.com/JedWatson/classnames",
"authors": [
"Jed Watson"
],
"moduleType": [
"amd",
"globals",
"node"
],
"keywords": [
"react",
"css",
"classes",
"classname",
"classnames",
"util",
"utility"
],
"license": "MIT",
"ignore": [
".editorconfig",
".gitignore",
"gulpfile.js",
"package.json",
"node_modules",
"tests.js"
]
}

View File

@@ -0,0 +1,109 @@
/*!
Copyright (c) 2016 Jed Watson.
Licensed under the MIT License (MIT), see
http://jedwatson.github.io/classnames
*/
/* global define */
(function () {
'use strict';
var classNames = (function () {
// don't inherit from Object so we can skip hasOwnProperty check later
// http://stackoverflow.com/questions/15518328/creating-js-object-with-object-createnull#answer-21079232
function StorageObject() {}
StorageObject.prototype = Object.create(null);
function _parseArray (resultSet, array) {
var length = array.length;
for (var i = 0; i < length; ++i) {
_parse(resultSet, array[i]);
}
}
var hasOwn = {}.hasOwnProperty;
function _parseNumber (resultSet, num) {
resultSet[num] = true;
}
function _parseObject (resultSet, object) {
for (var k in object) {
if (hasOwn.call(object, k)) {
// set value to false instead of deleting it to avoid changing object structure
// https://www.smashingmagazine.com/2012/11/writing-fast-memory-efficient-javascript/#de-referencing-misconceptions
resultSet[k] = !!object[k];
}
}
}
var SPACE = /\s+/;
function _parseString (resultSet, str) {
var array = str.split(SPACE);
var length = array.length;
for (var i = 0; i < length; ++i) {
resultSet[array[i]] = true;
}
}
function _parse (resultSet, arg) {
if (!arg) return;
var argType = typeof arg;
// 'foo bar'
if (argType === 'string') {
_parseString(resultSet, arg);
// ['foo', 'bar', ...]
} else if (Array.isArray(arg)) {
_parseArray(resultSet, arg);
// { 'foo': true, ... }
} else if (argType === 'object') {
_parseObject(resultSet, arg);
// '130'
} else if (argType === 'number') {
_parseNumber(resultSet, arg);
}
}
function _classNames () {
// don't leak arguments
// https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#32-leaking-arguments
var len = arguments.length;
var args = Array(len);
for (var i = 0; i < len; i++) {
args[i] = arguments[i];
}
var classSet = new StorageObject();
_parseArray(classSet, args);
var list = [];
for (var k in classSet) {
if (classSet[k]) {
list.push(k)
}
}
return list.join(' ');
}
return _classNames;
})();
if (typeof module !== 'undefined' && module.exports) {
module.exports = classNames;
} else if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) {
// register as 'classnames', consistent with npm package name
define('classnames', [], function () {
return classNames;
});
} else {
window.classNames = classNames;
}
}());

View File

@@ -0,0 +1,48 @@
/*!
Copyright (c) 2016 Jed Watson.
Licensed under the MIT License (MIT), see
http://jedwatson.github.io/classnames
*/
/* global define */
(function () {
'use strict';
var hasOwn = {}.hasOwnProperty;
function classNames () {
var classes = [];
for (var i = 0; i < arguments.length; i++) {
var arg = arguments[i];
if (!arg) continue;
var argType = typeof arg;
if (argType === 'string' || argType === 'number') {
classes.push(arg);
} else if (Array.isArray(arg)) {
classes.push(classNames.apply(null, arg));
} else if (argType === 'object') {
for (var key in arg) {
if (hasOwn.call(arg, key) && arg[key]) {
classes.push(key);
}
}
}
}
return classes.join(' ');
}
if (typeof module !== 'undefined' && module.exports) {
module.exports = classNames;
} else if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) {
// register as 'classnames', consistent with npm package name
define('classnames', [], function () {
return classNames;
});
} else {
window.classNames = classNames;
}
}());

View File

@@ -0,0 +1,65 @@
{
"_args": [
[
"classnames@2.2.5",
"C:\\Users\\deranjer\\go\\src\\github.com\\deranjer\\goTorrent\\torrent-project"
]
],
"_from": "classnames@2.2.5",
"_id": "classnames@2.2.5",
"_inBundle": false,
"_integrity": "sha1-+zgB1FNGdknvNgPH1hoCvRKb3m0=",
"_location": "/react-grid-layout/classnames",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "classnames@2.2.5",
"name": "classnames",
"escapedName": "classnames",
"rawSpec": "2.2.5",
"saveSpec": null,
"fetchSpec": "2.2.5"
},
"_requiredBy": [
"/react-grid-layout",
"/react-grid-layout/react-draggable"
],
"_resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.5.tgz",
"_spec": "2.2.5",
"_where": "C:\\Users\\deranjer\\go\\src\\github.com\\deranjer\\goTorrent\\torrent-project",
"author": {
"name": "Jed Watson"
},
"bugs": {
"url": "https://github.com/JedWatson/classnames/issues"
},
"description": "A simple utility for conditionally joining classNames together",
"devDependencies": {
"benchmark": "^1.0.0",
"mocha": "^2.1.0"
},
"homepage": "https://github.com/JedWatson/classnames#readme",
"keywords": [
"react",
"css",
"classes",
"classname",
"classnames",
"util",
"utility"
],
"license": "MIT",
"main": "index.js",
"name": "classnames",
"repository": {
"type": "git",
"url": "git+https://github.com/JedWatson/classnames.git"
},
"scripts": {
"benchmarks": "node ./benchmarks/run",
"test": "npm run unit",
"unit": "mocha tests/*.js"
},
"version": "2.2.5"
}

View File

@@ -0,0 +1,409 @@
## Changelog
##### 1.2.7 [LEGACY] - 2016.07.18
* some fixes for issues like #159, #186, #194, #207
##### 1.2.6 - 2015.11.09
* reject with `TypeError` on attempt resolve promise itself
* correct behavior with broken `Promise` subclass constructors / methods
* added `Promise`-based fallback for microtask
* fixed V8 and FF `Array#{values, @@iterator}.name`
* fixed IE7- `[1, 2].join(undefined) -> '1,2'`
* some other fixes / improvements / optimizations
##### 1.2.5 - 2015.11.02
* some more `Number` constructor fixes:
* fixed V8 ~ Node 0.8 bug: `Number('+0x1')` should be `NaN`
* fixed `Number(' 0b1\n')` case, should be `1`
* fixed `Number()` case, should be `0`
##### 1.2.4 - 2015.11.01
* fixed `Number('0b12') -> NaN` case in the shim
* fixed V8 ~ Chromium 40- bug - `Weak(Map|Set)#{delete, get, has}` should not throw errors [#124](https://github.com/zloirock/core-js/issues/124)
* some other fixes and optimizations
##### 1.2.3 - 2015.10.23
* fixed some problems related old V8 bug `Object('a').propertyIsEnumerable(0) // => false`, for example, `Object.assign({}, 'qwe')` from the last release
* fixed `.name` property and `Function#toString` conversion some polyfilled methods
* fixed `Math.imul` arity in Safari 8-
##### 1.2.2 - 2015.10.18
* improved optimisations for V8
* fixed build process from external packages, [#120](https://github.com/zloirock/core-js/pull/120)
* one more `Object.{assign, values, entries}` fix for [**very** specific case](https://github.com/ljharb/proposal-object-values-entries/issues/5)
##### 1.2.1 - 2015.10.02
* replaced fix `JSON.stringify` + `Symbol` behavior from `.toJSON` method to wrapping `JSON.stringify` - little more correct, [compat-table/642](https://github.com/kangax/compat-table/pull/642)
* fixed typo which broke tasks scheduler in WebWorkers in old FF, [#114](https://github.com/zloirock/core-js/pull/114)
##### 1.2.0 - 2015.09.27
* added browser [`Promise` rejection hook](#unhandled-rejection-tracking), [#106](https://github.com/zloirock/core-js/issues/106)
* added correct [`IsRegExp`](http://www.ecma-international.org/ecma-262/6.0/#sec-isregexp) logic to [`String#{includes, startsWith, endsWith}`](https://github.com/zloirock/core-js/#ecmascript-6-string) and [`RegExp` constructor](https://github.com/zloirock/core-js/#ecmascript-6-regexp), `@@match` case, [example](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/match#Disabling_the_isRegExp_check)
* updated [`String#leftPad`](https://github.com/zloirock/core-js/#ecmascript-7) [with proposal](https://github.com/ljharb/proposal-string-pad-left-right/issues/6): string filler truncated from the right side
* replaced V8 [`Object.assign`](https://github.com/zloirock/core-js/#ecmascript-6-object) - its properties order not only [incorrect](https://github.com/sindresorhus/object-assign/issues/22), it is non-deterministic and it causes some problems
* fixed behavior with deleted in getters properties for `Object.{`[`assign`](https://github.com/zloirock/core-js/#ecmascript-6-object)`, `[`entries, values`](https://github.com/zloirock/core-js/#ecmascript-7)`}`, [example](http://goo.gl/iQE01c)
* fixed [`Math.sinh`](https://github.com/zloirock/core-js/#ecmascript-6-math) with very small numbers in V8 near Chromium 38
* some other fixes and optimizations
##### 1.1.4 - 2015.09.05
* fixed support symbols in FF34-35 [`Object.assign`](https://github.com/zloirock/core-js/#ecmascript-6-object)
* fixed [collections iterators](https://github.com/zloirock/core-js/#ecmascript-6-iterators) in FF25-26
* fixed non-generic WebKit [`Array.of`](https://github.com/zloirock/core-js/#ecmascript-6-array)
* some other fixes and optimizations
##### 1.1.3 - 2015.08.29
* fixed support Node.js domains in [`Promise`](https://github.com/zloirock/core-js/#ecmascript-6-promise), [#103](https://github.com/zloirock/core-js/issues/103)
##### 1.1.2 - 2015.08.28
* added `toJSON` method to [`Symbol`](https://github.com/zloirock/core-js/#ecmascript-6-symbol) polyfill and to MS Edge implementation for expected `JSON.stringify` result w/o patching this method
* replaced [`Reflect.construct`](https://github.com/zloirock/core-js/#ecmascript-6-reflect) implementations w/o correct support third argument
* fixed `global` detection with changed `document.domain` in ~IE8, [#100](https://github.com/zloirock/core-js/issues/100)
##### 1.1.1 - 2015.08.20
* added more correct microtask implementation for [`Promise`](#ecmascript-6-promise)
##### 1.1.0 - 2015.08.17
* updated [string padding](https://github.com/zloirock/core-js/#ecmascript-7) to [actual proposal](https://github.com/ljharb/proposal-string-pad-left-right) - renamed, minor internal changes:
* `String#lpad` -> `String#padLeft`
* `String#rpad` -> `String#padRight`
* added [string trim functions](#ecmascript-7) - [proposal](https://github.com/sebmarkbage/ecmascript-string-left-right-trim), defacto standard - required only for IE11- and fixed for some old engines:
* `String#trimLeft`
* `String#trimRight`
* [`String#trim`](https://github.com/zloirock/core-js/#ecmascript-6-string) fixed for some engines by es6 spec and moved from `es5` to single `es6` module
* splitted [`es6.object.statics-accept-primitives`](https://github.com/zloirock/core-js/#ecmascript-6-object)
* caps for `freeze`-family `Object` methods moved from `es5` to `es6` namespace and joined with [es6 wrappers](https://github.com/zloirock/core-js/#ecmascript-6-object)
* `es5` [namespace](https://github.com/zloirock/core-js/#commonjs) also includes modules, moved to `es6` namespace - you can use it as before
* increased `MessageChannel` priority in `$.task`, [#95](https://github.com/zloirock/core-js/issues/95)
* does not get `global.Symbol` on each getting iterator, if you wanna use alternative `Symbol` shim - add it before `core-js`
* [`Reflect.construct`](https://github.com/zloirock/core-js/#ecmascript-6-reflect) optimized and fixed for some cases
* simplified [`Reflect.enumerate`](https://github.com/zloirock/core-js/#ecmascript-6-reflect), see [this question](https://esdiscuss.org/topic/question-about-enumerate-and-property-decision-timing)
* some corrections in [`Math.acosh`](https://github.com/zloirock/core-js/#ecmascript-6-math)
* fixed [`Math.imul`](https://github.com/zloirock/core-js/#ecmascript-6-math) for old WebKit
* some fixes in string / RegExp [well-known symbols](https://github.com/zloirock/core-js/#ecmascript-6-regexp) logic
* some other fixes and optimizations
##### 1.0.1 - 2015.07.31
* some fixes for final MS Edge, replaced broken native `Reflect.defineProperty`
* some minor fixes and optimizations
* changed compression `client/*.min.js` options for safe `Function#name` and `Function#length`, should be fixed [#92](https://github.com/zloirock/core-js/issues/92)
##### 1.0.0 - 2015.07.22
* added logic for [well-known symbols](https://github.com/zloirock/core-js/#ecmascript-6-regexp):
* `Symbol.match`
* `Symbol.replace`
* `Symbol.split`
* `Symbol.search`
* actualized and optimized work with iterables:
* optimized [`Map`, `Set`, `WeakMap`, `WeakSet` constructors](https://github.com/zloirock/core-js/#ecmascript-6-collections), [`Promise.all`, `Promise.race`](https://github.com/zloirock/core-js/#ecmascript-6-promise) for default `Array Iterator`
* optimized [`Array.from`](https://github.com/zloirock/core-js/#ecmascript-6-array) for default `Array Iterator`
* added [`core.getIteratorMethod`](https://github.com/zloirock/core-js/#ecmascript-6-iterators) helper
* uses enumerable properties in shimmed instances - collections, iterators, etc for optimize performance
* added support native constructors to [`Reflect.construct`](https://github.com/zloirock/core-js/#ecmascript-6-reflect) with 2 arguments
* added support native constructors to [`Function#bind`](https://github.com/zloirock/core-js/#ecmascript-5) shim with `new`
* removed obsolete `.clear` methods native [`Weak`-collections](https://github.com/zloirock/core-js/#ecmascript-6-collections)
* maximum modularity, reduced minimal custom build size, separated into submodules:
* [`es6.reflect`](https://github.com/zloirock/core-js/#ecmascript-6-reflect)
* [`es6.regexp`](https://github.com/zloirock/core-js/#ecmascript-6-regexp)
* [`es6.math`](https://github.com/zloirock/core-js/#ecmascript-6-math)
* [`es6.number`](https://github.com/zloirock/core-js/#ecmascript-6-number)
* [`es7.object.to-array`](https://github.com/zloirock/core-js/#ecmascript-7)
* [`core.object`](https://github.com/zloirock/core-js/#object)
* [`core.string`](https://github.com/zloirock/core-js/#escaping-html)
* [`core.iter-helpers`](https://github.com/zloirock/core-js/#ecmascript-6-iterators)
* internal modules (`$`, `$.iter`, etc)
* many other optimizations
* final cleaning non-standard features
* moved `$for` to [separate library](https://github.com/zloirock/forof). This work for syntax - `for-of` loop and comprehensions
* moved `Date#{format, formatUTC}` to [separate library](https://github.com/zloirock/dtf). Standard way for this - `ECMA-402`
* removed `Math` methods from `Number.prototype`. Slight sugar for simple `Math` methods calling
* removed `{Array#, Array, Dict}.turn`
* removed `core.global`
* uses `ToNumber` instead of `ToLength` in [`Number Iterator`](https://github.com/zloirock/core-js/#number-iterator), `Array.from(2.5)` will be `[0, 1, 2]` instead of `[0, 1]`
* fixed [#85](https://github.com/zloirock/core-js/issues/85) - invalid `Promise` unhandled rejection message in nested `setTimeout`
* fixed [#86](https://github.com/zloirock/core-js/issues/86) - support FF extensions
* fixed [#89](https://github.com/zloirock/core-js/issues/89) - behavior `Number` constructor in strange case
##### 0.9.18 - 2015.06.17
* removed `/` from [`RegExp.escape`](https://github.com/zloirock/core-js/#ecmascript-7) escaped characters
##### 0.9.17 - 2015.06.14
* updated [`RegExp.escape`](https://github.com/zloirock/core-js/#ecmascript-7) to the [latest proposal](https://github.com/benjamingr/RexExp.escape)
* fixed conflict with webpack dev server + IE buggy behavior
##### 0.9.16 - 2015.06.11
* more correct order resolving thenable in [`Promise`](https://github.com/zloirock/core-js/#ecmascript-6-promise) polyfill
* uses polyfill instead of [buggy V8 `Promise`](https://github.com/zloirock/core-js/issues/78)
##### 0.9.15 - 2015.06.09
* [collections](https://github.com/zloirock/core-js/#ecmascript-6-collections) from `library` version return wrapped native instances
* fixed collections prototype methods in `library` version
* optimized [`Math.hypot`](https://github.com/zloirock/core-js/#ecmascript-6-math)
##### 0.9.14 - 2015.06.04
* updated [`Promise.resolve` behavior](https://esdiscuss.org/topic/fixing-promise-resolve)
* added fallback for IE11 buggy `Object.getOwnPropertyNames` + iframe
* some other fixes
##### 0.9.13 - 2015.05.25
* added fallback for [`Symbol` polyfill](https://github.com/zloirock/core-js/#ecmascript-6-symbol) for old Android
* some other fixes
##### 0.9.12 - 2015.05.24
* different instances `core-js` should use / recognize the same symbols
* some fixes
##### 0.9.11 - 2015.05.18
* simplified [custom build](https://github.com/zloirock/core-js/#custom-build)
* add custom build js api
* added `grunt-cli` to `devDependencies` for `npm run grunt`
* some fixes
##### 0.9.10 - 2015.05.16
* wrapped `Function#toString` for correct work wrapped methods / constructors with methods similar to the [`lodash` `isNative`](https://github.com/lodash/lodash/issues/1197)
* added proto versions of methods to export object in `default` version for consistency with `library` version
##### 0.9.9 - 2015.05.14
* wrapped `Object#propertyIsEnumerable` for [`Symbol` polyfill](https://github.com/zloirock/core-js/#ecmascript-6-symbol)
* [added proto versions of methods to `library` for ES7 bind syntax](https://github.com/zloirock/core-js/issues/65)
* some other fixes
##### 0.9.8 - 2015.05.12
* fixed [`Math.hypot`](https://github.com/zloirock/core-js/#ecmascript-6-math) with negative arguments
* added `Object#toString.toString` as fallback for [`lodash` `isNative`](https://github.com/lodash/lodash/issues/1197)
##### 0.9.7 - 2015.05.07
* added [support DOM collections](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice#Streamlining_cross-browser_behavior) to IE8- `Array#slice`
##### 0.9.6 - 2015.05.01
* added [`String#lpad`, `String#rpad`](https://github.com/zloirock/core-js/#ecmascript-7)
##### 0.9.5 - 2015.04.30
* added cap for `Function#@@hasInstance`
* some fixes and optimizations
##### 0.9.4 - 2015.04.27
* fixed `RegExp` constructor
##### 0.9.3 - 2015.04.26
* some fixes and optimizations
##### 0.9.2 - 2015.04.25
* more correct [`Promise`](https://github.com/zloirock/core-js/#ecmascript-6-promise) unhandled rejection tracking and resolving / rejection priority
##### 0.9.1 - 2015.04.25
* fixed `__proto__`-based [`Promise`](https://github.com/zloirock/core-js/#ecmascript-6-promise) subclassing in some environments
##### 0.9.0 - 2015.04.24
* added correct [symbols](https://github.com/zloirock/core-js/#ecmascript-6-symbol) descriptors
* fixed behavior `Object.{assign, create, defineProperty, defineProperties, getOwnPropertyDescriptor, getOwnPropertyDescriptors}` with symbols
* added [single entry points](https://github.com/zloirock/core-js/#commonjs) for `Object.{create, defineProperty, defineProperties}`
* added [`Map#toJSON`](https://github.com/zloirock/core-js/#ecmascript-7)
* removed non-standard methods `Object#[_]` and `Function#only` - they solves syntax problems, but now in compilers available arrows and ~~in near future will be available~~ [available](http://babeljs.io/blog/2015/05/14/function-bind/) [bind syntax](https://github.com/zenparsing/es-function-bind)
* removed non-standard undocumented methods `Symbol.{pure, set}`
* some fixes and internal changes
##### 0.8.4 - 2015.04.18
* uses `webpack` instead of `browserify` for browser builds - more compression-friendly result
##### 0.8.3 - 2015.04.14
* fixed `Array` statics with single entry points
##### 0.8.2 - 2015.04.13
* [`Math.fround`](https://github.com/zloirock/core-js/#ecmascript-6-math) now also works in IE9-
* added [`Set#toJSON`](https://github.com/zloirock/core-js/#ecmascript-7)
* some optimizations and fixes
##### 0.8.1 - 2015.04.03
* fixed `Symbol.keyFor`
##### 0.8.0 - 2015.04.02
* changed [CommonJS API](https://github.com/zloirock/core-js/#commonjs)
* splitted and renamed some modules
* added support ES3 environment (ES5 polyfill) to **all** default versions - size increases slightly (+ ~4kb w/o gzip), many issues disappear, if you don't need it - [simply include only required namespaces / features / modules](https://github.com/zloirock/core-js/#commonjs)
* removed [abstract references](https://github.com/zenparsing/es-abstract-refs) support - proposal has been superseded =\
* [`$for.isIterable` -> `core.isIterable`, `$for.getIterator` -> `core.getIterator`](https://github.com/zloirock/core-js/#ecmascript-6-iterators), temporary available in old namespace
* fixed iterators support in v8 `Promise.all` and `Promise.race`
* many other fixes
##### 0.7.2 - 2015.03.09
* some fixes
##### 0.7.1 - 2015.03.07
* some fixes
##### 0.7.0 - 2015.03.06
* rewritten and splitted into [CommonJS modules](https://github.com/zloirock/core-js/#commonjs)
##### 0.6.1 - 2015.02.24
* fixed support [`Object.defineProperty`](https://github.com/zloirock/core-js/#ecmascript-5) with accessors on DOM elements on IE8
##### 0.6.0 - 2015.02.23
* added support safe closing iteration - calling `iterator.return` on abort iteration, if it exists
* added basic support [`Promise`](https://github.com/zloirock/core-js/#ecmascript-6-promise) unhandled rejection tracking in shim
* added [`Object.getOwnPropertyDescriptors`](https://github.com/zloirock/core-js/#ecmascript-7)
* removed `console` cap - creates too many problems - you can use [`core.log`](https://github.com/zloirock/core-js/#console) module as that
* restructuring [namespaces](https://github.com/zloirock/core-js/#custom-build)
* some fixes
##### 0.5.4 - 2015.02.15
* some fixes
##### 0.5.3 - 2015.02.14
* added [support binary and octal literals](https://github.com/zloirock/core-js/#ecmascript-6-number) to `Number` constructor
* added [`Date#toISOString`](https://github.com/zloirock/core-js/#ecmascript-5)
##### 0.5.2 - 2015.02.10
* some fixes
##### 0.5.1 - 2015.02.09
* some fixes
##### 0.5.0 - 2015.02.08
* systematization of modules
* splitted [`es6` module](https://github.com/zloirock/core-js/#ecmascript-6)
* splitted [`console` module](https://github.com/zloirock/core-js/#console): `web.console` - only cap for missing methods, `core.log` - bound methods & additional features
* added [`delay` method](https://github.com/zloirock/core-js/#delay)
* some fixes
##### 0.4.10 - 2015.01.28
* [`Object.getOwnPropertySymbols`](https://github.com/zloirock/core-js/#ecmascript-6-symbol) polyfill returns array of wrapped keys
##### 0.4.9 - 2015.01.27
* FF20-24 fix
##### 0.4.8 - 2015.01.25
* some [collections](https://github.com/zloirock/core-js/#ecmascript-6-collections) fixes
##### 0.4.7 - 2015.01.25
* added support frozen objects as [collections](https://github.com/zloirock/core-js/#ecmascript-6-collections) keys
##### 0.4.6 - 2015.01.21
* added [`Object.getOwnPropertySymbols`](https://github.com/zloirock/core-js/#ecmascript-6-symbol)
* added [`NodeList.prototype[@@iterator]`](https://github.com/zloirock/core-js/#ecmascript-6-iterators)
* added basic `@@species` logic - getter in native constructors
* removed `Function#by`
* some fixes
##### 0.4.5 - 2015.01.16
* some fixes
##### 0.4.4 - 2015.01.11
* enabled CSP support
##### 0.4.3 - 2015.01.10
* added `Function` instances `name` property for IE9+
##### 0.4.2 - 2015.01.10
* `Object` static methods accept primitives
* `RegExp` constructor can alter flags (IE9+)
* added `Array.prototype[Symbol.unscopables]`
##### 0.4.1 - 2015.01.05
* some fixes
##### 0.4.0 - 2015.01.03
* added [`es6.reflect`](https://github.com/zloirock/core-js/#ecmascript-6-reflect) module:
* added `Reflect.apply`
* added `Reflect.construct`
* added `Reflect.defineProperty`
* added `Reflect.deleteProperty`
* added `Reflect.enumerate`
* added `Reflect.get`
* added `Reflect.getOwnPropertyDescriptor`
* added `Reflect.getPrototypeOf`
* added `Reflect.has`
* added `Reflect.isExtensible`
* added `Reflect.preventExtensions`
* added `Reflect.set`
* added `Reflect.setPrototypeOf`
* `core-js` methods now can use external `Symbol.iterator` polyfill
* some fixes
##### 0.3.3 - 2014.12.28
* [console cap](https://github.com/zloirock/core-js/#console) excluded from node.js default builds
##### 0.3.2 - 2014.12.25
* added cap for [ES5](https://github.com/zloirock/core-js/#ecmascript-5) freeze-family methods
* fixed `console` bug
##### 0.3.1 - 2014.12.23
* some fixes
##### 0.3.0 - 2014.12.23
* Optimize [`Map` & `Set`](https://github.com/zloirock/core-js/#ecmascript-6-collections):
* use entries chain on hash table
* fast & correct iteration
* iterators moved to [`es6`](https://github.com/zloirock/core-js/#ecmascript-6) and [`es6.collections`](https://github.com/zloirock/core-js/#ecmascript-6-collections) modules
##### 0.2.5 - 2014.12.20
* `console` no longer shortcut for `console.log` (compatibility problems)
* some fixes
##### 0.2.4 - 2014.12.17
* better compliance of ES6
* added [`Math.fround`](https://github.com/zloirock/core-js/#ecmascript-6-math) (IE10+)
* some fixes
##### 0.2.3 - 2014.12.15
* [Symbols](https://github.com/zloirock/core-js/#ecmascript-6-symbol):
* added option to disable addition setter to `Object.prototype` for Symbol polyfill:
* added `Symbol.useSimple`
* added `Symbol.useSetter`
* added cap for well-known Symbols:
* added `Symbol.hasInstance`
* added `Symbol.isConcatSpreadable`
* added `Symbol.match`
* added `Symbol.replace`
* added `Symbol.search`
* added `Symbol.species`
* added `Symbol.split`
* added `Symbol.toPrimitive`
* added `Symbol.unscopables`
##### 0.2.2 - 2014.12.13
* added [`RegExp#flags`](https://github.com/zloirock/core-js/#ecmascript-6-regexp) ([December 2014 Draft Rev 29](http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts#december_6_2014_draft_rev_29))
* added [`String.raw`](https://github.com/zloirock/core-js/#ecmascript-6-string)
##### 0.2.1 - 2014.12.12
* repair converting -0 to +0 in [native collections](https://github.com/zloirock/core-js/#ecmascript-6-collections)
##### 0.2.0 - 2014.12.06
* added [`es7.proposals`](https://github.com/zloirock/core-js/#ecmascript-7) and [`es7.abstract-refs`](https://github.com/zenparsing/es-abstract-refs) modules
* added [`String#at`](https://github.com/zloirock/core-js/#ecmascript-7)
* added real [`String Iterator`](https://github.com/zloirock/core-js/#ecmascript-6-iterators), older versions used Array Iterator
* added abstract references support:
* added `Symbol.referenceGet`
* added `Symbol.referenceSet`
* added `Symbol.referenceDelete`
* added `Function#@@referenceGet`
* added `Map#@@referenceGet`
* added `Map#@@referenceSet`
* added `Map#@@referenceDelete`
* added `WeakMap#@@referenceGet`
* added `WeakMap#@@referenceSet`
* added `WeakMap#@@referenceDelete`
* added `Dict.{...methods}[@@referenceGet]`
* removed deprecated `.contains` methods
* some fixes
##### 0.1.5 - 2014.12.01
* added [`Array#copyWithin`](https://github.com/zloirock/core-js/#ecmascript-6-array)
* added [`String#codePointAt`](https://github.com/zloirock/core-js/#ecmascript-6-string)
* added [`String.fromCodePoint`](https://github.com/zloirock/core-js/#ecmascript-6-string)
##### 0.1.4 - 2014.11.27
* added [`Dict.mapPairs`](https://github.com/zloirock/core-js/#dict)
##### 0.1.3 - 2014.11.20
* [TC39 November meeting](https://github.com/rwaldron/tc39-notes/tree/master/es6/2014-11):
* [`.contains` -> `.includes`](https://github.com/rwaldron/tc39-notes/blob/master/es6/2014-11/nov-18.md#51--44-arrayprototypecontains-and-stringprototypecontains)
* `String#contains` -> [`String#includes`](https://github.com/zloirock/core-js/#ecmascript-6-string)
* `Array#contains` -> [`Array#includes`](https://github.com/zloirock/core-js/#ecmascript-7)
* `Dict.contains` -> [`Dict.includes`](https://github.com/zloirock/core-js/#dict)
* [removed `WeakMap#clear`](https://github.com/rwaldron/tc39-notes/blob/master/es6/2014-11/nov-19.md#412-should-weakmapweakset-have-a-clear-method-markm)
* [removed `WeakSet#clear`](https://github.com/rwaldron/tc39-notes/blob/master/es6/2014-11/nov-19.md#412-should-weakmapweakset-have-a-clear-method-markm)
##### 0.1.2 - 2014.11.19
* `Map` & `Set` bug fix
##### 0.1.1 - 2014.11.18
* public release

View File

@@ -0,0 +1,2 @@
require('LiveScript');
module.exports = require('./build/Gruntfile');

View File

@@ -0,0 +1,19 @@
Copyright (c) 2015 Denis Pushkarev
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,34 @@
{
"name": "core.js",
"main": "client/core.js",
"version": "1.2.7",
"description": "Standard Library",
"keywords": [
"ES6",
"ECMAScript 6",
"ES7",
"ECMAScript 7",
"Map",
"Set",
"WeakMap",
"WeakSet",
"Dict",
"Promise",
"Symbol",
"console"
],
"authors": [
"Denis Pushkarev <zloirock@zloirock.ru> (http://zloirock.ru/)"
],
"license": "MIT",
"homepage": "https://github.com/zloirock/core-js",
"repository": {
"type": "git",
"url": "https://github.com/zloirock/core-js.git"
},
"ignore": [
"build",
"node_modules",
"tests"
]
}

View File

@@ -0,0 +1,84 @@
require! <[./build fs ./config]>
library-tests = <[client/library.js tests/helpers.js tests/library.js]>map -> src: it
module.exports = (grunt)->
grunt.loadNpmTasks \grunt-contrib-clean
grunt.loadNpmTasks \grunt-contrib-copy
grunt.loadNpmTasks \grunt-contrib-uglify
grunt.loadNpmTasks \grunt-contrib-watch
grunt.loadNpmTasks \grunt-livescript
grunt.loadNpmTasks \grunt-karma
grunt.initConfig do
pkg: grunt.file.readJSON './package.json'
uglify: build:
files: '<%=grunt.option("path")%>.min.js': '<%=grunt.option("path")%>.js'
options:
mangle: {+sort, +keep_fnames}
compress: {+pure_getters, +keep_fargs, +keep_fnames}
sourceMap: on
banner: config.banner
livescript: src: files:
'./tests/helpers.js': './tests/helpers/*'
'./tests/tests.js': './tests/tests/*'
'./tests/library.js': './tests/library/*'
'./tests/es.js': './tests/tests/es*'
'./tests/experimental.js': './tests/experimental/*'
'./build/index.js': './build/build.ls*'
clean: <[./library]>
copy: lib: files:
* expand: on
cwd: './'
src: <[es5/** es6/** es7/** js/** web/** core/** fn/** index.js shim.js]>
dest: './library/'
* expand: on
cwd: './'
src: <[modules/*]>
dest: './library/'
filter: \isFile
* expand: on
cwd: './modules/library/'
src: '*'
dest: './library/modules/'
watch:
core:
files: './modules/*'
tasks: \default
tests:
files: './tests/tests/*'
tasks: \livescript
karma:
'options':
configFile: './tests/karma.conf.js'
browsers: <[PhantomJS]>
singleRun: on
'continuous': {}
'continuous-library':
files: library-tests
grunt.registerTask \build (options)->
done = @async!
err, it <- build {
modules: (options || 'es5,es6,es7,js,web,core')split \,
blacklist: (grunt.option(\blacklist) || '')split \,
library: !!grunt.option \library
}
if err
console.error err
process.exit 1
grunt.option(\path) || grunt.option(\path, './custom')
fs.writeFile grunt.option(\path) + '.js', it, done
grunt.registerTask \client ->
grunt.option \library ''
grunt.option \path './client/core'
grunt.task.run <[build:es5,es6,es7,js,web,core uglify]>
grunt.registerTask \library ->
grunt.option \library 'true'
grunt.option \path './client/library'
grunt.task.run <[build:es5,es6,es7,js,web,core uglify]>
grunt.registerTask \shim ->
grunt.option \library ''
grunt.option \path './client/shim'
grunt.task.run <[build:es5,es6,es7,js,web uglify]>
grunt.registerTask \e ->
grunt.option \library ''>
grunt.option \path './client/core'
grunt.task.run <[build:es5,es6,es7,js,web,core,exp uglify]>
grunt.registerTask \default <[clean copy client library shim]>

View File

@@ -0,0 +1,218 @@
require! {'./config': {banner}, fs: {readFile, writeFile, unlink}, path, webpack}
list = <[
es5
es6.symbol
es6.object.assign
es6.object.is
es6.object.set-prototype-of
es6.object.to-string
es6.object.freeze
es6.object.seal
es6.object.prevent-extensions
es6.object.is-frozen
es6.object.is-sealed
es6.object.is-extensible
es6.object.get-own-property-descriptor
es6.object.get-prototype-of
es6.object.keys
es6.object.get-own-property-names
es6.function.name
es6.function.has-instance
es6.number.constructor
es6.number.epsilon
es6.number.is-finite
es6.number.is-integer
es6.number.is-nan
es6.number.is-safe-integer
es6.number.max-safe-integer
es6.number.min-safe-integer
es6.number.parse-float
es6.number.parse-int
es6.math.acosh
es6.math.asinh
es6.math.atanh
es6.math.cbrt
es6.math.clz32
es6.math.cosh
es6.math.expm1
es6.math.fround
es6.math.hypot
es6.math.imul
es6.math.log10
es6.math.log1p
es6.math.log2
es6.math.sign
es6.math.sinh
es6.math.tanh
es6.math.trunc
es6.string.from-code-point
es6.string.raw
es6.string.trim
es6.string.code-point-at
es6.string.ends-with
es6.string.includes
es6.string.repeat
es6.string.starts-with
es6.string.iterator
es6.array.from
es6.array.of
es6.array.iterator
es6.array.species
es6.array.copy-within
es6.array.fill
es6.array.find
es6.array.find-index
es6.regexp.constructor
es6.regexp.flags
es6.regexp.match
es6.regexp.replace
es6.regexp.search
es6.regexp.split
es6.promise
es6.map
es6.set
es6.weak-map
es6.weak-set
es6.reflect.apply
es6.reflect.construct
es6.reflect.define-property
es6.reflect.delete-property
es6.reflect.enumerate
es6.reflect.get
es6.reflect.get-own-property-descriptor
es6.reflect.get-prototype-of
es6.reflect.has
es6.reflect.is-extensible
es6.reflect.own-keys
es6.reflect.prevent-extensions
es6.reflect.set
es6.reflect.set-prototype-of
es6.date.to-string
es6.typed.array-buffer
es6.typed.data-view
es6.typed.int8-array
es6.typed.uint8-array
es6.typed.uint8-clamped-array
es6.typed.int16-array
es6.typed.uint16-array
es6.typed.int32-array
es6.typed.uint32-array
es6.typed.float32-array
es6.typed.float64-array
es7.array.includes
es7.string.at
es7.string.pad-left
es7.string.pad-right
es7.string.trim-left
es7.string.trim-right
es7.regexp.escape
es7.object.get-own-property-descriptors
es7.object.values
es7.object.entries
es7.map.to-json
es7.set.to-json
web.immediate
web.dom.iterable
web.timers
core.dict
core.get-iterator-method
core.get-iterator
core.is-iterable
core.delay
core.function.part
core.object.is-object
core.object.classof
core.object.define
core.object.make
core.number.iterator
core.string.escape-html
core.string.unescape-html
core.log
js.array.statics
]>
experimental = <[
es6.date.to-string
es6.typed.array-buffer
es6.typed.data-view
es6.typed.int8-array
es6.typed.uint8-array
es6.typed.uint8-clamped-array
es6.typed.int16-array
es6.typed.uint16-array
es6.typed.int32-array
es6.typed.uint32-array
es6.typed.float32-array
es6.typed.float64-array
]>
libraryBlacklist = <[
es6.object.to-string
es6.function.name
es6.regexp.constructor
es6.regexp.flags
es6.regexp.match
es6.regexp.replace
es6.regexp.search
es6.regexp.split
es6.number.constructor
]>
es5SpecialCase = <[
es6.object.freeze
es6.object.seal
es6.object.prevent-extensions
es6.object.is-frozen
es6.object.is-sealed
es6.object.is-extensible
es6.string.trim
]>
module.exports = ({modules = [], blacklist = [], library = no}, next)!->
let @ = modules.reduce ((memo, it)-> memo[it] = on; memo), {}
check = (err)->
if err
next err, ''
on
if @exp => for experimental => @[..] = on
if @es5 => for es5SpecialCase => @[..] = on
for ns of @
if @[ns]
for name in list
if name.indexOf("#ns.") is 0 and name not in experimental
@[name] = on
if library => blacklist ++= libraryBlacklist
for ns in blacklist
for name in list
if name is ns or name.indexOf("#ns.") is 0
@[name] = no
TARGET = "./__tmp#{ Math.random! }__.js"
err, info <~! webpack do
entry: list.filter(~> @[it]).map ~>
path.join(__dirname, '../', "#{ if library => '/library' else '' }/modules/#it")
output:
path: ''
filename: TARGET
if check err => return
err, script <~! readFile TARGET
if check err => return
err <~! unlink TARGET
if check err => return
next null """
#banner
!function(__e, __g, undefined){
'use strict';
#script
// CommonJS export
if(typeof module != 'undefined' && module.exports)module.exports = __e;
// RequireJS export
else if(typeof define == 'function' && define.amd)define(function(){return __e});
// Export to global object
else __g.core = __e;
}(1, 1);
"""

View File

@@ -0,0 +1,8 @@
module.exports = {
banner: '/**\n' +
' * core-js ' + require('../package').version + '\n' +
' * https://github.com/zloirock/core-js\n' +
' * License: http://rock.mit-license.org\n' +
' * © ' + new Date().getFullYear() + ' Denis Pushkarev\n' +
' */'
};

View File

@@ -0,0 +1,98 @@
// Generated by LiveScript 1.3.1
(function(){
var banner, ref$, readFile, writeFile, unlink, path, webpack, list, experimental, libraryBlacklist, es5SpecialCase;
banner = require('./config').banner;
ref$ = require('fs'), readFile = ref$.readFile, writeFile = ref$.writeFile, unlink = ref$.unlink;
path = require('path');
webpack = require('webpack');
list = ['es5', 'es6.symbol', 'es6.object.assign', 'es6.object.is', 'es6.object.set-prototype-of', 'es6.object.to-string', 'es6.object.freeze', 'es6.object.seal', 'es6.object.prevent-extensions', 'es6.object.is-frozen', 'es6.object.is-sealed', 'es6.object.is-extensible', 'es6.object.get-own-property-descriptor', 'es6.object.get-prototype-of', 'es6.object.keys', 'es6.object.get-own-property-names', 'es6.function.name', 'es6.function.has-instance', 'es6.number.constructor', 'es6.number.epsilon', 'es6.number.is-finite', 'es6.number.is-integer', 'es6.number.is-nan', 'es6.number.is-safe-integer', 'es6.number.max-safe-integer', 'es6.number.min-safe-integer', 'es6.number.parse-float', 'es6.number.parse-int', 'es6.math.acosh', 'es6.math.asinh', 'es6.math.atanh', 'es6.math.cbrt', 'es6.math.clz32', 'es6.math.cosh', 'es6.math.expm1', 'es6.math.fround', 'es6.math.hypot', 'es6.math.imul', 'es6.math.log10', 'es6.math.log1p', 'es6.math.log2', 'es6.math.sign', 'es6.math.sinh', 'es6.math.tanh', 'es6.math.trunc', 'es6.string.from-code-point', 'es6.string.raw', 'es6.string.trim', 'es6.string.code-point-at', 'es6.string.ends-with', 'es6.string.includes', 'es6.string.repeat', 'es6.string.starts-with', 'es6.string.iterator', 'es6.array.from', 'es6.array.of', 'es6.array.iterator', 'es6.array.species', 'es6.array.copy-within', 'es6.array.fill', 'es6.array.find', 'es6.array.find-index', 'es6.regexp.constructor', 'es6.regexp.flags', 'es6.regexp.match', 'es6.regexp.replace', 'es6.regexp.search', 'es6.regexp.split', 'es6.promise', 'es6.map', 'es6.set', 'es6.weak-map', 'es6.weak-set', 'es6.reflect.apply', 'es6.reflect.construct', 'es6.reflect.define-property', 'es6.reflect.delete-property', 'es6.reflect.enumerate', 'es6.reflect.get', 'es6.reflect.get-own-property-descriptor', 'es6.reflect.get-prototype-of', 'es6.reflect.has', 'es6.reflect.is-extensible', 'es6.reflect.own-keys', 'es6.reflect.prevent-extensions', 'es6.reflect.set', 'es6.reflect.set-prototype-of', 'es6.date.to-string', 'es6.typed.array-buffer', 'es6.typed.data-view', 'es6.typed.int8-array', 'es6.typed.uint8-array', 'es6.typed.uint8-clamped-array', 'es6.typed.int16-array', 'es6.typed.uint16-array', 'es6.typed.int32-array', 'es6.typed.uint32-array', 'es6.typed.float32-array', 'es6.typed.float64-array', 'es7.array.includes', 'es7.string.at', 'es7.string.pad-left', 'es7.string.pad-right', 'es7.string.trim-left', 'es7.string.trim-right', 'es7.regexp.escape', 'es7.object.get-own-property-descriptors', 'es7.object.values', 'es7.object.entries', 'es7.map.to-json', 'es7.set.to-json', 'web.immediate', 'web.dom.iterable', 'web.timers', 'core.dict', 'core.get-iterator-method', 'core.get-iterator', 'core.is-iterable', 'core.delay', 'core.function.part', 'core.object.is-object', 'core.object.classof', 'core.object.define', 'core.object.make', 'core.number.iterator', 'core.string.escape-html', 'core.string.unescape-html', 'core.log', 'js.array.statics'];
experimental = ['es6.date.to-string', 'es6.typed.array-buffer', 'es6.typed.data-view', 'es6.typed.int8-array', 'es6.typed.uint8-array', 'es6.typed.uint8-clamped-array', 'es6.typed.int16-array', 'es6.typed.uint16-array', 'es6.typed.int32-array', 'es6.typed.uint32-array', 'es6.typed.float32-array', 'es6.typed.float64-array'];
libraryBlacklist = ['es6.object.to-string', 'es6.function.name', 'es6.regexp.constructor', 'es6.regexp.flags', 'es6.regexp.match', 'es6.regexp.replace', 'es6.regexp.search', 'es6.regexp.split', 'es6.number.constructor'];
es5SpecialCase = ['es6.object.freeze', 'es6.object.seal', 'es6.object.prevent-extensions', 'es6.object.is-frozen', 'es6.object.is-sealed', 'es6.object.is-extensible', 'es6.string.trim'];
module.exports = function(arg$, next){
var modules, ref$, blacklist, library;
modules = (ref$ = arg$.modules) != null
? ref$
: [], blacklist = (ref$ = arg$.blacklist) != null
? ref$
: [], library = (ref$ = arg$.library) != null ? ref$ : false;
(function(){
var check, i$, x$, ref$, len$, y$, ns, name, j$, len1$, TARGET, this$ = this;
check = function(err){
if (err) {
next(err, '');
return true;
}
};
if (this.exp) {
for (i$ = 0, len$ = (ref$ = experimental).length; i$ < len$; ++i$) {
x$ = ref$[i$];
this[x$] = true;
}
}
if (this.es5) {
for (i$ = 0, len$ = (ref$ = es5SpecialCase).length; i$ < len$; ++i$) {
y$ = ref$[i$];
this[y$] = true;
}
}
for (ns in this) {
if (this[ns]) {
for (i$ = 0, len$ = (ref$ = list).length; i$ < len$; ++i$) {
name = ref$[i$];
if (name.indexOf(ns + ".") === 0 && !in$(name, experimental)) {
this[name] = true;
}
}
}
}
if (library) {
blacklist = blacklist.concat(libraryBlacklist);
}
for (i$ = 0, len$ = blacklist.length; i$ < len$; ++i$) {
ns = blacklist[i$];
for (j$ = 0, len1$ = (ref$ = list).length; j$ < len1$; ++j$) {
name = ref$[j$];
if (name === ns || name.indexOf(ns + ".") === 0) {
this[name] = false;
}
}
}
TARGET = "./__tmp" + Math.random() + "__.js";
webpack({
entry: list.filter(function(it){
return this$[it];
}).map(function(it){
return path.join(__dirname, '../', (library ? '/library' : '') + "/modules/" + it);
}),
output: {
path: '',
filename: TARGET
}
}, function(err, info){
if (check(err)) {
return;
}
readFile(TARGET, function(err, script){
if (check(err)) {
return;
}
unlink(TARGET, function(err){
if (check(err)) {
return;
}
next(null, "" + banner + "\n!function(__e, __g, undefined){\n'use strict';\n" + script + "\n// CommonJS export\nif(typeof module != 'undefined' && module.exports)module.exports = __e;\n// RequireJS export\nelse if(typeof define == 'function' && define.amd)define(function(){return __e});\n// Export to global object\nelse __g.core = __e;\n}(1, 1);");
});
});
});
}.call(modules.reduce(function(memo, it){
memo[it] = true;
return memo;
}, {})));
};
function in$(x, xs){
var i = -1, l = xs.length >>> 0;
while (++i < l) if (x === xs[i]) return true;
return false;
}
}).call(this);

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
require('../modules/core.function.part');
module.exports = require('../modules/$.core')._;

View File

@@ -0,0 +1,2 @@
require('../modules/core.delay');
module.exports = require('../modules/$.core').delay;

View File

@@ -0,0 +1,2 @@
require('../modules/core.dict');
module.exports = require('../modules/$.core').Dict;

View File

@@ -0,0 +1,2 @@
require('../modules/core.function.part');
module.exports = require('../modules/$.core').Function;

View File

@@ -0,0 +1,15 @@
require('../modules/core.dict');
require('../modules/core.get-iterator-method');
require('../modules/core.get-iterator');
require('../modules/core.is-iterable');
require('../modules/core.delay');
require('../modules/core.function.part');
require('../modules/core.object.is-object');
require('../modules/core.object.classof');
require('../modules/core.object.define');
require('../modules/core.object.make');
require('../modules/core.number.iterator');
require('../modules/core.string.escape-html');
require('../modules/core.string.unescape-html');
require('../modules/core.log');
module.exports = require('../modules/$.core');

View File

@@ -0,0 +1,2 @@
require('../modules/core.log');
module.exports = require('../modules/$.core').log;

View File

@@ -0,0 +1,2 @@
require('../modules/core.number.iterator');
module.exports = require('../modules/$.core').Number;

View File

@@ -0,0 +1,5 @@
require('../modules/core.object.is-object');
require('../modules/core.object.classof');
require('../modules/core.object.define');
require('../modules/core.object.make');
module.exports = require('../modules/$.core').Object;

View File

@@ -0,0 +1,3 @@
require('../modules/core.string.escape-html');
require('../modules/core.string.unescape-html');
module.exports = require('../modules/$.core').String;

View File

@@ -0,0 +1,9 @@
require('../modules/es5');
require('../modules/es6.object.freeze');
require('../modules/es6.object.seal');
require('../modules/es6.object.prevent-extensions');
require('../modules/es6.object.is-frozen');
require('../modules/es6.object.is-sealed');
require('../modules/es6.object.is-extensible');
require('../modules/es6.string.trim');
module.exports = require('../modules/$.core');

View File

@@ -0,0 +1,10 @@
require('../modules/es6.string.iterator');
require('../modules/es6.array.from');
require('../modules/es6.array.of');
require('../modules/es6.array.species');
require('../modules/es6.array.iterator');
require('../modules/es6.array.copy-within');
require('../modules/es6.array.fill');
require('../modules/es6.array.find');
require('../modules/es6.array.find-index');
module.exports = require('../modules/$.core').Array;

View File

@@ -0,0 +1,3 @@
require('../modules/es6.function.name');
require('../modules/es6.function.has-instance');
module.exports = require('../modules/$.core').Function;

View File

@@ -0,0 +1,87 @@
require('../modules/es6.symbol');
require('../modules/es6.object.assign');
require('../modules/es6.object.is');
require('../modules/es6.object.set-prototype-of');
require('../modules/es6.object.to-string');
require('../modules/es6.object.freeze');
require('../modules/es6.object.seal');
require('../modules/es6.object.prevent-extensions');
require('../modules/es6.object.is-frozen');
require('../modules/es6.object.is-sealed');
require('../modules/es6.object.is-extensible');
require('../modules/es6.object.get-own-property-descriptor');
require('../modules/es6.object.get-prototype-of');
require('../modules/es6.object.keys');
require('../modules/es6.object.get-own-property-names');
require('../modules/es6.function.name');
require('../modules/es6.function.has-instance');
require('../modules/es6.number.constructor');
require('../modules/es6.number.epsilon');
require('../modules/es6.number.is-finite');
require('../modules/es6.number.is-integer');
require('../modules/es6.number.is-nan');
require('../modules/es6.number.is-safe-integer');
require('../modules/es6.number.max-safe-integer');
require('../modules/es6.number.min-safe-integer');
require('../modules/es6.number.parse-float');
require('../modules/es6.number.parse-int');
require('../modules/es6.math.acosh');
require('../modules/es6.math.asinh');
require('../modules/es6.math.atanh');
require('../modules/es6.math.cbrt');
require('../modules/es6.math.clz32');
require('../modules/es6.math.cosh');
require('../modules/es6.math.expm1');
require('../modules/es6.math.fround');
require('../modules/es6.math.hypot');
require('../modules/es6.math.imul');
require('../modules/es6.math.log10');
require('../modules/es6.math.log1p');
require('../modules/es6.math.log2');
require('../modules/es6.math.sign');
require('../modules/es6.math.sinh');
require('../modules/es6.math.tanh');
require('../modules/es6.math.trunc');
require('../modules/es6.string.from-code-point');
require('../modules/es6.string.raw');
require('../modules/es6.string.trim');
require('../modules/es6.string.iterator');
require('../modules/es6.string.code-point-at');
require('../modules/es6.string.ends-with');
require('../modules/es6.string.includes');
require('../modules/es6.string.repeat');
require('../modules/es6.string.starts-with');
require('../modules/es6.array.from');
require('../modules/es6.array.of');
require('../modules/es6.array.species');
require('../modules/es6.array.iterator');
require('../modules/es6.array.copy-within');
require('../modules/es6.array.fill');
require('../modules/es6.array.find');
require('../modules/es6.array.find-index');
require('../modules/es6.regexp.constructor');
require('../modules/es6.regexp.flags');
require('../modules/es6.regexp.match');
require('../modules/es6.regexp.replace');
require('../modules/es6.regexp.search');
require('../modules/es6.regexp.split');
require('../modules/es6.promise');
require('../modules/es6.map');
require('../modules/es6.set');
require('../modules/es6.weak-map');
require('../modules/es6.weak-set');
require('../modules/es6.reflect.apply');
require('../modules/es6.reflect.construct');
require('../modules/es6.reflect.define-property');
require('../modules/es6.reflect.delete-property');
require('../modules/es6.reflect.enumerate');
require('../modules/es6.reflect.get');
require('../modules/es6.reflect.get-own-property-descriptor');
require('../modules/es6.reflect.get-prototype-of');
require('../modules/es6.reflect.has');
require('../modules/es6.reflect.is-extensible');
require('../modules/es6.reflect.own-keys');
require('../modules/es6.reflect.prevent-extensions');
require('../modules/es6.reflect.set');
require('../modules/es6.reflect.set-prototype-of');
module.exports = require('../modules/$.core');

View File

@@ -0,0 +1,5 @@
require('../modules/es6.object.to-string');
require('../modules/es6.string.iterator');
require('../modules/web.dom.iterable');
require('../modules/es6.map');
module.exports = require('../modules/$.core').Map;

View File

@@ -0,0 +1,18 @@
require('../modules/es6.math.acosh');
require('../modules/es6.math.asinh');
require('../modules/es6.math.atanh');
require('../modules/es6.math.cbrt');
require('../modules/es6.math.clz32');
require('../modules/es6.math.cosh');
require('../modules/es6.math.expm1');
require('../modules/es6.math.fround');
require('../modules/es6.math.hypot');
require('../modules/es6.math.imul');
require('../modules/es6.math.log10');
require('../modules/es6.math.log1p');
require('../modules/es6.math.log2');
require('../modules/es6.math.sign');
require('../modules/es6.math.sinh');
require('../modules/es6.math.tanh');
require('../modules/es6.math.trunc');
module.exports = require('../modules/$.core').Math;

View File

@@ -0,0 +1,11 @@
require('../modules/es6.number.constructor');
require('../modules/es6.number.epsilon');
require('../modules/es6.number.is-finite');
require('../modules/es6.number.is-integer');
require('../modules/es6.number.is-nan');
require('../modules/es6.number.is-safe-integer');
require('../modules/es6.number.max-safe-integer');
require('../modules/es6.number.min-safe-integer');
require('../modules/es6.number.parse-float');
require('../modules/es6.number.parse-int');
module.exports = require('../modules/$.core').Number;

View File

@@ -0,0 +1,17 @@
require('../modules/es6.symbol');
require('../modules/es6.object.assign');
require('../modules/es6.object.is');
require('../modules/es6.object.set-prototype-of');
require('../modules/es6.object.to-string');
require('../modules/es6.object.freeze');
require('../modules/es6.object.seal');
require('../modules/es6.object.prevent-extensions');
require('../modules/es6.object.is-frozen');
require('../modules/es6.object.is-sealed');
require('../modules/es6.object.is-extensible');
require('../modules/es6.object.get-own-property-descriptor');
require('../modules/es6.object.get-prototype-of');
require('../modules/es6.object.keys');
require('../modules/es6.object.get-own-property-names');
module.exports = require('../modules/$.core').Object;

View File

@@ -0,0 +1,5 @@
require('../modules/es6.object.to-string');
require('../modules/es6.string.iterator');
require('../modules/web.dom.iterable');
require('../modules/es6.promise');
module.exports = require('../modules/$.core').Promise;

View File

@@ -0,0 +1,15 @@
require('../modules/es6.reflect.apply');
require('../modules/es6.reflect.construct');
require('../modules/es6.reflect.define-property');
require('../modules/es6.reflect.delete-property');
require('../modules/es6.reflect.enumerate');
require('../modules/es6.reflect.get');
require('../modules/es6.reflect.get-own-property-descriptor');
require('../modules/es6.reflect.get-prototype-of');
require('../modules/es6.reflect.has');
require('../modules/es6.reflect.is-extensible');
require('../modules/es6.reflect.own-keys');
require('../modules/es6.reflect.prevent-extensions');
require('../modules/es6.reflect.set');
require('../modules/es6.reflect.set-prototype-of');
module.exports = require('../modules/$.core').Reflect;

View File

@@ -0,0 +1,7 @@
require('../modules/es6.regexp.constructor');
require('../modules/es6.regexp.flags');
require('../modules/es6.regexp.match');
require('../modules/es6.regexp.replace');
require('../modules/es6.regexp.search');
require('../modules/es6.regexp.split');
module.exports = require('../modules/$.core').RegExp;

View File

@@ -0,0 +1,5 @@
require('../modules/es6.object.to-string');
require('../modules/es6.string.iterator');
require('../modules/web.dom.iterable');
require('../modules/es6.set');
module.exports = require('../modules/$.core').Set;

View File

@@ -0,0 +1,14 @@
require('../modules/es6.string.from-code-point');
require('../modules/es6.string.raw');
require('../modules/es6.string.trim');
require('../modules/es6.string.iterator');
require('../modules/es6.string.code-point-at');
require('../modules/es6.string.ends-with');
require('../modules/es6.string.includes');
require('../modules/es6.string.repeat');
require('../modules/es6.string.starts-with');
require('../modules/es6.regexp.match');
require('../modules/es6.regexp.replace');
require('../modules/es6.regexp.search');
require('../modules/es6.regexp.split');
module.exports = require('../modules/$.core').String;

View File

@@ -0,0 +1,3 @@
require('../modules/es6.symbol');
require('../modules/es6.object.to-string');
module.exports = require('../modules/$.core').Symbol;

View File

@@ -0,0 +1,4 @@
require('../modules/es6.object.to-string');
require('../modules/es6.array.iterator');
require('../modules/es6.weak-map');
module.exports = require('../modules/$.core').WeakMap;

View File

@@ -0,0 +1,4 @@
require('../modules/es6.object.to-string');
require('../modules/web.dom.iterable');
require('../modules/es6.weak-set');
module.exports = require('../modules/$.core').WeakSet;

View File

@@ -0,0 +1,2 @@
require('../modules/es7.array.includes');
module.exports = require('../modules/$.core').Array;

View File

@@ -0,0 +1,13 @@
require('../modules/es7.array.includes');
require('../modules/es7.string.at');
require('../modules/es7.string.pad-left');
require('../modules/es7.string.pad-right');
require('../modules/es7.string.trim-left');
require('../modules/es7.string.trim-right');
require('../modules/es7.regexp.escape');
require('../modules/es7.object.get-own-property-descriptors');
require('../modules/es7.object.values');
require('../modules/es7.object.entries');
require('../modules/es7.map.to-json');
require('../modules/es7.set.to-json');
module.exports = require('../modules/$.core');

View File

@@ -0,0 +1,2 @@
require('../modules/es7.map.to-json');
module.exports = require('../modules/$.core').Map;

View File

@@ -0,0 +1,4 @@
require('../modules/es7.object.get-own-property-descriptors');
require('../modules/es7.object.values');
require('../modules/es7.object.entries');
module.exports = require('../modules/$.core').Object;

View File

@@ -0,0 +1,2 @@
require('../modules/es7.regexp.escape');
module.exports = require('../modules/$.core').RegExp;

View File

@@ -0,0 +1,2 @@
require('../modules/es7.set.to-json');
module.exports = require('../modules/$.core').Set;

View File

@@ -0,0 +1,6 @@
require('../modules/es7.string.at');
require('../modules/es7.string.pad-left');
require('../modules/es7.string.pad-right');
require('../modules/es7.string.trim-left');
require('../modules/es7.string.trim-right');
module.exports = require('../modules/$.core').String;

View File

@@ -0,0 +1,2 @@
require('../modules/core.function.part');
module.exports = require('../modules/$.core')._;

View File

@@ -0,0 +1,2 @@
require('../../modules/js.array.statics');
module.exports = require('../../modules/$.core').Array.concat;

View File

@@ -0,0 +1,2 @@
require('../../modules/es6.array.copy-within');
module.exports = require('../../modules/$.core').Array.copyWithin;

View File

@@ -0,0 +1,2 @@
require('../../modules/es6.array.iterator');
module.exports = require('../../modules/$.core').Array.entries;

View File

@@ -0,0 +1,2 @@
require('../../modules/js.array.statics');
module.exports = require('../../modules/$.core').Array.every;

View File

@@ -0,0 +1,2 @@
require('../../modules/es6.array.fill');
module.exports = require('../../modules/$.core').Array.fill;

View File

@@ -0,0 +1,2 @@
require('../../modules/js.array.statics');
module.exports = require('../../modules/$.core').Array.filter;

View File

@@ -0,0 +1,2 @@
require('../../modules/es6.array.find-index');
module.exports = require('../../modules/$.core').Array.findIndex;

View File

@@ -0,0 +1,2 @@
require('../../modules/es6.array.find');
module.exports = require('../../modules/$.core').Array.find;

Some files were not shown because too many files have changed in this diff Show More