Skip to content

Commit

Permalink
first experimental source code
Browse files Browse the repository at this point in the history
  • Loading branch information
tinchoz49 committed Mar 17, 2017
0 parents commit 2d6d358
Show file tree
Hide file tree
Showing 11 changed files with 362 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules

npm-debug.log
29 changes: 29 additions & 0 deletions example/components/li.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
const h = require('snabbdom/h').default;

module.exports = function Li({ emitter, props }) {
function store() {
const state = {
value: props.value
};

emitter.on('item:change', () => {
state.value = Date.now();
emitter.emit('self:update');
});

return state;
}

function change() {
emitter.emit('item:change');
}

function view({ state }) {
return h('li', { on: { click: change } }, state.value);
}

return {
store,
view
};
};
45 changes: 45 additions & 0 deletions example/components/list.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
const Li = require('./li');
const h = require('snabbdom/h').default;

module.exports = function List({ emitter, component, props }) {
function store() {
const state = {
items: props.items
};

emitter.on('item:add', (e) => {
state.items.push(e.value);
emitter.emit('self:update');
});

emitter.on('item:remove', () => {
state.items.pop();
emitter.emit('self:update');
});

return state;
}

function add() {
emitter.emit('item:add', { value: Date.now() });
}

function remove() {
emitter.emit('item:remove');
}

const li = component(Li);

function view({ state }) {
return h('div#list', [
h('button', { on: { click: add } }, 'add'),
h('button', { on: { click: remove } }, 'remove'),
h('ul', state.items.map((value, key) => li({ value, key })))
]);
}

return {
store,
view
};
};
42 changes: 42 additions & 0 deletions example/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
const { start } = require('../index');
const List = require('./components/list');
const h = require('snabbdom/h').default;

function App({ emitter, component }) {
function store() {
const state = {
time: Date.now()
};

emitter.on('change:time', (e) => {
state.time = e.time;
emitter.emit('self:update');
});

return state;
}

const change = () => {
emitter.emit('change:time', { time: Date.now() });
};

function view({ state }) {
return h('div#app', [
h('h1', { on: { click: change } }, state.time),
component(List, { items: ['test 1', 'test 2'] })
]);
}

return {
store,
view
};
}

window.addEventListener('DOMContentLoaded', () => {
const container = document.createElement('div');
container.id = 'app';
document.body.insertBefore(container, document.body.firstChild);

start(container, App);
});
23 changes: 23 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const mitt = require('mitt');
const createRenderer = require('./lib/create-renderer');
const { component } = require('./lib/component');

function start(container, createApp, props = {}) {
const render = createRenderer(container);

const emitter = mitt();

emitter.on('self:update', () => {
render({ view, state, props });
});

const { view, store } = createApp({ emitter, component: component(emitter), props });

const state = store();

emitter.emit('self:update');

return emitter;
}

exports.start = start;
61 changes: 61 additions & 0 deletions lib/component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
const mitt = require('mitt');
const give = require('xet');
const curry = require('curry');
const DeepMap = require('./deepmap');
const createRenderer = require('./create-renderer');
const noop = () => {};
const instances = new DeepMap();

function defineHooks(emitter, vnode) {
vnode.data.hook = vnode.data.hook || {};

const userInsert = vnode.data.hook.insert || noop;
const userPostpatch = vnode.data.hook.postpatch || noop;

vnode.data.hook.insert = vnode => {
vnode.emitter = emitter;
userInsert(vnode);
};

vnode.data.hook.postpatch = (oldVnode, vnode) => {
const children = vnode.elm.parentElement.vnode.children;
children[children.indexOf(oldVnode)] = vnode;
userPostpatch(oldVnode, vnode);
};

return vnode;
}

function createComponent(factory, { props = {} }) {
const render = createRenderer();

const emitter = mitt();

emitter.on('self:update', () => {
render({ view, state, props });
});

const { view: userView, store } = factory({ emitter, component: component(emitter), props });

const view = ({ state, props }) => {
return defineHooks(emitter, userView({ state, props }));
};

const state = store();

render({ view, state, props });

return render;
}

const component = curry((emitter, factory, props) => {
const keys = [emitter, component, props.key];

const instance = give.call(instances, keys, () => createComponent(factory, { props }));

return instance.getVnode();
});

exports.defineHooks = defineHooks;
exports.createComponent = createComponent;
exports.component = component;
26 changes: 26 additions & 0 deletions lib/create-renderer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const snabbdom = require('snabbdom');
const patch = snabbdom.init([
require('snabbdom/modules/eventlisteners').default,
require('snabbdom/modules/style').default,
require('./remember-vnode')
], require('./htmldomapi'));

module.exports = function createRenderer(container) {
let vnode = container;

function render({ view, state, props }) {
if (vnode) {
vnode = patch(vnode, view({ state, props }));
} else {
vnode = view({ state, props });
}

return vnode;
}

render.getVnode = () => {
return vnode;
};

return render;
};
79 changes: 79 additions & 0 deletions lib/deepmap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
const give = require('xet');
const root = new WeakMap();
const leaves = new Map();

const deepClear = deepMap => {
if (leaves.has(deepMap)) {
leaves.delete(deepMap);
}

for (let map of deepMap.values()) {
deepClear(map);
}

return deepMap.clear();
};

module.exports = class DeepMap {
constructor(entries = []) {
for (let entry of entries) {
this.set(...entry);
}

root.set(this, new Map());
}

clear() {
return deepClear(this);
}

delete(keys) {
let branch = root.get(this);

for (let key of keys) {
if (branch.has(key)) {
branch = branch.get(key);
} else {
return false;
}
}

return leaves.delete(branch);
}

has(keys) {
let branch = root.get(this);

for (let key of keys) {
if (branch.has(key)) {
branch = branch.get(key);
} else {
return false;
}
}

return leaves.has(branch);
}

get(keys) {
let branch = root.get(this);

for (let key of keys) {
branch = branch.get(key);
}

return leaves.get(branch);
}

set(keys, value) {
let branch = root.get(this);

for (let key of keys) {
branch = give.call(branch, key, () => new Map());
}

leaves.set(branch, value);

return this;
}
};
10 changes: 10 additions & 0 deletions lib/htmldomapi.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const htmldomapi = require('snabbdom/htmldomapi').default;
const removeChild = htmldomapi.removeChild;

htmldomapi.removeChild = (node, child) => {
if (node && child) {
removeChild(node, child);
}
};

module.exports = htmldomapi;
8 changes: 8 additions & 0 deletions lib/remember-vnode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
create(oldVnode, vnode) {
vnode.elm.vnode = vnode;
},
update(oldVnode, vnode) {
vnode.elm.vnode = vnode;
}
};
36 changes: 36 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"name": "snabbmitt",
"version": "0.0.1",
"description": "",
"main": "index.js",
"scripts": {
"test": "eslint .",
"start": "budo example/index.js --live --open"
},
"keywords": [],
"author": "",
"license": "ISC",
"eslintConfig": {
"extends": "postcss",
"env": {
"browser": true,
"node": true
},
"rules": {
"max-len": 0,
"no-use-before-define": 0,
"no-shadow": 0
}
},
"dependencies": {
"curry": "^1.2.0",
"mitt": "^1.1.0",
"snabbdom": "^0.6.6",
"xet": "^1.0.4"
},
"devDependencies": {
"budo": "^9.4.7",
"eslint": "^3.17.1",
"eslint-config-postcss": "^2.0.2"
}
}

0 comments on commit 2d6d358

Please sign in to comment.