react-values
Version:
A set of tiny, composable React components for handling state with render props.
789 lines (644 loc) • 22.4 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react')) :
typeof define === 'function' && define.amd ? define(['exports', 'react'], factory) :
(factory((global.ReactValues = {}),global.React));
}(this, (function (exports,React) { 'use strict';
React = React && React.hasOwnProperty('default') ? React['default'] : React;
var classCallCheck = function (instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
};
var createClass = function () {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function (Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
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 inherits = function (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 possibleConstructorReturn = function (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 createComponent(Store) {
return function (_React$Component) {
inherits(Value, _React$Component);
function Value(props, context) {
classCallCheck(this, Value);
var _this = possibleConstructorReturn(this, (Value.__proto__ || Object.getPrototypeOf(Value)).call(this, props));
var value = props.value,
defaultValue = props.defaultValue,
store = props.store;
var connected = !store;
var controlled = false;
if (!store) {
if (value !== undefined) {
store = new Store(value, props);
controlled = true;
} else {
store = new Store(defaultValue, props);
}
}
_this.state = {
connected: connected,
controlled: controlled,
store: store,
value: store.value
};
return _this;
}
createClass(Value, [{
key: 'componentDidMount',
value: function componentDidMount() {
var _this2 = this;
var _state = this.state,
controlled = _state.controlled,
store = _state.store;
this.mounted = true;
this.unsubscribe = store.on(function (value) {
if (!_this2.mounted) return;
if (controlled) {
_this2.onChange(value);
} else {
_this2.setState({ value: value }, function () {
return _this2.onChange(_this2.state.value);
});
}
});
}
}, {
key: 'componentWillUnmount',
value: function componentWillUnmount() {
this.mounted = false;
this.unsubscribe();
}
}, {
key: 'onChange',
value: function onChange(value) {
if (this.props.onChange) {
this.props.onChange(value);
}
}
}, {
key: 'render',
value: function render() {
var _props = this.props,
children = _props.children,
render = _props.render,
_props$disabled = _props.disabled,
disabled = _props$disabled === undefined ? false : _props$disabled;
var _state2 = this.state,
controlled = _state2.controlled,
connected = _state2.connected,
store = _state2.store;
var value = controlled ? this.props.value : this.state.value;
var transforms = disabled ? store.noops : store.transforms;
var fn = children || render;
if (controlled) {
store.value = value;
}
if (!connected) {
store.props = this.props;
}
if (fn === null) {
return null;
}
var renderProps = _extends({ value: value, disabled: disabled }, transforms);
for (var key in store.computeds) {
renderProps[key] = store.computeds[key]();
}
var ret = typeof fn === 'function' ? fn(renderProps) : fn;
return ret;
}
}]);
return Value;
}(React.Component);
}
function createFactory(Store, Value) {
return function (initial, props) {
var store = new Store(initial, props);
var Connected = function (_React$Component) {
inherits(Connected, _React$Component);
function Connected() {
classCallCheck(this, Connected);
return possibleConstructorReturn(this, (Connected.__proto__ || Object.getPrototypeOf(Connected)).apply(this, arguments));
}
createClass(Connected, [{
key: 'render',
value: function render() {
return React.createElement(Value, _extends({}, this.props, { store: store }));
}
}], [{
key: 'value',
get: function get$$1() {
return store.value;
}
}]);
return Connected;
}(React.Component);
for (var k in store.transforms) {
Connected[k] = store.transforms[k];
}
Connected.store = store;
Connected.displayName = 'Connected' + Value.displayName;
return Connected;
};
}
var Store = function () {
function Store(value) {
var _this = this;
var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var empty = arguments[2];
classCallCheck(this, Store);
this.callbacks = [];
this.value = value === undefined ? empty : value;
this.transforms = {};
this.noops = {};
this.computeds = {};
this.props = props;
this.define('set', function (v, next) {
return next;
});
this.define('reset', function () {
return _this.clone(value);
});
this.define('clear', function () {
return _this.clone(empty);
});
if (props.onChange) {
this.on(props.onChange);
}
}
createClass(Store, [{
key: 'on',
value: function on(callback) {
var _this2 = this;
var index = this.callbacks.push(callback) - 1;
var off = function off() {
return _this2.callbacks[index] = null;
};
return off;
}
}, {
key: 'clone',
value: function clone(v) {
return v;
}
}, {
key: 'transform',
value: function transform(fn) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var value = this.value,
callbacks = this.callbacks;
var _options$mutates = options.mutates,
mutates = _options$mutates === undefined ? false : _options$mutates;
var current = mutates ? this.clone(value) : value;
var next = typeof fn === 'function' ? fn(current) : fn;
this.value = next;
callbacks.forEach(function (cb) {
return cb && cb(next);
});
}
}, {
key: 'define',
value: function define(name, fn, options) {
var _this3 = this;
this.noops[name] = function () {};
this.transforms[name] = function () {
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
_this3.transform(function (v) {
return fn.apply(undefined, [v].concat(args));
}, options);
};
}
}, {
key: 'compute',
value: function compute(name, fn) {
var _this4 = this;
this.computeds[name] = function () {
return fn(_this4.value);
};
}
}, {
key: 'proxy',
value: function proxy(method) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var _options$alias = options.alias,
alias = _options$alias === undefined ? method : _options$alias,
_options$mutates2 = options.mutates,
mutates = _options$mutates2 === undefined ? false : _options$mutates2;
this.define(alias, function (v) {
for (var _len2 = arguments.length, args = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
args[_key2 - 1] = arguments[_key2];
}
var ret = v[method].apply(v, args);
return mutates ? v : ret;
}, options);
}
}]);
return Store;
}();
var Value = createComponent(Store);
var createValue = createFactory(Store, Value);
var ArrayStore = function (_Store) {
inherits(ArrayStore, _Store);
function ArrayStore(value, props) {
classCallCheck(this, ArrayStore);
var _this = possibleConstructorReturn(this, (ArrayStore.__proto__ || Object.getPrototypeOf(ArrayStore)).call(this, value, props, []));
_this.compute('first', function (v) {
return v[0];
});
_this.compute('last', function (v) {
return v[Math.max(0, v.length - 1)];
});
_this.proxy('concat');
_this.proxy('fill', { mutates: true });
_this.proxy('filter');
_this.proxy('flat');
_this.proxy('flatMap');
_this.proxy('map');
_this.proxy('pop', { mutates: true });
_this.proxy('push', { mutates: true });
_this.proxy('reverse', { mutates: true });
_this.proxy('shift', { mutates: true });
_this.proxy('slice');
_this.proxy('sort', { mutates: true });
_this.proxy('splice', { mutates: true });
_this.proxy('unshift', { mutates: true });
return _this;
}
createClass(ArrayStore, [{
key: 'clone',
value: function clone(value) {
return value.slice();
}
}]);
return ArrayStore;
}(Store);
var ArrayValue = createComponent(ArrayStore);
var createArrayValue = createFactory(ArrayStore, ArrayValue);
var BooleanStore = function (_Store) {
inherits(BooleanStore, _Store);
function BooleanStore(value, props) {
classCallCheck(this, BooleanStore);
var _this = possibleConstructorReturn(this, (BooleanStore.__proto__ || Object.getPrototypeOf(BooleanStore)).call(this, value, props, false));
_this.define('toggle', function (v) {
return !v;
});
return _this;
}
return BooleanStore;
}(Store);
var BooleanValue = createComponent(BooleanStore);
var createBooleanValue = createFactory(BooleanStore, BooleanValue);
var SECONDS = 1000;
var MINUTES = 1000 * 60;
var HOURS = 1000 * 60 * 60;
var DateStore = function (_Store) {
inherits(DateStore, _Store);
function DateStore(value, props) {
classCallCheck(this, DateStore);
var _this = possibleConstructorReturn(this, (DateStore.__proto__ || Object.getPrototypeOf(DateStore)).call(this, value, props, new Date()));
_this.compute('date', function (v) {
return v.getDate();
});
_this.compute('hours', function (v) {
return v.getHours();
});
_this.compute('milliseconds', function (v) {
return v.getMilliseconds();
});
_this.compute('minutes', function (v) {
return v.getMinutes();
});
_this.compute('month', function (v) {
return v.getMonth();
});
_this.compute('seconds', function (v) {
return v.getSeconds();
});
_this.compute('year', function (v) {
return v.getFullYear();
});
_this.define('setMonth', setMonth);
_this.proxy('setDate', { mutates: true });
_this.proxy('setFullYear', { alias: 'setYear', mutates: true });
_this.proxy('setFullYear', { mutates: true });
_this.proxy('setHours', { mutates: true });
_this.proxy('setMilliseconds', { mutates: true });
_this.proxy('setMinutes', { mutates: true });
_this.proxy('setSeconds', { mutates: true });
_this.define('incrementDate', function (v) {
var n = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
return incDate(v, n);
});
_this.define('incrementHours', function (v) {
var n = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
return incMil(v, n * HOURS);
});
_this.define('incrementMilliseconds', function (v) {
var n = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
return incMil(v, n);
});
_this.define('incrementMinutes', function (v) {
var n = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
return incMil(v, n * MINUTES);
});
_this.define('incrementMonth', function (v) {
var n = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
return incMonth(v, n);
});
_this.define('incrementSeconds', function (v) {
var n = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
return incMil(v, n * SECONDS);
});
_this.define('incrementYear', function (v) {
var n = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
return incMonth(v, n * 12);
});
_this.define('decrementDate', function (v) {
var n = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
return incDate(v, 0 - n);
});
_this.define('decrementHours', function (v) {
var n = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
return incMil(v, 0 - n * HOURS);
});
_this.define('decrementMilliseconds', function (v) {
var n = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
return incMil(v, 0 - n);
});
_this.define('decrementMinutes', function (v) {
var n = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
return incMil(v, 0 - n * MINUTES);
});
_this.define('decrementMonth', function (v) {
var n = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
return incMonth(v, 0 - n);
});
_this.define('decrementSeconds', function (v) {
var n = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
return incMil(v, 0 - n * SECONDS);
});
_this.define('decrementYear', function (v) {
var n = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
return incMonth(v, 0 - n * 12);
});
return _this;
}
createClass(DateStore, [{
key: 'clone',
value: function clone(value) {
return new Date(value.getTime());
}
}]);
return DateStore;
}(Store);
function incMil(v, n) {
return new Date(v.getTime() + n);
}
function incDate(v, n) {
var d = new Date(v.getTime());
d.setDate(d.getDate() + n);
return d;
}
function incMonth(v, n) {
var year = v.getFullYear();
var desiredMonth = v.getMonth() + n;
var desired = new Date(0);
desired.setFullYear(year, desiredMonth, 1);
desired.setHours(0, 0, 0, 0);
var max = days(desired);
v.setMonth(desiredMonth, Math.min(max, v.getDate()));
return v;
}
function setMonth(v, m) {
var d = new Date(v.getTime());
var year = d.getFullYear();
var day = d.getDate();
var desired = new Date(0);
desired.setFullYear(year, m, 15);
desired.setHours(0, 0, 0, 0);
var max = days(desired);
d.setMonth(m, Math.min(day, max));
return d;
}
function days(v) {
var year = v.getFullYear();
var monthIndex = v.getMonth();
var lastDayOfMonth = new Date(0);
lastDayOfMonth.setFullYear(year, monthIndex + 1, 0);
lastDayOfMonth.setHours(0, 0, 0, 0);
return lastDayOfMonth.getDate();
}
var DateValue = createComponent(DateStore);
var createDateValue = createFactory(DateStore, DateValue);
var MapStore = function (_Store) {
inherits(MapStore, _Store);
function MapStore(value, props) {
classCallCheck(this, MapStore);
var _this = possibleConstructorReturn(this, (MapStore.__proto__ || Object.getPrototypeOf(MapStore)).call(this, value, props, new Map()));
_this.define('set', function (v) {
for (var _len = arguments.length, a = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
a[_key - 1] = arguments[_key];
}
var first = a[0];
return a.length === 1 ? typeof first === 'function' ? first(v) : first : v.set.apply(v, a);
});
_this.proxy('clear', { mutates: true });
_this.proxy('delete', { mutates: true });
_this.proxy('delete', { alias: 'unset', mutates: true });
return _this;
}
createClass(MapStore, [{
key: 'clone',
value: function clone(value) {
return new Map(value);
}
}]);
return MapStore;
}(Store);
var MapValue = createComponent(MapStore);
var createMapValue = createFactory(MapStore, MapValue);
var NumberStore = function (_Store) {
inherits(NumberStore, _Store);
function NumberStore(value, props) {
classCallCheck(this, NumberStore);
var _this = possibleConstructorReturn(this, (NumberStore.__proto__ || Object.getPrototypeOf(NumberStore)).call(this, value, props, 0));
_this.define('increment', function (v) {
var n = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
var num = typeof n !== 'number' ? 1 : n;
return Math.min(v + num, _this.props.max);
});
_this.define('decrement', function (v) {
var n = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
var num = typeof n !== 'number' ? 1 : n;
return Math.max(v - num, _this.props.min);
});
return _this;
}
return NumberStore;
}(Store);
var NumberValue = createComponent(NumberStore);
var createNumberValue = createFactory(NumberStore, NumberValue);
NumberValue.defaultProps = {
max: Number.MAX_SAFE_INTEGER,
min: Number.MIN_SAFE_INTEGER
};
var ObjectStore = function (_Store) {
inherits(ObjectStore, _Store);
function ObjectStore(value, props) {
classCallCheck(this, ObjectStore);
var _this = possibleConstructorReturn(this, (ObjectStore.__proto__ || Object.getPrototypeOf(ObjectStore)).call(this, value, props, {}));
_this.define('set', function (v) {
for (var _len = arguments.length, a = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
a[_key - 1] = arguments[_key];
}
var first = a[0];
if (a.length === 1) {
return typeof first === 'function' ? first(v) : first;
}
var key = a[0],
val = a[1];
var clone = _extends({}, v);
clone[key] = val;
return clone;
});
_this.define('assign', function (v) {
var val = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
return _extends({}, v, val);
});
_this.define('clear', function () {
return {};
});
_this.define('delete', unset);
_this.define('unset', unset);
return _this;
}
createClass(ObjectStore, [{
key: 'clone',
value: function clone(value) {
return _extends({}, value);
}
}]);
return ObjectStore;
}(Store);
function unset(v, key) {
var clone = _extends({}, v);
delete clone[key];
return clone;
}
var ObjectValue = createComponent(ObjectStore);
var createObjectValue = createFactory(ObjectStore, ObjectValue);
var SetStore = function (_Store) {
inherits(SetStore, _Store);
function SetStore(value, props) {
classCallCheck(this, SetStore);
var _this = possibleConstructorReturn(this, (SetStore.__proto__ || Object.getPrototypeOf(SetStore)).call(this, value, props, new Set()));
_this.define('toggle', function (v, val, boolean) {
if (boolean) {
return v.add(val);
} else {
v.delete(val);
return v;
}
}, { mutates: true });
_this.proxy('add');
_this.proxy('clear', { mutates: true });
_this.proxy('delete', { mutates: true });
_this.proxy('delete', { alias: 'remove', mutates: true });
return _this;
}
createClass(SetStore, [{
key: 'clone',
value: function clone(value) {
return new Set(value);
}
}]);
return SetStore;
}(Store);
var SetValue = createComponent(SetStore);
var createSetValue = createFactory(SetStore, SetValue);
var StringStore = function (_Store) {
inherits(StringStore, _Store);
function StringStore(value, props) {
classCallCheck(this, StringStore);
var _this = possibleConstructorReturn(this, (StringStore.__proto__ || Object.getPrototypeOf(StringStore)).call(this, value, props, ''));
_this.proxy('concat');
_this.proxy('normalize');
_this.proxy('padEnd');
_this.proxy('padStart');
_this.proxy('repeat');
_this.proxy('replace');
_this.proxy('slice');
_this.proxy('substr');
_this.proxy('substring');
_this.proxy('toLowerCase');
_this.proxy('toUpperCase');
_this.proxy('trim');
_this.proxy('trimEnd');
_this.proxy('trimStart');
return _this;
}
return StringStore;
}(Store);
var StringValue = createComponent(StringStore);
var createStringValue = createFactory(StringStore, StringValue);
exports.ArrayValue = ArrayValue;
exports.createArrayValue = createArrayValue;
exports.BooleanValue = BooleanValue;
exports.createBooleanValue = createBooleanValue;
exports.DateValue = DateValue;
exports.createDateValue = createDateValue;
exports.MapValue = MapValue;
exports.createMapValue = createMapValue;
exports.NumberValue = NumberValue;
exports.createNumberValue = createNumberValue;
exports.ObjectValue = ObjectValue;
exports.createObjectValue = createObjectValue;
exports.SetValue = SetValue;
exports.createSetValue = createSetValue;
exports.StringValue = StringValue;
exports.createStringValue = createStringValue;
exports.Value = Value;
exports.createValue = createValue;
Object.defineProperty(exports, '__esModule', { value: true });
})));