Upgrade dependencies

This commit is contained in:
futpib 2019-08-11 00:39:28 +03:00
parent f3d5c209ff
commit 5f529a6168
26 changed files with 2992 additions and 2233 deletions

View File

@ -159,5 +159,5 @@ module.exports = connect(
actions: bindActionCreators(pulseActions, dispatch), actions: bindActionCreators(pulseActions, dispatch),
}), }),
null, null,
{ withRef: true }, { forwardRef: true },
)(Cards); )(Cards);

View File

@ -93,8 +93,8 @@ class GraphView extends GraphViewBase {
} }
shouldComponentUpdate(nextProps, nextState) { shouldComponentUpdate(nextProps, nextState) {
return super.shouldComponentUpdate(nextProps, nextState) || return super.shouldComponentUpdate(nextProps, nextState)
this.state.edgeEndNode !== nextState.edgeEndNode; || this.state.edgeEndNode !== nextState.edgeEndNode;
} }
componentDidUpdate(prevProps, prevState) { componentDidUpdate(prevProps, prevState) {
@ -102,11 +102,12 @@ class GraphView extends GraphViewBase {
if (this.state.edgeEndNode !== prevState.edgeEndNode) { if (this.state.edgeEndNode !== prevState.edgeEndNode) {
if (prevState.edgeEndNode) { if (prevState.edgeEndNode) {
const prevNode = document.getElementById('node-' + prevState.edgeEndNode[nodeKey]); const prevNode = document.querySelector('#node-' + prevState.edgeEndNode[nodeKey]);
prevNode.classList.remove('targeted'); prevNode.classList.remove('targeted');
} }
if (this.state.edgeEndNode) { if (this.state.edgeEndNode) {
const node = document.getElementById('node-' + this.state.edgeEndNode[nodeKey]); const node = document.querySelector('#node-' + this.state.edgeEndNode[nodeKey]);
node.classList.add('targeted'); node.classList.add('targeted');
} }
} }
@ -120,13 +121,13 @@ class GraphView extends GraphViewBase {
} }
} }
if (this.props.selected && if (this.props.selected
this.props.moved && && this.props.moved
( && (
prevProps.selected !== this.props.selected || prevProps.selected !== this.props.selected
prevProps.moved !== this.props.moved || prevProps.moved !== this.props.moved
) && )
this.state.draggedEdge && this.state.draggedEdge
) { ) {
this.dragEdge(); this.dragEdge();
} }
@ -141,6 +142,7 @@ class GraphView extends GraphViewBase {
this.props.selected.y, this.props.selected.y,
]; ];
} }
return super.getMouseCoordinates(); return super.getMouseCoordinates();
} }
@ -153,6 +155,7 @@ class GraphView extends GraphViewBase {
onMouseDown: onBackgroundMouseDown, onMouseDown: onBackgroundMouseDown,
}); });
} }
return this._super_renderBackground(); return this._super_renderBackground();
} }
@ -186,6 +189,7 @@ class GraphView extends GraphViewBase {
if (this.props.onZoomStart) { if (this.props.onZoomStart) {
this.props.onZoomStart(); this.props.onZoomStart();
} }
return this._super_handleZoomStart(...args); return this._super_handleZoomStart(...args);
} }
@ -193,6 +197,7 @@ class GraphView extends GraphViewBase {
if (this.props.onZoomEnd) { if (this.props.onZoomEnd) {
this.props.onZoomEnd(); this.props.onZoomEnd();
} }
return this._super_handleZoomEnd(...args); return this._super_handleZoomEnd(...args);
} }
@ -267,8 +272,8 @@ class GraphView extends GraphViewBase {
this.renderEdge(id, element, edge, nodeMoving); this.renderEdge(id, element, edge, nodeMoving);
if (this.isEdgeSelected(edge)) { if (this.isEdgeSelected(edge)) {
const container = document.getElementById(`${id}-container`); const container = document.querySelector(`#${id}-container`);
container.parentNode.appendChild(container); container.parentNode.append(container);
} }
} }
} }
@ -318,6 +323,7 @@ class Node extends NodeBase {
if (this.props.onNodeDragStart) { if (this.props.onNodeDragStart) {
this.props.onNodeDragStart(...args); this.props.onNodeDragStart(...args);
} }
return this._super_handleDragStart(...args); return this._super_handleDragStart(...args);
} }
@ -325,6 +331,7 @@ class Node extends NodeBase {
if (this.props.onNodeDragEnd) { if (this.props.onNodeDragEnd) {
this.props.onNodeDragEnd(...args); this.props.onNodeDragEnd(...args);
} }
this.oldSibling = null; this.oldSibling = null;
return this._super_handleDragEnd(...args); return this._super_handleDragEnd(...args);
} }

View File

@ -28,19 +28,30 @@ const {
} = require('ramda'); } = require('ramda');
const React = require('react'); const React = require('react');
const PropTypes = require('prop-types');
const r = require('r-dom'); const r = require('r-dom');
const { connect, Provider: ReduxProvider } = require('react-redux'); const {
connect,
Provider: ReduxProvider,
ReactReduxContext: { Consumer: ReduxConsumer },
} = require('react-redux');
const { bindActionCreators } = require('redux'); const { bindActionCreators } = require('redux');
const {
fromRenderProps,
} = require('recompose');
const { HotKeys } = require('react-hotkeys'); const { HotKeys } = require('react-hotkeys');
const { PopupMenu, MenuItem } = require('@futpib/react-electron-menu'); const { PopupMenu, MenuItem } = require('@futpib/react-electron-menu');
const d = require('../../utils/d'); const d = require('../../utils/d');
const memoize = require('../../utils/memoize'); const memoize = require('../../utils/memoize');
const {
forwardRef,
unforwardRef,
} = require('../../utils/recompose');
const { const {
pulse: pulseActions, pulse: pulseActions,
@ -123,6 +134,7 @@ const selectionObjectTypes = {
if (type === 'client' || type === 'module') { if (type === 'client' || type === 'module') {
return 'client|module'; return 'client|module';
} }
return type; return type;
}, },
@ -131,6 +143,7 @@ const selectionObjectTypes = {
if (type === 'client|module') { if (type === 'client|module') {
return o => (o.type === 'client' || o.type === 'module'); return o => (o.type === 'client' || o.type === 'module');
} }
return o => o.type === type; return o => o.type === type;
}, },
}; };
@ -141,9 +154,11 @@ const sourceKey = pai => {
if (pai.type === 'monitorSource') { if (pai.type === 'monitorSource') {
return `sink-${pai.sinkIndex}`; return `sink-${pai.sinkIndex}`;
} }
if (pai.clientIndex === -1) { if (pai.clientIndex === -1) {
return `module-${pai.moduleIndex}`; return `module-${pai.moduleIndex}`;
} }
return `client-${pai.clientIndex}`; return `client-${pai.clientIndex}`;
}; };
@ -151,9 +166,11 @@ const targetKey = pai => {
if (pai.type === 'monitorSource') { if (pai.type === 'monitorSource') {
return `source-${pai.sourceIndex}`; return `source-${pai.sourceIndex}`;
} }
if (pai.type === 'sinkInput') { if (pai.type === 'sinkInput') {
return `sink-${pai.sinkIndex}`; return `sink-${pai.sinkIndex}`;
} }
return `source-${pai.sourceIndex}`; return `source-${pai.sourceIndex}`;
}; };
@ -172,9 +189,9 @@ const paoToEdge = memoize(pao => ({
})); }));
const getPaiIcon = memoize(pai => { const getPaiIcon = memoize(pai => {
return null || return null
path([ 'properties', 'application', 'icon_name' ], pai) || || path([ 'properties', 'application', 'icon_name' ], pai)
path([ 'properties', 'device', 'icon_name' ], pai); || path([ 'properties', 'device', 'icon_name' ], pai);
}); });
const s2 = size / 2; const s2 = size / 2;
@ -301,6 +318,7 @@ const getVolumesForThumbnail = ({ pai, lockChannelsTogether }) => {
]; ];
} }
} }
return volumes; return volumes;
}; };
@ -397,6 +415,7 @@ const getVolumes = ({ pai, lockChannelsTogether }) => {
maximum(volumes), maximum(volumes),
]; ];
} }
return volumes; return volumes;
}; };
@ -783,6 +802,7 @@ class Graph extends React.PureComponent {
if (edge.type === 'monitorSource') { if (edge.type === 'monitorSource') {
return; return;
} }
connectedNodeKeys.add(edge.source); connectedNodeKeys.add(edge.source);
connectedNodeKeys.add(edge.target); connectedNodeKeys.add(edge.target);
}); });
@ -790,10 +810,10 @@ class Graph extends React.PureComponent {
const filteredNodeKeys = new Set(); const filteredNodeKeys = new Set();
const nodes = filter(node => { const nodes = filter(node => {
if ((props.preferences.hideDisconnectedClients && node.type === 'client') || if ((props.preferences.hideDisconnectedClients && node.type === 'client')
(props.preferences.hideDisconnectedModules && node.type === 'module') || || (props.preferences.hideDisconnectedModules && node.type === 'module')
(props.preferences.hideDisconnectedSources && node.type === 'source') || || (props.preferences.hideDisconnectedSources && node.type === 'source')
(props.preferences.hideDisconnectedSinks && node.type === 'sink') || (props.preferences.hideDisconnectedSinks && node.type === 'sink')
) { ) {
if (!connectedNodeKeys.has(node.id)) { if (!connectedNodeKeys.has(node.id)) {
return false; return false;
@ -802,9 +822,9 @@ class Graph extends React.PureComponent {
const pai = getPaiByDgoFromInfos(node)(props.infos); const pai = getPaiByDgoFromInfos(node)(props.infos);
if (pai) { if (pai) {
if (props.preferences.hideMonitors && if (props.preferences.hideMonitors
pai.properties.device && && pai.properties.device
pai.properties.device.class === 'monitor' && pai.properties.device.class === 'monitor'
) { ) {
return false; return false;
} }
@ -812,11 +832,11 @@ class Graph extends React.PureComponent {
if (props.preferences.hidePulseaudioApps) { if (props.preferences.hidePulseaudioApps) {
const binary = path([ 'properties', 'application', 'process', 'binary' ], pai) || ''; const binary = path([ 'properties', 'application', 'process', 'binary' ], pai) || '';
const name = path([ 'properties', 'application', 'name' ], pai) || ''; const name = path([ 'properties', 'application', 'name' ], pai) || '';
if (binary.startsWith('pavucontrol') || if (binary.startsWith('pavucontrol')
binary.startsWith('kmix') || || binary.startsWith('kmix')
binary === 'pulseaudio' || || binary === 'pulseaudio'
name === 'papeaks' || || name === 'papeaks'
name === 'paclient.js' || name === 'paclient.js'
) { ) {
return false; return false;
} }
@ -836,6 +856,7 @@ class Graph extends React.PureComponent {
if (props.preferences.hideMonitorSourceEdges && edge.type === 'monitorSource') { if (props.preferences.hideMonitorSourceEdges && edge.type === 'monitorSource') {
return false; return false;
} }
return filteredNodeKeys.has(edge.source) && filteredNodeKeys.has(edge.target); return filteredNodeKeys.has(edge.source) && filteredNodeKeys.has(edge.target);
}, edges); }, edges);
@ -846,18 +867,18 @@ class Graph extends React.PureComponent {
} }
if (selected) { if (selected) {
selected = find(x => x.id === selected.id, nodes) || selected = find(x => x.id === selected.id, nodes)
find(x => x.id === selected.id, edges); || find(x => x.id === selected.id, edges);
} }
if (moved) { if (moved) {
moved = find(x => x.id === moved.id, nodes) || moved = find(x => x.id === moved.id, nodes)
find(x => x.id === moved.id, edges); || find(x => x.id === moved.id, edges);
} }
if (contexted && contexted !== backgroundSymbol) { if (contexted && contexted !== backgroundSymbol) {
contexted = find(x => x.id === contexted.id, nodes) || contexted = find(x => x.id === contexted.id, nodes)
find(x => x.id === contexted.id, edges); || find(x => x.id === contexted.id, edges);
} }
return { return {
@ -897,6 +918,7 @@ class Graph extends React.PureComponent {
if (!this._requestedIcons.has(icon) && !this.props.icons[icon]) { if (!this._requestedIcons.has(icon) && !this.props.icons[icon]) {
this.props.getIconPath(icon, 128); this.props.getIconPath(icon, 128);
} }
this._requestedIcons.add(icon); this._requestedIcons.add(icon);
} }
@ -927,10 +949,10 @@ class Graph extends React.PureComponent {
onNodeMouseDown(event, data) { onNodeMouseDown(event, data) {
const pai = getPaiByDgoFromInfos(data)(this.props.infos); const pai = getPaiByDgoFromInfos(data)(this.props.infos);
if (pai && event.button === 1) { if (pai && event.button === 1) {
if (pai.type === 'sink' || if (pai.type === 'sink'
pai.type === 'source' || || pai.type === 'source'
pai.type === 'client' || || pai.type === 'client'
pai.type === 'module' || pai.type === 'module'
) { ) {
this.toggleMute(pai); this.toggleMute(pai);
} }
@ -973,8 +995,8 @@ class Graph extends React.PureComponent {
onCreateEdge(source, target) { onCreateEdge(source, target) {
const sourcePai = getPaiByDgoFromInfos(source)(this.props.infos); const sourcePai = getPaiByDgoFromInfos(source)(this.props.infos);
const targetPai = getPaiByDgoFromInfos(target)(this.props.infos); const targetPai = getPaiByDgoFromInfos(target)(this.props.infos);
if (sourcePai && targetPai && if (sourcePai && targetPai
source.type === 'source' && target.type === 'sink' && source.type === 'source' && target.type === 'sink'
) { ) {
this.props.loadModule('module-loopback', `source=${sourcePai.name} sink=${targetPai.name}`); this.props.loadModule('module-loopback', `source=${sourcePai.name} sink=${targetPai.name}`);
} else { } else {
@ -997,8 +1019,8 @@ class Graph extends React.PureComponent {
onEdgeMouseDown(event, data) { onEdgeMouseDown(event, data) {
const pai = getPaiByDgoFromInfos(data)(this.props.infos); const pai = getPaiByDgoFromInfos(data)(this.props.infos);
if (pai && event.button === 1) { if (pai && event.button === 1) {
if (pai.type === 'sinkInput' || if (pai.type === 'sinkInput'
pai.type === 'sourceOutput' || pai.type === 'sourceOutput'
) { ) {
this.toggleMute(pai); this.toggleMute(pai);
} }
@ -1027,7 +1049,7 @@ class Graph extends React.PureComponent {
this.props.setSourceOutputMuteByIndex(pai.index, muted); this.props.setSourceOutputMuteByIndex(pai.index, muted);
} else if (pai.type === 'sink') { } else if (pai.type === 'sink') {
if (sourceBiased) { if (sourceBiased) {
const sinkInputs = getSinkSinkInputs(pai)(this.context.store.getState()); const sinkInputs = getSinkSinkInputs(pai)(this.props.store.getState());
this.toggleAllMute(sinkInputs); this.toggleAllMute(sinkInputs);
} else { } else {
this.props.setSinkMute(pai.index, muted); this.props.setSinkMute(pai.index, muted);
@ -1036,18 +1058,18 @@ class Graph extends React.PureComponent {
this.props.setSourceMute(pai.index, muted); this.props.setSourceMute(pai.index, muted);
} else if (pai.type === 'client') { } else if (pai.type === 'client') {
if (sourceBiased) { if (sourceBiased) {
const sourceOutputs = getClientSourceOutputs(pai)(this.context.store.getState()); const sourceOutputs = getClientSourceOutputs(pai)(this.props.store.getState());
this.toggleAllMute(sourceOutputs); this.toggleAllMute(sourceOutputs);
} else { } else {
const sinkInputs = getClientSinkInputs(pai)(this.context.store.getState()); const sinkInputs = getClientSinkInputs(pai)(this.props.store.getState());
this.toggleAllMute(sinkInputs); this.toggleAllMute(sinkInputs);
} }
} else if (pai.type === 'module') { } else if (pai.type === 'module') {
if (sourceBiased) { if (sourceBiased) {
const sourceOutputs = getModuleSourceOutputs(pai)(this.context.store.getState()); const sourceOutputs = getModuleSourceOutputs(pai)(this.props.store.getState());
this.toggleAllMute(sourceOutputs); this.toggleAllMute(sourceOutputs);
} else { } else {
const sinkInputs = getModuleSinkInputs(pai)(this.context.store.getState()); const sinkInputs = getModuleSinkInputs(pai)(this.props.store.getState());
this.toggleAllMute(sinkInputs); this.toggleAllMute(sinkInputs);
} }
} }
@ -1065,9 +1087,9 @@ class Graph extends React.PureComponent {
} else if (selected.type === 'sourceOutput') { } else if (selected.type === 'sourceOutput') {
this.props.killSourceOutputByIndex(selected.index); this.props.killSourceOutputByIndex(selected.index);
} else if ( } else if (
(selected.type === 'sink' || selected.type === 'source') && (selected.type === 'sink' || selected.type === 'source')
pai && && pai
pai.moduleIndex >= 0 && pai.moduleIndex >= 0
) { ) {
this.props.unloadModuleByIndex(pai.moduleIndex); this.props.unloadModuleByIndex(pai.moduleIndex);
} }
@ -1159,17 +1181,18 @@ class Graph extends React.PureComponent {
if (all) { if (all) {
this.toggleAllMute(this.props.infos.sources); this.toggleAllMute(this.props.infos.sources);
} else { } else {
const defaultSource = getDefaultSourcePai(this.context.store.getState()); const defaultSource = getDefaultSourcePai(this.props.store.getState());
this.toggleMute(defaultSource); this.toggleMute(defaultSource);
} }
} else { } else {
if (all) { // eslint-disable-line no-lonely-if if (all) { // eslint-disable-line no-lonely-if
this.toggleAllMute(this.props.infos.sinks); this.toggleAllMute(this.props.infos.sinks);
} else { } else {
const defaultSink = getDefaultSinkPai(this.context.store.getState()); const defaultSink = getDefaultSinkPai(this.props.store.getState());
this.toggleMute(defaultSink); this.toggleMute(defaultSink);
} }
} }
return; return;
} }
@ -1218,7 +1241,7 @@ class Graph extends React.PureComponent {
if (this.state.selected) { if (this.state.selected) {
pai = getPaiByDgoFromInfos(this.state.selected)(this.props.infos); pai = getPaiByDgoFromInfos(this.state.selected)(this.props.infos);
} else { } else {
pai = getDefaultSinkPai(this.context.store.getState()); pai = getDefaultSinkPai(this.props.store.getState());
} }
if (!pai) { if (!pai) {
@ -1226,12 +1249,13 @@ class Graph extends React.PureComponent {
} }
if (pai.type === 'client') { if (pai.type === 'client') {
const sinkInputs = getClientSinkInputs(pai)(this.context.store.getState()); const sinkInputs = getClientSinkInputs(pai)(this.props.store.getState());
this._volumeAll(sinkInputs, direction); this._volumeAll(sinkInputs, direction);
return; return;
} }
if (pai.type === 'module') { if (pai.type === 'module') {
const sinkInputs = getModuleSinkInputs(pai)(this.context.store.getState()); const sinkInputs = getModuleSinkInputs(pai)(this.props.store.getState());
this._volumeAll(sinkInputs, direction); this._volumeAll(sinkInputs, direction);
return; return;
} }
@ -1283,15 +1307,16 @@ class Graph extends React.PureComponent {
let node = null; let node = null;
for (const type of types) { for (const type of types) {
const predicate = selectionObjectTypes.toPulsePredicate(type); const predicate = selectionObjectTypes.toPulsePredicate(type);
node = node
(isBest && find(allPass([ predicate, isBest ]), this.state.nodes)) || = (isBest && find(allPass([ predicate, isBest ]), this.state.nodes))
(isBest && find(allPass([ predicate, isBest ]), this.state.edges)) || || (isBest && find(allPass([ predicate, isBest ]), this.state.edges))
find(predicate, this.state.nodes) || || find(predicate, this.state.nodes)
find(predicate, this.state.edges); || find(predicate, this.state.edges);
if (node) { if (node) {
break; break;
} }
} }
return node; return node;
} }
@ -1318,11 +1343,11 @@ class Graph extends React.PureComponent {
range(0, 3) range(0, 3)
); );
const bestSelectionPredicate = x => null || const bestSelectionPredicate = x => null
x.source === selected.id || || x.source === selected.id
x.target === selected.id || || x.target === selected.id
selected.source === x.id || || selected.source === x.id
selected.target === x.id; || selected.target === x.id;
this.setState({ this.setState({
selected: this._findAnyObjectForSelection(types, bestSelectionPredicate), selected: this._findAnyObjectForSelection(types, bestSelectionPredicate),
@ -1348,9 +1373,9 @@ class Graph extends React.PureComponent {
_hotKeyMovePosition(direction) { _hotKeyMovePosition(direction) {
const { selected, moved } = this.state; const { selected, moved } = this.state;
if (!selected || if (!selected
selected !== moved || || selected !== moved
![ 'sink', 'source', 'client', 'module' ].includes(moved.type) || ![ 'sink', 'source', 'client', 'module' ].includes(moved.type)
) { ) {
return false; return false;
} }
@ -1488,15 +1513,15 @@ class Graph extends React.PureComponent {
renderDefs, renderDefs,
renderNode, renderNode,
renderNodeText: renderNodeText(this.context.store), renderNodeText: renderNodeText(this.props.store),
renderEdge, renderEdge,
renderEdgeText: renderEdgeText(this.context.store), renderEdgeText: renderEdgeText(this.props.store),
}), }),
this.state.contexted && ( this.state.contexted && (
this.state.contexted === backgroundSymbol ? this.state.contexted === backgroundSymbol
r(BackgroundContextMenu, { ? r(BackgroundContextMenu, {
key: 'background-context-menu', key: 'background-context-menu',
onClose: this.onContextMenuClose, onClose: this.onContextMenuClose,
@ -1506,8 +1531,8 @@ class Graph extends React.PureComponent {
onLoadModuleLoopback: this.onLoadModuleLoopback, onLoadModuleLoopback: this.onLoadModuleLoopback,
onLoadModuleCombineSink: this.onLoadModuleCombineSink, onLoadModuleCombineSink: this.onLoadModuleCombineSink,
onLoadModuleNullSink: this.onLoadModuleNullSink, onLoadModuleNullSink: this.onLoadModuleNullSink,
}) : })
r(GraphObjectContextMenu, { : r(GraphObjectContextMenu, {
key: 'graph-object-context-menu', key: 'graph-object-context-menu',
onClose: this.onContextMenuClose, onClose: this.onContextMenuClose,
@ -1523,11 +1548,10 @@ class Graph extends React.PureComponent {
} }
} }
Graph.contextTypes = { module.exports = compose(
store: PropTypes.any, forwardRef(),
};
module.exports = connect( connect(
state => ({ state => ({
serverInfo: state.pulse[primaryPulseServer].serverInfo, serverInfo: state.pulse[primaryPulseServer].serverInfo,
@ -1546,6 +1570,12 @@ module.exports = connect(
'serverInfo', 'serverInfo',
'unloadModuleByIndex', 'unloadModuleByIndex',
], merge(pulseActions, iconsActions)), dispatch), ], merge(pulseActions, iconsActions)), dispatch),
null, ),
{ withRef: true },
fromRenderProps(
ReduxConsumer,
({ store }) => ({ store }),
),
unforwardRef(),
)(Graph); )(Graph);

View File

@ -27,8 +27,8 @@ module.exports = class LayoutEngine {
return undefined; return undefined;
} }
return (((a.x - size - margin) < b.x) && (b.x < (a.x + size + margin))) && return (((a.x - size - margin) < b.x) && (b.x < (a.x + size + margin)))
(((a.y - size - margin) < b.y) && (b.y < (a.y + size + margin))); && (((a.y - size - margin) < b.y) && (b.y < (a.y + size + margin)));
} }
calculatePosition(node) { calculatePosition(node) {
@ -81,6 +81,7 @@ module.exports = class LayoutEngine {
if (estimatedColumnHeights.get(2) < targetClientsColumnHeight) { if (estimatedColumnHeights.get(2) < targetClientsColumnHeight) {
targetCol = 2; targetCol = 2;
} }
node.x = (2 * step) + (targetCol * step); node.x = (2 * step) + (targetCol * step);
} }

View File

@ -8,7 +8,7 @@ const PIXI = require('pixi.js');
const theme = require('../../utils/theme'); const theme = require('../../utils/theme');
PIXI.ticker.shared.autoStart = false; PIXI.Ticker.shared.autoStart = false;
class Peaks extends React.Component { class Peaks extends React.Component {
constructor(props) { constructor(props) {
@ -25,24 +25,24 @@ class Peaks extends React.Component {
} }
componentDidMount() { componentDidMount() {
this.app = new PIXI.Application(window.innerWidth, window.innerHeight, { this.app = new PIXI.Application({
autoStart: false, autoStart: false,
transparent: true, transparent: true,
}); });
this.app.ticker.add(this.handleTick); this.app.ticker.add(this.handleTick);
this.trailTexture = PIXI.Texture.fromImage('assets/trail.png'); this.trailTexture = PIXI.Texture.from('assets/trail.png');
this.points = [ this.points = [
new PIXI.Point(0, 0), new PIXI.Point(0, 0),
new PIXI.Point(100, 100), new PIXI.Point(100, 100),
]; ];
this.rope = new PIXI.mesh.Rope(this.trailTexture, this.points); this.rope = new PIXI.SimpleRope(this.trailTexture, this.points);
this.rope.blendmode = PIXI.BLEND_MODES.ADD; this.rope.blendmode = PIXI.BLEND_MODES.ADD;
this.app.stage.addChild(this.rope); this.app.stage.addChild(this.rope);
this.ropes = {}; this.ropes = {};
this.containerRef.current.appendChild(this.app.view); this.containerRef.current.append(this.app.view);
this.peaks = {}; this.peaks = {};
this.props.peaks.on('peak', this.handlePeak); this.props.peaks.on('peak', this.handlePeak);
@ -51,6 +51,7 @@ class Peaks extends React.Component {
this.view = this.graph.querySelector('.view'); this.view = this.graph.querySelector('.view');
window.addEventListener('resize', this.handleResize); window.addEventListener('resize', this.handleResize);
this.handleResize();
this.lastAnimationFrameTimeStamp = 0; this.lastAnimationFrameTimeStamp = 0;
this.requestAnimationFrame(); this.requestAnimationFrame();
@ -74,9 +75,11 @@ class Peaks extends React.Component {
if (window.document.hidden) { if (window.document.hidden) {
return 2 * 1000; return 2 * 1000;
} }
if (this.props.accommodateGraphAnimation) { if (this.props.accommodateGraphAnimation) {
return 1000 / 70; return 1000 / 70;
} }
return 1000 / 25; return 1000 / 25;
} }
@ -120,7 +123,7 @@ class Peaks extends React.Component {
p(target), p(target),
p(source), p(source),
]; ];
const rope = new PIXI.mesh.Rope(this.trailTexture, points); const rope = new PIXI.SimpleRope(this.trailTexture, points);
rope.blendmode = PIXI.BLEND_MODES.ADD; rope.blendmode = PIXI.BLEND_MODES.ADD;
rope.alpha = peak === undefined ? 0 : peak ** (1 / 3); rope.alpha = peak === undefined ? 0 : peak ** (1 / 3);
rope.tint = parseInt(theme.colors.themeSelectedBgColor.replace(/#/g, ''), 16); rope.tint = parseInt(theme.colors.themeSelectedBgColor.replace(/#/g, ''), 16);

View File

@ -140,11 +140,12 @@ class SatellitesGraphView extends React.Component {
satelliteNode.y = position.y; satelliteNode.y = position.y;
return; return;
} }
satelliteNode.x = position.x; satelliteNode.x = position.x;
satelliteNode.y = position.y + satelliteNode.y = position.y
offsetY + + offsetY
(satelliteSpread * plusMinus(i)) + + (satelliteSpread * plusMinus(i))
((satelliteSpread / 2) * ((satelliteNodes.length + 1) % 2)); + ((satelliteSpread / 2) * ((satelliteNodes.length + 1) % 2));
}); });
} }

View File

@ -57,42 +57,42 @@ class MyHotKeys extends React.Component {
} }
hotKeyFocusGraph() { hotKeyFocusGraph() {
this.cardsRef.current.getWrappedInstance().close(); this.cardsRef.current.close();
this.networkRef.current.getWrappedInstance().close(); this.networkRef.current.close();
this.preferencesRef.current.getWrappedInstance().close(); this.preferencesRef.current.close();
this.graphRef.current.getWrappedInstance().focus(); this.graphRef.current.focus();
} }
hotKeyFocusCards() { hotKeyFocusCards() {
this.networkRef.current.getWrappedInstance().close(); this.networkRef.current.close();
this.preferencesRef.current.getWrappedInstance().close(); this.preferencesRef.current.close();
const cards = this.cardsRef.current.getWrappedInstance(); const cards = this.cardsRef.current;
cards.toggle(); cards.toggle();
if (!cards.isOpen()) { if (!cards.isOpen()) {
this.graphRef.current.getWrappedInstance().focus(); this.graphRef.current.focus();
} }
} }
hotKeyFocusNetwork() { hotKeyFocusNetwork() {
this.cardsRef.current.getWrappedInstance().close(); this.cardsRef.current.close();
this.preferencesRef.current.getWrappedInstance().close(); this.preferencesRef.current.close();
const network = this.networkRef.current.getWrappedInstance(); const network = this.networkRef.current;
network.toggle(); network.toggle();
if (!network.isOpen()) { if (!network.isOpen()) {
this.graphRef.current.getWrappedInstance().focus(); this.graphRef.current.focus();
} }
} }
hotKeyFocusPreferences() { hotKeyFocusPreferences() {
this.cardsRef.current.getWrappedInstance().close(); this.cardsRef.current.close();
this.networkRef.current.getWrappedInstance().close(); this.networkRef.current.close();
const preferences = this.preferencesRef.current.getWrappedInstance(); const preferences = this.preferencesRef.current;
preferences.toggle(); preferences.toggle();
if (!preferences.isOpen()) { if (!preferences.isOpen()) {
this.graphRef.current.getWrappedInstance().focus(); this.graphRef.current.focus();
} }
} }

View File

@ -9,7 +9,7 @@ const {
const React = require('react'); const React = require('react');
const { CSSTransitionGroup } = require('react-transition-group'); const { TransitionGroup, CSSTransition } = require('react-transition-group');
const r = require('r-dom'); const r = require('r-dom');
@ -49,6 +49,7 @@ class Log extends React.Component {
if (item.type === 'error') { if (item.type === 'error') {
return `${item.error.name}: ${item.error.message}`; return `${item.error.name}: ${item.error.message}`;
} }
return actionTypeText[item.action] || item.action; return actionTypeText[item.action] || item.action;
} }
@ -62,19 +63,18 @@ class Log extends React.Component {
render() { render() {
return r.div({ return r.div({
className: 'log', className: 'log',
}, r(CSSTransitionGroup, { }, r(TransitionGroup, compose(
transitionName: 'log-item-transition', map(item => r(CSSTransition, {
transitionEnterTimeout: 300,
transitionLeaveTimeout: 2000,
}, compose(
map(item => r.div({
key: weakmapId(item), key: weakmapId(item),
className: 'log-item-transition',
timeout: { enter: 300, leave: 2000 },
}, r.div({
classSet: { classSet: {
'log-item': true, 'log-item': true,
'log-item-error': item.type === 'error', 'log-item-error': item.type === 'error',
'log-item-info': item.type === 'info', 'log-item-info': item.type === 'info',
}, },
}, this.itemText(item))), }, this.itemText(item)))),
filter(item => this.shouldShowItem(item)), filter(item => this.shouldShowItem(item)),
)(this.props.log.items))); )(this.props.log.items)));
} }

View File

@ -13,9 +13,17 @@ const PropTypes = require('prop-types');
const Modal = require('react-modal'); const Modal = require('react-modal');
const { connect } = require('react-redux'); const {
connect,
ReactReduxContext: { Consumer: ReduxConsumer },
} = require('react-redux');
const { bindActionCreators } = require('redux'); const { bindActionCreators } = require('redux');
const {
compose,
fromRenderProps,
} = require('recompose');
const { const {
pulse: pulseActions, pulse: pulseActions,
preferences: preferencesActions, preferences: preferencesActions,
@ -47,10 +55,12 @@ const bind = that => f => {
if (!bindMemo.has(that)) { if (!bindMemo.has(that)) {
bindMemo.set(that, new WeakMap()); bindMemo.set(that, new WeakMap());
} }
const bounds = bindMemo.get(that); const bounds = bindMemo.get(that);
if (!bounds.has(f)) { if (!bounds.has(f)) {
bounds.set(f, f.bind(that)); bounds.set(f, f.bind(that));
} }
return bounds.get(f); return bounds.get(f);
}; };
@ -196,10 +206,17 @@ Modals.contextTypes = {
store: PropTypes.any, store: PropTypes.any,
}; };
module.exports = connect( module.exports = compose(
connect(
state => ({ state => ({
infos: state.pulse[primaryPulseServer].infos, infos: state.pulse[primaryPulseServer].infos,
preferences: state.preferences, preferences: state.preferences,
}), }),
dispatch => bindActionCreators(merge(pulseActions, preferencesActions), dispatch), dispatch => bindActionCreators(merge(pulseActions, preferencesActions), dispatch),
),
fromRenderProps(
ReduxConsumer,
({ store }) => ({ store }),
),
)(Modals); )(Modals);

View File

@ -240,5 +240,5 @@ module.exports = connect(
actions: bindActionCreators(pulseActions, dispatch), actions: bindActionCreators(pulseActions, dispatch),
}), }),
null, null,
{ withRef: true }, { forwardRef: true },
)(Cards); )(Cards);

View File

@ -207,5 +207,5 @@ module.exports = connect(
actions: bindActionCreators(preferencesActions, dispatch), actions: bindActionCreators(preferencesActions, dispatch),
}), }),
null, null,
{ withRef: true }, { forwardRef: true },
)(Preferences); )(Preferences);

View File

@ -48,11 +48,11 @@ function spawnProcess({ onPeak, onExit }) {
const peak = data.readFloatLE(p); const peak = data.readFloatLE(p);
p += 4; p += 4;
const typeStr = type === PA_SUBSCRIPTION_EVENT_SOURCE ? const typeStr = type === PA_SUBSCRIPTION_EVENT_SOURCE
'source' : ? 'source'
type === PA_SUBSCRIPTION_EVENT_SINK_INPUT ? : type === PA_SUBSCRIPTION_EVENT_SINK_INPUT
'sinkInput' : ? 'sinkInput'
'unexpected'; : 'unexpected';
onPeak(typeStr, index, peak); onPeak(typeStr, index, peak);
} }
}; };

View File

@ -104,9 +104,9 @@ module.exports = class VolumeSlider extends React.Component {
draggingX, draggingX,
} = this.state; } = this.state;
const x = draggingX === null ? const x = draggingX === null
((height / 2) + vol2pix(value, maxVolume)) : ? ((height / 2) + vol2pix(value, maxVolume))
draggingX; : draggingX;
this._lastRenderedX = x; this._lastRenderedX = x;

View File

@ -308,6 +308,10 @@ div[tabindex="-1"]:focus {
cursor: pointer; cursor: pointer;
} }
.graph foreignObject {
overflow: visible;
}
.node-text, .edge-text { .node-text, .edge-text {
pointer-events: none; pointer-events: none;

View File

@ -8,6 +8,9 @@ const theme = require('./utils/theme');
app.on('ready', () => { app.on('ready', () => {
const win = new BrowserWindow({ const win = new BrowserWindow({
backgroundColor: theme.colors.themeBaseColor, backgroundColor: theme.colors.themeBaseColor,
webPreferences: {
nodeIntegration: true,
},
}); });
win.setAutoHideMenuBar(true); win.setAutoHideMenuBar(true);
win.setMenuBarVisibility(false); win.setMenuBarVisibility(false);

View File

@ -5,15 +5,15 @@
"main": "index.js", "main": "index.js",
"license": "GPL-3.0", "license": "GPL-3.0",
"devDependencies": { "devDependencies": {
"ava": "^0.25.0", "ava": "^2.2.0",
"electron": "^4.1.1", "electron": "^6.0.1",
"electron-devtools-installer": "^2.2.4", "electron-devtools-installer": "^2.2.4",
"electron-packager": "^12.2.0", "electron-packager": "^14.0.4",
"eslint-config-xo-overrides": "^1.1.2", "eslint-config-xo-overrides": "^1.4.0",
"nyc": "^13.1.0", "nyc": "^14.1.1",
"remotedev-server": "^0.3.1", "remotedev-server": "^0.3.1",
"uws": "^99.0.0", "uws": "^100.0.1",
"xo": "^0.23.0" "xo": "^0.24.0"
}, },
"scripts": { "scripts": {
"start": "NODE_ENV=development electron .", "start": "NODE_ENV=development electron .",
@ -28,32 +28,32 @@
"dependencies": { "dependencies": {
"@futpib/paclient": "^0.0.10", "@futpib/paclient": "^0.0.10",
"@futpib/react-electron-menu": "^0.3.1", "@futpib/react-electron-menu": "^0.3.1",
"bluebird": "^3.5.3", "bluebird": "^3.5.5",
"camelcase": "^5.0.0", "camelcase": "^5.3.1",
"d3": "^5.7.0", "d3": "^5.9.7",
"electron-store": "^2.0.0", "electron-store": "^4.0.0",
"freedesktop-icons": "^0.1.0", "freedesktop-icons": "^0.1.0",
"ini": "^1.3.5", "ini": "^1.3.5",
"mathjs": "^5.2.3", "mathjs": "^6.0.4",
"pixi.js": "^4.8.2", "pixi.js": "^5.1.1",
"prop-types": "^15.6.2", "prop-types": "^15.7.2",
"r-dom": "^2.4.0", "r-dom": "^2.4.0",
"ramda": "^0.25.0", "ramda": "^0.26.1",
"react": "^16.6.0", "react": "^16.9.0",
"react-digraph": "^6.2.2", "react-digraph": "^6.5.0",
"react-dom": "^16.6.0", "react-dom": "^16.9.0",
"react-hotkeys": "^1.1.4", "react-hotkeys": "^2.0.0",
"react-modal": "^3.6.1", "react-modal": "^3.9.1",
"react-redux": "^5.1.0", "react-redux": "^7.1.0",
"react-transition-group": "^1.2.1", "react-transition-group": "^4.2.2",
"recompose": "^0.30.0", "recompose": "^0.30.0",
"redux": "^4.0.1", "redux": "^4.0.4",
"redux-actions": "^2.6.4", "redux-actions": "^2.6.5",
"redux-persist": "^5.10.0", "redux-persist": "^5.10.0",
"redux-persist-electron-storage": "^2.0.0", "redux-persist-electron-storage": "^2.1.0",
"redux-promise-middleware": "^5.1.1", "redux-promise-middleware": "^6.1.1",
"redux-thunk": "^2.3.0", "redux-thunk": "^2.3.0",
"remote-redux-devtools": "^0.5.13", "remote-redux-devtools": "^0.5.16",
"reselect": "^4.0.0" "reselect": "^4.0.0"
} }
} }

View File

@ -51,9 +51,9 @@ const serverReducer = combineReducers({
serverInfo: handleActions({ serverInfo: handleActions({
[pulse.serverInfo]: (state, { payload }) => { [pulse.serverInfo]: (state, { payload }) => {
return equals(state, payload) ? return equals(state, payload)
state : ? state
payload; : payload;
}, },
[pulse.close]: always(serverInitialState.serverInfo), [pulse.close]: always(serverInitialState.serverInfo),
}, serverInitialState.serverInfo), }, serverInitialState.serverInfo),
@ -63,9 +63,11 @@ const serverReducer = combineReducers({
if (payload.type !== type) { if (payload.type !== type) {
return state; return state;
} }
if (payload.type === 'sinkInput' || payload.type === 'sourceOutput') { if (payload.type === 'sinkInput' || payload.type === 'sourceOutput') {
return state; return state;
} }
return merge(state, { return merge(state, {
[payload.index]: payload, [payload.index]: payload,
}); });
@ -74,12 +76,14 @@ const serverReducer = combineReducers({
if (payload.type !== type) { if (payload.type !== type) {
return state; return state;
} }
return omit([ payload.index ], state); return omit([ payload.index ], state);
}, },
[pulse.info]: (state, { payload }) => { [pulse.info]: (state, { payload }) => {
if (payload.type !== type) { if (payload.type !== type) {
return state; return state;
} }
if (payload.type === 'sinkInput' || payload.type === 'sourceOutput') { if (payload.type === 'sinkInput' || payload.type === 'sourceOutput') {
const newPao = pick([ const newPao = pick([
'type', 'type',
@ -100,6 +104,7 @@ const serverReducer = combineReducers({
[newPao.index]: newPao, [newPao.index]: newPao,
}); });
} }
return state; return state;
}, },
[pulse.close]: () => serverInitialState.objects[key], [pulse.close]: () => serverInitialState.objects[key],
@ -110,12 +115,14 @@ const serverReducer = combineReducers({
if (payload.type !== type) { if (payload.type !== type) {
return state; return state;
} }
return omit([ payload.index ], state); return omit([ payload.index ], state);
}, },
[pulse.info]: (state, { payload }) => { [pulse.info]: (state, { payload }) => {
if (payload.type !== type) { if (payload.type !== type) {
return state; return state;
} }
return merge(state, { return merge(state, {
[payload.index]: payload, [payload.index]: payload,
}); });

View File

@ -51,4 +51,4 @@ Object.entries(theme.colors).forEach(([ key, value ]) => {
document.body.style.setProperty('--' + key, value); document.body.style.setProperty('--' + key, value);
}); });
render(r(Root), document.getElementById('root')); render(r(Root), document.querySelector('#root'));

View File

@ -4,7 +4,7 @@ const { createStore, applyMiddleware } = require('redux');
const { composeWithDevTools } = require('remote-redux-devtools'); const { composeWithDevTools } = require('remote-redux-devtools');
const { default: thunkMiddleware } = require('redux-thunk'); const { default: thunkMiddleware } = require('redux-thunk');
const { default: createPromiseMiddleware } = require('redux-promise-middleware'); const { default: promiseMiddleware } = require('redux-promise-middleware');
const { persistStore, persistReducer } = require('redux-persist'); const { persistStore, persistReducer } = require('redux-persist');
const createElectronStorage = require('redux-persist-electron-storage'); const createElectronStorage = require('redux-persist-electron-storage');
@ -24,7 +24,7 @@ const dev = process.env.NODE_ENV !== 'production';
module.exports = (state = initialState) => { module.exports = (state = initialState) => {
const middlewares = [ const middlewares = [
thunkMiddleware, thunkMiddleware,
createPromiseMiddleware(), promiseMiddleware,
pulseMiddleware, pulseMiddleware,
].filter(Boolean); ].filter(Boolean);

View File

@ -42,6 +42,7 @@ function getFnFromType(type) {
default: default:
throw new Error('Unexpected type: ' + type); throw new Error('Unexpected type: ' + type);
} }
return 'get' + fn[0].toUpperCase() + fn.slice(1); return 'get' + fn[0].toUpperCase() + fn.slice(1);
} }
@ -49,14 +50,17 @@ function setSinkChannelVolume(pa, store, index, channelIndex, volume, cb) {
const pai = getPaiByTypeAndIndex('sink', index)(store.getState()); const pai = getPaiByTypeAndIndex('sink', index)(store.getState());
pa.setSinkVolumes(index, pai.channelVolumes.map((v, i) => i === channelIndex ? volume : v), cb); pa.setSinkVolumes(index, pai.channelVolumes.map((v, i) => i === channelIndex ? volume : v), cb);
} }
function setSourceChannelVolume(pa, store, index, channelIndex, volume, cb) { function setSourceChannelVolume(pa, store, index, channelIndex, volume, cb) {
const pai = getPaiByTypeAndIndex('source', index)(store.getState()); const pai = getPaiByTypeAndIndex('source', index)(store.getState());
pa.setSourceVolumes(index, pai.channelVolumes.map((v, i) => i === channelIndex ? volume : v), cb); pa.setSourceVolumes(index, pai.channelVolumes.map((v, i) => i === channelIndex ? volume : v), cb);
} }
function setSinkInputChannelVolume(pa, store, index, channelIndex, volume, cb) { function setSinkInputChannelVolume(pa, store, index, channelIndex, volume, cb) {
const pai = getPaiByTypeAndIndex('sinkInput', index)(store.getState()); const pai = getPaiByTypeAndIndex('sinkInput', index)(store.getState());
pa.setSinkInputVolumesByIndex(index, pai.channelVolumes.map((v, i) => i === channelIndex ? volume : v), cb); pa.setSinkInputVolumesByIndex(index, pai.channelVolumes.map((v, i) => i === channelIndex ? volume : v), cb);
} }
function setSourceOutputChannelVolume(pa, store, index, channelIndex, volume, cb) { function setSourceOutputChannelVolume(pa, store, index, channelIndex, volume, cb) {
const pai = getPaiByTypeAndIndex('sourceOutput', index)(store.getState()); const pai = getPaiByTypeAndIndex('sourceOutput', index)(store.getState());
pa.setSourceOutputVolumesByIndex(index, pai.channelVolumes.map((v, i) => i === channelIndex ? volume : v), cb); pa.setSourceOutputVolumesByIndex(index, pai.channelVolumes.map((v, i) => i === channelIndex ? volume : v), cb);
@ -78,6 +82,7 @@ const createPulseClient = (store, pulseServerId = primaryPulseServer) => {
console.warn(error); console.warn(error);
return; return;
} }
throw error; throw error;
} }
@ -87,8 +92,10 @@ const createPulseClient = (store, pulseServerId = primaryPulseServer) => {
console.warn(err.message, type, index); console.warn(err.message, type, index);
return; return;
} }
throw err; throw err;
} }
info.type = info.type || type; info.type = info.type || type;
store.dispatch(pulseActions.info(info, pulseServerId)); store.dispatch(pulseActions.info(info, pulseServerId));
}); });
@ -122,6 +129,7 @@ const createPulseClient = (store, pulseServerId = primaryPulseServer) => {
getServerInfo(); getServerInfo();
return; return;
} }
store.dispatch(pulseActions.new({ type, index }, pulseServerId)); store.dispatch(pulseActions.new({ type, index }, pulseServerId));
getInfo(type, index); getInfo(type, index);
}) })
@ -130,6 +138,7 @@ const createPulseClient = (store, pulseServerId = primaryPulseServer) => {
getServerInfo(); getServerInfo();
return; return;
} }
store.dispatch(pulseActions.change({ type, index }, pulseServerId)); store.dispatch(pulseActions.change({ type, index }, pulseServerId));
getInfo(type, index); getInfo(type, index);
}) })
@ -161,6 +170,7 @@ const createPulseClient = (store, pulseServerId = primaryPulseServer) => {
if (error.message === 'Unable to connect to PulseAudio server') { if (error.message === 'Unable to connect to PulseAudio server') {
return Bluebird.delay(5000).then(reconnect); return Bluebird.delay(5000).then(reconnect);
} }
throw error; throw error;
}); });
@ -335,6 +345,7 @@ const updateTunnels = (dispatch, primaryState, remoteServerId, remoteState) => {
if ((tunnelAttempts[sink.name] || 0) + tunnelAttemptTimeout > Date.now()) { if ((tunnelAttempts[sink.name] || 0) + tunnelAttemptTimeout > Date.now()) {
return; return;
} }
if (!sinkTunnels[sink.name]) { if (!sinkTunnels[sink.name]) {
tunnelAttempts[sink.name] = Date.now(); tunnelAttempts[sink.name] = Date.now();
dispatch(pulseActions.loadModule('module-tunnel-sink', formatModuleArgs({ dispatch(pulseActions.loadModule('module-tunnel-sink', formatModuleArgs({
@ -348,6 +359,7 @@ const updateTunnels = (dispatch, primaryState, remoteServerId, remoteState) => {
if ((tunnelAttempts[source.name] || 0) + tunnelAttemptTimeout > Date.now()) { if ((tunnelAttempts[source.name] || 0) + tunnelAttemptTimeout > Date.now()) {
return; return;
} }
if (!sourceTunnels[source.name]) { if (!sourceTunnels[source.name]) {
tunnelAttempts[source.name] = Date.now(); tunnelAttempts[source.name] = Date.now();
dispatch(pulseActions.loadModule('module-tunnel-source', formatModuleArgs({ dispatch(pulseActions.loadModule('module-tunnel-source', formatModuleArgs({
@ -394,10 +406,10 @@ module.exports = store => {
const remoteState = nextState.pulse[pulseServerId]; const remoteState = nextState.pulse[pulseServerId];
if (primaryState.state === 'ready' && if (primaryState.state === 'ready'
remoteState.state === 'ready' && && remoteState.state === 'ready'
primaryState.targetState === 'ready' && && primaryState.targetState === 'ready'
primaryState.targetState === 'ready' && primaryState.targetState === 'ready'
) { ) {
updateTunnels(store.dispatch, primaryState, pulseServerId, remoteState); updateTunnels(store.dispatch, primaryState, pulseServerId, remoteState);
} }

View File

@ -60,6 +60,7 @@ for (const themePath of themePaths) {
if (error.code === 'ENOENT') { if (error.code === 'ENOENT') {
continue; continue;
} }
throw error; throw error;
} }
@ -70,6 +71,7 @@ for (const themePath of themePaths) {
if (error.code === 'ENOENT') { if (error.code === 'ENOENT') {
continue; continue;
} }
throw error; throw error;
} }
} }

View File

@ -16,6 +16,7 @@ const formatModuleArgs = object => map(([ k, v ]) => {
} else { } else {
v = v.join(','); v = v.join(',');
} }
return `${k}=${v}`; return `${k}=${v}`;
}, toPairs(object)).join(' '); }, toPairs(object)).join(' ');

View File

@ -5,7 +5,7 @@ import { map, range } from 'ramda';
import plusMinus from './plus-minus'; import plusMinus from './plus-minus';
test(t => { test('plusMinus', t => {
t.deepEqual( t.deepEqual(
map(plusMinus, range(0, 7)), map(plusMinus, range(0, 7)),
[ 0, -1, 1, -2, 2, -3, 3 ], [ 0, -1, 1, -2, 2, -3, 3 ],

19
utils/recompose/index.js Normal file
View File

@ -0,0 +1,19 @@
const React = require('react');
const r = require('r-dom');
const forwardRef = () => Component => React.forwardRef((props, ref) => r(Component, {
...props,
__forwardedRef: ref,
}));
const unforwardRef = () => Component => ({ __forwardedRef, ...props }) => r(Component, {
...props,
ref: __forwardedRef,
});
module.exports = {
forwardRef,
unforwardRef,
};

View File

@ -5,6 +5,7 @@ const weakmapId = o => {
if (!weakmap.has(o)) { if (!weakmap.has(o)) {
weakmap.set(o, String(counter++)); weakmap.set(o, String(counter++));
} }
return weakmap.get(o); return weakmap.get(o);
}; };

4739
yarn.lock

File diff suppressed because it is too large Load Diff