Compare commits

...

1973 Commits

Author SHA1 Message Date
Greg Johnston
3d733b54b1 missed one 2025-02-13 14:39:19 -05:00
Greg Johnston
8284f303d5 pause AsyncDerived (resources) as well 2025-02-13 14:22:14 -05:00
Greg Johnston
1dab980b02 fix: don't re-run memos if the effects that read them are paused 2025-02-13 14:22:14 -05:00
autofix-ci[bot]
4612125e5e [autofix.ci] apply automated fixes 2025-02-13 01:06:28 +00:00
Greg Johnston
53853ab105 feat: allow pausing and resuming effects 2025-02-12 19:56:11 -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
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
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
Greg Johnston
c6de7c714e fix: emit syntax errors in components rather than swallowing them (closes #3535) (#3538) 2025-02-01 15:29:40 -05:00
Greg Johnston
6154199850 fix: attribute type erasure nightly (closes #3536) (#3537) 2025-02-01 11:32:32 -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
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
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
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
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
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
Greg Johnston
14eb707e82 rc2 2024-11-22 15:27:00 -05:00
Greg Johnston
3de0414ed5 docs: adds more helpful text for hydration errors (closes #3267) (#3275) 2024-11-22 15:10:37 -05:00
Greg Johnston
75cae91661 chore: expose some internals of routing to make wrappers easier (#3232) 2024-11-22 15:10:23 -05:00
Greg Johnston
8b258b0d26 fix: notify Suspense on subsequent reloads (closes #3277) (#3278) 2024-11-22 14:55:24 -05:00
dependabot[bot]
84bdd6b568 chore(deps): bump serde_json from 1.0.132 to 1.0.133 (#3261)
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.132 to 1.0.133.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.132...v1.0.133)

---
updated-dependencies:
- dependency-name: serde_json
  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-21 19:24:47 -05:00
dependabot[bot]
809023a2ad chore(deps): bump attribute-derive from 0.10.2 to 0.10.3 (#3260)
Bumps [attribute-derive](https://github.com/ModProg/attribute-derive) from 0.10.2 to 0.10.3.
- [Release notes](https://github.com/ModProg/attribute-derive/releases)
- [Changelog](https://github.com/ModProg/attribute-derive/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ModProg/attribute-derive/commits)

---
updated-dependencies:
- dependency-name: attribute-derive
  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-21 19:24:39 -05:00
dependabot[bot]
1477ae2cfb chore(deps): bump axum from 0.7.8 to 0.7.9 (#3259)
Bumps [axum](https://github.com/tokio-rs/axum) from 0.7.8 to 0.7.9.
- [Release notes](https://github.com/tokio-rs/axum/releases)
- [Changelog](https://github.com/tokio-rs/axum/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tokio-rs/axum/compare/axum-v0.7.8...axum-v0.7.9)

---
updated-dependencies:
- dependency-name: axum
  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-21 19:24:31 -05:00
dependabot[bot]
26995f8efd chore(deps): bump tower-http from 0.6.1 to 0.6.2 (#3266)
Bumps [tower-http](https://github.com/tower-rs/tower-http) from 0.6.1 to 0.6.2.
- [Release notes](https://github.com/tower-rs/tower-http/releases)
- [Commits](https://github.com/tower-rs/tower-http/compare/tower-http-0.6.1...tower-http-0.6.2)

---
updated-dependencies:
- dependency-name: tower-http
  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-21 19:24:23 -05:00
dependabot[bot]
3c174b26a5 chore(deps): bump syn from 2.0.87 to 2.0.89 (#3272)
Bumps [syn](https://github.com/dtolnay/syn) from 2.0.87 to 2.0.89.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/2.0.87...2.0.89)

---
updated-dependencies:
- dependency-name: syn
  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-21 19:24:13 -05:00
dependabot[bot]
0c7e77800a chore(deps): bump proc-macro2 from 1.0.89 to 1.0.91 (#3273)
Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.89 to 1.0.91.
- [Release notes](https://github.com/dtolnay/proc-macro2/releases)
- [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.89...1.0.91)

---
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-21 19:24:04 -05:00
Greg Johnston
fee2421047 chore: fix broken links, etc. in docs (#3269) 2024-11-21 19:23:55 -05:00
Ari Seyhun
89f26f6e9b feat: add fallback prop to ProtectedRoute and ProtectedParentRoute (#3264) 2024-11-19 22:32:45 -08:00
Silver
e76b22bec8 Remove unused shell() function definition (#3254) 2024-11-19 12:17:45 -08:00
Greg Johnston
cff277b3db fix: add Write implementatations for Field<T> and ArcField<T> (closes #3257) (#3262) 2024-11-19 10:04:40 -05:00
Ari Seyhun
0258ac6df4 feat(reactive_stores): add map_untracked to OptionStoreExt (#3245) 2024-11-18 09:41:04 -05:00
Greg Johnston
36132a5823 Merge pull request #3249 from metatoaster/pr3213_e2e_tests
test: aria-current end-to-end tests (#3213)
2024-11-17 15:50:13 -05:00
autofix-ci[bot]
6f35f8d197 [autofix.ci] apply automated fixes 2024-11-17 01:51:40 +00:00
Tommy Yu
3973c4f420 test: aria-current end-to-end tests (#3213) 2024-11-17 14:40:47 +13:00
benwis
7f2237b91e Remove hash.txt from tracking, update dependencies in tests 2024-11-16 11:19:11 -08:00
Tommy Yu
aa6cd08387 test: fixtures for testing aria-current (#3202) 2024-11-16 11:11:54 -08:00
dependabot[bot]
15fc7dd7be chore(deps): bump thiserror from 2.0.0 to 2.0.3 (#3231)
Bumps [thiserror](https://github.com/dtolnay/thiserror) from 2.0.0 to 2.0.3.
- [Release notes](https://github.com/dtolnay/thiserror/releases)
- [Commits](https://github.com/dtolnay/thiserror/compare/2.0.0...2.0.3)

---
updated-dependencies:
- dependency-name: thiserror
  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-16 11:07:00 -08:00
dependabot[bot]
eac979e309 chore(deps): bump serde from 1.0.214 to 1.0.215 (#3236)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.214 to 1.0.215.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.214...v1.0.215)

---
updated-dependencies:
- dependency-name: serde
  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-16 11:06:49 -08:00
dependabot[bot]
f7ac7be32b chore(deps): bump glib from 0.20.5 to 0.20.6 (#3237)
Bumps [glib](https://github.com/gtk-rs/gtk-rs-core) from 0.20.5 to 0.20.6.
- [Release notes](https://github.com/gtk-rs/gtk-rs-core/releases)
- [Changelog](https://github.com/gtk-rs/gtk-rs-core/blob/main/CHANGELOG.md)
- [Commits](https://github.com/gtk-rs/gtk-rs-core/compare/0.20.5...0.20.6)

---
updated-dependencies:
- dependency-name: glib
  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-16 11:06:39 -08:00
dependabot[bot]
2462a1dc92 chore(deps): bump axum from 0.7.7 to 0.7.8 (#3246)
Bumps [axum](https://github.com/tokio-rs/axum) from 0.7.7 to 0.7.8.
- [Release notes](https://github.com/tokio-rs/axum/releases)
- [Changelog](https://github.com/tokio-rs/axum/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tokio-rs/axum/compare/axum-v0.7.7...axum-v0.7.8)

---
updated-dependencies:
- dependency-name: axum
  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-16 11:06:30 -08:00
Greg Johnston
2c6d790cdb change: rename from experimental-islands to islands (#3247)
* change: rename from `experimental-islands` to `islands`

* update examples
2024-11-16 11:06:18 -08:00
Kalin Staykov
1c26261fd7 fix: migration syntax and insert query (#2597) 2024-11-13 09:37:19 -08:00
Saber Haj Rabiee
c2b239dba2 fix: run autofix.ci on pull requests only (#3238) 2024-11-12 14:16:34 -08:00
Saber Haj Rabiee
d4044cd5a1 feat: add autofix.ci to address formatting issues and possible clippy fixes (#3235)
* feat: add `autofix.ci` to address formatting issues and possible clippy
fixes

* fix: initial run of `autofix.ci` script to prevent PR pollution at first
run

* fix: typo and indent issue in `autofix.yml`

* fix: run `autofix.ci` over members with no features
2024-11-12 10:54:14 -08:00
Greg Johnston
43912f4fd0 chore: fmt 2024-11-12 09:05:36 -05:00
Greg Johnston
a5293f0b79 chore: add missing docs for 0.7 (#3203) 2024-11-11 19:58:38 -05:00
Niklas Eicker
998eefb8c5 chore: add tests for converting path segments into paths (#3229) 2024-11-10 20:04:04 -05:00
Greg Johnston
63f3508818 fix: don't generate additional / for empty static segments in static routes (closes #3224, #3226) (#3228) 2024-11-10 20:03:03 -05:00
Niklas Eicker
24308bb0eb feat: support browsers without startViewTransition (#3227) 2024-11-10 16:34:12 -05:00
Paul Hansen
f804a69f2f chore: fix deprecated parameters js warning (#3219) 2024-11-10 14:52:10 -05:00
dependabot[bot]
b596af45f0 chore(deps): bump tempfile from 3.13.0 to 3.14.0 (#3212)
Bumps [tempfile](https://github.com/Stebalien/tempfile) from 3.13.0 to 3.14.0.
- [Changelog](https://github.com/Stebalien/tempfile/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stebalien/tempfile/compare/v3.13.0...v3.14.0)

---
updated-dependencies:
- dependency-name: tempfile
  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-11-10 14:51:44 -05:00
Greg Johnston
5206755124 chore: add docs for stores (#3216) 2024-11-10 14:51:25 -05:00
Greg Johnston
53a55a1ef2 fix: support all ___: attributes on components (#3218) 2024-11-10 14:51:11 -05:00
Niklas Eicker
0f74332d38 chore: remove obsolete build_static_routes (#3223) 2024-11-10 14:51:00 -05:00
Greg Johnston
bb0dff6af5 fix: support complex punctuated attribute keys in attr: syntax (closes #3221) (#3214) 2024-11-08 17:01:27 -05:00
Greg Johnston
d204ac6d5e fix: ensure that aria-current is set correctly (closes #3196) (#3213) 2024-11-08 16:19:03 -05:00
Greg Johnston
b0ad85e624 chore: clarify GTK example status in README (closes #3215) 2024-11-08 16:18:51 -05:00
Greg Johnston
0eebe9e289 fix: only register async work with transition if it isn't already done (closes #3197) (#3209) 2024-11-08 09:04:52 -05:00
Greg Johnston
2abbdb6594 fix: complete navigation after rendering fallback (closes #3199) (#3208) 2024-11-08 09:04:40 -05:00
dependabot[bot]
8f8f3e23e4 chore(deps): bump tokio from 1.41.0 to 1.41.1 (#3207)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.41.0 to 1.41.1.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.41.0...tokio-1.41.1)

---
updated-dependencies:
- dependency-name: tokio
  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-07 19:16:59 -05:00
Saber Haj Rabiee
aab952357e Dependabot, Attemp #2 (#3204)
* fix: remove examples and benchmarks from dependabot search path

* chore: update/upgrade deps to prevent dependabot PR pollution at first
run

* fix: increase number of pull requests from dependabot as the workspace
is pretty big

* fix: revert rkyv version as it was unexpectedly downgraded

* fix: tower in example
2024-11-07 10:55:57 -08:00
Saber Haj Rabiee
f1ebf77fa6 fix: make free space for ci workflows before running them (#3206) 2024-11-07 10:55:42 -08:00
Darwin Boersma
5cc2f3858d Add futures-executor feature for any_spawner (#3195)
Signed-off-by: Darwin Boersma <darwin@sadlark.com>
2024-11-05 10:11:34 -08:00
Tommy Yu
8252655959 Updated tests for #3182 (#3194)
* fix: ensure we check memos the first time a dependency uses them, even if the dependency always runs on its first run (closes #3181)

* Correct expected counter values down due to #3182

- As #3182 fixed the issue where superfluous resource fetches happened
  when hydration happened inside a nested component, the expected values
  for the counters are down to where they actually are supposed to be.

---------

Co-authored-by: Greg Johnston <greg.johnston@gmail.com>
2024-11-04 18:12:54 -08:00
Saber Haj Rabiee
14e47e87ba chore: add Cargo.lock (closes #2881) (#3192) 2024-11-04 16:21:35 -05:00
Greg Johnston
4a8cfad7c5 chore(ci): suppress warnings about unused code in example tests (#3193) 2024-11-04 13:08:50 -05:00
Louis Dispa
d9f52dad76 feat: implement rendering traits for fixed-size arrays (#3174) 2024-11-04 12:26:43 -05:00
Greg Johnston
3a8508df6c rc1 2024-11-03 20:19:57 -05:00
Daniëlle Huisman
865c6df483 wasm-bindgen 0.2.95 (#3186) 2024-11-03 20:19:21 -05:00
Greg Johnston
c1d7f0f8d1 fix: exclude excluded server fn paths instead of unregistering them (closes #3150, #3175) (#3176) 2024-11-03 20:02:11 -05:00
zakstucke
8c2dd73b70 chore: expose internals of SerializedDataId and SsrSharedContext to allow creating custom hydration contexts (#3145) 2024-11-03 19:55:59 -05:00
Greg Johnston
d5894555cc fix: allow !Send errors in Actix extract() (#3189) 2024-11-03 19:53:24 -05:00
Enzo Nocera
2ef1723607 Makes the wasm32-wasip1/2 target a first-class citizen for Leptos's Server-Side (#3063)
* feat: WIP wasi integrations crate

Signed-off-by: Enzo "raskyld" Nocera <enzo@nocera.eu>

* feat(server_fn): add generic types

This commit adds `From` implementations for the
`Req` and `Res` types using abstraction that are deemed
"platform-agnostic".

Indeed, both the `http` and `bytes` crates contains types
that allows us to represent HTTP Request and Response,
while being capable to target unconventional platforms
(they even have `no-std` support). This allows the
server_fn functions to target new platforms,
for example, the `wasm32-wasip*` targets.

Signed-off-by: Enzo "raskyld" Nocera <enzo@nocera.eu>

* chore(server_fn): generic types cleanup

Signed-off-by: Enzo "raskyld" Nocera <enzo@nocera.eu>

* feat(integrations/wasi): make WASI a first-class citizen of leptos server-side

Signed-off-by: Enzo "raskyld" Nocera <enzo@nocera.eu>

* WIP: chore(any_spawner): make the futures::Executor runable

Signed-off-by: Enzo "raskyld" Nocera <enzo@nocera.eu>

* fix(server_fn): include `generic` in axum.

Signed-off-by: Enzo "raskyld" Nocera <enzo@nocera.eu>

* chore(any_spawner): some clippy suggestions

I ran clippy in really annoying mode since I am still
learning Rust and I want to write clean idiomatic code.
I took suggestions that I thought made sense, if any
maintainers think those are *too much*, I can relax
those changes:

* Use `core` instead of `std` to ease migration to `no_std`
  (https://rust-lang.github.io/rust-clippy/master/index.html#/std_instead_of_core)
* Add documentation on exported types and statics
* Bring some types in, with `use`
* Add `#[non_exhaustive]` on types we are not sure we
  won't extend (https://rust-lang.github.io/rust-clippy/master/index.html#exhaustive_enums)
* Add `#[inline]` to help the compiler when doing
  cross-crate compilation and Link-Time optimization
  is not enabled. (https://rust-lang.github.io/rust-clippy/master/index.html#/missing_inline_in_public_items)
* Use generic types instead of anonymous `impl` params
  so callers can use the `::<>` turbofish syntax (https://rust-lang.github.io/rust-clippy/master/index.html#/impl_trait_in_params)

Signed-off-by: Enzo "raskyld" Nocera <enzo@nocera.eu>

* chore(leptos_wasi): fine-tune linter and clean-up

Signed-off-by: Enzo "raskyld" Nocera <enzo@nocera.eu>

* feat(leptos_wasi): better handling of server fn with form

Signed-off-by: Enzo "raskyld" Nocera <enzo@nocera.eu>

* chore: cargo fmt

Signed-off-by: Enzo "raskyld" Nocera <enzo@nocera.eu>

* chore: remove custom clippy

Remove clippy crate rules since it
seems to make tests fails in tests.

Signed-off-by: Enzo "raskyld" Nocera <enzo@nocera.eu>

* chore: use `wasi` crate

Signed-off-by: Enzo "raskyld" Nocera <enzo@nocera.eu>

* chore: revert changes to any_spawner

Signed-off-by: Enzo "raskyld" Nocera <enzo@nocera.eu>

* chore: simpler crate features + cleanup

Signed-off-by: Enzo "raskyld" Nocera <enzo@nocera.eu>

* feat(any_spawner): add local custom executor

This commit adds a single-thread "local"
custom executor, which is useful for environments
like `wasm32` targets.

Signed-off-by: Enzo "raskyld" Nocera <enzo@nocera.eu>

* feat(leptos_wasi): async runtime

This commit adds a single-threaded
async runtime for `wasm32-wasip*`
targets.

Signed-off-by: Enzo "raskyld" Nocera <enzo@nocera.eu>

* feat(leptos_wasi): error handling

This commit adds error types for the users
to implement better error handling.

Signed-off-by: Enzo "raskyld" Nocera <enzo@nocera.eu>

* chore: migrate integration off-tree

Signed-off-by: Enzo "raskyld" Nocera <enzo@nocera.eu>

* chore(ci): fix formatting

Signed-off-by: Enzo "raskyld" Nocera <enzo@nocera.eu>

* chore: remove ref to leptos_wasi in Cargo.toml

Signed-off-by: Enzo "raskyld" Nocera <enzo@nocera.eu>

* chore(ci): fix fmt

Signed-off-by: Enzo "raskyld" Nocera <enzo@nocera.eu>

* chore(ci): remove explicit into_inter()

Signed-off-by: Enzo "raskyld" Nocera <enzo@nocera.eu>

* chore(ci): make generic mutually exclusive with other options

Signed-off-by: Enzo "raskyld" Nocera <enzo@nocera.eu>

---------

Signed-off-by: Enzo "raskyld" Nocera <enzo@nocera.eu>
2024-11-02 09:44:50 -07:00
Greg Johnston
13f7387d45 fix: Oco equality check (closes #3178) (#3180) 2024-11-01 14:55:49 -04:00
Greg Johnston
0a13f7c08c chore: reexport unescape (closes #3177) (#3179) 2024-11-01 14:55:37 -04:00
Greg Johnston
7c83904aea Merge pull request #3173 from leptos-rs/store-tweaks
Store tweaks
2024-10-30 20:33:10 -04:00
Greg Johnston
6e13ff9787 feat: impl Into<Field<T>> for Store<T> (closes #3102) 2024-10-28 20:28:09 -04:00
Greg Johnston
234d138f03 chore: remove log 2024-10-28 20:17:23 -04:00
Greg Johnston
97110cd5ac chore: remove Then 2024-10-28 20:17:23 -04:00
Greg Johnston
5acc1b1a5a chore: rename .iter() to .iter_unkeyed() for clarity 2024-10-28 20:16:54 -04:00
Nicolas Cura
f3987246cb docs: remove duplicated "calls" word (#3171) 2024-10-28 20:04:33 -04:00
Greg Johnston
e5149fb348 fix: correctly track inner subfields on Field (closes #3169) (#3170) 2024-10-28 20:04:16 -04:00
Greg Johnston
d67ff03568 chore: fix leptos_dom reexports (closes #3166) (#3168) 2024-10-27 21:12:41 -04:00
Greg Johnston
1dbca3005d Merge pull request #3163 from leptos-rs/undep-mp
chores
2024-10-25 17:47:14 -04:00
Greg Johnston
af61be0c72 fix: correctly reset classes when using Option<T> (#3164) 2024-10-25 17:47:00 -04:00
Johannes Heuel
76facf9539 feat: improve tailwind config to also catch dynamic classes (#3143) 2024-10-25 14:06:19 -04:00
Tommy Yu
0e73d18d7b ci: regression tests for double suspense/double resource fetch (#3103)
* test: first cut of the instrumented suspense_tests

- Based on initial concepts developed for reproducing #2937 and others,
  streamlined and instrumented for e2e testing and refined for inclusion
  as a standalone module to be plugged into some other App.

* First cut of the fixtures and tests

* Actually make it work properly

- Instead of using examples, just feed it the table because examples
  will rerun the whole scenario from scratch, which isn't what we are
  trying to test here.
- Provide a basic example with item listing to show how this will work.

* Use ticketing system to disambiguate CSR calls

- Keep all SSR calls on ticket 0 as a means to disambiguate them from
  CSR calls.  For the mean time the focus of tests isn't on that
  behavior but this may be modified when suitable.

* Update the baseline fixtures

- Given the new understanding, the scenerios all being the baseline
  tests they are now moved into one file.
- Have the checks against all calls at once for better diff output,
  and reword the new scenerios into more idomatic gherkin.
- Streamline the steps and provide additional ones that will help with
  feature definitions.

* Translate the reproduction steps into Gherkin

* Comment out logging to avoid output interference.

* Be able to reset CSR counters everywhere

- Done by providing a button directly on the top level component with
  the navigation footer.  This will be useful for the next test.

* Test showing difference between hydrate and CSR

- Specifically, under hydrated load, resources that shouldn't need
  refetching gets refetched, while CSR does not show this issue.
2024-10-25 14:05:42 -04:00
Greg Johnston
d306a15f86 fix: avoid deadlocking if can't take Memo write lock (closes #3158) (#3160) 2024-10-25 13:57:44 -04:00
Greg Johnston
bf95648dc9 chore: clippy doc comment length 2024-10-25 13:56:02 -04:00
Greg Johnston
00edfc0e0a chore: undeprecate MaybeProp 2024-10-25 13:49:19 -04:00
zakstucke
396327b667 feat: Option<T> read-like traits & deprecate MaybeSignal (#3098) 2024-10-25 13:41:26 -04:00
zakstucke
a437289f81 feat: impl IntoStyle for Option<impl IntoStyle & Oco (#3119) 2024-10-25 13:31:07 -04:00
zakstucke
58e7897db6 fix: From<> impls between ArcLocalResource and LocalResource (#3144) 2024-10-25 13:30:18 -04:00
Greg Johnston
1be1f41fba fix: restore array syntax for setting multiple classes dynamically (closes #3151) (#3152) 2024-10-23 20:10:04 -04:00
Greg Johnston
7b8cd90a6e 0.7.0-rc0 2024-10-21 21:16:20 -04:00
Greg Johnston
d0ef7b904d feat: add OptionalParamSegment (closes #2896) (#3140) 2024-10-21 21:15:14 -04:00
Greg Johnston
7904e0c395 fix: unregister server functions whose paths are in excluded routes (closes #2735) (#3138) 2024-10-21 09:14:36 -04:00
Greg Johnston
7b4c470155 perf: type erasure in router (#3107) 2024-10-20 20:07:14 -04:00
Greg Johnston
98eccc9eb8 perf: make LeptosOptions lighter-weight to clone (closes #3036) (#3136) 2024-10-20 20:05:29 -04:00
Greg Johnston
70d06e2716 feat: Action::clear() to clear action value (closes #2364) (#3135) 2024-10-20 16:29:05 -04:00
PenguinWithATie
67c3bf2478 chore: add tachys::view::fragment::Fragment to prelude (#3125) 2024-10-20 14:15:15 -04:00
Corvus
f3aaae857a feat: allow axum to serve precompressed files (#3133) 2024-10-19 20:47:35 -04:00
Greg Johnston
d727e53dd6 chore(ci): reduce tachys feature set combinations (#3131) 2024-10-19 20:45:49 -04:00
zakstucke
e4543ab5df feat: new nostrip: prop prefix to pass Option<T> directly when prop(optional) (#3105) 2024-10-19 15:41:51 -04:00
Greg Johnston
1ca0f4430c feat: use View Transition API for router animations (#3112) 2024-10-19 15:41:20 -04:00
Joaquim Pedro França Simão
b59fa11853 feat: add two-way data binding support for stores (#3115) 2024-10-19 15:39:45 -04:00
Greg Johnston
e55f08e017 feat: expose use_matched() (closes #3124) (#3126) 2024-10-18 16:12:41 -04:00
zakstucke
fa1939e5b2 chore: From<ArcResource> for ArcResource and AsyncDerived (#3121) 2024-10-18 16:12:11 -04:00
zakstucke
8b2f0eaf44 fix: do not warn when reading resources in effect outside Suspense (#3118) 2024-10-18 15:24:09 -04:00
Chris
b118d69281 fix: remove unused Params attribute params (#3123)
See 1966 for original PR on older version
2024-10-18 15:20:45 -04:00
stefnotch
ee66f6c395 Add support for user-supplied executors (#3091) 2024-10-16 06:24:07 -07:00
Greg Johnston
eba08ad592 fix: don't render empty string as a space in unescaped elements (closes #3120) (#3122) 2024-10-15 18:57:09 -04:00
Greg Johnston
4833b4e287 fix: avoid double-polling synchronously-available Suspend (closes #3113) (#3114) 2024-10-15 08:49:40 -04:00
Greg Johnston
9d1be64e4d chore: publish stores (#3110) 2024-10-14 10:18:38 -04:00
benwis
d6e6cd3be0 v0.7.0gamma3 2024-10-14 05:01:19 -07:00
stefnotch
70476f9277 feat: add support for async-executor from smol-rs (#3090) 2024-10-14 07:57:19 -04:00
zakstucke
d8ddfc26e9 perf: use the Track trait for the Signal wrapper. (#3076) 2024-10-12 20:29:03 -04:00
stefnotch
c8acc3e8bd fix: correctly support local pools for futures-executor (#3089) 2024-10-12 20:13:50 -04:00
zakstucke
547442243b impl IntoClass for Option<impl IntoClass> (#3104) 2024-10-12 05:03:53 -07:00
Greg Johnston
6e58266f54 feat: support set_is_routing/RoutingProgress for nested routes (#3101) 2024-10-11 19:05:33 -04:00
Greg Johnston
f0cd0fb41d feat: condense Router/Routes base prop into one (#3100) 2024-10-11 14:06:11 -04:00
Daniil Polyakov
7585faf57e fix: use full path to Result in Params derive (#3096) 2024-10-10 15:20:38 -04:00
zakstucke
da7f6a34e8 chore: expose AnyView in prelude (#3099) 2024-10-10 15:20:24 -04:00
Greg Johnston
4f7fa41262 fix: don't on WASM server targets unless you actually try to generate static routes (closes #3094) (#3097) 2024-10-10 15:20:04 -04:00
Greg Johnston
4becfa39ca correct version number 2024-10-10 09:13:39 -04:00
Greg Johnston
f8388b122d fix: avoid reentering lock when initializing nested keyed store fields (closes #3086) (#3087) 2024-10-10 08:53:28 -04:00
Greg Johnston
f57a57b92b feat: restore AnimatedShow for 0.7 (#3084) 2024-10-10 08:53:05 -04:00
vsuryamurthy
f0bcbd9cfe remove unused dependencies leptos_axum and leptos_router (#2960)
* remove unused dependencies leptos_axum and leptos_router

* cargo fmt

* Restore http::Uri under default feature

* use axum re-exported headers instead of http directly

---------

Co-authored-by: Greg Johnston <greg.johnston@gmail.com>
2024-10-10 04:29:11 -07:00
Greg Johnston
115477ef1d chore: remove unused code from leptos package (#3085) 2024-10-10 04:23:37 -07:00
Greg Johnston
832b9cb321 chore: pin wasm-bindgen to 0.2.93 to fix example builds (#3088) 2024-10-09 22:56:05 -04:00
Greg Johnston
b0150ceeec fix: missing Copy/Clone implementations for OnceResource (#3080) 2024-10-09 19:33:33 -04:00
dependabot[bot]
af8df34360 chore(deps): bump denoland/setup-deno from 1 to 2 (#3081)
Bumps [denoland/setup-deno](https://github.com/denoland/setup-deno) from 1 to 2.
- [Release notes](https://github.com/denoland/setup-deno/releases)
- [Commits](https://github.com/denoland/setup-deno/compare/v1...v2)

---
updated-dependencies:
- dependency-name: denoland/setup-deno
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-09 18:50:31 -04:00
Greg Johnston
b2e6185b22 fix: don't escape script/style/textarea in InertHtml (closes #3078) (#3079) 2024-10-09 10:07:40 -04:00
Greg Johnston
d2bfb3080b Merge pull request #3077 from leptos-rs/router-fixes
Router fixes
2024-10-09 07:33:24 -04:00
Greg Johnston
72ebd17042 fix: only set browser URL if it matches current router URL (closes #2979( 2024-10-08 22:12:18 -04:00
Greg Johnston
e2f0b4deeb fix: prevent simultaneous \query_signal\ writes from canceling each other (closes #2369) 2024-10-08 22:12:02 -04:00
Greg Johnston
57c07e9aec feat: enable faster compile times with RUSTFLAGS="--cfg erase_components (#2905) 2024-10-08 17:03:40 -04:00
Greg Johnston
0835066bc0 chore: re-add regression tests from #2639 (#3073) 2024-10-08 17:02:18 -04:00
webmstk
656e83fe24 docs: fix comment for set_interval helper (#3074) 2024-10-08 13:30:17 -04:00
Greg Johnston
ad0252ecfd fix: inconsistencies in check for latest version in actions (#3070) 2024-10-07 21:02:02 -04:00
Greg Johnston
77f05c6f4e fix: add HEAD support for Actix in leptos_routes (closes #2885) (#3069) 2024-10-07 21:01:46 -04:00
zakstucke
a4ea491dc0 feat: add Read/ReadUntracked/Track for Signal/MaybeSignal/MaybeProp (#3031) 2024-10-07 19:55:07 -04:00
Greg Johnston
3c89b9c930 feat: add an optimized OnceResource and use it to rebuild Await (#3064) 2024-10-06 20:47:22 -04:00
Greg Johnston
93d7ba0d5f fix: add SVG <use> (closes #3065) (#3067) 2024-10-06 20:47:06 -04:00
Greg Johnston
e188993800 fix: remove unnecessary Send/Sync bounds on LocalResource (#3061) 2024-10-04 16:16:24 -04:00
Greg Johnston
c1dc8c7629 Merge pull request #3062 from leptos-rs/into-render
feat: add `IntoRender` for rendering custom data
2024-10-04 14:43:55 -04:00
Greg Johnston
ab9de1b8c0 chore: remove unused variable 2024-10-04 13:56:38 -04:00
Greg Johnston
b39985d9b8 fix: only use IntoAttributeValue for parts of view that are actually attribute values 2024-10-04 13:38:09 -04:00
Greg Johnston
5e8e93001d docs: IntoRender and IntoAttributeValue 2024-10-04 13:25:57 -04:00
Greg Johnston
a4ed0cbe5b feat: add IntoAttributeValue for rendering arbitrary attribute values 2024-10-04 13:24:39 -04:00
Greg Johnston
422fe9f43b feat: add IntoRender for rendering arbitrary types 2024-10-04 13:13:23 -04:00
kczimm
36df36e16c feat: allow ParamsMap to support multiple values per key (closes #2882) (#2966)
Co-authored-by: Greg Johnston <greg.johnston@gmail.com>
2024-10-03 18:35:50 -04:00
Chris
95fc79034b chore: dead router::router module from 0.6 (#2943) 2024-10-02 19:35:49 -04:00
Greg Johnston
7403e4084f Merge pull request #3040 from mahdi739/double-ended-iterator-for-stores
Double-ended-iterator-for-stores
2024-10-02 19:19:40 -04:00
jk
8feee5e5d7 Migrate rkyv 0.8.x (#3054) 2024-10-02 10:03:20 -07:00
Greg Johnston
e6da266b4f Merge pull request #3050 from leptos-rs/2086
Module restructuring and docs cleanup
2024-10-01 21:23:47 -04:00
Greg Johnston
0798e0812d fix: unused import in example 2024-10-01 21:23:22 -04:00
Greg Johnston
03514e68be chore: fix test import 2024-10-01 20:43:46 -04:00
Greg Johnston
4092368581 chore: remove unused import 2024-10-01 20:43:37 -04:00
Greg Johnston
dcc7865989 fix: remove r# from raw attribute names in InertHtml (closes #3049) (#3058) 2024-10-01 20:18:29 -04:00
Greg Johnston
896f7de8e1 fix: update import of spawn_local in test examples 2024-10-01 20:06:04 -04:00
Greg Johnston
29b2d3024a fix: update import of tick in test examples 2024-10-01 20:05:22 -04:00
Greg Johnston
c47893ad60 fix: <textarea> does not parse its children as HTML, like <script> and <style> (#3052) 2024-10-01 19:39:10 -04:00
Greg Johnston
0d4f3b51e9 fix: import of reactive_graph in integrations 2024-10-01 19:38:55 -04:00
Greg Johnston
2431b19cdf chore: reexport reactive_graph as leptos::reactive 2024-10-01 19:36:20 -04:00
Greg Johnston
4801e1ec6d chore: hide unwrap_signal from docs 2024-10-01 19:36:20 -04:00
Greg Johnston
e206b93ba5 chore: inline docs for reexported crates 2024-10-01 19:36:20 -04:00
Greg Johnston
f0675446d8 chore: reexport reactive_graph as leptos::reactive 2024-10-01 19:36:20 -04:00
Greg Johnston
2ac7eaad15 chore: add missing docs for tick 2024-10-01 19:36:20 -04:00
Greg Johnston
8a040fda69 chore: rename Writeable to Write for consistency 2024-10-01 19:36:20 -04:00
Greg Johnston
2f5c966cf4 chore: reexport untrack from leptos::prelude but not from reactive_graph 2024-10-01 19:36:20 -04:00
Greg Johnston
45e2629f0e chore: remove reexport of tachys in leptos::prelude 2024-10-01 19:36:20 -04:00
Greg Johnston
517566d085 change: rename spawn module to task 2024-10-01 19:35:45 -04:00
Greg Johnston
6df8657700 fix: escape text nodes and attributes in InertHtml (closes #3056) (#3057) 2024-10-01 19:19:21 -04:00
Georg Vienna
2a4063a259 projects: port session_auth_axum (#2970) 2024-10-01 09:40:57 -07:00
Marc-Stefan Cassola
013ec4a09d Two-way data binding (#2977)
* added two-way data binding to dom elements

* added two-way data binding to radio groups

* moved bind into reactive_graph mod

* chore: use `::leptos` absolute path in macro

* chore: move `Group` into the reactive module, as that's the only place it has meaning

* feat: use new `bind:` syntax

* chore: update for non-generic rendering

* chore: ignore this test

---------

Co-authored-by: Greg Johnston <greg.johnston@gmail.com>
2024-10-01 09:39:45 -07:00
Greg Johnston
d10fec08e2 Merge pull request #3037 from leptos-rs/rename-island-router
change: rename island-router feature so people don't use it
2024-09-30 20:55:08 -04:00
Greg Johnston
94f4328586 example: add README that actually explains this example 2024-09-30 20:08:39 -04:00
Greg Johnston
2b70961110 change: rename island-router feature so people don't use it 2024-09-30 20:08:24 -04:00
Greg Johnston
699c54e16c -gamma prerelease 2024-09-30 14:16:38 -04:00
Greg Johnston
1217ef4d8e beta7 2024-09-30 14:16:01 -04:00
Sean Aye
9aba3efbe4 chore: remove unnecessary trait bounds (#3046) 2024-09-29 17:26:31 -04:00
SleeplessOne1917
1b48a2f8d5 Replace proc-macro-error with proc-macro-error2 (#3044) 2024-09-28 18:03:28 -07:00
Greg Johnston
31cb766206 docs: restore warning when reading resource outside Suspense (closes #3038) (#3041) 2024-09-28 13:10:30 -04:00
Mahdi
4c3bcaa68d implement DoubleEndedIterator for StoreFieldKeyedIter 2024-09-28 17:15:43 +03:30
Mahdi
fe060617d2 implement DoubleEndedIterator for StoreFieldIter 2024-09-28 17:14:45 +03:30
Greg Johnston
de28a317f0 fix: do not emit HTML comments inside script/style, and do not try to hydrate them (closes #3033) (#3034) 2024-09-27 12:33:51 -04:00
Greg Johnston
d29433b98d fix: more robust arena sandboxing (closes #2995) (#3026) 2024-09-26 19:48:04 -04:00
Greg Johnston
f2582b6ac9 fix: properly scope Suspend rebuilds within ownership tree (closes #3024) (#3030) 2024-09-26 18:19:36 -04:00
zakstucke
67845be161 feat: read and write for StoredValue (#3027) 2024-09-26 15:46:09 -04:00
Greg Johnston
2bf1f46b88 fix: add correct namespaces for SVG and MathML elements (closes #3021) (#3025) 2024-09-25 19:42:42 -04:00
VincentBerthier
70ae3a0abb fix: island hydration warning message (#3023) 2024-09-25 15:38:04 -04:00
Greg Johnston
96e2b5cba1 fix: abort Suspend on cleanup, to avoid using disposed items (closes #3012) (#3019) 2024-09-24 21:45:39 -04:00
Greg Johnston
ef27a198d9 fix: correct Owner restoration in FlatRoutes (closes #3014) (#3018) 2024-09-24 21:45:30 -04:00
Greg Johnston
47299926bb fix: suppress resource loading during route generation (closes #3013) (#3017) 2024-09-24 21:45:22 -04:00
Greg Johnston
bdc2285658 change: remove generic rendering (#3015) 2024-09-24 17:01:57 -04:00
zakstucke
9d4ce6e526 Fix custom root when not using islands. (#3016) 2024-09-24 11:42:54 -07:00
Greg Johnston
3d2cdc21a1 beta6 2024-09-23 08:57:44 -04:00
Greg Johnston
93d939aef8 Merge pull request #3009 from leptos-rs/stores-patch
Stores patching
2024-09-22 21:45:10 -04:00
Greg Johnston
fb04750607 example: add example of patching fields 2024-09-22 19:52:48 -04:00
Greg Johnston
a080496e7e fix: notify correctly when patching stores 2024-09-22 19:51:50 -04:00
Greg Johnston
9fc1002167 perf: do not notify keyed iterator when only an inner field has changed 2024-09-22 19:50:30 -04:00
Greg Johnston
bc5c766530 fix: notify stores when modifying parent, without notifying siblings 2024-09-22 19:33:14 -04:00
Greg Johnston
17821f863a fix: restructure StoredValue so that nested calls do not deadlock (closes #2968) (#3004) 2024-09-22 19:21:49 -04:00
Baptiste
1ca4f34ef3 fix: optional props with islands (#3005) 2024-09-21 18:13:58 -04:00
Greg Johnston
8f0a1554b1 Merge pull request #3000 from leptos-rs/add-attr-any-view
Doing chores
2024-09-21 08:51:32 -04:00
Greg Johnston
38d4f26d03 fix: snip infinite type recursion 2024-09-21 07:51:27 -04:00
Greg Johnston
2b04c2710d Merge pull request #3002 from leptos-rs/fix-stores
Fix stores
2024-09-21 07:37:54 -04:00
Greg Johnston
a4937a1236 fix: correctly triggering parents vs siblings 2024-09-20 21:25:42 -04:00
Greg Johnston
f6f2c39686 chore: remove UntrackedWriter 2024-09-20 20:47:46 -04:00
Greg Johnston
d7eacf1ab5 chore: remove unused DocumentFragment mounting code 2024-09-20 20:41:51 -04:00
Greg Johnston
d1a4bbe28e chore: fix adding attr todo for static types 2024-09-20 20:41:51 -04:00
Greg Johnston
412ecd6b1b chore: remove dead iterator wrapper code 2024-09-20 20:41:51 -04:00
Greg Johnston
9bc0152121 chore: clean up todos in template SSR code 2024-09-20 20:41:51 -04:00
Greg Johnston
4b05cada8f chore: remove dead code for rendering guards 2024-09-20 20:41:51 -04:00
Greg Johnston
a818862704 chore: tidy up todos on EitherKeepAlive 2024-09-20 20:41:51 -04:00
Greg Johnston
173487debc fix: add add_any_attr() for AnyView<R> 2024-09-20 20:41:51 -04:00
Greg Johnston
449d96cc9a feat: add wrapper to support add_any_attr() fixes 2024-09-20 20:41:51 -04:00
Greg Johnston
f9bf6a95ed Merge pull request #3001 from leptos-rs/ci
Fix CI
2024-09-20 20:40:53 -04:00
Greg Johnston
5bf6c94bb2 chore: remove some testing combinations 2024-09-20 20:11:44 -04:00
Greg Johnston
e1ce94a28d fix: rationalize reactive_stores tests 2024-09-20 18:25:40 -04:00
Greg Johnston
2a62dcf27e chore: fix unused import 2024-09-20 18:18:11 -04:00
Greg Johnston
3094766c5c chore: allow unused methods 2024-09-20 18:08:09 -04:00
Greg Johnston
a52804595d chore: allow unused methods 2024-09-20 17:35:43 -04:00
Greg Johnston
e72f12d32b chore: clean up tests 2024-09-20 17:31:11 -04:00
Greg Johnston
e70083708a chore: fix dependencies 2024-09-20 16:39:21 -04:00
Greg Johnston
cbc4caef19 chore: fix testing 2024-09-20 16:36:40 -04:00
Greg Johnston
fbeee4dbf5 chore: cargo fmt 2024-09-20 16:31:07 -04:00
Greg Johnston
d13f7e5438 chore: remove unused import 2024-09-20 16:02:41 -04:00
Greg Johnston
7b543bd31c chore: fix syn features 2024-09-20 15:57:54 -04:00
Greg Johnston
1743724420 chore: AsRef/AsMut 2024-09-20 15:46:15 -04:00
Greg Johnston
73e0add670 chore: cargo fmt 2024-09-20 15:44:19 -04:00
Greg Johnston
4f5eb444bc chore: remove print 2024-09-20 15:43:46 -04:00
Greg Johnston
7de98823fb chore: clippy and missing GTK implementations 2024-09-20 15:38:15 -04:00
Georg Vienna
6d930573fc feat: add either macro (#2900) 2024-09-20 08:17:40 -07:00
Saber Haj Rabiee
3317002ff5 fix: improve CI workflow (#2838)
* fix: improve CI workflow

* fix: add missing `Makefile.toml` to workspace crates
(reactive_stores and reactive_stores_macro)

* fix: remove trailing slash in workflow names

* fix: add gtk example and improve excluding example's logic

* fix: install gtk example deps
2024-09-20 08:08:28 -07:00
martin frances
99403d0167 MSRV Bump to 1.80.0, drop crate lazy_static and use std::sync::LazyLock. (#2767) 2024-09-19 21:40:33 -07:00
Greg Johnston
23ce022c60 Merge pull request #2997 from leptos-rs/2971
Changes related to stack overflows
2024-09-19 17:20:45 -04:00
Greg Johnston
96e1fd0fb8 fix: turn off InertHtml for SVG/MathML (closes #2998) (#2999) 2024-09-19 17:20:30 -04:00
Greg Johnston
f28dac1093 chore: remove unused debug info from HtmlElement 2024-09-19 15:38:52 -04:00
Greg Johnston
ff28544fb2 feat: add BoxedView wrapper 2024-09-19 15:38:52 -04:00
Deep Gaurav
27765b417c fix: static generation should wait for file writes before resolving (#2994) 2024-09-19 15:36:54 -04:00
Greg Johnston
b0d8d4ee26 fix: properly trigger Suspense when Suspend is called again (#2993) 2024-09-18 21:35:37 -04:00
Greg Johnston
c4b1176a6a fix: drop lock on current URL before rendering, in case of redirect (closes #2990) (#2992) 2024-09-18 21:27:18 -04:00
Greg Johnston
fd133dd79a chore: re-export untrack 2024-09-18 20:25:35 -04:00
Greg Johnston
9c2477a4cf Revert "chore: re-export untrack (#2991)"
This reverts commit f3b6d1f351.
2024-09-18 20:25:03 -04:00
Greg Johnston
f3b6d1f351 chore: re-export untrack (#2991) 2024-09-18 19:51:20 -04:00
Greg Johnston
5af7b54c9c perf: optimize inert HTML elements (#2989) 2024-09-18 19:42:07 -04:00
Baptiste
ba9604101d fix: correct lifetimes for PartialPathMatch (#2981) 2024-09-16 21:59:49 -04:00
Greg Johnston
e136c1fc44 Merge pull request #2986 from leptos-rs/2957
fix: get Suspend and ErrorBoundary working together correctly
2024-09-16 21:58:49 -04:00
Greg Johnston
c581b3293e Merge pull request #2985 from leptos-rs/2982
fix: sort attributes so `class` and `style` always run before `class:` and `style:` (closes #2982)
2024-09-16 21:58:38 -04:00
Greg Johnston
cc7f861637 fix: add missing Debug and DefinedAt impls for Resource/ArcResource (closes #2983) (#2984) 2024-09-16 21:58:23 -04:00
Greg Johnston
642d6fc72b fix: stable hashes across different client and server builds for islands (closes #2978) (#2980) 2024-09-16 21:58:09 -04:00
Kajetan Welc
e69c7f4ae0 feat(#2946): add #[store(skip)] for #[derive(Store)] (#2975) 2024-09-16 21:57:57 -04:00
Greg Johnston
9ca36d4763 chore: remove deprecated function in doctest example 2024-09-16 21:34:04 -04:00
Greg Johnston
8dc600ca02 fix: do not sort class and style that are after spread marker 2024-09-16 21:33:46 -04:00
Greg Johnston
b621ead607 fix: forward subscribers for already-resolved Suspend during client-side build 2024-09-16 21:10:02 -04:00
Greg Johnston
66cf21f650 fix: Ok => Err transition with Suspend (closes #2957) 2024-09-16 21:02:30 -04:00
Greg Johnston
f3dcdc057d fix: sort attributes so class and style always run before class: and style: (closes #2982) 2024-09-16 20:26:51 -04:00
Greg Johnston
2bdacf636e Merge pull request #2974 from leptos-rs/more-stores
Improve efficiency of keyed stores
2024-09-14 21:49:27 -04:00
Greg Johnston
fc06980c60 feat: directly implement IntoIterator on keyed fields 2024-09-14 21:22:16 -04:00
Greg Johnston
550a3a4e6d perf: use FxHashMap for sets of keys 2024-09-14 21:20:09 -04:00
Greg Johnston
3310e7766b perf: only rebuild keys when we've touched the list itself, not when we edit a row 2024-09-14 18:33:59 -04:00
Greg Johnston
5ab865e89d example: fix so we remove by ID, not by id-as-index 2024-09-14 18:33:36 -04:00
Greg Johnston
f0c60f6ef6 Merge pull request #2871 from leptos-rs/more-stores
(draft) More work on stores
2024-09-14 17:34:13 -04:00
Greg Johnston
f3f685c923 chore: clean up Trigger <> Notify rename 2024-09-14 17:00:47 -04:00
Greg Johnston
3646bf31b0 example: only show date if in scheduling mode 2024-09-14 17:00:31 -04:00
Greg Johnston
b39895fa2d feat: remove outdated entries and recycle their keys 2024-09-14 17:00:11 -04:00
Greg Johnston
1fce8931ab fix: do not match incomplete static segments (closes #2916) (#2973) 2024-09-14 16:20:45 -04:00
Greg Johnston
6166f6edbd fix: ensure that we retain the correct sandoxed arena when spawning Futures (#2965) 2024-09-14 09:10:01 -04:00
Greg Johnston
dc9fbb0585 Merge branch 'main' into more-stores 2024-09-13 17:31:54 -04:00
Greg Johnston
d7b2f9d05b feat: keyed store fields, with keyed iteration 2024-09-13 17:21:09 -04:00
Greg Johnston
69c4090d32 example: update stores example to show enum matching 2024-09-13 12:12:05 -04:00
Greg Johnston
fff5fa3459 feat: add support for named and unnamed enum fields in Stores 2024-09-13 11:11:31 -04:00
Greg Johnston
e92b80c71e fix: tracking ArcStore should track, not trigger, its root trigger 2024-09-13 10:54:07 -04:00
Greg Johnston
8bb04ef248 chore: remove dead code 2024-09-13 10:53:27 -04:00
luoxiaozero
d7881ccfb5 fix: allow component to use span prop when tracing feature is enabled (#2969) 2024-09-13 09:35:59 -04:00
Álvaro Mondéjar Rubio
96a1f80daf tests: fix Effect doctests not being executed, and test-related issues (#2886) 2024-09-12 16:43:32 -04:00
Greg Johnston
a083b57260 fix: do not panic in automatic Track implementation if source is disposed (#2964) 2024-09-12 09:22:46 -04:00
Chris
4fa6660a3f doc: router::{Wildcard, Static, Param}Segment (#2949) 2024-09-11 21:02:02 -04:00
Baptiste
43f2ad7043 chore: add #[track_caller] to to_any_source (#2963) 2024-09-11 20:01:06 -04:00
Greg Johnston
2bf04072ea Merge pull request #2959 from leptos-rs/2956
fix: do not retrigger parent effect when Suspend's resources resolve (closes #2956)
2024-09-10 14:08:32 -04:00
Greg Johnston
efc6fc017d fix: forward subscribers for already-resolved Suspend during hydration 2024-09-10 06:59:47 -04:00
Greg Johnston
6cb10401df chore(ci): update list of core crates 2024-09-09 21:20:14 -04:00
Greg Johnston
346efd66f5 chore: remove unused cancellation logic for now 2024-09-09 21:19:55 -04:00
Greg Johnston
7c0889e873 fix: do not retrigger parent effect when Suspend's resources resolve (closes #2956) 2024-09-09 18:10:48 -04:00
Greg Johnston
bb40576bd5 Merge pull request #2955 from leptos-rs/fix-refetch
Fix refetch
2024-09-09 07:33:01 -04:00
Greg Johnston
6baf20275f fix: Resource::refetch() 2024-09-08 21:41:44 -04:00
Greg Johnston
5a57d48913 beta5 2024-09-08 19:40:32 -04:00
jk
73f0207a7d feat: add a copyable Trigger type (closes #2901) (#2939) 2024-09-08 19:39:40 -04:00
Greg Johnston
4e4fb8ab10 chore(examples): SsrMode is no longer clone (#2954) 2024-09-08 19:39:15 -04:00
Greg Johnston
b9cccc6b91 fix: revert change, making writes to children notify parents 2024-09-08 13:58:45 -04:00
Greg Johnston
d42163d888 fix: tracking a subfield should track its parents, as changing these can change it 2024-09-08 13:56:32 -04:00
Greg Johnston
2db3e4f4d8 chore: move Option tests into option module 2024-09-08 13:56:32 -04:00
Greg Johnston
45380a258a feat: add support for simple enums in stores 2024-09-08 13:56:32 -04:00
Greg Johnston
40292d0896 feat: add mapping over Option store fields 2024-09-08 13:56:32 -04:00
Greg Johnston
e8be9e31ff fix/change: do not trigger every parent when writing to a store subfield 2024-09-08 13:56:32 -04:00
Greg Johnston
3d0fdb1ab0 feat: add mapped unwrap for Option store fields 2024-09-08 13:56:32 -04:00
Tommy Yu
4dea1195e2 examples: include axum_js_ssr for discussion of integrating JS libraries (#2878) 2024-09-08 13:42:14 -04:00
Greg Johnston
92ea39ddac feat: version Resources to avoid race conditions (#2950) 2024-09-08 13:27:55 -04:00
Matt Kane
05e08166c4 chore: update suspense_test example to use Resource::map (#2877) 2024-09-07 20:56:30 -04:00
Greg Johnston
827cc0bdfa fix: ensure Resource always tracks its source, and does not double-run (#2948) 2024-09-07 18:57:31 -04:00
Greg Johnston
57bd343f4a fix: remove Owner from thread-local when it is ordinarily dropped, to ensure cleanup (closes #2942) (#2944) 2024-09-07 07:01:54 -04:00
Azriel Hoh
4a76aead68 Switch to proc-macro-error2 to address unmaintained security advisory. (#2934) 2024-09-06 17:24:03 -04:00
Greg Johnston
48c2148589 fix: untrack in the async block of a Resource (closes #2937) (#2941) 2024-09-06 17:23:40 -04:00
Greg Johnston
32bea69c28 fix: implement dry_resolve on Suspend so that resources created inside a Suspend are registered (closes #2917) (#2940) 2024-09-06 14:49:37 -04:00
Greg Johnston
f3c57f8bce Merge pull request #2929 from leptos-rs/relative-flat
feat: correctly support relative routing for `FlatRoutes`
2024-09-05 09:13:07 -04:00
Greg Johnston
000896b2f7 fix: allow clone: syntax on components (closes #2903) (#2928) 2024-09-04 20:44:37 -04:00
Greg Johnston
88004e5042 feat: correctly support relative routing for FlatRoutes 2024-09-04 20:43:59 -04:00
Greg Johnston
6001a93475 fix: correctly set ownership on view of ProtectedParentRoute (closes #2897) (#2927)
* fix: correctly set ownership on view of ProtectedParentRoute (closes #2897)

* chore: clippy false positive
2024-09-04 20:42:10 -04:00
Greg Johnston
4784b2ddab chore: remove dead code 2024-09-04 20:20:49 -04:00
Chris Biscardi
32b4cd008f Enable CDN support for assets (#2925)
* Enable CDN support for assets

This enables setting a root for a url, especially relating to generated .wasm, .js, and .css files.

This allows using a CDN for static assets.

* fix lint
2024-09-04 15:05:51 -07:00
Greg Johnston
823f8b51be Merge pull request #2924 from leptos-rs/2915 2024-09-04 11:15:11 -04:00
Greg Johnston
209743d6bc fix: ensure unique names for islands (closes #2915) 2024-09-04 08:53:03 -04:00
Greg Johnston
b93a88accc Merge pull request #2921 from leptos-rs/2920 2024-09-03 21:03:29 -04:00
Greg Johnston
dc2314d5e2 fix: ensure that LocalResource never creates a SendWrapper on the server 2024-09-03 20:40:12 -04:00
Greg Johnston
33aa676854 fix: ensure stability of hydration IDs on client and server, when using partial hydration (closes #2920) 2024-09-03 19:53:21 -04:00
Greg Johnston
4a3b3ffb8a fix: allow > 26 children for element children as well as top-level fragments (#2918) 2024-09-03 14:53:38 -04:00
Greg Johnston
ee5cbf1891 fix/change: remove replace and state props from <A/>, and add them via spreading instead (#2912) 2024-09-03 14:25:25 -04:00
mrvillage
8fcf3544a8 fix: trim spaces in file hashes (closes #2908) (#2913) 2024-09-03 08:51:03 -04:00
Greg Johnston
2b8e987cb8 fix: check whether we're on the server before adding window event listener (closes #2891) (#2910) 2024-09-02 09:11:07 -04:00
Greg Johnston
998165148b fix: automatically break children into tuples of a size the trait system can handle (closes #2863) (#2909) 2024-09-02 08:01:41 -04:00
Greg Johnston
c80eff1098 Merge pull request #2898 from leptos-rs/min-serialization
fix: only serialize Resources if we're in a part of the tree that needs hydration
2024-09-02 07:11:12 -04:00
Greg Johnston
cd8f2c2153 fix: correctly provide parent outlets when rebuilding from fewer to more nested routes (closes #2904) (#2906) 2024-09-02 07:08:15 -04:00
Greg Johnston
cb0abff2d5 fix: only serialize resource data if we're in a part of the tree being hydrated (i.e., in full hydration or in an island) 2024-08-31 16:18:06 -04:00
Greg Johnston
3b1b2e2dcc fix version for publish 2024-08-31 11:59:05 -04:00
Greg Johnston
7831e4ad05 next beta release 2024-08-31 11:59:05 -04:00
Greg Johnston
e7bb859cd9 feat: add support for static routing and incremental static regeneration (#2875) 2024-08-31 10:33:12 -04:00
Rakshith Ravi
9fc26e609c feat: allow for documentation and other attributes to fields in server fn (#2876) 2024-08-31 09:35:08 -04:00
mrvillage
4f1ee65e6c Add hash files support to 0.7 (#2894)
* Add support for JS and WASM file name hashing

* Add `<HashedStylesheet />`

* Update `<HashedStylesheet />`

* Whoops

* Fix formatting

* My IDE is just refusing to work apparently

* I hate my IDE

* Don't run the doctest

* Just remove the example, I don't know enough about doctest for this
2024-08-30 14:29:59 -07:00
Greg Johnston
ceff827a77 Merge pull request #2884 from leptos-rs/rstml-0.12
update to rstml and improve recoverability in attributes
2024-08-28 07:46:08 -04:00
Álvaro Mondéjar Rubio
a7db918775 docs: update main documentation of leptos crate (#2853) 2024-08-28 07:44:29 -04:00
Baptiste
be20ecd366 fix: implement Copy and Clone for HtmlElement without needing Rndr to be Clone/copy (#2889) 2024-08-28 07:25:51 -04:00
Greg Johnston
5790d8ad12 fix: derive various traits on Dom to make it easier to derive traits on structs that take a generic Renderer 2024-08-28 07:25:08 -04:00
luoxiaozero
7dc58e248c fix: compile attr:aria-* syntax (#2887) 2024-08-27 09:00:13 -07:00
Greg Johnston
7b03e63b23 docs: add note about curly braces 2024-08-26 21:00:45 -04:00
Greg Johnston
55fd7c6421 chore: clippy 2024-08-26 20:57:02 -04:00
Greg Johnston
ba1ea4c2bb do not error on unbraced 2024-08-26 20:56:23 -04:00
blorbb
6a4fc96835 rstml 0.12 and enforce braces in attribute values 2024-08-26 20:55:12 -04:00
Marc-Stefan Cassola
58476bb98e feat: variadic From for callbacks (#2873) 2024-08-26 20:47:11 -04:00
Oliver
88d4f14541 added attributes to source element (#2883)
Co-authored-by: Oliver Nordh <oliver.nordh@proton.me>
2024-08-26 19:27:01 -04:00
niklass-l
6bba233ba7 Add support for postcard codec in server_fn (#2879)
* Add support for postcard codec

* Add postcard feature set exclusions

* Add postcard server fn encoding example
2024-08-26 13:58:23 -07:00
Greg Johnston
1d99764740 Merge pull request #2870 from leptos-rs/dependabot/github_actions/tj-actions/changed-files-45
chore(deps): bump tj-actions/changed-files from 44 to 45
2024-08-23 17:36:21 -04:00
Álvaro Mondéjar Rubio
53cc479c14 chore: set tracing as feature for all crates (#2843) 2024-08-23 17:34:05 -04:00
Greg Johnston
d3707d9b88 Merge pull request #2865 from mkane0814/feat/add-map-and-then-for-resource
feat: add Resouce::map and Resouce::and_then
2024-08-23 17:30:57 -04:00
Marc-Stefan Cassola
1df4076fd2 updated codee version (#2874) 2024-08-23 13:50:55 -07:00
dependabot[bot]
28337bb6c9 chore(deps): bump tj-actions/changed-files from 44 to 45
Bumps [tj-actions/changed-files](https://github.com/tj-actions/changed-files) from 44 to 45.
- [Release notes](https://github.com/tj-actions/changed-files/releases)
- [Changelog](https://github.com/tj-actions/changed-files/blob/main/HISTORY.md)
- [Commits](https://github.com/tj-actions/changed-files/compare/v44...v45)

---
updated-dependencies:
- dependency-name: tj-actions/changed-files
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-21 18:22:38 +00:00
Greg Johnston
c5dea52e69 chore: restore Playwright tests for counters example (#2864) 2024-08-20 13:38:22 -04:00
Greg Johnston
d5096ff2e6 feat: allow including a view from an external file (closes #2182) (#2862) 2024-08-20 09:00:40 -04:00
Matt Kane
84734f1110 feat: add ArcResource::and_then 2024-08-20 07:41:55 -05:00
Matt Kane
7094308287 feat: add Resource::and_then 2024-08-20 00:06:56 -05:00
Matt Kane
3b88c8ccd2 feat: add Resource::map 2024-08-19 23:38:36 -05:00
Greg Johnston
b932bd5e04 Merge pull request #2859 from leptos-rs/2743
Add `Resource::refetch()` and `Resource::update()`
2024-08-19 07:23:41 -04:00
Greg Johnston
a0638b786c feat: allow mutating AsyncDerived and therefore Resources (closes #2743) 2024-08-18 17:31:06 -04:00
Greg Johnston
1033133d3a feat: add Resource::refetch() 2024-08-18 17:05:06 -04:00
Matt Kane
ba40560ad7 added ToHref impl for Rc<str> (#2857) 2024-08-18 16:52:42 -04:00
Tomer Hanochi
78dc8b4410 fix: make any_spawner optional and dependent on the reactive_graph feature (#2858) 2024-08-18 16:32:20 -04:00
Greg Johnston
c6bf525270 chore: version bump for tachys and meta bug 2024-08-18 16:25:53 -04:00
Chris
fcdfd617f5 fix: redundant spans (#2836)
Per https://docs.rs/quote/latest/quote/macro.quote.html#hygiene
regarding token hygiene.

> Any interpolated tokens preserve the Span information provided by their
> `ToTokens` implementation.

In many instances, the procedural macros are spanning tokens with their
own span redundantly.
2024-08-16 20:25:56 -04:00
Álvaro Mondéjar Rubio
d9c8d4ff66 fix: #[component] macro attributes propagation (#2835) 2024-08-16 20:21:46 -04:00
Chris
621f112f4c docs: leptos_router_macro::path (#2841) 2024-08-16 20:19:38 -04:00
Greg Johnston
cfe2341dec fix: when in browser, resolve relative links relative to current origin (closes #2806) (#2846) 2024-08-16 20:18:59 -04:00
Greg Johnston
5ed2cc9596 docs: provide an error when you try to create identically-named attributes (closes #1692) (#2849) 2024-08-16 20:18:43 -04:00
Greg Johnston
47b07b0143 fix: support navigating to other origins with use_navigate (#2847) 2024-08-16 20:18:28 -04:00
Greg Johnston
0793d56648 Merge pull request #2851 from leptos-rs/2850
Fix nested routing/related issues
2024-08-16 20:17:42 -04:00
Greg Johnston
2dde9738b2 fix: unmount meta tags when state is dropped, because parents won't unmount them (closes #2832) 2024-08-16 17:51:37 -04:00
Greg Johnston
1b276e1e02 Revert "fix: run unmount logic for element children (closes #2832) (#2834)"
This reverts commit 951f4a73ee.
2024-08-16 17:43:55 -04:00
Greg Johnston
9771619b0d tests: add regression test for #2569 (#2848) 2024-08-16 16:53:00 -04:00
Greg Johnston
382a36406c chore: add crate info to router macro 2024-08-14 20:51:29 -04:00
Greg Johnston
a898d3f2f7 beta2 release 2024-08-14 20:13:14 -04:00
Greg Johnston
951f4a73ee fix: run unmount logic for element children (closes #2832) (#2834) 2024-08-14 19:59:54 -04:00
Greg Johnston
2a26a648ba examples: fix/update GTK example, and remove web parallels (#2839) 2024-08-14 19:47:33 -04:00
Saber Haj Rabiee
66d7cb5d12 feat: add memo! macro (closes #2708) (#2826) 2024-08-14 06:14:17 -07:00
Chris
aa49ad760b feat: StoredValue::default (#2818) 2024-08-13 21:20:10 -04:00
Álvaro Mondéjar Rubio
3469e9335c Provide several deprecated functions (#2831) 2024-08-13 21:19:52 -04:00
benwis
62408d9202 Run cargo fmt 2024-08-13 17:10:58 -07:00
Saber Haj Rabiee
db1c15f4e4 fix: fix web-sys warnings in server_fn (#2828)
* fix: fix web-sys warnings in server_fn

* fix: update web-sys to 0.3.70

* fix: web-sys clipboard api in 0.3.70
2024-08-13 15:46:34 -07:00
Álvaro Mondéjar Rubio
3f751551a8 feat: provide deprecated create_memo (#2825) 2024-08-13 15:43:17 -07:00
Álvaro Mondéjar Rubio
2470036f57 feat: provide deprecated create_rw_signal (#2824) 2024-08-13 15:42:47 -07:00
Saber Haj Rabiee
e01dfbf497 fix: update to wasm-bindgen 0.2.93 (#2827) 2024-08-13 15:21:57 -07:00
Saber Haj Rabiee
49c1661f92 fix: exclude projects from workspace (#2819) 2024-08-13 14:51:59 -07:00
Chris
b9dfd9a5ae docs: StoredValue methods and examples for 0.7 (#2817) 2024-08-13 14:38:07 -07:00
Saber Haj Rabiee
17a150b3bf fix: increase MSRV to 1.76 (#2829) 2024-08-13 14:31:22 -07:00
Rakshith Ravi
c860f524ad Add 0.7 warning to README (#2823) 2024-08-13 10:42:13 -04:00
mahmoud-eltahawy
20af4928b2 chore: use workspace edition for examples and crates (#2816) 2024-08-12 19:25:47 -04:00
Greg Johnston
7b62ad44d2 feat: restore hot reloading for 0.7 (#2775) 2024-08-12 16:11:30 -04:00
Greg Johnston
5657abc07d Merge pull request #2809 from leptos-rs/callback
Callback changes
2024-08-12 16:11:10 -04:00
Greg Johnston
9fc351ceac chore: remove unused import 2024-08-12 08:09:12 -04:00
Greg Johnston
893d47f1c5 feat: add missing server fn redirect hook to router (#2815) 2024-08-12 08:07:45 -04:00
Greg Johnston
3c2a2304e4 change: rename Callable::call() to Callable::run() to avoid warnings about name collision with Fn() 2024-08-12 07:48:22 -04:00
Greg Johnston
3de4b7b982 fix: impl Copy for UnsyncCallback 2024-08-12 07:45:29 -04:00
Greg Johnston
36957cb569 change: impl From<F: Fn> for all callbacks, rather than implement Fn traits on them in nightly (closes #2041, #2142) 2024-08-12 07:45:28 -04:00
Greg Johnston
27dbadb7d2 fix: allow generic parameters for directive functions (closes #2808) (#2812) 2024-08-11 20:37:57 -04:00
Greg Johnston
84590b98ed Merge pull request #2814 from leptos-rs/2719
Provide parent route params to children
2024-08-11 18:36:15 -04:00
Greg Johnston
0222182286 fix: provide parent params to children (closes #2719) 2024-08-11 17:20:25 -04:00
Greg Johnston
7ed4d08dab feat: From<ArcRwSignal<_>> for ArcMemo<_> 2024-08-11 17:19:35 -04:00
Greg Johnston
4fa2e58551 fix: properly resolve nested relative routes with multiple parents (closes #2720) (#2797) 2024-08-11 13:21:22 -04:00
Greg Johnston
5fe58369f5 fix: only implement global attributes on HtmlElement, not on all renderable types, to improve autocomplete (#2811) 2024-08-11 13:21:08 -04:00
Tommy Yu
10860ebb1e doc: more details on how redirect works (closes #2789) (#2796) 2024-08-11 07:11:05 -04:00
Greg Johnston
887eb99cf6 chore: cargo fmt 2024-08-10 20:31:28 -04:00
Tommy Yu
9f99571b28 fix: a more robust aria-current="page" algorithm for A (#2770) 2024-08-10 20:31:10 -04:00
Saber Haj Rabiee
b3e2040ec9 chore: upgrade dependencies (#2765) 2024-08-10 20:01:41 -04:00
Greg Johnston
693861434c Merge pull request #2799 from leptos-rs/2798
fix: ProtectedRoute calling view multiple times during server rendering
2024-08-09 10:27:10 -04:00
Greg Johnston
d1248d3faf fix: hydration for attributes with Option<_> (closes #2793) (#2794) 2024-08-08 14:11:26 -04:00
Greg Johnston
f1fae63064 fix: only run Suspense on the condition in ProtectedRoute (closes #2798) 2024-08-08 13:57:58 -04:00
Greg Johnston
f7053ac960 feat: add Unsuspend as a way to opt out of Suspense in a section of the tree 2024-08-08 13:56:02 -04:00
Greg Johnston
8670365594 fix: support complex struct form submits without JS (closes #2790) (#2792) 2024-08-07 11:10:59 -04:00
Alicia Garcia-Raboso
e0cc6fd7b9 fix: correctly report whether a stored_value is disposed (#2791) 2024-08-07 09:19:01 -04:00
Greg Johnston
84457b45ff fix: introduce more intuitive/useful behavior for new_with_initial (closes #2787) (#2788) 2024-08-07 09:14:22 -04:00
Greg Johnston
8c959d3e24 fix: correctly dispose of original RouteContext, allowing Owner to be dropped (closes #2785) (#2786) 2024-08-07 09:14:10 -04:00
Greg Johnston
288da232ac Merge pull request #2782 from leptos-rs/dependabot/github_actions/pnpm/action-setup-4
chore(deps): bump pnpm/action-setup from 3 to 4
2024-08-06 10:26:01 -04:00
Greg Johnston
ef52e8620b Merge pull request #2781 from leptos-rs/dependabot/github_actions/tj-actions/changed-files-44
chore(deps): bump tj-actions/changed-files from 41 to 44
2024-08-06 10:25:51 -04:00
Greg Johnston
a8c5ce2722 chore(ci): temporarily disable semver checks while main branch is itself a breaking change (#2783) 2024-08-06 09:51:21 -04:00
dependabot[bot]
a40ba9a39e chore(deps): bump pnpm/action-setup from 3 to 4
Bumps [pnpm/action-setup](https://github.com/pnpm/action-setup) from 3 to 4.
- [Release notes](https://github.com/pnpm/action-setup/releases)
- [Commits](https://github.com/pnpm/action-setup/compare/v3...v4)

---
updated-dependencies:
- dependency-name: pnpm/action-setup
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-06 01:32:44 +00:00
dependabot[bot]
83a110fb85 chore(deps): bump tj-actions/changed-files from 41 to 44
Bumps [tj-actions/changed-files](https://github.com/tj-actions/changed-files) from 41 to 44.
- [Release notes](https://github.com/tj-actions/changed-files/releases)
- [Changelog](https://github.com/tj-actions/changed-files/blob/main/HISTORY.md)
- [Commits](https://github.com/tj-actions/changed-files/compare/v41...v44)

---
updated-dependencies:
- dependency-name: tj-actions/changed-files
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-06 01:32:42 +00:00
Saber Haj Rabiee
5deedf721e feat: add dependabot to get dep's update alerts and PRs automatically (#2768) 2024-08-05 21:23:45 -04:00
Álvaro Mondéjar Rubio
0ae67cf122 chore: clean up examples (#2779) 2024-08-05 21:23:17 -04:00
martin frances
97e0222061 chore: cargo outdated, bump rustc-hash to version 2.0.0, no additional fixup needed. (#2778) 2024-08-05 20:53:16 -04:00
luoxiaozero
a7aedee4fd feat: adds ForEnumerate component that gives reactive access to current index in list (#2773) 2024-08-05 20:52:18 -04:00
Corvus
f180941b7b feat: complete img and video attributes set (#2774) 2024-08-05 20:38:20 -04:00
Marc-Stefan Cassola
83cb3cb764 feat: allow effect functions without parameters (#2776) 2024-08-05 20:36:47 -04:00
Corvus
f174688974 feat: provide deprecated create_node_ref (#2777) 2024-08-05 20:33:58 -04:00
Greg Johnston
1f4c410f78 Merge pull request #2607 from leptos-rs/leptos_0.7
(draft) Leptos 0.7
2024-08-04 11:45:22 -04:00
Corvus
3dbedfc871 feat: reintroduce custom events (#2762) 2024-08-04 08:21:10 -04:00
luoxiaozero
026152d20e fix: correctly rebuild reactive attributes to avoid stale signals (#2763) 2024-08-04 08:16:02 -04:00
luoxiaozero
c70009243a fix: allow svg elements to use inner_html (#2764) 2024-08-04 08:14:22 -04:00
Greg Johnston
dcdad73476 chore: fmt 2024-08-03 21:55:07 -04:00
Corvus
42a8e49e1a feat: provide deprecated watch function (#2761) 2024-08-03 21:24:46 -04:00
Greg Johnston
9ba894764e chore: fmt 2024-08-03 11:52:21 -04:00
Greg Johnston
1d97494e19 fix: update syntax now that dispatch returns something 2024-08-03 11:52:09 -04:00
Greg Johnston
982bfd8011 feat: allow aborting dispatched actions (closes #2746) 2024-08-03 10:59:54 -04:00
Greg Johnston
a0ad927097 fix: generated tests should not use old APIs 2024-08-03 10:48:11 -04:00
Greg Johnston
4845459511 chore: update tests 2024-08-03 10:11:29 -04:00
Greg Johnston
54e4205541 chore: update tests 2024-08-02 11:16:35 -04:00
Greg Johnston
25f0186098 chore: update tests 2024-08-02 10:29:48 -04:00
Greg Johnston
00fb8f29d3 fix: do not pass SendWrappers through Suspense (closes #2756) 2024-08-02 10:27:35 -04:00
Greg Johnston
82ea4eb7ce chore: fix ssr tests 2024-08-02 09:40:18 -04:00
Greg Johnston
34382c0c23 chore: fix ssr tests 2024-08-02 09:24:51 -04:00
Greg Johnston
605e4b1eec chore: update examples and doctests 2024-08-02 09:07:23 -04:00
Greg Johnston
71ca02a432 chore: clippy 2024-08-01 22:25:16 -04:00
Greg Johnston
ac751dd0d3 chore(ci): update nightly 2024-08-01 21:28:19 -04:00
Greg Johnston
114df8797c chore: clippy 2024-08-01 21:25:35 -04:00
Greg Johnston
35b457aa82 chore: update examples and doctests 2024-08-01 20:59:39 -04:00
Greg Johnston
c43b71d3fa chore: update examples and doctests 2024-08-01 20:45:40 -04:00
Greg Johnston
5ad17d6b6c fix: correct thread-local behavior for Effects (closes #2754) 2024-08-01 19:43:10 -04:00
Greg Johnston
805be42f7a chore: fix doctest 2024-08-01 19:43:10 -04:00
Greg Johnston
bb63a1521e chore: update tests and doctests 2024-08-01 19:43:10 -04:00
Greg Johnston
05cd1bc6f0 chore: proper feature gating for imports 2024-08-01 19:43:10 -04:00
Greg Johnston
84ac64284c chore: update tests and doctests 2024-08-01 19:43:10 -04:00
Greg Johnston
8beb988ecc chore: update tests and doctests 2024-08-01 19:43:10 -04:00
Greg Johnston
05999069b7 feat: add create_slice functions 2024-08-01 19:43:10 -04:00
Greg Johnston
dbb4c79d9c chore: remove unused features 2024-08-01 19:43:10 -04:00
Greg Johnston
d1d6126259 chore: add makefile for CI 2024-08-01 19:43:10 -04:00
Greg Johnston
0e979a0767 chore: remove dead code from leptos_dom (now found in tachys) 2024-08-01 19:43:10 -04:00
Greg Johnston
3a4ad07a91 chore: remove unused dependencies 2024-08-01 19:43:10 -04:00
Greg Johnston
f2f35cd785 chore: fix imports in tests 2024-08-01 19:43:10 -04:00
Greg Johnston
c953432659 chore: fmt 2024-08-01 19:43:10 -04:00
Greg Johnston
27f2e60d16 chore: clean up unused imports in tests 2024-08-01 19:43:10 -04:00
Greg Johnston
9330cf23b1 fix: set default storage type for SignalTypes 2024-08-01 19:43:10 -04:00
Greg Johnston
04f5207457 fix: be ready to complete navigation immediately 2024-08-01 19:43:09 -04:00
Greg Johnston
c88409a333 fix: update reactive views for new requirements 2024-08-01 19:43:09 -04:00
Greg Johnston
a2d3d9431c feat: support memos with !Send values 2024-08-01 19:43:09 -04:00
Greg Johnston
213365e4e9 chore: clippy 2024-08-01 19:43:09 -04:00
Greg Johnston
ab3e94dafa chore: clippy 2024-08-01 19:43:09 -04:00
Greg Johnston
3e05b5bcb4 feat: support class = in view macro 2024-08-01 19:43:09 -04:00
Greg Johnston
632ce0f401 fix merge issues 2024-08-01 19:43:09 -04:00
Greg Johnston
93c893f4b3 fix: use correct Request type in Actix extractor 2024-08-01 19:43:09 -04:00
Greg Johnston
4fa72a94fb feat: allow reusing the same endpoint for server functions with different HTTP verbs in their input encodings 2024-08-01 19:43:09 -04:00
Greg Johnston
24775fb59b fix: properly handle islands used in the body of other islands (closes #2725) 2024-08-01 19:43:09 -04:00
Greg Johnston
6c749f5e24 fix: provide a hydration context during route generation 2024-08-01 19:43:09 -04:00
Marc-Stefan Cassola
c22f20ac28 feat: add Effect::watch (#2732) 2024-08-01 19:43:09 -04:00
Greg Johnston
11011c2bda fix: correct async resolution for islands (closes #2734) 2024-08-01 19:43:09 -04:00
Greg Johnston
a51faea9a9 fix: abort when leaving *this* owner, but don't force it if already complete 2024-08-01 19:43:09 -04:00
Greg Johnston
dcc43e574b fix: correctly handle Action abort if it has already completed (closes #2740) 2024-08-01 19:43:09 -04:00
Greg Johnston
6cc0604497 fix: no longer necessary to 'seal' ErrorBoundary (closes #2738) 2024-08-01 19:43:09 -04:00
Chris
8c375534bb fix: leptos_router_macro::path into public api (#2737) 2024-08-01 19:43:09 -04:00
Greg Johnston
f2d6375d93 fix: never resolve LocalResource synchronously (closes #2736) 2024-08-01 19:43:09 -04:00
Greg Johnston
5fb80aaa40 fix: cancel action when original owner, not current owner, is cleaned up (closes #2739) 2024-08-01 19:43:09 -04:00
Greg Johnston
29b0dca1d8 fix: allow Suspense to remount before rebuilding (closes #2721) 2024-08-01 19:43:09 -04:00
Greg Johnston
a6a65ba562 fix: release borrow on shared context when hydrating island (closes #2733) 2024-08-01 19:43:09 -04:00
Greg Johnston
260c624461 fix: serializing island props (closes #2730) 2024-08-01 19:43:09 -04:00
Greg Johnston
0f50aced26 fix: tracking/notifications for AsyncDerived if they start with initial values, and prevent over-notification (closes #2716) 2024-08-01 19:43:09 -04:00
Greg Johnston
1aa2752842 fix: if island is not entry point, update hydration cursor correctly to include island node (closes #2724) 2024-08-01 19:43:09 -04:00
Greg Johnston
b92bfa4ea7 docs: suppress warning about wrong client-side mode after initial call, for things like Portal (closes #2725) 2024-08-01 19:43:09 -04:00
Greg Johnston
30cf1167f2 fix: correct re-exports for islands with props (closes #2723) 2024-08-01 19:43:09 -04:00
Greg Johnston
1c05389707 fix: prevent LocalResource from spawning a local task on the server, when it should only run on the client (closes #2717) 2024-08-01 19:43:09 -04:00
Greg Johnston
1534dd5261 fix: CSR <ErrorBoundary/> 2024-08-01 19:43:09 -04:00
Greg Johnston
8b9685e01d fix: throw_error version 2024-08-01 19:43:09 -04:00
Greg Johnston
d9b590b8e0 fix: unique IDs and correct hydration for <ErrorBoundary/> (closes #2704) 2024-08-01 19:43:09 -04:00
Greg Johnston
25bfc27544 fix: set <Title/> text and formatter in context during client-side rendering (closes #2715) 2024-08-01 19:43:09 -04:00
Greg Johnston
89bbdc58af feat: patch reactive stores in place, only notifying on changed fields 2024-08-01 19:43:09 -04:00
Greg Johnston
4fb00e29d6 chore: remove unused imports 2024-08-01 19:43:09 -04:00
Greg Johnston
54401c6f69 beta version 2024-08-01 19:43:09 -04:00
Greg Johnston
6a705e2a21 chore: clippy 2024-08-01 19:43:09 -04:00
Greg Johnston
43421c56d5 example: use a local signal for the input 2024-08-01 19:43:09 -04:00
Greg Johnston
4c4d3dcfa3 feat: mark branches in AnyView 2024-08-01 19:43:09 -04:00
Greg Johnston
55053da00c chore: clippy 2024-08-01 19:43:09 -04:00
Greg Johnston
be83b5f27e chore: remove unused imports 2024-08-01 19:43:09 -04:00
Greg Johnston
a4ce79769a fix: improve type inference for the default threadsafe signal case 2024-08-01 19:43:09 -04:00
Greg Johnston
e3f64188c2 chore: clippy 2024-08-01 19:43:09 -04:00
Greg Johnston
f7abe727d9 fix: add missing imports 2024-08-01 19:43:09 -04:00
Greg Johnston
eb29d84169 docs: fix cfg for docsrs 2024-08-01 19:43:09 -04:00
Greg Johnston
200047a8bc chore: remove unnecessary default generics 2024-08-01 19:43:09 -04:00
Greg Johnston
634ac1c4a3 chore: clippy and fmt 2024-08-01 19:43:09 -04:00
Saber Haj Rabiee
efe832e39a fix: hackernews_js_fetch example for leptos_0.7 (#2678) 2024-08-01 19:43:09 -04:00
Greg Johnston
1f2b13a976 feat: allow !Send signals 2024-08-01 19:42:51 -04:00
Greg Johnston
d4ec5e187b fix: rename nightly feature for const generic &'static str (d0c11bf6e3\#diff-7b65e42e2b87910c94950caf7f0687fda2f9f98f311099404f5c4afb4a36e50c) 2024-08-01 19:42:51 -04:00
Greg Johnston
4fe7fe725f chore: remove pub field in Suspend so that Suspend::new() must be used 2024-08-01 19:42:51 -04:00
Greg Johnston
a1ca8549a1 chore: fmt 2024-08-01 19:42:51 -04:00
Greg Johnston
e7a8067f9b fix: only create Future once initially, and poll it twice, rather than creating it twice 2024-08-01 19:42:51 -04:00
Greg Johnston
6be090079f chore: fmt 2024-08-01 19:42:51 -04:00
Greg Johnston
8635887ca7 feat: optional branch-marking in HTML to support initial work on client-side islands routing 2024-08-01 19:42:51 -04:00
Corvus
e3482b433b feat: reintroduce queue_microtask (#2703) 2024-08-01 19:42:51 -04:00
Greg Johnston
e6c2f8c614 fix: allow one-element tuples for route matching 2024-08-01 19:42:51 -04:00
Greg Johnston
28fcfe4a46 example: use path! macro in router example 2024-08-01 19:42:51 -04:00
Greg Johnston
75336bc265 fix: add HTML global on___ attributes 2024-08-01 19:42:51 -04:00
boyswan
f4f129caaf feat: add path! macro in router to parse string paths into tuples (#2694) 2024-08-01 19:42:51 -04:00
mahmoud-eltahawy
873aec5787 feat: allow using enums for StaticSegment by implementing AsPath (#2685) 2024-08-01 19:42:51 -04:00
Greg Johnston
a2385e4c42 fix: set None observer properly in ScopedFuture 2024-08-01 19:42:51 -04:00
Greg Johnston
d24f97b59f fix: remove unnecessary untrack in Show 2024-08-01 19:42:51 -04:00
Greg Johnston
51f368c5c5 fix: Suspend::new() in router 2024-08-01 19:42:51 -04:00
Greg Johnston
4107203da2 examples: update to Suspend::new() 2024-08-01 19:42:51 -04:00
Greg Johnston
efb699a319 docs: improved warning location 2024-08-01 19:42:51 -04:00
Greg Johnston
93e6456e19 fix: require Suspend::new() to ensure the Future is properly scoped at creation time, not at render time 2024-08-01 19:42:51 -04:00
Greg Johnston
b24ae7a5e3 fix: explicitly untrack the children of <Show/> 2024-08-01 19:42:51 -04:00
Greg Johnston
bf8d2e079c fix: custom elements should support any attribute names 2024-08-01 19:42:50 -04:00
Greg Johnston
7752ab78e3 fix: custom elements SSR 2024-08-01 19:42:50 -04:00
Greg Johnston
64bc2580ff docs: add tachys docs 2024-08-01 19:42:50 -04:00
Greg Johnston
ddb596feb5 chore: start with a default sandbox, to avoid panics in tests 2024-08-01 19:42:50 -04:00
Greg Johnston
dac4589194 docs: finish reactive graph docs for 0.7 2024-08-01 19:42:50 -04:00
Greg Johnston
8f0a8e05b4 docs: porting docs from 0.6 to 0.7 2024-08-01 19:42:50 -04:00
Greg Johnston
05d01141c5 chore: remove unused AsyncState 2024-08-01 19:42:50 -04:00
Bruno De Simone
66d6038f2d add allow too_many_arguments (#2684) 2024-08-01 19:42:50 -04:00
Greg Johnston
3b09312e1a chore: clippy 2024-08-01 19:42:50 -04:00
Greg Johnston
62cb361031 chore: clippy 2024-08-01 19:42:50 -04:00
Greg Johnston
04c67cb8b6 chore: clear warnings 2024-08-01 19:42:50 -04:00
Greg Johnston
efd060c955 feat: Suspend on style: and class: 2024-08-01 19:42:50 -04:00
Greg Johnston
6290c42159 fix: proper building of paths for nested fields 2024-08-01 19:42:50 -04:00
Greg Johnston
0a89f151be feat: type-erased store Field structs 2024-08-01 19:42:50 -04:00
Greg Johnston
c72c2f4803 fix: allow creating resources inside Suspense 2024-08-01 19:42:50 -04:00
Greg Johnston
c771ab7e71 examples: revert changes to counter 2024-08-01 19:42:50 -04:00
Bruno De Simone
2c4f11b238 remove FromRef implementation from LeptosRoutes axum impl (#2670) 2024-08-01 19:42:50 -04:00
luoxiaozero
12a9e06c5e feat: additional ARIA attributes (#2677) 2024-08-01 19:42:50 -04:00
Greg Johnston
3515469835 feat: iteration over reactive store list 2024-08-01 19:42:50 -04:00
Greg Johnston
e5c159f7a5 feat: add arena-allocated/Copy Store 2024-08-01 19:42:50 -04:00
Greg Johnston
6590749956 docs: initial work on porting docs from 0.6 to 0.7 2024-08-01 19:42:50 -04:00
Greg Johnston
db8f5e4899 feat: initial work on reactive stores 2024-08-01 19:42:50 -04:00
Greg Johnston
6ca3639c3e fix: improved API for unsync actions that doesn't require SendWrapper on input 2024-08-01 19:42:50 -04:00
Greg Johnston
37db7b5d0a chore: leptosfmt 2024-08-01 19:42:50 -04:00
Greg Johnston
8ac1564b90 fix: properly handle errors in streaming body responses 2024-08-01 19:42:50 -04:00
Greg Johnston
e2721d53bd fix: invalid p/ul relationship causing hydration issue 2024-08-01 19:42:50 -04:00
Saber Haj Rabiee
e1f3be6416 chore: cargo fmt (#2672) 2024-08-01 19:42:50 -04:00
Greg Johnston
9536480739 feat: use codee for shared ser-de codexes with leptos-use (and more possibilities in future) 2024-08-01 19:42:50 -04:00
Greg Johnston
5d3a1752c4 chore: remove unused dependencies 2024-08-01 19:42:50 -04:00
Greg Johnston
4b539b524b fix: was disposing of Suspense Owner too early 2024-08-01 19:42:50 -04:00
Greg Johnston
67fe4cc540 fix: rebuilding NodeRef 2024-08-01 19:42:50 -04:00
Greg Johnston
fa731d5018 feat: top-level Suspend without Suspense 2024-08-01 19:42:50 -04:00
Greg Johnston
ccf6703274 chore: clippy and clean up unused functions 2024-08-01 19:42:50 -04:00
Greg Johnston
504c958001 docs: update syntax for Html/Body 2024-08-01 19:42:50 -04:00
Greg Johnston
f7b16b726b feat: correct HTML rendering for spread attributes on <Body/> and <Html/> 2024-08-01 19:42:50 -04:00
Greg Johnston
e9c7b50dfd feat: attributes on body and html 2024-08-01 19:42:50 -04:00
Greg Johnston
208ab97867 feat: move to a channel-based implementation for meta 2024-08-01 19:42:50 -04:00
Greg Johnston
4a0f173bb5 feat: support Suspend in attributes 2024-08-01 19:42:50 -04:00
Greg Johnston
0cf3113812 feat: local resources with .await 2024-08-01 19:42:50 -04:00
Greg Johnston
87f9fa23d5 chore: cfg warnings 2024-08-01 19:42:50 -04:00
Greg Johnston
746bf8e453 fix: MaybeProp None case 2024-08-01 19:42:50 -04:00
Greg Johnston
8b9bcffbb9 reexport SVG and MathML element types 2024-08-01 19:42:50 -04:00
Greg Johnston
dc80e387e3 router alpha 3 2024-08-01 19:42:50 -04:00
Greg Johnston
2006eca1a0 Form component in 0.7 2024-08-01 19:42:50 -04:00
Greg Johnston
1dae77d6b4 fix: don't break Routes SSR now that it uses Suspend 2024-08-01 19:42:50 -04:00
Alicia Garcia-Raboso
2f58191a56 Implement Default trait for signals with a parameter that also implements Default (#2662)
Co-authored-by: alicia.garcia.raboso <alicia.garcia.raboso@bbva.com>
2024-08-01 19:42:50 -04:00
Greg Johnston
a68653b385 feat: automatically replace Suspense blocks if they are still waiting to be flushed, without JS (replaces PartiallyBlocked) 2024-08-01 19:42:50 -04:00
Greg Johnston
d7ca969848 blocking resources 2024-08-01 19:42:50 -04:00
Greg Johnston
fd48a61eef macro alpha 2 2024-08-01 19:42:50 -04:00
Greg Johnston
52a3f84de5 router alpha 2 2024-08-01 19:42:50 -04:00
Luke Naylor
f8283f4674 Add missing 'form' attribute for <mo> (#2660)
This attribute seems to be missing in the attribute
table on Mozilla Docs, however does appear in the
compatibility table lower down.
This attribute is also frequently used by temml,
a common generator for mathml content.
2024-08-01 19:42:50 -04:00
Greg Johnston
989f2989fa allow Outlet to be called multiple times 2024-08-01 19:42:50 -04:00
Greg Johnston
33a3708f91 fix: prevent panicking if conditionally rendering Outlet 2024-08-01 19:42:50 -04:00
Greg Johnston
4eea1f046d remove log 2024-08-01 19:42:50 -04:00
Greg Johnston
8f46288973 fix: ensure correct ownership chain when passing views through Outlet 2024-08-01 19:42:50 -04:00
Greg Johnston
059c8abd2f chore: clippy 2024-08-01 19:42:50 -04:00
Greg Johnston
6885777c75 support MaybeSignal in view 2024-08-01 19:42:50 -04:00
Kajetan Welc
ddc7abf081 fix: impl Copy for Callback (#2658) 2024-08-01 19:42:50 -04:00
Greg Johnston
180511e9bb fix: update imports and methods 2024-08-01 19:42:50 -04:00
Greg Johnston
381ff8a7b0 fix: trait import 2024-08-01 19:42:50 -04:00
Greg Johnston
3ed1ad7b7f impl From<T> for (Arc)Signal<T> 2024-08-01 19:42:50 -04:00
Greg Johnston
2ccf5e99a9 Revert "lazy Future construction for AsyncDerived"
This reverts commit 9e84e1f57c.
2024-08-01 19:42:50 -04:00
Greg Johnston
055701ebf6 fix: <option> struct generation 2024-08-01 19:42:50 -04:00
Greg Johnston
88af893703 fix: <option> struct generation 2024-08-01 19:42:50 -04:00
Lucas Åström
ce4fe632a2 Destructuring let (0.7) (#2655)
* Use `let()` syntax for bindings

This lets users use destructuring when binding more complex values, and we also get better IDE support.

* Update rstml
2024-08-01 19:42:50 -04:00
Greg Johnston
c76208aad0 fix: nonexistent feature 2024-08-01 19:42:50 -04:00
Greg Johnston
514c51ca30 fix: rebuilding AnyView 2024-08-01 19:42:50 -04:00
Greg Johnston
7e3781b5dd support wasm-only 2024-08-01 19:42:50 -04:00
Greg Johnston
97dc3cc2e5 support wasm-only 2024-08-01 19:42:50 -04:00
Greg Johnston
61e51cbe1c support wasm-only 2024-08-01 19:42:50 -04:00
Greg Johnston
efa6d603f9 any_spawner tick version 2024-08-01 19:42:50 -04:00
Greg Johnston
da045f7358 un-break circular dependency 2024-08-01 19:42:50 -04:00
Greg Johnston
8502745036 chore: update test output 2024-08-01 19:42:50 -04:00
Greg Johnston
0a5e6fd85a chore: unused import 2024-08-01 19:42:50 -04:00
Greg Johnston
64fc6cd514 restore fallback for compressed version 2024-08-01 19:42:50 -04:00
Greg Johnston
a2d8fde8cf docs: working on memo docs 2024-08-01 19:42:50 -04:00
Greg Johnston
44eae4c2ed 0.7.0-alpha 2024-08-01 19:42:50 -04:00
Greg Johnston
38d51b01d7 feat: support reactive and asynchronous ProtectedRoute conditions 2024-08-01 19:42:49 -04:00
Greg Johnston
61876dff10 fix: correct For behavior when mounting with siblings, and when clearing 2024-08-01 19:42:49 -04:00
Ben Wishovich
c676cf921d Make get_configuration sync (#2647)
* Made get_configuraiton sync

* Update examples
2024-08-01 19:42:49 -04:00
Greg Johnston
fc59cdaf61 examples: update directives tests 2024-08-01 19:42:49 -04:00
Greg Johnston
081f4ec550 chore: cargo fmt 2024-08-01 19:42:49 -04:00
Greg Johnston
598c59b9c2 make RemoveEventHandler a concrete type 2024-08-01 19:42:49 -04:00
Greg Johnston
9de6c5bb4a feat: add ElementExt to give access to the same view APIs at runtime that we do at compile time 2024-08-01 19:42:49 -04:00
Greg Johnston
f65eaec9ba feat: add ElementExt to give access to the same view APIs at runtime that we do at compile time 2024-08-01 19:42:49 -04:00
Greg Johnston
95756aa2f7 chore: cargo fmt 2024-08-01 19:42:49 -04:00
Greg Johnston
fd121fd8c1 docs: warn on unused RenderEffect 2024-08-01 19:42:49 -04:00
Greg Johnston
c1877354f0 chore: missing Debug implementations 2024-08-01 19:42:49 -04:00
Greg Johnston
be92dc56aa chore: suppress unnecessary .into() warning 2024-08-01 19:42:49 -04:00
Greg Johnston
165a593b32 cargo fmt 2024-08-01 19:42:49 -04:00
Greg Johnston
18b33c7606 updated directives example 2024-08-01 19:42:49 -04:00
brofrain
d2ee093132 fix: update HtmlViewState & BodyViewState as well 2024-08-01 19:42:49 -04:00
Kajetan Welc
83e0438527 fix: do not accidentally mount things before meta tags in the <head> when updating the DOM v2 2024-08-01 19:42:49 -04:00
Greg Johnston
095dc78893 remove log 2024-08-01 19:42:49 -04:00
Greg Johnston
3ebea79e05 preliminary work on directives (not useful yet until we have an ElementExt that allows you to do things declaratively from an Element 2024-08-01 19:42:49 -04:00
Greg Johnston
fe7c7c3a99 omit () entirely if it is the only child of an HTML element 2024-08-01 19:42:49 -04:00
Greg Johnston
8b142c72f0 fix: don't override a text node's 'next sibling after text' position if it's in Either, now that they don't have separate marker nodes 2024-08-01 19:42:49 -04:00
Greg Johnston
70655b57b1 fix: do not accidentally mount things before meta tags in the <head> when updating the DOM 2024-08-01 19:42:49 -04:00
Greg Johnston
c6192badfb fix docs for hydrate_islands 2024-08-01 19:42:49 -04:00
Greg Johnston
5b7f5e3db3 hackernews islands example 2024-08-01 19:42:49 -04:00
Greg Johnston
ae14644806 update static file serving in Axum examples 2024-08-01 19:42:21 -04:00
Greg Johnston
7ca810d8bd fix islands ci setup 2024-08-01 19:42:21 -04:00
Greg Johnston
04e09d2005 fix: remove extra comment at end of Suspense now that Either no longer requires it 2024-08-01 19:42:21 -04:00
Greg Johnston
2916873985 feat: provide static file handling/fallback directly in integration 2024-08-01 19:42:21 -04:00
Greg Johnston
2a558aa3f0 islands example 2024-08-01 19:42:21 -04:00
Greg Johnston
36d16d9253 remove unused tests and dependencies 2024-08-01 19:42:21 -04:00
Greg Johnston
722fd0f6c2 fix: () in templates 2024-08-01 19:42:21 -04:00
Greg Johnston
a42e371e79 chore: clippy 2024-08-01 19:42:21 -04:00
Greg Johnston
11119144d2 fix js-framework-benchmark for stable 2024-08-01 19:42:21 -04:00
Greg Johnston
a0b158f016 update hackernews_axum to 0.7 2024-08-01 19:42:21 -04:00
Greg Johnston
8dc7338b85 fix ErrorBoundary starting in error state in CSR 2024-08-01 19:42:21 -04:00
Greg Johnston
737949cff6 fix example tests 2024-08-01 19:42:21 -04:00
Greg Johnston
d7e17a2ec9 remove unnecessary logs 2024-08-01 19:42:21 -04:00
Greg Johnston
7c5b7fcbb1 update islands example 2024-08-01 19:42:21 -04:00
Greg Johnston
1182aff410 chore: unused hooks 2024-08-01 19:42:21 -04:00
Greg Johnston
bdcd4cb1cc regression test for 7094dee150 2024-08-01 19:42:21 -04:00
Greg Johnston
c74a791d9f fix: signals mark subscribers dirty, but don't say they're always dirty if they haven't changed 2024-08-01 19:42:21 -04:00
Greg Johnston
772a837050 make Routes fallback run lazily 2024-08-01 19:42:21 -04:00
Greg Johnston
92552deb0d make ErrorBoundary fallback run lazily 2024-08-01 19:42:21 -04:00
Greg Johnston
417d345b83 examples: errors_axum 2024-08-01 19:42:21 -04:00
Greg Johnston
3fb2d49d89 chore(ci): fix examples 2024-08-01 19:42:21 -04:00
Greg Johnston
27feaf4309 enable reactive-graph hydration when hydration is enabled 2024-08-01 19:42:21 -04:00
Greg Johnston
35f489a52e allow conversion directly from Arc signal types to MaybeSignal 2024-08-01 19:42:21 -04:00
Greg Johnston
ba8bd2bc82 expose Owner::shared_context() 2024-08-01 19:42:21 -04:00
Greg Johnston
76506c03e1 0.7 Provider component 2024-08-01 19:42:21 -04:00
Greg Johnston
4323e30133 fix tests 2024-08-01 19:42:21 -04:00
Greg Johnston
81c0947ce5 fix reactive styles 2024-08-01 19:42:21 -04:00
Greg Johnston
309a3d504a fix: correctly rebuild reactive attributes to avoid stale signals 2024-08-01 19:42:21 -04:00
Greg Johnston
2a236e043a type-erase RenderEffeect functions for binary size improvements 2024-08-01 19:42:21 -04:00
luoxiaozero
63f8da2fb5 feat: Attr exposes PhantomData field (#2641) 2024-08-01 19:42:21 -04:00
Greg Johnston
c9e32b66bf chore(ci): remove warnings in tests 2024-08-01 19:42:21 -04:00
Greg Johnston
a32c71539d feat: 0.7 query signals 2024-08-01 19:42:21 -04:00
Greg Johnston
f7ee0c4764 chore(ci): add Makefiles for smaller packages 2024-08-01 19:42:21 -04:00
Greg Johnston
7034375cdd chore(ci): only run semver checks if not labeled 'breaking' 2024-08-01 19:42:21 -04:00
Greg Johnston
3c9c5aaf83 chore: clippy 2024-08-01 19:42:21 -04:00
Greg Johnston
ce832cef21 rename from new_serde to new 2024-08-01 19:42:21 -04:00
Greg Johnston
10230d6d65 remove most remaining marker/placeholder elements 2024-08-01 19:42:21 -04:00
Greg Johnston
e4d25608df add trait impls and encodings for SharedValue 2024-08-01 19:42:21 -04:00
Greg Johnston
bd1601e892 default to SerdeJson encoding for resources, use new_str() for Str encoding 2024-08-01 19:42:21 -04:00
Greg Johnston
602ac60a85 feat: synchronous serialized values with SharedValue 2024-08-01 19:42:21 -04:00
Greg Johnston
9e4c0b86f2 whenever we create a new root Owner, set it as the current owner, which will make it the default owner (e.g., during SSR) instead of None 2024-08-01 19:42:21 -04:00
Greg Johnston
4a80c8b65b fix: can't memoize JS properties, because they can be set between signal updates by user input 2024-08-01 19:42:21 -04:00
Greg Johnston
f191bb8324 fix: correctly escape style and class attributes 2024-08-01 19:42:21 -04:00
Greg Johnston
1ff1d48e6e chore: clippy 2024-08-01 19:42:21 -04:00
Greg Johnston
df6a4628c3 don't require spawn_local for actios 2024-08-01 19:42:21 -04:00
Greg Johnston
e28e5ceb1e catch resource reads inside Signal during Suspense 2024-08-01 19:42:21 -04:00
Greg Johnston
e69f62b939 fix CSS file names 2024-08-01 19:42:21 -04:00
Greg Johnston
2c48b07186 update todo app csr 2024-08-01 19:42:21 -04:00
Greg Johnston
0d867ba016 fix: correctly escape text nodes, except in script/style tags 2024-08-01 19:42:21 -04:00
Greg Johnston
3f83ad7dda chore: clean up examples for CI 2024-08-01 19:42:21 -04:00
Greg Johnston
50403846c9 fix: provide matched route via context when rebuilding (so <A> works) 2024-08-01 19:42:21 -04:00
Greg Johnston
4ead16e5d3 unused 2024-08-01 19:42:21 -04:00
Greg Johnston
32f77cc42b refactor insert_before_this to find parent lazily, and use it for rebuilding reactive components by replacing their whole contents 2024-08-01 19:42:21 -04:00
Greg Johnston
d8834a0423 make sure SendWrapper supports Futures 2024-08-01 19:42:21 -04:00
Greg Johnston
0d665c9c05 move several complex examples into projects 2024-08-01 19:42:21 -04:00
Greg Johnston
a03d74494d update js-framework-benchmark example 2024-08-01 19:42:20 -04:00
Greg Johnston
131c83e28e fix test text 2024-08-01 19:42:20 -04:00
Greg Johnston
6d93185478 fix: custom Stream implementation for streaming resource data that supports nested data/multiple polled values, rather than taking it all at once at the beginning 2024-08-01 19:42:20 -04:00
Greg Johnston
202abd1d35 suspense_tests: actually wait for other resource in nested case 2024-08-01 19:42:20 -04:00
Greg Johnston
a50c6b0140 can save a lookup here 2024-08-01 19:42:20 -04:00
Greg Johnston
705ea3a3bb remove unused workspace member 2024-08-01 19:42:20 -04:00
Greg Johnston
cb788758df update workflows 2024-08-01 19:42:20 -04:00
Greg Johnston
1afdc4fe1e remove unused leptos_reactive integration 2024-08-01 19:42:20 -04:00
Greg Johnston
3382047857 remove old router files 2024-08-01 19:42:20 -04:00
Greg Johnston
a29ffc8dcb fix Cargo.toml after merge 2024-08-01 19:42:20 -04:00
Greg Johnston
a18dd6dfd7 re-enable all routes 2024-08-01 19:42:20 -04:00
Greg Johnston
626bcdc9ae chore: clean up warnings and logging 2024-08-01 19:42:20 -04:00
Greg Johnston
d6dce76725 reverted Fn()/FnMut() change 2024-08-01 19:42:20 -04:00
Greg Johnston
36272a0b1b Revert "fix: constrain reactive rendering to Fn(), because using dry_resolve() for Suspense requires idempotent render functions so that they can be called once (to register resources) and called a second time to resolve"
This reverts commit 7ec5c77ba3e8f45bae04a7661a56741f95125adb.
2024-08-01 19:42:20 -04:00
Greg Johnston
96c956efdf progress on updating suspense tests 2024-08-01 19:42:20 -04:00
Greg Johnston
29cf1f4814 add server redirects 2024-08-01 19:42:20 -04:00
Greg Johnston
39c3a63787 fix: relative path resolution 2024-08-01 19:42:20 -04:00
Greg Johnston
068865b7de simplifying todo examples 2024-08-01 19:42:20 -04:00
Greg Johnston
fa8bb15a67 initial work updating suspense tests 2024-08-01 19:42:20 -04:00
Greg Johnston
faa481f2b6 clarify hydrate/csr warning 2024-08-01 19:42:20 -04:00
Greg Johnston
b41d988865 export actions in prelude 2024-08-01 19:42:20 -04:00
Greg Johnston
025c28b489 remove Into<_> by default for setting signals, because it interferes with type inference 2024-08-01 19:42:20 -04:00
Greg Johnston
0c7c7c9b38 add support for unsync actions 2024-08-01 19:42:20 -04:00
Greg Johnston
b109c3e9a3 simplifying and updating server fns example 2024-08-01 19:42:20 -04:00
Greg Johnston
0a559935e7 change name to shell 2024-08-01 19:42:20 -04:00
Greg Johnston
bccc05fec8 update control flow components to new Fn() constraint 2024-08-01 19:42:20 -04:00
Greg Johnston
e0f98dc0fd fix: constrain reactive rendering to Fn(), because using dry_resolve() for Suspense requires idempotent render functions so that they can be called once (to register resources) and called a second time to resolve 2024-08-01 19:42:20 -04:00
Greg Johnston
5d9bd8f913 add Debug impl 2024-08-01 19:42:20 -04:00
Greg Johnston
0a41ae9a5e fix: actually concatenate nested routes during route generation 2024-08-01 19:42:20 -04:00
Greg Johnston
fbc6be922d reorganize Outlet export 2024-08-01 19:42:20 -04:00
Greg Johnston
b5551863fe examples: porting to 0.7 and cleaning up 2024-08-01 19:42:20 -04:00
Greg Johnston
14b3877293 fix merge 2024-08-01 19:41:56 -04:00
Rakshith Ravi
98ea18009d Update import statements in examples (#2625) 2024-08-01 19:41:56 -04:00
Greg Johnston
d133cff092 examples: use application 404 page 2024-08-01 19:41:56 -04:00
Greg Johnston
48028b476a chore: cargo fmt 2024-08-01 19:41:56 -04:00
Greg Johnston
404ad50bd3 chore: cargo fmt 2024-08-01 19:41:56 -04:00
Greg Johnston
b89fbe027b add warnings if correct features not set for browser 2024-08-01 19:41:56 -04:00
Greg Johnston
0ba53afa08 use csr feature so that reactivity runs 2024-08-01 19:41:55 -04:00
Greg Johnston
c384b53a0f chore: clippy 2024-08-01 19:41:55 -04:00
Greg Johnston
2f53e09bb6 examples: fix input type so tests work, and update text to make the purpose clearer 2024-08-01 19:41:55 -04:00
Greg Johnston
319eefb169 remove leptos_reactive (moved into reactive_graph and leptos_server) 2024-08-01 19:41:55 -04:00
Greg Johnston
949f43d145 fix: Clone for ArcResource and default to SerdeJson for Resource 2024-08-01 19:41:55 -04:00
Greg Johnston
a47759007f chore: clippy 2024-08-01 19:41:55 -04:00
Greg Johnston
095faf15b1 fix: don't dispose of parent owners before Suspense children have been rendered 2024-08-01 19:41:55 -04:00
Greg Johnston
f9eb562050 warn if trying to use meta on server side without context 2024-08-01 19:41:55 -04:00
Greg Johnston
7f57b88e8d only run RenderEffects when effects are enabled 2024-08-01 19:41:55 -04:00
Greg Johnston
8a8862be9e add set_pending to <Transition/> 2024-08-01 19:41:55 -04:00
Greg Johnston
619dc59e1d simplify FlatRoutes logic by using existing OwnedView infrastructure 2024-08-01 19:41:55 -04:00
Greg Johnston
5f49504137 reexport tick() for testing 2024-08-01 19:41:55 -04:00
Greg Johnston
ca68fa5a3d fix: ensure that leptos_meta and leptos_router are in SSR mode if using one of the server integrations 2024-08-01 19:41:55 -04:00
Greg Johnston
e6a472b467 examples: update hackernews for SSR support 2024-08-01 19:41:55 -04:00
Greg Johnston
f8da9e30e0 fix: correctly notify multiple subscribers to same AsyncDerived 2024-08-01 19:41:36 -04:00
Greg Johnston
984ede8887 fix: Routes SSR 2024-08-01 19:41:36 -04:00
Greg Johnston
c3656416a2 fix: correct owner for HTML rendering in FlatRoutes 2024-08-01 19:41:36 -04:00
Greg Johnston
7ecfbd9109 testing: provide tick() that can be called anywhere in tests 2024-08-01 19:41:36 -04:00
Greg Johnston
531c39759a testing: provide tick() that can be called anywhere in tests 2024-08-01 19:41:36 -04:00
Greg Johnston
f5d06577f4 fix portal tests 2024-08-01 19:41:36 -04:00
Greg Johnston
39902d1e66 fix cleanups in render effects 2024-08-01 19:41:36 -04:00
Greg Johnston
7def5f65ed chore: clippy 2024-08-01 19:41:36 -04:00
Greg Johnston
6b60d48203 update counters_isomorphic 2024-08-01 19:41:36 -04:00
Greg Johnston
9ef51166d3 reexport spawn and spawn_local 2024-08-01 19:41:27 -04:00
Greg Johnston
8da6bbc3be ReadSignal from stream 2024-08-01 19:41:27 -04:00
Greg Johnston
3c39674622 refactor to allow rendering Resource directly in view 2024-08-01 19:41:27 -04:00
Greg Johnston
914b07491e removed AnimatedShow example (duplicates the component docs) 2024-08-01 19:41:27 -04:00
Greg Johnston
1d2d11b83d properly serialize errors 2024-08-01 19:41:27 -04:00
Greg Johnston
07e878adf7 chore: clear warning 2024-08-01 19:41:27 -04:00
Greg Johnston
f32d43ce94 pick up on server action error in both server and client 2024-08-01 19:41:27 -04:00
Greg Johnston
65e3c57ed1 fmt and chores in examples 2024-08-01 19:41:27 -04:00
Greg Johnston
2e40bace88 fix: serialize an empty string into HTML so it still works as a text node 2024-08-01 19:41:27 -04:00
Greg Johnston
b9945e0ce1 fix: make router fallback lazy 2024-08-01 19:41:27 -04:00
Greg Johnston
d7f70214b9 add expect_context 2024-08-01 19:41:27 -04:00
Greg Johnston
adf57f5771 fix attr:class when spreading onto a component 2024-08-01 19:41:27 -04:00
Greg Johnston
bae79e2b2c add ServerAction error handling for any error type (closes #2325) 2024-08-01 19:41:27 -04:00
Greg Johnston
e2b1210461 remove unused import 2024-08-01 19:41:13 -04:00
Greg Johnston
7c24b7482d clean up example 2024-08-01 19:41:13 -04:00
Greg Johnston
25c66a4624 add CollectView 2024-08-01 19:41:13 -04:00
Greg Johnston
71ddacef8e Actix todo_app_sqlite 2024-08-01 19:41:13 -04:00
Greg Johnston
338b01bee3 fix: don't drop Owner in FlatRoutes until route has been rendered (thanks @benwis) 2024-08-01 19:41:13 -04:00
Greg Johnston
a36f22e439 fix: make sure all resource reads are registered 2024-08-01 19:41:13 -04:00
Greg Johnston
56977411f2 chore: clippy and unused dependencies in integrations 2024-08-01 19:41:13 -04:00
Greg Johnston
0fc47e3a35 add some tracing and debug info to HTML elements 2024-08-01 19:41:13 -04:00
Greg Johnston
caf797dba0 refactor integrations and add Actix integration 2024-08-01 19:41:13 -04:00
Greg Johnston
2f54d937a1 feat: 0.7 nonce support 2024-08-01 19:41:13 -04:00
Greg Johnston
40c1f38a07 ResponseOptions support 2024-08-01 19:41:13 -04:00
Greg Johnston
402d6297f4 fix counters tests 2024-08-01 19:41:13 -04:00
Greg Johnston
93734a5222 allow .children() on HTML elements 2024-08-01 19:41:13 -04:00
Greg Johnston
770d02d8e6 remove async demo 2024-08-01 19:41:13 -04:00
Greg Johnston
e275862a20 fix: writing to lock that has a read 2024-08-01 19:41:13 -04:00
Greg Johnston
17f1d25d03 allow untracking on write guards to support maybe_update 2024-08-01 19:41:13 -04:00
Greg Johnston
0a99a378aa feat: allow .write() on all writeable signals 2024-08-01 19:41:13 -04:00
Greg Johnston
14b7073863 feat: add .by_ref() to create a Future from an AsyncDerived (etc.) that takes a reference, rather than cloning 2024-08-01 19:41:12 -04:00
Greg Johnston
4e4deef144 use impl trait in props 2024-08-01 19:41:12 -04:00
Greg Johnston
c360f0ed0d update wasm-bindgen testing approaches 2024-08-01 19:41:12 -04:00
Greg Johnston
88ab9693db chore: clearing warnings in examples 2024-08-01 19:41:12 -04:00
Greg Johnston
6dfea0b0a2 additional warnings 2024-08-01 19:41:12 -04:00
Greg Johnston
9fd881603f cargo fmt 2024-08-01 19:41:12 -04:00
Greg Johnston
9666c9c0c5 chore: clear up... a few warnings 2024-08-01 19:41:12 -04:00
Greg Johnston
9e8b304b8a update sledgehammer integration 2024-08-01 19:41:12 -04:00
Greg Johnston
064ccce5b1 remove signal function setter Send-only implementation (dead code) 2024-08-01 19:41:12 -04:00
Greg Johnston
2e31177f62 remove signal function call Read implementations (dead code) 2024-08-01 19:41:12 -04:00
Greg Johnston
4215cef04b remove leptos_reactive dependency 2024-08-01 19:41:12 -04:00
Greg Johnston
de3dd3c296 oco merge issues 2024-08-01 19:41:12 -04:00
Greg Johnston
846ff2fefb feat: return an async guard from .await rather than cloning the value every time 2024-08-01 19:41:12 -04:00
Greg Johnston
6003212f6e fix return type in async tests 2024-08-01 19:41:11 -04:00
Greg Johnston
054cff7883 fix tests that run effects 2024-08-01 19:41:11 -04:00
Greg Johnston
ce5738d7c4 feat: return Option from AsyncDerived.get() instead of AsyncState 2024-08-01 19:41:11 -04:00
Greg Johnston
47331b5c8d example: restore ErrorBoundary 2024-08-01 19:41:11 -04:00
Greg Johnston
a6cee3b1e9 docs for Owner and context 2024-08-01 19:41:11 -04:00
Greg Johnston
43c0e384c4 fix tests 2024-08-01 19:41:11 -04:00
Greg Johnston
db654cbfda poll AsyncDerived synchronously so that it has the correct value during hydration if it reads from a resource 2024-08-01 19:41:11 -04:00
Greg Johnston
e13b1561d8 correct dirty-checking on AsyncDerived 2024-08-01 19:41:11 -04:00
Greg Johnston
02f76dec35 fix regular suspense if nothing was read synchronously 2024-08-01 19:41:11 -04:00
Greg Johnston
4bd99a41e5 missing dry_resolve on Static 2024-08-01 19:41:11 -04:00
Greg Johnston
85d29a5af5 feat: support *either* .await or reactive reads inside Suspense 2024-08-01 19:41:11 -04:00
Greg Johnston
4d54574f9e feat: 0.7 slots 2024-08-01 19:41:11 -04:00
Greg Johnston
f6c7ac473a feat: enhanced spreading syntax 2024-08-01 19:41:11 -04:00
Greg Johnston
747d847183 fix external navigations 2024-08-01 19:41:11 -04:00
Greg Johnston
8dd63a402b make WindowListenerHandle Send + Sync so it can be remove via on_cleanup 2024-08-01 19:41:11 -04:00
Greg Johnston
694eccbadc restore ssr/hydration for Routes 2024-08-01 19:41:11 -04:00
Greg Johnston
24f2e71563 get nested Routes working again 2024-08-01 19:41:11 -04:00
Greg Johnston
1766bfedb9 default to Params::get() giving an owned value (which you want in a derived signal), but use reference in the macro 2024-08-01 19:41:11 -04:00
Greg Johnston
242d35cc37 add proper dirty checking on AsyncDerived so it can read from memos properly 2024-08-01 19:41:11 -04:00
Greg Johnston
85b9f87620 make NavigateOptions pub 2024-08-01 19:41:11 -04:00
Greg Johnston
db33bc2e61 feat: owning memo 2024-08-01 19:41:11 -04:00
Greg Johnston
a1329ea044 remove warnings in tests and only run if effects are enabled 2024-08-01 19:41:11 -04:00
Greg Johnston
050bf8f821 fix: prevent memos that have changed from re-triggering the running effect, by setting the Observer during .update_if_necessary() 2024-08-01 19:41:11 -04:00
Greg Johnston
1a68743fcc feat: add Popover API 2024-08-01 19:41:11 -04:00
Greg Johnston
2925db8676 fix Script children 2024-08-01 19:41:11 -04:00
Greg Johnston
13d5f12d7f fix hydration of Suspend by including the missing placeholder it expects during hydration 2024-08-01 19:41:11 -04:00
Greg Johnston
3d9c295613 add missing marker comments for Result 2024-08-01 19:41:11 -04:00
Greg Johnston
b2c0068e2c include marker comments in html len 2024-08-01 19:41:11 -04:00
Greg Johnston
94a3f7c092 unused owner 2024-08-01 19:41:11 -04:00
Greg Johnston
330dcfeb7c impl From/Into for Signal/ArcSignal 2024-08-01 19:41:11 -04:00
Greg Johnston
f7bbec5f06 add ArcSignal::derive() 2024-08-01 19:41:11 -04:00
Greg Johnston
8815529955 routing progress indicator 2024-08-01 19:41:11 -04:00
Greg Johnston
12db58a7e0 missing min attribute 2024-08-01 19:41:11 -04:00
Greg Johnston
83c9edde26 clean up 2024-08-01 19:41:11 -04:00
Greg Johnston
2037a6966a remove log 2024-08-01 19:41:11 -04:00
Greg Johnston
4f041f5a5e relax trait bounds on reactive types where possible 2024-08-01 19:41:11 -04:00
Greg Johnston
6467e067ef add SignalSetter 2024-08-01 19:41:11 -04:00
Greg Johnston
3814879d80 use transition between navigations 2024-08-01 19:41:11 -04:00
Greg Johnston
5e16ae6a26 add async transitions that wait for any AsyncDerived created/triggered under them before resolving 2024-08-01 19:41:11 -04:00
Greg Johnston
6d474713f6 resolve() on OwnedView 2024-08-01 19:41:11 -04:00
Greg Johnston
0d47399424 restore hydration feature for some of its feature-gating benefits for Resource deserialization 2024-08-01 19:41:11 -04:00
Greg Johnston
ae254836d7 cargo fmt 2024-08-01 19:41:11 -04:00
Greg Johnston
2dd5efc5d0 create separate URL/params signals for each route, to prevent updating them and running side effects while navigating away 2024-08-01 19:41:11 -04:00
Greg Johnston
15eeda9c7a fmt 2024-08-01 19:41:11 -04:00
Greg Johnston
1a739015e1 distinguish between dirty and check in effects, so that memos and signals both work correctly 2024-08-01 19:41:11 -04:00
Greg Johnston
8385287123 remove unused feature 2024-08-01 19:41:11 -04:00
Greg Johnston
c4aa3ba1ba updated future impls 2024-08-01 19:41:11 -04:00
Greg Johnston
ce5f2c81ed check whether ArcAsyncDerived actually needs to run when marked check 2024-08-01 19:41:11 -04:00
Greg Johnston
941689fc5b add ancestry debugging for owners 2024-08-01 19:41:11 -04:00
Greg Johnston
961bf89a8b lazy Future construction for AsyncDerived 2024-08-01 19:41:11 -04:00
Greg Johnston
d360cc280f support Resource in CSR for backward-compat 2024-08-01 19:41:11 -04:00
Greg Johnston
bb7bb8f4c2 allow let: syntax to work 2024-08-01 19:41:11 -04:00
Greg Johnston
b29b8fb5ff scope Suspense/Transition correctly within ownership tree 2024-08-01 19:41:11 -04:00
Greg Johnston
4ffa3c46b6 upgrading hackernews example 2024-08-01 19:41:10 -04:00
Greg Johnston
32294d6cab immediately commit URL signal updates 2024-08-01 19:40:57 -04:00
Greg Johnston
46d286755e reexport A from router::components 2024-08-01 19:40:57 -04:00
Greg Johnston
b936e0352f add IntoAny to tachys prelude 2024-08-01 19:40:57 -04:00
Greg Johnston
b5bd70ab94 finish support for innerHTML 2024-08-01 19:40:57 -04:00
Greg Johnston
0dd1932b7f feat: iterating over items in children with ChildrenFragment, ChildrenFragmentFn, ChildrenFragmentMut 2024-08-01 19:40:57 -04:00
Greg Johnston
f5d203f0c9 only warn about non-reactive accesses if effects are enabled 2024-08-01 19:40:57 -04:00
Greg Johnston
1bc0b414e3 only run effects on client 2024-08-01 19:40:57 -04:00
Greg Johnston
d6e19c0a60 resolve() implementation for AnyView 2024-08-01 19:40:57 -04:00
Greg Johnston
fc60d6b2d7 fix deadlock on nested Signals 2024-08-01 19:40:57 -04:00
Greg Johnston
292e7c1f27 fix FlatRouter SSR/hydration after lazy routes 2024-08-01 19:40:57 -04:00
Greg Johnston
1da84db1aa feat: nested islands with context for 0.7 2024-08-01 19:40:57 -04:00
Greg Johnston
535e3e3880 fix: correct Send + Sync bounds for children 2024-08-01 19:40:57 -04:00
Greg Johnston
109244b28b feat: minimal island support in 0.7 2024-08-01 19:40:57 -04:00
Greg Johnston
fd048295a4 docs: full docs and doctests for Action/MultiAction 2024-08-01 19:40:57 -04:00
Greg Johnston
26cf4848db remove support for rendering guards directly, as they are !Send and holding onto them in State is also a bad idea 2024-08-01 19:40:57 -04:00
Greg Johnston
757a5c73c3 support nightly static values for style:key="value" 2024-08-01 19:40:57 -04:00
Greg Johnston
da496def16 revert to using .get() for function calls 2024-08-01 19:40:57 -04:00
Greg Johnston
3a755bd8c3 fix: only rerun effects if they have dirty ancestors (or it's the first run) 2024-08-01 19:40:57 -04:00
Greg Johnston
e514f7144d start working on porting over docs and tests and 0.7... 2024-08-01 19:40:57 -04:00
Greg Johnston
b881167b8f fix meta issue with attributes 2024-08-01 19:40:57 -04:00
Greg Johnston
1e9d345831 fix tracing issue 2024-08-01 19:40:57 -04:00
Greg Johnston
7f7bba6ea3 chore: get tests in a working state 2024-08-01 19:40:57 -04:00
Greg Johnston
015a4b63ec fix: make Selector Send/Sync 2024-08-01 19:40:57 -04:00
Greg Johnston
dcec7af4f3 docs: runtime warning if you use .track() outside a tracking context 2024-08-01 19:40:57 -04:00
Greg Johnston
5bc97654dc preliminary tracing for tachys 2024-08-01 19:40:57 -04:00
Greg Johnston
2788d93e96 chore: warnings 2024-08-01 19:40:57 -04:00
Greg Johnston
604043b4d8 examples: router in 0.7 2024-08-01 19:40:57 -04:00
Greg Johnston
ab28c80593 fix: passing context through router 2024-08-01 19:40:57 -04:00
Greg Johnston
49da073fed chore: fix warnings about variable case 2024-08-01 19:40:57 -04:00
Greg Johnston
3629302f88 examples: timer in 0.7 2024-08-01 19:40:57 -04:00
Greg Johnston
274e31018b feat: Portals in 0.7 2024-08-01 19:40:57 -04:00
Greg Johnston
802fcc5c2a allow either eager or lazy routes 2024-08-01 19:40:57 -04:00
Greg Johnston
da084a2ece update StoredValue API in callbacks 2024-08-01 19:40:57 -04:00
Greg Johnston
d9f6836933 chore: clippy warnings 2024-08-01 19:40:57 -04:00
Greg Johnston
d8d2fdac5d smooth out StoredValue APIs 2024-08-01 19:40:57 -04:00
Greg Johnston
9818e7cb68 MaybeSignal and MaybeProp 2024-08-01 19:40:57 -04:00
Marc-Stefan Cassola
986fbe5328 added a few old deprecated functions to help users port (#2580) 2024-08-01 19:40:57 -04:00
Greg Johnston
711175a760 implement With(Untracked) for Signal 2024-08-01 19:40:57 -04:00
Greg Johnston
00a536a5dc don't over-rerender nested router 2024-08-01 19:40:57 -04:00
Greg Johnston
a7b1152910 initial async routing work (to support bundle splitting) 2024-08-01 19:40:57 -04:00
Greg Johnston
cfba7a2797 noop attribute 'spreading' for routers 2024-08-01 19:40:57 -04:00
Greg Johnston
cebe744a84 support arbitrary attributes on components in view 2024-08-01 19:40:57 -04:00
Greg Johnston
e93a34a2c9 full attribute spreading 2024-08-01 19:40:57 -04:00
Greg Johnston
9ec30d71d2 update counter_without_macros imports 2024-08-01 19:40:57 -04:00
Greg Johnston
3c13280bf6 stashing 2024-08-01 19:40:57 -04:00
Greg Johnston
45fd9423f8 give a route to upgrade any attribute into a cloneable one 2024-08-01 19:40:56 -04:00
Greg Johnston
7a92208c4f work on attribute spreading 2024-08-01 19:40:56 -04:00
Greg Johnston
89b972e3c5 disable AddAnyAttr again now that I remember why it was broken 2024-08-01 19:40:56 -04:00
Greg Johnston
8dac92b251 reenable AnyAttr 2024-08-01 19:40:56 -04:00
Greg Johnston
b24eaedfe9 reorganizing exports and updating examples 2024-08-01 19:40:56 -04:00
Greg Johnston
4336051f78 prep for preview release 2024-08-01 19:40:56 -04:00
Greg Johnston
97ce5adb8e fix reorganized exports 2024-08-01 19:40:56 -04:00
Greg Johnston
20fb5454b0 prep for preview release 2024-08-01 19:40:56 -04:00
Greg Johnston
aac607f338 prep for preview release 2024-08-01 19:40:56 -04:00
Greg Johnston
738986415d prep for preview release 2024-08-01 19:40:56 -04:00
Greg Johnston
3406446ebd module restructuring for 0.7 2024-08-01 19:40:56 -04:00
Greg Johnston
21dd7e9c76 let ErrorBoundary own the fallback 2024-08-01 19:40:56 -04:00
Greg Johnston
9bab4da172 make Suspend a transparent wrapper 2024-08-01 19:40:56 -04:00
Greg Johnston
420dccda60 provide params properly in FlatRouter 2024-08-01 19:40:56 -04:00
Greg Johnston
53b22a9b74 clear some warnings 2024-08-01 19:40:56 -04:00
Greg Johnston
e68730d15f rename TupleBuilder to NextTuple and prep for release 2024-08-01 19:40:56 -04:00
Greg Johnston
11d134c4ba prep for preview release 2024-08-01 19:40:56 -04:00
Greg Johnston
2239f04f6b prep for preview release 2024-08-01 19:40:56 -04:00
Greg Johnston
78e5a7ebc3 prep for preview release 2024-08-01 19:40:56 -04:00
Greg Johnston
0148d92f48 prep for preview release 2024-08-01 19:40:56 -04:00
Greg Johnston
ab67bea7ec rename any_error 2024-08-01 19:40:56 -04:00
Greg Johnston
0beef3b2e0 prep for preview release 2024-08-01 19:40:56 -04:00
Greg Johnston
81fc7e6ada remove twiggy file 2024-08-01 19:40:56 -04:00
Greg Johnston
75d6763f4e move router crates 2024-08-01 19:40:56 -04:00
Greg Johnston
da4d2cf538 comparison demo 2024-08-01 19:40:25 -04:00
Greg Johnston
2470637b0b SSR optimizations for binary size, and flat router 2024-08-01 19:40:25 -04:00
Greg Johnston
2934c295b5 work on Axum integration and on error boundaries 2024-08-01 19:40:25 -04:00
Greg Johnston
789eef914d stash 2024-08-01 19:40:25 -04:00
Greg Johnston
782cb93743 feat: add <A> 2024-08-01 19:40:25 -04:00
Greg Johnston
8642c563d8 add use_navigate and Redirect 2024-08-01 19:40:25 -04:00
Greg Johnston
755fbd3866 preliminary use_navigate work 2024-08-01 19:40:25 -04:00
Greg Johnston
d83471e02b fix fallback => match update 2024-08-01 19:40:25 -04:00
Greg Johnston
2dd2bb5958 add more hooks and primitives to router 2024-08-01 19:40:25 -04:00
Greg Johnston
12f2cec5c7 nested route CSR working 2024-08-01 19:40:25 -04:00
Greg Johnston
a41bf2784f continuing on nested routes 2024-08-01 19:40:25 -04:00
Greg Johnston
ebdd31cd9f continuing on nested routes 2024-08-01 19:40:25 -04:00
Greg Johnston
acec3bb313 working on reconfiguring nested routing 2024-08-01 19:40:25 -04:00
Greg Johnston
464f157186 make placeholder-finding code consistent across container types 2024-08-01 19:40:25 -04:00
Greg Johnston
b53e4d8ff8 remove logs 2024-08-01 19:40:25 -04:00
Greg Johnston
cd438e0bcf fix Transition hydration 2024-08-01 19:40:25 -04:00
Greg Johnston
13da1e743d remove TryCatch/fallible rendering in favor of better ErrorBoundary model 2024-08-01 19:40:25 -04:00
Greg Johnston
0c9167fd30 finish todo_app_sqlite_axum 2024-08-01 19:40:25 -04:00
Greg Johnston
52da0e43ac fix Vec hydration 2024-08-01 19:40:25 -04:00
Greg Johnston
dad91f5960 add MultiActionForm 2024-08-01 19:40:25 -04:00
Greg Johnston
72e97047a5 add MultiAction/ServerMultiAction 2024-08-01 19:40:25 -04:00
Greg Johnston
883fd57fe1 stash 2024-08-01 19:40:25 -04:00
Greg Johnston
42b99dd912 ErrorBoundary SSR and serialization of errors to support hydration 2024-08-01 19:40:25 -04:00
Greg Johnston
851e1f73fd get types working with nested ErrorBoundary/Suspense 2024-08-01 19:40:25 -04:00
Greg Johnston
e11eea1af1 probably as far as I can go with the current SuspenseBoundary approach 2024-08-01 19:40:25 -04:00
Greg Johnston
f508cc4510 fix static types 2024-08-01 19:40:25 -04:00
Greg Johnston
e4f3cf9cca fix cancellation logic for server fn requests 2024-08-01 19:40:25 -04:00
Greg Johnston
60d883a26c only subscribe to memo manually if already loaded 2024-08-01 19:40:25 -04:00
Greg Johnston
add3be0ff5 Suspense SSR 2024-08-01 19:40:25 -04:00
Greg Johnston
a01640cafd updates toward todo_app_sqlite 2024-08-01 19:40:25 -04:00
Greg Johnston
e837e9fded fix stable examples 2024-08-01 19:40:25 -04:00
Greg Johnston
e0e67360aa implement rendering traits for signals directly on stable 2024-08-01 19:40:25 -04:00
Greg Johnston
439deea066 suspend!() macro 2024-08-01 19:40:25 -04:00
Greg Johnston
e5f5710f46 add Transition 2024-08-01 19:40:25 -04:00
Greg Johnston
8626db27d7 loosen requirements for Show 2024-08-01 19:40:25 -04:00
Greg Johnston
ec3f0933fe working on examples 2024-08-01 19:40:25 -04:00
Greg Johnston
b50de3a005 finish TodoMVC example 2024-08-01 19:40:25 -04:00
Greg Johnston
aa878534ad simplify Suspense: this should still work with hydration 2024-08-01 19:40:25 -04:00
Greg Johnston
603f9f96c4 working model for Suspense with new version 2024-08-01 19:40:25 -04:00
Greg Johnston
f78e675506 probably as far as I can go with the current SuspenseBoundary approach 2024-08-01 19:40:24 -04:00
Greg Johnston
cc2714c03d fix ErrorBoundary/Suspense 2024-08-01 19:40:24 -04:00
Greg Johnston
c06110128b feat: ErrorBoundary and Suspense 2024-08-01 19:40:24 -04:00
Greg Johnston
d7c62622ae feat: ErrorBoundary 2024-08-01 19:40:24 -04:00
Greg Johnston
1edec6c36a fix Cargo.toml merge issues 2024-08-01 19:40:24 -04:00
Greg Johnston
c5049ca1bb working on examples 2024-08-01 19:40:24 -04:00
Greg Johnston
f69dbb48ca styling with CSS 2024-08-01 19:40:24 -04:00
Greg Johnston
5feaf1aea6 example with isomorphic GTK/web design system 2024-08-01 19:40:24 -04:00
Greg Johnston
ec3ab6a355 gtk example 2024-08-01 19:40:24 -04:00
Greg Johnston
100ed7d926 ErrorBoundary component 2024-08-01 19:40:24 -04:00
Greg Johnston
88b93f40f9 Suspense/Transition components 2024-08-01 19:40:24 -04:00
Greg Johnston
b8b77138ea GTK example for 0.7 2024-08-01 19:40:24 -04:00
Greg Johnston
20c29cab89 add serde-wasm-bindgen encoding for resources 2024-08-01 19:40:24 -04:00
Greg Johnston
54fd74839a add typed children 2024-08-01 19:40:24 -04:00
Greg Johnston
ea3790d91c scope Arena to each request 2024-08-01 19:40:24 -04:00
Greg Johnston
f5935c6333 correctly omit HTML-generating code from AnyView 2024-08-01 19:40:24 -04:00
Greg Johnston
c8e5e1b16b experimental sledgehammer Renderer backend 2024-08-01 19:40:24 -04:00
Greg Johnston
a12c707f3f fix async context issues, add flat routing 2024-08-01 19:40:24 -04:00
Greg Johnston
6d9906111d test more dynamic string length work 2024-08-01 19:40:24 -04:00
Greg Johnston
5ea314c998 attribute value escaping 2024-08-01 19:40:24 -04:00
Greg Johnston
2bc04444e1 work related to 0.7 blog port 2024-08-01 19:40:24 -04:00
Greg Johnston
b41fde3ff9 work related to 0.7 blog port 2024-08-01 19:40:24 -04:00
Greg Johnston
c29081b12a completing work on meta 2024-08-01 19:40:24 -04:00
Greg Johnston
2fefc8b4bf completing work on meta 2024-08-01 19:40:24 -04:00
Greg Johnston
72b43d1e2b initial work on meta 2024-08-01 19:40:24 -04:00
Greg Johnston
39607adc94 initial work on meta 2024-08-01 19:40:24 -04:00
Greg Johnston
30c1cd921b stash 2024-08-01 19:40:24 -04:00
Greg Johnston
abfe3cabd2 fix nested route rebuilding 2024-08-01 19:40:24 -04:00
Greg Johnston
16bd2942db navigation between nested routes 2024-08-01 19:40:24 -04:00
Greg Johnston
13cccced06 initial stage for working nested route rendering 2024-08-01 19:40:24 -04:00
Greg Johnston
db4c1cb4b3 stash 2024-08-01 19:40:24 -04:00
Greg Johnston
9cdd8cac15 stash 2024-08-01 19:40:24 -04:00
Greg Johnston
84ebdc1b92 get basic routing working 2024-08-01 19:40:24 -04:00
Greg Johnston
9f02cc8cc1 stash 2024-08-01 19:40:24 -04:00
Greg Johnston
c3b9932172 reorganize 2024-08-01 19:40:24 -04:00
Greg Johnston
dbd9951a85 working on nesting routing 2024-08-01 19:40:24 -04:00
Greg Johnston
6eb8b44fff reorganize 2024-08-01 19:40:24 -04:00
Greg Johnston
4fa31be5dc stash 2024-08-01 19:40:24 -04:00
Greg Johnston
b46dffb729 abstract interface to walk nested routes and to access views 2024-08-01 19:40:24 -04:00
Greg Johnston
ca54762806 reorganize and clean up 2024-08-01 19:40:24 -04:00
Greg Johnston
f122f9109f nested route matching 2024-08-01 19:40:24 -04:00
Greg Johnston
f894d6e4f6 stash 2024-08-01 19:40:24 -04:00
Greg Johnston
4cc925c950 stash 2024-08-01 19:40:24 -04:00
Greg Johnston
21e53042e8 work on routing utils 2024-08-01 19:40:24 -04:00
Greg Johnston
4d3fb37b35 nested route matching working 2024-08-01 19:40:24 -04:00
Greg Johnston
d3a21c922d stash 2024-08-01 19:40:24 -04:00
Greg Johnston
317f90e1e3 use either_of crate 2024-08-01 19:40:24 -04:00
Greg Johnston
26869a78a0 nested routes take 1 2024-08-01 19:40:24 -04:00
Greg Johnston
f46f864f05 split EitherOfX into its own crate 2024-08-01 19:40:24 -04:00
Greg Johnston
b21f1853c6 work on routing 2024-08-01 19:40:24 -04:00
Greg Johnston
1454c5d272 work on routing 2024-08-01 19:40:24 -04:00
Greg Johnston
c1f4616a31 set up routing 2024-08-01 19:40:24 -04:00
Greg Johnston
a3c3478831 clear warning 2024-08-01 19:40:24 -04:00
Greg Johnston
1ca8a9189c chore: clear warnings 2024-08-01 19:40:24 -04:00
Greg Johnston
9e276a8879 pass on: to components (and lay basis for passing all other attributes) 2024-08-01 19:40:24 -04:00
Greg Johnston
53703f208a working on AddAttr 2024-08-01 19:40:24 -04:00
Greg Johnston
9a60b21a0a remove boilerplate: require that Node, Element, etc. types always be Clone + 'static 2024-08-01 19:40:24 -04:00
Greg Johnston
524ed395fa parent_child example 2024-08-01 19:40:24 -04:00
Greg Johnston
5bc8c4e0d3 use AnyError for all try_ rendering errors, so that they can compose 2024-08-01 19:40:24 -04:00
Greg Johnston
7f7003f7f1 support for guards with class: syntax 2024-08-01 19:40:24 -04:00
Greg Johnston
ddf2ac0cf7 add Borrow implementation to make it easier to abstract over T and Guard<T> 2024-08-01 19:40:24 -04:00
Greg Johnston
992e2bce78 finish error boundary (fix last state transition issue) 2024-08-01 19:40:24 -04:00
Greg Johnston
6c2469ec3a progress on error boundary that works with nested reactivity 2024-08-01 19:40:24 -04:00
Greg Johnston
a7162d7907 progress on error boundary that works with nested reactivity 2024-08-01 19:40:24 -04:00
Greg Johnston
f584154156 error example 2024-08-01 19:40:24 -04:00
Greg Johnston
13464b10c9 enable event delegation 2024-08-01 19:40:24 -04:00
Greg Johnston
696bf14d13 fix release build 2024-08-01 19:40:24 -04:00
Greg Johnston
be92bab3e5 update TODO.md 2024-08-01 19:40:24 -04:00
Greg Johnston
4bb2bc4797 store effects in reactive system 2024-08-01 19:40:24 -04:00
Greg Johnston
a8adf8eea2 todomvc example 2024-08-01 19:40:24 -04:00
Greg Johnston
1a7da39fb7 work on async demo 2024-08-01 19:40:23 -04:00
Greg Johnston
201adb7406 clone values for Futures 2024-08-01 19:40:23 -04:00
Greg Johnston
4df42cbc60 make guard types more nestable/flexible so that we can implement render traits on any of them 2024-08-01 19:40:23 -04:00
Greg Johnston
44a0a0a93a work on async demo 2024-08-01 19:40:23 -04:00
Greg Johnston
66e1e6d7a1 work on async demo 2024-08-01 19:40:23 -04:00
Greg Johnston
8252c4a977 feat: create generic any_spawner crate to share between reactive system and renderer 2024-08-01 19:40:23 -04:00
Greg Johnston
6a2eafcbc6 add other methods on Stored 2024-08-01 19:40:23 -04:00
Greg Johnston
b49a13f8c1 work on async demo 2024-08-01 19:40:23 -04:00
Greg Johnston
0d5c67408f stash: working on jsfb 2024-08-01 19:40:23 -04:00
Greg Johnston
1eddd5a5f1 chore: remove unnecessary log 2024-08-01 19:40:23 -04:00
Greg Johnston
ca1e62c0b9 fix: correct owner for rows of For, correct cleanup of arenas 2024-08-01 19:40:23 -04:00
Greg Johnston
043cd7dc61 fix: close memory leak in tasks waiting on channels 2024-08-01 19:40:23 -04:00
Greg Johnston
68486cfb72 feat: typed event targets 2024-08-01 19:40:23 -04:00
Greg Johnston
eea971b9fe working on examples 2024-08-01 19:40:23 -04:00
Greg Johnston
d726b56b71 begin migrating to leptos and leptos_dom packages 2024-08-01 19:40:23 -04:00
Greg Johnston
0fddfb4823 stash 2024-08-01 19:40:23 -04:00
Greg Johnston
17732a6e6a stash 2024-08-01 19:40:23 -04:00
Greg Johnston
c8441f0f00 chore: remove leptos_reactive and add reactive_graph 2024-08-01 19:40:23 -04:00
Greg Johnston
ff4cde0764 feat: improved ergonomics of read guards 2024-08-01 19:40:23 -04:00
Greg Johnston
1d38439bd8 feat: add Readable implementation for all types 2024-08-01 19:40:23 -04:00
Greg Johnston
9ca1cba504 feat: add no_std support in appropriate crates 2024-08-01 19:40:23 -04:00
Greg Johnston
63dacdcc95 feat: tachys 2024-08-01 19:40:23 -04:00
Greg Johnston
61f5294f67 feat: add Fn traits 2024-08-01 19:40:23 -04:00
Greg Johnston
0149632a4c docs: note re: execution order (see #2261 and #2262) 2024-08-01 19:40:23 -04:00
Greg Johnston
96384ed116 feat: modular SharedContext for hydration 2024-08-01 19:40:23 -04:00
Greg Johnston
f56023bb25 chore: split OrPoisoned trait into its own crate for reuse 2024-08-01 19:40:23 -04:00
Greg Johnston
6bb5d58369 feat: modular, trait-based, Send/Sync reactive system 2024-08-01 19:40:23 -04:00
Saber Haj Rabiee
d50012f8d4 chore: update gloo-net and reqwest to http 1.0 (closes #2688) (leptos 0.6) (#2751) 2024-08-01 19:39:54 -04:00
Greg Johnston
c9d4ea9307 Merge pull request #2755 from leptos-rs/nightly-july24
chore(ci): update nightly
2024-08-01 15:30:22 -04:00
Greg Johnston
77c74bccbb chore: cargo fmt 2024-08-01 14:53:24 -04:00
Greg Johnston
528d1eae65 chore(ci): update nightly 2024-08-01 14:48:52 -04:00
martin frances
5809c8f699 As of rust1.80: cargo clippy now reports doc indentation issues. (#2728) 2024-07-30 09:25:53 -07:00
renshuncui
b9c620d4cd chore: fix some comments (#2712)
Signed-off-by: renshuncui <renshun@111.com>
2024-07-29 09:30:50 -04:00
Greg Johnston
8c9dfd9c9d fix: untrack children in Portal to avoid re-triggering it accidentally (closes #2693) (#2713) 2024-07-29 09:29:18 -04:00
Greg Johnston
8848eb8b87 0.6.13 2024-07-24 08:00:11 -04:00
Ar4ys
7e75801f7c fix: move lint rules outside of quote_spanned (closes #2527) (#2709) 2024-07-24 07:54:46 -04:00
Dreo
0763a81cf1 fix: remove unnecessary 'static lifetime from argument in function Style::as_value_string() (#2683) 2024-07-12 11:53:48 -04:00
Dreo
3d37f08539 add impl IntoStyle for Style (#2682) 2024-07-12 11:13:29 -04:00
Oleg Shatov
b3db094618 chore: remove cfg-related warnings (#2654) 2024-07-03 06:49:32 -04:00
Oleg Shatov
0c817d51fe fix: accurately update number of pending action dispatches (closes #2652) (#2653) 2024-07-03 06:48:02 -04:00
Chris
fb5d8513ff docs: generate link to definition (#2656) 2024-07-03 06:46:02 -04:00
David Karrick
c53fc67d38 feat: Add Compression to Hacker News w/ Islands Example (#2613)
* Add task for cargo leptos w/ precompression

* Update makefile

* Update deps

* Serve precompressed assets

Code was taken from https://github.com/leptos-rs/cargo-leptos/pull/165#issuecomment-1647843037

Co-authored-by: Sebastian Dobe <sebastiandobe@mailbox.org>

* Dynamically compress html

* Update README

* Refactor: Format for ci

* Refactor: Replace use of format!

* Chore: Remove old build file

* Feat: Hash files

This will prevent users from using an old cached file after updates are made

* Fix: Prevent chicken & egg problem with target/site

* Refactor: Use normal cargo-leptos

---------

Co-authored-by: Sebastian Dobe <sebastiandobe@mailbox.org>
2024-06-28 15:01:05 -04:00
Greg Johnston
ff0c8252b0 fix: do not unescape / and other route characters when following a link (#2651) 2024-06-28 14:29:05 -04:00
Evan Almloff
551f9b0a04 feat: add a StreamingJson encoding (#2623) 2024-06-28 11:49:26 -04:00
Greg Johnston
44cd3272f9 Merge pull request #2639 from Giovanni-Tably/dispose-fix
fix: ensure everything is disposed of consistently
2024-06-28 11:30:31 -04:00
Vasily Zorin
73a9797ef9 book_ru: SUMMARY.md (#2648)
* book_ru: SUMMARY.md

* book_ru: SUMMARY.md

* book_ru: SUMMARY.md
2024-06-27 06:46:36 -07:00
Spencer Ferris
57a00a33a3 docs: Add docs for ToChildren (#2643)
* docs: Add docs for `ToChildren`

As discussed in https://github.com/leptos-rs/leptos/discussions/2640,
the `ToChildren` trait is useful to consumers who want to use the
builder syntax. However, because it is currently annotated with
`#[docs(hidden)]`, it's not visible in docs and also not included in
Jetbrains's auto-complete.

Add a doc comment for the `ToChildren` trait, including doc tests that
demonstrate how to use the trait and how it compares to directly
creating children.

* docs: Fix incorrect examples in `ToChildren` docs

Some examples were added to `ToChildren` that don't compile. This
wasn't caught earlier because no errors were seen in the IDE when
writing the examples. The issue was correctly caught by CI, however.
2024-06-26 14:57:40 -07:00
Adrian
5f445cdfbf Translating titles of sections in SUMMARY (#2542) 2024-06-26 14:56:59 -07:00
Hamir Mahal
c9d0ef5033 chore: simplify string interpolation (#2626) 2024-06-21 07:51:38 -04:00
Giovanni
af85623a22 test: add regression tests 2024-06-20 19:37:08 +01:00
Giovanni
40ecc2bd78 fix: dispose of watch effect normally 2024-06-20 15:36:03 +01:00
Giovanni
41a18a1218 fix: clean up recursively in dispose_node 2024-06-20 15:26:55 +01:00
Giovanni
739d1b2e3e refactor: split a couple of functions 2024-06-20 15:26:37 +01:00
Giovanni
9e6996a59f fix: untrack around all on_cleanups 2024-06-20 15:26:37 +01:00
Giovanni
cca3f1f42d refactor: rename cleanup_property -> dispose_property
The property and its node are removed entirely, so it's more aligned with `dispose_node` than `cleanup_node`.
2024-06-20 15:26:37 +01:00
Greg Johnston
80bbb20089 Merge pull request #2631 from leptos-rs/2610
fix `rkyv` feature interaction with Axum integration
2024-06-14 15:10:26 -04:00
Greg Johnston
33e7ed83cc fix: specify correct serialization trait in server fn handler (closes #2610) 2024-06-14 14:20:50 -04:00
Greg Johnston
dcaa1df63d fix: derive rkyv traits on ServerFnError 2024-06-14 14:19:54 -04:00
Oto Petřík
8606f3d928 fix: try_with should not panic on disposed resources (closes #2620) (#2621) 2024-06-12 20:19:44 -04:00
Thomas Versteeg
32e6ac7bb7 docs: remove duplicated code block in example of For (#2622) 2024-06-12 20:11:57 -04:00
ARSON
b22f3bb3bd fix: extract dyn_bindings impl into DynBindings trait (#2619) 2024-06-12 09:07:56 -04:00
Greg Johnston
00a42daa63 Merge pull request #2611 from leptos-rs/failing-ci
Fix failing CI
2024-06-02 15:39:58 -04:00
Greg Johnston
ec19c59850 chore: update hackernews_js_fetch example to latest versions of leptos and axum 2024-06-02 15:39:01 -04:00
Greg Johnston
b06097d085 chore(ci): fix wasm-pack installation 2024-06-02 15:38:22 -04:00
Greg Johnston
a59561f796 chore: clippy 2024-06-02 15:37:54 -04:00
Greg Johnston
96b448805d v0.6.12 2024-06-02 14:08:08 -04:00
Luxalpa
2ef27cb0bb fix: URL encoding issue (closes #2602) (#2601) 2024-06-02 14:06:41 -04:00
SleeplessOne1917
21a6551ce6 feat: allow slice! macro to index tuples (#2598)
* Allow slice! macro to index tuples

* Undo changes to component tests

---------

Co-authored-by: Greg Johnston <greg.johnston@gmail.com>
2024-05-29 09:07:41 -04:00
Mingwei Samuel
2f4fd87c05 feat: #[component] now handles impl Trait by converting to generic type params, fix #2274 (#2599)
Book needs to be updated to remove this line:
35c380ffc8/src/view/03_components.md (L233)
2024-05-29 09:06:52 -04:00
Hecatron
13ad1b235d projects: example using the bevy 3d game engine and leptos (#2577)
* feat: Added example using the bevy 3d game engine and leptos

* fix: moved example to projects

* workspace fix
2024-05-27 15:55:27 -04:00
David Pitoniak
a2c7e23d54 docs: grammar typo for MultiActon doc comment (#2589) 2024-05-11 15:05:35 -04:00
Greg Johnston
9e65f71db4 fix: only issue NodeRef warning in debug mode (necessary to compile in --release) (#2587) 2024-05-11 15:05:17 -04:00
Luxalpa
7f4a2926c1 fix: StoredValue and Resource borrowMut error during dispose (#2583) 2024-05-11 15:04:57 -04:00
Hecatron
7c5203db19 examples: counter with DWARF debugging (breakpoints and sourcemap) (#2563)
* feat: Added initial dwarf debug counter example

* fix: update to readme and launch.json, task.json

* fix: fix tasks.json for debugging

* fix: added Trunk.toml to fix the port

* fix: moved example to projects
2024-05-11 15:02:33 -04:00
Greg Johnston
3760ced0ec fix: allow temporaries as props (closes #2541) (#2582) 2024-05-08 19:35:57 -04:00
Greg Johnston
f3f3a053ba fix: don't insert empty child for comment/doctype (closes #2549) (#2581) 2024-05-08 07:19:57 -04:00
Antoine Büsch
6a8e4bb453 Fix empty_docs warnings in #[component] macro (#2574) 2024-05-06 22:09:19 -04:00
Luxalpa
20f4323e50 feat: allow customize derives for serverfn input struct (#2545) 2024-05-06 08:54:29 -04:00
martin frances
47bcee0ef4 docs: improve NodeRef warning (#2414) (#2467) 2024-05-06 08:51:32 -04:00
SleeplessOne1917
ac3b95d35a examples: use trunk's built-in way of handling tailwind (#2557)
* Use trunk built-in way of handling tailwind

* Remove package manager from package.json
2024-05-06 08:49:07 -04:00
Greg Johnston
a314a4fcd9 docs: clarify the purpose of local resources (#2543) 2024-05-06 08:48:29 -04:00
Sam Judelson
b2a77f06b9 projects: OpenAPI Utopia (#2556) 2024-05-06 08:48:09 -04:00
Sam Judelson
9741c41356 projects: added an index to projects README (#2555)
The Index gives a high level overview of the projects
2024-05-06 08:47:13 -04:00
Joey McKenzie
4e4a770600 projects: add sitemap demo project (#2553) 2024-05-06 08:46:49 -04:00
martin frances
289c02fdac Minor: examples/server_fns_axum FileWatcher logs errors to the console. (#2547)
* Minor: examples/server_fns_axum FileWatcher logs errors to the console.

The cause is an assumption that the directory

./watched_files/

exits.

* chore: Now using .gitkeep to preserve directory structure.
2024-05-06 08:45:27 -04:00
itowlson
123d95c34c Update leptos-spin-macro reference (#2570)
Signed-off-by: itowlson <ivan.towlson@fermyon.com>
2024-05-02 15:25:22 -07:00
Greg Johnston
da9711a743 docs: add caveats for ProtectedRoute (#2558) 2024-05-01 07:06:54 -04:00
Greg Johnston
9353316947 chore: create README for projects directory 2024-04-19 10:39:58 -04:00
Sam Judelson
2960dada4a docs: add projects directory with 4 projects (#2500) 2024-04-17 19:30:31 -04:00
kryesh
c1ebaf9d04 feat: add create_query_signal_with_options to leptos_router (#2517) 2024-04-17 19:23:33 -04:00
bicarlsen
9a7dbd50eb feat: ability to use multiple classes in view macro using array syntax. (#2532) 2024-04-17 19:04:33 -04:00
Ethan Niser
410225c4d1 docs: remove unnecessary type parameter and trait bound in component macro 'bad' example (#2520) 2024-04-17 18:53:18 -04:00
ARSON
8b1c0a7013 feat: spread component attrs (#2534)
* add `dyn_bindings` builder method to component

* Revert "add `dyn_bindings` builder method to component"

This reverts commit cdd5e0f682.

* add `dyn_bindings` builder method to component
2024-04-17 14:05:00 -07:00
0e4ef622
6e819737cd fix: make TextProp's IntoView and IntoAttribute impls reactive (#2518) 2024-04-17 14:02:52 -07:00
Adrian
c4560b7e76 Adding Russian book branch (#2516) 2024-04-17 13:22:32 -07:00
Greg Johnston
0d20f6aca8 chore: publish Oco separately as oco_ref crate so that it can be used elsewhere (#2536) 2024-04-16 20:25:34 -04:00
martin frances
158b0bd294 chore(ci): bump trunk-action to 0.5. (#2533) 2024-04-16 19:19:01 -04:00
Ben Wishovich
c8186eea13 Add id to ActionForm and MultiActionForm (#2535) 2024-04-16 14:52:51 -07:00
Greg Johnston
6141e73436 Merge pull request #2531 from leptos-rs/2523
fix: do not submit `<ActionForm>` on `formmethod="dialog"` submission (closes #2523)
2024-04-15 19:52:06 -04:00
Greg Johnston
03a56f8795 chore(ci): latest nightly 2024-04-15 18:33:06 -04:00
Greg Johnston
fe06c6b91b fix: do not submit <ActionForm> on formmethod="dialog" submission (closes #2523) 2024-04-15 16:49:02 -04:00
martin frances
9a51fb17fc Minor: Bumped serde_qs to 0.13. (#2512) 2024-04-14 14:39:44 -07:00
Sam Judelson
35a8ca1f39 Add beginner tip to ErrorBoundary (#2385)
* Add beginner tip to ErrorBoundary

This might seem simple, but the nuances of types and traits confuse many people learning the language.

* edit

* Update error_boundary.rs

* edits

* ignore error block
2024-04-14 14:38:08 -07:00
Ben Wishovich
1ff0a7176d Update spin_sdk to spin v3 (#2525)
* Update spin_sdk to spin v3

* Add id to Body
2024-04-14 14:34:38 -07:00
Greg Johnston
e29d31e686 0.6.11 2024-04-10 09:33:22 -04:00
Greg Johnston
e68f1bbad5 fix: stable Router IDs (closes #2514) (#2515) 2024-04-10 09:31:34 -04:00
Greg Johnston
454a4f4ccb Merge pull request #2511 from leptos-rs/simplify-stable
Simplify stable syntax in examples
2024-04-09 15:30:51 -04:00
Greg Johnston
85a91af7c6 examples: simplify stable syntax for using signals in view 2024-04-09 14:45:19 -04:00
Greg Johnston
871d2c1b9f feat: directly implement IntoView on resources on stable 2024-04-09 14:45:01 -04:00
Greg Johnston
f0c1061161 chore(ci): remove nightly feature on counter_isomorphic (#2510) 2024-04-09 13:18:37 -04:00
Greg Johnston
d74af819a0 fix: invalid Location header when using leptos_actix::redirect() without JS/WASM (#2507) 2024-04-08 20:10:09 -04:00
Ar4ys
36b2f919dd feat: signifiantly improved error reporting in view macro (#2289)
* Added name span to .build in component_to_tokens

* Added #[allow(unreachable_code)] to  leptos::component_view inside component_to_tokens

* Added span to name reference in component_to_tokens

* Added span to leptos::component_props_builder in component_to_tokens

* Added span to props in component_to_tokens

* Added span to "on" method in events component_to_tokens

* Added spans in directive_call_from_attribute_node

* Added spans in fragment_to_tokens and it's ssr version

* Added span to props in slot_to_tokens

* Added span to the whole slot quote

* Changed slots's name span to last slot node

* Added span to the slot vec

* Added #[allow(unreachable_code)] to `.into()` in slot_to_tokens

* Added span to `.build()` in slot_to_tokens

* Added span for the whole component

* Added span to "clone:" directive

* Added span to ".children()"

* Removed unused "_span" param from fragment_to_tokens and fragment_to_tokens_ssr

* Removed unnecessary parenthesis around values in `attribute_to_tokens`

* Removed unnecessary curly braces around value in `spread_attrs`

* Removed unnecessary parenthesis around children in `element_to_tokens`

* Added catch-all span to element_to_tokens

* Formatted `quote!` according to official guidelines

* Updated view/snapshots in leptos_macro

* Added span to spread props in element_to_tokens_ssr

* Removed unnecessary curly braces in element_to_token_ssr

* Updated view/snapshots in leptos_macro

* Added view macro tests to leptos_macro

* Fixed clippy warnings in view macro output

* Updated view snapshots in tests

* Fixed expected_one_let_bind_got_none test in leptos_macro

* Removed snapshot tests in leptos_macro/tests/ui/view

---------

Co-authored-by: Greg Johnston <greg.johnston@gmail.com>
2024-04-08 08:14:33 -04:00
Greg Johnston
ab1c4ca7a6 chore(ci): run all examples under stable and fix remaining linting issue (#2503) 2024-04-05 16:09:23 -04:00
mahmoud-eltahawy
a1a989011a chore(ci): move all examples to run on stable (#2501) 2024-04-05 14:57:48 -04:00
Greg Johnston
43178b56dc chore(ci): move example CI over to stable (#2502) 2024-04-05 14:55:31 -04:00
Lukas Potthast
119c9ea23f feat: allow spreading of both attributes and event handlers (#2432) 2024-04-05 14:30:34 -04:00
Yann Dirson
fc537c14c4 feat: implement IntoView for Rc<str> (#2462)
With-help-from: Greg Johnston <greg.johnston@gmail.com>
Signed-off-by: Yann Dirson <ydirson@free.fr>
2024-04-05 09:58:35 -04:00
mahmoud-eltahawy
15f8bdd4dc stable todo_app_sqlite_axum example (#2493) 2024-04-04 20:12:45 -07:00
Sam Judelson
ca07d29db5 stable examples change (#2497) 2024-04-04 20:11:28 -07:00
Adrian
a82af6110f ex: counter_url_query; to stable (#2499) 2024-04-04 20:09:55 -07:00
Joseph Cruz
03ac6903f2 ci(examples/error-boundary): use stable syntax (#2496) 2024-04-04 20:08:50 -07:00
Joseph Cruz
e5af1456a6 fix(ci): false leptos changes detected (#2491) 2024-04-04 20:06:09 -07:00
mahmoud-eltahawy
8686d5aabb stable todomvc example (#2489) 2024-04-02 13:38:07 -07:00
Greg Johnston
c750f57ddc v0.6.10 2024-04-02 09:39:53 -04:00
Joseph Cruz
cc1f6f0a94 chore(ci): run semver checks on push (#2483) 2024-04-01 20:38:28 -04:00
Greg Johnston
a9034a92b0 fix: handle directives properly in SSR mode (closes #2488) (#2477) 2024-04-01 17:29:30 -04:00
zakstucke
9f1c09e131 feat: add View::on support for CoreComponent::{DynChild, Each} (#2422) 2024-04-01 17:09:05 -04:00
Greg Johnston
b79037b96f fix: correctly handle empty view! {} in hot-reloading code (closes #2421) (#2478) 2024-04-01 16:23:29 -04:00
Greg Johnston
41f3c46830 chore: bump nightly version in examples (#2479) 2024-04-01 15:16:53 -04:00
Greg Johnston
bfac4cba2a chore: cargo fmt 2024-03-31 14:12:33 -04:00
Paolo Barbolini
3e18edb8f9 chore: add repository field to server_fn_macro (#2474) 2024-03-31 14:10:47 -04:00
Joseph Cruz
e926ff24a6 ci: disable semver checks (#2471) 2024-03-30 20:05:20 +00:00
Gunnar Raßmann
d528cbd828 Fix: Environment variables do not overwrite Config.toml options (#2433)
* Fix environment variable parsing

* Fix failing tests

dfgdfgfd

dsf

* Add new test
2024-03-30 00:02:52 +00:00
Alex Lazar
642504f2ba Remove panic for axum ResponseOptions (#2468) 2024-03-29 07:37:12 +00:00
zakstucke
fd2817de26 Allow CDN_PKG_PATH at runtime as well as current build time, preferring it when available. (#2466) 2024-03-28 08:30:54 +00:00
Bart Toersche
73b8c7872e Fix: Small fix for location hash/fragment (#2464) 2024-03-27 06:45:29 +00:00
martin frances
f3d19ca744 Minor: Ran cargo clippy --fix (#2461)
Manually reviewed the changes. All look like reasonable nudges.

A summary :-

In one place removed a redundant call to .clone().

In two places, now using clone_from() which clippy says
**MAY** be an optimisation.
2024-03-23 18:27:31 -07:00
boyswan
0abcc348ca Persist parent span context within resource fetchers (#2456) 2024-03-22 15:51:50 -07:00
Joseph Cruz
572ae5bbdf test(ci): check semver (#2450)
* test(ci): check semver

* chore: simulate change

* fix(ci): add checkout

* fix(ci): version typo

* chore: remove simulated change
2024-03-22 15:51:13 -07:00
martin frances
0b70949118 Bumped base64 to 0.22. (#2457) 2024-03-22 15:07:04 -07:00
martin frances
5819014ccc Chore(ci) bumping tj-actions/changed-files to version 43. (#2454) 2024-03-22 07:23:57 -04:00
Joseph Cruz
630fd4570d fix(ci): trunk command not found (#2453)
* chore: simulate change

* chore: remove print trunk version

* Revert "chore: remove print trunk version"

This reverts commit c203a83b44.

* chore(ci): use jetli/trunk-action

* chore: remove simulated change
2024-03-22 07:23:48 -04:00
Ratul
d1560f9e1f Added missing link for #[server] macro (#2437)
* Added missing link for #[server] macro

Added missing link for #[server] macro

* Removed spurious entry
2024-03-20 14:24:54 -07:00
martin frances
841d7a690a chore: examples/tailwind_axum bumped tailwindcss to 3.4.2. (#2443) 2024-03-19 09:40:24 -07:00
sify21
104c09f3bf register server_fn first to allow for wildcard Route path (#2435)
It's normal to have a `NotFound` page with a wildcard path like this
```
<Routes>
    ...
    <Route path="*any" view=NotFound>
</Routes>
```
In `ssr` mode, most servers do a `first match win` approach, so we
should register server functions before view routes, or else a wildcard
route would block all api requests.

https://discord.com/channels/1031524867910148188/1218508054442545185

Signed-off-by: 司芳源 <sify21@163.com>
2024-03-19 09:37:42 -07:00
Joseph Cruz
ac75999c9f chore(ci): upgrade actions to node 20 (#2444)
* chore(ci): install jq with apt

* chore(ci): install trunk with cargo

* chore(ci): replace toolchain action

* chore(ci): upgrade pnpm cache action

* chore: simulate change

* fix(ci): pnpm cache action typo

* chore: remove simulated change
2024-03-19 09:36:30 -07:00
Richard Laughlin
7ef186f642 For the session_auth_axum example, move the passhash into a separate (#2446)
non-serializable struct.

This prevents it from being returned in the
get_user() API, and prevents it from being unintentionally returned on any
new API the end-user may create on top of this example code.
2024-03-19 09:35:53 -07:00
Joseph Cruz
fda4dba237 build(examples): clean more output (#2420)
* chore(examples): update workspace members

* build(examples): clean e2e crates

* build(examples): clean pkg directories

* chore: remove simulated change comment

* chore: add simulated change

* chore: remove simulated change
2024-03-18 11:58:37 -04:00
Roland Fredenhagen
4e578e335b chore: update attribute-derive (#2438) 2024-03-18 11:39:34 -04:00
Joseph Cruz
97fd8ff6c4 fix(ci): leptos examples fail with bindgen schema error (#2428) 2024-03-13 22:33:54 -04:00
battmdpkq
4faf3fa894 chore: fix types in some comments (#2413)
Signed-off-by: battmdpkq <cmaker@163.com>
2024-03-09 07:38:25 -05:00
Greg Johnston
480d741749 chore: update to gloo-net 0.5 (closes #2411) (#2416) 2024-03-08 15:22:12 -05:00
Álvaro Mondéjar
7928f61401 chore: add lint to disallow prints to stdout (#2404) 2024-03-08 13:18:37 -05:00
Giovanni
2b4f5e0f58 docs: runtime error if setting the same event listener 2x rather than silent failure (#2383)
Delegated event listeners do not support adding more than one event listener of the same type. This can cause confusion if two listeners are added, as one is silently dropped.
2024-03-07 16:49:23 -05:00
Giovanni
943a992570 fix: re-throw errors in delegated event listeners (#2382) 2024-03-07 16:48:21 -05:00
ARSON
372a241d78 feat: allow #[prop(attrs)] on slots (#2396) 2024-03-04 17:34:21 -08:00
Chris Biscardi
c06f6bede2 fix: remove erroneous debug println!()s in islands (#2402) 2024-03-04 06:56:18 -05:00
benwis
3e93a686f4 Fix and release deps 2024-03-03 17:04:34 -08:00
benwis
34cdff4cb3 Update deps in one crate to 0.6.8 2024-03-03 17:02:50 -08:00
John Lewis
530087d77d Add MessagePack codec (#2371)
* feat: added messagepack codec

* fix: deserialize msgpack from bytes, not string
2024-03-03 13:54:23 -08:00
martin frances
4bb43f6207 examples/todomvc - Rename Todos::new() Todos::default(). (#2390) 2024-03-03 13:48:40 -08:00
benwis
9e2fb62857 0.6.8 2024-03-02 18:01:10 -08:00
Ben Wishovich
1da2fff706 Fix missed stuff (#2398) 2024-03-02 17:57:20 -08:00
Greg Johnston
9fd2987447 fix: correctly reset hydration status in islands mode Suspense (closes #2332) (#2393) 2024-03-02 11:57:35 -05:00
zroug
7996f835d0 fix: remove unnecessary trait bound PartialEq from create_owning_memo (#2394) 2024-03-02 07:27:22 -05:00
Greg Johnston
d72b12524e Merge pull request #2395 from leptos-rs/int-ax-doc 2024-03-01 20:08:18 -05:00
Greg Johnston
8e79c5be5c fix: ignore as with other doctests for now 2024-03-01 18:39:55 -05:00
Greg Johnston
de25658c36 Merge pull request #2392 from paul-hansen/fix-ci
fix(ci): "needless borrow" error and example never exiting
2024-03-01 18:37:48 -05:00
Paul Hansen
e2e35a9659 fix(ci) Wait a bit longer for server to start
It took longer than I thought in Github and barely worked, giving it a
bit more of a buffer.
2024-03-01 15:47:59 -06:00
Paul Hansen
bf1ba589c5 fix(ci): Another attempt to fix hanging example 2024-03-01 15:41:22 -06:00
Sam Judelson
f70ebc1289 docs: add note on how to get ResponseOptions (#2380) 2024-03-01 10:47:02 -05:00
Paul Hansen
3cab09e015 fix(ci): error_boundary example never exiting 2024-03-01 09:21:58 -06:00
Paul Hansen
b431315f7c fix(ci): "needless borrow" error 2024-03-01 09:21:58 -06:00
Baptiste
5b40881e77 fix: specify path to wasm_bindgen in island macro (#2387) 2024-03-01 10:15:19 -05:00
benwis
59d3cce3be 0.6.7 2024-02-29 13:38:09 -08:00
Paul Hansen
6a83161368 chore: add MSRV (#2360) 2024-02-28 07:19:09 -05:00
Marc-Stefan Cassola
4b00c16cb9 added hashes generated from cargo-leptos (#2373)
* added hashes generated from cargo-leptos

* Added config option to disable frontend file name hash
2024-02-27 16:28:27 -08:00
haslersn
6d6019b956 fix: do not strip query in redirect hook when using client-side navigation (#2376) 2024-02-27 09:06:48 -08:00
Sam Judelson
3540291065 docs: Resource::read() in doc examples with Resource::get() (#2372) 2024-02-26 21:37:29 -05:00
zoomiti
4809cf473e feat: provide leptos_router::Method via context (#1808) (#2315) 2024-02-26 21:25:53 -05:00
Tadas Dailyda
aa977001c1 feat: add support for trailing slashes (closes #2154) (#2217) 2024-02-26 20:56:44 -05:00
Greg Johnston
c16189f095 Merge pull request #2362 from leptos-rs/remove-deprecation
chore(ci): fix failing CI by removing deprecation note
2024-02-24 13:05:02 -05:00
Greg Johnston
d0a013c248 chore(ci): omit a few feature flag in CI 2024-02-24 11:55:36 -05:00
Greg Johnston
531ea74e33 chore: cargo fmt in leptos_macro 2024-02-24 07:12:46 -05:00
Greg Johnston
545e87e540 chore(ci): fix failing CI by removing deprecation note 2024-02-24 07:07:31 -05:00
Joseph Cruz
2ca30a0b2d ci(examples): build hackernews_js_fetch with deno (#2344)
* ci(examples): refactor process management

* ci(examples): build hackernews_js_fetch with deno

* ci(workflows): detect hackernews_js_fetch change

* chore(web-report): report deno usage

* chore(web-report): ignore gtk example

* ci(todo_app_sqlite): simulate change

* ci(workflows): install deno

* ci(todo_app_sqlite): remove simulated change
2024-02-23 13:40:44 -05:00
zoomiti
753bf1ed54 Fix Broken Doc links and Deprecate FromUtf8Error in oco.rs (#2318)
* fix: deprecate `FromUtf8Error` in `oco.rs`

* chore: fix broken doc links (#859)

* chore: fix broken doc link to server attribute macro

* cargo fmt
2024-02-21 19:24:40 -08:00
Sam Judelson
37c6387fea finish doc sentence (#2348) 2024-02-21 19:21:57 -08:00
Janu (Janeshwar) Cambrelen
0a73487152 feat(leptos-axum): propagate trace context to server functions (#2340) 2024-02-21 19:21:00 -08:00
Sam Judelson
747aba0d7f add comment specifying edgecase of server function prefixes (#2345) 2024-02-20 18:17:20 -08:00
Sam Judelson
04cf47d5da Update suspense_component.rs documentation to use .get() instead of .read() (#2346) 2024-02-20 18:16:03 -08:00
rjmac
47abe00993 fix: don't leak canceled timeouts (#2331)
Instead of using `Closure::once_into_js`, this uses `into_js_value`,
which uses weak references to clean up the closure when Javascript no
longer has need of it.

It would be nice to make this (and the similar interval function) drop
the callback promptly when cancelled, but I don't think that's
possible while keeping the handles Copy.

Fixes #2330

Co-authored-by: Robert Macomber <robertm@mox>
2024-02-19 21:17:26 -05:00
eliza
aa3700ffb9 feat: add impl_from argument to #[server] proc_macro (#2335)
* Add `impl_into` argument

* Add `impl_into` argument

* Revert unneeded changes

* Address review comments

Rename `impl_into` back to be `impl_from`
Rework docstring

* Fix typo in docstring
2024-02-19 21:16:46 -05:00
Aphek
0770b87cb7 feat: Add owning memos to allow memos that re-use the previous value (#2139) 2024-02-19 21:16:19 -05:00
benwis
330ebdb018 v0.6.6 2024-02-19 13:48:32 -08:00
benwis
c3179d88cf Moved leptos-spin-macro dep to released version 2024-02-19 12:54:43 -08:00
Sahaj
ffcf3c2952 example: fix href path in tailwind_csr example (#2328) 2024-02-17 13:10:07 -05:00
haslersn
001ca5148e fix: handle cross-origin redirects in server function redirect hook (#2329)
In client-side navigation we now handle redirects returned from
server functions by resolving the location against the current
origin as a base. The base is only relevant if the location
doesn't already include an origin. This fixes cross-origin
redirects.

Note: in order to handle redirects in the same way as the browser
would handle them, we need to use the server function's URL
(typically `<origin>/api/something`) as a base. I leave this as
a TODO for a future leptos version, because it probably
requires changing the signature of the `server_fn` redirect hook.

In order to not be affected by a future breaking change, users
should already start making sure that their redirect locations
either include an origin or at least start with a single slash
(e.g. `Location: /foo`).
2024-02-17 13:09:39 -05:00
Greg Johnston
1e000afa78 examples: fix CSS file name in tailwind_axum (#2324) 2024-02-17 12:56:03 -05:00
Greg Johnston
0f7b8841b2 chore(ci): reduce set of tested features to prevent running out of disk space in server_fn (#2320) 2024-02-16 20:26:26 -05:00
Greg Johnston
7dc0441f6c docs: log error on failing to convert form to ServerFn type, in addition to setting action value (#2319) 2024-02-16 17:11:14 -05:00
Joseph Cruz
0a321a1bd7 docs(examples): update docs (#2313)
* docs(examples): fix metadata typo

* docs(examples): update first step about using cargo make
2024-02-16 13:32:01 -05:00
Greg Johnston
88742952f0 fix: Transition in hydrate mode that isn't initially created (closes #2279) (#2314) 2024-02-16 08:16:09 -05:00
martin frances
8a4b972e0b chore: bump config to 0.14 (#2302) 2024-02-15 20:24:12 -05:00
zoomiti
95bd9cc544 feat: use CDN_PKG_PATH at build time to set alternate base URL for JS/WASM bundles (#2281) (#2283) 2024-02-15 20:21:47 -05:00
Marc-Stefan Cassola
23bc892a24 fix: #[server] macro error type detection (#2298)
In most cases when you return `Result<..., ServerFnError<E>>` this worked but when you tried
`Result<..., leptos::ServerFnError<E>>` then it didn't.
2024-02-15 20:20:41 -05:00
Esteban Borai
830fba794e docs: add missing provide_meta_context() in example (#2311)
Otherwise user gets:

```
use_head() is being called without a MetaContext being provided. We'll automatically create and provide one, but if this is being called in a child route it may cause bugs. To be safe, you should provide_meta_context() somewhere in the root of the app.
```
2024-02-15 20:19:07 -05:00
martin frances
98633c8700 chore(ci): update node version for GitHub Actions (#2303) 2024-02-15 20:17:12 -05:00
David Rebbe
b0f5c39711 example: replace yanked version of session_auth_axum crate (#2310) 2024-02-15 20:16:26 -05:00
Greg Johnston
b54aa7f3f5 Merge pull request #2294 from agilarity/add-cargo-make-leptos 2024-02-15 18:52:37 -05:00
Sam Judelson
e33ee7ec99 pub export server is either from leptos_macro or leptos_spin_macro depending on if spin feature is enabled. (#2280)
* leptos spin server macro

* leptos spin

* git chng

* based on the fermyon official git for when that works
2024-02-15 14:37:19 -08:00
Joseph Cruz
cd70b2f52b fix(ci): should exclude cargo-make 2024-02-11 20:40:20 -05:00
Joseph Cruz
c75842ed0c ci(hackernews_islands_axum): build with cargo leptos 2024-02-11 15:40:32 -05:00
Joseph Cruz
4ad228bf47 docs(test-report): add leptos ci warning 2024-02-11 15:40:32 -05:00
Joseph Cruz
bbe7115360 docs(test-report): mention options 2024-02-11 15:40:32 -05:00
Greg Johnston
0658a550b0 fix(examples): align crate name and output name (closes #2206) (#2291) 2024-02-10 15:47:25 -05:00
Joseph Cruz
4222c832b1 fix(ci): empty directory vector error (#2288)
* fix(ci): empty directory vector error

* chore(ci): simulate example change

* chore(ci): remove simulated example change
2024-02-10 10:02:21 -08:00
Greg Johnston
dfddbd6bf9 docs: give a warning when you try to .dispatch() an action immediately (closes #2225) (#2286) 2024-02-09 20:55:10 -05:00
Greg Johnston
8a77691cb5 Merge pull request #2285 from leptos-rs/fix-issues
Fix remaining CI issues
2024-02-09 19:29:01 -05:00
Greg Johnston
1dbe8b2d4b fix: correct feature name for server-fn-macro crate (broken in #2270) 2024-02-09 17:18:44 -05:00
Greg Johnston
fe64f0d332 examples: fix counter_isomorphic (broken in #2244) and fix additional warnings 2024-02-09 17:12:31 -05:00
Joseph Cruz
c00207aa46 fix(test-report) should show all cargo-make leptos configuration (#2282)
* refactor(test-report): extract script
* refactor(test-report): extract functions
* refactor(test-report): split option to tasks
* chore(test-report): highlight examples without tags
* fix(test-report): show all cargo-make leptos configuration
* docs(test-report): update keys
* chore(test-report): include all crates in report
2024-02-09 16:31:46 -05:00
Joseph Cruz
65b7603192 fix(ci): address clippy issue (#2278)
* fix(ci): address clippy issue
* fix(ci): add missing nightly specifications
* fix(ci):  set all nightly references
* chore(ci): do not lint example crates
2024-02-09 16:30:11 -05:00
haslersn
d4bdc36062 fix: add key/value pair from submit button when parsing form event (#2268) 2024-02-07 11:09:01 -05:00
Sam Judelson
1b55227d10 fix: remove unnecessary default features on axum in server_fns to support running Axum in a WASM environment (#2270) 2024-02-07 11:08:48 -05:00
Saikat Das
a903e19eb2 chore: fix typo (#2267) 2024-02-06 17:55:35 -05:00
blorbb
38bf73947f fix: make directive .into() calls consistent (#2249) 2024-02-05 08:52:12 -05:00
Greg Johnston
e4b89ba243 Merge pull request #2262 from leptos-rs/2261
fix: guarantee execution order of effects (closes #2261)
2024-02-05 08:51:23 -05:00
Greg Johnston
701e3077fb chore: cargo fmt 2024-02-05 06:38:02 -05:00
Greg Johnston
aec4d680aa fix: guarantee execution order of effects (closes #2261) 2024-02-05 06:35:57 -05:00
Steffen
06721c5fcd examples: fix typos in examples (#2260) 2024-02-05 05:20:53 -05:00
SleeplessOne1917
1ddb39e9bd docs: typo in actix integrations docs (#2258)
Co-authored-by: SleeplessOne1917 <insomnia-void@protonmail.com>
2024-02-04 20:57:51 -05:00
Chris
15d4ca0638 feat(axum): provide state to server fn context (#2257)
Note that this is a minimal implementation and will __not__ allow the
user to `expect_state` if they have external calls to rendering their
app (i.e. using `render_app_to_*` directly).
2024-02-04 19:26:21 -05:00
zoomiti
85c3755f6d fix: bug with percent decoding of url params (#2251) 2024-02-04 19:24:02 -05:00
Sam Judelson
66ea072bc0 docs: a note to HtmlElement<El> about Deref (#2218) 2024-02-04 15:34:39 -05:00
Joris Hartog
b0b3c21285 docs: fix broken link in leptos_router (#2256) 2024-02-04 15:29:34 -05:00
Greg Johnston
56088a9ead fix: error rather than panicking if unable to send response in Axum integration (#2241)
* fix: error rather than panicking if unable to send response in Axum integration
2024-02-03 19:18:41 -05:00
martin frances
69d25d9c63 examples/hackernews: Add a "Suspense" wrapper. (#2253)
This warning appears in the browser's console log.

```
hackernews.js:933 At src/routes/stories.rs:39:17, you are reading a resource in `hydrate` mode outside a <Suspense/> or <Transition/>. This can cause hydration mismatch errors and loses out on a significant performance optimization. To fix this issue, you can either:
1. Wrap the place where you read the resource in a <Suspense/> or <Transition/> component, or
2. Switch to using create_local_resource(), which will wait to load the resource until the app is hydrated on the client side. (This will have worse performance in most cases.)
```
2024-02-03 14:24:46 -08:00
martin frances
5029b8f315 Chore: Minor, ran ``cargo fmt`` (#2254) 2024-02-03 14:24:12 -08:00
martin frances
0cba7bc22b example/counter_isomorphic Removed console warning. (#2244)
This warning is seen in the browsers console window.

```
counter_isomorphic.js:1068 At src/counters.rs:138:17, you are reading a resource in `hydrate` mode outside a <Suspense/> or <Transition/>. This can cause hydration mismatch errors and loses out on a significant performance optimization. To fix this issue, you can either:
1. Wrap the place where you read the resource in a <Suspense/> or <Transition/> component, or
2. Switch to using create_local_resource(), which will wait to load the resource until the app is hydrated on the client side. (This will have worse performance in most cases.)
```

Two derived signals "value" and "error_msg" need to be wrapped in a <Suspense> block.

"value" falls back to just the initial text.
"error" uses the default fallback.
2024-02-01 16:50:15 -08:00
Michael Kadziela
fb97c50886 Update rkyv example button text to accurately reflect what it does (#2250) 2024-02-01 16:49:29 -08:00
Greg Johnston
f1bc734dcf 0.6.5 2024-01-31 19:40:41 -05:00
Greg Johnston
f71b4aae69 feat: easily create custom server fn clients (#2247) 2024-01-31 09:15:30 -05:00
Greg Johnston
a834c03974 fix: bug with Actix redirects (#2246) 2024-01-31 09:14:40 -05:00
Greg Johnston
595013579c 0.6.4 2024-01-30 09:17:52 -05:00
Greg Johnston
8b1bd1ae9e Merge pull request #2240 from leptos-rs/err-serialization
fix: serialization error during SSR on ServerFnError
2024-01-29 16:32:55 -05:00
Greg Johnston
6ef1531059 example: file upload with streaming progress bar (#2242) 2024-01-29 15:20:19 -05:00
Greg Johnston
9f1406250e chore: update deprecated .remove() method on IndexSet 2024-01-29 11:32:15 -05:00
Greg Johnston
1f6a892291 fix: serialization error during SSR on ServerFnError 2024-01-29 10:36:08 -05:00
Greg Johnston
0ff1e279a2 fix: correctly track source in create_local_resource (#2238) 2024-01-28 10:09:03 -08:00
Chris
c6096cc2a0 chore: define edtion = "2021" in rustfmt.toml (#2235) 2024-01-27 16:04:25 -08:00
Greg Johnston
8a2ae7fc7c \v0.6.3\ 2024-01-26 21:00:21 -05:00
Greg Johnston
9de34b74cf 0.6.2 2024-01-26 18:07:04 -05:00
Greg Johnston
1b5961edaa fix: fix type inference on extract() functions (#2233) 2024-01-26 17:54:42 -05:00
Greg Johnston
26d1aee9ad Update README.md framework comparisons (#2232) 2024-01-26 17:01:26 -05:00
benwis
2bf09384df 0.6.1
Signed-off-by: benwis <ben@celcyon.com>
2024-01-26 12:32:14 -08:00
benwis
ac12e1a411 0.6.0
Signed-off-by: benwis <ben@celcyon.com>
2024-01-26 11:54:07 -08:00
Greg Johnston
b367b68a43 fix: use #[server(default)] to pass use default values for a field (#2231) 2024-01-26 14:46:31 -05:00
Greg Johnston
1f9dad421f fix: allow paths to ServerFnError type (#2230) 2024-01-26 11:32:43 -08:00
Greg Johnston
4648fb2cfc Update README.md 2024-01-25 20:34:15 -05:00
Saber Haj Rabiee
817ec045f7 chore: fix import of quote::quote (#2227) 2024-01-25 17:48:41 -05:00
Greg Johnston
ca3806e6bc v0.6.0-rc1 2024-01-24 21:35:14 -05:00
Greg Johnston
936c2077c3 Merge pull request #2222 from leptos-rs/2221
fix: `.refetch()` should not include any tracked reads
2024-01-24 20:44:51 -05:00
Greg Johnston
b3b18875c6 chore: allow unknown lints 2024-01-24 19:43:28 -05:00
Greg Johnston
5cbab48713 chore: avoid possible false positive in cargo check 2024-01-24 19:38:16 -05:00
Greg Johnston
5a8880dd2e fix: correctly track in the effect that creates the resource 2024-01-24 16:18:45 -05:00
Greg Johnston
ea6c957f3d fix: .refetch() should not track any reads (closes #2221) 2024-01-23 11:08:50 -05:00
Greg Johnston
694e5f1cb3 fix: cast to correct type on Memo::try_with_untracked 2024-01-23 11:08:33 -05:00
Greg Johnston
fce2c727ab feat: add support for custom encodings to #[server] macro (#2216) (closes #2210) 2024-01-21 16:14:02 -05:00
Greg Johnston
7d1ce45a57 chore: minimize features activated with leptos_axum's default feature (#1846) (#2213)
- `leptos_axum` default feature:
  - remove `tokio/full`, `axum/macros`
  - add `tokio/fs`, `tokio/sync`
- example `leptos-tailwind-axum`:
  - enable `tokio`'s `rt-multi-thread` and `macros` features
- example `ssr_modes_axum`:
  - enable `tokio`'s `rt-multi-thread` and `macros` features

Co-authored-by: Paul Nettleton <paulnett7@hotmail.com>
2024-01-21 15:22:46 -05:00
Niklas Eicker
997b99081b change: for static routes, remove .static and provide additional context for static_params closures (#2207) 2024-01-21 13:33:05 -05:00
Chris
d33e57d4b7 feat: Default for LeptosOptions, ConfFile (#2208)
Co-authored-by: chrisp60 <gh@cperry.me>
2024-01-21 13:26:10 -05:00
Greg Johnston
b450f0fd10 fix: don't enable tracing feature on leptos by default (#2211) 2024-01-20 17:58:22 -05:00
Greg Johnston
c84c6ee8cd Merge pull request #2158 from leptos-rs/leptos_v0.6 2024-01-20 15:58:25 -05:00
Greg Johnston
567644df8f clarify docs here 2024-01-20 14:29:22 -05:00
Greg Johnston
39f5481b8c clean up in docs and rename Axum extract() to match Actix extract() 2024-01-20 14:29:08 -05:00
Greg Johnston
c88bfbe0a0 tweak sets of features for CI 2024-01-20 14:18:25 -05:00
Greg Johnston
40da1fe94e clippy 2024-01-20 14:16:13 -05:00
Greg Johnston
8df46fcdb9 examples: use old Axum version of hackernews_js_fetch until supported by axum-js-fetch 2024-01-20 12:39:16 -05:00
Greg Johnston
b4a1d90327 clean up for CI 2024-01-20 12:32:51 -05:00
Chris
d746f83387 docs: View::render_to_string panic (#2200)
Co-authored-by: chrisp60 <gh@cperry.me>
2024-01-19 17:07:39 -08:00
Greg Johnston
2092c40bc7 missing derives 2024-01-19 18:21:57 -05:00
Greg Johnston
70ec0c2d0a update sso example 2024-01-19 18:02:22 -05:00
Greg Johnston
eb45d05f3b clippy 2024-01-19 17:43:05 -05:00
Greg Johnston
f19def9541 clippy 2024-01-19 16:55:16 -05:00
Greg Johnston
ddda785045 fix multipart support 2024-01-19 16:52:41 -05:00
Greg Johnston
26d9d75cf2 cargo fmt 2024-01-19 15:56:57 -05:00
Greg Johnston
46e7abf9ba allow custom req/res/client types 2024-01-19 15:48:14 -05:00
Greg Johnston
1b1e02729e clean up examples 2024-01-19 15:17:17 -05:00
Greg Johnston
fdd576535a clean up examples 2024-01-19 15:14:39 -05:00
Greg Johnston
2a9e502893 fix rkyv deserialization 2024-01-19 15:03:21 -05:00
Greg Johnston
a519859a66 Revert "use &[u8] instead of Bytes for requests"
This reverts commit e179db1d42.
2024-01-19 14:37:03 -05:00
Greg Johnston
25120c0e9f fix streaming requests and clarify in docs 2024-01-19 14:17:26 -05:00
Greg Johnston
94cb4c0ec3 remove pavex work (now in pavex branch) 2024-01-19 14:17:26 -05:00
Greg Johnston
f9cd8539e4 add missing PartialEq/Eq implementations on ServerFnError (closes #2198) 2024-01-19 14:17:26 -05:00
Greg Johnston
14072457d0 clean up docs (closes #2197) 2024-01-19 14:17:26 -05:00
Greg Johnston
e179db1d42 use &[u8] instead of Bytes for requests 2024-01-19 14:17:26 -05:00
Greg Johnston
2fa60103b4 share inventory collect across types 2024-01-19 14:17:26 -05:00
Greg Johnston
a3a15f244d expose all fields of ServerFnTraitObj via methods 2024-01-19 14:17:26 -05:00
Greg Johnston
0df5dfeaf8 weak dependency on Cargo.toml 2024-01-19 14:17:26 -05:00
Greg Johnston
3f22906053 fix warning 2024-01-19 14:17:26 -05:00
Greg Johnston
33ad30515d serde-lite support should be enabled directly on server_fn 2024-01-19 14:17:26 -05:00
Greg Johnston
c5bab09423 partial support for streaming requests (doesn't actually work in the browser) 2024-01-19 14:17:26 -05:00
Greg Johnston
320179bc04 remove misleading warning 2024-01-19 14:17:26 -05:00
Greg Johnston
5065bed594 example of middleware that can run before and/or after server fn 2024-01-19 14:17:26 -05:00
Greg Johnston
22b4537f27 fix version numbers 2024-01-19 14:17:26 -05:00
Greg Johnston
8d23d5136a add package metadata 2024-01-19 14:17:25 -05:00
Greg Johnston
c7fac64054 fix merge error 2024-01-19 14:17:25 -05:00
Greg Johnston
047235e7c1 clippy 2024-01-19 14:17:25 -05:00
Greg Johnston
7a086ad159 update version number 2024-01-19 14:17:25 -05:00
Greg Johnston
bb923b3f9b erroneous hyphen 2024-01-19 14:16:59 -05:00
Greg Johnston
6a8c26a820 streaming example with filesystem watcher 2024-01-19 14:16:59 -05:00
Greg Johnston
21f8085851 add streaming/file watcher example 2024-01-19 14:16:59 -05:00
Greg Johnston
9a5a102ce3 add middleware to kitchen-sink example 2024-01-19 14:16:59 -05:00
Greg Johnston
4d602c21f8 example with custom errors 2024-01-19 14:16:59 -05:00
Greg Johnston
7d114c7414 file upload example 2024-01-19 14:16:58 -05:00
Greg Johnston
1f017a2ade hm custom encodings have orphan rule issues 2024-01-19 14:16:58 -05:00
Greg Johnston
35e8e74dcf get rkyv working and work on custom encoding example 2024-01-19 14:16:58 -05:00
Markus Kohlhase
4366d786ac Update login example (CSR only) (#2155) 2024-01-19 14:16:58 -05:00
Ari Seyhun
1777a4057a fix!: remove clone in Cow<'static, str> IntoView impl (#1946) 2024-01-19 14:16:58 -05:00
Greg Johnston
0571ebbc36 working on example 2024-01-19 14:16:58 -05:00
Greg Johnston
06c478b7cb feature-gate the form redirect stuff, and clear old errors from query 2024-01-19 14:16:58 -05:00
Greg Johnston
90ba3529e9 working on Axum version 2024-01-19 14:16:58 -05:00
Greg Johnston
13a2691806 working on server fn example 2024-01-19 14:16:58 -05:00
Greg Johnston
1ad7ee8a03 generalize error redirect behavior across integrations 2024-01-19 14:16:58 -05:00
Greg Johnston
88fee243a8 support setting server URL on either platform 2024-01-19 14:16:58 -05:00
Greg Johnston
5e08253521 get both client and server side working 2024-01-19 14:16:58 -05:00
Greg Johnston
cc6f65cd83 initial version of server action error handling without JS 2024-01-19 14:16:58 -05:00
Greg Johnston
9488114801 docs 2024-01-19 14:16:58 -05:00
Greg Johnston
b0cdeab906 remove old code 2024-01-19 14:16:58 -05:00
Greg Johnston
def4be80b2 docs 2024-01-19 14:16:58 -05:00
Greg Johnston
15b04a8a85 more docs 2024-01-19 14:16:58 -05:00
Greg Johnston
0a9cdba22e getting started on docs 2024-01-19 14:16:58 -05:00
Greg Johnston
1d1de4ac38 remove cfg-if from all examples 2024-01-19 14:16:58 -05:00
Greg Johnston
31b2b9e94c remove explicit handle_server_fns in most cases because it's now included in .leptos_routes() 2024-01-19 14:16:58 -05:00
Greg Johnston
8f07818687 nicer formatting, remove cfg-if 2024-01-19 14:16:58 -05:00
Greg Johnston
a5cbfa0aad remove viz integration (see #2177) 2024-01-19 14:16:58 -05:00
Greg Johnston
6c8e704fb3 smh 2024-01-19 14:16:58 -05:00
Greg Johnston
81fb5160e5 missing makefiles 2024-01-19 14:16:58 -05:00
Greg Johnston
2af0d3d781 update session_auth_axum 2024-01-19 14:16:58 -05:00
Greg Johnston
7f532cda70 update todo_app_sqlite_csrs 2024-01-19 14:16:58 -05:00
Greg Johnston
c7941f7639 clippy 2024-01-19 14:16:58 -05:00
Greg Johnston
61148026d1 allow type paths for input/output, and properly namespace built-in encodings 2024-01-19 14:16:58 -05:00
Greg Johnston
738eeefe73 chore: clear warnings 2024-01-19 14:16:18 -05:00
Greg Johnston
be084a5d1d remove list of magic identifiers, use rust-analyzer to help with imports instead 2024-01-19 14:16:18 -05:00
Greg Johnston
f5c007df7b use server fns directly in ActionForm and MultiActionForm 2024-01-19 14:16:18 -05:00
Rakshith Ravi
a1bd84f3dc feat: add serde-lite codec for server functions (#2168) 2024-01-19 14:16:18 -05:00
Rakshith Ravi
f6ce82c9d1 Fixed tests for server_fn (#2167)
* Fixed server_fn tests

* Changed type_name to TypeId

* Fixed handling of leading slashes for server_fn endpoint
2024-01-19 14:16:18 -05:00
Greg Johnston
853c080707 add missing server fn registration 2024-01-19 14:16:18 -05:00
Greg Johnston
f6b95e40f4 make sure endpoint names begin with a / 2024-01-19 14:16:18 -05:00
Greg Johnston
db1497b9c2 set version, input, etc. correctly 2024-01-19 14:16:18 -05:00
Greg Johnston
f53ac1a4ae remove unused var 2024-01-19 14:16:18 -05:00
Greg Johnston
5e6f4403ca set up redirects in Actix 2024-01-19 14:16:18 -05:00
Greg Johnston
4e3f1c834c handle client-side and server-side redirects correctly (in Axum) 2024-01-19 14:16:18 -05:00
Greg Johnston
566df034ff actually use server functions in ActionForm 2024-01-19 14:16:17 -05:00
Greg Johnston
fd97e2e027 Restore the previous full functionality of Form 2024-01-19 14:16:17 -05:00
Greg Johnston
c8fbee18c8 finished Actix support? 2024-01-19 14:16:17 -05:00
Greg Johnston
e1a9856ca9 more Actix work 2024-01-19 14:16:17 -05:00
Greg Johnston
60efaefff4 start Actix work 2024-01-19 14:16:17 -05:00
Greg Johnston
db4158f5c3 clear up warnings 2024-01-19 14:16:17 -05:00
Greg Johnston
af62d2e900 automatically include server function handler in .leptos_router() 2024-01-19 14:16:17 -05:00
Greg Johnston
c3e3ce7878 changes to get todo_app_sqlite_axum example working 2024-01-19 14:16:17 -05:00
Greg Johnston
dec17fc65b fix server actions and server multi actions 2024-01-19 14:16:03 -05:00
Greg Johnston
2dbc5899f3 cargo fmt 2024-01-19 14:16:03 -05:00
Greg Johnston
dd368a845c @ealmloff changes to reexport actix/axum 2024-01-19 14:16:03 -05:00
Greg Johnston
9c258219dd fix Actix implementation with middleware 2024-01-19 14:16:03 -05:00
Greg Johnston
6a1685936b fix rkyv 2024-01-19 14:16:03 -05:00
Greg Johnston
7d45e6bb13 clean up my mistake 2024-01-19 14:16:03 -05:00
Greg Johnston
8fae76828e FromStr-based lightweight ServerFnError deserialization 2024-01-19 14:16:03 -05:00
Greg Johnston
d5b9e84f36 properly gate inventory 2024-01-19 14:16:03 -05:00
benwis
197edebd51 Made some progress, started work on pavex integration as well 2024-01-19 14:16:03 -05:00
benwis
2a5c855595 It starts to compile! 2024-01-19 14:16:03 -05:00
benwis
c9627bfeb4 Setup folder structure as before. Got a cyclical dependency though 2024-01-19 14:16:03 -05:00
benwis
c7422cd96e First commit, checkpoint for cyclical dependency error 2024-01-19 14:15:51 -05:00
Daniel Santana
cadd217078 Update integration with support for axum 0.7 (#2082)
* chore: update to axum 0.7

Removed http, since it's included in axum, and replaced hyper by http-body-util, which is a smaller.

* chore: update samples to work with nre axum

Missing sessions_axum_auth, pending PR merge.

* chore: all dependencies update to axum 0.7

* chore: cargo fmt

* chore: fix doctests

* chore: Fix example that in reality doesn't use axum.

Fixed anyway.

* chore: more examples support for axum 0.7

* Small tweak
2024-01-19 14:13:55 -05:00
Greg Johnston
0c4cf5471d v0.5.7 2024-01-19 13:03:44 -05:00
Greg Johnston
dd0c349554 examples: update axum-session because old version was yanked (#2205) 2024-01-19 12:54:08 -05:00
Greg Johnston
dd5a0ae094 Merge pull request #2203 from leptos-rs/2201
fix: routing regressions caused by `trailing_slash` support
2024-01-19 12:14:20 -05:00
Greg Johnston
5cacb57283 chore: new clippy warnings 2024-01-19 11:14:36 -05:00
Greg Johnston
b356d3cd28 ci: add regression test for #2190 2024-01-19 10:29:30 -05:00
Greg Johnston
ae1de88916 Revert "Better handling for trailing slashes. (#2154) (#2172)"
This reverts commit 1eaf886481.
2024-01-19 10:27:38 -05:00
Greg Johnston
67dd188358 ci: add regression test for matching main page correctly in router example 2024-01-19 10:26:58 -05:00
Joseph Cruz
1d4772251a fix: ci stopped detecting leptos or example changes (#2194) 2024-01-17 18:58:21 -05:00
benwis
98f18e7c31 release: version 0.5.6 2024-01-16 16:57:07 -08:00
Greg Johnston
3f34d9bb23 fix: doc comments breaking server functions (closes #2190) (#2191) 2024-01-16 15:31:29 -05:00
Greg Johnston
44db400f6b chore: fix spin-sdk dependency 2024-01-15 17:11:50 -05:00
Greg Johnston
3a5730800c v0.5.5 2024-01-15 17:10:49 -05:00
Sam Judelson
041b86e6e5 sso_auth_session example (#2117)
* example draft

* fmt

* db delete

* db

* oops clippy

* clippy 2

* - nightly ?

* fmt

* - cargo all features?
2024-01-15 10:48:22 -08:00
Greg Johnston
d71feada7e change: change all tracing levels to trace to reduce verbosity (#2176) 2024-01-13 08:19:12 -08:00
Cody Casterline
1eaf886481 Better handling for trailing slashes. (#2154) (#2172)
* retain trailing slashes in paths but leave matching trail-slash-insensitive

* fix: Allow trailing slashes to remain in leptos_path.

* Better handling for trailing slashes. (#2154)

This adds a trailing_slash option to <Router> and <Route>.

By default, this option is backward compatible with current Leptos
behavior, but users can opt into two new modes for handling trailing
slashes.

* cargo fmt

* Fix redirect routes for wildcard patterns.

* Clippy fixies

* (Re)Reduce the scope of PossibleBranchContext's internals.

* Test real code, not copied code.

* Test TrailingSlash redirects.

* Fixes and more tests for matching "" && "/".

This path is the exception to the rule and *should* be treated
as equivalent regardless of its trailing slash.

* cargo fmt

---------

Co-authored-by: Tadas Dailyda <tadas@dailyda.com>
2024-01-11 13:51:31 -08:00
dependabot[bot]
c7da3998ba chore(deps): bump tj-actions/changed-files in /.github/workflows (#2180)
Bumps [tj-actions/changed-files](https://github.com/tj-actions/changed-files) from 39 to 41.
- [Release notes](https://github.com/tj-actions/changed-files/releases)
- [Changelog](https://github.com/tj-actions/changed-files/blob/main/HISTORY.md)
- [Commits](https://github.com/tj-actions/changed-files/compare/v39...v41)

---
updated-dependencies:
- dependency-name: tj-actions/changed-files
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-11 16:04:21 -05:00
Luxalpa
10bbeea697 fix: remember router state (fixes #2164) (#2165) 2024-01-10 19:51:37 -05:00
webmstk
2d70229608 chore: add rust-toolchain.toml to examples (closes #2151) (#2161) 2024-01-07 15:29:54 -05:00
Paul Hansen
bbcef811f4 chore: remove dead code in actix tailwind example (#2160) 2024-01-07 15:29:15 -05:00
Simon Bihel
f5bf539148 fix: allow multiple SSRed Leptos apps on same server (closes #1806) (#2135) 2024-01-07 15:28:50 -05:00
Greg Johnston
855a3c65c0 chore: remove newly-detected unused tuple fields (#2169) 2024-01-06 18:25:20 -05:00
SleeplessOne1917
16cf3c4eaf feat: make IntoAttribute more flexible for Option<T: IntoAttribute> (#2130) 2023-12-30 13:10:07 -05:00
Greg Johnston
da533ad4e0 chore: clarify cargo-make and examples (see #2141) (#2150) 2023-12-30 08:14:23 -05:00
JackSpagnoli
b4a9db51be chore: fix broken tailwind example repo link (#2138) 2023-12-28 20:07:49 -05:00
Greg Johnston
15946c6136 fix: emit original token stream when there are syntax errors in #[component] or #[island] function signature (closes #2133) (#2134) 2023-12-25 14:30:31 -05:00
Greg Johnston
9f4c480725 docs: specify form for component generics (#2129) 2023-12-23 07:36:28 -05:00
Greg Johnston
74f9c3cd82 fix: <Transition/> fallback should show if client-rendered (closes #2123) (#2128) 2023-12-22 17:10:09 -05:00
martin frances
34fb39c976 chore: fix lifetime on example (#2125)
```bash
cd leptos/leptos_macro/example
cargo clippy
```

warning: the following explicit lifetimes could be elided: 'a
  --> src/lib.rs:41:20
   |
41 | fn TestMutCallback<'a, F>(mut callback: F, value: &'a str) -> impl IntoView
   |                    ^^                              ^^
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
   = note: `#[warn(clippy::needless_lifetimes)]` on by default
help: elide the lifetimes
   |
41 - fn TestMutCallback<'a, F>(mut callback: F, value: &'a str) -> impl IntoView
41 + fn TestMutCallback<F>(mut callback: F, value: &str) -> impl IntoView
   |

warning: `example` (lib) generated 1 warning (run `cargo clippy --fix --lib -p example` to apply 1 suggestion)
2023-12-20 19:10:59 -05:00
martin frances
ea80a21a54 chore: remove duplicate itertools versions (#2124)
The root cause is the family of leptos modules requiring both versions 0.10.5 and 0.11.0
This PR will fix that. ( Also needs a bump to 0.12.0 )

```
warning: multiple versions for dependency `itertools`: 0.10.5, 0.11.0
  |
  = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#multiple_crate_versions
note: the lint level is defined here
 --> src/lib.rs:4:9
  |
4 | #![warn(clippy::cargo)]
  |         ^^^^^^^^^^^^^
  = note: `#[warn(clippy::multiple_crate_versions)]` implied by `#[warn(clippy::cargo)]`
```
2023-12-20 19:10:00 -05:00
Greg Johnston
33590d487b chore: clean up warnings causing CI issues (#2119) 2023-12-18 08:15:46 -05:00
Rakshith Ravi
880002de31 fix: pass through doc comments for server fns (#2099) 2023-12-17 20:40:22 -05:00
Niklas Eicker
fb0a62f3f6 fix: support additional context for route generation (#2113) 2023-12-17 20:37:27 -05:00
Greg Johnston
a4bd7c4274 chore: don't warn when stabilized features are used (#2118) 2023-12-17 20:34:32 -05:00
NKID00
8122941c3c fix: let mount_to_body accept FnOnce closures (closes #2115) (#2116) 2023-12-17 20:28:18 -05:00
Gentle
21f4c27cfb chore: add nix-darwin support, update flake (#2106)
Co-authored-by: Gentle <ramon.klass@gmail.com>
2023-12-14 09:42:07 -05:00
Simon Richard
b578ec82d7 examples: change output names to clarify Tailwind examples (#2102) 2023-12-11 20:25:10 -05:00
jo!
50432e2651 examples: ergonomic improvements to session_auth_axum (#2057)
I've always hated the get_todos function and I
wanted to change it badly. Added a .env file
containing the db url for sqlx-cli, and cleaned
up with leptosfmt

Co-authored-by: j0lol <me@j0.lol>
2023-12-10 14:28:42 -05:00
Niclas Åhdén
fcc9242a63 docs: minor documentation corrections (#2098)
* Docs: Fix Body docs incorrectly referring to html

* Docs: Correct X/Z/Z to X/Y/Z in CONTRIBUTING
2023-12-10 14:24:16 -05:00
Greg Johnston
6014a70d0d fix: support complete URLs in <A/> and <Form/> (closes #2076) (#2096) 2023-12-01 19:20:43 -05:00
Trey Lowerison
ed61ea9dd2 feat: add support for placing attributes on server functions (#2093)
* fix: add support for placing attributes on server functions

Adding instrumentation to server functions is not straightforward (requires calling out to another ssr-only function which is instrumented). This commit adds all attributes on the server function to both the generated front end and back end functions. If those attributes are only desirable on the backend say, a user can always wrap their attribute in `#[cfg_attr(feature = "ssr", ..)]`.

* nit: formatting in example cargo
2023-12-01 15:36:52 -05:00
itowlson
9bbd881757 feat: support spawn_local on Spin WASI (#2066)
Signed-off-by: itowlson <ivan.towlson@fermyon.com>
2023-12-01 15:34:29 -05:00
Greg Johnston
8d68c34796 docs: point the book toward its new location with redirects (#2095) 2023-12-01 15:20:44 -05:00
Daniel Mantei
e8025705a4 docs: book restructuring and updates (#2052)
* move DX page under "Getting Started" section; add leptosfmt to DX page

* add a "community and leptos-* crates" page

* create folder for "getting_started"

* updates to 'getting started' chapter (feedback-based)

* clarify book structure + add necessary explanations

* address PR comments by @reedwoodruff

* update "getting started"

* address gbj's comments

* remove the term "universal" from book

* minor update

* formatting

* address reedwoodruff comment
2023-11-30 19:24:18 -05:00
blorbb
19711e16b6 feat: improved macro hygiene (#2084) 2023-11-29 07:47:18 -05:00
Alex Lazar
1272bd12f0 docs: use with!() macro in book and update formatting on Effect page (#2054) 2023-11-29 07:41:13 -05:00
martin frances
731b028b11 chore: Bump http from 0.2.8 to 0.2.11. (#2068) 2023-11-29 07:36:03 -05:00
sdutwsl
1a295bb3d6 docs: correct titile level for 04b_iteration.md (#2080) 2023-11-28 19:53:41 -05:00
Rockie Guo
9c44da2594 docs: minor fixes for some code examples in the book (#2077) 2023-11-28 19:53:26 -05:00
Alex Lazar
75c27e0b85 docs: fix book chapter 3.9 #3 (#2053)
* Fix book chapter 3.9 #3

* Add note about Layout and Content
2023-11-28 19:52:01 -05:00
Greg Johnston
b95a79240e v0.5.4 2023-11-28 18:46:51 -05:00
Alexis Fontaine
8e374efe8d fix: invalid attribute value for aria-current (#2089) 2023-11-28 15:23:16 -05:00
Greg Johnston
b578660624 docs: make it easy to see how to run each example in its README (#2085) 2023-11-28 11:47:56 -05:00
Greg Johnston
d6ee2a37f4 v0.5.3 2023-11-27 19:38:33 -05:00
Greg Johnston
18a92bbfd8 fix: improved rust-analyzer support in #[component] macro (#2075) 2023-11-27 19:37:43 -05:00
Greg Johnston
4e8c3accf2 fix: make prop serialization opt-in for devtools (closes #1952) (#2081) 2023-11-27 16:35:31 -05:00
Joseph Cruz
a8e25af523 ci(leptos): run ci on change instead of check (#2061)
* ci: run ci examples on leptos change

* chore(ci): simulate leptos source change

* ci(todo_app_sqlite_csr): increase retries

* ci: delete check examples workflow

* ci: rename ci examples workflow

* ci: run ci examples with stable toolchain

* chore(ci): remove simulated change

* ci: delete check stable workflow
2023-11-24 14:59:13 -05:00
Greg Johnston
d531848db5 fix: dispose previous route or outlet before rendering new one (closes #2070) (#2071) 2023-11-24 14:51:51 -05:00
hpepper
670f415565 docs: add instruction to install trunk to examples/README.md (#2064)
Co-authored-by: Henry Pepper <henry>
2023-11-24 14:06:02 -05:00
Greg Johnston
061213ca78 fix: correctly mark Trigger as clean when it is re-tracked (closes #1948, #2048) (#2059) 2023-11-22 09:29:25 -05:00
Greg Johnston
0ce4ee8a7a docs: add warning for nested Fn in attribute (see #2023) (#2045) 2023-11-22 07:35:20 -05:00
Greg Johnston
1cd6603da0 ci(examples): fix portal test (#2051) 2023-11-20 20:39:19 -05:00
Andrew Wheeler(Genusis)
453911e6fc examples: updated axum session to latest 0.9 in examples (#2049)
* updated axum_database_sessions to axum_session along with axum_sessions_auth to axum_session_auth

* updated to axum session 0.9
2023-11-20 20:33:31 -05:00
Greg Johnston
cb6267ad08 feat: <Provider/> component to fix context shadowing (closes #2038) (#2040) 2023-11-19 20:24:36 -05:00
Ken
4518d3c89f Have fetch example conform to docs guidance around using <ErrorBoundary> and <Transition> in conjunction (#2035)
* put `<ErrorBoundary>` inside `<Transition>`

* fix indentation
2023-11-18 08:24:30 -05:00
Greg Johnston
e47a619556 examples: add CSR with server functions example (closes #1975) (#2031) 2023-11-18 08:24:15 -05:00
Daniel Mantei
414f5fc393 docs: reorganize deployment section (#2036)
* Update mdbook-admonish book dependency

* Move "Optimizing Binary Size" to Deploy.. chapter

* Minor text updates to the Deployment section
2023-11-17 15:40:20 -05:00
martin frances
362e3bc603 chore: stop using std::fmt, instead used core::fmt. (#2033) 2023-11-17 15:36:13 -05:00
taohua
4d549f70c9 docs: fix misnamed form field in <Form/> example (#2024)
Co-authored-by: datewu <>
2023-11-17 15:27:06 -05:00
Chris
85dd726d43 docs: ActionForm examples for indexing into struct fields (#2017)
Co-authored-by: chrisp60 <gh@cperry.me>
2023-11-17 15:22:11 -05:00
blorbb
24febe11f3 feat: impl Default for TextProp (#2016) 2023-11-17 15:20:03 -05:00
Greg Johnston
64b1e9bed3 fix: use create_effect for <Portal/> to avoid hydration issues (closes #2010) (#2029) 2023-11-17 15:19:07 -05:00
Greg Johnston
68c91a732d fix: allow nested functions in Attribute (closes #2023) (#2027) 2023-11-15 11:00:15 -05:00
blorbb
8573f22d96 fix: re-export slice! macro (#2008) 2023-11-11 06:47:15 -05:00
Greg Johnston
61c7ff4256 docs: add note about context shadowing (closes #1986) (#2015) 2023-11-10 18:04:22 -05:00
Greg Johnston
860d887931 chore: remove duplicate benchmarks in leptos_reactive (#2014) 2023-11-10 15:53:32 -05:00
Chris
5e929a75fa feat: Action::new and Action::server (#1998) 2023-11-10 15:53:20 -05:00
Greg Johnston
d82cf0b76a docs: remove outdated APP_ENVIRONMENT variable (#2013) 2023-11-10 14:27:45 -05:00
Greg Johnston
cb7e07496a docs: fix CodeSandbox for resources (#2002) 2023-11-07 20:11:30 -05:00
Greg Johnston
17881c5c6e docs: fix chapter 10 CodeSandbox 2023-11-07 20:07:38 -05:00
Greg Johnston
2e816b26aa benchmarks: get benchmarks directory working with updated tachys 2023-11-07 20:03:35 -05:00
Gabriel Hansson
68d67c9e92 book: Fix <Body/> link in metadata.md (#1999) 2023-11-07 16:16:47 -05:00
Greg Johnston
0dea6fdcea fix: correctly reset island/not-island state of SSRed Suspense streaming into island (closes #1996) (#2000) 2023-11-07 16:16:27 -05:00
Greg Johnston
530dcff86a examples: remove incorrect CSR information for hackernews_js_fetch example (#1997) 2023-11-06 14:45:26 -05:00
Greg Johnston
9d9a4932b3 fix: run <ErrorBoundary/> in a child so siblings don't collide (closes #1987) (#1991) 2023-11-05 21:29:35 -05:00
Greg Johnston
bfb67d45e8 examples: fix style.css path (closes #1992) (#1994) 2023-11-05 21:29:17 -05:00
Greg Johnston
b1e8105442 fix: treat Suspense as containing a Set of resources, not a counter (closes Suspense only working with a single Resource (closes #1805, closes #1905) (#1985) 2023-11-04 11:03:36 -04:00
Greg Johnston
7aced17976 docs: clarify need to provide context to both rendering and server function handler (#1983) 2023-11-03 18:34:50 -04:00
Gabriel Hansson
191b40b2ac docs: point leptos_server docs.rs url to latest version. (#1982) 2023-11-03 17:05:42 -04:00
Gabriel Hansson
15ca5bec61 docs: fix <Transition/> url in 12_transition.md (#1980) 2023-11-03 17:00:26 -04:00
Gabriel Hansson
ba4d226004 docs: Fix 08_parent_child.md callback example code. (#1976) 2023-11-03 16:58:45 -04:00
Chris
3adfd334df fix: leptos_router::params_map! (#1973)
Fixing implementation comes with the benefit of knocking a crate out of
the deps tree (`common_macros`).
2023-11-02 16:29:50 -04:00
martin frances
d7ca5f2e96 chore: typed-builder and typed-builder-macro - bumped version numbers. (#1958) 2023-10-29 21:49:48 -04:00
Chris
67bdb3498f docs: switch feature flag stable to nightly (#1959) 2023-10-29 21:48:53 -04:00
Greg Johnston
9e9386b223 does this make clippy happy in CI? (#1965) 2023-10-29 21:48:33 -04:00
SleeplessOne1917
4029de2d42 feat: impl IntoAttribute for TextProp (#1925) 2023-10-27 17:10:09 -04:00
Greg Johnston
777095670e fix: add leptos_axum::build_static_routes (closes #1843) (#1855) 2023-10-27 17:09:52 -04:00
koopa
a11c6303e2 feat: allow arbitrary attributes for <A/> component (#1953) 2023-10-27 15:30:30 -04:00
Daniél Kerkmann
3394e316b7 docs: add ignoring #[server] macro for helix as well (#1951)
Update helix configuration for the newest version.
To be consistent, adding the `server` ignore entry to helix as well.
Also sorting the parameters alphabetically.
2023-10-27 13:55:00 -04:00
Ari Seyhun
4b0437394c feat: impl IntoAttribute for Cow<'static, str> (#1945) 2023-10-27 13:48:43 -04:00
Ari Seyhun
d10a566e48 feat: add new method to Trigger (#1935) 2023-10-27 13:48:15 -04:00
martin frances
e0cca3e7a3 workflows: bumped tj-actions/changed-files to @39. (#1942) 2023-10-27 13:47:56 -04:00
martin frances
0c8ab7c725 workflows: bump setup-node to version 4. (#1944) 2023-10-27 13:47:33 -04:00
Ari Seyhun
a2bef05a4b perf: IntoView and IntoAttribute for std::fmt::Arguments improvements (#1947)
* fix: use static str when possible in `std::fmt::Arguments` in views

* feat: impl `IntoAttribute` for `std::fmt::Arguments`
2023-10-27 13:42:27 -04:00
Greg Johnston
6361985fb1 fix: relax 'static bound on as_child_of_current_owner (#1955) 2023-10-27 13:20:34 -04:00
Greg Johnston
ad290f5ed2 chore: update README.md to remove note about 0.5 2023-10-24 22:12:12 -04:00
Greg Johnston
5f53a1459e v0.5.2 2023-10-24 21:03:29 -04:00
Greg Johnston
379623d548 chore: fix SSR tests (#1943) 2023-10-24 17:53:45 -04:00
Greg Johnston
db1113e5b3 fix: use separate key in hydration ID for router outlets (closes #1909) (#1939) 2023-10-24 15:42:30 -04:00
Greg Johnston
d943a50df1 fix: misaligned </head> tags in streaming responses (closes #1930) (#1932) 2023-10-24 15:42:07 -04:00
Greg Johnston
eb86899e08 chore: remove wee_alloc to make Dependabot happy (#1938) 2023-10-24 15:41:03 -04:00
Greg Johnston
e2842ede44 chore: fix broken doctests in leptos_reactive 2023-10-24 15:35:16 -04:00
Greg Johnston
fdd4b3d919 chore: cargo fmt 2023-10-24 15:01:33 -04:00
nikhilraojl
7771052db8 docs: clarify docs on resource source signal (#1918) 2023-10-24 14:29:09 -04:00
martin frances
d999ff857d chore: remove cargo doc lint warnings (#1936) 2023-10-24 14:28:01 -04:00
Sadra
30370a55e1 feat: add a slice!() macro (#1867) 2023-10-24 14:27:10 -04:00
koopa
a7330d61b6 feat: add replace prop to Form component (#1923) 2023-10-24 14:24:23 -04:00
Marc-Stefan Cassola
e2f6780de4 docs: added Callback to documentation and examples. (#1926)
* added Callback to documentation and examples.
Also reduced code duplication in Callback implementation.

* added back the closure event callback example
2023-10-24 14:14:51 -04:00
martin frances
05b4f8e617 chore: use .first() [not .get(0)] (#1929) 2023-10-23 21:02:42 -04:00
Greg Johnston
eb888029d1 docs: fix potential panic in 04b_iteration.md 2023-10-22 07:28:06 -04:00
Daniél Kerkmann
3e08486385 feat: Add local attribute for Await (#1922)
This PR adds the ability to use `create_local_resource` instead of
`create_resource`. This will run the create resource locally on the
system and therefore its result type does not need to be `Seriaziable`.

Closes #1567
2023-10-21 18:34:02 -04:00
Greg Johnston
12b0295906 chore: please clippy (#1924) 2023-10-21 18:33:21 -04:00
Greg Johnston
2756327f12 fix: add missing IntoView implementation for Oco<'static, str> 2023-10-21 16:02:14 -04:00
Greg Johnston
b8ca8b7849 docs: add chapter on nested reactivity and iteration (#1920) 2023-10-20 15:18:38 -04:00
Greg Johnston
6abdca0597 docs: better document default and wasm features on leptos_axum (closes #1872) (#1883) 2023-10-20 14:57:53 -04:00
Greg Johnston
bf14999eb2 fix: router should still scroll to hash even if path didn't change (closes #1907) (#1917) 2023-10-20 14:57:35 -04:00
Marc-Stefan Cassola
c87328f5cf feat: add directives with use: (#1821) 2023-10-19 16:15:36 -04:00
safx
9a70898b09 feat: optional named arguments for #[server] macro (#1904) 2023-10-19 16:07:43 -04:00
Greg Johnston
4a83ffca6f fix: try_update() and try_set() on Resource should not panic (closes #1915) (#1916) 2023-10-19 15:56:57 -04:00
Saikat Das
319017f03f docs: fix typo (#1910) 2023-10-19 09:00:30 -04:00
Greg Johnston
33e166a462 allow construction by making data public 2023-10-18 19:16:08 -04:00
Greg Johnston
8994154b23 fix: maintain hash when setting query signal (closes #1902) (#1908) 2023-10-17 20:28:57 -04:00
luoxiaozero
7b88df32d1 feat: add a target prop to the <A/> component (#1906) 2023-10-17 20:28:37 -04:00
PianoPrinter
0d6ddfb71e fix: properly handle trailing / in more routes (#1900) 2023-10-17 12:45:22 -04:00
Greg Johnston
4a4e16c206 chore: tweak tracing levels (#1901) 2023-10-17 12:44:37 -04:00
Henry Rovnyak
11f6a5d341 fix: remove Clone bound for SignalWith for Resource (#1895) 2023-10-16 14:37:38 -04:00
Greg Johnston
ad208ec473 fix: bug with client-side routing no longer working due to different origin (#1899) 2023-10-15 20:39:03 -04:00
Ari Seyhun
72ad1d7c68 feat: add new method to NodeRef (#1896) 2023-10-15 19:56:23 -04:00
Quan Hua
d6a9d2efdf docs: update deployment.md (#1898)
cargo-leptos@0.2.0 changes the file structure under target folder
2023-10-15 19:55:36 -04:00
Greg Johnston
8eed999611 fix: properly handle trailing / in splat routes (closes #1764) (#1890) 2023-10-14 08:37:31 -04:00
Azzam S.A
07f2cbfbba examples: rename Tailwind examples (#1875) 2023-10-13 16:20:26 -04:00
ymijorski
fc4dea6839 feat: allow custom attributes on leptos_meta components (#1874) 2023-10-13 15:30:48 -04:00
Greg Johnston
17b3300351 fix: ensure there's no reactive tracking in an on_cleanup (closes #1882) (#1889) 2023-10-12 07:36:07 -04:00
Greg Johnston
f3508cef36 feat: add reasonable fallback behavior for ActionForm in an island (#1888) 2023-10-11 18:59:49 -04:00
Greg Johnston
5c41d20421 Merge pull request #1887 from leptos-rs/1886
Fix failing `cargo make lint` for `hackernews_js_fetch`
2023-10-11 18:59:22 -04:00
Greg Johnston
53e16751a7 chore: clean up style and bring into line with other hackernews examples 2023-10-11 16:45:48 -04:00
Greg Johnston
18f7b56c03 fix: do not force target wasm32 for CI purposes 2023-10-11 16:45:36 -04:00
Greg Johnston
c6f51e6a09 docs: add some missing #[must_use] to avoid accidental () rendering (#1885) 2023-10-11 15:00:27 -04:00
dandante
971fb734de docs: fix Markdown in 02_getting_started.md (#1873) 2023-10-11 12:06:16 -04:00
luoxiaozero
200304402f feat: implement Default for RwSignal and StoredValue (#1877) 2023-10-11 12:05:05 -04:00
Greg Johnston
4baa75ccf0 fix: correctly untrack in .try_with_untracked (closes #1880) (#1881) 2023-10-11 12:04:16 -04:00
Greg Johnston
9af1c7e1a3 fix: hydration ID clash with Suspense > Outlet > Suspense (closes #1863) (#1864) 2023-10-09 16:22:43 -04:00
obioma
a302257129 docs: improvements in book - closes #1845 (#1856) 2023-10-09 16:21:09 -04:00
Marc-Stefan Cassola
4251f6c0f4 feat: add Portal component (#1820) 2023-10-09 16:18:52 -04:00
Markus Kohlhase
c080c2cbca fix: use placeholder in comments for empty component names (#1850) 2023-10-09 16:17:46 -04:00
Tyrone Tudehope
0676348bd4 docs: fix Prop-drilling example in Parent-Child Communication section (#1865) 2023-10-09 16:17:26 -04:00
Tyrone Tudehope
18ad7cde20 docs: Add missing argument name to WrapsChildren component (#1866) 2023-10-09 16:16:59 -04:00
Jesse He
b61d0553a0 docs: remove extra "```rust" and add closing bracket to Testing docs (#1870) 2023-10-09 16:16:43 -04:00
Greg Johnston
2a3b613230 docs: add islands guide/demo to the docs (#1861) 2023-10-07 13:10:49 -04:00
Greg Johnston
0d4862b238 feat: add extractor functions with better API than extract (closes #1755) (#1859) 2023-10-07 13:10:30 -04:00
hiraginoyuki
c7607f6fcc fix: documentation in leptos_reactive::Trigger (#1844) 2023-10-07 10:45:27 -04:00
Artur Corrêa Souza
29216b226f docs: clarify what "once per signal change" means (#1858) 2023-10-07 10:44:06 -04:00
Greg Johnston
32ba0ce4fb add awesome-leptos to README 2023-10-07 10:43:21 -04:00
Greg Johnston
c781b4e1c7 docs: update CodeSandboxes to 0.5 2023-10-06 14:20:01 -04:00
Greg Johnston
be2d014f08 v0.5.1 2023-10-06 09:40:23 -04:00
Jesse He
18cdf70864 docs: fix hidden #two 2023-10-06 07:31:23 -04:00
Greg Johnston
1be25f0f47 fix: clippy "needless lifetimes" warning (closes #1825) (#1852) 2023-10-06 07:29:34 -04:00
Greg Johnston
cc93651bc9 fix: panic during generate_route_list if you immediately dispatch an action (#1853) 2023-10-06 07:29:10 -04:00
Kevin Old
a7a1559e01 fix: update log debug to use get_untracked for logged in user to resolve client side error (#1834) 2023-10-05 21:34:58 -04:00
martin frances
15f08aaa30 chore: removed warning in build artefacts. (#1840)
```
The following actions uses node12 which is deprecated and will be forced to run
   on node16: actions-rs/toolchain@v1. For more info:
   https://github.blog/changelog/2023-06-13-github-actions-all-actions-will-run-on-node16-instead-of-node12-by-default/
```

In other places @3 was being used, so for consitency I have bumped everything up to @4

-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
2023-10-05 21:15:01 -04:00
blorbb
d0295bae01 feat: support stored values in with! and update! (#1836) 2023-10-05 21:14:33 -04:00
Ben Wishovich
5220c37edd fix: make Async Mode return Content-Type header in Response (#1851) 2023-10-05 21:13:33 -04:00
Paul Wagener
4f649e020c feat: allow disposing of Signal & StoredValue (#1849) 2023-10-05 21:02:50 -04:00
Greg Johnston
e0d15c1a09 fix: correctly quote spread attributes in {..attrs} syntax (closes #1826) (#1831) 2023-10-02 18:02:49 -04:00
Greg Johnston
6f9c40b0a8 fix: correctly handle Suspense with local resources during hydration (closes #1823) (#1824) 2023-10-02 18:02:35 -04:00
Daniel Santana
a946a0181d fix: don't overwrite <Html/> props (closes #1828) 2023-10-02 13:46:20 -04:00
Marc-Stefan Cassola
6d44540ab3 feat: optional fallbacks for Show, Suspense, and Transition (#1817) 2023-10-02 08:29:21 -04:00
Sebastian Dobe
6a547cb9db docs: DX improvements: add section about jetbrains intellij-rust (#1804) 2023-10-02 08:26:35 -04:00
Tanguy
ac8dd7af67 fix: template! cfg condition (#1822) 2023-10-02 07:52:54 -04:00
Greg Johnston
0962f699e4 Merge pull request #1818 from leptos-rs/1816
Missing docs and `Copy` impl for `Callback`
2023-10-01 08:27:29 -04:00
Greg Johnston
fcd1028fb7 docs: missing module-level docs for Callback 2023-09-30 15:52:47 -04:00
Greg Johnston
dc429e33ff fix: missing Copy impl on Callback 2023-09-30 15:52:11 -04:00
Greg Johnston
6b40ca36a5 docs: fix For view prop name (closes #1813) (#1814) 2023-09-30 15:49:26 -04:00
Greg Johnston
d869bc6675 chore: clippy 2023-09-29 20:36:15 -04:00
Greg Johnston
d8aeb82949 cargo fmt 2023-09-29 20:35:39 -04:00
Greg Johnston
32e8213ebf v0.5.0 2023-09-29 17:13:56 -04:00
Greg Johnston
fa2be59895 feat: better error handling for ScopedFuture (#1810) 2023-09-29 17:12:56 -04:00
Sirius902
321c522fa5 fix: extra set of brackets in generate_head_metadata (#1811) 2023-09-29 17:12:46 -04:00
Greg Johnston
7378b8581a fix: broken Suspense when a resource loads immediately (closes #1805) (#1809) 2023-09-29 14:44:49 -04:00
Ben Wishovich
2d634364a9 feat: set Content-Type header for all Responses to text/html;charset="utf-8" (#1803) 2023-09-29 13:51:15 -04:00
Greg Johnston
f7adf6f73d examples: fix hackernews examples oops 2023-09-29 13:36:13 -04:00
martin frances
fb914e1a50 chore: bump outdated dependencies in leptos_macro (#1796)
-attribute-derive = { version = "0.6", features = ["syn-full"] }
+attribute-derive = { version = "0.8", features = ["syn-full"] }
-itertools = "0.10"
+itertools = "0.11"
2023-09-29 13:05:57 -04:00
Julien Scholz
772bb1d60c fix: improve rust-analyzer auto-completion (#1782) 2023-09-29 13:05:13 -04:00
Antonin Peronnet
bd4d2202ea feat: standardize on a Callback type that is Copy (#1795) 2023-09-29 13:04:53 -04:00
Greg Johnston
870808e63f feat: implement From<Fn() -> T> for Signal<T> (#1801) 2023-09-29 09:13:27 -04:00
Ben Wishovich
d7fff5a8ab fix: render_route error message and matching of non standard routes (#1799) 2023-09-29 09:10:59 -04:00
jquesada2016
609afce544 feat: Scoped Futures (#1761) 2023-09-28 15:20:18 -04:00
messense
181bcadbe2 feat(leptos_config): only enable toml feature for the config dependency (#1788) 2023-09-27 19:42:25 -04:00
Greg Johnston
3f2a9facf8 change: enable inline children for For by switching to children and bind: (#1773) 2023-09-26 14:24:02 -04:00
Saeed Andalib
c5c79234f1 docs: update working_with_signals.md (#1785)
Pulled the option number 2 out of the blockquote
2023-09-26 14:23:47 -04:00
Fangdun Tsai
de9fb5e382 chore(leptos_meta): enhance links in docs (#1783) 2023-09-25 20:34:11 -04:00
Greg Johnston
c9d132f007 change: use let: instead of bind: (#1774) 2023-09-25 20:33:36 -04:00
Greg Johnston
a1a9d41a7a updating SSR benchmarks to include tachys 2023-09-25 15:45:52 -04:00
Greg Johnston
73112c9faa Merge pull request #1779 from leptos-rs/docs-show
docs: fix `Show` docs reference to scope
2023-09-25 07:54:38 -04:00
Sean Aye
50678dafe1 feat: add JS Fetch integration support (#1554) 2023-09-25 07:51:25 -04:00
Greg Johnston
b1363a16ab docs: fix Show docs reference to scope 2023-09-23 12:46:41 -04:00
Greg Johnston
ae986e71fa change: only run create_local_resource in the browser (#1777) 2023-09-23 11:10:50 -04:00
Antonin Peronnet
0531831fe8 chore: add cargo-make and trunk in nix flake (#1763)
* add `cargo-make` dependency for nix
* add `trunk` dependency for nix
2023-09-23 11:10:24 -04:00
Greg Johnston
18eeee8e1f 0.5.0-rc3 2023-09-22 17:38:54 -04:00
Greg Johnston
d99269afac docs: error in view! macro if you use cx, (#1772) 2023-09-22 17:29:55 -04:00
Nico Burniske
38d1727e9c change: generate_route_list no longer async in any integration (#1485) 2023-09-22 15:42:58 -04:00
Greg Johnston
e0265252d7 fix: broken benchmarks (closes #1763) (#1771) 2023-09-22 15:41:44 -04:00
Fangdun Tsai
6cc92cee8d chore(leptos_hot_reload): apply lints suggestions (#1735) 2023-09-22 13:48:23 -04:00
Fangdun Tsai
1d392483b4 chore(leptos_marco): enhancement of document generation (#1768) 2023-09-22 13:32:58 -04:00
Village
3b864ac1a0 feat: Static Site Generation (#1649) 2023-09-22 13:32:09 -04:00
Danik Vitek
baa5ea83fa fix: reimplement Oco cloning (#1749) 2023-09-22 13:31:04 -04:00
Gabriel de Perthuis
d651400fa2 docs: better document the interaction of SsrModes with blocking resources (#1765)
Meant to address users making the same mistake as
https://github.com/leptos-rs/leptos/issues/1119
2023-09-22 12:58:28 -04:00
Fangdun Tsai
b729a658df chore(leptos_router): improve docs (#1769) 2023-09-22 12:56:49 -04:00
Gabriel de Perthuis
2c8f46466b feat: support default values for annotated server_fn arguments with #[server(default)] (#1762)
This allows form submission with checkbox inputs to work.
For example:

    let doit = create_server_action::<DoItSFn>();
    <ActionForm action=doit>
      <input type="checkbox" name="is_good" value="true"/>
      <input type="submit"/>
    </ActionForm>

    #[server(DoItSFn, "/api")]
    pub async fn doit(#[server(default)] is_good: bool) -> Result<(), ServerFnError> {}

If is_good is absent in the request to the server API,
`Default::default()` is used instead.
2023-09-20 20:43:20 -04:00
Greg Johnston
f2117b1186 fix: restore missing run_as_child 2023-09-20 19:37:39 -04:00
Greg Johnston
726cf47f17 Merge pull request #1758 from leptos-rs/sus2
Fix Suspense issues on subsequent navigations
2023-09-20 13:32:35 -04:00
Greg Johnston
1759a3e149 feat: correctly use_context between islands (#1747) 2023-09-19 21:16:47 -04:00
Fangdun Tsai
2374439cd8 chore(server_fn): improve docs in server_fn (#1734) 2023-09-19 21:16:30 -04:00
Greg Johnston
f85bfd31db fix: Transition double-rendering 2023-09-19 21:04:41 -04:00
Greg Johnston
43b58bfba9 Revert "fix: #1742 part 2 (Suspense running children a second time => extra animations)"
This reverts commit fafb6c01da.
2023-09-19 21:04:02 -04:00
Greg Johnston
fafb6c01da fix: #1742 part 2 (Suspense running children a second time => extra animations) 2023-09-19 10:32:25 -04:00
Greg Johnston
1bd47f34e5 feat: make Transition set_pending use #[prop(into)] (#1746) 2023-09-18 22:46:03 -04:00
Greg Johnston
661a038780 fix: Resource::with() (pt. 3!) — closes #1751 without breaking #1742 or #1711 (#1752) 2023-09-18 22:45:50 -04:00
Fangdun Tsai
e706a69139 chore(server_fn_macro): improve docs (#1733) 2023-09-18 20:48:47 -04:00
Greg Johnston
2b59ae18bc fix: Resource::with() pt. 2 — (closes #1742 without reopening #1711) (#1750) 2023-09-18 16:13:48 -04:00
Lukas Potthast
7d3e2a41b9 fix: Callback clone impls missing a generic (#1744) 2023-09-18 13:47:29 -04:00
Joseph Cruz
7ef57345ca fix(examples/error_boundary): ci error (#1739)
* fix(examples/build): maybe spawn client process

* docs(examples/error_boundary): add testing note
2023-09-17 20:38:03 -04:00
Greg Johnston
7e5169e66d 0.5.0-rc2 2023-09-15 20:06:56 -04:00
Greg Johnston
73a85b4955 feat: use attr: syntax rather than AdditionalAttributes (#1728) 2023-09-15 18:36:54 -04:00
Village
2c12256260 feat: allow component names to be paths (#1725) 2023-09-15 18:18:29 -04:00
Chris
a821abfb11 fix: relax bounds on LeptosRoutes (#1729) 2023-09-15 18:17:55 -04:00
Greg Johnston
20e5db22b8 fix: replace uses of create_effect internally with create_isomorphic_effect (closes #1709) (#1723) 2023-09-15 17:23:36 -04:00
Greg Johnston
54e8a536c4 fix: correctly register Resource::with() (closes #1711) (#1726) 2023-09-15 16:49:28 -04:00
Greg Johnston
afa67726c1 fix: document #[prop(default = ...)] as in Optional Props (closes #1710) (#1721) 2023-09-15 15:16:46 -04:00
Greg Johnston
1db3e9c686 feat: implement Serialize and Deserialize for Oco<_> (#1720) 2023-09-15 15:16:35 -04:00
blorbb
2fd6e0a2a8 feat: support move on with! macros (#1717) 2023-09-15 12:58:30 -04:00
Gabriel de Perthuis
af454c7643 docs: typo in table of contents (#1719) 2023-09-15 12:58:09 -04:00
Joseph Cruz
1a589fcf32 fix(examples/build): do not require stop to end trunk (#1713)
* fix(examples/build): let ctrl-c stop trunk

* doc(examples/build): add stop server hints
2023-09-14 17:07:16 -04:00
Joseph Cruz
af215d6ce8 fix: exclude markdown files from examples lists (#1716)
* fix(examples/gen-members): exclude markdown files

* fix(ci): exclude markdown files from examples list

* test(ci): simulate leptos change

* chore(ci) :remove simulated change
2023-09-14 16:58:46 -04:00
Greg Johnston
e9fef73f53 docs: note about 0.5 in book 2023-09-14 15:53:27 -04:00
Chris
7c9b118b2d docs: update out-of-date docs for component macro (#1696) 2023-09-14 13:47:04 -04:00
Cosmo Brain
5db2590bc6 feat: implement LeptosRoutes for &mut ServiceConfig in leptos_actix (#1706) 2023-09-13 20:56:03 -04:00
Lukas Potthast
dc1ba24470 fix: manual Clone and Debug impl for Callbacks (#1703) 2023-09-13 19:59:23 -04:00
Joseph Cruz
e384d53996 doc(examples): reference run instructions (#1705) 2023-09-13 19:57:50 -04:00
jquesada2016
946f9ff3e1 feat: impl From<HtmlElement<El>> for HtmlElement<AnyElement> (#1700) 2023-09-13 19:55:48 -04:00
Baptiste
8d690ac146 fix: IntoView impl for Rc<dyn Fn() -> impl IntoView> (#1698) 2023-09-13 19:55:08 -04:00
Greg Johnston
8245d77738 Merge pull request #1704 from leptos-rs/rc1-fixes
A few fixes to rc1
2023-09-13 16:51:19 -04:00
Greg Johnston
59c7684568 fix: warnings on hydrating () 2023-09-13 12:01:05 -04:00
Greg Johnston
a158e7f8bd fix: remove erroneous log 2023-09-13 12:00:56 -04:00
Joseph Cruz
c11c4b0e3e build(examples): make it easier to run examples (#1697)
* build(examples): support process management
* build(examples): manage trunk
* build(examples): manage cargo leptos
* doc(examples): add run instructions
2023-09-12 10:46:16 -04:00
Greg Johnston
fe42ac11a8 0.5.0-rc1 2023-09-11 21:08:14 -04:00
blorbb
00f8c9583d feat: with! macros (#1693) 2023-09-11 21:01:50 -04:00
Greg Johnston
a317874f93 change: run effects after a tick (#1680) 2023-09-11 21:01:35 -04:00
Greg Johnston
651356a9ec docs: add docs for #[island] macro (#1691) 2023-09-11 19:56:33 -04:00
Village
1c2327b2d6 feat: attr: and #[prop(attrs)] syntax for passing attributes down to components (#1628) 2023-09-10 15:19:53 -04:00
Michael Jarvis
8c3e0f23b0 docs: fix interlude_projecting_children.md (#1690) 2023-09-10 15:18:11 -04:00
martin frances
1719c0d352 chore: cleared "cargo doc" issue. (#1687)
warning: Rust code block is empty
   --> leptos_reactive/src/memo.rs:209:9
    |
209 |     /// ```
    |         ^^^
    |
    = note: `#[warn(rustdoc::invalid_rust_codeblocks)]` on by default
help: mark blocks that do not contain Rust code as text
    |
209 |     /// ```text
    |            ++++
2023-09-10 15:17:36 -04:00
Greg Johnston
bb78f64cd5 fix: broken mount_to_body in CSR mode (#1688) 2023-09-10 13:23:32 -04:00
Greg Johnston
2fe5be2483 fix: restore deleted extract_with_state function (#1683) 2023-09-10 07:55:13 -04:00
martin frances
929fe08525 chore: remove ambiguity surrounding serde version numbers. (#1685)
These lint warnings.

warning: /home/martin/build/leptos/leptos/Cargo.toml: dependency (serde) specified without providing a local path, Git repository, version, or workspace dependency to use. This will be considered an error in future versions
warning: /home/martin/build/leptos/leptos/Cargo.toml: dependency (serde_json) specified without providing a local path, Git repository, version, or workspace dependency to use. This will be considered an error in future versions
2023-09-09 16:15:34 -04:00
Greg Johnston
66dfef8729 Merge pull request #1681 from leptos-rs/docs 2023-09-08 17:11:47 -04:00
Greg Johnston
238d61ce1e feat: experimental islands (#1660) 2023-09-08 16:33:00 -04:00
Greg Johnston
2fa2bf1706 docs: format 2023-09-08 16:27:50 -04:00
Greg Johnston
a07984be9e docs: add runtime warnings for mixing view! and builder in SSR mode (closes #1645) 2023-09-08 16:27:29 -04:00
Greg Johnston
e8a7086546 docs: add section on small DX wins (closes #1310) 2023-09-08 16:12:27 -04:00
Greg Johnston
23d48d4c0e docs: remove stray references to Scope (closes #1671) 2023-09-08 16:02:45 -04:00
Greg Johnston
3342faa039 docs: discuss #[component(transparent)] in router docs (closes #1627) 2023-09-08 15:57:02 -04:00
Greg Johnston
6c24061c82 docs: emphasize that you should only render <Routes/> once (closes #1552, #1620) 2023-09-08 15:48:41 -04:00
Greg Johnston
b9a1fb7743 examples: add note about potential for memory leaks with nested signals (#1675) 2023-09-08 15:28:18 -04:00
martin frances
3c3fc969ac chore: removed resolver link warning in example (#1677) 2023-09-08 14:47:14 -04:00
blorbb
c87212f2d7 chore: remove (most) syn 1 dependencies (#1670) 2023-09-08 14:46:38 -04:00
Baptiste
b3a4c95dad feat: Rc-backed ChildrenFn (#1669) 2023-09-08 07:44:50 -04:00
Greg Johnston
de44b1f91f Merge pull request #1673 from martinfrances107/router_version_bump
Router version bump
2023-09-08 07:43:47 -04:00
Greg Johnston
689022661d change: move logging macros into a logging module to avoid name conflicts with log and tracing (#1658) 2023-09-08 07:42:58 -04:00
Joseph Cruz
905d46a09d refactor(examples): extract client process tasks (#1665) (#1666)
* doc(test-report): report trunk and node

* refactor(examples): extract client process tasks

* chore(exaples): force ci
2023-09-08 07:31:55 -04:00
martinfrances107
5585f20940 chore: Bumped a few outdated packages.
-cached = { version = "0.44.0", optional = true }
+cached = { version = "0.45.0", optional = true }
-lru = { version = "0.10", optional = true }
+lru = { version = "0.11", optional = true }
2023-09-08 09:30:13 +01:00
martinfrances107
5c3ed3f018 Chore: Bump to actions/checkout@v4 2023-09-08 08:28:01 +01:00
Greg Johnston
03cabf6ea3 chore: create SECURITY.md 2023-09-06 21:19:33 -04:00
SleeplessOne1917
2798dc455f examples: use cargo-leptos Tailwind support in Tailwind examples (#1625) 2023-09-06 07:25:00 -04:00
Florian Wickert
db20be5576 fix: compare path components to detect active link in router (#1656) 2023-09-06 06:49:10 -04:00
Nya
495862e9f9 fix: custom events on components (#1648) 2023-09-04 13:27:33 -04:00
Joseph Cruz
2ca1c51fdc test(error_boundary): add e2e testing (#1651)
* test(error_boundary): open app

* test(error_boundary): click up arrow

* test(error_boundary): click down arrow

* test(error_boundary): type number

* test(error_boundary): clear number

* fix(build): clean trunk directories

* fix(test-report): detect unit tests

* ci(build): echo stop trunk
2023-09-04 13:25:44 -04:00
Greg Johnston
70e1ad41e2 Merge pull request #1579 from leptos-rs/rusty
feat: start adding some Rustier interfaces for reactive types
2023-09-04 13:23:18 -04:00
Greg Johnston
53ec7ed272 feat: add Effect::with_value_mut() 2023-09-04 11:14:07 -04:00
Greg Johnston
d98a577740 feat: add Rustier interfaces for reactive system types 2023-09-04 11:05:23 -04:00
jquesada2016
fd834f48c2 change: rename .derived_signal() and .mapped_signal_setter() methods (#1637) 2023-09-04 08:41:41 -04:00
Greg Johnston
7be65a37c6 fix: versioned resources never decrement Suspense (closes #1640) (#1641) 2023-09-03 20:21:16 -04:00
Banzobotic
3b5e2d86fb docs: clean up messy spacing left over from cx replacements (#1626) 2023-09-03 20:21:05 -04:00
jquesada2016
716b9fb50b feat: add .into_X_boxed() for classes, properties, and styles as for attributes 2023-09-03 20:18:49 -04:00
jquesada2016
006ca13797 chore: hide get_property (#1638) 2023-09-03 20:15:15 -04:00
Village
6e008343c8 feat: add component generics (#1636) 2023-09-03 20:09:50 -04:00
Greg Johnston
2ca24883ac fix: memoize Suspense readiness to avoid rerendering children/fallback (#1642) 2023-09-03 20:07:20 -04:00
Village
4a43983f4e feat: implement spreading attributes onto elements (#1619) 2023-09-01 20:52:15 -04:00
IcosaHedron
d9e83121c1 feat: add reload websocket configuration and enable env configuration (#1613) 2023-09-01 20:51:46 -04:00
Antonin Peronnet
f5b4b97c9b feat: Callback types to make it easier to accept (optional) callback props (#1596) 2023-09-01 20:51:32 -04:00
Gareth
bcfa430a40 docs: fix incorrect variable name (#1623) 2023-09-01 07:39:41 -04:00
Lawrence Qupty
7c51815cf5 docs: remove extra space (#1622) 2023-09-01 07:39:05 -04:00
Dmitry Pytaylo
fee2fb953b docs: fix typo (#1618) 2023-09-01 07:37:52 -04:00
Sadra M
8ecb7f59c4 docs: update references to server binary in dockerfile (#1617) 2023-09-01 07:37:24 -04:00
martin frances
b85cb9fb3b docs: clarify how many times derived signals are called (#1614) 2023-09-01 07:36:15 -04:00
Joseph Cruz
a631c5ca1c doc(examples): report fantoccini use (#1616) 2023-09-01 07:35:29 -04:00
Greg Johnston
bee9bd8f67 0.5.0-beta2 2023-08-29 21:23:59 -04:00
Greg Johnston
8d3874f8a9 cargo fmt 2023-08-29 21:19:24 -04:00
Einherjar
bade16d227 docs: discuss unique paths for #[server] functions (#1610) 2023-08-29 20:49:31 -04:00
Jon Cahill
e0a132bde3 fix: don't try to parse as JSON the result from a server function redirect (#1604) 2023-08-29 20:42:19 -04:00
Daniel Oliveira
4d7e1f4d26 feat: improve server function client side error handling (#1597)
Handle all error codes 401-499 in addition to the
400 and 500-599 that were already handled.

In addition, handle them all in the same way
and improve the error message.
2023-08-29 20:40:03 -04:00
Maneren
700eee6604 fix(macro/params): clippy warning (#1612) 2023-08-29 20:31:54 -04:00
Joseph Cruz
694ed61e4c fix(ci): add new webkit dependency (#1607) (#1608) 2023-08-28 11:08:47 -04:00
Joseph Cruz
d7330097ba chore(examples): improve cucumber support #1598 (#1599)
* chore(examples): add cucumber runner

* chore(examples): clean cargo recursively
2023-08-28 11:08:22 -04:00
Greg Johnston
c65a3a6ca3 docs: add docs for builder syntax (#1603) 2023-08-28 11:08:07 -04:00
Danik Vitek
793c191619 feat: Oco (Owned Clones Once) smart pointer (#1480) 2023-08-26 11:43:51 -04:00
Greg Johnston
6c3e2fe53e feat: update to typed-builder 0.16 (closes #1455) (#1590) 2023-08-26 10:10:42 -04:00
Greg Johnston
08c419e3ee fix: broken test with untrack in tracing props (#1593) 2023-08-26 09:20:14 -04:00
Greg Johnston
736f4185b5 Merge pull request #1588 from leptos-rs/1457
Some resource and transition fixes
2023-08-26 07:34:21 -04:00
Greg Johnston
9cc0fc8c49 fix: adjust tracing properties 2023-08-26 07:24:52 -04:00
Greg Johnston
8f067dcde7 chore: clear release-mode warnings 2023-08-25 17:16:00 -04:00
Greg Johnston
ad6eb58fe1 fix: <Transition/> fallback in CSR 2023-08-25 17:12:01 -04:00
Greg Johnston
3f3ab1c3c8 remove unnecessary parens 2023-08-25 16:49:26 -04:00
Greg Johnston
9adae32847 examples: improve hackernews behavior 2023-08-25 16:00:47 -04:00
Greg Johnston
b8098e7992 fix: <Transition/> fallback on non-initial page loads 2023-08-25 16:00:47 -04:00
Greg Johnston
bef4d0dd3b fix: resource loading signal pattern for subsequent hydration page loads 2023-08-25 16:00:47 -04:00
Matt Cuneo
a789100e22 feat: allow autoreload websocket connection to work outside of localhost (#1548)
* Updated client reloading to use window.location.protocol/host to determine websocket connection. Added optional config reload_external_port to provide further control of the client websocket connection. These changes allow reloading while accessing the served site from outside of localhost.
2023-08-25 15:54:22 -04:00
Greg Johnston
abeca70625 fix: correct logic for resource loading signal when read outside suspense (#1586) 2023-08-25 11:46:54 -04:00
rkuklik
cc293b1170 feat: generic event handler types to make it easier to create collections of event handlers (#1444) 2023-08-25 11:41:16 -04:00
Greg Johnston
8ab62c17c6 feat: add Fn traits for resources on nightly (#1587) 2023-08-25 11:20:29 -04:00
Joseph Cruz
cf14e857ca refactor(check-stable): use matrix (#1543) (#1583)
* refactor(check-stable): use matrix

* chore: simulate leptos change

* chore: remove simulated change
2023-08-25 10:30:00 -04:00
Greg Johnston
c322ef38fd feat: signal traits should take associated types instead of generics (#1578) 2023-08-25 10:29:24 -04:00
Greg Johnston
c9cc493063 fix: fourth argument to server functions (#1585) 2023-08-25 10:28:54 -04:00
Joseph Cruz
fb48f7f117 fix(counters_stable): restore wasm tests (#1581) (#1582) 2023-08-24 16:33:01 -04:00
尹吉峰
c344e54cf6 feat: return an Effect from create_effect that can be disposed (#1571) 2023-08-24 10:24:10 -04:00
Greg Johnston
7306ecccbc feat: make struct name and path optional for server functions (#1573) 2023-08-24 10:22:35 -04:00
Greg Johnston
b98174db7a feat: support passing signals directly as attributes, classes, styles, and props on stable (#1577) 2023-08-24 10:22:14 -04:00
Greg Johnston
e48f66694d fix: runtime disposal time in render_to_string_async (#1574) 2023-08-24 10:22:00 -04:00
Mark Catley
533fccd1d3 fix: nightly warning in server macro for lifetime (#1580)
On the latest lifetime we're getting the following warning in the server
macro:
 warning: `&` without an explicit lifetime name cannot be used here
   --> src/login.rs:19:1
    |
 19 | #[server(Login, "/api")]
    | ^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #115010 <https://github.com/rust-lang/rust/issues/115010>
    = note: this warning originates in the attribute macro `server` (in Nightly builds, run with -Z macro-backtrace for more info)
2023-08-24 06:30:13 -04:00
Greg Johnston
ec4bd7600f fix: suppress warning about non-reactivity when calling .refetch() (occurs in e.g., async blocks in actions) (#1576)
* fix: suppress warning about non-reactivity when calling `.refetch()` (occurs in e.g., async blocks in actions)

* fix: don't reenter reactivity if these are nested
2023-08-23 20:57:05 -04:00
Greg Johnston
65d4e98d38 fix: INFO is too high a level for this prop tracing (#1570) 2023-08-23 06:39:37 -04:00
Nathan Lapel
195b843840 feat: remove Clone requirement for slots in vectors (#1564) 2023-08-22 21:23:38 -04:00
Joseph Cruz
00ac66e450 refactor(verify-changed-examples): improve readability and runtime (#1556)
* refactor(workflows): split setup

* test((verify-changed-examples): simulate  change

* refactor(verify-changes-examples): inline os setup

* refactor(verify-changed-examples): skip w/o change

* chore(verify-changed-examples): remove simulated change

* refactor(verify-changed-examples): revert inline

* refactor(verify-changes-examples): extract example changed

* fix(verify-changed-examples): pull up example changed

* refactor(verify-change-examples): extract matrix

* refactor(verify-changed-examples): pass input

* refactor(verify-changed-examples): rename workflow

* ci(workflows): install chromedriver if needed

* fix(ci-changed-examples): pass input from json

* perf(run-cargo-make-task): maybe install chromedriver

* fix((run-cargo-make-task): maybe install chromedriver

* perf(run-cargo-make-task): maybe install playwrigh deps

* fix(run-cargo-make-task): maybe install playwrigh deps

* chore(suspsense_tests): retry e2e

* refactor(verify-changed-examples): rename calls

* refactor(run-cargo-make-test): remove playwright count
2023-08-22 21:22:13 -04:00
Joseph Cruz
351701036b refactor(workflows): extract calls (#1566)
* refactor(workflows): extract leptos changed

* refactor(workflows): rename matrix job

* refactor(workflows): extract examples matrix

* chore(workflows): simulate leptos change

* chore(workflows): remove simulated leptos change
2023-08-22 21:19:58 -04:00
Greg Johnston
2bead5dadd docs: note 0.4 vs 0.5 in README.md 2023-08-21 19:35:23 -04:00
Greg Johnston
dbc707adcd feat/change: adopt reactive ownership model and drop cx/Scope (#918) 2023-08-21 19:31:37 -04:00
Greg Johnston
5066242ef3 remove file accidentally included from islands branch 2023-08-20 19:52:47 -04:00
Greg Johnston
e9deff52a7 v0.4.9 2023-08-20 14:27:49 -04:00
Greg Johnston
eb3d9b8714 build(docs): only publish on new version tags (#1562) 2023-08-20 09:38:35 -04:00
luoxiaozero
18deb398ca feat: tracing support for component props (#1531) 2023-08-18 08:29:41 -04:00
Geert Stappers
d9abebb4be docs: add link to source code for book 2023-08-18 07:57:38 -04:00
Jonathan
a480db8b77 <Show/> update (#1557) 2023-08-18 07:50:26 -04:00
Greg Johnston
1f26b68d45 docs: inner_html in book 2023-08-16 21:31:06 -04:00
Greg Johnston
937501c61b docs: add note about #[component(transparent)] 2023-08-16 21:26:53 -04:00
Joseph Cruz
5523fb86fb perf(check-stable): only run on source change (#1542) 2023-08-15 06:20:01 -04:00
Joseph Cruz
7dcfcf8ca8 chore(test_examples): remove obsolete directory (#1540) 2023-08-15 06:19:36 -04:00
Joseph Cruz
087c68569a test(suspense-tests): add e2e tests (Closes #1519) (#1533)
* test(suspense-tests): add e2e tests (closes #1519)

test(suspense_tests): load nested

test(suspense_tests): load parallel

test(suspsense_tests): load nested inside

test(suspense_tests): load single

test(suspense_tests): load inside component

test(suspense_tests): load no resources

test(suspense_tests): click nested count

test(suspense_tests): click inside component count

test(suspense_tests): click nested inside count

test(suspense_tests): click single count

test(suspense_tests): click parallel counts

test(suspense_tests): click no resources count

refactor(suspense_tests): change view strategy

* fix(suspense_tests): let_unit_value
2023-08-15 06:19:20 -04:00
Milo Moisson
6abfdd2345 examples: on_cleanup misorder? in fetch examples (#1532)
* Update api.rs

* fix: second hackernews example
2023-08-15 06:18:38 -04:00
martin frances
cddd784e8d chore: fixed lint warning seen while running ``cargo doc`` (#1539)
"component" is both a module and a macro and so we must
disambiguate
2023-08-15 06:18:19 -04:00
Greg Johnston
f6978217fb docs: give a compile error when trying to put a child inside a self-closing HTML tag (closes #1535) (#1537) 2023-08-13 12:44:45 -04:00
Greg Johnston
aa58cedc15 Merge pull request #1529 from leptos-rs/docs-advanced-reactivity
Add advanced docs on reactive graph, and update testing docs
2023-08-11 13:52:08 -04:00
Greg Johnston
a0b0d72d19 docs: update testing section 2023-08-11 13:51:10 -04:00
Greg Johnston
fa8d0945e0 docs: add section on reactive graph internals 2023-08-11 13:36:27 -04:00
Greg Johnston
3ed49381e3 docs: expand on the need for prop:value (#1526) 2023-08-10 14:59:12 -04:00
Greg Johnston
8ec3fb95f0 docs: typos in NavigateOptions docs (#1525) 2023-08-09 20:44:39 -04:00
Greg Johnston
cc11430d16 docs: add use_navigate to router docs in guide (#1524) 2023-08-09 20:44:31 -04:00
Greg Johnston
0b650ee2dc Merge pull request #1523 from leptos-rs/more-docs
Additional random docs
2023-08-09 20:24:48 -04:00
Greg Johnston
4def35cb45 docs: add <Await/> 2023-08-09 20:24:04 -04:00
Greg Johnston
0e56f27e0d docs: add watch 2023-08-09 20:19:12 -04:00
Greg Johnston
bd8983f462 docs: expand docs on Axum State/FromRef pattern 2023-08-09 20:14:37 -04:00
Greg Johnston
7ef635d9cf docs: deployment 2023-08-09 20:09:54 -04:00
Joseph Cruz
19ea6fae6a test(todo_app_sqlite_axum): add e2e tests (#1514) (#1515)
* refactor(examples): pull up cargo leptos tasks

* test(todo_app_sqlite_axum): add e2e tests
2023-08-09 08:37:28 -04:00
Joseph Cruz
651a111db9 fix(suspense-tests): build errors (#1517) (#1518) 2023-08-09 08:36:25 -04:00
Danik Vitek
3a98bdb3c2 fix: use current pathname for create_query_signal (#1508) 2023-08-07 20:25:22 -04:00
Greg Johnston
f01b982cff fix: render empty dynamic text node in HTML as (closes #1382) (#1507) 2023-08-07 18:04:56 -04:00
Joseph Cruz
69dd96f76f test(todo_app_sqlite): add e2e tests (#1448) (#1467) 2023-08-07 17:51:24 -04:00
starmaker
329ae08e60 chore: enable stable support for rkyv feature (#1503) 2023-08-07 08:54:02 -04:00
Greg Johnston
1e13ad8fee perf: in hydration, reuse existing text node rather than destroying and remounting (#1506) 2023-08-07 08:34:10 -04:00
Geert Stappers
e0c9a9523a docs: typo
Signed-off-by: Geert Stappers <stappers@stappers.nl>
2023-08-04 10:56:51 -04:00
Mark Catley
0726a3034d examples: fix github links (#1493) 2023-08-04 07:55:04 -04:00
Greg Johnston
a88d047eff template refactor + snapshot tests (#1435) 2023-08-04 07:54:03 -04:00
mateusvmv
4001561987 fix: scoping of JS variable names in inline scripts (#1489) 2023-08-03 08:46:06 -04:00
Greg Johnston
2f860b37bd v0.4.8 2023-08-02 19:25:32 -04:00
Greg Johnston
b86009b9d0 fix: remove erroneous logging 2023-08-02 19:16:32 -04:00
Greg Johnston
54733e1b34 v0.4.7 2023-08-02 17:03:38 -04:00
Greg Johnston
56f01888b7 Merge pull request #1486 from leptos-rs/export-all-helpers
fix: correctly export all DOM helpers
2023-08-02 17:02:19 -04:00
Greg Johnston
8320f16716 chore: fix new clippy warnings 2023-08-02 16:05:42 -04:00
Greg Johnston
0b16e5992d fix: correctly export all DOM helpers 2023-08-02 14:41:54 -04:00
Danik Vitek
248beb4a55 docs: typo in docs for ServerFnErrorErr (#1477) 2023-08-01 14:27:39 -04:00
martin frances
c9f608d030 docs: fix doclink to Error (#1469) 2023-08-01 13:24:13 -04:00
Greg Johnston
f837d3e6a2 fix: correctly escape HTML in DynChild text nodes (closes #1475) (#1478) 2023-08-01 13:22:24 -04:00
Greg Johnston
8847d5fc42 fix: compile-time regression for deeply-nested component trees (#1476) 2023-07-31 14:23:09 -04:00
Greg Johnston
7819a6fac0 fix: properly replace text nodes in DynChild (closes #1456) (#1472) 2023-07-30 22:37:53 -04:00
Marco Inacio
c199185808 docs: README.md to reflect new version (#1470) 2023-07-30 11:52:09 -04:00
martin frances
e0b5738606 chore: document the magic number in FILTER_SHOW_COMMENT. (#1468) 2023-07-29 16:53:10 -04:00
Sebastian Dobe
f3e3880a57 fix: AnimatedShow - possible panic on cleanup (#1464) 2023-07-29 06:33:49 -04:00
Greg Johnston
d44b90c16d feat: allow mut in component props and suppress "needless lifetime" warning (closes #1458) (#1459) 2023-07-29 06:32:06 -04:00
Joseph Cruz
cc32a3e863 perf(examples): speed up the test-info report (#1446) (#1447) 2023-07-27 20:40:26 -04:00
Greg Johnston
5740c9b76b feat: add MaybeProp type (#1443) 2023-07-27 18:18:25 -04:00
Greg Johnston
80fa6ad3eb docs: fix typo in 23_ssr_modes.md (#1445) 2023-07-26 16:33:21 -04:00
Greg Johnston
7bc1ad2b4f fix: incorrect opening node for <Each/> in debug mode (closes #1168) (#1436) 2023-07-26 10:43:46 -04:00
Joseph Cruz
82a2fe7cbe fix(examples): unable to parse makefile (#1440) (#1441) 2023-07-26 10:43:20 -04:00
Bechma
40bf944957 docs: expand spawn_local documentation (#1433) 2023-07-25 11:42:48 -04:00
Greg Johnston
7ef7546fa9 v0.4.6 2023-07-25 06:08:53 -04:00
Greg Johnston
5e26e84d77 feat: allow feature-name flexibility when using server functions (#1427) 2023-07-25 06:07:52 -04:00
mforsb
e67bc2083a feat: add noscroll attribute to Form, ActionForm (#1432) 2023-07-25 06:07:37 -04:00
g-re-g
a3cb3f7f77 perf: use binary search for event and tag names in view macro (#1430) 2023-07-24 15:06:34 -04:00
Greg Johnston
daeb47e72e build(examples): update Makefiles for recent examples (#1431) 2023-07-24 12:02:30 -04:00
Joseph Cruz
8c5ab99fa7 build(examples): pull up compile tasks (#1417)
* build(examples): pull up compile tasks

* build(examples): set toolchain for compiles tasks

* build(examples): set toolchain for build and check

* build(examples): set toolchain of other examples
2023-07-24 11:35:34 -04:00
Greg Johnston
984a7388f1 fix: clear <title> correctly when navigating between pages (closes #1369) (#1428) 2023-07-24 11:25:28 -04:00
Greg Johnston
274b105676 docs: fix messed up component closing tags router docs 2023-07-24 11:24:58 -04:00
Greg Johnston
a689d1b4c0 docs: note on optional generic component props 2023-07-24 07:52:40 -04:00
Greg Johnston
1581e91317 docs: note on how to opt out of client-side routing 2023-07-24 07:52:29 -04:00
Andrew Grande
20f4034c1c docs: proofreading and fixing the links (#1425)
* Update 23_ssr_modes.md

Fixed grammar, added the section anchor links

* Fixed a broken link

The github link doesn't get properly rendered in the Leptos book site. Make the book work, 'break' the github link.

* Update 26_extractors.md

Fixed broken Axum links. Added an Axum extract function doc link for consistency (had Actix, but not Axum before)
2023-07-24 07:25:02 -04:00
Jason Hansen
9fb1c4b67c docs/warnings: fix warning message about updating a signal after it has been disposed (#1423)
* Remove "either" because it didn't make sense in the sentence
* Change "cause cause" to "not cause"
2023-07-24 07:24:06 -04:00
Ari Seyhun
2e559d6a06 feat: add create_query_signal for URL-synced signals (#1377) 2023-07-23 12:20:15 -04:00
Sebastian Dobe
71de6c395b feat: create a <AnimatedShow> component (closes #1370) (#1386) 2023-07-23 07:46:47 -04:00
Vladimir Motylenko
b09f9e4814 feat: Update rstml to v0.11.0 (#1416) 2023-07-23 07:46:33 -04:00
Greg Johnston
ec4bfb0e8a chore: resolve clippy incorrect_clone_impl_on_copy_type (closes #1401) (#1418) 2023-07-22 22:14:52 -04:00
Greg Johnston
39bf38d1e4 docs: CONTRIBUTING.md with helpful info re: CI (#1415) 2023-07-22 08:26:46 -04:00
Joshua Marsh
e6fd1379b8 docs: fix typo for WrapsChildren (#1402) 2023-07-22 08:26:36 -04:00
Doug A
1d9931a5a8 docs: typo in 01_basic_component.md (#1412)
typo fix
2023-07-22 08:24:30 -04:00
Greg Johnston
06164d34b5 docs: note about typed params on stable (#1414) 2023-07-22 08:23:05 -04:00
Joseph Cruz
f3de288e19 build(examples): make it easy to see which examples do what kind of testing (#1411)
* build(examples): list example projects with CI tests runners

* build(examples): add show all mode
2023-07-22 08:13:49 -04:00
Greg Johnston
62bf315059 fix: <use_/> as typed top-level element in view (#1410) 2023-07-21 10:07:34 -04:00
Greg Johnston
011c97e3a4 fix: closing element names wrong for svg::, math::, and use_ (closes #1403) (#1406) 2023-07-20 17:03:30 -04:00
Greg Johnston
2ca3d2c7a4 fix: RawText/unquoted text nodes in SSR (closes #1384) (#1407) 2023-07-20 17:03:19 -04:00
Greg Johnston
cc52c94348 docs/examples: use shorthand form for <Route/> views when possible (#1375) 2023-07-20 16:28:43 -04:00
Andrew Grande
4b8cc96dfa docs: typo in 16_routes.md
Fixed grammar
2023-07-20 16:13:25 -04:00
Greg Johnston
338d2ab839 Merge pull request #1379 from agilarity/lint-with-clippy
ci: lint with clippy
2023-07-20 14:15:16 -04:00
Greg Johnston
54fc6da24e feat: implement Resource::dispose() (#1393) 2023-07-20 14:14:49 -04:00
Andrew Grande
825b3fb858 chore: typo in README.md (#1399) 2023-07-20 14:00:43 -04:00
Andrew Grande
fd0212a142 docs: typo in 15_global_state.md (#1395)
Proofreading
2023-07-20 08:57:12 -04:00
Greg Johnston
3b397cb39c examples: remove random <form> (#1398) 2023-07-20 08:56:49 -04:00
martin frances
1e002c2c2f chore: Removed call to .into(), plus minor touch to docs. (#1396) 2023-07-20 08:07:31 -04:00
Greg Johnston
8f45daeca8 docs: correct docs for create_memo to reflect laziness (#1388) 2023-07-19 14:50:34 -04:00
Joseph Cruz
105ef989b7 ci: install clippy 2023-07-19 08:54:05 -04:00
Greg Johnston
9e7c31d1e4 docs: small issues (#1385) 2023-07-19 08:53:37 -04:00
Joseph Cruz
771dfa6b68 ci: lint with clippy 2023-07-19 08:44:36 -04:00
Joseph Cruz
fb52cfa73e fix: needless_raw_string_hashes 2023-07-19 08:43:57 -04:00
Ari Seyhun
b2c75d215b chore: remove unnecessary string allocation in TryFrom for Url (#1376) 2023-07-19 07:04:06 -04:00
Andrew Grande
951607de74 docs: typos
* Fixed wording

* Update ARCHITECTURE.md

Fixed superfluous whitespace
2023-07-19 07:03:50 -04:00
Joseph Cruz
122fd2bc74 fix: useless_conversion 2023-07-18 20:56:55 -04:00
Joseph Cruz
f102125d3c fix: needless_borrow 2023-07-18 20:56:55 -04:00
Joseph Cruz
14bda76b30 fix: needless_raw_string_hashes (allow) 2023-07-18 20:56:39 -04:00
Joseph Cruz
3af115a663 fix: maybe_misused_cfg 2023-07-18 20:56:39 -04:00
Joseph Cruz
a344804734 fix: incorrect_clone_impl_on_copy_type (allow) 2023-07-18 20:54:51 -04:00
Greg Johnston
c1c49ce53b v0.4.5 2023-07-18 14:02:56 -04:00
Joseph Cruz
d8eaa5c004 build: use cargo hack for clippy 2023-07-18 08:02:24 -04:00
Greg Johnston
e8aa9b24f1 fix: memory leak in leptos_axum (#1374) 2023-07-17 21:59:20 -04:00
Greg Johnston
3036cd223e v0.4.4 2023-07-17 17:33:44 -04:00
Greg Johnston
1ae5150b08 fix: release lock on stored values during update/set (#1373) 2023-07-17 14:19:03 -04:00
Greg Johnston
47148f2033 perf: exclude hydration code in CSR mode (#1372) 2023-07-17 12:20:33 -04:00
Sebastian Probst Eide
4d4d15436b fix: incorrect tree walker filter in hot reloading (closes #1355) (#1368) 2023-07-17 08:44:32 -04:00
Jack DeVries
7f4741b3a3 doc: add previews to backup CodeSandbox (#1169) 2023-07-17 08:40:30 -04:00
Hans Baker
85644a7c1c Fix broken link to example code in testing book page (#1365) 2023-07-16 20:00:56 -04:00
Greg Johnston
f40ae6af30 fix: correctly show fallback for Transition on first load even if not hydrating (#1362) 2023-07-16 15:19:51 -04:00
Greg Johnston
708e1a5aab docs: wasm-pack instructions missing --debug for Tailwind examples 2023-07-16 12:28:20 -04:00
Joseph Cruz
55613c9a31 ci(check-examples): only run on source change (#1356)
* ci(check-examples): only run on source change

* ci(check-examples):  simulate source change

* ci(check-examples): fix expression

* ci(check-examples): simulate source change

* ci(check-examples): test change against files

* ci(check-examples): adjust expression

* ci(check-examples): remove quotes

* ci(check-examples): use from json

* ci(check-examples): set output value

* ci(check-examples): remove simulated change
2023-07-15 19:09:54 -04:00
Joseph Cruz
e6590c7d31 ci(ci): only run on source change (#1357)
* ci(ci): only run on source change

* ci(ci): simulate source change

* ci(ci): remove simulated source change
2023-07-15 19:09:33 -04:00
Greg Johnston
5af2f4e98d docs/warning: fix <ActionForm/> docs and add runtime warning for incorrect encodings (#1360) 2023-07-15 19:09:03 -04:00
1410 changed files with 123762 additions and 48533 deletions

54
.github/workflows/autofix.yml vendored Normal file
View File

@@ -0,0 +1,54 @@
name: autofix.ci
on:
pull_request:
# Running this workflow on main branch pushes requires write permission to apply changes.
# Leave it alone for future uses.
# push:
# branches: ["main"]
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
DEBIAN_FRONTEND: noninteractive
jobs:
autofix:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- 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: |
echo "Formatting the workspace"
cargo fmt --all
echo "Running Clippy against each member's features (default features included)"
for member in $(cargo metadata --no-deps --format-version 1 | jq -r '.packages[] | .name'); do
echo "Working on member $member":
echo -e "\tdefault-features/no-features:"
# this will also run on members with no features or default features
cargo clippy --allow-dirty --fix --lib --package "$member"
features=$(cargo metadata --no-deps --format-version 1 | jq -r ".packages[] | select(.name == \"$member\") | .features | keys[]")
for feature in $features; do
if [ "$feature" = "default" ]; then
continue
fi
echo -e "\tfeature $feature"
cargo clippy --allow-dirty --fix --lib --package "$member" --features "$feature"
done
done
- uses: autofix-ci/action@v1.3.1
if: ${{ always() }}
with:
fail-fast: false

View File

@@ -1,46 +0,0 @@
name: Check Examples
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
setup:
name: Get Examples
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install JQ Tool
uses: mbround18/install-jq@v1
- name: Set Matrix
id: set-matrix
run: |
examples=$(ls examples |
awk '{print "examples/" $0}' |
grep -v examples/README.md |
grep -v examples/Makefile.toml |
grep -v examples/cargo-make |
grep -v examples/gtk |
jq -R -s -c 'split("\n")[:-1]')
echo "Example Directories: $examples"
echo "matrix={\"directory\":$examples}" >> "$GITHUB_OUTPUT"
matrix-job:
name: Check
needs: [setup]
strategy:
matrix: ${{ fromJSON(needs.setup.outputs.matrix) }}
fail-fast: false
uses: ./.github/workflows/run-cargo-make-task.yml
with:
directory: ${{ matrix.directory }}
cargo_make_task: "check"

View File

@@ -1,46 +0,0 @@
name: Check stable
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
CARGO_TERM_COLOR: always
CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
jobs:
test:
name: Check examples ${{ matrix.os }} (using rustc ${{ matrix.rust }})
runs-on: ${{ matrix.os }}
strategy:
matrix:
rust:
- stable
os:
- ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Rust
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ matrix.rust }}
override: true
components: rustfmt
- 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
- name: Run cargo check on all examples
run: cargo make --profile=github-actions check-stable

View File

@@ -0,0 +1,32 @@
name: CI Changed Examples
on:
push:
branches:
- main
- leptos_0.6
- leptos_0.8
pull_request:
branches:
- main
- leptos_0.6
- leptos_0.8
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

29
.github/workflows/ci-examples.yml vendored Normal file
View File

@@ -0,0 +1,29 @@
name: CI Examples
on:
push:
branches:
- main
- leptos_0.6
- leptos_0.8
pull_request:
branches:
- main
- leptos_0.6
- leptos_0.8
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

33
.github/workflows/ci-semver.yml vendored Normal file
View File

@@ -0,0 +1,33 @@
name: CI semver
on:
push:
branches:
- main
- leptos_0.6
- leptos_0.8
pull_request:
branches:
- main
- leptos_0.6
- leptos_0.8
env:
DEBIAN_FRONTEND: noninteractive
jobs:
get-leptos-changed:
uses: ./.github/workflows/get-leptos-changed.yml
test:
needs: [get-leptos-changed]
if: 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: 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
with:
rust-toolchain: nightly-2024-08-01

View File

@@ -1,38 +1,29 @@
name: CI
on:
push:
branches:
- main
- leptos_0.6
- leptos_0.8
pull_request:
branches:
- main
- leptos_0.6
- leptos_0.8
jobs:
matrix-job:
get-leptos-changed:
uses: ./.github/workflows/get-leptos-changed.yml
get-leptos-matrix:
uses: ./.github/workflows/get-leptos-matrix.yml
test:
name: CI
needs: [get-leptos-changed, get-leptos-matrix]
if: needs.get-leptos-changed.outputs.leptos_changed == 'true'
strategy:
matrix:
directory:
[
integrations/actix,
integrations/axum,
integrations/viz,
integrations/utils,
leptos,
leptos_config,
leptos_dom,
leptos_hot_reload,
leptos_macro,
leptos_reactive,
leptos_server,
meta,
router,
server_fn,
server_fn/server_fn_macro_default,
server_fn_macro,
]
matrix: ${{ fromJSON(needs.get-leptos-matrix.outputs.matrix) }}
fail-fast: false
uses: ./.github/workflows/run-cargo-make-task.yml
with:
directory: ${{ matrix.directory }}
cargo_make_task: "ci"
toolchain: nightly-2024-08-01

View File

@@ -0,0 +1,54 @@
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

@@ -0,0 +1,33 @@
name: Examples Changed Call
on:
workflow_call:
outputs:
example_changed:
description: "Example Changed"
value: ${{ jobs.get-example-changed.outputs.example_changed }}
jobs:
get-example-changed:
name: Get Example Changed
runs-on: ubuntu-latest
outputs:
example_changed: ${{ steps.set-example-changed.outputs.example_changed }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get example files that changed
id: changed-files
uses: tj-actions/changed-files@v45
with:
files: |
examples/**
!examples/cargo-make/**
!examples/Makefile.toml
!examples/*.md
- name: List example files that changed
run: echo '${{ steps.changed-files.outputs.all_changed_files }}'
- name: Set example_changed
id: set-example-changed
run: |
echo "example_changed=${{ steps.changed-files.outputs.any_changed }}" >> "$GITHUB_OUTPUT"

View File

@@ -0,0 +1,36 @@
name: Get Examples Matrix Call
on:
workflow_call:
outputs:
matrix:
description: "Matrix"
value: ${{ jobs.create.outputs.matrix }}
jobs:
create:
name: Create Examples Matrix
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
env:
# separate examples using "|" (vertical bar) char like "a|b|c".
# cargo-make should be excluded by default.
EXCLUDED_EXAMPLES: cargo-make
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install jq
run: sudo apt-get install jq
- name: Set Matrix
id: set-matrix
run: |
examples=$(ls -1d examples/*/ |
grep -vE "($EXCLUDED_EXAMPLES)" |
sed 's/\/$//' |
jq -R -s -c 'split("\n")[:-1]')
echo "Example Directories: $examples"
echo "matrix={\"directory\":$examples}" >> "$GITHUB_OUTPUT"
- name: Print Location Info
run: |
echo "Workspace: ${{ github.workspace }}"
pwd
ls | sort -u

View File

@@ -0,0 +1,35 @@
name: Get Leptos Changed Call
on:
workflow_call:
outputs:
leptos_changed:
description: "Leptos Changed"
value: ${{ jobs.create.outputs.leptos_changed }}
jobs:
create:
name: Detect Source Change
runs-on: ubuntu-latest
outputs:
leptos_changed: ${{ steps.set-source-changed.outputs.leptos_changed }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get source files that changed
id: changed-source
uses: tj-actions/changed-files@v45
with:
files_ignore: |
.*/**/*
cargo-make/**/*
examples/**/*
projects/**/*
benchmarks/**/*
docs/**/*
- name: List source files that changed
run: echo '${{ steps.changed-source.outputs.all_changed_files }}'
- name: Set leptos_changed
id: set-source-changed
run: |
echo "leptos_changed=${{ steps.changed-source.outputs.any_changed }}" >> "$GITHUB_OUTPUT"

32
.github/workflows/get-leptos-matrix.yml vendored Normal file
View File

@@ -0,0 +1,32 @@
name: Get Leptos Matrix Call
on:
workflow_call:
outputs:
matrix:
description: "Matrix"
value: ${{ jobs.create.outputs.matrix }}
jobs:
create:
name: Create Leptos Matrix
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install jq
run: sudo apt-get install jq
- name: Set Matrix
id: set-matrix
run: |
crates=$(cargo metadata --no-deps --quiet --format-version 1 |
jq -r '.packages[] | select(.name != "workspace") | .manifest_path| rtrimstr("/Cargo.toml")' |
sed "s|$(pwd)/||" |
jq -R -s -c 'split("\n")[:-1]')
echo "Leptos Directories: $crates"
echo "matrix={\"directory\":$crates}" >> "$GITHUB_OUTPUT"
- name: Print Location Info
run: |
echo "Workspace: ${{ github.workspace }}"
pwd
ls | sort -u

View File

@@ -1,7 +1,7 @@
name: Deploy book
on:
push:
paths: ['docs/book/**']
paths: ["docs/book/**"]
branches:
- main
@@ -9,29 +9,29 @@ jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: write # To push a branch
pull-requests: write # To create a PR from that branch
contents: write # To push a branch
pull-requests: write # To create a PR from that branch
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Install mdbook
run: |
mkdir mdbook
curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.4.27/mdbook-v0.4.27-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook
echo `pwd`/mdbook >> $GITHUB_PATH
- name: Deploy GitHub Pages
run: |
cd docs/book
mdbook build
git worktree add gh-pages
git config user.name "Deploy book from CI"
git config user.email ""
cd gh-pages
# Delete the ref to avoid keeping history.
git update-ref -d refs/heads/gh-pages
rm -rf *
mv ../book/* .
git add .
git commit -m "Deploy book $GITHUB_SHA to gh-pages"
git push --force --set-upstream origin gh-pages
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install mdbook
run: |
mkdir mdbook
curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.4.27/mdbook-v0.4.27-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook
echo `pwd`/mdbook >> $GITHUB_PATH
- name: Deploy GitHub Pages
run: |
cd docs/book
mdbook build
git worktree add gh-pages
git config user.name "Deploy book from CI"
git config user.email ""
cd gh-pages
# Delete the ref to avoid keeping history.
git update-ref -d refs/heads/gh-pages
rm -rf *
mv ../book/* .
git add .
git commit -m "Deploy book $GITHUB_SHA to gh-pages"
git push --force --set-upstream origin gh-pages

View File

@@ -1,5 +1,4 @@
name: Run Task
on:
workflow_call:
inputs:
@@ -9,87 +8,121 @@ on:
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
jobs:
test:
name: Run ${{ matrix.os }} (using rustc ${{ matrix.rust }})
runs-on: ${{ matrix.os }}
strategy:
matrix:
rust:
- nightly
os:
- ubuntu-latest
name: Run ${{ inputs.cargo_make_task }} (${{ inputs.toolchain }})
runs-on: ubuntu-latest
steps:
- name: Free Disk Space
run: |
echo "Disk space before cleanup:"
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/share/dotnet
sudo rm -rf /opt/ghc
sudo rm -rf /usr/local/share/boost
sudo apt-get clean
echo "Disk space after cleanup:"
df -h
# Setup environment
- name: Install playwright browser dependencies
- name: Install Glib
run: |
sudo apt-get update
sudo apt-get install libegl1 libvpx7 libevent-2.1-7 libopus0 libopengl0 libwoff1 libharfbuzz-icu0 libgstreamer-plugins-base1.0-0 libgstreamer-gl1.0-0 libhyphen0 libmanette-0.2-0 libgles2 gstreamer1.0-libav
- uses: actions/checkout@v3
sudo apt-get install -y libglib2.0-dev
- uses: actions/checkout@v4
- name: Setup Rust
uses: actions-rs/toolchain@v1
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust }}
override: true
components: rustfmt
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
- 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 --locked --no-confirm
- name: Install Trunk
uses: jetli/trunk-action@v0.4.0
uses: jetli/trunk-action@v0.5.0
with:
version: "latest"
- name: Print Trunk Version
run: trunk --version
- name: Install Node.js
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: 18
- uses: pnpm/action-setup@v2
node-version: 20
- uses: pnpm/action-setup@v4
name: Install pnpm
id: pnpm-install
with:
version: 8
run_install: false
- name: Get pnpm store directory
id: pnpm-cache
run: |
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
- uses: actions/cache@v3
- uses: actions/cache@v4
name: Setup pnpm cache
with:
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Maybe install chromedriver
run: |
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
echo chromedriver required
sudo apt-get update
sudo apt-get install chromium-chromedriver
else
echo chromedriver is already installed
fi
else
echo chromedriver is not required
fi
- name: Maybe install playwright browser dependencies
run: |
for pw_path in $(find ${{inputs.directory}} -name playwright.config.ts)
do
pw_dir=$(dirname $pw_path)
if [ ! -v $pw_dir ]; then
echo "Playwright required in $pw_dir"
cd $pw_dir
pnpm dlx playwright install --with-deps
else
echo Playwright is not required
fi
done
- name: Install Deno
uses: denoland/setup-deno@v2
with:
deno-version: v1.x
- name: Maybe install gtk-rs dependencies
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
# Run Cargo Make Task
- name: ${{ inputs.cargo_make_task }}
run: |
if [ "${{ inputs.directory }}" = "INTERNAL" ]; then
echo No verification required
else
cd ${{ inputs.directory }}
cargo make --profile=github-actions ${{ inputs.cargo_make_task }}
fi
cd ${{ inputs.directory }}
cargo make --profile=github-actions ${{ inputs.cargo_make_task }}

View File

@@ -1,47 +0,0 @@
name: Verify All Examples
on:
workflow_dispatch:
push:
tags:
- v*
schedule:
# Run once a day at 3:00 AM EST
- cron: "0 8 * * *"
jobs:
setup:
name: Get Examples
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install JQ Tool
uses: mbround18/install-jq@v1
- name: Set Matrix
id: set-matrix
run: |
examples=$(ls examples |
awk '{print "examples/" $0}' |
grep -v examples/README.md |
grep -v examples/Makefile.toml |
grep -v examples/cargo-make |
grep -v examples/gtk |
jq -R -s -c 'split("\n")[:-1]')
echo "Example Directories: $examples"
echo "matrix={\"directory\":$examples}" >> "$GITHUB_OUTPUT"
matrix-job:
name: Verify
needs: [setup]
strategy:
matrix: ${{ fromJSON(needs.setup.outputs.matrix) }}
fail-fast: false
uses: ./.github/workflows/run-cargo-make-task.yml
with:
directory: ${{ matrix.directory }}
cargo_make_task: "verify-flow"

View File

@@ -1,71 +0,0 @@
name: Verify Changed Examples
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
setup:
name: Get Changes
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Get all example files that changed
id: changed-files
uses: tj-actions/changed-files@v36
with:
files: |
examples
- name: List all example files that changed
run: echo '${{ steps.changed-files.outputs.all_changed_files }}'
- name: Get example project directories that changed
id: changed-dirs
uses: tj-actions/changed-files@v36
with:
dir_names: true
dir_names_max_depth: "2"
files: |
examples
!examples/cargo-make
!examples/gtk
!examples/Makefile.toml
!examples/README.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 [ ${{ steps.changed-files.outputs.any_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\":[\"INTERNAL\"]}" >> "$GITHUB_OUTPUT"
fi
matrix-job:
name: Verify
needs: [setup]
strategy:
matrix: ${{ fromJSON(needs.setup.outputs.matrix) }}
fail-fast: false
uses: ./.github/workflows/run-cargo-make-task.yml
with:
directory: ${{ matrix.directory }}
cargo_make_task: "verify-flow"

8
.gitignore vendored
View File

@@ -3,9 +3,15 @@ dist
pkg
comparisons
blob.rs
Cargo.lock
**/projects/**/Cargo.lock
**/examples/**/Cargo.lock
**/benchmarks/**/Cargo.lock
**/*.rs.bk
.DS_Store
.idea
.direnv
.envrc
.vscode
vendor
hash.txt

View File

@@ -220,8 +220,8 @@ for reference: they include large amounts of manual SSR route handling, etc.
## `cargo-leptos` helpers
`leptos_config` and `leptos_hot_reload` exist to support two different features
of `cargo-leptos`, namely its configuration and its view-patching/hot-
reloading features.
of `cargo-leptos`, namely its configuration and its view-patching/hot-reloading
features.
Its important to say that the main feature `cargo-leptos` remains its ability
to conveniently tie together different build tooling, compiling your app to

View File

@@ -62,7 +62,7 @@ are a few guidelines that will make it a better experience for everyone:
- If its an unsolicited PR not linked to an open issue, please include a
specific explanation for what its trying to achieve. For example: “When I
was trying to deploy my app under _circumstances X_, I found that the way
_function Z_ was implemented caused _issue Z_. This PR should fix that by
_function Y_ was implemented caused _issue Z_. This PR should fix that by
_solution._
- Our CI tests every PR against all the existing examples, sometimes requiring
compilation for both server and client side, etc. Its thorough but slow. If
@@ -70,6 +70,32 @@ are a few guidelines that will make it a better experience for everyone:
`cargo-make` and using `cargo make check && cargo make test && cargo make
check-examples`.
## Before Submitting a PR
We have a fairly extensive CI setup that runs both lints (like `rustfmt` and `clippy`)
and tests on PRs. You can run most of these locally if you have `cargo-make` installed.
Note that some of the `rustfmt` settings used require usage of the nightly compiler.
Formatting the code using the stable toolchain may result in a wrong code format and
subsequently CI errors.
Run `cargo +nightly fmt` if you want to keep the stable toolchain active.
You may want to let your IDE automatically use the `+nightly` parameter when a
"format on save" action is used.
If you added an example, make sure to add it to the list in `examples/Makefile.toml`.
From the root directory of the repo, run
- `cargo +nightly fmt`
- `cargo +nightly make check`
- `cargo +nightly make test`
- `cargo +nightly make check-examples`
- `cargo +nightly make --profile=github-actions ci`
If you modified an example:
- `cd examples/your_example`
- `cargo +nightly fmt -- --config-path ../..`
- `cargo +nightly make --profile=github-actions verify-flow`
## Architecture
See [ARCHITECTURE.md](./ARCHITECTURE.md).

4356
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,47 +1,75 @@
[workspace]
resolver = "2"
members = [
# utilities
"oco",
"any_spawner",
"const_str_slice_concat",
"either_of",
"next_tuple",
"oco",
"or_poisoned",
# core
"hydration_context",
"leptos",
"leptos_dom",
"leptos_config",
"leptos_hot_reload",
"leptos_macro",
"leptos_reactive",
"leptos_server",
"reactive_graph",
"reactive_stores",
"reactive_stores_macro",
"server_fn",
"server_fn_macro",
"server_fn/server_fn_macro_default",
"tachys",
# integrations
"integrations/actix",
"integrations/axum",
"integrations/viz",
"integrations/utils",
# libraries
"meta",
"router",
"router_macro",
"any_error",
]
exclude = ["benchmarks", "examples"]
exclude = ["benchmarks", "examples", "projects"]
[workspace.package]
version = "0.4.3"
version = "0.7.7"
edition = "2021"
rust-version = "1.76"
[workspace.dependencies]
leptos = { path = "./leptos", version = "0.4.3" }
leptos_dom = { path = "./leptos_dom", version = "0.4.3" }
leptos_hot_reload = { path = "./leptos_hot_reload", version = "0.4.3" }
leptos_macro = { path = "./leptos_macro", version = "0.4.3" }
leptos_reactive = { path = "./leptos_reactive", version = "0.4.3" }
leptos_server = { path = "./leptos_server", version = "0.4.3" }
server_fn = { path = "./server_fn", version = "0.4.3" }
server_fn_macro = { path = "./server_fn_macro", version = "0.4.3" }
server_fn_macro_default = { path = "./server_fn/server_fn_macro_default", version = "0.4.3" }
leptos_config = { path = "./leptos_config", version = "0.4.3" }
leptos_router = { path = "./router", version = "0.4.3" }
leptos_meta = { path = "./meta", version = "0.4.3" }
leptos_integration_utils = { path = "./integrations/utils", version = "0.4.3" }
throw_error = { path = "./any_error/", version = "0.2.0" }
any_spawner = { path = "./any_spawner/", version = "0.2.0" }
const_str_slice_concat = { path = "./const_str_slice_concat", version = "0.1" }
either_of = { path = "./either_of/", version = "0.1.0" }
hydration_context = { path = "./hydration_context", version = "0.2.0" }
leptos = { path = "./leptos", version = "0.7.7" }
leptos_config = { path = "./leptos_config", version = "0.7.7" }
leptos_dom = { path = "./leptos_dom", version = "0.7.7" }
leptos_hot_reload = { path = "./leptos_hot_reload", version = "0.7.7" }
leptos_integration_utils = { path = "./integrations/utils", version = "0.7.7" }
leptos_macro = { path = "./leptos_macro", version = "0.7.7" }
leptos_router = { path = "./router", version = "0.7.7" }
leptos_router_macro = { path = "./router_macro", version = "0.7.7" }
leptos_server = { path = "./leptos_server", version = "0.7.7" }
leptos_meta = { path = "./meta", version = "0.7.7" }
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.7" }
reactive_stores = { path = "./reactive_stores", version = "0.1.7" }
reactive_stores_macro = { path = "./reactive_stores_macro", version = "0.1.7" }
server_fn = { path = "./server_fn", version = "0.7.7" }
server_fn_macro = { path = "./server_fn_macro", version = "0.7.7" }
server_fn_macro_default = { path = "./server_fn/server_fn_macro_default", version = "0.7.7" }
tachys = { path = "./tachys", version = "0.1.7" }
[profile.release]
codegen-units = 1
@@ -50,3 +78,9 @@ opt-level = 'z'
[workspace.metadata.cargo-all-features]
skip_feature_sets = [["csr", "ssr"], ["csr", "hydrate"], ["ssr", "hydrate"]]
[workspace.lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = [
'cfg(leptos_debuginfo)',
'cfg(erase_components)',
] }

View File

@@ -20,6 +20,18 @@ cwd = "examples"
command = "cargo"
args = ["make", "ci-clean"]
[tasks.check-examples]
workspace = false
cwd = "examples"
command = "cargo"
args = ["make", "check-clean"]
[tasks.build-examples]
workspace = false
cwd = "examples"
command = "cargo"
args = ["make", "build-clean"]
[tasks.clean-examples]
workspace = false
cwd = "examples"

View File

@@ -5,20 +5,23 @@
[![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)
[Website](https://leptos.dev) | [Book](https://leptos-rs.github.io/leptos/) | [Docs.rs](https://docs.rs/leptos/latest/leptos/) | [Playground](https://codesandbox.io/p/sandbox/leptos-rtfggt?file=%2Fsrc%2Fmain.rs%3A1%2C1) | [Discord](https://discord.gg/YdRAhS7eQB)
You can find a list of useful libraries and example projects at [`awesome-leptos`](https://github.com/leptos-rs/awesome-leptos).
# Leptos
```rust
use leptos::*;
#[component]
pub fn SimpleCounter(cx: Scope, initial_value: i32) -> impl IntoView {
pub fn SimpleCounter(initial_value: i32) -> impl IntoView {
// create a reactive signal with the initial value
let (value, set_value) = create_signal(cx, initial_value);
let (value, set_value) = create_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
@@ -27,21 +30,42 @@ pub fn SimpleCounter(cx: Scope, initial_value: i32) -> impl IntoView {
let increment = move |_| set_value.update(|value| *value += 1);
// create user interfaces with the declarative `view!` macro
view! { cx,
view! {
<div>
<button on:click=clear>"Clear"</button>
<button on:click=decrement>"-1"</button>
<button on:click=clear>Clear</button>
<button on:click=decrement>-1</button>
// text nodes can be quoted or unquoted
<span>"Value: " {value} "!"</span>
<button on:click=increment>"+1"</button>
<button on:click=increment>+1</button>
</div>
}
}
// Easy to use with Trunk (trunkrs.dev) or with a simple wasm-bindgen setup
pub fn main() {
mount_to_body(|cx| view! { cx, <SimpleCounter initial_value=3 /> })
// we also support a builder syntax rather than the JSX-like `view` macro
#[component]
pub fn SimpleCounterWithBuilder(initial_value: i32) -> impl IntoView {
use leptos::html::*;
let (value, set_value) = create_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);
// the `view` macro above expands to this builder syntax
div().child((
button().on(ev::click, clear).child("Clear"),
button().on(ev::click, decrement).child("-1"),
span().child(("Value: ", value, "!")),
button().on(ev::click, increment).child("+1")
))
}
// Easy to use with Trunk (trunkrs.dev) or with a simple wasm-bindgen setup
pub fn main() {
mount_to_body(|| view! {
<SimpleCounter initial_value=3 />
})
}
```
## About the Framework
@@ -88,8 +112,6 @@ targets = ["wasm32-unknown-unknown"]
The `nightly` feature enables the function call syntax for accessing and setting signals, as opposed to `.get()` and `.set()`. This leads to a consistent mental model in which accessing a reactive value of any kind (a signal, memo, or derived signal) is always represented as a function call. This is only possible with nightly Rust and the `nightly` feature.
> Note: The `nightly` feature is present on the main branch version right now, but not in 0.3.x. For 0.3.x, nightly is the default and `stable` has a special feature.
## `cargo-leptos`
[`cargo-leptos`](https://github.com/leptos-rs/cargo-leptos) is a build tool that's designed to make it easy to build apps that run on both the client and the server, with seamless integration. The best way to get started with a real Leptos project right now is to use `cargo-leptos` and our starter templates for [Actix](https://github.com/leptos-rs/start) or [Axum](https://github.com/leptos-rs/start-axum).
@@ -107,7 +129,7 @@ Open browser to [http://localhost:3000/](http://localhost:3000/).
### Whats up with the name?
_Leptos_ (λεπτός) is an ancient Greek word meaning “thin, light, refine, fine-grained.” To me, a classicist and not a dog owner, it evokes the lightweight reactive system that powers the framework. I've since learned the same word is at the root of the medical term “leptospirosis,” a blood infection that affects humans and animals... My bad. No dogs were harmed in the creation of this framework.
_Leptos_ (λεπτός) is an ancient Greek word meaning “thin, light, refined, fine-grained.” To me, a classicist and not a dog owner, it evokes the lightweight reactive system that powers the framework. I've since learned the same word is at the root of the medical term “leptospirosis,” a blood infection that affects humans and animals... My bad. No dogs were harmed in the creation of this framework.
### Is it production ready?
@@ -115,7 +137,7 @@ People usually mean one of three things by this question.
1. **Are the APIs stable?** i.e., will I have to rewrite my whole app from Leptos 0.1 to 0.2 to 0.3 to 0.4, or can I write it now and benefit from new features and updates as new versions come?
The APIs are basically settled. Were adding new features, but were very happy with where the type system and patterns have landed. I would not expect major breaking changes to your code to adapt to future releases. The sorts of breaking changes that we discuss are things like “Oh yeah, that function should probably take `cx` as its argument...” not major changes to the way you write your application.
The APIs are basically settled. Were adding new features, but were very happy with where the type system and patterns have landed. I would not expect major breaking changes to your code to adapt to future releases, in terms of architecture.
2. **Are there bugs?**
@@ -129,44 +151,34 @@ There are several people in the community using Leptos right now for internal ap
### Can I use this for native GUI?
Sure! Obviously the `view` macro is for generating DOM nodes but you can use the reactive system to drive native any GUI toolkit that uses the same kind of object-oriented, event-callback-based framework as the DOM pretty easily. The principles are the same:
Sure! Obviously the `view` macro is for generating DOM nodes but you can use the reactive system to drive any native GUI toolkit that uses the same kind of object-oriented, event-callback-based framework as the DOM pretty easily. The principles are the same:
- Use signals, derived signals, and memos to create your reactive system
- Create GUI widgets
- Use event listeners to update signals
- Create effects to update the UI
I've put together a [very simple GTK example](https://github.com/leptos-rs/leptos/blob/main/examples/gtk/src/main.rs) so you can see what I mean.
The 0.7 update originally set out to create a "generic rendering" approach that would allow us to reuse most of the same view logic to do all of the above. Unfortunately, this has had to be shelved for now due to difficulties encountered by the Rust compiler when building larger-scale applications with the number of generics spread throughout the codebase that this required. It's an approach I'm looking forward to exploring again in the future; feel free to reach out if you're interested in this kind of work.
### How is this different from Yew/Dioxus?
### How is this different from Yew?
On the surface level, these libraries may seem similar. Yew is, of course, the most mature Rust library for web UI development and has a huge ecosystem. Dioxus is similar in many ways, being heavily inspired by React. Here are some conceptual differences between Leptos and these frameworks:
Yew is the most-used library for Rust web UI development, but there are several differences between Yew and Leptos, in philosophy, approach, and performance.
- **VDOM vs. fine-grained:** Yew is built on the virtual DOM (VDOM) model: state changes cause components to re-render, generating a new virtual DOM tree. Yew diffs this against the previous VDOM, and applies those patches to the actual DOM. Component functions rerun whenever state changes. Leptos takes an entirely different approach. Components run once, creating (and returning) actual DOM nodes and setting up a reactive system to update those DOM nodes.
- **Performance:** This has huge performance implications: Leptos is simply much faster at both creating and updating the UI than Yew is. (Dioxus has made huge advances in performance with its recent 0.3 release, and is now roughly on par with Leptos.)
- **Mental model:** Adopting fine-grained reactivity also tends to simplify the mental model. There are no surprising component re-renders because there are no re-renders. You can call functions, create timeouts, etc. within the body of your component functions because they wont be re-run. You dont need to think about manual dependency tracking for effects; fine-grained reactivity tracks dependencies automatically.
- **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?
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?
Conceptually, these two frameworks are very similar: because both are built on fine-grained reactivity, most apps will end up looking very similar between the two, and Sycamore or Leptos apps will both look a lot like SolidJS apps, in the same way that Yew or Dioxus can look a lot like React.
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:
There are some practical differences that make a significant difference:
- **Templating:** Leptos uses a JSX-like template format (built on [syn-rsx](https://github.com/stoically/syn-rsx)) for its `view` macro. Sycamore offers the choice of its own templating DSL or a builder syntax.
- **Server integration:** Leptos provides primitives that encourage HTML streaming and allow for easy async integration and RPC calls, even without WASM enabled, making it easy to opt into integrations between your frontend and backend code without pushing you toward any particular metaframework patterns.
- **Read-write segregation:** Leptos, like Solid, encourages read-write segregation between signal getters and setters, so you end up accessing signals with tuples like `let (count, set_count) = create_signal(cx, 0);` _(If you prefer or if it's more convenient for your API, you can use [`create_rw_signal`](https://docs.rs/leptos/latest/leptos/fn.create_rw_signal.html) to give a unified read/write signal.)_
- **Signals are functions:** In Leptos, you can call a signal to access it rather than calling a specific method (so, `count()` instead of `count.get()`) This creates a more consistent mental model: accessing a reactive value is always a matter of calling a function. For example:
```rust
let (count, set_count) = create_signal(cx, 0); // a signal
let double_count = move || count() * 2; // a derived signal
let memoized_count = create_memo(cx, move |_| count() * 3); // a memo
// all are accessed by calling them
assert_eq!(count(), 0);
assert_eq!(double_count(), 0);
assert_eq!(memoized_count(), 0);
// this function can accept any of those signals
fn do_work_on_signal(my_signal: impl Fn() -> i32) { ... }
```
- **Signals and scopes are `'static`:** Both Leptos and Sycamore ease the pain of moving signals in closures (in particular, event listeners) by making them `Copy`, to avoid the `{ let count = count.clone(); move |_| ... }` that's very familiar in Rust UI code. Sycamore does this by using bump allocation to tie the lifetimes of its signals to its scopes: since references are `Copy`, `&'a Signal<T>` can be moved into a closure. Leptos does this by using arena allocation and passing around indices: types like `ReadSignal<T>`, `WriteSignal<T>`, and `Memo<T>` are actually wrappers for indices into an arena. This means that both scopes and signals are both `Copy` and `'static` in Leptos, which means that they can be moved easily into closures without adding lifetime complexity.
- **Templating DSLs:** Sycamore uses a custom templating language for its views, while Leptos uses a JSX-like template format.
- **`'static` signals:** One of Leptoss main innovations was the creation of `Copy + 'static` signals, which have excellent ergonomics. Sycamore is in the process of adopting the same pattern, but this is not yet released.
- **Perseus vs. server functions:** The Perseus metaframework provides an opinionated way to build Sycamore apps that include server functionality. Leptos instead provides primitives like server functions in the core of the framework.

13
SECURITY.md Normal file
View File

@@ -0,0 +1,13 @@
# Security Policy
## Reporting a Vulnerability
To report a suspected security issue, please contact security@leptos.dev rather than opening
a public issue.
## Supported Versions
The most-recently-released version of the library is supported with security updates.
For example, if a security issue is discovered that affects 0.3.2 and all later releases,
a 0.4.x patch will be released but a new 0.3.x patch release will not be made. You should
plan to update to the latest version to receive any new features or bugfixes of any kind.

40
TODO.md Normal file
View File

@@ -0,0 +1,40 @@
- core examples
- [x] counter
- [x] counters
- [x] fetch
- [x] todomvc
- [x] error_boundary
- [x] parent\_child
- [x] on: on components
- [ ] router
- [ ] slots
- [ ] hackernews
- [ ] counter\_isomorphic
- [ ] todo\_app\_sqlite
- other ssr examples
- [ ] error boundary SSR
- reactivity
- Signal wrappers
- SignalDispose implementations on all Copy types
- untracked access warnings
- ErrorBoundary
- [ ] RenderHtml implementation
- [ ] Separate component?
- Suspense/Transition components?
- callbacks
- unsync StoredValue
- SSR
- escaping HTML correctly (attributes + text nodes)
- router
- nested routes
- trailing slashes
- \_meta package (and use in hackernews)
- integrations
- update tests
- hackernews example
- TODOs
- Suspense/Transition/Await components
- nicer routing components
- async routing (waiting for data to load before navigation)
- `<A>` component
- figure out rebuilding issues: list (needs new signal IDs) vs. regular rebuild

13
any_error/Cargo.toml Normal file
View File

@@ -0,0 +1,13 @@
[package]
name = "throw_error"
version = "0.2.0"
authors = ["Greg Johnston"]
license = "MIT"
readme = "../README.md"
repository = "https://github.com/leptos-rs/leptos"
description = "Utilities for wrapping, throwing, and catching errors."
rust-version.workspace = true
edition.workspace = true
[dependencies]
pin-project-lite = "0.2.15"

2
any_error/README.md Normal file
View File

@@ -0,0 +1,2 @@
A utility library for wrapping arbitrary errors, and for “throwing” errors in a way
that can be caught by user-defined error hooks.

165
any_error/src/lib.rs Normal file
View File

@@ -0,0 +1,165 @@
#![forbid(unsafe_code)]
#![deny(missing_docs)]
//! A utility library for wrapping arbitrary errors, and for “throwing” errors in a way
//! that can be caught by user-defined error hooks.
use std::{
cell::RefCell,
error,
fmt::{self, Display},
future::Future,
mem, ops,
pin::Pin,
sync::Arc,
task::{Context, Poll},
};
/* 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)]
pub struct Error(Arc<dyn error::Error + Send + Sync>);
impl Error {
/// Converts the wrapper into the inner reference-counted error.
pub fn into_inner(self) -> Arc<dyn error::Error + Send + Sync> {
Arc::clone(&self.0)
}
}
impl ops::Deref for Error {
type Target = Arc<dyn error::Error + Send + Sync>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl<T> From<T> for Error
where
T: error::Error + Send + Sync + 'static,
{
fn from(value: T) -> Self {
Error(Arc::new(value))
}
}
/// Implements behavior that allows for global or scoped error handling.
///
/// This allows for both "throwing" errors to register them, and "clearing" errors when they are no
/// longer valid. This is useful for something like a user interface, in which an error can be
/// "thrown" on some invalid user input, and later "cleared" if the user corrects the input.
/// Keeping a unique identifier for each error allows the UI to be updated accordingly.
pub trait ErrorHook: Send + Sync {
/// Handles the given error, returning a unique identifier.
fn throw(&self, error: Error) -> ErrorId;
/// Clears the error associated with the given identifier.
fn clear(&self, id: &ErrorId);
}
/// A unique identifier for an error. This is returned when you call [`throw`], which calls a
/// global error handler.
#[derive(Debug, PartialEq, Eq, Hash, Clone, Default)]
pub struct ErrorId(usize);
impl Display for ErrorId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Display::fmt(&self.0, f)
}
}
impl From<usize> for ErrorId {
fn from(value: usize) -> Self {
Self(value)
}
}
thread_local! {
static ERROR_HOOK: RefCell<Option<Arc<dyn ErrorHook>>> = RefCell::new(None);
}
/// Resets the error hook to its previous state when dropped.
pub struct ResetErrorHookOnDrop(Option<Arc<dyn ErrorHook>>);
impl Drop for ResetErrorHookOnDrop {
fn drop(&mut self) {
ERROR_HOOK.with_borrow_mut(|this| *this = self.0.take())
}
}
/// Returns the current error hook.
pub fn get_error_hook() -> Option<Arc<dyn ErrorHook>> {
ERROR_HOOK.with_borrow(Clone::clone)
}
/// 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))),
)
}
/// Invokes the error hook set by [`set_error_hook`] with the given error.
pub fn throw(error: impl Into<Error>) -> ErrorId {
ERROR_HOOK
.with_borrow(|hook| hook.as_ref().map(|hook| hook.throw(error.into())))
.unwrap_or_default()
}
/// Clears the given error from the current error hook.
pub fn clear(id: &ErrorId) {
ERROR_HOOK
.with_borrow(|hook| hook.as_ref().map(|hook| hook.clear(id)))
.unwrap_or_default()
}
pin_project_lite::pin_project! {
/// A [`Future`] that reads the error hook that is set when it is created, and sets this as the
/// current error hook whenever it is polled.
pub struct ErrorHookFuture<Fut> {
hook: Option<Arc<dyn ErrorHook>>,
#[pin]
inner: Fut
}
}
impl<Fut> ErrorHookFuture<Fut> {
/// Reads the current hook and wraps the given [`Future`], returning a new `Future` that will
/// set the error hook whenever it is polled.
pub fn new(inner: Fut) -> Self {
Self {
hook: ERROR_HOOK.with_borrow(Clone::clone),
inner,
}
}
}
impl<Fut> Future for ErrorHookFuture<Fut>
where
Fut: Future,
{
type Output = Fut::Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project();
let _hook = this
.hook
.as_ref()
.map(|hook| set_error_hook(Arc::clone(hook)));
this.inner.poll(cx)
}
}

36
any_spawner/Cargo.toml Normal file
View File

@@ -0,0 +1,36 @@
[package]
name = "any_spawner"
version = "0.2.1"
authors = ["Greg Johnston"]
license = "MIT"
readme = "../README.md"
repository = "https://github.com/leptos-rs/leptos"
description = "Spawn asynchronous tasks in an executor-independent way."
edition.workspace = true
[dependencies]
async-executor = { version = "1.13.1", optional = true }
futures = "0.3.31"
glib = { version = "0.20.6", optional = true }
thiserror = "2.0"
tokio = { version = "1.41", optional = true, default-features = false, features = [
"rt",
] }
tracing = { version = "0.1.41", optional = true }
wasm-bindgen-futures = { version = "0.4.47", optional = true }
[features]
async-executor = ["dep:async-executor"]
tracing = ["dep:tracing"]
tokio = ["dep:tokio"]
glib = ["dep:glib"]
wasm-bindgen = ["dep:wasm-bindgen-futures"]
futures-executor = ["futures/thread-pool", "futures/executor"]
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[package.metadata.cargo-all-features]
denylist = ["tracing"]

View File

@@ -0,0 +1 @@
extend = { path = "../cargo-make/main.toml" }

26
any_spawner/README.md Normal file
View File

@@ -0,0 +1,26 @@
This crate makes it easier to write asynchronous code that is executor-agnostic, by providing a
utility that can be used to spawn tasks in a variety of executors.
It only supports single executor per program, but that executor can be set at runtime, anywhere
in your crate (or an application that depends on it).
This can be extended to support any executor or runtime that supports spawning [`Future`]s.
This is a least common denominator implementation in many ways. Limitations include:
- setting an executor is a one-time, global action
- no "join handle" or other result is returned from the spawn
- the `Future` must output `()`
```rust
use any_spawner::Executor;
Executor::init_futures_executor()
.expect("executor should only be initialized once");
// spawn a thread-safe Future
Executor::spawn(async { /* ... */ });
// spawn a Future that is !Send
Executor::spawn_local(async { /* ... */ });
```

361
any_spawner/src/lib.rs Normal file
View File

@@ -0,0 +1,361 @@
//! This crate makes it easier to write asynchronous code that is executor-agnostic, by providing a
//! utility that can be used to spawn tasks in a variety of executors.
//!
//! It only supports single executor per program, but that executor can be set at runtime, anywhere
//! in your crate (or an application that depends on it).
//!
//! This can be extended to support any executor or runtime that supports spawning [`Future`]s.
//!
//! This is a least common denominator implementation in many ways. Limitations include:
//! - setting an executor is a one-time, global action
//! - no "join handle" or other result is returned from the spawn
//! - the `Future` must output `()`
//!
//! ```rust
//! 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)]
#![deny(missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg))]
use std::{future::Future, pin::Pin, sync::OnceLock};
use thiserror::Error;
/// A future that has been pinned.
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();
/// 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.")]
AlreadySet,
}
/// A global async executor that can spawn tasks.
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 { /* ... */ });
/// # }
/// ```
#[track_caller]
pub fn spawn(fut: impl Future<Output = ()> + Send + 'static) {
if let Some(spawner) = SPAWN.get() {
spawner(Box::pin(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()
);
}
}
/// 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 { /* ... */ });
/// # }
/// ```
#[track_caller]
pub fn spawn_local(fut: impl Future<Output = ()> + 'static) {
if let Some(spawner) = SPAWN_LOCAL.get() {
spawner(Box::pin(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()
);
}
}
/// Waits until the next "tick" of the current async executor.
pub async fn tick() {
let (tx, rx) = futures::channel::oneshot::channel();
Executor::spawn(async move {
_ = tx.send(());
});
_ = rx.await;
}
/// Polls the current async executor.
/// Not all async executors support polling, so this function may not do anything.
pub fn poll_local() {
if let Some(poller) = POLL_LOCAL.get() {
poller()
}
}
}
impl Executor {
/// Globally sets the [`tokio`] runtime as the executor used to spawn tasks.
///
/// Returns `Err(_)` if an 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| {
tokio::spawn(fut);
})
.map_err(|_| ExecutorError::AlreadySet)?;
SPAWN_LOCAL
.set(|fut| {
tokio::task::spawn_local(fut);
})
.map_err(|_| ExecutorError::AlreadySet)?;
Ok(())
}
/// Globally sets the [`wasm-bindgen-futures`] runtime as the executor used to spawn tasks.
///
/// Returns `Err(_)` if an 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| {
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(())
}
/// Globally sets the [`glib`] runtime as the executor used to spawn tasks.
///
/// Returns `Err(_)` if an 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 main_context = glib::MainContext::default();
main_context.spawn(fut);
})
.map_err(|_| ExecutorError::AlreadySet)?;
SPAWN_LOCAL
.set(|fut| {
let main_context = glib::MainContext::default();
main_context.spawn_local(fut);
})
.map_err(|_| ExecutorError::AlreadySet)?;
Ok(())
}
/// 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.
///
/// Requires the `futures-executor` feature to be activated on this crate.
#[cfg(feature = "futures-executor")]
#[cfg_attr(docsrs, doc(cfg(feature = "futures-executor")))]
pub fn init_futures_executor() -> Result<(), ExecutorError> {
use futures::{
executor::{LocalPool, LocalSpawner, ThreadPool},
task::{LocalSpawnExt, SpawnExt},
};
use std::cell::RefCell;
static THREAD_POOL: OnceLock<ThreadPool> = OnceLock::new();
thread_local! {
static LOCAL_POOL: RefCell<LocalPool> = RefCell::new(LocalPool::new());
static SPAWNER: LocalSpawner = LOCAL_POOL.with(|pool| pool.borrow().spawner());
}
fn get_thread_pool() -> &'static ThreadPool {
THREAD_POOL.get_or_init(|| {
ThreadPool::new()
.expect("could not create futures executor ThreadPool")
})
}
SPAWN
.set(|fut| {
get_thread_pool()
.spawn(fut)
.expect("failed to spawn future");
})
.map_err(|_| ExecutorError::AlreadySet)?;
SPAWN_LOCAL
.set(|fut| {
SPAWNER.with(|spawner| {
spawner.spawn_local(fut).expect("failed to spawn future");
});
})
.map_err(|_| ExecutorError::AlreadySet)?;
POLL_LOCAL
.set(|| {
LOCAL_POOL.with(|pool| {
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.
});
})
.map_err(|_| ExecutorError::AlreadySet)?;
Ok(())
}
/// 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.
///
/// 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};
static THREAD_POOL: OnceLock<Executor> = OnceLock::new();
thread_local! {
static LOCAL_POOL: LocalExecutor<'static> = const { LocalExecutor::new() };
}
fn get_thread_pool() -> &'static Executor<'static> {
THREAD_POOL.get_or_init(Executor::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(())
}
/// Globally sets a custom executor as the executor used to spawn tasks.
///
/// Returns `Err(_)` if an 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
.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(())
}
/// Locally sets a custom executor as the executor used to spawn tasks
/// in the current thread.
///
/// Returns `Err(_)` if an executor has already been set.
pub fn init_local_custom_executor(
custom_executor: impl CustomExecutor + 'static,
) -> Result<(), ExecutorError> {
thread_local! {
static EXECUTOR: OnceLock<Box<dyn CustomExecutor>> = OnceLock::new();
}
EXECUTOR.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(())
}
}
/// 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.
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.
fn poll_local(&self);
}

View File

@@ -0,0 +1,55 @@
#[cfg(feature = "futures-executor")]
use any_spawner::{CustomExecutor, Executor, PinnedFuture, PinnedLocalFuture};
#[cfg(feature = "futures-executor")]
#[test]
fn can_create_custom_executor() {
use futures::{
executor::{LocalPool, LocalSpawner},
task::LocalSpawnExt,
};
use std::{
cell::RefCell,
sync::{
atomic::{AtomicUsize, Ordering},
Arc,
},
};
thread_local! {
static LOCAL_POOL: RefCell<LocalPool> = RefCell::new(LocalPool::new());
static SPAWNER: LocalSpawner = LOCAL_POOL.with(|pool| pool.borrow().spawner());
}
struct CustomFutureExecutor;
impl CustomExecutor for CustomFutureExecutor {
fn spawn(&self, _fut: PinnedFuture<()>) {
panic!("not supported in this test");
}
fn spawn_local(&self, fut: PinnedLocalFuture<()>) {
SPAWNER.with(|spawner| {
spawner.spawn_local(fut).expect("failed to spawn future");
});
}
fn poll_local(&self) {
LOCAL_POOL.with(|pool| {
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.
});
}
}
Executor::init_custom_executor(CustomFutureExecutor)
.expect("couldn't set executor");
let counter = Arc::new(AtomicUsize::new(0));
let counter_clone = Arc::clone(&counter);
Executor::spawn_local(async move {
counter_clone.store(1, Ordering::Release);
});
Executor::poll_local();
assert_eq!(counter.load(Ordering::Acquire), 1);
}

View File

@@ -0,0 +1,38 @@
#[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;
let _ = Executor::init_futures_executor();
let rc = Rc::new(());
Executor::spawn_local(async {
_ = rc;
});
Executor::spawn(async {});
}
#[cfg(feature = "futures-executor")]
#[test]
fn can_make_local_progress() {
use std::sync::{
atomic::{AtomicUsize, Ordering},
Arc,
};
let _ = Executor::init_futures_executor();
let counter = Arc::new(AtomicUsize::new(0));
Executor::spawn_local({
let counter = Arc::clone(&counter);
async move {
assert_eq!(counter.fetch_add(1, Ordering::AcqRel), 0);
Executor::spawn_local(async {
// Should not crash
});
}
});
Executor::poll_local();
assert_eq!(counter.load(Ordering::Acquire), 1);
}

View File

@@ -2,26 +2,36 @@
name = "benchmarks"
version = "0.1.0"
edition = "2021"
# std::sync::LazyLock is stabilized in Rust version 1.80.0
rust-version = "1.80.0"
[dependencies]
l021 = { package = "leptos", version = "0.2.1" }
leptos = { path = "../leptos", features = ["ssr"] }
sycamore = { version = "0.8", features = ["ssr"] }
yew = { git = "https://github.com/yewstack/yew", features = ["ssr"] }
tokio-test = "0.4"
miniserde = "0.1"
gloo = "0.8"
uuid = { version = "1", features = ["serde", "v4", "wasm-bindgen"] }
wasm-bindgen = "0.2"
lazy_static = "1"
log = "0.4"
strum = "0.24"
strum_macros = "0.24"
serde = { version = "1", features = ["derive", "rc"] }
serde_json = "1"
tera = "1"
reactive-signals = "0.1.0-alpha.4"
l0410 = { package = "leptos", version = "0.4.10", features = [
"nightly",
"ssr",
] }
leptos = { path = "../leptos", features = ["ssr", "nightly"] }
leptos_reactive = { path = "../leptos_reactive", features = ["ssr", "nightly"] }
tachydom = { git = "https://github.com/gbj/tachys", features = [
"nightly",
"leptos",
] }
tachy_maccy = { git = "https://github.com/gbj/tachys", features = ["nightly"] }
sycamore = { version = "0.8.0", features = ["ssr"] }
yew = { version = "0.20.0", features = ["ssr"] }
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"
lazy_static = "1.0"
log = "0.4.0"
strum = "0.24.0"
strum_macros = "0.24.0"
serde = { version = "1.0", features = ["derive", "rc"] }
serde_json = "1.0"
tera = "1.0"
[dependencies.web-sys]
version = "0.3"
version = "0.3.0"
features = ["Window", "Document", "HtmlElement", "HtmlInputElement"]

View File

@@ -2,6 +2,6 @@
extern crate test;
//åmod reactive;
//mod ssr;
mod reactive;
mod ssr;
mod todomvc;

View File

@@ -7,19 +7,16 @@ fn leptos_deep_creation(b: &mut Bencher) {
let runtime = create_runtime();
b.iter(|| {
create_scope(runtime, |cx| {
let signal = create_rw_signal(cx, 0);
let mut memos = Vec::<Memo<usize>>::new();
for _ in 0..1000usize {
let prev = memos.last().copied();
if let Some(prev) = prev {
memos.push(create_memo(cx, move |_| prev.get() + 1));
} else {
memos.push(create_memo(cx, move |_| signal.get() + 1));
}
let signal = create_rw_signal(0);
let mut memos = Vec::<Memo<usize>>::new();
for _ in 0..1000usize {
let prev = memos.last().copied();
if let Some(prev) = prev {
memos.push(create_memo(move |_| prev.get() + 1));
} else {
memos.push(create_memo(move |_| signal.get() + 1));
}
})
.dispose()
}
});
runtime.dispose();
@@ -31,20 +28,17 @@ fn leptos_deep_update(b: &mut Bencher) {
let runtime = create_runtime();
b.iter(|| {
create_scope(runtime, |cx| {
let signal = create_rw_signal(cx, 0);
let mut memos = Vec::<Memo<usize>>::new();
for _ in 0..1000usize {
if let Some(prev) = memos.last().copied() {
memos.push(create_memo(cx, move |_| prev.get() + 1));
} else {
memos.push(create_memo(cx, move |_| signal.get() + 1));
}
let signal = create_rw_signal(0);
let mut memos = Vec::<Memo<usize>>::new();
for _ in 0..1000usize {
if let Some(prev) = memos.last().copied() {
memos.push(create_memo(move |_| prev.get() + 1));
} else {
memos.push(create_memo(move |_| signal.get() + 1));
}
signal.set(1);
assert_eq!(memos[999].get(), 1001);
})
.dispose()
}
signal.set(1);
assert_eq!(memos[999].get(), 1001);
});
runtime.dispose();
@@ -56,17 +50,12 @@ fn leptos_narrowing_down(b: &mut Bencher) {
let runtime = create_runtime();
b.iter(|| {
create_scope(runtime, |cx| {
let sigs =
(0..1000).map(|n| create_signal(cx, n)).collect::<Vec<_>>();
let reads = sigs.iter().map(|(r, _)| *r).collect::<Vec<_>>();
let writes = sigs.iter().map(|(_, w)| *w).collect::<Vec<_>>();
let memo = create_memo(cx, move |_| {
reads.iter().map(|r| r.get()).sum::<i32>()
});
assert_eq!(memo(), 499500);
})
.dispose()
let sigs = (0..1000).map(|n| create_signal(n)).collect::<Vec<_>>();
let reads = sigs.iter().map(|(r, _)| *r).collect::<Vec<_>>();
let writes = sigs.iter().map(|(_, w)| *w).collect::<Vec<_>>();
let memo =
create_memo(move |_| reads.iter().map(|r| r.get()).sum::<i32>());
assert_eq!(memo(), 499500);
});
runtime.dispose();
@@ -78,16 +67,13 @@ fn leptos_fanning_out(b: &mut Bencher) {
let runtime = create_runtime();
b.iter(|| {
create_scope(runtime, |cx| {
let sig = create_rw_signal(cx, 0);
let memos = (0..1000)
.map(|_| create_memo(cx, move |_| sig.get()))
.collect::<Vec<_>>();
assert_eq!(memos.iter().map(|m| m.get()).sum::<i32>(), 0);
sig.set(1);
assert_eq!(memos.iter().map(|m| m.get()).sum::<i32>(), 1000);
})
.dispose()
let sig = create_rw_signal(0);
let memos = (0..1000)
.map(|_| create_memo(move |_| sig.get()))
.collect::<Vec<_>>();
assert_eq!(memos.iter().map(|m| m.get()).sum::<i32>(), 0);
sig.set(1);
assert_eq!(memos.iter().map(|m| m.get()).sum::<i32>(), 1000);
});
runtime.dispose();
@@ -98,143 +84,36 @@ fn leptos_narrowing_update(b: &mut Bencher) {
use leptos::*;
let runtime = create_runtime();
b.iter(|| {
create_scope(runtime, |cx| {
let acc = Rc::new(Cell::new(0));
let sigs =
(0..1000).map(|n| create_signal(cx, n)).collect::<Vec<_>>();
let reads = sigs.iter().map(|(r, _)| *r).collect::<Vec<_>>();
let writes = sigs.iter().map(|(_, w)| *w).collect::<Vec<_>>();
let memo = create_memo(cx, move |_| {
reads.iter().map(|r| r.get()).sum::<i32>()
});
assert_eq!(memo(), 499500);
create_isomorphic_effect(cx, {
let acc = Rc::clone(&acc);
move |_| {
acc.set(memo());
}
});
assert_eq!(acc.get(), 499500);
writes[1].update(|n| *n += 1);
writes[10].update(|n| *n += 1);
writes[100].update(|n| *n += 1);
assert_eq!(acc.get(), 499503);
assert_eq!(memo(), 499503);
})
.dispose()
});
runtime.dispose();
}
#[bench]
fn leptos_scope_creation_and_disposal(b: &mut Bencher) {
use leptos::*;
let runtime = create_runtime();
b.iter(|| {
let acc = Rc::new(Cell::new(0));
let disposers = (0..1000)
.map(|_| {
create_scope(runtime, {
let acc = Rc::clone(&acc);
move |cx| {
let (r, w) = create_signal(cx, 0);
create_isomorphic_effect(cx, {
move |_| {
acc.set(r());
}
});
w.update(|n| *n += 1);
}
})
})
.collect::<Vec<_>>();
for disposer in disposers {
disposer.dispose();
}
});
runtime.dispose();
}
#[bench]
fn rs_deep_update(b: &mut Bencher) {
use reactive_signals::{Scope, Signal, signal, runtimes::ClientRuntime, types::Func};
let sc = ClientRuntime::new_root_scope();
b.iter(|| {
let signal = signal!(sc, 0);
let mut memos = Vec::<Signal<Func<i32>, ClientRuntime>>::new();
for i in 0..1000usize {
let prev = memos.get(i.saturating_sub(1)).copied();
if let Some(prev) = prev {
memos.push(signal!(sc, move || prev.get() + 1))
} else {
memos.push(signal!(sc, move || signal.get() + 1))
}
}
signal.set(1);
assert_eq!(memos[999].get(), 1001);
});
}
#[bench]
fn rs_fanning_out(b: &mut Bencher) {
use reactive_signals::{Scope, Signal, signal, runtimes::ClientRuntime, types::Func};
let cx = ClientRuntime::new_root_scope();
b.iter(|| {
let sig = signal!(cx, 0);
let memos = (0..1000)
.map(|_| signal!(cx, move || sig.get()))
.collect::<Vec<_>>();
assert_eq!(memos.iter().map(|m| m.get()).sum::<i32>(), 0);
sig.set(1);
assert_eq!(memos.iter().map(|m| m.get()).sum::<i32>(), 1000);
});
}
#[bench]
fn rs_narrowing_update(b: &mut Bencher) {
use reactive_signals::{Scope, Signal, signal, runtimes::ClientRuntime, types::Func};
let cx = ClientRuntime::new_root_scope();
b.iter(|| {
let acc = Rc::new(Cell::new(0));
let sigs =
(0..1000).map(|n| signal!(cx, n)).collect::<Vec<_>>();
let memo = signal!(cx, {
let sigs = sigs.clone();
move || {
sigs.iter().map(|r| r.get()).sum::<i32>()
}
});
assert_eq!(memo.get(), 499500);
signal!(cx, {
let sigs = (0..1000).map(|n| create_signal(n)).collect::<Vec<_>>();
let reads = sigs.iter().map(|(r, _)| *r).collect::<Vec<_>>();
let writes = sigs.iter().map(|(_, w)| *w).collect::<Vec<_>>();
let memo =
create_memo(move |_| reads.iter().map(|r| r.get()).sum::<i32>());
assert_eq!(memo(), 499500);
create_isomorphic_effect({
let acc = Rc::clone(&acc);
move || {
acc.set(memo.get());
move |_| {
acc.set(memo());
}
});
assert_eq!(acc.get(), 499500);
sigs[1].update(|n| *n += 1);
sigs[10].update(|n| *n += 1);
sigs[100].update(|n| *n += 1);
writes[1].update(|n| *n += 1);
writes[10].update(|n| *n += 1);
writes[100].update(|n| *n += 1);
assert_eq!(acc.get(), 499503);
assert_eq!(memo.get(), 499503);
assert_eq!(memo(), 499503);
});
runtime.dispose();
}
#[bench]
fn l021_deep_creation(b: &mut Bencher) {
use l021::*;
fn l0410_deep_creation(b: &mut Bencher) {
use l0410::*;
let runtime = create_runtime();
b.iter(|| {
@@ -256,8 +135,8 @@ fn l021_deep_creation(b: &mut Bencher) {
}
#[bench]
fn l021_deep_update(b: &mut Bencher) {
use l021::*;
fn l0410_deep_update(b: &mut Bencher) {
use l0410::*;
let runtime = create_runtime();
b.iter(|| {
@@ -281,8 +160,8 @@ fn l021_deep_update(b: &mut Bencher) {
}
#[bench]
fn l021_narrowing_down(b: &mut Bencher) {
use l021::*;
fn l0410_narrowing_down(b: &mut Bencher) {
use l0410::*;
let runtime = create_runtime();
b.iter(|| {
@@ -304,8 +183,8 @@ fn l021_narrowing_down(b: &mut Bencher) {
}
#[bench]
fn l021_fanning_out(b: &mut Bencher) {
use leptos::*;
fn l0410_fanning_out(b: &mut Bencher) {
use l0410::*;
let runtime = create_runtime();
b.iter(|| {
@@ -324,8 +203,8 @@ fn l021_fanning_out(b: &mut Bencher) {
runtime.dispose();
}
#[bench]
fn l021_narrowing_update(b: &mut Bencher) {
use l021::*;
fn l0410_narrowing_update(b: &mut Bencher) {
use l0410::*;
let runtime = create_runtime();
b.iter(|| {
@@ -338,11 +217,11 @@ fn l021_narrowing_update(b: &mut Bencher) {
let memo = create_memo(cx, move |_| {
reads.iter().map(|r| r.get()).sum::<i32>()
});
assert_eq!(memo(), 499500);
assert_eq!(memo.get(), 499500);
create_isomorphic_effect(cx, {
let acc = Rc::clone(&acc);
move |_| {
acc.set(memo());
acc.set(memo.get());
}
});
assert_eq!(acc.get(), 499500);
@@ -352,7 +231,7 @@ fn l021_narrowing_update(b: &mut Bencher) {
writes[100].update(|n| *n += 1);
assert_eq!(acc.get(), 499503);
assert_eq!(memo(), 499503);
assert_eq!(memo.get(), 499503);
})
.dispose()
});
@@ -361,8 +240,8 @@ fn l021_narrowing_update(b: &mut Bencher) {
}
#[bench]
fn l021_scope_creation_and_disposal(b: &mut Bencher) {
use l021::*;
fn l0410_scope_creation_and_disposal(b: &mut Bencher) {
use l0410::*;
let runtime = create_runtime();
b.iter(|| {
@@ -375,7 +254,7 @@ fn l021_scope_creation_and_disposal(b: &mut Bencher) {
let (r, w) = create_signal(cx, 0);
create_isomorphic_effect(cx, {
move |_| {
acc.set(r());
acc.set(r.get());
}
});
w.update(|n| *n += 1);

View File

@@ -2,15 +2,14 @@ use test::Bencher;
#[bench]
fn leptos_ssr_bench(b: &mut Bencher) {
use leptos::*;
let r = create_runtime();
b.iter(|| {
use leptos::*;
leptos_dom::HydrationCtx::reset_id();
_ = create_scope(create_runtime(), |cx| {
leptos::leptos_dom::HydrationCtx::reset_id();
#[component]
fn Counter(cx: Scope, initial: i32) -> impl IntoView {
let (value, set_value) = create_signal(cx, initial);
fn Counter(initial: i32) -> impl IntoView {
let (value, set_value) = create_signal(initial);
view! {
cx,
<div>
<button on:click=move |_| set_value.update(|value| *value -= 1)>"-1"</button>
<span>"Value: " {move || value().to_string()} "!"</span>
@@ -19,8 +18,7 @@ fn leptos_ssr_bench(b: &mut Bencher) {
}
}
let rendered = view! {
cx,
let rendered = view! {
<main>
<h1>"Welcome to our benchmark page."</h1>
<p>"Here's some introductory text."</p>
@@ -28,14 +26,53 @@ fn leptos_ssr_bench(b: &mut Bencher) {
<Counter initial=2/>
<Counter initial=3/>
</main>
}.into_view(cx).render_to_string(cx);
}.into_view().render_to_string();
assert_eq!(
rendered,
"<main id=\"_0-1\"><h1 id=\"_0-2\">Welcome to our benchmark page.</h1><p id=\"_0-3\">Here&#x27;s some introductory text.</p><div id=\"_0-3-1\"><button id=\"_0-3-2\">-1</button><span id=\"_0-3-3\">Value: <!>1<!--hk=_0-3-4-->!</span><button id=\"_0-3-5\">+1</button></div><!--hk=_0-3-0--><div id=\"_0-3-5-1\"><button id=\"_0-3-5-2\">-1</button><span id=\"_0-3-5-3\">Value: <!>2<!--hk=_0-3-5-4-->!</span><button id=\"_0-3-5-5\">+1</button></div><!--hk=_0-3-5-0--><div id=\"_0-3-5-5-1\"><button id=\"_0-3-5-5-2\">-1</button><span id=\"_0-3-5-5-3\">Value: <!>3<!--hk=_0-3-5-5-4-->!</span><button id=\"_0-3-5-5-5\">+1</button></div><!--hk=_0-3-5-5-0--></main>"
);
});
"<main data-hk=\"0-0-0-1\"><h1 data-hk=\"0-0-0-2\">Welcome to our benchmark page.</h1><p data-hk=\"0-0-0-3\">Here&#x27;s some introductory text.</p><div data-hk=\"0-0-0-5\"><button data-hk=\"0-0-0-6\">-1</button><span data-hk=\"0-0-0-7\">Value: <!>1<!--hk=0-0-0-8-->!</span><button data-hk=\"0-0-0-9\">+1</button></div><!--hk=0-0-0-4--><div data-hk=\"0-0-0-11\"><button data-hk=\"0-0-0-12\">-1</button><span data-hk=\"0-0-0-13\">Value: <!>2<!--hk=0-0-0-14-->!</span><button data-hk=\"0-0-0-15\">+1</button></div><!--hk=0-0-0-10--><div data-hk=\"0-0-0-17\"><button data-hk=\"0-0-0-18\">-1</button><span data-hk=\"0-0-0-19\">Value: <!>3<!--hk=0-0-0-20-->!</span><button data-hk=\"0-0-0-21\">+1</button></div><!--hk=0-0-0-16--></main>" );
});
r.dispose();
}
#[bench]
fn tachys_ssr_bench(b: &mut Bencher) {
use leptos::{create_runtime, create_signal, SignalGet, SignalUpdate};
use tachy_maccy::view;
use tachydom::view::{Render, RenderHtml};
use tachydom::html::element::ElementChild;
use tachydom::html::attribute::global::ClassAttribute;
use tachydom::html::attribute::global::GlobalAttributes;
use tachydom::html::attribute::global::OnAttribute;
use tachydom::renderer::dom::Dom;
let rt = create_runtime();
b.iter(|| {
fn counter(initial: i32) -> impl Render<Dom> + RenderHtml<Dom> {
let (value, set_value) = create_signal(initial);
view! {
<div>
<button on:click=move |_| set_value.update(|value| *value -= 1)>"-1"</button>
<span>"Value: " {move || value().to_string()} "!"</span>
<button on:click=move |_| set_value.update(|value| *value += 1)>"+1"</button>
</div>
}
}
let rendered = view! {
<main>
<h1>"Welcome to our benchmark page."</h1>
<p>"Here's some introductory text."</p>
{counter(1)}
{counter(2)}
{counter(3)}
</main>
}.to_html();
assert_eq!(
rendered,
"<main><h1>Welcome to our benchmark page.</h1><p>Here's some introductory text.</p><div><button>-1</button><span>Value: <!>1<!>!</span><button>+1</button></div><div><button>-1</button><span>Value: <!>2<!>!</span><button>+1</button></div><div><button>-1</button><span>Value: <!>3<!>!</span><button>+1</button></div></main>"
);
});
rt.dispose();
}
#[bench]
@@ -55,13 +92,13 @@ fn tera_ssr_bench(b: &mut Bencher) {
{% endfor %}
</main>"#;
lazy_static::lazy_static! {
static ref TERA: Tera = {
let mut tera = Tera::default();
tera.add_raw_templates(vec![("template.html", TEMPLATE)]).unwrap();
tera
};
}
static LazyCell<TERA>: Tera = LazyLock::new(|| {
let mut tera = Tera::default();
tera.add_raw_templates(vec![("template.html", TEMPLATE)]).unwrap();
tera
});
#[derive(Serialize, Deserialize)]
struct Counter {

View File

@@ -1,7 +1,7 @@
pub use leptos::*;
use miniserde::*;
use web_sys::HtmlInputElement;
use wasm_bindgen::JsCast;
use web_sys::HtmlInputElement;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Todos(pub Vec<Todo>);
@@ -9,13 +9,13 @@ pub struct Todos(pub Vec<Todo>);
const STORAGE_KEY: &str = "todos-leptos";
impl Todos {
pub fn new(cx: Scope) -> Self {
pub fn new() -> Self {
Self(vec![])
}
pub fn new_with_1000(cx: Scope) -> Self {
pub fn new_with_1000() -> Self {
let todos = (0..1000)
.map(|id| Todo::new(cx, id, format!("Todo #{id}")))
.map(|id| Todo::new(id, format!("Todo #{id}")))
.collect();
Self(todos)
}
@@ -72,13 +72,17 @@ pub struct Todo {
}
impl Todo {
pub fn new(cx: Scope, id: usize, title: String) -> Self {
Self::new_with_completed(cx, id, title, false)
pub fn new(id: usize, title: String) -> Self {
Self::new_with_completed(id, title, false)
}
pub fn new_with_completed(cx: Scope, id: usize, title: String, completed: bool) -> Self {
let (title, set_title) = create_signal(cx, title);
let (completed, set_completed) = create_signal(cx, completed);
pub fn new_with_completed(
id: usize,
title: String,
completed: bool,
) -> Self {
let (title, set_title) = create_signal(title);
let (completed, set_completed) = create_signal(completed);
Self {
id,
title,
@@ -98,7 +102,7 @@ const ESCAPE_KEY: u32 = 27;
const ENTER_KEY: u32 = 13;
#[component]
pub fn TodoMVC(cx: Scope, todos: Todos) -> impl IntoView {
pub fn TodoMVC(todos: Todos) -> impl IntoView {
let mut next_id = todos
.0
.iter()
@@ -107,10 +111,10 @@ pub fn TodoMVC(cx: Scope, todos: Todos) -> impl IntoView {
.map(|last| last + 1)
.unwrap_or(0);
let (todos, set_todos) = create_signal(cx, todos);
provide_context(cx, set_todos);
let (todos, set_todos) = create_signal(todos);
provide_context(set_todos);
let (mode, set_mode) = create_signal(cx, Mode::All);
let (mode, set_mode) = create_signal(Mode::All);
let add_todo = move |ev: web_sys::KeyboardEvent| {
let target = event_target::<HtmlInputElement>(&ev);
@@ -120,7 +124,7 @@ pub fn TodoMVC(cx: Scope, todos: Todos) -> impl IntoView {
let title = event_target_value(&ev);
let title = title.trim();
if !title.is_empty() {
let new = Todo::new(cx, next_id, title.to_string());
let new = Todo::new(next_id, title.to_string());
set_todos.update(|t| t.add(new));
next_id += 1;
target.set_value("");
@@ -128,7 +132,7 @@ pub fn TodoMVC(cx: Scope, todos: Todos) -> impl IntoView {
}
};
let filtered_todos = create_memo::<Vec<Todo>>(cx, move |_| {
let filtered_todos = create_memo::<Vec<Todo>>(move |_| {
todos.with(|todos| match mode.get() {
Mode::All => todos.0.to_vec(),
Mode::Active => todos
@@ -148,7 +152,7 @@ pub fn TodoMVC(cx: Scope, todos: Todos) -> impl IntoView {
// effect to serialize to JSON
// this does reactive reads, so it will automatically serialize on any relevant change
create_effect(cx, move |_| {
create_effect(move |_| {
if let Ok(Some(storage)) = window().local_storage() {
let objs = todos
.get()
@@ -163,7 +167,7 @@ pub fn TodoMVC(cx: Scope, todos: Todos) -> impl IntoView {
}
});
view! { cx,
view! {
<main>
<section class="todoapp">
<header class="header">
@@ -188,8 +192,8 @@ pub fn TodoMVC(cx: Scope, todos: Todos) -> impl IntoView {
<For
each=filtered_todos
key=|todo| todo.id
view=move |cx, todo: Todo| {
view! { cx, <Todo todo=todo.clone()/> }
children=move |todo: Todo| {
view! { <Todo todo=todo.clone()/> }
}
/>
</ul>
@@ -236,14 +240,14 @@ pub fn TodoMVC(cx: Scope, todos: Todos) -> impl IntoView {
<p>"Part of " <a href="http://todomvc.com">"TodoMVC"</a></p>
</footer>
</main>
}.into_view(cx)
}.into_view()
}
#[component]
pub fn Todo(cx: Scope, todo: Todo) -> impl IntoView {
let (editing, set_editing) = create_signal(cx, false);
let set_todos = use_context::<WriteSignal<Todos>>(cx).unwrap();
//let input = NodeRef::new(cx);
pub fn Todo(todo: Todo) -> impl IntoView {
let (editing, set_editing) = create_signal(false);
let set_todos = use_context::<WriteSignal<Todos>>().unwrap();
//let input = NodeRef::new();
let save = move |value: &str| {
let value = value.trim();
@@ -255,7 +259,7 @@ pub fn Todo(cx: Scope, todo: Todo) -> impl IntoView {
set_editing(false);
};
view! { cx,
view! {
<li class="todo" class:editing=editing class:completed=move || (todo.completed)()>
<div class="view">
<input class="toggle" type="checkbox" prop:checked=move || (todo.completed)()/>
@@ -268,7 +272,7 @@ pub fn Todo(cx: Scope, todo: Todo) -> impl IntoView {
{move || {
editing()
.then(|| {
view! { cx,
view! {
<input
class="edit"
class:hidden=move || !(editing)()
@@ -319,8 +323,8 @@ pub struct TodoSerialized {
}
impl TodoSerialized {
pub fn into_todo(self, cx: Scope) -> Todo {
Todo::new_with_completed(cx, self.id, self.title, self.completed)
pub fn into_todo(self, ) -> Todo {
Todo::new_with_completed(self.id, self.title, self.completed)
}
}

View File

@@ -2,6 +2,7 @@ use test::Bencher;
mod leptos;
mod sycamore;
mod tachys;
mod tera;
mod yew;
@@ -12,18 +13,34 @@ fn leptos_todomvc_ssr(b: &mut Bencher) {
b.iter(|| {
use crate::todomvc::leptos::*;
let html = ::leptos::ssr::render_to_string(|cx| {
view! { cx, <TodoMVC todos=Todos::new(cx)/> }
let html = ::leptos::ssr::render_to_string(|| {
view! { <TodoMVC todos=Todos::new()/> }
});
assert!(html.len() > 1);
});
runtime.dispose();
}
#[bench]
fn tachys_todomvc_ssr(b: &mut Bencher) {
use ::leptos::*;
let runtime = create_runtime();
b.iter(|| {
use crate::todomvc::tachys::*;
use tachydom::view::{Render, RenderHtml};
let rendered = TodoMVC(Todos::new()).to_html();
assert_eq!(
rendered,
"<main><section class=\"todoapp\"><header class=\"header\"><h1>todos</h1><input placeholder=\"What needs to be done?\" autofocus class=\"new-todo\"></header><section class=\"main hidden\"><input id=\"toggle-all\" type=\"checkbox\" class=\"toggle-all\"><label for=\"toggle-all\">Mark all as complete</label><ul class=\"todo-list\"></ul></section><footer class=\"footer hidden\"><span class=\"todo-count\"><strong>0</strong><!> items<!> left</span><ul class=\"filters\"><li><a href=\"#/\" class=\"selected selected\">All</a></li><li><a href=\"#/active\" class=\"\">Active</a></li><li><a href=\"#/completed\" class=\"\">Completed</a></li></ul><button class=\"clear-completed hidden hidden\">Clear completed</button></footer></section><footer class=\"info\"><p>Double-click to edit a todo</p><p>Created by <a href=\"http://todomvc.com\">Greg Johnston</a></p><p>Part of <a href=\"http://todomvc.com\">TodoMVC</a></p></footer></main>" );
});
runtime.dispose();
}
#[bench]
fn sycamore_todomvc_ssr(b: &mut Bencher) {
use self::sycamore::*;
use ::sycamore::prelude::*;
use ::sycamore::*;
use ::sycamore::{prelude::*, *};
b.iter(|| {
_ = create_scope(|cx| {
@@ -42,8 +59,7 @@ fn sycamore_todomvc_ssr(b: &mut Bencher) {
#[bench]
fn yew_todomvc_ssr(b: &mut Bencher) {
use self::yew::*;
use ::yew::prelude::*;
use ::yew::ServerRenderer;
use ::yew::{prelude::*, ServerRenderer};
b.iter(|| {
tokio_test::block_on(async {
@@ -60,21 +76,33 @@ fn leptos_todomvc_ssr_with_1000(b: &mut Bencher) {
use self::leptos::*;
use ::leptos::*;
let html = ::leptos::ssr::render_to_string(|cx| {
let html = ::leptos::ssr::render_to_string(|| {
view! {
cx,
<TodoMVC todos=Todos::new_with_1000(cx)/>
<TodoMVC todos=Todos::new_with_1000()/>
}
});
assert!(html.len() > 1);
});
}
#[bench]
fn tachys_todomvc_ssr_with_1000(b: &mut Bencher) {
use ::leptos::*;
let runtime = create_runtime();
b.iter(|| {
use crate::todomvc::tachys::*;
use tachydom::view::{Render, RenderHtml};
let rendered = TodoMVC(Todos::new_with_1000()).to_html();
assert!(rendered.len() > 20_000)
});
runtime.dispose();
}
#[bench]
fn sycamore_todomvc_ssr_with_1000(b: &mut Bencher) {
use self::sycamore::*;
use ::sycamore::prelude::*;
use ::sycamore::*;
use ::sycamore::{prelude::*, *};
b.iter(|| {
_ = create_scope(|cx| {
@@ -93,8 +121,7 @@ fn sycamore_todomvc_ssr_with_1000(b: &mut Bencher) {
#[bench]
fn yew_todomvc_ssr_with_1000(b: &mut Bencher) {
use self::yew::*;
use ::yew::prelude::*;
use ::yew::ServerRenderer;
use ::yew::{prelude::*, ServerRenderer};
b.iter(|| {
tokio_test::block_on(async {
@@ -103,4 +130,19 @@ fn yew_todomvc_ssr_with_1000(b: &mut Bencher) {
assert!(rendered.len() > 1);
});
});
}
}
#[bench]
fn tera_todomvc_ssr(b: &mut Bencher) {
use ::leptos::*;
let runtime = create_runtime();
b.iter(|| {
use crate::todomvc::leptos::*;
let html = ::leptos::ssr::render_to_string(|| {
view! { <TodoMVC todos=Todos::new()/> }
});
assert!(html.len() > 1);
});
runtime.dispose();
}

View File

@@ -0,0 +1,333 @@
pub use leptos_reactive::*;
use miniserde::*;
use tachy_maccy::view;
use tachydom::{
html::{
attribute::global::{ClassAttribute, GlobalAttributes, OnAttribute},
element::ElementChild,
},
renderer::dom::Dom,
view::{keyed::keyed, Render, RenderHtml},
};
use wasm_bindgen::JsCast;
use web_sys::HtmlInputElement;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Todos(pub Vec<Todo>);
const STORAGE_KEY: &str = "todos-leptos";
impl Todos {
pub fn new() -> Self {
Self(vec![])
}
pub fn new_with_1000() -> Self {
let todos = (0..1000)
.map(|id| Todo::new(id, format!("Todo #{id}")))
.collect();
Self(todos)
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn add(&mut self, todo: Todo) {
self.0.push(todo);
}
pub fn remove(&mut self, id: usize) {
self.0.retain(|todo| todo.id != id);
}
pub fn remaining(&self) -> usize {
self.0.iter().filter(|todo| !(todo.completed)()).count()
}
pub fn completed(&self) -> usize {
self.0.iter().filter(|todo| (todo.completed)()).count()
}
pub fn toggle_all(&self) {
// if all are complete, mark them all active instead
if self.remaining() == 0 {
for todo in &self.0 {
if todo.completed.get() {
(todo.set_completed)(false);
}
}
}
// otherwise, mark them all complete
else {
for todo in &self.0 {
(todo.set_completed)(true);
}
}
}
fn clear_completed(&mut self) {
self.0.retain(|todo| !todo.completed.get());
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Todo {
pub id: usize,
pub title: ReadSignal<String>,
pub set_title: WriteSignal<String>,
pub completed: ReadSignal<bool>,
pub set_completed: WriteSignal<bool>,
}
impl Todo {
pub fn new(id: usize, title: String) -> Self {
Self::new_with_completed(id, title, false)
}
pub fn new_with_completed(
id: usize,
title: String,
completed: bool,
) -> Self {
let (title, set_title) = create_signal(title);
let (completed, set_completed) = create_signal(completed);
Self {
id,
title,
set_title,
completed,
set_completed,
}
}
pub fn toggle(&self) {
self.set_completed
.update(|completed| *completed = !*completed);
}
}
const ESCAPE_KEY: u32 = 27;
const ENTER_KEY: u32 = 13;
pub fn TodoMVC(todos: Todos) -> impl Render<Dom> + RenderHtml<Dom> {
let mut next_id = todos
.0
.iter()
.map(|todo| todo.id)
.max()
.map(|last| last + 1)
.unwrap_or(0);
let (todos, set_todos) = create_signal(todos);
provide_context(set_todos);
let (mode, set_mode) = create_signal(Mode::All);
let add_todo = move |ev: web_sys::KeyboardEvent| {
todo!()
/* let target = event_target::<HtmlInputElement>(&ev);
ev.stop_propagation();
let key_code = ev.unchecked_ref::<web_sys::KeyboardEvent>().key_code();
if key_code == ENTER_KEY {
let title = event_target_value(&ev);
let title = title.trim();
if !title.is_empty() {
let new = Todo::new(next_id, title.to_string());
set_todos.update(|t| t.add(new));
next_id += 1;
target.set_value("");
}
} */
};
let filtered_todos = create_memo::<Vec<Todo>>(move |_| {
todos.with(|todos| match mode.get() {
Mode::All => todos.0.to_vec(),
Mode::Active => todos
.0
.iter()
.filter(|todo| !todo.completed.get())
.cloned()
.collect(),
Mode::Completed => todos
.0
.iter()
.filter(|todo| todo.completed.get())
.cloned()
.collect(),
})
});
// effect to serialize to JSON
// this does reactive reads, so it will automatically serialize on any relevant change
create_effect(move |_| {
()
/* if let Ok(Some(storage)) = window().local_storage() {
let objs = todos
.get()
.0
.iter()
.map(TodoSerialized::from)
.collect::<Vec<_>>();
let json = json::to_string(&objs);
if storage.set_item(STORAGE_KEY, &json).is_err() {
log::error!("error while trying to set item in localStorage");
}
} */
});
view! {
<main>
<section class="todoapp">
<header class="header">
<h1>"todos"</h1>
<input
class="new-todo"
placeholder="What needs to be done?"
autofocus
/>
</header>
<section class="main" class:hidden=move || todos.with(|t| t.is_empty())>
<input
id="toggle-all"
class="toggle-all"
r#type="checkbox"
//prop:checked=move || todos.with(|t| t.remaining() > 0)
on:input=move |_| set_todos.update(|t| t.toggle_all())
/>
<label r#for="toggle-all">"Mark all as complete"</label>
<ul class="todo-list">
{move || {
keyed(filtered_todos.get(), |todo| todo.id, Todo)
}}
</ul>
</section>
<footer class="footer" class:hidden=move || todos.with(|t| t.is_empty())>
<span class="todo-count">
<strong>{move || todos.with(|t| t.remaining().to_string())}</strong>
{move || if todos.with(|t| t.remaining()) == 1 { " item" } else { " items" }}
" left"
</span>
<ul class="filters">
<li>
<a
href="#/"
class="selected"
class:selected=move || mode() == Mode::All
>
"All"
</a>
</li>
<li>
<a href="#/active" class:selected=move || mode() == Mode::Active>
"Active"
</a>
</li>
<li>
<a href="#/completed" class:selected=move || mode() == Mode::Completed>
"Completed"
</a>
</li>
</ul>
<button
class="clear-completed hidden"
class:hidden=move || todos.with(|t| t.completed() == 0)
on:click=move |_| set_todos.update(|t| t.clear_completed())
>
"Clear completed"
</button>
</footer>
</section>
<footer class="info">
<p>"Double-click to edit a todo"</p>
<p>"Created by " <a href="http://todomvc.com">"Greg Johnston"</a></p>
<p>"Part of " <a href="http://todomvc.com">"TodoMVC"</a></p>
</footer>
</main>
}
}
pub fn Todo(todo: Todo) -> impl Render<Dom> + RenderHtml<Dom> {
let (editing, set_editing) = create_signal(false);
let set_todos = use_context::<WriteSignal<Todos>>().unwrap();
//let input = NodeRef::new();
let save = move |value: &str| {
let value = value.trim();
if value.is_empty() {
set_todos.update(|t| t.remove(todo.id));
} else {
(todo.set_title)(value.to_string());
}
set_editing(false);
};
view! {
<li class="todo" class:editing=editing class:completed=move || (todo.completed)()>
/* <div class="view">
<input class="toggle" r#type="checkbox"/>
<label on:dblclick=move |_| set_editing(true)>{move || todo.title.get()}</label>
<button
class="destroy"
on:click=move |_| set_todos.update(|t| t.remove(todo.id))
></button>
</div>
{move || {
editing()
.then(|| {
view! {
<input
class="edit"
class:hidden=move || !(editing)()
/>
}
})
}} */
</li>
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Mode {
Active,
Completed,
All,
}
impl Default for Mode {
fn default() -> Self {
Mode::All
}
}
pub fn route(hash: &str) -> Mode {
match hash {
"/active" => Mode::Active,
"/completed" => Mode::Completed,
_ => Mode::All,
}
}
#[derive(Serialize, Deserialize)]
pub struct TodoSerialized {
pub id: usize,
pub title: String,
pub completed: bool,
}
impl TodoSerialized {
pub fn into_todo(self) -> Todo {
Todo::new_with_completed(self.id, self.title, self.completed)
}
}
impl From<&Todo> for TodoSerialized {
fn from(todo: &Todo) -> Self {
Self {
id: todo.id,
title: todo.title.get(),
completed: (todo.completed)(),
}
}
}

View File

@@ -55,7 +55,7 @@ static TEMPLATE: &str = r#"<main>
{% else %}
<li><a href="/">All</a></li>
{% endif %}
{% if mode_active %}
<li><a href="/active" class="selected">Active</a></li>
{% else %}
@@ -87,17 +87,17 @@ static TEMPLATE: &str = r#"<main>
</main>"#;
#[bench]
fn tera_todomvc(b: &mut Bencher) {
fn tera_todomvc_ssr(b: &mut Bencher) {
use serde::{Deserialize, Serialize};
use tera::*;
lazy_static::lazy_static! {
static ref TERA: Tera = {
static LazyLock<TERA>: Tera = LazyLock( || {
let mut tera = Tera::default();
tera.add_raw_templates(vec![("template.html", TEMPLATE)]).unwrap();
tera
};
}
});
#[derive(Serialize, Deserialize)]
struct Todo {
@@ -127,17 +127,17 @@ fn tera_todomvc(b: &mut Bencher) {
}
#[bench]
fn tera_todomvc_1000(b: &mut Bencher) {
fn tera_todomvc_ssr_1000(b: &mut Bencher) {
use serde::{Deserialize, Serialize};
use tera::*;
lazy_static::lazy_static! {
static ref TERA: Tera = {
let mut tera = Tera::default();
tera.add_raw_templates(vec![("template.html", TEMPLATE)]).unwrap();
tera
};
}
static TERA: LazyLock<Tera> = LazyLock::new(|| {
let mut tera = Tera::default();
tera.add_raw_templates(vec![("template.html", TEMPLATE)]).unwrap();
tera
});
#[derive(Serialize, Deserialize)]
struct Todo {
@@ -174,4 +174,4 @@ fn tera_todomvc_1000(b: &mut Bencher) {
let _ = TERA.render("template.html", &ctx).unwrap();
});
}
}

View File

@@ -3,5 +3,5 @@ alias = "check-all"
[tasks.check-all]
command = "cargo"
args = ["+nightly", "check-all-features"]
args = ["check-all-features"]
install_crate = "cargo-all-features"

View File

@@ -1,9 +1,18 @@
[tasks.pre-clippy]
env = { CARGO_MAKE_CLIPPY_ARGS = "--all-targets --all-features -- -D warnings" }
[tasks.check-style]
dependencies = ["check-format-flow", "clippy-flow"]
[tasks.lint]
dependencies = ["check-format-flow", "clippy-each-feature"]
[tasks.check-format]
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",
]

View File

@@ -13,6 +13,3 @@ RUSTFLAGS = "-D warnings"
[tasks.ci]
dependencies = ["lint", "test"]
[tasks.lint]
dependencies = ["check-format-flow"]

View File

@@ -3,5 +3,5 @@ alias = "test-all"
[tasks.test-all]
command = "cargo"
args = ["+nightly", "test-all-features"]
args = ["test-all-features"]
install_crate = "cargo-all-features"

View File

@@ -0,0 +1,12 @@
[package]
name = "const_str_slice_concat"
version = "0.1.0"
authors = ["Greg Johnston"]
license = "MIT"
readme = "../README.md"
repository = "https://github.com/leptos-rs/leptos"
description = "Utilities for const concatenation of string slices."
rust-version.workspace = true
edition.workspace = true
[dependencies]

View File

@@ -0,0 +1 @@
extend = { path = "../cargo-make/main.toml" }

View File

@@ -0,0 +1,139 @@
#![no_std]
#![forbid(unsafe_code)]
#![deny(missing_docs)]
//! Utilities for const concatenation of string slices.
pub(crate) const MAX_TEMPLATE_SIZE: usize = 4096;
/// Converts a zero-terminated buffer of bytes into a UTF-8 string.
pub const fn str_from_buffer(buf: &[u8; MAX_TEMPLATE_SIZE]) -> &str {
match core::ffi::CStr::from_bytes_until_nul(buf) {
Ok(cstr) => match cstr.to_str() {
Ok(str) => str,
Err(_) => panic!("TEMPLATE FAILURE"),
},
Err(_) => panic!("TEMPLATE FAILURE"),
}
}
/// Concatenates any number of static strings into a single array.
// credit to Rainer Stropek, "Constant fun," Rust Linz, June 2022
pub const fn const_concat(
strs: &'static [&'static str],
) -> [u8; MAX_TEMPLATE_SIZE] {
let mut buffer = [0; MAX_TEMPLATE_SIZE];
let mut position = 0;
let mut remaining = strs;
while let [current, tail @ ..] = remaining {
let x = current.as_bytes();
let mut i = 0;
// have it iterate over bytes manually, because, again,
// no mutable refernces in const fns
while i < x.len() {
buffer[position] = x[i];
position += 1;
i += 1;
}
remaining = tail;
}
buffer
}
/// Converts a zero-terminated buffer of bytes into a UTF-8 string with the given prefix.
pub const fn const_concat_with_prefix(
strs: &'static [&'static str],
prefix: &'static str,
suffix: &'static str,
) -> [u8; MAX_TEMPLATE_SIZE] {
let mut buffer = [0; MAX_TEMPLATE_SIZE];
let mut position = 0;
let mut remaining = strs;
while let [current, tail @ ..] = remaining {
let x = current.as_bytes();
let mut i = 0;
// have it iterate over bytes manually, because, again,
// no mutable refernces in const fns
while i < x.len() {
buffer[position] = x[i];
position += 1;
i += 1;
}
remaining = tail;
}
if buffer[0] == 0 {
buffer
} else {
let mut new_buf = [0; MAX_TEMPLATE_SIZE];
let prefix = prefix.as_bytes();
let suffix = suffix.as_bytes();
let mut position = 0;
let mut i = 0;
while i < prefix.len() {
new_buf[position] = prefix[i];
position += 1;
i += 1;
}
i = 0;
while i < buffer.len() {
if buffer[i] == 0 {
break;
}
new_buf[position] = buffer[i];
position += 1;
i += 1;
}
i = 0;
while i < suffix.len() {
new_buf[position] = suffix[i];
position += 1;
i += 1;
}
new_buf
}
}
/// Converts any number of strings into a UTF-8 string, separated by the given string.
pub const fn const_concat_with_separator(
strs: &[&str],
separator: &'static str,
) -> [u8; MAX_TEMPLATE_SIZE] {
let mut buffer = [0; MAX_TEMPLATE_SIZE];
let mut position = 0;
let mut remaining = strs;
while let [current, tail @ ..] = remaining {
let x = current.as_bytes();
let mut i = 0;
// have it iterate over bytes manually, because, again,
// no mutable refernces in const fns
while i < x.len() {
buffer[position] = x[i];
position += 1;
i += 1;
}
if !x.is_empty() {
let mut position = 0;
let separator = separator.as_bytes();
while i < separator.len() {
buffer[position] = separator[i];
position += 1;
i += 1;
}
}
remaining = tail;
}
buffer
}

View File

@@ -9,10 +9,10 @@ This document is intended as a running list of common issues, with example code
**Issue**: Sometimes you want to update a reactive signal in a way that depends on another signal.
```rust
let (a, set_a) = create_signal(cx, 0);
let (b, set_b) = create_signal(cx, false);
let (a, set_a) = create_signal(0);
let (b, set_b) = create_signal(false);
create_effect(cx, move |_| {
create_effect(move |_| {
if a() > 5 {
set_b(true);
}
@@ -24,7 +24,7 @@ This creates an inefficient chain of updates, and can easily lead to infinite lo
**Solution**: Follow the rule, _What can be derived, should be derived._ In this case, this has the benefit of massively reducing the code size, too!
```rust
let (a, set_a) = create_signal(cx, 0);
let (a, set_a) = create_signal(0);
let b = move || a () > 5;
```
@@ -34,19 +34,19 @@ Sometimes you have nested signals: for example, hash-map that can change over ti
```rust
#[component]
pub fn App(cx: Scope) -> impl IntoView {
let resources = create_rw_signal(cx, HashMap::new());
pub fn App() -> impl IntoView {
let resources = create_rw_signal(HashMap::new());
let update = move |id: usize| {
resources.update(|resources| {
resources
.entry(id)
.or_insert_with(|| create_rw_signal(cx, 0))
.or_insert_with(|| create_rw_signal(0))
.update(|amount| *amount += 1)
})
};
view! { cx,
view! {
<div>
<pre>{move || format!("{:#?}", resources.get().into_iter().map(|(id, resource)| (id, resource.get())).collect::<Vec<_>>())}</pre>
<button on:click=move |_| update(1)>"+"</button>
@@ -55,17 +55,17 @@ pub fn App(cx: Scope) -> impl IntoView {
}
```
Clicking the button twice will cause a panic, because of the nested signal *read*. Calling the `update` function on `resources` immediately takes out a mutable borrow on `resources`, then updates the `resource` signal—which re-runs the effect that reads from the signals, which tries to immutably access `resources` and panics. It's the nested update here which causes a problem, because the inner update triggers and effect that tries to read both signals while the outer is still updating.
Clicking the button twice will cause a panic, because of the nested signal _read_. Calling the `update` function on `resources` immediately takes out a mutable borrow on `resources`, then updates the `resource` signal—which re-runs the effect that reads from the signals, which tries to immutably access `resources` and panics. It's the nested update here which causes a problem, because the inner update triggers and effect that tries to read both signals while the outer is still updating.
You can fix this fairly easily by using the [`Scope::batch()`](https://docs.rs/leptos/latest/leptos/struct.Scope.html#method.batch) method:
You can fix this fairly easily by using the [`batch()`](https://docs.rs/leptos/latest/leptos/fn.batch.html) method:
```rust
let update = move |id: usize| {
cx.batch(move || {
batch(move || {
resources.update(|resources| {
resources
.entry(id)
.or_insert_with(|| create_rw_signal(cx, 0))
.or_insert_with(|| create_rw_signal(0))
.update(|amount| *amount += 1)
})
});
@@ -83,11 +83,11 @@ Many DOM attributes can be updated either by setting an attribute on the DOM nod
This means that in practice, attributes like `value` or `checked` on an `<input/>` element only update the _default_ value for the `<input/>`. If you want to reactively update the value, you should use `prop:value` instead to set the `value` property.
```rust
let (a, set_a) = create_signal(cx, "Starting value".to_string());
let (a, set_a) = create_signal("Starting value".to_string());
let on_input = move |ev| set_a(event_target_value(&ev));
view! {
cx,
// ❌ reactivity doesn't work as expected: typing only updates the default
// of each input, so if you start typing in the second input, it won't
// update the first one
@@ -97,11 +97,11 @@ view! {
```
```rust
let (a, set_a) = create_signal(cx, "Starting value".to_string());
let (a, set_a) = create_signal("Starting value".to_string());
let on_input = move |ev| set_a(event_target_value(&ev));
view! {
cx,
// ✅ works as intended by setting the value *property*
<input prop:value=a on:input=on_input />
<input prop:value=a on:input=on_input />

View File

@@ -1,14 +1,3 @@
This project contains the core of a new introductory guide to Leptos.
The Leptos book is now available at [https://book.leptos.dev](https://book.leptos.dev).
It is built using `mdbook`. You can view a local copy by installing `mdbook`
```bash
cargo install mdbook
```
and run the book with
```
mdbook serve
```
It should be available at `http://localhost:3000`.
The source code for the book has moved to [https://github.com/leptos-rs/book](https://github.com/leptos-rs/book). Please open issues or make PRs in that repository.

View File

@@ -1,2 +1,10 @@
[output.html]
additional-css = ["./mdbook-admonish.css"]
[output.html.playground]
runnable = false
[preprocessor]
[preprocessor.admonish]
command = "mdbook-admonish"
assets_version = "3.0.1" # do not edit: managed by `mdbook-admonish install`

View File

@@ -0,0 +1,345 @@
@charset "UTF-8";
:root {
--md-admonition-icon--admonish-note: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75L3 17.25z'/></svg>");
--md-admonition-icon--admonish-abstract: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17 9H7V7h10m0 6H7v-2h10m-3 6H7v-2h7M12 3a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1m7 0h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2z'/></svg>");
--md-admonition-icon--admonish-info: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 9h-2V7h2m0 10h-2v-6h2m-1-9A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10A10 10 0 0 0 12 2z'/></svg>");
--md-admonition-icon--admonish-tip: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17.66 11.2c-.23-.3-.51-.56-.77-.82-.67-.6-1.43-1.03-2.07-1.66C13.33 7.26 13 4.85 13.95 3c-.95.23-1.78.75-2.49 1.32-2.59 2.08-3.61 5.75-2.39 8.9.04.1.08.2.08.33 0 .22-.15.42-.35.5-.23.1-.47.04-.66-.12a.58.58 0 0 1-.14-.17c-1.13-1.43-1.31-3.48-.55-5.12C5.78 10 4.87 12.3 5 14.47c.06.5.12 1 .29 1.5.14.6.41 1.2.71 1.73 1.08 1.73 2.95 2.97 4.96 3.22 2.14.27 4.43-.12 6.07-1.6 1.83-1.66 2.47-4.32 1.53-6.6l-.13-.26c-.21-.46-.77-1.26-.77-1.26m-3.16 6.3c-.28.24-.74.5-1.1.6-1.12.4-2.24-.16-2.9-.82 1.19-.28 1.9-1.16 2.11-2.05.17-.8-.15-1.46-.28-2.23-.12-.74-.1-1.37.17-2.06.19.38.39.76.63 1.06.77 1 1.98 1.44 2.24 2.8.04.14.06.28.06.43.03.82-.33 1.72-.93 2.27z'/></svg>");
--md-admonition-icon--admonish-success: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m9 20.42-6.21-6.21 2.83-2.83L9 14.77l9.88-9.89 2.83 2.83L9 20.42z'/></svg>");
--md-admonition-icon--admonish-question: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m15.07 11.25-.9.92C13.45 12.89 13 13.5 13 15h-2v-.5c0-1.11.45-2.11 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41a2 2 0 0 0-2-2 2 2 0 0 0-2 2H8a4 4 0 0 1 4-4 4 4 0 0 1 4 4 3.2 3.2 0 0 1-.93 2.25M13 19h-2v-2h2M12 2A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10c0-5.53-4.5-10-10-10z'/></svg>");
--md-admonition-icon--admonish-warning: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 14h-2V9h2m0 9h-2v-2h2M1 21h22L12 2 1 21z'/></svg>");
--md-admonition-icon--admonish-failure: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20 6.91 17.09 4 12 9.09 6.91 4 4 6.91 9.09 12 4 17.09 6.91 20 12 14.91 17.09 20 20 17.09 14.91 12 20 6.91z'/></svg>");
--md-admonition-icon--admonish-danger: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M11 15H6l7-14v8h5l-7 14v-8z'/></svg>");
--md-admonition-icon--admonish-bug: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 12h-4v-2h4m0 6h-4v-2h4m6-6h-2.81a5.985 5.985 0 0 0-1.82-1.96L17 4.41 15.59 3l-2.17 2.17a6.002 6.002 0 0 0-2.83 0L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8z'/></svg>");
--md-admonition-icon--admonish-example: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M7 13v-2h14v2H7m0 6v-2h14v2H7M7 7V5h14v2H7M3 8V5H2V4h2v4H3m-1 9v-1h3v4H2v-1h2v-.5H3v-1h1V17H2m2.25-7a.75.75 0 0 1 .75.75c0 .2-.08.39-.21.52L3.12 13H5v1H2v-.92L4 11H2v-1h2.25z'/></svg>");
--md-admonition-icon--admonish-quote: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 17h3l2-4V7h-6v6h3M6 17h3l2-4V7H5v6h3l-2 4z'/></svg>");
--md-details-icon: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M8.59 16.58 13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.42Z'/></svg>");
}
:is(.admonition) {
display: flow-root;
margin: 1.5625em 0;
padding: 0 1.2rem;
color: var(--fg);
page-break-inside: avoid;
background-color: var(--bg);
border: 0 solid black;
border-inline-start-width: 0.4rem;
border-radius: 0.2rem;
box-shadow: 0 0.2rem 1rem rgba(0, 0, 0, 0.05), 0 0 0.1rem rgba(0, 0, 0, 0.1);
}
@media print {
:is(.admonition) {
box-shadow: none;
}
}
:is(.admonition) > * {
box-sizing: border-box;
}
:is(.admonition) :is(.admonition) {
margin-top: 1em;
margin-bottom: 1em;
}
:is(.admonition) > .tabbed-set:only-child {
margin-top: 0;
}
html :is(.admonition) > :last-child {
margin-bottom: 1.2rem;
}
a.admonition-anchor-link {
display: none;
position: absolute;
left: -1.2rem;
padding-right: 1rem;
}
a.admonition-anchor-link:link, a.admonition-anchor-link:visited {
color: var(--fg);
}
a.admonition-anchor-link:link:hover, a.admonition-anchor-link:visited:hover {
text-decoration: none;
}
a.admonition-anchor-link::before {
content: "§";
}
:is(.admonition-title, summary.admonition-title) {
position: relative;
min-height: 4rem;
margin-block: 0;
margin-inline: -1.6rem -1.2rem;
padding-block: 0.8rem;
padding-inline: 4.4rem 1.2rem;
font-weight: 700;
background-color: rgba(68, 138, 255, 0.1);
print-color-adjust: exact;
-webkit-print-color-adjust: exact;
display: flex;
}
:is(.admonition-title, summary.admonition-title) p {
margin: 0;
}
html :is(.admonition-title, summary.admonition-title):last-child {
margin-bottom: 0;
}
:is(.admonition-title, summary.admonition-title)::before {
position: absolute;
top: 0.625em;
inset-inline-start: 1.6rem;
width: 2rem;
height: 2rem;
background-color: #448aff;
print-color-adjust: exact;
-webkit-print-color-adjust: exact;
mask-image: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"></svg>');
-webkit-mask-image: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"></svg>');
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-size: contain;
content: "";
}
:is(.admonition-title, summary.admonition-title):hover a.admonition-anchor-link {
display: initial;
}
details.admonition > summary.admonition-title::after {
position: absolute;
top: 0.625em;
inset-inline-end: 1.6rem;
height: 2rem;
width: 2rem;
background-color: currentcolor;
mask-image: var(--md-details-icon);
-webkit-mask-image: var(--md-details-icon);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-size: contain;
content: "";
transform: rotate(0deg);
transition: transform 0.25s;
}
details[open].admonition > summary.admonition-title::after {
transform: rotate(90deg);
}
:is(.admonition):is(.admonish-note) {
border-color: #448aff;
}
:is(.admonish-note) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(68, 138, 255, 0.1);
}
:is(.admonish-note) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #448aff;
mask-image: var(--md-admonition-icon--admonish-note);
-webkit-mask-image: var(--md-admonition-icon--admonish-note);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.admonish-abstract, .admonish-summary, .admonish-tldr) {
border-color: #00b0ff;
}
:is(.admonish-abstract, .admonish-summary, .admonish-tldr) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(0, 176, 255, 0.1);
}
:is(.admonish-abstract, .admonish-summary, .admonish-tldr) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #00b0ff;
mask-image: var(--md-admonition-icon--admonish-abstract);
-webkit-mask-image: var(--md-admonition-icon--admonish-abstract);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.admonish-info, .admonish-todo) {
border-color: #00b8d4;
}
:is(.admonish-info, .admonish-todo) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(0, 184, 212, 0.1);
}
:is(.admonish-info, .admonish-todo) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #00b8d4;
mask-image: var(--md-admonition-icon--admonish-info);
-webkit-mask-image: var(--md-admonition-icon--admonish-info);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.admonish-tip, .admonish-hint, .admonish-important) {
border-color: #00bfa5;
}
:is(.admonish-tip, .admonish-hint, .admonish-important) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(0, 191, 165, 0.1);
}
:is(.admonish-tip, .admonish-hint, .admonish-important) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #00bfa5;
mask-image: var(--md-admonition-icon--admonish-tip);
-webkit-mask-image: var(--md-admonition-icon--admonish-tip);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.admonish-success, .admonish-check, .admonish-done) {
border-color: #00c853;
}
:is(.admonish-success, .admonish-check, .admonish-done) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(0, 200, 83, 0.1);
}
:is(.admonish-success, .admonish-check, .admonish-done) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #00c853;
mask-image: var(--md-admonition-icon--admonish-success);
-webkit-mask-image: var(--md-admonition-icon--admonish-success);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.admonish-question, .admonish-help, .admonish-faq) {
border-color: #64dd17;
}
:is(.admonish-question, .admonish-help, .admonish-faq) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(100, 221, 23, 0.1);
}
:is(.admonish-question, .admonish-help, .admonish-faq) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #64dd17;
mask-image: var(--md-admonition-icon--admonish-question);
-webkit-mask-image: var(--md-admonition-icon--admonish-question);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.admonish-warning, .admonish-caution, .admonish-attention) {
border-color: #ff9100;
}
:is(.admonish-warning, .admonish-caution, .admonish-attention) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(255, 145, 0, 0.1);
}
:is(.admonish-warning, .admonish-caution, .admonish-attention) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #ff9100;
mask-image: var(--md-admonition-icon--admonish-warning);
-webkit-mask-image: var(--md-admonition-icon--admonish-warning);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.admonish-failure, .admonish-fail, .admonish-missing) {
border-color: #ff5252;
}
:is(.admonish-failure, .admonish-fail, .admonish-missing) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(255, 82, 82, 0.1);
}
:is(.admonish-failure, .admonish-fail, .admonish-missing) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #ff5252;
mask-image: var(--md-admonition-icon--admonish-failure);
-webkit-mask-image: var(--md-admonition-icon--admonish-failure);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.admonish-danger, .admonish-error) {
border-color: #ff1744;
}
:is(.admonish-danger, .admonish-error) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(255, 23, 68, 0.1);
}
:is(.admonish-danger, .admonish-error) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #ff1744;
mask-image: var(--md-admonition-icon--admonish-danger);
-webkit-mask-image: var(--md-admonition-icon--admonish-danger);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.admonish-bug) {
border-color: #f50057;
}
:is(.admonish-bug) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(245, 0, 87, 0.1);
}
:is(.admonish-bug) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #f50057;
mask-image: var(--md-admonition-icon--admonish-bug);
-webkit-mask-image: var(--md-admonition-icon--admonish-bug);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.admonish-example) {
border-color: #7c4dff;
}
:is(.admonish-example) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(124, 77, 255, 0.1);
}
:is(.admonish-example) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #7c4dff;
mask-image: var(--md-admonition-icon--admonish-example);
-webkit-mask-image: var(--md-admonition-icon--admonish-example);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.admonish-quote, .admonish-cite) {
border-color: #9e9e9e;
}
:is(.admonish-quote, .admonish-cite) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(158, 158, 158, 0.1);
}
:is(.admonish-quote, .admonish-cite) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #9e9e9e;
mask-image: var(--md-admonition-icon--admonish-quote);
-webkit-mask-image: var(--md-admonition-icon--admonish-quote);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
.navy :is(.admonition) {
background-color: var(--sidebar-bg);
}
.ayu :is(.admonition),
.coal :is(.admonition) {
background-color: var(--theme-hover);
}
.rust :is(.admonition) {
background-color: var(--sidebar-bg);
color: var(--sidebar-fg);
}
.rust .admonition-anchor-link:link, .rust .admonition-anchor-link:visited {
color: var(--sidebar-fg);
}

View File

@@ -1,20 +1,2 @@
# Introduction
This book is intended as an introduction to the [Leptos](https://github.com/leptos-rs/leptos) Web framework.
It will walk through the fundamental concepts you need to build applications,
beginning with a simple application rendered in the browser, and building toward a
full-stack application with server-side rendering and hydration.
The guide doesnt assume you know anything about fine-grained reactivity or the
details of modern Web frameworks. It does assume you are familiar with the Rust
programming language, HTML, CSS, and the DOM and basic Web APIs.
Leptos is most similar to frameworks like [Solid](https://www.solidjs.com) (JavaScript)
and [Sycamore](https://sycamore-rs.netlify.app/) (Rust). There are some similarities
to other frameworks like React (JavaScript), Svelte (JavaScript), Yew (Rust), and
Dioxus (Rust), so knowledge of one of those frameworks may also make it easier to
understand Leptos.
You can find more detailed docs for each part of the API at [Docs.rs](https://docs.rs/leptos/latest/leptos/).
**The guide is a work in progress.**
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/">
<link rel="canonical" href="https://book.leptos.dev/">

View File

@@ -1,84 +0,0 @@
# Getting Started
There are two basic paths to getting started with Leptos:
1. Client-side rendering with [Trunk](https://trunkrs.dev/)
2. Full-stack rendering with [`cargo-leptos`](https://github.com/leptos-rs/cargo-leptos)
For the early examples, it will be easiest to begin with Trunk. Well introduce
`cargo-leptos` a little later in this series.
If you dont already have it installed, you can install Trunk by running
```bash
cargo install trunk
```
Create a basic Rust project
```bash
cargo init leptos-tutorial
```
`cd` into your new `leptos-tutorial` project and add `leptos` as a dependency
```bash
cargo add leptos --features=csr,nightly
```
Or you can leave off `nighly` if you're using stable Rust
```bash
cargo add leptos --features=csr
```
> Using `nightly` Rust, and the `nightly` feature in Leptos enables the function-call syntax for signal getters and setters that is used in most of this book.
>
> To use `nightly` Rust, you can run
>
> ```bash
> rustup toolchain install nightly
> rustup default nightly
> ```
>
> If youd rather use stable Rust with Leptos, you can do that too. In the guide and examples, youll just use the [`ReadSignal::get()`](https://docs.rs/leptos/latest/leptos/struct.ReadSignal.html#impl-SignalGet%3CT%3E-for-ReadSignal%3CT%3E) and [`WriteSignal::set()`](https://docs.rs/leptos/latest/leptos/struct.WriteSignal.html#impl-SignalGet%3CT%3E-for-ReadSignal%3CT%3E) methods instead of calling signal getters and setters as functions.
Make sure you've added the `wasm32-unknown-unknown` target so that Rust can compile your code to WebAssembly to run in the browser.
```bash
rustup target add wasm32-unknown-unknown
```
Create a simple `index.html` in the root of the `leptos-tutorial` directory
```html
<!DOCTYPE html>
<html>
<head></head>
<body></body>
</html>
```
And add a simple “Hello, world!” to your `main.rs`
```rust
use leptos::*;
fn main() {
mount_to_body(|cx| view! { cx, <p>"Hello, world!"</p> })
}
```
Your directory structure should now look something like this
```
leptos_tutorial
├── src
│ └── main.rs
├── Cargo.toml
├── index.html
```
Now run `trunk serve --open` from the root of the `leptos-tutorial` directory.
Trunk should automatically compile your app and open it in your default browser.
If you make edits to `main.rs`, Trunk will recompile your source code and
live-reload the page.

View File

@@ -1,185 +1,2 @@
# Global State Management
So far, we've only been working with local state in components, and weve seen how to coordinate state between parent and child components. On occasion, there are times where people look for a more general solution for global state management that can work throughout an application.
In general, **you do not need this chapter.** The typical pattern is to compose your application out of components, each of which manages its own local state, not to store all state in a global structure. However, there are some cases (like theming, saving user settings, or sharing data between components in different parts of your UI) in which you may want to use some kind of global state management.
The three best approaches to global state are
1. Using the router to drive global state via the URL
2. Passing signals through context
3. Creating a global state struct and creating lenses into it with `create_slice`
## Option #1: URL as Global State
In many ways, the URL is actually the best way to store global state. It can be accessed from any component, anywhere in your tree. There are native HTML elements like `<form>` and `<a>` that exist solely to update the URL. And it persists across page reloads and between devices; you can share a URL with a friend or send it from your phone to your laptop and any state stored in it will be replicated.
The next few sections of the tutorial will be about the router, and well get much more into these topics.
But for now, we'll just look at options #2 and #3.
## Option #2: Passing Signals through Context
In the section on [parent-child communication](view/08_parent_child.md), we saw that you can use `provide_context` to pass signal from a parent component to a child, and `use_context` to read it in the child. But `provide_context` works across any distance. If you want to create a global signal that holds some piece of state, you can provide it and access it via context anywhere in the descendants of the component where you provide it.
A signal provided via context only causes reactive updates where it is read, not in any of the components in between, so it maintains the power of fine-grained reactive updates, even at a distance.
We start by creating a signal in the root of the app and providing it to
all its children and descendants using `provide_context`.
```rust
#[component]
fn App(cx: Scope) -> impl IntoView {
// here we create a signal in the root that can be consumed
// anywhere in the app.
let (count, set_count) = create_signal(cx, 0);
// we'll pass the setter to specific components,
// but provide the count itself to the whole app via context
provide_context(cx, count);
view! { cx,
// SetterButton is allowed to modify the count
<SetterButton set_count/>
// These consumers can only read from it
// But we could give them write access by passing `set_count` if we wanted
<FancyMath/>
<ListItems/>
}
}
```
`<SetterButton/>` is the kind of counter weve written several times now.
(See the sandbox below if you dont understand what I mean.)
`<FancyMath/>` and `<ListItems/>` both consume the signal were providing via
`use_context` and do something with it.
```rust
/// A component that does some "fancy" math with the global count
#[component]
fn FancyMath(cx: Scope) -> impl IntoView {
// here we consume the global count signal with `use_context`
let count = use_context::<ReadSignal<u32>>(cx)
// we know we just provided this in the parent component
.expect("there to be a `count` signal provided");
let is_even = move || count() & 1 == 0;
view! { cx,
<div class="consumer blue">
"The number "
<strong>{count}</strong>
{move || if is_even() {
" is"
} else {
" is not"
}}
" even."
</div>
}
}
```
Note that this same pattern can be applied to more complex state. If you have multiple fields you want to update independently, you can do that by providing some struct of signals:
```rust
#[derive(Copy, Clone, Debug)]
struct GlobalState {
count: RwSignal<i32>,
name: RwSignal<String>
}
impl GlobalState {
pub fn new(cx: Scope) -> Self {
Self {
count: create_rw_signal(cx, 0),
name: create_rw_signal(cx, "Bob".to_string())
}
}
}
#[component]
fn App(cx: Scope) -> impl IntoView {
provide_context(cx, GlobalState::new(cx));
// etc.
}
```
## Option #3: Create a Global State Struct and Slices
You may find it cumbersome to wrap each field of a structure in a separate signal like this. In some cases, it can be useful to create a plain struct with non-reactive fields, and then wrap that in a signal.
```rust
#[derive(Copy, Clone, Debug, Default)]
struct GlobalState {
count: i32,
name: String
}
#[component]
fn App(cx: Scope) -> impl IntoView {
provide_context(cx, create_rw_signal(GlobalState::default()));
// etc.
}
```
But theres a problem: because our whole state is wrapped in one signal, updating the value of one field will cause reactive updates in parts of the UI that only depend on the other.
```rust
let state = expect_context::<RwSignal<GlobalState>>(cx);
view! { cx,
<button on:click=move |_| state.update(|n| *n += 1)>"+1"</button>
<p>{move || state.with(|state| state.name.clone())}</p>
}
```
In this example, clicking the button will cause the text inside `<p>` to be updated, cloning `state.name` again! Because signals are the atomic unit of reactivity, updating any field of the signal triggers updates to everything that depends on the signal.
Theres a better way. You can use take fine-grained, reactive slices by using [`create_memo`](https://docs.rs/leptos/latest/leptos/fn.create_memo.html) or [`create_slice`](https://docs.rs/leptos/latest/leptos/fn.create_slice.html) (which uses `create_memo` but also provides a setter). “Memoizing” a value means creating a new reactive value which will only update when it changes. “Memoizing a slice” means creating a new reactive value which will only update when some field of the state struct updates.
Here, instead of reading from the state signal directly, we create “slices” of that state with fine-grained updates via `create_slice`. Each slice signal only updates when the particular piece of the larger struct it accesses updates. This means you can create a single root signal, and then take independent, fine-grained slices of it in different components, each of which can update without notifying the others of changes.
```rust
/// A component that updates the count in the global state.
#[component]
fn GlobalStateCounter(cx: Scope) -> impl IntoView {
let state = expect_context::<RwSignal<GlobalState>>(cx);
// `create_slice` lets us create a "lens" into the data
let (count, set_count) = create_slice(
cx,
// we take a slice *from* `state`
state,
// our getter returns a "slice" of the data
|state| state.count,
// our setter describes how to mutate that slice, given a new value
|state, n| state.count = n,
);
view! { cx,
<div class="consumer blue">
<button
on:click=move |_| {
set_count(count() + 1);
}
>
"Increment Global Count"
</button>
<br/>
<span>"Count is: " {count}</span>
</div>
}
}
```
Clicking this button only updates `state.count`, so if we create another slice
somewhere else that only takes `state.name`, clicking the button wont cause
that other slice to update. This allows you to combine the benefits of a top-down
data flow and of fine-grained reactive updates.
> **Note**: There are some significant drawbacks to this approach. Both signals and memos need to own their values, so a memo will need to clone the fields value on every change. The most natural way to manage state in a framework like Leptos is always to provide signals that are as locally-scoped and fine-grained as they can be, not to hoist everything up into global state. But when you _do_ need some kind of global state, `create_slice` can be a useful tool.
[Click to open CodeSandbox.](https://codesandbox.io/p/sandbox/1-basic-component-forked-8bte19?selection=%5B%7B%22endColumn%22%3A1%2C%22endLineNumber%22%3A2%2C%22startColumn%22%3A1%2C%22startLineNumber%22%3A2%7D%5D&file=%2Fsrc%2Fmain.rs)
<iframe src="https://codesandbox.io/p/sandbox/1-basic-component-forked-8bte19?selection=%5B%7B%22endColumn%22%3A1%2C%22endLineNumber%22%3A2%2C%22startColumn%22%3A1%2C%22startLineNumber%22%3A2%7D%5D&file=%2Fsrc%2Fmain.rs" width="100%" height="1000px" style="max-height: 100vh"></iframe>
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/15_global_state.html">
<link rel="canonical" href="https://book.leptos.dev/15_global_state.html">

View File

@@ -1,17 +1,21 @@
# Summary
- [Introduction](./01_introduction.md)
- [Getting Started](./02_getting_started.md)
- [Building User Interfaces](./view/README.md)
- [Getting Started](./getting_started/README.md)
- [Leptos DX](./getting_started/leptos_dx.md)
- [The Leptos Community and leptos-* Crates](./getting_started/community_crates.md)
- [Part 1: Building User Interfaces](./view/README.md)
- [A Basic Component](./view/01_basic_component.md)
- [Dynamic Attributes](./view/02_dynamic_attributes.md)
- [Components and Props](./view/03_components.md)
- [Iteration](./view/04_iteration.md)
- [Iterating over More Complex Data](./view/04b_iteration.md)
- [Forms and Inputs](./view/05_forms.md)
- [Control Flow](./view/06_control_flow.md)
- [Error Handling](./view/07_errors.md)
- [Parent-Child Communication](./view/08_parent_child.md)
- [Passing Children to Components](./view/09_component_children.md)
- [No Macros: The View Builder Syntax](./view/builder.md)
- [Reactivity](./reactivity/README.md)
- [Working with Signals](./reactivity/working_with_signals.md)
- [Responding to Changes with `create_effect`](./reactivity/14_create_effect.md)
@@ -32,7 +36,8 @@
- [`<Form/>`](./router/20_form.md)
- [Interlude: Styling](./interlude_styling.md)
- [Metadata](./metadata.md)
- [Server Side Rendering](./ssr/README.md)
- [Client-Side Rendering: Wrapping Up](./csr_wrapping_up.md)
- [Part 2: Server Side Rendering](./ssr/README.md)
- [`cargo-leptos`](./ssr/21_cargo_leptos.md)
- [The Life of a Page Load](./ssr/22_life_cycle.md)
- [Async Rendering and SSR “Modes”](./ssr/23_ssr_modes.md)
@@ -43,5 +48,9 @@
- [Responses and Redirects](./server/27_response.md)
- [Progressive Enhancement and Graceful Degradation](./progressive_enhancement/README.md)
- [`<ActionForm/>`s](./progressive_enhancement/action_form.md)
- [Deployment]()
- [Appendix: Optimizing WASM Binary Size](./appendix_binary_size.md)
- [Deployment](./deployment/README.md)
- [Optimizing WASM Binary Size](./deployment/binary_size.md)
- [Guide: Islands](./islands.md)
- [Appendix: How Does the Reactive System Work?](./appendix_reactive_graph.md)

View File

@@ -1,72 +0,0 @@
# Appendix: Optimizing WASM Binary Size
One of the primary downsides of deploying a Rust/WebAssembly frontend app is that splitting a WASM file into smaller chunks to be dynamically loaded is significantly more difficult than splitting a JavaScript bundle. There have been experiments like [`wasm-split`](https://emscripten.org/docs/optimizing/Module-Splitting.html) in the Emscripten ecosystem but at present theres no way to split and dynamically load a Rust/`wasm-bindgen` binary. This means that the whole WASM binary needs to be loaded before your app becomes interactive. Because the WASM format is designed for streaming compilation, WASM files are much faster to compile per kilobyte than JavaScript files. (For a deeper look, you can [read this great article from the Mozilla team](https://hacks.mozilla.org/2018/01/making-webassembly-even-faster-firefoxs-new-streaming-and-tiering-compiler/) on streaming WASM compilation.)
Still, its important to ship the smallest WASM binary to users that you can, as it will reduce their network usage and make your app interactive as quickly as possible.
So what are some practical steps?
## Things to Do
1. Make sure youre looking at a release build. (Debug builds are much, much larger.)
2. Add a release profile for WASM that optimizes for size, not speed.
For a `cargo-leptos` project, for example, you can add this to your `Cargo.toml`:
```toml
[profile.wasm-release]
inherits = "release"
opt-level = 'z'
lto = true
codegen-units = 1
# ....
[package.metadata.leptos]
# ....
lib-profile-release = "wasm-release"
```
This will hyper-optimize the WASM for your release build for size, while keeping your server build optimized for speed. (For a pure client-rendered app without server considerations, just use the `[profile.wasm-release]` block as your `[profile.release]`.)
3. Always serve compressed WASM in production. WASM tends to compress very well, typically shrinking to less than 50% its uncompressed size, and its trivial to enable compression for static files being served from Actix or Axum.
4. If youre using nightly Rust, you can rebuild the standard library with this same profile rather than the prebuilt standard library thats distributed with the `wasm32-unknown-unknown` target.
To do this, create a file in your project at `.cargo/config.toml`
```toml
[unstable]
build-std = ["std", "panic_abort", "core", "alloc"]
build-std-features = ["panic_immediate_abort"]
```
Note that if you're using this with SSR too, the same Cargo profile will be applied. You'll need to explicitly specify your target:
```toml
[build]
target = "x86_64-unknown-linux-gnu" # or whatever
```
Also note that in some cases, the cfg feature `has_std` will not be set, which may cause build errors with some dependencies which check for `has_std`. You may fix any build errors due to this by adding:
```toml
[build]
rustflags = ["--cfg=has_std"]
```
And you'll need to add `panic = "abort"` to `[profile.release]` in `Cargo.toml`. Note that this applies the same `build-std` and panic settings to your server binary, which may not be desirable. Some further exploration is probably needed here.
5. One of the sources of binary size in WASM binaries can be `serde` serialization/deserialization code. Leptos uses `serde` by default to serialize and deserialize resources created with `create_resource`. You might try experimenting with the `miniserde` and `serde-lite` features, which allow you to use those crates for serialization and deserialization instead; each only implements a subset of `serde`s functionality, but typically optimizes for size over speed.
## Things to Avoid
There are certain crates that tend to inflate binary sizes. For example, the `regex` crate with its default features adds about 500kb to a WASM binary (largely because it has to pull in Unicode table data!) In a size-conscious setting, you might consider avoiding regexes in general, or even dropping down and calling browser APIs to use the built-in regex engine instead. (This is what `leptos_router` does on the few occasions it needs a regular expression.)
In general, Rusts commitment to runtime performance is sometimes at odds with a commitment to a small binary. For example, Rust monomorphizes generic functions, meaning it creates a distinct copy of the function for each generic type its called with. This is significantly faster than dynamic dispatch, but increases binary size. Leptos tries to balance runtime performance with binary size considerations pretty carefully; but you might find that writing code that uses many generics tends to increase binary size. For example, if you have a generic component with a lot of code in its body and call it with four different types, remember that the compiler could include four copies of that same code. Refactoring to use a concrete inner function or helper can often maintain performance and ergonomics while reducing binary size.
## A Final Thought
Remember that in a server-rendered app, JS bundle size/WASM binary size affects only _one_ thing: time to interactivity on the first load. This is very important to a good user experience—nobody wants to click a button three times and have it do nothing because the interactive code is still loading—but it is not the only important measure.
Its especially worth remembering that streaming in a single WASM binary means all subsequent navigations are nearly instantaneous, depending only on any additional data loading. Precisely because your WASM binary is _not_ bundle split, navigating to a new route does not require loading additional JS/WASM, as it does in nearly every JavaScript framework. Is this copium? Maybe. Or maybe its just an honest trade-off between the two approaches!
Always take the opportunity to optimize the low-hanging fruit in your application. And always test your app under real circumstances with real user network speeds and devices before making any heroic efforts.

View File

@@ -0,0 +1,2 @@
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/appendix_reactive_graph.html">
<link rel="canonical" href="https://book.leptos.dev/appendix_reactive_graph.html">

View File

@@ -1,55 +1,2 @@
# Loading Data with Resources
A [Resource](https://docs.rs/leptos/latest/leptos/struct.Resource.html) is a reactive data structure that reflects the current state of an asynchronous task, allowing you to integrate asynchronous `Future`s into the synchronous reactive system. Rather than waiting for its data to load with `.await`, you transform the `Future` into a signal that returns `Some(T)` if it has resolved, and `None` if its still pending.
You do this by using the [`create_resource`](https://docs.rs/leptos/latest/leptos/fn.create_resource.html) function. This takes two arguments (other than the ubiquitous `cx`):
1. a source signal, which will generate a new `Future` whenever it changes
2. a fetcher function, which takes the data from that signal and returns a `Future`
Heres an example
```rust
// our source signal: some synchronous, local state
let (count, set_count) = create_signal(cx, 0);
// our resource
let async_data = create_resource(cx,
count,
// every time `count` changes, this will run
|value| async move {
log!("loading data from API");
load_data(value).await
},
);
```
To create a resource that simply runs once, you can pass a non-reactive, empty source signal:
```rust
let once = create_resource(cx, || (), |_| async move { load_data().await });
```
To access the value you can use `.read(cx)` or `.with(cx, |data| /* */)`. These work just like `.get()` and `.with()` on a signal—`read` clones the value and returns it, `with` applies a closure to it—but with two differences
1. For any `Resource<_, T>`, they always return `Option<T>`, not `T`: because its always possible that your resource is still loading.
2. They take a `Scope` argument. Youll see why in the next chapter, on `<Suspense/>`.
So, you can show the current state of a resource in your view:
```rust
let once = create_resource(cx, || (), |_| async move { load_data().await });
view! { cx,
<h1>"My Data"</h1>
{move || match once.read(cx) {
None => view! { cx, <p>"Loading..."</p> }.into_view(cx),
Some(data) => view! { cx, <ShowData data/> }.into_view(cx)
}}
}
```
Resources also provide a `refetch()` method that allows you to manually reload the data (for example, in response to a button click) and a `loading()` method that returns a `ReadSignal<bool>` indicating whether the resource is currently loading or not.
[Click to open CodeSandbox.](https://codesandbox.io/p/sandbox/10-async-resources-4z0qt3?file=%2Fsrc%2Fmain.rs&selection=%5B%7B%22endColumn%22%3A1%2C%22endLineNumber%22%3A3%2C%22startColumn%22%3A1%2C%22startLineNumber%22%3A3%7D%5D)
<iframe src="https://codesandbox.io/p/sandbox/10-async-resources-4z0qt3?file=%2Fsrc%2Fmain.rs&selection=%5B%7B%22endColumn%22%3A1%2C%22endLineNumber%22%3A3%2C%22startColumn%22%3A1%2C%22startLineNumber%22%3A3%7D%5D" width="100%" height="1000px" style="max-height: 100vh"></iframe>
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/async/10_resources.html">
<link rel="canonical" href="https://book.leptos.dev/async/10_resources.html">

View File

@@ -1,74 +1,2 @@
# `<Suspense/>`
In the previous chapter, we showed how you can create a simple loading screen to show some fallback while a resource is loading.
```rust
let (count, set_count) = create_signal(cx, 0);
let a = create_resource(cx, count, |count| async move { load_a(count).await });
view! { cx,
<h1>"My Data"</h1>
{move || match once.read(cx) {
None => view! { cx, <p>"Loading..."</p> }.into_view(cx),
Some(data) => view! { cx, <ShowData data/> }.into_view(cx)
}}
}
```
But what if we have two resources, and want to wait for both of them?
```rust
let (count, set_count) = create_signal(cx, 0);
let (count2, set_count2) = create_signal(cx, 0);
let a = create_resource(cx, count, |count| async move { load_a(count).await });
let b = create_resource(cx, count2, |count| async move { load_b(count).await });
view! { cx,
<h1>"My Data"</h1>
{move || match (a.read(cx), b.read(cx)) {
(Some(a), Some(b)) => view! { cx,
<ShowA a/>
<ShowA b/>
}.into_view(cx),
_ => view! { cx, <p>"Loading..."</p> }.into_view(cx)
}}
}
```
Thats not _so_ bad, but its kind of annoying. What if we could invert the flow of control?
The [`<Suspense/>`](https://docs.rs/leptos/latest/leptos/fn.Suspense.html) component lets us do exactly that. You give it a `fallback` prop and children, one or more of which usually involves reading from a resource. Reading from a resource “under” a `<Suspense/>` (i.e., in one of its children) registers that resource with the `<Suspense/>`. If its still waiting for resources to load, it shows the `fallback`. When theyve all loaded, it shows the children.
```rust
let (count, set_count) = create_signal(cx, 0);
let (count2, set_count2) = create_signal(cx, 0);
let a = create_resource(cx, count, |count| async move { load_a(count).await });
let b = create_resource(cx, count2, |count| async move { load_b(count).await });
view! { cx,
<h1>"My Data"</h1>
<Suspense
fallback=move || view! { cx, <p>"Loading..."</p> }
>
<h2>"My Data"</h2>
<h3>"A"</h3>
{move || {
a.read(cx)
.map(|a| view! { cx, <ShowA a/> })
}}
<h3>"B"</h3>
{move || {
b.read(cx)
.map(|b| view! { cx, <ShowB b/> })
}}
</Suspense>
}
```
Every time one of the resources is reloading, the `"Loading..."` fallback will show again.
This inversion of the flow of control makes it easier to add or remove individual resources, as you dont need to handle the matching yourself. It also unlocks some massive performance improvements during server-side rendering, which well talk about during a later chapter.
[Click to open CodeSandbox.](https://codesandbox.io/p/sandbox/11-suspense-907niv?file=%2Fsrc%2Fmain.rs)
<iframe src="https://codesandbox.io/p/sandbox/11-suspense-907niv?file=%2Fsrc%2Fmain.rs" width="100%" height="1000px" style="max-height: 100vh"></iframe>
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/async/11_suspense.html">
<link rel="canonical" href="https://book.leptos.dev/async/11_suspense.html">

View File

@@ -1,11 +1,2 @@
# `<Transition/>`
Youll notice in the `<Suspense/>` example that if you keep reloading the data, it keeps flickering back to `"Loading..."`. Sometimes this is fine. For other times, theres [`<Transition/>`](https://docs.rs/leptos/latest/leptos/fn.Suspense.html).
`<Transition/>` behaves exactly the same as `<Suspense/>`, but instead of falling back every time, it only shows the fallback the first time. On all subsequent loads, it continues showing the old data until the new data are ready. This can be really handy to prevent the flickering effect, and to allow users to continue interacting with your application.
This example shows how you can create a simple tabbed contact list with `<Transition/>`. When you select a new tab, it continues showing the current contact until the new data loads. This can be a much better user experience than constantly falling back to a loading message.
[Click to open CodeSandbox.](https://codesandbox.io/p/sandbox/12-transition-sn38sd?selection=%5B%7B%22endColumn%22%3A15%2C%22endLineNumber%22%3A2%2C%22startColumn%22%3A15%2C%22startLineNumber%22%3A2%7D%5D&file=%2Fsrc%2Fmain.rs)
<iframe src="https://codesandbox.io/p/sandbox/12-transition-sn38sd?selection=%5B%7B%22endColumn%22%3A15%2C%22endLineNumber%22%3A2%2C%22startColumn%22%3A15%2C%22startLineNumber%22%3A2%7D%5D&file=%2Fsrc%2Fmain.rs" width="100%" height="1000px" style="max-height: 100vh"></iframe>
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/async/12_transition.html">
<link rel="canonical" href="https://book.leptos.dev/async/12_transition.html">

View File

@@ -1,96 +1,2 @@
# Mutating Data with Actions
Weve talked about how to load `async` data with resources. Resources immediately load data and work closely with `<Suspense/>` and `<Transition/>` components to show whether data is loading in your app. But what if you just want to call some arbitrary `async` function and keep track of what its doing?
Well, you could always use [`spawn_local`](https://docs.rs/leptos/latest/leptos/fn.spawn_local.html). This allows you to just spawn an `async` task in a synchronous environment by handing the `Future` off to the browser (or, on the server, Tokio or whatever other runtime youre using). But how do you know if its still pending? Well, you could just set a signal to show whether its loading, and another one to show the result...
All of this is true. Or you could use the final `async` primitive: [`create_action`](https://docs.rs/leptos/latest/leptos/fn.create_action.html).
Actions and resources seem similar, but they represent fundamentally different things. If youre trying to load data by running an `async` function, either once or when some other value changes, you probably want to use `create_resource`. If youre trying to occasionally run an `async` function in response to something like a user clicking a button, you probably want to use `create_action`.
Say we have some `async` function we want to run.
```rust
async fn add_todo_request(new_title: &str) -> Uuid {
/* do some stuff on the server to add a new todo */
}
```
`create_action` takes a reactive `Scope` and an `async` function that takes a reference to a single argument, which you could think of as its “input type.”
> The input is always a single type. If you want to pass in multiple arguments, you can do it with a struct or tuple.
>
> ```rust
> // if there's a single argument, just use that
> let action1 = create_action(cx, |input: &String| {
> let input = input.clone();
> async move { todo!() }
> });
>
> // if there are no arguments, use the unit type `()`
> let action2 = create_action(cx, |input: &()| async { todo!() });
>
> // if there are multiple arguments, use a tuple
> let action3 = create_action(cx,
> |input: &(usize, String)| async { todo!() }
> );
> ```
>
> Because the action function takes a reference but the `Future` needs to have a `'static` lifetime, youll usually need to clone the value to pass it into the `Future`. This is admittedly awkward but it unlocks some powerful features like optimistic UI. Well see a little more about that in future chapters.
So in this case, all we need to do to create an action is
```rust
let add_todo_action = create_action(cx, |input: &String| {
let input = input.to_owned();
async move { add_todo_request(&input).await }
});
```
Rather than calling `add_todo_action` directly, well call it with `.dispatch()`, as in
```rust
add_todo_action.dispatch("Some value".to_string());
```
You can do this from an event listener, a timeout, or anywhere; because `.dispatch()` isnt an `async` function, it can be called from a synchronous context.
Actions provide access to a few signals that synchronize between the asynchronous action youre calling and the synchronous reactive system:
```rust
let submitted = add_todo_action.input(); // RwSignal<Option<String>>
let pending = add_todo_action.pending(); // ReadSignal<bool>
let todo_id = add_todo_action.value(); // RwSignal<Option<Uuid>>
```
This makes it easy to track the current state of your request, show a loading indicator, or do “optimistic UI” based on the assumption that the submission will succeed.
```rust
let input_ref = create_node_ref::<Input>(cx);
view! { cx,
<form
on:submit=move |ev| {
ev.prevent_default(); // don't reload the page...
let input = input_ref.get().expect("input to exist");
add_todo_action.dispatch(input.value());
}
>
<label>
"What do you need to do?"
<input type="text"
node_ref=input_ref
/>
</label>
<button type="submit">"Add Todo"</button>
</form>
// use our loading state
<p>{move || pending().then("Loading...")}</p>
}
```
Now, theres a chance this all seems a little over-complicated, or maybe too restricted. I wanted to include actions here, alongside resources, as the missing piece of the puzzle. In a real Leptos app, youll actually most often use actions alongside server functions, [`create_server_action`](https://docs.rs/leptos/latest/leptos/fn.create_server_action.html), and the [`<ActionForm/>`](https://docs.rs/leptos_router/latest/leptos_router/fn.ActionForm.html) component to create really powerful progressively-enhanced forms. So if this primitive seems useless to you... Dont worry! Maybe it will make sense later. (Or check out our [`todo_app_sqlite`](https://github.com/leptos-rs/leptos/blob/main/examples/todo_app_sqlite/src/todo.rs) example now.)
[Click to open CodeSandbox.](https://codesandbox.io/p/sandbox/10-async-resources-forked-hgpfp0?selection=%5B%7B%22endColumn%22%3A1%2C%22endLineNumber%22%3A4%2C%22startColumn%22%3A1%2C%22startLineNumber%22%3A4%7D%5D&file=%2Fsrc%2Fmain.rs)
<iframe src="https://codesandbox.io/p/sandbox/10-async-resources-forked-hgpfp0?selection=%5B%7B%22endColumn%22%3A1%2C%22endLineNumber%22%3A4%2C%22startColumn%22%3A1%2C%22startLineNumber%22%3A4%7D%5D&file=%2Fsrc%2Fmain.rs" width="100%" height="1000px" style="max-height: 100vh"></iframe>
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/async/13_action.html">
<link rel="canonical" href="https://book.leptos.dev/async/13_action.html">

View File

@@ -1,9 +1,2 @@
# Working with `async`
So far weve only been working with synchronous users interfaces: You provide some input,
the app immediately processes it and updates the interface. This is great, but is a tiny
subset of what web applications do. In particular, most web apps have to deal with some kind of asynchronous data loading, usually loading something from an API.
Asynchronous data is notoriously hard to integrate with the synchronous parts of your code. Leptos provides a cross-platform [`spawn_local`](https://docs.rs/leptos/latest/leptos/fn.spawn_local.html) function that makes it easy to run a `Future`, but theres much more to it than that.
In this chapter, well see how Leptos helps smooth out that process for you.
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/async/index.html">
<link rel="canonical" href="https://book.leptos.dev/async/index.html">

View File

@@ -0,0 +1,2 @@
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/csr_wrapping_up.html">
<link rel="canonical" href="https://book.leptos.dev/csr_wrapping_up.html">

View File

@@ -0,0 +1,2 @@
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/deployment/index.html">
<link rel="canonical" href="https://book.leptos.dev/deployment/index.html">

View File

@@ -0,0 +1,2 @@
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/deployment/binary_size.html">
<link rel="canonical" href="https://book.leptos.dev/deployment/binary_size.html">

View File

@@ -0,0 +1,2 @@
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/getting_started/index.html">
<link rel="canonical" href="https://book.leptos.dev/getting_started/index.html">

View File

@@ -0,0 +1,2 @@
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/getting_started/community_crates.html">
<link rel="canonical" href="https://book.leptos.dev/getting_started/community_crates.html">

View File

@@ -0,0 +1,2 @@
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/getting_started/leptos_dx.html">
<link rel="canonical" href="https://book.leptos.dev/getting_started/leptos_dx.html">

View File

@@ -1,177 +1,2 @@
# Projecting Children
As you build components you may occasionally find yourself wanting to “project” children through multiple layers of components.
## The Problem
Consider the following:
```rust
pub fn LoggedIn<F, IV>(cx: Scope, fallback: F, children: ChildrenFn) -> impl IntoView
where
F: Fn(Scope) -> IV + 'static,
IV: IntoView,
{
view! { cx,
<Suspense
fallback=|| ()
>
<Show
// check whether user is verified
// by reading from the resource
when=move || todo!()
fallback=fallback
>
{children(cx)}
</Show>
</Suspense>
}
}
```
This is pretty straightforward: when the user is logged in, we want to show `children`. If the user is not logged in, we want to show `fallback`. And while were waiting to find out, we just render `()`, i.e., nothing.
In other words, we want to pass the children of `<LoggedIn/>` _through_ the `<Suspense/>` component to become the children of the `<Show/>`. This is what I mean by “projection.”
This wont compile.
```
error[E0507]: cannot move out of `fallback`, a captured variable in an `Fn` closure
error[E0507]: cannot move out of `children`, a captured variable in an `Fn` closure
```
The problem here is that both `<Suspense/>` and `<Show/>` need to be able to construct their `children` multiple times. The first time you construct `<Suspense/>`s children, it would take ownership of `fallback` and `children` to move them into the invocation of `<Show/>`, but then they're not available for future `<Suspense/>` children construction.
## The Details
> Feel free to skip ahead to the solution.
If you want to really understand the issue here, it may help to look at the expanded `view` macro. Heres a cleaned-up version:
```rust
Suspense(
cx,
::leptos::component_props_builder(&Suspense)
.fallback(|| ())
.children({
// fallback and children are moved into this closure
Box::new(move |cx| {
{
// fallback and children captured here
leptos::Fragment::lazy(|| {
vec![
(Show(
cx,
::leptos::component_props_builder(&Show)
.when(|| true)
// but fallback is moved into Show here
.fallback(fallback)
// and children is moved into Show here
.children(children)
.build(),
)
.into_view(cx)),
]
})
}
})
})
.build(),
)
```
All components own their props; so the `<Show/>` in this case cant be called because it only has captured references to `fallback` and `children`.
## Solution
However, both `<Suspense/>` and `<Show/>` take `ChildrenFn`, i.e., their `children` should implement the `Fn` type so they can be called multiple times with only an immutable reference. This means we dont need to own `children` or `fallback`; we just need to be able to pass `'static` references to them.
We can solve this problem by using the [`store_value`](https://docs.rs/leptos/latest/leptos/fn.store_value.html) primitive. This essentially stores a value in the reactive system, handing ownership off to the framework in exchange for a reference that is, like signals, `Copy` and `'static`, which we can access or modify through certain methods.
In this case, its really simple:
```rust
pub fn LoggedIn<F, IV>(cx: Scope, fallback: F, children: ChildrenFn) -> impl IntoView
where
F: Fn(Scope) -> IV + 'static,
IV: IntoView,
{
let fallback = store_value(cx, fallback);
let children = store_value(cx, children);
view! { cx,
<Suspense
fallback=|| ()
>
<Show
when=|| todo!()
fallback=move |cx| fallback.with_value(|fallback| fallback(cx))
>
{children.with_value(|children| children(cx))}
</Show>
</Suspense>
}
}
```
At the top level, we store both `fallback` and `children` in the reactive scope owned by `LoggedIn`. Now we can simply move those references down through the other layers into the `<Show/>` component and call them there.
## A Final Note
Note that this works because `<Show/>` and `<Suspense/>` only need an immutable reference to their children (which `.with_value` can give it), not ownership.
In other cases, you may need to project owned props through a function that takes `ChildrenFn` and therefore needs to be called more than once. In this case, you may find the `clone:` helper in the`view` macro helpful.
Consider this example
```rust
#[component]
pub fn App(cx: Scope) -> impl IntoView {
let name = "Alice".to_string();
view! { cx,
<Outer>
<Inner>
<Inmost name=name.clone()/>
</Inner>
</Outer>
}
}
#[component]
pub fn Outer(cx: Scope, children: ChildrenFn) -> impl IntoView {
children(cx)
}
#[component]
pub fn Inner(cx: Scope, children: ChildrenFn) -> impl IntoView {
children(cx)
}
#[component]
pub fn Inmost(cx: Scope, name: String) -> impl IntoView {
view! { cx,
<p>{name}</p>
}
}
```
Even with `name=name.clone()`, this gives the error
```
cannot move out of `name`, a captured variable in an `Fn` closure
```
Its captured through multiple levels of children that need to run more than once, and theres no obvious way to clone it _into_ the children.
In this case, the `clone:` syntax comes in handy. Calling `clone:name` will clone `name` _before_ moving it into `<Inner/>`s children, which solves our ownership issue.
```rust
view! { cx,
<Outer>
<Inner clone:name>
<Inmost name=name.clone()/>
</Inner>
</Outer>
}
```
These issues can be a little tricky to understand or debug, because of the opacity of the `view` macro. But in general, they can always be solved.
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/interlude_projecting_children.html">
<link rel="canonical" href="https://book.leptos.dev/interlude_projecting_children.html">

View File

@@ -1,112 +1,2 @@
# Interlude: Styling
Anyone creating a website or application soon runs into the question of styling. For a small app, a single CSS file is probably plenty to style your user interface. But as an application grows, many developers find that plain CSS becomes increasingly hard to manage.
Some frontend frameworks (like Angular, Vue, and Svelte) provide built-in ways to scope your CSS to particular components, making it easier to manage styles across a whole application without styles meant to modify one small component having a global effect. Other frameworks (like React or Solid) dont provide built-in CSS scoping, but rely on libraries in the ecosystem to do it for them. Leptos is in this latter camp: the framework itself has no opinions about CSS at all, but provides a few tools and primitives that allow others to build styling libraries.
Here are a few different approaches to styling your Leptos app, other than plain CSS.
## TailwindCSS: Utility-first CSS
[TailwindCSS](https://tailwindcss.com/) is a popular utility-first CSS library. It allows you to style your application by using inline utility classes, with a custom CLI tool that scans your files for Tailwind class names and bundles the necessary CSS.
This allows you to write components like this:
```rust
#[component]
fn Home(cx: Scope) -> impl IntoView {
let (count, set_count) = create_signal(cx, 0);
view! { cx,
<main class="my-0 mx-auto max-w-3xl text-center">
<h2 class="p-6 text-4xl">"Welcome to Leptos with Tailwind"</h2>
<p class="px-10 pb-10 text-left">"Tailwind will scan your Rust files for Tailwind class names and compile them into a CSS file."</p>
<button
class="bg-sky-600 hover:bg-sky-700 px-5 py-3 text-white rounded-lg"
on:click=move |_| set_count.update(|count| *count += 1)
>
{move || if count() == 0 {
"Click me!".to_string()
} else {
count().to_string()
}}
</button>
</main>
}
}
```
It can be a little complicated to set up the Tailwind integration at first, but you can check out our two examples of how to use Tailwind with a [client-side-rendered `trunk` application](https://github.com/leptos-rs/leptos/tree/main/examples/tailwind_csr_trunk) or with a [server-rendered `cargo-leptos` application](https://github.com/leptos-rs/leptos/tree/main/examples/tailwind). `cargo-leptos` also has some [built-in Tailwind support](https://github.com/leptos-rs/cargo-leptos#site-parameters) that you can use as an alternative to Tailwinds CLI.
## Stylers: Compile-time CSS Extraction
[Stylers](https://github.com/abishekatp/stylers) is a compile-time scoped CSS library that lets you declare scoped CSS in the body of your component. Stylers will extract this CSS at compile time into CSS files that you can then import into your app, which means that it doesnt add anything to the WASM binary size of your application.
This allows you to write components like this:
```rust
use stylers::style;
#[component]
pub fn App(cx: Scope) -> impl IntoView {
let styler_class = style! { "App",
#two{
color: blue;
}
div.one{
color: red;
content: raw_str(r#"\hello"#);
font: "1.3em/1.2" Arial, Helvetica, sans-serif;
}
div {
border: 1px solid black;
margin: 25px 50px 75px 100px;
background-color: lightblue;
}
h2 {
color: purple;
}
@media only screen and (max-width: 1000px) {
h3 {
background-color: lightblue;
color: blue
}
}
};
view! { cx, class = styler_class,
<div class="one">
<h1 id="two">"Hello"</h1>
<h2>"World"</h2>
<h2>"and"</h2>
<h3>"friends!"</h3>
</div>
}
}
```
## Styled: Runtime CSS Scoping
[Styled](https://github.com/eboody/styled) is a runtime scoped CSS library that integrates well with Leptos. It lets you declare scoped CSS in the body of your component function, and then applies those styles at runtime.
```rust
use styled::style;
#[component]
pub fn MyComponent(cx: Scope) -> impl IntoView {
let styles = style!(
div {
background-color: red;
color: white;
}
);
styled::view! { cx, styles,
<div>"This text should be red with white text."</div>
}
}
```
## Contributions Welcome
Leptos has no opinions on how you style your website or app, but were very happy to provide support to any tools youre trying to create to make it easier. If youre working on a CSS or styling approach that youd like to add to this list, please let us know!
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/interlude_styling.html">
<link rel="canonical" href="https://book.leptos.dev/interlude_styling.html">

2
docs/book/src/islands.md Normal file
View File

@@ -0,0 +1,2 @@
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/islands.html">
<link rel="canonical" href="https://book.leptos.dev/islands.html">

View File

@@ -1,49 +1,2 @@
# Metadata
So far, everything weve rendered has been inside the `<body>` of the HTML document. And this makes sense. After all, everything you can see on a web page lives inside the `<body>`.
However, there are plenty of occasions where you might want to update something inside the `<head>` of the document using the same reactive primitives and component patterns you use for your UI.
Thats where the [`leptos_meta`](https://docs.rs/leptos_meta/latest/leptos_meta/) package comes in.
## Metadata Components
`leptos_meta` provides special components that let you inject data from inside components anywhere in your application into the `<head>`:
[`<Title/>`](https://docs.rs/leptos_meta/latest/leptos_meta/fn.Title.html) allows you to set the documents title from any component. It also takes a `formatter` function that can be used to apply the same format to the title set by other pages. So, for example, if you put `<Title formatter=|text| format!("{text} — My Awesome Site")/>` in your `<App/>` component, and then `<Title text="Page 1"/>` and `<Title text="Page 2"/>` on your routes, youll get `Page 1 — My Awesome Site` and `Page 2 — My Awesome Site`.
[`<Link/>`](https://docs.rs/leptos_meta/latest/leptos_meta/fn.Link.html) takes the standard attributes of the `<link>` element.
[`<Stylesheet/>`](https://docs.rs/leptos_meta/latest/leptos_meta/fn.Stylesheet.html) creates a `<link rel="stylesheet">` with the `href` you give.
[`<Style/>`](https://docs.rs/leptos_meta/latest/leptos_meta/fn.Style.html) creates a `<style>` with the children you pass in (usually a string). You can use this to import some custom CSS from another file at compile time `<Style>{include_str!("my_route.css")}</Style>`.
[`<Meta/>`](https://docs.rs/leptos_meta/latest/leptos_meta/fn.Meta.html) lets you set `<meta>` tags with descriptions and other metadata.
## `<Script/>` and `<script>`
`leptos_meta` also provides a [`<Script/>`](https://docs.rs/leptos_meta/latest/leptos_meta/fn.Script.html) component, and its worth pausing here for a second. All of the other components weve considered inject `<head>`-only elements in the `<head>`. But a `<script>` can also be included in the body.
Theres a very simple way to determine whether you should use a capital-S `<Script/>` component or a lowercase-s `<script>` element: the `<Script/>` component will be rendered in the `<head>`, and the `<script>` element will be rendered wherever in the `<body>` of your user interface you put it in, alongside other normal HTML elements. These cause JavaScript to load and run at different times, so use whichever is appropriate to your needs.
## `<Body/>` and `<Html/>`
There are even a couple elements designed to make semantic HTML and styling easier. [`<Html/>`](https://docs.rs/leptos_meta/latest/leptos_meta/fn.Html.html) lets you set the `lang` and `dir` on your `<html>` tag from your application code. `<Html/>` and [`<Body/>`](https://docs.rs/leptos_meta/latest/leptos_meta/fn.Html.html) both have `class` props that let you set their respective `class` attributes, which is sometimes needed by CSS frameworks for styling.
`<Body/>` and `<Html/>` both also have `attributes` props which can be used to set any number of additional attributes on them via the [`AdditionalAttributes`](https://docs.rs/leptos/latest/leptos/struct.AdditionalAttributes.html) type:
```rust
<Html
lang="he"
dir="rtl"
attributes=AdditionalAttributes::from(vec![("data-theme", "dark")])
/>
```
## Metadata and Server Rendering
Now, some of this is useful in any scenario, but some of it is especially important for search-engine optimization (SEO). Making sure you have things like appropriate `<title>` and `<meta>` tags is crucial. Modern search engine crawlers do handle client-side rendering, i.e., apps that are shipped as an empty `index.html` and rendered entirely in JS/WASM. But they prefer to receive pages in which your app has been rendered to actual HTML, with metadata in the `<head>`.
This is exactly what `leptos_meta` is for. And in fact, during server rendering, this is exactly what it does: collect all the `<head>` content youve declared by using its components throughout your application, and then inject it into the actual `<head>`.
But Im getting ahead of myself. We havent actually talked about server-side rendering yet. As a matter of fact... Lets do that next!
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/metadata.html">
<link rel="canonical" href="https://book.leptos.dev/metadata.html">

View File

@@ -1,36 +1,2 @@
# Progressive Enhancement (and Graceful Degradation)
Ive been driving around Boston for about fifteen years. If you dont know Boston, let me tell you: Massachusetts has some of the most aggressive drivers(and pedestrians!) in the world. Ive learned to practice whats sometimes called “defensive driving”: assuming that someones about to swerve in front of you at an intersection when you have the right of way, preparing for a pedestrian to cross into the street at any moment, and driving accordingly.
“Progressive enhancement” is the “defensive driving” of web design. Or really, thats “graceful degradation,” although theyre two sides of the same coin, or the same process, from two different directions.
**Progressive enhancement**, in this context, means beginning with a simple HTML site or application that works for any user who arrives at your page, and gradually enhancing it with layers of additional features: CSS for styling, JavaScript for interactivity, WebAssembly for Rust-powered interactivity; using particular Web APIs for a richer experience if theyre available and as needed.
**Graceful degradation** means handling failure gracefully when parts of that stack of enhancement *arent* available. Here are some sources of failure your users might encounter in your app:
- Their browser doesnt support WebAssembly because it needs to be updated.
- Their browser cant support WebAssembly because browser updates are limited to newer OS versions, which cant be installed on the device. (Looking at you, Apple.)
- They have WASM turned off for security or privacy reasons.
- They have JavaScript turned off for security or privacy reasons.
- JavaScript isnt supported on their device (for example, some accessibility devices only support HTML browsing)
- The JavaScript (or WASM) never arrived at their device because they walked outside and lost WiFi.
- They stepped onto a subway car after loading the initial page and subsequent navigations cant load data.
- ... and so on.
How much of your app still works if one of these holds true? Two of them? Three?
If the answer is something like “95%... okay, then 90%... okay, then 75%,” thats graceful degradation. If the answer is “my app shows a blank screen unless everything works correctly,” thats... rapid unscheduled disassembly.
**Graceful degradation is especially important for WASM apps,** because WASM is the newest and least-likely-to-be-supported of the four languages that run in the browser (HTML, CSS, JS, WASM).
Luckily, weve got some tools to help.
## Defensive Design
There are a few practices that can help your apps degrade more gracefully:
1. **Server-side rendering.** Without SSR, your app simply doesnt work without both JS and WASM loading. In some cases this may be appropriate (think internal apps gated behind a login) but in others its simply broken.
2. **Native HTML elements.** Use HTML elements that do the things that you want, without additional code: `<a>` for navigation (including to hashes within the page), `<details>` for an accordion, `<form>` to persist information in the URL, etc.
3. **URL-driven state.** The more of your global state is stored in the URL (as a route param or part of the query string), the more of the page can be generated during server rendering and updated by an `<a>` or a `<form>`, which means that not only navigations but state changes can work without JS/WASM.
4. **[`SsrMode::PartiallyBlocked` or `SsrMode::InOrder`](https://docs.rs/leptos_router/latest/leptos_router/enum.SsrMode.html).** Out-of-order streaming requires a small amount of inline JS, but can fail if 1) the connection is broken halfway through the response or 2) the clients device doesnt support JS. Async streaming will give a complete HTML page, but only after all resources load. In-order streaming begins showing pieces of the page sooner, in top-down order. “Partially-blocked” SSR builds on out-of-order streaming by replacing `<Suspense/>` fragments that read from blocking resources on the server. This adds marginally to the initial response time (because of the `O(n)` string replacement work), in exchange for a more complete initial HTML response. This can be a good choice for situations in which theres a clear distinction between “more important” and “less important” content, e.g., blog post vs. comments, or product info vs. reviews. If you choose to block on all the content, youve essentially recreated async rendering.
5. **Leaning on `<form>`s.** Theres been a bit of a `<form>` renaissance recently, and its no surprise. The ability of a `<form>` to manage complicated `POST` or `GET` requests in an easily-enhanced way makes it a powerful tool for graceful degradation. The example in [the `<Form/>` chapter](../router/20_form.md), for example, would work fine with no JS/WASM: because it uses a `<form method="GET">` to persist state in the URL, it works with pure HTML by making normal HTTP requests and then progressively enhances to use client-side navigations instead.
Theres one final feature of the framework that we havent seen yet, and which builds on this characteristic of forms to build powerful applications: the `<ActionForm/>`.
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/progressive_enhancement/index.html">
<link rel="canonical" href="https://book.leptos.dev/progressive_enhancement/index.html">

View File

@@ -1,56 +1,2 @@
# `<ActionForm/>`
[`<ActionForm/>`](https://docs.rs/leptos_router/latest/leptos_router/fn.ActionForm.html) is a specialized `<Form/>` that takes a server action, and automatically dispatches it on form submission. This allows you to call a server function directly from a `<form>`, even without JS/WASM.
The process is simple:
1. Define a server function using the [`#[server]` macro](https://docs.rs/leptos/latest/leptos/attr.server.html) (see [Server Functions](../server/25_server_functions.md).)
2. Create an action using [`create_server_action`](https://docs.rs/leptos/latest/leptos/fn.create_server_action.html), specifying the type of the server function youve defined.
3. Create an `<ActionForm/>`, providing the server action in the `action` prop.
4. Pass the named arguments to the server function as form fields with the same names.
> **Note:** `<ActionForm/>` only works with the default URL-encoded `POST` encoding for server functions, to ensure graceful degradation/correct behavior as an HTML form.
```rust
#[server(AddTodo, "/api")]
pub async fn add_todo(title: String) -> Result<(), ServerFnError> {
todo!()
}
#[component]
fn AddTodo(cx: Scope) -> impl IntoView {
let add_todo = create_server_action::<AddTodo>(cx);
// holds the latest *returned* value from the server
let value = add_todo.value();
// check if the server has returned an error
let has_error = move || value.with(|val| matches!(val, Some(Err(_))));
view! { cx,
<ActionForm action=add_todo>
<label>
"Add a Todo"
// `title` matches the `title` argument to `add_todo`
<input type="text" name="title"/>
</label>
<input type="submit" value="Add"/>
</ActionForm>
}
}
```
Its really that easy. With JS/WASM, your form will submit without a page reload, storing its most recent submission in the `.input()` signal of the action, its pending status in `.pending()`, and so on. (See the [`Action`](https://docs.rs/leptos/latest/leptos/struct.Action.html) docs for a refresher, if you need.) Without JS/WASM, your form will submit with a page reload. If you call a `redirect` function (from `leptos_axum` or `leptos_actix`) it will redirect to the correct page. By default, it will redirect back to the page youre currently on. The power of HTML, HTTP, and isomorphic rendering mean that your `<ActionForm/>` simply works, even with no JS/WASM.
## Client-Side Validation
Because the `<ActionForm/>` is just a `<form>`, it fires a `submit` event. You can use either HTML validation, or your own client-side validation logic in an `on:submit`. Just call `ev.prevent_default()` to prevent submission.
The [`FromFormData`](https://docs.rs/leptos_router/latest/leptos_router/trait.FromFormData.html) trait can be helpful here, for attempting to parse your server functions data type from the submitted form.
```rust
let on_submit = move |ev| {
let data = AddTodo::from_event(&ev);
// silly example of validation: if the todo is "nope!", nope it
if data.is_err() || data.unwrap().title == "nope!" {
// ev.prevent_default() will prevent form submission
ev.prevent_default();
}
}
```
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/progressive_enhancement/action_form.html">
<link rel="canonical" href="https://book.leptos.dev/progressive_enhancement/action_form.html">

View File

@@ -1,114 +1,2 @@
# Responding to Changes with `create_effect`
Weve made it this far without having mentioned half of the reactive system: effects.
Reactivity works in two halves: updating individual reactive values (“signals”) notifies the pieces of code that depend on them (“effects”) that they need to run again. These two halves of the reactive system are inter-dependent. Without effects, signals can change within the reactive system but never be observed in a way that interacts with the outside world. Without signals, effects run once but never again, as theres no observable value to subscribe to. Effects are quite literally “side effects” of the reactive system: they exist to synchronize the reactive system with the non-reactive world outside it.
Hidden behind the whole reactive DOM renderer that weve seen so far is a function called `create_effect`.
[`create_effect`](https://docs.rs/leptos_reactive/latest/leptos_reactive/fn.create_effect.html) takes a function as its argument. It immediately runs the function. If you access any reactive signal inside that function, it registers the fact that the effect depends on that signal with the reactive runtime. Whenever one of the signals that the effect depends on changes, the effect runs again.
```rust
let (a, set_a) = create_signal(cx, 0);
let (b, set_b) = create_signal(cx, 0);
create_effect(cx, move |_| {
// immediately prints "Value: 0" and subscribes to `a`
log::debug!("Value: {}", a());
});
```
The effect function is called with an argument containing whatever value it returned the last time it ran. On the initial run, this is `None`.
By default, effects **do not run on the server**. This means you can call browser-specific APIs within the effect function without causing issues. If you need an effect to run on the server, use [`create_isomorphic_effect`](https://docs.rs/leptos_reactive/latest/leptos_reactive/fn.create_isomorphic_effect.html).
## Autotracking and Dynamic Dependencies
If youre familiar with a framework like React, you might notice one key difference. React and similar frameworks typically require you to pass a “dependency array,” an explicit set of variables that determine when the effect should rerun.
Because Leptos comes from the tradition of synchronous reactive programming, we dont need this explicit dependency list. Instead, we automatically track dependencies depending on which signals are accessed within the effect.
This has two effects (no pun intended). Dependencies are:
1. **Automatic**: You dont need to maintain a dependency list, or worry about what should or shouldnt be included. The framework simply tracks which signals might cause the effect to rerun, and handles it for you.
2. **Dynamic**: The dependency list is cleared and updated every time the effect runs. If your effect contains a conditional (for example), only signals that are used in the current branch are tracked. This means that effects rerun the absolute minimum number of times.
> If this sounds like magic, and if you want a deep dive into how automatic dependency tracking works, [check out this video](https://www.youtube.com/watch?v=GWB3vTWeLd4). (Apologies for the low volume!)
## Effects as Zero-Cost-ish Abstraction
While theyre not a “zero-cost abstraction” in the most technical sense—they require some additional memory use, exist at runtime, etc.—at a higher level, from the perspective of whatever expensive API calls or other work youre doing within them, effects are a zero-cost abstraction. They rerun the absolute minimum number of times necessary, given how youve described them.
Imagine that Im creating some kind of chat software, and I want people to be able to display their full name, or just their first name, and to notify the server whenever their name changes:
```rust
let (first, set_first) = create_signal(cx, String::new());
let (last, set_last) = create_signal(cx, String::new());
let (use_last, set_use_last) = create_signal(cx, true);
// this will add the name to the log
// any time one of the source signals changes
create_effect(cx, move |_| {
log(
cx,
if use_last() {
format!("{} {}", first(), last())
} else {
first()
},
)
});
```
If `use_last` is `true`, effect should rerun whenever `first`, `last`, or `use_last` changes. But if I toggle `use_last` to `false`, a change in `last` will never cause the full name to change. In fact, `last` will be removed from the dependency list until `use_last` toggles again. This saves us from sending multiple unnecessary requests to the API if I change `last` multiple times while `use_last` is still `false`.
## To `create_effect`, or not to `create_effect`?
Effects are intended to run _side-effects_ of the system, not to synchronize state _within_ the system. In other words: dont write to signals within effects.
If you need to define a signal that depends on the value of other signals, use a derived signal or [`create_memo`](https://docs.rs/leptos_reactive/latest/leptos_reactive/fn.create_memo.html).
If you need to synchronize some reactive value with the non-reactive world outside—like a web API, the console, the filesystem, or the DOM—create an effect.
> If youre curious for more information about when you should and shouldnt use `create_effect`, [check out this video](https://www.youtube.com/watch?v=aQOFJQ2JkvQ) for a more in-depth consideration!
## Effects and Rendering
Weve managed to get this far without mentioning effects because theyre built into the Leptos DOM renderer. Weve seen that you can create a signal and pass it into the `view` macro, and it will update the relevant DOM node whenever the signal changes:
```rust
let (count, set_count) = create_signal(cx, 0);
view! { cx,
<p>{count}</p>
}
```
This works because the framework essentially creates an effect wrapping this update. You can imagine Leptos translating this view into something like this:
```rust
let (count, set_count) = create_signal(cx, 0);
// create a DOM element
let p = create_element("p");
// create an effect to reactively update the text
create_effect(cx, move |prev_value| {
// first, access the signals value and convert it to a string
let text = count().to_string();
// if this is different from the previous value, update the node
if prev_value != Some(text) {
p.set_text_content(&text);
}
// return this value so we can memoize the next update
text
});
```
Every time `count` is updated, this effect wil rerun. This is what allows reactive, fine-grained updates to the DOM.
[Click to open CodeSandbox.](https://codesandbox.io/p/sandbox/serene-thompson-40974n?file=%2Fsrc%2Fmain.rs&selection=%5B%7B%22endColumn%22%3A1%2C%22endLineNumber%22%3A2%2C%22startColumn%22%3A1%2C%22startLineNumber%22%3A2%7D%5D)
<iframe src="https://codesandbox.io/p/sandbox/serene-thompson-40974n?file=%2Fsrc%2Fmain.rs&selection=%5B%7B%22endColumn%22%3A1%2C%22endLineNumber%22%3A2%2C%22startColumn%22%3A1%2C%22startLineNumber%22%3A2%7D%5D" width="100%" height="1000px" style="max-height: 100vh"></iframe>
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/reactivity/14_create_effect.html">
<link rel="canonical" href="https://book.leptos.dev/reactivity/14_create_effect.html">

View File

@@ -1,5 +1,2 @@
# Reactivity
Leptos is built on top of a fine-grained reactive system, designed to run expensive side effects (like rendering something in a browser, or making a network request) as infrequently as possible in response to change, reactive values.
So far weve seen signals in action. These chapters will go into a bit more depth, and look at effects, which are the other half of the story.
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/reactivity/index.html">
<link rel="canonical" href="https://book.leptos.dev/reactivity/index.html">

View File

@@ -1,76 +1,2 @@
# Interlude: Reactivity and Functions
One of our core contributors said to me recently: “I never used closures this often
until I started using Leptos.” And its true. Closures are at the heart of any Leptos
application. It sometimes looks a little silly:
```rust
// a signal holds a value, and can be updated
let (count, set_count) = create_signal(cx, 0);
// a derived signal is a function that accesses other signals
let double_count = move || count() * 2;
let count_is_odd = move || count() & 1 == 1;
let text = move || if count_is_odd() {
"odd"
} else {
"even"
};
// an effect automatically tracks the signals it depends on
// and reruns when they change
create_effect(cx, move |_| {
log!("text = {}", text());
});
view! { cx,
<p>{move || text().to_uppercase()}</p>
}
```
Closures, closures everywhere!
But why?
## Functions and UI Frameworks
Functions are at the heart of every UI framework. And this makes perfect sense. Creating a user interface is basically divided into two phases:
1. initial rendering
2. updates
In a web framework, the framework does some kind of initial rendering. Then it hands control back over to the browser. When certain events fire (like a mouse click) or asynchronous tasks finish (like an HTTP request finishing), the browser wakes the framework back up to update something. The framework runs some kind of code to update your user interface, and goes back asleep until the browser wakes it up again.
The key phrase here is “runs some kind of code.” The natural way to “run some kind of code” at an arbitrary point in time—in Rust or in any other programming language—is to call a function. And in fact every UI framework is based on rerunning some kind of function over and over:
1. virtual DOM (VDOM) frameworks like React, Yew, or Dioxus rerun a component or render function over and over, to generate a virtual DOM tree that can be reconciled with the previous result to patch the DOM
2. compiled frameworks like Angular and Svelte divide your component templates into “create” and “update” functions, rerunning the update function when they detect a change to the components state
3. in fine-grained reactive frameworks like SolidJS, Sycamore, or Leptos, _you_ define the functions that rerun
Thats what all our components are doing.
Take our typical `<SimpleCounter/>` example in its simplest form:
```rust
#[component]
pub fn SimpleCounter(cx: Scope) -> impl IntoView {
let (value, set_value) = create_signal(cx, 0);
let increment = move |_| set_value.update(|value| *value += 1);
view! { cx,
<button on:click=increment>
{value}
</button>
}
}
```
The `SimpleCounter` function itself runs once. The `value` signal is created once. The framework hands off the `increment` function to the browser as an event listener. When you click the button, the browser calls `increment`, which updates `value` via `set_value`. And that updates the single text node represented in our view by `{value}`.
Closures are key to reactivity. They provide the framework with the ability to rerun the smallest possible unit of your application in responsive to a change.
So remember two things:
1. Your component function is a setup function, not a render function: it only runs once.
2. For values in your view template to be reactive, they must be functions: either signals (which implement the `Fn` traits) or closures.
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/reactivity/interlude_functions.html">
<link rel="canonical" href="https://book.leptos.dev/reactivity/interlude_functions.html">

View File

@@ -1,106 +1,2 @@
# Working with Signals
So far weve used some simple examples of [`create_signal`](https://docs.rs/leptos/latest/leptos/fn.create_signal.html), which returns a [`ReadSignal`](https://docs.rs/leptos/latest/leptos/struct.ReadSignal.html) getter and a [`WriteSignal`](https://docs.rs/leptos/latest/leptos/struct.WriteSignal.html) setter.
## Getting and Setting
There are four basic signal operations:
1. [`.get()`](https://docs.rs/leptos/latest/leptos/struct.ReadSignal.html#impl-SignalGet%3CT%3E-for-ReadSignal%3CT%3E) clones the current value of the signal and tracks any future changes to the value reactively.
2. [`.with()`](https://docs.rs/leptos/latest/leptos/struct.ReadSignal.html#impl-SignalWith%3CT%3E-for-ReadSignal%3CT%3E) takes a function, which receives the current value of the signal by reference (`&T`), and tracks any future changes.
3. [`.set()`](https://docs.rs/leptos/latest/leptos/struct.WriteSignal.html#impl-SignalSet%3CT%3E-for-WriteSignal%3CT%3E) replaces the current value of the signal and notifies any subscribers that they need to update.
4. [`.update()`](https://docs.rs/leptos/latest/leptos/struct.WriteSignal.html#impl-SignalUpdate%3CT%3E-for-WriteSignal%3CT%3E) takes a function, which receives a mutable reference to the current value of the signal (`&mut T`), and notifies any subscribers that they need to update. (`.update()` doesnt return the value returned by the closure, but you can use [`.try_update()`](https://docs.rs/leptos/latest/leptos/trait.SignalUpdate.html#tymethod.try_update) if you need to; for example, if youre removing an item from a `Vec<_>` and want the removed item.)
Calling a `ReadSignal` as a function is syntax sugar for `.get()`. Calling a `WriteSignal` as a function is syntax sugar for `.set()`. So
```rust
let (count, set_count) = create_signal(cx, 0);
set_count(1);
log!(count());
```
is the same as
```rust
let (count, set_count) = create_signal(cx, 0);
set_count.set(1);
log!(count.get());
```
You might notice that `.get()` and `.set()` can be implemented in terms of `.with()` and `.update()`. In other words, `count.get()` is identical with `count.with(|n| n.clone())`, and `count.set(1)` is implemented by doing `count.update(|n| *n = 1)`.
But of course, `.get()` and `.set()` (or the plain function-call forms!) are much nicer syntax.
However, there are some very good use cases for `.with()` and `.update()`.
For example, consider a signal that holds a `Vec<String>`.
```rust
let (names, set_names) = create_signal(cx, Vec::new());
if names().is_empty() {
set_names(vec!["Alice".to_string()]);
}
```
In terms of logic, this is simple enough, but its hiding some significant inefficiencies. Remember that `names().is_empty()` is sugar for `names.get().is_empty()`, which clones the value (its `names.with(|n| n.clone()).is_empty()`). This means we clone the whole `Vec<String>`, run `is_empty()`, and then immediately throw away the clone.
Likewise, `set_names` replaces the value with a whole new `Vec<_>`. This is fine, but we might as well just mutate the original `Vec<_>` in place.
```rust
let (names, set_names) = create_signal(cx, Vec::new());
if names.with(|names| names.is_empty()) {
set_names.update(|names| names.push("Alice".to_string()));
}
```
Now our function simply takes `names` by reference to run `is_empty()`, avoiding that clone.
And if you have Clippy on, or if you have sharp eyes, you may notice we can make this even neater:
```rust
if names.with(Vec::is_empty) {
// ...
}
```
After all, `.with()` simply takes a function that takes the value by reference. Since `Vec::is_empty` takes `&self`, we can pass it in directly and avoid the unncessary closure.
## Making signals depend on each other
Often people ask about situations in which some signal needs to change based on some other signals value. There are three good ways to do this, and one thats less than ideal but okay under controlled circumstances.
### Good Options
**1) B is a function of A.** Create a signal for A and a derived signal or memo for B.
```rust
let (count, set_count) = create_signal(cx, 1);
let derived_signal_double_count = move || count() * 2;
let memoized_double_count = create_memo(cx, move |_| count() * 2);
```
> For guidance on whether to use a derived signal or a memo, see the docs for [`create_memo`](https://docs.rs/leptos/latest/leptos/fn.create_memo.html)
>
**2) C is a function of A and some other thing B.** Create signals for A and B and a derived signal or memo for C.
```rust
let (first_name, set_first_name) = create_signal(cx, "Bridget".to_string());
let (last_name, set_last_name) = create_signal(cx, "Jones".to_string());
let full_name = move || format!("{} {}", first_name(), last_name());
```
**3) A and B are independent signals, but sometimes updated at the same time.** When you make the call to update A, make a separate call to update B.
```rust
let (age, set_age) = create_signal(cx, 32);
let (favorite_number, set_favorite_number) = create_signal(cx, 42);
// use this to handle a click on a `Clear` button
let clear_handler = move |_| {
set_age(0);
set_favorite_number(0);
};
```
### If you really must...
**4) Create an effect to write to B whenever A changes.** This is officially discouraged, for several reasons:
a) It will always be less efficient, as it means every time A updates you do two full trips through the reactive process. (You set A, which causes the effect to run, as well as any other effects that depend on A. Then you set B, which causes any effects that depend on B to run.)
b) It increases your chances of accidentally creating things like infinite loops or over-re-running effects. This is the kind of ping-ponging, reactive spaghetti code that was common in the early 2010s and that we try to avoid with things like read-write segregation and discouraging writing to signals from effects.
In most situations, its best to rewrite things such that theres a clear, top-down data flow based on derived signals or memos. But this isnt the end of the world.
> Im intentionally not providing an example here. Read the [`create_effect`](https://docs.rs/leptos/latest/leptos/fn.create_effect.html) docs to figure out how this would work.
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/reactivity/working_with_signals.html">
<link rel="canonical" href="https://book.leptos.dev/reactivity/working_with_signals.html">

View File

@@ -1,101 +1,2 @@
# Defining Routes
## Getting Started
Its easy to get started with the router.
First things first, make sure youve added the `leptos_router` package to your dependencies.
> Its important that the router is a separate package from `leptos` itself. This means that everything in the router can be defined in user-land code. If you want to create your own router, or use no router, youre completely free to do that!
And import the relevant types from the router, either with something like
```rust
use leptos_router::{Route, RouteProps, Router, RouterProps, Routes, RoutesProps};
```
or simply
```rust
use leptos_router::*;
```
## Providing the `<Router/>`
Routing behavior is provided by the [`<Router/>`](https://docs.rs/leptos_router/latest/leptos_router/fn.Router.html) component. This should usually be somewhere near the root of your application, the rest of the app.
> You shouldnt try to use multiple `<Router/>`s in your app. Remember that the router drives global state: if you have multiple routers, which ones decides what to do when the URL changes?
Lets start with a simple `<App/>` component using the router:
```rust
use leptos::*;
use leptos_router::*;
#[component]
pub fn App(cx: Scope) -> impl IntoView {
view! { cx,
<Router>
<nav>
/* ... */
</nav>
<main>
/* ... */
</main>
</Router>
}
}
```
## Defining `<Routes/>`
The [`<Routes/>`](https://docs.rs/leptos_router/latest/leptos_router/fn.Routes.html) component is where you define all the routes to which a user can navigate in your application. Each possible route is defined by a [`<Route/>`](https://docs.rs/leptos_router/latest/leptos_router/fn.Route.html) component.
You should place the `<Routes/>` component at the location within your app where you want routes to be rendered. Everything outside `<Routes/>` will be present on every page, so you can leave things like a navigation bar or menu outside the `<Routes/>`.
```rust
use leptos::*;
use leptos_router::*;
#[component]
pub fn App(cx: Scope) -> impl IntoView {
view! { cx,
<Router>
<nav>
/* ... */
</nav>
<main>
// all our routes will appear inside <main>
<Routes>
/* ... */
</Routes>
</main>
</Router>
}
}
```
Individual routes are defined by providing children to `<Routes/>` with the `<Route/>` component. `<Route/>` takes a `path` and a `view`. When the current location matches `path`, the `view` will be created and displayed.
The `path` can include
- a static path (`/users`),
- dynamic, named parameters beginning with a colon (`/:id`),
- and/or a wildcard beginning with an asterisk (`/user/*any`)
The `view` is a function that takes a `Scope` and returns a view.
```rust
<Routes>
<Route path="/" view=|cx| view! { cx, <Home/> }/>
<Route path="/users" view=|cx| view! { cx, <Users/> }/>
<Route path="/users/:id" view=|cx| view! { cx, <UserProfile/> }/>
<Route path="/*any" view=|cx| view! { cx, <NotFound/> }/>
</Routes>
```
> The router scores each route to see how good a match it is, so you can define your routes in any order.
Now if you navigate to `/` or to `/users` youll get the home page or the `<Users/>`. If you go to `/users/3` or `/blahblah` youll get a user profile or your 404 page (`<NotFound/>`). On every navigation, the router determines which `<Route/>` should be matched, and therefore what content should be displayed where the `<Routes/>` component is defined.
Simple enough?
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/router/16_routes.html">
<link rel="canonical" href="https://book.leptos.dev/router/16_routes.html">

View File

@@ -1,172 +1,2 @@
# Nested Routing
We just defined the following set of routes:
```rust
<Routes>
<Route path="/" view=|cx| view! { cx, <Home /> }/>
<Route path="/users" view=|cx| view! { cx, <Users /> }/>
<Route path="/users/:id" view=|cx| view! { cx, <UserProfile /> }/>
<Route path="/*any" view=|cx| view! { cx, <NotFound /> }/>
</Routes>
```
Theres a certain amount of duplication here: `/users` and `/users/:id`. This is fine for a small app, but you can probably already tell it wont scale well. Wouldnt it be nice if we could nest these routes?
Well... you can!
```rust
<Routes>
<Route path="/" view=|cx| view! { cx, <Home /> }/>
<Route path="/users" view=|cx| view! { cx, <Users /> }>
<Route path=":id" view=|cx| view! { cx, <UserProfile /> }/>
</Route>
<Route path="/*any" view=|cx| view! { cx, <NotFound /> }/>
</Routes>
```
But wait. Weve just subtly changed what our application does.
The next section is one of the most important in this entire routing section of the guide. Read it carefully, and feel free to ask questions if theres anything you dont understand.
# Nested Routes as Layout
Nested routes are a form of layout, not a method of route definition.
Let me put that another way: The goal of defining nested routes is not primarily to avoid repeating yourself when typing out the paths in your route definitions. It is actually to tell the router to display multiple `<Route/>`s on the page at the same time, side by side.
Lets look back at our practical example.
```rust
<Routes>
<Route path="/users" view=|cx| view! { cx, <Users /> }/>
<Route path="/users/:id" view=|cx| view! { cx, <UserProfile /> }/>
</Routes>
```
This means:
- If I go to `/users`, I get the `<Users/>` component.
- If I go to `/users/3`, I get the `<UserProfile/>` component (with the parameter `id` set to `3`; more on that later)
Lets say I use nested routes instead:
```rust
<Routes>
<Route path="/users" view=|cx| view! { cx, <Users /> }>
<Route path=":id" view=|cx| view! { cx, <UserProfile /> }/>
</Route>
</Routes>
```
This means:
- If I go to `/users/3`, the path matches two `<Route/>`s: `<Users/>` and `<UserProfile/>`.
- If I go to `/users`, the path is not matched.
I actually need to add a fallback route
```rust
<Routes>
<Route path="/users" view=|cx| view! { cx, <Users /> }>
<Route path=":id" view=|cx| view! { cx, <UserProfile /> }/>
<Route path="" view=|cx| view! { cx, <NoUser /> }/>
</Route>
</Routes>
```
Now:
- If I go to `/users/3`, the path matches `<Users/>` and `<UserProfile/>`.
- If I go to `/users`, the path matches `<Users/>` and `<NoUser/>`.
When I use nested routes, in other words, each **path** can match multiple **routes**: each URL can render the views provided by multiple `<Route/>` components, at the same time, on the same page.
This may be counter-intuitive, but its very powerful, for reasons youll hopefully see in a few minutes.
## Why Nested Routing?
Why bother with this?
Most web applications contain levels of navigation that correspond to different parts of the layout. For example, in an email app you might have a URL like `/contacts/greg`, which shows a list of contacts on the left of the screen, and contact details for Greg on the right of the screen. The contact list and the contact details should always appear on the screen at the same time. If theres no contact selected, maybe you want to show a little instructional text.
You can easily define this with nested routes
```rust
<Routes>
<Route path="/contacts" view=|cx| view! { cx, <ContactList/> }>
<Route path=":id" view=|cx| view! { cx, <ContactInfo/> }/>
<Route path="" view=|cx| view! { cx,
<p>"Select a contact to view more info."</p>
}/>
</Route>
</Routes>
```
You can go even deeper. Say you want to have tabs for each contacts address, email/phone, and your conversations with them. You can add _another_ set of nested routes inside `:id`:
```rust
<Routes>
<Route path="/contacts" view=|cx| view! { cx, <ContactList/> }>
<Route path=":id" view=|cx| view! { cx, <ContactInfo/> }>
<Route path="" view=|cx| view! { cx, <EmailAndPhone/> }/>
<Route path="address" view=|cx| view! { cx, <Address/> }/>
<Route path="messages" view=|cx| view! { cx, <Messages/> }/>
</Route>
<Route path="" view=|cx| view! { cx,
<p>"Select a contact to view more info."</p>
}/>
</Route>
</Routes>
```
> The main page of the [Remix website](https://remix.run/), a React framework from the creators of React Router, has a great visual example if you scroll down, with three levels of nested routing: Sales > Invoices > an invoice.
## `<Outlet/>`
Parent routes do not automatically render their nested routes. After all, they are just components; they dont know exactly where they should render their children, and “just stick it at the end of the parent component” is not a great answer.
Instead, you tell a parent component where to render any nested components with an `<Outlet/>` component. The `<Outlet/>` simply renders one of two things:
- if there is no nested route that has been matched, it shows nothing
- if there is a nested route that has been matched, it shows its `view`
Thats all! But its important to know and to remember, because its a common source of “Why isnt this working?” frustration. If you dont provide an `<Outlet/>`, the nested route wont be displayed.
```rust
#[component]
pub fn ContactList(cx: Scope) -> impl IntoView {
let contacts = todo!();
view! { cx,
<div style="display: flex">
// the contact list
<For each=contacts
key=|contact| contact.id
view=|cx, contact| todo!()
>
// the nested child, if any
// dont forget this!
<Outlet/>
</div>
}
}
```
## Nested Routing and Performance
All of this is nice, conceptually, but again—whats the big deal?
Performance.
In a fine-grained reactive library like Leptos, its always important to do the least amount of rendering work you can. Because were working with real DOM nodes and not diffing a virtual DOM, we want to “rerender” components as infrequently as possible. Nested routing makes this extremely easy.
Imagine my contact list example. If I navigate from Greg to Alice to Bob and back to Greg, the contact information needs to change on each navigation. But the `<ContactList/>` should never be rerendered. Not only does this save on rendering performance, it also maintains state in the UI. For example, if I have a search bar at the top of `<ContactList/>`, navigating from Greg to Alice to Bob wont clear the search.
In fact, in this case, we dont even need to rerender the `<Contact/>` component when moving between contacts. The router will just reactively update the `:id` parameter as we navigate, allowing us to make fine-grained updates. As we navigate between contacts, well update single text nodes to change the contacts name, address, and so on, without doing _any_ additional rerendering.
> This sandbox includes a couple features (like nested routing) discussed in this section and the previous one, and a couple well cover in the rest of this chapter. The router is such an integrated system that it makes sense to provide a single example, so dont be surprised if theres anything you dont understand.
[Click to open CodeSandbox.](https://codesandbox.io/p/sandbox/16-router-fy4tjv?file=%2Fsrc%2Fmain.rs&selection=%5B%7B%22endColumn%22%3A1%2C%22endLineNumber%22%3A3%2C%22startColumn%22%3A1%2C%22startLineNumber%22%3A3%7D%5D)
<iframe src="https://codesandbox.io/p/sandbox/16-router-fy4tjv?file=%2Fsrc%2Fmain.rs&selection=%5B%7B%22endColumn%22%3A1%2C%22endLineNumber%22%3A3%2C%22startColumn%22%3A1%2C%22startLineNumber%22%3A3%7D%5D" width="100%" height="1000px" style="max-height: 100vh"></iframe>
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/router/17_nested_routing.html">
<link rel="canonical" href="https://book.leptos.dev/router/17_nested_routing.html">

View File

@@ -1,79 +1,2 @@
# Params and Queries
Static paths are useful for distinguishing between different pages, but almost every application wants to pass data through the URL at some point.
There are two ways you can do this:
1. named route **params** like `id` in `/users/:id`
2. named route **queries** like `q` in `/search?q=Foo`
Because of the way URLs are built, you can access the query from _any_ `<Route/>` view. You can access route params from the `<Route/>` that defines them or any of its nested children.
Accessing params and queries is pretty simple with a couple of hooks:
- [`use_query`](https://docs.rs/leptos_router/latest/leptos_router/fn.use_query.html) or [`use_query_map`](https://docs.rs/leptos_router/latest/leptos_router/fn.use_query_map.html)
- [`use_params`](https://docs.rs/leptos_router/latest/leptos_router/fn.use_params.html) or [`use_params_map`](https://docs.rs/leptos_router/latest/leptos_router/fn.use_query_map.html)
Each of these comes with a typed option (`use_query` and `use_params`) and an untyped option (`use_query_map` and `use_params_map`).
The untyped versions hold a simple key-value map. To use the typed versions, derive the [`Params`](https://docs.rs/leptos_router/0.2.3/leptos_router/trait.Params.html) trait on a struct.
> `Params` is a very lightweight trait to convert a flat key-value map of strings into a struct by applying `FromStr` to each field. Because of the flat structure of route params and URL queries, its significantly less flexible than something like `serde`; it also adds much less weight to your binary.
```rust
use leptos::*;
use leptos_router::*;
#[derive(Params)]
struct ContactParams {
id: usize
}
#[derive(Params)]
struct ContactSearch {
q: String
}
```
> Note: The `Params` derive macro is located at `leptos::Params`, and the `Params` trait is at `leptos_router::Params`. If you avoid using glob imports like `use leptos::*;`, make sure youre importing the right one for the derive macro.
Now we can use them in a component. Imagine a URL that has both params and a query, like `/contacts/:id?q=Search`.
The typed versions return `Memo<Result<T, _>>`. Its a Memo so it reacts to changes in the URL. Its a `Result` because the params or query need to be parsed from the URL, and may or may not be valid.
```rust
let params = use_params::<ContactParams>(cx);
let query = use_query::<ContactSearch>(cx);
// id: || -> usize
let id = move || {
params.with(|params| {
params
.map(|params| params.id)
.unwrap_or_default()
})
};
```
The untyped versions return `Memo<ParamsMap>`. Again, its memo to react to changes in the URL. [`ParamsMap`](https://docs.rs/leptos_router/0.2.3/leptos_router/struct.ParamsMap.html) behaves a lot like any other map type, with a `.get()` method that returns `Option<&String>`.
```rust
let params = use_params_map(cx);
let query = use_query_map(cx);
// id: || -> Option<String>
let id = move || {
params.with(|params| params.get("id").cloned())
};
```
This can get a little messy: deriving a signal that wraps an `Option<_>` or `Result<_>` can involve a couple steps. But its worth doing this for two reasons:
1. Its correct, i.e., it forces you to consider the cases, “What if the user doesnt pass a value for this query field? What if they pass an invalid value?”
2. Its performant. Specifically, when you navigate between different paths that match the same `<Route/>` with only params or the query changing, you can get fine-grained updates to different parts of your app without rerendering. For example, navigating between different contacts in our contact-list example does a targeted update to the name field (and eventually contact info) without needing to replace or rerender the wrapping `<Contact/>`. This is what fine-grained reactivity is for.
> This is the same example from the previous section. The router is such an integrated system that it makes sense to provide a single example highlighting multiple features, even if we havent explained them all yet.
[Click to open CodeSandbox.](https://codesandbox.io/p/sandbox/16-router-fy4tjv?file=%2Fsrc%2Fmain.rs&selection=%5B%7B%22endColumn%22%3A1%2C%22endLineNumber%22%3A3%2C%22startColumn%22%3A1%2C%22startLineNumber%22%3A3%7D%5D)
<iframe src="https://codesandbox.io/p/sandbox/16-router-fy4tjv?file=%2Fsrc%2Fmain.rs&selection=%5B%7B%22endColumn%22%3A1%2C%22endLineNumber%22%3A3%2C%22startColumn%22%3A1%2C%22startLineNumber%22%3A3%7D%5D" width="100%" height="1000px" style="max-height: 100vh"></iframe>
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/router/18_params_and_queries.html">
<link rel="canonical" href="https://book.leptos.dev/router/18_params_and_queries.html">

View File

@@ -1,23 +1,2 @@
# The `<A/>` Component
Client-side navigation works perfectly fine with ordinary HTML `<a>` elements. The router adds a listener that handles every click on a `<a>` element and tries to handle it on the client side, i.e., without doing another round trip to the server to request HTML. This is what enables the snappy “single-page app” navigations youre probably familiar with from most modern web apps.
The router will bail out of handling an `<a>` click under a number of situations
- the click event has had `prevent_default()` called on it
- the <kbd>Meta</kbd>, <kbd>Alt</kbd>, <kbd>Ctrl</kbd>, or <kbd>Shift</kbd> keys were held during click
- the `<a>` has a `target` or `download` attribute, or `rel="external"`
- the link has a different origin from the current location
In other words, the router will only try to do a client-side navigation when its pretty sure it can handle it, and it will upgrade every `<a>` element to get this special behavior.
The router also provides an [`<A>`](https://docs.rs/leptos_router/latest/leptos_router/fn.A.html) component, which does two additional things:
1. Correctly resolves relative nested routes. Relative routing with ordinary `<a>` tags can be tricky. For example, if you have a route like `/post/:id`, `<A href="1">` will generate the correct relative route, but `<a href="1">` likely will not (depending on where it appears in your view.) `<A/>` resolves routes relative to the path of the nested route within which it appears.
2. Sets the `aria-current` attribute to `page` if this link is the active link (i.e., its a link to the page youre on). This is helpful for accessibility and for styling. For example, if you want to set the link a different color if its a link to the page youre currently on, you can match this attribute with a CSS selector.
> Once again, this is the same example. Check out the relative `<A/>` components, and take a look at the CSS in `index.html` to see the ARIA-based styling.
[Click to open CodeSandbox.](https://codesandbox.io/p/sandbox/16-router-fy4tjv?file=%2Fsrc%2Fmain.rs&selection=%5B%7B%22endColumn%22%3A1%2C%22endLineNumber%22%3A3%2C%22startColumn%22%3A1%2C%22startLineNumber%22%3A3%7D%5D)
<iframe src="https://codesandbox.io/p/sandbox/16-router-fy4tjv?file=%2Fsrc%2Fmain.rs&selection=%5B%7B%22endColumn%22%3A1%2C%22endLineNumber%22%3A3%2C%22startColumn%22%3A1%2C%22startLineNumber%22%3A3%7D%5D" width="100%" height="1000px" style="max-height: 100vh"></iframe>
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/router/19_a.html">
<link rel="canonical" href="https://book.leptos.dev/router/19_a.html">

View File

@@ -1,67 +1,2 @@
# The `<Form/>` Component
Links and forms sometimes seem completely unrelated. But, in fact, they work in very similar ways.
In plain HTML, there are three ways to navigate to another page:
1. An `<a>` element that links to another page: Navigates to the URL in its `href` attribute with the `GET` HTTP method.
2. A `<form method="GET">`: Navigates to the URL in its `action` attribute with the `GET` HTTP method and the form data from its inputs encoded in the URL query string.
3. A `<form method="POST">`: Navigates to the URL in its `action` attribute with the `POST` HTTP method and the form data from its inputs encoded in the body of the request.
Since we have a client-side router, we can do client-side link navigations without reloading the page, i.e., without a full round-trip to the server and back. It makes sense that we can do client-side form navigations in the same way.
The router provides a [`<Form>`](https://docs.rs/leptos_router/latest/leptos_router/fn.Form.html) component, which works like the HTML `<form>` element, but uses client-side navigations instead of full page reloads. `<Form/>` works with both `GET` and `POST` requests. With `method="GET"`, it will navigate to the URL encoded in the form data. With `method="POST"` it will make a `POST` request and handle the servers response.
`<Form/>` provides the basis for some components like `<ActionForm/>` and `<MultiActionForm/>` that well see in later chapters. But it also enables some powerful patterns of its own.
For example, imagine that you want to create a search field that updates search results in real time as the user searches, without a page reload, but that also stores the search in the URL so a user can copy and paste it to share results with someone else.
It turns out that the patterns weve learned so far make this easy to implement.
```rust
async fn fetch_results() {
// some async function to fetch our search results
}
#[component]
pub fn FormExample(cx: Scope) -> impl IntoView {
// reactive access to URL query strings
let query = use_query_map(cx);
// search stored as ?q=
let search = move || query().get("q").cloned().unwrap_or_default();
// a resource driven by the search string
let search_results = create_resource(cx, search, fetch_results);
view! { cx,
<Form method="GET" action="">
<input type="search" name="search" value=search/>
<input type="submit"/>
</Form>
<Transition fallback=move || ()>
/* render search results */
</Transition>
}
}
```
Whenever you click `Submit`, the `<Form/>` will “navigate” to `?q={search}`. But because this navigation is done on the client side, theres no page flicker or reload. The URL query string changes, which triggers `search` to update. Because `search` is the source signal for the `search_results` resource, this triggers `search_results` to reload its resource. The `<Transition/>` continues displaying the current search results until the new ones have loaded. When they are complete, it switches to displaying the new result.
This is a great pattern. The data flow is extremely clear: all data flows from the URL to the resource into the UI. The current state of the application is stored in the URL, which means you can refresh the page or text the link to a friend and it will show exactly what youre expecting. And once we introduce server rendering, this pattern will prove to be really fault-tolerant, too: because it uses a `<form>` element and URLs under the hood, it actually works really well without even loading your WASM on the client.
We can actually take it a step further and do something kind of clever:
```rust
view! { cx,
<Form method="GET" action="">
<input type="search" name="search" value=search
oninput="this.form.requestSubmit()"
/>
</Form>
}
```
Youll notice that this version drops the `Submit` button. Instead, we add an `oninput` attribute to the input. Note that this is _not_ `on:input`, which would listen for the `input` event and run some Rust code. Without the colon, `oninput` is the plain HTML attribute. So the string is actually a JavaScript string. `this.form` gives us the form the input is attached to. `requestSubmit()` fires the `submit` event on the `<form>`, which is caught by `<Form/>` just as if we had clicked a `Submit` button. Now the form will “navigate” on every keystroke or input to keep the URL (and therefore the search) perfectly in sync with the users input as they type.
[Click to open CodeSandbox.](https://codesandbox.io/p/sandbox/16-router-forked-hrrt3h?file=%2Fsrc%2Fmain.rs)
<iframe src="https://codesandbox.io/p/sandbox/16-router-forked-hrrt3h?file=%2Fsrc%2Fmain.rs" width="100%" height="1000px" style="max-height: 100vh"></iframe>
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/router/20_form.html">
<link rel="canonical" href="https://book.leptos.dev/router/20_form.html">

View File

@@ -1,23 +1,2 @@
# Routing
## The Basics
Routing drives most websites. A router is the answer to the question, “Given this URL, what should appear on the page?”
A URL consists of many parts. For example, the URL `https://my-cool-blog.com/blog/search?q=Search#results` consists of
- a _scheme_: `https`
- a _domain_: `my-cool-blog.com`
- a **path**: `/blog/search`
- a **query** (or **search**): `?q=Search`
- a _hash_: `#results`
The Leptos Router works with the path and query (`/blog/search?q=Search`). Given this piece of the URL, what should the app render on the page?
## The Philosophy
In most cases, the path should drive what is displayed on the page. From the users perspective, for most applications, most major changes in the state of the app should be reflected in the URL. If you copy and paste the URL and open it in another tab, you should find yourself more or less in the same place.
In this sense, the router is really at the heart of the global state management for your application. More than anything else, it drives what is displayed on the page.
The router handles most of this work for you by mapping the current location to particular components.
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/router/index.html">
<link rel="canonical" href="https://book.leptos.dev/router/index.html">

View File

@@ -1,124 +1,2 @@
# Server Functions
If youre creating anything beyond a toy app, youll need to run code on the server all the time: reading from or writing to a database that only runs on the server, running expensive computations using libraries you dont want to ship down to the client, accessing APIs that need to be called from the server rather than the client for CORS reasons or because you need a secret API key thats stored on the server and definitely shouldnt be shipped down to a users browser.
Traditionally, this is done by separating your server and client code, and by setting up something like a REST API or GraphQL API to allow your client to fetch and mutate data on the server. This is fine, but it requires you to write and maintain your code in multiple separate places (client-side code for fetching, server-side functions to run), as well as creating a third thing to manage, which is the API contract between the two.
Leptos is one of a number of modern frameworks that introduce the concept of **server functions**. Server functions have two key characteristics:
1. Server functions are **co-located** with your component code, so that you can organize your work by feature, not by technology. For example, you might have a “dark mode” feature that should persist a users dark/light mode preference across sessions, and be applied during server rendering so theres no flicker. This requires a component that needs to be interactive on the client, and some work to be done on the server (setting a cookie, maybe even storing a user in a database.) Traditionally, this feature might end up being split between two different locations in your code, one in your “frontend” and one in your “backend.” With server functions, youll probably just write them both in one `dark_mode.rs` and forget about it.
2. Server functions are **isomorphic**, i.e., they can be called either from the server or the browser. This is done by generating code differently for the two platforms. On the server, a server function simply runs. In the browser, the server functions body is replaced with a stub that actually makes a fetch request to the server, serializing the arguments into the request and deserializing the return value from the response. But on either end, the function can simply be called: you can create an `add_todo` function that writes to your database, and simply call it from a click handler on a button in the browser!
## Using Server Functions
Actually, I kind of like that example. What would it look like? Its pretty simple, actually.
```rust
// todo.rs
#[server(AddTodo, "/api")]
pub async fn add_todo(title: String) -> Result<(), ServerFnError> {
let mut conn = db().await?;
match sqlx::query("INSERT INTO todos (title, completed) VALUES ($1, false)")
.bind(title)
.execute(&mut conn)
.await
{
Ok(_row) => Ok(()),
Err(e) => Err(ServerFnError::ServerError(e.to_string())),
}
}
#[component]
pub fn BusyButton(cx: Scope) -> impl IntoView {
view! {
cx,
<button on:click=move |_| {
spawn_local(async {
add_todo("So much to do!".to_string()).await;
});
}>
"Add Todo"
</button>
}
}
```
Youll notice a couple things here right away:
- Server functions can use server-only dependencies, like `sqlx`, and can access server-only resources, like our database.
- Server functions are `async`. Even if they only did synchronous work on the server, the function signature would still need to be `async`, because calling them from the browser _must_ be asynchronous.
- Server functions return `Result<T, ServerFnError>`. Again, even if they only do infallible work on the server, this is true, because `ServerFnError`s variants include the various things that can be wrong during the process of making a network request.
- Server functions can be called from the client. Take a look at our click handler. This is code that will _only ever_ run on the client. But it can call the function `add_todo` (using `spawn_local` to run the `Future`) as if it were an ordinary async function:
```rust
move |_| {
spawn_local(async {
add_todo("So much to do!".to_string()).await;
});
}
```
- Server functions are top-level functions defined with `fn`. Unlike event listeners, derived signals, and most everything else in Leptos, they are not closures! As `fn` calls, they have no access to the reactive state of your app or anything else that is not passed in as an argument. And again, this makes perfect sense: When you make a request to the server, the server doesnt have access to client state unless you send it explicitly. (Otherwise wed have to serialize the whole reactive system and send it across the wire with every request, which—while it served classic ASP for a while—is a really bad idea.)
- Server function arguments and return values both need to be serializable with `serde`. Again, hopefully this makes sense: while function arguments in general dont need to be serialized, calling a server function from the browser means serializing the arguments and sending them over HTTP.
There are a few things to note about the way you define a server function, too.
- Server functions are created by using the [`#[server]` macro](https://docs.rs/leptos_server/latest/leptos_server/index.html#server) to annotate a top-level function, which can be defined anywhere.
- We provide the macro a type name. The type name is used internally as a container to hold, serialize, and deserialize the arguments.
- We provide the macro a path. This is a prefix for the path at which well mount a server function handler on our server. (See examples for [Actix](https://github.com/leptos-rs/leptos/blob/main/examples/todo_app_sqlite/src/main.rs#L44) and [Axum](https://github.com/leptos-rs/leptos/blob/598523cd9d0d775b017cb721e41ebae9349f01e2/examples/todo_app_sqlite_axum/src/main.rs#L51).)
- Youll need to have `serde` as a dependency with the `derive` featured enabled for the macro to work properly. You can easily add it to `Cargo.toml` with `cargo add serde --features=derive`.
## Server Function Encodings
By default, the server function call is a `POST` request that serializes the arguments as URL-encoded form data in the body of the request. (This means that server functions can be called from HTML forms, which well see in a future chapter.) But there are a few other methods supported. Optionally, we can provide another argument to the `#[server]` macro to specify an alternate encoding:
```rust
#[server(AddTodo, "/api", "Url")]
#[server(AddTodo, "/api", "GetJson")]
#[server(AddTodo, "/api", "Cbor")]
#[server(AddTodo, "/api", "GetCbor")]
```
The four options use different combinations of HTTP verbs and encoding methods:
| Name | Method | Request | Response |
| ----------------- | ------ | ----------- | -------- |
| **Url** (default) | POST | URL encoded | JSON |
| **GetJson** | GET | URL encoded | JSON |
| **Cbor** | POST | CBOR | CBOR |
| **GetCbor** | GET | URL encoded | CBOR |
In other words, you have two choices:
- `GET` or `POST`? This has implications for things like browser or CDN caching; while `POST` requests should not be cached, `GET` requests can be.
- Plain text (arguments sent with URL/form encoding, results sent as JSON) or a binary format (CBOR, encoded as a base64 string)?
**But remember**: Leptos will handle all the details of this encoding and decoding for you. When you use a server function, it looks just like calling any other asynchronous function!
> **Why not `PUT` or `DELETE`? Why URL/form encoding, and not JSON?**
>
> These are reasonable questions. Much of the web is built on REST API patterns that encourage the use of semantic HTTP methods like `DELETE` to delete an item from a database, and many devs are accustomed to sending data to APIs in the JSON format.
>
> The reason we use `POST` or `GET` with URL-encoded data by default is the `<form>` support. For better or for worse, HTML forms dont support `PUT` or `DELETE`, and they dont support sending JSON. This means that if you use anything but a `GET` or `POST` request with URL-encoded data, it can only work once WASM has loaded. As well see [in a later chapter](../progressive_enhancement), this isnt always a great idea.
>
> The CBOR encoding is suported for historical reasons; an earlier version of server functions used a URL encoding that didnt support nested objects like structs or vectors as server function arguments, which CBOR did. But note that the CBOR forms encounter the same issue as `PUT`, `DELETE`, or JSON: they do not degrade gracefully if the WASM version of your app is not available.
## An Important Note on Security
Server functions are a cool technology, but its very important to remember. **Server functions are not magic; theyre syntax sugar for defining a public API.** The _body_ of a server function is never made public; its just part of your server binary. But the server function is a publicly accessible API endpoint, and its return value is just a JSON or similar blob. You should _never_ return something sensitive from a server function.
## Integrating Server Functions with Leptos
So far, everything Ive said is actually framework agnostic. (And in fact, the Leptos server function crate has been integrated into Dioxus as well!) Server functions are simply a way of defining a function-like RPC call that leans on Web standards like HTTP requests and URL encoding.
But in a way, they also provide the last missing primitive in our story so far. Because a server function is just a plain Rust async function, it integrates perfectly with the async Leptos primitives we discussed [earlier](../async/README.md). So you can easily integrate your server functions with the rest of your applications:
- Create **resources** that call the server function to load data from the server
- Read these resources under `<Suspense/>` or `<Transition/>` to enable streaming SSR and fallback states while data loads.
- Create **actions** that call the server function to mutate data on the server
The final section of this book will make this a little more concrete by introducing patterns that use progressively-enhanced HTML forms to run these server actions.
But in the next few chapters, well actually take a look at some of the details of what you might want to do with your server functions, including the best ways to integrate with the powerful extractors provided by the Actix and Axum server frameworks.
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/server/25_server_functions.html">
<link rel="canonical" href="https://book.leptos.dev/server/25_server_functions.html">

View File

@@ -1,73 +1,2 @@
# Extractors
The server functions we looked at in the last chapter showed how to run code on the server, and integrate it with the user interface youre rendering in the browser. But they didnt show you much about how to actually use your server to its full potential.
## Server Frameworks
We call Leptos a “full-stack” framework, but “full-stack” is always a misnomer (after all, it never means everything from the browser to your power company.) For us, “full stack” means that your Leptos app can run in the browser, and can run on the server, and can integrate the two, drawing together the unique features available in each; as weve seen in the book so far, a button click on the browser can drive a database read on the server, both written in the same Rust module. But Leptos itself doesnt provide the server (or the database, or the operating system, or the firmware, or the electrical cables...)
Instead, Leptos provides integrations for the two most popular Rust web server frameworks, Actix Web ([`leptos_actix`](https://docs.rs/leptos_actix/latest/leptos_actix/)) and Axum ([`leptos_axum`](https://docs.rs/leptos_actix/latest/leptos_axum/)). Weve built integrations with each servers router so that you can simply plug your Leptos app into an existing server with `.leptos_routes()`, and easily handle server function calls.
> If havent seen our [Actix](https://github.com/leptos-rs/start) and [Axum](https://github.com/leptos-rs/start-axum) templates, nows a good time to check them out.
## Using Extractors
Both Actix and Axum handlers are built on the same powerful idea of **extractors**. Extractors “extract” typed data from an HTTP request, allowing you to access server-specific data easily.
Leptos provides `extract` helper functions to let you use these extractors directly in your server functions, with a convenient syntax very similar to handlers for each framework.
### Actix Extractors
The [`extract` function in `leptos_actix`](https://docs.rs/leptos_actix/latest/leptos_actix/fn.extract.html) takes a handler function as its argument. The handler follows similar rules to an Actix handler: it is an async function that receives arguments that will be extracted from the request and returns some value. The handler function receives that extracted data as its arguments, and can do further `async` work on them inside the body of the `async move` block. It returns whatever value you return back out into the server function.
```rust
#[server(ActixExtract, "/api")]
pub async fn actix_extract(cx: Scope) -> Result<String, ServerFnError> {
use leptos_actix::extract;
use actix_web::dev::ConnectionInfo;
use actix_web::web::{Data, Query};
extract(cx,
|search: Query<Search>, connection: ConnectionInfo| async move {
format!(
"search = {}\nconnection = {:?}",
search.q,
connection
)
},
)
.await
}
```
## Axum Extractors
The syntax for the `leptos_axum::extract` function is very similar. (**Note**: This is available on the git main branch, but has not been released as of writing.) Note that Axum extractors return a `Result`, so youll need to add something to handle the error case.
```rust
#[server(AxumExtract, "/api")]
pub async fn axum_extract(cx: Scope) -> Result<String, ServerFnError> {
use axum::{extract::Query, http::Method};
use leptos_axum::extract;
extract(cx, |method: Method, res: Query<MyQuery>| async move {
format!("{method:?} and {}", res.q)
},
)
.await
.map_err(|e| ServerFnError::ServerError("Could not extract method and query...".to_string()))
}
```
These are relatively simple examples accessing basic data from the server. But you can use extractors to access things like headers, cookies, database connection pools, and more, using the exact same `extract()` pattern.
> Note: For now, the Axum `extract` function only supports extractors for which the state is `()`, i.e., you can't yet use it to extract `State(_)`. You can access `State(_)` by using a custom handler that extracts the state and then provides it via context. [Click here for an example](https://github.com/leptos-rs/leptos/blob/a5f73b441c079f9138102b3a7d8d4828f045448c/examples/session_auth_axum/src/main.rs#L91-L92).
## A Note about Data-Loading Patterns
Because Actix and (especially) Axum are built on the idea of a single round-trip HTTP request and response, you typically run extractors near the “top” of your application (i.e., before you start rendering) and use the extracted data to determine how that should be rendered. Before you render a `<button>`, you load all the data your app could need. And any given route handler needs to know all the data that will need to be extracted by that route.
But Leptos integrates both the client and the server, and its important to be able to refresh small pieces of your UI with new data from the server without forcing a full reload of all the data. So Leptos likes to push data loading “down” in your application, as far towards the leaves of your user interface as possible. When you click a `<button>`, it can refresh just the data it needs. This is exactly what server functions are for: they give you granular access to data to be loaded and reloaded.
The `extract()` functions let you combine both models by using extractors in your server functions. You get access to the full power of route extractors, while decentralizing knowledge of what needs to be extracted down to your individual components. This makes it easier to refactor and reorganize routes: you dont need to specify all the data a route needs up front.
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/server/26_extractors.html">
<link rel="canonical" href="https://book.leptos.dev/server/26_extractors.html">

View File

@@ -1,74 +1,2 @@
# Responses and Redirects
Extractors provide an easy way to access request data inside server functions. Leptos also provides a way to modify the HTTP response, using the `ResponseOptions` type (see docs for [Actix](https://docs.rs/leptos_actix/latest/leptos_actix/struct.ResponseOptions.html) or [Axum](https://docs.rs/leptos_axum/latest/leptos_axum/struct.ResponseOptions.html)) types and the `redirect` helper function (see docs for [Actix](https://docs.rs/leptos_actix/latest/leptos_actix/fn.redirect.html) or [Axum](https://docs.rs/leptos_axum/latest/leptos_axum/fn.redirect.html)).
## `ResponseOptions`
`ResponseOptions` is provided via context during the initial server rendering response and during any subsequent server function call. It allows you to easily set the status code for the HTTP response, or to add headers to the HTTP response, e.g., to set cookies.
```rust
#[server(TeaAndCookies)]
pub async fn tea_and_cookies(cx: Scope) -> Result<(), ServerFnError> {
use actix_web::{cookie::Cookie, http::header, http::header::HeaderValue};
use leptos_actix::ResponseOptions;
// pull ResponseOptions from context
let response = expect_context::<ResponseOptions>(cx);
// set the HTTP status code
response.set_status(StatusCode::IM_A_TEAPOT);
// set a cookie in the HTTP response
let mut cookie = Cookie::build("biscuits", "yes").finish();
if let Ok(cookie) = HeaderValue::from_str(&cookie.to_string()) {
res.insert_header(header::SET_COOKIE, cookie);
}
}
```
## `redirect`
One common modification to an HTTP response is to redirect to another page. The Actix and Axum integrations provide a `redirect` function to make this easy to do. `redirect` simply sets an HTTP status code of `302 Found` and sets the `Location` header.
Heres a simplified example from our [`session_auth_axum` example](https://github.com/leptos-rs/leptos/blob/a5f73b441c079f9138102b3a7d8d4828f045448c/examples/session_auth_axum/src/auth.rs#L154-L181).
```rust
#[server(Login, "/api")]
pub async fn login(
cx: Scope,
username: String,
password: String,
remember: Option<String>,
) -> Result<(), ServerFnError> {
// pull the DB pool and auth provider from context
let pool = pool(cx)?;
let auth = auth(cx)?;
// check whether the user exists
let user: User = User::get_from_username(username, &pool)
.await
.ok_or_else(|| {
ServerFnError::ServerError("User does not exist.".into())
})?;
// check whether the user has provided the correct password
match verify(password, &user.password)? {
// if the password is correct...
true => {
// log the user in
auth.login_user(user.id);
auth.remember_user(remember.is_some());
// and redirect to the home page
leptos_axum::redirect(cx, "/");
Ok(())
}
// if not, return an error
false => Err(ServerFnError::ServerError(
"Password does not match.".to_string(),
)),
}
}
```
This server function can then be used from your application. This `redirect` works well with the progressively-enhanced `<ActionForm/>` component: without JS/WASM, the server response will redirect because of the status code and header. With JS/WASM, the `<ActionForm/>` will detect the redirect in the server function response, and use client-side navigation to redirect to the new page.
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/server/27_response.html">
<link rel="canonical" href="https://book.leptos.dev/server/27_response.html">

View File

@@ -1,11 +1,2 @@
# Working with the Server
The previous section described the process of server-side rendering, using the server to generate an HTML version of the page that will become interactive in the browser. So far, everything has been “isomorphic” or “universal”; in other words, your app has had the “same (_iso_) shape (_morphe_)” on the client and the server.
But a server can do a lot more than just render HTML! In fact, a server can do a whole bunch of things your browser _cant,_ like reading from and writing to a SQL database.
If youre used to building JavaScript frontend apps, youre probably used to calling out to some kind of REST API to do this sort of server work. If youre used to building sites with PHP or Python or Ruby (or Java or C# or...), this server-side work is your bread and butter, and its the client-side interactivity that tends to be an afterthought.
With Leptos, you can do both: not only in the same language, not only sharing the same types, but even in the same files!
This section will talk about how to build the uniquely-server-side parts of your application.
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/server/index.html">
<link rel="canonical" href="https://book.leptos.dev/server/index.html">

View File

@@ -1,37 +1,2 @@
# Introducing `cargo-leptos`
So far, weve just been running code in the browser and using Trunk to coordinate the build process and run a local development process. If were going to add server-side rendering, well need to run our application code on the server as well. This means well need to build two separate binaries, one compiled to native code and running the server, the other compiled to WebAssembly (WASM) and running in the users browser. Additionally, the server needs to know how to serve this WASM version (and the JavaScript required to initialize it) to the browser.
This is not an insurmountable task but it adds some complication. For convenience and an easier developer experience, we built the [`cargo-leptos`](https://github.com/leptos-rs/cargo-leptos) build tool. `cargo-leptos` basically exists to coordinate the build process for your app, handling recompiling the server and client halves when you make changes, and adding some built-in support for things like Tailwind, SASS, and testing.
Getting started is pretty easy. Just run
```bash
cargo install cargo-leptos
```
And then to create a new project, you can run either
```bash
# for an Actix template
cargo leptos new --git leptos-rs/start
```
or
```bash
# for an Axum template
cargo leptos new --git leptos-rs/start-axum
```
Now `cd` into the directory youve created and run
```bash
cargo leptos watch
```
Once your app has compiled you can open up your browser to [`http://localhost:3000`](http://localhost:3000) to see it.
`cargo-leptos` has lots of additional features and built in tools. You can learn more [in its `README`](https://github.com/leptos-rs/cargo-leptos/blob/main/README.md).
But what exactly is happening when you open our browser to `localhost:3000`? Well, read on to find out.
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/ssr/21_cargo_leptos.html">
<link rel="canonical" href="https://book.leptos.dev/ssr/21_cargo_leptos.html">

View File

@@ -1,43 +1,2 @@
# The Life of a Page Load
Before we get into the weeds it might be helpful to have a higher-level overview. What exactly happens between the moment you type in the URL of a server-rendered Leptos app, and the moment you click a button and a counter increases?
Im assuming some basic knowledge of how the Internet works here, and wont get into the weeds about HTTP or whatever. Instead, Ill try to show how different parts of the Leptos APIs map onto each part of the process.
This description also starts from the premise that your app is being compiled for two separate targets:
1. A server version, often running on Actix or Axum, compiled with the Leptos `ssr` feature
2. A browser version, compiled to WebAssembly (WASM) with the Leptos `hydrate` feature
The [`cargo-leptos`](https://github.com/leptos-rs/cargo-leptos) build tool exists to coordinate the process of compiling your app for these two different targets.
## On the Server
- Your browser makes a `GET` request for that URL to your server. At this point, the browser knows almost nothing about the page thats going to be rendered. (The question “How does the browser know where to ask for the page?” is an interesting one, but out of the scope of this tutorial!)
- The server receives that request, and checks whether it has a way to handle a `GET` request at that path. This is what the `.leptos_routes()` methods in [`leptos_axum`](https://docs.rs/leptos_axum/0.2.5/leptos_axum/trait.LeptosRoutes.html) and [`leptos_actix`](https://docs.rs/leptos_actix/0.2.5/leptos_actix/trait.LeptosRoutes.html) are for. When the server starts up, these methods walk over the routing structure you provide in `<Routes/>`, generating a list of all possible routes your app can handle and telling the servers router “for each of these routes, if you get a request... hand it off to Leptos.”
- The server sees that this route can be handled by Leptos. So it renders your root component (often called something like `<App/>`), providing it with the URL thats being requested and some other data like the HTTP headers and request metadata.
- Your application runs once on the server, building up an HTML version of the component tree that will be rendered at that route. (Theres more to be said here about resources and `<Suspense/>` in the next chapter.)
- The server returns this HTML page, also injecting information on how to load the version of your app that has been compiled to WASM so that it can run in the browser.
> The HTML page thats returned is essentially your app, “dehydrated” or “freeze-dried”: it is HTML without any of the reactivity or event listeners youve added. The browser will “rehydrate” this HTML page by adding the reactive system and attaching event listeners to that server-rendered HTML. Hence the two feature flags that apply to the two halves of this process: `ssr` on the server for “server-side rendering”, and `hydrate` in the browser for that process of rehydration.
## In the Browser
- The browser receives this HTML page from the server. It immediately goes back to the server to begin loading the JS and WASM necessary to run the interactive, client side version of the app.
- In the meantime, it renders the HTML version.
- When the WASM version has reloaded, it does the same route-matching process that the server did. Because the `<Routes/>` component is identical on the server and in the client, the browser version will read the URL and render the same page that was already returned by the server.
- During this initial “hydration” phase, the WASM version of your app doesnt re-create the DOM nodes that make up your application. Instead, it walks over the existing HTML tree, “picking up” existing elements and adding the necessary interactivity.
> Note that there are some trade-offs here. Before this hydration process is complete, the page will _appear_ interactive but wont actually respond to interactions. For example, if you have a counter button and click it before WASM has loaded, the count will not increment, because the necessary event listeners and reactivity have not been added yet. Well look at some ways to build in “graceful degradation” in future chapters.
## Client-Side Navigation
The next step is very important. Imagine that the user now clicks a link to navigate to another page in your application.
The browser will _not_ make another round trip to the server, reloading the full page as it would for navigating between plain HTML pages or an application that uses server rendering (for example with PHP) but without a client-side half.
Instead, the WASM version of your app will load the new page, right there in the browser, without requesting another page from the server. Essentially, your app upgrades itself from a server-loaded “multi-page app” into a browser-rendered “single-page app.” This yields the best of both worlds: a fast initial load time due to the server-rendered HTML, and fast secondary navigations because of the client-side routing.
Some of what will be described in the following chapters—like the interactions between server functions, resources, and `<Suspense/>`—may seem overly complicated. You might find yourself asking, “If my page is being rendered to HTML on the server, why cant I just `.await` this on the server? If I can just call library X in a server function, why cant I call it in my component?” The reason is pretty simple: to enable the upgrade from server rendering to client rendering, everything in your application must be able to run either on the server or in the browser.
This is not the only way to create a website or web framework, of course. But its the most common way, and we happen to think its quite a good way, to create the smoothest possible experience for your users.
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/ssr/22_life_cycle.html">
<link rel="canonical" href="https://book.leptos.dev/ssr/22_life_cycle.html">

View File

@@ -1,132 +1,2 @@
# Async Rendering and SSR “Modes”
Server-rendering a page that uses only synchronous data is pretty simple: You just walk down the component tree, rendering each element to an HTML string. But this is a pretty big caveat: it doesnt answer the question of what we should do with pages that includes asynchronous data, i.e., the sort of stuff that would be rendered under a `<Suspense/>` node on the client.
When a page loads async data that it needs to render, what should we do? Should we wait for all the async data to load, and then render everything at once? (Lets call this “async” rendering) Should we go all the way in the opposite direction, just sending the HTML we have immediately down to the client and letting the client load the resources and fill them in? (Lets call this “synchronous” rendering) Or is there some middle-ground solution that somehow beats them both? (Hint: There is.)
If youve ever listened to streaming music or watched a video online, Im sure you realize that HTTP supports streaming, allowing a single connection to send chunks of data one after another without waiting for the full content to load. You may not realize that browsers are also really good at rendering partial HTML pages. Taken together, this means that you can actually enhance your users experience by **streaming HTML**: and this is something that Leptos supports out of the box, with no configuration at all. And theres actually more than one way to stream HTML: you can stream the chunks of HTML that make up your page in order, like frames of a video, or you can stream them... well, out of order.
Let me say a little more about what I mean.
Leptos supports all four different of these different ways to render HTML that includes asynchronous data.
## Synchronous Rendering
1. **Synchronous**: Serve an HTML shell that includes `fallback` for any `<Suspense/>`. Load data on the client using `create_local_resource`, replacing `fallback` once resources are loaded.
- _Pros_: App shell appears very quickly: great TTFB (time to first byte).
- _Cons_
- Resources load relatively slowly; you need to wait for JS + WASM to load before even making a request.
- No ability to include data from async resources in the `<title>` or other `<meta>` tags, hurting SEO and things like social media link previews.
If youre using server-side rendering, the synchronous mode is almost never what you actually want, from a performance perspective. This is because it misses out on an important optimization. If youre loading async resources during server rendering, you can actually begin loading the data on the server. Rather than waiting for the client to receive the HTML response, then loading its JS + WASM, _then_ realize it needs the resources and begin loading them, server rendering can actually begin loading the resources when the client first makes the response. In this sense, during server rendering an async resource is like a `Future` that begins loading on the server and resolves on the client. As long as the resources are actually serializable, this will always lead to a faster total load time.
> This is why [`create_resource`](https://docs.rs/leptos/latest/leptos/fn.create_resource.html) requires resources data to be serializable by default, and why you need to explicitly use [`create_local_resource`](https://docs.rs/leptos/latest/leptos/fn.create_local_resource.html) for any async data that is not serializable and should therefore only be loaded in the browser itself. Creating a local resource when you could create a serializable resource is always a deoptimization.
## Async Rendering
<video controls>
<source src="https://github.com/leptos-rs/leptos/blob/main/docs/video/async.mov?raw=true" type="video/mp4">
</video>
2. **`async`**: Load all resources on the server. Wait until all data are loaded, and render HTML in one sweep.
- _Pros_: Better handling for meta tags (because you know async data even before you render the `<head>`). Faster complete load than **synchronous** because async resources begin loading on server.
- _Cons_: Slower load time/TTFB: you need to wait for all async resources to load before displaying anything on the client. The page is totally blank until everything is loaded.
## In-Order Streaming
<video controls>
<source src="https://github.com/leptos-rs/leptos/blob/main/docs/video/in-order.mov?raw=true" type="video/mp4">
</video>
3. **In-order streaming**: Walk through the component tree, rendering HTML until you hit a `<Suspense/>`. Send down all the HTML youve got so far as a chunk in the stream, wait for all the resources accessed under the `<Suspense/>` to load, then render it to HTML and keep walking until you hit another `<Suspense/>` or the end of the page.
- _Pros_: Rather than a blank screen, shows at least _something_ before the data are ready.
- _Cons_
- Loads the shell more slowly than synchronous rendering (or out-of-order streaming) because it needs to pause at every `<Suspense/>`.
- Unable to show fallback states for `<Suspense/>`.
- Cant begin hydration until the entire page has loaded, so earlier pieces of the page will not be interactive until the suspended chunks have loaded.
## Out-of-Order Streaming
<video controls>
<source src="https://github.com/leptos-rs/leptos/blob/main/docs/video/out-of-order.mov?raw=true" type="video/mp4">
</video>
4. **Out-of-order streaming**: Like synchronous rendering, serve an HTML shell that includes `fallback` for any `<Suspense/>`. But load data on the **server**, streaming it down to the client as it resolves, and streaming down HTML for `<Suspense/>` nodes, which is swapped in to replace the fallback.
- _Pros_: Combines the best of **synchronous** and **`async`**.
- Fast initial response/TTFB because it immediately sends the whole synchronous shell
- Fast total time because resources begin loading on the server.
- Able to show the fallback loading state and dynamically replace it, instead of showing blank sections for un-loaded data.
- _Cons_: Requires JavaScript to be enabled for suspended fragments to appear in correct order. (This small chunk of JS streamed down in a `<script>` tag alongside the `<template>` tag that contains the rendered `<Suspense/>` fragment, so it does not need to load any additional JS files.)
5. **Partially-blocked streaming**: “Partially-blocked” streaming is useful when you have multiple separate `<Suspense/>` components on the page. If one of them reads from one or more “blocking resources” (see below), the fallback will not be sent; rather, the server will wait until that `<Suspense/>` has resolved and then replace the fallback with the resolved fragment on the server, which means that it is included in the initial HTML response and appears even if JavaScript is disabled or not supported. Other `<Suspense/>` stream in out of order as usual.
This is useful when you have multiple `<Suspense/>` on the page, and one is more important than the other: think of a blog post and comments, or product information and reviews. It is *not* useful if theres only one `<Suspense/>`, or if every `<Suspense/>` reads from blocking resources. In those cases it is a slower form of `async` rendering.
- _Pros_: Works if JavaScript is disabled or not supported on the users device.
- _Cons_
- Slower initial response time than out-of-order.
- Marginally overall response due to additional work on the server.
- No fallback state shown.
## Using SSR Modes
Because it offers the best blend of performance characteristics, Leptos defaults to out-of-order streaming. But its really simple to opt into these different modes. You do it by adding an `ssr` property onto one or more of your `<Route/>` components, like in the [`ssr_modes` example](https://github.com/leptos-rs/leptos/blob/main/examples/ssr_modes/src/app.rs).
```rust
<Routes>
// Well load the home page with out-of-order streaming and <Suspense/>
<Route path="" view=|cx| view! { cx, <HomePage/> }/>
// We'll load the posts with async rendering, so they can set
// the title and metadata *after* loading the data
<Route
path="/post/:id"
view=|cx| view! { cx, <Post/> }
ssr=SsrMode::Async
/>
</Routes>
```
For a path that includes multiple nested routes, the most restrictive mode will be used: i.e., if even a single nested route asks for `async` rendering, the whole initial request will be rendered `async`. `async` is the most restricted requirement, followed by in-order, and then out-of-order. (This probably makes sense if you think about it for a few minutes.)
## Blocking Resources
Any Leptos versions later than `0.2.5` (i.e., git main and `0.3.x` or later) introduce a new resource primitive with `create_blocking_resource`. A blocking resource still loads asynchronously like any other `async`/`.await` in Rust; it doesnt block a server thread or anything. Instead, reading from a blocking resource under a `<Suspense/>` blocks the HTML _stream_ from returning anything, including its initial synchronous shell, until that `<Suspense/>` has resolved.
Now from a performance perspective, this is not ideal. None of the synchronous shell for your page will load until that resource is ready. However, rendering nothing means that you can do things like set the `<title>` or `<meta>` tags in your `<head>` in actual HTML. This sounds a lot like `async` rendering, but theres one big difference: if you have multiple `<Suspense/>` sections, you can block on _one_ of them but still render a placeholder and then stream in the other.
For example, think about a blog post. For SEO and for social sharing, I definitely want my blog posts title and metadata in the initial HTML `<head>`. But I really dont care whether comments have loaded yet or not; Id like to load those as lazily as possible.
With blocking resources, I can do something like this:
```rust
#[component]
pub fn BlogPost(cx: Scope) -> impl IntoView {
let post_data = create_blocking_resource(cx, /* load blog post */);
let comment_data = create_resource(cx, /* load blog post */);
view! { cx,
<Suspense fallback=|| ()>
{move || {
post_data.with(cx, |data| {
view! { cx,
<Title text=data.title/>
<Meta name="description" content=data.excerpt/>
<article>
/* render the post content */
</article>
}
})
}}
</Suspense>
<Suspense fallback=|| "Loading comments...">
/* render comment data here */
</Suspense>
}
}
```
The first `<Suspense/>`, with the body of the blog post, will block my HTML stream, because it reads from a blocking resource. The second `<Suspense/>`, with the comments, will not block the stream. Blocking resources gave me exactly the power and granularity I needed to optimize my page for SEO and user experience.
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/ssr/23_ssr_modes.html">
<link rel="canonical" href="https://book.leptos.dev/ssr/23_ssr_modes.html">

View File

@@ -1,198 +1,2 @@
# Hydration Bugs _(and how to avoid them)_
## A Thought Experiment
Lets try an experiment to test your intuitions. Open up an app youre server-rendering with `cargo-leptos`. (If youve just been using `trunk` so far to play with examples, go [clone a `cargo-leptos` template](./21_cargo_leptos.md) just for the sake of this exercise.)
Put a log somewhere in your root component. (I usually call mine `<App/>`, but anything will do.)
```rust
#[component]
pub fn App(cx: Scope) -> impl IntoView {
leptos::log!("where do I run?");
// ... whatever
}
```
And lets fire it up
```bash
cargo leptos watch
```
Where do you expect `where do I run?` to log?
- In the command line where youre running the server?
- In the browser console when you load the page?
- Neither?
- Both?
Try it out.
...
...
...
Okay, consider the spoiler alerted.
Youll notice of course that it logs in both places, assuming everything goes according to plan. In fact on the server it logs twice—first during the initial server startup, when Leptos renders your app once to extract the route tree, then a second time when you make a request. Each time you reload the page, `where do I run?` should log once on the server and once on the client.
If you think about the description in the last couple sections, hopefully this makes sense. Your application runs once on the server, where it builds up a tree of HTML which is sent to the client. During this initial render, `where do I run?` logs on the server.
Once the WASM binary has loaded in the browser, your application runs a second time, walking over the same user interface tree and adding interactivity.
> Does that sound like a waste? It is, in a sense. But reducing that waste is a genuinely hard problem. Its what some JS frameworks like Qwik are intended to solve, although its probably too early to tell whether its a net performance gain as opposed to other approaches.
## The Potential for Bugs
Okay, hopefully all of that made sense. But what does it have to do with the title of this chapter, which is “Hydration bugs (and how to avoid them)”?
Remember that the application needs to run on both the server and the client. This generates a few different sets of potential issues you need to know how to avoid.
### Mismatches between server and client code
One way to create a bug is by creating a mismatch between the HTML thats sent down by the server and whats rendered on the client. Its actually fairly hard to do this unintentionally, I think (at least judging by the bug reports I get from people.) But imagine I do something like this
```rust
#[component]
pub fn App(cx: Scope) -> impl IntoView {
let data = if cfg!(target_arch = "wasm32") {
vec![0, 1, 2]
} else {
vec![]
};
data.into_iter()
.map(|value| view! { cx, <span>{value}</span> })
.collect_view(cx)
}
```
In other words, if this is being compiled to WASM, it has three items; otherwise its empty.
When I load the page in the browser, I see nothing. If I open the console I see a bunch of warnings:
```
element with id 0-3 not found, ignoring it for hydration
element with id 0-4 not found, ignoring it for hydration
element with id 0-5 not found, ignoring it for hydration
component with id _0-6c not found, ignoring it for hydration
component with id _0-6o not found, ignoring it for hydration
```
The WASM version of your app, running in the browser, expects to find three items; but the HTML has none.
#### Solution
Its pretty rare that you do this intentionally, but it could happen from somehow running different logic on the server and in the browser. If youre seeing warnings like this and you dont think its your fault, its much more likely that its a bug with `<Suspense/>` or something. Feel free to go ahead and open an [issue](https://github.com/leptos-rs/leptos/issues) or [discussion](https://github.com/leptos-rs/leptos/discussions) on GitHub for help.
### Mutating the DOM during rendering
This is a slightly more common way to create a client/server mismatch: updating a signal _during rendering_ in a way that mutates the view.
```rust
#[component]
pub fn App(cx: Scope) -> impl IntoView {
let (loaded, set_loaded) = create_signal(cx, false);
// create_effect only runs on the client
create_effect(cx, move |_| {
// do something like reading from localStorage
set_loaded(true);
});
move || {
if loaded() {
view! { cx, <p>"Hello, world!"</p> }.into_any()
} else {
view! { cx, <div class="loading">"Loading..."</div> }.into_any()
}
}
}
```
This one gives us the scary panic
```
panicked at 'assertion failed: `(left == right)`
left: `"DIV"`,
right: `"P"`: SSR and CSR elements have the same hydration key but different node kinds.
```
And a handy link to this page!
The problem here is that `create_effect` runs **immediately** and **synchronously**, but only in the browser. As a result, on the server, `loaded` is false, and a `<div>` is rendered. But on the browser, by the time the view is being rendered, `loaded` has already been set to `true`, and the browser is expecting to find a `<p>`.
#### Solution
You can simply tell the effect to wait a tick before updating the signal, by using something like `request_animation_frame`, which will set a short timeout and then update the signal before the next frame.
```rust
create_effect(cx, move |_| {
// do something like reading from localStorage
request_animation_frame(move || set_loaded(true));
});
```
This allows the browser to hydrate with the correct, matching state (`loaded` is `false` when it reaches the view), then immediately update it to `true` once hydration is complete.
### Not all client code can run on the server
Imagine you happily import a dependency like `gloo-net` that youve been used to using to make requests in the browser, and use it in a `create_resource` in a server-rendered app.
Youll probably instantly see the dreaded message
```
panicked at 'cannot call wasm-bindgen imported functions on non-wasm targets'
```
Uh-oh.
But of course this makes sense. Weve just said that your app needs to run on the client and the server.
#### Solution
There are a few ways to avoid this:
1. Only use libraries that can run on both the server and the client. `reqwest`, for example, works for making HTTP requests in both settings.
2. Use different libraries on the server and the client, and gate them using the `#[cfg]` macro. ([Click here for an example](https://github.com/leptos-rs/leptos/blob/main/examples/hackernews/src/api.rs).)
3. Wrap client-only code in `create_effect`. Because `create_effect` only runs on the client, this can be an effective way to access browser APIs that are not needed for initial rendering.
For example, say that I want to store something in the browsers `localStorage` whenever a signal changes.
```rust
#[component]
pub fn App(cx: Scope) -> impl IntoView {
use gloo_storage::Storage;
let storage = gloo_storage::LocalStorage::raw();
leptos::log!("{storage:?}");
}
```
This panics because I cant access `LocalStorage` during server rendering.
But if I wrap it in an effect...
```rust
#[component]
pub fn App(cx: Scope) -> impl IntoView {
use gloo_storage::Storage;
create_effect(cx, move |_| {
let storage = gloo_storage::LocalStorage::raw();
leptos::log!("{storage:?}");
});
}
```
Its fine! This will render appropriately on the server, ignoring the client-only code, and then access the storage and log a message on the browser.
### Not all server code can run on the client
WebAssembly running in the browser is a pretty limited environment. You dont have access to a file-system or to many of the other things the standard library may be used to having. Not every crate can even be compiled to WASM, let alone run in a WASM environment.
In particular, youll sometimes see errors about the crate `mio` or missing things from `core`. This is generally a sign that you are trying to compile something to WASM that cant be compiled to WASM. If youre adding server-only dependencies, youll want to mark them `optional = true` in your `Cargo.toml` and then enable them in the `ssr` feature definition. (Check out one of the template `Cargo.toml` files to see more details.)
You can use `create_effect` to specify that something should only run on the client, and not in the server. Is there a way to specify that something should run only on the server, and not the client?
In fact, there is. The next chapter will cover the topic of server functions in some detail. (In the meantime, you can check out their docs [here](https://docs.rs/leptos_server/0.2.5/leptos_server/index.html).)
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/ssr/24_hydration_bugs.html">
<link rel="canonical" href="https://book.leptos.dev/ssr/24_hydration_bugs.html">

View File

@@ -1,21 +1,2 @@
# Server Side Rendering
So far, everything weve written has been rendered almost entirely in the browser. When we create an app using Trunk, its served using a local development server. If you build it for production and deploy it, its served by whatever server or CDN youre using. In either case, whats served is an HTML page with
1. the URL of your Leptos app, which has been compiled to WebAssembly (WASM)
2. the URL of the JavaScript used to initialized this WASM blob
3. an empty `<body>` element
When the JS and WASM have loaded, Leptos will render your app into the `<body>`. This means that nothing appears on the screen until JS/WASM have loaded and run. This has some drawbacks:
1. It increases load time, as your users screen is blank until additional resources have been downloaded.
2. Its bad for SEO, as load times are longer and the HTML you serve has no meaningful content.
3. Its broken for users for whom JS/WASM dont load for some reason (e.g., theyre on a train and just went into a tunnel before WASM finished loading; theyre using an older device that doesnt support WASM; they have JavaScript or WASM turned off for some reason; etc.)
These downsides apply across the web ecosystem, but especially to WASM apps.
So what do you do if you want to return more than just an empty `<body>` tag? Use “server-side rendering.”
Whole books could be (and probably have been) written about this topic, but at its core, its really simple: rather than returning an empty `<body>` tag, return an initial HTML page that reflects the actual starting state of your app or site, so that while JS/WASM are loading, and until they load, the user can access the plain HTML version.
The rest of this section will cover this topic in some detail!
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/ssr/index.html">
<link rel="canonical" href="https://book.leptos.dev/ssr/index.html">

View File

@@ -1,180 +1,2 @@
# Testing Your Components
Testing user interfaces can be relatively tricky, but really important. This article
will discuss a couple principles and approaches for testing a Leptos app.
## 1. Test business logic with ordinary Rust tests
In many cases, it makes sense to pull the logic out of your components and test
it separately. For some simple components, theres no particular logic to test, but
for many its worth using a testable wrapping type and implementing the logic in
ordinary Rust `impl` blocks.
For example, instead of embedding logic in a component directly like this:
```rust
#[component]
pub fn TodoApp(cx: Scope) -> impl IntoView {
let (todos, set_todos) = create_signal(cx, vec![Todo { /* ... */ }]);
// ⚠️ this is hard to test because it's embedded in the component
let num_remaining = move || todos.with(|todos| {
todos.iter().filter(|todo| !todo.completed).sum()
});
}
```
You could pull that logic out into a separate data structure and test it:
```rust
pub struct Todos(Vec<Todo>);
impl Todos {
pub fn num_remaining(&self) -> usize {
todos.iter().filter(|todo| !todo.completed).sum()
}
}
#[cfg(test)]
mod tests {
#[test]
fn test_remaining {
// ...
}
}
#[component]
pub fn TodoApp(cx: Scope) -> impl IntoView {
let (todos, set_todos) = create_signal(cx, Todos(vec![Todo { /* ... */ }]));
// ✅ this has a test associated with it
let num_remaining = move || todos.with(Todos::num_remaining);
}
```
In general, the less of your logic is wrapped into your components themselves, the
more idiomatic your code will feel and the easier it will be to test.
## 2. Test components with `wasm-bindgen-test`
[`wasm-bindgen-test`](https://crates.io/crates/wasm-bindgen-test) is a great utility
for integrating or end-to-end testing WebAssembly apps in a headless browser.
To use this testing utility, you need to add `wasm-bindgen-test` to your `Cargo.toml`:
```toml
[dev-dependencies]
wasm-bindgen-test = "0.3.0"
```
You should create tests in a separate `tests` directory. You can then run your tests in the browser of your choice:
```bash
wasm-pack test --firefox
```
> To see the full setup, check out the tests for the [`counter`](https://github.com/leptos-rs/leptos/tree/main/examples/counter) example.
### Writing Your Tests
Most tests will involve some combination of vanilla DOM manipulation and comparison to a `view`. For example, heres a test [for the
`counter` example](https://github.com/leptos-rs/leptos/blob/main/examples/counter/tests/mod.rs).
First, we set up the testing environment.
```rust
use wasm_bindgen_test::*;
use counter::*;
use leptos::*;
use web_sys::HtmlElement;
// tell the test runner to run tests in the browser
wasm_bindgen_test_configure!(run_in_browser);
```
Im going to create a simpler wrapper for each test case, and mount it there.
This makes it easy to encapsulate the test results.
```rust
// like marking a regular test with #[test]
#[wasm_bindgen_test]
fn clear() {
let document = leptos::document();
let test_wrapper = document.create_element("section").unwrap();
document.body().unwrap().append_child(&test_wrapper);
// start by rendering our counter and mounting it to the DOM
// note that we start at the initial value of 10
mount_to(
test_wrapper.clone().unchecked_into(),
|cx| view! { cx, <SimpleCounter initial_value=10 step=1/> },
);
}
```
Well use some manual DOM operations to grab the `<div>` that wraps
the whole component, as well as the `clear` button.
```rust
// now we extract the buttons by iterating over the DOM
// this would be easier if they had IDs
let div = test_wrapper.query_selector("div").unwrap().unwrap();
let clear = test_wrapper
.query_selector("button")
.unwrap()
.unwrap()
.unchecked_into::<web_sys::HtmlElement>();
```
Now we can use ordinary DOM APIs to simulate user interaction.
```rust
// now let's click the `clear` button
clear.click();
```
You can test individual DOM element attributes or text node values. Sometimes
I like to test the whole view at once. We can do this by testing the elements
`outerHTML` against our expectations.
```rust
assert_eq!(
div.outer_html(),
// here we spawn a mini reactive system to render the test case
run_scope(create_runtime(), |cx| {
// it's as if we're creating it with a value of 0, right?
let (value, set_value) = create_signal(cx, 0);
// we can remove the event listeners because they're not rendered to HTML
view! { cx,
<div>
<button>"Clear"</button>
<button>"-1"</button>
<span>"Value: " {value} "!"</span>
<button>"+1"</button>
</div>
}
// the view returned an HtmlElement<Div>, which is a smart pointer for
// a DOM element. So we can still just call .outer_html()
.outer_html()
})
);
```
That test involved us manually replicating the `view` thats inside the component.
There's actually an easier way to do this... We can just test against a `<SimpleCounter/>`
with the initial value `0`. This is where our wrapping element comes in: Ill just test
the wrappers `innerHTML` against another comparison case.
```rust
assert_eq!(test_wrapper.inner_html(), {
let comparison_wrapper = document.create_element("section").unwrap();
leptos::mount_to(
comparison_wrapper.clone().unchecked_into(),
|cx| view! { cx, <SimpleCounter initial_value=0 step=1/>},
);
comparison_wrapper.inner_html()
});
```
This is only a very limited introduction to testing. But I hope its useful as you begin to build applications.
> For more, see [the testing section of the `wasm-bindgen` guide](https://rustwasm.github.io/wasm-bindgen/wasm-bindgen-test/index.html#testing-on-wasm32-unknown-unknown-with-wasm-bindgen-test).
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/testing.html">
<link rel="canonical" href="https://book.leptos.dev/testing.html">

View File

@@ -1,162 +1,2 @@
# A Basic Component
That “Hello, world!” was a _very_ simple example. Lets move on to something a
little more like an ordinary app.
First, lets edit the `main` function so that, instead of rendering the whole
app, it just renders an `<App/>` component. Components are the basic unit of
composition and design in most web frameworks, and Leptos is no exception.
Conceptually, they are similar to HTML elements: they represent a section of the
DOM, with self-contained, defined behavior. Unlike HTML elements, they are in
`PascalCase`, so most Leptos applications will start with something like an
`<App/>` component.
```rust
fn main() {
leptos::mount_to_body(|cx| view! { cx, <App/> })
}
```
Now lets define our `<App/>` component itself. Because its relatively simple,
Ill give you the whole thing up front, then walk through it line by line.
```rust
#[component]
fn App(cx: Scope) -> impl IntoView {
let (count, set_count) = create_signal(cx, 0);
view! { cx,
<button
on:click=move |_| {
set_count(3);
}
>
"Click me: "
{move || count.get()}
</button>
}
}
```
## The Component Signature
```rust
#[component]
```
Like all component definitions, this begins with the [`#[component]`](https://docs.rs/leptos/latest/leptos/attr.component.html) macro. `#[component]` annotates a function so it can be
used as a component in your Leptos application. Well see some of the other features of
this macro in a couple chapters.
```rust
fn App(cx: Scope) -> impl IntoView
```
Every component is a function with the following characteristics
1. It takes a reactive [`Scope`](https://docs.rs/leptos/latest/leptos/struct.Scope.html)
as its first argument. This `Scope` is our entrypoint into the reactive system.
By convention, its usually named `cx`.
2. You can include other arguments, which will be available as component “props.”
3. Component functions return `impl IntoView`, which is an opaque type that includes
anything you could return from a Leptos `view`.
## The Component Body
The body of the component function is a set-up function that runs once, not a
render function that reruns multiple times. Youll typically use it to create a
few reactive variables, define any side effects that run in response to those values
changing, and describe the user interface.
```rust
let (count, set_count) = create_signal(cx, 0);
```
[`create_signal`](https://docs.rs/leptos/latest/leptos/fn.create_signal.html)
creates a signal, the basic unit of reactive change and state management in Leptos.
This returns a `(getter, setter)` tuple. To access the current value, youll
use `count.get()` (or, on `nightly` Rust, the shorthand `count()`). To set the
current value, youll call `set_count.set(...)` (or `set_count(...)`).
> `.get()` clones the value and `.set()` overwrites it. In many cases, its more efficient to use `.with()` or `.update()`; check out the docs for [`ReadSignal`](https://docs.rs/leptos/latest/leptos/struct.ReadSignal.html) and [`WriteSignal`](https://docs.rs/leptos/latest/leptos/struct.WriteSignal.html) if youd like to learn more about those trade-offs at this point.
## The View
Leptos defines user interfaces using a JSX-like format via the [`view`](https://docs.rs/leptos/latest/leptos/macro.view.html) macro.
```rust
view! { cx,
<button
// define an event listener with on:
on:click=move |_| {
// on stable, this is set_count.set(3);
set_count(3);
}
>
// text nodes are wrapped in quotation marks
"Click me: "
// blocks can include Rust code
{move || count.get()}
</button>
}
```
This should mostly be easy to understand: it looks like HTML, with a special
`on:click` to define a `click` event listener, a text node thats formatted like
a Rust string, and then...
```rust
{move || count.get()}
```
whatever that is.
People sometimes joke that they use more closures in their first Leptos application
than theyve ever used in their lives. And fair enough. Basically, passing a function
into the view tells the framework: “Hey, this is something that might change.”
When we click the button and call `set_count`, the `count` signal is updated. This
`move || count.get()` closure, whose value depends on the value of `count`, reruns,
and the framework makes a targeted update to that one specific text node, touching
nothing else in your application. This is what allows for extremely efficient updates
to the DOM.
Now, if you have Clippy on—or if you have a particularly sharp eye—you might notice
that this closure is redundant, at least if youre in `nightly` Rust. If youre using
Leptos with `nightly` Rust, signals are already functions, so the closure is unnecessary.
As a result, you can write a simpler view:
```rust
view! { cx,
<button /* ... */>
"Click me: "
// identical to {move || count.get()}
{count}
</button>
}
```
Remember—and this is _very important_—only functions are reactive. This means that
`{count}` and `{count()}` do very different things in your view. `{count}` passes
in a function, telling the framework to update the view every time `count` changes.
`{count()}` access the value of `count` once, and passes an `i32` into the view,
rendering it once, unreactively. You can see the difference in the CodeSandbox below!
Lets make one final change. `set_count(3)` is a pretty useless thing for a click handler to do. Lets replace “set this value to 3” with “increment this value by 1”:
```rust
move |_| {
set_count.update(|n| *n += 1);
}
```
You can see here that while `set_count` just sets the value, `set_count.update()` gives us a mutable reference and mutates the value in place. Either one will trigger a reactive update in our UI.
> Throughout this tutorial, well use CodeSandbox to show interactive examples. To
> show the browser in the sandbox, you may need to click `Add DevTools >
Other Previews > 8080.` Hover over any of the variables to show Rust-Analyzer details
> and docs for whats going on. Feel free to fork the examples to play with them yourself!
[Click to open CodeSandbox.](https://codesandbox.io/p/sandbox/1-basic-component-3d74p3?file=%2Fsrc%2Fmain.rs&selection=%5B%7B%22endColumn%22%3A31%2C%22endLineNumber%22%3A19%2C%22startColumn%22%3A31%2C%22startLineNumber%22%3A19%7D%5D)
<iframe src="https://codesandbox.io/p/sandbox/1-basic-component-3d74p3?file=%2Fsrc%2Fmain.rs&selection=%5B%7B%22endColumn%22%3A31%2C%22endLineNumber%22%3A19%2C%22startColumn%22%3A31%2C%22startLineNumber%22%3A19%7D%5D" width="100%" height="1000px" style="max-height: 100vh"></iframe>
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/view/01_basic_component.html">
<link rel="canonical" href="https://book.leptos.dev/view/01_basic_component.html">

View File

@@ -1,154 +1,2 @@
# `view`: Dynamic Classes, Styles and Attributes
So far weve seen how to use the `view` macro to create event listeners and to
create dynamic text by passing a function (such as a signal) into the view.
But of course there are other things you might want to update in your user interface.
In this section, well look at how to update classes, styles and attributes dynamically,
and well introduce the concept of a **derived signal**.
Lets start with a simple component that should be familiar: click a button to
increment a counter.
```rust
#[component]
fn App(cx: Scope) -> impl IntoView {
let (count, set_count) = create_signal(cx, 0);
view! { cx,
<button
on:click=move |_| {
set_count.update(|n| *n += 1);
}
>
"Click me: "
{move || count()}
</button>
}
}
```
So far, this is just the example from the last chapter.
## Dynamic Classes
Now lets say Id like to update the list of CSS classes on this element dynamically.
For example, lets say I want to add the class `red` when the count is odd. I can
do this using the `class:` syntax.
```rust
class:red=move || count() % 2 == 1
```
`class:` attributes take
1. the class name, following the colon (`red`)
2. a value, which can be a `bool` or a function that returns a `bool`
When the value is `true`, the class is added. When the value is `false`, the class
is removed. And if the value is a function that accesses a signal, the class will
reactively update when the signal changes.
Now every time I click the button, the text should toggle between red and black as
the number switches between even and odd.
Some CSS class names cant be directly parsed by the `view` macro, especially if they include a mix of dashes and numbers or other characters. In that case, you can use a tuple syntax: `class=("name", value)` still directly updates a single class.
```rust
class=("button-20", move || count() % 2 == 1)
```
> If youre following along, make sure you go into your `index.html` and add something like this:
>
> ```html
> <style>
> .red {
> color: red;
> }
> </style>
> ```
## Dynamic Styles
Individual CSS properties can be directly updated with a similar `style:` syntax.
```rust
let (x, set_x) = create_signal(cx, 0);
let (y, set_y) = create_signal(cx, 0);
view! { cx,
<div
style="position: absolute"
style:left=move || format!("{}px", x() + 100)
style:top=move || format!("{}px", y() + 100)
style:background-color=move || format!("rgb({}, {}, 100)", x(), y())
style=("--columns", x)
>
"Moves when coordinates change"
</div>
}
```
## Dynamic Attributes
The same applies to plain attributes. Passing a plain string or primitive value to
an attribute gives it a static value. Passing a function (including a signal) to
an attribute causes it to update its value reactively. Lets add another element
to our view:
```rust
<progress
max="50"
// signals are functions, so this <=> `move || count.get()`
value=count
/>
```
Now every time we set the count, not only will the `class` of the `<button>` be
toggled, but the `value` of the `<progress>` bar will increase, which means that
our progress bar will move forward.
## Derived Signals
Lets go one layer deeper, just for fun.
You already know that we create reactive interfaces just by passing functions into
the `view`. This means that we can easily change our progress bar. For example,
suppose we want it to move twice as fast:
```rust
<progress
max="50"
value=move || count() * 2
/>
```
But imagine we want to reuse that calculation in more than one place. You can do this
using a **derived signal**: a closure that accesses a signal.
```rust
let double_count = move || count() * 2;
/* insert the rest of the view */
<progress
max="50"
// we use it once here
value=double_count
/>
<p>
"Double Count: "
// and again here
{double_count}
</p>
```
Derived signals let you create reactive computed values that can be used in multiple
places in your application with minimal overhead.
> Note: Using a derived signal like this means that the calculation runs once per
> signal change per place we access `double_count`; in other words, twice. This is a
> very cheap calculation, so thats fine. Well look at memos in a later chapter, which
> are designed to solve this problem for expensive calculations.
[Click to open CodeSandbox.](https://codesandbox.io/p/sandbox/2-dynamic-attribute-pqyvzl?file=%2Fsrc%2Fmain.rs&selection=%5B%7B%22endColumn%22%3A1%2C%22endLineNumber%22%3A2%2C%22startColumn%22%3A1%2C%22startLineNumber%22%3A2%7D%5D)
<iframe src="https://codesandbox.io/p/sandbox/2-dynamic-attribute-pqyvzl?file=%2Fsrc%2Fmain.rs&selection=%5B%7B%22endColumn%22%3A1%2C%22endLineNumber%22%3A2%2C%22startColumn%22%3A1%2C%22startLineNumber%22%3A2%7D%5D" width="100%" height="1000px" style="max-height: 100vh"></iframe>
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/view/02_dynamic_attributes.html">
<link rel="canonical" href="https://book.leptos.dev/view/02_dynamic_attributes.html">

View File

@@ -1,311 +1,2 @@
# Components and Props
So far, weve been building our whole application in a single component. This
is fine for really tiny examples, but in any real application youll need to
break the user interface out into multiple components, so you can break your
interface down into smaller, reusable, composable chunks.
Lets take our progress bar example. Imagine that you want two progress bars
instead of one: one that advances one tick per click, one that advances two ticks
per click.
You _could_ do this by just creating two `<progress>` elements:
```rust
let (count, set_count) = create_signal(cx, 0);
let double_count = move || count() * 2;
view! { cx,
<progress
max="50"
value=count
/>
<progress
max="50"
value=double_count
/>
}
```
But of course, this doesnt scale very well. If you want to add a third progress
bar, you need to add this code another time. And if you want to edit anything
about it, you need to edit it in triplicate.
Instead, lets create a `<ProgressBar/>` component.
```rust
#[component]
fn ProgressBar(
cx: Scope
) -> impl IntoView {
view! { cx,
<progress
max="50"
// hmm... where will we get this from?
value=progress
/>
}
}
```
Theres just one problem: `progress` is not defined. Where should it come from?
When we were defining everything manually, we just used the local variable names.
Now we need some way to pass an argument into the component.
## Component Props
We do this using component properties, or “props.” If youve used another frontend
framework, this is probably a familiar idea. Basically, properties are to components
as attributes are to HTML elements: they let you pass additional information into
the component.
In Leptos, you define props by giving additional arguments to the component function.
```rust
#[component]
fn ProgressBar(
cx: Scope,
progress: ReadSignal<i32>
) -> impl IntoView {
view! { cx,
<progress
max="50"
// now this works
value=progress
/>
}
}
```
Now we can use our component in the main `<App/>` components view.
```rust
#[component]
fn App(cx: Scope) -> impl IntoView {
let (count, set_count) = create_signal(cx, 0);
view! { cx,
<button on:click=move |_| { set_count.update(|n| *n += 1); }>
"Click me"
</button>
// now we use our component!
<ProgressBar progress=count/>
}
}
```
Using a component in the view looks a lot like using an HTML element. Youll
notice that you can easily tell the difference between an element and a component
because components always have `PascalCase` names. You pass the `progress` prop
in as if it were an HTML element attribute. Simple.
### Reactive and Static Props
Youll notice that throughout this example, `progress` takes a reactive
`ReadSignal<i32>`, and not a plain `i32`. This is **very important**.
Component props have no special meaning attached to them. A component is simply
a function that runs once to set up the user interface. The only way to tell the
interface to respond to changing is to pass it a signal type. So if you have a
component property that will change over time, like our `progress`, it should
be a signal.
### `optional` Props
Right now the `max` setting is hard-coded. Lets take that as a prop too. But
lets add a catch: lets make this prop optional by annotating the particular
argument to the component function with `#[prop(optional)]`.
```rust
#[component]
fn ProgressBar(
cx: Scope,
// mark this prop optional
// you can specify it or not when you use <ProgressBar/>
#[prop(optional)]
max: u16,
progress: ReadSignal<i32>
) -> impl IntoView {
view! { cx,
<progress
max=max
value=progress
/>
}
}
```
Now, we can use `<ProgressBar max=50 value=count/>`, or we can omit `max`
to use the default value (i.e., `<ProgressBar value=count/>`). The default value
on an `optional` is its `Default::default()` value, which for a `u16` is going to
be `0`. In the case of a progress bar, a max value of `0` is not very useful.
So lets give it a particular default value instead.
### `default` props
You can specify a default value other than `Default::default()` pretty simply
with `#[prop(default = ...)`.
```rust
#[component]
fn ProgressBar(
cx: Scope,
#[prop(default = 100)]
max: u16,
progress: ReadSignal<i32>
) -> impl IntoView {
view! { cx,
<progress
max=max
value=progress
/>
}
}
```
### Generic Props
This is great. But we began with two counters, one driven by `count`, and one by
the derived signal `double_count`. Lets recreate that by using `double_count`
as the `progress` prop on another `<ProgressBar/>`.
```rust
#[component]
fn App(cx: Scope) -> impl IntoView {
let (count, set_count) = create_signal(cx, 0);
let double_count = move || count() * 2;
view! { cx,
<button on:click=move |_| { set_count.update(|n| *n += 1); }>
"Click me"
</button>
<ProgressBar progress=count/>
// add a second progress bar
<ProgressBar progress=double_count/>
}
}
```
Hm... this wont compile. It should be pretty easy to understand why: weve declared
that the `progress` prop takes `ReadSignal<i32>`, and `double_count` is not
`ReadSignal<i32>`. As rust-analyzer will tell you, its type is `|| -> i32`, i.e.,
its a closure that returns an `i32`.
There are a couple ways to handle this. One would be to say: “Well, I know that
a `ReadSignal` is a function, and I know that a closure is a function; maybe I
could just take any function?” If youre savvy, you may know that both these
implement the trait `Fn() -> i32`. So you could use a generic component:
```rust
#[component]
fn ProgressBar<F>(
cx: Scope,
#[prop(default = 100)]
max: u16,
progress: F
) -> impl IntoView
where
F: Fn() -> i32 + 'static,
{
view! { cx,
<progress
max=max
value=progress
/>
}
}
```
This is a perfectly reasonable way to write this component: `progress` now takes
any value that implements this `Fn()` trait.
> Note that generic component props _cannot_ be specified inline (as `<F: Fn() -> i32>`)
> or as `progress: impl Fn() -> i32 + 'static,`, in part because theyre actually used to generate
> a `struct ProgressBarProps`, and struct fields cannot be `impl` types.
### `into` Props
Theres one more way we could implement this, and it would be to use `#[prop(into)]`.
This attribute automatically calls `.into()` on the values you pass as props,
which allows you to easily pass props with different values.
In this case, its helpful to know about the
[`Signal`](https://docs.rs/leptos/latest/leptos/struct.Signal.html) type. `Signal`
is an enumerated type that represents any kind of readable reactive signal. It can
be useful when defining APIs for components youll want to reuse while passing
different sorts of signals. The [`MaybeSignal`](https://docs.rs/leptos/latest/leptos/enum.MaybeSignal.html) type is useful when you want to be able to take either a static or
reactive value.
```rust
#[component]
fn ProgressBar(
cx: Scope,
#[prop(default = 100)]
max: u16,
#[prop(into)]
progress: Signal<i32>
) -> impl IntoView
{
view! { cx,
<progress
max=max
value=progress
/>
}
}
#[component]
fn App(cx: Scope) -> impl IntoView {
let (count, set_count) = create_signal(cx, 0);
let double_count = move || count() * 2;
view! { cx,
<button on:click=move |_| { set_count.update(|n| *n += 1); }>
"Click me"
</button>
// .into() converts `ReadSignal` to `Signal`
<ProgressBar progress=count/>
// use `Signal::derive()` to wrap a derived signal
<ProgressBar progress=Signal::derive(cx, double_count)/>
}
}
```
## Documenting Components
This is one of the least essential but most important sections of this book.
Its not strictly necessary to document your components and their props. It may
be very important, depending on the size of your team and your app. But its very
easy, and bears immediate fruit.
To document a component and its props, you can simply add doc comments on the
component function, and each one of the props:
```rust
/// Shows progress toward a goal.
#[component]
fn ProgressBar(
cx: Scope,
/// The maximum value of the progress bar.
#[prop(default = 100)]
max: u16,
/// How much progress should be displayed.
#[prop(into)]
progress: Signal<i32>,
) -> impl IntoView {
/* ... */
}
```
Thats all you need to do. These behave like ordinary Rust doc comments, except
that you can document individual component props, which cant be done with Rust
function arguments.
This will automatically generate documentation for your component, its `Props`
type, and each of the fields used to add props. It can be a little hard to
understand how powerful this is until you hover over the component name or props
and see the power of the `#[component]` macro combined with rust-analyzer here.
[Click to open CodeSandbox.](https://codesandbox.io/p/sandbox/3-components-50t2e7?file=%2Fsrc%2Fmain.rs&selection=%5B%7B%22endColumn%22%3A1%2C%22endLineNumber%22%3A7%2C%22startColumn%22%3A1%2C%22startLineNumber%22%3A7%7D%5D)
<iframe src="https://codesandbox.io/p/sandbox/3-components-50t2e7?file=%2Fsrc%2Fmain.rs&selection=%5B%7B%22endColumn%22%3A1%2C%22endLineNumber%22%3A7%2C%22startColumn%22%3A1%2C%22startLineNumber%22%3A7%7D%5D" width="100%" height="1000px" style="max-height: 100vh"></iframe>
<meta http-equiv="refresh" content="0; URL=https://book.leptos.dev/view/03_components.html">
<link rel="canonical" href="https://book.leptos.dev/view/03_components.html">

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