diff --git a/base/__tests__/inferno/callbag/index.tsx b/base/__tests__/inferno/callbag/index.tsx index 83c636ab..e421519f 100644 --- a/base/__tests__/inferno/callbag/index.tsx +++ b/base/__tests__/inferno/callbag/index.tsx @@ -2,9 +2,16 @@ import { createElement } from 'inferno-create-element' import { withEffects, Handler, - ObservableComponent + ObservableComponent, + PropEffect } from '../../../../packages/refract-inferno-callbag/src' -import aperture, { Effect, Props } from '../../react/callbag/aperture' +import { + aperture, + toPropsAperture, + asPropsAperture, + Effect, + Props +} from '../../react/callbag/aperture' import { mount } from 'enzyme' describe('refract-inferno-callbag', () => { @@ -80,4 +87,53 @@ describe('refract-inferno-callbag', () => { type: 'Stop' }) }) + + it('should map props to wrapped component', () => { + interface Props { + prop: string + } + interface ChildProps { + newProp: string + } + const BaseComponent = jest.fn().mockReturnValue(
) + const hander = () => () => void 0 + const WithEffects = withEffects(hander)( + asPropsAperture + )(BaseComponent) + + mount( + // @ts-ignore + + ) + + const props = BaseComponent.mock.calls[0][0] + + expect(props.prop).toBeUndefined() + expect(props.newProp).toBe('hello world') + }) + + it('should add props to wrapped component', () => { + interface Props { + prop: string + } + interface ChildProps { + prop: string + newProp: string + } + const BaseComponent = jest.fn().mockReturnValue(
) + const hander = () => () => void 0 + const WithEffects = withEffects(hander)( + toPropsAperture + )(BaseComponent) + + mount( + // @ts-ignore + + ) + + const props = BaseComponent.mock.calls[0][0] + + expect(props.prop).toBe('hello') + expect(props.newProp).toBe('hello world') + }) }) diff --git a/base/__tests__/inferno/most/index.tsx b/base/__tests__/inferno/most/index.tsx index 7334aeca..2264f0d1 100644 --- a/base/__tests__/inferno/most/index.tsx +++ b/base/__tests__/inferno/most/index.tsx @@ -2,9 +2,16 @@ import { createElement } from 'inferno-create-element' import { withEffects, Handler, - ObservableComponent + ObservableComponent, + PropEffect } from '../../../../packages/refract-inferno-most/src' -import aperture, { Effect, Props } from '../../react/most/aperture' +import { + aperture, + toPropsAperture, + asPropsAperture, + Effect, + Props +} from '../../react/most/aperture' import { mount } from 'enzyme' describe('refract-inferno-most', () => { @@ -80,4 +87,53 @@ describe('refract-inferno-most', () => { type: 'Stop' }) }) + + it('should map props to wrapped component', () => { + interface Props { + prop: string + } + interface ChildProps { + newProp: string + } + const BaseComponent = jest.fn().mockReturnValue(
) + const hander = () => () => void 0 + const WithEffects = withEffects(hander)( + asPropsAperture + )(BaseComponent) + + mount( + // @ts-ignore + + ) + + const props = BaseComponent.mock.calls[0][0] + + expect(props.prop).toBeUndefined() + expect(props.newProp).toBe('hello world') + }) + + it('should add props to wrapped component', () => { + interface Props { + prop: string + } + interface ChildProps { + prop: string + newProp: string + } + const BaseComponent = jest.fn().mockReturnValue(
) + const hander = () => () => void 0 + const WithEffects = withEffects(hander)( + toPropsAperture + )(BaseComponent) + + mount( + // @ts-ignore + + ) + + const props = BaseComponent.mock.calls[0][0] + + expect(props.prop).toBe('hello') + expect(props.newProp).toBe('hello world') + }) }) diff --git a/base/__tests__/inferno/rxjs/index.tsx b/base/__tests__/inferno/rxjs/index.tsx index 532bfa75..49f9bb20 100644 --- a/base/__tests__/inferno/rxjs/index.tsx +++ b/base/__tests__/inferno/rxjs/index.tsx @@ -2,9 +2,16 @@ import { createElement } from 'inferno-create-element' import { withEffects, Handler, - ObservableComponent + ObservableComponent, + PropEffect } from '../../../../packages/refract-inferno-rxjs/src' -import aperture, { Effect, Props } from '../../react/rxjs/aperture' +import { + aperture, + toPropsAperture, + asPropsAperture, + Effect, + Props +} from '../../react/rxjs/aperture' import { mount } from 'enzyme' describe('refract-inferno-rxjs', () => { @@ -80,4 +87,53 @@ describe('refract-inferno-rxjs', () => { type: 'Stop' }) }) + + it('should map props to wrapped component', () => { + interface Props { + prop: string + } + interface ChildProps { + newProp: string + } + const BaseComponent = jest.fn().mockReturnValue(
) + const hander = () => () => void 0 + const WithEffects = withEffects(hander)( + asPropsAperture + )(BaseComponent) + + mount( + // @ts-ignore + + ) + + const props = BaseComponent.mock.calls[0][0] + + expect(props.prop).toBeUndefined() + expect(props.newProp).toBe('hello world') + }) + + it('should add props to wrapped component', () => { + interface Props { + prop: string + } + interface ChildProps { + prop: string + newProp: string + } + const BaseComponent = jest.fn().mockReturnValue(
) + const hander = () => () => void 0 + const WithEffects = withEffects(hander)( + toPropsAperture + )(BaseComponent) + + mount( + // @ts-ignore + + ) + + const props = BaseComponent.mock.calls[0][0] + + expect(props.prop).toBe('hello') + expect(props.newProp).toBe('hello world') + }) }) diff --git a/base/__tests__/inferno/xstream/index.tsx b/base/__tests__/inferno/xstream/index.tsx index d2df4fe5..110deb61 100644 --- a/base/__tests__/inferno/xstream/index.tsx +++ b/base/__tests__/inferno/xstream/index.tsx @@ -2,9 +2,16 @@ import { createElement } from 'inferno-create-element' import { withEffects, Handler, - ObservableComponent + ObservableComponent, + PropEffect } from '../../../../packages/refract-inferno-xstream/src' -import aperture, { Effect, Props } from '../../react/xstream/aperture' +import { + aperture, + toPropsAperture, + asPropsAperture, + Effect, + Props +} from '../../react/xstream/aperture' import { mount } from 'enzyme' describe('refract-inferno-xstream', () => { @@ -80,4 +87,53 @@ describe('refract-inferno-xstream', () => { type: 'Stop' }) }) + + it('should map props to wrapped component', () => { + interface Props { + prop: string + } + interface ChildProps { + newProp: string + } + const BaseComponent = jest.fn().mockReturnValue(
) + const hander = () => () => void 0 + const WithEffects = withEffects(hander)( + asPropsAperture + )(BaseComponent) + + mount( + // @ts-ignore + + ) + + const props = BaseComponent.mock.calls[0][0] + + expect(props.prop).toBeUndefined() + expect(props.newProp).toBe('hello world') + }) + + it('should add props to wrapped component', () => { + interface Props { + prop: string + } + interface ChildProps { + prop: string + newProp: string + } + const BaseComponent = jest.fn().mockReturnValue(
) + const hander = () => () => void 0 + const WithEffects = withEffects(hander)( + toPropsAperture + )(BaseComponent) + + mount( + // @ts-ignore + + ) + + const props = BaseComponent.mock.calls[0][0] + + expect(props.prop).toBe('hello') + expect(props.newProp).toBe('hello world') + }) }) diff --git a/base/__tests__/preact/callbag/index.tsx b/base/__tests__/preact/callbag/index.tsx index 13038341..8e9b3408 100644 --- a/base/__tests__/preact/callbag/index.tsx +++ b/base/__tests__/preact/callbag/index.tsx @@ -4,7 +4,7 @@ import { Handler, ObservableComponent } from '../../../../packages/refract-preact-callbag/src' -import aperture, { Effect, Props } from '../../react/callbag/aperture' +import { aperture, Effect, Props } from '../../react/callbag/aperture' import { mount } from 'enzyme' describe('refract-preact-callbag', () => { diff --git a/base/__tests__/preact/most/index.tsx b/base/__tests__/preact/most/index.tsx index 8d38779e..6afd2092 100644 --- a/base/__tests__/preact/most/index.tsx +++ b/base/__tests__/preact/most/index.tsx @@ -4,7 +4,7 @@ import { Handler, ObservableComponent } from '../../../../packages/refract-preact-most/src' -import aperture, { Effect, Props } from '../../react/most/aperture' +import { aperture, Effect, Props } from '../../react/most/aperture' import { mount } from 'enzyme' describe('refract-preact-most', () => { diff --git a/base/__tests__/preact/rxjs/index.tsx b/base/__tests__/preact/rxjs/index.tsx index 66787c17..52f157e3 100644 --- a/base/__tests__/preact/rxjs/index.tsx +++ b/base/__tests__/preact/rxjs/index.tsx @@ -4,7 +4,7 @@ import { Handler, ObservableComponent } from '../../../../packages/refract-preact-rxjs/src' -import aperture, { Effect, Props } from '../../react/rxjs/aperture' +import { aperture, Effect, Props } from '../../react/rxjs/aperture' import { mount } from 'enzyme' describe('refract-preact-rxjs', () => { diff --git a/base/__tests__/preact/xstream/index.tsx b/base/__tests__/preact/xstream/index.tsx index 950ccf52..354ad57a 100644 --- a/base/__tests__/preact/xstream/index.tsx +++ b/base/__tests__/preact/xstream/index.tsx @@ -4,7 +4,7 @@ import { Handler, ObservableComponent } from '../../../../packages/refract-preact-xstream/src' -import aperture, { Effect, Props } from '../../react/xstream/aperture' +import { aperture, Effect, Props } from '../../react/xstream/aperture' import { mount } from 'enzyme' describe('refract-preact-xstream', () => { diff --git a/base/__tests__/react/callbag/aperture.ts b/base/__tests__/react/callbag/aperture.ts index 4dff1c9f..2bf9a268 100644 --- a/base/__tests__/react/callbag/aperture.ts +++ b/base/__tests__/react/callbag/aperture.ts @@ -1,6 +1,11 @@ -import { merge, map } from 'callbag-basics' +import { merge, map, pipe } from 'callbag-basics' -import { Aperture } from '../../../../packages/refract-callbag/src' +import { + Aperture, + toProps, + asProps, + PropEffect +} from '../../../../packages/refract-callbag/src' export interface Effect { type: string @@ -12,7 +17,7 @@ export interface Props { setValue: (value: number) => void } -const aperture: Aperture = props => component => { +export const aperture: Aperture = props => component => { const value$ = component.observe('value') const valueSet$ = component.observe('setValue') const mount$ = component.mount @@ -44,4 +49,33 @@ const aperture: Aperture = props => component => { ) } -export default aperture +export interface SourceProps { + prop: string +} +interface SinkProps { + newProp: string +} + +export const asPropsAperture: Aperture< + SourceProps, + PropEffect +> = () => component => + pipe( + component.observe(), + map(({ prop }) => ({ + newProp: `${prop} world` + })), + map(asProps) + ) + +export const toPropsAperture: Aperture< + SourceProps, + PropEffect +> = () => component => + pipe( + component.observe(), + map(({ prop }) => ({ + newProp: `${prop} world` + })), + map(toProps) + ) diff --git a/base/__tests__/react/callbag/index.tsx b/base/__tests__/react/callbag/index.tsx index 4045371e..47de3066 100644 --- a/base/__tests__/react/callbag/index.tsx +++ b/base/__tests__/react/callbag/index.tsx @@ -2,9 +2,16 @@ import * as React from 'react' import { withEffects, Handler, - ObservableComponent + ObservableComponent, + PropEffect } from '../../../../packages/refract-callbag/src' -import aperture, { Effect, Props } from './aperture' +import { + aperture, + toPropsAperture, + asPropsAperture, + Effect, + Props +} from './aperture' import { mount } from 'enzyme' describe('refract-callbag', () => { @@ -79,4 +86,46 @@ describe('refract-callbag', () => { type: 'Stop' }) }) + + it('should map props to wrapped component', () => { + interface Props { + prop: string + } + interface ChildProps { + newProp: string + } + const BaseComponent = jest.fn().mockReturnValue(
) + const hander = () => () => void 0 + const WithEffects = withEffects(hander)( + asPropsAperture + )(BaseComponent) + + mount() + + const props = BaseComponent.mock.calls[0][0] + + expect(props.prop).toBeUndefined() + expect(props.newProp).toBe('hello world') + }) + + it('should add props to wrapped component', () => { + interface Props { + prop: string + } + interface ChildProps { + prop: string + newProp: string + } + const BaseComponent = jest.fn().mockReturnValue(
) + const hander = () => () => void 0 + const WithEffects = withEffects(hander)( + toPropsAperture + )(BaseComponent) + + mount() + + const props = BaseComponent.mock.calls[0][0] + expect(props.prop).toBe('hello') + expect(props.newProp).toBe('hello world') + }) }) diff --git a/base/__tests__/react/most/aperture.ts b/base/__tests__/react/most/aperture.ts index 22ed3fe2..adeb0bba 100644 --- a/base/__tests__/react/most/aperture.ts +++ b/base/__tests__/react/most/aperture.ts @@ -1,6 +1,11 @@ import { merge } from 'most' -import { Aperture } from '../../../../packages/refract-most/src' +import { + Aperture, + toProps, + asProps, + PropEffect +} from '../../../../packages/refract-most/src' export interface Effect { type: string @@ -12,7 +17,7 @@ export interface Props { setValue: (value: number) => void } -const aperture: Aperture = props => component => { +export const aperture: Aperture = props => component => { const value$ = component.observe('value') const valueSet$ = component.observe('setValue') const mount$ = component.mount @@ -44,4 +49,31 @@ const aperture: Aperture = props => component => { ) } -export default aperture +export interface SourceProps { + prop: string +} +interface SinkProps { + newProp: string +} + +export const asPropsAperture: Aperture< + SourceProps, + PropEffect +> = () => component => + component + .observe() + .map(({ prop }) => ({ + newProp: `${prop} world` + })) + .map(asProps) + +export const toPropsAperture: Aperture< + SourceProps, + PropEffect +> = () => component => + component + .observe() + .map(({ prop }) => ({ + newProp: `${prop} world` + })) + .map(toProps) diff --git a/base/__tests__/react/most/index.tsx b/base/__tests__/react/most/index.tsx index ab24844f..9a9f116b 100644 --- a/base/__tests__/react/most/index.tsx +++ b/base/__tests__/react/most/index.tsx @@ -2,9 +2,16 @@ import * as React from 'react' import { withEffects, Handler, - ObservableComponent + ObservableComponent, + PropEffect } from '../../../../packages/refract-most/src' -import aperture, { Effect, Props } from './aperture' +import { + aperture, + toPropsAperture, + asPropsAperture, + Effect, + Props +} from './aperture' import { mount } from 'enzyme' describe('refract-most', () => { @@ -79,4 +86,46 @@ describe('refract-most', () => { type: 'Stop' }) }) + + it('should map props to wrapped component', () => { + interface Props { + prop: string + } + interface ChildProps { + newProp: string + } + const BaseComponent = jest.fn().mockReturnValue(
) + const hander = () => () => void 0 + const WithEffects = withEffects(hander)( + asPropsAperture + )(BaseComponent) + + mount() + + const props = BaseComponent.mock.calls[0][0] + + expect(props.prop).toBeUndefined() + expect(props.newProp).toBe('hello world') + }) + + it('should add props to wrapped component', () => { + interface Props { + prop: string + } + interface ChildProps { + prop: string + newProp: string + } + const BaseComponent = jest.fn().mockReturnValue(
) + const hander = () => () => void 0 + const WithEffects = withEffects(hander)( + toPropsAperture + )(BaseComponent) + + mount() + + const props = BaseComponent.mock.calls[0][0] + expect(props.prop).toBe('hello') + expect(props.newProp).toBe('hello world') + }) }) diff --git a/base/__tests__/react/rxjs/aperture.ts b/base/__tests__/react/rxjs/aperture.ts index 08508bb2..1cf70388 100644 --- a/base/__tests__/react/rxjs/aperture.ts +++ b/base/__tests__/react/rxjs/aperture.ts @@ -1,11 +1,17 @@ -import { map, mapTo, concat } from 'rxjs/operators' +import { map, mapTo } from 'rxjs/operators' import { merge } from 'rxjs' -import { Aperture } from '../../../../packages/refract-rxjs/src' +import { + Aperture, + toProps, + asProps, + PropEffect +} from '../../../../packages/refract-rxjs/src' export interface Effect { type: string value?: number + payload?: object } export interface Props { @@ -13,7 +19,7 @@ export interface Props { setValue: (value: number) => void } -const aperture: Aperture = props => component => { +export const aperture: Aperture = props => component => { const value$ = component.observe('value') const valueSet$ = component.observe('setValue') const mount$ = component.mount @@ -55,4 +61,31 @@ const aperture: Aperture = props => component => { ) } -export default aperture +export interface SourceProps { + prop: string +} +interface SinkProps { + newProp: string +} + +export const asPropsAperture: Aperture< + SourceProps, + PropEffect +> = () => component => + component.observe().pipe( + map(({ prop }) => ({ + newProp: `${prop} world` + })), + map(asProps) + ) + +export const toPropsAperture: Aperture< + SourceProps, + PropEffect +> = () => component => + component.observe().pipe( + map(({ prop }) => ({ + newProp: `${prop} world` + })), + map(toProps) + ) diff --git a/base/__tests__/react/rxjs/index.tsx b/base/__tests__/react/rxjs/index.tsx index 1b3c38c0..aad0fc02 100644 --- a/base/__tests__/react/rxjs/index.tsx +++ b/base/__tests__/react/rxjs/index.tsx @@ -2,9 +2,16 @@ import * as React from 'react' import { withEffects, Handler, - ObservableComponent + ObservableComponent, + PropEffect } from '../../../../packages/refract-rxjs/src' -import aperture, { Effect, Props } from './aperture' +import { + aperture, + toPropsAperture, + asPropsAperture, + Effect, + Props +} from './aperture' import { mount } from 'enzyme' describe('refract-rxjs', () => { @@ -32,9 +39,7 @@ describe('refract-rxjs', () => {
)) - const component = mount( - React.createElement(WithEffects, { value: 1, setValue }) - ) + const component = mount() expect(component.prop('value')).toBe(1) expect(effectValueHandler).toHaveBeenCalledWith({ @@ -79,4 +84,47 @@ describe('refract-rxjs', () => { type: 'Stop' }) }) + + it('should map props to wrapped component', () => { + interface Props { + prop: string + } + interface ChildProps { + newProp: string + } + const BaseComponent = jest.fn().mockReturnValue(
) + const hander = () => () => void 0 + const WithEffects = withEffects(hander)( + asPropsAperture + )(BaseComponent) + + mount() + + const props = BaseComponent.mock.calls[0][0] + + expect(props.prop).toBeUndefined() + expect(props.newProp).toBe('hello world') + }) + + it('should add props to wrapped component', () => { + interface Props { + prop: string + } + interface ChildProps { + prop: string + newProp: string + } + const BaseComponent = jest.fn().mockReturnValue(
) + const hander = () => () => void 0 + const WithEffects = withEffects(hander)( + toPropsAperture + )(BaseComponent) + + mount() + + const props = BaseComponent.mock.calls[0][0] + + expect(props.prop).toBe('hello') + expect(props.newProp).toBe('hello world') + }) }) diff --git a/base/__tests__/react/xstream/aperture.ts b/base/__tests__/react/xstream/aperture.ts index 7806f632..1b7afa07 100644 --- a/base/__tests__/react/xstream/aperture.ts +++ b/base/__tests__/react/xstream/aperture.ts @@ -1,5 +1,10 @@ import xs from 'xstream' -import { Aperture } from '../../../../packages/refract-xstream/src' +import { + Aperture, + toProps, + asProps, + PropEffect +} from '../../../../packages/refract-xstream/src' export interface Effect { type: string @@ -11,7 +16,7 @@ export interface Props { setValue: (value: number) => void } -const aperture: Aperture = props => component => { +export const aperture: Aperture = props => component => { const value$ = component.observe('value') const valueSet$ = component.observe('setValue') const mount$ = component.mount @@ -43,4 +48,31 @@ const aperture: Aperture = props => component => { ) } -export default aperture +export interface SourceProps { + prop: string +} +interface SinkProps { + newProp: string +} + +export const asPropsAperture: Aperture< + SourceProps, + PropEffect +> = () => component => + component + .observe() + .map(({ prop }) => ({ + newProp: `${prop} world` + })) + .map(asProps) + +export const toPropsAperture: Aperture< + SourceProps, + PropEffect +> = () => component => + component + .observe() + .map(({ prop }) => ({ + newProp: `${prop} world` + })) + .map(toProps) diff --git a/base/__tests__/react/xstream/index.tsx b/base/__tests__/react/xstream/index.tsx index 73f68b80..3edcf1fa 100644 --- a/base/__tests__/react/xstream/index.tsx +++ b/base/__tests__/react/xstream/index.tsx @@ -2,9 +2,16 @@ import * as React from 'react' import { withEffects, Handler, - ObservableComponent + ObservableComponent, + PropEffect } from '../../../../packages/refract-xstream/src' -import aperture, { Effect, Props } from './aperture' +import { + aperture, + toPropsAperture, + asPropsAperture, + Effect, + Props +} from './aperture' import { mount } from 'enzyme' describe('refract-xstream', () => { @@ -79,4 +86,46 @@ describe('refract-xstream', () => { type: 'Stop' }) }) + + it('should map props to wrapped component', () => { + interface Props { + prop: string + } + interface ChildProps { + newProp: string + } + const BaseComponent = jest.fn().mockReturnValue(
) + const hander = () => () => void 0 + const WithEffects = withEffects(hander)( + asPropsAperture + )(BaseComponent) + + mount() + + const props = BaseComponent.mock.calls[0][0] + + expect(props.prop).toBeUndefined() + expect(props.newProp).toBe('hello world') + }) + + it('should add props to wrapped component', () => { + interface Props { + prop: string + } + interface ChildProps { + prop: string + newProp: string + } + const BaseComponent = jest.fn().mockReturnValue(
) + const hander = () => () => void 0 + const WithEffects = withEffects(hander)( + toPropsAperture + )(BaseComponent) + + mount() + + const props = BaseComponent.mock.calls[0][0] + expect(props.prop).toBe('hello') + expect(props.newProp).toBe('hello world') + }) }) diff --git a/base/react/configureComponent.ts b/base/react/configureComponent.ts index d385c590..17d64302 100644 --- a/base/react/configureComponent.ts +++ b/base/react/configureComponent.ts @@ -1,4 +1,5 @@ import { Listeners, Handler, ErrorHandler, PushEvent } from './baseTypes' +import { PROPS_EFFECT } from './effects' import { Subscription, createObservable, @@ -11,6 +12,33 @@ const configureComponent = ( handler: Handler, errorHandler?: ErrorHandler

) => (aperture: Aperture, instance: any) => { + instance.state = { + children: null + } + + const setState = state => { + if (instance.unmounted) { + return + } + if (instance.mounted) { + instance.setState(state) + } else { + instance.state = state + } + } + + const finalHandler = initialProps => { + const effectHandler = handler(initialProps) + + return effect => { + if (effect && effect.type === PROPS_EFFECT) { + setState(effect.payload) + } else { + effectHandler(effect) + } + } + } + const listeners: Listeners = { mount: [], unmount: [], @@ -111,7 +139,7 @@ const configureComponent = ( const sinkSubscription: Subscription = subscribeToSink( sinkObservable, - handler(instance.props), + finalHandler(instance.props), errorHandler ? errorHandler(instance.props) : undefined ) @@ -152,9 +180,19 @@ const configureComponent = ( } instance.getChildProps = () => { - const { children, ...props } = instance.props + const { props = {}, replace } = instance.state + + if (replace === true) { + return Object.assign({}, props, { + pushEvent + }) + } else if (replace === false) { + return Object.assign({}, instance.props, decoratedProps, props, { + pushEvent + }) + } - return Object.assign({}, props, decoratedProps, { + return Object.assign({}, instance.props, decoratedProps, { pushEvent }) } diff --git a/base/react/effects.ts b/base/react/effects.ts new file mode 100644 index 00000000..5e9e1038 --- /dev/null +++ b/base/react/effects.ts @@ -0,0 +1,25 @@ +export const PROPS_EFFECT: string = '@@refract/effect/props' + +export interface PropEffect

{ + type: string + payload: { + replace: boolean + props: P + } +} + +export const toProps =

(props: P): PropEffect

=> ({ + type: PROPS_EFFECT, + payload: { + replace: false, + props + } +}) + +export const asProps =

(props: P): PropEffect

=> ({ + type: PROPS_EFFECT, + payload: { + replace: true, + props + } +}) diff --git a/base/react/index.ts b/base/react/index.ts index 7c350f23..dd47a491 100644 --- a/base/react/index.ts +++ b/base/react/index.ts @@ -2,6 +2,7 @@ import { withEffects } from './withEffects' import { ObservableComponent, Aperture } from './observable' import { ErrorHandler, Handler } from './baseTypes' import { compose, Compose } from './compose' +import { asProps, toProps, PROPS_EFFECT, PropEffect } from './effects' export { withEffects, @@ -10,5 +11,9 @@ export { Handler, ErrorHandler, compose, - Compose + Compose, + asProps, + toProps, + PropEffect, + PROPS_EFFECT } diff --git a/base/react/observable_callbag.ts b/base/react/observable_callbag.ts index ed3acd65..6c93ce8e 100644 --- a/base/react/observable_callbag.ts +++ b/base/react/observable_callbag.ts @@ -14,7 +14,7 @@ export interface Subscription { } export interface ObservableComponent { - observe: (propName: string) => Source + observe: (propName?: string) => Source event: (eventName: string) => Source mount: Source unmount: Source diff --git a/base/react/observable_most.ts b/base/react/observable_most.ts index 76624696..d08203c4 100644 --- a/base/react/observable_most.ts +++ b/base/react/observable_most.ts @@ -4,7 +4,7 @@ import $$observable from 'symbol-observable' export { Listener } export interface ObservableComponent { - observe: (propName: string) => Stream + observe: (propName?: string) => Stream event: (eventName: string) => Stream mount: Stream unmount: Stream diff --git a/base/react/observable_xstream.ts b/base/react/observable_xstream.ts index f58a3c42..96ba9414 100644 --- a/base/react/observable_xstream.ts +++ b/base/react/observable_xstream.ts @@ -3,7 +3,7 @@ import xs, { Stream, Listener, Subscription } from 'xstream' export { Listener, Subscription } export interface ObservableComponent { - observe: (propName: string) => Stream + observe: (propName?: string) => Stream event: (eventName: string) => Stream mount: Stream unmount: Stream diff --git a/base/react/withEffects.ts b/base/react/withEffects.ts index 483da88d..ff0325b9 100644 --- a/base/react/withEffects.ts +++ b/base/react/withEffects.ts @@ -5,18 +5,20 @@ import configureComponent from './configureComponent' import { Handler, ErrorHandler, PushEvent } from './baseTypes' import { Aperture } from './observable' -export const withEffects = ( +export const withEffects = ( handler: Handler, errorHandler?: ErrorHandler

) => (aperture: Aperture) => ( - BaseComponent: React.ComponentType

+ BaseComponent: React.ComponentType ): React.ComponentClass

=> class WithEffects extends React.PureComponent

{ private triggerMount: () => void private triggerUnmount: () => void private reDecorateProps: (nextProps: P) => void private pushProps: (props: P) => void - private getChildProps: () => P & { pushEvent: PushEvent } + private getChildProps: () => CP & { pushEvent: PushEvent } + private mounted: boolean = false + private unmounted: boolean = false constructor(props: any, context: any) { super(props, context) @@ -25,6 +27,7 @@ export const withEffects = ( } public componentDidMount() { + this.mounted = true this.triggerMount() } @@ -37,14 +40,11 @@ export const withEffects = ( } public componentWillUnmount() { + this.unmounted = true this.triggerUnmount() } public render() { - return React.createElement( - BaseComponent, - this.getChildProps(), - this.props.children - ) + return React.createElement(BaseComponent, this.getChildProps()) } } diff --git a/base/react/withEffects_inferno.ts b/base/react/withEffects_inferno.ts index 890eccce..5e96ad51 100644 --- a/base/react/withEffects_inferno.ts +++ b/base/react/withEffects_inferno.ts @@ -6,18 +6,20 @@ import configureComponent from './configureComponent' import { Handler, ErrorHandler, PushEvent } from './baseTypes' import { Aperture } from './observable' -export const withEffects = ( +export const withEffects = ( handler: Handler, errorHandler?: ErrorHandler

) => (aperture: Aperture) => ( - BaseComponent: ComponentType

+ BaseComponent: ComponentType ): ComponentClass

=> class WithEffects extends Component

{ private triggerMount: () => void private triggerUnmount: () => void private reDecorateProps: (nextProps: P) => void private pushProps: (props: P) => void - private getChildProps: () => P & { pushEvent: PushEvent } + private getChildProps: () => CP & { pushEvent: PushEvent } + private mounted: boolean = false + private unmounted: boolean = false constructor(props: any, context: any) { super(props, context) @@ -26,6 +28,7 @@ export const withEffects = ( } public componentDidMount() { + this.mounted = true this.triggerMount() } @@ -38,14 +41,11 @@ export const withEffects = ( } public componentWillUnmount() { + this.unmounted = true this.triggerUnmount() } public render() { - return createElement( - BaseComponent, - this.getChildProps(), - this.props.children - ) + return createElement(BaseComponent, this.getChildProps()) } } diff --git a/base/react/withEffects_preact.ts b/base/react/withEffects_preact.ts index db0b6c1b..52659dd7 100644 --- a/base/react/withEffects_preact.ts +++ b/base/react/withEffects_preact.ts @@ -5,18 +5,20 @@ import configureComponent from './configureComponent' import { Handler, ErrorHandler, PushEvent } from './baseTypes' import { Aperture } from './observable' -export const withEffects = ( +export const withEffects = ( handler: Handler, errorHandler?: ErrorHandler

) => (aperture: Aperture) => ( - BaseComponent: ComponentFactory

+ BaseComponent: ComponentFactory ): ComponentFactory

=> class WithEffects extends Component

{ private triggerMount: () => void private triggerUnmount: () => void private reDecorateProps: (nextProps: P) => void private pushProps: (props: P) => void - private getChildProps: () => P & { pushEvent: PushEvent } + private getChildProps: () => CP & { pushEvent: PushEvent } + private mounted: boolean = false + private unmounted: boolean = false constructor(props: P) { super(props) @@ -25,6 +27,7 @@ export const withEffects = ( } public componentDidMount() { + this.mounted = true this.triggerMount() } @@ -37,10 +40,11 @@ export const withEffects = ( } public componentWillUnmount() { + this.unmounted = true this.triggerUnmount() } public render() { - return h(BaseComponent, this.getChildProps(), this.props.children) + return h(BaseComponent, this.getChildProps()) } } diff --git a/scripts/copy.js b/scripts/copy.js index e3454bcc..c00ce3b0 100644 --- a/scripts/copy.js +++ b/scripts/copy.js @@ -11,6 +11,7 @@ const getPackages = require('../packages') const filesPerBaseDir = { react: [ 'baseTypes.ts', + 'effects.ts', 'index.ts', ({ mainLib }) => ({ src: `withEffects${mainLib === 'react' ? '' : `_${mainLib}`}.ts`,