@playframe/playframe v1.0.5
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/playframeUsing UNPKG for es6 bundle:
https://unpkg.com/@playframe/playframe@1.0.2/dist/playframe.min.jsAPI
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