diff --git a/README.md b/README.md
index b11d707..5ed0e2a 100644
--- a/README.md
+++ b/README.md
@@ -7,11 +7,11 @@ Um, is an experimental composable UI builder that takes ideas from early [hypera
Um, because you should think about, um, NOT using it.
## Features
-- No Virtual Dom
+- Real DOM
+- [Non-destructive (re)Rendering](https://github.com/bryhoyt/emerj)
- No Build System
- No Over Engineering
-- ~1kb minified
-- Totally INEFFICIENT rendering (at scale)
+- ~2kb minified
## Install
@@ -81,4 +81,5 @@ The `h()` is an **optional** hypertext build utility that weighs in around **~25
### TODO
-- Improve Update
+- Some tag attributes do not work, like rowspan on td
+- Rethink State Management, might be ok
diff --git a/index.js b/index.js
index c164ad9..71f7ae3 100644
--- a/index.js
+++ b/index.js
@@ -1,5 +1,5 @@
-import h from "./src/tag.js";
import app from "./src/app.js";
+import h from "./src/tag.js";
export {app};
export {h};
\ No newline at end of file
diff --git a/src/app.js b/src/app.js
index 7e078a4..28d6a2d 100644
--- a/src/app.js
+++ b/src/app.js
@@ -1,3 +1,7 @@
+import diff from "./emerj.js";
+
+/*! Um v0.5.0 | MIT LICENSE | https://github.com/n2geoff/um */
+
/**
* App Builder
*
@@ -54,7 +58,7 @@ export default function app(opts) {
/** update dom */
const update = () => {
- document.querySelector(mount).replaceChildren(view(state, actions));
+ diff.merge(document.querySelector(mount), view(state, actions));
}
// mount view
diff --git a/src/emerj.js b/src/emerj.js
new file mode 100644
index 0000000..378aa7e
--- /dev/null
+++ b/src/emerj.js
@@ -0,0 +1,122 @@
+/*! Emerj v1.0.0 | MIT LICENSE | https://github.com/bryhoyt/emerj */
+export default {
+ attrs(elem) {
+ const attrs = {};
+ for (let i=0; i < elem.attributes.length; i++) {
+ const attr = elem.attributes[i];
+ attrs[attr.name] = attr.value;
+ }
+ return attrs;
+ },
+ nodesByKey(parent, makeKey) {
+ const map = {};
+ for (let j=0; j < parent.childNodes.length; j++) {
+ const key = makeKey(parent.childNodes[j]);
+ if (key) map[key] = parent.childNodes[j];
+ }
+ return map;
+ },
+ merge(base, modified, opts) {
+ /* Merge any differences between base and modified back into base.
+ *
+ * Operates only the children nodes, and does not change the root node or its
+ * attributes.
+ *
+ * Conceptually similar to React's reconciliation algorithm:
+ * https://facebook.github.io/react/docs/reconciliation.html
+ *
+ * I haven't thoroughly tested performance to compare to naive DOM updates (i.e.
+ * just updating the entire DOM from a string using .innerHTML), but some quick
+ * tests on a basic DOMs were twice as fast -- so at least it's not slower in
+ * a simple scenario -- and it's definitely "fast enough" for responsive UI and
+ * even smooth animation.
+ *
+ * The real advantage for me is not so much performance, but that state & identity
+ * of existing elements is preserved -- text typed into an , an open
+ *