Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ac17e9d
commit 9b56c5a
Showing
12 changed files
with
3,812 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
node_modules | ||
lib | ||
npm-debug.log | ||
yarn-error.log |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
src | ||
test | ||
.git | ||
.gitignore |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
{ | ||
"name": "react-conduit", | ||
"version": "0.1.0", | ||
"description": "Place components anywhere in your dom tree", | ||
"main": "lib/index.js", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/trabe/react-conduit.git" | ||
}, | ||
"author": "Roman Coedo <romancoedo@gmail.com>", | ||
"license": "MIT", | ||
"devDependencies": { | ||
"babel-cli": "^6.24.0", | ||
"babel-core": "^6.24.0", | ||
"babel-preset-es2015": "^6.24.0", | ||
"babel-preset-react": "^6.23.0", | ||
"babel-preset-stage-3": "^6.22.0", | ||
"chai": "^3.5.0", | ||
"enzyme": "^2.8.0", | ||
"enzyme-to-json": "^1.5.0", | ||
"jest": "^19.0.2", | ||
"prettier": "^0.22.0", | ||
"react": "^15.4.2", | ||
"react-addons-create-fragment": "^15.4.2", | ||
"react-addons-test-utils": "^15.4.2", | ||
"react-dom": "^15.4.2", | ||
"sinon": "^2.1.0" | ||
}, | ||
"scripts": { | ||
"clean": "rm -rf ./lib", | ||
"precompile": "npm run clean && npm run test", | ||
"compile": "babel -d lib/ src/", | ||
"compile:watch": "npm run compile -- --watch", | ||
"test": "jest", | ||
"test:watch": "npm run test -- --watch", | ||
"prepublish": "npm run compile" | ||
}, | ||
"peerDependencies": { | ||
"react": ">= 0.14.x", | ||
"react-addons-create-fragment": ">= 0.14.x" | ||
}, | ||
"babel": { | ||
"presets": [ | ||
"es2015", | ||
"stage-3", | ||
"react" | ||
] | ||
}, | ||
"jest": { | ||
"snapshotSerializers": [ | ||
"<rootDir>/node_modules/enzyme-to-json/serializer" | ||
] | ||
}, | ||
"dependencies": { | ||
"uuid": "^3.0.1" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import React, { Component, Children, PropTypes } from "react"; | ||
import { createRegistry } from "./registry"; | ||
|
||
class ConduitProvider extends Component { | ||
constructor(props) { | ||
super(props); | ||
const { registry } = this.props; | ||
|
||
this.registry = registry ? registry : createRegistry(); | ||
} | ||
|
||
getChildContext() { | ||
return { registry: this.registry }; | ||
} | ||
|
||
render() { | ||
return Children.only(this.props.children); | ||
} | ||
} | ||
|
||
ConduitProvider.childContextTypes = { | ||
registry: PropTypes.object.isRequired, | ||
}; | ||
|
||
export default ConduitProvider; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export { default as ConduitProvider } from "./conduit-provider"; | ||
export { default as Inlet } from "./inlet"; | ||
export { default as Outlet } from "./outlet"; | ||
export { createRegistry } from "./registry"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import React, { Component, Children, PropTypes } from "react"; | ||
import uuidV4 from "uuid/v4"; | ||
import { updateChildren, removeInlet, addInlet } from "./registry"; | ||
|
||
export class Inlet extends Component { | ||
constructor(props) { | ||
super(props); | ||
this.id = uuidV4(); | ||
} | ||
|
||
componentWillReceiveProps(nextProps) { | ||
if (this.props.label !== nextProps.label) { | ||
removeInlet(this.context.registry, this.props.label, this.id); | ||
addInlet(this.context.registry, nextProps.label, this.id); | ||
} | ||
updateChildren(this.context.registry, this.id, nextProps.children); | ||
} | ||
|
||
componentWillMount() { | ||
addInlet(this.context.registry, this.props.label, this.id); | ||
updateChildren(this.context.registry, this.id, this.props.children); | ||
} | ||
|
||
componentWillUnmount() { | ||
removeInlet(this.context.registry, this.props.label, this.id); | ||
} | ||
|
||
render() { | ||
return null; | ||
} | ||
} | ||
|
||
Inlet.contextTypes = { | ||
registry: PropTypes.object.isRequired, | ||
}; | ||
|
||
Inlet.PropTypes = { | ||
label: PropTypes.string.isRequired, | ||
}; | ||
|
||
export default Inlet; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import React, { Component, PropTypes } from "react"; | ||
import { watchOutlet, mergeInletChildren } from "./registry"; | ||
|
||
class Outlet extends Component { | ||
constructor(props, context) { | ||
super(props, context); | ||
|
||
this.state = { children: this.getChildren() }; | ||
|
||
this.getChildren = this.getChildren.bind(this); | ||
this.updateChildren = this.updateChildren.bind(this); | ||
} | ||
|
||
componentWillMount() { | ||
watchOutlet(this.context.registry, this.props.label, this.updateChildren); | ||
} | ||
|
||
componentWillReceiveProps(nextProps) { | ||
if (this.props.label !== nextProps.label) { | ||
this.updateChildren(); | ||
} | ||
} | ||
|
||
getChildren() { | ||
return mergeInletChildren(this.context.registry, this.props.label); | ||
} | ||
|
||
updateChildren() { | ||
this.setState({ children: this.getChildren() }); | ||
} | ||
|
||
render() { | ||
return ( | ||
<div> | ||
{this.state.children} | ||
</div> | ||
); | ||
} | ||
} | ||
|
||
Outlet.contextTypes = { | ||
registry: PropTypes.object.isRequired, | ||
}; | ||
|
||
Outlet.PropTypes = { | ||
label: PropTypes.string.isRequired, | ||
}; | ||
|
||
export default Outlet; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import createFragment from "react-addons-create-fragment"; | ||
import uuidV4 from "uuid"; | ||
|
||
export const createRegistry = () => ({ | ||
// outletId -> { id: outletId, inlets: [inletIds], watchers: { uuid: fn }} | ||
outlets: {}, | ||
// inletId -> children | ||
children: {}, | ||
}); | ||
|
||
const initializeOutlet = (registry, { id, inlets = new Set(), watchers = {} }) => { | ||
registry.outlets[id] = { id, inlets, watchers }; | ||
}; | ||
|
||
const ensureOutletInitialized = fn => | ||
(registry, outletId, ...args) => { | ||
if (!registry.outlets[outletId]) { | ||
initializeOutlet(registry, { id: outletId }); | ||
} | ||
return fn(registry, outletId, ...args); | ||
}; | ||
|
||
export const watchOutlet = ensureOutletInitialized((registry, outletId, fn) => { | ||
const watcherId = uuidV4(); | ||
registry.outlets[outletId].watchers[watcherId] = fn; | ||
|
||
return () => { | ||
delete registry.outlets[outletId].watchers[watcherId]; | ||
}; | ||
}); | ||
|
||
export const mergeInletChildren = ({ outlets, children }, outletId) => | ||
createFragment( | ||
Array.from((outlets[outletId] && outlets[outletId].inlets) || []) | ||
.map(inletId => [inletId, children[inletId]]) | ||
.reduce((acc, [id, children]) => ({ ...acc, [id]: children }), {}), | ||
); | ||
|
||
export const addInlet = ensureOutletInitialized((registry, outletId, inletId) => { | ||
registry.outlets[outletId].inlets.add(inletId); | ||
notifyWatchers(registry, outletId); | ||
}); | ||
|
||
export const removeInlet = ensureOutletInitialized((registry, outletId, inletId) => { | ||
registry.outlets[outletId].inlets.delete(inletId); | ||
notifyWatchers(registry, outletId); | ||
}); | ||
|
||
export const updateChildren = (registry, inletId, children) => { | ||
registry.children[inletId] = children; | ||
|
||
Object.values(registry.outlets) | ||
.filter(outlet => outlet.inlets.has(inletId)) | ||
.forEach(outlet => notifyWatchers(registry, outlet.id)); | ||
}; | ||
|
||
export const notifyWatchers = ensureOutletInitialized(({ outlets }, outletId) => { | ||
Object.values(outlets[outletId].watchers).forEach(watcher => watcher()); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`conduit snapshots Inlet Inlet should not render its children 1`] = `null`; | ||
|
||
exports[`conduit snapshots Inlet and Outlet Inlet children are sent to their corresponding outlets 1`] = ` | ||
<div> | ||
<div | ||
id="outlet1" | ||
> | ||
<div> | ||
<div> | ||
first inlet | ||
</div> | ||
<div> | ||
second inlet | ||
</div> | ||
</div> | ||
</div> | ||
<div | ||
id="outlet2" | ||
> | ||
<div> | ||
<div> | ||
third inlet | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
`; | ||
|
||
exports[`conduit snapshots Inlet and Outlet should merge the associated Inlet's children to the corresponding outlet 1`] = ` | ||
<div> | ||
<div> | ||
<div> | ||
first inlet | ||
</div> | ||
<div> | ||
second inlet | ||
</div> | ||
<div> | ||
third inlet | ||
</div> | ||
</div> | ||
</div> | ||
`; | ||
|
||
exports[`conduit snapshots Inlet and Outlet should output Inlet's children to the corresponding outlet 1`] = ` | ||
<div> | ||
<div> | ||
this should be rendered in the outlet | ||
</div> | ||
</div> | ||
`; | ||
|
||
exports[`conduit snapshots Inlet and Outlet two outlets with the same label will duplicate the children rendering 1`] = ` | ||
<div> | ||
<div> | ||
<div> | ||
inlet | ||
</div> | ||
</div> | ||
<div> | ||
<div> | ||
inlet | ||
</div> | ||
</div> | ||
</div> | ||
`; | ||
|
||
exports[`conduit snapshots Outlet Outlet should not render its children 1`] = `<div />`; |
Oops, something went wrong.