├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── Dioxus.prime-ministers.toml ├── IDEAS.md ├── Makefile ├── README.md ├── docs └── examples │ └── prime-ministers │ ├── assets │ └── dioxus │ │ ├── dioxus-sortable.js │ │ ├── dioxus-sortable_bg.wasm │ │ └── snippets │ │ ├── dioxus-interpreter-js-603636eeca72cf05 │ │ ├── inline0.js │ │ └── src │ │ │ └── common.js │ │ └── dioxus-web-54817add8ba334eb │ │ ├── inline0.js │ │ └── src │ │ └── eval.js │ └── index.html ├── examples └── prime_ministers.rs └── src ├── lib.rs ├── rsx.rs └── use_sorter.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /dist 3 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "ahash" 7 | version = "0.7.7" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" 10 | dependencies = [ 11 | "getrandom", 12 | "once_cell", 13 | "version_check", 14 | ] 15 | 16 | [[package]] 17 | name = "async-channel" 18 | version = "1.9.0" 19 | source = "registry+https://github.com/rust-lang/crates.io-index" 20 | checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" 21 | dependencies = [ 22 | "concurrent-queue", 23 | "event-listener", 24 | "futures-core", 25 | ] 26 | 27 | [[package]] 28 | name = "async-lock" 29 | version = "2.8.0" 30 | source = "registry+https://github.com/rust-lang/crates.io-index" 31 | checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" 32 | dependencies = [ 33 | "event-listener", 34 | ] 35 | 36 | [[package]] 37 | name = "async-task" 38 | version = "4.5.0" 39 | source = "registry+https://github.com/rust-lang/crates.io-index" 40 | checksum = "b4eb2cdb97421e01129ccb49169d8279ed21e829929144f4a22a6e54ac549ca1" 41 | 42 | [[package]] 43 | name = "async-trait" 44 | version = "0.1.74" 45 | source = "registry+https://github.com/rust-lang/crates.io-index" 46 | checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" 47 | dependencies = [ 48 | "proc-macro2", 49 | "quote", 50 | "syn", 51 | ] 52 | 53 | [[package]] 54 | name = "atomic-waker" 55 | version = "1.1.2" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" 58 | 59 | [[package]] 60 | name = "autocfg" 61 | version = "1.1.0" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 64 | 65 | [[package]] 66 | name = "bitflags" 67 | version = "1.3.2" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 70 | 71 | [[package]] 72 | name = "blocking" 73 | version = "1.4.1" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "8c36a4d0d48574b3dd360b4b7d95cc651d2b6557b6402848a27d4b228a473e2a" 76 | dependencies = [ 77 | "async-channel", 78 | "async-lock", 79 | "async-task", 80 | "fastrand", 81 | "futures-io", 82 | "futures-lite", 83 | "piper", 84 | "tracing", 85 | ] 86 | 87 | [[package]] 88 | name = "bumpalo" 89 | version = "3.14.0" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" 92 | 93 | [[package]] 94 | name = "cfg-if" 95 | version = "1.0.0" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 98 | 99 | [[package]] 100 | name = "concurrent-queue" 101 | version = "2.3.0" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "f057a694a54f12365049b0958a1685bb52d567f5593b355fbf685838e873d400" 104 | dependencies = [ 105 | "crossbeam-utils", 106 | ] 107 | 108 | [[package]] 109 | name = "console_error_panic_hook" 110 | version = "0.1.7" 111 | source = "registry+https://github.com/rust-lang/crates.io-index" 112 | checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" 113 | dependencies = [ 114 | "cfg-if", 115 | "wasm-bindgen", 116 | ] 117 | 118 | [[package]] 119 | name = "crossbeam-utils" 120 | version = "0.8.16" 121 | source = "registry+https://github.com/rust-lang/crates.io-index" 122 | checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" 123 | dependencies = [ 124 | "cfg-if", 125 | ] 126 | 127 | [[package]] 128 | name = "darling" 129 | version = "0.20.3" 130 | source = "registry+https://github.com/rust-lang/crates.io-index" 131 | checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" 132 | dependencies = [ 133 | "darling_core", 134 | "darling_macro", 135 | ] 136 | 137 | [[package]] 138 | name = "darling_core" 139 | version = "0.20.3" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" 142 | dependencies = [ 143 | "fnv", 144 | "ident_case", 145 | "proc-macro2", 146 | "quote", 147 | "syn", 148 | ] 149 | 150 | [[package]] 151 | name = "darling_macro" 152 | version = "0.20.3" 153 | source = "registry+https://github.com/rust-lang/crates.io-index" 154 | checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" 155 | dependencies = [ 156 | "darling_core", 157 | "quote", 158 | "syn", 159 | ] 160 | 161 | [[package]] 162 | name = "dioxus" 163 | version = "0.4.0" 164 | source = "registry+https://github.com/rust-lang/crates.io-index" 165 | checksum = "734b13d4894daf5cee7d4a1d7960da207acd7d4b4e427c05c201a2ba87a5c032" 166 | dependencies = [ 167 | "dioxus-core", 168 | "dioxus-core-macro", 169 | "dioxus-hooks", 170 | "dioxus-hot-reload", 171 | "dioxus-html", 172 | "dioxus-rsx", 173 | ] 174 | 175 | [[package]] 176 | name = "dioxus-core" 177 | version = "0.4.2" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "9980d48779193a6fb30fb43cdb06cdcc6ada2173a73579bf92dec81607a7ed5e" 180 | dependencies = [ 181 | "bumpalo", 182 | "futures-channel", 183 | "futures-util", 184 | "log", 185 | "longest-increasing-subsequence", 186 | "rustc-hash", 187 | "serde", 188 | "slab", 189 | "smallbox", 190 | ] 191 | 192 | [[package]] 193 | name = "dioxus-core-macro" 194 | version = "0.4.0" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | checksum = "e98f3e3fc1fb1f8796e30a5eaa6e037ca44105bdee3a70ed66721ac8b720c931" 197 | dependencies = [ 198 | "dioxus-rsx", 199 | "proc-macro2", 200 | "quote", 201 | "syn", 202 | ] 203 | 204 | [[package]] 205 | name = "dioxus-debug-cell" 206 | version = "0.1.1" 207 | source = "registry+https://github.com/rust-lang/crates.io-index" 208 | checksum = "2ea539174bb236e0e7dc9c12b19b88eae3cb574dedbd0252a2d43ea7e6de13e2" 209 | 210 | [[package]] 211 | name = "dioxus-hooks" 212 | version = "0.4.0" 213 | source = "registry+https://github.com/rust-lang/crates.io-index" 214 | checksum = "808e553203e4c2534e186a8a9da0f4032027ff5413067307ea8ecbd793e37f57" 215 | dependencies = [ 216 | "dioxus-core", 217 | "dioxus-debug-cell", 218 | "futures-channel", 219 | "log", 220 | "slab", 221 | "thiserror", 222 | ] 223 | 224 | [[package]] 225 | name = "dioxus-hot-reload" 226 | version = "0.4.0" 227 | source = "registry+https://github.com/rust-lang/crates.io-index" 228 | checksum = "1ceb8aca167a64e4b0afaff447b13052402a9ade3f21b9e7d031b6b72669994a" 229 | dependencies = [ 230 | "dioxus-core", 231 | "dioxus-html", 232 | "dioxus-rsx", 233 | "interprocess-docfix", 234 | "serde", 235 | "serde_json", 236 | ] 237 | 238 | [[package]] 239 | name = "dioxus-html" 240 | version = "0.4.0" 241 | source = "registry+https://github.com/rust-lang/crates.io-index" 242 | checksum = "fb712fe56650dafddb626f8aed3d6ae194706c0299e175e99b45464add8b7af1" 243 | dependencies = [ 244 | "async-channel", 245 | "async-trait", 246 | "dioxus-core", 247 | "enumset", 248 | "euclid", 249 | "keyboard-types", 250 | "serde", 251 | "serde-value", 252 | "serde_json", 253 | "serde_repr", 254 | "wasm-bindgen", 255 | "web-sys", 256 | ] 257 | 258 | [[package]] 259 | name = "dioxus-interpreter-js" 260 | version = "0.4.0" 261 | source = "registry+https://github.com/rust-lang/crates.io-index" 262 | checksum = "b2d35a6680cb2cf003a6c84fcaaa6d2a60b930efe4750910977b4e513bd73826" 263 | dependencies = [ 264 | "js-sys", 265 | "sledgehammer_bindgen", 266 | "sledgehammer_utils", 267 | "wasm-bindgen", 268 | "web-sys", 269 | ] 270 | 271 | [[package]] 272 | name = "dioxus-rsx" 273 | version = "0.4.0" 274 | source = "registry+https://github.com/rust-lang/crates.io-index" 275 | checksum = "531a6b418fb75d08389920c024d1c082b500844cf50ccb16ad8d9ee33a1907a1" 276 | dependencies = [ 277 | "dioxus-core", 278 | "proc-macro2", 279 | "quote", 280 | "syn", 281 | ] 282 | 283 | [[package]] 284 | name = "dioxus-sortable" 285 | version = "0.1.2" 286 | dependencies = [ 287 | "dioxus", 288 | "dioxus-web", 289 | "log", 290 | "wasm-bindgen", 291 | "wasm-logger", 292 | ] 293 | 294 | [[package]] 295 | name = "dioxus-web" 296 | version = "0.4.0" 297 | source = "registry+https://github.com/rust-lang/crates.io-index" 298 | checksum = "91d9dcd05db44c292220d520868bf703ea8165539ed8d80c60a7c33c3a846e8c" 299 | dependencies = [ 300 | "async-channel", 301 | "async-trait", 302 | "console_error_panic_hook", 303 | "dioxus-core", 304 | "dioxus-html", 305 | "dioxus-interpreter-js", 306 | "futures-channel", 307 | "futures-util", 308 | "js-sys", 309 | "log", 310 | "rustc-hash", 311 | "serde", 312 | "serde-wasm-bindgen", 313 | "serde_json", 314 | "wasm-bindgen", 315 | "wasm-bindgen-futures", 316 | "web-sys", 317 | ] 318 | 319 | [[package]] 320 | name = "enumset" 321 | version = "1.1.3" 322 | source = "registry+https://github.com/rust-lang/crates.io-index" 323 | checksum = "226c0da7462c13fb57e5cc9e0dc8f0635e7d27f276a3a7fd30054647f669007d" 324 | dependencies = [ 325 | "enumset_derive", 326 | ] 327 | 328 | [[package]] 329 | name = "enumset_derive" 330 | version = "0.8.1" 331 | source = "registry+https://github.com/rust-lang/crates.io-index" 332 | checksum = "e08b6c6ab82d70f08844964ba10c7babb716de2ecaeab9be5717918a5177d3af" 333 | dependencies = [ 334 | "darling", 335 | "proc-macro2", 336 | "quote", 337 | "syn", 338 | ] 339 | 340 | [[package]] 341 | name = "euclid" 342 | version = "0.22.9" 343 | source = "registry+https://github.com/rust-lang/crates.io-index" 344 | checksum = "87f253bc5c813ca05792837a0ff4b3a580336b224512d48f7eda1d7dd9210787" 345 | dependencies = [ 346 | "num-traits", 347 | "serde", 348 | ] 349 | 350 | [[package]] 351 | name = "event-listener" 352 | version = "2.5.3" 353 | source = "registry+https://github.com/rust-lang/crates.io-index" 354 | checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" 355 | 356 | [[package]] 357 | name = "fastrand" 358 | version = "2.0.1" 359 | source = "registry+https://github.com/rust-lang/crates.io-index" 360 | checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" 361 | 362 | [[package]] 363 | name = "fnv" 364 | version = "1.0.7" 365 | source = "registry+https://github.com/rust-lang/crates.io-index" 366 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 367 | 368 | [[package]] 369 | name = "futures-channel" 370 | version = "0.3.29" 371 | source = "registry+https://github.com/rust-lang/crates.io-index" 372 | checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" 373 | dependencies = [ 374 | "futures-core", 375 | ] 376 | 377 | [[package]] 378 | name = "futures-core" 379 | version = "0.3.29" 380 | source = "registry+https://github.com/rust-lang/crates.io-index" 381 | checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" 382 | 383 | [[package]] 384 | name = "futures-io" 385 | version = "0.3.29" 386 | source = "registry+https://github.com/rust-lang/crates.io-index" 387 | checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" 388 | 389 | [[package]] 390 | name = "futures-lite" 391 | version = "1.13.0" 392 | source = "registry+https://github.com/rust-lang/crates.io-index" 393 | checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" 394 | dependencies = [ 395 | "futures-core", 396 | "pin-project-lite", 397 | ] 398 | 399 | [[package]] 400 | name = "futures-macro" 401 | version = "0.3.29" 402 | source = "registry+https://github.com/rust-lang/crates.io-index" 403 | checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" 404 | dependencies = [ 405 | "proc-macro2", 406 | "quote", 407 | "syn", 408 | ] 409 | 410 | [[package]] 411 | name = "futures-task" 412 | version = "0.3.29" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" 415 | 416 | [[package]] 417 | name = "futures-util" 418 | version = "0.3.29" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" 421 | dependencies = [ 422 | "futures-core", 423 | "futures-macro", 424 | "futures-task", 425 | "pin-project-lite", 426 | "pin-utils", 427 | "slab", 428 | ] 429 | 430 | [[package]] 431 | name = "getrandom" 432 | version = "0.2.10" 433 | source = "registry+https://github.com/rust-lang/crates.io-index" 434 | checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" 435 | dependencies = [ 436 | "cfg-if", 437 | "libc", 438 | "wasi", 439 | ] 440 | 441 | [[package]] 442 | name = "hashbrown" 443 | version = "0.12.3" 444 | source = "registry+https://github.com/rust-lang/crates.io-index" 445 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 446 | dependencies = [ 447 | "ahash", 448 | ] 449 | 450 | [[package]] 451 | name = "ident_case" 452 | version = "1.0.1" 453 | source = "registry+https://github.com/rust-lang/crates.io-index" 454 | checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 455 | 456 | [[package]] 457 | name = "interprocess-docfix" 458 | version = "1.2.2" 459 | source = "registry+https://github.com/rust-lang/crates.io-index" 460 | checksum = "4b84ee245c606aeb0841649a9288e3eae8c61b853a8cd5c0e14450e96d53d28f" 461 | dependencies = [ 462 | "blocking", 463 | "cfg-if", 464 | "futures-core", 465 | "futures-io", 466 | "intmap", 467 | "libc", 468 | "once_cell", 469 | "rustc_version", 470 | "spinning", 471 | "thiserror", 472 | "to_method", 473 | "winapi", 474 | ] 475 | 476 | [[package]] 477 | name = "intmap" 478 | version = "0.7.1" 479 | source = "registry+https://github.com/rust-lang/crates.io-index" 480 | checksum = "ae52f28f45ac2bc96edb7714de995cffc174a395fb0abf5bff453587c980d7b9" 481 | 482 | [[package]] 483 | name = "itoa" 484 | version = "1.0.9" 485 | source = "registry+https://github.com/rust-lang/crates.io-index" 486 | checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" 487 | 488 | [[package]] 489 | name = "js-sys" 490 | version = "0.3.65" 491 | source = "registry+https://github.com/rust-lang/crates.io-index" 492 | checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" 493 | dependencies = [ 494 | "wasm-bindgen", 495 | ] 496 | 497 | [[package]] 498 | name = "keyboard-types" 499 | version = "0.6.2" 500 | source = "registry+https://github.com/rust-lang/crates.io-index" 501 | checksum = "0b7668b7cff6a51fe61cdde64cd27c8a220786f399501b57ebe36f7d8112fd68" 502 | dependencies = [ 503 | "bitflags", 504 | "serde", 505 | "unicode-segmentation", 506 | ] 507 | 508 | [[package]] 509 | name = "libc" 510 | version = "0.2.150" 511 | source = "registry+https://github.com/rust-lang/crates.io-index" 512 | checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" 513 | 514 | [[package]] 515 | name = "lock_api" 516 | version = "0.4.11" 517 | source = "registry+https://github.com/rust-lang/crates.io-index" 518 | checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" 519 | dependencies = [ 520 | "autocfg", 521 | "scopeguard", 522 | ] 523 | 524 | [[package]] 525 | name = "log" 526 | version = "0.4.20" 527 | source = "registry+https://github.com/rust-lang/crates.io-index" 528 | checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" 529 | 530 | [[package]] 531 | name = "longest-increasing-subsequence" 532 | version = "0.1.0" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | checksum = "b3bd0dd2cd90571056fdb71f6275fada10131182f84899f4b2a916e565d81d86" 535 | 536 | [[package]] 537 | name = "lru" 538 | version = "0.8.1" 539 | source = "registry+https://github.com/rust-lang/crates.io-index" 540 | checksum = "b6e8aaa3f231bb4bd57b84b2d5dc3ae7f350265df8aa96492e0bc394a1571909" 541 | dependencies = [ 542 | "hashbrown", 543 | ] 544 | 545 | [[package]] 546 | name = "num-traits" 547 | version = "0.2.17" 548 | source = "registry+https://github.com/rust-lang/crates.io-index" 549 | checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" 550 | dependencies = [ 551 | "autocfg", 552 | ] 553 | 554 | [[package]] 555 | name = "once_cell" 556 | version = "1.18.0" 557 | source = "registry+https://github.com/rust-lang/crates.io-index" 558 | checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" 559 | 560 | [[package]] 561 | name = "ordered-float" 562 | version = "2.10.1" 563 | source = "registry+https://github.com/rust-lang/crates.io-index" 564 | checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" 565 | dependencies = [ 566 | "num-traits", 567 | ] 568 | 569 | [[package]] 570 | name = "pin-project-lite" 571 | version = "0.2.13" 572 | source = "registry+https://github.com/rust-lang/crates.io-index" 573 | checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" 574 | 575 | [[package]] 576 | name = "pin-utils" 577 | version = "0.1.0" 578 | source = "registry+https://github.com/rust-lang/crates.io-index" 579 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 580 | 581 | [[package]] 582 | name = "piper" 583 | version = "0.2.1" 584 | source = "registry+https://github.com/rust-lang/crates.io-index" 585 | checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" 586 | dependencies = [ 587 | "atomic-waker", 588 | "fastrand", 589 | "futures-io", 590 | ] 591 | 592 | [[package]] 593 | name = "proc-macro2" 594 | version = "1.0.69" 595 | source = "registry+https://github.com/rust-lang/crates.io-index" 596 | checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" 597 | dependencies = [ 598 | "unicode-ident", 599 | ] 600 | 601 | [[package]] 602 | name = "quote" 603 | version = "1.0.33" 604 | source = "registry+https://github.com/rust-lang/crates.io-index" 605 | checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" 606 | dependencies = [ 607 | "proc-macro2", 608 | ] 609 | 610 | [[package]] 611 | name = "rustc-hash" 612 | version = "1.1.0" 613 | source = "registry+https://github.com/rust-lang/crates.io-index" 614 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" 615 | 616 | [[package]] 617 | name = "rustc_version" 618 | version = "0.4.0" 619 | source = "registry+https://github.com/rust-lang/crates.io-index" 620 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" 621 | dependencies = [ 622 | "semver", 623 | ] 624 | 625 | [[package]] 626 | name = "ryu" 627 | version = "1.0.15" 628 | source = "registry+https://github.com/rust-lang/crates.io-index" 629 | checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" 630 | 631 | [[package]] 632 | name = "scopeguard" 633 | version = "1.2.0" 634 | source = "registry+https://github.com/rust-lang/crates.io-index" 635 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 636 | 637 | [[package]] 638 | name = "semver" 639 | version = "1.0.20" 640 | source = "registry+https://github.com/rust-lang/crates.io-index" 641 | checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" 642 | 643 | [[package]] 644 | name = "serde" 645 | version = "1.0.190" 646 | source = "registry+https://github.com/rust-lang/crates.io-index" 647 | checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7" 648 | dependencies = [ 649 | "serde_derive", 650 | ] 651 | 652 | [[package]] 653 | name = "serde-value" 654 | version = "0.7.0" 655 | source = "registry+https://github.com/rust-lang/crates.io-index" 656 | checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" 657 | dependencies = [ 658 | "ordered-float", 659 | "serde", 660 | ] 661 | 662 | [[package]] 663 | name = "serde-wasm-bindgen" 664 | version = "0.5.0" 665 | source = "registry+https://github.com/rust-lang/crates.io-index" 666 | checksum = "f3b143e2833c57ab9ad3ea280d21fd34e285a42837aeb0ee301f4f41890fa00e" 667 | dependencies = [ 668 | "js-sys", 669 | "serde", 670 | "wasm-bindgen", 671 | ] 672 | 673 | [[package]] 674 | name = "serde_derive" 675 | version = "1.0.190" 676 | source = "registry+https://github.com/rust-lang/crates.io-index" 677 | checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" 678 | dependencies = [ 679 | "proc-macro2", 680 | "quote", 681 | "syn", 682 | ] 683 | 684 | [[package]] 685 | name = "serde_json" 686 | version = "1.0.108" 687 | source = "registry+https://github.com/rust-lang/crates.io-index" 688 | checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" 689 | dependencies = [ 690 | "itoa", 691 | "ryu", 692 | "serde", 693 | ] 694 | 695 | [[package]] 696 | name = "serde_repr" 697 | version = "0.1.17" 698 | source = "registry+https://github.com/rust-lang/crates.io-index" 699 | checksum = "3081f5ffbb02284dda55132aa26daecedd7372a42417bbbab6f14ab7d6bb9145" 700 | dependencies = [ 701 | "proc-macro2", 702 | "quote", 703 | "syn", 704 | ] 705 | 706 | [[package]] 707 | name = "slab" 708 | version = "0.4.9" 709 | source = "registry+https://github.com/rust-lang/crates.io-index" 710 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 711 | dependencies = [ 712 | "autocfg", 713 | ] 714 | 715 | [[package]] 716 | name = "sledgehammer_bindgen" 717 | version = "0.2.4" 718 | source = "registry+https://github.com/rust-lang/crates.io-index" 719 | checksum = "c0bc2cf26c12673eee8674b19d56cec04e9b815704c71298eafac61f131f99d7" 720 | dependencies = [ 721 | "quote", 722 | "syn", 723 | ] 724 | 725 | [[package]] 726 | name = "sledgehammer_utils" 727 | version = "0.2.0" 728 | source = "registry+https://github.com/rust-lang/crates.io-index" 729 | checksum = "5cd16550f1dd7866c7580dbf80c892dc1bef106737eeb850d42c62ec61896059" 730 | dependencies = [ 731 | "lru", 732 | "once_cell", 733 | "rustc-hash", 734 | ] 735 | 736 | [[package]] 737 | name = "smallbox" 738 | version = "0.8.2" 739 | source = "registry+https://github.com/rust-lang/crates.io-index" 740 | checksum = "d92359f97e6b417da4328a970cf04a044db104fbd57f7d72cb7ff665bb8806af" 741 | 742 | [[package]] 743 | name = "spinning" 744 | version = "0.1.0" 745 | source = "registry+https://github.com/rust-lang/crates.io-index" 746 | checksum = "2d4f0e86297cad2658d92a707320d87bf4e6ae1050287f51d19b67ef3f153a7b" 747 | dependencies = [ 748 | "lock_api", 749 | ] 750 | 751 | [[package]] 752 | name = "syn" 753 | version = "2.0.38" 754 | source = "registry+https://github.com/rust-lang/crates.io-index" 755 | checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" 756 | dependencies = [ 757 | "proc-macro2", 758 | "quote", 759 | "unicode-ident", 760 | ] 761 | 762 | [[package]] 763 | name = "thiserror" 764 | version = "1.0.50" 765 | source = "registry+https://github.com/rust-lang/crates.io-index" 766 | checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" 767 | dependencies = [ 768 | "thiserror-impl", 769 | ] 770 | 771 | [[package]] 772 | name = "thiserror-impl" 773 | version = "1.0.50" 774 | source = "registry+https://github.com/rust-lang/crates.io-index" 775 | checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" 776 | dependencies = [ 777 | "proc-macro2", 778 | "quote", 779 | "syn", 780 | ] 781 | 782 | [[package]] 783 | name = "to_method" 784 | version = "1.1.0" 785 | source = "registry+https://github.com/rust-lang/crates.io-index" 786 | checksum = "c7c4ceeeca15c8384bbc3e011dbd8fccb7f068a440b752b7d9b32ceb0ca0e2e8" 787 | 788 | [[package]] 789 | name = "tracing" 790 | version = "0.1.40" 791 | source = "registry+https://github.com/rust-lang/crates.io-index" 792 | checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" 793 | dependencies = [ 794 | "pin-project-lite", 795 | "tracing-core", 796 | ] 797 | 798 | [[package]] 799 | name = "tracing-core" 800 | version = "0.1.32" 801 | source = "registry+https://github.com/rust-lang/crates.io-index" 802 | checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" 803 | 804 | [[package]] 805 | name = "unicode-ident" 806 | version = "1.0.12" 807 | source = "registry+https://github.com/rust-lang/crates.io-index" 808 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 809 | 810 | [[package]] 811 | name = "unicode-segmentation" 812 | version = "1.10.1" 813 | source = "registry+https://github.com/rust-lang/crates.io-index" 814 | checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" 815 | 816 | [[package]] 817 | name = "version_check" 818 | version = "0.9.4" 819 | source = "registry+https://github.com/rust-lang/crates.io-index" 820 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 821 | 822 | [[package]] 823 | name = "wasi" 824 | version = "0.11.0+wasi-snapshot-preview1" 825 | source = "registry+https://github.com/rust-lang/crates.io-index" 826 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 827 | 828 | [[package]] 829 | name = "wasm-bindgen" 830 | version = "0.2.88" 831 | source = "registry+https://github.com/rust-lang/crates.io-index" 832 | checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" 833 | dependencies = [ 834 | "cfg-if", 835 | "wasm-bindgen-macro", 836 | ] 837 | 838 | [[package]] 839 | name = "wasm-bindgen-backend" 840 | version = "0.2.88" 841 | source = "registry+https://github.com/rust-lang/crates.io-index" 842 | checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" 843 | dependencies = [ 844 | "bumpalo", 845 | "log", 846 | "once_cell", 847 | "proc-macro2", 848 | "quote", 849 | "syn", 850 | "wasm-bindgen-shared", 851 | ] 852 | 853 | [[package]] 854 | name = "wasm-bindgen-futures" 855 | version = "0.4.38" 856 | source = "registry+https://github.com/rust-lang/crates.io-index" 857 | checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" 858 | dependencies = [ 859 | "cfg-if", 860 | "js-sys", 861 | "wasm-bindgen", 862 | "web-sys", 863 | ] 864 | 865 | [[package]] 866 | name = "wasm-bindgen-macro" 867 | version = "0.2.88" 868 | source = "registry+https://github.com/rust-lang/crates.io-index" 869 | checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" 870 | dependencies = [ 871 | "quote", 872 | "wasm-bindgen-macro-support", 873 | ] 874 | 875 | [[package]] 876 | name = "wasm-bindgen-macro-support" 877 | version = "0.2.88" 878 | source = "registry+https://github.com/rust-lang/crates.io-index" 879 | checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" 880 | dependencies = [ 881 | "proc-macro2", 882 | "quote", 883 | "syn", 884 | "wasm-bindgen-backend", 885 | "wasm-bindgen-shared", 886 | ] 887 | 888 | [[package]] 889 | name = "wasm-bindgen-shared" 890 | version = "0.2.88" 891 | source = "registry+https://github.com/rust-lang/crates.io-index" 892 | checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" 893 | 894 | [[package]] 895 | name = "wasm-logger" 896 | version = "0.2.0" 897 | source = "registry+https://github.com/rust-lang/crates.io-index" 898 | checksum = "074649a66bb306c8f2068c9016395fa65d8e08d2affcbf95acf3c24c3ab19718" 899 | dependencies = [ 900 | "log", 901 | "wasm-bindgen", 902 | "web-sys", 903 | ] 904 | 905 | [[package]] 906 | name = "web-sys" 907 | version = "0.3.65" 908 | source = "registry+https://github.com/rust-lang/crates.io-index" 909 | checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" 910 | dependencies = [ 911 | "js-sys", 912 | "wasm-bindgen", 913 | ] 914 | 915 | [[package]] 916 | name = "winapi" 917 | version = "0.3.9" 918 | source = "registry+https://github.com/rust-lang/crates.io-index" 919 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 920 | dependencies = [ 921 | "winapi-i686-pc-windows-gnu", 922 | "winapi-x86_64-pc-windows-gnu", 923 | ] 924 | 925 | [[package]] 926 | name = "winapi-i686-pc-windows-gnu" 927 | version = "0.4.0" 928 | source = "registry+https://github.com/rust-lang/crates.io-index" 929 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 930 | 931 | [[package]] 932 | name = "winapi-x86_64-pc-windows-gnu" 933 | version = "0.4.0" 934 | source = "registry+https://github.com/rust-lang/crates.io-index" 935 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 936 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dioxus-sortable" 3 | version = "0.1.2" 4 | authors = [ "Joshua McQuistan " ] 5 | edition = "2021" 6 | description = "Sortable tables and components for Dioxus" 7 | documentation = "https://docs.rs/dioxus-sortable" 8 | repository = "https://github.com/feral-dot-io/dioxus-sortable" 9 | license = "LGPL-3.0-or-later" 10 | keywords = [ "dioxus", "ui", "gui", "wasm" ] 11 | categories = [ "wasm", "gui", "web-programming" ] 12 | 13 | [dependencies] 14 | dioxus = "0.4" 15 | wasm-bindgen = "0.2.87" 16 | 17 | [dev-dependencies] 18 | dioxus-web = "0.4" 19 | log = "0.4" 20 | wasm-logger = "0.2" 21 | -------------------------------------------------------------------------------- /Dioxus.prime-ministers.toml: -------------------------------------------------------------------------------- 1 | # This builds examples/prime_ministers.rs for GitHub Pages 2 | # Usage: dioxus build --example prime_ministers --release 3 | 4 | [application] 5 | name = "dioxus-sortable" 6 | default_platform = "web" 7 | out_dir = "docs/examples/prime-ministers" 8 | asset_dir = "public" 9 | 10 | [web.app] 11 | title = "Prime ministers of GB | dioxus-sortable" 12 | base_path = "dioxus-sortable/examples/prime-ministers" 13 | 14 | [web.watcher] 15 | index_on_404 = true 16 | watch_path = ["src"] 17 | 18 | [web.resource] 19 | style = [] 20 | script = [] 21 | 22 | [web.resource.dev] 23 | script = [] 24 | 25 | [application.plugins] 26 | available = true 27 | required = [] 28 | -------------------------------------------------------------------------------- /IDEAS.md: -------------------------------------------------------------------------------- 1 | # Development ideas 2 | 3 | - Add a Table rsx component. 4 | - Add a derive(Sortable) on T struct. 5 | - Consider making SortBy an opaque trait covered by SortBy::* builders. 6 | - Consider a default impl of Sortable that returns increasing_or_decreasing. 7 | - Consider minimising Sortable in the docs and offering it as a way to customise further. 8 | - Add a gif to README.md 9 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all 2 | 3 | all: example 4 | 5 | example: 6 | # Dioxus CLI doesn't seem to allow for a custom config 7 | mv Dioxus.toml Dioxus.toml.temp || true 8 | cp Dioxus.prime-ministers.toml Dioxus.toml 9 | 10 | # Build release 11 | dx build --example prime_ministers --release 12 | 13 | # Restore config 14 | rm Dioxus.toml 15 | mv Dioxus.toml.temp Dioxus.toml || true 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sortable components for Dioxus 2 | 3 |

4 | 5 | 6 | Crates.io version 7 | 8 | 9 | 10 | docs.rs docs 11 | 12 |

13 | 14 | Create sortable tables (and other components) of any type for [Dioxus](https://dioxuslabs.com/). 15 | 16 | A full example of [British prime ministers](https://feral-dot-io.github.io/dioxus-sortable/examples/prime-ministers/) ([and the code](https://github.com/feral-dot-io/dioxus-sortable/blob/master/examples/prime_ministers.rs)) is available. Full documentation and examples available on [https://docs.rs/dioxus-sortable](https://docs.rs/dioxus-sortable) 17 | -------------------------------------------------------------------------------- /docs/examples/prime-ministers/assets/dioxus/dioxus-sortable.js: -------------------------------------------------------------------------------- 1 | import { create, update_memory, save_template, get_node, initilize } from './snippets/dioxus-interpreter-js-603636eeca72cf05/inline0.js'; 2 | import { setAttributeInner } from './snippets/dioxus-interpreter-js-603636eeca72cf05/src/common.js'; 3 | import { get_form_data } from './snippets/dioxus-web-54817add8ba334eb/inline0.js'; 4 | import { Dioxus } from './snippets/dioxus-web-54817add8ba334eb/src/eval.js'; 5 | import * as __wbg_star0 from './snippets/dioxus-interpreter-js-603636eeca72cf05/inline0.js'; 6 | 7 | let wasm; 8 | 9 | const heap = new Array(128).fill(undefined); 10 | 11 | heap.push(undefined, null, true, false); 12 | 13 | function getObject(idx) { return heap[idx]; } 14 | 15 | let heap_next = heap.length; 16 | 17 | function dropObject(idx) { 18 | if (idx < 132) return; 19 | heap[idx] = heap_next; 20 | heap_next = idx; 21 | } 22 | 23 | function takeObject(idx) { 24 | const ret = getObject(idx); 25 | dropObject(idx); 26 | return ret; 27 | } 28 | 29 | function _assertBoolean(n) { 30 | if (typeof(n) !== 'boolean') { 31 | throw new Error('expected a boolean argument'); 32 | } 33 | } 34 | 35 | let WASM_VECTOR_LEN = 0; 36 | 37 | let cachedUint8Memory0 = null; 38 | 39 | function getUint8Memory0() { 40 | if (cachedUint8Memory0 === null || cachedUint8Memory0.byteLength === 0) { 41 | cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer); 42 | } 43 | return cachedUint8Memory0; 44 | } 45 | 46 | const cachedTextEncoder = (typeof TextEncoder !== 'undefined' ? new TextEncoder('utf-8') : { encode: () => { throw Error('TextEncoder not available') } } ); 47 | 48 | const encodeString = (typeof cachedTextEncoder.encodeInto === 'function' 49 | ? function (arg, view) { 50 | return cachedTextEncoder.encodeInto(arg, view); 51 | } 52 | : function (arg, view) { 53 | const buf = cachedTextEncoder.encode(arg); 54 | view.set(buf); 55 | return { 56 | read: arg.length, 57 | written: buf.length 58 | }; 59 | }); 60 | 61 | function passStringToWasm0(arg, malloc, realloc) { 62 | 63 | if (typeof(arg) !== 'string') throw new Error('expected a string argument'); 64 | 65 | if (realloc === undefined) { 66 | const buf = cachedTextEncoder.encode(arg); 67 | const ptr = malloc(buf.length, 1) >>> 0; 68 | getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf); 69 | WASM_VECTOR_LEN = buf.length; 70 | return ptr; 71 | } 72 | 73 | let len = arg.length; 74 | let ptr = malloc(len, 1) >>> 0; 75 | 76 | const mem = getUint8Memory0(); 77 | 78 | let offset = 0; 79 | 80 | for (; offset < len; offset++) { 81 | const code = arg.charCodeAt(offset); 82 | if (code > 0x7F) break; 83 | mem[ptr + offset] = code; 84 | } 85 | 86 | if (offset !== len) { 87 | if (offset !== 0) { 88 | arg = arg.slice(offset); 89 | } 90 | ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0; 91 | const view = getUint8Memory0().subarray(ptr + offset, ptr + len); 92 | const ret = encodeString(arg, view); 93 | if (ret.read !== arg.length) throw new Error('failed to pass whole string'); 94 | offset += ret.written; 95 | } 96 | 97 | WASM_VECTOR_LEN = offset; 98 | return ptr; 99 | } 100 | 101 | function isLikeNone(x) { 102 | return x === undefined || x === null; 103 | } 104 | 105 | let cachedInt32Memory0 = null; 106 | 107 | function getInt32Memory0() { 108 | if (cachedInt32Memory0 === null || cachedInt32Memory0.byteLength === 0) { 109 | cachedInt32Memory0 = new Int32Array(wasm.memory.buffer); 110 | } 111 | return cachedInt32Memory0; 112 | } 113 | 114 | function addHeapObject(obj) { 115 | if (heap_next === heap.length) heap.push(heap.length + 1); 116 | const idx = heap_next; 117 | heap_next = heap[idx]; 118 | 119 | if (typeof(heap_next) !== 'number') throw new Error('corrupt heap'); 120 | 121 | heap[idx] = obj; 122 | return idx; 123 | } 124 | 125 | function _assertNum(n) { 126 | if (typeof(n) !== 'number') throw new Error('expected a number argument'); 127 | } 128 | 129 | const cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } ); 130 | 131 | if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); }; 132 | 133 | function getStringFromWasm0(ptr, len) { 134 | ptr = ptr >>> 0; 135 | return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len)); 136 | } 137 | 138 | let cachedFloat64Memory0 = null; 139 | 140 | function getFloat64Memory0() { 141 | if (cachedFloat64Memory0 === null || cachedFloat64Memory0.byteLength === 0) { 142 | cachedFloat64Memory0 = new Float64Array(wasm.memory.buffer); 143 | } 144 | return cachedFloat64Memory0; 145 | } 146 | 147 | function _assertBigInt(n) { 148 | if (typeof(n) !== 'bigint') throw new Error('expected a bigint argument'); 149 | } 150 | 151 | let cachedBigInt64Memory0 = null; 152 | 153 | function getBigInt64Memory0() { 154 | if (cachedBigInt64Memory0 === null || cachedBigInt64Memory0.byteLength === 0) { 155 | cachedBigInt64Memory0 = new BigInt64Array(wasm.memory.buffer); 156 | } 157 | return cachedBigInt64Memory0; 158 | } 159 | 160 | function debugString(val) { 161 | // primitive types 162 | const type = typeof val; 163 | if (type == 'number' || type == 'boolean' || val == null) { 164 | return `${val}`; 165 | } 166 | if (type == 'string') { 167 | return `"${val}"`; 168 | } 169 | if (type == 'symbol') { 170 | const description = val.description; 171 | if (description == null) { 172 | return 'Symbol'; 173 | } else { 174 | return `Symbol(${description})`; 175 | } 176 | } 177 | if (type == 'function') { 178 | const name = val.name; 179 | if (typeof name == 'string' && name.length > 0) { 180 | return `Function(${name})`; 181 | } else { 182 | return 'Function'; 183 | } 184 | } 185 | // objects 186 | if (Array.isArray(val)) { 187 | const length = val.length; 188 | let debug = '['; 189 | if (length > 0) { 190 | debug += debugString(val[0]); 191 | } 192 | for(let i = 1; i < length; i++) { 193 | debug += ', ' + debugString(val[i]); 194 | } 195 | debug += ']'; 196 | return debug; 197 | } 198 | // Test for built-in 199 | const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val)); 200 | let className; 201 | if (builtInMatches.length > 1) { 202 | className = builtInMatches[1]; 203 | } else { 204 | // Failed to match the standard '[object ClassName]' 205 | return toString.call(val); 206 | } 207 | if (className == 'Object') { 208 | // we're a user defined class or Object 209 | // JSON.stringify avoids problems with cycles, and is generally much 210 | // easier than looping through ownProperties of `val`. 211 | try { 212 | return 'Object(' + JSON.stringify(val) + ')'; 213 | } catch (_) { 214 | return 'Object'; 215 | } 216 | } 217 | // errors 218 | if (val instanceof Error) { 219 | return `${val.name}: ${val.message}\n${val.stack}`; 220 | } 221 | // TODO we could test for more things here, like `Set`s and `Map`s. 222 | return className; 223 | } 224 | 225 | function makeMutClosure(arg0, arg1, dtor, f) { 226 | const state = { a: arg0, b: arg1, cnt: 1, dtor }; 227 | const real = (...args) => { 228 | // First up with a closure we increment the internal reference 229 | // count. This ensures that the Rust closure environment won't 230 | // be deallocated while we're invoking it. 231 | state.cnt++; 232 | const a = state.a; 233 | state.a = 0; 234 | try { 235 | return f(a, state.b, ...args); 236 | } finally { 237 | if (--state.cnt === 0) { 238 | wasm.__wbindgen_export_2.get(state.dtor)(a, state.b); 239 | 240 | } else { 241 | state.a = a; 242 | } 243 | } 244 | }; 245 | real.original = state; 246 | 247 | return real; 248 | } 249 | 250 | function logError(f, args) { 251 | try { 252 | return f.apply(this, args); 253 | } catch (e) { 254 | let error = (function () { 255 | try { 256 | return e instanceof Error ? `${e.message}\n\nStack:\n${e.stack}` : e.toString(); 257 | } catch(_) { 258 | return ""; 259 | } 260 | }()); 261 | console.error("wasm-bindgen: imported JS function that was not marked as `catch` threw an error:", error); 262 | throw e; 263 | } 264 | } 265 | function __wbg_adapter_48(arg0, arg1) { 266 | _assertNum(arg0); 267 | _assertNum(arg1); 268 | wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hd4a862b7f45ead23(arg0, arg1); 269 | } 270 | 271 | function __wbg_adapter_51(arg0, arg1, arg2) { 272 | _assertNum(arg0); 273 | _assertNum(arg1); 274 | wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__he62093f60c2e143f(arg0, arg1, addHeapObject(arg2)); 275 | } 276 | 277 | let stack_pointer = 128; 278 | 279 | function addBorrowedObject(obj) { 280 | if (stack_pointer == 1) throw new Error('out of js stack'); 281 | heap[--stack_pointer] = obj; 282 | return stack_pointer; 283 | } 284 | function __wbg_adapter_54(arg0, arg1, arg2) { 285 | try { 286 | _assertNum(arg0); 287 | _assertNum(arg1); 288 | wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hdc5bcb7c85ed5532(arg0, arg1, addBorrowedObject(arg2)); 289 | } finally { 290 | heap[stack_pointer++] = undefined; 291 | } 292 | } 293 | 294 | function __wbg_adapter_57(arg0, arg1, arg2) { 295 | _assertNum(arg0); 296 | _assertNum(arg1); 297 | wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h939d9a621d2f25a2(arg0, arg1, addHeapObject(arg2)); 298 | } 299 | 300 | function getCachedStringFromWasm0(ptr, len) { 301 | if (ptr === 0) { 302 | return getObject(len); 303 | } else { 304 | return getStringFromWasm0(ptr, len); 305 | } 306 | } 307 | 308 | let cachedUint32Memory0 = null; 309 | 310 | function getUint32Memory0() { 311 | if (cachedUint32Memory0 === null || cachedUint32Memory0.byteLength === 0) { 312 | cachedUint32Memory0 = new Uint32Array(wasm.memory.buffer); 313 | } 314 | return cachedUint32Memory0; 315 | } 316 | 317 | function getArrayJsValueFromWasm0(ptr, len) { 318 | ptr = ptr >>> 0; 319 | const mem = getUint32Memory0(); 320 | const slice = mem.subarray(ptr / 4, ptr / 4 + len); 321 | const result = []; 322 | for (let i = 0; i < slice.length; i++) { 323 | result.push(takeObject(slice[i])); 324 | } 325 | return result; 326 | } 327 | 328 | function handleError(f, args) { 329 | try { 330 | return f.apply(this, args); 331 | } catch (e) { 332 | wasm.__wbindgen_exn_store(addHeapObject(e)); 333 | } 334 | } 335 | 336 | async function __wbg_load(module, imports) { 337 | if (typeof Response === 'function' && module instanceof Response) { 338 | if (typeof WebAssembly.instantiateStreaming === 'function') { 339 | try { 340 | return await WebAssembly.instantiateStreaming(module, imports); 341 | 342 | } catch (e) { 343 | if (module.headers.get('Content-Type') != 'application/wasm') { 344 | console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e); 345 | 346 | } else { 347 | throw e; 348 | } 349 | } 350 | } 351 | 352 | const bytes = await module.arrayBuffer(); 353 | return await WebAssembly.instantiate(bytes, imports); 354 | 355 | } else { 356 | const instance = await WebAssembly.instantiate(module, imports); 357 | 358 | if (instance instanceof WebAssembly.Instance) { 359 | return { instance, module }; 360 | 361 | } else { 362 | return instance; 363 | } 364 | } 365 | } 366 | 367 | function __wbg_get_imports() { 368 | const imports = {}; 369 | imports.wbg = {}; 370 | imports.wbg.__wbindgen_object_drop_ref = function(arg0) { 371 | takeObject(arg0); 372 | }; 373 | imports.wbg.__wbg_new_86c764e2105c4284 = function() { return logError(function (arg0) { 374 | const ret = new Dioxus(getObject(arg0)); 375 | return addHeapObject(ret); 376 | }, arguments) }; 377 | imports.wbg.__wbindgen_is_undefined = function(arg0) { 378 | const ret = getObject(arg0) === undefined; 379 | _assertBoolean(ret); 380 | return ret; 381 | }; 382 | imports.wbg.__wbindgen_string_get = function(arg0, arg1) { 383 | const obj = getObject(arg1); 384 | const ret = typeof(obj) === 'string' ? obj : undefined; 385 | var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 386 | var len1 = WASM_VECTOR_LEN; 387 | getInt32Memory0()[arg0 / 4 + 1] = len1; 388 | getInt32Memory0()[arg0 / 4 + 0] = ptr1; 389 | }; 390 | imports.wbg.__wbg_rustSend_aa102e1dd65dd988 = function() { return logError(function (arg0, arg1) { 391 | getObject(arg0).rustSend(takeObject(arg1)); 392 | }, arguments) }; 393 | imports.wbg.__wbindgen_object_clone_ref = function(arg0) { 394 | const ret = getObject(arg0); 395 | return addHeapObject(ret); 396 | }; 397 | imports.wbg.__wbindgen_boolean_get = function(arg0) { 398 | const v = getObject(arg0); 399 | const ret = typeof(v) === 'boolean' ? (v ? 1 : 0) : 2; 400 | _assertNum(ret); 401 | return ret; 402 | }; 403 | imports.wbg.__wbindgen_is_bigint = function(arg0) { 404 | const ret = typeof(getObject(arg0)) === 'bigint'; 405 | _assertBoolean(ret); 406 | return ret; 407 | }; 408 | imports.wbg.__wbindgen_bigint_from_i64 = function(arg0) { 409 | const ret = arg0; 410 | return addHeapObject(ret); 411 | }; 412 | imports.wbg.__wbindgen_jsval_eq = function(arg0, arg1) { 413 | const ret = getObject(arg0) === getObject(arg1); 414 | _assertBoolean(ret); 415 | return ret; 416 | }; 417 | imports.wbg.__wbindgen_bigint_from_u64 = function(arg0) { 418 | const ret = BigInt.asUintN(64, arg0); 419 | return addHeapObject(ret); 420 | }; 421 | imports.wbg.__wbindgen_error_new = function(arg0, arg1) { 422 | const ret = new Error(getStringFromWasm0(arg0, arg1)); 423 | return addHeapObject(ret); 424 | }; 425 | imports.wbg.__wbindgen_number_get = function(arg0, arg1) { 426 | const obj = getObject(arg1); 427 | const ret = typeof(obj) === 'number' ? obj : undefined; 428 | if (!isLikeNone(ret)) { 429 | _assertNum(ret); 430 | } 431 | getFloat64Memory0()[arg0 / 8 + 1] = isLikeNone(ret) ? 0 : ret; 432 | getInt32Memory0()[arg0 / 4 + 0] = !isLikeNone(ret); 433 | }; 434 | imports.wbg.__wbindgen_is_object = function(arg0) { 435 | const val = getObject(arg0); 436 | const ret = typeof(val) === 'object' && val !== null; 437 | _assertBoolean(ret); 438 | return ret; 439 | }; 440 | imports.wbg.__wbindgen_in = function(arg0, arg1) { 441 | const ret = getObject(arg0) in getObject(arg1); 442 | _assertBoolean(ret); 443 | return ret; 444 | }; 445 | imports.wbg.__wbindgen_string_new = function(arg0, arg1) { 446 | const ret = getStringFromWasm0(arg0, arg1); 447 | return addHeapObject(ret); 448 | }; 449 | imports.wbg.__wbg_getformdata_30aff64ff4a9a080 = function() { return logError(function (arg0) { 450 | const ret = get_form_data(getObject(arg0)); 451 | return addHeapObject(ret); 452 | }, arguments) }; 453 | imports.wbg.__wbindgen_is_string = function(arg0) { 454 | const ret = typeof(getObject(arg0)) === 'string'; 455 | _assertBoolean(ret); 456 | return ret; 457 | }; 458 | imports.wbg.__wbg_new_abda76e883ba8a5f = function() { return logError(function () { 459 | const ret = new Error(); 460 | return addHeapObject(ret); 461 | }, arguments) }; 462 | imports.wbg.__wbg_stack_658279fe44541cf6 = function() { return logError(function (arg0, arg1) { 463 | const ret = getObject(arg1).stack; 464 | const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 465 | const len1 = WASM_VECTOR_LEN; 466 | getInt32Memory0()[arg0 / 4 + 1] = len1; 467 | getInt32Memory0()[arg0 / 4 + 0] = ptr1; 468 | }, arguments) }; 469 | imports.wbg.__wbg_error_f851667af71bcfc6 = function() { return logError(function (arg0, arg1) { 470 | var v0 = getCachedStringFromWasm0(arg0, arg1); 471 | if (arg0 !== 0) { wasm.__wbindgen_free(arg0, arg1, 1); } 472 | console.error(v0); 473 | }, arguments) }; 474 | imports.wbg.__wbindgen_cb_drop = function(arg0) { 475 | const obj = takeObject(arg0).original; 476 | if (obj.cnt-- == 1) { 477 | obj.a = 0; 478 | return true; 479 | } 480 | const ret = false; 481 | _assertBoolean(ret); 482 | return ret; 483 | }; 484 | imports.wbg.__wbg_queueMicrotask_e5949c35d772a669 = function() { return logError(function (arg0) { 485 | queueMicrotask(getObject(arg0)); 486 | }, arguments) }; 487 | imports.wbg.__wbg_queueMicrotask_2be8b97a81fe4d00 = function() { return logError(function (arg0) { 488 | const ret = getObject(arg0).queueMicrotask; 489 | return addHeapObject(ret); 490 | }, arguments) }; 491 | imports.wbg.__wbindgen_is_function = function(arg0) { 492 | const ret = typeof(getObject(arg0)) === 'function'; 493 | _assertBoolean(ret); 494 | return ret; 495 | }; 496 | imports.wbg.__wbindgen_jsval_loose_eq = function(arg0, arg1) { 497 | const ret = getObject(arg0) == getObject(arg1); 498 | _assertBoolean(ret); 499 | return ret; 500 | }; 501 | imports.wbg.__wbg_String_88810dfeb4021902 = function() { return logError(function (arg0, arg1) { 502 | const ret = String(getObject(arg1)); 503 | const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 504 | const len1 = WASM_VECTOR_LEN; 505 | getInt32Memory0()[arg0 / 4 + 1] = len1; 506 | getInt32Memory0()[arg0 / 4 + 0] = ptr1; 507 | }, arguments) }; 508 | imports.wbg.__wbg_set_841ac57cff3d672b = function() { return logError(function (arg0, arg1, arg2) { 509 | getObject(arg0)[takeObject(arg1)] = takeObject(arg2); 510 | }, arguments) }; 511 | imports.wbg.__wbindgen_number_new = function(arg0) { 512 | const ret = arg0; 513 | return addHeapObject(ret); 514 | }; 515 | imports.wbg.__wbg_create_4fa2dd8b14b6c3cc = function() { return logError(function (arg0) { 516 | create(arg0 >>> 0); 517 | }, arguments) }; 518 | imports.wbg.__wbg_updatememory_4c09c2246a86718f = function() { return logError(function (arg0) { 519 | update_memory(takeObject(arg0)); 520 | }, arguments) }; 521 | imports.wbg.__wbg_savetemplate_742f86aebd69bb83 = function() { return logError(function (arg0, arg1, arg2) { 522 | var v0 = getArrayJsValueFromWasm0(arg0, arg1).slice(); 523 | wasm.__wbindgen_free(arg0, arg1 * 4, 4); 524 | save_template(v0, arg2 >>> 0); 525 | }, arguments) }; 526 | imports.wbg.__wbg_getnode_b1633a4b84264ce7 = function() { return logError(function (arg0) { 527 | const ret = get_node(arg0 >>> 0); 528 | return addHeapObject(ret); 529 | }, arguments) }; 530 | imports.wbg.__wbg_initilize_8b525fbe950133cd = function() { return logError(function (arg0, arg1) { 531 | initilize(takeObject(arg0), getObject(arg1)); 532 | }, arguments) }; 533 | imports.wbg.__wbg_setAttributeInner_ce265aa8339405b1 = function() { return logError(function (arg0, arg1, arg2, arg3, arg4, arg5) { 534 | var v0 = getCachedStringFromWasm0(arg1, arg2); 535 | var v1 = getCachedStringFromWasm0(arg4, arg5); 536 | setAttributeInner(takeObject(arg0), v0, takeObject(arg3), v1); 537 | }, arguments) }; 538 | imports.wbg.__wbg_instanceof_Window_cde2416cf5126a72 = function() { return logError(function (arg0) { 539 | let result; 540 | try { 541 | result = getObject(arg0) instanceof Window; 542 | } catch (_) { 543 | result = false; 544 | } 545 | const ret = result; 546 | _assertBoolean(ret); 547 | return ret; 548 | }, arguments) }; 549 | imports.wbg.__wbg_document_183cf1eecfdbffee = function() { return logError(function (arg0) { 550 | const ret = getObject(arg0).document; 551 | return isLikeNone(ret) ? 0 : addHeapObject(ret); 552 | }, arguments) }; 553 | imports.wbg.__wbg_createElement_9ce3fdea8322ff34 = function() { return handleError(function (arg0, arg1, arg2) { 554 | var v0 = getCachedStringFromWasm0(arg1, arg2); 555 | const ret = getObject(arg0).createElement(v0); 556 | return addHeapObject(ret); 557 | }, arguments) }; 558 | imports.wbg.__wbg_createElementNS_6a08d8f33e767e18 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { 559 | var v0 = getCachedStringFromWasm0(arg1, arg2); 560 | var v1 = getCachedStringFromWasm0(arg3, arg4); 561 | const ret = getObject(arg0).createElementNS(v0, v1); 562 | return addHeapObject(ret); 563 | }, arguments) }; 564 | imports.wbg.__wbg_createTextNode_01a7250c5ca46b04 = function() { return logError(function (arg0, arg1, arg2) { 565 | var v0 = getCachedStringFromWasm0(arg1, arg2); 566 | const ret = getObject(arg0).createTextNode(v0); 567 | return addHeapObject(ret); 568 | }, arguments) }; 569 | imports.wbg.__wbg_getElementById_328f8c4a5bb51ba8 = function() { return logError(function (arg0, arg1, arg2) { 570 | var v0 = getCachedStringFromWasm0(arg1, arg2); 571 | const ret = getObject(arg0).getElementById(v0); 572 | return isLikeNone(ret) ? 0 : addHeapObject(ret); 573 | }, arguments) }; 574 | imports.wbg.__wbg_instanceof_Element_6c7af07f5e6c8d69 = function() { return logError(function (arg0) { 575 | let result; 576 | try { 577 | result = getObject(arg0) instanceof Element; 578 | } catch (_) { 579 | result = false; 580 | } 581 | const ret = result; 582 | _assertBoolean(ret); 583 | return ret; 584 | }, arguments) }; 585 | imports.wbg.__wbg_getAttribute_a5ee18ad06ff0c94 = function() { return logError(function (arg0, arg1, arg2, arg3) { 586 | var v0 = getCachedStringFromWasm0(arg2, arg3); 587 | const ret = getObject(arg1).getAttribute(v0); 588 | var ptr2 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 589 | var len2 = WASM_VECTOR_LEN; 590 | getInt32Memory0()[arg0 / 4 + 1] = len2; 591 | getInt32Memory0()[arg0 / 4 + 0] = ptr2; 592 | }, arguments) }; 593 | imports.wbg.__wbg_getBoundingClientRect_0d74d25dcac14a05 = function() { return logError(function (arg0) { 594 | const ret = getObject(arg0).getBoundingClientRect(); 595 | return addHeapObject(ret); 596 | }, arguments) }; 597 | imports.wbg.__wbg_scrollIntoView_b5628be96371c8ee = function() { return logError(function (arg0, arg1) { 598 | getObject(arg0).scrollIntoView(getObject(arg1)); 599 | }, arguments) }; 600 | imports.wbg.__wbg_toggleAttribute_54aa0bc29cb338d6 = function() { return handleError(function (arg0, arg1, arg2) { 601 | var v0 = getCachedStringFromWasm0(arg1, arg2); 602 | const ret = getObject(arg0).toggleAttribute(v0); 603 | _assertBoolean(ret); 604 | return ret; 605 | }, arguments) }; 606 | imports.wbg.__wbg_instanceof_HtmlElement_d9fe655ad4f1046c = function() { return logError(function (arg0) { 607 | let result; 608 | try { 609 | result = getObject(arg0) instanceof HTMLElement; 610 | } catch (_) { 611 | result = false; 612 | } 613 | const ret = result; 614 | _assertBoolean(ret); 615 | return ret; 616 | }, arguments) }; 617 | imports.wbg.__wbg_blur_38e4aafa977ce401 = function() { return handleError(function (arg0) { 618 | getObject(arg0).blur(); 619 | }, arguments) }; 620 | imports.wbg.__wbg_focus_bab0841297cb9142 = function() { return handleError(function (arg0) { 621 | getObject(arg0).focus(); 622 | }, arguments) }; 623 | imports.wbg.__wbg_instanceof_HtmlInputElement_8f81a6600ceb1918 = function() { return logError(function (arg0) { 624 | let result; 625 | try { 626 | result = getObject(arg0) instanceof HTMLInputElement; 627 | } catch (_) { 628 | result = false; 629 | } 630 | const ret = result; 631 | _assertBoolean(ret); 632 | return ret; 633 | }, arguments) }; 634 | imports.wbg.__wbg_checked_1ce2f33e2ed42870 = function() { return logError(function (arg0) { 635 | const ret = getObject(arg0).checked; 636 | _assertBoolean(ret); 637 | return ret; 638 | }, arguments) }; 639 | imports.wbg.__wbg_files_b7b48824af0dcef1 = function() { return logError(function (arg0) { 640 | const ret = getObject(arg0).files; 641 | return isLikeNone(ret) ? 0 : addHeapObject(ret); 642 | }, arguments) }; 643 | imports.wbg.__wbg_type_e1a53a8d05c20ba9 = function() { return logError(function (arg0, arg1) { 644 | const ret = getObject(arg1).type; 645 | const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 646 | const len1 = WASM_VECTOR_LEN; 647 | getInt32Memory0()[arg0 / 4 + 1] = len1; 648 | getInt32Memory0()[arg0 / 4 + 0] = ptr1; 649 | }, arguments) }; 650 | imports.wbg.__wbg_value_5e860795f53217cd = function() { return logError(function (arg0, arg1) { 651 | const ret = getObject(arg1).value; 652 | const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 653 | const len1 = WASM_VECTOR_LEN; 654 | getInt32Memory0()[arg0 / 4 + 1] = len1; 655 | getInt32Memory0()[arg0 / 4 + 0] = ptr1; 656 | }, arguments) }; 657 | imports.wbg.__wbg_instanceof_HtmlFormElement_eb100a9bdacc9fe6 = function() { return logError(function (arg0) { 658 | let result; 659 | try { 660 | result = getObject(arg0) instanceof HTMLFormElement; 661 | } catch (_) { 662 | result = false; 663 | } 664 | const ret = result; 665 | _assertBoolean(ret); 666 | return ret; 667 | }, arguments) }; 668 | imports.wbg.__wbg_propertyName_2596a74bb6aa3871 = function() { return logError(function (arg0, arg1) { 669 | const ret = getObject(arg1).propertyName; 670 | const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 671 | const len1 = WASM_VECTOR_LEN; 672 | getInt32Memory0()[arg0 / 4 + 1] = len1; 673 | getInt32Memory0()[arg0 / 4 + 0] = ptr1; 674 | }, arguments) }; 675 | imports.wbg.__wbg_elapsedTime_992eda80be93e07a = function() { return logError(function (arg0) { 676 | const ret = getObject(arg0).elapsedTime; 677 | return ret; 678 | }, arguments) }; 679 | imports.wbg.__wbg_pseudoElement_55749329fd50da1a = function() { return logError(function (arg0, arg1) { 680 | const ret = getObject(arg1).pseudoElement; 681 | const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 682 | const len1 = WASM_VECTOR_LEN; 683 | getInt32Memory0()[arg0 / 4 + 1] = len1; 684 | getInt32Memory0()[arg0 / 4 + 0] = ptr1; 685 | }, arguments) }; 686 | imports.wbg.__wbg_instanceof_CompositionEvent_8f9dac3d92305818 = function() { return logError(function (arg0) { 687 | let result; 688 | try { 689 | result = getObject(arg0) instanceof CompositionEvent; 690 | } catch (_) { 691 | result = false; 692 | } 693 | const ret = result; 694 | _assertBoolean(ret); 695 | return ret; 696 | }, arguments) }; 697 | imports.wbg.__wbg_data_af325f86d262b9bd = function() { return logError(function (arg0, arg1) { 698 | const ret = getObject(arg1).data; 699 | var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 700 | var len1 = WASM_VECTOR_LEN; 701 | getInt32Memory0()[arg0 / 4 + 1] = len1; 702 | getInt32Memory0()[arg0 / 4 + 0] = ptr1; 703 | }, arguments) }; 704 | imports.wbg.__wbg_width_0ad17fa8ba1e2189 = function() { return logError(function (arg0) { 705 | const ret = getObject(arg0).width; 706 | return ret; 707 | }, arguments) }; 708 | imports.wbg.__wbg_height_825e522e5c1788ba = function() { return logError(function (arg0) { 709 | const ret = getObject(arg0).height; 710 | return ret; 711 | }, arguments) }; 712 | imports.wbg.__wbg_altKey_f384daa388a44745 = function() { return logError(function (arg0) { 713 | const ret = getObject(arg0).altKey; 714 | _assertBoolean(ret); 715 | return ret; 716 | }, arguments) }; 717 | imports.wbg.__wbg_ctrlKey_ac674c31f44bd157 = function() { return logError(function (arg0) { 718 | const ret = getObject(arg0).ctrlKey; 719 | _assertBoolean(ret); 720 | return ret; 721 | }, arguments) }; 722 | imports.wbg.__wbg_shiftKey_a741da931809868b = function() { return logError(function (arg0) { 723 | const ret = getObject(arg0).shiftKey; 724 | _assertBoolean(ret); 725 | return ret; 726 | }, arguments) }; 727 | imports.wbg.__wbg_metaKey_d37dd650c2a748a7 = function() { return logError(function (arg0) { 728 | const ret = getObject(arg0).metaKey; 729 | _assertBoolean(ret); 730 | return ret; 731 | }, arguments) }; 732 | imports.wbg.__wbg_location_552afa6a520ec909 = function() { return logError(function (arg0) { 733 | const ret = getObject(arg0).location; 734 | _assertNum(ret); 735 | return ret; 736 | }, arguments) }; 737 | imports.wbg.__wbg_repeat_51ae8ebaf84cf3df = function() { return logError(function (arg0) { 738 | const ret = getObject(arg0).repeat; 739 | _assertBoolean(ret); 740 | return ret; 741 | }, arguments) }; 742 | imports.wbg.__wbg_key_ab25ddd694dd43f3 = function() { return logError(function (arg0, arg1) { 743 | const ret = getObject(arg1).key; 744 | const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 745 | const len1 = WASM_VECTOR_LEN; 746 | getInt32Memory0()[arg0 / 4 + 1] = len1; 747 | getInt32Memory0()[arg0 / 4 + 0] = ptr1; 748 | }, arguments) }; 749 | imports.wbg.__wbg_code_6f828892fabc6b0f = function() { return logError(function (arg0, arg1) { 750 | const ret = getObject(arg1).code; 751 | const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 752 | const len1 = WASM_VECTOR_LEN; 753 | getInt32Memory0()[arg0 / 4 + 1] = len1; 754 | getInt32Memory0()[arg0 / 4 + 0] = ptr1; 755 | }, arguments) }; 756 | imports.wbg.__wbg_deltaX_1cd49e80ca3599f6 = function() { return logError(function (arg0) { 757 | const ret = getObject(arg0).deltaX; 758 | return ret; 759 | }, arguments) }; 760 | imports.wbg.__wbg_deltaY_b9ab90e34f3a0f1d = function() { return logError(function (arg0) { 761 | const ret = getObject(arg0).deltaY; 762 | return ret; 763 | }, arguments) }; 764 | imports.wbg.__wbg_deltaZ_adf095cf52b12d56 = function() { return logError(function (arg0) { 765 | const ret = getObject(arg0).deltaZ; 766 | return ret; 767 | }, arguments) }; 768 | imports.wbg.__wbg_deltaMode_eeaea4efbd95e3d5 = function() { return logError(function (arg0) { 769 | const ret = getObject(arg0).deltaMode; 770 | _assertNum(ret); 771 | return ret; 772 | }, arguments) }; 773 | imports.wbg.__wbg_result_5e08da49132b9af2 = function() { return handleError(function (arg0) { 774 | const ret = getObject(arg0).result; 775 | return addHeapObject(ret); 776 | }, arguments) }; 777 | imports.wbg.__wbg_setonload_a5989ad0a3cbb169 = function() { return logError(function (arg0, arg1) { 778 | getObject(arg0).onload = getObject(arg1); 779 | }, arguments) }; 780 | imports.wbg.__wbg_new_b71bf93085f9d631 = function() { return handleError(function () { 781 | const ret = new FileReader(); 782 | return addHeapObject(ret); 783 | }, arguments) }; 784 | imports.wbg.__wbg_readAsArrayBuffer_55965fe069b748b7 = function() { return handleError(function (arg0, arg1) { 785 | getObject(arg0).readAsArrayBuffer(getObject(arg1)); 786 | }, arguments) }; 787 | imports.wbg.__wbg_readAsText_0eed9060756df153 = function() { return handleError(function (arg0, arg1) { 788 | getObject(arg0).readAsText(getObject(arg1)); 789 | }, arguments) }; 790 | imports.wbg.__wbg_pointerId_58d55b218fe0dea2 = function() { return logError(function (arg0) { 791 | const ret = getObject(arg0).pointerId; 792 | _assertNum(ret); 793 | return ret; 794 | }, arguments) }; 795 | imports.wbg.__wbg_width_02e787c8e65511d1 = function() { return logError(function (arg0) { 796 | const ret = getObject(arg0).width; 797 | _assertNum(ret); 798 | return ret; 799 | }, arguments) }; 800 | imports.wbg.__wbg_height_8396972d637b9128 = function() { return logError(function (arg0) { 801 | const ret = getObject(arg0).height; 802 | _assertNum(ret); 803 | return ret; 804 | }, arguments) }; 805 | imports.wbg.__wbg_pressure_f15f6f1645166bb8 = function() { return logError(function (arg0) { 806 | const ret = getObject(arg0).pressure; 807 | return ret; 808 | }, arguments) }; 809 | imports.wbg.__wbg_tangentialPressure_180acf3927e899e7 = function() { return logError(function (arg0) { 810 | const ret = getObject(arg0).tangentialPressure; 811 | return ret; 812 | }, arguments) }; 813 | imports.wbg.__wbg_tiltX_7c7440cbdb1abdaf = function() { return logError(function (arg0) { 814 | const ret = getObject(arg0).tiltX; 815 | _assertNum(ret); 816 | return ret; 817 | }, arguments) }; 818 | imports.wbg.__wbg_tiltY_770b221a43e49644 = function() { return logError(function (arg0) { 819 | const ret = getObject(arg0).tiltY; 820 | _assertNum(ret); 821 | return ret; 822 | }, arguments) }; 823 | imports.wbg.__wbg_twist_eb171c54906c1e43 = function() { return logError(function (arg0) { 824 | const ret = getObject(arg0).twist; 825 | _assertNum(ret); 826 | return ret; 827 | }, arguments) }; 828 | imports.wbg.__wbg_pointerType_bd2c7e4cb53a4409 = function() { return logError(function (arg0, arg1) { 829 | const ret = getObject(arg1).pointerType; 830 | const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 831 | const len1 = WASM_VECTOR_LEN; 832 | getInt32Memory0()[arg0 / 4 + 1] = len1; 833 | getInt32Memory0()[arg0 / 4 + 0] = ptr1; 834 | }, arguments) }; 835 | imports.wbg.__wbg_isPrimary_1ea3d4a479812d77 = function() { return logError(function (arg0) { 836 | const ret = getObject(arg0).isPrimary; 837 | _assertBoolean(ret); 838 | return ret; 839 | }, arguments) }; 840 | imports.wbg.__wbg_top_4c7f1ff83300d0a8 = function() { return logError(function (arg0) { 841 | const ret = getObject(arg0).top; 842 | return ret; 843 | }, arguments) }; 844 | imports.wbg.__wbg_left_28b38696ec8237b7 = function() { return logError(function (arg0) { 845 | const ret = getObject(arg0).left; 846 | return ret; 847 | }, arguments) }; 848 | imports.wbg.__wbg_name_6443ed5608a826ef = function() { return logError(function (arg0, arg1) { 849 | const ret = getObject(arg1).name; 850 | const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 851 | const len1 = WASM_VECTOR_LEN; 852 | getInt32Memory0()[arg0 / 4 + 1] = len1; 853 | getInt32Memory0()[arg0 / 4 + 0] = ptr1; 854 | }, arguments) }; 855 | imports.wbg.__wbg_animationName_216bd7816a6302cc = function() { return logError(function (arg0, arg1) { 856 | const ret = getObject(arg1).animationName; 857 | const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 858 | const len1 = WASM_VECTOR_LEN; 859 | getInt32Memory0()[arg0 / 4 + 1] = len1; 860 | getInt32Memory0()[arg0 / 4 + 0] = ptr1; 861 | }, arguments) }; 862 | imports.wbg.__wbg_elapsedTime_87f68bd9680e2aec = function() { return logError(function (arg0) { 863 | const ret = getObject(arg0).elapsedTime; 864 | return ret; 865 | }, arguments) }; 866 | imports.wbg.__wbg_pseudoElement_4a7382f4b2fad873 = function() { return logError(function (arg0, arg1) { 867 | const ret = getObject(arg1).pseudoElement; 868 | const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 869 | const len1 = WASM_VECTOR_LEN; 870 | getInt32Memory0()[arg0 / 4 + 1] = len1; 871 | getInt32Memory0()[arg0 / 4 + 0] = ptr1; 872 | }, arguments) }; 873 | imports.wbg.__wbg_instanceof_Node_0c2ef3446a9c63c1 = function() { return logError(function (arg0) { 874 | let result; 875 | try { 876 | result = getObject(arg0) instanceof Node; 877 | } catch (_) { 878 | result = false; 879 | } 880 | const ret = result; 881 | _assertBoolean(ret); 882 | return ret; 883 | }, arguments) }; 884 | imports.wbg.__wbg_parentElement_592cb54944d3d002 = function() { return logError(function (arg0) { 885 | const ret = getObject(arg0).parentElement; 886 | return isLikeNone(ret) ? 0 : addHeapObject(ret); 887 | }, arguments) }; 888 | imports.wbg.__wbg_textContent_d69d000f6081b514 = function() { return logError(function (arg0, arg1) { 889 | const ret = getObject(arg1).textContent; 890 | var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 891 | var len1 = WASM_VECTOR_LEN; 892 | getInt32Memory0()[arg0 / 4 + 1] = len1; 893 | getInt32Memory0()[arg0 / 4 + 0] = ptr1; 894 | }, arguments) }; 895 | imports.wbg.__wbg_appendChild_2e6a6c9d1f0d443d = function() { return handleError(function (arg0, arg1) { 896 | const ret = getObject(arg0).appendChild(getObject(arg1)); 897 | return addHeapObject(ret); 898 | }, arguments) }; 899 | imports.wbg.__wbg_pageX_c339ff6654c2cbd1 = function() { return logError(function (arg0) { 900 | const ret = getObject(arg0).pageX; 901 | _assertNum(ret); 902 | return ret; 903 | }, arguments) }; 904 | imports.wbg.__wbg_pageY_5e7965b7738fd1fd = function() { return logError(function (arg0) { 905 | const ret = getObject(arg0).pageY; 906 | _assertNum(ret); 907 | return ret; 908 | }, arguments) }; 909 | imports.wbg.__wbg_length_1172ab9213274731 = function() { return logError(function (arg0) { 910 | const ret = getObject(arg0).length; 911 | _assertNum(ret); 912 | return ret; 913 | }, arguments) }; 914 | imports.wbg.__wbg_item_d4c4440d84ad5f21 = function() { return logError(function (arg0, arg1) { 915 | const ret = getObject(arg0).item(arg1 >>> 0); 916 | return isLikeNone(ret) ? 0 : addHeapObject(ret); 917 | }, arguments) }; 918 | imports.wbg.__wbg_screenX_984cd42cf94d05d1 = function() { return logError(function (arg0) { 919 | const ret = getObject(arg0).screenX; 920 | _assertNum(ret); 921 | return ret; 922 | }, arguments) }; 923 | imports.wbg.__wbg_screenY_36df47c93f07c67f = function() { return logError(function (arg0) { 924 | const ret = getObject(arg0).screenY; 925 | _assertNum(ret); 926 | return ret; 927 | }, arguments) }; 928 | imports.wbg.__wbg_clientX_61d53edfc3453552 = function() { return logError(function (arg0) { 929 | const ret = getObject(arg0).clientX; 930 | _assertNum(ret); 931 | return ret; 932 | }, arguments) }; 933 | imports.wbg.__wbg_clientY_32145ace1ef7c9c0 = function() { return logError(function (arg0) { 934 | const ret = getObject(arg0).clientY; 935 | _assertNum(ret); 936 | return ret; 937 | }, arguments) }; 938 | imports.wbg.__wbg_offsetX_3a146805201e432d = function() { return logError(function (arg0) { 939 | const ret = getObject(arg0).offsetX; 940 | _assertNum(ret); 941 | return ret; 942 | }, arguments) }; 943 | imports.wbg.__wbg_offsetY_4a991814d3d6487d = function() { return logError(function (arg0) { 944 | const ret = getObject(arg0).offsetY; 945 | _assertNum(ret); 946 | return ret; 947 | }, arguments) }; 948 | imports.wbg.__wbg_ctrlKey_be79eb9c26bb9db2 = function() { return logError(function (arg0) { 949 | const ret = getObject(arg0).ctrlKey; 950 | _assertBoolean(ret); 951 | return ret; 952 | }, arguments) }; 953 | imports.wbg.__wbg_shiftKey_785a75b4a861011d = function() { return logError(function (arg0) { 954 | const ret = getObject(arg0).shiftKey; 955 | _assertBoolean(ret); 956 | return ret; 957 | }, arguments) }; 958 | imports.wbg.__wbg_altKey_8248b429b86fd766 = function() { return logError(function (arg0) { 959 | const ret = getObject(arg0).altKey; 960 | _assertBoolean(ret); 961 | return ret; 962 | }, arguments) }; 963 | imports.wbg.__wbg_metaKey_ed354cc496f6ca35 = function() { return logError(function (arg0) { 964 | const ret = getObject(arg0).metaKey; 965 | _assertBoolean(ret); 966 | return ret; 967 | }, arguments) }; 968 | imports.wbg.__wbg_button_22121917aaba48d0 = function() { return logError(function (arg0) { 969 | const ret = getObject(arg0).button; 970 | _assertNum(ret); 971 | return ret; 972 | }, arguments) }; 973 | imports.wbg.__wbg_buttons_40f0eebba8f0a11e = function() { return logError(function (arg0) { 974 | const ret = getObject(arg0).buttons; 975 | _assertNum(ret); 976 | return ret; 977 | }, arguments) }; 978 | imports.wbg.__wbg_instanceof_HtmlTextAreaElement_a38b7b941ea08357 = function() { return logError(function (arg0) { 979 | let result; 980 | try { 981 | result = getObject(arg0) instanceof HTMLTextAreaElement; 982 | } catch (_) { 983 | result = false; 984 | } 985 | const ret = result; 986 | _assertBoolean(ret); 987 | return ret; 988 | }, arguments) }; 989 | imports.wbg.__wbg_value_539db729f551be3a = function() { return logError(function (arg0, arg1) { 990 | const ret = getObject(arg1).value; 991 | const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 992 | const len1 = WASM_VECTOR_LEN; 993 | getInt32Memory0()[arg0 / 4 + 1] = len1; 994 | getInt32Memory0()[arg0 / 4 + 0] = ptr1; 995 | }, arguments) }; 996 | imports.wbg.__wbg_type_035d2025d17aefc7 = function() { return logError(function (arg0, arg1) { 997 | const ret = getObject(arg1).type; 998 | const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 999 | const len1 = WASM_VECTOR_LEN; 1000 | getInt32Memory0()[arg0 / 4 + 1] = len1; 1001 | getInt32Memory0()[arg0 / 4 + 0] = ptr1; 1002 | }, arguments) }; 1003 | imports.wbg.__wbg_target_6efb4504c149139f = function() { return logError(function (arg0) { 1004 | const ret = getObject(arg0).target; 1005 | return isLikeNone(ret) ? 0 : addHeapObject(ret); 1006 | }, arguments) }; 1007 | imports.wbg.__wbg_preventDefault_9299867e06da6909 = function() { return logError(function (arg0) { 1008 | getObject(arg0).preventDefault(); 1009 | }, arguments) }; 1010 | imports.wbg.__wbg_instanceof_HtmlSelectElement_1eb80c020d3f1d59 = function() { return logError(function (arg0) { 1011 | let result; 1012 | try { 1013 | result = getObject(arg0) instanceof HTMLSelectElement; 1014 | } catch (_) { 1015 | result = false; 1016 | } 1017 | const ret = result; 1018 | _assertBoolean(ret); 1019 | return ret; 1020 | }, arguments) }; 1021 | imports.wbg.__wbg_value_9af7d77fa0b242ba = function() { return logError(function (arg0, arg1) { 1022 | const ret = getObject(arg1).value; 1023 | const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 1024 | const len1 = WASM_VECTOR_LEN; 1025 | getInt32Memory0()[arg0 / 4 + 1] = len1; 1026 | getInt32Memory0()[arg0 / 4 + 0] = ptr1; 1027 | }, arguments) }; 1028 | imports.wbg.__wbg_altKey_b6593a1d59ceadb1 = function() { return logError(function (arg0) { 1029 | const ret = getObject(arg0).altKey; 1030 | _assertBoolean(ret); 1031 | return ret; 1032 | }, arguments) }; 1033 | imports.wbg.__wbg_metaKey_1691ffef7e48e07d = function() { return logError(function (arg0) { 1034 | const ret = getObject(arg0).metaKey; 1035 | _assertBoolean(ret); 1036 | return ret; 1037 | }, arguments) }; 1038 | imports.wbg.__wbg_ctrlKey_2407b26614bf12ca = function() { return logError(function (arg0) { 1039 | const ret = getObject(arg0).ctrlKey; 1040 | _assertBoolean(ret); 1041 | return ret; 1042 | }, arguments) }; 1043 | imports.wbg.__wbg_shiftKey_18d8930656b851e6 = function() { return logError(function (arg0) { 1044 | const ret = getObject(arg0).shiftKey; 1045 | _assertBoolean(ret); 1046 | return ret; 1047 | }, arguments) }; 1048 | imports.wbg.__wbg_debug_8f9a97dc395d342f = function() { return logError(function (arg0, arg1, arg2, arg3) { 1049 | console.debug(getObject(arg0), getObject(arg1), getObject(arg2), getObject(arg3)); 1050 | }, arguments) }; 1051 | imports.wbg.__wbg_error_f0a6627f4b23c19d = function() { return logError(function (arg0) { 1052 | console.error(getObject(arg0)); 1053 | }, arguments) }; 1054 | imports.wbg.__wbg_error_94a25ece8eeb7bca = function() { return logError(function (arg0, arg1, arg2, arg3) { 1055 | console.error(getObject(arg0), getObject(arg1), getObject(arg2), getObject(arg3)); 1056 | }, arguments) }; 1057 | imports.wbg.__wbg_info_1d035e3d63b89260 = function() { return logError(function (arg0, arg1, arg2, arg3) { 1058 | console.info(getObject(arg0), getObject(arg1), getObject(arg2), getObject(arg3)); 1059 | }, arguments) }; 1060 | imports.wbg.__wbg_log_00bb83da94eb9ca8 = function() { return logError(function (arg0, arg1, arg2, arg3) { 1061 | console.log(getObject(arg0), getObject(arg1), getObject(arg2), getObject(arg3)); 1062 | }, arguments) }; 1063 | imports.wbg.__wbg_warn_fab4b297e5c436a0 = function() { return logError(function (arg0, arg1, arg2, arg3) { 1064 | console.warn(getObject(arg0), getObject(arg1), getObject(arg2), getObject(arg3)); 1065 | }, arguments) }; 1066 | imports.wbg.__wbg_charCodeAt_0afea94da2316198 = function() { return logError(function (arg0, arg1) { 1067 | const ret = getObject(arg0).charCodeAt(arg1 >>> 0); 1068 | return ret; 1069 | }, arguments) }; 1070 | imports.wbg.__wbg_get_4a9aa5157afeb382 = function() { return logError(function (arg0, arg1) { 1071 | const ret = getObject(arg0)[arg1 >>> 0]; 1072 | return addHeapObject(ret); 1073 | }, arguments) }; 1074 | imports.wbg.__wbg_length_cace2e0b3ddc0502 = function() { return logError(function (arg0) { 1075 | const ret = getObject(arg0).length; 1076 | _assertNum(ret); 1077 | return ret; 1078 | }, arguments) }; 1079 | imports.wbg.__wbg_new_08236689f0afb357 = function() { return logError(function () { 1080 | const ret = new Array(); 1081 | return addHeapObject(ret); 1082 | }, arguments) }; 1083 | imports.wbg.__wbg_newnoargs_ccdcae30fd002262 = function() { return logError(function (arg0, arg1) { 1084 | var v0 = getCachedStringFromWasm0(arg0, arg1); 1085 | const ret = new Function(v0); 1086 | return addHeapObject(ret); 1087 | }, arguments) }; 1088 | imports.wbg.__wbg_new_1b94180eeb48f2a2 = function() { return logError(function () { 1089 | const ret = new Map(); 1090 | return addHeapObject(ret); 1091 | }, arguments) }; 1092 | imports.wbg.__wbg_next_15da6a3df9290720 = function() { return logError(function (arg0) { 1093 | const ret = getObject(arg0).next; 1094 | return addHeapObject(ret); 1095 | }, arguments) }; 1096 | imports.wbg.__wbg_next_1989a20442400aaa = function() { return handleError(function (arg0) { 1097 | const ret = getObject(arg0).next(); 1098 | return addHeapObject(ret); 1099 | }, arguments) }; 1100 | imports.wbg.__wbg_done_bc26bf4ada718266 = function() { return logError(function (arg0) { 1101 | const ret = getObject(arg0).done; 1102 | _assertBoolean(ret); 1103 | return ret; 1104 | }, arguments) }; 1105 | imports.wbg.__wbg_value_0570714ff7d75f35 = function() { return logError(function (arg0) { 1106 | const ret = getObject(arg0).value; 1107 | return addHeapObject(ret); 1108 | }, arguments) }; 1109 | imports.wbg.__wbg_iterator_7ee1a391d310f8e4 = function() { return logError(function () { 1110 | const ret = Symbol.iterator; 1111 | return addHeapObject(ret); 1112 | }, arguments) }; 1113 | imports.wbg.__wbg_get_2aff440840bb6202 = function() { return handleError(function (arg0, arg1) { 1114 | const ret = Reflect.get(getObject(arg0), getObject(arg1)); 1115 | return addHeapObject(ret); 1116 | }, arguments) }; 1117 | imports.wbg.__wbg_call_669127b9d730c650 = function() { return handleError(function (arg0, arg1) { 1118 | const ret = getObject(arg0).call(getObject(arg1)); 1119 | return addHeapObject(ret); 1120 | }, arguments) }; 1121 | imports.wbg.__wbg_new_c728d68b8b34487e = function() { return logError(function () { 1122 | const ret = new Object(); 1123 | return addHeapObject(ret); 1124 | }, arguments) }; 1125 | imports.wbg.__wbg_length_dc3d54e407f84296 = function() { return logError(function (arg0) { 1126 | const ret = getObject(arg0).length; 1127 | _assertNum(ret); 1128 | return ret; 1129 | }, arguments) }; 1130 | imports.wbg.__wbg_self_3fad056edded10bd = function() { return handleError(function () { 1131 | const ret = self.self; 1132 | return addHeapObject(ret); 1133 | }, arguments) }; 1134 | imports.wbg.__wbg_window_a4f46c98a61d4089 = function() { return handleError(function () { 1135 | const ret = window.window; 1136 | return addHeapObject(ret); 1137 | }, arguments) }; 1138 | imports.wbg.__wbg_globalThis_17eff828815f7d84 = function() { return handleError(function () { 1139 | const ret = globalThis.globalThis; 1140 | return addHeapObject(ret); 1141 | }, arguments) }; 1142 | imports.wbg.__wbg_global_46f939f6541643c5 = function() { return handleError(function () { 1143 | const ret = global.global; 1144 | return addHeapObject(ret); 1145 | }, arguments) }; 1146 | imports.wbg.__wbg_set_0ac78a2bc07da03c = function() { return logError(function (arg0, arg1, arg2) { 1147 | getObject(arg0)[arg1 >>> 0] = takeObject(arg2); 1148 | }, arguments) }; 1149 | imports.wbg.__wbg_isArray_38525be7442aa21e = function() { return logError(function (arg0) { 1150 | const ret = Array.isArray(getObject(arg0)); 1151 | _assertBoolean(ret); 1152 | return ret; 1153 | }, arguments) }; 1154 | imports.wbg.__wbg_instanceof_ArrayBuffer_c7cc317e5c29cc0d = function() { return logError(function (arg0) { 1155 | let result; 1156 | try { 1157 | result = getObject(arg0) instanceof ArrayBuffer; 1158 | } catch (_) { 1159 | result = false; 1160 | } 1161 | const ret = result; 1162 | _assertBoolean(ret); 1163 | return ret; 1164 | }, arguments) }; 1165 | imports.wbg.__wbg_newwithargs_a80ae0747e4a86fc = function() { return logError(function (arg0, arg1, arg2, arg3) { 1166 | var v0 = getCachedStringFromWasm0(arg0, arg1); 1167 | var v1 = getCachedStringFromWasm0(arg2, arg3); 1168 | const ret = new Function(v0, v1); 1169 | return addHeapObject(ret); 1170 | }, arguments) }; 1171 | imports.wbg.__wbg_call_53fc3abd42e24ec8 = function() { return handleError(function (arg0, arg1, arg2) { 1172 | const ret = getObject(arg0).call(getObject(arg1), getObject(arg2)); 1173 | return addHeapObject(ret); 1174 | }, arguments) }; 1175 | imports.wbg.__wbg_set_3355b9f2d3092e3b = function() { return logError(function (arg0, arg1, arg2) { 1176 | const ret = getObject(arg0).set(getObject(arg1), getObject(arg2)); 1177 | return addHeapObject(ret); 1178 | }, arguments) }; 1179 | imports.wbg.__wbg_entries_6e8b68fd33fafc40 = function() { return logError(function (arg0) { 1180 | const ret = getObject(arg0).entries(); 1181 | return addHeapObject(ret); 1182 | }, arguments) }; 1183 | imports.wbg.__wbg_isSafeInteger_c38b0a16d0c7cef7 = function() { return logError(function (arg0) { 1184 | const ret = Number.isSafeInteger(getObject(arg0)); 1185 | _assertBoolean(ret); 1186 | return ret; 1187 | }, arguments) }; 1188 | imports.wbg.__wbg_entries_6d727b73ee02b7ce = function() { return logError(function (arg0) { 1189 | const ret = Object.entries(getObject(arg0)); 1190 | return addHeapObject(ret); 1191 | }, arguments) }; 1192 | imports.wbg.__wbg_resolve_a3252b2860f0a09e = function() { return logError(function (arg0) { 1193 | const ret = Promise.resolve(getObject(arg0)); 1194 | return addHeapObject(ret); 1195 | }, arguments) }; 1196 | imports.wbg.__wbg_then_89e1c559530b85cf = function() { return logError(function (arg0, arg1) { 1197 | const ret = getObject(arg0).then(getObject(arg1)); 1198 | return addHeapObject(ret); 1199 | }, arguments) }; 1200 | imports.wbg.__wbg_buffer_344d9b41efe96da7 = function() { return logError(function (arg0) { 1201 | const ret = getObject(arg0).buffer; 1202 | return addHeapObject(ret); 1203 | }, arguments) }; 1204 | imports.wbg.__wbg_new_d8a000788389a31e = function() { return logError(function (arg0) { 1205 | const ret = new Uint8Array(getObject(arg0)); 1206 | return addHeapObject(ret); 1207 | }, arguments) }; 1208 | imports.wbg.__wbg_set_dcfd613a3420f908 = function() { return logError(function (arg0, arg1, arg2) { 1209 | getObject(arg0).set(getObject(arg1), arg2 >>> 0); 1210 | }, arguments) }; 1211 | imports.wbg.__wbg_length_a5587d6cd79ab197 = function() { return logError(function (arg0) { 1212 | const ret = getObject(arg0).length; 1213 | _assertNum(ret); 1214 | return ret; 1215 | }, arguments) }; 1216 | imports.wbg.__wbg_instanceof_Uint8Array_19e6f142a5e7e1e1 = function() { return logError(function (arg0) { 1217 | let result; 1218 | try { 1219 | result = getObject(arg0) instanceof Uint8Array; 1220 | } catch (_) { 1221 | result = false; 1222 | } 1223 | const ret = result; 1224 | _assertBoolean(ret); 1225 | return ret; 1226 | }, arguments) }; 1227 | imports.wbg.__wbg_stringify_4039297315a25b00 = function() { return handleError(function (arg0) { 1228 | const ret = JSON.stringify(getObject(arg0)); 1229 | return addHeapObject(ret); 1230 | }, arguments) }; 1231 | imports.wbg.__wbg_set_40f7786a25a9cc7e = function() { return handleError(function (arg0, arg1, arg2) { 1232 | const ret = Reflect.set(getObject(arg0), getObject(arg1), getObject(arg2)); 1233 | _assertBoolean(ret); 1234 | return ret; 1235 | }, arguments) }; 1236 | imports.wbg.__wbindgen_bigint_get_as_i64 = function(arg0, arg1) { 1237 | const v = getObject(arg1); 1238 | const ret = typeof(v) === 'bigint' ? v : undefined; 1239 | if (!isLikeNone(ret)) { 1240 | _assertBigInt(ret); 1241 | } 1242 | getBigInt64Memory0()[arg0 / 8 + 1] = isLikeNone(ret) ? BigInt(0) : ret; 1243 | getInt32Memory0()[arg0 / 4 + 0] = !isLikeNone(ret); 1244 | }; 1245 | imports.wbg.__wbindgen_debug_string = function(arg0, arg1) { 1246 | const ret = debugString(getObject(arg1)); 1247 | const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 1248 | const len1 = WASM_VECTOR_LEN; 1249 | getInt32Memory0()[arg0 / 4 + 1] = len1; 1250 | getInt32Memory0()[arg0 / 4 + 0] = ptr1; 1251 | }; 1252 | imports.wbg.__wbindgen_throw = function(arg0, arg1) { 1253 | throw new Error(getStringFromWasm0(arg0, arg1)); 1254 | }; 1255 | imports.wbg.__wbindgen_memory = function() { 1256 | const ret = wasm.memory; 1257 | return addHeapObject(ret); 1258 | }; 1259 | imports.wbg.__wbindgen_closure_wrapper382 = function() { return logError(function (arg0, arg1, arg2) { 1260 | const ret = makeMutClosure(arg0, arg1, 170, __wbg_adapter_48); 1261 | return addHeapObject(ret); 1262 | }, arguments) }; 1263 | imports.wbg.__wbindgen_closure_wrapper383 = function() { return logError(function (arg0, arg1, arg2) { 1264 | const ret = makeMutClosure(arg0, arg1, 170, __wbg_adapter_51); 1265 | return addHeapObject(ret); 1266 | }, arguments) }; 1267 | imports.wbg.__wbindgen_closure_wrapper386 = function() { return logError(function (arg0, arg1, arg2) { 1268 | const ret = makeMutClosure(arg0, arg1, 170, __wbg_adapter_54); 1269 | return addHeapObject(ret); 1270 | }, arguments) }; 1271 | imports.wbg.__wbindgen_closure_wrapper534 = function() { return logError(function (arg0, arg1, arg2) { 1272 | const ret = makeMutClosure(arg0, arg1, 223, __wbg_adapter_57); 1273 | return addHeapObject(ret); 1274 | }, arguments) }; 1275 | imports['./snippets/dioxus-interpreter-js-603636eeca72cf05/inline0.js'] = __wbg_star0; 1276 | 1277 | return imports; 1278 | } 1279 | 1280 | function __wbg_init_memory(imports, maybe_memory) { 1281 | 1282 | } 1283 | 1284 | function __wbg_finalize_init(instance, module) { 1285 | wasm = instance.exports; 1286 | __wbg_init.__wbindgen_wasm_module = module; 1287 | cachedBigInt64Memory0 = null; 1288 | cachedFloat64Memory0 = null; 1289 | cachedInt32Memory0 = null; 1290 | cachedUint32Memory0 = null; 1291 | cachedUint8Memory0 = null; 1292 | 1293 | wasm.__wbindgen_start(); 1294 | return wasm; 1295 | } 1296 | 1297 | function initSync(module) { 1298 | if (wasm !== undefined) return wasm; 1299 | 1300 | const imports = __wbg_get_imports(); 1301 | 1302 | __wbg_init_memory(imports); 1303 | 1304 | if (!(module instanceof WebAssembly.Module)) { 1305 | module = new WebAssembly.Module(module); 1306 | } 1307 | 1308 | const instance = new WebAssembly.Instance(module, imports); 1309 | 1310 | return __wbg_finalize_init(instance, module); 1311 | } 1312 | 1313 | async function __wbg_init(input) { 1314 | if (wasm !== undefined) return wasm; 1315 | 1316 | 1317 | const imports = __wbg_get_imports(); 1318 | 1319 | if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) { 1320 | input = fetch(input); 1321 | } 1322 | 1323 | __wbg_init_memory(imports); 1324 | 1325 | const { instance, module } = await __wbg_load(await input, imports); 1326 | 1327 | return __wbg_finalize_init(instance, module); 1328 | } 1329 | 1330 | export { initSync } 1331 | export default __wbg_init; 1332 | -------------------------------------------------------------------------------- /docs/examples/prime-ministers/assets/dioxus/dioxus-sortable_bg.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feral-dot-io/dioxus-sortable/a830a2e7dba76175e8e93055dedc341ea3f17626/docs/examples/prime-ministers/assets/dioxus/dioxus-sortable_bg.wasm -------------------------------------------------------------------------------- /docs/examples/prime-ministers/assets/dioxus/snippets/dioxus-interpreter-js-603636eeca72cf05/inline0.js: -------------------------------------------------------------------------------- 1 | let m,p,ls,d,t,op,i,e,z,metaflags; 2 | 3 | class ListenerMap { 4 | constructor(root) { 5 | // bubbling events can listen at the root element 6 | this.global = {}; 7 | // non bubbling events listen at the element the listener was created at 8 | this.local = {}; 9 | this.root = null; 10 | this.handler = null; 11 | } 12 | 13 | create(event_name, element, bubbles) { 14 | if (bubbles) { 15 | if (this.global[event_name] === undefined) { 16 | this.global[event_name] = {}; 17 | this.global[event_name].active = 1; 18 | this.root.addEventListener(event_name, this.handler); 19 | } else { 20 | this.global[event_name].active++; 21 | } 22 | } 23 | else { 24 | const id = element.getAttribute("data-dioxus-id"); 25 | if (!this.local[id]) { 26 | this.local[id] = {}; 27 | } 28 | element.addEventListener(event_name, this.handler); 29 | } 30 | } 31 | 32 | remove(element, event_name, bubbles) { 33 | if (bubbles) { 34 | this.global[event_name].active--; 35 | if (this.global[event_name].active === 0) { 36 | this.root.removeEventListener(event_name, this.global[event_name].callback); 37 | delete this.global[event_name]; 38 | } 39 | } 40 | else { 41 | const id = element.getAttribute("data-dioxus-id"); 42 | delete this.local[id][event_name]; 43 | if (this.local[id].length === 0) { 44 | delete this.local[id]; 45 | } 46 | element.removeEventListener(event_name, this.handler); 47 | } 48 | } 49 | 50 | removeAllNonBubbling(element) { 51 | const id = element.getAttribute("data-dioxus-id"); 52 | delete this.local[id]; 53 | } 54 | } 55 | function SetAttributeInner(node, field, value, ns) { 56 | const name = field; 57 | if (ns === "style") { 58 | // ????? why do we need to do this 59 | if (node.style === undefined) { 60 | node.style = {}; 61 | } 62 | node.style[name] = value; 63 | } else if (ns !== null && ns !== undefined && ns !== "") { 64 | node.setAttributeNS(ns, name, value); 65 | } else { 66 | switch (name) { 67 | case "value": 68 | if (value !== node.value) { 69 | node.value = value; 70 | } 71 | break; 72 | case "initial_value": 73 | node.defaultValue = value; 74 | break; 75 | case "checked": 76 | node.checked = truthy(value); 77 | break; 78 | case "selected": 79 | node.selected = truthy(value); 80 | break; 81 | case "dangerous_inner_html": 82 | node.innerHTML = value; 83 | break; 84 | default: 85 | // https://github.com/facebook/react/blob/8b88ac2592c5f555f315f9440cbb665dd1e7457a/packages/react-dom/src/shared/DOMProperty.js#L352-L364 86 | if (!truthy(value) && bool_attrs.hasOwnProperty(name)) { 87 | node.removeAttribute(name); 88 | } else { 89 | node.setAttribute(name, value); 90 | } 91 | } 92 | } 93 | } 94 | function LoadChild(ptr, len) { 95 | // iterate through each number and get that child 96 | node = stack[stack.length - 1]; 97 | ptr_end = ptr + len; 98 | for (; ptr < ptr_end; ptr++) { 99 | end = m.getUint8(ptr); 100 | for (node = node.firstChild; end > 0; end--) { 101 | node = node.nextSibling; 102 | } 103 | } 104 | return node; 105 | } 106 | const listeners = new ListenerMap(); 107 | let nodes = []; 108 | let stack = []; 109 | let root; 110 | const templates = {}; 111 | let node, els, end, ptr_end, k; 112 | export function save_template(nodes, tmpl_id) { 113 | templates[tmpl_id] = nodes; 114 | } 115 | export function set_node(id, node) { 116 | nodes[id] = node; 117 | } 118 | export function get_node(id) { 119 | return nodes[id]; 120 | } 121 | export function initilize(root, handler) { 122 | listeners.handler = handler; 123 | nodes = [root]; 124 | stack = [root]; 125 | listeners.root = root; 126 | } 127 | function AppendChildren(id, many){ 128 | root = nodes[id]; 129 | els = stack.splice(stack.length-many); 130 | for (k = 0; k < many; k++) { 131 | root.appendChild(els[k]); 132 | } 133 | } 134 | const bool_attrs = { 135 | allowfullscreen: true, 136 | allowpaymentrequest: true, 137 | async: true, 138 | autofocus: true, 139 | autoplay: true, 140 | checked: true, 141 | controls: true, 142 | default: true, 143 | defer: true, 144 | disabled: true, 145 | formnovalidate: true, 146 | hidden: true, 147 | ismap: true, 148 | itemscope: true, 149 | loop: true, 150 | multiple: true, 151 | muted: true, 152 | nomodule: true, 153 | novalidate: true, 154 | open: true, 155 | playsinline: true, 156 | readonly: true, 157 | required: true, 158 | reversed: true, 159 | selected: true, 160 | truespeed: true, 161 | webkitdirectory: true, 162 | }; 163 | function truthy(val) { 164 | return val === "true" || val === true; 165 | } 166 | let s = "";let lsp,sp,sl; let c = new TextDecoder();const ns_cache = []; 167 | let ns_cache_tmp1, ns_cache_tmp2; 168 | function get_ns_cache() { 169 | ns_cache_tmp2 = u8buf[u8bufp++]; 170 | if(ns_cache_tmp2 & 128){ 171 | ns_cache_tmp1=s.substring(sp,sp+=u8buf[u8bufp++]); 172 | ns_cache[ns_cache_tmp2&4294967167]=ns_cache_tmp1; 173 | return ns_cache_tmp1; 174 | } 175 | else{ 176 | return ns_cache[ns_cache_tmp2&4294967167]; 177 | } 178 | }const attr = []; 179 | let attr_tmp1, attr_tmp2; 180 | function get_attr() { 181 | attr_tmp2 = u8buf[u8bufp++]; 182 | if(attr_tmp2 & 128){ 183 | attr_tmp1=s.substring(sp,sp+=u8buf[u8bufp++]); 184 | attr[attr_tmp2&4294967167]=attr_tmp1; 185 | return attr_tmp1; 186 | } 187 | else{ 188 | return attr[attr_tmp2&4294967167]; 189 | } 190 | }const evt = []; 191 | let evt_tmp1, evt_tmp2; 192 | function get_evt() { 193 | evt_tmp2 = u8buf[u8bufp++]; 194 | if(evt_tmp2 & 128){ 195 | evt_tmp1=s.substring(sp,sp+=u8buf[u8bufp++]); 196 | evt[evt_tmp2&4294967167]=evt_tmp1; 197 | return evt_tmp1; 198 | } 199 | else{ 200 | return evt[evt_tmp2&4294967167]; 201 | } 202 | }let u32buf,u32bufp;let u8buf,u8bufp; 203 | let ptr,len,ns,id,bubbles,field,value,event_name; 204 | export function create(r){ 205 | d=r; 206 | } 207 | export function update_memory(b){ 208 | m=new DataView(b.buffer) 209 | } 210 | export function run(){ 211 | metaflags=m.getUint32(d,true); 212 | if((metaflags>>>12)&1){ 213 | ls=m.getUint32(d+12*4,true); 214 | } 215 | p=ls; 216 | if (metaflags&1){ 217 | lsp = m.getUint32(d+1*4,true); 218 | } 219 | if ((metaflags>>>2)&1) { 220 | sl = m.getUint32(d+2*4,true); 221 | if ((metaflags>>>1)&1) { 222 | sp = lsp; 223 | s = ""; 224 | e = sp + ((sl / 4) | 0) * 4; 225 | while (sp < e) { 226 | t = m.getUint32(sp, true); 227 | s += String.fromCharCode( 228 | t & 255, 229 | (t & 65280) >> 8, 230 | (t & 16711680) >> 16, 231 | t >> 24 232 | ); 233 | sp += 4; 234 | } 235 | while (sp < lsp + sl) { 236 | s += String.fromCharCode(m.getUint8(sp++)); 237 | } 238 | } else { 239 | s = c.decode(new DataView(m.buffer, lsp, sl)); 240 | } 241 | } 242 | sp=0;if ((metaflags>>>3)&1){ 243 | u32buf=new Uint32Array(m.buffer,m.getUint32(d+3*4,true)) 244 | } 245 | u32bufp=0;if ((metaflags>>>5)&1){ 246 | u8buf=new Uint8Array(m.buffer,m.getUint32(d+5*4,true)) 247 | } 248 | u8bufp=0; 249 | for(;;){ 250 | op=m.getUint32(p,true); 251 | p+=4; 252 | z=0; 253 | while(z++<4){ 254 | switch(op&255){ 255 | case 0:{AppendChildren(root, stack.length-1);}break;case 1:{stack.push(nodes[u32buf[u32bufp++]]);}break;case 2:{AppendChildren(u32buf[u32bufp++], u32buf[u32bufp++]);}break;case 3:{stack.pop();}break;case 4:{root = nodes[u32buf[u32bufp++]]; els = stack.splice(stack.length-u32buf[u32bufp++]); if (root.listening) { listeners.removeAllNonBubbling(root); } root.replaceWith(...els);}break;case 5:{nodes[u32buf[u32bufp++]].after(...stack.splice(stack.length-u32buf[u32bufp++]));}break;case 6:{nodes[u32buf[u32bufp++]].before(...stack.splice(stack.length-u32buf[u32bufp++]));}break;case 7:{node = nodes[u32buf[u32bufp++]]; if (node !== undefined) { if (node.listening) { listeners.removeAllNonBubbling(node); } node.remove(); }}break;case 8:{stack.push(document.createTextNode(s.substring(sp,sp+=u32buf[u32bufp++])));}break;case 9:{node = document.createTextNode(s.substring(sp,sp+=u32buf[u32bufp++])); nodes[u32buf[u32bufp++]] = node; stack.push(node);}break;case 10:{node = document.createElement('pre'); node.hidden = true; stack.push(node); nodes[u32buf[u32bufp++]] = node;}break;case 11:event_name=get_evt();id=u32buf[u32bufp++];bubbles=u8buf[u8bufp++];node = nodes[id]; if(node.listening){node.listening += 1;}else{node.listening = 1;} node.setAttribute('data-dioxus-id', `${id}`); listeners.create(event_name, node, bubbles);break;case 12:{node = nodes[u32buf[u32bufp++]]; node.listening -= 1; node.removeAttribute('data-dioxus-id'); listeners.remove(node, get_evt(), u8buf[u8bufp++]);}break;case 13:{nodes[u32buf[u32bufp++]].textContent = s.substring(sp,sp+=u32buf[u32bufp++]);}break;case 14:{node = nodes[u32buf[u32bufp++]]; SetAttributeInner(node, get_attr(), s.substring(sp,sp+=u32buf[u32bufp++]), get_ns_cache());}break;case 15:id=u32buf[u32bufp++];field=get_attr();ns=get_ns_cache();{ 256 | node = nodes[id]; 257 | if (!ns) { 258 | switch (field) { 259 | case "value": 260 | node.value = ""; 261 | break; 262 | case "checked": 263 | node.checked = false; 264 | break; 265 | case "selected": 266 | node.selected = false; 267 | break; 268 | case "dangerous_inner_html": 269 | node.innerHTML = ""; 270 | break; 271 | default: 272 | node.removeAttribute(field); 273 | break; 274 | } 275 | } else if (ns == "style") { 276 | node.style.removeProperty(name); 277 | } else { 278 | node.removeAttributeNS(ns, field); 279 | } 280 | }break;case 16:{nodes[u32buf[u32bufp++]] = LoadChild(u32buf[u32bufp++], u8buf[u8bufp++]);}break;case 17:ptr=u32buf[u32bufp++];len=u8buf[u8bufp++];value=s.substring(sp,sp+=u32buf[u32bufp++]);id=u32buf[u32bufp++];{ 281 | node = LoadChild(ptr, len); 282 | if (node.nodeType == Node.TEXT_NODE) { 283 | node.textContent = value; 284 | } else { 285 | let text = document.createTextNode(value); 286 | node.replaceWith(text); 287 | node = text; 288 | } 289 | nodes[id] = node; 290 | }break;case 18:{els = stack.splice(stack.length - u32buf[u32bufp++]); node = LoadChild(u32buf[u32bufp++], u8buf[u8bufp++]); node.replaceWith(...els);}break;case 19:{node = templates[u32buf[u32bufp++]][u32buf[u32bufp++]].cloneNode(true); nodes[u32buf[u32bufp++]] = node; stack.push(node);}break;case 20:return true; 291 | } 292 | op>>>=8; 293 | } 294 | } 295 | } -------------------------------------------------------------------------------- /docs/examples/prime-ministers/assets/dioxus/snippets/dioxus-interpreter-js-603636eeca72cf05/src/common.js: -------------------------------------------------------------------------------- 1 | const bool_attrs = { 2 | allowfullscreen: true, 3 | allowpaymentrequest: true, 4 | async: true, 5 | autofocus: true, 6 | autoplay: true, 7 | checked: true, 8 | controls: true, 9 | default: true, 10 | defer: true, 11 | disabled: true, 12 | formnovalidate: true, 13 | hidden: true, 14 | ismap: true, 15 | itemscope: true, 16 | loop: true, 17 | multiple: true, 18 | muted: true, 19 | nomodule: true, 20 | novalidate: true, 21 | open: true, 22 | playsinline: true, 23 | readonly: true, 24 | required: true, 25 | reversed: true, 26 | selected: true, 27 | truespeed: true, 28 | webkitdirectory: true, 29 | }; 30 | 31 | export function setAttributeInner(node, field, value, ns) { 32 | const name = field; 33 | if (ns === "style") { 34 | // ????? why do we need to do this 35 | if (node.style === undefined) { 36 | node.style = {}; 37 | } 38 | node.style[name] = value; 39 | } else if (ns != null && ns != undefined) { 40 | node.setAttributeNS(ns, name, value); 41 | } else { 42 | switch (name) { 43 | case "value": 44 | if (value !== node.value) { 45 | node.value = value; 46 | } 47 | break; 48 | case "initial_value": 49 | node.defaultValue = value; 50 | break; 51 | case "checked": 52 | node.checked = truthy(value); 53 | break; 54 | case "selected": 55 | node.selected = truthy(value); 56 | break; 57 | case "dangerous_inner_html": 58 | node.innerHTML = value; 59 | break; 60 | default: 61 | // https://github.com/facebook/react/blob/8b88ac2592c5f555f315f9440cbb665dd1e7457a/packages/react-dom/src/shared/DOMProperty.js#L352-L364 62 | if (!truthy(value) && bool_attrs.hasOwnProperty(name)) { 63 | node.removeAttribute(name); 64 | } else { 65 | node.setAttribute(name, value); 66 | } 67 | } 68 | } 69 | } 70 | 71 | function truthy(val) { 72 | return val === "true" || val === true; 73 | } 74 | -------------------------------------------------------------------------------- /docs/examples/prime-ministers/assets/dioxus/snippets/dioxus-web-54817add8ba334eb/inline0.js: -------------------------------------------------------------------------------- 1 | 2 | export function get_form_data(form) { 3 | let values = new Map(); 4 | const formData = new FormData(form); 5 | 6 | for (let name of formData.keys()) { 7 | values.set(name, formData.getAll(name)); 8 | } 9 | 10 | return values; 11 | } 12 | -------------------------------------------------------------------------------- /docs/examples/prime-ministers/assets/dioxus/snippets/dioxus-web-54817add8ba334eb/src/eval.js: -------------------------------------------------------------------------------- 1 | export class Dioxus { 2 | constructor(sendCallback, returnCallback) { 3 | this.sendCallback = sendCallback; 4 | this.returnCallback = returnCallback; 5 | this.promiseResolve = null; 6 | this.received = []; 7 | } 8 | 9 | // Receive message from Rust 10 | recv() { 11 | return new Promise((resolve, _reject) => { 12 | // If data already exists, resolve immediately 13 | let data = this.received.shift(); 14 | if (data) { 15 | resolve(data); 16 | return; 17 | } 18 | 19 | // Otherwise set a resolve callback 20 | this.promiseResolve = resolve; 21 | }); 22 | } 23 | 24 | // Send message to rust. 25 | send(data) { 26 | this.sendCallback(data); 27 | } 28 | 29 | // Internal rust send 30 | rustSend(data) { 31 | // If a promise is waiting for data, resolve it, and clear the resolve callback 32 | if (this.promiseResolve) { 33 | this.promiseResolve(data); 34 | this.promiseResolve = null; 35 | return; 36 | } 37 | 38 | // Otherwise add the data to a queue 39 | this.received.push(data); 40 | } 41 | } -------------------------------------------------------------------------------- /docs/examples/prime-ministers/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Prime ministers of GB | dioxus-sortable 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /examples/prime_ministers.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | use dioxus_sortable::{use_sorter, NullHandling, PartialOrdBy, SortBy, Sortable, Th, ThStatus}; 3 | 4 | fn main() { 5 | wasm_logger::init(wasm_logger::Config::new(log::Level::Info)); 6 | dioxus_web::launch(app); 7 | } 8 | 9 | fn app(cx: Scope) -> Element { 10 | // Trigger pulling our data "externally" 11 | let future = use_future(cx, (), |_| load_prime_ministers()); 12 | 13 | cx.render(rsx! { 14 | h1 { "Birthplaces of British prime ministers" } 15 | future.value().map_or_else( 16 | // Show a loading message while the data is being fetched 17 | || rsx!{ 18 | p { "Loading..." } 19 | }, 20 | // Pass the data onto our table component 21 | |data| rsx!{ 22 | PrimeMinisters{ data: data.to_vec(), } 23 | }) 24 | }) 25 | } 26 | 27 | /// Creates a sortable table of prime ministers and their birthplaces. Can be filtered by name. 28 | /// 29 | /// Each column header can be clicked to sort by that column. The current sort state is displayed in the header. 30 | #[allow(non_snake_case)] 31 | #[inline_props] 32 | fn PrimeMinisters(cx: Scope, data: Vec) -> Element { 33 | // Sorter hook must be called unconditionally 34 | let sorter = use_sorter::(cx); 35 | let name = use_state(cx, || "".to_string()); 36 | 37 | // Filter the data 38 | let mut data = data 39 | .to_owned() 40 | .into_iter() 41 | .filter(|row| row.name.to_lowercase().contains(&name.get().to_lowercase())) 42 | .collect::>(); 43 | // Sort the data. Unlike use_sorter, may be skipped 44 | sorter.sort(data.as_mut_slice()); 45 | 46 | cx.render(rsx! { 47 | // Our simple search box 48 | input { 49 | placeholder: "Search by name", 50 | oninput: move |evt| name.set(evt.value.clone()), 51 | } 52 | 53 | // Render a table like we would any other except for the `Th` component 54 | table { 55 | thead { 56 | tr { 57 | // The `Th` helper component is used to render a sortable column header 58 | Th { sorter: sorter, field: PersonField::Name, "Name" } 59 | // It will display an arrow to indicate the current sort direction and state 60 | Th { sorter: sorter, field: PersonField::LeftOffice, "Left office" } 61 | // Here's how we might do it manually: 62 | th { 63 | // The `toggle_field` method triggers the state change and sorts the table 64 | onclick: move |_| sorter.toggle_field(PersonField::Birthplace), 65 | "Birthplace" 66 | // The `ThStatus` helper component renders the current state. You could write your own custom status viewer with by using [`UseSorter::get_state`]. 67 | ThStatus { 68 | sorter: sorter, 69 | field: PersonField::Birthplace, 70 | } 71 | } 72 | // We could also skip all the status fields entirely and have a separate form for controlling the sort state. In that situation we'd use the normal td {} elements. 73 | Th { sorter: sorter, field: PersonField::Country, "Country" } 74 | } 75 | } 76 | tbody { 77 | // Iterate over our Person data like we would any other. 78 | data.iter().map(|row| { 79 | rsx! { 80 | tr { 81 | td { "{row.name}" } 82 | td { 83 | match row.left_office { 84 | None => rsx!(em { "Present" }), 85 | Some(ref x) => rsx!("{x}"), 86 | } 87 | } 88 | td { 89 | match row.birthplace { 90 | Birthplace::Unknown => rsx!(em { "Unknown" }), 91 | Birthplace::City(ref city) => rsx!("{city}") 92 | } 93 | } 94 | td { "{row.country}" } 95 | } 96 | } 97 | }) 98 | } 99 | } 100 | }) 101 | } 102 | 103 | /// Our per-row data type that we want to sort 104 | #[derive(Clone, Debug, PartialEq)] 105 | struct Person { 106 | name: String, 107 | /// None means the person is still in office 108 | left_office: Option, 109 | /// Another way of dealing with unknown values is to use an enum 110 | birthplace: Birthplace, 111 | country: String, 112 | } 113 | 114 | /// Where was the person born? 115 | #[derive(Clone, Debug, Default, PartialEq)] 116 | enum Birthplace { 117 | #[default] 118 | Unknown, 119 | City(String), 120 | } 121 | 122 | /// This is the field we want to sort by. Each variant corresponds to a column in our table or field in our Person struct. Keep it simple, use `{struct}Field`. 123 | #[derive(Copy, Clone, Debug, Default, PartialEq)] 124 | enum PersonField { 125 | Name, 126 | #[default] 127 | LeftOffice, 128 | Birthplace, 129 | Country, 130 | } 131 | 132 | /// This trait decides how our rows are sorted 133 | impl PartialOrdBy for PersonField { 134 | fn partial_cmp_by(&self, a: &Person, b: &Person) -> Option { 135 | match self { 136 | // Most values like Strings, integers and f64 require no special treatment and partial_cmp can be used directly. 137 | PersonField::Name => a.name.partial_cmp(&b.name), 138 | 139 | // We're using None to say that the person is still in office which becomes our NULL value. There's a gotcha here as Rust will treat None values as smaller than Some (not NULL). 140 | PersonField::LeftOffice => a 141 | .left_office 142 | .zip(b.left_office) 143 | .and_then(|(a, b)| a.partial_cmp(&b)), 144 | 145 | // Similar to LeftOffice, our unknown birthplace is treated as NULL value. Instead of using Option we've wrapped it up in our own enum closer to what we'd do in a real app. If either of the values are unknown (our NULL) then we must return None. Otherwise do a standard comparison on the city name. 146 | PersonField::Birthplace => match (&a.birthplace, &b.birthplace) { 147 | (Birthplace::Unknown, _) => None, 148 | (_, Birthplace::Unknown) => None, 149 | (Birthplace::City(a), Birthplace::City(b)) => a.partial_cmp(b), 150 | }, 151 | 152 | PersonField::Country => a.country.partial_cmp(&b.country), 153 | } 154 | } 155 | } 156 | 157 | /// This trait decides how fields (columns) may be sorted 158 | impl Sortable for PersonField { 159 | fn sort_by(&self) -> Option { 160 | use PersonField::*; 161 | match self { 162 | Name => SortBy::increasing_or_decreasing(), 163 | // Let's say we want our list to focus on the most recent prime ministers. We can use decreasing sort order to put the most recent ones at the top. Another useful value would be decreasing_or_increasing which would allow the user to toggle the column. 164 | LeftOffice => SortBy::decreasing(), 165 | // You might notice increasing_or_decreasing is used a lot. It's the default value. 166 | Birthplace => SortBy::increasing_or_decreasing(), 167 | // An acceptable implementation of sort_by is to return increasing_or_decreasing for all fields. 168 | Country => SortBy::increasing_or_decreasing(), 169 | } 170 | } 171 | 172 | fn null_handling(&self) -> NullHandling { 173 | use PersonField::*; 174 | match self { 175 | // Our left office column is ordered from most recent to oldest. We want the most recent prime minister to be at the top of the list. So since we're using the NULL value to mean they're still in office, we want NULLs to come first. 176 | LeftOffice => NullHandling::First, 177 | 178 | // We don't normally have to specify null_handling. The default value is NullHandling::Last. 179 | _ => NullHandling::Last, 180 | } 181 | } 182 | } 183 | 184 | impl Person { 185 | /// Helper function for load_prime_ministers to create a new Person 186 | fn new( 187 | name: &'static str, 188 | left: impl Into>, 189 | birth: impl Into>, 190 | country: &'static str, 191 | ) -> Person { 192 | Person { 193 | name: name.to_string(), 194 | left_office: left.into(), 195 | birthplace: match birth.into() { 196 | Some(city) => Birthplace::City(city.to_string()), 197 | None => Birthplace::Unknown, 198 | }, 199 | country: country.to_string(), 200 | } 201 | } 202 | } 203 | 204 | /// Our mock data source. In a real app this could be something like a `reqwest` call 205 | async fn load_prime_ministers() -> Vec { 206 | vec![ 207 | Person::new("Robert Walpole", 1742, "Houghton Hall, Norfolk", "England"), 208 | Person::new( 209 | "Spencer Compton", 210 | 1743, 211 | "Compton Wynyates, Warwickshire", 212 | "England", 213 | ), 214 | Person::new("Henry Pelham", 1756, "Laughton, Sussex", "England"), 215 | Person::new("William Cavendish", 1757, None, "England"), 216 | Person::new("Thomas Pelham-Holles", 1762, "London", "England"), 217 | Person::new( 218 | "John Stuart", 219 | 1763, 220 | "Parliament Square, Edinburgh", 221 | "Scotland", 222 | ), 223 | Person::new( 224 | "George Grenville", 225 | 1765, 226 | "Wotton, Buckinghamshire", 227 | "England", 228 | ), 229 | Person::new("William Pitt", 1768, "Westminster, London", "England"), 230 | Person::new("Augustus FitzRoy", 1770, None, "England"), 231 | Person::new("Frederick North", 1782, "Piccadilly, London", "England"), 232 | Person::new( 233 | "Charles Watson-Wentworth", 234 | 1782, 235 | "Wentworth, Yorkshire", 236 | "England", 237 | ), 238 | Person::new( 239 | "William Petty", 240 | 1783, 241 | "Dublin, County Dublin", 242 | "Republic of Ireland", 243 | ), 244 | Person::new("Henry Addington", 1804, "Holborn, London", "England"), 245 | Person::new("William Pitt", 1806, "Hayes, Kent", "England"), 246 | Person::new( 247 | "William Grenville", 248 | 1807, 249 | "Wotton, Buckinghamshire", 250 | "England", 251 | ), 252 | Person::new( 253 | "William Cavendish-Bentinck", 254 | 1809, 255 | "Nottinghamshire", 256 | "England", 257 | ), 258 | Person::new("Spencer Perceval", 1812, "Mayfair, London", "England"), 259 | Person::new("Robert Jenkinson", 1827, "London", "England"), 260 | Person::new("George Canning", 1827, "Marylebone, London", "England"), 261 | Person::new( 262 | "Frederick Robinson", 263 | 1828, 264 | "Skelton-on-Ure, Yorkshire", 265 | "England", 266 | ), 267 | Person::new( 268 | "Arthur Wellesley", 269 | 1834, 270 | "Dublin, County Dublin", 271 | "Republic of Ireland", 272 | ), 273 | Person::new("William Lamb", 1841, "London", "England"), 274 | Person::new("Robert Peel", 1846, "Bury, Lancashire", "England"), 275 | Person::new( 276 | "George Hamilton Gordon", 277 | 1855, 278 | "Edinburgh, Midlothian", 279 | "Scotland", 280 | ), 281 | Person::new( 282 | "Henry John Temple, Lord Palmerston", 283 | 1858, 284 | "Westminster, Middlesex", 285 | "England", 286 | ), 287 | Person::new("John Russell", 1852, "Mayfair, Middlesex", "England"), 288 | Person::new( 289 | "Edward Smith-Stanley", 290 | 1852, 291 | "Knowsley Hall, Knowsley, Lancashire", 292 | "England", 293 | ), 294 | Person::new( 295 | "Benjamin Disraeli", 296 | 1868, 297 | "Bloomsbury, Middlesex", 298 | "England", 299 | ), 300 | Person::new( 301 | "William Ewart Gladstone", 302 | 1894, 303 | "Liverpool, Lancashire", 304 | "England", 305 | ), 306 | Person::new("Archibald Primrose", 1895, "Mayfair, Middlesex", "England"), 307 | Person::new( 308 | "Robert Gascoyne-Cecil", 309 | 1902, 310 | "Hatfield, Hertfordshire", 311 | "England", 312 | ), 313 | Person::new( 314 | "Arthur Balfour", 315 | 1905, 316 | "Whittingehame, East Lothian", 317 | "Scotland", 318 | ), 319 | Person::new( 320 | "Henry Campbell-Bannerman", 321 | 1908, 322 | "Kelvinside, Glasgow", 323 | "Scotland", 324 | ), 325 | Person::new( 326 | "H. H. Asquith", 327 | 1916, 328 | "Morley, West Riding of Yorkshire", 329 | "England", 330 | ), 331 | Person::new( 332 | "David Lloyd George", 333 | 1922, 334 | "Chorlton-on-Medlock, Lancashire,", 335 | "England", 336 | ), 337 | Person::new("Bonar Law", 1923, "Rexton, Kent County", "Canada"), 338 | Person::new( 339 | "Ramsay MacDonald", 340 | 1935, 341 | "Lossiemouth, Morayshire", 342 | "Scotland", 343 | ), 344 | Person::new( 345 | "Stanley Baldwin", 346 | 1937, 347 | "Bewdley, Worcestershire", 348 | "England", 349 | ), 350 | Person::new( 351 | "Neville Chamberlain", 352 | 1940, 353 | "Edgbaston, Birmingham", 354 | "England", 355 | ), 356 | Person::new( 357 | "Winston Churchill", 358 | 1955, 359 | "Blenheim, Oxfordshire", 360 | "England", 361 | ), 362 | Person::new("Clement Attlee", 1951, "Putney, Surrey", "England"), 363 | Person::new( 364 | "Anthony Eden", 365 | 1957, 366 | "Windlestone Hall, County Durham", 367 | "England", 368 | ), 369 | Person::new("Harold Macmillan", 1963, "Belgravia, London", "England"), 370 | Person::new("Alec Douglas-Home", 1964, "Mayfair, London", "England"), 371 | Person::new( 372 | "Harold Wilson", 373 | 1976, 374 | "Huddersfield, West Riding of Yorkshire", 375 | "England", 376 | ), 377 | Person::new("Edward Heath", 1974, "Broadstairs, Kent", "England"), 378 | Person::new("James Callaghan", 1979, "Portsmouth, Hampshire", "England"), 379 | Person::new( 380 | "Margaret Thatcher", 381 | 1990, 382 | "Grantham, Lincolnshire", 383 | "England", 384 | ), 385 | Person::new("John Major", 1997, "St Helier, Surrey", "England"), 386 | Person::new("Tony Blair", 2007, "Edinburgh, Midlothian", "Scotland"), 387 | Person::new("Gordon Brown", 2010, "Giffnock, Renfrewshire", "Scotland"), 388 | Person::new("David Cameron", 2016, "Marylebone, London", "England"), 389 | Person::new("Theresa May", 2019, "Eastbourne, East Sussex", "England"), 390 | Person::new( 391 | "Boris Johnson", 392 | 2022, 393 | "New York City, New York", 394 | "United States", 395 | ), 396 | Person::new("Liz Truss", 2022, "Oxford, Oxfordshire", "England"), 397 | Person::new("Rishi Sunak", None, "Southampton, Hampshire", "England "), 398 | ] 399 | } 400 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![warn(missing_docs)] 2 | //! 3 | //! # Sortable components for Dioxus 4 | //! 5 | //! Create sortable tables (and other components) of any type for [Dioxus](https://dioxuslabs.com/). 6 | //! 7 | //! The focus is on tables but this library can be used to create any type of sortable component. Your tables can be customised however you wish. Sorting state is kept separately from the data. 8 | //! 9 | //! Throughout this documentation, you'll see the type `T` used to refer to the data type that you wish to sort. You'll also see `F` which is expected to be an enum referring to each sortable field of `T`. Your `F` enum should implement [`PartialOrdBy`] to sort and [`Sortable`] to describe how it may be sorted. 10 | //! 11 | //! We use [`PartialOrd`] to allow sorting of types with NULL semantics. This is useful where we have `f64::NAN` or an "unknown" field. It allows us to handle more general cases. We try to keep ordering semantics the same as SQL's ORDER BY clause. 12 | //! 13 | //! ## Usage 14 | //! 15 | //! 1. Create a `struct T` that you wish to sort. The table row. 16 | //! 2. Create an `enum F` that describes each sortable field in `T`. 17 | //! 3. Implement [`PartialOrdBy`] for `F`. This is used to sort `T` by `F`. 18 | //! 4. Implement [`Sortable`] for `F`. This is used to describe how `F` may be sorted. 19 | //! 5. Call [`use_sorter()`] in your component and get a [`UseSorter`]. 20 | //! 6. Call [`UseSorter::sort`] to sort data. This may be called conditionally e.g., when waiting for data to arrive. 21 | //! 7. Create a table using [`Th`] or write your own with [`ThStatus`] and [`UseSorter::toggle_field`]. 22 | //! 23 | //! ## Examples 24 | //! 25 | //! See a full example of [British prime ministers](https://feral-dot-io.github.io/dioxus-sortable/examples/prime-ministers/) ([and the code](https://github.com/feral-dot-io/dioxus-sortable/blob/master/examples/prime_ministers.rs)). You can modify and run it locally with `dioxus serve --example prime_ministers` 26 | //! 27 | //! A minimal example giving a tour of how to use the library is below. 28 | //! 29 | //! ```rust 30 | //! use dioxus::prelude::*; 31 | //! use dioxus_sortable::{use_sorter, PartialOrdBy, SortBy, Sortable, Th}; 32 | //! 33 | //! /// Our table row. Type `T`. 34 | //! #[derive(Clone, Debug, PartialEq)] 35 | //! struct Person { 36 | //! name: String, 37 | //! age: u8, 38 | //! } 39 | //! 40 | //! /// Our table columns. Type `F`. One for each field in Person. 41 | //! #[derive(Copy, Clone, Debug, Default, PartialEq)] 42 | //! enum PersonField { 43 | //! Name, 44 | //! /// Use default for the initial sort. 45 | //! #[default] 46 | //! Age, 47 | //! } 48 | //! 49 | //! /// Specify how we sort our `Person` using `PersonField`. 50 | //! impl PartialOrdBy for PersonField { 51 | //! fn partial_cmp_by(&self, a: &Person, b: &Person) -> Option { 52 | //! // Note how it's just a passthru to `PartialOrd` for each field. 53 | //! match self { 54 | //! PersonField::Name => a.name.partial_cmp(&b.name), 55 | //! PersonField::Age => a.age.partial_cmp(&b.age), 56 | //! } 57 | //! } 58 | //! } 59 | //! 60 | //! /// Specify sorting options available on a column. 61 | //! impl Sortable for PersonField { 62 | //! fn sort_by(&self) -> Option { 63 | //! // We can choose column specifics but this is good for the minimum. 64 | //! SortBy::increasing_or_decreasing() 65 | //! } 66 | //! } 67 | //! 68 | //! #[inline_props] 69 | //! fn OurMinimalExampleTable(cx: Scope) -> Element { 70 | //! // Set up Dioxus state hooks. *Must* be called every time in the same order 71 | //! let sorter = use_sorter::(cx); 72 | //! // Obtain our data. Either passed via props or pulled from a server 73 | //! let mut data = load_data(); 74 | //! // Sort our data. This is optional but needed to apply the sort 75 | //! sorter.sort(data.as_mut_slice()); 76 | //! 77 | //! // Render our table like normal. 78 | //! cx.render(rsx! { 79 | //! table { 80 | //! thead { 81 | //! tr { 82 | //! // Note that we use `Th` instead of `th`. 83 | //! // We could customise `th` by using `ThStatus` instead. 84 | //! // Or use `UseSorter::toggle_field` elsewhere to lift 85 | //! // the sorter out of the table entirely. 86 | //! Th { sorter: sorter, field: PersonField::Name, "Name" } 87 | //! Th { sorter: sorter, field: PersonField::Age, "Age" } 88 | //! } 89 | //! } 90 | //! tbody { 91 | //! // Iterate on our sorted data. 92 | //! // If we didn't want sortable tables, this could easily be a 93 | //! // `ul { li { ... } }` instead. 94 | //! for person in data.iter() { 95 | //! tr { 96 | //! td { "{person.name}" } 97 | //! td { "{person.age}" } 98 | //! } 99 | //! } 100 | //! } 101 | //! } 102 | //! }) 103 | //! } 104 | //! 105 | //! # fn load_data() -> Vec { 106 | //! # vec![ 107 | //! # Person { name: "John".to_string(), age: 32 }, 108 | //! # Person { name: "Jane".to_string(), age: 28 }, 109 | //! # Person { name: "Bob".to_string(), age: 42 }, 110 | //! # ] 111 | //! # } 112 | //! ``` 113 | //! 114 | 115 | mod rsx; 116 | pub use rsx::*; 117 | mod use_sorter; 118 | pub use use_sorter::*; 119 | -------------------------------------------------------------------------------- /src/rsx.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | use crate::{Direction, SortBy, Sortable, UseSorter}; 3 | use dioxus::prelude::*; 4 | 5 | /// See [`Th`]. 6 | #[derive(Props)] 7 | pub struct ThProps<'a, F: 'static> { 8 | sorter: UseSorter<'a, F>, 9 | field: F, 10 | children: Element<'a>, 11 | } 12 | 13 | /// Convenience helper. Builds a `` element with a click handler that calls [`UseSorter::toggle_field`]. Renders the current state using [`ThStatus`]. 14 | pub fn Th<'a, F: Copy + Sortable>(cx: Scope<'a, ThProps<'a, F>>) -> Element<'a> { 15 | let sorter = cx.props.sorter; 16 | let field = cx.props.field; 17 | cx.render(rsx! { 18 | th { 19 | onclick: move |_| sorter.toggle_field(field), 20 | &cx.props.children 21 | ThStatus { 22 | sorter: sorter, 23 | field: field, 24 | } 25 | } 26 | }) 27 | } 28 | 29 | /// See [`ThStatus`]. 30 | #[derive(PartialEq, Props)] 31 | pub struct ThStatusProps<'a, F: 'static> { 32 | sorter: UseSorter<'a, F>, 33 | field: F, 34 | } 35 | 36 | /// Convenience helper. Renders the [`Sortable`] value for a given [`UseSorter`] and field. 37 | /// - If the field is unsortable then render an empty string. 38 | /// - If the field is sortable in one direction then render an arrow pointing in that direction. 39 | /// - If the field is sortable in both directions then render an arrow pointing in the active direction, or a double-headed arrow if the field is inactive. 40 | /// 41 | /// Active fields will be shown in bold (i.e., the current field being sorted by). Inactive fields will be greyed out. 42 | pub fn ThStatus<'a, F: Copy + Sortable>(cx: Scope<'a, ThStatusProps<'a, F>>) -> Element<'a> { 43 | let sorter = &cx.props.sorter; 44 | let field = cx.props.field; 45 | let (active_field, active_dir) = sorter.get_state(); 46 | let active = *active_field == field; 47 | 48 | cx.render(match field.sort_by() { 49 | None => rsx!(""), 50 | Some(sort_by) => { 51 | use Direction::*; 52 | use SortBy::*; 53 | match sort_by { 54 | Fixed(Ascending) => rsx!(ThSpan { active: active, "↓" }), 55 | Fixed(Descending) => rsx!(ThSpan { active: active, "↑" }), 56 | 57 | Reversible(_) => rsx!( 58 | ThSpan { 59 | active: active, 60 | match (active, active_dir) { 61 | (true, Direction::Ascending) => "↓", 62 | (true, Direction::Descending) => "↑", 63 | (false, _) => "↕", 64 | } 65 | }), 66 | } 67 | } 68 | }) 69 | } 70 | 71 | /// See [`ThSpan`]. 72 | #[derive(Props)] 73 | struct ThSpan<'a> { 74 | active: bool, 75 | children: Element<'a>, 76 | } 77 | 78 | /// Convenience helper. Renders an active or inactive gielement. 79 | fn ThSpan<'a>(cx: Scope<'a, ThSpan<'a>>) -> Element<'a> { 80 | let colour = if cx.props.active { "#555" } else { "#ccc" }; 81 | let nbsp = " "; 82 | cx.render(rsx! { 83 | span { 84 | style: "color: {colour};", 85 | span { dangerous_inner_html: "{nbsp}", } 86 | &cx.props.children 87 | } 88 | }) 89 | } 90 | -------------------------------------------------------------------------------- /src/use_sorter.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | use std::cmp::Ordering; 3 | 4 | /// Stores Dioxus hooks and state of our sortable items. 5 | #[derive(Copy, Clone, Debug, PartialEq)] 6 | pub struct UseSorter<'a, F: 'static> { 7 | field: &'a UseState, 8 | direction: &'a UseState, 9 | } 10 | 11 | /// Trait used by [UseSorter](UseSorter) to sort a struct by a specific field. This must be implemented on the field enum. Type `T` represents the struct (table row) that is being sorted. 12 | /// 13 | /// The implementation should use the [`PartialOrd::partial_cmp`] trait to compare the field values and return the result. For example: 14 | /// ```rust 15 | /// # use dioxus_sortable::PartialOrdBy; 16 | /// # #[derive(PartialEq)] 17 | /// struct MyStruct { 18 | /// first: String, 19 | /// second: f64, // <- Note: can return None if f64::NAN 20 | /// } 21 | /// 22 | /// # #[derive(Copy, Clone, Debug, PartialEq)] 23 | /// enum MyStructField { 24 | /// First, 25 | /// Second, 26 | /// } 27 | /// 28 | /// impl PartialOrdBy for MyStructField { 29 | /// fn partial_cmp_by(&self, a: &MyStruct, b: &MyStruct) -> Option { 30 | /// match self { 31 | /// MyStructField::First => a.first.partial_cmp(&b.first), 32 | /// MyStructField::Second => a.second.partial_cmp(&b.second), 33 | /// } 34 | /// } 35 | /// } 36 | /// ``` 37 | /// 38 | /// Be careful when using [`Option::None`] or a custom enum to represent missing data (`NULL` values). As `partial_cmp` as `None` is less than `Some`: 39 | /// 40 | /// ```rust 41 | /// # use std::cmp::Ordering; 42 | /// assert_eq!(Ordering::Less, None.cmp(&Some(0))); 43 | /// ``` 44 | /// 45 | pub trait PartialOrdBy: PartialEq { 46 | /// Compare two values of type `T` by the field's enum. Return values of `None` are treated as `NULL` values. See [`Sortable`] for more information. 47 | /// 48 | /// Be careful when comparing types like `Option` which implement `Ord`. This means that `None` and `Some` have an order where we might use them as unknown / `NULL` values. This can be a surprise. 49 | /// 50 | /// Another issue is `f64` only implements `PartialOrd` and not `Ord` because a value can hold `f64::NAN`. In this situation `partial_cmp` will return `None` and we'll treat these values as `NULL` as expected. 51 | fn partial_cmp_by(&self, a: &T, b: &T) -> Option; 52 | } 53 | 54 | /// Trait used to describe how a field can be sorted. This must be implemented on the field enum. 55 | /// 56 | /// Our [`PartialOrdBy`] fn may result in `None` values which we refer to as `NULL`. We borrow from SQL here to handle these values in a similar way to the [SQL ORDER BY clause](https://www.postgresql.org/docs/current/sql-select.html#SQL-ORDERBY). The PostgreSQL general form is `ORDER BY expression [ ASC | DESC | USING operator ] [ NULLS { FIRST | LAST } ] [, ...]` where: 57 | /// - `expression` is the field being sorted. 58 | /// - `ASC` and `DESC` are the sort [`Direction`]. 59 | /// - `USING operator` is implied by [`PartialOrdBy`]. 60 | /// - `NULLS { FIRST | LAST }` corresponds to [`NullHandling`]. 61 | /// Meaning you can sort by ascending or descending and optionally specify `NULL` ordering. 62 | pub trait Sortable: PartialEq { 63 | /// Describes how this field can be sorted. 64 | fn sort_by(&self) -> Option; 65 | 66 | /// Describes how `NULL` values (when [`PartialOrdBy`] returns `None`) should be ordered when sorting. Either all at the start or the end. 67 | /// 68 | /// Provided implementation relies on the default (all at the end) and should be overridden if you want to change this generally or on a per-field basis. 69 | fn null_handling(&self) -> NullHandling { 70 | NullHandling::default() 71 | } 72 | } 73 | 74 | /// Describes how a field should be sorted. Returned by [`Sortable::sort_by`]. 75 | #[derive(Copy, Clone, Debug, PartialEq)] 76 | pub enum SortBy { 77 | /// This field is limited to being sorted in the one direction specified. 78 | Fixed(Direction), 79 | /// This field can be sorted in either direction. The direction specifies the initial direction. Fields of this sort can be toggled between directions. 80 | Reversible(Direction), 81 | } 82 | 83 | /// Sort direction. Does not have a default -- implied by the field via [`SortBy`]. 84 | /// 85 | /// Actual sorting is done by [`PartialOrdBy`]. 86 | #[derive(Copy, Clone, Debug, PartialEq)] 87 | pub enum Direction { 88 | /// Ascending sort. A-Z, 0-9, little to big, etc. 89 | Ascending, 90 | /// Descending sort. Z-A, opposite of ascending. 91 | Descending, 92 | } 93 | 94 | impl Direction { 95 | /// Inverts the direction. 96 | pub fn invert(&self) -> Self { 97 | match self { 98 | Self::Ascending => Self::Descending, 99 | Self::Descending => Self::Ascending, 100 | } 101 | } 102 | 103 | fn from_field(field: &F) -> Direction { 104 | field.sort_by().unwrap_or_default().direction() 105 | } 106 | } 107 | 108 | /// Describes how `NULL` values should be ordered when sorting. We refer to `None` values returned from [`PartialOrdBy::partial_cmp_by`] as `NULL`. Warning: Rust's `Option::None` is not strictly equivalent to SQL's `NULL` but we borrow from SQL terminology to handle them. 109 | #[derive(Copy, Clone, Debug, Default, PartialEq)] 110 | pub enum NullHandling { 111 | /// Places all `NULL` values first. 112 | First, 113 | /// Places all `NULL` values last. The default. 114 | #[default] 115 | Last, 116 | } 117 | 118 | impl Default for SortBy { 119 | fn default() -> SortBy { 120 | Self::increasing_or_decreasing().unwrap() 121 | } 122 | } 123 | 124 | impl SortBy { 125 | /// Field may not be sorted. Convenience fn for specifying how a field may be sorted. 126 | pub fn unsortable() -> Option { 127 | None 128 | } 129 | /// Field may only be sorted in ascending order. 130 | pub fn increasing() -> Option { 131 | Some(Self::Fixed(Direction::Ascending)) 132 | } 133 | /// Field may only be sorted in descending order. 134 | pub fn decreasing() -> Option { 135 | Some(Self::Fixed(Direction::Descending)) 136 | } 137 | /// Field may be sorted in either direction. The initial direction is ascending. This is the default. 138 | pub fn increasing_or_decreasing() -> Option { 139 | Some(Self::Reversible(Direction::Ascending)) 140 | } 141 | /// Field may be sorted in either direction. The initial direction is descending. 142 | pub fn decreasing_or_increasing() -> Option { 143 | Some(Self::Reversible(Direction::Descending)) 144 | } 145 | 146 | /// Returns the initial / implied direction of the sort. 147 | pub fn direction(&self) -> Direction { 148 | match self { 149 | Self::Fixed(dir) => *dir, 150 | Self::Reversible(dir) => *dir, 151 | } 152 | } 153 | 154 | fn ensure_direction(&self, dir: Direction) -> Direction { 155 | use SortBy::*; 156 | match self { 157 | // Must match allowed 158 | Fixed(allowed) if *allowed == dir => dir, 159 | // Did not match allowed 160 | Fixed(allowed) => *allowed, 161 | // Any allowed 162 | Reversible(_) => dir, 163 | } 164 | } 165 | } 166 | 167 | /// Builder for [UseSorter](UseSorter). Use this to specify the field and direction of the sorter. For example by passing sort state from URL parameters. 168 | /// 169 | /// Ordering of [`Self::with_field`] and [`Self::with_direction`] matters as the builder will ignore invalid combinations specified by the field's [`Sortable`]. This is to prevent the user from specifying a direction that is not allowed by the field. 170 | #[derive(Copy, Clone, Debug, PartialEq)] 171 | pub struct UseSorterBuilder { 172 | field: F, 173 | direction: Direction, 174 | } 175 | 176 | impl Default for UseSorterBuilder { 177 | fn default() -> Self { 178 | let field = F::default(); 179 | let direction = Direction::from_field(&field); 180 | Self { field, direction } 181 | } 182 | } 183 | 184 | impl UseSorterBuilder { 185 | /// Optionally sets the initial field to sort by. 186 | pub fn with_field(&self, field: F) -> Self { 187 | Self { field, ..*self } 188 | } 189 | 190 | /// Optionally sets the initial direction to sort by.[`Direction::Ascending`] can be set. 191 | pub fn with_direction(&self, direction: Direction) -> Self { 192 | Self { direction, ..*self } 193 | } 194 | 195 | /// Creates Dioxus hooks to manage state. Must follow Dioxus hook rules and be called unconditionally in the same order as other hooks. See [use_sorter()] for simple usage. 196 | /// 197 | /// This fn (or [`Self::use_sorter`]) *must* be called or never used. See the docs on [`UseSorter::sort`] on using conditions. 198 | /// 199 | /// If the field or direction has not been set then the default values will be used. 200 | pub fn use_sorter(self, cx: &ScopeState) -> UseSorter { 201 | let sorter = use_sorter(cx); 202 | sorter.set_field(self.field, self.direction); 203 | sorter 204 | } 205 | } 206 | 207 | /// Creates Dioxus hooks to manage state. Must follow Dioxus hook rules and be called unconditionally in the same order as other hooks. See [UseSorterBuilder](UseSorterBuilder) for more advanced usage. 208 | /// 209 | /// This fn (or [`UseSorterBuilder::use_sorter`]) *must* be called or never used. See the docs on [`UseSorter::sort`] on using conditions. 210 | /// 211 | /// Relies on `F::default()` for the initial value. 212 | pub fn use_sorter(cx: &ScopeState) -> UseSorter<'_, F> { 213 | let field = F::default(); 214 | UseSorter { 215 | field: use_state(cx, || field), 216 | direction: use_state(cx, || Direction::from_field(&field)), 217 | } 218 | } 219 | 220 | impl<'a, F> UseSorter<'a, F> { 221 | /// Returns the current field and direction. Can be used to recreate state with [UseSorterBuilder](UseSorterBuilder). 222 | pub fn get_state(&self) -> (&F, &Direction) { 223 | (self.field.get(), self.direction.get()) 224 | } 225 | 226 | /// Sets the sort field and toggles the direction (if applicable). Ignores unsortable fields. 227 | pub fn toggle_field(&self, field: F) 228 | where 229 | F: Sortable, 230 | { 231 | match field.sort_by() { 232 | None => (), // Do nothing, don't switch to unsortable 233 | Some(sort_by) => { 234 | use SortBy::*; 235 | match sort_by { 236 | Fixed(dir) => self.direction.set(dir), 237 | Reversible(dir) => { 238 | // Invert direction if the same field 239 | let dir = if *self.field.get() == field { 240 | self.direction.get().invert() 241 | } else { 242 | // Reset state to new field 243 | dir 244 | }; 245 | self.direction.set(dir); 246 | } 247 | } 248 | self.field.set(field); 249 | } 250 | } 251 | } 252 | 253 | /// Sets the sort field and direction state directly. Ignores unsortable fields. Ignores the direction if not valid for a field. 254 | pub fn set_field(&self, field: F, dir: Direction) 255 | where 256 | F: Sortable, 257 | { 258 | match field.sort_by() { 259 | None => (), // Do nothing, ignore unsortable 260 | Some(sort_by) => { 261 | // Set state but ensure direction is valid 262 | let dir = sort_by.ensure_direction(dir); 263 | self.field.set(field); 264 | self.direction.set(dir); 265 | } 266 | } 267 | } 268 | 269 | /// Sorts items according to the current field and direction. 270 | /// 271 | /// This is not a hook and may be called conditionally. For example: 272 | /// - If data is coming from a `use_future` then you can call this fn once it has completed. 273 | /// - If you need to apply a filter, do so before calling this fn. 274 | pub fn sort(&self, items: &mut [T]) 275 | where 276 | F: PartialOrdBy + Sortable, 277 | { 278 | let (field, dir) = self.get_state(); 279 | sort_by(field, *dir, field.null_handling(), items); 280 | } 281 | } 282 | 283 | fn sort_by>( 284 | sort_by: &F, 285 | dir: Direction, 286 | nulls: NullHandling, 287 | items: &mut [T], 288 | ) { 289 | items.sort_by(|a, b| { 290 | let partial = sort_by.partial_cmp_by(a, b); 291 | partial.map_or_else( 292 | || { 293 | let a_is_null = sort_by.partial_cmp_by(a, a).is_none(); 294 | let b_is_null = sort_by.partial_cmp_by(b, b).is_none(); 295 | match (a_is_null, b_is_null) { 296 | (true, true) => Ordering::Equal, 297 | (true, false) => match nulls { 298 | NullHandling::First => Ordering::Less, 299 | NullHandling::Last => Ordering::Greater, 300 | }, 301 | (false, true) => match nulls { 302 | NullHandling::First => Ordering::Greater, 303 | NullHandling::Last => Ordering::Less, 304 | }, 305 | // Uh-oh, first partial_cmp_by should not have returned None 306 | (false, false) => unreachable!(), 307 | } 308 | }, 309 | // Reversal must be applied per item to avoid ordering NULLs 310 | |o| match dir { 311 | Direction::Ascending => o, 312 | Direction::Descending => o.reverse(), 313 | }, 314 | ) 315 | }); 316 | } 317 | 318 | #[cfg(test)] 319 | mod tests { 320 | use super::*; 321 | 322 | #[derive(Clone, Debug, Default, PartialEq)] 323 | struct Row(f64); 324 | 325 | #[derive(Copy, Clone, Debug, Default, PartialEq)] 326 | enum RowField { 327 | #[default] 328 | Value, 329 | } 330 | 331 | impl PartialOrdBy for RowField { 332 | fn partial_cmp_by(&self, a: &Row, b: &Row) -> Option { 333 | match self { 334 | Self::Value => a.0.partial_cmp(&b.0), 335 | } 336 | } 337 | } 338 | 339 | #[test] 340 | fn test_sort_by() { 341 | use Direction::*; 342 | use NullHandling::*; 343 | use RowField::*; 344 | 345 | // Ascending 346 | let mut rows = vec![Row(2.0), Row(1.0), Row(3.0)]; 347 | sort_by(&Value, Ascending, First, rows.as_mut_slice()); 348 | assert_eq!(rows, vec![Row(1.0), Row(2.0), Row(3.0)]); 349 | // Descending 350 | sort_by(&Value, Descending, First, rows.as_mut_slice()); 351 | assert_eq!(rows, vec![Row(3.0), Row(2.0), Row(1.0)]); 352 | 353 | // Nulls last, ascending 354 | let mut rows = vec![Row(f64::NAN), Row(f64::NAN), Row(2.0), Row(1.0), Row(3.0)]; 355 | sort_by(&Value, Ascending, Last, rows.as_mut_slice()); 356 | assert_eq!(rows[0], Row(1.0)); 357 | assert_eq!(rows[1], Row(2.0)); 358 | assert_eq!(rows[2], Row(3.0)); 359 | assert!(rows[3].0.is_nan()); 360 | assert!(rows[4].0.is_nan()); 361 | // Nulls first, ascending 362 | sort_by(&Value, Ascending, First, rows.as_mut_slice()); 363 | assert!(rows[0].0.is_nan()); 364 | assert!(rows[1].0.is_nan()); 365 | assert_eq!(rows[2], Row(1.0)); 366 | assert_eq!(rows[3], Row(2.0)); 367 | assert_eq!(rows[4], Row(3.0)); 368 | 369 | // Nulls last, descending 370 | sort_by(&Value, Descending, Last, rows.as_mut_slice()); 371 | assert_eq!(rows[0], Row(3.0)); 372 | assert_eq!(rows[1], Row(2.0)); 373 | assert_eq!(rows[2], Row(1.0)); 374 | assert!(rows[3].0.is_nan()); 375 | assert!(rows[4].0.is_nan()); 376 | // Nulls first, descending 377 | sort_by(&Value, Descending, First, rows.as_mut_slice()); 378 | assert!(rows[0].0.is_nan()); 379 | assert!(rows[1].0.is_nan()); 380 | assert_eq!(rows[2], Row(3.0)); 381 | assert_eq!(rows[3], Row(2.0)); 382 | assert_eq!(rows[4], Row(1.0)); 383 | } 384 | } 385 | --------------------------------------------------------------------------------