on master help sign in
Merge pull request #19 from fitzgen/builder

Builder

commit14c6b006b51358670798fe3c1003921f7e46411f authorNick Fitzgerald <fitzgen@gmail.com> dateThu 14 Feb 2019, 09:46 (8 years ago) parent21bafbcaa8d0f9
21 files changed+1376−737
Cargo.lock+59−59 Cargo.toml+6−6 examples/counter/Cargo.toml+3−3 examples/counter/src/lib.rs+18−26 examples/hello-world/Cargo.toml+3−3 examples/hello-world/src/lib.rs+4−11 examples/input-form/Cargo.toml+3−3 examples/input-form/src/lib.rs+28−37 examples/todomvc/Cargo.toml+5−5 examples/todomvc/src/lib.rs+2−2 examples/todomvc/src/todo.rs+70−124 examples/todomvc/src/todos.rs+108−242 src/builder.rs+884 src/cached.rs+4−5 src/lib.rs+24−28 src/node.rs+18−24 src/render.rs+9−1 tests/web/cached.rs+8−6 tests/web/events.rs+23−46 tests/web/main.rs+4−4 tests/web/render.rs+93−102
Cargo.lock+59−59
@@ -66,7 +66,7 @@ version = "0.1.5"
6666source = "registry+https://github.com/rust-lang/crates.io-index"
6767dependencies = [
6868 "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
69− "wasm-bindgen 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
69+ "wasm-bindgen 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
7070]
7171
7272[[package]]
@@ -75,7 +75,7 @@ version = "0.1.2"
7575source = "registry+https://github.com/rust-lang/crates.io-index"
7676dependencies = [
7777 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
78− "web-sys 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
78+ "web-sys 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
7979]
8080
8181[[package]]
@@ -85,12 +85,12 @@ dependencies = [
8585 "bumpalo 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
8686 "console_log 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
8787 "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
88− "js-sys 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
88+ "js-sys 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
8989 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
90− "wasm-bindgen 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
91− "wasm-bindgen-futures 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
92− "wasm-bindgen-test 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
93− "web-sys 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
90+ "wasm-bindgen 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
91+ "wasm-bindgen-futures 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
92+ "wasm-bindgen-test 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
93+ "web-sys 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
9494]
9595
9696[[package]]
@@ -101,9 +101,9 @@ dependencies = [
101101 "console_log 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
102102 "dodrio 0.1.0",
103103 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
104− "wasm-bindgen 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
105− "wasm-bindgen-test 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
106− "web-sys 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
104+ "wasm-bindgen 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
105+ "wasm-bindgen-test 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
106+ "web-sys 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
107107]
108108
109109[[package]]
@@ -112,9 +112,9 @@ version = "0.1.0"
112112dependencies = [
113113 "console_error_panic_hook 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
114114 "dodrio 0.1.0",
115− "wasm-bindgen 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
116− "wasm-bindgen-test 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
117− "web-sys 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
115+ "wasm-bindgen 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
116+ "wasm-bindgen-test 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
117+ "web-sys 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
118118]
119119
120120[[package]]
@@ -123,9 +123,9 @@ version = "0.1.0"
123123dependencies = [
124124 "console_error_panic_hook 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
125125 "dodrio 0.1.0",
126− "wasm-bindgen 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
127− "wasm-bindgen-test 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
128− "web-sys 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
126+ "wasm-bindgen 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
127+ "wasm-bindgen-test 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
128+ "web-sys 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
129129]
130130
131131[[package]]
@@ -137,14 +137,14 @@ dependencies = [
137137 "console_log 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
138138 "dodrio 0.1.0",
139139 "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
140− "js-sys 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
140+ "js-sys 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
141141 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
142142 "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)",
143143 "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
144− "wasm-bindgen 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
145− "wasm-bindgen-futures 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
146− "wasm-bindgen-test 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
147− "web-sys 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
144+ "wasm-bindgen 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
145+ "wasm-bindgen-futures 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
146+ "wasm-bindgen-test 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
147+ "web-sys 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
148148]
149149
150150[[package]]
@@ -207,10 +207,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
207207
208208[[package]]
209209name = "js-sys"
210−version = "0.3.11"
210+version = "0.3.13"
211211source = "registry+https://github.com/rust-lang/crates.io-index"
212212dependencies = [
213− "wasm-bindgen 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
213+ "wasm-bindgen 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
214214]
215215
216216[[package]]
@@ -421,15 +421,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
421421
422422[[package]]
423423name = "wasm-bindgen"
424−version = "0.2.34"
424+version = "0.2.36"
425425source = "registry+https://github.com/rust-lang/crates.io-index"
426426dependencies = [
427− "wasm-bindgen-macro 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
427+ "wasm-bindgen-macro 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
428428]
429429
430430[[package]]
431431name = "wasm-bindgen-backend"
432−version = "0.2.34"
432+version = "0.2.36"
433433source = "registry+https://github.com/rust-lang/crates.io-index"
434434dependencies = [
435435 "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -437,62 +437,62 @@ dependencies = [
437437 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
438438 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
439439 "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
440− "wasm-bindgen-shared 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
440+ "wasm-bindgen-shared 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
441441]
442442
443443[[package]]
444444name = "wasm-bindgen-futures"
445−version = "0.3.11"
445+version = "0.3.13"
446446source = "registry+https://github.com/rust-lang/crates.io-index"
447447dependencies = [
448448 "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
449− "js-sys 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
450− "wasm-bindgen 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
449+ "js-sys 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
450+ "wasm-bindgen 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
451451]
452452
453453[[package]]
454454name = "wasm-bindgen-macro"
455−version = "0.2.34"
455+version = "0.2.36"
456456source = "registry+https://github.com/rust-lang/crates.io-index"
457457dependencies = [
458458 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
459− "wasm-bindgen-macro-support 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
459+ "wasm-bindgen-macro-support 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
460460]
461461
462462[[package]]
463463name = "wasm-bindgen-macro-support"
464−version = "0.2.34"
464+version = "0.2.36"
465465source = "registry+https://github.com/rust-lang/crates.io-index"
466466dependencies = [
467467 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
468468 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
469469 "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
470− "wasm-bindgen-backend 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
471− "wasm-bindgen-shared 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
470+ "wasm-bindgen-backend 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
471+ "wasm-bindgen-shared 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
472472]
473473
474474[[package]]
475475name = "wasm-bindgen-shared"
476−version = "0.2.34"
476+version = "0.2.36"
477477source = "registry+https://github.com/rust-lang/crates.io-index"
478478
479479[[package]]
480480name = "wasm-bindgen-test"
481−version = "0.2.34"
481+version = "0.2.36"
482482source = "registry+https://github.com/rust-lang/crates.io-index"
483483dependencies = [
484484 "console_error_panic_hook 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
485485 "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
486− "js-sys 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
486+ "js-sys 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
487487 "scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
488− "wasm-bindgen 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
489− "wasm-bindgen-futures 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
490− "wasm-bindgen-test-macro 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
488+ "wasm-bindgen 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
489+ "wasm-bindgen-futures 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
490+ "wasm-bindgen-test-macro 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
491491]
492492
493493[[package]]
494494name = "wasm-bindgen-test-macro"
495−version = "0.2.34"
495+version = "0.2.36"
496496source = "registry+https://github.com/rust-lang/crates.io-index"
497497dependencies = [
498498 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -501,7 +501,7 @@ dependencies = [
501501
502502[[package]]
503503name = "wasm-bindgen-webidl"
504−version = "0.2.28"
504+version = "0.2.30"
505505source = "registry+https://github.com/rust-lang/crates.io-index"
506506dependencies = [
507507 "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -510,21 +510,21 @@ dependencies = [
510510 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
511511 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
512512 "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
513− "wasm-bindgen-backend 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
513+ "wasm-bindgen-backend 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
514514 "weedle 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
515515]
516516
517517[[package]]
518518name = "web-sys"
519−version = "0.3.11"
519+version = "0.3.13"
520520source = "registry+https://github.com/rust-lang/crates.io-index"
521521dependencies = [
522522 "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
523523 "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
524− "js-sys 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
524+ "js-sys 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
525525 "sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
526− "wasm-bindgen 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
527− "wasm-bindgen-webidl 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)",
526+ "wasm-bindgen 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
527+ "wasm-bindgen-webidl 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)",
528528]
529529
530530[[package]]
@@ -589,7 +589,7 @@ dependencies = [
589589"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
590590"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114"
591591"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
592−"checksum js-sys 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "838d3c46e859486a1c7d24defa6fb2a4d4a7fc64ab79079a2b8dd6a92b4c327f"
592+"checksum js-sys 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9639a5b9944fc99bc02992f25ac25f8617e81860b0b31f61eb15a1f4fe4b39f3"
593593"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
594594"checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047"
595595"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
@@ -619,16 +619,16 @@ dependencies = [
619619"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
620620"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737"
621621"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
622−"checksum wasm-bindgen 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)" = "0f71ae64fc0c84c202fbaf421f2433a9529adf8ab6b5145fc4bc557da39d006b"
623−"checksum wasm-bindgen-backend 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)" = "a566cfa6bc9802a13a49a89df84b28f2d3ac92e169c1d30fd4fdd800981ba956"
624−"checksum wasm-bindgen-futures 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3408930b9c2bf6658ecc2f4f902b5f36b1ee99d3c288fe593567f595b8ff4081"
625−"checksum wasm-bindgen-macro 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)" = "01869df54a1821867d100eb1c351fad50a10248463c3097e990c3ed0fac7233a"
626−"checksum wasm-bindgen-macro-support 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)" = "1e727ad9d3811bbf0f6d0b8b3cc784169e832ca6ed8a9190587ebfde87893d70"
627−"checksum wasm-bindgen-shared 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)" = "77b13edbe385eb9b3f7f17960f6dbf0adcdb8dac422c7f14a6279426c052336f"
628−"checksum wasm-bindgen-test 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2220139a62fccd897d00f2a3ef953a9fcd2082461bfa50d8a9f9c0c85a6c94"
629−"checksum wasm-bindgen-test-macro 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)" = "12201f5a4fe123303e93efbb1f799e9577312c6e53cb00f6539ace9355b70ad5"
630−"checksum wasm-bindgen-webidl 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)" = "e8acb042c9989ffa6128467193bc7fe046b475a6151b9f31b0cfe7e5b313cc11"
631−"checksum web-sys 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "254e5875171dad18fda43e02054d83bc0699d447b72297110bc7c2a647572416"
622+"checksum wasm-bindgen 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a07590bf415481c15debf0fb459e4ee7bc5f7063b3adf450cea87cfc5451ff"
623+"checksum wasm-bindgen-backend 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "93c3e81841784d407e9ce7a047a88f093861b70584de6ae9072d1c6985de62b8"
624+"checksum wasm-bindgen-futures 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "09c886eacd2ea2662f02daa11bdd836778dfd97b5e7b5320bc7c6c7824835fd5"
625+"checksum wasm-bindgen-macro 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "702fae71b06d1c0527bf920cca51b75b2332aace0be6dc28abb50567f5f8e8d6"
626+"checksum wasm-bindgen-macro-support 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "0bb7feb04fa2c73d0c28579143c4104c7edbb84299f27bbc1dacc0dda3b56e19"
627+"checksum wasm-bindgen-shared 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "d191314b24a75d0798a22632aad4b18ed0098df42d0fcb0f759b394cf3bba02f"
628+"checksum wasm-bindgen-test 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "e403218d15f3a0be08ad984a4b97f4ce4d05f6d3df98ce6708c32f58cdd76286"
629+"checksum wasm-bindgen-test-macro 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "e1feb1af4e075b19eab744a8ed0da087b024ae79afc0b35e49c3ca9a4a1c327b"
630+"checksum wasm-bindgen-webidl 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)" = "142b34c5209bd1b6562b9fee0e4bddd1bebf00717b6cb4ccc9f0a9b3cc9f5f03"
631+"checksum web-sys 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "5cec4b17aece169adf93e8d05919e9ba7fb2156ebcf2280e6b5987868f287600"
632632"checksum weedle 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "26a4c67f132386d965390b8a734d5d10adbcd30eb5cc74bd9229af8b83f10044"
633633"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
634634"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
Cargo.toml+6−6
@@ -10,13 +10,13 @@ default = []
1010[dependencies]
1111bumpalo = "2.1.0"
1212futures = "0.1.25"
13−wasm-bindgen = "0.2.34"
14−wasm-bindgen-futures = "0.3.11"
15−js-sys = "0.3.11"
13+wasm-bindgen = "0.2.36"
14+wasm-bindgen-futures = "0.3.13"
15+js-sys = "0.3.13"
1616log = "0.4.6"
1717
1818[dependencies.web-sys]
19−version = "0.3.11"
19+version = "0.3.13"
2020features = [
2121 "console",
2222 "Document",
@@ -27,11 +27,11 @@ features = [
2727]
2828
2929[dev-dependencies]
30−wasm-bindgen-test = "0.2.34"
30+wasm-bindgen-test = "0.2.36"
3131console_log = "0.1.2"
3232
3333[dev-dependencies.web-sys]
34−version = "0.3.11"
34+version = "0.3.13"
3535features = [
3636 "Attr",
3737 "EventTarget",
examples/counter/Cargo.toml+3−3
@@ -14,10 +14,10 @@ console_error_panic_hook = "0.1.5"
1414console_log = "0.1.2"
1515dodrio = { path = "../.." }
1616log = "0.4.6"
17−wasm-bindgen = "0.2.34"
17+wasm-bindgen = "0.2.36"
1818
1919[dependencies.web-sys]
20−version = "0.3.11"
20+version = "0.3.13"
2121features = [
2222 "console",
2323 "Document",
@@ -30,4 +30,4 @@ features = [
3030]
3131
3232[dev-dependencies]
33−wasm-bindgen-test = "0.2.34"
33+wasm-bindgen-test = "0.2.36"
examples/counter/src/lib.rs+18−26
@@ -1,5 +1,5 @@
11use dodrio::bumpalo::{self, Bump};
2−use dodrio::{on, Node, Render};
2+use dodrio::Render;
33use log::*;
44use wasm_bindgen::prelude::*;
55
@@ -32,19 +32,15 @@ impl Render for Counter {
3232 where
3333 'a: 'bump,
3434 {
35+ use dodrio::builder::*;
36+
3537 // Stringify the count as a bump-allocated string.
3638 let count = bumpalo::format!(in bump, "{}", self.count);
3739
38− Node::element(
39− bump,
40− "div",
41− [],
42− [],
43− [
44− Node::element(
45− bump,
46− "button",
47− [on(bump, "click", |root, vdom, _event| {
40+ div(bump)
41+ .children([
42+ button(bump)
43+ .on("click", |root, vdom, _event| {
4844 // Cast the root render component to a `Counter`, since
4945 // we know that's what it is.
5046 let counter = root.unwrap_mut::<Counter>();
@@ -55,24 +51,20 @@ impl Render for Counter {
5551 // Since the count has updated, we should re-render the
5652 // counter on the next animation frame.
5753 vdom.schedule_render();
58− })],
59− [],
60− [Node::text("+")],
61− ),
62− Node::text(count.into_bump_str()),
63− Node::element(
64− bump,
65− "button",
66− [on(bump, "click", |root, vdom, _event| {
54+ })
55+ .children([text("+")])
56+ .finish(),
57+ text(count.into_bump_str()),
58+ button(bump)
59+ .on("click", |root, vdom, _event| {
6760 // Same as above, but decrementing instead of incrementing.
6861 root.unwrap_mut::<Counter>().decrement();
6962 vdom.schedule_render();
70− })],
71− [],
72− [Node::text("-")],
73− ),
74− ],
75− )
63+ })
64+ .children([text("-")])
65+ .finish(),
66+ ])
67+ .finish()
7668 }
7769}
7870
examples/hello-world/Cargo.toml+3−3
@@ -11,11 +11,11 @@ crate-type = ["cdylib"]
1111
1212[dependencies]
1313dodrio = { path = "../.." }
14−wasm-bindgen = "0.2.34"
14+wasm-bindgen = "0.2.36"
1515console_error_panic_hook = "0.1.5"
1616
1717[dependencies.web-sys]
18−version = "0.3.11"
18+version = "0.3.13"
1919features = [
2020 "Document",
2121 "HtmlElement",
@@ -24,4 +24,4 @@ features = [
2424]
2525
2626[dev-dependencies]
27−wasm-bindgen-test = "0.2.34"
27+wasm-bindgen-test = "0.2.36"
examples/hello-world/src/lib.rs+4−11
@@ -15,17 +15,10 @@ impl<'who> Render for Hello<'who> {
1515 where
1616 'a: 'bump,
1717 {
18− Node::element(
19− bump,
20− // The element's tag name. In this case a `<p>` element.
21− "p",
22− // Event listeners. Empty in this case.
23− [],
24− // Attributes. Again, empty in this case.
25− [],
26− // Child nodes.
27− [Node::text("Hello, "), Node::text(self.who), Node::text("!")],
28− )
18+ use dodrio::builder::*;
19+ p(bump)
20+ .children([text("Hello, "), text(self.who), text("!")])
21+ .finish()
2922 }
3023}
3124
examples/input-form/Cargo.toml+3−3
@@ -11,11 +11,11 @@ crate-type = ["cdylib"]
1111
1212[dependencies]
1313dodrio = { path = "../.." }
14−wasm-bindgen = "0.2.34"
14+wasm-bindgen = "0.2.36"
1515console_error_panic_hook = "0.1.5"
1616
1717[dependencies.web-sys]
18−version = "0.3.11"
18+version = "0.3.13"
1919features = [
2020 "console",
2121 "Document",
@@ -29,4 +29,4 @@ features = [
2929]
3030
3131[dev-dependencies]
32−wasm-bindgen-test = "0.2.34"
32+wasm-bindgen-test = "0.2.36"
examples/input-form/src/lib.rs+28−37
@@ -1,5 +1,5 @@
11use dodrio::bumpalo::{self, Bump};
2−use dodrio::{on, Attribute, Node, Render};
2+use dodrio::{Node, Render};
33use wasm_bindgen::prelude::*;
44use wasm_bindgen::JsCast;
55
@@ -25,48 +25,39 @@ impl SayHelloTo {
2525// The `Render` implementation has a text `<input>` and a `<div>` that shows a
2626// greeting to the `<input>`'s value.
2727impl Render for SayHelloTo {
28− fn render<'a, 'bump>(&'a self, bump: &'bump Bump) -> dodrio::Node<'bump>
28+ fn render<'a, 'bump>(&'a self, bump: &'bump Bump) -> Node<'bump>
2929 where
3030 'a: 'bump,
3131 {
32− let input = Node::element(
33− bump,
34− "input",
35− [on(bump, "input", |root, vdom, event| {
36− // If the event's target is our input...
37− let input = match event
38− .target()
39− .and_then(|t| t.dyn_into::<web_sys::HtmlInputElement>().ok())
40− {
41− None => return,
42− Some(input) => input,
43− };
32+ use dodrio::builder::*;
4433
45− // ...then get its value and update who we are greeting.
46− let value = input.value();
47− let hello = root.unwrap_mut::<SayHelloTo>();
48− hello.set_who(value);
34+ div(bump)
35+ .children([
36+ input(bump)
37+ .attr("type", "text")
38+ .attr("value", &self.who)
39+ .on("input", |root, vdom, event| {
40+ // If the event's target is our input...
41+ let input = match event
42+ .target()
43+ .and_then(|t| t.dyn_into::<web_sys::HtmlInputElement>().ok())
44+ {
45+ None => return,
46+ Some(input) => input,
47+ };
4948
50− // Finally, re-render the component on the next animation frame.
51− vdom.schedule_render();
52− })],
53− [
54− Attribute {
55− name: "type",
56− value: "text",
57− },
58− Attribute {
59− name: "value",
60− value: &self.who,
61− },
62− ],
63− [],
64− );
49+ // ...then get its value and update who we are greeting.
50+ let value = input.value();
51+ let hello = root.unwrap_mut::<SayHelloTo>();
52+ hello.set_who(value);
6553
66− let hello = bumpalo::format!(in bump, "Hello, {}!", self.who);
67− let hello = Node::text(hello.into_bump_str());
68−
69− Node::element(bump, "div", [], [], [input, hello])
54+ // Finally, re-render the component on the next animation frame.
55+ vdom.schedule_render();
56+ })
57+ .finish(),
58+ text(bumpalo::format!(in bump, "Hello, {}!", self.who).into_bump_str()),
59+ ])
60+ .finish()
7061 }
7162}
7263
examples/todomvc/Cargo.toml+5−5
@@ -8,11 +8,11 @@ version = "0.1.0"
88cfg-if = "0.1.6"
99dodrio = { path = "../.." }
1010futures = "0.1.25"
11−js-sys = "0.3.11"
11+js-sys = "0.3.13"
1212serde = { features = ["derive"], version = "1.0.87" }
1313serde_json = "1.0.38"
14−wasm-bindgen = "0.2.34"
15−wasm-bindgen-futures = "0.3.11"
14+wasm-bindgen = "0.2.36"
15+wasm-bindgen-futures = "0.3.13"
1616
1717# Optional dependencies for logging.
1818console_error_panic_hook = { optional = true, version = "0.1.5" }
@@ -20,7 +20,7 @@ console_log = { optional = true, version = "0.1.2" }
2020log = { optional = true, version = "0.4.6" }
2121
2222[dependencies.web-sys]
23−version = "0.3.11"
23+version = "0.3.13"
2424features = [
2525 "Document",
2626 "Event",
@@ -35,7 +35,7 @@ features = [
3535]
3636
3737[dev-dependencies]
38−wasm-bindgen-test = "0.2.34"
38+wasm-bindgen-test = "0.2.36"
3939
4040[features]
4141logging = [
examples/todomvc/src/lib.rs+2−2
@@ -10,9 +10,9 @@ pub mod todos;
1010pub mod utils;
1111pub mod visibility;
1212
13−use controller::Controller;
13+use crate::controller::Controller;
14+use crate::todos::Todos;
1415use dodrio::Vdom;
15−use todos::Todos;
1616use wasm_bindgen::prelude::*;
1717
1818/// Run the TodoMVC app!
examples/todomvc/src/todo.rs+70−124
@@ -1,7 +1,7 @@
11//! Type definition and `dodrio::Render` implementation for a single todo item.
22
33use crate::keys;
4−use dodrio::{bumpalo::Bump, on, Attribute, Node, Render, RootRender, VdomWeak};
4+use dodrio::{bumpalo::Bump, Node, Render, RootRender, VdomWeak};
55use serde::{Deserialize, Serialize};
66use std::marker::PhantomData;
77use wasm_bindgen::{prelude::*, JsCast};
@@ -93,137 +93,83 @@ impl<C> Todo<C> {
9393}
9494
9595impl<C: TodoActions> Render for Todo<C> {
96− fn render<'a, 'bump>(&'a self, bump: &'bump Bump) -> dodrio::Node<'bump>
96+ fn render<'a, 'bump>(&'a self, bump: &'bump Bump) -> Node<'bump>
9797 where
9898 'a: 'bump,
9999 {
100− use dodrio::bumpalo::{self, collections::String};
101−
102− let mut class = String::new_in(bump);
103− if self.completed {
104− class.push_str("completed ");
105− }
106− if self.edits.is_some() {
107− class.push_str("editing");
108− }
100+ use dodrio::{
101+ builder::*,
102+ bumpalo::{self, collections::String},
103+ };
109104
110105 let id = self.id;
111106 let title = self.edits.as_ref().unwrap_or(&self.title);
112− let elem_id = bumpalo::format!(in bump, "todo-{}", id);
113−
114− let mut input_attrs = bumpalo::vec![
115− in bump;
116− Attribute {
117− name: "class",
118− value: "toggle",
119− },
120− Attribute {
121− name: "type",
122− value: "checkbox",
123− }
124− ];
125− if self.completed {
126− input_attrs.push(Attribute {
127− name: "checked",
128− value: "",
129− });
130− }
131− let input_attrs = input_attrs.into_bump_slice();
132−
133− Node::element(
134− bump,
135− "li",
136− [],
137− [Attribute {
138− name: "class",
139− value: class.into_bump_str(),
140− }],
141− [
142− Node::element(
143− bump,
144− "div",
145− [],
146− [Attribute {
147− name: "class",
148− value: "view",
149− }],
150− [
151− Node::element(
152− bump,
153− "input",
154− [on(bump, "click", move |root, vdom, _event| {
107+
108+ li(bump)
109+ .attr("class", {
110+ let mut class = String::new_in(bump);
111+ if self.completed {
112+ class.push_str("completed ");
113+ }
114+ if self.edits.is_some() {
115+ class.push_str("editing");
116+ }
117+ class.into_bump_str()
118+ })
119+ .children([
120+ div(bump)
121+ .attr("class", "view")
122+ .children([
123+ input(bump)
124+ .attr("class", "toggle")
125+ .attr("type", "checkbox")
126+ .bool_attr("checked", self.completed)
127+ .on("click", move |root, vdom, _event| {
155128 C::toggle_completed(root, vdom, id);
156− })],
157− input_attrs,
158− [],
159− ),
160− Node::element(
161− bump,
162− "label",
163− [on(bump, "dblclick", move |root, vdom, _event| {
129+ })
130+ .finish(),
131+ label(bump)
132+ .on("dblclick", move |root, vdom, _event| {
164133 C::begin_editing(root, vdom, id);
165− })],
166− [],
167− [Node::text(title)],
168− ),
169− Node::element(
170− bump,
171− "button",
172− [on(bump, "click", move |root, vdom, _event| {
134+ })
135+ .children([text(title)])
136+ .finish(),
137+ button(bump)
138+ .attr("class", "destroy")
139+ .on("click", move |root, vdom, _event| {
173140 C::delete(root, vdom, id);
174− })],
175− [Attribute {
176− name: "class",
177− value: "destroy",
178− }],
179− [],
180− ),
181− ],
182− ),
183− Node::element(
184− bump,
185− "input",
186− [
187− on(bump, "input", move |root, vdom, event| {
188− let input = event
189− .target()
190− .unwrap_throw()
191− .unchecked_into::<web_sys::HtmlInputElement>();
192− C::update_edits(root, vdom, id, input.value());
193− }),
194− on(bump, "blur", move |root, vdom, _event| {
195− C::finish_edits(root, vdom, id);
196− }),
197− on(bump, "keydown", move |root, vdom, event| {
198− let event = event.unchecked_into::<web_sys::KeyboardEvent>();
199− match event.key_code() {
200− keys::ENTER => C::finish_edits(root, vdom, id),
201− keys::ESCAPE => C::cancel_edits(root, vdom, id),
202− _ => {}
203− }
204− }),
205− ],
206− [
207− Attribute {
208− name: "class",
209− value: "edit",
210− },
211− Attribute {
212− name: "value",
213− value: title,
214− },
215− Attribute {
216− name: "name",
217− value: "title",
218− },
219− Attribute {
220− name: "id",
221− value: elem_id.into_bump_str(),
222− },
223− ],
224− [],
225− ),
226− ],
227− )
141+ })
142+ .finish(),
143+ ])
144+ .finish(),
145+ input(bump)
146+ .attr("class", "edit")
147+ .attr("value", title)
148+ .attr("name", "title")
149+ .attr(
150+ "id",
151+ bumpalo::format!(in bump, "todo-{}", id).into_bump_str(),
152+ )
153+ .on("input", move |root, vdom, event| {
154+ let input = event
155+ .target()
156+ .unwrap_throw()
157+ .unchecked_into::<web_sys::HtmlInputElement>();
158+ C::update_edits(root, vdom, id, input.value());
159+ })
160+ .on("blur", move |root, vdom, _event| {
161+ C::finish_edits(root, vdom, id);
162+ })
163+ .on("keydown", move |root, vdom, event| {
164+ let event = event.unchecked_into::<web_sys::KeyboardEvent>();
165+ match event.key_code() {
166+ keys::ENTER => C::finish_edits(root, vdom, id),
167+ keys::ESCAPE => C::cancel_edits(root, vdom, id),
168+ _ => {}
169+ }
170+ })
171+ .finish(),
172+ ])
173+ .finish()
228174 }
229175}
examples/todomvc/src/todos.rs+108−242
@@ -7,7 +7,7 @@ use crate::visibility::Visibility;
77use crate::{keys, utils};
88use dodrio::{
99 bumpalo::{self, Bump},
10− on, Attribute, Node, Render, RootRender, VdomWeak,
10+ Node, Render, RootRender, VdomWeak,
1111};
1212use serde::{Deserialize, Serialize};
1313use std::marker::PhantomData;
@@ -140,65 +140,42 @@ impl<C: TodosActions> Todos<C> {
140140 where
141141 'a: 'bump,
142142 {
143− Node::element(
144− bump,
145− "header",
146− [],
147− [Attribute {
148− name: "class",
149− value: "header",
150− }],
151− [
152− Node::element(bump, "h1", [], [], [Node::text("todos")]),
153− Node::element(
154− bump,
155− "input",
156− [
157− on(bump, "input", |root, vdom, event| {
158− let input = event
159− .target()
160− .unwrap_throw()
161− .unchecked_into::<web_sys::HtmlInputElement>();
162− C::update_draft(root, vdom, input.value());
163− }),
164− on(bump, "keydown", |root, vdom, event| {
165− let event = event.unchecked_into::<web_sys::KeyboardEvent>();
166− if event.key_code() == keys::ENTER {
167− C::finish_draft(root, vdom);
168− }
169− }),
170− ],
171− [
172− Attribute {
173− name: "class",
174− value: "new-todo",
175− },
176− Attribute {
177− name: "placeholder",
178− value: "What needs to be done?",
179− },
180− Attribute {
181− name: "autofocus",
182− value: "",
183− },
184− Attribute {
185− name: "value",
186− value: &self.draft,
187− },
188− ],
189− [],
190− ),
191− ],
192− )
143+ use dodrio::builder::*;
144+
145+ header(bump)
146+ .attr("class", "header")
147+ .children([
148+ h1(bump).children([text("todos")]).finish(),
149+ input(bump)
150+ .on("input", |root, vdom, event| {
151+ let input = event
152+ .target()
153+ .unwrap_throw()
154+ .unchecked_into::<web_sys::HtmlInputElement>();
155+ C::update_draft(root, vdom, input.value());
156+ })
157+ .on("keydown", |root, vdom, event| {
158+ let event = event.unchecked_into::<web_sys::KeyboardEvent>();
159+ if event.key_code() == keys::ENTER {
160+ C::finish_draft(root, vdom);
161+ }
162+ })
163+ .attr("class", "new-todo")
164+ .attr("placeholder", "What needs to be done?")
165+ .attr("autofocus", "")
166+ .attr("value", &self.draft)
167+ .finish(),
168+ ])
169+ .finish()
193170 }
194171
195172 fn todos_list<'a, 'bump>(&'a self, bump: &'bump Bump) -> Node<'bump>
196173 where
197174 'a: 'bump,
198175 {
199− use dodrio::bumpalo::collections::Vec;
176+ use dodrio::{builder::*, bumpalo::collections::Vec};
200177
201− let mut todos = Vec::new_in(bump);
178+ let mut todos = Vec::with_capacity_in(self.todos.len(), bump);
202179 todos.extend(
203180 self.todos
204181 .iter()
@@ -209,91 +186,43 @@ impl<C: TodosActions> Todos<C> {
209186 })
210187 .map(|t| t.render(bump)),
211188 );
212− let todos = todos.into_bump_slice();
213−
214− let mut input_attrs = bumpalo::vec![
215− in bump;
216− Attribute {
217− name: "class",
218− value: "toggle-all",
219− },
220− Attribute {
221− name: "id",
222− value: "toggle-all",
223− },
224− Attribute {
225− name: "type",
226− value: "checkbox",
227− },
228− Attribute {
229− name: "name",
230− value: "toggle",
231− }
232− ];
233− if self.todos.iter().all(|t| t.is_complete()) {
234− input_attrs.push(Attribute {
235− name: "checked",
236− value: "",
237− });
238− }
239− let input_attrs = input_attrs.into_bump_slice();
240−
241− Node::element(
242− bump,
243− "section",
244− [],
245− [
246− Attribute {
247− name: "class",
248− value: "main",
249− },
250− Attribute {
251− name: "visibility",
252− value: if self.todos.is_empty() {
253− "hidden"
254− } else {
255− "visible"
256− },
189+
190+ section(bump)
191+ .attr("class", "main")
192+ .attr(
193+ "visibility",
194+ if self.todos.is_empty() {
195+ "hidden"
196+ } else {
197+ "visible"
257198 },
258− ],
259− [
260− Node::element(
261− bump,
262− "input",
263− [on(bump, "click", |root, vdom, _event| {
199+ )
200+ .children([
201+ input(bump)
202+ .attr("class", "toggle-all")
203+ .attr("id", "toggle-all")
204+ .attr("type", "checkbox")
205+ .attr("name", "toggle")
206+ .bool_attr("checked", self.todos.iter().all(|t| t.is_complete()))
207+ .on("click", |root, vdom, _event| {
264208 C::toggle_all(root, vdom);
265− })],
266− input_attrs,
267− [],
268− ),
269− Node::element(
270− bump,
271− "label",
272− [],
273− [Attribute {
274− name: "for",
275− value: "toggle-all",
276− }],
277− [Node::text("Mark all as complete")],
278− ),
279− Node::element(
280− bump,
281− "ul",
282− [],
283− [Attribute {
284− name: "class",
285− value: "todo-list",
286− }],
287− todos,
288− ),
289− ],
290− )
209+ })
210+ .finish(),
211+ label(bump)
212+ .attr("for", "toggle-all")
213+ .children([text("Mark all as complete")])
214+ .finish(),
215+ ul(bump).attr("class", "todo-list").children(todos).finish(),
216+ ])
217+ .finish()
291218 }
292219
293220 fn footer<'a, 'bump>(&'a self, bump: &'bump Bump) -> Node<'bump>
294221 where
295222 'a: 'bump,
296223 {
224+ use dodrio::builder::*;
225+
297226 let completed_count = self.todos.iter().filter(|t| t.is_complete()).count();
298227 let incomplete_count = self.todos.len() - completed_count;
299228 let items_left = if incomplete_count == 1 {
@@ -303,95 +232,43 @@ impl<C: TodosActions> Todos<C> {
303232 };
304233 let incomplete_count = bumpalo::format!(in bump, "{}", incomplete_count);
305234
306− let attrs = if self.todos.is_empty() {
307− &bump.alloc([
308− Attribute {
309− name: "class",
310− value: "footer",
311− },
312− Attribute {
313− name: "hidden",
314− value: "",
315− },
316− ])[..]
317− } else {
318− &bump.alloc([Attribute {
319− name: "class",
320− value: "footer",
321− }])[..]
322− };
323−
324235 let clear_completed_text = bumpalo::format!(
325236 in bump,
326237 "Clear completed ({})",
327238 self.todos.iter().filter(|t| t.is_complete()).count()
328239 );
329240
330− Node::element(
331− bump,
332− "footer",
333− [],
334− attrs,
335− [
336− Node::element(
337− bump,
338− "span",
339− [],
340− [Attribute {
341− name: "class",
342− value: "todo-count",
343− }],
344− [
345− Node::element(
346− bump,
347− "strong",
348− [],
349− [],
350− [Node::text(incomplete_count.into_bump_str())],
351− ),
352− Node::text(items_left),
353− ],
354− ),
355− Node::element(
356− bump,
357− "ul",
358− [],
359− [Attribute {
360− name: "class",
361− value: "filters",
362− }],
363− [
241+ footer(bump)
242+ .attr("class", "footer")
243+ .bool_attr("hidden", self.todos.is_empty())
244+ .children([
245+ span(bump)
246+ .attr("class", "todo-count")
247+ .children([
248+ strong(bump)
249+ .children([text(incomplete_count.into_bump_str())])
250+ .finish(),
251+ text(items_left),
252+ ])
253+ .finish(),
254+ ul(bump)
255+ .attr("class", "filters")
256+ .children([
364257 self.visibility_swap(bump, "#/", Visibility::All),
365258 self.visibility_swap(bump, "#/active", Visibility::Active),
366259 self.visibility_swap(bump, "#/completed", Visibility::Completed),
367− ],
368− ),
369− Node::element(
370− bump,
371− "button",
372− [on(bump, "click", |root, vdom, _event| {
260+ ])
261+ .finish(),
262+ button(bump)
263+ .on("click", |root, vdom, _event| {
373264 C::delete_completed(root, vdom);
374− })],
375− {
376− let mut attrs = bumpalo::vec![
377− in bump;
378− Attribute {
379− name: "class",
380− value: "clear-completed",
381− }
382− ];
383− if self.todos.iter().all(|t| !t.is_complete()) {
384− attrs.push(Attribute {
385− name: "hidden",
386− value: "",
387− });
388− }
389− attrs
390− },
391− [Node::text(clear_completed_text.into_bump_str())],
392− ),
393− ],
394− )
265+ })
266+ .attr("class", "clear-completed")
267+ .bool_attr("hidden", completed_count == 0)
268+ .children([text(clear_completed_text.into_bump_str())])
269+ .finish(),
270+ ])
271+ .finish()
395272 }
396273
397274 fn visibility_swap<'a, 'bump>(
@@ -403,34 +280,25 @@ impl<C: TodosActions> Todos<C> {
403280 where
404281 'a: 'bump,
405282 {
406− Node::element(
407− bump,
408− "li",
409− [on(bump, "click", move |root, vdom, _event| {
283+ use dodrio::builder::*;
284+
285+ li(bump)
286+ .on("click", move |root, vdom, _event| {
410287 C::change_visibility(root, vdom, target_vis);
411− })],
412− [],
413− [Node::element(
414− bump,
415− "a",
416− [],
417− [
418− Attribute {
419− name: "href",
420− value: url,
421− },
422− Attribute {
423− name: "class",
424− value: if self.visibility == target_vis {
425− "selected"
426− } else {
427− ""
428− },
288+ })
289+ .children([a(bump)
290+ .attr("href", url)
291+ .attr(
292+ "class",
293+ if self.visibility == target_vis {
294+ "selected"
295+ } else {
296+ ""
429297 },
430− ],
431− [Node::text(target_vis.label())],
432− )],
433− )
298+ )
299+ .children([text(target_vis.label())])
300+ .finish()])
301+ .finish()
434302 }
435303}
436304
@@ -439,12 +307,10 @@ impl<C: TodosActions> Render for Todos<C> {
439307 where
440308 'a: 'bump,
441309 {
442− Node::element(
443− bump,
444− "div",
445− [],
446− [],
447− [self.header(bump), self.todos_list(bump), self.footer(bump)],
448− )
310+ use dodrio::builder::*;
311+
312+ div(bump)
313+ .children([self.header(bump), self.todos_list(bump), self.footer(bump)])
314+ .finish()
449315 }
450316}
src/builder.rsnew file+884
@@ -0,0 +1,884 @@
1+//! Helpers for building virtual DOM nodes.
2+
3+use crate::{Attribute, Listener, Node, RootRender, VdomWeak};
4+use bumpalo::Bump;
5+
6+/// A virtual DOM element builder.
7+///
8+/// Typically constructed with element-specific constructors, eg the `div`
9+/// function for building `<div>` elements or the `button` function for building
10+/// `<button>` elements.
11+#[derive(Clone, Debug)]
12+pub struct ElementBuilder<'a, Listeners, Attributes, Children>
13+where
14+ Listeners: 'a + AsRef<[Listener<'a>]>,
15+ Attributes: 'a + AsRef<[Attribute<'a>]>,
16+ Children: 'a + AsRef<[Node<'a>]>,
17+{
18+ bump: &'a Bump,
19+ tag_name: &'a str,
20+ listeners: Listeners,
21+ attributes: Attributes,
22+ children: Children,
23+}
24+
25+impl<'a, Listeners, Attributes, Children> ElementBuilder<'a, Listeners, Attributes, Children>
26+where
27+ Listeners: 'a + AsRef<[Listener<'a>]>,
28+ Attributes: 'a + AsRef<[Attribute<'a>]>,
29+ Children: 'a + AsRef<[Node<'a>]>,
30+{
31+ /// Set the listeners for this element.
32+ ///
33+ /// You can use this method to customize the backing storage for listeners,
34+ /// for example to use a fixed-size array instead of the default
35+ /// dynamically-sized `bumpalo::collections::Vec`.
36+ ///
37+ /// Any listeners already added to the builder will be overridden.
38+ ///
39+ /// # Example
40+ ///
41+ /// ```no_run
42+ /// use dodrio::{builder::*, bumpalo::Bump};
43+ ///
44+ /// let b = Bump::new();
45+ ///
46+ /// // Create a `<div>` with a fixed-size array of two listeners.
47+ /// let my_div = div(&b)
48+ /// .listeners([
49+ /// on(&b, "click", |root, vdom, event| {
50+ /// // ...
51+ /// }),
52+ /// on(&b, "dblclick", |root, vdom, event| {
53+ /// // ...
54+ /// }),
55+ /// ])
56+ /// .finish();
57+ /// ```
58+ #[inline]
59+ pub fn listeners<L>(self, listeners: L) -> ElementBuilder<'a, L, Attributes, Children>
60+ where
61+ L: 'a + AsRef<[Listener<'a>]>,
62+ {
63+ ElementBuilder {
64+ bump: self.bump,
65+ tag_name: self.tag_name,
66+ listeners,
67+ attributes: self.attributes,
68+ children: self.children,
69+ }
70+ }
71+
72+ /// Set the attributes for this element.
73+ ///
74+ /// You can use this method to customize the backing storage for attributes,
75+ /// for example to use a fixed-size array instead of the default
76+ /// dynamically-sized `bumpalo::collections::Vec`.
77+ ///
78+ /// Any attributes already added to the builder will be overridden.
79+ ///
80+ /// # Example
81+ ///
82+ /// ```no_run
83+ /// use dodrio::{builder::*, bumpalo::Bump, Attribute};
84+ ///
85+ /// let b = Bump::new();
86+ ///
87+ /// // Create a `<div>` with a fixed-size array of two attributes.
88+ /// let my_div = div(&b)
89+ /// .attributes([
90+ /// attr("id", "my-div"),
91+ /// attr("class", "notification"),
92+ /// ])
93+ /// .finish();
94+ /// ```
95+ #[inline]
96+ pub fn attributes<A>(self, attributes: A) -> ElementBuilder<'a, Listeners, A, Children>
97+ where
98+ A: 'a + AsRef<[Attribute<'a>]>,
99+ {
100+ ElementBuilder {
101+ bump: self.bump,
102+ tag_name: self.tag_name,
103+ listeners: self.listeners,
104+ attributes,
105+ children: self.children,
106+ }
107+ }
108+
109+ /// Set the children for this element.
110+ ///
111+ /// You can use this method to customize the backing storage for children,
112+ /// for example to use a fixed-size array instead of the default
113+ /// dynamically-sized `bumpalo::collections::Vec`.
114+ ///
115+ /// Any children already added to the builder will be overridden.
116+ ///
117+ /// # Example
118+ ///
119+ /// ```no_run
120+ /// use dodrio::{builder::*, bumpalo::Bump};
121+ ///
122+ /// let b = Bump::new();
123+ ///
124+ /// // Create a `<div>` with a fixed-size array of two `<span>` children.
125+ /// let my_div = div(&b)
126+ /// .children([
127+ /// span(&b).finish(),
128+ /// span(&b).finish(),
129+ /// ])
130+ /// .finish();
131+ /// ```
132+ #[inline]
133+ pub fn children<C>(self, children: C) -> ElementBuilder<'a, Listeners, Attributes, C>
134+ where
135+ C: 'a + AsRef<[Node<'a>]>,
136+ {
137+ ElementBuilder {
138+ bump: self.bump,
139+ tag_name: self.tag_name,
140+ listeners: self.listeners,
141+ attributes: self.attributes,
142+ children,
143+ }
144+ }
145+
146+ /// Create the virtual DOM node described by this builder.
147+ ///
148+ /// # Example
149+ ///
150+ /// ```no_run
151+ /// use dodrio::{builder::*, bumpalo::Bump, Node};
152+ ///
153+ /// let b = Bump::new();
154+ ///
155+ /// // Start with a builder...
156+ /// let builder: ElementBuilder<_, _, _> = div(&b);
157+ ///
158+ /// // ...and finish it to create a virtual DOM node!
159+ /// let my_div: Node = builder.finish();
160+ /// ```
161+ #[inline]
162+ pub fn finish(self) -> Node<'a> {
163+ Node::element(
164+ self.bump,
165+ self.tag_name,
166+ self.listeners,
167+ self.attributes,
168+ self.children,
169+ )
170+ }
171+}
172+
173+impl<'a, Attributes, Children>
174+ ElementBuilder<'a, bumpalo::collections::Vec<'a, Listener<'a>>, Attributes, Children>
175+where
176+ Attributes: 'a + AsRef<[Attribute<'a>]>,
177+ Children: 'a + AsRef<[Node<'a>]>,
178+{
179+ /// Add a new event listener to this element.
180+ ///
181+ /// The `event` string specifies which event will be listened for. The
182+ /// `callback` function is the function that will be invoked if the
183+ /// specified event occurs.
184+ ///
185+ /// # Example
186+ ///
187+ /// ```no_run
188+ /// use dodrio::{builder::*, bumpalo::Bump};
189+ ///
190+ /// let b = Bump::new();
191+ ///
192+ /// // A button that does something when clicked!
193+ /// let my_button = button(&b)
194+ /// .on("click", |root, vdom, event| {
195+ /// // ...
196+ /// })
197+ /// .finish();
198+ /// ```
199+ #[inline]
200+ pub fn on<F>(mut self, event: &'a str, callback: F) -> Self
201+ where
202+ F: 'static + Fn(&mut dyn RootRender, VdomWeak, web_sys::Event),
203+ {
204+ self.listeners.push(Listener {
205+ event,
206+ callback: self.bump.alloc(callback),
207+ });
208+ self
209+ }
210+}
211+
212+impl<'a, Listeners, Children>
213+ ElementBuilder<'a, Listeners, bumpalo::collections::Vec<'a, Attribute<'a>>, Children>
214+where
215+ Listeners: 'a + AsRef<[Listener<'a>]>,
216+ Children: 'a + AsRef<[Node<'a>]>,
217+{
218+ /// Add a new attribute to this element.
219+ ///
220+ /// # Example
221+ ///
222+ /// ```no_run
223+ /// use dodrio::{builder::*, bumpalo::Bump};
224+ ///
225+ /// let b = Bump::new();
226+ ///
227+ /// // Create the `<div id="my-div"/>` element.
228+ /// let my_div = div(&b).attr("id", "my-div").finish();
229+ /// ```
230+ #[inline]
231+ pub fn attr(mut self, name: &'a str, value: &'a str) -> Self {
232+ self.attributes.push(Attribute { name, value });
233+ self
234+ }
235+
236+ /// Conditionally add a "boolean-style" attribute to this element.
237+ ///
238+ /// If the `should_add` parameter is true, then adds an attribute with the
239+ /// given `name` and an empty string value. If the `should_add` parameter is
240+ /// false, then the attribute is not added.
241+ ///
242+ /// This method is useful for attributes whose semantics are defined by
243+ /// whether or not the attribute is present or not, and whose value is
244+ /// ignored. Example attributes like this include:
245+ ///
246+ /// * `checked`
247+ /// * `hidden`
248+ /// * `selected`
249+ ///
250+ /// # Example
251+ ///
252+ /// ```no_run
253+ /// use dodrio::{builder::*, bumpalo::Bump};
254+ /// use js_sys::Math;
255+ ///
256+ /// let b = Bump::new();
257+ ///
258+ /// // Create the `<div>` that is randomly hidden 50% of the time.
259+ /// let my_div = div(&b)
260+ /// .bool_attr("hidden", Math::random() >= 0.5)
261+ /// .finish();
262+ /// ```
263+ pub fn bool_attr(mut self, name: &'a str, should_add: bool) -> Self {
264+ if should_add {
265+ self.attributes.push(Attribute { name, value: "" });
266+ }
267+ self
268+ }
269+}
270+
271+impl<'a, Listeners, Attributes>
272+ ElementBuilder<'a, Listeners, Attributes, bumpalo::collections::Vec<'a, Node<'a>>>
273+where
274+ Listeners: 'a + AsRef<[Listener<'a>]>,
275+ Attributes: 'a + AsRef<[Attribute<'a>]>,
276+{
277+ /// Add a new child to this element.
278+ ///
279+ /// # Example
280+ ///
281+ /// ```no_run
282+ /// use dodrio::{builder::*, bumpalo::Bump};
283+ /// use js_sys::Math;
284+ ///
285+ /// let b = Bump::new();
286+ ///
287+ /// // Create `<p><span></span></p>`.
288+ /// let my_div = p(&b)
289+ /// .child(span(&b).finish())
290+ /// .finish();
291+ /// ```
292+ #[inline]
293+ pub fn child(mut self, child: Node<'a>) -> Self {
294+ self.children.push(child);
295+ self
296+ }
297+}
298+
299+macro_rules! builder_constructors {
300+ ( $(
301+ $(#[$attr:meta])*
302+ $name:ident;
303+ )* ) => {
304+ $(
305+ $(#[$attr])*
306+ #[inline]
307+ pub fn $name<'a>(
308+ bump: &'a Bump,
309+ ) -> ElementBuilder<
310+ 'a,
311+ bumpalo::collections::Vec<'a, Listener<'a>>,
312+ bumpalo::collections::Vec<'a, Attribute<'a>>,
313+ bumpalo::collections::Vec<'a, Node<'a>>,
314+ > {
315+ ElementBuilder {
316+ bump,
317+ tag_name: stringify!($name),
318+ listeners: bumpalo::collections::Vec::new_in(bump),
319+ attributes: bumpalo::collections::Vec::new_in(bump),
320+ children: bumpalo::collections::Vec::new_in(bump),
321+ }
322+ }
323+ )*
324+ }
325+}
326+
327+// Organized in the same order as
328+// https://developer.mozilla.org/en-US/docs/Web/HTML/Element
329+//
330+// Does not include obsolete elements.
331+builder_constructors! {
332+ // Document metadata
333+
334+ /// Build a
335+ /// [`<base>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base)
336+ /// element.
337+ base;
338+ /// Build a
339+ /// [`<head>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/head)
340+ /// element.
341+ head;
342+ /// Build a
343+ /// [`<link>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link)
344+ /// element.
345+ link;
346+ /// Build a
347+ /// [`<meta>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta)
348+ /// element.
349+ meta;
350+ /// Build a
351+ /// [`<style>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/style)
352+ /// element.
353+ style;
354+ /// Build a
355+ /// [`<title>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/title)
356+ /// element.
357+ title;
358+
359+ // Sectioning root
360+
361+ /// Build a
362+ /// [`<body>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/body)
363+ /// element.
364+ body;
365+
366+ // Content sectioning
367+
368+ /// Build a
369+ /// [`<address>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/address)
370+ /// element.
371+ address;
372+ /// Build a
373+ /// [`<article>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/article)
374+ /// element.
375+ article;
376+ /// Build a
377+ /// [`<aside>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/aside)
378+ /// element.
379+ aside;
380+ /// Build a
381+ /// [`<footer>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/footer)
382+ /// element.
383+ footer;
384+ /// Build a
385+ /// [`<header>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/header)
386+ /// element.
387+ header;
388+ /// Build a
389+ /// [`<h1>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h1)
390+ /// element.
391+ h1;
392+ /// Build a
393+ /// [`<h2>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h2)
394+ /// element.
395+ h2;
396+ /// Build a
397+ /// [`<h3>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h3)
398+ /// element.
399+ h3;
400+ /// Build a
401+ /// [`<h4>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h4)
402+ /// element.
403+ h4;
404+ /// Build a
405+ /// [`<h5>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h5)
406+ /// element.
407+ h5;
408+ /// Build a
409+ /// [`<h6>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h6)
410+ /// element.
411+ h6;
412+ /// Build a
413+ /// [`<hgroup>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/hgroup)
414+ /// element.
415+ hgroup;
416+ /// Build a
417+ /// [`<main>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/main)
418+ /// element.
419+ main;
420+ /// Build a
421+ /// [`<nav>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/nav)
422+ /// element.
423+ nav;
424+ /// Build a
425+ /// [`<section>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/section)
426+ /// element.
427+ section;
428+
429+ // Text content
430+
431+ /// Build a
432+ /// [`<blockquote>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/blockquote)
433+ /// element.
434+ blockquote;
435+ /// Build a
436+ /// [`<dd>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dd)
437+ /// element.
438+ dd;
439+ /// Build a
440+ /// [`<div>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div)
441+ /// element.
442+ div;
443+ /// Build a
444+ /// [`<dl>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dl)
445+ /// element.
446+ dl;
447+ /// Build a
448+ /// [`<dt>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dt)
449+ /// element.
450+ dt;
451+ /// Build a
452+ /// [`<figcaption>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/figcaption)
453+ /// element.
454+ figcaption;
455+ /// Build a
456+ /// [`<figure>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/figure)
457+ /// element.
458+ figure;
459+ /// Build a
460+ /// [`<hr>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/hr)
461+ /// element.
462+ hr;
463+ /// Build a
464+ /// [`<li>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/li)
465+ /// element.
466+ li;
467+ /// Build a
468+ /// [`<ol>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ol)
469+ /// element.
470+ ol;
471+ /// Build a
472+ /// [`<p>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/p)
473+ /// element.
474+ p;
475+ /// Build a
476+ /// [`<pre>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/pre)
477+ /// element.
478+ pre;
479+ /// Build a
480+ /// [`<ul>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul)
481+ /// element.
482+ ul;
483+
484+ // Inline text semantics
485+
486+ /// Build a
487+ /// [`<a>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a)
488+ /// element.
489+ a;
490+ /// Build a
491+ /// [`<abbr>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/abbr)
492+ /// element.
493+ abbr;
494+ /// Build a
495+ /// [`<b>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/b)
496+ /// element.
497+ b;
498+ /// Build a
499+ /// [`<bdi>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/bdi)
500+ /// element.
501+ bdi;
502+ /// Build a
503+ /// [`<bdo>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/bdo)
504+ /// element.
505+ bdo;
506+ /// Build a
507+ /// [`<br>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/br)
508+ /// element.
509+ br;
510+ /// Build a
511+ /// [`<cite>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/cite)
512+ /// element.
513+ cite;
514+ /// Build a
515+ /// [`<code>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/code)
516+ /// element.
517+ code;
518+ /// Build a
519+ /// [`<data>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/data)
520+ /// element.
521+ data;
522+ /// Build a
523+ /// [`<dfn>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dfn)
524+ /// element.
525+ dfn;
526+ /// Build a
527+ /// [`<em>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/em)
528+ /// element.
529+ em;
530+ /// Build a
531+ /// [`<i>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/i)
532+ /// element.
533+ i;
534+ /// Build a
535+ /// [`<kbd>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/kbd)
536+ /// element.
537+ kbd;
538+ /// Build a
539+ /// [`<mark>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/mark)
540+ /// element.
541+ mark;
542+ /// Build a
543+ /// [`<q>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/q)
544+ /// element.
545+ q;
546+ /// Build a
547+ /// [`<rb>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/rb)
548+ /// element.
549+ rb;
550+ /// Build a
551+ /// [`<rp>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/rp)
552+ /// element.
553+ rp;
554+ /// Build a
555+ /// [`<rt>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/rt)
556+ /// element.
557+ rt;
558+ /// Build a
559+ /// [`<rtc>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/rtc)
560+ /// element.
561+ rtc;
562+ /// Build a
563+ /// [`<ruby>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ruby)
564+ /// element.
565+ ruby;
566+ /// Build a
567+ /// [`<s>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/s)
568+ /// element.
569+ s;
570+ /// Build a
571+ /// [`<samp>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/samp)
572+ /// element.
573+ samp;
574+ /// Build a
575+ /// [`<small>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/small)
576+ /// element.
577+ small;
578+ /// Build a
579+ /// [`<span>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/span)
580+ /// element.
581+ span;
582+ /// Build a
583+ /// [`<strong>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/strong)
584+ /// element.
585+ strong;
586+ /// Build a
587+ /// [`<sub>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/sub)
588+ /// element.
589+ sub;
590+ /// Build a
591+ /// [`<sup>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/sup)
592+ /// element.
593+ sup;
594+ /// Build a
595+ /// [`<time>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/time)
596+ /// element.
597+ time;
598+ /// Build a
599+ /// [`<u>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/u)
600+ /// element.
601+ u;
602+ /// Build a
603+ /// [`<var>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/var)
604+ /// element.
605+ var;
606+ /// Build a
607+ /// [`<wbr>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/wbr)
608+ /// element.
609+ wbr;
610+
611+ // Image and multimedia
612+
613+ /// Build a
614+ /// [`<area>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/area)
615+ /// element.
616+ area;
617+ /// Build a
618+ /// [`<audio>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/audio)
619+ /// element.
620+ audio;
621+ /// Build a
622+ /// [`<img>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img)
623+ /// element.
624+ img;
625+ /// Build a
626+ /// [`<map>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/map)
627+ /// element.
628+ map;
629+ /// Build a
630+ /// [`<track>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/track)
631+ /// element.
632+ track;
633+ /// Build a
634+ /// [`<video>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video)
635+ /// element.
636+ video;
637+
638+ // Embedded content
639+
640+ /// Build a
641+ /// [`<embed>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/embed)
642+ /// element.
643+ embed;
644+ /// Build a
645+ /// [`<iframe>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe)
646+ /// element.
647+ iframe;
648+ /// Build a
649+ /// [`<object>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/object)
650+ /// element.
651+ object;
652+ /// Build a
653+ /// [`<param>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/param)
654+ /// element.
655+ param;
656+ /// Build a
657+ /// [`<picture>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture)
658+ /// element.
659+ picture;
660+ /// Build a
661+ /// [`<source>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/source)
662+ /// element.
663+ source;
664+
665+ // Scripting
666+
667+ /// Build a
668+ /// [`<canvas>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas)
669+ /// element.
670+ canvas;
671+ /// Build a
672+ /// [`<noscript>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/noscript)
673+ /// element.
674+ noscript;
675+ /// Build a
676+ /// [`<script>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script)
677+ /// element.
678+ script;
679+
680+ // Demarcating edits
681+
682+ /// Build a
683+ /// [`<del>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/del)
684+ /// element.
685+ del;
686+ /// Build a
687+ /// [`<ins>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ins)
688+ /// element.
689+ ins;
690+
691+ // Table content
692+
693+ /// Build a
694+ /// [`<caption>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/caption)
695+ /// element.
696+ caption;
697+ /// Build a
698+ /// [`<col>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/col)
699+ /// element.
700+ col;
701+ /// Build a
702+ /// [`<colgroup>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/colgroup)
703+ /// element.
704+ colgroup;
705+ /// Build a
706+ /// [`<table>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/table)
707+ /// element.
708+ table;
709+ /// Build a
710+ /// [`<tbody>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/tbody)
711+ /// element.
712+ tbody;
713+ /// Build a
714+ /// [`<td>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/td)
715+ /// element.
716+ td;
717+ /// Build a
718+ /// [`<tfoot>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/tfoot)
719+ /// element.
720+ tfoot;
721+ /// Build a
722+ /// [`<th>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/th)
723+ /// element.
724+ th;
725+ /// Build a
726+ /// [`<thead>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/thead)
727+ /// element.
728+ thead;
729+ /// Build a
730+ /// [`<tr>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/tr)
731+ /// element.
732+ tr;
733+
734+ // Forms
735+
736+ /// Build a
737+ /// [`<button>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button)
738+ /// element.
739+ button;
740+ /// Build a
741+ /// [`<datalist>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/datalist)
742+ /// element.
743+ datalist;
744+ /// Build a
745+ /// [`<fieldset>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/fieldset)
746+ /// element.
747+ fieldset;
748+ /// Build a
749+ /// [`<form>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form)
750+ /// element.
751+ form;
752+ /// Build a
753+ /// [`<input>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input)
754+ /// element.
755+ input;
756+ /// Build a
757+ /// [`<label>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/label)
758+ /// element.
759+ label;
760+ /// Build a
761+ /// [`<legend>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/legend)
762+ /// element.
763+ legend;
764+ /// Build a
765+ /// [`<meter>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meter)
766+ /// element.
767+ meter;
768+ /// Build a
769+ /// [`<optgroup>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/optgroup)
770+ /// element.
771+ optgroup;
772+ /// Build a
773+ /// [`<option>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/option)
774+ /// element.
775+ option;
776+ /// Build a
777+ /// [`<output>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/output)
778+ /// element.
779+ output;
780+ /// Build a
781+ /// [`<progress>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/progress)
782+ /// element.
783+ progress;
784+ /// Build a
785+ /// [`<select>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select)
786+ /// element.
787+ select;
788+ /// Build a
789+ /// [`<textarea>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea)
790+ /// element.
791+ textarea;
792+
793+ // Interactive elements
794+
795+ /// Build a
796+ /// [`<details>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details)
797+ /// element.
798+ details;
799+ /// Build a
800+ /// [`<dialog>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog)
801+ /// element.
802+ dialog;
803+ /// Build a
804+ /// [`<menu>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/menu)
805+ /// element.
806+ menu;
807+ /// Build a
808+ /// [`<menuitem>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/menuitem)
809+ /// element.
810+ menuitem;
811+ /// Build a
812+ /// [`<summary>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/summary)
813+ /// element.
814+ summary;
815+
816+ // Web components
817+
818+ /// Build a
819+ /// [`<slot>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/slot)
820+ /// element.
821+ slot;
822+ /// Build a
823+ /// [`<template>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template)
824+ /// element.
825+ template;
826+}
827+
828+/// Construct a text node.
829+///
830+/// This is `dodrio`'s virtual DOM equivalent of `document.createTextNode`.
831+///
832+/// # Example
833+///
834+/// ```no_run
835+/// use dodrio::builder::*;
836+///
837+/// let my_text = text("hello, dodrio!");
838+/// ```
839+#[inline]
840+pub fn text<'a>(contents: &'a str) -> Node<'a> {
841+ Node::text(contents)
842+}
843+
844+/// Construct an attribute for an element.
845+///
846+/// # Example
847+///
848+/// This example creates the `id="my-id"` for some element like `<div
849+/// id="my-id"/>`.
850+///
851+/// ```no_run
852+/// use dodrio::builder::*;
853+///
854+/// let my_id_attr = attr("id", "my-id");
855+/// ```
856+pub fn attr<'a>(name: &'a str, value: &'a str) -> Attribute<'a> {
857+ Attribute { name, value }
858+}
859+
860+/// Create an event listener.
861+///
862+/// `event` is the type of event to listen for, e.g. `"click"`. The `callback`
863+/// is the function that will be invoked when the event occurs.
864+///
865+/// # Example
866+///
867+/// ```no_run
868+/// use dodrio::{builder::*, bumpalo::Bump};
869+///
870+/// let b = Bump::new();
871+///
872+/// let listener = on(&b, "click", |root, vdom, event| {
873+/// // do something when a click happens...
874+/// });
875+/// ```
876+pub fn on<'a, F>(bump: &'a Bump, event: &'a str, callback: F) -> Listener<'a>
877+where
878+ F: Fn(&mut dyn RootRender, VdomWeak, web_sys::Event) + 'static,
879+{
880+ Listener {
881+ event,
882+ callback: bump.alloc(callback),
883+ }
884+}
src/cached.rs+4−5
@@ -89,11 +89,10 @@ impl<R> Cached<R> {
8989 /// where
9090 /// 'a: 'bump,
9191 /// {
92− /// Node::element(bump, "p", [], [], [
93− /// Node::text("Hello, "),
94− /// Node::text(&self.who),
95− /// Node::text("!"),
96− /// ])
92+ /// use dodrio::builder::*;
93+ /// p(bump)
94+ /// .children([text("Hello, "), text(&self.who), text("!")])
95+ /// .finish()
9796 /// }
9897 /// }
9998 ///
src/lib.rs+24−28
@@ -3,7 +3,7 @@
33//! ## Example
44//!
55//! ```no_run
6−//! use dodrio::{on, bumpalo::Bump, Attribute, Node, Render};
6+//! use dodrio::{bumpalo::Bump, Attribute, Node, Render};
77//! use wasm_bindgen::UnwrapThrowExt;
88//!
99//! /// A component that greets someone.
@@ -23,34 +23,28 @@
2323//! where
2424//! 'a: 'bump,
2525//! {
26+//! use dodrio::builder::*;
27+//!
2628//! let id = bumpalo::format!(in bump, "hello-{}", self.who);
27−//! Node::element(
28−//! bump,
29−//! // The element's tag name. In this case a `<p>` element.
30−//! "p",
31−//! // Listeners.
32−//! [on(bump, "click", |root, _vdom, _event| {
29+//!
30+//! div(bump)
31+//! .attr("id", id.into_bump_str())
32+//! .on("click", |root, _vdom, _event| {
3333//! let hello = root.unwrap_mut::<Hello>();
34−//! let window = web_sys::window().expect_throw("should have a `Window` on the Web");
35−//! window.alert_with_message(hello.who);
36−//! })],
37−//! // Attributes.
38−//! [Attribute { name: "id", value: id.into_bump_str() }],
39−//! // Child nodes.
40−//! [
41−//! Node::text("Hello, "),
42−//! Node::element(
43−//! bump,
44−//! "strong",
45−//! [],
46−//! [],
47−//! [
48−//! Node::text(self.who),
49−//! Node::text("!"),
50−//! ],
51−//! ),
52−//! ],
53−//! )
34+//! web_sys::window()
35+//! .expect_throw("should have a `Window` on the Web")
36+//! .alert_with_message(hello.who);
37+//! })
38+//! .children([
39+//! text("Hello, "),
40+//! strong(bump)
41+//! .children([
42+//! text(self.who),
43+//! text("!"),
44+//! ])
45+//! .finish(),
46+//! ])
47+//! .finish()
5448//! }
5549//! }
5650//! ```
@@ -69,8 +63,10 @@ mod node;
6963mod render;
7064mod vdom;
7165
66+pub mod builder;
67+
7268// Re-export items at the top level.
7369pub use self::cached::Cached;
74−pub use self::node::{on, Attribute, ElementNode, Listener, ListenerCallback, Node, TextNode};
70+pub use self::node::{Attribute, ElementNode, Listener, ListenerCallback, Node, TextNode};
7571pub use self::render::{Render, RootRender};
7672pub use self::vdom::{Vdom, VdomWeak};
src/node.rs+18−24
@@ -43,19 +43,17 @@ pub type ListenerCallback<'a> =
4343/// An event listener.
4444pub struct Listener<'a> {
4545 /// The type of event to listen for.
46− pub event: &'a str,
46+ pub(crate) event: &'a str,
4747 /// The callback to invoke when the event happens.
48− pub callback: ListenerCallback<'a>,
48+ pub(crate) callback: ListenerCallback<'a>,
4949}
5050
5151/// An attribute on a DOM node, such as `id="my-thing"` or
5252/// `href="https://example.com"`.
5353#[derive(Clone, Debug)]
5454pub struct Attribute<'a> {
55− /// The attribute name, such as `id`.
56− pub name: &'a str,
57− /// The attribute value, such as `"my-thing"`.
58− pub value: &'a str,
55+ pub(crate) name: &'a str,
56+ pub(crate) value: &'a str,
5957}
6058
6159impl fmt::Debug for Listener<'_> {
@@ -71,6 +69,18 @@ impl fmt::Debug for Listener<'_> {
7169}
7270
7371impl<'a> Attribute<'a> {
72+ /// Get this attribute's name, such as `"id"` in `<div id="my-thing" />`.
73+ #[inline]
74+ pub fn name(&self) -> &'a str {
75+ self.name
76+ }
77+
78+ /// The attribute value, such as `"my-thing"` in `<div id="my-thing" />`.
79+ #[inline]
80+ pub fn value(&self) -> &'a str {
81+ self.value
82+ }
83+
7484 /// Certain attributes are considered "volatile" and can change via user
7585 /// input that we can't see when diffing against the old virtual DOM. For
7686 /// these attributes, we want to always re-set the attribute on the physical
@@ -87,7 +97,7 @@ impl<'a> Attribute<'a> {
8797impl<'a> Node<'a> {
8898 /// Construct a new element node with the given tag name and children.
8999 #[inline]
90− pub fn element<Listeners, Attributes, Children>(
100+ pub(crate) fn element<Listeners, Attributes, Children>(
91101 bump: &'a Bump,
92102 tag_name: &'a str,
93103 listeners: Listeners,
@@ -134,7 +144,7 @@ impl<'a> Node<'a> {
134144
135145 /// Construct a new text node with the given text.
136146 #[inline]
137− pub fn text(text: &'a str) -> Node<'a> {
147+ pub(crate) fn text(text: &'a str) -> Node<'a> {
138148 Node::Text(TextNode { text })
139149 }
140150}
@@ -186,19 +196,3 @@ impl Listener<'_> {
186196 }
187197 }
188198}
189−
190−/// Utility function for creating event listeners and downcasting the component
191−/// to its `RootRender` concrete type.
192−pub fn on<'a, F>(bump: &'a Bump, event: &'a str, callback: F) -> Listener<'a>
193−where
194− F: Fn(&mut dyn RootRender, VdomWeak, web_sys::Event) + 'static,
195−{
196− Listener {
197− event,
198− callback: bump.alloc(
199− move |component: &mut dyn RootRender, vdom: VdomWeak, event: web_sys::Event| {
200− callback(component, vdom, event);
201− },
202− ),
203− }
204−}
src/render.rs+9−1
@@ -36,7 +36,15 @@ use wasm_bindgen::UnwrapThrowExt;
3636/// where
3737/// 'a: 'bump
3838/// {
39−/// Node::text("This is my component rendered!")
39+/// use dodrio::builder::*;
40+///
41+/// p(bump)
42+/// .children([
43+/// text("This is "),
44+/// strong(bump).children([text("my component")]).finish(),
45+/// text(" rendered!"),
46+/// ])
47+/// .finish()
4048/// }
4149/// }
4250/// ```
tests/web/cached.rs+8−6
@@ -1,5 +1,5 @@
11use super::{assert_rendered, create_element, RenderFn};
2−use dodrio::{bumpalo::Bump, Cached, Node, Render, Vdom};
2+use dodrio::{builder::*, bumpalo::Bump, Cached, Node, Render, Vdom};
33use futures::prelude::*;
44use std::cell::Cell;
55use std::rc::Rc;
@@ -27,12 +27,14 @@ impl Render for CountRenders {
2727 self.render_count.set(count);
2828
2929 let s = bumpalo::format!(in bump, "{}", count);
30− Node::text(s.into_bump_str())
30+ text(s.into_bump_str())
3131 }
3232}
3333
3434#[wasm_bindgen_test(async)]
3535fn uses_cached_render() -> impl Future<Item = (), Error = JsValue> {
36+ use dodrio::builder::*;
37+
3638 let cached = Cached::new(CountRenders::new());
3739
3840 let container0 = create_element("div");
@@ -58,7 +60,7 @@ fn uses_cached_render() -> impl Future<Item = (), Error = JsValue> {
5860 vdom0.weak().with_component(move |comp| {
5961 let comp = comp.unwrap_mut::<Cached<CountRenders>>();
6062 assert_eq!(comp.render_count.get(), 1);
61− assert_rendered(&container1, &RenderFn(|_| Node::text("1")));
63+ assert_rendered(&container1, &RenderFn(|_| text("1")));
6264 })
6365 })
6466 // We re-render, re-use the cached node, and get "1" again.
@@ -67,7 +69,7 @@ fn uses_cached_render() -> impl Future<Item = (), Error = JsValue> {
6769 vdom2.weak().with_component(move |comp| {
6870 let comp = comp.unwrap_mut::<Cached<CountRenders>>();
6971 assert_eq!(comp.render_count.get(), 1);
70− assert_rendered(&container2, &RenderFn(|_| Node::text("1")));
72+ assert_rendered(&container2, &RenderFn(|_| text("1")));
7173 })
7274 })
7375 // We invalidate the cache, re-render, re-populate the cache, and should
@@ -83,7 +85,7 @@ fn uses_cached_render() -> impl Future<Item = (), Error = JsValue> {
8385 vdom5.weak().with_component(move |comp| {
8486 let comp = comp.unwrap_mut::<Cached<CountRenders>>();
8587 assert_eq!(comp.render_count.get(), 2);
86− assert_rendered(&container3, &RenderFn(|_| Node::text("2")));
88+ assert_rendered(&container3, &RenderFn(|_| text("2")));
8789 })
8890 })
8991 // We re-render, re-use the cached node, and get "2" again.
@@ -92,7 +94,7 @@ fn uses_cached_render() -> impl Future<Item = (), Error = JsValue> {
9294 vdom7.weak().with_component(move |comp| {
9395 let comp = comp.unwrap_mut::<Cached<CountRenders>>();
9496 assert_eq!(comp.render_count.get(), 2);
95− assert_rendered(&container4, &RenderFn(|_| Node::text("2")));
97+ assert_rendered(&container4, &RenderFn(|_| text("2")));
9698 })
9799 })
98100 .map_err(|e| JsValue::from(e.to_string()))
tests/web/events.rs+23−46
@@ -1,6 +1,6 @@
11use super::create_element;
22use bumpalo::Bump;
3−use dodrio::{on, Attribute, Node, Render, Vdom};
3+use dodrio::{Node, Render, Vdom};
44use futures::Future;
55use std::cell::{Cell, RefCell};
66use std::rc::Rc;
@@ -30,18 +30,13 @@ impl Render for EventContainer {
3030 where
3131 'a: 'bump,
3232 {
33− Node::element(
34− bump,
35− "div",
36− [on(bump, self.event, |root, _scheduler, _event| {
33+ use dodrio::builder::*;
34+ div(bump)
35+ .attr("id", "target")
36+ .on(self.event, |root, _scheduler, _event| {
3737 (root.unwrap_mut::<EventContainer>().on_event)();
38− })],
39− [Attribute {
40− name: "id",
41− value: "target",
42− }],
43− [],
44− )
38+ })
39+ .finish()
4540 }
4641}
4742
@@ -147,33 +142,18 @@ impl Render for ListensOnlyOnFirstRender {
147142 where
148143 'a: 'bump,
149144 {
145+ use dodrio::builder::*;
146+
150147 let count = self.count.get();
151148 self.count.set(count + 1);
149+
150+ let mut elem = div(bump).attr("id", "target");
152151 if count == 0 {
153− Node::element(
154− bump,
155− "div",
156− [on(bump, "click", |root, _scheduler, _event| {
157− (root.unwrap_mut::<ListensOnlyOnFirstRender>().callback)();
158− })],
159− [Attribute {
160− name: "id",
161− value: "target",
162− }],
163− [],
164− )
165− } else {
166− Node::element(
167− bump,
168− "div",
169− [],
170− [Attribute {
171− name: "id",
172− value: "target",
173− }],
174− [],
175− )
152+ elem = elem.on("click", |root, _scheduler, _event| {
153+ (root.unwrap_mut::<ListensOnlyOnFirstRender>().callback)();
154+ });
176155 }
156+ elem.finish()
177157 }
178158}
179159
@@ -315,23 +295,20 @@ impl Render for CountRendersAndListen {
315295 where
316296 'a: 'bump,
317297 {
298+ use dodrio::builder::*;
299+
318300 let count = self.count.get() + 1;
319301 self.count.set(count);
320− Node::element(
321− bump,
322− "button",
323− [on(bump, "click", |comp, _vdom, _event| {
302+
303+ button(bump)
304+ .attr("id", "target")
305+ .on("click", |comp, _vdom, _event| {
324306 let comp: &mut _ = comp.unwrap_mut::<dodrio::Cached<CountRendersAndListen>>();
325307 let comp: &mut CountRendersAndListen = comp;
326308 let n = comp.count.get();
327309 (comp.callback)(n);
328− })],
329− [Attribute {
330− name: "id",
331− value: "target",
332− }],
333− [],
334− )
310+ })
311+ .finish()
335312 }
336313}
337314
tests/web/main.rs+4−4
@@ -103,13 +103,13 @@ pub fn assert_rendered<R: Render>(container: &web_sys::Element, r: &R) {
103103 );
104104 for attr in expected {
105105 let actual_attr = actual
106− .get_named_item(attr.name)
107− .expect(&format!("should have attribute \"{}\"", attr.name));
106+ .get_named_item(attr.name())
107+ .expect(&format!("should have attribute \"{}\"", attr.name()));
108108 assert_eq!(
109109 actual_attr.value(),
110− attr.value,
110+ attr.value(),
111111 "actual attr value == expected attr value for attr \"{}\"",
112− attr.name
112+ attr.name()
113113 );
114114 }
115115 }
tests/web/render.rs+93−102
@@ -1,12 +1,12 @@
11use super::{assert_rendered, before_after, create_element, RenderFn};
2−use dodrio::{Attribute, Node, Vdom};
2+use dodrio::{builder::*, Vdom};
33use futures::prelude::*;
44use std::rc::Rc;
55use wasm_bindgen_test::*;
66
77#[wasm_bindgen_test]
88fn render_initial_text() {
9− let hello = Rc::new(RenderFn(|_bump| Node::text("hello")));
9+ let hello = Rc::new(RenderFn(|_bump| text("hello")));
1010
1111 let container = create_element("div");
1212 let _vdom = Vdom::new(&container, hello.clone());
@@ -16,19 +16,10 @@ fn render_initial_text() {
1616#[wasm_bindgen_test]
1717fn render_initial_node() {
1818 let hello = Rc::new(RenderFn(|bump| {
19− Node::element(
20− bump,
21− "div",
22− [],
23− [Attribute {
24− name: "id",
25− value: "hello-world",
26− }],
27− [
28− Node::text("Hello "),
29− Node::element(bump, "span", [], [], [Node::text("World!")]),
30− ],
31− )
19+ div(bump)
20+ .attr("id", "hello-world")
21+ .children([text("Hello "), span(bump).child(text("World!")).finish()])
22+ .finish()
3223 }));
3324
3425 let container = create_element("div");
@@ -39,7 +30,7 @@ fn render_initial_node() {
3930#[wasm_bindgen_test]
4031fn container_is_emptied_upon_drop() {
4132 let container = create_element("div");
42− let vdom = Vdom::new(&container, RenderFn(|_bump| Node::text("blah")));
33+ let vdom = Vdom::new(&container, RenderFn(|_bump| text("blah")));
4334 drop(vdom);
4435 assert!(container.first_child().is_none());
4536}
@@ -47,206 +38,206 @@ fn container_is_emptied_upon_drop() {
4738before_after! {
4839 same_text {
4940 before(_bump) {
50− Node::text("hello")
41+ text("hello")
5142 }
5243 after(_bump) {
53− Node::text("hello")
44+ text("hello")
5445 }
5546 }
5647
5748 update_text {
5849 before(_bump) {
59− Node::text("before")
50+ text("before")
6051 }
6152 after(_bump) {
62− Node::text("after")
53+ text("after")
6354 }
6455 }
6556
6657 replace_text_with_elem {
6758 before(_bump) {
68− Node::text("before")
59+ text("before")
6960 }
7061 after(bump) {
71− Node::element(bump, "div", [], [], [])
62+ div(bump).finish()
7263 }
7364 }
7465
7566 replace_elem_with_text {
7667 before(bump) {
77− Node::element(bump, "div", [], [], [])
68+ div(bump).finish()
7869 }
7970 after(_bump) {
80− Node::text("before")
71+ text("before")
8172 }
8273 }
8374
8475 same_elem {
8576 before(bump) {
86− Node::element(bump, "div", [], [], [])
77+ div(bump).finish()
8778 }
8879 after(bump) {
89− Node::element(bump, "div", [], [], [])
80+ div(bump).finish()
9081 }
9182 }
9283
9384 elems_with_different_tag_names {
9485 before(bump) {
95− Node::element(bump, "span", [], [], [])
86+ span(bump).finish()
9687 }
9788 after(bump) {
98− Node::element(bump, "div", [], [], [])
89+ div(bump).finish()
9990 }
10091 }
10192
10293 same_tag_name_update_attribute {
10394 before(bump) {
104− Node::element(bump, "div", [], [Attribute { name: "value", value: "1" }], [])
95+ div(bump).attr("value", "1").finish()
10596 }
10697 after(bump) {
107− Node::element(bump, "div", [], [Attribute { name: "value", value: "2" }], [])
98+ div(bump).attr("value", "2").finish()
10899 }
109100 }
110101
111102 same_tag_name_remove_attribute {
112103 before(bump) {
113− Node::element(bump, "div", [], [Attribute { name: "value", value: "1" }], [])
104+ div(bump).attr("value", "1").finish()
114105 }
115106 after(bump) {
116− Node::element(bump, "div", [], [], [])
107+ div(bump).finish()
117108 }
118109 }
119110
120111 same_tag_name_add_attribute {
121112 before(bump) {
122− Node::element(bump, "div", [], [], [])
113+ div(bump).finish()
123114 }
124115 after(bump) {
125− Node::element(bump, "div", [], [Attribute { name: "value", value: "2" }], [])
116+ div(bump).attr("value", "2").finish()
126117 }
127118 }
128119
129120 same_tag_name_many_attributes {
130121 before(bump) {
131− Node::element(bump, "div", [], [
132− Attribute { name: "before-1", value: "1" },
133− Attribute { name: "shared-1", value: "1" },
134− Attribute { name: "modified-1", value: "1" },
135− Attribute { name: "before-2", value: "2" },
136− Attribute { name: "shared-2", value: "2" },
137− Attribute { name: "modified-2", value: "2" },
138− Attribute { name: "before-3", value: "3" },
139− Attribute { name: "shared-3", value: "3" },
140− Attribute { name: "modified-3", value: "3" },
141− ], [])
122+ div(bump)
123+ .attr("before-1", "1")
124+ .attr("shared-1", "1")
125+ .attr("modified-1", "1")
126+ .attr("before-2", "2")
127+ .attr("shared-2", "2")
128+ .attr("modified-2", "2")
129+ .attr("before-3", "3")
130+ .attr("shared-3", "3")
131+ .attr("modified-3", "3")
132+ .finish()
142133 }
143134 after(bump) {
144− Node::element(bump, "div", [], [
145− Attribute { name: "after-1", value: "1" },
146− Attribute { name: "shared-1", value: "1" },
147− Attribute { name: "modified-1", value: "100" },
148− Attribute { name: "after-2", value: "2" },
149− Attribute { name: "shared-2", value: "2" },
150− Attribute { name: "modified-2", value: "200" },
151− Attribute { name: "after-3", value: "3" },
152− Attribute { name: "shared-3", value: "3" },
153− Attribute { name: "modified-3", value: "300" },
154− ], [])
135+ div(bump)
136+ .attr("after-1", "1")
137+ .attr("shared-1", "1")
138+ .attr("modified-1", "100")
139+ .attr("after-2", "2")
140+ .attr("shared-2", "2")
141+ .attr("modified-2", "200")
142+ .attr("after-3", "3")
143+ .attr("shared-3", "3")
144+ .attr("modified-3", "300")
145+ .finish()
155146 }
156147 }
157148
158149 same_tag_same_children {
159150 before(bump) {
160− Node::element(bump, "div", [], [], [
161− Node::text("child")
162− ])
151+ div(bump).child(text("child")).finish()
163152 }
164153 after(bump) {
165− Node::element(bump, "div", [], [], [
166− Node::text("child")
167− ])
154+ div(bump).child(text("child")).finish()
168155 }
169156 }
170157
171158 same_tag_update_child {
172159 before(bump) {
173− Node::element(bump, "div", [], [], [
174− Node::text("before")
175− ])
160+ div(bump).child(text("before")).finish()
176161 }
177162 after(bump) {
178− Node::element(bump, "div", [], [], [
179− Node::text("after")
180− ])
163+ div(bump).child(text("after")).finish()
181164 }
182165 }
183166
184167 same_tag_add_child {
185168 before(bump) {
186− Node::element(bump, "div", [], [], [])
169+ div(bump).finish()
187170 }
188171 after(bump) {
189− Node::element(bump, "div", [], [], [
190− Node::text("child")
191− ])
172+ div(bump).child(text("child")).finish()
192173 }
193174 }
194175
195176 same_tag_remove_child {
196177 before(bump) {
197− Node::element(bump, "div", [], [], [
198− Node::text("child")
199− ])
178+ div(bump).child(text("child")).finish()
200179 }
201180 after(bump) {
202− Node::element(bump, "div", [], [], [])
181+ div(bump).finish()
203182 }
204183 }
205184
206185 same_tag_update_many_children {
207186 before(bump) {
208− Node::element(bump, "div", [], [], [
209− Node::element(bump, "div", [], [], []),
210− Node::element(bump, "span", [], [], []),
211− Node::element(bump, "p", [], [], []),
212− ])
187+ div(bump)
188+ .children([
189+ div(bump).finish(),
190+ span(bump).finish(),
191+ p(bump).finish(),
192+ ])
193+ .finish()
213194 }
214195 after(bump) {
215− Node::element(bump, "div", [], [], [
216− Node::element(bump, "span", [], [], []),
217− Node::element(bump, "p", [], [], []),
218− Node::element(bump, "div", [], [], []),
219− ])
196+ div(bump)
197+ .children([
198+ span(bump).finish(),
199+ p(bump).finish(),
200+ div(bump).finish(),
201+ ])
202+ .finish()
220203 }
221204 }
222205
223206 same_tag_remove_many_children {
224207 before(bump) {
225− Node::element(bump, "div", [], [], [
226− Node::element(bump, "div", [], [], []),
227− Node::element(bump, "span", [], [], []),
228− Node::element(bump, "p", [], [], []),
229− ])
208+ div(bump)
209+ .children([
210+ div(bump).finish(),
211+ span(bump).finish(),
212+ p(bump).finish(),
213+ ])
214+ .finish()
230215 }
231216 after(bump) {
232− Node::element(bump, "div", [], [], [
233− Node::element(bump, "div", [], [], []),
234− ])
217+ div(bump)
218+ .children([
219+ div(bump).finish(),
220+ ])
221+ .finish()
235222 }
236223 }
237224
238225 same_tag_add_many_children {
239226 before(bump) {
240− Node::element(bump, "div", [], [], [
241− Node::element(bump, "div", [], [], []),
242− ])
227+ div(bump)
228+ .children([
229+ div(bump).finish(),
230+ ])
231+ .finish()
243232 }
244233 after(bump) {
245− Node::element(bump, "div", [], [], [
246− Node::element(bump, "div", [], [], []),
247− Node::element(bump, "span", [], [], []),
248− Node::element(bump, "p", [], [], []),
249− ])
234+ div(bump)
235+ .children([
236+ div(bump).finish(),
237+ span(bump).finish(),
238+ p(bump).finish(),
239+ ])
240+ .finish()
250241 }
251242 }
252243}