Compare commits

...

491 Commits
3280 ... 3890

Author SHA1 Message Date
Greg Johnston
d7dfb33153 fix(examples): broken favicons in hackernews examples (closes #3890) 2025-04-27 15:30:00 -04:00
Greg Johnston
171c8e7ff7 v0.8.0-rc3 2025-04-26 15:53:20 -04:00
Greg Johnston
53ffbeeb67 chore: fmt 2025-04-26 15:49:32 -04:00
Greg Johnston
ee86844077 Merge pull request #3882 from leptos-rs/3871
fix: remove event listeners from Suspense fallback during SSR (closes #3871)
2025-04-26 12:48:45 -04:00
Greg Johnston
1cee3f2f52 Merge branch 'main' into 3871 2025-04-26 12:48:40 -04:00
Greg Johnston
23c89dbfe1 Merge pull request #3878 from leptos-rs/3828
fix: correctly calculate starting index for first new key (closes #3828)
2025-04-26 12:48:12 -04:00
Greg Johnston
9f71f39f89 Merge branch 'main' into 3828 2025-04-26 12:47:56 -04:00
Greg Johnston
ef1d0f108a Merge pull request #3880 from sabify/websocket-example
fix(examples): websocket example tests fail on latency
2025-04-26 12:47:17 -04:00
Greg Johnston
a7a78317b7 Merge pull request #3879 from huuff/prelude-textprop
chore: put `TextProp` in the prelude (closes #3877)
2025-04-26 12:46:53 -04:00
autofix-ci[bot]
5005cc3587 [autofix.ci] apply automated fixes (attempt 2/3) 2025-04-26 16:15:06 +00:00
autofix-ci[bot]
08708f3388 [autofix.ci] apply automated fixes 2025-04-26 16:03:45 +00:00
Greg Johnston
c19c1b32f1 fix: remove event listeners from Suspense fallback during SSR (closes #3871) 2025-04-26 11:48:59 -04:00
Saber Haj Rabiee
e70cc08e96 fix(examples): websocket example tests fail on latency 2025-04-26 07:06:50 -07:00
autofix-ci[bot]
97175663ef [autofix.ci] apply automated fixes 2025-04-26 00:05:33 +00:00
Haf
92524a93cd chore: put TextProp in the prelude (closes #3877) 2025-04-25 23:50:08 +02:00
autofix-ci[bot]
9449f41ca9 [autofix.ci] apply automated fixes (attempt 2/3) 2025-04-25 20:31:56 +00:00
autofix-ci[bot]
d979055b70 [autofix.ci] apply automated fixes 2025-04-25 20:18:03 +00:00
Greg Johnston
97686f71a5 fix: improve support for keyed fields in ArcField<_> 2025-04-25 16:04:01 -04:00
Greg Johnston
06a0c768dc fix: correctly calculate starting index for first new key (closes #3828) 2025-04-25 15:57:30 -04:00
Saber Haj Rabiee
fff6a508fc feat(examples): add WebSocket example (#3853) 2025-04-24 20:17:08 -04:00
Greg Johnston
e65fc23fc7 fix: prevent infinite loop when sending Result over websocket, remove Display bound (#3848)
* chore: easing `Display` bound on `FromServerFnError`, #3811 follow-up

* fix: send/receive websocket data

* fix: clippy warnings

* fix: server_fn_axum example

* fix: make de/serialize_result functions public

* fix: make websocket result ser/de private

* chore: make the doc a comment and remove allow dead_code
2025-04-23 07:52:42 -04:00
Saber Haj Rabiee
f83b14d76c feat: enhancing ByteStream error handling (#3869)
* feat: enhancing `ByteStream` error handling

* fix: easing unnecessary trait bound over some `TextStream` methods
2025-04-23 07:38:39 -04:00
zakstucke
62dac6fb8a fix: prevent ScopedFuture stopping owner cleanup (#3863) 2025-04-23 07:37:12 -04:00
Rakshith Ravi
b36dec8269 feat: add header generation method to BrowserResponse (#3873) 2025-04-23 07:33:18 -04:00
Fea
0c50852251 fix: Use stabilized ClipboardEvent (#3849) 2025-04-23 07:27:24 -04:00
Nikolai Morin
50cb6005a8 chore(examples): complete the migration to Tailwind 4 (#3861)
The tailwind_csr example was not working yet with version 4, and the
tailwind_actix example still had the no-longer-needed config file.

This also brings the three tailwind examples back in sync, mostly. I
don't know why the axum example has a packages.json and
packages-lock.json file, to be honest.
2025-04-23 07:26:56 -04:00
Sathish
b725291ce9 chore: forward lint attributes used with #[component] macro (#3864)
* Forward lint attributes used with #[component] macro

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-04-23 07:26:26 -04:00
Greg Johnston
ed6d45d92d Merge pull request #3870 from leptos-rs/3851
Error boundary fixes
2025-04-23 07:25:41 -04:00
Greg Johnston
73b5587738 fix: correctly insert out-of-order stream chunks when Ok 2025-04-21 13:12:30 -04:00
Greg Johnston
68813a5918 fix: clear old errors when going from error state to error state (closes #3850) 2025-04-21 12:10:47 -04:00
Greg Johnston
8f6a96341e fix: wait for any inner Suspense before rendering ErrorBoundary (closes #3851) 2025-04-21 09:29:33 -04:00
Greg Johnston
046d5286c3 fix: correctly flush synchronous parts of SSR stream when appending another StreamBuilder 2025-04-21 09:28:14 -04:00
Greg Johnston
b45f982feb fix: close Actix websocket stream when browser disconnects (closes #3865) (#3866) 2025-04-19 16:47:09 -04:00
Greg Johnston
2b50ddc0db v0.8.0-rc2 2025-04-18 08:43:16 -04:00
Saber Haj Rabiee
c743f0641c chore: make the doc a comment and remove allow dead_code 2025-04-17 06:45:40 -07:00
Saber Haj Rabiee
078c252e2e fix: make websocket result ser/de private 2025-04-17 03:38:04 -07:00
martin frances
410aedbba8 chore: ran cargo outdated. (#3722)
* chore: ran cargo outdated fixed issues.

In bumping the rand crate, calls to thread_rng() becomes rng().

* backed out changes to rand.
2025-04-16 16:42:01 -07:00
Saber Haj Rabiee
00e474599f fix: reactive_graph keymap impl and clippy warnings (#3843) 2025-04-16 16:39:07 -07:00
Greg Johnston
8f38559aa2 chore(nightly): update proc-macro span file name method name (#3852) 2025-04-16 16:35:59 -07:00
Greg Johnston
3934c8b162 Update issue templates 2025-04-16 09:15:10 -04:00
Saber Haj Rabiee
de3a558203 fix: make de/serialize_result functions public 2025-04-15 09:24:43 -07:00
Saber Haj Rabiee
4d20105760 fix: server_fn_axum example 2025-04-15 09:23:32 -07:00
Saber Haj Rabiee
b95e827b8b fix: clippy warnings 2025-04-15 08:31:42 -07:00
Saber Haj Rabiee
30c445a419 fix: send/receive websocket data 2025-04-15 07:43:47 -07:00
Saber Haj Rabiee
6d5ab73594 chore: easing Display bound on FromServerFnError, #3811 follow-up 2025-04-14 23:52:02 -07:00
Greg Johnston
e0bf5ec480 fix: don't try to move keyed elements within the DOM if they're not yet mounted (closes #3844) (#3846) 2025-04-14 20:06:31 -04:00
Greg Johnston
28d9b3676d fix: correctly decode base64-encoded error messages stored in URL (#3842) 2025-04-13 13:28:58 -04:00
Greg Johnston
bb47916ebe fix: call additional_context after providing other server context in all cases (#3841) 2025-04-12 20:29:43 -04:00
Greg Johnston
cf843a8349 v0.8.0-rc1 2025-04-11 12:03:17 -04:00
Saber Haj Rabiee
7637e586d5 feat: enhancing server_fn errors (#3811)
* feat: enhancing server_fn errors

* fix: `server_fn` `not_result.stderr` line numbers

* fix: example server_fns_axum

* fix: not need to force ser/de traits

* fix(docs): deserialize error comment

* fix: remove unneeded traits bounds
2025-04-10 14:04:16 -07:00
Mykyta
ba7bfd8bac feat: allow using different error types for req/resp with WebSockets, closes #3724 (#3766)
* feat: allow using different error types for request/response with WebSocket

* [autofix.ci] apply automated fixes

* chore: clean up merge issues

* chore: fix custom client example

* we can't use nightly features on stable

* update flake inputs

* include gcc and glib to flake dev shell

* update expected stderr outputs server_fn/tests/invalid

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Greg Johnston <greg.johnston@gmail.com>
2025-04-09 10:03:47 -07:00
Saber Haj Rabiee
8bc4fd4198 Introducing cargo all-features clippy|nextest part of build process (#3767)
* fix: intoducing cargo all-features clippy

* fix: change check to clippy for better diagnostics

* chore: build is redundant

* fix: lint task

* feat: speed up tests by 2x with cargo-nextest

* fix: re-add flags

* fix: router example build process

* fix: correct clippy arguments

* fix: adapt examples makefile to new tools

* fix(CI): add cargo-all-features part of CI dep

* fix: just warn if there is no tests

* fix(CI): add clippy and rustfmt components

* fix: nextest in examples

* fix: clippy should not run on empty set of features in examples
(quickfix)

* fix: pin cargo-all-features installation to a branch

* fix: nextest --no-tests=warn?

* fix: do not use built-in cargo-make workflows

* fix: remove --all-targets

* fix: do not run tests in parallel in certain examples

* fix: disable nextest for examples

* fix: properly override the make task

* chore: run tests with no-deps

* fix: hackernews_islands_axum

* fix(CI): properly use --no-deps

* fix(CI): --no-deps is not supported in tests

* fix(CI): run doctests separately due to stable rust limitation in nextest

* fix(examples): makefile lint recursion

* fix(CI): run tests correctly

* fix: remove unused clear in test makefile

* fix: --no-deps positional arg in clippy

* fix: run doctests for all-features

* fix: running cargo-all-features over doctests

* fix: improve playwright makefile
2025-04-07 08:57:01 -07:00
Alexander Krivács Schrøder
3254d38d2d Revert "Remove getrandom (#3589)" (#3830)
Restores `getrandom` dependency to avoid compilation error when
compiling for WASM with the `nonce` feature.
2025-04-07 08:42:13 -07:00
Greg Johnston
b4abac2614 chore: missing Copy/Clone impls for MappedSignal (#3827) 2025-04-06 19:24:21 -04:00
Greg Johnston
767147f4ab Merge pull request #3802 from sabify/any-spawner-race
fix: prevent race condition in executor initialization + docs, optimization and tests
2025-04-06 15:39:34 -04:00
Greg Johnston
9128545388 fix: do not match static segment with last character missing before slash (closes #3817) (#3823) 2025-04-05 21:58:50 -04:00
Greg Johnston
b8810ba42f fix: correctly establish root ownership for static site generation (closes #3822) (#3824) 2025-04-05 19:50:28 -04:00
Saber Haj Rabiee
6006c33307 Revert "fix: more atomic orderings"
This reverts commit 02f4cfe437.
2025-04-03 09:11:14 -07:00
Saber Haj Rabiee
e113c79fb8 Revert "fix: preserve the ordering of read/write operations on atomic variables"
This reverts commit 2ea0381bb5.
2025-04-03 09:10:20 -07:00
尹吉峰
bdc73594ea change: pass reference to key for Selector::selected (#3694) 2025-04-02 21:43:13 -04:00
Pico Bolero
a55e82afe3 chore: migrate Axum example from Tailwind 3 to Tailwind 4 (#3804)
documentation e.g., input.css and output.css.
Uses @tailwindcss/cli tool to build the output.css
Removes no longer needed tailwind.config.js as that configuration can be
embedded in input.css.
Removes src/style.css as it only included tailwind 3 configurations that
are no longer needed.
2025-04-02 20:58:36 -04:00
Greg Johnston
300d301c11 Merge pull request #3755 from ifiokjr/feat/support_aliased_results_in_server_fn
feat: support aliased `Result` return types for `server_fn`
2025-04-02 20:56:29 -04:00
Greg Johnston
98ee336d0c fix: remove SendOption from public API of actions (#3812) 2025-04-02 13:03:21 -04:00
mahdi739
f102b2f43b fix: Move several Into* trait impls for store fields out of stable module for wider use (#3807)
* Move several Into* trait impls for store fields out of stable module for wider use

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-04-02 09:29:23 -04:00
Greg Johnston
47aebf3e22 fix: allow custom status codes or redirects for route fallbacks (#3808) 2025-04-01 19:25:59 -04:00
jasper
7d3a9da577 chore: add track_caller to store field methods (#3805) 2025-03-30 16:13:44 -04:00
Saber Haj Rabiee
6d90e05c13 fix: do not expose any_spawner::Executor in prelude to encourage local
spawn/spawn_local* implementations
2025-03-30 03:41:48 -07:00
Saber Haj Rabiee
5d0fd5b693 fix: four more spawns usage 2025-03-30 01:52:18 -07:00
Saber Haj Rabiee
d665719b27 fix: no global spawn for wasm executor 2025-03-30 00:28:33 -07:00
Saber Haj Rabiee
ae373b5a52 fix: revert back tick implementation to respect global executor 2025-03-29 23:19:45 -07:00
Saber Haj Rabiee
02f4cfe437 fix: more atomic orderings 2025-03-29 23:19:45 -07:00
Saber Haj Rabiee
40710adfd5 fix: glib test 2025-03-29 23:19:45 -07:00
Saber Haj Rabiee
d0f26ac64b chore: use futures_lite yield_now in glib test 2025-03-29 23:19:45 -07:00
Saber Haj Rabiee
9d2ac0a18f fix: improving tick logic in any_spawner 2025-03-29 23:19:45 -07:00
Saber Haj Rabiee
ab0832ad68 fix: correctly using executator tick instead of timer 2025-03-29 23:19:45 -07:00
Saber Haj Rabiee
2ea0381bb5 fix: preserve the ordering of read/write operations on atomic variables 2025-03-29 23:19:38 -07:00
Saber Haj Rabiee
94acdc24c7 fix: wasm-bindgen unused tests warnings 2025-03-29 23:17:35 -07:00
Saber Haj Rabiee
c175357e69 fix: lib docs 2025-03-29 23:17:35 -07:00
Saber Haj Rabiee
ef86a50c68 fix: wasm in spawn_local condition 2025-03-29 23:17:35 -07:00
Saber Haj Rabiee
e8e0808684 fix: run tests sequentially for glib 2025-03-29 23:17:35 -07:00
Saber Haj Rabiee
4973cc9eff fix: prevent race condition in executor + docs, optimization and tests 2025-03-29 23:17:35 -07:00
Greg Johnston
1a83a78980 Merge pull request #3803 from leptos-rs/store-test-fixes
Store test fixes
2025-03-29 14:55:36 -04:00
ChosunOne
4c6c79da40 feat: add support for more HTTP methods in server fn codecs (#3797) 2025-03-29 14:55:08 -04:00
Greg Johnston
c204df2ff3 Merge pull request #3785 from sabify/fix-portal-example
fix: portal example
2025-03-29 13:56:16 -04:00
zakstucke
0794681011 feat: derive_local for ArcSignal<T, LocalStorage> (#3798) 2025-03-29 13:55:11 -04:00
Greg Johnston
45dc1f4690 chore: update Store Option patch tests to reflect correct behavior 2025-03-29 13:45:39 -04:00
Greg Johnston
b80d58039e fix: prevent sibling over-notification due to #3799) 2025-03-29 13:20:52 -04:00
Greg Johnston
a7619c63bf Merge pull request #3793 from leptos-rs/3783
Improved handling of `<Title/>`
2025-03-28 15:43:45 -04:00
Greg Johnston
4038438cb4 Merge pull request #3799 from leptos-rs/3790
Fix Store notification order for nested keyed fields
2025-03-28 15:43:29 -04:00
Greg Johnston
f23335278b fix: allow repeated class= for all tuples, not only static ones (closes #3794) (#3801) 2025-03-28 15:43:13 -04:00
Greg Johnston
7f51a46b1a fix: correctly notify parent fields when patching 2025-03-27 20:20:04 -04:00
Greg Johnston
a54e3fdb40 fix: notify keyed Store fields from the top down (closes #3790) 2025-03-27 20:19:46 -04:00
Greg Johnston
64ba9b9dd4 fix: do not re-create effect when building a new route 2025-03-27 17:21:16 -04:00
Greg Johnston
568a16b880 chore: clippy 2025-03-26 22:07:32 -04:00
autofix-ci[bot]
d9179f0b19 [autofix.ci] apply automated fixes (attempt 2/3) 2025-03-26 20:05:52 +00:00
autofix-ci[bot]
62161c83c5 [autofix.ci] apply automated fixes 2025-03-26 19:58:41 +00:00
Greg Johnston
97f31f1af5 fix: smarter handling of <Title/> (closes #3783) 2025-03-26 15:46:55 -04:00
Greg Johnston
aa4dd53890 fix: correct insertion of a list of items when the first one doesn't exist in the DOM 2025-03-26 15:46:37 -04:00
Saber Haj Rabiee
a0c6f2b7ac fix: there is no way in cargo-make to override external task, so run
ordinary test for every examples
2025-03-26 08:25:28 -07:00
Ifiok Jr.
753d02a14c chore: fix formatting 2025-03-26 15:12:32 +00:00
Ifiok Jr.
ae23364ef8 chore: add comment explaining annotation 2025-03-26 15:12:32 +00:00
Ifiok Jr.
a74713a371 fix: only use diagnostic attribute on versions after 1.78 2025-03-26 15:12:31 +00:00
Ifiok Jr.
72e84f4e38 feat: support aliased Result return types for server_fn
- Enhanced error messages for better clarity when server functions do not meet the expected return type requirements.
- Added `trybuild` tests to ensure behaviour is not broken in future releases.
2025-03-26 15:12:31 +00:00
Ifiok Jr.
0a13ebd94d fix: also include ServerFnErrorErr in prelude 2025-03-26 15:12:30 +00:00
Ifiok Jr.
23c6f548ec fix: add FromServerFnError to leptos::prelude::* 2025-03-26 15:12:30 +00:00
Saber Haj Rabiee
543063ac24 fix: run cargo test for portal eample (minify tests) 2025-03-26 08:07:43 -07:00
Saber Haj Rabiee
04da08f82d fix: portal example makefile to run cargo test 2025-03-25 23:45:14 -07:00
Saber Haj Rabiee
c8ee4b3e05 fix: portal minify test 2025-03-25 23:42:09 -07:00
Saber Haj Rabiee
999a09d064 fix: quoting strings in portal example 2025-03-25 23:27:29 -07:00
Saber Haj Rabiee
9a32ae7bd5 fix: write simple minifier for portal tests 2025-03-25 23:12:19 -07:00
zakstucke
a96ef29d9e feat: re-export the codee crate to make custom encodings for resources easier (#3761) 2025-03-25 21:40:48 -04:00
Saber Haj Rabiee
0553c2af30 fix: signal CI to install chromedriver 2025-03-25 12:58:14 -07:00
Saber Haj Rabiee
668b7b4adb fix: limit opt-level to test 2025-03-25 12:57:51 -07:00
Saber Haj Rabiee
0a90def2da fix: portal example too many locals 2025-03-25 12:32:44 -07:00
Saber Haj Rabiee
d095879ef2 fix: portal example 2025-03-25 12:16:19 -07:00
Saber Haj Rabiee
2508b016d5 fix(CI): run only the exact examples on the only examples change (#3782)
* fix(CI): run only the exact examples on the only examples change

* chore: format html (retrigger ci)

* fix: missing the right field

* fix(CI): add missing output key

* fix(CI): properly set matrix directory for test-only-examples

* fix(CI): missing bracket token

* fix(CI): do not run semver check on examples only tests

* fix(CI): semver logic
2025-03-25 09:38:25 -07:00
Saber Haj Rabiee
bf35298708 fix: router example build process (#3779)
* fix: router example build process

* fix: a working router example
2025-03-24 23:53:45 -07:00
Greg Johnston
1a1e436cff fix: correctly handle optional parameters in ParentRoute (#3784) 2025-03-24 20:15:31 -04:00
Greg Johnston
b4731e61c6 Merge pull request #3781 from leptos-rs/partialeq-sendoption
Tweaks to `MaybeSendWrapperOption<_>`
2025-03-24 20:12:06 -04:00
autofix-ci[bot]
5bdc68a2f2 [autofix.ci] apply automated fixes 2025-03-24 21:56:27 +00:00
Greg Johnston
0a6cd9e33f update example 2025-03-24 17:40:52 -04:00
Greg Johnston
eca8e3cc72 chore: update tests 2025-03-23 20:33:51 -04:00
Greg Johnston
e0856eee33 chore: remove duplicate implementation due to merge 2025-03-23 20:20:30 -04:00
Greg Johnston
514cf62bf6 docs: add some more documentation to SendOption 2025-03-23 20:20:12 -04:00
Greg Johnston
26522666d5 chore: rename MaybeSendWrapperOption to SendOption 2025-03-23 20:19:30 -04:00
Greg Johnston
dcb3f202cd fix: correctly handle == and similar traits for MaybeSendWrapperOption 2025-03-23 20:14:43 -04:00
Greg Johnston
b032c15a84 Merge pull request #3762 from leptos-rs/reduce-local-signals
Reduce use local signals for `Action::new_local` and similar primitives
2025-03-23 15:55:02 -04:00
Saber Haj Rabiee
f24e804985 fix(CI): toolchain will be determined and test against by CI (#3778)
* fix(CI): toolchain will be determined and test against by CI

* chore: formatting examples

* fix: clippy
2025-03-23 10:10:52 -07:00
Alexander Krivács Schrøder
2c1194a71a docs: correct docs for default value for hash_files (closes #3774) (#3775)
Resolves #3774
2025-03-23 09:08:20 -04:00
Greg Johnston
fcdc9a07e4 Merge pull request #3777 from sabify/fix-ci-examples-logic
fix(CI): conditional executions of only changed examples
2025-03-23 09:07:16 -04:00
Greg Johnston
3d5b0127c2 Merge pull request #3776 from sabify/remove-ci-cache
fix(CI): remove caching
2025-03-23 09:06:59 -04:00
Saber Haj Rabiee
1cbbcda48b fix(CI): conditional executions of only changed examples 2025-03-23 01:42:53 -07:00
Saber Haj Rabiee
d9b998ed0c fix(CI): add was32 target in rust-toolchain setup 2025-03-23 01:12:46 -07:00
Saber Haj Rabiee
79f0482325 fix(CI): install trunk with bininstall 2025-03-23 01:12:13 -07:00
Saber Haj Rabiee
78d70fc400 fix(CI): caching may not be needed 2025-03-23 01:11:27 -07:00
Saber Haj Rabiee
2a011dd89c fix(CI): install deno only if needed, #3768 follow-up (#3773) 2025-03-23 00:04:07 -07:00
Saber Haj Rabiee
bc7c59d880 fix: clippy errors (#3772)
* fix: use map instead of if else

* fix: needless lifetime
2025-03-22 23:44:49 -07:00
Greg Johnston
a5d158765f fix: support IntoFragment for single element (closes #3757) (#3759) 2025-03-22 19:55:16 -04:00
Saber Haj Rabiee
999c8be6a0 fix(CI): install deps only if needed, speeds up CI (#3768) 2025-03-22 15:30:53 -07:00
Greg Johnston
5cfb16c79f feat: consolidate sync/unsync Action APIs 2025-03-22 15:24:10 -04:00
Greg Johnston
fd95f11dff Revert "fix: use signals rather than Action::new_local() (closes #3746) (#3749)"
This reverts commit 2658ae8b40.
2025-03-22 15:24:10 -04:00
Greg Johnston
2d8336ac91 feat: consolidate sync/unsync Action APIs 2025-03-22 15:24:10 -04:00
Saber Haj Rabiee
bb0c352f75 fix: remove duplicate semver (#3764) 2025-03-22 11:50:43 -07:00
Saber Haj Rabiee
b6eddca2c1 fix(CI): optimize CI workflow (#3758)
* chore: optimize CI

* chore: fomratting makefile to retrigger ci

* fix: run tests against both stable and nightly toolchains

* chore: simplify workflow

* fix(CI): remove unused inputs

* fix(CI): correctly indicating erased mode

* fix(CI): replace input with the name

* fix(CI): fixed logic of running cargo cmake on workspace on each example
and memeber!

* fix(CI): organized, simplified and unified CI jobs

* chore: change CI name

* fix(CI): keyword

* fix(CI): wait for dependent jobs
2025-03-22 09:48:54 -07:00
Saber Haj Rabiee
57272926ad fix: properly feature gating ui macro tests (Closes #3742) (#3756)
* fix: properly feature gating ui macro tests (Closes #3742)

* fix: wrongly gated main in test and added more gates

* docs: formatting
2025-03-22 09:48:08 -07:00
Greg Johnston
e903c297a9 chore: add SignalSetter to prelude (closes #3547) (#3753) 2025-03-21 16:58:00 -04:00
Nicolas Cura
b6e6588c8d fix: make trailing comma optional for either!() macro (#3736) 2025-03-21 16:39:52 -04:00
Greg Johnston
713abb3072 chore: ensure WASM target is installed for examples with provided rust-toolchain.toml (closes #3717) (#3752) 2025-03-21 16:38:35 -04:00
Greg Johnston
fce202db39 Merge pull request #3529 from leptos-rs/leptos_0.8
Leptos 0.8
2025-03-21 16:18:55 -04:00
Greg Johnston
1fe39bf7c8 Merge remote-tracking branch 'origin' into leptos_0.8 2025-03-21 16:18:01 -04:00
Jérôme MEVEL
fb5fdfc429 docs: in Effect::watch, refer to 'dependency_fn' and 'handler' in doc (#3731) 2025-03-21 16:01:56 -04:00
Alexander Krivács Schrøder
c738c5d81b feat: switch extract() helper to use ServerFnErrorErr (closes #3745) (#3750)
* feat: switch `extract()` helper to use `ServerFnErrorErr`

This provides much better compatibility with server functions using
custom errors while still working as before with server functions using
`ServerFnError`

* style: apply autofix diff
2025-03-21 16:01:12 -04:00
Greg Johnston
2658ae8b40 fix: use signals rather than Action::new_local() (closes #3746) (#3749) 2025-03-21 15:51:44 -04:00
Saber Haj Rabiee
a0d75fda03 chore: no need to filter out "nightly" feature as of #3735 (#3747)
* chore: no need to filter out "nightly" feature as of #3735

* fix: enable hot-reload only if in all debug mode, nightly feature and
nightly rustc

* fix: do not build/test against nightly feature alone

* fix: don not test against nightly feature alone

* fix: add trace-components to denylist
2025-03-21 10:16:16 -07:00
Saber Haj Rabiee
716c770a45 fix(CI): sermver job name (#3748) 2025-03-21 06:42:42 -07:00
Saber Haj Rabiee
a2d268606c fix(CI): cleanup directory no matter of results (#3743) 2025-03-20 17:53:25 -07:00
zakstucke
90fc727d60 ArcLocalResource fix (#3740) 2025-03-20 16:20:05 -07:00
zakstucke
aae827923c ArcLocalResource fix (0.8) (#3741) 2025-03-20 16:19:32 -07:00
Saber Haj Rabiee
52c770c7da fix(CI): free-up disk, properly gate nightly feature and pre-install deps (#3735)
* fix(CI): pre-install tailwind and sass

* chore: retrigger CI

* fix(CI): properly set `erased_mode` in examples

* fix(CI): workflow logic install deps locally

* chore(CI): organized tailwind and sass versions

* fix: properly ignore nightly features on stable rustc

* fix(CI): typo

* fix: missing cfg attr

* fix: properly gate nightly module in `reactive_graph``

* fix: complete `rustc_nightly` cfg gate

* fix(CI): making even more space for CI workers

* fix: missing one more rustc_nightly gated feature

* fix: maximize the speed of cargo-all-features by limiting combinations to 2
2025-03-20 14:28:07 -07:00
Saber Haj Rabiee
9210636266 fix(CI): cancel in-group inflight and pending jobs on new pushes in CI (#3739) 2025-03-20 13:02:17 -07:00
Saber Haj Rabiee
012616c4d8 fix(CI): switch to stable in semver for most compatibility (#3737) 2025-03-20 13:01:45 -07:00
Evan Almloff
6b9520f1a9 More flexible server fn macro api (#3725)
* Split up the server function expansion into multiple functions

* Use LitStr instead of Literal

* Refactor out more of the expansion

* Fix the parse example

* Expose some of the parsed server function arguments and body fields

* mark ServerFnBody as non_exhaustive

* [autofix.ci] apply automated fixes

* Fix server function paths

* rename from impl

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-03-20 09:55:38 -07:00
benwis
9052804ab4 v0.7.8 2025-03-20 08:21:11 -07:00
benwis
e95c903e85 v0.7.7 2025-03-19 18:19:37 -07:00
Greg Johnston
2faae43d5f v0.8.0-beta 2025-03-19 21:02:10 -04:00
Nicolas Cura
6760c87e83 Merge pull request #3727 from NCura/patch-1
Fix typo
2025-03-19 21:02:10 -04:00
bimoadityar
8a179e6f45 examples: update example tailwind input css to v4 (#3702) 2025-03-19 21:01:03 -04:00
Greg Johnston
e765f99016 fix: matching optional params after an initial static param (closes #3730) (#3732) 2025-03-19 20:59:41 -04:00
autofix-ci[bot]
e19e42c650 [autofix.ci] apply automated fixes 2025-03-19 23:42:02 +00:00
zakstucke
fb4be49ebf feat: remove SendWrapper from the external interface of LocalResource (#3715) 2025-03-19 19:26:14 -04:00
Nicolas Cura
30548eca31 Merge pull request #3727 from NCura/patch-1
Fix typo
2025-03-18 14:30:23 -04:00
Greg Johnston
0b4cbbc17d Merge remote-tracking branch 'origin' into leptos_0.8 2025-03-16 14:27:23 -04:00
Greg Johnston
dbbeb7c6ef fix: don't retrigger rendering when only param has changed (closes #3719( 2025-03-16 14:26:23 -04:00
Greg Johnston
36aef2565d chore: merge issues 2025-03-16 14:25:31 -04:00
Greg Johnston
a2a7eb8a2a Merge remote-tracking branch 'origin' into leptos_0.8 2025-03-16 14:21:21 -04:00
Zak Stucke
97e22e2506 Extra trait impls for MaybeSendWrapper 2025-03-16 14:20:35 -04:00
autofix-ci[bot]
8bedacb0c7 [autofix.ci] apply automated fixes 2025-03-16 14:20:35 -04:00
Zak Stucke
56b7b9a16a Remove SendWrapper from the external interface of LocalResource, by internalising a MaybeSendWrapper inside ArcAsyncDerived 2025-03-16 14:20:35 -04:00
Greg Johnston
d04d4c77f9 Merge pull request #3720 from metatoaster/regression_tests_3502
test: regression from #3502
2025-03-16 14:16:05 -04:00
Tommy Yu
5c75928b5b test: avoiding testdriver browser contention
- The number of tests have increased sufficiently that the browser test
  instances spawned by the driver are choked out on CI.
2025-03-16 22:43:21 +13:00
Tommy Yu
abc5631654 test: regression from #3502
- Also as reported in #3719, which has an actual minimum example.
- The "quicker" test had a reset but that runs into timing issue with
  the way this reset is done too soon after resource usage, so leaving
  this out and we will just trust the bigger counters.
2025-03-16 22:43:21 +13:00
Tommy Yu
40e5288ac1 fix instrumented use_context
- It shouldn't be in on_cleanup, move into it from the component to
  avoid BorrowMut error.
2025-03-16 22:43:21 +13:00
Greg Johnston
335934d40e Merge pull request #3716 from zakstucke/string-opt
view!{} macro optimisation: don't wrap string types in closures when passing to ToChildren
2025-03-15 10:56:40 -04:00
Greg Johnston
6ee72f42e2 Merge pull request #3687 from leptos-rs/3671
Various issues related to setting signals and context in cleanups
2025-03-15 10:34:53 -04:00
Thomas Versteeg
93af23a970 feat: allow closures for shell parameter in file_and_error_handler* (#3711) 2025-03-15 10:24:09 -04:00
Danik Vitek
95e8ae84af feat(reactive_stores): Replace AsRef bound of StoreFieldIterator blanket impl with Len bound (#3701) 2025-03-15 10:23:09 -04:00
Danik Vitek
5cfe7f6b5e fix: make tuple struct field locator in Patch impl Index instead of usize (#3700) 2025-03-15 10:19:41 -04:00
Greg Johnston
0404efd5c3 fix: ensure that store subfield mutations notify from the root down (closes #3704) (#3714) 2025-03-15 10:04:52 -04:00
Zak Stucke
93173c1400 view!} macro optimisation: don't wrap string types in closures when passing to ToChildren 2025-03-15 03:17:20 +00:00
Tommy Yu
cd2904f6a6 chore: prep common base to share example with 0.8 2025-03-15 14:35:55 +13:00
Greg Johnston
6b453845f9 fix: allow NodeRef to work with AttributeInterceptor (closes #3697) 2025-03-13 21:38:28 -04:00
zakstucke
111b84ce3b feat: allow LocalResource sync methods to be used outside Suspense (#3708) 2025-03-13 21:36:51 -04:00
zakstucke
5633148047 feat: allow LocalResource sync methods to be used outside Suspense (#3708) 2025-03-13 09:28:00 -04:00
autofix-ci[bot]
4edb012de3 [autofix.ci] apply automated fixes 2025-03-13 01:16:55 +00:00
Greg Johnston
b2bea2e6b7 fix: support for websockets under default features 2025-03-12 21:06:52 -04:00
Greg Johnston
acbd6378a8 chore: bump version for 0.8 2025-03-12 20:29:46 -04:00
Greg Johnston
b7462aab10 fix: broken type inference for Action::new_unsync (closes #3328) (#3705) 2025-03-12 19:12:46 -04:00
Greg Johnston
7593540774 Merge remote-tracking branch 'origin' into leptos_0.8 2025-03-12 16:16:10 -04:00
Greg Johnston
ed915f8e06 Merge pull request #3656 from ealmloff/websockets
Add websocket support for server functions
2025-03-12 16:13:41 -04:00
Greg Johnston
f65d87d566 chore: allow dead code in example 2025-03-10 21:07:41 -04:00
Greg Johnston
5034539411 chore: update server_fns_axum example 2025-03-10 21:06:36 -04:00
Greg Johnston
bc48aa4228 chore: reexport Bytes to make it easier to implement Client 2025-03-10 21:06:26 -04:00
Greg Johnston
d2c81fe955 change: enable url and json by default on server_fn 2025-03-10 16:02:50 -04:00
Greg Johnston
28eb96831a chore: fix up doctests on server_fn crate 2025-03-10 15:57:59 -04:00
Greg Johnston
330920eae2 chore: clippy 2025-03-10 10:14:46 -04:00
Greg Johnston
a94bc0a6da fix: only store a weak reference to an Owner in the current thread (see #3671) 2025-03-10 10:14:46 -04:00
Greg Johnston
f85e01f4d6 fix: do not panic unnecessarily in try_ methods on Arena (closes #3671) 2025-03-10 10:14:46 -04:00
autofix-ci[bot]
599c87c88a [autofix.ci] apply automated fixes 2025-03-10 14:03:07 +00:00
Evan Almloff
3ca98279e1 forward server fn visibility 2025-03-10 08:52:32 -05:00
mahdi739
a730bffe13 fix: Ensure reactive functions passed to TextProp are kept reactive (closes: #3689) (#3690) 2025-03-09 19:40:28 -04:00
Greg Johnston
d0bf843821 Merge pull request #3692 from QuartzLibrary/immediate-effect
`ImmediateEffect` follow up
2025-03-09 13:50:26 -04:00
QuartzLibrary
7250bc312e docs: clarify need for ThreadId 2025-03-09 11:49:23 +00:00
QuartzLibrary
0e8242f94c feat: simplify ImmediateEffect 2025-03-08 18:40:52 +00:00
QuartzLibrary
439b41f0e8 test: parallel ImmediateEffect r/w access 2025-03-08 18:35:16 +00:00
Evan Almloff
18570e970c Fix clippy 2025-03-07 17:19:24 -06:00
autofix-ci[bot]
787bf385d3 [autofix.ci] apply automated fixes 2025-03-07 23:18:19 +00:00
Evan Almloff
b6d2808671 Document the protocol trait and implementations 2025-03-07 17:12:49 -06:00
Evan Almloff
2e4d94b6c6 Add encoding suffix to the encoding types and revert renaming the post encodings 2025-03-07 17:12:49 -06:00
autofix-ci[bot]
66f9c8c999 [autofix.ci] apply automated fixes 2025-03-07 21:26:39 +00:00
Greg Johnston
352080d91a fix: don't use ws feature of Axum on JS-fetch/no-default platform 2025-03-07 16:19:11 -05:00
Greg Johnston
1e579614a5 chore: remove unused import 2025-03-07 15:55:28 -05:00
Greg Johnston
a4e47d4086 Merge pull request #3650 from QuartzLibrary/immediate-effect
`ImmediateEffect`
2025-03-07 15:18:50 -05:00
Greg Johnston
3164721fdb fix: untrack in NodeRef::on_load() to avoid re-triggering it if you read something reactively (closes #3684) (#3686) 2025-03-07 12:07:46 -05:00
Evan Almloff
fee4bccb32 Create post type aliases for encodings 2025-03-07 08:40:08 -06:00
mahdi739
4ba9f67440 feat: implement IntoClass for store fields (#3670)
* Implement `IntoClass` for store fields

* [autofix.ci] apply automated fixes

* [autofix.ci] apply automated fixes (attempt 2/3)

* [autofix.ci] apply automated fixes (attempt 3/3)

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-03-07 08:22:59 -05:00
Saber Haj Rabiee
2242ad1847 fix: semver and feature handy script for update nightly (#3674) 2025-03-07 08:21:21 -05:00
Greg Johnston
131b18bddb Merge pull request #3677 from sabify/fix-enum-stack
fix: enum stack size
2025-03-07 08:20:20 -05:00
Greg Johnston
5e9d6e2dfd fix: point bind:group to correct location (closes #3678) (#3680) 2025-03-07 08:04:53 -05:00
Saber Haj Rabiee
d76e5bb4ea fix: moved value 2025-03-05 21:21:29 -08:00
Saber Haj Rabiee
f752e32ae3 fix: clippy on large enum variant (https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant) 2025-03-05 21:10:30 -08:00
Saber Haj Rabiee
a9197102a6 fix: clippy warning on match usage 2025-03-05 21:08:10 -08:00
Saber Haj Rabiee
58f1bf95e1 fix: clippy clone_on_copy (https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_copy) 2025-03-05 21:07:37 -08:00
autofix-ci[bot]
d84ab6d9bf [autofix.ci] apply automated fixes (attempt 2/3) 2025-03-05 16:23:48 +00:00
autofix-ci[bot]
f069d4478e [autofix.ci] apply automated fixes 2025-03-05 15:20:59 +00:00
Evan Almloff
65b5d55d62 deny missing docs 2025-03-05 09:01:22 -06:00
Evan Almloff
860ad7a221 return an error when the sever doesn't support spawning tasks 2025-03-05 09:00:26 -06:00
Evan Almloff
901e038aa0 update form integration 2025-03-05 08:53:54 -06:00
Evan Almloff
f49f0965bc remove default actix feature 2025-03-05 08:51:31 -06:00
Evan Almloff
bb62d08d3f implement actix integration 2025-03-05 08:47:06 -06:00
Greg Johnston
bfe04593fd Merge pull request #3658 from mahdi739/impl-several-into-traits-for-store-fields-0.8
Implement several into traits for store fields (0.8)
2025-03-04 08:54:02 -05:00
Greg Johnston
38a3aae28e Merge branch 'main' into immediate-effect 2025-03-03 21:02:43 -05:00
martin frances
5eaaff045f chore(clippy): replace mem::replace with Option::replace (#3668) 2025-03-03 18:01:19 -05:00
autofix-ci[bot]
5b484eaec4 [autofix.ci] apply automated fixes (attempt 3/3) 2025-03-03 22:02:22 +00:00
autofix-ci[bot]
e9384e3286 [autofix.ci] apply automated fixes 2025-03-03 21:42:06 +00:00
autofix-ci[bot]
5149ad54db [autofix.ci] apply automated fixes (attempt 2/3) 2025-03-03 21:36:44 +00:00
autofix-ci[bot]
4d9ec54ad1 [autofix.ci] apply automated fixes 2025-03-03 21:22:46 +00:00
Evan Almloff
a1cd7ae9a1 implement reqwest websocket integration 2025-03-03 14:58:37 -06:00
autofix-ci[bot]
083f9c663f [autofix.ci] apply automated fixes 2025-03-03 14:02:22 +00:00
Greg Johnston
63c9549120 fix: ensure cleanups run for all replaced nested routes (closes #3665) (#3666) 2025-03-03 08:19:05 -05:00
Greg Johnston
6232f6482a fix: param segments should not match an empty string that contains only / separator (closes #3527) (#3662) 2025-03-01 12:05:17 -05:00
Greg Johnston
825e89f25c fix: do not double-insert hash character in URLs (closes #3647) (#3661) 2025-03-01 12:05:05 -05:00
Greg Johnston
3dbb251853 fix: tweak bounds on For for backwards-compat (#3663) 2025-03-01 11:50:09 -05:00
zakstucke
98e00fcb3b Erased mode in CI (#3640)
* Erased mode in CI

* Trigger CI

* Rename dev_mode erased_mode plus add to more matrices

* nested routes in separate component fix

* Fix lint

* Small fixes

* Fixes

* proc-macro rustflags cross-compilation workaround with internal erasure feature for leptos_macro

* Re-trigger CI

* fix unrelated doc CI and remove unneeded IntoAttribute trait

* Fix StaticVec rebuild() fn

* Conflict fixes

* Maybe fix

* Bump example toolchain
2025-03-01 07:43:13 -08:00
martin frances
5da4c438d9 chore: examples/server_fns_axum - Bumped various packages (not axum). (#3655)
tower-http
tower
thiserror
strum
notify

axum has breaking changes and so will addressed in a separate PR.
2025-02-28 14:30:03 -05:00
mahdi739
80ed74c075 chore: implement Debug for ArcField and Field (#3660) 2025-02-28 14:29:35 -05:00
Greg Johnston
cdee2a9476 feat: "islands router" for client-side navigations when in islands mode (#3502) 2025-02-28 14:01:33 -05:00
autofix-ci[bot]
c97ab9a72c [autofix.ci] apply automated fixes 2025-02-28 15:27:34 +00:00
Evan Almloff
4fc8972f2b make the into websocket function async 2025-02-28 09:26:37 -06:00
QuartzLibrary
79e9340a9b refactor: improve naming and docs after changes 2025-02-27 23:26:36 +00:00
QuartzLibrary
41d01cedb2 fix: parallel execution in ImmediateEffect 2025-02-27 23:10:08 +00:00
Evan Almloff
b800c009c7 Integrate the websocket protocol with the server function macro 2025-02-27 16:31:06 -06:00
QuartzLibrary
374a020d84 feat: do not store user state in ImmediateEffect 2025-02-27 22:17:06 +00:00
QuartzLibrary
83fcf8663c feat: make ImmediateEffect more robust
The goal here is to make the behavior under recursion better defined.
2025-02-27 22:12:55 +00:00
Greg Johnston
e7a73595de chore: remove unnecessary Debug bound 2025-02-27 17:00:00 -05:00
autofix-ci[bot]
a9a988e0e1 [autofix.ci] apply automated fixes 2025-02-27 14:46:56 +00:00
Mahdi
db10d961df Implement Render, RenderHtml, AttributeValue for store fields 2025-02-27 17:44:07 +03:30
Mahdi
fb608158cb Implement IntoSplitSignal for AtKeyed, AtIndex and DerefedField 2025-02-27 17:16:51 +03:30
Mahdi
1a472ebad1 Implement InnerHtmlValue for store fields 2025-02-27 17:09:34 +03:30
Mahdi
2d1b66a5c6 Implement IntoProperty for store fields 2025-02-27 17:00:33 +03:30
Mahdi
c524b0aefc rename style_store_field macro to style_reactive 2025-02-27 16:55:37 +03:30
Mahdi
e4c977911c Implement IntoStyle and IntoStyleValue for store fields 2025-02-27 16:41:53 +03:30
autofix-ci[bot]
f488d4b5b7 [autofix.ci] apply automated fixes 2025-02-26 19:58:25 +00:00
Evan Almloff
d4cfd0e2cb Move content type to a separate trait 2025-02-26 13:56:59 -06:00
autofix-ci[bot]
a4b0d3408c [autofix.ci] apply automated fixes 2025-02-26 15:44:01 +00:00
Evan Almloff
2037bf12cb Merge branch 'leptos_0.8' into websockets 2025-02-26 09:40:58 -06:00
Evan Almloff
2747a496fc fix formatting 2025-02-26 09:40:22 -06:00
Evan Almloff
c286812116 move the server request and response into a separate trait 2025-02-26 09:36:02 -06:00
Greg Johnston
1e0a9ef189 fix: avoid hydration issues with HashedStylesheet (closes #3633) (#3654) 2025-02-26 09:18:23 -05:00
TERRORW0LF
1363b941bc feat: .map() and .and_then() for OnceResource and LocalResource (#3652) 2025-02-26 09:16:50 -05:00
Evan Almloff
7479010f84 unified http protocol for non-websocket sever functions 2025-02-25 16:20:33 -06:00
QuartzLibrary
f7a1a2cab2 feat: introduce ImmediateEffect 2025-02-25 21:45:28 +00:00
QuartzLibrary
92b82688a6 fix: relax bounds on OrPoisoned blanket impls 2025-02-25 20:59:47 +00:00
Evan Almloff
9b9983af79 expose encoding types 2025-02-25 08:36:04 -06:00
Greg Johnston
04e79a0dc4 chore: clean up fetch example a bit 2025-02-25 08:06:47 -05:00
Greg Johnston
f64951126e chore: merge issues 2025-02-25 07:42:39 -05:00
Greg Johnston
0a29071779 Merge remote-tracking branch 'origin' into leptos_0.8 2025-02-25 07:39:43 -05:00
Greg Johnston
efcb6f6d21 feat: support IntoSplitSignal for (Signal<T>, SignalSetter<T>) (closes #3634) (#3643) 2025-02-25 07:32:37 -05:00
Greg Johnston
42988b1bc1 chore: fix Axum test setup (#3651) 2025-02-25 07:22:12 -05:00
Evan Almloff
6904eec207 remove into/from request/response bounds on server fn 2025-02-24 13:05:37 -06:00
Evan Almloff
7eb8ca702d switch most encodings into the new system 2025-02-24 12:00:02 -06:00
QuartzLibrary
c75397ea75 chore: small refactor 2025-02-23 17:27:40 +00:00
Greg Johnston
848fd724dd Merge pull request #3644 from leptos-rs/nightly-ci-update 2025-02-22 15:19:44 -05:00
Greg Johnston
5bc254d49f chore: better way of not running whole doc tests 2025-02-22 14:29:25 -05:00
Greg Johnston
885f4a1654 chore: ignore type complexity lint 2025-02-22 08:39:00 -05:00
Greg Johnston
ddd243d07a chore: better way of not running whole doc tests 2025-02-22 08:38:39 -05:00
Greg Johnston
362c300eac chore: clippy doc comment indentation 2025-02-22 08:28:26 -05:00
Greg Johnston
284a724e5f chore(ci): update pinned nightly version 2025-02-22 07:35:09 -05:00
Evan Almloff
1a7b40b507 implement gloo websockets 2025-02-21 15:48:41 -06:00
Evan Almloff
73dd677843 switch to async fn for get implementation 2025-02-20 17:02:19 -06:00
Evan Almloff
131f414fdc move run client into the protocol trait 2025-02-20 17:01:51 -06:00
Evan Almloff
c3ed874d4d Create websocket protocol trait 2025-02-19 14:49:57 -06:00
benwis
f003e50446 Update throw_error to v0.3 2025-02-19 08:08:21 -08:00
Greg Johnston
ea29685c92 change: remove unused Result alias (#3543) 2025-02-19 07:22:20 -08:00
Greg Johnston
6ecc681cdd fix: allow decoding already-decoded URI components (closes #3606) (#3628)
* fix: allow decoding already-decoded URI components (closes #3606)

* clippy
2025-02-19 06:04:18 -08:00
zakstucke
49e44a2ec2 Erased routing, codegen opts (#3623) 2025-02-18 12:39:30 -08:00
Greg Johnston
7c34b4a4a5 fix: only render meta tags when rendered, not when created (closes #3629) (#3630) 2025-02-18 09:06:51 -05:00
Greg Johnston
7157958822 feat: support Option<_> in style: (closes #3568) (#3618) 2025-02-15 16:47:21 -05:00
martin frances
37cf25fba5 serde_json is common to (#3610)
integrations/actix
leptos/server
oco
server_fn

This is a defensive PR - Putting the crate definition into the root
workspcace makes it less likely to get difficult to trace version
slip bugs.

This does not help where sede_json is optional so care manual review
is required.
2025-02-15 10:24:07 -08:00
Greg Johnston
f975b8d33b fix: hydration of () (#3615) 2025-02-15 13:23:09 -05:00
zakstucke
d37450d12f Internally erase html elements (#3614) 2025-02-15 09:58:43 -08:00
Greg Johnston
4804dac32d chore: update either_of minimum version in workspace (#3612) 2025-02-15 08:19:05 -05:00
martin frances
a9f27d6128 chore: update syntax in README example (#3611) 2025-02-15 08:18:48 -05:00
Greg Johnston
04cb036a7d fix: reorder pause check in new_isomorphic (#3613) 2025-02-15 08:18:23 -05:00
jasper
1d3784ed7b feat: impl Into<Signal> for store subfields (#3579) 2025-02-14 17:14:49 -05:00
Greg Johnston
8cc1a34c00 feat: allow pausing and resuming effects (#3599) 2025-02-14 14:48:27 -05:00
mahdi739
68f4d46c5f feat: add invert to OptionStoreExt (#3534) 2025-02-14 13:52:38 -05:00
martin frances
590728e47e projects/bevy3d_ui: Bevy - Bugfix, clippy and crate bump (#3603)
The bugfix is related to access to a signal

"
bevy3d_ui-b20a0a6a298e7144.js:2637 At src/routes/demo1.rs:24:23, you access a
reactive_graph::signal::read::ReadSignal<bevy3d_ui::demos::bevydemo1::scene::Scene>
(defined at src/routes/demo1.rs:19:39) outside a reactive tracking context.
This might mean your app is not responding to changes in signal values in the way you expect.
"

The solution is to use .get_untracked() inside an "effect" block.

Lots of small clippy fixes.

Also here are the crates that have been bumped

-wasm-bindgen = "0.2.92"
-wasm-bindgen-test = "0.3.42"
-web-sys = "0.3.69"
+wasm-bindgen = "0.2.100"
+wasm-bindgen-test = "0.3.50"
+web-sys = "0.3.77"
2025-02-13 15:37:23 -08:00
martin frances
e84b527743 Minor: Bump tokio to 1.43. (#3600) 2025-02-12 23:14:00 -08:00
martin frances
96b125d54f Remove getrandom (#3589)
* Resolved this warning see while running cargo outdated

warning: Feature js of package getrandom has been obsolete in version 0.3.1

Now using the feature "wasm_js"

* the crate "getrandom" needs special configuration.

* getrandom_backend - a more generic config.

* Removed the crate getrandom
2025-02-12 23:13:27 -08:00
martin frances
16d66362f8 Minor: "wasm-bindgen" - Moved the crate definition up to the root workspace (#3588)
* Minor: "wasm-bindgen" - Moved the crate definition up to the root workspace

This synchronizes the version number amongst all sub-projects.
[Where the definition is "optional" manual adjustment is still required]

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-02-12 12:25:22 -08:00
martin frances
e27801a2c2 Minor: Bumped version of convert_case to 0.7 (#3590) 2025-02-12 12:17:36 -08:00
martin frances
b81f71997b Minor: Bump itertools to "0.14.0" (#3593)
The crate is used by "leptos_macro","reactive_stores" and "tachys"

So the definition of itertools can be centralized up into the root workspace
2025-02-12 12:16:47 -08:00
martin frances
2a11325749 Minor: leptos_config - Bump the "config" crate to version 0.15.8 (#3594) 2025-02-12 12:15:57 -08:00
martin frances
5604f3e979 projects/bevy3d_ui: Bevy migration (#3597)
-bevy = "0.14.1"
+bevy = "0.15.2"

<https://bevyengine.org/learn/migration-guides/0-14-to-0-15/>
2025-02-12 12:14:33 -08:00
martin frances
3a9a0891a3 projects/bevy3d_ui Migrate to leptos 0.7.7 (#3596)
* projects/bevy3d_ui Migrate to leptos 0.7.7

* Minor: projects/bevy3d_ui - Better Meta.
2025-02-12 12:13:32 -08:00
Greg Johnston
a39add50c0 fix: occasional use-after-disposed panic in Suspense (#3595) 2025-02-12 14:59:44 -05:00
Greg Johnston
2a2675dd36 fix: remove extra placeholder in Vec of text nodes (closes #3583) (#3592) 2025-02-12 10:45:56 -05:00
Greg Johnston
7be6a9da86 v0.7.7 2025-02-11 20:29:31 -05:00
Greg Johnston
c51e07b5a4 v0.7.6 (#3586) 2025-02-11 20:23:57 -05:00
jasper
b17a4c92c7 fix: allow non static lifetimes in component macro (#3571) 2025-02-10 20:51:15 -05:00
Alexis Fontaine
03f9c6cb6d fix: add <fieldset> attributes (#3581) 2025-02-10 15:19:00 -08:00
zakstucke
6ad300c592 Binary size wins (#3566)
* Random binary size opts

* [autofix.ci] apply automated fixes

* Stop autofixer removing an import

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-02-10 15:18:26 -08:00
zakstucke
b4e683d969 RenderHtml::into_owned (#3580) 2025-02-10 12:53:33 -08:00
Greg Johnston
c2289b23a7 fix: Actix stream error handling with 0.8 error types (#3574) 2025-02-10 08:32:44 -05:00
Greg Johnston
9e8b8886da feat: add :capture flag for events to handle them during capture phase (closes #3457) (#3575) 2025-02-10 08:26:00 -05:00
Greg Johnston
299acd25f3 implement AddAnyAttr for AnyView (#3562) 2025-02-09 20:46:41 -05:00
Danik Vitek
6a6b3dee15 fix(reactive_stores_macro): store attribute signature error message (#3567) 2025-02-09 14:09:43 -05:00
Alexis Fontaine
5d71913523 Handle erase_components on Either<A, B> (#3572) 2025-02-09 10:50:20 -08:00
mahdi739
706617ab0a fix: panic at fewer places in stores (#3551) 2025-02-07 14:45:12 -05:00
mahdi739
cd64bb9d67 fix: return empty set of keys instead of panicking when the KeyedSubfield is disposed (#3550) 2025-02-07 14:43:33 -05:00
Greg Johnston
f881c1877d fix: do not hold lock on arena when dispatching Action (#3561) 2025-02-07 14:26:58 -05:00
Greg Johnston
8783f6a478 fix: don't use InertElement for style: etc. (closes #3554) (#3558) 2025-02-06 21:26:15 -05:00
Greg Johnston
2add714c65 chore(ci): cargo install --locked for cargo-leptos installation (#3559) 2025-02-06 21:22:37 -05:00
Alexis Fontaine
88b1b2d882 feat: implement Attribute for Either<A, B> (#3556) 2025-02-06 21:21:53 -05:00
zakstucke
9d3a743d33 Fix ci (#3557) 2025-02-06 16:17:31 -08:00
zakstucke
287fc47163 "Update axum paths to 0.8 syntax" (#3555)
* Update axum paths to 0.8 syntax

* [autofix.ci] apply automated fixes

* [autofix.ci] apply automated fixes (attempt 2/3)

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-02-06 16:17:12 -08:00
zakstucke
8f74a6d8a0 AddAnyAttr static (#3553) 2025-02-06 14:00:25 -08:00
Greg Johnston
c6de7c714e fix: emit syntax errors in components rather than swallowing them (closes #3535) (#3538) 2025-02-01 15:29:40 -05:00
starmaker
597175a54b Fixing closing brace (#3539)
Most likely confglict merge artefact
2025-02-01 09:40:03 -08:00
Greg Johnston
6154199850 fix: attribute type erasure nightly (closes #3536) (#3537) 2025-02-01 11:32:32 -05:00
Chris
ede25b9e3d fix: remove Default impl for LeptosOptions and ConfFile (#3522)
* fix: remove `Default` impl for `LeptosOptions` and `ConfFile`

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-02-01 09:41:44 -05:00
Ivan Radiček
32be3a023a feat: implement PatchField for Option<_> (#3528) 2025-02-01 09:40:43 -05:00
Greg Johnston
d9043e4f34 feat: impl From<ArcField<T>> for Field<T> (#3533)
* feat: impl `From<ArcField<T>>` for `Field<T>`

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-02-01 09:37:38 -05:00
Greg Johnston
8f636e354a change: allow IntoFuture for Suspend::new() (closes #3509) (#3532) 2025-01-31 14:25:35 -05:00
Serhii Stepanchuk
e3010c7f1f feat: add file_and_error_handler_with_context (#3526)
* add file_and_error_handler_with_context
like in leptos_routes_with_context func

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-01-31 12:33:55 -05:00
Greg Johnston
1dcc5838f7 v0.7.5 2025-01-30 21:42:39 -05:00
Greg Johnston
7da64f22c4 Merge branch 'main' into leptos_0.8 2025-01-30 21:32:58 -05:00
Greg Johnston
0073ae7d8a chore: update version numbers preparing for 0.8.0-alpha 2025-01-30 21:29:54 -05:00
Georg Vienna
1ff373dbc2 feat: allow raw identifiers in Params derive macro (#3525) 2025-01-29 19:39:23 -05:00
Greg Johnston
c35c42c6e3 fix: correctly notify descendants and ancestors of store fields (closes #3523) (#3524) 2025-01-29 19:28:26 -05:00
Geoffrey Garrett
d4cbba7c63 feat(callback): implement matches method for Callback and UnsyncCallback (#3520)
* feat(callback): implement matches method for Callback and UnsyncCallback

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-01-27 20:37:11 -05:00
stefnotch
9cc8ee3c5a fix: memo recomputation (closes #3252) (#3495) 2025-01-27 20:19:16 -05:00
SleeplessOne1917
f0c5ffe55f impl IntoAttributeValue for TextProp (#3517)
* impl IntoAttributeValue for TextProp

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-01-26 14:16:58 -05:00
benwis
8465716a19 Fix formatting 2025-01-26 09:51:22 -08:00
zakstucke
0e24b2e63f AddAnyAttr working with erase_components (#3518)
* AddAnyAttr working with erase_components

* CI fixes
2025-01-26 09:51:22 -08:00
Danik Vitek
c64d205984 feat (either_of): Extent API; Implement other iterator methods; Update deps (#3478)
* Implement other iterator methods. Update deps

* Formatting

* Update Cargo.lock

* [autofix.ci] apply automated fixes

* Formatting

* Move `Either` declaration into the `tuples` macro

* Comment out non-MSRV-compliant methods

* [autofix.ci] apply automated fixes

* Formatting

* Implement mapping functions

* Fix clippy warnings

* Impl `Error`; Impl `From<Result<A, B>> for Either<B, A>`

* Fix `Error` impl

* Move `Error` impl under `#[cfg(not(feature="no_std"))] until MSRV >= 1.81

* [autofix.ci] apply automated fixes

* Make `From<Result>` compliant with `EitherOr`. Add `impl EitherOr for Either`

* fix: use fully-qualified name

* fix: `EitherOf` test

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-01-26 09:51:22 -08:00
Greg Johnston
f17cb98eb0 chore: update workspace dependency versions to latest (#3506) 2025-01-26 09:51:22 -08:00
Danik Vitek
30f3e82664 docs: Fix README.md & Add MSRV badge (#3480)
* Fix README.md

* Add MSRV badge

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-01-26 09:51:22 -08:00
starmaker
152d5a5c92 issue-3467 - bumping codee version to support rkyv 8 (#3504)
* issue-3467 - bumping codee version to support rkyv 8

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-01-26 09:51:22 -08:00
Sam Jude
669e1ba7fa hexagonal architecture (#3342)
Co-authored-by: Sam <@>
2025-01-26 09:51:22 -08:00
dcsturman
2ad6a086f9 Enhanced docs for reactive_stores (#3508)
Added docs on shadow traits, Option, Enum, Vec, and Box usage with Store.
2025-01-26 09:51:22 -08:00
Greg Johnston
32e58d6b66 fix: including node_ref after {..} on arbitrary components (#3503) 2025-01-26 09:51:22 -08:00
Greg Johnston
a107443104 chore(ci): add CI for leptos_0.8 branch (#3500) 2025-01-26 09:51:22 -08:00
Greg Johnston
c859b07901 feat: #[lazy] macros to support lazy loading and code splitting (#3477) 2025-01-26 09:51:22 -08:00
Greg Johnston
a9868bea2b chore: restore reactivity warning at top level of components (closes #3354) (#3499) 2025-01-26 09:51:22 -08:00
Greg Johnston
7183c2b993 fix: correctly handle ErrorBoundary through reactive views (closes #3487) (#3492) 2025-01-26 09:51:22 -08:00
Greg Johnston
7a03621db1 feat: implement unboxing support for recursive store nodes (closes #3491) (#3493) 2025-01-26 09:51:22 -08:00
benwis
586c330995 Fix formatting 2025-01-26 09:46:19 -08:00
zakstucke
72f960a026 AddAnyAttr working with erase_components (#3518)
* AddAnyAttr working with erase_components

* CI fixes
2025-01-26 09:43:32 -08:00
Danik Vitek
b62ae56094 feat (either_of): Extent API; Implement other iterator methods; Update deps (#3478)
* Implement other iterator methods. Update deps

* Formatting

* Update Cargo.lock

* [autofix.ci] apply automated fixes

* Formatting

* Move `Either` declaration into the `tuples` macro

* Comment out non-MSRV-compliant methods

* [autofix.ci] apply automated fixes

* Formatting

* Implement mapping functions

* Fix clippy warnings

* Impl `Error`; Impl `From<Result<A, B>> for Either<B, A>`

* Fix `Error` impl

* Move `Error` impl under `#[cfg(not(feature="no_std"))] until MSRV >= 1.81

* [autofix.ci] apply automated fixes

* Make `From<Result>` compliant with `EitherOr`. Add `impl EitherOr for Either`

* fix: use fully-qualified name

* fix: `EitherOf` test

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-01-24 21:15:29 -08:00
Greg Johnston
9ccefbbd8c chore: update workspace dependency versions to latest (#3506) 2025-01-24 21:07:20 -08:00
Danik Vitek
d1108826cc docs: Fix README.md & Add MSRV badge (#3480)
* Fix README.md

* Add MSRV badge

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-01-24 21:06:19 -08:00
starmaker
d6c4cd2a81 issue-3467 - bumping codee version to support rkyv 8 (#3504)
* issue-3467 - bumping codee version to support rkyv 8

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-01-24 20:29:55 -08:00
Sam Jude
f8acdf9168 hexagonal architecture (#3342)
Co-authored-by: Sam <@>
2025-01-24 20:29:07 -08:00
dcsturman
09bbae2a72 Enhanced docs for reactive_stores (#3508)
Added docs on shadow traits, Option, Enum, Vec, and Box usage with Store.
2025-01-24 20:23:13 -08:00
Spencer Ferris
2b589fa61f feat: Add more options for generating server fn routes (#3438)
* feat: Allow disabling server fn hash and customizing the default prefix

Allow configuring the default prefix for server function API routes. This is useful to
override the default prefix (`/api`) for all server functions without needing to manually
specify via `#[server(prefix = "...")]` on every server function.

Also, allow disabling appending the server functions' hashes to the end of their API names.
This is useful when an app's client side needs a stable server API. For example, shipping
the CSR WASM binary in a Tauri app. Tauri app releases are dependent on each platform's
distribution method (e.g., the Apple App Store or the Google Play Store), which typically
are much slower than the frequency at which a website can be updated. In addition, it's
common for users to not have the latest app version installed. In these cases, the CSR WASM
app would need to be able to continue calling the backend server function API, so the API
path needs to be consistent and not have a hash appended.

* Mark public structs as `#[non_exhaustive]` and add doc comments

* Minor refactor to pull the fn hash logic out of the `path` statement

* feat: Use module path in prefix for server fn API route

Allow including the module path of the server function in the API route. This
is an alternative strategy to prevent duplicate server function API routes
(the default strategy is to add a hash to the end of the route). Each element
of the module path will be separated by a `/`. For example, a server function
with a fully qualified name of `parent:🧒:server_fn` would have an API
route of `/api/parent/child/server_fn` (possibly with a different prefix and
a hash suffix depending on the values of the other server fn configs).

* Fix `enable_hash` if statement

* Add missing import
2025-01-24 20:11:38 -08:00
Greg Johnston
ac3352724b fix: including node_ref after {..} on arbitrary components (#3503) 2025-01-18 09:18:05 -05:00
Greg Johnston
3413825638 chore(ci): add CI for leptos_0.8 branch (#3500) 2025-01-17 16:04:36 -05:00
Greg Johnston
22b2d8ec84 feat: #[lazy] macros to support lazy loading and code splitting (#3477) 2025-01-17 15:15:12 -05:00
Greg Johnston
1c3e013a63 chore: restore reactivity warning at top level of components (closes #3354) (#3499) 2025-01-17 14:06:39 -05:00
Saber Haj Rabiee
35e6f17930 chore: upgrade axum to v0.8 (#3439) 2025-01-17 13:38:37 -05:00
Greg Johnston
d1513a4a0b feat(breaking): allow make PossibleRouteMatch dyn-safe (#3421) 2025-01-17 13:33:00 -05:00
Mario Carbajal
aa27b9e474 feat: impl Dispose for Callback types and add try_run to the Callable trait (#3371)
* impl Dispose for Callback types and add try_run to the Callable trait

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-01-17 13:32:04 -05:00
Ryo Hirayama
cfe925d58f feat: allow any type that implements FromServerFnError as a replacement of the ServerFnError in server_fn (#3274) 2025-01-17 13:30:12 -05:00
Greg Johnston
9d4b1bc4b7 fix: correctly handle ErrorBoundary through reactive views (closes #3487) (#3492) 2025-01-17 13:22:06 -05:00
Greg Johnston
f303ff9706 feat: implement unboxing support for recursive store nodes (closes #3491) (#3493) 2025-01-17 13:21:40 -05:00
Georg Vienna
9fd2a75da4 feat: either_or combinator (#3417) 2025-01-17 13:12:18 -05:00
Michael Scofield
429d1b1262 feat: support for custom patch function on stores (#3449) 2025-01-17 13:10:44 -05:00
Greg Johnston
035586e5d8 chore: work around wasm-bindgen breakage (#3498) 2025-01-17 12:16:05 -05:00
Greg Johnston
fdd5671fe1 v0.7.4 2025-01-15 19:38:44 -05:00
Greg Johnston
293149eeb2 fix: include missing nonces on streaming script tags and on leptos_meta components (closes #3482) (#3485) 2025-01-13 22:06:14 -05:00
Greg Johnston
a9ce608433 fix: do not use stale values in AsyncDerived if it is mutated before running (#3475) 2025-01-13 21:32:08 -05:00
Thomas Versteeg
62196ff638 docs: warn about callbacks outside the ownership tree (#3442) 2025-01-10 15:23:08 -05:00
WorldSEnder
db9cabb365 chore: use cfg! macro instead of #[cfg] attribute (#3446)
this unifies the code path. The alternative will *move* arguments passed
to the debug_warn! macro only when compiling without debug_assertions.
This version will instead always use additional format arguments by reference.
2025-01-10 15:22:41 -05:00
Greg Johnston
5293afddb7 chore: fix tracing warning mess (#3473) 2025-01-10 14:27:03 -05:00
林玮 (Jade Lin)
eeb01e2d52 feat: add [Arc]LocalResource::refetch method (#3394) 2025-01-10 13:57:37 -05:00
Geoffrey Garrett
7d9cd43c0e feat: impl AddAnyAttr trait for Static<V> (#3464)
* Implement AddAnyAttr trait for Static<V>

Closes #3463

* [autofix.ci] apply automated fixes

---------

Co-authored-by: geoffreygarrett <geoffrey@apollo.xyz>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-01-10 12:54:01 -05:00
Greg Johnston
723685c370 fix: do not overwrite SuspenseContext in adjacent Transition components (closes #3465) (#3471) 2025-01-10 12:52:28 -05:00
Michael Kadziela
6d19e1a921 chore: derive Clone for RouteChildren (#3462)
This change allows users to clone RouteChildren and call .into_inner() on it to get an owned version of <Children>, and then pass on the original RouteChildren to an underlying Routes, or ParentRoute component.
This helps users snapshot all possible routes in an application.
2025-01-10 12:03:52 -05:00
Greg Johnston
165911b2e6 fix: allow multiple overlapping notifications of AsyncDerived/LocalResource (closes #3454) (#3455) 2025-01-06 22:53:15 -05:00
starmaker
575186349c Rkyv feature should propagate properly (#3448)
I suppose enabling `rkyv` feature on `leptos` crate should enable it on all dependencies.
2025-01-06 12:09:26 -08:00
Greg Johnston
10db2f83eb v0.7.3 2025-01-04 08:55:44 -05:00
Greg Johnston
357f3be393 fix: erase_components with AttributeInterceptor (#3435) 2025-01-04 08:46:17 -05:00
Soso
a1f5d6f79f feat: impl IntoClass for Cow<'_, str> (#3420)
I also thought about making the implementation more generic, for example over
T: AsRef<str>, but that would change the associated types and be a breaking change
it would also conflict with the `Option` impl due to the orphan rules.

Maybe there is something to be done with Borrow or Deref in a future release?
2025-01-03 15:42:42 -05:00
Michael Scofield
34ecd2d541 feat: add Dispose for Store (#3429) 2025-01-03 15:37:59 -05:00
Michael Scofield
df38b075d8 feat: add Default to stores (#3432) 2025-01-03 15:37:41 -05:00
Konstantin Stepanov
46233e3097 fix: avoid failure on guard try_new() functions (#3436) 2025-01-03 15:37:06 -05:00
Greg Johnston
46f6d9ae26 fix: correct ownership in redirect route hook (closes #3425) (#3428) 2024-12-31 11:48:52 -05:00
Chris
8264d478e4 docs: remove islands mention from leptos_axum (#3423) 2024-12-31 10:35:20 -05:00
Greg Johnston
9c54da304e Merge pull request #3424 from leptos-rs/3419
Fix issues with island hydration when nested in a closure, and with context (closes #3419)
2024-12-31 10:35:02 -05:00
Michael Scofield
1c002a2df8 chore: add missing #[track_caller]s (#3422) 2024-12-31 10:34:47 -05:00
Greg Johnston
6e4dac91bf perf: optimize and simplify island walk 2024-12-31 09:02:36 -05:00
Greg Johnston
6493b0b359 fix: a more substantial island context system that restores ownership properly 2024-12-30 19:13:55 -05:00
Greg Johnston
d58042b7ba fix: establish hydration status via ownership and context 2024-12-30 16:49:43 -05:00
Georg Vienna
7a5b27ad20 feat: allow prop destructuring via new #[prop(name = ...)] (#3382) 2024-12-27 16:57:34 -05:00
Spencer Ferris
78d0dbdfa2 fix: provide custom state in file_and_error_handler (#3408)
The `file_and_error_handler` provided by leptos_axum does not provide
the app's custom state in the context. This means that when the fallback
handler tries to render the app, the app will not be able to access the
custom state (and will panic if it uses `expect_context`).

The handle defined by `file_and_error_handler` has access to the custom
state from Axum, so we can pass the custom state from Axum into the
Leptos handler using the `additional_context` parameter of
`handle_response_inner`.
2024-12-27 13:44:39 -05:00
Greg Johnston
1c30a4c131 fix: getrandom needs js feature (used when nonce feature is active) (closes #3409) (#3410) 2024-12-26 07:29:53 -05:00
Greg Johnston
b91429d4f0 fix: correctly track updates to keyed fields in keyed iterator (closes #3401) (#3403) 2024-12-24 08:14:14 -05:00
Alexis Fontaine
6663fddf76 fix: enable console feature of web-sys (#3406) 2024-12-24 08:14:01 -05:00
Greg Johnston
28af33d511 v0.7.2 2024-12-21 14:09:01 -05:00
Greg Johnston
5a3413d3b3 fix: correct hydration position for static text nodes in nightly (closes #3395) (#3396) 2024-12-21 14:02:38 -05:00
Saber Haj Rabiee
702d2e247b fix(ci): add missing glib for semver checks (#3393) 2024-12-21 09:07:07 -05:00
Greg Johnston
71f698f322 fix: correct span for let: syntax (closes #3387) (#3391) 2024-12-20 15:35:48 -05:00
Michael Scofield
8d4776bf5f feat: add a From<ArcStore<T>> for Store<T, S> (#3389) 2024-12-20 13:02:48 -05:00
Oliver
65798e430f docs: showcase let syntax in for_loop (closes #3059) (#3383)
* docs: showcase let syntax in for_loop

* fix: doctests on for_loop

---------

Co-authored-by: Oliver Nordh <oliver.nordh@proton.me>
2024-12-20 13:00:46 -05:00
Greg Johnston
d46d1a4fab Merge pull request #3376 from sabify/fix-ci
fix(ci): missing glib in ci
2024-12-20 12:59:45 -05:00
Alyx Mote
f9533ab75b Update elements.rs (#3379)
fix: add missing `popovertarget` and `popovertargetaction` attributes for `<button>`
2024-12-17 19:26:04 -05:00
Saber Haj Rabiee
d08f8822c0 fix(ci): add missing glib for autofix ci 2024-12-16 23:35:05 -08:00
Saber Haj Rabiee
7357839efb fix(ci): missing glib in ci 2024-12-16 23:34:33 -08:00
Greg Johnston
1b8ad58114 chore: update lockfile 2024-12-16 20:57:56 -05:00
Greg Johnston
ef72f1ce96 v0.7.1 2024-12-16 20:52:00 -05:00
Gary Coady
6a5bfe9a5d feat: impl IntoSplitSignal for Field (closes #3362) (#3364) 2024-12-16 20:48:13 -05:00
stefnotch
1661fe2412 feat: add signal.into_inner() (#3343) 2024-12-16 20:47:25 -05:00
Greg Johnston
2324853155 chore: reenable cargo-semver-checks on PRs (#3375) 2024-12-16 19:48:52 -05:00
Greg Johnston
28a3859365 fix: rebuilding of InertElement (closes #3368) (#3370) 2024-12-16 19:23:15 -05:00
Greg Johnston
6b50179189 docs: clarify Signal::derive() behavior (#3351) 2024-12-16 09:22:30 -05:00
Paul Hansen
0bb825f6bd feat: AttributeInterceptor component to allow passing attributes to other elements (#3340) 2024-12-16 09:18:10 -05:00
Greg Johnston
a6aa111122 fix: only mark memos Check if they aren't already Dirty (closes #3339) (#3356) 2024-12-16 09:10:20 -05:00
Marcus Whybrow
753cfe8e44 chore: implement PatchField for usize (#3346) 2024-12-16 09:09:50 -05:00
zakstucke
bc9c3add87 feat: accessing context by reference (with_context and update_context) (#3279) 2024-12-16 09:09:22 -05:00
Michael Scofield
d0bb45dbc4 chore: update leptos_meta feature docs (#3350) 2024-12-16 08:33:24 -05:00
zakstucke
2a4b80cf22 feat: opt-in locations in release mode with --cfg locations (#3281) 2024-12-16 08:32:57 -05:00
redforks
881734b43a chore: impl Clone trait for TypedChildrenFn (#3349) 2024-12-16 08:32:17 -05:00
bicarlsen
68fdc8d9c4 docs: typo fix in ToChildren::to_children docs. (#3352) 2024-12-14 10:58:49 -05:00
sutantodadang
03ed805137 implemented actix multipart (#3361) 2024-12-14 10:58:29 -05:00
Greg Johnston
5d4603e988 fix: don't try to hydrate inside <noscript> (closes #3360) (#3363) 2024-12-14 10:57:51 -05:00
Greg Johnston
e65969cfcd fix: nested keyed fields in stores (closes #3338) (#3344) 2024-12-11 20:03:41 -05:00
Greg Johnston
e1e90b8595 Merge pull request #3341 from FreezyLemon/fix-some-doc-typos
Fix a doc typo and one broken intra-doc link
2024-12-10 16:27:30 -05:00
bicarlsen
71a136c7af feat: increase number of branch arms for either! macro (#3337) 2024-12-10 16:26:41 -05:00
Greg Johnston
49366be2a5 feat: add scroll prop to <A/> component to control scrolling behavior (closes #2666) (#3333) 2024-12-10 16:26:11 -05:00
FreezyLemon
6f5bdcc675 Fix rustdoc link to ArenaItem on Sandboxed::new 2024-12-09 23:01:27 +01:00
FreezyLemon
726a99441f Fix typo in Signal/ArcSignal 2024-12-09 22:49:07 +01:00
Greg Johnston
775bea46d9 fix: correctly mount/unmount hydrated static text nodes in nightly mode (closes #3334) (#3336) 2024-12-08 12:39:16 -05:00
Greg Johnston
2aa9827a1f fix: correctly support !Send Actix APIs in server functions (#3326)
* fix: correctly support `!Send` Actix APIs in server functions

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2024-12-07 15:41:32 -05:00
Greg Johnston
be3c1811fc fix: correctly swap Vec<_> in the DOM (closes #3321) (#3324)
* fix: correctly swap `Vec<_>` in the DOM (closes #3321)

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2024-12-05 21:08:05 -05:00
Greg Johnston
8df4f3c71d publish 0.1.1 to include either! macro 2024-12-04 18:53:18 -05:00
dependabot[bot]
3028a9acd0 chore(deps): bump rustls in the cargo group across 1 directory (#3289)
Bumps the cargo group with 1 update in the / directory: [rustls](https://github.com/rustls/rustls).


Updates `rustls` from 0.23.16 to 0.23.18
- [Release notes](https://github.com/rustls/rustls/releases)
- [Changelog](https://github.com/rustls/rustls/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustls/rustls/compare/v/0.23.16...v/0.23.18)

---
updated-dependencies:
- dependency-name: rustls
  dependency-type: indirect
  dependency-group: cargo
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-03 15:21:55 -08:00
dependabot[bot]
4b167fb809 chore(deps): bump hyper from 1.5.0 to 1.5.1 (#3265)
Bumps [hyper](https://github.com/hyperium/hyper) from 1.5.0 to 1.5.1.
- [Release notes](https://github.com/hyperium/hyper/releases)
- [Changelog](https://github.com/hyperium/hyper/blob/master/CHANGELOG.md)
- [Commits](https://github.com/hyperium/hyper/compare/v1.5.0...v1.5.1)

---
updated-dependencies:
- dependency-name: hyper
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-03 15:21:42 -08:00
dependabot[bot]
46ae8ef9b2 chore(deps): bump rkyv from 0.8.8 to 0.8.9 (#3290)
Bumps [rkyv](https://github.com/rkyv/rkyv) from 0.8.8 to 0.8.9.
- [Release notes](https://github.com/rkyv/rkyv/releases)
- [Commits](https://github.com/rkyv/rkyv/commits)

---
updated-dependencies:
- dependency-name: rkyv
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-03 15:21:26 -08:00
benwis
21f26e7a6b Remove dependa 2024-12-03 09:00:34 -08:00
dependabot[bot]
204648d388 chore(deps): bump wasm-bindgen from 0.2.95 to 0.2.97 (#3317)
Bumps [wasm-bindgen](https://github.com/rustwasm/wasm-bindgen) from 0.2.95 to 0.2.97.
- [Release notes](https://github.com/rustwasm/wasm-bindgen/releases)
- [Changelog](https://github.com/rustwasm/wasm-bindgen/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustwasm/wasm-bindgen/compare/0.2.95...0.2.97)

---
updated-dependencies:
- dependency-name: wasm-bindgen
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ben Wishovich <benwis@users.noreply.github.com>
2024-12-03 08:54:32 -08:00
dependabot[bot]
a04bca55a2 chore(deps): bump tracing from 0.1.40 to 0.1.41 (#3294)
Bumps [tracing](https://github.com/tokio-rs/tracing) from 0.1.40 to 0.1.41.
- [Release notes](https://github.com/tokio-rs/tracing/releases)
- [Commits](https://github.com/tokio-rs/tracing/compare/tracing-0.1.40...tracing-0.1.41)

---
updated-dependencies:
- dependency-name: tracing
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ben Wishovich <benwis@users.noreply.github.com>
2024-12-03 08:50:46 -08:00
dependabot[bot]
1fec678174 chore(deps): bump url from 2.5.3 to 2.5.4 (#3291)
Bumps [url](https://github.com/servo/rust-url) from 2.5.3 to 2.5.4.
- [Release notes](https://github.com/servo/rust-url/releases)
- [Commits](https://github.com/servo/rust-url/compare/v2.5.3...v2.5.4)

---
updated-dependencies:
- dependency-name: url
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-03 08:49:04 -08:00
dependabot[bot]
4dbb8d1a42 chore(deps): bump bytes from 1.8.0 to 1.9.0 (#3297)
Bumps [bytes](https://github.com/tokio-rs/bytes) from 1.8.0 to 1.9.0.
- [Release notes](https://github.com/tokio-rs/bytes/releases)
- [Changelog](https://github.com/tokio-rs/bytes/blob/master/CHANGELOG.md)
- [Commits](https://github.com/tokio-rs/bytes/compare/v1.8.0...v1.9.0)

---
updated-dependencies:
- dependency-name: bytes
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-03 08:48:33 -08:00
dependabot[bot]
fc2c52eb04 chore(deps): bump js-sys from 0.3.72 to 0.3.74 (#3306)
Bumps [js-sys](https://github.com/rustwasm/wasm-bindgen) from 0.3.72 to 0.3.74.
- [Release notes](https://github.com/rustwasm/wasm-bindgen/releases)
- [Changelog](https://github.com/rustwasm/wasm-bindgen/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustwasm/wasm-bindgen/commits)

---
updated-dependencies:
- dependency-name: js-sys
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-03 08:48:03 -08:00
dependabot[bot]
1ae35ce5b3 chore(deps): bump wasm-bindgen-futures from 0.4.45 to 0.4.47 (#3318)
Bumps [wasm-bindgen-futures](https://github.com/rustwasm/wasm-bindgen) from 0.4.45 to 0.4.47.
- [Release notes](https://github.com/rustwasm/wasm-bindgen/releases)
- [Changelog](https://github.com/rustwasm/wasm-bindgen/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustwasm/wasm-bindgen/commits)

---
updated-dependencies:
- dependency-name: wasm-bindgen-futures
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-03 08:47:49 -08:00
dependabot[bot]
8edb11f324 chore(deps): bump postcard from 1.0.10 to 1.1.1 (#3319)
Bumps [postcard](https://github.com/jamesmunns/postcard) from 1.0.10 to 1.1.1.
- [Release notes](https://github.com/jamesmunns/postcard/releases)
- [Changelog](https://github.com/jamesmunns/postcard/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jamesmunns/postcard/compare/v1.0.10...postcard/v1.1.1)

---
updated-dependencies:
- dependency-name: postcard
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-03 08:47:36 -08:00
mahdi739
5a01a7f2ed chore: fix typo (#3320) 2024-12-03 08:47:25 -08:00
Greg Johnston
f252460d02 fix: wait for blocking resources before sending subsequent chunks (close #3280) (#3282) 2024-12-02 16:44:36 -08:00
rjmac
6331b488e4 Remove the Send requirement on a local Action's future (fixes #3309) (#3310)
Co-authored-by: Robert Macomber <robertm@mox>
2024-12-02 09:19:42 -08:00
Gabriel Lopes Veiga
fcba8b3b17 fix: prevent multiple location headers on redirect (#3298) (#3311) 2024-12-01 18:54:35 -08:00
Greg Johnston
d665dd4b89 v0.7.0 2024-11-30 12:09:41 -05:00
Greg Johnston
be740b38ee feat: add NodeRef::on_load() and writeable NodeRef (#3305) 2024-11-30 11:55:13 -05:00
Rakshith Ravi
d2803c938c chore: remove pre-release message from README (#3075) 2024-11-30 11:48:50 -05:00
Greg Johnston
f29224415a fix: sort tuple-syntax class and style in addition to colon-syntax (closes #3296) (#3303) 2024-11-29 19:28:11 -05:00
Greg Johnston
292772c4d6 fix: allow a deprecated wasm-bindgen struct 2024-11-29 15:50:57 -05:00
benwis
5947aa299e Release rc3 2024-11-28 11:28:20 -08:00
Greg Johnston
6098836cf7 docs: improve line location of hydration error message when using view macro (#3293) 2024-11-27 14:36:31 -05:00
Niklas Eicker
2dfa61ff6a docs: fix help message for island macro (#3287) 2024-11-24 14:45:10 -05:00
Darwin Boersma
4f39b0b0ef Version any_spawner alongside other crates, reexport CustomExecutor (#3284)
* rc2 version any_spawner

Signed-off-by: Darwin Boersma <darwin@sadlark.com>

* reexport full any_spawner crate

Signed-off-by: Darwin Boersma <darwin@sadlark.com>

---------

Signed-off-by: Darwin Boersma <darwin@sadlark.com>
2024-11-23 14:49:43 -08:00
dependabot[bot]
980595f1f0 chore(deps): bump proc-macro2 from 1.0.91 to 1.0.92 (#3276)
Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.91 to 1.0.92.
- [Release notes](https://github.com/dtolnay/proc-macro2/releases)
- [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.91...1.0.92)

---
updated-dependencies:
- dependency-name: proc-macro2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-23 08:29:52 -05:00
500 changed files with 27967 additions and 8640 deletions

View File

@@ -29,11 +29,14 @@ Steps to reproduce the behavior:
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Next Steps**
[ ] I will make a PR
[ ] I would like to make a PR, but need help getting started
[ ] I want someone else to take the time to fix this
[ ] This is a low priority for me and is just shared for your information
**Additional context**
Add any other context about the problem here.

View File

@@ -1,12 +0,0 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "cargo"
directories:
- "/"
schedule:
interval: "daily"
open-pull-requests-limit: 10

View File

@@ -13,6 +13,7 @@ concurrency:
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
DEBIAN_FRONTEND: noninteractive
jobs:
autofix:
runs-on: ubuntu-latest
@@ -21,6 +22,10 @@ jobs:
- uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1
with: {toolchain: nightly, components: "rustfmt, clippy", target: "wasm32-unknown-unknown", rustflags: ""}
- name: Install Glib
run: |
sudo apt-get update
sudo apt-get install -y libglib2.0-dev
- name: Install jq
run: sudo apt-get install jq
- run: |

View File

@@ -1,30 +0,0 @@
name: CI Changed Examples
on:
push:
branches:
- main
- leptos_0.6
pull_request:
branches:
- main
- leptos_0.6
jobs:
get-example-changed:
uses: ./.github/workflows/get-example-changed.yml
get-matrix:
needs: [get-example-changed]
uses: ./.github/workflows/get-changed-examples-matrix.yml
with:
example_changed: ${{ fromJSON(needs.get-example-changed.outputs.example_changed) }}
test:
name: CI
needs: [get-example-changed, get-matrix]
if: needs.get-example-changed.outputs.example_changed == 'true'
strategy:
matrix: ${{ fromJSON(needs.get-matrix.outputs.matrix) }}
fail-fast: false
uses: ./.github/workflows/run-cargo-make-task.yml
with:
directory: ${{ matrix.directory }}
cargo_make_task: "ci"
toolchain: stable

View File

@@ -1,27 +0,0 @@
name: CI Examples
on:
push:
branches:
- main
- leptos_0.6
pull_request:
branches:
- main
- leptos_0.6
jobs:
get-leptos-changed:
uses: ./.github/workflows/get-leptos-changed.yml
get-examples-matrix:
uses: ./.github/workflows/get-examples-matrix.yml
test:
name: CI
needs: [get-leptos-changed, get-examples-matrix]
if: needs.get-leptos-changed.outputs.leptos_changed == 'true'
strategy:
matrix: ${{ fromJSON(needs.get-examples-matrix.outputs.matrix) }}
fail-fast: false
uses: ./.github/workflows/run-cargo-make-task.yml
with:
directory: ${{ matrix.directory }}
cargo_make_task: "ci"
toolchain: stable

View File

@@ -1,25 +0,0 @@
name: CI semver
on:
push:
branches:
- main
- leptos_0.6
pull_request:
branches:
- main
- leptos_0.6
jobs:
get-leptos-changed:
uses: ./.github/workflows/get-leptos-changed.yml
test:
needs: [get-leptos-changed]
if: github.event.pull_request.labels[0].name == 'semver' # needs.get-leptos-changed.outputs.leptos_changed == 'true' && github.event.pull_request.labels[0].name != 'breaking'
name: Run semver check (nightly-2024-08-01)
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Semver Checks
uses: obi1kenobi/cargo-semver-checks-action@v2
with:
rust-toolchain: nightly-2024-08-01

View File

@@ -4,17 +4,26 @@ on:
branches:
- main
- leptos_0.6
- leptos_0.8
pull_request:
branches:
- main
- leptos_0.6
- leptos_0.8
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
get-leptos-changed:
uses: ./.github/workflows/get-leptos-changed.yml
get-leptos-matrix:
uses: ./.github/workflows/get-leptos-matrix.yml
test:
name: CI
get-example-changed:
uses: ./.github/workflows/get-example-changed.yml
get-examples-matrix:
uses: ./.github/workflows/get-examples-matrix.yml
test-members:
name: CI (members)
needs: [get-leptos-changed, get-leptos-matrix]
if: needs.get-leptos-changed.outputs.leptos_changed == 'true'
strategy:
@@ -23,5 +32,37 @@ jobs:
uses: ./.github/workflows/run-cargo-make-task.yml
with:
directory: ${{ matrix.directory }}
cargo_make_task: "ci"
toolchain: nightly-2024-08-01
test-examples:
name: CI (examples)
needs: [test-members, get-examples-matrix]
if: ${{ success() }}
strategy:
matrix: ${{ fromJSON(needs.get-examples-matrix.outputs.matrix) }}
fail-fast: false
uses: ./.github/workflows/run-cargo-make-task.yml
with:
directory: ${{ matrix.directory }}
test-only-examples:
name: CI (examples)
needs: [get-leptos-changed, get-example-changed]
if: needs.get-leptos-changed.outputs.leptos_changed != 'true' && needs.get-example-changed.outputs.example_changed == 'true'
strategy:
matrix: ${{ fromJSON(needs.get-example-changed.outputs.matrix) }}
fail-fast: false
uses: ./.github/workflows/run-cargo-make-task.yml
with:
directory: ${{ matrix.directory }}
semver-check:
name: SemVer check (stable)
needs: [get-leptos-changed, test-members, test-examples]
if: ${{ success() && needs.get-leptos-changed.outputs.leptos_changed == 'true' && !contains(github.event.pull_request.labels.*.name, 'breaking') }}
runs-on: ubuntu-latest
steps:
- name: Install Glib
run: |
sudo apt-get update
sudo apt-get install -y libglib2.0-dev
- name: Checkout
uses: actions/checkout@v4
- name: Semver Checks
uses: obi1kenobi/cargo-semver-checks-action@v2

View File

@@ -1,54 +0,0 @@
name: Changed Examples Matrix Call
on:
workflow_call:
inputs:
example_changed:
description: "Example Changed"
required: true
type: boolean
outputs:
matrix:
description: "Matrix"
value: ${{ jobs.get-example-changed.outputs.matrix }}
jobs:
get-example-changed:
name: Get Changed Example Matrix
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get example project directories that changed
id: changed-dirs
uses: tj-actions/changed-files@v45
with:
dir_names: true
dir_names_max_depth: "2"
files: |
examples/**
!examples/cargo-make/**
!examples/gtk/**
!examples/Makefile.toml
!examples/*.md
json: true
quotepath: false
- name: List example project directories that changed
run: echo '${{ steps.changed-dirs.outputs.all_changed_files }}'
- name: Set Matrix
id: set-matrix
run: |
if [ ${{ inputs.example_changed }} == 'true' ]; then
# Create matrix with changed directories
echo "matrix={\"directory\":${{ steps.changed-dirs.outputs.all_changed_files }}}" >> "$GITHUB_OUTPUT"
else
# Create matrix with one item to prevent an empty vector error
echo "matrix={\"directory\":[\"NO_CHANGE\"]}" >> "$GITHUB_OUTPUT"
fi

View File

@@ -5,12 +5,18 @@ on:
example_changed:
description: "Example Changed"
value: ${{ jobs.get-example-changed.outputs.example_changed }}
# This is for test-only-examples workflow in ci.yml
matrix:
description: "Example Changed Directories"
value: ${{ jobs.get-example-changed.outputs.matrix }}
jobs:
get-example-changed:
name: Get Example Changed
runs-on: ubuntu-latest
outputs:
example_changed: ${{ steps.set-example-changed.outputs.example_changed }}
# This is for test-only-examples workflow in ci.yml
matrix: ${{ steps.set-example-changed.outputs.matrix }}
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -18,7 +24,7 @@ jobs:
fetch-depth: 0
- name: Get example files that changed
id: changed-files
uses: tj-actions/changed-files@v45
uses: tj-actions/changed-files@v46
with:
files: |
examples/**
@@ -27,7 +33,11 @@ jobs:
!examples/*.md
- name: List example files that changed
run: echo '${{ steps.changed-files.outputs.all_changed_files }}'
- name: Install jq
run: sudo apt-get install jq
- name: Set example_changed
id: set-example-changed
run: |
echo "example_changed=${{ steps.changed-files.outputs.any_changed }}" >> "$GITHUB_OUTPUT"
# This is for test-only-examples workflow in ci.yml
echo "matrix={\"directory\": $(echo '${{ steps.changed-files.outputs.all_changed_files }}' | tr ' ' '\n' | awk -F'/' '{print $1 "/" $2}'| sort -u | jq -R -s -c 'split("\n") | .[:-1]')}" >> "$GITHUB_OUTPUT"

View File

@@ -18,7 +18,7 @@ jobs:
fetch-depth: 0
- name: Get source files that changed
id: changed-source
uses: tj-actions/changed-files@v45
uses: tj-actions/changed-files@v46
with:
files_ignore: |
.*/**/*

View File

@@ -5,19 +5,21 @@ on:
directory:
required: true
type: string
cargo_make_task:
required: true
type: string
toolchain:
required: true
type: string
env:
CARGO_TERM_COLOR: always
CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
DEBIAN_FRONTEND: noninteractive
RUSTFLAGS: ${{ inputs.erased_mode && '--cfg erase_components' || '' }}
LEPTOS_TAILWIND_VERSION: v4.0.14
LEPTOS_SASS_VERSION: 1.86.0
jobs:
test:
name: Run ${{ inputs.cargo_make_task }} (${{ inputs.toolchain }})
name: "Run (${{ matrix.toolchain }}) (erased_mode: ${{ matrix.erased_mode && 'enabled' || 'disabled' }})"
runs-on: ubuntu-latest
strategy:
matrix:
toolchain: [stable, nightly-2025-03-05]
erased_mode: [true, false]
steps:
- name: Free Disk Space
run: |
@@ -25,53 +27,76 @@ jobs:
df -h
sudo rm -rf /usr/local/.ghcup
sudo rm -rf /opt/hostedtoolcache/CodeQL
sudo rm -rf /usr/local/lib/android/sdk/ndk
sudo rm -rf /usr/local/lib/android
sudo rm -rf /usr/share/dotnet
sudo rm -rf /opt/ghc
sudo rm -rf /usr/local/share/boost
sudo apt-get clean
sudo rm -rf /usr/local/lib/node_modules
# following lines currenly not needed as it takes too much time
# the new isolated CI doesn't need much space to test libraries
#
# uncommet only if nneded
#
# sudo apt-get clean
# sudo apt-get purge -y '^ghc-.*' '^dotnet-.*' '^llvm-.*' '^mono-.*' '^php.*' '^ruby.*'
# sudo apt-get autoremove -y
# sudo apt-get clean
# sudo rm -rf "$AGENT_TOOLSDIRECTORY"
# docker system prune -af
# docker image prune -af
# docker volume prune -f
echo "Disk space after cleanup:"
df -h
# Setup environment
- name: Install Glib
run: |
sudo apt-get update
sudo apt-get install -y libglib2.0-dev
- uses: actions/checkout@v4
- name: Setup Rust
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ inputs.toolchain }}
- name: Add wasm32-unknown-unknown
run: rustup target add wasm32-unknown-unknown
- name: Setup cargo-make
uses: davidB/rust-cargo-make@v1
- name: Cargo generate-lockfile
run: cargo generate-lockfile
- uses: Swatinem/rust-cache@v2
toolchain: ${{ matrix.toolchain }}
targets: wasm32-unknown-unknown
components: clippy,rustfmt
- name: Install binstall
uses: cargo-bins/cargo-binstall@main
- name: Install wasm-bindgen
run: cargo binstall wasm-bindgen-cli --no-confirm
- name: Install cargo-leptos
run: cargo binstall cargo-leptos --no-confirm
run: cargo binstall cargo-leptos --locked --no-confirm
- name: Install cargo-make
run: cargo binstall cargo-make --no-confirm
- name: Install nextest
run: cargo binstall cargo-nextest --no-confirm
- name: Install cargo-all-features
run: cargo install --git https://github.com/sabify/cargo-all-features --branch arbitrary-command-support
- name: Install Trunk
uses: jetli/trunk-action@v0.5.0
with:
version: "latest"
if: contains(inputs.directory, 'examples')
run: cargo binstall trunk --no-confirm
- name: Print Trunk Version
if: contains(inputs.directory, 'examples')
run: trunk --version
- name: Install Node.js
if: contains(inputs.directory, 'examples')
uses: actions/setup-node@v4
with:
node-version: 20
- uses: pnpm/action-setup@v4
name: Install pnpm
if: contains(inputs.directory, 'examples')
id: pnpm-install
with:
version: 8
run_install: false
- name: Get pnpm store directory
if: contains(inputs.directory, 'examples')
id: pnpm-cache
run: |
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
- uses: actions/cache@v4
if: contains(inputs.directory, 'examples')
name: Setup pnpm cache
with:
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
@@ -79,8 +104,9 @@ jobs:
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Maybe install chromedriver
if: contains(inputs.directory, 'examples')
run: |
project_makefile=${{inputs.directory}}/Makefile.toml
project_makefile='${{inputs.directory}}/Makefile.toml'
webdriver_count=$(cat $project_makefile | grep "cargo-make/webdriver.toml" | wc -l)
if [ $webdriver_count -eq 1 ]; then
if ! command -v chromedriver &>/dev/null; then
@@ -94,8 +120,9 @@ jobs:
echo chromedriver is not required
fi
- name: Maybe install playwright browser dependencies
if: contains(inputs.directory, 'examples')
run: |
for pw_path in $(find ${{inputs.directory}} -name playwright.config.ts)
for pw_path in $(find '${{inputs.directory}}' -name playwright.config.ts)
do
pw_dir=$(dirname $pw_path)
if [ ! -v $pw_dir ]; then
@@ -107,17 +134,35 @@ jobs:
fi
done
- name: Install Deno
if: contains(inputs.directory, 'examples')
uses: denoland/setup-deno@v2
with:
deno-version: v1.x
- name: Maybe install gtk-rs dependencies
if: contains(inputs.directory, 'gtk')
run: |
if [ ! -z $(echo ${{inputs.directory}} | grep gtk) ]; then
sudo apt-get update
sudo apt-get install -y libglib2.0-dev libgio2.0-cil-dev libgraphene-1.0-dev libcairo2-dev libpango1.0-dev libgtk-4-dev
fi
sudo apt-get install -y libglib2.0-dev libgio2.0-cil-dev libgraphene-1.0-dev libcairo2-dev libpango1.0-dev libgtk-4-dev
- name: Install Tailwind and Sass dependencies
if: contains(inputs.directory, 'examples')
run: |
cd '${{ inputs.directory }}'
tailwindcss_version=$(echo "$LEPTOS_TAILWIND_VERSION" | sed 's/^v//')
sass_version="$LEPTOS_SASS_VERSION"
pnpm add "tailwindcss@$tailwindcss_version" "@tailwindcss/cli@$tailwindcss_version" "sass@$sass_version"
echo "Tailwind CSS version:"
./node_modules/.bin/tailwindcss --version
echo "Sass version:"
./node_modules/.bin/sass --version
# Run Cargo Make Task
- name: ${{ inputs.cargo_make_task }}
run: |
cd ${{ inputs.directory }}
cargo make --profile=github-actions ${{ inputs.cargo_make_task }}
cd '${{ inputs.directory }}'
cargo make --no-workspace --profile=github-actions ci
- name: Clean up ${{ inputs.directory }}
if: always()
run: |
cd '${{ inputs.directory }}'
cargo clean || true
rm -rf node_modules || true

1638
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -40,36 +40,44 @@ members = [
exclude = ["benchmarks", "examples", "projects"]
[workspace.package]
version = "0.7.0-rc2"
version = "0.8.0-rc3"
edition = "2021"
rust-version = "1.76"
[workspace.dependencies]
throw_error = { path = "./any_error/", version = "0.2.0-rc2" }
any_spawner = { path = "./any_spawner/", version = "0.1.0" }
const_str_slice_concat = { path = "./const_str_slice_concat", version = "0.1.0" }
either_of = { path = "./either_of/", version = "0.1.0" }
hydration_context = { path = "./hydration_context", version = "0.2.0-rc2" }
leptos = { path = "./leptos", version = "0.7.0-rc2" }
leptos_config = { path = "./leptos_config", version = "0.7.0-rc2" }
leptos_dom = { path = "./leptos_dom", version = "0.7.0-rc2" }
leptos_hot_reload = { path = "./leptos_hot_reload", version = "0.7.0-rc2" }
leptos_integration_utils = { path = "./integrations/utils", version = "0.7.0-rc2" }
leptos_macro = { path = "./leptos_macro", version = "0.7.0-rc2" }
leptos_router = { path = "./router", version = "0.7.0-rc2" }
leptos_router_macro = { path = "./router_macro", version = "0.7.0-rc2" }
leptos_server = { path = "./leptos_server", version = "0.7.0-rc2" }
leptos_meta = { path = "./meta", version = "0.7.0-rc2" }
next_tuple = { path = "./next_tuple", version = "0.1.0-rc2" }
convert_case = "0.8"
throw_error = { path = "./any_error/", version = "0.3.0" }
any_spawner = { path = "./any_spawner/", version = "0.3.0-rc3" }
const_str_slice_concat = { path = "./const_str_slice_concat", version = "0.1" }
either_of = { path = "./either_of/", version = "0.1.5" }
hydration_context = { path = "./hydration_context", version = "0.3.0" }
itertools = "0.14.0"
leptos = { path = "./leptos", version = "0.8.0-rc3" }
leptos_config = { path = "./leptos_config", version = "0.8.0-rc3" }
leptos_dom = { path = "./leptos_dom", version = "0.8.0-rc3" }
leptos_hot_reload = { path = "./leptos_hot_reload", version = "0.8.0-rc3" }
leptos_integration_utils = { path = "./integrations/utils", version = "0.8.0-rc3" }
leptos_macro = { path = "./leptos_macro", version = "0.8.0-rc3" }
leptos_router = { path = "./router", version = "0.8.0-rc3" }
leptos_router_macro = { path = "./router_macro", version = "0.8.0-rc3" }
leptos_server = { path = "./leptos_server", version = "0.8.0-rc3" }
leptos_meta = { path = "./meta", version = "0.8.0-rc3" }
next_tuple = { path = "./next_tuple", version = "0.1.0" }
oco_ref = { path = "./oco", version = "0.2.0" }
or_poisoned = { path = "./or_poisoned", version = "0.1.0" }
reactive_graph = { path = "./reactive_graph", version = "0.1.0-rc2" }
reactive_stores = { path = "./reactive_stores", version = "0.1.0-rc2" }
reactive_stores_macro = { path = "./reactive_stores_macro", version = "0.1.0-rc2" }
server_fn = { path = "./server_fn", version = "0.7.0-rc2" }
server_fn_macro = { path = "./server_fn_macro", version = "0.7.0-rc2" }
server_fn_macro_default = { path = "./server_fn/server_fn_macro_default", version = "0.7.0-rc2" }
tachys = { path = "./tachys", version = "0.1.0-rc2" }
reactive_graph = { path = "./reactive_graph", version = "0.2.0-rc3" }
reactive_stores = { path = "./reactive_stores", version = "0.2.0-rc3" }
reactive_stores_macro = { path = "./reactive_stores_macro", version = "0.2.0-rc3" }
rustversion = "1"
serde_json = "1.0.0"
server_fn = { path = "./server_fn", version = "0.8.0-rc3" }
server_fn_macro = { path = "./server_fn_macro", version = "0.8.0-rc3" }
server_fn_macro_default = { path = "./server_fn/server_fn_macro_default", version = "0.8.0-rc3" }
tachys = { path = "./tachys", version = "0.2.0-rc3" }
trybuild = "1"
typed-builder = "0.21.0"
thiserror = "2.0.12"
wasm-bindgen = "0.2.100"
[profile.release]
codegen-units = 1
@@ -78,3 +86,10 @@ opt-level = 'z'
[workspace.metadata.cargo-all-features]
skip_feature_sets = [["csr", "ssr"], ["csr", "hydrate"], ["ssr", "hydrate"]]
max_combination_size = 2
[workspace.lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = [
'cfg(leptos_debuginfo)',
'cfg(erase_components)',
] }

View File

@@ -10,8 +10,8 @@ CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = true
workspace = false
clear = true
dependencies = [
{ name = "check", path = "examples/counter_without_macros" },
{ name = "check", path = "examples/counters_stable" },
{ name = "lint", path = "examples/counter_without_macros" },
{ name = "lint", path = "examples/counters_stable" },
]
[tasks.ci-examples]

View File

@@ -5,6 +5,7 @@
[![crates.io](https://img.shields.io/crates/v/leptos.svg)](https://crates.io/crates/leptos)
[![docs.rs](https://docs.rs/leptos/badge.svg)](https://docs.rs/leptos)
![Crates.io MSRV](https://img.shields.io/crates/msrv/leptos)
[![Discord](https://img.shields.io/discord/1031524867910148188?color=%237289DA&label=discord)](https://discord.gg/YdRAhS7eQB)
[![Matrix](https://img.shields.io/badge/Matrix-leptos-grey?logo=matrix&labelColor=white&logoColor=black)](https://matrix.to/#/#leptos:matrix.org)
@@ -12,8 +13,6 @@
You can find a list of useful libraries and example projects at [`awesome-leptos`](https://github.com/leptos-rs/awesome-leptos).
# The `main` branch is currently undergoing major changes in preparation for the [0.7](https://github.com/leptos-rs/leptos/milestone/4) release. For a stable version, please use the [v0.6.13 tag](https://github.com/leptos-rs/leptos/tree/v0.6.13)
# Leptos
```rust
@@ -22,7 +21,7 @@ use leptos::*;
#[component]
pub fn SimpleCounter(initial_value: i32) -> impl IntoView {
// create a reactive signal with the initial value
let (value, set_value) = create_signal(initial_value);
let (value, set_value) = signal(initial_value);
// create event handlers for our buttons
// note that `value` and `set_value` are `Copy`, so it's super easy to move them into closures
@@ -47,7 +46,7 @@ pub fn SimpleCounter(initial_value: i32) -> impl IntoView {
pub fn SimpleCounterWithBuilder(initial_value: i32) -> impl IntoView {
use leptos::html::*;
let (value, set_value) = create_signal(initial_value);
let (value, set_value) = signal(initial_value);
let clear = move |_| set_value(0);
let decrement = move |_| set_value.update(|value| *value -= 1);
let increment = move |_| set_value.update(|value| *value += 1);
@@ -169,14 +168,14 @@ Yew is the most-used library for Rust web UI development, but there are several
- **Performance:** This has huge performance implications: Leptos is simply much faster at both creating and updating the UI than Yew is.
- **Server integration:** Yew was created in an era in which browser-rendered single-page apps (SPAs) were the dominant paradigm. While Leptos supports client-side rendering, it also focuses on integrating with the server side of your application via server functions and multiple modes of serving HTML, including out-of-order streaming.
- ### How is this different from Dioxus?
### How is this different from Dioxus?
Like Leptos, Dioxus is a framework for building UIs using web technologies. However, there are significant differences in approach and features.
- **VDOM vs. fine-grained:** While Dioxus has a performant virtual DOM (VDOM), it still uses coarse-grained/component-scoped reactivity: changing a stateful value reruns the component function and diffs the old UI against the new one. Leptos components use a different mental model, creating (and returning) actual DOM nodes and setting up a reactive system to update those DOM nodes.
- **Web vs. desktop priorities:** Dioxus uses Leptos server functions in its fullstack mode, but does not have the same `<Suspense>`-based support for things like streaming HTML rendering, or share the same focus on holistic web performance. Leptos tends to prioritize holistic web performance (streaming HTML rendering, smaller WASM binary sizes, etc.), whereas Dioxus has an unparalleled experience when building desktop apps, because your application logic runs as a native Rust binary.
- ### How is this different from Sycamore?
### How is this different from Sycamore?
Sycamore and Leptos are both heavily influenced by SolidJS. At this point, Leptos has a larger community and ecosystem and is more actively developed. Other differences:

View File

@@ -1,6 +1,6 @@
[package]
name = "throw_error"
version = "0.2.0-rc2"
version = "0.3.0"
authors = ["Greg Johnston"]
license = "MIT"
readme = "../README.md"

View File

@@ -9,7 +9,7 @@ use std::{
error,
fmt::{self, Display},
future::Future,
mem, ops,
ops,
pin::Pin,
sync::Arc,
task::{Context, Poll},
@@ -17,11 +17,6 @@ use std::{
/* Wrapper Types */
/// This is a result type into which any error can be converted.
///
/// Results are stored as [`Error`].
pub type Result<T, E = Error> = core::result::Result<T, E>;
/// A generic wrapper for any error.
#[derive(Debug, Clone)]
#[repr(transparent)]
@@ -109,7 +104,7 @@ pub fn get_error_hook() -> Option<Arc<dyn ErrorHook>> {
/// Sets the current thread-local error hook, which will be invoked when [`throw`] is called.
pub fn set_error_hook(hook: Arc<dyn ErrorHook>) -> ResetErrorHookOnDrop {
ResetErrorHookOnDrop(
ERROR_HOOK.with_borrow_mut(|this| mem::replace(this, Some(hook))),
ERROR_HOOK.with_borrow_mut(|this| Option::replace(this, hook)),
)
}

View File

@@ -1,6 +1,6 @@
[package]
name = "any_spawner"
version = "0.1.1"
version = "0.3.0-rc3"
authors = ["Greg Johnston"]
license = "MIT"
readme = "../README.md"
@@ -12,12 +12,22 @@ edition.workspace = true
async-executor = { version = "1.13.1", optional = true }
futures = "0.3.31"
glib = { version = "0.20.6", optional = true }
thiserror = "2.0"
thiserror = { workspace = true }
tokio = { version = "1.41", optional = true, default-features = false, features = [
"rt",
] }
tracing = { version = "0.1.40", optional = true }
wasm-bindgen-futures = { version = "0.4.45", optional = true }
tracing = { version = "0.1.41", optional = true }
wasm-bindgen-futures = { version = "0.4.50", optional = true }
[dev-dependencies]
futures-lite = { version = "2.6.0", default-features = false }
tokio = { version = "1.41", default-features = false, features = [
"rt",
"macros",
"time",
] }
wasm-bindgen-test = { version = "0.3.50" }
serial_test = "3.2.0"
[features]
async-executor = ["dep:async-executor"]
@@ -34,3 +44,4 @@ rustdoc-args = ["--cfg", "docsrs"]
[package.metadata.cargo-all-features]
denylist = ["tracing"]
max_combination_size = 2

View File

@@ -1 +1,4 @@
extend = { path = "../cargo-make/main.toml" }
extend = [
{ path = "../cargo-make/main.toml" },
{ path = "../cargo-make/wasm-test.toml" },
]

View File

@@ -11,18 +11,16 @@
//! - no "join handle" or other result is returned from the spawn
//! - the `Future` must output `()`
//!
//! ```rust
//! ```no_run
//! use any_spawner::Executor;
//!
//! // make sure an Executor has been initialized with one of the init_ functions
//!
//! # if false {
//! // spawn a thread-safe Future
//! Executor::spawn(async { /* ... */ });
//!
//! // spawn a Future that is !Send
//! Executor::spawn_local(async { /* ... */ });
//! # }
//! ```
#![forbid(unsafe_code)]
@@ -37,15 +35,67 @@ pub type PinnedFuture<T> = Pin<Box<dyn Future<Output = T> + Send>>;
/// A future that has been pinned.
pub type PinnedLocalFuture<T> = Pin<Box<dyn Future<Output = T>>>;
static SPAWN: OnceLock<fn(PinnedFuture<()>)> = OnceLock::new();
static SPAWN_LOCAL: OnceLock<fn(PinnedLocalFuture<()>)> = OnceLock::new();
static POLL_LOCAL: OnceLock<fn()> = OnceLock::new();
// Type alias for the spawn function pointer.
type SpawnFn = fn(PinnedFuture<()>);
// Type alias for the spawn_local function pointer.
type SpawnLocalFn = fn(PinnedLocalFuture<()>);
// Type alias for the poll_local function pointer.
type PollLocalFn = fn();
/// Holds the function pointers for the current global executor.
#[derive(Clone, Copy)]
struct ExecutorFns {
spawn: SpawnFn,
spawn_local: SpawnLocalFn,
poll_local: PollLocalFn,
}
// Use a single OnceLock to ensure atomic initialization of all functions.
static EXECUTOR_FNS: OnceLock<ExecutorFns> = OnceLock::new();
// No-op functions to use when an executor doesn't support a specific operation.
#[cfg(any(feature = "tokio", feature = "wasm-bindgen", feature = "glib"))]
#[cold]
#[inline(never)]
fn no_op_poll() {}
#[cfg(all(not(feature = "wasm-bindgen"), not(debug_assertions)))]
#[cold]
#[inline(never)]
fn no_op_spawn(_: PinnedFuture<()>) {
#[cfg(debug_assertions)]
eprintln!(
"Warning: Executor::spawn called, but no global 'spawn' function is \
configured (perhaps only spawn_local is supported, e.g., on wasm \
without threading?)."
);
}
// Wasm panics if you spawn without an executor
#[cfg(feature = "wasm-bindgen")]
#[cold]
#[inline(never)]
fn no_op_spawn(_: PinnedFuture<()>) {
panic!(
"Executor::spawn called, but no global 'spawn' function is configured."
);
}
#[cfg(not(debug_assertions))]
#[cold]
#[inline(never)]
fn no_op_spawn_local(_: PinnedLocalFuture<()>) {
panic!(
"Executor::spawn_local called, but no global 'spawn_local' function \
is configured."
);
}
/// Errors that can occur when using the executor.
#[derive(Error, Debug)]
pub enum ExecutorError {
/// The executor has already been set.
#[error("Executor has already been set.")]
#[error("Global executor has already been set.")]
AlreadySet,
}
@@ -54,150 +104,143 @@ pub struct Executor;
impl Executor {
/// Spawns a thread-safe [`Future`].
/// ```rust
/// use any_spawner::Executor;
/// # if false {
/// // spawn a thread-safe Future
/// Executor::spawn(async { /* ... */ });
/// # }
/// ```
///
/// Uses the globally configured executor.
/// Panics if no global executor has been initialized.
#[inline(always)]
#[track_caller]
pub fn spawn(fut: impl Future<Output = ()> + Send + 'static) {
if let Some(spawner) = SPAWN.get() {
spawner(Box::pin(fut))
let pinned_fut = Box::pin(fut);
if let Some(fns) = EXECUTOR_FNS.get() {
(fns.spawn)(pinned_fut)
} else {
#[cfg(all(debug_assertions, feature = "tracing"))]
tracing::error!(
"At {}, tried to spawn a Future with Executor::spawn() before \
the Executor had been set.",
std::panic::Location::caller()
);
#[cfg(all(debug_assertions, not(feature = "tracing")))]
panic!(
"At {}, tried to spawn a Future with Executor::spawn() before \
the Executor had been set.",
std::panic::Location::caller()
);
// No global executor set.
handle_uninitialized_spawn(pinned_fut);
}
}
/// Spawns a [`Future`] that cannot be sent across threads.
/// ```rust
/// use any_spawner::Executor;
///
/// # if false {
/// // spawn a thread-safe Future
/// Executor::spawn_local(async { /* ... */ });
/// # }
/// ```
/// Uses the globally configured executor.
/// Panics if no global executor has been initialized.
#[inline(always)]
#[track_caller]
pub fn spawn_local(fut: impl Future<Output = ()> + 'static) {
if let Some(spawner) = SPAWN_LOCAL.get() {
spawner(Box::pin(fut))
let pinned_fut = Box::pin(fut);
if let Some(fns) = EXECUTOR_FNS.get() {
(fns.spawn_local)(pinned_fut)
} else {
#[cfg(all(debug_assertions, feature = "tracing"))]
tracing::error!(
"At {}, tried to spawn a Future with Executor::spawn_local() \
before the Executor had been set.",
std::panic::Location::caller()
);
#[cfg(all(debug_assertions, not(feature = "tracing")))]
panic!(
"At {}, tried to spawn a Future with Executor::spawn_local() \
before the Executor had been set.",
std::panic::Location::caller()
);
// No global executor set.
handle_uninitialized_spawn_local(pinned_fut);
}
}
/// Waits until the next "tick" of the current async executor.
/// Respects the global executor.
#[inline(always)]
pub async fn tick() {
let (tx, rx) = futures::channel::oneshot::channel();
#[cfg(not(all(feature = "wasm-bindgen", target_family = "wasm")))]
Executor::spawn(async move {
_ = tx.send(());
});
#[cfg(all(feature = "wasm-bindgen", target_family = "wasm"))]
Executor::spawn_local(async move {
_ = tx.send(());
});
_ = rx.await;
}
/// Polls the current async executor.
/// Not all async executors support polling, so this function may not do anything.
/// Polls the global async executor.
///
/// Uses the globally configured executor.
/// Does nothing if the global executor does not support polling.
#[inline(always)]
pub fn poll_local() {
if let Some(poller) = POLL_LOCAL.get() {
poller()
if let Some(fns) = EXECUTOR_FNS.get() {
(fns.poll_local)()
}
// If not initialized or doesn't support polling, do nothing gracefully.
}
}
impl Executor {
/// Globally sets the [`tokio`] runtime as the executor used to spawn tasks.
///
/// Returns `Err(_)` if an executor has already been set.
/// Returns `Err(_)` if a global executor has already been set.
///
/// Requires the `tokio` feature to be activated on this crate.
#[cfg(feature = "tokio")]
#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
pub fn init_tokio() -> Result<(), ExecutorError> {
SPAWN
.set(|fut| {
let executor_impl = ExecutorFns {
spawn: |fut| {
tokio::spawn(fut);
})
.map_err(|_| ExecutorError::AlreadySet)?;
SPAWN_LOCAL
.set(|fut| {
},
spawn_local: |fut| {
tokio::task::spawn_local(fut);
})
.map_err(|_| ExecutorError::AlreadySet)?;
Ok(())
},
// Tokio doesn't have an explicit global poll function like LocalPool::run_until_stalled
poll_local: no_op_poll,
};
EXECUTOR_FNS
.set(executor_impl)
.map_err(|_| ExecutorError::AlreadySet)
}
/// Globally sets the [`wasm-bindgen-futures`] runtime as the executor used to spawn tasks.
///
/// Returns `Err(_)` if an executor has already been set.
/// Returns `Err(_)` if a global executor has already been set.
///
/// Requires the `wasm-bindgen` feature to be activated on this crate.
#[cfg(feature = "wasm-bindgen")]
#[cfg_attr(docsrs, doc(cfg(feature = "wasm-bindgen")))]
pub fn init_wasm_bindgen() -> Result<(), ExecutorError> {
SPAWN
.set(|fut| {
let executor_impl = ExecutorFns {
// wasm-bindgen-futures only supports spawn_local
spawn: no_op_spawn,
spawn_local: |fut| {
wasm_bindgen_futures::spawn_local(fut);
})
.map_err(|_| ExecutorError::AlreadySet)?;
SPAWN_LOCAL
.set(|fut| {
wasm_bindgen_futures::spawn_local(fut);
})
.map_err(|_| ExecutorError::AlreadySet)?;
Ok(())
},
poll_local: no_op_poll,
};
EXECUTOR_FNS
.set(executor_impl)
.map_err(|_| ExecutorError::AlreadySet)
}
/// Globally sets the [`glib`] runtime as the executor used to spawn tasks.
///
/// Returns `Err(_)` if an executor has already been set.
/// Returns `Err(_)` if a global executor has already been set.
///
/// Requires the `glib` feature to be activated on this crate.
#[cfg(feature = "glib")]
#[cfg_attr(docsrs, doc(cfg(feature = "glib")))]
pub fn init_glib() -> Result<(), ExecutorError> {
SPAWN
.set(|fut| {
let executor_impl = ExecutorFns {
spawn: |fut| {
let main_context = glib::MainContext::default();
main_context.spawn(fut);
})
.map_err(|_| ExecutorError::AlreadySet)?;
SPAWN_LOCAL
.set(|fut| {
},
spawn_local: |fut| {
let main_context = glib::MainContext::default();
main_context.spawn_local(fut);
})
.map_err(|_| ExecutorError::AlreadySet)?;
Ok(())
},
// Glib needs event loop integration, explicit polling isn't the standard model here.
poll_local: no_op_poll,
};
EXECUTOR_FNS
.set(executor_impl)
.map_err(|_| ExecutorError::AlreadySet)
}
/// Globally sets the [`futures`] executor as the executor used to spawn tasks,
/// lazily creating a thread pool to spawn tasks into.
///
/// Returns `Err(_)` if an executor has already been set.
/// Returns `Err(_)` if a global executor has already been set.
///
/// Requires the `futures-executor` feature to be activated on this crate.
#[cfg(feature = "futures-executor")]
@@ -209,9 +252,11 @@ impl Executor {
};
use std::cell::RefCell;
// Keep the lazy-init ThreadPool and thread-local LocalPool for spawn_local impl
static THREAD_POOL: OnceLock<ThreadPool> = OnceLock::new();
thread_local! {
static LOCAL_POOL: RefCell<LocalPool> = RefCell::new(LocalPool::new());
// SPAWNER is derived from LOCAL_POOL, keep it for efficiency inside the closure
static SPAWNER: LocalSpawner = LOCAL_POOL.with(|pool| pool.borrow().spawner());
}
@@ -222,140 +267,248 @@ impl Executor {
})
}
SPAWN
.set(|fut| {
let executor_impl = ExecutorFns {
spawn: |fut| {
get_thread_pool()
.spawn(fut)
.expect("failed to spawn future");
})
.map_err(|_| ExecutorError::AlreadySet)?;
SPAWN_LOCAL
.set(|fut| {
.expect("failed to spawn future on ThreadPool");
},
spawn_local: |fut| {
// Use the thread_local SPAWNER derived from LOCAL_POOL
SPAWNER.with(|spawner| {
spawner.spawn_local(fut).expect("failed to spawn future");
spawner
.spawn_local(fut)
.expect("failed to spawn local future");
});
})
.map_err(|_| ExecutorError::AlreadySet)?;
POLL_LOCAL
.set(|| {
},
poll_local: || {
// Use the thread_local LOCAL_POOL
LOCAL_POOL.with(|pool| {
// Use try_borrow_mut to prevent panic during re-entrant calls
if let Ok(mut pool) = pool.try_borrow_mut() {
pool.run_until_stalled();
}
// If we couldn't borrow_mut, we're in a nested call to poll, so we don't need to do anything.
// If already borrowed, we're likely in a nested poll, so do nothing.
});
})
.map_err(|_| ExecutorError::AlreadySet)?;
Ok(())
},
};
EXECUTOR_FNS
.set(executor_impl)
.map_err(|_| ExecutorError::AlreadySet)
}
/// Globally sets the [`async_executor`] executor as the executor used to spawn tasks,
/// lazily creating a thread pool to spawn tasks into.
///
/// Returns `Err(_)` if an executor has already been set.
/// Returns `Err(_)` if a global executor has already been set.
///
/// Requires the `async-executor` feature to be activated on this crate.
#[cfg(feature = "async-executor")]
#[cfg_attr(docsrs, doc(cfg(feature = "async-executor")))]
pub fn init_async_executor() -> Result<(), ExecutorError> {
use async_executor::{Executor, LocalExecutor};
use async_executor::{Executor as AsyncExecutor, LocalExecutor};
static THREAD_POOL: OnceLock<Executor> = OnceLock::new();
// Keep the lazy-init global Executor and thread-local LocalExecutor for spawn_local impl
static ASYNC_EXECUTOR: OnceLock<AsyncExecutor<'static>> =
OnceLock::new();
thread_local! {
static LOCAL_POOL: LocalExecutor<'static> = const { LocalExecutor::new() };
static LOCAL_EXECUTOR_POOL: LocalExecutor<'static> = const { LocalExecutor::new() };
}
fn get_thread_pool() -> &'static Executor<'static> {
THREAD_POOL.get_or_init(Executor::new)
fn get_async_executor() -> &'static AsyncExecutor<'static> {
ASYNC_EXECUTOR.get_or_init(AsyncExecutor::new)
}
SPAWN
.set(|fut| {
get_thread_pool().spawn(fut).detach();
})
.map_err(|_| ExecutorError::AlreadySet)?;
SPAWN_LOCAL
.set(|fut| {
LOCAL_POOL.with(|pool| pool.spawn(fut).detach());
})
.map_err(|_| ExecutorError::AlreadySet)?;
POLL_LOCAL
.set(|| {
LOCAL_POOL.with(|pool| pool.try_tick());
})
.map_err(|_| ExecutorError::AlreadySet)?;
Ok(())
let executor_impl = ExecutorFns {
spawn: |fut| {
get_async_executor().spawn(fut).detach();
},
spawn_local: |fut| {
LOCAL_EXECUTOR_POOL.with(|pool| pool.spawn(fut).detach());
},
poll_local: || {
LOCAL_EXECUTOR_POOL.with(|pool| {
// try_tick polls the local executor without blocking
// This prevents issues if called recursively or from within a task.
pool.try_tick();
});
},
};
EXECUTOR_FNS
.set(executor_impl)
.map_err(|_| ExecutorError::AlreadySet)
}
/// Globally sets a custom executor as the executor used to spawn tasks.
///
/// Returns `Err(_)` if an executor has already been set.
/// Requires the custom executor to be `Send + Sync` as it will be stored statically.
///
/// Returns `Err(_)` if a global executor has already been set.
pub fn init_custom_executor(
custom_executor: impl CustomExecutor + Send + Sync + 'static,
) -> Result<(), ExecutorError> {
static EXECUTOR: OnceLock<Box<dyn CustomExecutor + Send + Sync>> =
OnceLock::new();
EXECUTOR
// Store the custom executor instance itself to call its methods.
// Use Box for dynamic dispatch.
static CUSTOM_EXECUTOR_INSTANCE: OnceLock<
Box<dyn CustomExecutor + Send + Sync>,
> = OnceLock::new();
CUSTOM_EXECUTOR_INSTANCE
.set(Box::new(custom_executor))
.map_err(|_| ExecutorError::AlreadySet)?;
SPAWN
.set(|fut| {
EXECUTOR.get().unwrap().spawn(fut);
})
.map_err(|_| ExecutorError::AlreadySet)?;
SPAWN_LOCAL
.set(|fut| EXECUTOR.get().unwrap().spawn_local(fut))
.map_err(|_| ExecutorError::AlreadySet)?;
POLL_LOCAL
.set(|| EXECUTOR.get().unwrap().poll_local())
.map_err(|_| ExecutorError::AlreadySet)?;
Ok(())
// Now set the ExecutorFns using the stored instance
let executor_impl = ExecutorFns {
spawn: |fut| {
// Unwrap is safe because we just set it successfully or returned Err.
CUSTOM_EXECUTOR_INSTANCE.get().unwrap().spawn(fut);
},
spawn_local: |fut| {
CUSTOM_EXECUTOR_INSTANCE.get().unwrap().spawn_local(fut);
},
poll_local: || {
CUSTOM_EXECUTOR_INSTANCE.get().unwrap().poll_local();
},
};
EXECUTOR_FNS
.set(executor_impl)
.map_err(|_| ExecutorError::AlreadySet)
// If setting EXECUTOR_FNS fails (extremely unlikely race if called *concurrently*
// with another init_* after CUSTOM_EXECUTOR_INSTANCE was set), we technically
// leave CUSTOM_EXECUTOR_INSTANCE set but EXECUTOR_FNS not. This is an edge case,
// but the primary race condition is solved.
}
/// Locally sets a custom executor as the executor used to spawn tasks
/// in the current thread.
/// Sets a custom executor *for the current thread only*.
///
/// Returns `Err(_)` if an executor has already been set.
/// This overrides the global executor for calls to `spawn`, `spawn_local`, and `poll_local`
/// made *from the current thread*. It does not affect other threads or the global state.
///
/// The provided `custom_executor` must implement [`CustomExecutor`] and `'static`, but does
/// **not** need to be `Send` or `Sync`.
///
/// Returns `Err(ExecutorError::AlreadySet)` if a *local* executor has already been set
/// *for this thread*.
pub fn init_local_custom_executor(
custom_executor: impl CustomExecutor + 'static,
) -> Result<(), ExecutorError> {
// Store the custom executor instance itself to call its methods.
// Use Box for dynamic dispatch.
thread_local! {
static EXECUTOR: OnceLock<Box<dyn CustomExecutor>> = OnceLock::new();
}
EXECUTOR.with(|this| {
static CUSTOM_EXECUTOR_INSTANCE: OnceLock<
Box<dyn CustomExecutor>,
> = OnceLock::new();
};
CUSTOM_EXECUTOR_INSTANCE.with(|this| {
this.set(Box::new(custom_executor))
.map_err(|_| ExecutorError::AlreadySet)
})?;
SPAWN
.set(|fut| {
EXECUTOR.with(|this| this.get().unwrap().spawn(fut));
})
.map_err(|_| ExecutorError::AlreadySet)?;
SPAWN_LOCAL
.set(|fut| {
EXECUTOR.with(|this| this.get().unwrap().spawn_local(fut));
})
.map_err(|_| ExecutorError::AlreadySet)?;
POLL_LOCAL
.set(|| {
EXECUTOR.with(|this| this.get().unwrap().poll_local());
})
.map_err(|_| ExecutorError::AlreadySet)?;
Ok(())
// Now set the ExecutorFns using the stored instance
let executor_impl = ExecutorFns {
spawn: |fut| {
// Unwrap is safe because we just set it successfully or returned Err.
CUSTOM_EXECUTOR_INSTANCE
.with(|this| this.get().unwrap().spawn(fut));
},
spawn_local: |fut| {
CUSTOM_EXECUTOR_INSTANCE
.with(|this| this.get().unwrap().spawn_local(fut));
},
poll_local: || {
CUSTOM_EXECUTOR_INSTANCE
.with(|this| this.get().unwrap().poll_local());
},
};
EXECUTOR_FNS
.set(executor_impl)
.map_err(|_| ExecutorError::AlreadySet)
}
}
/// A trait for custom executors.
/// Custom executors can be used to integrate with any executor that supports spawning futures.
///
/// All methods can be called recursively.
///
/// If used with `init_custom_executor`, the implementation must be `Send + Sync + 'static`.
///
/// All methods can be called recursively. Implementors should be mindful of potential
/// deadlocks or excessive resource consumption if recursive calls are not handled carefully
/// (e.g., using `try_borrow_mut` or non-blocking polls within implementations).
pub trait CustomExecutor {
/// Spawns a future, usually on a thread pool.
fn spawn(&self, fut: PinnedFuture<()>);
/// Spawns a local future. May require calling `poll_local` to make progress.
fn spawn_local(&self, fut: PinnedLocalFuture<()>);
/// Polls the executor, if it supports polling.
/// Polls the executor, if it supports polling. Implementations should ideally be
/// non-blocking or use mechanisms like `try_tick` or `try_borrow_mut` to handle
/// re-entrant calls safely.
fn poll_local(&self);
}
// Ensure CustomExecutor is object-safe
#[allow(dead_code)]
fn test_object_safety(_: Box<dyn CustomExecutor + Send + Sync>) {} // Added Send + Sync constraint here for global usage
/// Handles the case where `Executor::spawn` is called without an initialized executor.
#[cold] // Less likely path
#[inline(never)]
#[track_caller]
fn handle_uninitialized_spawn(_fut: PinnedFuture<()>) {
let caller = std::panic::Location::caller();
#[cfg(all(debug_assertions, feature = "tracing"))]
{
tracing::error!(
target: "any_spawner",
spawn_caller=%caller,
"Executor::spawn called before a global executor was initialized. Task dropped."
);
// Drop the future implicitly after logging
drop(_fut);
}
#[cfg(all(debug_assertions, not(feature = "tracing")))]
{
panic!(
"At {caller}, tried to spawn a Future with Executor::spawn() \
before a global executor was initialized."
);
}
// In release builds (without tracing), call the specific no-op function.
#[cfg(not(debug_assertions))]
{
no_op_spawn(_fut);
}
}
/// Handles the case where `Executor::spawn_local` is called without an initialized executor.
#[cold] // Less likely path
#[inline(never)]
#[track_caller]
fn handle_uninitialized_spawn_local(_fut: PinnedLocalFuture<()>) {
let caller = std::panic::Location::caller();
#[cfg(all(debug_assertions, feature = "tracing"))]
{
tracing::error!(
target: "any_spawner",
spawn_caller=%caller,
"Executor::spawn_local called before a global executor was initialized. \
Task likely dropped or panicked."
);
// Fall through to panic or no-op depending on build/target
}
#[cfg(all(debug_assertions, not(feature = "tracing")))]
{
panic!(
"At {caller}, tried to spawn a Future with \
Executor::spawn_local() before a global executor was initialized."
);
}
// In release builds (without tracing), call the specific no-op function (which usually panics).
#[cfg(not(debug_assertions))]
{
no_op_spawn_local(_fut);
}
}

View File

@@ -0,0 +1,24 @@
use any_spawner::{Executor, ExecutorError};
#[test]
fn test_already_set_error() {
struct SimpleExecutor;
impl any_spawner::CustomExecutor for SimpleExecutor {
fn spawn(&self, _fut: any_spawner::PinnedFuture<()>) {}
fn spawn_local(&self, _fut: any_spawner::PinnedLocalFuture<()>) {}
fn poll_local(&self) {}
}
// First initialization should succeed
Executor::init_custom_executor(SimpleExecutor)
.expect("First initialization failed");
// Second initialization should fail with AlreadySet error
let result = Executor::init_custom_executor(SimpleExecutor);
assert!(matches!(result, Err(ExecutorError::AlreadySet)));
// First local initialization should fail
let result = Executor::init_local_custom_executor(SimpleExecutor);
assert!(matches!(result, Err(ExecutorError::AlreadySet)));
}

View File

@@ -0,0 +1,74 @@
#![cfg(feature = "async-executor")]
use std::{
future::Future,
pin::Pin,
sync::{Arc, Mutex},
};
// A simple async executor for testing
struct TestExecutor {
tasks: Mutex<Vec<Pin<Box<dyn Future<Output = ()> + Send + 'static>>>>,
}
impl TestExecutor {
fn new() -> Self {
TestExecutor {
tasks: Mutex::new(Vec::new()),
}
}
fn spawn<F>(&self, future: F)
where
F: Future<Output = ()> + Send + 'static,
{
self.tasks.lock().unwrap().push(Box::pin(future));
}
fn run_all(&self) {
// Take all tasks out to process them
let tasks = self.tasks.lock().unwrap().drain(..).collect::<Vec<_>>();
// Use a basic future executor to run each task to completion
for mut task in tasks {
// Use futures-lite's block_on to complete the future
futures::executor::block_on(async {
unsafe {
let task_mut = Pin::new_unchecked(&mut task);
let _ = std::future::Future::poll(
task_mut,
&mut std::task::Context::from_waker(
futures::task::noop_waker_ref(),
),
);
}
});
}
}
}
#[test]
fn test_async_executor() {
let executor = Arc::new(TestExecutor::new());
let executor_clone = executor.clone();
// Create a spawner function that will use our test executor
let spawner = move |future| {
executor_clone.spawn(future);
};
// Prepare test data
let counter = Arc::new(Mutex::new(0));
let counter_clone = counter.clone();
// Use the spawner to spawn a task
spawner(async move {
*counter_clone.lock().unwrap() += 1;
});
// Run all tasks
executor.run_all();
// Check if the task completed correctly
assert_eq!(*counter.lock().unwrap(), 1);
}

View File

@@ -0,0 +1,63 @@
use any_spawner::Executor;
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
};
#[test]
fn test_custom_executor() {
// Define a simple custom executor
struct TestExecutor {
spawn_called: Arc<AtomicBool>,
spawn_local_called: Arc<AtomicBool>,
poll_local_called: Arc<AtomicBool>,
}
impl any_spawner::CustomExecutor for TestExecutor {
fn spawn(&self, fut: any_spawner::PinnedFuture<()>) {
self.spawn_called.store(true, Ordering::SeqCst);
// Execute the future immediately (this works for simple test futures)
futures::executor::block_on(fut);
}
fn spawn_local(&self, fut: any_spawner::PinnedLocalFuture<()>) {
self.spawn_local_called.store(true, Ordering::SeqCst);
// Execute the future immediately
futures::executor::block_on(fut);
}
fn poll_local(&self) {
self.poll_local_called.store(true, Ordering::SeqCst);
}
}
let spawn_called = Arc::new(AtomicBool::new(false));
let spawn_local_called = Arc::new(AtomicBool::new(false));
let poll_local_called = Arc::new(AtomicBool::new(false));
let executor = TestExecutor {
spawn_called: spawn_called.clone(),
spawn_local_called: spawn_local_called.clone(),
poll_local_called: poll_local_called.clone(),
};
// Initialize with our custom executor
Executor::init_custom_executor(executor)
.expect("Failed to initialize custom executor");
// Test spawn
Executor::spawn(async {
// Simple task
});
assert!(spawn_called.load(Ordering::SeqCst));
// Test spawn_local
Executor::spawn_local(async {
// Simple local task
});
assert!(spawn_local_called.load(Ordering::SeqCst));
// Test poll_local
Executor::poll_local();
assert!(poll_local_called.load(Ordering::SeqCst));
}

View File

@@ -1,6 +1,7 @@
#[cfg(feature = "futures-executor")]
#![cfg(feature = "futures-executor")]
use any_spawner::{CustomExecutor, Executor, PinnedFuture, PinnedLocalFuture};
#[cfg(feature = "futures-executor")]
#[test]
fn can_create_custom_executor() {
use futures::{

View File

@@ -0,0 +1,28 @@
#![cfg(feature = "tokio")]
use any_spawner::Executor;
use std::{
sync::{Arc, Mutex},
time::Duration,
};
#[tokio::test]
async fn test_executor_tick() {
// Initialize the tokio executor
Executor::init_tokio().expect("Failed to initialize tokio executor");
let value = Arc::new(Mutex::new(false));
let value_clone = value.clone();
// Spawn a task that sets the value after a tick
Executor::spawn(async move {
Executor::tick().await;
*value_clone.lock().unwrap() = true;
});
// Allow some time for the task to complete
tokio::time::sleep(Duration::from_millis(50)).await;
// Check that the value was set
assert!(*value.lock().unwrap());
}

View File

@@ -0,0 +1,44 @@
#![cfg(feature = "futures-executor")]
use any_spawner::Executor;
use futures::channel::oneshot;
use std::{
sync::{Arc, Mutex},
time::Duration,
};
#[test]
fn test_futures_executor() {
// Initialize the futures executor
Executor::init_futures_executor()
.expect("Failed to initialize futures executor");
let (tx, rx) = oneshot::channel();
let result = Arc::new(Mutex::new(None));
let result_clone = result.clone();
// Spawn a task
Executor::spawn(async move {
tx.send(84).expect("Failed to send value");
});
// Spawn a task that waits for the result
Executor::spawn(async move {
match rx.await {
Ok(val) => *result_clone.lock().unwrap() = Some(val),
Err(_) => panic!("Failed to receive value"),
}
});
// Poll a few times to ensure the task completes
for _ in 0..10 {
Executor::poll_local();
std::thread::sleep(Duration::from_millis(10));
if result.lock().unwrap().is_some() {
break;
}
}
assert_eq!(*result.lock().unwrap(), Some(84));
}

View File

@@ -1,8 +1,8 @@
#[cfg(feature = "futures-executor")]
#![cfg(feature = "futures-executor")]
use any_spawner::Executor;
// All tests in this file use the same executor.
#[cfg(feature = "futures-executor")]
#[test]
fn can_spawn_local_future() {
use std::rc::Rc;
@@ -15,7 +15,6 @@ fn can_spawn_local_future() {
Executor::spawn(async {});
}
#[cfg(feature = "futures-executor")]
#[test]
fn can_make_local_progress() {
use std::sync::{

151
any_spawner/tests/glib.rs Normal file
View File

@@ -0,0 +1,151 @@
#![cfg(feature = "glib")]
use any_spawner::Executor;
use glib::{MainContext, MainLoop};
use serial_test::serial;
use std::{
cell::Cell,
future::Future,
rc::Rc,
sync::{
atomic::{AtomicBool, Ordering},
Arc, Mutex,
},
time::Duration,
};
// Helper to run a future to completion on a dedicated glib MainContext.
// Returns true if the future completed within the timeout, false otherwise.
fn run_on_glib_context<F>(fut: F)
where
F: Future<Output = ()> + Send + 'static,
{
let _ = Executor::init_glib();
let context = MainContext::default();
let main_loop = MainLoop::new(Some(&context), false);
let main_loop_clone = main_loop.clone();
Executor::spawn(async move {
fut.await;
main_loop_clone.quit();
});
main_loop.run();
}
// Helper to run a local (!Send) future on the glib context.
fn run_local_on_glib_context<F>(fut: F)
where
F: Future<Output = ()> + 'static,
{
let _ = Executor::init_glib();
let context = MainContext::default();
let main_loop = MainLoop::new(Some(&context), false);
let main_loop_clone = main_loop.clone();
Executor::spawn_local(async move {
fut.await;
main_loop_clone.quit();
});
main_loop.run();
}
// This test must run after a test that successfully initializes glib,
// or within its own process.
#[test]
#[serial]
fn test_glib_spawn() {
let success_flag = Arc::new(AtomicBool::new(false));
let flag_clone = success_flag.clone();
run_on_glib_context(async move {
// Simulate async work
futures_lite::future::yield_now().await;
flag_clone.store(true, Ordering::SeqCst);
// We need to give the spawned task time to run.
// The run_on_glib_context handles the main loop.
// We just need to ensure spawn happened correctly.
// Let's wait a tiny bit within the driving future to ensure spawn gets processed.
glib::timeout_future(Duration::from_millis(10)).await;
});
assert!(
success_flag.load(Ordering::SeqCst),
"Spawned future did not complete successfully"
);
}
// Similar conditions as test_glib_spawn regarding initialization state.
#[test]
#[serial]
fn test_glib_spawn_local() {
let success_flag = Rc::new(Cell::new(false));
let flag_clone = success_flag.clone();
run_local_on_glib_context(async move {
// Use Rc to make the future !Send
let non_send_data = Rc::new(Cell::new(10));
let data = non_send_data.get();
assert_eq!(data, 10, "Rc data should be accessible");
non_send_data.set(20); // Modify non-Send data
// Simulate async work
futures_lite::future::yield_now().await;
assert_eq!(
non_send_data.get(),
20,
"Rc data should persist modification"
);
flag_clone.set(true);
// Wait a tiny bit
glib::timeout_future(Duration::from_millis(10)).await;
});
assert!(
success_flag.get(),
"Spawned local future did not complete successfully"
);
}
// Test Executor::tick with glib backend
#[test]
#[serial]
fn test_glib_tick() {
run_on_glib_context(async {
let value = Arc::new(Mutex::new(false));
let value_clone = value.clone();
// Spawn a task that sets the value after a tick
Executor::spawn(async move {
Executor::tick().await;
*value_clone.lock().unwrap() = true;
});
// Allow some time for the task to complete
glib::timeout_future(Duration::from_millis(10)).await;
// Check that the value was set
assert!(*value.lock().unwrap());
});
}
// Test Executor::poll_local with glib backend (should be a no-op)
#[test]
#[serial]
fn test_glib_poll_local_is_no_op() {
// Ensure glib executor is initialized
let _ = Executor::init_glib();
// poll_local for glib is configured as a no-op
// Calling it should not panic or cause issues.
Executor::poll_local();
Executor::poll_local();
println!("Executor::poll_local called successfully (expected no-op).");
}

View File

@@ -0,0 +1,54 @@
use any_spawner::Executor;
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
};
#[test]
fn test_local_custom_executor() {
// Define a thread-local custom executor
struct LocalTestExecutor {
spawn_called: Arc<AtomicBool>,
spawn_local_called: Arc<AtomicBool>,
}
impl any_spawner::CustomExecutor for LocalTestExecutor {
fn spawn(&self, fut: any_spawner::PinnedFuture<()>) {
self.spawn_called.store(true, Ordering::SeqCst);
futures::executor::block_on(fut);
}
fn spawn_local(&self, fut: any_spawner::PinnedLocalFuture<()>) {
self.spawn_local_called.store(true, Ordering::SeqCst);
futures::executor::block_on(fut);
}
fn poll_local(&self) {
// No-op for this test
}
}
let local_spawn_called = Arc::new(AtomicBool::new(false));
let local_spawn_local_called = Arc::new(AtomicBool::new(false));
let local_executor = LocalTestExecutor {
spawn_called: local_spawn_called.clone(),
spawn_local_called: local_spawn_local_called.clone(),
};
// Initialize a thread-local executor
Executor::init_local_custom_executor(local_executor)
.expect("Failed to initialize local custom executor");
// Test spawn - should use the thread-local executor
Executor::spawn(async {
// Simple task
});
assert!(local_spawn_called.load(Ordering::SeqCst));
// Test spawn_local - should use the thread-local executor
Executor::spawn_local(async {
// Simple local task
});
assert!(local_spawn_local_called.load(Ordering::SeqCst));
}

View File

@@ -0,0 +1,35 @@
#![cfg(feature = "tokio")]
use any_spawner::Executor;
use futures::channel::oneshot;
use std::sync::{Arc, Mutex};
#[tokio::test]
async fn test_multiple_tasks() {
Executor::init_tokio().expect("Failed to initialize tokio executor");
let counter = Arc::new(Mutex::new(0));
let tasks = 10;
let mut handles = Vec::new();
// Spawn multiple tasks that increment the counter
for _ in 0..tasks {
let counter_clone = counter.clone();
let (tx, rx) = oneshot::channel();
Executor::spawn(async move {
*counter_clone.lock().unwrap() += 1;
tx.send(()).expect("Failed to send completion signal");
});
handles.push(rx);
}
// Wait for all tasks to complete
for handle in handles {
handle.await.expect("Task failed");
}
// Verify that all tasks incremented the counter
assert_eq!(*counter.lock().unwrap(), tasks);
}

View File

@@ -0,0 +1,20 @@
#![cfg(feature = "tokio")]
use any_spawner::Executor;
use futures::channel::oneshot;
#[tokio::test]
async fn test_tokio_executor() {
// Initialize the tokio executor
Executor::init_tokio().expect("Failed to initialize tokio executor");
let (tx, rx) = oneshot::channel();
// Spawn a task that sends a value
Executor::spawn(async move {
tx.send(42).expect("Failed to send value");
});
// Wait for the spawned task to complete
assert_eq!(rx.await.unwrap(), 42);
}

View File

@@ -0,0 +1,88 @@
#![cfg(all(feature = "wasm-bindgen", target_family = "wasm"))]
use any_spawner::Executor;
use futures::channel::oneshot;
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
};
use wasm_bindgen_test::*;
wasm_bindgen_test_configure!(run_in_browser);
#[wasm_bindgen_test]
async fn test_wasm_bindgen_spawn_local() {
// Initialize the wasm-bindgen executor
let _ = Executor::init_wasm_bindgen();
// Create a channel to verify the task completes
let (tx, rx) = oneshot::channel();
// Spawn a local task (wasm doesn't support sending futures between threads)
Executor::spawn_local(async move {
// Simulate some async work
Executor::tick().await;
tx.send(42).expect("Failed to send result");
});
// Wait for the task to complete
let result = rx.await.expect("Failed to receive result");
assert_eq!(result, 42);
}
#[wasm_bindgen_test]
async fn test_wasm_bindgen_tick() {
// Initialize the wasm-bindgen executor if not already initialized
let _ = Executor::init_wasm_bindgen();
let flag = Arc::new(AtomicBool::new(false));
let flag_clone = flag.clone();
// Spawn a task that will set the flag
Executor::spawn_local(async move {
flag_clone.store(true, Ordering::SeqCst);
});
// Wait for a tick, which should allow the spawned task to run
Executor::tick().await;
// Verify the flag was set
assert!(flag.load(Ordering::SeqCst));
}
#[wasm_bindgen_test]
async fn test_multiple_wasm_bindgen_tasks() {
// Initialize once for all tests
let _ = Executor::init_wasm_bindgen();
// Create channels for multiple tasks
let (tx1, rx1) = oneshot::channel();
let (tx2, rx2) = oneshot::channel();
// Spawn multiple tasks
Executor::spawn_local(async move {
tx1.send("task1").expect("Failed to send from task1");
});
Executor::spawn_local(async move {
tx2.send("task2").expect("Failed to send from task2");
});
// Wait for both tasks to complete
let (result1, result2) = futures::join!(rx1, rx2);
assert_eq!(result1.unwrap(), "task1");
assert_eq!(result2.unwrap(), "task2");
}
// This test verifies that spawn (not local) fails on wasm as expected
#[wasm_bindgen_test]
#[should_panic]
fn test_wasm_bindgen_spawn_errors() {
let _ = Executor::init_wasm_bindgen();
// Using should_panic to test that Executor::spawn panics in wasm
Executor::spawn(async {
// This should panic since wasm-bindgen doesn't support Send futures
});
}

View File

@@ -23,7 +23,7 @@ tokio-test = "0.4.0"
miniserde = "0.1.0"
gloo = "0.8.0"
uuid = { version = "1.0", features = ["serde", "v4", "wasm-bindgen"] }
wasm-bindgen = "0.2.0"
wasm-bindgen = "0.2.100"
lazy_static = "1.0"
log = "0.4.0"
strum = "0.24.0"

View File

@@ -1,7 +0,0 @@
[tasks.check]
alias = "check-all"
[tasks.check-all]
command = "cargo"
args = ["check-all-features"]
install_crate = "cargo-all-features"

View File

@@ -6,13 +6,15 @@ env = { LEPTOS_PROJECT_DIRECTORY = "../" }
args = ["fmt", "--", "--check", "--config-path", "${LEPTOS_PROJECT_DIRECTORY}"]
[tasks.clippy-each-feature]
dependencies = ["install-clippy"]
command = "cargo"
args = [
"clippy",
"--all-features",
"--no-deps",
"--",
"-D",
"clippy::print_stdout",
"all-features",
"clippy",
"--no-deps",
"--",
"-D",
"clippy::print_stdout",
]
install_script = '''
cargo install --git https://github.com/sabify/cargo-all-features --branch arbitrary-command-support
'''

View File

@@ -1,8 +1,4 @@
extend = [
{ path = "./check.toml" },
{ path = "./lint.toml" },
{ path = "./test.toml" },
]
extend = [{ path = "./lint.toml" }, { path = "./test.toml" }]
[env]
RUSTFLAGS = ""
@@ -12,4 +8,4 @@ LEPTOS_OUTPUT_NAME = "ci" # allows examples to check/build without cargo-leptos
RUSTFLAGS = "-D warnings"
[tasks.ci]
dependencies = ["lint", "test"]
dependencies = ["lint", "test-each-feature", "doctests"]

View File

@@ -1,7 +1,16 @@
[tasks.test]
alias = "test-all"
[tasks.test-all]
[tasks.test-each-feature]
env = { "NEXTEST_NO_TESTS" = "warn" }
command = "cargo"
args = ["test-all-features"]
install_crate = "cargo-all-features"
args = ["all-features", "nextest", "run", "--all-targets"]
install_script = '''
cargo install --git https://github.com/sabify/cargo-all-features --branch arbitrary-command-support
'''
# This can be removed once doctests is supported in nextest
# https://github.com/nextest-rs/nextest/issues/16
[tasks.doctests]
command = "cargo"
args = ["all-features", "test", "--doc"]
install_script = '''
cargo install --git https://github.com/sabify/cargo-all-features --branch arbitrary-command-support
'''

View File

@@ -0,0 +1,7 @@
[tasks.post-test]
dependencies = ["test-wasm"]
[tasks.test-wasm]
env = { CARGO_MAKE_WASM_TEST_ARGS = "--headless --chrome --features=wasm-bindgen" }
command = "cargo"
args = ["make", "wasm-pack-test"]

View File

@@ -1,6 +1,6 @@
[package]
name = "either_of"
version = "0.1.0"
version = "0.1.6"
authors = ["Greg Johnston"]
license = "MIT"
readme = "../README.md"
@@ -10,4 +10,9 @@ rust-version.workspace = true
edition.workspace = true
[dependencies]
pin-project-lite = "0.2.15"
pin-project-lite = "0.2.16"
paste = "1.0.15"
[features]
default = ["no_std"]
no_std = []

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@ edition = "2021"
crate-type = ["cdylib", "rlib"]
[dependencies]
axum = { version = "0.7.5", optional = true }
axum = { version = "0.8.1", optional = true }
console_error_panic_hook = "0.1.7"
console_log = "1.0"
gloo-utils = "0.2.0"
@@ -20,18 +20,27 @@ leptos_axum = { path = "../../integrations/axum", optional = true }
leptos_router = { path = "../../router" }
serde = { version = "1.0", features = ["derive"] }
thiserror = "1.0"
tokio = { version = "1.39", features = [ "rt-multi-thread", "macros", "time" ], optional = true }
tokio = { version = "1.39", features = [
"rt-multi-thread",
"macros",
"time",
], optional = true }
tower = { version = "0.4.13", optional = true }
tower-http = { version = "0.5.2", features = ["fs"], optional = true }
wasm-bindgen = "0.2.92"
web-sys = { version = "0.3.69", features = [ "AddEventListenerOptions", "Document", "Element", "Event", "EventListener", "EventTarget", "Performance", "Window" ], optional = true }
web-sys = { version = "0.3.69", features = [
"AddEventListenerOptions",
"Document",
"Element",
"Event",
"EventListener",
"EventTarget",
"Performance",
"Window",
], optional = true }
[features]
hydrate = [
"leptos/hydrate",
"dep:js-sys",
"dep:web-sys",
]
hydrate = ["leptos/hydrate", "dep:js-sys", "dep:web-sys"]
ssr = [
"dep:axum",
"dep:http-body-util",
@@ -56,7 +65,7 @@ panic = "abort"
[package.metadata.cargo-all-features]
denylist = ["axum", "tower", "tower-http", "tokio", "sqlx", "leptos_axum"]
skip_feature_sets = [["ssr", "hydrate"]]
skip_feature_sets = [["ssr", "hydrate"], []]
[package.metadata.leptos]
# The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name

View File

@@ -1227,4 +1227,4 @@ begin:"\\b[0-9]{4}(-[0-9][0-9]){0,2}([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?(\\.[0
;return c.pop(),c.push(i),r.contains=c,{name:"YAML",case_insensitive:!0,
aliases:["yml"],contains:l}}});const Ke=te;for(const e of Object.keys(Pe)){
const n=e.replace("grmr_","").replace("_","-");Ke.registerLanguage(n,Pe[e])}
export{Ke as default};
export{Ke as defaultMod};

View File

@@ -1,2 +0,0 @@
[toolchain]
channel = "stable" # test change

View File

@@ -13,13 +13,13 @@ mod csr {
extern "C" {
type HighlightOptions;
#[wasm_bindgen(catch, js_namespace = default, js_name = highlight)]
#[wasm_bindgen(catch, js_namespace = defaultMod, js_name = highlight)]
fn highlight_lang(
code: String,
options: Object,
) -> Result<Object, JsValue>;
#[wasm_bindgen(js_namespace = default, js_name = highlightAll)]
#[wasm_bindgen(js_namespace = defaultMod, js_name = highlightAll)]
pub fn highlight_all();
}

View File

@@ -26,8 +26,7 @@ async fn main() {
};
use axum_js_ssr::app::*;
use http_body_util::BodyExt;
use leptos::logging::log;
use leptos::prelude::*;
use leptos::{logging::log, prelude::*};
use leptos_axum::{generate_route_list, LeptosRoutes};
latency::LATENCY.get_or_init(|| [0, 4, 40, 400].iter().cycle().into());

View File

@@ -1,7 +1,3 @@
extend = [
{ path = "./lint.toml" }
]
[tasks.make-target-site-dir]
command = "mkdir"
args = ["-p", "target/site"]
@@ -24,21 +20,16 @@ clear = true
dependencies = ["check-debug", "check-release"]
[tasks.check-debug]
toolchain = "stable"
dependencies = ["cargo-all-features"]
command = "cargo"
args = ["check-all-features"]
install_crate = "cargo-all-features"
args = ["all-features", "clippy"]
[tasks.check-release]
toolchain = "stable"
dependencies = ["cargo-all-features"]
command = "cargo"
args = ["check-all-features", "--release"]
install_crate = "cargo-all-features"
[tasks.lint]
dependencies = ["make-target-site-dir", "check-style"]
args = ["all-features", "clippy", "--release"]
[tasks.start-client]
dependencies = ["install-cargo-leptos"]
command = "cargo"
args = ["leptos", "watch", "--release", "-P"]
args = ["leptos", "watch", "--release", "-P"]

View File

@@ -1,5 +1,11 @@
[tasks.cargo-all-features]
install_script = '''
cargo install --git https://github.com/sabify/cargo-all-features --branch arbitrary-command-support
'''
[tasks.install-cargo-leptos]
install_crate = { crate_name = "cargo-leptos", binary = "cargo-leptos", test_arg = "--help" }
args = ["--locked"]
[tasks.cargo-leptos-e2e]
command = "cargo"
@@ -15,16 +21,14 @@ clear = true
dependencies = ["check-debug", "check-release"]
[tasks.check-debug]
toolchain = "stable"
dependencies = ["cargo-all-features"]
command = "cargo"
args = ["check-all-features"]
install_crate = "cargo-all-features"
args = ["all-features", "clippy"]
[tasks.check-release]
toolchain = "stable"
dependencies = ["cargo-all-features"]
command = "cargo"
args = ["check-all-features", "--release"]
install_crate = "cargo-all-features"
args = ["all-features", "clippy", "--release"]
[tasks.start-client]
dependencies = ["install-cargo-leptos"]

View File

@@ -1,11 +1,9 @@
[tasks.build]
toolchain = "stable"
command = "cargo"
args = ["build-all-features"]
install_crate = "cargo-all-features"
[tasks.cargo-all-features]
install_script = '''
cargo install --git https://github.com/sabify/cargo-all-features --branch arbitrary-command-support
'''
[tasks.check]
toolchain = "stable"
[tasks.build]
dependencies = ["cargo-all-features"]
command = "cargo"
args = ["check-all-features"]
install_crate = "cargo-all-features"
args = ["all-features", "build"]

View File

@@ -1,3 +1,8 @@
[tasks.cargo-all-features]
install_script = '''
cargo install --git https://github.com/sabify/cargo-all-features --branch arbitrary-command-support
'''
[tasks.build]
install_crate = { crate_name = "wasm-pack", binary = "wasm-pack", test_arg = "--help" }
clear = true
@@ -14,13 +19,11 @@ clear = true
dependencies = ["check-debug", "check-release"]
[tasks.check-debug]
toolchain = "stable"
dependencies = ["cargo-all-features"]
command = "cargo"
args = ["check-all-features"]
install_crate = "cargo-all-features"
args = ["all-features", "clippy"]
[tasks.check-release]
toolchain = "stable"
dependencies = ["cargo-all-features"]
command = "cargo"
args = ["check-all-features", "--release"]
install_crate = "cargo-all-features"
args = ["all-features", "clippy", "--release"]

View File

@@ -1,8 +1,15 @@
[tasks.pre-clippy]
env = { CARGO_MAKE_CLIPPY_ARGS = "--no-deps --all-targets --all-features -- -D warnings" }
[tasks.cargo-all-features]
install_script = '''
cargo install --git https://github.com/sabify/cargo-all-features --branch arbitrary-command-support
'''
[tasks.check-style]
dependencies = ["check-format-flow", "clippy-flow"]
[tasks.lint]
dependencies = ["check-format-flow", "clippy-each-feature"]
[tasks.clippy-each-feature]
dependencies = ["cargo-all-features"]
command = "cargo"
args = ["all-features", "clippy", "--no-deps", "--", "-D", "warnings"]
[tasks.check-format]
env = { LEPTOS_PROJECT_DIRECTORY = "../../" }

View File

@@ -1,22 +1,19 @@
extend = [
{ path = "./compile.toml" },
{ path = "./clean.toml" },
{ path = "./lint.toml" },
{ path = "./node.toml" },
{ path = "./process.toml" },
{ path = "./compile.toml" },
{ path = "./clean.toml" },
{ path = "./lint.toml" },
{ path = "./node.toml" },
{ path = "./process.toml" },
]
# CI Stages
[tasks.ci]
dependencies = ["prepare", "lint", "build", "test-flow", "integration-test"]
dependencies = ["prepare", "lint", "test-flow", "integration-test"]
[tasks.prepare]
dependencies = ["setup-node"]
[tasks.lint]
dependencies = ["check-style"]
[tasks.integration-test]
# Support Local Runs

View File

@@ -1,22 +1,8 @@
extend = [
{ path = "../cargo-make/playwright.toml" },
{ path = "../cargo-make/trunk_server.toml" },
{ path = "../cargo-make/playwright.toml" },
{ path = "../cargo-make/trunk_server.toml" },
]
[tasks.integration-test]
dependencies = ["build", "start-client", "test-playwright"]
description = "Run integration test with automated start and stop of processes"
env = { SPAWN_CLIENT_PROCESS = "1" }
run_task = { name = ["start", "wait-test-stop"], parallel = true }
[tasks.wait-test-stop]
private = true
dependencies = ["wait-server", "test-playwright", "stop"]
[tasks.wait-server]
script = '''
for run in {1..12}; do
echo "Waiting to ensure server is started..."
sleep 10
done
echo "Times up, running tests"
'''

View File

@@ -6,5 +6,6 @@ command = "trunk"
args = ["build"]
[tasks.start-client]
command = "trunk"
args = ["serve", "${@}"]
script = '''
trunk serve -q "${@}" &
'''

View File

@@ -1,7 +1,3 @@
[tasks.test]
env = { RUN_CARGO_TEST = false }
condition = { env_true = ["RUN_CARGO_TEST"] }
[tasks.post-test]
dependencies = ["test-wasm"]

View File

@@ -1,8 +1,9 @@
<!DOCTYPE html>
<!doctype html>
<html>
<head>
<link data-trunk rel="rust" data-wasm-opt="z"/>
<link data-trunk rel="icon" type="image/ico" href="/public/favicon.ico"/>
</head>
<body></body>
</html>
<head>
<link data-trunk rel="rust" data-wasm-opt="z" />
<link data-trunk rel="icon" type="image/ico" href="/public/favicon.ico" />
</head>
<body></body>
</html>

View File

@@ -1,2 +1,2 @@
[toolchain]
channel = "stable" # test change
targets = ["wasm32-unknown-unknown"]

View File

@@ -1,9 +1,7 @@
#![allow(dead_code)]
use counter::*;
use leptos::mount::mount_to;
use leptos::prelude::*;
use leptos::task::tick;
use leptos::{mount::mount_to, prelude::*, task::tick};
use wasm_bindgen::JsCast;
use wasm_bindgen_test::*;

View File

@@ -44,7 +44,7 @@ ssr = [
[package.metadata.cargo-all-features]
denylist = ["actix-files", "actix-web", "leptos_actix"]
skip_feature_sets = [["ssr", "hydrate"]]
skip_feature_sets = [["ssr", "hydrate"], []]
[package.metadata.leptos]
# The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name

View File

@@ -1,2 +1,2 @@
[toolchain]
channel = "stable" # test change
targets = ["wasm32-unknown-unknown"]

View File

@@ -1,17 +1,15 @@
extend = [
{ path = "../cargo-make/main.toml" },
{ path = "../cargo-make/wasm-test.toml" },
{ path = "../cargo-make/trunk_server.toml" },
{ path = "../cargo-make/main.toml" },
{ path = "../cargo-make/wasm-test.toml" },
{ path = "../cargo-make/trunk_server.toml" },
]
[tasks.build]
toolchain = "stable"
dependencies = ["cargo-all-features"]
command = "cargo"
args = ["build-all-features"]
install_crate = "cargo-all-features"
args = ["all-features", "build"]
[tasks.check]
toolchain = "stable"
dependencies = ["cargo-all-features"]
command = "cargo"
args = ["check-all-features"]
install_crate = "cargo-all-features"
args = ["all-features", "clippy"]

View File

@@ -1,2 +1,2 @@
[toolchain]
channel = "stable" # test change
targets = ["wasm32-unknown-unknown"]

View File

@@ -5,8 +5,7 @@ use wasm_bindgen_test::*;
wasm_bindgen_test_configure!(run_in_browser);
use counters::Counters;
use leptos::prelude::*;
use leptos::task::tick;
use leptos::{prelude::*, task::tick};
use web_sys::HtmlElement;
#[wasm_bindgen_test]
@@ -24,8 +23,9 @@ async fn inc() {
assert_eq!(
div.inner_html(),
"<button>Add Counter</button><button>Add 1000 \
Counters</button><button>Clear Counters</button><p>Total: \
<span data-testid=\"total\">0</span> from <span data-testid=\"counters\">0</span> counters.</p><ul><!----></ul>"
Counters</button><button>Clear Counters</button><p>Total: <span \
data-testid=\"total\">0</span> from <span \
data-testid=\"counters\">0</span> counters.</p><ul><!----></ul>"
);
// add 3 counters
@@ -39,8 +39,9 @@ async fn inc() {
assert_eq!(
div.inner_html(),
"<button>Add Counter</button><button>Add 1000 \
Counters</button><button>Clear Counters</button><p>Total: \
<span data-testid=\"total\">0</span> from <span data-testid=\"counters\">3</span> \
Counters</button><button>Clear Counters</button><p>Total: <span \
data-testid=\"total\">0</span> from <span \
data-testid=\"counters\">3</span> \
counters.</p><ul><li><button>-1</button><input \
type=\"text\"><span>0</span><button>+1</button><button>x</button></\
li><li><button>-1</button><input \
@@ -81,8 +82,9 @@ async fn inc() {
assert_eq!(
div.inner_html(),
"<button>Add Counter</button><button>Add 1000 \
Counters</button><button>Clear Counters</button><p>Total: \
<span data-testid=\"total\">6</span> from <span data-testid=\"counters\">3</span> \
Counters</button><button>Clear Counters</button><p>Total: <span \
data-testid=\"total\">6</span> from <span \
data-testid=\"counters\">3</span> \
counters.</p><ul><li><button>-1</button><input \
type=\"text\"><span>1</span><button>+1</button><button>x</button></\
li><li><button>-1</button><input \
@@ -106,8 +108,9 @@ async fn inc() {
assert_eq!(
div.inner_html(),
"<button>Add Counter</button><button>Add 1000 \
Counters</button><button>Clear Counters</button><p>Total: \
<span data-testid=\"total\">5</span> from <span data-testid=\"counters\">2</span> \
Counters</button><button>Clear Counters</button><p>Total: <span \
data-testid=\"total\">5</span> from <span \
data-testid=\"counters\">2</span> \
counters.</p><ul><li><button>-1</button><input \
type=\"text\"><span>2</span><button>+1</button><button>x</button></\
li><li><button>-1</button><input \

View File

@@ -1,2 +1,2 @@
[toolchain]
channel = "stable" # test change
targets = ["wasm32-unknown-unknown"]

View File

@@ -1,2 +1,2 @@
[toolchain]
channel = "stable" # test change
targets = ["wasm32-unknown-unknown"]

View File

@@ -13,7 +13,7 @@ leptos_axum = { path = "../../integrations/axum", optional = true }
leptos_meta = { path = "../../meta" }
leptos_router = { path = "../../router" }
serde = { version = "1.0", features = ["derive"] }
axum = { version = "0.7.5", optional = true }
axum = { version = "0.8.1", optional = true }
tower = { version = "0.4.13", optional = true }
tower-http = { version = "0.5.2", features = ["fs"], optional = true }
tokio = { version = "1.39", features = ["full"], optional = true }
@@ -36,7 +36,7 @@ ssr = [
[package.metadata.cargo-all-features]
denylist = ["axum", "tower", "tower-http", "tokio", "leptos_axum"]
skip_feature_sets = [["ssr", "hydrate"]]
skip_feature_sets = [["ssr", "hydrate"], []]
[package.metadata.leptos]
# The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name

View File

@@ -1,2 +1,2 @@
[toolchain]
channel = "stable" # test change
targets = ["wasm32-unknown-unknown"]

View File

@@ -45,7 +45,7 @@ async fn main() {
// build our application with a route
let app = Router::new()
.route("/special/:id", get(custom_handler))
.route("/special/{id}", get(custom_handler))
.leptos_routes(&leptos_options, routes, {
let leptos_options = leptos_options.clone();
move || shell(leptos_options.clone())

View File

@@ -1,2 +1,2 @@
[toolchain]
channel = "stable" # test change
targets = ["wasm32-unknown-unknown"]

View File

@@ -1,5 +1,4 @@
use leptos::prelude::*;
use leptos::tachys::html::style::style;
use serde::{Deserialize, Serialize};
use thiserror::Error;
@@ -16,7 +15,7 @@ pub enum CatError {
type CatCount = usize;
async fn fetch_cats(count: CatCount) -> Result<Vec<String>> {
async fn fetch_cats(count: CatCount) -> Result<Vec<String>, Error> {
if count > 0 {
gloo_timers::future::TimeoutFuture::new(1000).await;
// make the request
@@ -42,11 +41,7 @@ async fn fetch_cats(count: CatCount) -> Result<Vec<String>> {
pub fn fetch_example() -> impl IntoView {
let (cat_count, set_cat_count) = signal::<CatCount>(1);
// we use new_unsync here because the reqwasm request type isn't Send
// if we were doing SSR, then
// 1) we'd want to use a Resource, so the data would be serialized to the client
// 2) we'd need to make sure there was a thread-local spawner set up
let cats = AsyncDerived::new_unsync(move || fetch_cats(cat_count.get()));
let cats = LocalResource::new(move || fetch_cats(cat_count.get()));
let fallback = move |errors: ArcRwSignal<Errors>| {
let error_list = move || {
@@ -66,8 +61,6 @@ pub fn fetch_example() -> impl IntoView {
}
};
let spreadable = style(("background-color", "AliceBlue"));
view! {
<div>
<label>
@@ -82,7 +75,7 @@ pub fn fetch_example() -> impl IntoView {
/>
</label>
<Transition fallback=|| view! { <div>"Loading..."</div> } {..spreadable}>
<Transition fallback=|| view! { <div>"Loading..."</div> }>
<ErrorBoundary fallback>
<ul>
{move || Suspend::new(async move {
@@ -92,7 +85,7 @@ pub fn fetch_example() -> impl IntoView {
.map(|s| {
view! {
<li>
<img src=s.clone()/>
<img src=s.clone() />
</li>
}
})

View File

@@ -43,7 +43,7 @@ codegen-units = 1
[package.metadata.cargo-all-features]
denylist = ["actix-files", "actix-web", "leptos_actix"]
skip_feature_sets = [["csr", "ssr"], ["csr", "hydrate"], ["ssr", "hydrate"]]
skip_feature_sets = [["csr", "ssr"], ["csr", "hydrate"], ["ssr", "hydrate"], []]
[package.metadata.leptos]
# The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name

View File

@@ -1,2 +1,2 @@
[toolchain]
channel = "stable" # test change
targets = ["wasm32-unknown-unknown"]

View File

@@ -1,5 +1,4 @@
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
pub fn story(path: &str) -> String {
format!("https://node-hnapi.herokuapp.com/{path}")

View File

@@ -1,9 +1,7 @@
use crate::api;
use leptos::either::Either;
use leptos::prelude::*;
use leptos::{either::Either, prelude::*};
use leptos_meta::Meta;
use leptos_router::components::A;
use leptos_router::hooks::use_params_map;
use leptos_router::{components::A, hooks::use_params_map};
#[component]
pub fn Story() -> impl IntoView {

View File

@@ -1,6 +1,5 @@
use crate::api::{self, User};
use leptos::server::Resource;
use leptos::{either::Either, prelude::*};
use leptos::{either::Either, prelude::*, server::Resource};
use leptos_router::hooks::use_params_map;
#[component]

View File

@@ -20,7 +20,7 @@ serde = { version = "1.0", features = ["derive"] }
tracing = "0.1.40"
gloo-net = { version = "0.6.0", features = ["http"] }
reqwest = { version = "0.12.5", features = ["json"] }
axum = { version = "0.7.5", optional = true }
axum = { version = "0.8.1", optional = true }
tower = { version = "0.4.13", optional = true }
tower-http = { version = "0.5.2", features = ["fs"], optional = true }
tokio = { version = "1.39", features = ["full"], optional = true }
@@ -47,7 +47,7 @@ ssr = [
[package.metadata.cargo-all-features]
denylist = ["axum", "tower", "tower-http", "tokio", "http", "leptos_axum"]
skip_feature_sets = [["csr", "ssr"], ["csr", "hydrate"], ["ssr", "hydrate"]]
skip_feature_sets = [["csr", "ssr"], ["csr", "hydrate"], ["ssr", "hydrate"], []]
[package.metadata.leptos]
# The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name

View File

@@ -1,2 +1,2 @@
[toolchain]
channel = "stable" # test change
targets = ["wasm32-unknown-unknown"]

View File

@@ -1,6 +1,5 @@
use leptos::logging;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
pub fn story(path: &str) -> String {
format!("https://node-hnapi.herokuapp.com/{path}")

View File

@@ -1,7 +1,7 @@
#[cfg(feature = "ssr")]
#[tokio::main]
async fn main() {
use axum::Router;
use axum::{routing::get, Router};
use hackernews_axum::{shell, App};
use leptos::config::get_configuration;
use leptos_axum::{generate_route_list, LeptosRoutes};
@@ -13,6 +13,15 @@ async fn main() {
// build our application with a route
let app = Router::new()
.route(
"/favicon.ico",
get(|| async {
(
[("content-type", "image/x-icon")],
include_bytes!("../public/favicon.ico"),
)
}),
)
.leptos_routes(&leptos_options, routes, {
let leptos_options = leptos_options.clone();
move || shell(leptos_options.clone())

View File

@@ -1,9 +1,7 @@
use crate::api;
use leptos::either::Either;
use leptos::prelude::*;
use leptos::{either::Either, prelude::*};
use leptos_meta::Meta;
use leptos_router::components::A;
use leptos_router::hooks::use_params_map;
use leptos_router::{components::A, hooks::use_params_map};
#[component]
pub fn Story() -> impl IntoView {

View File

@@ -1,6 +1,5 @@
use crate::api::{self, User};
use leptos::server::Resource;
use leptos::{either::Either, prelude::*};
use leptos::{either::Either, prelude::*, server::Resource};
use leptos_router::hooks::use_params_map;
#[component]

View File

@@ -20,7 +20,7 @@ serde = { version = "1.0", features = ["derive"] }
tracing = "0.1.40"
gloo-net = { version = "0.6.0", features = ["http"] }
reqwest = { version = "0.12.5", features = ["json"] }
axum = { version = "0.7.5", optional = true, features = ["http2"] }
axum = { version = "0.8.1", optional = true, features = ["http2"] }
tower = { version = "0.4.13", optional = true }
tower-http = { version = "0.5.2", features = [
"fs",
@@ -57,7 +57,8 @@ ssr = [
[package.metadata.cargo-all-features]
denylist = ["axum", "tower", "tower-http", "tokio", "http", "leptos_axum"]
skip_feature_sets = [["csr", "ssr"], ["csr", "hydrate"], ["ssr", "hydrate"]]
skip_feature_sets = [["csr", "ssr"], ["csr", "hydrate"], ["ssr", "hydrate"], []]
max_combination_size = 2
[package.metadata.leptos]
# The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name

View File

@@ -1,8 +1,16 @@
extend = [
{ path = "../cargo-make/main.toml" },
{ path = "../cargo-make/cargo-leptos-compress.toml" },
{ path = "../cargo-make/main.toml" },
{ path = "../cargo-make/cargo-leptos-compress.toml" },
]
[tasks.ci]
dependencies = [
"prepare",
"make-target-site-dir",
"lint",
"test-flow",
"integration-test",
]
[env]
CLIENT_PROCESS_NAME = "hackernews_islands"

View File

@@ -1,2 +1,2 @@
[toolchain]
channel = "stable" # test change
targets = ["wasm32-unknown-unknown"]

View File

@@ -3,6 +3,7 @@ use axum::{
http::{header, Request, Response, StatusCode, Uri},
response::{IntoResponse, Response as AxumResponse},
};
use rust_embed::Embed;
use std::borrow::Cow;
#[cfg(not(debug_assertions))]
@@ -11,7 +12,7 @@ const DEV_MODE: bool = false;
#[cfg(debug_assertions)]
const DEV_MODE: bool = true;
#[derive(rust_embed::RustEmbed)]
#[derive(Embed)]
#[folder = "target/site/"]
struct Assets;

View File

@@ -1,6 +1,7 @@
#[cfg(feature = "ssr")]
#[tokio::main]
async fn main() {
use axum::routing::get;
pub use axum::Router;
use hackernews_islands::*;
pub use leptos::config::get_configuration;
@@ -25,6 +26,7 @@ async fn main() {
// build our application with a route
let app = Router::new()
.route("/favicon.ico", get(fallback::file_and_error_handler))
.leptos_routes(&leptos_options, routes, {
let leptos_options = leptos_options.clone();
move || shell(leptos_options.clone())

View File

@@ -1,9 +1,7 @@
use crate::api;
use leptos::either::Either;
use leptos::prelude::*;
use leptos::{either::Either, prelude::*};
use leptos_meta::Meta;
use leptos_router::components::A;
use leptos_router::hooks::use_params_map;
use leptos_router::{components::A, hooks::use_params_map};
#[server]
pub async fn fetch_story(

View File

@@ -1,6 +1,5 @@
use crate::api;
use leptos::server::Resource;
use leptos::{either::Either, prelude::*};
use leptos::{either::Either, prelude::*, server::Resource};
use leptos_router::hooks::use_params_map;
#[server]

View File

@@ -23,7 +23,7 @@ serde = { version = "1.0", features = ["derive"] }
tracing = "0.1.40"
gloo-net = { version = "0.6.0", features = ["http"] }
reqwest = { version = "0.12.5", features = ["json"] }
axum = { version = "0.7.5", default-features = false, optional = true }
axum = { version = "0.8.1", default-features = false, optional = true }
tower = { version = "0.4.13", optional = true }
http = { version = "1.1", optional = true }
web-sys = { version = "0.3.70", features = [
@@ -57,7 +57,7 @@ ssr = [
[package.metadata.cargo-all-features]
denylist = ["axum", "tower", "http", "leptos_axum"]
skip_feature_sets = [["csr", "ssr"], ["csr", "hydrate"], ["ssr", "hydrate"]]
skip_feature_sets = [["csr", "ssr"], ["csr", "hydrate"], ["ssr", "hydrate"], []]
[package.metadata.leptos]
# The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name

View File

@@ -1,2 +1,2 @@
[toolchain]
channel = "stable" # test change
targets = ["wasm32-unknown-unknown"]

View File

@@ -10,15 +10,12 @@ crate-type = ["cdylib", "rlib"]
console_error_panic_hook = "0.1.7"
futures = "0.3.30"
http = "1.1"
leptos = { path = "../../leptos", features = [
"tracing",
"islands",
] }
leptos = { path = "../../leptos", features = ["tracing", "islands"] }
server_fn = { path = "../../server_fn", features = ["serde-lite"] }
leptos_axum = { path = "../../integrations/axum", optional = true }
log = "0.4.22"
serde = { version = "1.0", features = ["derive"] }
axum = { version = "0.7.5", optional = true }
axum = { version = "0.8.1", optional = true }
tower = { version = "0.4.13", optional = true }
tower-http = { version = "0.5.2", features = ["fs"], optional = true }
tokio = { version = "1.39", features = ["full"], optional = true }
@@ -44,7 +41,7 @@ panic = "abort"
[package.metadata.cargo-all-features]
denylist = ["axum", "tower", "tower-http", "tokio", "sqlx", "leptos_axum"]
skip_feature_sets = [["csr", "ssr"], ["csr", "hydrate"], ["ssr", "hydrate"]]
skip_feature_sets = [["csr", "ssr"], ["csr", "hydrate"], ["ssr", "hydrate"], []]
[package.metadata.leptos]
# The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name

View File

@@ -1,2 +1,2 @@
[toolchain]
channel = "stable" # test change
targets = ["wasm32-unknown-unknown"]

View File

@@ -10,22 +10,20 @@ crate-type = ["cdylib", "rlib"]
console_error_panic_hook = "0.1.7"
futures = "0.3.30"
http = "1.1"
leptos = { path = "../../leptos", features = [
"tracing",
"islands",
] }
leptos = { path = "../../leptos", features = ["tracing", "islands"] }
leptos_router = { path = "../../router" }
server_fn = { path = "../../server_fn", features = ["serde-lite"] }
leptos_axum = { path = "../../integrations/axum", features = [
"dont-use-islands-router",
"islands-router",
], optional = true }
log = "0.4.22"
serde = { version = "1.0", features = ["derive"] }
axum = { version = "0.7.5", optional = true }
axum = { version = "0.8.1", optional = true }
tower = { version = "0.4.13", optional = true }
tower-http = { version = "0.5.2", features = ["fs"], optional = true }
tokio = { version = "1.39", features = ["full"], optional = true }
wasm-bindgen = "0.2.93"
wasm-bindgen = "0.2.100"
serde_json = "1.0.133"
[features]
hydrate = ["leptos/hydrate"]
@@ -47,7 +45,7 @@ panic = "abort"
[package.metadata.cargo-all-features]
denylist = ["axum", "tower", "tower-http", "tokio", "sqlx", "leptos_axum"]
skip_feature_sets = [["csr", "ssr"], ["csr", "hydrate"], ["ssr", "hydrate"]]
skip_feature_sets = [["csr", "ssr"], ["csr", "hydrate"], ["ssr", "hydrate"], []]
[package.metadata.leptos]
# The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name
@@ -58,11 +56,11 @@ site-root = "target/site"
# Defaults to pkg
site-pkg-dir = "pkg"
# [Optional] The source CSS file. If it ends with .sass or .scss then it will be compiled by dart-sass into CSS. The CSS is optimized by Lightning CSS before being written to <site-root>/<site-pkg>/app.css
style-file = "./style.css"
style-file = "style.css"
# [Optional] Files in the asset-dir will be copied to the site-root directory
assets-dir = "public"
# The IP and port (ex: 127.0.0.1:3000) where the server serves the content. Use it in your server setup.
site-addr = "127.0.0.1:3000"
site-addr = "127.0.0.1:3009"
# The port to use for automatic reload monitoring
reload-port = 3001
# The browserlist query used for optimizing the CSS.

File diff suppressed because it is too large Load Diff

View File

@@ -1,140 +0,0 @@
window.addEventListener("click", async (ev) => {
// confirm that this is an <a> that meets our requirements
if (
ev.defaultPrevented ||
ev.button !== 0 ||
ev.metaKey ||
ev.altKey ||
ev.ctrlKey ||
ev.shiftKey
)
return;
/** @type HTMLAnchorElement | undefined;*/
const a = ev
.composedPath()
.find(el => el instanceof Node && el.nodeName.toUpperCase() === "A");
if (!a) return;
const svg = a.namespaceURI === "http://www.w3.org/2000/svg";
const href = svg ? a.href.baseVal : a.href;
const target = svg ? a.target.baseVal : a.target;
if (target || (!href && !a.hasAttribute("state"))) return;
const rel = (a.getAttribute("rel") || "").split(/\s+/);
if (a.hasAttribute("download") || (rel && rel.includes("external"))) return;
const url = svg ? new URL(href, document.baseURI) : new URL(href);
if (
url.origin !== window.location.origin // ||
// TODO base
//(basePath && url.pathname && !url.pathname.toLowerCase().startsWith(basePath.toLowerCase()))
)
return;
ev.preventDefault();
// fetch the new page
const resp = await fetch(url);
const htmlString = await resp.text();
// Use DOMParser to parse the HTML string
const parser = new DOMParser();
// TODO parse from the request stream instead?
const doc = parser.parseFromString(htmlString, 'text/html');
// The 'doc' variable now contains the parsed DOM
const transition = async () => {
const oldDocWalker = document.createTreeWalker(document);
const newDocWalker = doc.createTreeWalker(doc);
let oldNode = oldDocWalker.currentNode;
let newNode = newDocWalker.currentNode;
while(oldDocWalker.nextNode() && newDocWalker.nextNode()) {
oldNode = oldDocWalker.currentNode;
newNode = newDocWalker.currentNode;
// if the nodes are different, we need to replace the old with the new
// because of the typed view tree, this should never actually happen
if (oldNode.nodeType !== newNode.nodeType) {
oldNode.replaceWith(newNode);
}
// if it's a text node, just update the text with the new text
else if (oldNode.nodeType === Node.TEXT_NODE) {
oldNode.textContent = newNode.textContent;
}
// if it's an element, replace if it's a different tag, or update attributes
else if (oldNode.nodeType === Node.ELEMENT_NODE) {
/** @type Element */
const oldEl = oldNode;
/** @type Element */
const newEl = newNode;
if (oldEl.tagName !== newEl.tagName) {
oldEl.replaceWith(newEl);
}
else {
for(const attr of newEl.attributes) {
oldEl.setAttribute(attr.name, attr.value);
}
}
}
// we use comment "branch marker" nodes to distinguish between different branches in the statically-typed view tree
// if one of these marker is hit, then there are two options
// 1) it's the same branch, and we just keep walking until the end
// 2) it's a different branch, in which case the old can be replaced with the new wholesale
else if (oldNode.nodeType === Node.COMMENT_NODE) {
const oldText = oldNode.textContent;
const newText = newNode.textContent;
if(oldText.startsWith("bo") && newText !== oldText) {
oldDocWalker.nextNode();
newDocWalker.nextNode();
const oldRange = new Range();
const newRange = new Range();
let oldBranches = 1;
let newBranches = 1;
while(oldBranches > 0 && newBranches > 0) {
if(oldDocWalker.nextNode() && newDocWalker.nextNode()) {
console.log(oldDocWalker.currentNode, newDocWalker.currentNode);
if(oldDocWalker.currentNode.nodeType === Node.COMMENT_NODE) {
if(oldDocWalker.currentNode.textContent.startsWith("bo")) {
oldBranches += 1;
} else if(oldDocWalker.currentNode.textContent.startsWith("bc")) {
oldBranches -= 1;
}
}
if(newDocWalker.currentNode.nodeType === Node.COMMENT_NODE) {
if(newDocWalker.currentNode.textContent.startsWith("bo")) {
newBranches += 1;
} else if(newDocWalker.currentNode.textContent.startsWith("bc")) {
newBranches -= 1;
}
}
}
}
try {
oldRange.setStartAfter(oldNode);
oldRange.setEndBefore(oldDocWalker.currentNode);
newRange.setStartAfter(newNode);
newRange.setEndBefore(newDocWalker.currentNode);
const newContents = newRange.extractContents();
oldRange.deleteContents();
oldRange.insertNode(newContents);
oldNode.replaceWith(newNode);
oldDocWalker.currentNode.replaceWith(newDocWalker.currentNode);
} catch (e) {
console.error(e);
}
} }
}
};
// Not all browsers support startViewTransition; see https://caniuse.com/?search=startViewTransition
if (document.startViewTransition) {
await document.startViewTransition(transition);
} else {
await transition()
}
window.history.pushState(undefined, null, url);
});

View File

@@ -1,2 +1,2 @@
[toolchain]
channel = "stable" # test change
targets = ["wasm32-unknown-unknown"]

View File

@@ -1,8 +1,13 @@
use leptos::prelude::*;
use leptos_router::{
components::{FlatRoutes, Route, Router},
StaticSegment,
use leptos::{
either::{Either, EitherOf3},
prelude::*,
};
use leptos_router::{
components::{Route, Router, Routes},
hooks::{use_params_map, use_query_map},
path,
};
use serde::{Deserialize, Serialize};
pub fn shell(options: LeptosOptions) -> impl IntoView {
view! {
@@ -12,7 +17,7 @@ pub fn shell(options: LeptosOptions) -> impl IntoView {
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<AutoReload options=options.clone()/>
<HydrationScripts options=options islands=true/>
<HydrationScripts options=options islands=true islands_router=true/>
<link rel="stylesheet" id="leptos" href="/pkg/islands.css"/>
<link rel="shortcut icon" type="image/ico" href="/favicon.ico"/>
</head>
@@ -26,34 +31,180 @@ pub fn shell(options: LeptosOptions) -> impl IntoView {
#[component]
pub fn App() -> impl IntoView {
view! {
<script src="/routing.js"></script>
<Router>
<header>
<h1>"My Application"</h1>
<h1>"My Contacts"</h1>
</header>
<nav>
<a href="/">"Page A"</a>
<a href="/b">"Page B"</a>
<a href="/">"Home"</a>
<a href="/about">"About"</a>
</nav>
<main>
<p>
<label>"Home Checkbox" <input type="checkbox"/></label>
</p>
<FlatRoutes fallback=|| "Not found.">
<Route path=StaticSegment("") view=PageA/>
<Route path=StaticSegment("b") view=PageB/>
</FlatRoutes>
<Routes fallback=|| "Not found.">
<Route path=path!("") view=Home/>
<Route path=path!("user/:id") view=Details/>
<Route path=path!("about") view=About/>
</Routes>
</main>
</Router>
}
}
#[component]
pub fn PageA() -> impl IntoView {
view! { <label>"Page A" <input type="checkbox"/></label> }
#[server]
pub async fn search(query: String) -> Result<Vec<User>, ServerFnError> {
let users = tokio::fs::read_to_string("./mock_data.json").await?;
let data: Vec<User> = serde_json::from_str(&users)?;
let query = query.to_ascii_lowercase();
Ok(data
.into_iter()
.filter(|user| {
user.first_name.to_ascii_lowercase().contains(&query)
|| user.last_name.to_ascii_lowercase().contains(&query)
|| user.email.to_ascii_lowercase().contains(&query)
})
.collect())
}
#[server]
pub async fn delete_user(id: u32) -> Result<(), ServerFnError> {
let users = tokio::fs::read_to_string("./mock_data.json").await?;
let mut data: Vec<User> = serde_json::from_str(&users)?;
data.retain(|user| user.id != id);
let new_json = serde_json::to_string(&data)?;
tokio::fs::write("./mock_data.json", &new_json).await?;
Ok(())
}
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct User {
id: u32,
first_name: String,
last_name: String,
email: String,
}
#[component]
pub fn PageB() -> impl IntoView {
view! { <label>"Page B" <input type="checkbox"/></label> }
pub fn Home() -> impl IntoView {
let q = use_query_map();
let q = move || q.read().get("q");
let data = Resource::new(q, |q| async move {
if let Some(q) = q {
search(q).await
} else {
Ok(vec![])
}
});
let delete_user_action = ServerAction::<DeleteUser>::new();
let view = move || {
Suspend::new(async move {
let users = data.await.unwrap();
if q().is_none() {
EitherOf3::A(view! {
<p class="note">"Enter a search to begin viewing contacts."</p>
})
} else if users.is_empty() {
EitherOf3::B(view! {
<p class="note">"No users found matching that search."</p>
})
} else {
EitherOf3::C(view! {
<table>
<tbody>
<For
each=move || users.clone()
key=|user| user.id
let:user
>
<tr>
<td>{user.first_name}</td>
<td>{user.last_name}</td>
<td>{user.email}</td>
<td>
<a href=format!("/user/{}", user.id)>"Details"</a>
<input type="checkbox"/>
<ActionForm action=delete_user_action>
<input type="hidden" name="id" value=user.id/>
<input type="submit" value="Delete"/>
</ActionForm>
</td>
</tr>
</For>
</tbody>
</table>
})
}
})
};
view! {
<section class="page">
<form method="GET" class="search">
<input type="search" name="q" value=q autofocus oninput="this.form.requestSubmit()"/>
<input type="submit"/>
</form>
<Suspense fallback=|| view! { <p>"Loading..."</p> }>{view}</Suspense>
</section>
}
}
#[component]
pub fn Details() -> impl IntoView {
#[server]
pub async fn get_user(id: u32) -> Result<Option<User>, ServerFnError> {
let users = tokio::fs::read_to_string("./mock_data.json").await?;
let data: Vec<User> = serde_json::from_str(&users)?;
Ok(data.iter().find(|user| user.id == id).cloned())
}
let params = use_params_map();
let id = move || {
params
.read()
.get("id")
.and_then(|id| id.parse::<u32>().ok())
};
let user = Resource::new(id, |id| async move {
match id {
None => Ok(None),
Some(id) => get_user(id).await,
}
});
move || {
Suspend::new(async move {
user.await.map(|user| match user {
None => Either::Left(view! {
<section class="page">
<h2>"Not found."</h2>
<p>"Sorry — we couldnt find that user."</p>
</section>
}),
Some(user) => Either::Right(view! {
<section class="page">
<h2>{user.first_name} " " { user.last_name}</h2>
<p class="email">{user.email}</p>
</section>
}),
})
})
}
}
#[component]
pub fn About() -> impl IntoView {
view! {
<section class="page">
<h2>"About"</h2>
<p>"This demo is intended to show off an experimental “islands router” feature, which mimics the smooth transitions and user experience of client-side routing while minimizing the amount of code that actually runs in the browser."</p>
<p>"By default, all the content in this application is only rendered on the server. But you can add client-side interactivity via islands like this one:"</p>
<Counter/>
</section>
}
}
#[island]
pub fn Counter() -> impl IntoView {
let count = RwSignal::new(0);
view! {
<button class="counter" on:click=move |_| *count.write() += 1>{count}</button>
}
}

View File

@@ -1,3 +1,52 @@
.pending {
color: purple;
body {
font-family: system-ui, sans-serif;
background-color: #f6f6fa;
}
h1, h2, h3, h4, h5, h6 {
font-family: ui-rounded, 'Hiragino Maru Gothic ProN', Quicksand, Comfortaa, Manjari, 'Arial Rounded MT', 'Arial Rounded MT Bold', Calibri, source-sans-pro, sans-serif;
text-align: center;
}
nav {
padding: 1rem;
text-align: center;
}
nav a {
margin: 1rem;
}
form.search {
display: flex;
margin: 2rem auto;
justify-content: center;
}
td {
min-width: 10rem;
width: 10rem;
}
table {
min-width: 100%;
}
.page {
width: 80%;
margin: auto;
}
td:last-child > * {
display: inline-block;
}
.note, .note {
text-align: center;
}
button.counter {
display: block;
font-size: 2rem;
margin: auto;
}

View File

@@ -1,20 +1,19 @@
extend = [
{ path = "../cargo-make/main.toml" },
{ path = "../cargo-make/wasm-test.toml" },
{ path = "../cargo-make/trunk_server.toml" },
{ path = "../cargo-make/main.toml" },
{ path = "../cargo-make/wasm-test.toml" },
{ path = "../cargo-make/trunk_server.toml" },
]
[tasks.build]
toolchain = "stable"
[tasks.clippy-each-feature]
dependencies = ["cargo-all-features"]
command = "cargo"
args = ["build-all-features", "--target", "wasm32-unknown-unknown"]
install_crate = "cargo-all-features"
[tasks.check]
toolchain = "stable"
command = "cargo"
args = ["check-all-features", "--target", "wasm32-unknown-unknown"]
install_crate = "cargo-all-features"
[tasks.pre-clippy]
env = { CARGO_MAKE_CLIPPY_ARGS = "--all-targets --all-features --target wasm32-unknown-unknown -- -D warnings" }
args = [
"all-features",
"clippy",
"--target",
"wasm32-unknown-unknown",
"--no-deps",
"--",
"-D",
"warnings",
]

View File

@@ -1,2 +0,0 @@
[toolchain]
channel = "stable"

View File

@@ -149,12 +149,12 @@ pub fn App() -> impl IntoView {
</div>
<div class="col-md-6">
<div class="row">
<Button id="run" text="Create 1,000 rows" on:click=run/>
<Button id="runlots" text="Create 10,000 rows" on:click=run_lots/>
<Button id="add" text="Append 1,000 rows" on:click=add/>
<Button id="update" text="Update every 10th row" on:click=update/>
<Button id="clear" text="Clear" on:click=clear/>
<Button id="swaprows" text="Swap Rows" on:click=swap_rows/>
<Button id="run" text="Create 1,000 rows" on:click=run />
<Button id="runlots" text="Create 10,000 rows" on:click=run_lots />
<Button id="add" text="Append 1,000 rows" on:click=add />
<Button id="update" text="Update every 10th row" on:click=update />
<Button id="clear" text="Clear" on:click=clear />
<Button id="swaprows" text="Swap Rows" on:click=swap_rows />
</div>
</div>
</div>
@@ -169,7 +169,7 @@ pub fn App() -> impl IntoView {
let label = row.label;
let is_selected = is_selected.clone();
template! {
< tr class : danger = { move || is_selected.selected(Some(row_id)) }
< tr class : danger = { move || is_selected.selected(&Some(row_id)) }
> < td class = "col-md-1" > { row_id.to_string() } </ td > < td
class = "col-md-4" >< a on : click = move | _ | set_selected
.set(Some(row_id)) > { move || label.get() } </ a ></ td > < td

Some files were not shown because too many files have changed in this diff Show More