Example #1
0
function prepatch(oldVNode: VNode, newVNode: VNode) {
  const animations = newVNode.data.animations as Animations

  const oldChildren = oldVNode.children || []
  const newChildren = newVNode.children || []

  const oldKeys = lift(oldChildren).map(c => c.key || '').toSet().value()
  const newKeys = lift(newChildren).map(c => c.key || '').toSet().value()

  // children making an exit
  oldChildren.forEach(child => {
    if (newKeys[child.key || '']) return

    child.data.hook = child.data.hook || {}

    const otherHook = child.data.hook.remove
    child.data.hook.remove = (vnode: VNode.Assigned, cb: Function) => {
      if (otherHook) otherHook(vnode, noop)
      animations.remove(vnode.elm, cb)
    }
  })

  // children making an entrance
  newChildren.forEach(child => {
    if (oldKeys[child.key || '']) return

    child.data.hook = child.data.hook || {}

    const otherHook = child.data.hook.create
    child.data.hook.create = (emptyNode: {}, vnode: VNode.Assigned) => {
      if (otherHook) otherHook(emptyNode, vnode)
      animations.create(vnode.elm)
    }
  })
}
Example #2
0
  // Translate our RouteDefs into abyssa States
  function transformRouteTree(
    name: string,
    route: RouteDef<RT>,
    parent: RouteDef<RT> | undefined = undefined
  ): State {

    routeByName[name] = route

    route.parent = parent
    route.fullName = name

    const children = route.children
      ? lift(route.children)
          .mapValues((childName, childRoute) => transformRouteTree(`${name}.${childName}`, childRoute, route))
          .value()
      : {}

    return State(route.uri, {
      enter(_, __, router) {
        components.push(
          route.enter(router, currentRoute!))
      },
      update() {
        if (route.update)
          route.update(currentRoute!)
      },
      exit() {
        components.pop()
        if (route.exit)
          route.exit()
      }
    }, children)
  }
Example #3
0
export function startApp<RT extends string>(options: RouterOptions<RT>): void {

  // The lookup of our custom route objects by full name
  const routeByName: Record<string, RouteDef<RT>> = {}

  // The components currently mounted, top-down
  const components: Array<(route: Route<RT>, child: VNode) => VNode> = []

  // The current route in the transition
  let currentRoute: Route<RT> | undefined

  // The current app VNode
  let currentVNode: VNode | undefined

  // Translate our RouteDefs into abyssa States
  function transformRouteTree(
    name: string,
    route: RouteDef<RT>,
    parent: RouteDef<RT> | undefined = undefined
  ): State {

    routeByName[name] = route

    route.parent = parent
    route.fullName = name

    const children = route.children
      ? lift(route.children)
          .mapValues((childName, childRoute) => transformRouteTree(`${name}.${childName}`, childRoute, route))
          .value()
      : {}

    return State(route.uri, {
      enter(_, __, router) {
        components.push(
          route.enter(router, currentRoute!))
      },
      update() {
        if (route.update)
          route.update(currentRoute!)
      },
      exit() {
        components.pop()
        if (route.exit)
          route.exit()
      }
    }, children)
  }


  const rootStates = lift({ app: options.app }).mapValues(transformRouteTree).value()
  const router = AbyssaRouter(rootStates)

  const abyssaOptions = Object.assign({}, options, {
    notFound: options.notFound && options.notFound.fullName
  })

  router.configure(abyssaOptions)

  router.on('started', newState => {
    currentRoute = Object.assign({}, newState, {
      fullName: newState.fullName.replace('app.', ''),
      isIn: (parent: string) => newState.isIn(`app.${ parent }`)
    })
  })

  router.on('ended', () => {
    const newAppNode = components.reduceRight((previous, current) => {
      return current(currentRoute!, previous)
    }, emptyVNode())

    if (currentVNode) {
      Render.into(currentVNode, newAppNode)
    }
    else {
      startKaijuApp({
        app: newAppNode,
        elm: options.elm,
        replaceElm: options.replaceElm,
        snabbdomModules: options.snabbdomModules
      })
    }

    currentVNode = newAppNode
  })

  router.init()
}