on master help sign in
Merge pull request #19 from fitzgen/builder
14c6b00Nick Fitzgerald
Cargo.lock+59−59
@@ -66,7 +66,7 @@ version = "0.1.5"
66source = "registry+https://github.com/rust-lang/crates.io-index"
66source = "registry+https://github.com/rust-lang/crates.io-index"
67dependencies = [
67dependencies = [
68 "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
68 "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)",
70]
70]
71
71
72[[package]]
72[[package]]
@@ -75,7 +75,7 @@ version = "0.1.2"
75source = "registry+https://github.com/rust-lang/crates.io-index"
75source = "registry+https://github.com/rust-lang/crates.io-index"
76dependencies = [
76dependencies = [
77 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
77 "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)",
79]
79]
80
80
81[[package]]
81[[package]]
@@ -85,12 +85,12 @@ dependencies = [
85 "bumpalo 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
85 "bumpalo 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
86 "console_log 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
86 "console_log 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
87 "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
87 "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)",
89 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
89 "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)",
90+ "wasm-bindgen 0.2.36 (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)",
91+ "wasm-bindgen-futures 0.3.13 (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)",
92+ "wasm-bindgen-test 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
93− "web-sys 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
93+ "web-sys 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
94]
94]
95
95
96[[package]]
96[[package]]
@@ -101,9 +101,9 @@ dependencies = [
101 "console_log 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
101 "console_log 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
102 "dodrio 0.1.0",
102 "dodrio 0.1.0",
103 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
103 "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)",
104+ "wasm-bindgen 0.2.36 (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)",
105+ "wasm-bindgen-test 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
106− "web-sys 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
106+ "web-sys 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
107]
107]
108
108
109[[package]]
109[[package]]
@@ -112,9 +112,9 @@ version = "0.1.0"
112dependencies = [
112dependencies = [
113 "console_error_panic_hook 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
113 "console_error_panic_hook 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
114 "dodrio 0.1.0",
114 "dodrio 0.1.0",
115− "wasm-bindgen 0.2.34 (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.34 (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.11 (registry+https://github.com/rust-lang/crates.io-index)",
117+ "web-sys 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
118]
118]
119
119
120[[package]]
120[[package]]
@@ -123,9 +123,9 @@ version = "0.1.0"
123dependencies = [
123dependencies = [
124 "console_error_panic_hook 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
124 "console_error_panic_hook 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
125 "dodrio 0.1.0",
125 "dodrio 0.1.0",
126− "wasm-bindgen 0.2.34 (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.34 (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.11 (registry+https://github.com/rust-lang/crates.io-index)",
128+ "web-sys 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
129]
129]
130
130
131[[package]]
131[[package]]
@@ -137,14 +137,14 @@ dependencies = [
137 "console_log 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
137 "console_log 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
138 "dodrio 0.1.0",
138 "dodrio 0.1.0",
139 "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
139 "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)",
141 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
141 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
142 "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)",
142 "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)",
143 "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
143 "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)",
144+ "wasm-bindgen 0.2.36 (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)",
145+ "wasm-bindgen-futures 0.3.13 (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)",
146+ "wasm-bindgen-test 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
147− "web-sys 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
147+ "web-sys 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
148]
148]
149
149
150[[package]]
150[[package]]
@@ -207,10 +207,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
207
207
208[[package]]
208[[package]]
209name = "js-sys"
209name = "js-sys"
210−version = "0.3.11"
210+version = "0.3.13"
211source = "registry+https://github.com/rust-lang/crates.io-index"
211source = "registry+https://github.com/rust-lang/crates.io-index"
212dependencies = [
212dependencies = [
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)",
214]
214]
215
215
216[[package]]
216[[package]]
@@ -421,15 +421,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
421
421
422[[package]]
422[[package]]
423name = "wasm-bindgen"
423name = "wasm-bindgen"
424−version = "0.2.34"
424+version = "0.2.36"
425source = "registry+https://github.com/rust-lang/crates.io-index"
425source = "registry+https://github.com/rust-lang/crates.io-index"
426dependencies = [
426dependencies = [
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)",
428]
428]
429
429
430[[package]]
430[[package]]
431name = "wasm-bindgen-backend"
431name = "wasm-bindgen-backend"
432−version = "0.2.34"
432+version = "0.2.36"
433source = "registry+https://github.com/rust-lang/crates.io-index"
433source = "registry+https://github.com/rust-lang/crates.io-index"
434dependencies = [
434dependencies = [
435 "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
435 "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -437,62 +437,62 @@ dependencies = [
437 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
437 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
438 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
438 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
439 "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
439 "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)",
441]
441]
442
442
443[[package]]
443[[package]]
444name = "wasm-bindgen-futures"
444name = "wasm-bindgen-futures"
445−version = "0.3.11"
445+version = "0.3.13"
446source = "registry+https://github.com/rust-lang/crates.io-index"
446source = "registry+https://github.com/rust-lang/crates.io-index"
447dependencies = [
447dependencies = [
448 "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
448 "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)",
449+ "js-sys 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
450− "wasm-bindgen 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
450+ "wasm-bindgen 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
451]
451]
452
452
453[[package]]
453[[package]]
454name = "wasm-bindgen-macro"
454name = "wasm-bindgen-macro"
455−version = "0.2.34"
455+version = "0.2.36"
456source = "registry+https://github.com/rust-lang/crates.io-index"
456source = "registry+https://github.com/rust-lang/crates.io-index"
457dependencies = [
457dependencies = [
458 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
458 "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)",
460]
460]
461
461
462[[package]]
462[[package]]
463name = "wasm-bindgen-macro-support"
463name = "wasm-bindgen-macro-support"
464−version = "0.2.34"
464+version = "0.2.36"
465source = "registry+https://github.com/rust-lang/crates.io-index"
465source = "registry+https://github.com/rust-lang/crates.io-index"
466dependencies = [
466dependencies = [
467 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
467 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
468 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
468 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
469 "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
469 "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)",
470+ "wasm-bindgen-backend 0.2.36 (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)",
471+ "wasm-bindgen-shared 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
472]
472]
473
473
474[[package]]
474[[package]]
475name = "wasm-bindgen-shared"
475name = "wasm-bindgen-shared"
476−version = "0.2.34"
476+version = "0.2.36"
477source = "registry+https://github.com/rust-lang/crates.io-index"
477source = "registry+https://github.com/rust-lang/crates.io-index"
478
478
479[[package]]
479[[package]]
480name = "wasm-bindgen-test"
480name = "wasm-bindgen-test"
481−version = "0.2.34"
481+version = "0.2.36"
482source = "registry+https://github.com/rust-lang/crates.io-index"
482source = "registry+https://github.com/rust-lang/crates.io-index"
483dependencies = [
483dependencies = [
484 "console_error_panic_hook 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
484 "console_error_panic_hook 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
485 "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
485 "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)",
487 "scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
487 "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)",
488+ "wasm-bindgen 0.2.36 (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)",
489+ "wasm-bindgen-futures 0.3.13 (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)",
490+ "wasm-bindgen-test-macro 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
491]
491]
492
492
493[[package]]
493[[package]]
494name = "wasm-bindgen-test-macro"
494name = "wasm-bindgen-test-macro"
495−version = "0.2.34"
495+version = "0.2.36"
496source = "registry+https://github.com/rust-lang/crates.io-index"
496source = "registry+https://github.com/rust-lang/crates.io-index"
497dependencies = [
497dependencies = [
498 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
498 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -501,7 +501,7 @@ dependencies = [
501
501
502[[package]]
502[[package]]
503name = "wasm-bindgen-webidl"
503name = "wasm-bindgen-webidl"
504−version = "0.2.28"
504+version = "0.2.30"
505source = "registry+https://github.com/rust-lang/crates.io-index"
505source = "registry+https://github.com/rust-lang/crates.io-index"
506dependencies = [
506dependencies = [
507 "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
507 "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -510,21 +510,21 @@ dependencies = [
510 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
510 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
511 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
511 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
512 "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
512 "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)",
514 "weedle 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
514 "weedle 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
515]
515]
516
516
517[[package]]
517[[package]]
518name = "web-sys"
518name = "web-sys"
519−version = "0.3.11"
519+version = "0.3.13"
520source = "registry+https://github.com/rust-lang/crates.io-index"
520source = "registry+https://github.com/rust-lang/crates.io-index"
521dependencies = [
521dependencies = [
522 "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
522 "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
523 "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
523 "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)",
525 "sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
525 "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)",
526+ "wasm-bindgen 0.2.36 (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)",
527+ "wasm-bindgen-webidl 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)",
528]
528]
529
529
530[[package]]
530[[package]]
@@ -589,7 +589,7 @@ dependencies = [
589"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
589"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
590"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114"
590"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114"
591"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
591"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"
593"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
593"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
594"checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047"
594"checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047"
595"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
595"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
@@ -619,16 +619,16 @@ dependencies = [
619"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
619"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
620"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737"
620"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737"
621"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
621"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"
622+"checksum wasm-bindgen 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a07590bf415481c15debf0fb459e4ee7bc5f7063b3adf450cea87cfc5451ff"
623−"checksum wasm-bindgen-backend 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)" = "a566cfa6bc9802a13a49a89df84b28f2d3ac92e169c1d30fd4fdd800981ba956"
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.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3408930b9c2bf6658ecc2f4f902b5f36b1ee99d3c288fe593567f595b8ff4081"
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.34 (registry+https://github.com/rust-lang/crates.io-index)" = "01869df54a1821867d100eb1c351fad50a10248463c3097e990c3ed0fac7233a"
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.34 (registry+https://github.com/rust-lang/crates.io-index)" = "1e727ad9d3811bbf0f6d0b8b3cc784169e832ca6ed8a9190587ebfde87893d70"
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.34 (registry+https://github.com/rust-lang/crates.io-index)" = "77b13edbe385eb9b3f7f17960f6dbf0adcdb8dac422c7f14a6279426c052336f"
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.34 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2220139a62fccd897d00f2a3ef953a9fcd2082461bfa50d8a9f9c0c85a6c94"
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.34 (registry+https://github.com/rust-lang/crates.io-index)" = "12201f5a4fe123303e93efbb1f799e9577312c6e53cb00f6539ace9355b70ad5"
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.28 (registry+https://github.com/rust-lang/crates.io-index)" = "e8acb042c9989ffa6128467193bc7fe046b475a6151b9f31b0cfe7e5b313cc11"
630+"checksum wasm-bindgen-webidl 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)" = "142b34c5209bd1b6562b9fee0e4bddd1bebf00717b6cb4ccc9f0a9b3cc9f5f03"
631−"checksum web-sys 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "254e5875171dad18fda43e02054d83bc0699d447b72297110bc7c2a647572416"
631+"checksum web-sys 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "5cec4b17aece169adf93e8d05919e9ba7fb2156ebcf2280e6b5987868f287600"
632"checksum weedle 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "26a4c67f132386d965390b8a734d5d10adbcd30eb5cc74bd9229af8b83f10044"
632"checksum weedle 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "26a4c67f132386d965390b8a734d5d10adbcd30eb5cc74bd9229af8b83f10044"
633"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
633"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
634"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
634"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 = []
10[dependencies]
10[dependencies]
11bumpalo = "2.1.0"
11bumpalo = "2.1.0"
12futures = "0.1.25"
12futures = "0.1.25"
13−wasm-bindgen = "0.2.34"
13+wasm-bindgen = "0.2.36"
14−wasm-bindgen-futures = "0.3.11"
14+wasm-bindgen-futures = "0.3.13"
15−js-sys = "0.3.11"
15+js-sys = "0.3.13"
16log = "0.4.6"
16log = "0.4.6"
17
17
18[dependencies.web-sys]
18[dependencies.web-sys]
19−version = "0.3.11"
19+version = "0.3.13"
20features = [
20features = [
21 "console",
21 "console",
22 "Document",
22 "Document",
@@ -27,11 +27,11 @@ features = [
27]
27]
28
28
29[dev-dependencies]
29[dev-dependencies]
30−wasm-bindgen-test = "0.2.34"
30+wasm-bindgen-test = "0.2.36"
31console_log = "0.1.2"
31console_log = "0.1.2"
32
32
33[dev-dependencies.web-sys]
33[dev-dependencies.web-sys]
34−version = "0.3.11"
34+version = "0.3.13"
35features = [
35features = [
36 "Attr",
36 "Attr",
37 "EventTarget",
37 "EventTarget",
examples/counter/Cargo.toml+3−3
@@ -14,10 +14,10 @@ console_error_panic_hook = "0.1.5"
14console_log = "0.1.2"
14console_log = "0.1.2"
15dodrio = { path = "../.." }
15dodrio = { path = "../.." }
16log = "0.4.6"
16log = "0.4.6"
17−wasm-bindgen = "0.2.34"
17+wasm-bindgen = "0.2.36"
18
18
19[dependencies.web-sys]
19[dependencies.web-sys]
20−version = "0.3.11"
20+version = "0.3.13"
21features = [
21features = [
22 "console",
22 "console",
23 "Document",
23 "Document",
@@ -30,4 +30,4 @@ features = [
30]
30]
31
31
32[dev-dependencies]
32[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 @@
1use dodrio::bumpalo::{self, Bump};
1use dodrio::bumpalo::{self, Bump};
2−use dodrio::{on, Node, Render};
2+use dodrio::Render;
3use log::*;
3use log::*;
4use wasm_bindgen::prelude::*;
4use wasm_bindgen::prelude::*;
5
5
@@ -32,19 +32,15 @@ impl Render for Counter {
32 where
32 where
33 'a: 'bump,
33 'a: 'bump,
34 {
34 {
35+ use dodrio::builder::*;
36+
35 // Stringify the count as a bump-allocated string.
37 // Stringify the count as a bump-allocated string.
36 let count = bumpalo::format!(in bump, "{}", self.count);
38 let count = bumpalo::format!(in bump, "{}", self.count);
37
39
38− Node::element(
39− bump,
40− "div",
40+ div(bump)
41− [],
41+ .children([
42− [],
43− [
44− Node::element(
45− bump,
46− "button",
42+ button(bump)
47− [on(bump, "click", |root, vdom, _event| {
43+ .on("click", |root, vdom, _event| {
48 // Cast the root render component to a `Counter`, since
44 // Cast the root render component to a `Counter`, since
49 // we know that's what it is.
45 // we know that's what it is.
50 let counter = root.unwrap_mut::<Counter>();
46 let counter = root.unwrap_mut::<Counter>();
@@ -55,24 +51,20 @@ impl Render for Counter {
55 // Since the count has updated, we should re-render the
51 // Since the count has updated, we should re-render the
56 // counter on the next animation frame.
52 // counter on the next animation frame.
57 vdom.schedule_render();
53 vdom.schedule_render();
58− })],
54+ })
59− [],
60− [Node::text("+")],
55+ .children([text("+")])
61− ),
56+ .finish(),
62− Node::text(count.into_bump_str()),
57+ text(count.into_bump_str()),
63− Node::element(
64− bump,
65− "button",
58+ button(bump)
66− [on(bump, "click", |root, vdom, _event| {
59+ .on("click", |root, vdom, _event| {
67 // Same as above, but decrementing instead of incrementing.
60 // Same as above, but decrementing instead of incrementing.
68 root.unwrap_mut::<Counter>().decrement();
61 root.unwrap_mut::<Counter>().decrement();
69 vdom.schedule_render();
62 vdom.schedule_render();
70− })],
63+ })
71− [],
72− [Node::text("-")],
64+ .children([text("-")])
73− ),
65+ .finish(),
74− ],
66+ ])
75− )
67+ .finish()
76 }
68 }
77}
69}
78
70
examples/hello-world/Cargo.toml+3−3
@@ -11,11 +11,11 @@ crate-type = ["cdylib"]
11
11
12[dependencies]
12[dependencies]
13dodrio = { path = "../.." }
13dodrio = { path = "../.." }
14−wasm-bindgen = "0.2.34"
14+wasm-bindgen = "0.2.36"
15console_error_panic_hook = "0.1.5"
15console_error_panic_hook = "0.1.5"
16
16
17[dependencies.web-sys]
17[dependencies.web-sys]
18−version = "0.3.11"
18+version = "0.3.13"
19features = [
19features = [
20 "Document",
20 "Document",
21 "HtmlElement",
21 "HtmlElement",
@@ -24,4 +24,4 @@ features = [
24]
24]
25
25
26[dev-dependencies]
26[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> {
15 where
15 where
16 'a: 'bump,
16 'a: 'bump,
17 {
17 {
18− Node::element(
18+ use dodrio::builder::*;
19− bump,
19+ p(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("!")],
20+ .children([text("Hello, "), text(self.who), text("!")])
28− )
21+ .finish()
29 }
22 }
30}
23}
31
24
examples/input-form/Cargo.toml+3−3
@@ -11,11 +11,11 @@ crate-type = ["cdylib"]
11
11
12[dependencies]
12[dependencies]
13dodrio = { path = "../.." }
13dodrio = { path = "../.." }
14−wasm-bindgen = "0.2.34"
14+wasm-bindgen = "0.2.36"
15console_error_panic_hook = "0.1.5"
15console_error_panic_hook = "0.1.5"
16
16
17[dependencies.web-sys]
17[dependencies.web-sys]
18−version = "0.3.11"
18+version = "0.3.13"
19features = [
19features = [
20 "console",
20 "console",
21 "Document",
21 "Document",
@@ -29,4 +29,4 @@ features = [
29]
29]
30
30
31[dev-dependencies]
31[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 @@
1use dodrio::bumpalo::{self, Bump};
1use dodrio::bumpalo::{self, Bump};
2−use dodrio::{on, Attribute, Node, Render};
2+use dodrio::{Node, Render};
3use wasm_bindgen::prelude::*;
3use wasm_bindgen::prelude::*;
4use wasm_bindgen::JsCast;
4use wasm_bindgen::JsCast;
5
5
@@ -25,48 +25,39 @@ impl SayHelloTo {
25// The `Render` implementation has a text `<input>` and a `<div>` that shows a
25// The `Render` implementation has a text `<input>` and a `<div>` that shows a
26// greeting to the `<input>`'s value.
26// greeting to the `<input>`'s value.
27impl Render for SayHelloTo {
27impl 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>
29 where
29 where
30 'a: 'bump,
30 'a: 'bump,
31 {
31 {
32− let input = Node::element(
32+ use dodrio::builder::*;
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− };
44
33
45− // ...then get its value and update who we are greeting.
34+ div(bump)
46− let value = input.value();
35+ .children([
47− let hello = root.unwrap_mut::<SayHelloTo>();
36+ input(bump)
48− hello.set_who(value);
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+ };
49
48
50− // Finally, re-render the component on the next animation frame.
49+ // ...then get its value and update who we are greeting.
51− vdom.schedule_render();
50+ let value = input.value();
52− })],
51+ let hello = root.unwrap_mut::<SayHelloTo>();
53− [
52+ hello.set_who(value);
54− Attribute {
55− name: "type",
56− value: "text",
57− },
58− Attribute {
59− name: "value",
60− value: &self.who,
61− },
62− ],
63− [],
64− );
65
53
54+ // Finally, re-render the component on the next animation frame.
55+ vdom.schedule_render();
56+ })
57+ .finish(),
66− let hello = bumpalo::format!(in bump, "Hello, {}!", self.who);
58+ text(bumpalo::format!(in bump, "Hello, {}!", self.who).into_bump_str()),
67− let hello = Node::text(hello.into_bump_str());
59+ ])
68−
60+ .finish()
69− Node::element(bump, "div", [], [], [input, hello])
70 }
61 }
71}
62}
72
63
examples/todomvc/Cargo.toml+5−5
@@ -8,11 +8,11 @@ version = "0.1.0"
8cfg-if = "0.1.6"
8cfg-if = "0.1.6"
9dodrio = { path = "../.." }
9dodrio = { path = "../.." }
10futures = "0.1.25"
10futures = "0.1.25"
11−js-sys = "0.3.11"
11+js-sys = "0.3.13"
12serde = { features = ["derive"], version = "1.0.87" }
12serde = { features = ["derive"], version = "1.0.87" }
13serde_json = "1.0.38"
13serde_json = "1.0.38"
14−wasm-bindgen = "0.2.34"
14+wasm-bindgen = "0.2.36"
15−wasm-bindgen-futures = "0.3.11"
15+wasm-bindgen-futures = "0.3.13"
16
16
17# Optional dependencies for logging.
17# Optional dependencies for logging.
18console_error_panic_hook = { optional = true, version = "0.1.5" }
18console_error_panic_hook = { optional = true, version = "0.1.5" }
@@ -20,7 +20,7 @@ console_log = { optional = true, version = "0.1.2" }
20log = { optional = true, version = "0.4.6" }
20log = { optional = true, version = "0.4.6" }
21
21
22[dependencies.web-sys]
22[dependencies.web-sys]
23−version = "0.3.11"
23+version = "0.3.13"
24features = [
24features = [
25 "Document",
25 "Document",
26 "Event",
26 "Event",
@@ -35,7 +35,7 @@ features = [
35]
35]
36
36
37[dev-dependencies]
37[dev-dependencies]
38−wasm-bindgen-test = "0.2.34"
38+wasm-bindgen-test = "0.2.36"
39
39
40[features]
40[features]
41logging = [
41logging = [
examples/todomvc/src/lib.rs+2−2
@@ -10,9 +10,9 @@ pub mod todos;
10pub mod utils;
10pub mod utils;
11pub mod visibility;
11pub mod visibility;
12
12
13−use controller::Controller;
13+use crate::controller::Controller;
14+use crate::todos::Todos;
14use dodrio::Vdom;
15use dodrio::Vdom;
15−use todos::Todos;
16use wasm_bindgen::prelude::*;
16use wasm_bindgen::prelude::*;
17
17
18/// Run the TodoMVC app!
18/// Run the TodoMVC app!
examples/todomvc/src/todo.rs+70−124
@@ -1,7 +1,7 @@
1//! Type definition and `dodrio::Render` implementation for a single todo item.
1//! Type definition and `dodrio::Render` implementation for a single todo item.
2
2
3use crate::keys;
3use crate::keys;
4−use dodrio::{bumpalo::Bump, on, Attribute, Node, Render, RootRender, VdomWeak};
4+use dodrio::{bumpalo::Bump, Node, Render, RootRender, VdomWeak};
5use serde::{Deserialize, Serialize};
5use serde::{Deserialize, Serialize};
6use std::marker::PhantomData;
6use std::marker::PhantomData;
7use wasm_bindgen::{prelude::*, JsCast};
7use wasm_bindgen::{prelude::*, JsCast};
@@ -93,137 +93,83 @@ impl<C> Todo<C> {
93}
93}
94
94
95impl<C: TodoActions> Render for Todo<C> {
95impl<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>
97 where
97 where
98 'a: 'bump,
98 'a: 'bump,
99 {
99 {
100+ use dodrio::{
101+ builder::*,
100− use dodrio::bumpalo::{self, collections::String};
102+ bumpalo::{self, collections::String},
101−
102− let mut class = String::new_in(bump);
103− if self.completed {
104− class.push_str("completed ");
105− }
103+ };
106− if self.edits.is_some() {
107− class.push_str("editing");
108− }
109
104
110 let id = self.id;
105 let id = self.id;
111 let title = self.edits.as_ref().unwrap_or(&self.title);
106 let title = self.edits.as_ref().unwrap_or(&self.title);
112− let elem_id = bumpalo::format!(in bump, "todo-{}", id);
107+
113−
108+ li(bump)
114− let mut input_attrs = bumpalo::vec![
109+ .attr("class", {
115− in bump;
110+ let mut class = String::new_in(bump);
116− Attribute {
111+ if self.completed {
117− name: "class",
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)
118− value: "toggle",
124+ .attr("class", "toggle")
119− },
120− Attribute {
121− name: "type",
122− value: "checkbox",
125+ .attr("type", "checkbox")
123− }
126+ .bool_attr("checked", self.completed)
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| {
127+ .on("click", move |root, vdom, _event| {
155 C::toggle_completed(root, vdom, id);
128 C::toggle_completed(root, vdom, id);
156− })],
129+ })
157− input_attrs,
130+ .finish(),
158− [],
159− ),
160− Node::element(
161− bump,
162− "label",
131+ label(bump)
163− [on(bump, "dblclick", move |root, vdom, _event| {
132+ .on("dblclick", move |root, vdom, _event| {
164 C::begin_editing(root, vdom, id);
133 C::begin_editing(root, vdom, id);
165− })],
134+ })
166− [],
167− [Node::text(title)],
135+ .children([text(title)])
168− ),
136+ .finish(),
169− Node::element(
170− bump,
171− "button",
137+ button(bump)
138+ .attr("class", "destroy")
172− [on(bump, "click", move |root, vdom, _event| {
139+ .on("click", move |root, vdom, _event| {
173 C::delete(root, vdom, id);
140 C::delete(root, vdom, id);
174− })],
141+ })
175− [Attribute {
142+ .finish(),
143+ ])
144+ .finish(),
145+ input(bump)
176− name: "class",
146+ .attr("class", "edit")
177− value: "destroy",
147+ .attr("value", title)
178− }],
148+ .attr("name", "title")
179− [],
149+ .attr(
180− ),
150+ "id",
181− ],
151+ bumpalo::format!(in bump, "todo-{}", id).into_bump_str(),
182− ),
152+ )
183− Node::element(
184− bump,
185− "input",
186− [
187− on(bump, "input", move |root, vdom, event| {
153+ .on("input", move |root, vdom, event| {
188− let input = event
154+ let input = event
189− .target()
155+ .target()
190− .unwrap_throw()
156+ .unwrap_throw()
191− .unchecked_into::<web_sys::HtmlInputElement>();
157+ .unchecked_into::<web_sys::HtmlInputElement>();
192− C::update_edits(root, vdom, id, input.value());
158+ C::update_edits(root, vdom, id, input.value());
193− }),
159+ })
194− on(bump, "blur", move |root, vdom, _event| {
160+ .on("blur", move |root, vdom, _event| {
195− C::finish_edits(root, vdom, id);
161+ C::finish_edits(root, vdom, id);
196− }),
162+ })
197− on(bump, "keydown", move |root, vdom, event| {
163+ .on("keydown", move |root, vdom, event| {
198− let event = event.unchecked_into::<web_sys::KeyboardEvent>();
164+ let event = event.unchecked_into::<web_sys::KeyboardEvent>();
199− match event.key_code() {
165+ match event.key_code() {
200− keys::ENTER => C::finish_edits(root, vdom, id),
166+ keys::ENTER => C::finish_edits(root, vdom, id),
201− keys::ESCAPE => C::cancel_edits(root, vdom, id),
167+ keys::ESCAPE => C::cancel_edits(root, vdom, id),
202− _ => {}
168+ _ => {}
203− }
204− }),
169+ }
205− ],
206− [
207− Attribute {
208− name: "class",
209− value: "edit",
210− },
170+ })
211− Attribute {
171+ .finish(),
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− ),
172+ ])
226− ],
173+ .finish()
227− )
228 }
174 }
229}
175}
examples/todomvc/src/todos.rs+108−242
@@ -7,7 +7,7 @@ use crate::visibility::Visibility;
7use crate::{keys, utils};
7use crate::{keys, utils};
8use dodrio::{
8use dodrio::{
9 bumpalo::{self, Bump},
9 bumpalo::{self, Bump},
10− on, Attribute, Node, Render, RootRender, VdomWeak,
10+ Node, Render, RootRender, VdomWeak,
11};
11};
12use serde::{Deserialize, Serialize};
12use serde::{Deserialize, Serialize};
13use std::marker::PhantomData;
13use std::marker::PhantomData;
@@ -140,65 +140,42 @@ impl<C: TodosActions> Todos<C> {
140 where
140 where
141 'a: 'bump,
141 'a: 'bump,
142 {
142 {
143− Node::element(
143+ use dodrio::builder::*;
144− bump,
144+
145− "header",
145+ header(bump)
146− [],
147− [Attribute {
148− name: "class",
149− value: "header",
146+ .attr("class", "header")
150− }],
147+ .children([
151− [
148+ h1(bump).children([text("todos")]).finish(),
152− Node::element(bump, "h1", [], [], [Node::text("todos")]),
153− Node::element(
154− bump,
149+ input(bump)
155− "input",
156− [
157− on(bump, "input", |root, vdom, event| {
150+ .on("input", |root, vdom, event| {
158− let input = event
151+ let input = event
159− .target()
152+ .target()
160− .unwrap_throw()
153+ .unwrap_throw()
161− .unchecked_into::<web_sys::HtmlInputElement>();
154+ .unchecked_into::<web_sys::HtmlInputElement>();
162− C::update_draft(root, vdom, input.value());
155+ C::update_draft(root, vdom, input.value());
163− }),
156+ })
164− on(bump, "keydown", |root, vdom, event| {
157+ .on("keydown", |root, vdom, event| {
165− let event = event.unchecked_into::<web_sys::KeyboardEvent>();
158+ let event = event.unchecked_into::<web_sys::KeyboardEvent>();
166− if event.key_code() == keys::ENTER {
159+ if event.key_code() == keys::ENTER {
167− C::finish_draft(root, vdom);
160+ C::finish_draft(root, vdom);
168− }
169− }),
161+ }
170− ],
162+ })
171− [
172− Attribute {
173− name: "class",
174− value: "new-todo",
163+ .attr("class", "new-todo")
175− },
176− Attribute {
177− name: "placeholder",
178− value: "What needs to be done?",
164+ .attr("placeholder", "What needs to be done?")
179− },
180− Attribute {
181− name: "autofocus",
165+ .attr("autofocus", "")
182− value: "",
183− },
184− Attribute {
185− name: "value",
186− value: &self.draft,
166+ .attr("value", &self.draft)
187− },
167+ .finish(),
188− ],
189− [],
190− ),
191− ],
168+ ])
192− )
169+ .finish()
193 }
170 }
194
171
195 fn todos_list<'a, 'bump>(&'a self, bump: &'bump Bump) -> Node<'bump>
172 fn todos_list<'a, 'bump>(&'a self, bump: &'bump Bump) -> Node<'bump>
196 where
173 where
197 'a: 'bump,
174 'a: 'bump,
198 {
175 {
199− use dodrio::bumpalo::collections::Vec;
176+ use dodrio::{builder::*, bumpalo::collections::Vec};
200
177
201− let mut todos = Vec::new_in(bump);
178+ let mut todos = Vec::with_capacity_in(self.todos.len(), bump);
202 todos.extend(
179 todos.extend(
203 self.todos
180 self.todos
204 .iter()
181 .iter()
@@ -209,91 +186,43 @@ impl<C: TodosActions> Todos<C> {
209 })
186 })
210 .map(|t| t.render(bump)),
187 .map(|t| t.render(bump)),
211 );
188 );
212− let todos = todos.into_bump_slice();
189+
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",
190+ section(bump)
244− [],
245− [
246− Attribute {
247− name: "class",
191+ .attr("class", "main")
248− value: "main",
192+ .attr(
249− },
250− Attribute {
251− name: "visibility",
193+ "visibility",
252− value: if self.todos.is_empty() {
194+ if self.todos.is_empty() {
253− "hidden"
195+ "hidden"
254− } else {
196+ } else {
255− "visible"
197+ "visible"
256− },
257 },
198 },
258− ],
199+ )
259− [
200+ .children([
260− Node::element(
261− bump,
262− "input",
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()))
263− [on(bump, "click", |root, vdom, _event| {
207+ .on("click", |root, vdom, _event| {
264 C::toggle_all(root, vdom);
208 C::toggle_all(root, vdom);
265− })],
209+ })
266− input_attrs,
210+ .finish(),
267− [],
268− ),
269− Node::element(
270− bump,
271− "label",
211+ label(bump)
272− [],
273− [Attribute {
274− name: "for",
275− value: "toggle-all",
212+ .attr("for", "toggle-all")
276− }],
277− [Node::text("Mark all as complete")],
213+ .children([text("Mark all as complete")])
278− ),
214+ .finish(),
279− Node::element(
215+ ul(bump).attr("class", "todo-list").children(todos).finish(),
280− bump,
281− "ul",
282− [],
283− [Attribute {
284− name: "class",
285− value: "todo-list",
286− }],
287− todos,
288− ),
289− ],
216+ ])
290− )
217+ .finish()
291 }
218 }
292
219
293 fn footer<'a, 'bump>(&'a self, bump: &'bump Bump) -> Node<'bump>
220 fn footer<'a, 'bump>(&'a self, bump: &'bump Bump) -> Node<'bump>
294 where
221 where
295 'a: 'bump,
222 'a: 'bump,
296 {
223 {
224+ use dodrio::builder::*;
225+
297 let completed_count = self.todos.iter().filter(|t| t.is_complete()).count();
226 let completed_count = self.todos.iter().filter(|t| t.is_complete()).count();
298 let incomplete_count = self.todos.len() - completed_count;
227 let incomplete_count = self.todos.len() - completed_count;
299 let items_left = if incomplete_count == 1 {
228 let items_left = if incomplete_count == 1 {
@@ -303,95 +232,43 @@ impl<C: TodosActions> Todos<C> {
303 };
232 };
304 let incomplete_count = bumpalo::format!(in bump, "{}", incomplete_count);
233 let incomplete_count = bumpalo::format!(in bump, "{}", incomplete_count);
305
234
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−
324 let clear_completed_text = bumpalo::format!(
235 let clear_completed_text = bumpalo::format!(
325 in bump,
236 in bump,
326 "Clear completed ({})",
237 "Clear completed ({})",
327 self.todos.iter().filter(|t| t.is_complete()).count()
238 self.todos.iter().filter(|t| t.is_complete()).count()
328 );
239 );
329
240
330− Node::element(
331− bump,
241+ footer(bump)
332− "footer",
242+ .attr("class", "footer")
333− [],
243+ .bool_attr("hidden", self.todos.is_empty())
334− attrs,
244+ .children([
335− [
336− Node::element(
337− bump,
338− "span",
245+ span(bump)
339− [],
340− [Attribute {
341− name: "class",
342− value: "todo-count",
246+ .attr("class", "todo-count")
343− }],
247+ .children([
344− [
345− Node::element(
346− bump,
347− "strong",
248+ strong(bump)
348− [],
349− [],
350− [Node::text(incomplete_count.into_bump_str())],
249+ .children([text(incomplete_count.into_bump_str())])
351− ),
250+ .finish(),
352− Node::text(items_left),
251+ text(items_left),
353− ],
252+ ])
354− ),
253+ .finish(),
355− Node::element(
356− bump,
357− "ul",
254+ ul(bump)
358− [],
359− [Attribute {
360− name: "class",
361− value: "filters",
255+ .attr("class", "filters")
362− }],
256+ .children([
363− [
364 self.visibility_swap(bump, "#/", Visibility::All),
257 self.visibility_swap(bump, "#/", Visibility::All),
365 self.visibility_swap(bump, "#/active", Visibility::Active),
258 self.visibility_swap(bump, "#/active", Visibility::Active),
366 self.visibility_swap(bump, "#/completed", Visibility::Completed),
259 self.visibility_swap(bump, "#/completed", Visibility::Completed),
367− ],
260+ ])
368− ),
261+ .finish(),
369− Node::element(
370− bump,
371− "button",
262+ button(bump)
372− [on(bump, "click", |root, vdom, _event| {
263+ .on("click", |root, vdom, _event| {
373 C::delete_completed(root, vdom);
264 C::delete_completed(root, vdom);
374− })],
265+ })
375− {
376− let mut attrs = bumpalo::vec![
377− in bump;
378− Attribute {
379− name: "class",
380− value: "clear-completed",
266+ .attr("class", "clear-completed")
381− }
267+ .bool_attr("hidden", completed_count == 0)
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())],
268+ .children([text(clear_completed_text.into_bump_str())])
392− ),
269+ .finish(),
393− ],
270+ ])
394− )
271+ .finish()
395 }
272 }
396
273
397 fn visibility_swap<'a, 'bump>(
274 fn visibility_swap<'a, 'bump>(
@@ -403,34 +280,25 @@ impl<C: TodosActions> Todos<C> {
403 where
280 where
404 'a: 'bump,
281 'a: 'bump,
405 {
282 {
406− Node::element(
283+ use dodrio::builder::*;
407− bump,
284+
408− "li",
285+ li(bump)
409− [on(bump, "click", move |root, vdom, _event| {
286+ .on("click", move |root, vdom, _event| {
410 C::change_visibility(root, vdom, target_vis);
287 C::change_visibility(root, vdom, target_vis);
411− })],
288+ })
412− [],
413− [Node::element(
414− bump,
289+ .children([a(bump)
415− "a",
416− [],
417− [
418− Attribute {
419− name: "href",
290+ .attr("href", url)
420− value: url,
291+ .attr(
421− },
422− Attribute {
423− name: "class",
292+ "class",
424− value: if self.visibility == target_vis {
293+ if self.visibility == target_vis {
425− "selected"
294+ "selected"
426− } else {
295+ } else {
427− ""
296+ ""
428− },
429 },
297 },
430− ],
298+ )
431− [Node::text(target_vis.label())],
299+ .children([text(target_vis.label())])
432− )],
300+ .finish()])
433− )
301+ .finish()
434 }
302 }
435}
303}
436
304
@@ -439,12 +307,10 @@ impl<C: TodosActions> Render for Todos<C> {
439 where
307 where
440 'a: 'bump,
308 'a: 'bump,
441 {
309 {
442− Node::element(
310+ use dodrio::builder::*;
443− bump,
311+
444− "div",
312+ div(bump)
445− [],
446− [],
447− [self.header(bump), self.todos_list(bump), self.footer(bump)],
313+ .children([self.header(bump), self.todos_list(bump), self.footer(bump)])
448− )
314+ .finish()
449 }
315 }
450}
316}
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> {
89 /// where
89 /// where
90 /// 'a: 'bump,
90 /// 'a: 'bump,
91 /// {
91 /// {
92− /// Node::element(bump, "p", [], [], [
92+ /// use dodrio::builder::*;
93− /// Node::text("Hello, "),
93+ /// p(bump)
94− /// Node::text(&self.who),
94+ /// .children([text("Hello, "), text(&self.who), text("!")])
95− /// Node::text("!"),
96− /// ])
95+ /// .finish()
97 /// }
96 /// }
98 /// }
97 /// }
99 ///
98 ///
src/lib.rs+24−28
@@ -3,7 +3,7 @@
3//! ## Example
3//! ## Example
4//!
4//!
5//! ```no_run
5//! ```no_run
6−//! use dodrio::{on, bumpalo::Bump, Attribute, Node, Render};
6+//! use dodrio::{bumpalo::Bump, Attribute, Node, Render};
7//! use wasm_bindgen::UnwrapThrowExt;
7//! use wasm_bindgen::UnwrapThrowExt;
8//!
8//!
9//! /// A component that greets someone.
9//! /// A component that greets someone.
@@ -23,34 +23,28 @@
23//! where
23//! where
24//! 'a: 'bump,
24//! 'a: 'bump,
25//! {
25//! {
26+//! use dodrio::builder::*;
27+//!
26//! let id = bumpalo::format!(in bump, "hello-{}", self.who);
28//! let id = bumpalo::format!(in bump, "hello-{}", self.who);
27−//! Node::element(
29+//!
28−//! bump,
30+//! div(bump)
29−//! // The element's tag name. In this case a `<p>` element.
31+//! .attr("id", id.into_bump_str())
30−//! "p",
31−//! // Listeners.
32−//! [on(bump, "click", |root, _vdom, _event| {
32+//! .on("click", |root, _vdom, _event| {
33//! let hello = root.unwrap_mut::<Hello>();
33//! let hello = root.unwrap_mut::<Hello>();
34+//! web_sys::window()
34−//! let window = web_sys::window().expect_throw("should have a `Window` on the Web");
35+//! .expect_throw("should have a `Window` on the Web")
35−//! window.alert_with_message(hello.who);
36+//! .alert_with_message(hello.who);
36−//! })],
37+//! })
37−//! // Attributes.
38+//! .children([
38−//! [Attribute { name: "id", value: id.into_bump_str() }],
39−//! // Child nodes.
40−//! [
41−//! Node::text("Hello, "),
39+//! text("Hello, "),
42−//! Node::element(
43−//! bump,
40+//! strong(bump)
44−//! "strong",
45−//! [],
41+//! .children([
46−//! [],
47−//! [
48−//! Node::text(self.who),
42+//! text(self.who),
49−//! Node::text("!"),
43+//! text("!"),
50−//! ],
44+//! ])
51−//! ),
45+//! .finish(),
52−//! ],
46+//! ])
53−//! )
47+//! .finish()
54//! }
48//! }
55//! }
49//! }
56//! ```
50//! ```
@@ -69,8 +63,10 @@ mod node;
69mod render;
63mod render;
70mod vdom;
64mod vdom;
71
65
66+pub mod builder;
67+
72// Re-export items at the top level.
68// Re-export items at the top level.
73pub use self::cached::Cached;
69pub 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};
75pub use self::render::{Render, RootRender};
71pub use self::render::{Render, RootRender};
76pub use self::vdom::{Vdom, VdomWeak};
72pub use self::vdom::{Vdom, VdomWeak};
src/node.rs+18−24
@@ -43,19 +43,17 @@ pub type ListenerCallback<'a> =
43/// An event listener.
43/// An event listener.
44pub struct Listener<'a> {
44pub struct Listener<'a> {
45 /// The type of event to listen for.
45 /// The type of event to listen for.
46− pub event: &'a str,
46+ pub(crate) event: &'a str,
47 /// The callback to invoke when the event happens.
47 /// The callback to invoke when the event happens.
48− pub callback: ListenerCallback<'a>,
48+ pub(crate) callback: ListenerCallback<'a>,
49}
49}
50
50
51/// An attribute on a DOM node, such as `id="my-thing"` or
51/// An attribute on a DOM node, such as `id="my-thing"` or
52/// `href="https://example.com"`.
52/// `href="https://example.com"`.
53#[derive(Clone, Debug)]
53#[derive(Clone, Debug)]
54pub struct Attribute<'a> {
54pub struct Attribute<'a> {
55− /// The attribute name, such as `id`.
56− pub name: &'a str,
55+ pub(crate) name: &'a str,
57− /// The attribute value, such as `"my-thing"`.
58− pub value: &'a str,
56+ pub(crate) value: &'a str,
59}
57}
60
58
61impl fmt::Debug for Listener<'_> {
59impl fmt::Debug for Listener<'_> {
@@ -71,6 +69,18 @@ impl fmt::Debug for Listener<'_> {
71}
69}
72
70
73impl<'a> Attribute<'a> {
71impl<'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+
74 /// Certain attributes are considered "volatile" and can change via user
84 /// Certain attributes are considered "volatile" and can change via user
75 /// input that we can't see when diffing against the old virtual DOM. For
85 /// input that we can't see when diffing against the old virtual DOM. For
76 /// these attributes, we want to always re-set the attribute on the physical
86 /// these attributes, we want to always re-set the attribute on the physical
@@ -87,7 +97,7 @@ impl<'a> Attribute<'a> {
87impl<'a> Node<'a> {
97impl<'a> Node<'a> {
88 /// Construct a new element node with the given tag name and children.
98 /// Construct a new element node with the given tag name and children.
89 #[inline]
99 #[inline]
90− pub fn element<Listeners, Attributes, Children>(
100+ pub(crate) fn element<Listeners, Attributes, Children>(
91 bump: &'a Bump,
101 bump: &'a Bump,
92 tag_name: &'a str,
102 tag_name: &'a str,
93 listeners: Listeners,
103 listeners: Listeners,
@@ -134,7 +144,7 @@ impl<'a> Node<'a> {
134
144
135 /// Construct a new text node with the given text.
145 /// Construct a new text node with the given text.
136 #[inline]
146 #[inline]
137− pub fn text(text: &'a str) -> Node<'a> {
147+ pub(crate) fn text(text: &'a str) -> Node<'a> {
138 Node::Text(TextNode { text })
148 Node::Text(TextNode { text })
139 }
149 }
140}
150}
@@ -186,19 +196,3 @@ impl Listener<'_> {
186 }
196 }
187 }
197 }
188}
198}
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;
36/// where
36/// where
37/// 'a: 'bump
37/// 'a: 'bump
38/// {
38/// {
39+/// use dodrio::builder::*;
40+///
41+/// p(bump)
42+/// .children([
39−/// Node::text("This is my component rendered!")
43+/// text("This is "),
44+/// strong(bump).children([text("my component")]).finish(),
45+/// text(" rendered!"),
46+/// ])
47+/// .finish()
40/// }
48/// }
41/// }
49/// }
42/// ```
50/// ```
tests/web/cached.rs+8−6
@@ -1,5 +1,5 @@
1use super::{assert_rendered, create_element, RenderFn};
1use 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};
3use futures::prelude::*;
3use futures::prelude::*;
4use std::cell::Cell;
4use std::cell::Cell;
5use std::rc::Rc;
5use std::rc::Rc;
@@ -27,12 +27,14 @@ impl Render for CountRenders {
27 self.render_count.set(count);
27 self.render_count.set(count);
28
28
29 let s = bumpalo::format!(in bump, "{}", count);
29 let s = bumpalo::format!(in bump, "{}", count);
30− Node::text(s.into_bump_str())
30+ text(s.into_bump_str())
31 }
31 }
32}
32}
33
33
34#[wasm_bindgen_test(async)]
34#[wasm_bindgen_test(async)]
35fn uses_cached_render() -> impl Future<Item = (), Error = JsValue> {
35fn uses_cached_render() -> impl Future<Item = (), Error = JsValue> {
36+ use dodrio::builder::*;
37+
36 let cached = Cached::new(CountRenders::new());
38 let cached = Cached::new(CountRenders::new());
37
39
38 let container0 = create_element("div");
40 let container0 = create_element("div");
@@ -58,7 +60,7 @@ fn uses_cached_render() -> impl Future<Item = (), Error = JsValue> {
58 vdom0.weak().with_component(move |comp| {
60 vdom0.weak().with_component(move |comp| {
59 let comp = comp.unwrap_mut::<Cached<CountRenders>>();
61 let comp = comp.unwrap_mut::<Cached<CountRenders>>();
60 assert_eq!(comp.render_count.get(), 1);
62 assert_eq!(comp.render_count.get(), 1);
61− assert_rendered(&container1, &RenderFn(|_| Node::text("1")));
63+ assert_rendered(&container1, &RenderFn(|_| text("1")));
62 })
64 })
63 })
65 })
64 // We re-render, re-use the cached node, and get "1" again.
66 // 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> {
67 vdom2.weak().with_component(move |comp| {
69 vdom2.weak().with_component(move |comp| {
68 let comp = comp.unwrap_mut::<Cached<CountRenders>>();
70 let comp = comp.unwrap_mut::<Cached<CountRenders>>();
69 assert_eq!(comp.render_count.get(), 1);
71 assert_eq!(comp.render_count.get(), 1);
70− assert_rendered(&container2, &RenderFn(|_| Node::text("1")));
72+ assert_rendered(&container2, &RenderFn(|_| text("1")));
71 })
73 })
72 })
74 })
73 // We invalidate the cache, re-render, re-populate the cache, and should
75 // 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> {
83 vdom5.weak().with_component(move |comp| {
85 vdom5.weak().with_component(move |comp| {
84 let comp = comp.unwrap_mut::<Cached<CountRenders>>();
86 let comp = comp.unwrap_mut::<Cached<CountRenders>>();
85 assert_eq!(comp.render_count.get(), 2);
87 assert_eq!(comp.render_count.get(), 2);
86− assert_rendered(&container3, &RenderFn(|_| Node::text("2")));
88+ assert_rendered(&container3, &RenderFn(|_| text("2")));
87 })
89 })
88 })
90 })
89 // We re-render, re-use the cached node, and get "2" again.
91 // 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> {
92 vdom7.weak().with_component(move |comp| {
94 vdom7.weak().with_component(move |comp| {
93 let comp = comp.unwrap_mut::<Cached<CountRenders>>();
95 let comp = comp.unwrap_mut::<Cached<CountRenders>>();
94 assert_eq!(comp.render_count.get(), 2);
96 assert_eq!(comp.render_count.get(), 2);
95− assert_rendered(&container4, &RenderFn(|_| Node::text("2")));
97+ assert_rendered(&container4, &RenderFn(|_| text("2")));
96 })
98 })
97 })
99 })
98 .map_err(|e| JsValue::from(e.to_string()))
100 .map_err(|e| JsValue::from(e.to_string()))
tests/web/events.rs+23−46
@@ -1,6 +1,6 @@
1use super::create_element;
1use super::create_element;
2use bumpalo::Bump;
2use bumpalo::Bump;
3−use dodrio::{on, Attribute, Node, Render, Vdom};
3+use dodrio::{Node, Render, Vdom};
4use futures::Future;
4use futures::Future;
5use std::cell::{Cell, RefCell};
5use std::cell::{Cell, RefCell};
6use std::rc::Rc;
6use std::rc::Rc;
@@ -30,18 +30,13 @@ impl Render for EventContainer {
30 where
30 where
31 'a: 'bump,
31 'a: 'bump,
32 {
32 {
33− Node::element(
33+ use dodrio::builder::*;
34− bump,
35− "div",
34+ div(bump)
35+ .attr("id", "target")
36− [on(bump, self.event, |root, _scheduler, _event| {
36+ .on(self.event, |root, _scheduler, _event| {
37 (root.unwrap_mut::<EventContainer>().on_event)();
37 (root.unwrap_mut::<EventContainer>().on_event)();
38− })],
38+ })
39− [Attribute {
39+ .finish()
40− name: "id",
41− value: "target",
42− }],
43− [],
44− )
45 }
40 }
46}
41}
47
42
@@ -147,33 +142,18 @@ impl Render for ListensOnlyOnFirstRender {
147 where
142 where
148 'a: 'bump,
143 'a: 'bump,
149 {
144 {
145+ use dodrio::builder::*;
146+
150 let count = self.count.get();
147 let count = self.count.get();
151 self.count.set(count + 1);
148 self.count.set(count + 1);
149+
150+ let mut elem = div(bump).attr("id", "target");
152 if count == 0 {
151 if count == 0 {
153− Node::element(
154− bump,
155− "div",
156− [on(bump, "click", |root, _scheduler, _event| {
152+ elem = elem.on("click", |root, _scheduler, _event| {
157− (root.unwrap_mut::<ListensOnlyOnFirstRender>().callback)();
153+ (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− )
154+ });
176 }
155 }
156+ elem.finish()
177 }
157 }
178}
158}
179
159
@@ -315,23 +295,20 @@ impl Render for CountRendersAndListen {
315 where
295 where
316 'a: 'bump,
296 'a: 'bump,
317 {
297 {
298+ use dodrio::builder::*;
299+
318 let count = self.count.get() + 1;
300 let count = self.count.get() + 1;
319 self.count.set(count);
301 self.count.set(count);
320− Node::element(
302+
321− bump,
322− "button",
303+ button(bump)
304+ .attr("id", "target")
323− [on(bump, "click", |comp, _vdom, _event| {
305+ .on("click", |comp, _vdom, _event| {
324 let comp: &mut _ = comp.unwrap_mut::<dodrio::Cached<CountRendersAndListen>>();
306 let comp: &mut _ = comp.unwrap_mut::<dodrio::Cached<CountRendersAndListen>>();
325 let comp: &mut CountRendersAndListen = comp;
307 let comp: &mut CountRendersAndListen = comp;
326 let n = comp.count.get();
308 let n = comp.count.get();
327 (comp.callback)(n);
309 (comp.callback)(n);
328− })],
310+ })
329− [Attribute {
311+ .finish()
330− name: "id",
331− value: "target",
332− }],
333− [],
334− )
335 }
312 }
336}
313}
337
314
tests/web/main.rs+4−4
@@ -103,13 +103,13 @@ pub fn assert_rendered<R: Render>(container: &web_sys::Element, r: &R) {
103 );
103 );
104 for attr in expected {
104 for attr in expected {
105 let actual_attr = actual
105 let actual_attr = actual
106− .get_named_item(attr.name)
106+ .get_named_item(attr.name())
107− .expect(&format!("should have attribute \"{}\"", attr.name));
107+ .expect(&format!("should have attribute \"{}\"", attr.name()));
108 assert_eq!(
108 assert_eq!(
109 actual_attr.value(),
109 actual_attr.value(),
110− attr.value,
110+ attr.value(),
111 "actual attr value == expected attr value for attr \"{}\"",
111 "actual attr value == expected attr value for attr \"{}\"",
112− attr.name
112+ attr.name()
113 );
113 );
114 }
114 }
115 }
115 }
tests/web/render.rs+93−102
@@ -1,12 +1,12 @@
1use super::{assert_rendered, before_after, create_element, RenderFn};
1use super::{assert_rendered, before_after, create_element, RenderFn};
2−use dodrio::{Attribute, Node, Vdom};
2+use dodrio::{builder::*, Vdom};
3use futures::prelude::*;
3use futures::prelude::*;
4use std::rc::Rc;
4use std::rc::Rc;
5use wasm_bindgen_test::*;
5use wasm_bindgen_test::*;
6
6
7#[wasm_bindgen_test]
7#[wasm_bindgen_test]
8fn render_initial_text() {
8fn render_initial_text() {
9− let hello = Rc::new(RenderFn(|_bump| Node::text("hello")));
9+ let hello = Rc::new(RenderFn(|_bump| text("hello")));
10
10
11 let container = create_element("div");
11 let container = create_element("div");
12 let _vdom = Vdom::new(&container, hello.clone());
12 let _vdom = Vdom::new(&container, hello.clone());
@@ -16,19 +16,10 @@ fn render_initial_text() {
16#[wasm_bindgen_test]
16#[wasm_bindgen_test]
17fn render_initial_node() {
17fn render_initial_node() {
18 let hello = Rc::new(RenderFn(|bump| {
18 let hello = Rc::new(RenderFn(|bump| {
19− Node::element(
20− bump,
21− "div",
19+ div(bump)
22− [],
23− [Attribute {
24− name: "id",
25− value: "hello-world",
20+ .attr("id", "hello-world")
26− }],
21+ .children([text("Hello "), span(bump).child(text("World!")).finish()])
27− [
22+ .finish()
28− Node::text("Hello "),
29− Node::element(bump, "span", [], [], [Node::text("World!")]),
30− ],
31− )
32 }));
23 }));
33
24
34 let container = create_element("div");
25 let container = create_element("div");
@@ -39,7 +30,7 @@ fn render_initial_node() {
39#[wasm_bindgen_test]
30#[wasm_bindgen_test]
40fn container_is_emptied_upon_drop() {
31fn container_is_emptied_upon_drop() {
41 let container = create_element("div");
32 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")));
43 drop(vdom);
34 drop(vdom);
44 assert!(container.first_child().is_none());
35 assert!(container.first_child().is_none());
45}
36}
@@ -47,206 +38,206 @@ fn container_is_emptied_upon_drop() {
47before_after! {
38before_after! {
48 same_text {
39 same_text {
49 before(_bump) {
40 before(_bump) {
50− Node::text("hello")
41+ text("hello")
51 }
42 }
52 after(_bump) {
43 after(_bump) {
53− Node::text("hello")
44+ text("hello")
54 }
45 }
55 }
46 }
56
47
57 update_text {
48 update_text {
58 before(_bump) {
49 before(_bump) {
59− Node::text("before")
50+ text("before")
60 }
51 }
61 after(_bump) {
52 after(_bump) {
62− Node::text("after")
53+ text("after")
63 }
54 }
64 }
55 }
65
56
66 replace_text_with_elem {
57 replace_text_with_elem {
67 before(_bump) {
58 before(_bump) {
68− Node::text("before")
59+ text("before")
69 }
60 }
70 after(bump) {
61 after(bump) {
71− Node::element(bump, "div", [], [], [])
62+ div(bump).finish()
72 }
63 }
73 }
64 }
74
65
75 replace_elem_with_text {
66 replace_elem_with_text {
76 before(bump) {
67 before(bump) {
77− Node::element(bump, "div", [], [], [])
68+ div(bump).finish()
78 }
69 }
79 after(_bump) {
70 after(_bump) {
80− Node::text("before")
71+ text("before")
81 }
72 }
82 }
73 }
83
74
84 same_elem {
75 same_elem {
85 before(bump) {
76 before(bump) {
86− Node::element(bump, "div", [], [], [])
77+ div(bump).finish()
87 }
78 }
88 after(bump) {
79 after(bump) {
89− Node::element(bump, "div", [], [], [])
80+ div(bump).finish()
90 }
81 }
91 }
82 }
92
83
93 elems_with_different_tag_names {
84 elems_with_different_tag_names {
94 before(bump) {
85 before(bump) {
95− Node::element(bump, "span", [], [], [])
86+ span(bump).finish()
96 }
87 }
97 after(bump) {
88 after(bump) {
98− Node::element(bump, "div", [], [], [])
89+ div(bump).finish()
99 }
90 }
100 }
91 }
101
92
102 same_tag_name_update_attribute {
93 same_tag_name_update_attribute {
103 before(bump) {
94 before(bump) {
104− Node::element(bump, "div", [], [Attribute { name: "value", value: "1" }], [])
95+ div(bump).attr("value", "1").finish()
105 }
96 }
106 after(bump) {
97 after(bump) {
107− Node::element(bump, "div", [], [Attribute { name: "value", value: "2" }], [])
98+ div(bump).attr("value", "2").finish()
108 }
99 }
109 }
100 }
110
101
111 same_tag_name_remove_attribute {
102 same_tag_name_remove_attribute {
112 before(bump) {
103 before(bump) {
113− Node::element(bump, "div", [], [Attribute { name: "value", value: "1" }], [])
104+ div(bump).attr("value", "1").finish()
114 }
105 }
115 after(bump) {
106 after(bump) {
116− Node::element(bump, "div", [], [], [])
107+ div(bump).finish()
117 }
108 }
118 }
109 }
119
110
120 same_tag_name_add_attribute {
111 same_tag_name_add_attribute {
121 before(bump) {
112 before(bump) {
122− Node::element(bump, "div", [], [], [])
113+ div(bump).finish()
123 }
114 }
124 after(bump) {
115 after(bump) {
125− Node::element(bump, "div", [], [Attribute { name: "value", value: "2" }], [])
116+ div(bump).attr("value", "2").finish()
126 }
117 }
127 }
118 }
128
119
129 same_tag_name_many_attributes {
120 same_tag_name_many_attributes {
130 before(bump) {
121 before(bump) {
131− Node::element(bump, "div", [], [
122+ div(bump)
132− Attribute { name: "before-1", value: "1" },
123+ .attr("before-1", "1")
133− Attribute { name: "shared-1", value: "1" },
124+ .attr("shared-1", "1")
134− Attribute { name: "modified-1", value: "1" },
125+ .attr("modified-1", "1")
135− Attribute { name: "before-2", value: "2" },
126+ .attr("before-2", "2")
136− Attribute { name: "shared-2", value: "2" },
127+ .attr("shared-2", "2")
137− Attribute { name: "modified-2", value: "2" },
128+ .attr("modified-2", "2")
138− Attribute { name: "before-3", value: "3" },
129+ .attr("before-3", "3")
139− Attribute { name: "shared-3", value: "3" },
130+ .attr("shared-3", "3")
140− Attribute { name: "modified-3", value: "3" },
131+ .attr("modified-3", "3")
141− ], [])
132+ .finish()
142 }
133 }
143 after(bump) {
134 after(bump) {
144− Node::element(bump, "div", [], [
135+ div(bump)
145− Attribute { name: "after-1", value: "1" },
136+ .attr("after-1", "1")
146− Attribute { name: "shared-1", value: "1" },
137+ .attr("shared-1", "1")
147− Attribute { name: "modified-1", value: "100" },
138+ .attr("modified-1", "100")
148− Attribute { name: "after-2", value: "2" },
139+ .attr("after-2", "2")
149− Attribute { name: "shared-2", value: "2" },
140+ .attr("shared-2", "2")
150− Attribute { name: "modified-2", value: "200" },
141+ .attr("modified-2", "200")
151− Attribute { name: "after-3", value: "3" },
142+ .attr("after-3", "3")
152− Attribute { name: "shared-3", value: "3" },
143+ .attr("shared-3", "3")
153− Attribute { name: "modified-3", value: "300" },
144+ .attr("modified-3", "300")
154− ], [])
145+ .finish()
155 }
146 }
156 }
147 }
157
148
158 same_tag_same_children {
149 same_tag_same_children {
159 before(bump) {
150 before(bump) {
160− Node::element(bump, "div", [], [], [
161− Node::text("child")
151+ div(bump).child(text("child")).finish()
162− ])
163 }
152 }
164 after(bump) {
153 after(bump) {
165− Node::element(bump, "div", [], [], [
166− Node::text("child")
154+ div(bump).child(text("child")).finish()
167− ])
168 }
155 }
169 }
156 }
170
157
171 same_tag_update_child {
158 same_tag_update_child {
172 before(bump) {
159 before(bump) {
173− Node::element(bump, "div", [], [], [
174− Node::text("before")
160+ div(bump).child(text("before")).finish()
175− ])
176 }
161 }
177 after(bump) {
162 after(bump) {
178− Node::element(bump, "div", [], [], [
179− Node::text("after")
163+ div(bump).child(text("after")).finish()
180− ])
181 }
164 }
182 }
165 }
183
166
184 same_tag_add_child {
167 same_tag_add_child {
185 before(bump) {
168 before(bump) {
186− Node::element(bump, "div", [], [], [])
169+ div(bump).finish()
187 }
170 }
188 after(bump) {
171 after(bump) {
189− Node::element(bump, "div", [], [], [
190− Node::text("child")
172+ div(bump).child(text("child")).finish()
191− ])
192 }
173 }
193 }
174 }
194
175
195 same_tag_remove_child {
176 same_tag_remove_child {
196 before(bump) {
177 before(bump) {
197− Node::element(bump, "div", [], [], [
198− Node::text("child")
178+ div(bump).child(text("child")).finish()
199− ])
200 }
179 }
201 after(bump) {
180 after(bump) {
202− Node::element(bump, "div", [], [], [])
181+ div(bump).finish()
203 }
182 }
204 }
183 }
205
184
206 same_tag_update_many_children {
185 same_tag_update_many_children {
207 before(bump) {
186 before(bump) {
208− Node::element(bump, "div", [], [], [
187+ div(bump)
209− Node::element(bump, "div", [], [], []),
188+ .children([
210− Node::element(bump, "span", [], [], []),
189+ div(bump).finish(),
211− Node::element(bump, "p", [], [], []),
190+ span(bump).finish(),
191+ p(bump).finish(),
212− ])
192+ ])
193+ .finish()
213 }
194 }
214 after(bump) {
195 after(bump) {
215− Node::element(bump, "div", [], [], [
196+ div(bump)
216− Node::element(bump, "span", [], [], []),
197+ .children([
217− Node::element(bump, "p", [], [], []),
198+ span(bump).finish(),
218− Node::element(bump, "div", [], [], []),
199+ p(bump).finish(),
200+ div(bump).finish(),
219− ])
201+ ])
202+ .finish()
220 }
203 }
221 }
204 }
222
205
223 same_tag_remove_many_children {
206 same_tag_remove_many_children {
224 before(bump) {
207 before(bump) {
225− Node::element(bump, "div", [], [], [
208+ div(bump)
226− Node::element(bump, "div", [], [], []),
209+ .children([
227− Node::element(bump, "span", [], [], []),
210+ div(bump).finish(),
228− Node::element(bump, "p", [], [], []),
211+ span(bump).finish(),
212+ p(bump).finish(),
229− ])
213+ ])
214+ .finish()
230 }
215 }
231 after(bump) {
216 after(bump) {
232− Node::element(bump, "div", [], [], [
217+ div(bump)
233− Node::element(bump, "div", [], [], []),
218+ .children([
234− ])
219+ div(bump).finish(),
220+ ])
221+ .finish()
235 }
222 }
236 }
223 }
237
224
238 same_tag_add_many_children {
225 same_tag_add_many_children {
239 before(bump) {
226 before(bump) {
240− Node::element(bump, "div", [], [], [
227+ div(bump)
241− Node::element(bump, "div", [], [], []),
228+ .children([
242− ])
229+ div(bump).finish(),
230+ ])
231+ .finish()
243 }
232 }
244 after(bump) {
233 after(bump) {
245− Node::element(bump, "div", [], [], [
234+ div(bump)
246− Node::element(bump, "div", [], [], []),
235+ .children([
247− Node::element(bump, "span", [], [], []),
236+ div(bump).finish(),
248− Node::element(bump, "p", [], [], []),
237+ span(bump).finish(),
238+ p(bump).finish(),
249− ])
239+ ])
240+ .finish()
250 }
241 }
251 }
242 }
252}
243}