Skip to content

secobarbital/cycle-pushstate-driver

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

29 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Cycle PushState Driver

A Cycle.js driver for the History API.

Design Choices

This is a very minimal Cycle.js driver that simply isolates history.pushState calls and popstate events. It makes no assumption about how you want to filter and transform click/touch event streams to come up with the paths to push. Nor will it do e.preventDefault() for you.

In the absence of pushState support it lets the links work as normal links. This means that your preventDefault driver needs to know not to capture these click/touch events.

Finally, it does not currently support history.replaceState or the state argument of pushState

If you prefer a driver that covers all these cases, you may want to consider the TylorS/cycle-history driver which is a batteries-included approach to the same problem.

API

makePushStateDriver ()

Returns a driver that calls history.pushState on the input paths and outputs paths sent to pushState as well as received with popstate events, starting with the current path. If pushState is not supported, this function returns a driver that simply emits the current path.

Install

npm install cycle-pushstate-driver

Usage

Basics:

import Cycle from '@cycle/core'
import { makePushStateDriver } from 'cycle-pushstate-driver'

function main (responses) {
  // ...
}

const drivers = {
  Path: makePushStateDriver()
}

Cycle.run(main, drivers)

Simple use case:

function main({ DOM, Path }) {
  let localLinkClick$ = DOM.select('a').events('click')
    .filter(e => e.currentTarget.host === location.host)

  let navigate$ = localLinkClick$
    .map(e => e.currentTarget.href)

  let vtree$ = Path
    .map(url => {
      switch(url) {
        case '/':
          renderHome()
          break
        case '/user':
          renderUser()
          break
        default:
          render404()
          break
      }
    })

  return {
    DOM: vtree$,
    Path: navigate$,
    preventDefault: localLinkClick$
  };
}

Routing use case with switch-path:

import switchPath from 'switch-path'
import routes from './routes'

function resolve (path) {
  return switchPath(path, routes)
}

function main({ DOM, Path }) {
  const localLinkClick$ = DOM.select('a').events('click')
    .filter(e => e.currentTarget.host === location.host)

  const navigate$ = localLinkClick$
    .map(e => e.currentTarget.href)

  const vtree$ = Path
    .map(resolve)
    .map(({ value }) => value)

  return {
    DOM: vtree$,
    Path: navigate$,
    preventDefault: localLinkClick$
  };
}

Routing use case with wayfarer:

import wayfarer from 'wayfarer'

function route (path$) {
  const route$ = new Rx.ReplaySubject(1)
  const r = name => params => route$.onNext({ name, params })

  const router = wayfarer('/notfound')
  router.on('/', r('owers'))
  router.on('/owers/:ower', r('owees'))
  router.on('/notfound', r('notfound'))

  path$
    .subscribe(
      path => router(path),
      route$.onError.bind(route$),
      route$.onCompleted.bind(route$)
    )
  return route$
}

function main({ DOM, Path }) {
  const Route = route(Path)
  
  const localLinkClick$ = DOM.select('a').events('click')
    .filter(e => e.currentTarget.host === location.host)

  const navigate$ = localLinkClick$
    .map(e => e.currentTarget.href)

  const vtree$ = Rx.Observable.combineLatest(
    Route, owersVtree$, oweesVtree$, notfoundVtree$,
    (route, owersVtree, oweesVtree, notfoundVtree) => {
      const vtrees = {
        'owers': owersVtree,
        'owees': oweesVtree,
        'notfound': notfoundVtree
      }
      return vtrees[route.name]
    }
  )

  return {
    DOM: vtree$,
    Path: navigate$,
    preventDefault: localLinkClick$
  };
}

About

A Cycle.js driver for the History API

Resources

Stars

Watchers

Forks

Packages

No packages published