react-arbiter
Advanced tools
Comparing version 0.2.0 to 0.3.0
# React Arbiter Changelog | ||
## 0.3.0 | ||
- Added examples to README | ||
- Improved API of `wrapComponent` | ||
## 0.2.0 | ||
@@ -4,0 +9,0 @@ |
import * as React from 'react'; | ||
export interface ArbiterStasisProps { | ||
import { StasisOptions } from '../types'; | ||
export interface ArbiterStasisProps extends StasisOptions { | ||
/** | ||
* Event emitted in case of an error. | ||
*/ | ||
onError?(error: Error): void; | ||
/** | ||
* Place a renderer here to customize the error output. | ||
*/ | ||
renderError?(error: Error): React.ReactNode; | ||
/** | ||
* The children to be placed in the stasis field. | ||
@@ -13,0 +6,0 @@ */ |
@@ -17,8 +17,8 @@ "use strict"; | ||
const { onError } = this.props; | ||
if (typeof onError === 'function') { | ||
onError(error); | ||
} | ||
this.setState({ | ||
error, | ||
}); | ||
if (typeof onError === 'function') { | ||
onError(error); | ||
} | ||
} | ||
@@ -25,0 +25,0 @@ render() { |
@@ -8,2 +8,8 @@ import * as React from 'react'; | ||
} | ||
/** | ||
* Places a component inside a recall. The component is rendered once the recall | ||
* state is changed. | ||
* @param Component The component to render when the recall state changes. | ||
* @param options The options for setting up the recall. | ||
*/ | ||
export declare function withRecall<TProps, TApi>(Component: React.ComponentType<TProps & RecallProps<TApi>>, options: ArbiterOptions<TApi>): React.ComponentType<TProps>; |
@@ -5,2 +5,8 @@ "use strict"; | ||
const components_1 = require("../components"); | ||
/** | ||
* Places a component inside a recall. The component is rendered once the recall | ||
* state is changed. | ||
* @param Component The component to render when the recall state changes. | ||
* @param options The options for setting up the recall. | ||
*/ | ||
function withRecall(Component, options) { | ||
@@ -7,0 +13,0 @@ return props => (React.createElement(components_1.ArbiterRecall, Object.assign({}, options), (loaded, modules, error) => React.createElement(Component, Object.assign({ loaded: loaded, modules: modules, error: error }, props)))); |
@@ -5,2 +5,7 @@ import * as React from 'react'; | ||
} | ||
/** | ||
* Creates a new stasis field that can be placed around components. | ||
* @param Component The component that is rendered in case of an error. | ||
* @param onError The optional callback when an error is emitted. | ||
*/ | ||
export declare function withStasis<TProps>(Component: React.ComponentType<TProps & StasisProps>, onError?: (error: Error) => void): React.ComponentType<TProps>; |
@@ -5,2 +5,7 @@ "use strict"; | ||
const components_1 = require("../components"); | ||
/** | ||
* Creates a new stasis field that can be placed around components. | ||
* @param Component The component that is rendered in case of an error. | ||
* @param onError The optional callback when an error is emitted. | ||
*/ | ||
function withStasis(Component, onError) { | ||
@@ -7,0 +12,0 @@ return props => (React.createElement(components_1.ArbiterStasis, { onError: onError, renderError: error => React.createElement(Component, Object.assign({ error: error }, props, { children: undefined })) }, props.children)); |
@@ -31,2 +31,23 @@ import { ComponentType } from 'react'; | ||
} | ||
export interface StasisOptions { | ||
/** | ||
* Event emitted in case of an error. | ||
*/ | ||
onError?(error: Error): void; | ||
/** | ||
* Place a renderer here to customize the error output. | ||
*/ | ||
renderError?(error: Error): React.ReactNode; | ||
} | ||
export interface WrapOptions<T, K extends keyof T> extends StasisOptions { | ||
/** | ||
* The optional props to be forwarded (i.e., captured) to the wrapped | ||
* component. | ||
*/ | ||
forwardProps?: Pick<T, K>; | ||
/** | ||
* The optional contextTypes to consider for wrapping foreign components. | ||
*/ | ||
contextTypes?: Array<string>; | ||
} | ||
export interface ArbiterOptions<TApi> { | ||
@@ -33,0 +54,0 @@ /** |
import * as React from 'react'; | ||
import { ComponentDefinition } from '../types'; | ||
import { ComponentDefinition, WrapOptions } from '../types'; | ||
/** | ||
@@ -11,2 +11,2 @@ * Wraps the provided component (or rendering function) to a React component | ||
*/ | ||
export declare function wrapComponent<T, K extends keyof T>(value: ComponentDefinition<T>, options?: Pick<T, K>, contextTypes?: Array<string>): React.ComponentType<Exclude<T, K>>; | ||
export declare function wrapComponent<T, K extends keyof T>(value: ComponentDefinition<T>, options?: WrapOptions<T, K>): React.FunctionComponent<Exclude<T, never>> | React.ComponentClass<{}, any>; |
@@ -33,3 +33,3 @@ "use strict"; | ||
// tslint:disable-next-line | ||
ct[key] = () => { }; | ||
ct[key] = () => null; | ||
return ct; | ||
@@ -39,10 +39,10 @@ }, {}), | ||
} | ||
function wrapReactComponent(Component, options) { | ||
return (props) => (React.createElement(components_1.ArbiterStasis, null, | ||
React.createElement(Component, Object.assign({}, props, options)))); | ||
function wrapReactComponent(Component, stasisOptions, componentOptions) { | ||
return (props) => (React.createElement(components_1.ArbiterStasis, Object.assign({}, stasisOptions), | ||
React.createElement(Component, Object.assign({}, props, componentOptions)))); | ||
} | ||
function wrapForeignComponent(render, options, contextTypes) { | ||
function wrapForeignComponent(render, stasisOptions, componentOptions, contextTypes) { | ||
const Component = createForeignComponentContainer(contextTypes); | ||
return (props) => (React.createElement(components_1.ArbiterStasis, null, | ||
React.createElement(Component, Object.assign({}, props, options, { render: render })))); | ||
return (props) => (React.createElement(components_1.ArbiterStasis, Object.assign({}, stasisOptions), | ||
React.createElement(Component, Object.assign({}, props, componentOptions, { render: render })))); | ||
} | ||
@@ -57,3 +57,4 @@ /** | ||
*/ | ||
function wrapComponent(value, options, contextTypes) { | ||
function wrapComponent(value, options = {}) { | ||
const { forwardProps = {}, contextTypes = [] } = options, stasisOptions = __rest(options, ["forwardProps", "contextTypes"]); | ||
if (value) { | ||
@@ -64,11 +65,11 @@ const argAsReact = value; | ||
if (typeof argRender === 'function' || argAsReact.displayName) { | ||
return wrapReactComponent(argAsReact, options); | ||
return wrapReactComponent(argAsReact, stasisOptions, forwardProps); | ||
} | ||
return wrapForeignComponent(argAsRender, options, contextTypes); | ||
return wrapForeignComponent(argAsRender, stasisOptions, forwardProps, contextTypes); | ||
} | ||
else { | ||
console.error('The given value is not a valid component.'); | ||
return wrapForeignComponent(() => { }); | ||
return wrapForeignComponent(() => { }, stasisOptions, forwardProps, contextTypes); | ||
} | ||
} | ||
exports.wrapComponent = wrapComponent; |
import * as React from 'react'; | ||
import { ArbiterStasisProps } from '../components'; | ||
import { StasisOptions } from '../types'; | ||
/** | ||
@@ -10,2 +10,2 @@ * Wraps the given node in a stasis. If a plain HTML element is provided | ||
*/ | ||
export declare function wrapElement(content: React.ReactNode | HTMLElement, options?: ArbiterStasisProps): React.ReactChild; | ||
export declare function wrapElement(content: React.ReactNode | HTMLElement, options?: StasisOptions): React.ReactChild; |
@@ -14,4 +14,4 @@ "use strict"; | ||
if (content instanceof HTMLElement) { | ||
return (React.createElement(components_1.ArbiterStasis, Object.assign({}, options), | ||
React.createElement("div", { ref: host => host && host.appendChild(content) }))); | ||
const htmlNode = content; | ||
content = React.createElement("div", { ref: host => host && host.appendChild(htmlNode) }); | ||
} | ||
@@ -18,0 +18,0 @@ return React.createElement(components_1.ArbiterStasis, Object.assign({}, options), content); |
{ | ||
"name": "react-arbiter", | ||
"version": "0.2.0", | ||
"version": "0.3.0", | ||
"description": "Recall all your modules to extend your SPA dynamically at runtime.", | ||
@@ -54,4 +54,4 @@ "main": "dist/index.js", | ||
"peerDependencies": { | ||
"react": "16.x || 17.x" | ||
"react": "16.x" | ||
} | ||
} |
@@ -18,2 +18,4 @@ # ![React Arbiter](docs/logo.png) | ||
### Recalling Modules | ||
In the simplest case you want to just use the `ArbiterRecall` without any loading special rendering while loading. For this use | ||
@@ -58,6 +60,62 @@ | ||
(tbd) | ||
### Component Stasis | ||
React Arbiter comes with a stasis field for third-party components. This is essentially just an error boundary that helps to prevent any external components destroying the whole application when crashing. | ||
```jsx | ||
const ProtectedComponent = ( | ||
<ArbiterStasis onError={e => console.error(e)}> | ||
<MyCrashingComponent /> | ||
</ArbiterStasis> | ||
); | ||
``` | ||
Furthermore, we can determine what to render when an error occurs: | ||
```jsx | ||
const ProtectedComponent = ( | ||
<ArbiterStasis renderError={e => <div>Display the error: {e.message}</div>}> | ||
<MyCrashingComponent /> | ||
</ArbiterStasis> | ||
); | ||
``` | ||
There is also a HOC to combine the `renderError` with the component to put into a stasis field. | ||
```jsx | ||
const MyStasis = withStasis(({ error, type }) => ( | ||
<div> | ||
<h1>{type}</h1> | ||
<p>Display the error: {error.message}</p> | ||
</div> | ||
)); | ||
const ProtectedComponent = ( | ||
<MyStasis type="Example"> | ||
<MyCrashingComponent /> | ||
</MyStasis> | ||
); | ||
``` | ||
Besides the added `error` prop other props are being forwarded as expected (see, e.g., the `type` prop in the previous example). | ||
### Wrapping Components | ||
React Arbiter also gives you some utilities for wrapping components. For ordinary React components that means just placing them in a stasis field, however, for non-React components (referred to *foreign* components) we also introduce a React wrapper that hosts a DOM node for carrying the foreign component. | ||
```jsx | ||
const MyReactComponent = props => <div>{props.children}</div>; | ||
MyReactComponent.displayName = 'MyReactComponent'; | ||
const MyForeignComponent = (element, props) => { | ||
element.innerHTML = '<b>Hello World!</b>'; | ||
}; | ||
const WrappedReactComponent = wrapComponent(MyReactComponent); | ||
const WrappedForeignComponent = wrapComponent(MyForeignComponent); | ||
``` | ||
Important: The `wrapComponent` only supports React SFCs if they have the `displayName` property properly set (see above). Otherwise, this helper function cannot distinguish between a foreign and a React component and will therefore choose the foreign component. | ||
## License | ||
react-arbiter is released using the MIT license. For more information see the [LICENSE file](LICENSE). |
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
64437
780
120