Socket
Socket
Sign inDemoInstall

uncontrollable

Package Overview
Dependencies
Maintainers
1
Versions
50
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

uncontrollable - npm Package Compare versions

Comparing version 1.4.0 to 2.0.0

60

lib/uncontrollable.js
"use strict";
var babelHelpers = require("./util/babelHelpers.js");
var React = require("react");
var ReactUpdates = require("react/lib/ReactUpdates");
var invariant = require("react/lib/invariant");

@@ -30,3 +31,11 @@

module.exports = function (Component, controlledValues, taps) {
function forceUpdateIfMounted() {
if (this.isMounted() && this._needsUpdate) {
this._needsUpdate = false;
this.forceUpdate();
}
}
module.exports = function (Component, controlledValues) {
var name = Component.displayName || Component.name || "Component",

@@ -50,4 +59,2 @@ types = {};

taps = taps || {};
return React.createClass({

@@ -59,3 +66,7 @@

getInitialState: function () {
componentWillMount: function () {
var _this = this;
this.values = Object.create(null);
var props = this.props,

@@ -65,9 +76,8 @@ keys = Object.keys(controlledValues);

return transform(keys, function (state, key) {
state[key] = props[defaultKey(key)];
_this.values[key] = props[defaultKey(key)];
}, {});
},
shouldComponentUpdate: function () {
//let the setState trigger the update
return !this._notifying;
componentWillReceiveProps: function (nextProps) {
this._needsUpdate = false;
},

@@ -92,3 +102,3 @@

newProps[propName] = prop !== undefined ? prop : _this.state[propName];
newProps[propName] = prop !== undefined ? prop : _this.values[propName];

@@ -100,7 +110,2 @@ newProps[handle] = setAndNotify.bind(_this, propName);

//console.log('props: ', newProps)
each(taps, function (val, key) {
return newProps[key] = chain(_this, val, newProps[key]);
});
return React.createElement(Component, newProps);

@@ -111,2 +116,4 @@ }

function setAndNotify(propName, value) {
var _this = this;
for (var _len = arguments.length, args = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {

@@ -118,21 +125,15 @@ args[_key - 2] = arguments[_key];

handler = this.props[controlledValues[propName]];
//, controlled = handler && isProp(this.props, propName);
if (linkName && isProp(this.props, linkName) && !handler) {
handler = this.props[linkName].requestChange
//propName = propName === 'valueLink' ? 'value' : 'checked'
;
handler = this.props[linkName].requestChange;
}
if (handler) {
this._notifying = true;
handler.call.apply(handler, [this, value].concat(args));
this._notifying = false;
}
this._needsUpdate = true;
this.values[propName] = value;
this.setState((function () {
var _setState = {};
_setState[propName] = value;
return _setState;
})());
if (handler) handler.call.apply(handler, [this, value].concat(args));
ReactUpdates.batchedUpdates(function () {
ReactUpdates.asap(forceUpdateIfMounted, _this);
});
}

@@ -173,3 +174,2 @@

return o ? Object.prototype.hasOwnProperty.call(o, k) : false;
}
//return !controlled
}
{
"name": "uncontrollable",
"version": "1.4.0",
"version": "2.0.0",
"description": "Wrap a controlled react component, to allow spcific prop/handler pairs to be uncontrolled",

@@ -5,0 +5,0 @@ "author": {

'use strict';
var React = require('react/addons')
var uncontrol = require('../src/uncontrollable')
var Layer = require('react-layer')

@@ -28,13 +29,27 @@ var TestUtils = React.addons.TestUtils

onToggle: React.PropTypes.func,
onRender: React.PropTypes.func,
},
nonBatchingChange(val){
var target = this.refs.input.getDOMNode()
if (val) target.value = val
this.props.onChange(val)
},
render() {
if ( this.props.onRender )
this.props.onRender(this.props)
return (
<div>
<button onClick={this.props.onToggle}>toggle</button>
{ this.props.open &&
{ this.props.open &&
<span className='open'>open!</span>
}
<input className='valueInput'
value={this.props.value}
ref='input'
value={this.props.value}
onChange={ e => this.props.onChange(e.value)}/>

@@ -54,3 +69,3 @@ <input type='checkbox'

, instance = render(<Control value={3}/>)
warn.should.have.been.CalledOnce;

@@ -70,3 +85,3 @@

, input = findAllTag(instance, 'input')[0]
input.getDOMNode().value.should.equal('10')

@@ -84,3 +99,3 @@

, input = findAllTag(instance, 'input')[1]
input.getDOMNode().checked.should.equal(false)

@@ -107,10 +122,10 @@

it('should track state if no specified', () => {
it('should track internally if not specified', () => {
var Control = uncontrol(Base, { value: 'onChange' })
, instance = render(<Control />)
, input = findAllTag(instance, 'input')[0]
trigger.change(input.getDOMNode(), { value: 42})
instance.state.should.have.property('value')
expect(instance.values).to.have.property('value')
.that.equals(42)

@@ -124,3 +139,3 @@ })

, span = findClass(instance, 'open')
input.getDOMNode().value.should.equal('10')

@@ -130,33 +145,138 @@

instance.state.value.should.equal(42)
expect(instance.values.value).to.equal(42)
})
describe('taps', () => {
it('should not throw when not batching', () => {
var spy = sinon.spy();
it('should call the tap function before the handler', ()=> {
var tap = sinon.spy()
, onChange = sinon.spy()
, Control = uncontrol(Base, { value: 'onChange' }, { 'onChange': tap })
, instance = render(<Control defaultValue={10} onChange={onChange}/>)
, input = findAllTag(instance, 'input')[0];
var Control = uncontrol(Base, { value: 'onChange', open: 'onToggle' })
, instance = render(<Control defaultValue={10} defaultOpen onChange={spy} />)
, base = findType(instance, Base)
, span = findClass(instance, 'open')
trigger.change(input.getDOMNode(), { value: 42 })
expect(()=>
base.nonBatchingChange(42)).not.to.throw()
tap.should.have.been.CalledOnce
tap.should.have.been.calledBefore(onChange)
onChange.should.have.been.CalledOnce
spy.should.have.been.calledOnce
expect(instance.values.value).to.equal(42)
})
it('should update in the right order when controlled', () => {
var Control = uncontrol(Base, { value: 'onChange' })
, spy = sinon.spy();
var Parent = React.createClass({
getInitialState(){ return { value: 5 } },
render(){
return (
<Control
onRender={spy}
value={this.state.value}
onChange={value => this.setState({ value })}
/>
)
}
})
it('should call the tap function this `this` as the wrapping component', ()=> {
var tap = sinon.spy(function(){ this.should.equal(instance) })
, Control = uncontrol(Base, { value: 'onChange' }, { 'onChange': tap })
, instance = render(<Control defaultValue={10}/>)
, input = findAllTag(instance, 'input')[0];
var instance = render(<Parent/>)
, input = findAllTag(instance, 'input')[0]
trigger.change(input.getDOMNode(), { value: 42 })
trigger.change(input.getDOMNode(), { value: 42 })
tap.should.have.been.CalledOnce
spy.callCount.should.equal(2)
spy.firstCall.args[0].value.should.equal(5)
spy.secondCall.args[0].value.should.equal(42)
})
it('should update in the right order when uncontrolled', () => {
var Control = uncontrol(Base, { value: 'onChange' })
, spy = sinon.spy();
var Parent = React.createClass({
getInitialState(){ return { value: 5 } },
render(){
return (
<Control
ref='ctrl'
onRender={spy}
defaultValue={this.state.value}
/>
)
}
})
var instance = render(<Parent/>)
, input = findAllTag(instance, 'input')[0]
trigger.change(input.getDOMNode(), { value: 42 })
spy.callCount.should.equal(2)
spy.firstCall.args[0].value.should.equal(5)
spy.secondCall.args[0].value.should.equal(42)
spy.reset();
findType(instance.refs.ctrl, Base).nonBatchingChange(84);
spy.callCount.should.equal(1)
spy.firstCall.args[0].value.should.equal(84)
})
it('should update correctly in a Layer', () => {
var Control = uncontrol(Base, { value: 'onChange' })
, spy = sinon.spy();
var Parent = React.createClass({
getInitialState(){ return { value: 5 } },
componentWillUnmount () {
this._layer.destroy()
this._layer = null
},
componentDidUpdate(){this._renderOverlay()},
componentDidMount() {this._renderOverlay()},
_renderOverlay() {
if (!this._layer)
this._layer = new Layer(document.body, ()=> this._child)
this.layerInstance = this._layer.render()
},
render(){
this._child = (
<Control ref='ctrl'
onRender={spy}
value={this.state.value}
onChange={value => this.setState({ value, called: true })}
/>
)
return (
<div/>
)
}
})
var instance = render(<Parent/>)
, input = findAllTag(instance.layerInstance, 'input')[0]
trigger.change(input.getDOMNode(), { value: 42 })
spy.callCount.should.equal(2)
spy.firstCall.args[0].value.should.equal(5)
spy.secondCall.args[0].value.should.equal(42)
spy.reset();
findType(instance.refs.ctrl, Base).nonBatchingChange(84);
spy.callCount.should.equal(1)
spy.firstCall.args[0].value.should.equal(84)
})
})
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc