Skip to content

Commit 3dcbeb5

Browse files
committed
Merge PR #1912: Update uhtml frameworks
2 parents 47411b8 + bd6529f commit 3dcbeb5

17 files changed

+594
-907
lines changed

frameworks/keyed/uhtml/package-lock.json

Lines changed: 161 additions & 351 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frameworks/keyed/uhtml/package.json

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
{
22
"name": "js-framework-benchmark-uhtml",
3-
"version": "1.0.0",
43
"description": "uhtml demo",
5-
"main": "index.js",
64
"type": "module",
75
"js-framework-benchmark": {
86
"frameworkVersionFromPackage": "uhtml",
@@ -29,13 +27,12 @@
2927
},
3028
"homepage": "https://github.com/krausest/js-framework-benchmark#readme",
3129
"dependencies": {
32-
"js-framework-benchmark-utils": "^0.4.0",
33-
"uhtml": "^4.7.0"
30+
"uhtml": "^5.0.3"
3431
},
3532
"devDependencies": {
3633
"@rollup/plugin-node-resolve": "15.3.0",
3734
"@rollup/plugin-terser": "0.4.4",
3835
"rollup": "4.28.1",
39-
"rollup-plugin-html-literals": "1.1.8"
36+
"rollup-plugin-minify-template-literals": "^1.1.7"
4037
}
4138
}
Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import minifyHTML from "rollup-plugin-html-literals";
1+
import minifyHTML from "rollup-plugin-minify-template-literals";
22
import { nodeResolve } from "@rollup/plugin-node-resolve";
33
import terser from "@rollup/plugin-terser";
44

@@ -7,19 +7,21 @@ const isProduction = process.env.BUILD === "production";
77
/** @type {import('rollup').RollupOptions} */
88
export default {
99
input: "src/index.js",
10-
output: {
11-
esModule: true,
12-
file: "dist/index.js",
13-
},
1410
plugins: [
1511
minifyHTML({
1612
options: {
1713
minifyOptions: {
14+
ignoreCustomComments: [/^!/],
1815
keepClosingSlash: true,
16+
caseSensitive: true,
1917
},
2018
},
2119
}),
2220
nodeResolve(),
2321
isProduction && terser(),
2422
],
23+
output: {
24+
esModule: true,
25+
file: "dist/index.js",
26+
},
2527
};

frameworks/keyed/uhtml/src/index.js

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
1-
import {State} from 'js-framework-benchmark-utils';
2-
import {html, htmlFor, render} from 'uhtml/keyed';
3-
4-
import Jumbotron from './jumbotron.js';
5-
import Table from './table.js';
6-
7-
const state = State(Table, false, htmlFor);
8-
9-
render(document.getElementById('container'), html`
10-
<div class="container">
11-
${Jumbotron(state)}
12-
${Table(state)}
13-
<span class="preloadicon glyphicon glyphicon-remove" aria-hidden="true" />
14-
</div>
15-
`);
1+
import { html, render, signal } from 'uhtml';
2+
3+
import Table from './table.js';
4+
import Jumbotron from './jumbotron.js';
5+
import { handle } from './utils.js';
6+
7+
const App = ({ title, data }) => html`
8+
<div class="container">
9+
<!-- direct, non reactive, component -->
10+
${Jumbotron({ title, data })}
11+
<!-- reactive component -->
12+
<${Table} ...${{ data, select: handle('select'), remove: handle('remove') }} />
13+
<span class="preloadicon glyphicon glyphicon-remove" aria-hidden="true" />
14+
</div>
15+
`;
16+
17+
render(document.getElementById('container'), App({
18+
title: 'µhtml keyed',
19+
data: signal([], { greedy: true })
20+
}));
21+

frameworks/keyed/uhtml/src/jumbotron.js

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,55 @@
1-
import {html} from 'uhtml/keyed';
1+
import { html } from 'uhtml';
22

3-
export default ({run, runLots, add, update, clear, swapRows}) => html`
3+
import { create } from './utils.js';
4+
5+
// the Jumbotron can be used as component, even if it has no effect/subscription
6+
export default ({ title, data }) => html`
47
<div class="jumbotron">
58
<div class="row">
69
<div class="col-md-6">
7-
<h1>µhtml keyed</h1>
10+
<h1 .textContent=${title} />
811
</div>
912
<div class="col-md-6">
1013
<div class="row">
1114
<div class="col-sm-6 smallpad">
12-
<button type="button" class="btn btn-primary btn-block"
13-
id="run" onclick=${run}>Create 1,000 rows</button>
15+
<button id="run" type="button" class="btn btn-primary btn-block"
16+
onclick=${() => data.value = create(1_000)}
17+
>Create 1,000 rows</button>
1418
</div>
1519
<div class="col-sm-6 smallpad">
16-
<button type="button" class="btn btn-primary btn-block"
17-
id="runlots" onclick=${runLots}>Create 10,000 rows</button>
20+
<button id="runlots" type="button" class="btn btn-primary btn-block"
21+
onclick=${() => data.value = create(10_000)}
22+
>Create 10,000 rows</button>
1823
</div>
1924
<div class="col-sm-6 smallpad">
20-
<button type="button" class="btn btn-primary btn-block"
21-
id="add" onclick=${add}>Append 1,000 rows</button>
25+
<button id="add" type="button" class="btn btn-primary btn-block"
26+
onclick=${() => data.value = create(1_000, true)}
27+
>Append 1,000 rows</button>
2228
</div>
2329
<div class="col-sm-6 smallpad">
24-
<button type="button" class="btn btn-primary btn-block"
25-
id="update" onclick=${update}>Update every 10th row</button>
30+
<button id="update" type="button" class="btn btn-primary btn-block"
31+
onclick=${() => {
32+
const rows = create(-1);
33+
for (let i = 0; i < rows.length; i += 10) rows[i].label += ' !!!';
34+
data.value = rows;
35+
}}
36+
>Update every 10th row</button>
2637
</div>
2738
<div class="col-sm-6 smallpad">
28-
<button type="button" class="btn btn-primary btn-block"
29-
id="clear" onclick=${clear}>Clear</button>
39+
<button id="clear" type="button" class="btn btn-primary btn-block"
40+
onclick=${() => data.value = create(0)}
41+
>Clear</button>
3042
</div>
3143
<div class="col-sm-6 smallpad">
32-
<button type="button" class="btn btn-primary btn-block"
33-
id="swaprows" onclick=${swapRows}>Swap Rows</button>
44+
<button id="swaprows" type="button" class="btn btn-primary btn-block"
45+
onclick=${() => {
46+
const rows = create(-1);
47+
if (998 < rows.length) {
48+
[rows[1], rows[998]] = [rows[998], rows[1]];
49+
data.value = rows;
50+
}
51+
}}
52+
>Swap Rows</button>
3453
</div>
3554
</div>
3655
</div>

frameworks/keyed/uhtml/src/table-delegate.js

Lines changed: 0 additions & 34 deletions
This file was deleted.

frameworks/keyed/uhtml/src/table-tr.js

Lines changed: 0 additions & 40 deletions
This file was deleted.

frameworks/keyed/uhtml/src/table.js

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,22 @@
1-
import {htmlFor} from 'uhtml/keyed';
1+
import { html } from 'uhtml';
22

3-
export default (state) => {
4-
const {data, selected, selectRow, removeRow} = state;
5-
return htmlFor(state)`
6-
<table class="table table-hover table-striped test-data" .state=${state}>
7-
<tbody>${
8-
data.map(({id, label, html}) => html`
9-
<tr id=${id} class=${id === selected ? 'danger' : ''}>
10-
<td class="col-md-1">${id}</td>
11-
<td class="col-md-4">
12-
<a onclick=${selectRow}>${label}</a>
13-
</td>
14-
<td class="col-md-1">
15-
<a onclick=${removeRow}>
16-
<span class="glyphicon glyphicon-remove" aria-hidden="true" />
17-
</a>
18-
</td>
19-
<td class="col-md-6" />
20-
</tr>`
21-
)}</tbody>
22-
</table>
23-
`;
24-
};
3+
// Table component: it subscribes to the data signal
4+
// as it relies its array content to change and update rows
5+
export default ({ data, select, remove }) => html`
6+
<table class="table table-hover table-striped test-data">
7+
<tbody>${data.value.map(({ id, label, selected }) => html`
8+
<tr key=${id} id=${id} class=${id === selected ? 'danger' : ''}>
9+
<td class="col-md-1">${id}</td>
10+
<td class="col-md-4">
11+
<a onclick=${select}>${label}</a>
12+
</td>
13+
<td class="col-md-1">
14+
<a onclick=${remove}>
15+
<span class="glyphicon glyphicon-remove" aria-hidden="true" />
16+
</a>
17+
</td>
18+
<td class="col-md-6" />
19+
</tr>
20+
`)}</tbody>
21+
</table>
22+
`;

frameworks/keyed/uhtml/src/utils.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// variant of https://github.com/krausest/js-framework-benchmark/blob/master/frameworks/keyed/vanillajs-lite/src/Main.js
2+
3+
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'];
4+
const colours = ['red', 'yellow', 'blue', 'green', 'pink', 'brown', 'purple', 'brown', 'white', 'black', 'orange'];
5+
const nouns = ['table', 'chair', 'house', 'bbq', 'desk', 'car', 'pony', 'cookie', 'sandwich', 'burger', 'pizza', 'mouse', 'keyboard'];
6+
7+
const { round, random } = Math;
8+
const pick = list => list[round(random() * 1000) % list.length];
9+
const label = () => `${pick(adjectives)} ${pick(colours)} ${pick(nouns)}`;
10+
11+
let TR, ID = 1, SEL = 0, SIZE = 0, DATA = [];
12+
13+
// creats rows but it keep track of created data so
14+
// that it's possible to modify it and reflect next time it's needed
15+
export const create = (count, add) => {
16+
if (count < 1) {
17+
if (count < 0) return DATA;
18+
else TR = null;
19+
}
20+
if (add) count += SIZE;
21+
else DATA = [];
22+
for (let i = add ? SIZE : 0; i < count; i++) {
23+
const id = ID++;
24+
DATA[i] = { id, label: label(), selected: SEL === id };
25+
}
26+
SIZE = count;
27+
return DATA;
28+
};
29+
30+
// create once a handler that keep data state updated
31+
// by selecting something or removing it
32+
export const handle = type => ({ currentTarget }) => {
33+
const tr = currentTarget.closest('tr');
34+
const id = +tr.id;
35+
switch (type) {
36+
case 'select': {
37+
if (SEL === id) return;
38+
if (TR) TR.className = '';
39+
tr.className = 'danger';
40+
TR = tr;
41+
SEL = id;
42+
break;
43+
}
44+
case 'remove': {
45+
if (SEL === id) {
46+
TR = null;
47+
SEL = 0;
48+
}
49+
DATA.splice(DATA.findIndex(row => row.id === id), 1);
50+
SIZE--;
51+
tr.remove();
52+
break;
53+
}
54+
}
55+
};

0 commit comments

Comments
 (0)