Skip to content

Instantly share code, notes, and snippets.

@zheeeng
Created August 6, 2018 12:46
Show Gist options
  • Select an option

  • Save zheeeng/26e18cf9e368b7975c83788781bd807a to your computer and use it in GitHub Desktop.

Select an option

Save zheeeng/26e18cf9e368b7975c83788781bd807a to your computer and use it in GitHub Desktop.
cycle jsx component archive(uncompleted)
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