refract-callbag
Advanced tools
Comparing version 2.0.0-rc.3 to 2.0.0
222
index.es.js
@@ -54,4 +54,49 @@ import $$observable from 'symbol-observable'; | ||
var MOUNT_EVENT = '@@refract/event/mount'; | ||
var UNMOUNT_EVENT = '@@refract/event/unmount'; | ||
var DataType; | ||
(function (DataType) { | ||
DataType["EVENT"] = "event"; | ||
DataType["PROPS"] = "props"; | ||
DataType["CALLBACK"] = "callback"; | ||
})(DataType || (DataType = {})); | ||
var isEvent = function (eventName) { return function (data, index) { | ||
return data.type === DataType.EVENT && | ||
data.payload.name === eventName; | ||
}; }; | ||
var isProps = function (data) { return data.type === DataType.PROPS; }; | ||
var isCallback = function (propName) { return function (data) { | ||
return data.type === DataType.CALLBACK && | ||
data.payload.name === propName; | ||
}; }; | ||
var createEventData = function (name, value) { return ({ | ||
type: DataType.EVENT, | ||
payload: { | ||
name: name, | ||
value: value | ||
} | ||
}); }; | ||
var createPropsData = function (props) { return ({ | ||
type: DataType.PROPS, | ||
payload: props | ||
}); }; | ||
var createCallbackData = function (name, args) { return ({ | ||
type: DataType.CALLBACK, | ||
payload: { | ||
name: name, | ||
args: args | ||
} | ||
}); }; | ||
var shallowEquals = function (left, right) { | ||
return left === right || | ||
(Object.keys(left).length === Object.keys(right).length && | ||
Object.keys(left).every(function (leftKey) { return left[leftKey] === right[leftKey]; })); | ||
}; | ||
var fromObs = require('callbag-from-obs'); | ||
var toObs = require('callbag-to-obs'); | ||
var dropRepeats = require('callbag-drop-repeats'); | ||
var map = require('callbag-map'); | ||
var pipe = require('callbag-pipe'); | ||
var filter = require('callbag-filter'); | ||
var subscribeToSink = function (sink, next, error) { | ||
@@ -63,22 +108,34 @@ return toObs(sink).subscribe({ | ||
}; | ||
var createObservable = function (subscribe) { | ||
var observable = (_a = { | ||
subscribe: function (listener) { | ||
var unsubscribe = subscribe(listener); | ||
return { unsubscribe: unsubscribe }; | ||
var createComponent = function (instance, dataObservable, pushEvent) { | ||
var data = function () { return fromObs(dataObservable); }; | ||
return { | ||
mount: pipe(data(), filter(isEvent(MOUNT_EVENT)), map(function () { return undefined; })), | ||
unmount: pipe(data(), filter(isEvent(UNMOUNT_EVENT)), map(function () { return undefined; })), | ||
observe: function (propName, valueTransformer) { | ||
if (propName && typeof instance.props[propName] === 'function') { | ||
return pipe(data(), filter(isCallback(propName)), map(function (data) { | ||
var args = data.payload.args; | ||
return valueTransformer | ||
? valueTransformer(args) | ||
: args[0]; | ||
})); | ||
} | ||
if (propName) { | ||
return pipe(data(), filter(isProps), map(function (data) { | ||
var prop = data.payload[propName]; | ||
return valueTransformer ? valueTransformer(prop) : prop; | ||
}), dropRepeats()); | ||
} | ||
return pipe(data(), filter(isProps), map(function (data) { return data.payload; }), dropRepeats(shallowEquals)); | ||
}, | ||
_a[$$observable] = function () { | ||
return this; | ||
fromEvent: function (eventName, valueTransformer) { | ||
return pipe(data(), filter(isEvent(eventName)), map(function (data) { | ||
var value = data.payload.value; | ||
return valueTransformer ? valueTransformer(value) : value; | ||
})); | ||
}, | ||
_a); | ||
return fromObs(observable); | ||
var _a; | ||
pushEvent: pushEvent | ||
}; | ||
}; | ||
var shallowEquals = function (left, right) { | ||
return left === right || | ||
(Object.keys(left).length === Object.keys(right).length && | ||
Object.keys(left).every(function (leftKey) { return left[leftKey] === right[leftKey]; })); | ||
}; | ||
var configureComponent = function (handler, errorHandler) { return function (aperture, instance, isValidElement$$1, isComponentClass) { | ||
@@ -88,5 +145,5 @@ if (isValidElement$$1 === void 0) { isValidElement$$1 = function () { return false; }; } | ||
instance.state = { | ||
renderEffect: false, | ||
children: null, | ||
props: {}, | ||
decoratedProps: {} | ||
props: {} | ||
}; | ||
@@ -101,3 +158,3 @@ var setState = function (state) { | ||
else { | ||
instance.state = state; | ||
instance.state = __assign({}, instance.state, state); | ||
} | ||
@@ -110,2 +167,3 @@ }; | ||
setState({ | ||
renderEffect: true, | ||
children: effect | ||
@@ -115,15 +173,6 @@ }); | ||
else if (effect && effect.type === PROPS_EFFECT) { | ||
var payload_1 = effect.payload; | ||
var payload = effect.payload; | ||
setState({ | ||
replace: payload_1.replace, | ||
props: payload_1.props, | ||
decoratedProps: Object.keys(payload_1.props || {}).reduce(function (props, propName) { | ||
var prop = payload_1.props[propName]; | ||
var previousProp = instance.state.props[propName]; | ||
if (typeof prop === 'function' && | ||
prop !== previousProp) { | ||
decorateProp(props, prop, propName); | ||
} | ||
return props; | ||
}, {}) | ||
replace: payload.replace, | ||
props: payload.props | ||
}); | ||
@@ -136,14 +185,13 @@ } | ||
}; | ||
var listeners = { | ||
mount: [], | ||
unmount: [], | ||
allProps: [], | ||
props: {}, | ||
fnProps: {}, | ||
event: {} | ||
var decoratedProps = {}; | ||
var listeners = []; | ||
var addListener = function (listener) { | ||
listeners = listeners.concat(listener); | ||
}; | ||
var decoratedProps = {}; | ||
var removeListener = function (listener) { | ||
listeners = listeners.filter(function (l) { return l !== listener; }); | ||
}; | ||
var pushEvent = function (eventName) { return function (val) { | ||
(listeners.event[eventName] || []).forEach(function (listener) { | ||
return listener.next(val); | ||
listeners.forEach(function (listener) { | ||
listener.next(createEventData(eventName, val)); | ||
}); | ||
@@ -160,3 +208,5 @@ }; }; | ||
} | ||
(listeners.fnProps[propName] || []).forEach(function (l) { return l.next(args[0]); }); | ||
listeners.forEach(function (listener) { | ||
listener.next(createCallbackData(propName, args)); | ||
}); | ||
return prop.apply(void 0, args); | ||
@@ -170,59 +220,16 @@ }; | ||
}); | ||
var mountObservable = createObservable(function (listener) { | ||
listeners.mount = listeners.mount.concat(listener); | ||
return function () { return listeners.mount.filter(function (l) { return l !== listener; }); }; | ||
}); | ||
var unmountObservable = createObservable(function (listener) { | ||
listeners.unmount = listeners.unmount.concat(listener); | ||
return function () { return listeners.unmount.filter(function (l) { return l !== listener; }); }; | ||
}); | ||
var createPropObservable = function (propName) { | ||
var listenerType = propName | ||
? typeof instance.props[propName] === 'function' | ||
? 'fnProps' | ||
: 'props' | ||
: 'allProps'; | ||
return createObservable(function (listener) { | ||
if (listenerType === 'allProps') { | ||
listener.next(instance.props); | ||
listeners.allProps = listeners.allProps.concat(listener); | ||
return function () { | ||
listeners.allProps.filter(function (l) { return l !== listener; }); | ||
}; | ||
var dataObservable = (_a = { | ||
subscribe: function (listener) { | ||
addListener(listener); | ||
listener.next(createPropsData(instance.props)); | ||
return { unsubscribe: function () { return removeListener(listener); } }; | ||
} | ||
if (listenerType === 'props') { | ||
listener.next(instance.props[propName]); | ||
} | ||
listeners[listenerType][propName] = (listeners[listenerType][propName] || []).concat(listener); | ||
return function () { | ||
listeners[listenerType][propName].filter(function (l) { return l !== listener; }); | ||
}; | ||
}); | ||
}; | ||
var createEventObservable = function (eventName) { | ||
return createObservable(function (listener) { | ||
listeners.event[eventName] = (listeners.event[eventName] || []).concat(listener); | ||
return function () { | ||
listeners.event[eventName].filter(function (l) { return l !== listener; }); | ||
}; | ||
}); | ||
}; | ||
var component = { | ||
mount: mountObservable, | ||
unmount: unmountObservable, | ||
observe: createPropObservable, | ||
event: createEventObservable, | ||
pushEvent: pushEvent | ||
}; | ||
}, | ||
_a[$$observable] = function () { | ||
return this; | ||
}, | ||
_a); | ||
var component = createComponent(instance, dataObservable, pushEvent); | ||
var sinkObservable = aperture(instance.props)(component); | ||
var sinkSubscription = subscribeToSink(sinkObservable, finalHandler(instance.props), errorHandler ? errorHandler(instance.props) : undefined); | ||
var sendNext = function (prevProps) { | ||
Object.keys(listeners.props).forEach(function (propName) { | ||
var prop = instance.props[propName]; | ||
if (!prevProps || prevProps[propName] !== prop) { | ||
listeners.props[propName].forEach(function (l) { return l.next(prop); }); | ||
} | ||
}); | ||
listeners.allProps.forEach(function (l) { return l.next(instance.props); }); | ||
}; | ||
instance.reDecorateProps = function (nextProps) { | ||
@@ -236,10 +243,12 @@ Object.keys(nextProps).forEach(function (propName) { | ||
}; | ||
instance.pushProps = function (prevProps) { | ||
sendNext(prevProps); | ||
instance.pushProps = function (props) { | ||
listeners.forEach(function (listener) { | ||
listener.next(createPropsData(props)); | ||
}); | ||
}; | ||
instance.triggerMount = function () { | ||
listeners.mount.forEach(function (l) { return l.next(undefined); }); | ||
pushEvent(MOUNT_EVENT)(undefined); | ||
}; | ||
instance.triggerUnmount = function () { | ||
listeners.unmount.forEach(function (l) { return l.next(undefined); }); | ||
pushEvent(UNMOUNT_EVENT)(undefined); | ||
sinkSubscription.unsubscribe(); | ||
@@ -249,15 +258,15 @@ }; | ||
var state = instance.state; | ||
var stateProps = __assign({}, state.props, state.decoratedProps); | ||
var stateProps = state.props; | ||
if (state.replace === true) { | ||
return __assign({}, stateProps, { pushEvent: pushEvent }); | ||
} | ||
var componentProps = __assign({}, instance.props, decoratedProps, { pushEvent: pushEvent }); | ||
var additionalProps = __assign({}, decoratedProps, { pushEvent: pushEvent }); | ||
if (state.replace === false) { | ||
return __assign({}, componentProps, stateProps); | ||
return __assign({}, instance.props, stateProps, additionalProps); | ||
} | ||
return componentProps; | ||
return __assign({}, instance.props, additionalProps); | ||
}; | ||
instance.havePropsChanged = function (newProps, newState) { | ||
var state = instance.state; | ||
if (state.children || newState.children) { | ||
if (state.renderEffect) { | ||
return state.children !== newState.children; | ||
@@ -275,2 +284,3 @@ } | ||
}; | ||
var _a; | ||
}; }; | ||
@@ -301,2 +311,3 @@ | ||
this.reDecorateProps(nextProps); | ||
this.pushProps(nextProps); | ||
}; | ||
@@ -306,5 +317,2 @@ WithEffects.prototype.shouldComponentUpdate = function (nextProps, nextState) { | ||
}; | ||
WithEffects.prototype.componentDidUpdate = function (prevProps) { | ||
this.pushProps(prevProps); | ||
}; | ||
WithEffects.prototype.componentWillUnmount = function () { | ||
@@ -311,0 +319,0 @@ this.unmounted = true; |
222
index.js
@@ -60,4 +60,49 @@ 'use strict'; | ||
var MOUNT_EVENT = '@@refract/event/mount'; | ||
var UNMOUNT_EVENT = '@@refract/event/unmount'; | ||
var DataType; | ||
(function (DataType) { | ||
DataType["EVENT"] = "event"; | ||
DataType["PROPS"] = "props"; | ||
DataType["CALLBACK"] = "callback"; | ||
})(DataType || (DataType = {})); | ||
var isEvent = function (eventName) { return function (data, index) { | ||
return data.type === DataType.EVENT && | ||
data.payload.name === eventName; | ||
}; }; | ||
var isProps = function (data) { return data.type === DataType.PROPS; }; | ||
var isCallback = function (propName) { return function (data) { | ||
return data.type === DataType.CALLBACK && | ||
data.payload.name === propName; | ||
}; }; | ||
var createEventData = function (name, value) { return ({ | ||
type: DataType.EVENT, | ||
payload: { | ||
name: name, | ||
value: value | ||
} | ||
}); }; | ||
var createPropsData = function (props) { return ({ | ||
type: DataType.PROPS, | ||
payload: props | ||
}); }; | ||
var createCallbackData = function (name, args) { return ({ | ||
type: DataType.CALLBACK, | ||
payload: { | ||
name: name, | ||
args: args | ||
} | ||
}); }; | ||
var shallowEquals = function (left, right) { | ||
return left === right || | ||
(Object.keys(left).length === Object.keys(right).length && | ||
Object.keys(left).every(function (leftKey) { return left[leftKey] === right[leftKey]; })); | ||
}; | ||
var fromObs = require('callbag-from-obs'); | ||
var toObs = require('callbag-to-obs'); | ||
var dropRepeats = require('callbag-drop-repeats'); | ||
var map = require('callbag-map'); | ||
var pipe = require('callbag-pipe'); | ||
var filter = require('callbag-filter'); | ||
var subscribeToSink = function (sink, next, error) { | ||
@@ -69,22 +114,34 @@ return toObs(sink).subscribe({ | ||
}; | ||
var createObservable = function (subscribe) { | ||
var observable = (_a = { | ||
subscribe: function (listener) { | ||
var unsubscribe = subscribe(listener); | ||
return { unsubscribe: unsubscribe }; | ||
var createComponent = function (instance, dataObservable, pushEvent) { | ||
var data = function () { return fromObs(dataObservable); }; | ||
return { | ||
mount: pipe(data(), filter(isEvent(MOUNT_EVENT)), map(function () { return undefined; })), | ||
unmount: pipe(data(), filter(isEvent(UNMOUNT_EVENT)), map(function () { return undefined; })), | ||
observe: function (propName, valueTransformer) { | ||
if (propName && typeof instance.props[propName] === 'function') { | ||
return pipe(data(), filter(isCallback(propName)), map(function (data) { | ||
var args = data.payload.args; | ||
return valueTransformer | ||
? valueTransformer(args) | ||
: args[0]; | ||
})); | ||
} | ||
if (propName) { | ||
return pipe(data(), filter(isProps), map(function (data) { | ||
var prop = data.payload[propName]; | ||
return valueTransformer ? valueTransformer(prop) : prop; | ||
}), dropRepeats()); | ||
} | ||
return pipe(data(), filter(isProps), map(function (data) { return data.payload; }), dropRepeats(shallowEquals)); | ||
}, | ||
_a[$$observable] = function () { | ||
return this; | ||
fromEvent: function (eventName, valueTransformer) { | ||
return pipe(data(), filter(isEvent(eventName)), map(function (data) { | ||
var value = data.payload.value; | ||
return valueTransformer ? valueTransformer(value) : value; | ||
})); | ||
}, | ||
_a); | ||
return fromObs(observable); | ||
var _a; | ||
pushEvent: pushEvent | ||
}; | ||
}; | ||
var shallowEquals = function (left, right) { | ||
return left === right || | ||
(Object.keys(left).length === Object.keys(right).length && | ||
Object.keys(left).every(function (leftKey) { return left[leftKey] === right[leftKey]; })); | ||
}; | ||
var configureComponent = function (handler, errorHandler) { return function (aperture, instance, isValidElement, isComponentClass) { | ||
@@ -94,5 +151,5 @@ if (isValidElement === void 0) { isValidElement = function () { return false; }; } | ||
instance.state = { | ||
renderEffect: false, | ||
children: null, | ||
props: {}, | ||
decoratedProps: {} | ||
props: {} | ||
}; | ||
@@ -107,3 +164,3 @@ var setState = function (state) { | ||
else { | ||
instance.state = state; | ||
instance.state = __assign({}, instance.state, state); | ||
} | ||
@@ -116,2 +173,3 @@ }; | ||
setState({ | ||
renderEffect: true, | ||
children: effect | ||
@@ -121,15 +179,6 @@ }); | ||
else if (effect && effect.type === PROPS_EFFECT) { | ||
var payload_1 = effect.payload; | ||
var payload = effect.payload; | ||
setState({ | ||
replace: payload_1.replace, | ||
props: payload_1.props, | ||
decoratedProps: Object.keys(payload_1.props || {}).reduce(function (props, propName) { | ||
var prop = payload_1.props[propName]; | ||
var previousProp = instance.state.props[propName]; | ||
if (typeof prop === 'function' && | ||
prop !== previousProp) { | ||
decorateProp(props, prop, propName); | ||
} | ||
return props; | ||
}, {}) | ||
replace: payload.replace, | ||
props: payload.props | ||
}); | ||
@@ -142,14 +191,13 @@ } | ||
}; | ||
var listeners = { | ||
mount: [], | ||
unmount: [], | ||
allProps: [], | ||
props: {}, | ||
fnProps: {}, | ||
event: {} | ||
var decoratedProps = {}; | ||
var listeners = []; | ||
var addListener = function (listener) { | ||
listeners = listeners.concat(listener); | ||
}; | ||
var decoratedProps = {}; | ||
var removeListener = function (listener) { | ||
listeners = listeners.filter(function (l) { return l !== listener; }); | ||
}; | ||
var pushEvent = function (eventName) { return function (val) { | ||
(listeners.event[eventName] || []).forEach(function (listener) { | ||
return listener.next(val); | ||
listeners.forEach(function (listener) { | ||
listener.next(createEventData(eventName, val)); | ||
}); | ||
@@ -166,3 +214,5 @@ }; }; | ||
} | ||
(listeners.fnProps[propName] || []).forEach(function (l) { return l.next(args[0]); }); | ||
listeners.forEach(function (listener) { | ||
listener.next(createCallbackData(propName, args)); | ||
}); | ||
return prop.apply(void 0, args); | ||
@@ -176,59 +226,16 @@ }; | ||
}); | ||
var mountObservable = createObservable(function (listener) { | ||
listeners.mount = listeners.mount.concat(listener); | ||
return function () { return listeners.mount.filter(function (l) { return l !== listener; }); }; | ||
}); | ||
var unmountObservable = createObservable(function (listener) { | ||
listeners.unmount = listeners.unmount.concat(listener); | ||
return function () { return listeners.unmount.filter(function (l) { return l !== listener; }); }; | ||
}); | ||
var createPropObservable = function (propName) { | ||
var listenerType = propName | ||
? typeof instance.props[propName] === 'function' | ||
? 'fnProps' | ||
: 'props' | ||
: 'allProps'; | ||
return createObservable(function (listener) { | ||
if (listenerType === 'allProps') { | ||
listener.next(instance.props); | ||
listeners.allProps = listeners.allProps.concat(listener); | ||
return function () { | ||
listeners.allProps.filter(function (l) { return l !== listener; }); | ||
}; | ||
var dataObservable = (_a = { | ||
subscribe: function (listener) { | ||
addListener(listener); | ||
listener.next(createPropsData(instance.props)); | ||
return { unsubscribe: function () { return removeListener(listener); } }; | ||
} | ||
if (listenerType === 'props') { | ||
listener.next(instance.props[propName]); | ||
} | ||
listeners[listenerType][propName] = (listeners[listenerType][propName] || []).concat(listener); | ||
return function () { | ||
listeners[listenerType][propName].filter(function (l) { return l !== listener; }); | ||
}; | ||
}); | ||
}; | ||
var createEventObservable = function (eventName) { | ||
return createObservable(function (listener) { | ||
listeners.event[eventName] = (listeners.event[eventName] || []).concat(listener); | ||
return function () { | ||
listeners.event[eventName].filter(function (l) { return l !== listener; }); | ||
}; | ||
}); | ||
}; | ||
var component = { | ||
mount: mountObservable, | ||
unmount: unmountObservable, | ||
observe: createPropObservable, | ||
event: createEventObservable, | ||
pushEvent: pushEvent | ||
}; | ||
}, | ||
_a[$$observable] = function () { | ||
return this; | ||
}, | ||
_a); | ||
var component = createComponent(instance, dataObservable, pushEvent); | ||
var sinkObservable = aperture(instance.props)(component); | ||
var sinkSubscription = subscribeToSink(sinkObservable, finalHandler(instance.props), errorHandler ? errorHandler(instance.props) : undefined); | ||
var sendNext = function (prevProps) { | ||
Object.keys(listeners.props).forEach(function (propName) { | ||
var prop = instance.props[propName]; | ||
if (!prevProps || prevProps[propName] !== prop) { | ||
listeners.props[propName].forEach(function (l) { return l.next(prop); }); | ||
} | ||
}); | ||
listeners.allProps.forEach(function (l) { return l.next(instance.props); }); | ||
}; | ||
instance.reDecorateProps = function (nextProps) { | ||
@@ -242,10 +249,12 @@ Object.keys(nextProps).forEach(function (propName) { | ||
}; | ||
instance.pushProps = function (prevProps) { | ||
sendNext(prevProps); | ||
instance.pushProps = function (props) { | ||
listeners.forEach(function (listener) { | ||
listener.next(createPropsData(props)); | ||
}); | ||
}; | ||
instance.triggerMount = function () { | ||
listeners.mount.forEach(function (l) { return l.next(undefined); }); | ||
pushEvent(MOUNT_EVENT)(undefined); | ||
}; | ||
instance.triggerUnmount = function () { | ||
listeners.unmount.forEach(function (l) { return l.next(undefined); }); | ||
pushEvent(UNMOUNT_EVENT)(undefined); | ||
sinkSubscription.unsubscribe(); | ||
@@ -255,15 +264,15 @@ }; | ||
var state = instance.state; | ||
var stateProps = __assign({}, state.props, state.decoratedProps); | ||
var stateProps = state.props; | ||
if (state.replace === true) { | ||
return __assign({}, stateProps, { pushEvent: pushEvent }); | ||
} | ||
var componentProps = __assign({}, instance.props, decoratedProps, { pushEvent: pushEvent }); | ||
var additionalProps = __assign({}, decoratedProps, { pushEvent: pushEvent }); | ||
if (state.replace === false) { | ||
return __assign({}, componentProps, stateProps); | ||
return __assign({}, instance.props, stateProps, additionalProps); | ||
} | ||
return componentProps; | ||
return __assign({}, instance.props, additionalProps); | ||
}; | ||
instance.havePropsChanged = function (newProps, newState) { | ||
var state = instance.state; | ||
if (state.children || newState.children) { | ||
if (state.renderEffect) { | ||
return state.children !== newState.children; | ||
@@ -281,2 +290,3 @@ } | ||
}; | ||
var _a; | ||
}; }; | ||
@@ -307,2 +317,3 @@ | ||
this.reDecorateProps(nextProps); | ||
this.pushProps(nextProps); | ||
}; | ||
@@ -312,5 +323,2 @@ WithEffects.prototype.shouldComponentUpdate = function (nextProps, nextState) { | ||
}; | ||
WithEffects.prototype.componentDidUpdate = function (prevProps) { | ||
this.pushProps(prevProps); | ||
}; | ||
WithEffects.prototype.componentWillUnmount = function () { | ||
@@ -317,0 +325,0 @@ this.unmounted = true; |
{ | ||
"name": "refract-callbag", | ||
"description": "Refract bindings for React with Callbag: master your app effects reactively!", | ||
"version": "2.0.0-rc.3", | ||
"description": "Refract bindings for React with Callbag: harness the power of reactive programming to supercharge your components!", | ||
"version": "2.0.0", | ||
"main": "index.js", | ||
@@ -16,3 +16,7 @@ "jsnext:main": "index.es.js", | ||
"callbag": "~1.1.0", | ||
"callbag-drop-repeats": "~1.0.0", | ||
"callbag-filter": "~1.0.1", | ||
"callbag-from-obs": "~1.2.0", | ||
"callbag-map": "~1.0.1", | ||
"callbag-pipe": "~1.1.1", | ||
"callbag-to-obs": "~1.0.0", | ||
@@ -19,0 +23,0 @@ "symbol-observable": "~1.2.0" |
@@ -6,4 +6,4 @@ <p align="center"> | ||
<p align="center"> | ||
Master your component's effects through the<br/> | ||
power of reactive programming. | ||
Harness the power of reactive programming<br/> | ||
to supercharge your components | ||
</p> | ||
@@ -31,6 +31,20 @@ <br/> | ||
Refract lets you isolate your app's side effects - API calls, analytics, logging, etc - so that you can write your code in a clear, pure, and declarative fashion by using reactive programming. | ||
* :bowling: **Decentralised**: attach effects and side-effects to your components, for better code splitting results | ||
* :sunrise: **Gradual**: use on an existing component today, throughout your app tomorrow | ||
* :rocket: **Reactive**: leverage the power and benefits of reactive programming | ||
* :floppy_disk: **Tiny**: less than 2Kb minified and gzipped | ||
* :pencil: **Typed**: written in TypeScript, fully typed integrations | ||
* :zap: **Universal**: supports React, React Native, Inferno and Preact | ||
Refract is an extensible library built for React, with bindings available for Inferno and Preact. In addition we provide a Redux integration, which can also serve as a template for integrations with other libraries. | ||
Refract lets you handle your component effects and side-effects, so that you can write your code in a clear, pure, and declarative fashion by using reactive programming. | ||
Refract makes reactive programming possible in React, React Native, Preact and Inferno, with only a single higher-order component! You can choose to start using a tiny bit of reactive programming, or go full reactive. Refract allows you to: | ||
* [Manage side effects](https://refract.js.org/) like API calls, analytics, logging, etc. | ||
* [Manipulate, replace and inject props](https://refract.js.org/usage/pushing-props), you can even [fully replace Redux `connect` HoC](https://refract.js.org/recipes/replace-connect) | ||
* [Handle state](https://refract.js.org/recipes/handling-state) | ||
* [Render components](https://refract.js.org/usage/rendering-components) | ||
We also provide a Redux integration, which can serve as a template for integrations with other libraries. With a single HoC, you can fully replace libraries like [recompose](https://github.com/acdlite/recompose), [redux-observable](https://redux-observable.js.org/), and [react-redux](https://github.com/reduxjs/react-redux) to name a few! | ||
# Why? | ||
@@ -40,8 +54,6 @@ | ||
However, our apps don't exist in a vacuum! They need to make network requests, handle data persistence, log analytics, deal with changing time, and so on. Any non-trivial app has to handle any number of these external effects. | ||
However, our apps don't exist in a vacuum! They need to handle state, make network requests, handle data persistence, log analytics, deal with changing time, and so on. Any non-trivial app has to handle any number of these effects. Wouldn't it be nice to cleanly separate them from our apps? | ||
These side-effects hold us back from writing fully declarative code. Wouldn't it be nice to cleanly separate them from our apps? | ||
Refract solves this problem for you, by harnessing the power of reactive programming. [For an in-depth introduction, head to `Why Refract`.](./docs/introduction/why-refract.md) | ||
Refract solves this problem for you. [For an in-depth introduction, head to `Why Refract`.](../../docs/introduction/why-refract.md) | ||
# Installation | ||
@@ -48,0 +60,0 @@ |
@@ -1,15 +0,3 @@ | ||
import { Listener } from './observable' | ||
export interface KeyedListeners { | ||
[key: string]: Array<Partial<Listener<any>>> | ||
} | ||
export interface Listeners { | ||
mount: Array<Partial<Listener<any>>> | ||
unmount: Array<Partial<Listener<any>>> | ||
allProps: Array<Partial<Listener<any>>> | ||
props: KeyedListeners | ||
fnProps: KeyedListeners | ||
event: KeyedListeners | ||
} | ||
export declare type Handler<P, E> = (intialProps: P) => (val: E) => void | ||
export declare type ErrorHandler<P> = (intialProps: P) => (error: any) => void | ||
export declare type PushEvent = (eventName: string) => <T>(val: T) => void |
import { withEffects } from './withEffects' | ||
import { ObservableComponent, Aperture } from './observable' | ||
import { ErrorHandler, Handler } from './baseTypes' | ||
import { ErrorHandler, Handler, PushEvent } from './baseTypes' | ||
import { compose, Compose } from './compose' | ||
@@ -12,2 +12,3 @@ import { asProps, toProps, PROPS_EFFECT, PropEffect } from './effects' | ||
ErrorHandler, | ||
PushEvent, | ||
compose, | ||
@@ -14,0 +15,0 @@ Compose, |
@@ -12,4 +12,10 @@ import { Callbag, Source, Sink } from 'callbag' | ||
export interface ObservableComponent { | ||
observe: <T = any>(propName?: string) => Source<T> | ||
event: <T>(eventName: string) => Source<T> | ||
observe: <T = any>( | ||
propName?: string, | ||
valueTransformer?: (value: any) => T | ||
) => Source<T> | ||
fromEvent: <T>( | ||
eventName: string, | ||
valueTransformer?: (val: any) => T | ||
) => Source<T> | ||
mount: Source<any> | ||
@@ -27,2 +33,6 @@ unmount: Source<any> | ||
) => Subscription | ||
export declare const createObservable: <T>(subscribe: any) => Callbag<void, T> | ||
export declare const createComponent: <P>( | ||
instance: any, | ||
dataObservable: any, | ||
pushEvent: any | ||
) => ObservableComponent |
@@ -8,3 +8,3 @@ /// <reference types="react" /> | ||
props: object | ||
decoratedProps: object | ||
renderEffect: boolean | ||
children: React.ReactNode | null | ||
@@ -11,0 +11,0 @@ } |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
41076
12
842
0
167
9
+ Addedcallbag-drop-repeats@~1.0.0
+ Addedcallbag-filter@~1.0.1
+ Addedcallbag-map@~1.0.1
+ Addedcallbag-pipe@~1.1.1
+ Addedcallbag-drop-repeats@1.0.0(transitive)
+ Addedcallbag-filter@1.0.1(transitive)
+ Addedcallbag-map@1.0.1(transitive)
+ Addedcallbag-pipe@1.1.1(transitive)