@playframe/playframe
v1.0.5
Published
4 kB 60 fps Functional SPA/PWA Framework
Downloads
3
Readme
4 kB 60 fps Functional SPA/PWA Framework
framesync + React + Redux + router + Shadow Dom alike minimalistic functional framework built to be able to update DOM up to 60 times per second. Components can rerender independently from the rest of the app and only if their local state is changed
High-performance server-side rendering for PWA support is coming soon
SPA Example
import {h, app, mount} from '@playframe/playframe'
app({
// state
counter: 1,
// actions
_: {
inc: (e, state)=> state.counter++, // mutating
dec: (e, {counter})=> ({counter: counter - 1}) // or returning object
}
})( // view
(state)=>
<div>
<h1>Counter: {state.counter}</h1>
<button onclick={state._.inc}>Increment</button>
<button onclick={state._.dec}>Decrement</button>
</div>
}
)( // dom container
mount(document.body)
)
Routed Example
import {h, route, mount} from '@playframe/playframe'
route({
greeting: "Hello",
routes: {
'/': ()=> <a href="/hello/world"><h1>Link</h1></a>,
'/hello/:name': ({state, param})=> <h1>{state.greeting} {param.name}!</h1>,
'/*': ()=> <h1>404</h1>
}
})(
mount(document.body)
)
Installation
Using npm or yarn:
npm i @playframe/playframe
Using UNPKG for es6 bundle:
https://unpkg.com/@playframe/[email protected]/dist/playframe.min.js
API
PlayFrame.app(state_actions)(View)(container)
:
Creates a new app
and mounts it into container
. Initial state_actions
will
create a statue
instance that will be passed into the View
function. If state is modified by
actions, app is rerendered. Returns statue
instance
PlayFrame.route(state_actions)(container)
:
Creates a new routed
app and mounts it into container
. Initial state_actions
should have a routes
property. Returns statue
instance
PlayFrame.mount(domNode)
:
Creates a ShaDOM container for managing DOM mutations
PlayFrame.h(nodeName, attributes, children...)
:
Returns a lightweight Virtual DOM
node. If you are using JSX you might need
["@babel/plugin-transform-react-jsx", { "pragma": "h" }]
. Or you could use
rollup
with buble({jsx: 'h'})
PlayFrame.Component(state_actions)(View)(upgrade)(props)
:
Creates a Stateful Web Component
function for given state_actions
, View
and
upgrade
. upgrade
will extend state_actions
by using
evolve
function. Passing props
to
Component function will return Virtual DOM nodes. Styles are incaplulated by
Shadow Dom.
Example:
const createHover = PlayFrame.Component({
i: 0,
_: {add: (e, state)=> state.i++}
})((state)=>
<my-hover onhover={state._.add}>
<style>{`
:host {
display: block;
border: ${state.i}px;
}
`}</style>
<h6>This was hovered {state.i} time(s)</h6>
</my-hover>
)
let Hover = createHover()
let View = (state)=> <Hover></Hover>
PlayFrame.use(pureComponents)
:
Registering custom elements for Pure Components. Example:
PlayFrame.use({
'custom-heading': (props)=> <h1>{props.children}</h1>
})
const View = ()=> <custom-heading>Hello!</custom-heading>
PlayFrame.reuse(statefulComponents)
:
Registering custom elements for
Stateful Components.
To reuse the same Component
instances we cache them in
WeakMap
by mkey
property which needs to be an object, not a primitive value.
Example:
PlayFrame.reuse({
'my-hover': createHover
})
const hovers = [{}, {}, {}]
const View = (state)=> hovers.map((obj)=>
<my-hover mkey={obj}></my-hover>
)
Internal functions
PlayFrame.statue(state_actions, delayed, subscribe)
:
Creates a statue state machine
for a state_actions
object. delayed
will throttle state updates and
latest state will be passed to subscribe
function. Example:
const state_actions = {
// state
i: 0,
// actions
_: { add: (e, state)=> state.i++ },
subCounter: {
// nested state
i: 0,
// nested actions
_: { add: (e, state)=> state.i++ },
}
}
state = PlayFrame.statue(state_actions, requestIdleCallback, (state)=>
console.log(state)
)
state._.add()
state.subCounter._.add()
// Will log on idle
// {i: 1, subCounter: {i: 1, _: {add}}, _: {add}}
PlayFrame.evolve(base, upgrade)
:
evolve
function for deep object extending. If any value in upgrade
is a function it
will be called with existing value as an argument. Example:
const base = {
i: 1,
j: 2,
onclick: (e)=>{}
}
const upgrade = {
i: 10, // overwrite value
j: (j)=> j * 2, // double existing value
onclick: (onclick)=>(e)=> { // compose functions
console.log('click')
onclick(e); // original handler
}
console.log(PlayFrame.evolve(base, upgrade))
// {i: 10, j: 4, onclick: loggedOnClick}
}
PlayFrame.sync.{next, catch, then, finally, render, frame}
:
Initialized instance of OverSync that helps different parts of framework synchronize execution within the unified frame rendering flow
Source
sync = require('@playframe/oversync') Date.now, requestAnimationFrame
exports.sync = sync
exports.Component = require('@playframe/component') sync
exports.mount = require('@playframe/shadom') sync
router = require('@playframe/router') sync
exports.statue = statue = require '@playframe/statue'
exports.evolve = require '@playframe/evolve'
exports.app = app = (state_actions)=>(view)=>(container)=>
state_actions._ or= {}
state = statue state_actions, sync.finally, (state)=>
container view, state
container view, state
state
exports.route = (state_actions)=> app(state_actions) router
exports.h = h = require '@playframe/h'
exports.use = use = h.use
exports.reuse = (components)=>
purified = {}
for k, Component of components
purified[k] = (props)=>
mkey = props and props.mkey
Component(mkey and {mkey}) props
use purified
return