react-tunnels
Advanced tools
Comparing version 1.0.1 to 1.0.2
@@ -66,37 +66,26 @@ 'use strict'; | ||
id = _props.id, | ||
renderChildren = _props.children; | ||
renderChildren = _props.children, | ||
multiple = _props.multiple; | ||
var tunnelProps = tunnelState.getTunnelProps(id); | ||
if (Array.isArray(tunnelProps)) { | ||
if (renderChildren) { | ||
return (0, _react.createElement)(renderChildren, { items: tunnelProps }); | ||
} | ||
if (tunnelProps.length > 0) { | ||
return _react2.default.createElement( | ||
_react.Fragment, | ||
null, | ||
tunnelProps.map(function (props) { | ||
return props.children; | ||
}) | ||
); | ||
} | ||
} else { | ||
if (renderChildren) { | ||
if (renderChildren) { | ||
if (Array.isArray(tunnelProps) || multiple) { | ||
return !tunnelProps ? (0, _react.createElement)(renderChildren, { items: [] }) : (0, _react.createElement)(renderChildren, { | ||
items: Array.isArray(tunnelProps) ? tunnelProps : [tunnelProps] | ||
}); | ||
} else { | ||
return (0, _react.createElement)(renderChildren, tunnelProps || {}); | ||
} | ||
} | ||
if (!tunnelProps) { | ||
return null; | ||
} | ||
return _react2.default.createElement( | ||
_react.Fragment, | ||
null, | ||
tunnelProps.children | ||
); | ||
if (!tunnelProps) { | ||
return null; | ||
} | ||
return null; | ||
return _react2.default.createElement( | ||
_react.Fragment, | ||
null, | ||
tunnelProps.children | ||
); | ||
} | ||
@@ -110,3 +99,4 @@ }]); | ||
children: _propTypes2.default.func, | ||
id: _propTypes2.default.string.isRequired | ||
id: _propTypes2.default.string.isRequired, | ||
multiple: _propTypes2.default.bool | ||
}; | ||
@@ -113,0 +103,0 @@ TunnelPlaceholder.contextTypes = { |
{ | ||
"name": "react-tunnels", | ||
"version": "1.0.1", | ||
"version": "1.0.2", | ||
"description": "A easy way to communicate rendering logic and data to ancestor components in React.", | ||
@@ -5,0 +5,0 @@ "main": "./lib/index.js", |
@@ -1,2 +0,2 @@ | ||
# React Tunnels 🚇 [![npm](https://img.shields.io/npm/v/react-tunnels.svg?style=flat)](https://www.npmjs.org/package/react-tunnels) | ||
# React Tunnels 🚇 [![npm](https://img.shields.io/npm/v/react-tunnels.svg?style=flat)](https://www.npmjs.org/package/react-tunnels)[![Build Status](http://img.shields.io/travis/javivelasco/react-tunnels/master.svg?style=flat-square)](https://travis-ci.org/javivelasco/react-tunnels) | ||
@@ -13,7 +13,7 @@ Render React components in placeholders that are placed somewhere else in the component tree. | ||
There is a common use case in React apps where you want to define a `Layout` where the content of some elements are defined by child components. For example, you want define `Layout` just once and reuse it for every page but it has a breadcrumb whose steps depend on children components. This tiny library allows you to define "tunnels" to render from a element to whatever other element in the app, even elements on top of the tree. It's like `Portal` but the target is a component instead of a DOM element. | ||
There is a common use case in React apps where you want to define a `Layout` where the content of some elements are defined by `children` components. For example, you want define `Layout` just once and reuse it for every page but it has a breadcrumb whose steps depend on `children` components. This tiny library allows you to define *tunnels* to render from a element to whatever other element in the App, even elements located on top of the tree. It's like `Portal` but the target is a *component* instead of a *DOM element*. | ||
### Usage | ||
Define a `TunnelPlaceholder` identified by an `id` and decide what properties are going to be passed to its render function by defining `Tunnel` components with the same id anywhere else in the app. If you define just a single `Tunnel` its props will be passed, if there are more than once tunnel for an `id`, the tunnel will receive an array of `props`. Let's see some examples. | ||
Define a `TunnelPlaceholder` identified by an `id` and decide what properties are going to be passed to its `render` function by defining `Tunnel` components with the **same id** anywhere else in the app. If you define just a single `Tunnel` its props will be passed straight to the `render` function, if there are more than one `Tunnel` for a single `id`, the placeholder `render` function will receive a `item` argument which is an Array containing the `props` for each `Tunnel`. Let's see some examples. | ||
@@ -25,3 +25,3 @@ ### Simple example: tunneling children | ||
```jsx | ||
import { TunnelsProvider, TunnelPlaceholder, Tunnel } from 'preact-slots' | ||
import { TunnelsProvider, TunnelPlaceholder, Tunnel } from 'react-tunnels' | ||
@@ -75,3 +75,3 @@ render( | ||
- [React Slot Fill](https://github.com/camwest/react-slot-fill): [@camwest](https://github.com/camwest) has built a similar project but with a different API and a bit more limited use cases. The main difference is that you can't pass content to a placeholder from multiple entry points while react-tunnels does it by passing an array with the props defined by each tunnel to the render function of the placeholder. For simple cases, it is pretty similar. | ||
- [React Slots](https://github.com/developit/preact-slots): A library similar to React Slot Fill but for [Preact](https://github.com/developit/preact) developed by [Jason Miller](https://twitter.com/_developit). | ||
- [Preact Slots](https://github.com/developit/preact-slots): A library similar to React Slot Fill but for [Preact](https://github.com/developit/preact) developed by [Jason Miller](https://twitter.com/_developit). | ||
@@ -78,0 +78,0 @@ ## License |
@@ -8,2 +8,3 @@ import PropTypes from 'prop-types' | ||
id: PropTypes.string.isRequired, | ||
multiple: PropTypes.bool, | ||
} | ||
@@ -33,26 +34,22 @@ | ||
const { tunnelState } = this.context | ||
const { id, children: renderChildren } = this.props | ||
const { id, children: renderChildren, multiple } = this.props | ||
const tunnelProps = tunnelState.getTunnelProps(id) | ||
if (Array.isArray(tunnelProps)) { | ||
if (renderChildren) { | ||
return createElement(renderChildren, { items: tunnelProps }) | ||
} | ||
if (tunnelProps.length > 0) { | ||
return <Fragment>{tunnelProps.map(props => props.children)}</Fragment> | ||
} | ||
} else { | ||
if (renderChildren) { | ||
if (renderChildren) { | ||
if (Array.isArray(tunnelProps) || multiple) { | ||
return !tunnelProps | ||
? createElement(renderChildren, { items: [] }) | ||
: createElement(renderChildren, { | ||
items: Array.isArray(tunnelProps) ? tunnelProps : [tunnelProps], | ||
}) | ||
} else { | ||
return createElement(renderChildren, tunnelProps || {}) | ||
} | ||
} | ||
if (!tunnelProps) { | ||
return null | ||
} | ||
return <Fragment>{tunnelProps.children}</Fragment> | ||
if (!tunnelProps) { | ||
return null | ||
} | ||
return null | ||
return <Fragment>{tunnelProps.children}</Fragment> | ||
} | ||
@@ -59,0 +56,0 @@ } |
@@ -25,3 +25,3 @@ import { configure, mount } from 'enzyme' | ||
</TunnelPlaceholder> | ||
<Tunnel id={TUNNEL_ID} props={props} /> | ||
<Tunnel id={TUNNEL_ID} {...props} /> | ||
</div> | ||
@@ -47,14 +47,37 @@ </TunnelProvider>, | ||
it('should render passing a component', () => { | ||
it('should render multiple tunnels props when there is a multiple prop', () => { | ||
const wrapper = mount( | ||
<TunnelProvider> | ||
<div> | ||
<TunnelPlaceholder id={TUNNEL_ID} component={Msg} /> | ||
<Tunnel id={TUNNEL_ID} props={props} /> | ||
<TunnelPlaceholder id={TUNNEL_ID} multiple> | ||
{({ items = [] }) => | ||
items.map((props, i) => <div key={i}>{props.message}</div>) | ||
} | ||
</TunnelPlaceholder> | ||
<Tunnel id={TUNNEL_ID} message="Foo" /> | ||
</div> | ||
</TunnelProvider>, | ||
) | ||
assertTunnelPlaceholderContent(wrapper, props.message) | ||
expect(wrapper.contains([<div key={0}>Foo</div>])).toEqual(true) | ||
}) | ||
it('should render multiple tunnels props when there are many tunnels', () => { | ||
const wrapper = mount( | ||
<TunnelProvider> | ||
<div> | ||
<TunnelPlaceholder id={TUNNEL_ID}> | ||
{({ items = [] }) => | ||
items.map((props, i) => <div key={i}>{props.message}</div>) | ||
} | ||
</TunnelPlaceholder> | ||
<Tunnel id={TUNNEL_ID} message="Foo" /> | ||
<Tunnel id={TUNNEL_ID} message="Bar" /> | ||
</div> | ||
</TunnelProvider>, | ||
) | ||
expect( | ||
wrapper.contains([<div key={0}>Foo</div>, <div key={1}>Bar</div>]), | ||
).toEqual(true) | ||
}) | ||
describe('given Tunnel is not defined', () => { | ||
@@ -72,13 +95,2 @@ it('should render TunnelPlaceholder children passing empty props', () => { | ||
it('should render TunnelPlaceholder component passing empty props', () => { | ||
const wrapper = mount( | ||
<TunnelProvider> | ||
<div> | ||
<TunnelPlaceholder id={TUNNEL_ID} component={Msg} /> | ||
</div> | ||
</TunnelProvider>, | ||
) | ||
assertTunnelPlaceholderContent(wrapper, 'defaultMessage') | ||
}) | ||
it('should render empty is TunnelPlaceholder does not have children', () => { | ||
@@ -124,3 +136,3 @@ const wrapper = mount( | ||
it.only('should update TunnelPlaceholder when Tunnel is unmounted', () => { | ||
it('should update TunnelPlaceholder when Tunnel is unmounted', () => { | ||
const wrapper = mount(<Component msg={msg1} visible />) | ||
@@ -127,0 +139,0 @@ assertTunnelPlaceholderContent(wrapper, msg1) |
import TunnelState from '../src/TunnelState' | ||
const TUNNEL_ID = 'GroompyTunnel' | ||
const ITEM_ID = 'GroomyItem' | ||
const ITEM_ID = 'GroompyItem' | ||
const ITEM_ID2 = 'GroompyItem2' | ||
const props = { message: 'Aihop!' } | ||
const props2 = { message: 'Auhip!' } | ||
@@ -52,2 +54,9 @@ describe('TunnelState', () => { | ||
}) | ||
it('allows to retrieve an array of props when there are multiple items', () => { | ||
const state = new TunnelState() | ||
state.setTunnelProps(TUNNEL_ID, ITEM_ID, props) | ||
state.setTunnelProps(TUNNEL_ID, ITEM_ID2, props2) | ||
expect(state.getTunnelProps(TUNNEL_ID)).toEqual([props, props2]) | ||
}) | ||
}) |
Sorry, the diff of this file is not supported yet
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
184462
641