-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
189 lines (169 loc) · 5.98 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
// Generated by CoffeeScript 2.3.2
// 
// # Component
// ###### 0.3 kB Pure Stateful Styled Components
// ## Installation
// ```sh
// npm install --save @playframe/component
// ```
// ## Description
// Pure Functional Styled Web Components for
// [PlayFrame](https://github.com/playframe/playframe). Components are
// rendered independetly from the rest of the app. By using
// [Shadow DOM](https://developers.google.com/web/fundamentals/web-components/shadowdom)
// provided by
// [ShaDOM](https://github.com/playframe/shadom)
// we achieve scoped styling and simple css selectors.
// Please consider using
// [CSS Variables](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables)
// for maximum animation performance and flexibility.
// You can create instances manually and keep them in parent state or
// you can register them with `fp.use` or `h.use` and create them dynamically.
// To be able to identify the same dynamic component we use a unique
// object `mkey` as a
// [WeakMap](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap)
// key. For a `UserView` Component actual `user` object would be a perfect
// WeakMap key
// ## Usage
// ```js
// import h from '@playframe/h'
// import oversync from '@playframe/oversync'
// import component from '@playframe/component'
// const sync = oversync(Date.now, requestAnimationFrame)
// const Component = component(sync)
// export default myCounter = (Component)=>
// Component({
// seconds: 0,
// _: {
// reset: ()=> {seconds: 0}
// increment: (x, state)=> {
// state.seconds++
// setTimeout( state._.increment,
// (1000 - Date.now() % 1000) || 1000 )
// }
// }
// })((state)=>
// <my-counter style={ {'--border': state.border} }>
// <style>{`
// :host {
// display: block;
// border: var(--border, 0);
// }
// `}</style>
// <div>
// {props.children}
// <br/>
// {state.seconds} seconds passed
// <br/>
// <button onclick={state._.reset}> Reset </button>
// </div>
// </my-counter>
// )
// // our Counter instance with initial props
// const MyCounter = myCounter(Component)({seconds: 42})
// // reset in 10 seconds
// setTimeout(MyCounter._.reset, 10000)
// const view = ()=>
// <MyCounter border="1px solid grey">
// <h1>Hello</h1>
// </MyCounter>
// // or we can register component as custom element
// h.use({'my-counter': (props)=>
// let mkey = props && props.mkey
// makeMyCounter(Component)({mkey})(props)
// })
// // mkey is used as WeakMap key to cache our statefull component
// const mkey = {uniqueObject: true}
// const view = ()=>
// <my-counter mkey={mkey} border="1px solid grey">Hello</my-counter>
// ```
// ## Annotated Source
// We are going to use [statue](https://github.com/playframe/statue)
// for managing state of our Component
var evolve, statue;
evolve = require('@playframe/evolve');
statue = require('@playframe/statue');
// How about using a tree of
// [WeakMap](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap)
// instances to cache our Component instances by `mkey`?
// This allows us to cache our components aggresively because our `_cache`
// will be cleaned automatically by Garbage Collector if `mkey` gets dereferenced
// Let's export a higher order function that takes `sync` engine,
// `state_actions` for statue and a pure `view` function.
module.exports = (sync) => {
return (state_actions) => {
return (view) => {
var _cache;
_cache = new WeakMap;
return (upgrade) => {
var Component, _props, _rendering, _state, _v_dom, mkey, patch_shadow, render;
if ((mkey = upgrade && upgrade.mkey) && (Component = _cache.get(mkey))) {
return Component;
}
_v_dom = null;
_props = null;
_rendering = false;
_state = evolve(state_actions, upgrade);
// Creating a statue that will deliver the latest state on
// `sync.render` and patch shadow DOM if needed
_state = statue(_state, sync.render, (state) => {
_state = state;
if (!_rendering) {
patch_shadow();
}
_rendering = false;
});
// `patch_shadow` is responsible for producing new virtual DOM and using
// `patch` method for shadow DOM mutation provided by
// [ShaDOM](https://github.com/playframe/shadom).
patch_shadow = () => {
var patch;
({patch} = _v_dom);
_v_dom = view(_state);
_v_dom.patch = patch;
patch(_v_dom);
};
render = () => {
var attr;
_v_dom = view(_state);
attr = _v_dom[1] || (_v_dom[1] = {});
attr.attachShadow || (attr.attachShadow = {
mode: 'open'
});
};
// Here we create our `Component` function that mimics your `view`
// function. But first it's checking if `props` are meant to update `_state`
Component = (props) => {
var k, v;
if (_v_dom) {
if (props !== _props) {
// shallow equality check
for (k in props) {
v = props[k];
if (!(v !== _state[k])) {
continue;
}
// updating state with props and rendering
_state = _state._(_props = props);
_rendering = true;
render();
break; // first run
}
}
} else {
_state = Object.assign(_state._(), _props = props);
render();
}
return _v_dom;
};
// Assigning high level methods from statue, adding instance to cache and our
// fresh `Component` is ready!
Component._ = _state._;
if (mkey) {
_cache.set(mkey, Component);
}
return Component;
};
};
};
};