diff --git a/straylight-v0.3.4-keyed/.babelrc b/straylight-v0.3.4-keyed/.babelrc
new file mode 100644
index 000000000..b25395073
--- /dev/null
+++ b/straylight-v0.3.4-keyed/.babelrc
@@ -0,0 +1,3 @@
+{
+ "presets" : [ "babel-preset-es2015"]
+}
diff --git a/straylight-v0.3.4-keyed/index.html b/straylight-v0.3.4-keyed/index.html
new file mode 100644
index 000000000..af928bee4
--- /dev/null
+++ b/straylight-v0.3.4-keyed/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+ Straylight
+
+
+
+
+
+
+
+
diff --git a/straylight-v0.3.4-keyed/package.json b/straylight-v0.3.4-keyed/package.json
new file mode 100644
index 000000000..ad4c0edb3
--- /dev/null
+++ b/straylight-v0.3.4-keyed/package.json
@@ -0,0 +1,25 @@
+{
+ "name": "js-framework-benchmark-straylight",
+ "version": "1.1.1",
+ "description": "Straylight demo",
+ "main": "index.js",
+ "scripts": {
+ "build-dev": "webpack -w -d",
+ "build-prod": "webpack -p"
+ },
+ "author": "Stefan Krause",
+ "license": "Apache-2.0",
+ "homepage": "https://github.com/krausest/js-framework-benchmark",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/krausest/js-framework-benchmark.git"
+ },
+ "devDependencies": {
+ "babel-core": "6.24.1",
+ "babel-loader": "7.0.0",
+ "babel-preset-es2015": "6.24.1",
+ "storelax": "^0.2.4",
+ "straylight": "^0.3.4",
+ "webpack": "2.5.1"
+ }
+}
diff --git a/straylight-v0.3.4-keyed/src/main.js b/straylight-v0.3.4-keyed/src/main.js
new file mode 100644
index 000000000..ac337a52b
--- /dev/null
+++ b/straylight-v0.3.4-keyed/src/main.js
@@ -0,0 +1,95 @@
+import { html, applyTemplate } from 'straylight';
+import { withKeys } from 'straylight/extras';
+import { store, actions } from './store';
+
+function onActionClick(e) {
+ let { action, id } = e.target.dataset;
+ if (action) {
+ actions[action](id ? parseInt(id) : undefined);
+ }
+}
+
+applyTemplate('#main', html`
+
+
+
+
+
Straylight
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${
+ store.observable.map(({ data, selected }) =>
+ withKeys(data.map(d => [d.id, html`
+
+ | ${d.id} |
+
+ ${d.label}
+ |
+
+
+
+
+ |
+ |
+
+ `]))
+ )
+ }
+
+
+
+
+`);
diff --git a/straylight-v0.3.4-keyed/src/store.js b/straylight-v0.3.4-keyed/src/store.js
new file mode 100644
index 000000000..4c83c11be
--- /dev/null
+++ b/straylight-v0.3.4-keyed/src/store.js
@@ -0,0 +1,150 @@
+import Store from 'storelax';
+
+const timer = {
+ name: null,
+ startTime: null,
+ time(name, fn) {
+ this.start(name);
+ fn();
+ this.stop();
+ },
+ start(name) {
+ this.name = name;
+ this.startTime = performance.now();
+ },
+ stop() {
+ if (this.name) {
+ window.setTimeout(() => {
+ console.log(`${this.name} took ${performance.now() - this.startTime}`);
+ this.name = null;
+ }, 0);
+ }
+ },
+};
+
+export const store = new Store({
+ data: [],
+ selected: undefined,
+ id: 1,
+});
+
+export const actions = {
+ run() {
+ timer.time('run', () => {
+ store.update(({ id }) => {
+ const obj = buildData(id, 1000);
+ return {
+ data: obj.data,
+ id: obj.id,
+ selected: undefined,
+ };
+ });
+ });
+ },
+
+ add() {
+ timer.time('add', () => {
+ store.update(({ id, data }) => {
+ const obj = buildData(id, 1000);
+ return {
+ data: [...data, ...obj.data],
+ id: obj.id,
+ };
+ });
+ });
+ },
+
+ update() {
+ timer.time('update', () => {
+ store.update(({ data }) => {
+ for (let i = 0; i < data.length; i += 10) {
+ data[i].label = data[i].label + ' !!!';
+ }
+ return { data };
+ });
+ });
+ },
+
+ select(id) {
+ timer.time('select', () => {
+ store.update({ selected: id });
+ });
+ },
+
+ delete(id) {
+ timer.time('delete', () => {
+ store.update(({ data }) => {
+ return { data: data.filter(d => d.id != id) };
+ });
+ });
+ },
+
+ runLots() {
+ timer.time('runLots', () => {
+ store.update(({ id, data }) => {
+ const obj = buildData(id, 10000);
+ return {
+ data: obj.data,
+ id: obj.id,
+ selected: undefined,
+ };
+ });
+ });
+ },
+
+ clear() {
+ timer.time('clear', () => {
+ store.update({
+ data: [],
+ selected: undefined,
+ });
+ });
+ },
+
+ swapRows() {
+ timer.time('swapRows', () => {
+ store.update(({ data }) => {
+ if (data.length > 998) {
+ let temp = data[1];
+ data[1] = data[998];
+ data[998] = temp;
+ }
+ return { data };
+ });
+ });
+ },
+};
+
+function random(max) {
+ return Math.round(Math.random() * 1000) % max;
+}
+
+const adjectives = [
+ 'pretty', 'large', 'big', 'small', 'tall', 'short', 'long', 'handsome', 'plain',
+ 'quaint', 'clean', 'elegant', 'easy', 'angry', 'crazy', 'helpful', 'mushy', 'odd',
+ 'unsightly', 'adorable', 'important', 'inexpensive', 'cheap', 'expensive', 'fancy',
+];
+
+const colours = [
+ 'red', 'yellow', 'blue', 'green', 'pink', 'brown', 'purple', 'brown', 'white',
+ 'black', 'orange',
+];
+
+const nouns = [
+ 'table', 'chair', 'house', 'bbq', 'desk', 'car', 'pony', 'cookie', 'sandwich',
+ 'burger', 'pizza', 'mouse', 'keyboard',
+];
+
+export function buildData(id, count = 1000) {
+ let data = [];
+ for (let i = 0; i < count; i++) {
+ data.push({
+ id: id++,
+ label:
+ adjectives[random(adjectives.length)] + ' ' +
+ colours[random(colours.length)] + ' ' +
+ nouns[random(nouns.length)],
+ });
+ }
+ return { data, id };
+}
diff --git a/straylight-v0.3.4-keyed/webpack.config.js b/straylight-v0.3.4-keyed/webpack.config.js
new file mode 100644
index 000000000..2323d74b6
--- /dev/null
+++ b/straylight-v0.3.4-keyed/webpack.config.js
@@ -0,0 +1,36 @@
+'use strict';
+
+var path = require('path');
+
+module.exports = [{
+ cache: {},
+ module: {
+ loaders: [
+ {
+ test: /\.js$/,
+ loader: 'babel-loader'
+ },
+ {
+ test: /\.css$/,
+ loader: 'style-loader!css-loader'
+ }
+ ],
+ },
+ entry: {
+ main: './src/main.js',
+ },
+ output: {
+ path: path.resolve(__dirname, 'dist'),
+ filename: '[name].js'
+ },
+ resolve: {
+ extensions: ['.js'],
+ modules: [
+ __dirname,
+ path.resolve(__dirname, 'src'),
+ 'node_modules'
+ ],
+ alias: {
+ }
+ }
+}];
diff --git a/straylight-v0.3.4-non-keyed/.babelrc b/straylight-v0.3.4-non-keyed/.babelrc
new file mode 100755
index 000000000..b25395073
--- /dev/null
+++ b/straylight-v0.3.4-non-keyed/.babelrc
@@ -0,0 +1,3 @@
+{
+ "presets" : [ "babel-preset-es2015"]
+}
diff --git a/straylight-v0.3.4-non-keyed/index.html b/straylight-v0.3.4-non-keyed/index.html
new file mode 100644
index 000000000..af928bee4
--- /dev/null
+++ b/straylight-v0.3.4-non-keyed/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+ Straylight
+
+
+
+
+
+
+
+
diff --git a/straylight-v0.3.4-non-keyed/package.json b/straylight-v0.3.4-non-keyed/package.json
new file mode 100644
index 000000000..ad4c0edb3
--- /dev/null
+++ b/straylight-v0.3.4-non-keyed/package.json
@@ -0,0 +1,25 @@
+{
+ "name": "js-framework-benchmark-straylight",
+ "version": "1.1.1",
+ "description": "Straylight demo",
+ "main": "index.js",
+ "scripts": {
+ "build-dev": "webpack -w -d",
+ "build-prod": "webpack -p"
+ },
+ "author": "Stefan Krause",
+ "license": "Apache-2.0",
+ "homepage": "https://github.com/krausest/js-framework-benchmark",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/krausest/js-framework-benchmark.git"
+ },
+ "devDependencies": {
+ "babel-core": "6.24.1",
+ "babel-loader": "7.0.0",
+ "babel-preset-es2015": "6.24.1",
+ "storelax": "^0.2.4",
+ "straylight": "^0.3.4",
+ "webpack": "2.5.1"
+ }
+}
diff --git a/straylight-v0.3.4-non-keyed/src/main.js b/straylight-v0.3.4-non-keyed/src/main.js
new file mode 100644
index 000000000..008cd91d5
--- /dev/null
+++ b/straylight-v0.3.4-non-keyed/src/main.js
@@ -0,0 +1,94 @@
+import { html, applyTemplate } from 'straylight';
+import { store, actions } from './store';
+
+function onActionClick(e) {
+ let { action, id } = e.target.dataset;
+ if (action) {
+ actions[action](id ? parseInt(id) : undefined);
+ }
+}
+
+applyTemplate('#main', html`
+
+
+
+
+
Straylight
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${
+ store.observable.map(({ data, selected }) =>
+ data.map(d => html`
+
+ | ${d.id} |
+
+ ${d.label}
+ |
+
+
+
+
+ |
+ |
+
+ `)
+ )
+ }
+
+
+
+
+`);
diff --git a/straylight-v0.3.4-non-keyed/src/store.js b/straylight-v0.3.4-non-keyed/src/store.js
new file mode 100644
index 000000000..4c83c11be
--- /dev/null
+++ b/straylight-v0.3.4-non-keyed/src/store.js
@@ -0,0 +1,150 @@
+import Store from 'storelax';
+
+const timer = {
+ name: null,
+ startTime: null,
+ time(name, fn) {
+ this.start(name);
+ fn();
+ this.stop();
+ },
+ start(name) {
+ this.name = name;
+ this.startTime = performance.now();
+ },
+ stop() {
+ if (this.name) {
+ window.setTimeout(() => {
+ console.log(`${this.name} took ${performance.now() - this.startTime}`);
+ this.name = null;
+ }, 0);
+ }
+ },
+};
+
+export const store = new Store({
+ data: [],
+ selected: undefined,
+ id: 1,
+});
+
+export const actions = {
+ run() {
+ timer.time('run', () => {
+ store.update(({ id }) => {
+ const obj = buildData(id, 1000);
+ return {
+ data: obj.data,
+ id: obj.id,
+ selected: undefined,
+ };
+ });
+ });
+ },
+
+ add() {
+ timer.time('add', () => {
+ store.update(({ id, data }) => {
+ const obj = buildData(id, 1000);
+ return {
+ data: [...data, ...obj.data],
+ id: obj.id,
+ };
+ });
+ });
+ },
+
+ update() {
+ timer.time('update', () => {
+ store.update(({ data }) => {
+ for (let i = 0; i < data.length; i += 10) {
+ data[i].label = data[i].label + ' !!!';
+ }
+ return { data };
+ });
+ });
+ },
+
+ select(id) {
+ timer.time('select', () => {
+ store.update({ selected: id });
+ });
+ },
+
+ delete(id) {
+ timer.time('delete', () => {
+ store.update(({ data }) => {
+ return { data: data.filter(d => d.id != id) };
+ });
+ });
+ },
+
+ runLots() {
+ timer.time('runLots', () => {
+ store.update(({ id, data }) => {
+ const obj = buildData(id, 10000);
+ return {
+ data: obj.data,
+ id: obj.id,
+ selected: undefined,
+ };
+ });
+ });
+ },
+
+ clear() {
+ timer.time('clear', () => {
+ store.update({
+ data: [],
+ selected: undefined,
+ });
+ });
+ },
+
+ swapRows() {
+ timer.time('swapRows', () => {
+ store.update(({ data }) => {
+ if (data.length > 998) {
+ let temp = data[1];
+ data[1] = data[998];
+ data[998] = temp;
+ }
+ return { data };
+ });
+ });
+ },
+};
+
+function random(max) {
+ return Math.round(Math.random() * 1000) % max;
+}
+
+const adjectives = [
+ 'pretty', 'large', 'big', 'small', 'tall', 'short', 'long', 'handsome', 'plain',
+ 'quaint', 'clean', 'elegant', 'easy', 'angry', 'crazy', 'helpful', 'mushy', 'odd',
+ 'unsightly', 'adorable', 'important', 'inexpensive', 'cheap', 'expensive', 'fancy',
+];
+
+const colours = [
+ 'red', 'yellow', 'blue', 'green', 'pink', 'brown', 'purple', 'brown', 'white',
+ 'black', 'orange',
+];
+
+const nouns = [
+ 'table', 'chair', 'house', 'bbq', 'desk', 'car', 'pony', 'cookie', 'sandwich',
+ 'burger', 'pizza', 'mouse', 'keyboard',
+];
+
+export function buildData(id, count = 1000) {
+ let data = [];
+ for (let i = 0; i < count; i++) {
+ data.push({
+ id: id++,
+ label:
+ adjectives[random(adjectives.length)] + ' ' +
+ colours[random(colours.length)] + ' ' +
+ nouns[random(nouns.length)],
+ });
+ }
+ return { data, id };
+}
diff --git a/straylight-v0.3.4-non-keyed/webpack.config.js b/straylight-v0.3.4-non-keyed/webpack.config.js
new file mode 100644
index 000000000..2323d74b6
--- /dev/null
+++ b/straylight-v0.3.4-non-keyed/webpack.config.js
@@ -0,0 +1,36 @@
+'use strict';
+
+var path = require('path');
+
+module.exports = [{
+ cache: {},
+ module: {
+ loaders: [
+ {
+ test: /\.js$/,
+ loader: 'babel-loader'
+ },
+ {
+ test: /\.css$/,
+ loader: 'style-loader!css-loader'
+ }
+ ],
+ },
+ entry: {
+ main: './src/main.js',
+ },
+ output: {
+ path: path.resolve(__dirname, 'dist'),
+ filename: '[name].js'
+ },
+ resolve: {
+ extensions: ['.js'],
+ modules: [
+ __dirname,
+ path.resolve(__dirname, 'src'),
+ 'node_modules'
+ ],
+ alias: {
+ }
+ }
+}];