@casl/react
Advanced tools
Comparing version 0.7.2 to 0.8.0
@@ -5,2 +5,23 @@ # Change Log | ||
# [@casl/react-v0.8.0](https://github.com/stalniy/casl/compare/@casl/react@0.7.2...@casl/react@0.8.0) (2018-09-03) | ||
### Bug Fixes | ||
* **README:** changes links to [@casl](https://github.com/casl)/ability to point to npm package instead to git root [skip ci] ([a74086b](https://github.com/stalniy/casl/commit/a74086b)), closes [#102](https://github.com/stalniy/casl/issues/102) | ||
### Features | ||
* **react:can:** adds `an` alias to `on` prop ([748ea64](https://github.com/stalniy/casl/commit/748ea64)) | ||
* **react:can:** adds `passThrough` option ([045318c](https://github.com/stalniy/casl/commit/045318c)), closes [#105](https://github.com/stalniy/casl/issues/105) | ||
* **react:can:** adds support for multiple <Can> children ([c022b32](https://github.com/stalniy/casl/commit/c022b32)) | ||
* **react:can:** updates typescript declarations ([70953ed](https://github.com/stalniy/casl/commit/70953ed)) | ||
* **react:can:** updates typescript declarations ([213dcde](https://github.com/stalniy/casl/commit/213dcde)) | ||
### Performance Improvements | ||
* **react:can:** moves prop type checks undef `if`, so they can be removed for production builds ([4bebf0b](https://github.com/stalniy/casl/commit/4bebf0b)) | ||
# [@casl/react-v0.7.2](https://github.com/stalniy/casl/compare/@casl/react@0.7.1...@casl/react@0.7.2) (2018-07-29) | ||
@@ -7,0 +28,0 @@ |
@@ -1,2 +0,2 @@ | ||
import React, { PureComponent, createElement } from 'react'; | ||
import React, { PureComponent, Fragment, createElement } from 'react'; | ||
import PropTypes from 'prop-types'; | ||
@@ -54,17 +54,38 @@ import { Ability } from '@casl/ability'; | ||
var noop = function noop() {}; | ||
var REQUIRED_OBJECT_OR_STRING = PropTypes.oneOfType([PropTypes.object, PropTypes.string]).isRequired; | ||
var _renderChildren = Fragment ? function (children) { | ||
return createElement.apply(null, [Fragment, null].concat(children)); | ||
} : React.Children.only; | ||
var propTypes = {}; | ||
function alias(names, validate) { | ||
return function (props) { | ||
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { | ||
args[_key - 1] = arguments[_key]; | ||
} | ||
if (process.env.NODE_ENV !== 'production') { | ||
var REQUIRED_OBJECT_OR_STRING = PropTypes.oneOfType([PropTypes.object, PropTypes.string]).isRequired; | ||
// eslint-disable-line | ||
if (!names.split(' ').some(function (name) { | ||
return props[name]; | ||
})) { | ||
return validate.apply(undefined, [props].concat(args)); | ||
} | ||
var alias = function alias(names, validate) { | ||
return function (props) { | ||
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { | ||
args[_key - 1] = arguments[_key]; | ||
} | ||
// eslint-disable-line | ||
if (!names.split(' ').some(function (name) { | ||
return props[name]; | ||
})) { | ||
return validate.apply(undefined, [props].concat(args)); | ||
} | ||
}; | ||
}; | ||
propTypes = { | ||
I: alias('do', PropTypes.string.isRequired), | ||
a: alias('on this of an', REQUIRED_OBJECT_OR_STRING), | ||
an: alias('on this of a', REQUIRED_OBJECT_OR_STRING), | ||
of: alias('on a this an', REQUIRED_OBJECT_OR_STRING), | ||
this: alias('on a of an', REQUIRED_OBJECT_OR_STRING), | ||
do: alias('I', PropTypes.string.isRequired), | ||
on: alias('this a of an', REQUIRED_OBJECT_OR_STRING), | ||
not: PropTypes.bool, | ||
passThrough: PropTypes.bool, | ||
children: PropTypes.any.isRequired, | ||
ability: PropTypes.instanceOf(Ability).isRequired | ||
}; | ||
} | ||
@@ -142,3 +163,4 @@ | ||
Can.prototype.render = function render() { | ||
return this.state.allowed ? this.renderChildren() : null; | ||
var canRender = this.props.passThrough || this.state.allowed; | ||
return canRender ? this.renderChildren() : null; | ||
}; | ||
@@ -149,4 +171,5 @@ | ||
var elements = typeof children === 'function' ? children(this.state.allowed, this.state.ability) : children; | ||
return typeof children === 'function' ? children(this.state.ability) : React.Children.only(children); | ||
return _renderChildren(elements); | ||
}; | ||
@@ -163,13 +186,3 @@ | ||
Can.propTypes = { | ||
I: alias('do', PropTypes.string.isRequired), | ||
a: alias('on this of', REQUIRED_OBJECT_OR_STRING), | ||
of: alias('on a this', REQUIRED_OBJECT_OR_STRING), | ||
this: alias('on a of', REQUIRED_OBJECT_OR_STRING), | ||
do: alias('I', PropTypes.string.isRequired), | ||
on: alias('this a of', REQUIRED_OBJECT_OR_STRING), | ||
not: PropTypes.bool, | ||
children: PropTypes.any.isRequired, | ||
ability: PropTypes.instanceOf(Ability).isRequired | ||
}; | ||
Can.propTypes = propTypes; | ||
@@ -207,5 +220,6 @@ function createCanBoundTo(ability) { | ||
I: props.I || props.do, | ||
a: props.a || props.of || props.this || props.on, | ||
a: props.on || props.a || props.an || props.of || props.this, | ||
not: props.not, | ||
children: props.children | ||
children: props.children, | ||
passThrough: props.passThrough | ||
}); | ||
@@ -212,0 +226,0 @@ }); |
@@ -1,2 +0,2 @@ | ||
import React, { PureComponent, createElement } from 'react'; | ||
import React, { PureComponent, Fragment, createElement } from 'react'; | ||
import PropTypes from 'prop-types'; | ||
@@ -6,6 +6,9 @@ import { Ability } from '@casl/ability'; | ||
const noop = () => {}; | ||
const REQUIRED_OBJECT_OR_STRING = PropTypes.oneOfType([PropTypes.object, PropTypes.string]).isRequired; | ||
const renderChildren = Fragment ? children => createElement.apply(null, [Fragment, null].concat(children)) : React.Children.only; | ||
let propTypes = {}; | ||
function alias(names, validate) { | ||
return (props, ...args) => { | ||
if (process.env.NODE_ENV !== 'production') { | ||
const REQUIRED_OBJECT_OR_STRING = PropTypes.oneOfType([PropTypes.object, PropTypes.string]).isRequired; | ||
const alias = (names, validate) => (props, ...args) => { | ||
// eslint-disable-line | ||
@@ -16,2 +19,16 @@ if (!names.split(' ').some(name => props[name])) { | ||
}; | ||
propTypes = { | ||
I: alias('do', PropTypes.string.isRequired), | ||
a: alias('on this of an', REQUIRED_OBJECT_OR_STRING), | ||
an: alias('on this of a', REQUIRED_OBJECT_OR_STRING), | ||
of: alias('on a this an', REQUIRED_OBJECT_OR_STRING), | ||
this: alias('on a of an', REQUIRED_OBJECT_OR_STRING), | ||
do: alias('I', PropTypes.string.isRequired), | ||
on: alias('this a of an', REQUIRED_OBJECT_OR_STRING), | ||
not: PropTypes.bool, | ||
passThrough: PropTypes.bool, | ||
children: PropTypes.any.isRequired, | ||
ability: PropTypes.instanceOf(Ability).isRequired | ||
}; | ||
} | ||
@@ -75,3 +92,4 @@ | ||
render() { | ||
return this.state.allowed ? this.renderChildren() : null; | ||
const canRender = this.props.passThrough || this.state.allowed; | ||
return canRender ? this.renderChildren() : null; | ||
} | ||
@@ -81,17 +99,8 @@ | ||
const { children } = this.props; | ||
const elements = typeof children === 'function' ? children(this.state.allowed, this.state.ability) : children; | ||
return typeof children === 'function' ? children(this.state.ability) : React.Children.only(children); | ||
return renderChildren(elements); | ||
} | ||
} | ||
Can.propTypes = { | ||
I: alias('do', PropTypes.string.isRequired), | ||
a: alias('on this of', REQUIRED_OBJECT_OR_STRING), | ||
of: alias('on a this', REQUIRED_OBJECT_OR_STRING), | ||
this: alias('on a of', REQUIRED_OBJECT_OR_STRING), | ||
do: alias('I', PropTypes.string.isRequired), | ||
on: alias('this a of', REQUIRED_OBJECT_OR_STRING), | ||
not: PropTypes.bool, | ||
children: PropTypes.any.isRequired, | ||
ability: PropTypes.instanceOf(Ability).isRequired | ||
}; | ||
Can.propTypes = propTypes; | ||
@@ -117,5 +126,6 @@ function createCanBoundTo(ability) { | ||
I: props.I || props.do, | ||
a: props.a || props.of || props.this || props.on, | ||
a: props.on || props.a || props.an || props.of || props.this, | ||
not: props.not, | ||
children: props.children | ||
children: props.children, | ||
passThrough: props.passThrough | ||
})); | ||
@@ -122,0 +132,0 @@ }; |
@@ -1,1 +0,1 @@ | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("react"),require("prop-types"),require("@casl/ability")):"function"==typeof define&&define.amd?define(["exports","react","prop-types","@casl/ability"],e):e((t.casl=t.casl||{},t.casl.react={}),t.React,t.React.PropTypes,t.casl)}(this,function(t,n,i,r){"use strict";var e="default"in n?n.default:n;i=i&&i.hasOwnProperty("default")?i.default:i;var c=function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")},a=function(){function i(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(t,e,n){return e&&i(t.prototype,e),n&&i(t,n),t}}(),l=function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)},s=function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e},u=function(){},o=i.oneOfType([i.object,i.string]).isRequired;function p(r,o){return function(e){for(var t=arguments.length,n=Array(1<t?t-1:0),i=1;i<t;i++)n[i-1]=arguments[i];if(!r.split(" ").some(function(t){return e[t]}))return o.apply(void 0,[e].concat(n))}}var f=function(r){function o(){c(this,o);for(var t=arguments.length,e=Array(t),n=0;n<t;n++)e[n]=arguments[n];var i=s(this,r.call.apply(r,[this].concat(e)));return i.unsubscribeFromAbility=u,i.state={ability:i.props.ability,allowed:!1},i}return l(o,r),o.prototype.componentWillReceiveProps=function(t){t.ability&&this.state.ability!==t.ability?(this.setState({ability:t.ability}),this.connectToAbility(t.ability)):this.recheck(t)},o.prototype.componentWillMount=function(){this.connectToAbility(this.state.ability)},o.prototype.componentWillUnmount=function(){this.unsubscribeFromAbility()},o.prototype.connectToAbility=function(t){var e=this;this.unsubscribeFromAbility(),t&&(this.unsubscribeFromAbility=t.on("updated",function(){return e.recheck()}),this.recheck())},o.prototype.recheck=function(t){return this.setState({allowed:this.check(t)})},o.prototype.check=function(){var t=(0<arguments.length&&void 0!==arguments[0]?arguments[0]:null)||this.props,e=(t.I||t.do).split(/\s+/),n=e[0],i=e[1],r=t.of||t.a||t.this||t.on,o=t.not?"cannot":"can";return this.state.ability[o](n,r,i)},o.prototype.render=function(){return this.state.allowed?this.renderChildren():null},o.prototype.renderChildren=function(){var t=this.props.children;return"function"==typeof t?t(this.state.ability):e.Children.only(t)},a(o,[{key:"allowed",get:function(){return this.state.allowed}}]),o}(n.PureComponent);f.propTypes={I:p("do",i.string.isRequired),a:p("on this of",o),of:p("on a this",o),this:p("on a of",o),do:p("I",i.string.isRequired),on:p("this a of",o),not:i.bool,children:i.any.isRequired,ability:i.instanceOf(r.Ability).isRequired},t.Can=f,t.createCanBoundTo=function(a){var t,e;return e=t=function(r){function o(){c(this,o);for(var t=arguments.length,e=Array(t),n=0;n<t;n++)e[n]=arguments[n];var i=s(this,r.call.apply(r,[this].concat(e)));return i.state.ability=i.state.ability||a,i}return l(o,r),o}(f),t.propTypes=Object.assign({},f.propTypes,{ability:i.instanceOf(r.Ability)}),e},t.createContextualCan=function(t){return function(e){return n.createElement(t,null,function(t){return n.createElement(f,{ability:e.ability||t,I:e.I||e.do,a:e.a||e.of||e.this||e.on,not:e.not,children:e.children})})}},Object.defineProperty(t,"__esModule",{value:!0})}); | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("react"),require("prop-types"),require("@casl/ability")):"function"==typeof define&&define.amd?define(["exports","react","prop-types","@casl/ability"],e):e((t.casl=t.casl||{},t.casl.react={}),t.React,t.React.PropTypes,t.casl)}(this,function(t,n,i,o){"use strict";var e="default"in n?n.default:n;i=i&&i.hasOwnProperty("default")?i.default:i;var s=function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")},a=function(){function i(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}return function(t,e,n){return e&&i(t.prototype,e),n&&i(t,n),t}}(),c=function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)},l=function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e},u=function(){},p=n.Fragment?function(t){return n.createElement.apply(null,[n.Fragment,null].concat(t))}:e.Children.only,r={};if("production"!==process.env.NODE_ENV){var f=i.oneOfType([i.object,i.string]).isRequired,y=function(o,r){return function(e){for(var t=arguments.length,n=Array(1<t?t-1:0),i=1;i<t;i++)n[i-1]=arguments[i];if(!o.split(" ").some(function(t){return e[t]}))return r.apply(void 0,[e].concat(n))}};r={I:y("do",i.string.isRequired),a:y("on this of an",f),an:y("on this of a",f),of:y("on a this an",f),this:y("on a of an",f),do:y("I",i.string.isRequired),on:y("this a of an",f),not:i.bool,passThrough:i.bool,children:i.any.isRequired,ability:i.instanceOf(o.Ability).isRequired}}var h=function(o){function r(){s(this,r);for(var t=arguments.length,e=Array(t),n=0;n<t;n++)e[n]=arguments[n];var i=l(this,o.call.apply(o,[this].concat(e)));return i.unsubscribeFromAbility=u,i.state={ability:i.props.ability,allowed:!1},i}return c(r,o),r.prototype.componentWillReceiveProps=function(t){t.ability&&this.state.ability!==t.ability?(this.setState({ability:t.ability}),this.connectToAbility(t.ability)):this.recheck(t)},r.prototype.componentWillMount=function(){this.connectToAbility(this.state.ability)},r.prototype.componentWillUnmount=function(){this.unsubscribeFromAbility()},r.prototype.connectToAbility=function(t){var e=this;this.unsubscribeFromAbility(),t&&(this.unsubscribeFromAbility=t.on("updated",function(){return e.recheck()}),this.recheck())},r.prototype.recheck=function(t){return this.setState({allowed:this.check(t)})},r.prototype.check=function(){var t=(0<arguments.length&&void 0!==arguments[0]?arguments[0]:null)||this.props,e=(t.I||t.do).split(/\s+/),n=e[0],i=e[1],o=t.of||t.a||t.this||t.on,r=t.not?"cannot":"can";return this.state.ability[r](n,o,i)},r.prototype.render=function(){return this.props.passThrough||this.state.allowed?this.renderChildren():null},r.prototype.renderChildren=function(){var t=this.props.children,e="function"==typeof t?t(this.state.allowed,this.state.ability):t;return p(e)},a(r,[{key:"allowed",get:function(){return this.state.allowed}}]),r}(n.PureComponent);h.propTypes=r,t.Can=h,t.createCanBoundTo=function(a){var t,e;return e=t=function(o){function r(){s(this,r);for(var t=arguments.length,e=Array(t),n=0;n<t;n++)e[n]=arguments[n];var i=l(this,o.call.apply(o,[this].concat(e)));return i.state.ability=i.state.ability||a,i}return c(r,o),r}(h),t.propTypes=Object.assign({},h.propTypes,{ability:i.instanceOf(o.Ability)}),e},t.createContextualCan=function(t){return function(e){return n.createElement(t,null,function(t){return n.createElement(h,{ability:e.ability||t,I:e.I||e.do,a:e.on||e.a||e.an||e.of||e.this,not:e.not,children:e.children,passThrough:e.passThrough})})}},Object.defineProperty(t,"__esModule",{value:!0})}); |
@@ -12,2 +12,5 @@ import { PureComponent, StatelessComponent } from 'react' | ||
I: string | ||
an: string | ||
} | { | ||
I: string | ||
of: any | ||
@@ -22,2 +25,3 @@ } | { | ||
not?: boolean | ||
passThrough?: boolean | ||
} | ||
@@ -28,2 +32,3 @@ | ||
not?: boolean | ||
passThrough?: boolean | ||
} | ||
@@ -30,0 +35,0 @@ |
{ | ||
"name": "@casl/react", | ||
"version": "0.7.2", | ||
"version": "0.8.0", | ||
"description": "React component for CASL which makes it easy to add permissions in any React application", | ||
@@ -42,3 +42,3 @@ "main": "dist/umd/index.js", | ||
"peerDependencies": { | ||
"@casl/ability": "^2.0.0-alpha.1", | ||
"@casl/ability": "^2.0.0", | ||
"prop-types": "^15.0.0", | ||
@@ -52,5 +52,4 @@ "react": "^15.0.0 || ^16.0.0" | ||
"react": "^16.3.0", | ||
"react-test-renderer": "^16.3.0", | ||
"semantic-release": "^15.5.0" | ||
"react-test-renderer": "^16.3.0" | ||
} | ||
} |
# CASL React [](https://badge.fury.io/js/%40casl%2Freact) [](https://www.npmjs.com/package/%40casl%2Freact) [](https://stalniy.github.io/casl/) [](https://gitter.im/stalniy-casl/casl?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) | ||
This package allows to integrate [@casl/ability](/packages/casl-ability) into [React][react] application. So, you can show or hide UI elements based on user ability to see them. | ||
This package allows to integrate [@casl/ability][casl-ability] into [React][react] application. So, you can show or hide UI elements based on user ability to see them. | ||
@@ -24,3 +24,3 @@ ## Installation | ||
<Can I="create" a="Post" ability={ability}> | ||
() => <button onClick={this.createPost.bind(this)}>Create Post</button> | ||
{() => <button onClick={this.createPost.bind(this)}>Create Post</button>} | ||
</Can> | ||
@@ -66,3 +66,3 @@ ``` | ||
<Can I="create" a="Post"> | ||
() => <button onClick={this.createPost.bind(this)}>Create Post</button> | ||
{() => <button onClick={this.createPost.bind(this)}>Create Post</button>} | ||
</Can> | ||
@@ -113,3 +113,3 @@ ) | ||
<Can I="create" a="Todo"> | ||
() => <button onClick={this.createTodo.bind(this)}>Create Todo</button> | ||
{() => <button onClick={this.createTodo.bind(this)}>Create Todo</button>} | ||
</Can> | ||
@@ -177,3 +177,3 @@ ) | ||
Obviously, in this case your server API should provide the list of user abilities in `rules` field of the response. | ||
See [@casl/ability](/packages/casl-ability) package for more information on how to define abilities. | ||
See [@casl/ability][casl-ability] package for more information on how to define abilities. | ||
@@ -187,3 +187,3 @@ ### 3. Property names and aliases | ||
<Can I="create" a="Post"> | ||
() => <button onClick={...}>Create Post</button> | ||
{() => <button onClick={...}>Create Post</button>} | ||
</Can> | ||
@@ -194,3 +194,3 @@ ``` | ||
* use `a` alias when you check by Type | ||
* use `a` (or `an`) alias when you check by Type | ||
@@ -236,3 +236,11 @@ ```jsx | ||
* use `passThrough` if you want to customize behavior of `<Can>` component, for example disable button instead of hiding it: | ||
```jsx | ||
<Can I="read" a="Post" passThrough> | ||
{can => <button disabled={!can}>Save</button>} | ||
</Can> | ||
``` | ||
## Want to help? | ||
@@ -250,1 +258,2 @@ | ||
[react-ctx-api]: https://medium.com/dailyjs/reacts-%EF%B8%8F-new-context-api-70c9fe01596b | ||
[casl-ability]: https://www.npmjs.com/package/@casl/ability |
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
30042
5
340
252
3