xatto
Version:
xatto is View Layer Library based on Function and Context using VirtualDOM. This is developed by forking from jorgebucaran/superfine.
106 lines (88 loc) • 2.63 kB
text/typescript
import { Component } from './Component'
import { CONTEXT } from './consts/attributeNames'
import { MIDDLEWARES } from './consts/optionNames'
import { PROPS } from './consts/vNodeAttributeNames'
import { createGlueNodeByElement } from './createGlueNodeByElement'
import { deepGet } from './deepGet'
import { deepSet } from './deepSet'
import { GlueNode } from './GlueNode'
import { mutateProvider } from './mutateProvider'
import { nowaitProvider } from './nowaitProvider'
import { remodelProps } from './remodelProps'
import { rendererProvider } from './rendererProvider'
import { rendering } from './rendering'
/**
* atto
*
* @param view Component
* @param containerOrGlueNode Element | GlueNode
* @param options object default: `{}`
* @return (context: any, path?: string) => void
*/
export function atto (
view: Component,
containerOrGlueNode: Element | GlueNode,
options: any = {}
) {
let scheduled = false
let renderNow = false
let rerender = false
let glueNode =
containerOrGlueNode instanceof Element
? createGlueNodeByElement(containerOrGlueNode)
: (containerOrGlueNode as GlueNode)
const rootProps = remodelProps(glueNode[PROPS])
let rootContext: any = deepGet(rootProps, CONTEXT)
const middlewares = (MIDDLEWARES in options && options[MIDDLEWARES]) || []
const mutate = mutateProvider(getContext, setContext, scheduleRender)
const [nowait, nowaitUnsubscribe] = nowaitProvider(scheduleRender)
const extra = { mutate, nowait }
const rendererProviders = [rendererProvider]
.concat(middlewares)
.map((provider: Function) =>
provider(mutate, getContext, setContext, view, glueNode)
)
function getContext (path: string, def: any = {}) {
return (path ? deepGet(rootContext, path) : rootContext) || def
}
function setContext (newContext: any, path?: string) {
if (path) {
deepSet(rootContext, path, newContext)
} else {
rootContext = newContext
}
}
function render () {
renderNow = true
glueNode = rendering(
glueNode,
view,
extra,
rendererProviders.map((provider) => provider())
)
}
function rendered () {
renderNow = scheduled = false
if (rerender) {
rerender = false
scheduleRender()
} else {
nowaitUnsubscribe()
}
}
function renderedError (e) {
rendered()
throw e
}
function scheduleRender () {
if (!scheduled) {
scheduled = true
Promise.resolve()
.then(render)
.then(rendered, renderedError)
} else if (renderNow) {
rerender = true
}
}
return mutate
}