Created
August 6, 2018 12:46
-
-
Save zheeeng/26e18cf9e368b7975c83788781bd807a to your computer and use it in GitHub Desktop.
cycle jsx component archive(uncompleted)
This file contains hidden or 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
| import xs, { Stream } from 'xstream' | |
| import isolate from '@cycle/isolate' | |
| import { VNode, vnode } from 'snabbdom/vnode' | |
| import { h } from 'snabbdom' | |
| import { DOMSource } from '@cycle/dom' | |
| export type VDOMType = VNode | string | boolean | null | undefined | |
| export type DOMInstanceType<S extends string> = DOMSource | { [key in S] : DOMSource } | |
| type ComponentSource = { | |
| DOM: DOMSource, | |
| } | |
| type ComponentSink = { | |
| DOM: Stream<VNode>, | |
| } | |
| type ComponentProps = { | |
| [prop: string]: any, | |
| readonly children?: VDOMType[], | |
| } | |
| type ComponentType<SO extends ComponentSource, SI extends {}> = (sources: SO) => SI | |
| interface DOMInstance { | |
| events: DOMSource['events'], | |
| } | |
| type InstanceSink<C extends string> = { | |
| [key in C]: DOMInstance | |
| } | |
| type ToInjectedSinks<C extends string> = Pick<ComponentSink, 'DOM'> & { | |
| instances: InstanceSink<C>, | |
| } | |
| function injectSinks<SO extends ComponentSource, SI extends {}, C extends string> ( | |
| Component: ComponentType<SO, SI>, | |
| DOM: DOMSource, | |
| instanceNames: C[], | |
| ) { | |
| const toInjectedInstancesSink = instanceNames.reduce( | |
| (instances, instanceName) => Object.assign( | |
| instances, | |
| { | |
| [instanceName]: { | |
| events: ( | |
| eventType: any, | |
| option?: any, | |
| ) => DOM.select(`.${instanceName}`).events(eventType, option), | |
| }, | |
| }, | |
| ), | |
| {}, | |
| ) as InstanceSink<C> | |
| const toInjectedSinks: ToInjectedSinks<C> = { | |
| DOM: xs.of(h('')), | |
| instances: toInjectedInstancesSink, | |
| } | |
| return function WithOuterSinksComponent (sources: SO): SI & ToInjectedSinks<C> { | |
| const innerSinks = Component(sources) | |
| return Object.assign({}, innerSinks, toInjectedSinks) | |
| } | |
| } | |
| export type Render<P extends ComponentProps> = (props: P) => VNode | |
| export type RenderComponent<P extends ComponentProps> = (props: Omit<P, 'children'>, children?: VDOMType[]) => VNode | |
| export type HookRender<C extends string, P extends ComponentProps> = (selectors: DOMSelectors<C>) => Render<P> | |
| export interface ChainedComponent< | |
| SO extends ComponentSource, | |
| P extends ComponentProps, | |
| C extends string, | |
| > extends RenderComponent<P> { | |
| scope (scope: any): Scoped<SO, P, C>, | |
| source (sources: SO): Sourced<P, C>, | |
| } | |
| interface Scoped<SO extends ComponentSource, P extends ComponentProps, C extends string> { | |
| source (source: SO): Sourced<P, C>, | |
| } | |
| type Sourced<P extends ComponentProps, C extends string> = { | |
| DOM: Stream<RenderComponent<P>>, | |
| instances: InstanceSink<C>, | |
| } | |
| // type Sourced = (listDOM: FragmentProps) => VNode[] | |
| export default function mobius < | |
| SO extends ComponentSource, | |
| SI extends {} | |
| > (Component: ComponentType<SO, SI>) { | |
| return < | |
| P extends ComponentProps, | |
| C extends string | |
| >(hookRender: HookRender<C, P>, classNames: C[]) => { | |
| const closures = { | |
| scope: undefined as string | undefined, | |
| spiedVnodeSel: undefined as string | undefined, | |
| } | |
| function scopeComponent (scope: any) { | |
| closures.scope = scope | |
| return { source: IsolateComponent } | |
| } | |
| function IsolateComponent (sources: SO): SI & Sourced<P, C> { | |
| const WithOuterSinksComponent = injectSinks(Component, sources.DOM, [...classNames]) | |
| const withStubDOMSinks = isolate( | |
| WithOuterSinksComponent, closures.scope, | |
| )(sources) as SI & { DOM: Stream<VNode>, instances: InstanceSink<C> } | |
| return Object.assign( | |
| {}, | |
| withStubDOMSinks, | |
| { | |
| DOM: withStubDOMSinks.DOM | |
| .map(stubVnode => renderHOC( | |
| hookRender(makeHookClassnames(...classNames)), | |
| stubVnode.sel, | |
| )), | |
| instances: withStubDOMSinks.instances, | |
| }, | |
| ) | |
| } | |
| return Object.assign( | |
| renderHOC(hookRender(makeRenderHookClassnames(...classNames))), | |
| { | |
| scope: scopeComponent, | |
| source: IsolateComponent, | |
| }, | |
| ) as ChainedComponent<SO, P, C> | |
| } | |
| } | |
| export function renderHOC <P extends ComponentProps> ( | |
| DOM: Render<P>, | |
| sel?: string, | |
| ): RenderComponent<P> { | |
| return function PureDOM (props: Omit<P, 'children'>, children: VDOMType[]) { | |
| const componentNode = DOM({ | |
| ...props as any, | |
| children: children.length ? children : [props.children], | |
| }) as VNode | |
| return sel | |
| ? vnode( | |
| componentNode.sel + sel, | |
| componentNode.data, | |
| componentNode.children, | |
| componentNode.text, | |
| componentNode.elm as any, | |
| ) | |
| : componentNode | |
| } | |
| } | |
| export type DOMSelectors<C extends string> = { | |
| [key in C]: string | |
| } | |
| function makeHookSelectors <C extends string> (...classNames: C[]): DOMSelectors<C> { | |
| return classNames.reduce( | |
| (selectors, className) => Object.assign(selectors, { [className]: `.${className}` }), | |
| {} as DOMSelectors<C>, | |
| ) | |
| } | |
| function makeHookClassnames <C extends string> (...classNames: C[]): DOMSelectors<C> { | |
| return classNames.reduce( | |
| (selectors, className) => Object.assign(selectors, { [className]: className }), | |
| {} as DOMSelectors<C>, | |
| ) | |
| } | |
| function makeRenderHookClassnames <C extends string> (...classNames: C[]): DOMSelectors<C> { | |
| return classNames.reduce( | |
| (selectors, className) => Object.assign(selectors, { [className]: '' }), | |
| {} as DOMSelectors<C>, | |
| ) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment