mirror of
https://github.com/leptos-rs/leptos.git
synced 2025-12-28 14:52:35 -05:00
Compare commits
2 Commits
leptos_0.6
...
protected-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4e4872b7db | ||
|
|
6eb68a8794 |
4
.github/workflows/ci-semver.yml
vendored
4
.github/workflows/ci-semver.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
test:
|
||||
needs: [get-leptos-changed]
|
||||
if: needs.get-leptos-changed.outputs.leptos_changed == 'true'
|
||||
name: Run semver check (nightly-2024-07-21)
|
||||
name: Run semver check (nightly-2024-04-14)
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
@@ -25,4 +25,4 @@ jobs:
|
||||
- name: Semver Checks
|
||||
uses: obi1kenobi/cargo-semver-checks-action@v2
|
||||
with:
|
||||
rust-toolchain: nightly-2024-07-21
|
||||
rust-toolchain: nightly-2024-04-14
|
||||
|
||||
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -40,4 +40,4 @@ jobs:
|
||||
with:
|
||||
directory: ${{ matrix.directory }}
|
||||
cargo_make_task: "ci"
|
||||
toolchain: nightly-2024-07-21
|
||||
toolchain: nightly-2024-04-14
|
||||
|
||||
3
.github/workflows/run-cargo-make-task.yml
vendored
3
.github/workflows/run-cargo-make-task.yml
vendored
@@ -48,6 +48,9 @@ jobs:
|
||||
- name: Install wasm-bindgen
|
||||
run: cargo binstall wasm-bindgen-cli --no-confirm
|
||||
|
||||
- name: Install wasm-pack
|
||||
run: cargo binstall wasm-pack --no-confirm
|
||||
|
||||
- name: Install cargo-leptos
|
||||
run: cargo binstall cargo-leptos --no-confirm
|
||||
|
||||
|
||||
28
Cargo.toml
28
Cargo.toml
@@ -1,7 +1,7 @@
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
members = [
|
||||
# utilities
|
||||
# utilities
|
||||
"oco",
|
||||
|
||||
# core
|
||||
@@ -28,24 +28,24 @@ members = [
|
||||
exclude = ["benchmarks", "examples"]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.6.15"
|
||||
version = "0.6.11"
|
||||
rust-version = "1.75"
|
||||
|
||||
[workspace.dependencies]
|
||||
oco_ref = { path = "./oco", version = "0.1.0" }
|
||||
leptos = { path = "./leptos", version = "0.6.15" }
|
||||
leptos_dom = { path = "./leptos_dom", version = "0.6.15" }
|
||||
leptos_hot_reload = { path = "./leptos_hot_reload", version = "0.6.15" }
|
||||
leptos_macro = { path = "./leptos_macro", version = "0.6.15" }
|
||||
leptos_reactive = { path = "./leptos_reactive", version = "0.6.15" }
|
||||
leptos_server = { path = "./leptos_server", version = "0.6.15" }
|
||||
server_fn = { path = "./server_fn", version = "0.6.15" }
|
||||
server_fn_macro = { path = "./server_fn_macro", version = "0.6.15" }
|
||||
leptos = { path = "./leptos", version = "0.6.11" }
|
||||
leptos_dom = { path = "./leptos_dom", version = "0.6.11" }
|
||||
leptos_hot_reload = { path = "./leptos_hot_reload", version = "0.6.11" }
|
||||
leptos_macro = { path = "./leptos_macro", version = "0.6.11" }
|
||||
leptos_reactive = { path = "./leptos_reactive", version = "0.6.11" }
|
||||
leptos_server = { path = "./leptos_server", version = "0.6.11" }
|
||||
server_fn = { path = "./server_fn", version = "0.6.11" }
|
||||
server_fn_macro = { path = "./server_fn_macro", version = "0.6.11" }
|
||||
server_fn_macro_default = { path = "./server_fn/server_fn_macro_default", version = "0.6" }
|
||||
leptos_config = { path = "./leptos_config", version = "0.6.15" }
|
||||
leptos_router = { path = "./router", version = "0.6.15" }
|
||||
leptos_meta = { path = "./meta", version = "0.6.15" }
|
||||
leptos_integration_utils = { path = "./integrations/utils", version = "0.6.15" }
|
||||
leptos_config = { path = "./leptos_config", version = "0.6.11" }
|
||||
leptos_router = { path = "./router", version = "0.6.11" }
|
||||
leptos_meta = { path = "./meta", version = "0.6.11" }
|
||||
leptos_integration_utils = { path = "./integrations/utils", version = "0.6.11" }
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
|
||||
@@ -1,55 +1,56 @@
|
||||
# Оглавление
|
||||
# Summary
|
||||
|
||||
- [Вступление](./01_introduction.md)
|
||||
- [Начало работы](./getting_started/README.md)
|
||||
- [Introduction](./01_introduction.md)
|
||||
- [Getting Started](./getting_started/README.md)
|
||||
- [Leptos DX](./getting_started/leptos_dx.md)
|
||||
- [Сообщество Leptos и leptos-* Крейты](./getting_started/community_crates.md)
|
||||
- [Часть 1: Построение UI](./view/README.md)
|
||||
- [Простой компонент](./view/01_basic_component.md)
|
||||
- [Динамические атрибуты](./view/02_dynamic_attributes.md)
|
||||
- [Компоненты и свойства](./view/03_components.md)
|
||||
- [Итерирование](./view/04_iteration.md)
|
||||
- [Итерирование более сложных структур через `<For>`](./view/04b_iteration.md)
|
||||
- [Формы и поля ввода](./view/05_forms.md)
|
||||
- [Порядок выполнения](./view/06_control_flow.md)
|
||||
- [Обработка ошибок](./view/07_errors.md)
|
||||
- [Общение Родитель-Ребёнок в дереве компонентов](./view/08_parent_child.md)
|
||||
- [Передача Детей другим компонентам](./view/09_component_children.md)
|
||||
- [Без макросов: синтаксис билдера View](./view/builder.md)
|
||||
- [Реактивность](./reactivity/README.md)
|
||||
- [Работа с сигналами](./reactivity/working_with_signals.md)
|
||||
- [Реагирование на изменения с помощью `create_effect`](./reactivity/14_create_effect.md)
|
||||
- [Примечание: Реактивность и функции](./reactivity/interlude_functions.md)
|
||||
- [Тестирование](./testing.md)
|
||||
- [Асинхронность](./async/README.md)
|
||||
- [Подгрузка данных с помощью ресурсов (Resource)](./async/10_resources.md)
|
||||
- [Ожидания (Suspense)](./async/11_suspense.md)
|
||||
- [Переходы (Transition)](./async/12_transition.md)
|
||||
- [Действия (Action)](./async/13_actions.md)
|
||||
- [Примечание: Пробрасывание дочерних элементов](./interlude_projecting_children.md)
|
||||
- [Управление глобальным состоянием](./15_global_state.md)
|
||||
- [Маршрутизатор URL](./router/README.md)
|
||||
- [Определение `<Routes/>`](./router/16_routes.md)
|
||||
- [Вложенная маршрутизация](./router/17_nested_routing.md)
|
||||
- [Параметры в пути и в строке запроса](./router/18_params_and_queries.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)
|
||||
- [Interlude: Reactivity and Functions](./reactivity/interlude_functions.md)
|
||||
- [Testing](./testing.md)
|
||||
- [Async](./async/README.md)
|
||||
- [Loading Data with Resources](./async/10_resources.md)
|
||||
- [Suspense](./async/11_suspense.md)
|
||||
- [Transition](./async/12_transition.md)
|
||||
- [Actions](./async/13_actions.md)
|
||||
- [Interlude: Projecting Children](./interlude_projecting_children.md)
|
||||
- [Global State Management](./15_global_state.md)
|
||||
- [Router](./router/README.md)
|
||||
- [Defining `<Routes/>`](./router/16_routes.md)
|
||||
- [Nested Routing](./router/17_nested_routing.md)
|
||||
- [Params and Queries](./router/18_params_and_queries.md)
|
||||
- [`<A/>`](./router/19_a.md)
|
||||
- [`<Form/>`](./router/20_form.md)
|
||||
- [Примечание: Стили](./interlude_styling.md)
|
||||
- [Метаданные](./metadata.md)
|
||||
- [Рендеринг на стороне клиента (CSR): Заключение](./csr_wrapping_up.md)
|
||||
- [Часть 2: Рендеринг на стороне сервера (SSR)](./ssr/README.md)
|
||||
- [Interlude: Styling](./interlude_styling.md)
|
||||
- [Metadata](./metadata.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)
|
||||
- [Жизненный цикл загрузки страницы](./ssr/22_life_cycle.md)
|
||||
- [Асинхронный рендеринг и режимы SSR](./ssr/23_ssr_modes.md)
|
||||
- [Баги возникающие при гидратации](./ssr/24_hydration_bugs.md)
|
||||
- [Работа с сервером](./server/README.md)
|
||||
- [Серверные функции](./server/25_server_functions.md)
|
||||
- [Экстракторы](./server/26_extractors.md)
|
||||
- [Ответы и перенаправления](./server/27_response.md)
|
||||
- [Постепенное улучшение и Изящная деградация](./progressive_enhancement/README.md)
|
||||
- [`<ActionForm/>`](./progressive_enhancement/action_form.md)
|
||||
- [Развёртывание](./deployment/README.md)
|
||||
- [Оптимизация размера бинарника WASM](./deployment/binary_size.md)
|
||||
- [Руководство: Острова](./islands.md)
|
||||
- [The Life of a Page Load](./ssr/22_life_cycle.md)
|
||||
- [Async Rendering and SSR “Modes”](./ssr/23_ssr_modes.md)
|
||||
- [Hydration Bugs](./ssr/24_hydration_bugs.md)
|
||||
- [Working with the Server](./server/README.md)
|
||||
- [Server Functions](./server/25_server_functions.md)
|
||||
- [Extractors](./server/26_extractors.md)
|
||||
- [Responses and Redirects](./server/27_response.md)
|
||||
- [Progressive Enhancement and Graceful Degradation](./progressive_enhancement/README.md)
|
||||
- [`<ActionForm/>`s](./progressive_enhancement/action_form.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)
|
||||
|
||||
- [Приложение: Как работает реактивная система?](./appendix_reactive_graph.md)
|
||||
|
||||
@@ -47,11 +47,11 @@ CARGO_MAKE_CRATE_WORKSPACE_MEMBERS = [
|
||||
workspace = false
|
||||
description = "Generate the list of workspace members"
|
||||
script = '''
|
||||
examples=$(ls |
|
||||
grep -v .md |
|
||||
grep -v Makefile.toml |
|
||||
grep -v cargo-make |
|
||||
grep -v gtk |
|
||||
examples=$(ls |
|
||||
grep -v .md |
|
||||
grep -v Makefile.toml |
|
||||
grep -v cargo-make |
|
||||
grep -v gtk |
|
||||
jq -R -s -c 'split("\n")[:-1]')
|
||||
echo "CARGO_MAKE_CRATE_WORKSPACE_MEMBERS = $examples"
|
||||
'''
|
||||
|
||||
@@ -11,7 +11,7 @@ actix-files = { version = "0.6", optional = true }
|
||||
actix-web = { version = "4", optional = true, features = ["macros"] }
|
||||
console_error_panic_hook = "0.1"
|
||||
cfg-if = "1"
|
||||
http = { version = "1.0", optional = true }
|
||||
http = { version = "0.2", optional = true }
|
||||
leptos = { path = "../../leptos" }
|
||||
leptos_meta = { path = "../../meta" }
|
||||
leptos_actix = { path = "../../integrations/actix", optional = true }
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
extend = [
|
||||
{ path = "./lint.toml" }
|
||||
]
|
||||
|
||||
[tasks.make-target-site-dir]
|
||||
command = "mkdir"
|
||||
args = ["-p", "target/site"]
|
||||
|
||||
[tasks.install-cargo-leptos]
|
||||
install_crate = { crate_name = "cargo-leptos", binary = "cargo-leptos", test_arg = "--help" }
|
||||
|
||||
[tasks.cargo-leptos-e2e]
|
||||
command = "cargo"
|
||||
args = ["leptos", "end-to-end"]
|
||||
|
||||
[tasks.build]
|
||||
clear = true
|
||||
command = "cargo"
|
||||
dependencies = ["make-target-site-dir"]
|
||||
args = ["leptos", "build", "--release", "-P"]
|
||||
|
||||
[tasks.check]
|
||||
clear = true
|
||||
dependencies = ["check-debug", "check-release"]
|
||||
|
||||
[tasks.check-debug]
|
||||
toolchain = "stable"
|
||||
command = "cargo"
|
||||
args = ["check-all-features"]
|
||||
install_crate = "cargo-all-features"
|
||||
|
||||
[tasks.check-release]
|
||||
toolchain = "stable"
|
||||
command = "cargo"
|
||||
args = ["check-all-features", "--release"]
|
||||
install_crate = "cargo-all-features"
|
||||
|
||||
[tasks.lint]
|
||||
dependencies = ["make-target-site-dir", "check-style"]
|
||||
|
||||
[tasks.start-client]
|
||||
dependencies = ["install-cargo-leptos"]
|
||||
command = "cargo"
|
||||
args = ["leptos", "watch", "--release", "-P"]
|
||||
@@ -1,11 +1,9 @@
|
||||
[tasks.build]
|
||||
install_crate = { crate_name = "wasm-pack", binary = "wasm-pack", test_arg = "--help" }
|
||||
clear = true
|
||||
command = "deno"
|
||||
args = ["task", "build"]
|
||||
|
||||
[tasks.start-client]
|
||||
install_crate = { crate_name = "wasm-pack", binary = "wasm-pack", test_arg = "--help" }
|
||||
command = "deno"
|
||||
args = ["task", "start"]
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ leptos_meta = { path = "../../meta" }
|
||||
leptos_router = { path = "../../router" }
|
||||
log = "0.4"
|
||||
once_cell = "1.18"
|
||||
gloo-net = { version = "0.6" }
|
||||
gloo-net = { git = "https://github.com/rustwasm/gloo" }
|
||||
wasm-bindgen = "0.2"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
simple_logger = "4.3"
|
||||
@@ -33,13 +33,13 @@ tracing = { version = "0.1", optional = true }
|
||||
[features]
|
||||
hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]
|
||||
ssr = [
|
||||
"dep:actix-files",
|
||||
"dep:actix-web",
|
||||
"dep:tracing",
|
||||
"leptos/ssr",
|
||||
"leptos_actix",
|
||||
"leptos_meta/ssr",
|
||||
"leptos_router/ssr",
|
||||
"dep:actix-files",
|
||||
"dep:actix-web",
|
||||
"dep:tracing",
|
||||
"leptos/ssr",
|
||||
"leptos_actix",
|
||||
"leptos_meta/ssr",
|
||||
"leptos_router/ssr",
|
||||
]
|
||||
|
||||
[package.metadata.cargo-all-features]
|
||||
|
||||
@@ -22,4 +22,4 @@ rstest = "0.17.0"
|
||||
|
||||
[dev-dependencies.web-sys]
|
||||
features = ["HtmlElement", "XPathResult"]
|
||||
version = "0.3.70"
|
||||
version = "0.3.61"
|
||||
|
||||
@@ -23,7 +23,11 @@ pub fn copy_to_clipboard(el: HtmlElement<AnyElement>, content: &str) {
|
||||
evt.prevent_default();
|
||||
evt.stop_propagation();
|
||||
|
||||
let _ = window().navigator().clipboard().write_text(&content);
|
||||
let _ = window()
|
||||
.navigator()
|
||||
.clipboard()
|
||||
.expect("navigator.clipboard to be available")
|
||||
.write_text(&content);
|
||||
|
||||
let _ = el.clone().inner_html(format!("Copied \"{}\"", &content));
|
||||
});
|
||||
@@ -72,13 +76,9 @@ pub fn App() -> impl IntoView {
|
||||
let data = "Hello World!";
|
||||
|
||||
view! {
|
||||
<a href="#" use:copy_to_clipboard=data>
|
||||
"Copy \""
|
||||
{data}
|
||||
"\" to clipboard"
|
||||
</a>
|
||||
<a href="#" use:copy_to_clipboard=data>"Copy \"" {data} "\" to clipboard"</a>
|
||||
// automatically applies the directive to every root element in `SomeComponent`
|
||||
<SomeComponent use:highlight/>
|
||||
<SomeComponent use:highlight />
|
||||
// no value will default to `().into()`
|
||||
<button use:add_dot>"Add a dot"</button>
|
||||
// `5.into()` automatically called
|
||||
|
||||
@@ -21,8 +21,8 @@ leptos_actix = { path = "../../integrations/actix", optional = true }
|
||||
leptos_router = { path = "../../router" }
|
||||
log = "0.4"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
gloo-net = { version = "0.6", features = ["http"] }
|
||||
reqwest = { version = "0.12", features = ["json"] }
|
||||
gloo-net = { version = "0.2", features = ["http"] }
|
||||
reqwest = { version = "0.11", features = ["json"] }
|
||||
tracing = "0.1"
|
||||
# openssl = { version = "0.10", features = ["v110"] }
|
||||
wasm-bindgen = "0.2"
|
||||
@@ -32,12 +32,12 @@ web-sys = { version = "0.3", features = ["AbortController", "AbortSignal"] }
|
||||
csr = ["leptos/csr", "leptos_meta/csr", "leptos_router/csr"]
|
||||
hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]
|
||||
ssr = [
|
||||
"dep:actix-files",
|
||||
"dep:actix-web",
|
||||
"dep:leptos_actix",
|
||||
"leptos/ssr",
|
||||
"leptos_meta/ssr",
|
||||
"leptos_router/ssr",
|
||||
"dep:actix-files",
|
||||
"dep:actix-web",
|
||||
"dep:leptos_actix",
|
||||
"leptos/ssr",
|
||||
"leptos_meta/ssr",
|
||||
"leptos_router/ssr",
|
||||
]
|
||||
|
||||
[profile.wasm-release]
|
||||
|
||||
@@ -21,8 +21,8 @@ log = "0.4"
|
||||
simple_logger = "4.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
tracing = "0.1"
|
||||
gloo-net = { version = "0.6", features = ["http"] }
|
||||
reqwest = { version = "0.12", features = ["json"] }
|
||||
gloo-net = { version = "0.4", features = ["http"] }
|
||||
reqwest = { version = "0.11", features = ["json"] }
|
||||
axum = { version = "0.7", optional = true }
|
||||
tower = { version = "0.4", optional = true }
|
||||
tower-http = { version = "0.5", features = ["fs"], optional = true }
|
||||
|
||||
@@ -13,23 +13,24 @@ lto = true
|
||||
[dependencies]
|
||||
console_log = "1.0"
|
||||
console_error_panic_hook = "0.1"
|
||||
leptos = { path = "../../leptos", features = ["experimental-islands"] }
|
||||
leptos = { path = "../../leptos", features = [
|
||||
"experimental-islands",
|
||||
] }
|
||||
leptos_axum = { path = "../../integrations/axum", optional = true, features = [
|
||||
"experimental-islands",
|
||||
] }
|
||||
leptos_meta = { path = "../../meta" }
|
||||
leptos_router = { path = "../../router" }
|
||||
leptos_router = { path = "../../router"}
|
||||
log = "0.4"
|
||||
simple_logger = "4.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
tracing = "0.1"
|
||||
gloo-net = { version = "0.6", features = ["http"] }
|
||||
reqwest = { version = "0.12", features = ["json"] }
|
||||
gloo-net = { version = "0.4", features = ["http"] }
|
||||
reqwest = { version = "0.11", features = ["json"] }
|
||||
axum = { version = "0.7", optional = true, features = ["http2"] }
|
||||
tower = { version = "0.4", optional = true }
|
||||
tower-http = { version = "0.5", features = [
|
||||
"fs",
|
||||
"compression-gzip",
|
||||
"compression-br",
|
||||
], optional = true }
|
||||
tokio = { version = "1", features = ["full"], optional = true }
|
||||
@@ -37,12 +38,6 @@ http = { version = "1.0", optional = true }
|
||||
web-sys = { version = "0.3", features = ["AbortController", "AbortSignal"] }
|
||||
wasm-bindgen = "0.2"
|
||||
lazy_static = "1.4.0"
|
||||
rust-embed = { version = "8", features = [
|
||||
"axum",
|
||||
"mime_guess",
|
||||
"tokio",
|
||||
], optional = true }
|
||||
mime_guess = { version = "2.0.4", optional = true }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
@@ -54,8 +49,6 @@ ssr = [
|
||||
"dep:tower-http",
|
||||
"dep:tokio",
|
||||
"dep:http",
|
||||
"dep:rust-embed",
|
||||
"dep:mime_guess",
|
||||
"leptos/ssr",
|
||||
"leptos_axum",
|
||||
"leptos_meta/ssr",
|
||||
@@ -101,12 +94,6 @@ bin-features = ["ssr"]
|
||||
# Optional. Defaults to false.
|
||||
bin-default-features = false
|
||||
|
||||
# This feature will add a hash to the filename of assets.
|
||||
# This is useful here because our files are precompressed and use a `Cache-Control` policy to reduce HTTP requests
|
||||
#
|
||||
# Optional. Defaults to false.
|
||||
hash_file = true
|
||||
|
||||
# The features to use when compiling the lib target
|
||||
#
|
||||
# Optional. Can be over-ridden with the command line parameter --lib-features
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
extend = [
|
||||
{ path = "../cargo-make/main.toml" },
|
||||
{ path = "../cargo-make/cargo-leptos-compress.toml" },
|
||||
{ path = "../cargo-make/cargo-leptos.toml" },
|
||||
]
|
||||
|
||||
[env]
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
# Leptos Hacker News Example with Axum
|
||||
|
||||
This example creates a basic clone of the Hacker News site. It showcases Leptos' ability to:
|
||||
- Create a client-side rendered app
|
||||
- Create a server side rendered app with hydration
|
||||
- Precompress static assets and bundle those in with the server binary
|
||||
|
||||
This repo differs from the main Hacker News example by using Axum as it's server, precompressing and embedding static assets into the binary, and dynamically compressing the generated HTML.
|
||||
This example creates a basic clone of the Hacker News site. It showcases Leptos' ability to create both a client-side rendered app, and a server side rendered app with hydration, in a single repository. This repo differs from the main Hacker News example by using Axum as it's server.
|
||||
|
||||
## Getting Started
|
||||
|
||||
@@ -13,4 +8,4 @@ See the [Examples README](../README.md) for setup and run instructions.
|
||||
|
||||
## Quick Start
|
||||
|
||||
Run `cargo leptos watch --release -P` to run this example.
|
||||
Run `cargo leptos watch` to run this example.
|
||||
|
||||
8
examples/hackernews_islands_axum/build-front.sh
Executable file
8
examples/hackernews_islands_axum/build-front.sh
Executable file
@@ -0,0 +1,8 @@
|
||||
wasm-pack build --target=web --features=hydrate --release
|
||||
cd pkg
|
||||
rm *.br
|
||||
cp hackernews.js hackernews.unmin.js
|
||||
cat hackernews.unmin.js | esbuild > hackernews.js
|
||||
brotli hackernews.js
|
||||
brotli hackernews_bg.wasm
|
||||
brotli style.css
|
||||
@@ -2,34 +2,20 @@ use crate::error_template::error_template;
|
||||
use axum::{
|
||||
body::Body,
|
||||
extract::State,
|
||||
http::{header, Request, Response, StatusCode, Uri},
|
||||
http::{Request, Response, StatusCode, Uri},
|
||||
response::{IntoResponse, Response as AxumResponse},
|
||||
};
|
||||
use leptos::LeptosOptions;
|
||||
use std::borrow::Cow;
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
const DEV_MODE: bool = false;
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
const DEV_MODE: bool = true;
|
||||
|
||||
#[derive(rust_embed::RustEmbed)]
|
||||
#[folder = "target/site/"]
|
||||
struct Assets;
|
||||
use tower::ServiceExt;
|
||||
use tower_http::services::ServeDir;
|
||||
|
||||
pub async fn file_and_error_handler(
|
||||
uri: Uri,
|
||||
State(options): State<LeptosOptions>,
|
||||
req: Request<Body>,
|
||||
) -> AxumResponse {
|
||||
let accept_encoding = req
|
||||
.headers()
|
||||
.get("accept-encoding")
|
||||
.map(|h| h.to_str().unwrap_or("none"))
|
||||
.unwrap_or("none")
|
||||
.to_string();
|
||||
let res = get_static_file(uri.clone(), accept_encoding).await.unwrap();
|
||||
let root = options.site_root.clone();
|
||||
let res = get_static_file(uri.clone(), &root).await.unwrap();
|
||||
|
||||
if res.status() == StatusCode::OK {
|
||||
res.into_response()
|
||||
@@ -44,56 +30,19 @@ pub async fn file_and_error_handler(
|
||||
|
||||
async fn get_static_file(
|
||||
uri: Uri,
|
||||
accept_encoding: String,
|
||||
root: &str,
|
||||
) -> Result<Response<Body>, (StatusCode, String)> {
|
||||
let (_, path) = uri.path().split_at(1); // split off the first `/`
|
||||
let mime = mime_guess::from_path(path);
|
||||
|
||||
let (path, encoding) = if DEV_MODE {
|
||||
// during DEV, don't care about the precompression -> faster workflow
|
||||
(Cow::from(path), "none")
|
||||
} else if accept_encoding.contains("br") {
|
||||
(Cow::from(format!("{}.br", path)), "br")
|
||||
} else if accept_encoding.contains("gzip") {
|
||||
(Cow::from(format!("{}.gz", path)), "gzip")
|
||||
} else {
|
||||
(Cow::from(path), "none")
|
||||
};
|
||||
|
||||
match Assets::get(path.as_ref()) {
|
||||
Some(content) => {
|
||||
let body = Body::from(content.data);
|
||||
|
||||
let res = match DEV_MODE {
|
||||
true => Response::builder()
|
||||
.header(
|
||||
header::CONTENT_TYPE,
|
||||
mime.first_or_octet_stream().as_ref(),
|
||||
)
|
||||
.header(header::CONTENT_ENCODING, encoding)
|
||||
.body(body)
|
||||
.unwrap(),
|
||||
false => Response::builder()
|
||||
.header(header::CACHE_CONTROL, "max-age=86400")
|
||||
.header(
|
||||
header::CONTENT_TYPE,
|
||||
mime.first_or_octet_stream().as_ref(),
|
||||
)
|
||||
.header(header::CONTENT_ENCODING, encoding)
|
||||
.body(body)
|
||||
.unwrap(),
|
||||
};
|
||||
|
||||
Ok(res.into_response())
|
||||
}
|
||||
|
||||
None => {
|
||||
eprintln!(">> Asset {} not found", path);
|
||||
for a in Assets::iter() {
|
||||
eprintln!("Available asset: {}", a);
|
||||
}
|
||||
|
||||
Err((StatusCode::NOT_FOUND, "Not found".to_string()))
|
||||
}
|
||||
let req = Request::builder()
|
||||
.uri(uri.clone())
|
||||
.body(Body::empty())
|
||||
.unwrap();
|
||||
// `ServeDir` implements `tower::Service` so we can call it with `tower::ServiceExt::oneshot`
|
||||
// This path is relative to the cargo root
|
||||
match ServeDir::new(root).oneshot(req).await {
|
||||
Ok(res) => Ok(res.into_response()),
|
||||
Err(err) => Err((
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("Something went wrong: {}", err),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,33 +6,16 @@ async fn main() {
|
||||
use hackernews_islands::*;
|
||||
pub use leptos::get_configuration;
|
||||
pub use leptos_axum::{generate_route_list, LeptosRoutes};
|
||||
use tower_http::compression::{
|
||||
predicate::{NotForContentType, SizeAbove},
|
||||
CompressionLayer, CompressionLevel, Predicate,
|
||||
};
|
||||
|
||||
let conf = get_configuration(Some("Cargo.toml")).await.unwrap();
|
||||
let leptos_options = conf.leptos_options;
|
||||
let addr = leptos_options.site_addr;
|
||||
let routes = generate_route_list(App);
|
||||
|
||||
let predicate = SizeAbove::new(1500) // files smaller than 1501 bytes are not compressed, since the MTU (Maximum Transmission Unit) of a TCP packet is 1500 bytes
|
||||
.and(NotForContentType::GRPC)
|
||||
.and(NotForContentType::IMAGES)
|
||||
// prevent compressing assets that are already statically compressed
|
||||
.and(NotForContentType::const_new("application/javascript"))
|
||||
.and(NotForContentType::const_new("application/wasm"))
|
||||
.and(NotForContentType::const_new("text/css"));
|
||||
|
||||
// build our application with a route
|
||||
let app = Router::new()
|
||||
.route("/favicon.ico", get(file_and_error_handler))
|
||||
.leptos_routes(&leptos_options, routes, App)
|
||||
.layer(
|
||||
CompressionLayer::new()
|
||||
.quality(CompressionLevel::Fastest)
|
||||
.compress_when(predicate),
|
||||
)
|
||||
.fallback(file_and_error_handler)
|
||||
.with_state(leptos_options);
|
||||
|
||||
|
||||
@@ -14,19 +14,19 @@ lto = true
|
||||
console_log = "1.0.0"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
cfg-if = "1.0.0"
|
||||
leptos = { path = "../../leptos" }
|
||||
leptos_axum = { path = "../../integrations/axum", default-features = false, optional = true }
|
||||
leptos_meta = { path = "../../meta" }
|
||||
leptos_router = { path = "../../router" }
|
||||
leptos = { version = "0.5" }
|
||||
leptos_axum = { version = "0.5", default-features = false, optional = true }
|
||||
leptos_meta = { version = "0.5" }
|
||||
leptos_router = { version = "0.5" }
|
||||
log = "0.4.17"
|
||||
simple_logger = "4.0.0"
|
||||
serde = { version = "1.0.148", features = ["derive"] }
|
||||
tracing = "0.1"
|
||||
gloo-net = { version = "0.6", features = ["http"] }
|
||||
reqwest = { version = "0.12", features = ["json"] }
|
||||
axum = { version = "0.7", default-features = false, optional = true }
|
||||
gloo-net = { version = "0.4.0", features = ["http"] }
|
||||
reqwest = { version = "0.11.13", features = ["json"] }
|
||||
axum = { version = "0.6", default-features = false, optional = true }
|
||||
tower = { version = "0.4.13", optional = true }
|
||||
http = { version = "1.0", optional = true }
|
||||
http = { version = "0.2.11", optional = true }
|
||||
web-sys = { version = "0.3", features = [
|
||||
"AbortController",
|
||||
"AbortSignal",
|
||||
@@ -37,7 +37,7 @@ wasm-bindgen = "0.2"
|
||||
wasm-bindgen-futures = { version = "0.4.37", features = [
|
||||
"futures-core-03-stream",
|
||||
], optional = true }
|
||||
axum-js-fetch = { git = "https://github.com/seanaye/axum-js-fetch", optional = true }
|
||||
axum-js-fetch = { version = "0.2.1", optional = true }
|
||||
lazy_static = "1.4.0"
|
||||
|
||||
[features]
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
[toolchain]
|
||||
channel = "stable" # test change
|
||||
@@ -62,8 +62,8 @@ mod ssr_imports {
|
||||
let routes = generate_route_list(App);
|
||||
|
||||
// build our application with a route
|
||||
let app: axum::Router<()> = Router::new()
|
||||
.leptos_routes(&leptos_options, routes, App)
|
||||
let app: axum::Router<(), axum::body::Body> = Router::new()
|
||||
.leptos_routes(&leptos_options, routes, || view! { <App/> })
|
||||
.route("/api/*fn_name", post(leptos_axum::handle_server_fns))
|
||||
.with_state(leptos_options);
|
||||
|
||||
@@ -73,7 +73,7 @@ mod ssr_imports {
|
||||
}
|
||||
|
||||
pub async fn serve(&self, req: web_sys::Request) -> web_sys::Response {
|
||||
self.0.oneshot(req).await
|
||||
self.0.serve(req).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ leptos_router = { path = "../../../router", features = ["csr"] }
|
||||
log = "0.4"
|
||||
console_error_panic_hook = "0.1"
|
||||
console_log = "1"
|
||||
gloo-net = "0.6"
|
||||
gloo-net = "0.5"
|
||||
gloo-storage = "0.3"
|
||||
serde = "1.0"
|
||||
thiserror = "1.0"
|
||||
|
||||
@@ -27,7 +27,7 @@ thiserror = "1.0"
|
||||
wasm-bindgen = "0.2"
|
||||
serde_toml = "0.0.1"
|
||||
toml = "0.8.8"
|
||||
web-sys = { version = "0.3.70", features = ["FileList", "File"] }
|
||||
web-sys = { version = "0.3.67", features = ["FileList", "File"] }
|
||||
strum = { version = "0.25.0", features = ["strum_macros", "derive"] }
|
||||
notify = { version = "6.1.1", optional = true }
|
||||
pin-project-lite = "0.2.13"
|
||||
|
||||
@@ -27,39 +27,39 @@ tower-http = { version = "0.5", features = ["fs"], optional = true }
|
||||
tokio = { version = "1.22.0", features = ["full"], optional = true }
|
||||
http = { version = "1" }
|
||||
sqlx = { version = "0.7", features = [
|
||||
"runtime-tokio-rustls",
|
||||
"sqlite",
|
||||
"runtime-tokio-rustls",
|
||||
"sqlite",
|
||||
], optional = true }
|
||||
thiserror = "1.0.38"
|
||||
wasm-bindgen = "0.2"
|
||||
axum_session_auth = { version = "0.12", features = [
|
||||
"sqlite-rustls",
|
||||
"sqlite-rustls",
|
||||
], optional = true }
|
||||
axum_session = { version = "0.12", features = [
|
||||
"sqlite-rustls",
|
||||
"sqlite-rustls",
|
||||
], optional = true }
|
||||
async-trait = { version = "0.1.64", optional = true }
|
||||
reqwest = { version = "0.12", optional = true, features = ["json"] }
|
||||
reqwest = { version = "0.11", optional = true, features = ["json"] }
|
||||
|
||||
[features]
|
||||
hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]
|
||||
ssr = [
|
||||
"dep:serde_json",
|
||||
"dep:axum",
|
||||
"dep:tower",
|
||||
"dep:tower-http",
|
||||
"dep:tokio",
|
||||
"dep:reqwest",
|
||||
"dep:oauth2",
|
||||
"dep:axum_session_auth",
|
||||
"dep:axum_session",
|
||||
"dep:async-trait",
|
||||
"dep:sqlx",
|
||||
"dep:rand",
|
||||
"leptos/ssr",
|
||||
"leptos_meta/ssr",
|
||||
"leptos_router/ssr",
|
||||
"dep:leptos_axum",
|
||||
"dep:serde_json",
|
||||
"dep:axum",
|
||||
"dep:tower",
|
||||
"dep:tower-http",
|
||||
"dep:tokio",
|
||||
"dep:reqwest",
|
||||
"dep:oauth2",
|
||||
"dep:axum_session_auth",
|
||||
"dep:axum_session",
|
||||
"dep:async-trait",
|
||||
"dep:sqlx",
|
||||
"dep:rand",
|
||||
"leptos/ssr",
|
||||
"leptos_meta/ssr",
|
||||
"leptos_router/ssr",
|
||||
"dep:leptos_axum",
|
||||
]
|
||||
|
||||
[package.metadata.cargo-all-features]
|
||||
|
||||
@@ -13,7 +13,7 @@ leptos = { path = "../../leptos" }
|
||||
leptos_actix = { path = "../../integrations/actix", optional = true }
|
||||
leptos_meta = { path = "../../meta" }
|
||||
leptos_router = { path = "../../router" }
|
||||
gloo-net = { version = "0.6", features = ["http"] }
|
||||
gloo-net = { version = "0.2", features = ["http"] }
|
||||
log = "0.4"
|
||||
|
||||
# dependencies for client (enable when csr or hydrate set)
|
||||
|
||||
@@ -8,7 +8,7 @@ leptos = { path = "../../leptos", features = ["csr"] }
|
||||
leptos_meta = { path = "../../meta", features = ["csr"] }
|
||||
leptos_router = { path = "../../router", features = ["csr"] }
|
||||
log = "0.4"
|
||||
gloo-net = { version = "0.6", features = ["http"] }
|
||||
gloo-net = { version = "0.2", features = ["http"] }
|
||||
|
||||
# dependencies for client (enable when csr or hydrate set)
|
||||
wasm-bindgen = { version = "0.2" }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
extend = [
|
||||
{ path = "../cargo-make/main.toml" },
|
||||
{ path = "../cargo-make/trunk_server.toml" },
|
||||
{ path = "../cargo-make/main.toml" },
|
||||
{ path = "../cargo-make/trunk_server.toml" },
|
||||
]
|
||||
|
||||
4
examples/tailwind_csr/Trunk.toml
Normal file
4
examples/tailwind_csr/Trunk.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
[[hooks]]
|
||||
stage = "pre_build"
|
||||
command = "sh"
|
||||
command_arguments = ["-c", "npx tailwindcss -i input.css -o style/output.css"]
|
||||
@@ -1,12 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link data-trunk rel="rust" data-wasm-opt="z" />
|
||||
<link data-trunk rel="icon" type="image/ico" href="/public/favicon.ico" />
|
||||
<link data-trunk rel="tailwind-css" href="/style/tailwind.css" />
|
||||
<link data-trunk rel="css" href="/style/output.css" />
|
||||
<title>Leptos • Counter with Tailwind</title>
|
||||
</head>
|
||||
</head>
|
||||
|
||||
<body></body>
|
||||
|
||||
<body></body>
|
||||
</html>
|
||||
|
||||
604
examples/tailwind_csr/style/output.css
Normal file
604
examples/tailwind_csr/style/output.css
Normal file
@@ -0,0 +1,604 @@
|
||||
/*
|
||||
! tailwindcss v3.3.3 | MIT License | https://tailwindcss.com
|
||||
*/
|
||||
|
||||
/*
|
||||
1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
|
||||
2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
|
||||
*/
|
||||
|
||||
*,
|
||||
::before,
|
||||
::after {
|
||||
box-sizing: border-box;
|
||||
/* 1 */
|
||||
border-width: 0;
|
||||
/* 2 */
|
||||
border-style: solid;
|
||||
/* 2 */
|
||||
border-color: #e5e7eb;
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
::before,
|
||||
::after {
|
||||
--tw-content: '';
|
||||
}
|
||||
|
||||
/*
|
||||
1. Use a consistent sensible line-height in all browsers.
|
||||
2. Prevent adjustments of font size after orientation changes in iOS.
|
||||
3. Use a more readable tab size.
|
||||
4. Use the user's configured `sans` font-family by default.
|
||||
5. Use the user's configured `sans` font-feature-settings by default.
|
||||
6. Use the user's configured `sans` font-variation-settings by default.
|
||||
*/
|
||||
|
||||
html {
|
||||
line-height: 1.5;
|
||||
/* 1 */
|
||||
-webkit-text-size-adjust: 100%;
|
||||
/* 2 */
|
||||
-moz-tab-size: 4;
|
||||
/* 3 */
|
||||
-o-tab-size: 4;
|
||||
tab-size: 4;
|
||||
/* 3 */
|
||||
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
/* 4 */
|
||||
font-feature-settings: normal;
|
||||
/* 5 */
|
||||
font-variation-settings: normal;
|
||||
/* 6 */
|
||||
}
|
||||
|
||||
/*
|
||||
1. Remove the margin in all browsers.
|
||||
2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.
|
||||
*/
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
/* 1 */
|
||||
line-height: inherit;
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
/*
|
||||
1. Add the correct height in Firefox.
|
||||
2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
|
||||
3. Ensure horizontal rules are visible by default.
|
||||
*/
|
||||
|
||||
hr {
|
||||
height: 0;
|
||||
/* 1 */
|
||||
color: inherit;
|
||||
/* 2 */
|
||||
border-top-width: 1px;
|
||||
/* 3 */
|
||||
}
|
||||
|
||||
/*
|
||||
Add the correct text decoration in Chrome, Edge, and Safari.
|
||||
*/
|
||||
|
||||
abbr:where([title]) {
|
||||
-webkit-text-decoration: underline dotted;
|
||||
text-decoration: underline dotted;
|
||||
}
|
||||
|
||||
/*
|
||||
Remove the default font size and weight for headings.
|
||||
*/
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-size: inherit;
|
||||
font-weight: inherit;
|
||||
}
|
||||
|
||||
/*
|
||||
Reset links to optimize for opt-in styling instead of opt-out.
|
||||
*/
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
|
||||
/*
|
||||
Add the correct font weight in Edge and Safari.
|
||||
*/
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
/*
|
||||
1. Use the user's configured `mono` font family by default.
|
||||
2. Correct the odd `em` font sizing in all browsers.
|
||||
*/
|
||||
|
||||
code,
|
||||
kbd,
|
||||
samp,
|
||||
pre {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
/* 1 */
|
||||
font-size: 1em;
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
/*
|
||||
Add the correct font size in all browsers.
|
||||
*/
|
||||
|
||||
small {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
/*
|
||||
Prevent `sub` and `sup` elements from affecting the line height in all browsers.
|
||||
*/
|
||||
|
||||
sub,
|
||||
sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
/*
|
||||
1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
|
||||
2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
|
||||
3. Remove gaps between table borders by default.
|
||||
*/
|
||||
|
||||
table {
|
||||
text-indent: 0;
|
||||
/* 1 */
|
||||
border-color: inherit;
|
||||
/* 2 */
|
||||
border-collapse: collapse;
|
||||
/* 3 */
|
||||
}
|
||||
|
||||
/*
|
||||
1. Change the font styles in all browsers.
|
||||
2. Remove the margin in Firefox and Safari.
|
||||
3. Remove default padding in all browsers.
|
||||
*/
|
||||
|
||||
button,
|
||||
input,
|
||||
optgroup,
|
||||
select,
|
||||
textarea {
|
||||
font-family: inherit;
|
||||
/* 1 */
|
||||
font-feature-settings: inherit;
|
||||
/* 1 */
|
||||
font-variation-settings: inherit;
|
||||
/* 1 */
|
||||
font-size: 100%;
|
||||
/* 1 */
|
||||
font-weight: inherit;
|
||||
/* 1 */
|
||||
line-height: inherit;
|
||||
/* 1 */
|
||||
color: inherit;
|
||||
/* 1 */
|
||||
margin: 0;
|
||||
/* 2 */
|
||||
padding: 0;
|
||||
/* 3 */
|
||||
}
|
||||
|
||||
/*
|
||||
Remove the inheritance of text transform in Edge and Firefox.
|
||||
*/
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
/*
|
||||
1. Correct the inability to style clickable types in iOS and Safari.
|
||||
2. Remove default button styles.
|
||||
*/
|
||||
|
||||
button,
|
||||
[type='button'],
|
||||
[type='reset'],
|
||||
[type='submit'] {
|
||||
-webkit-appearance: button;
|
||||
/* 1 */
|
||||
background-color: transparent;
|
||||
/* 2 */
|
||||
background-image: none;
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
/*
|
||||
Use the modern Firefox focus style for all focusable elements.
|
||||
*/
|
||||
|
||||
:-moz-focusring {
|
||||
outline: auto;
|
||||
}
|
||||
|
||||
/*
|
||||
Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)
|
||||
*/
|
||||
|
||||
:-moz-ui-invalid {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/*
|
||||
Add the correct vertical alignment in Chrome and Firefox.
|
||||
*/
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
/*
|
||||
Correct the cursor style of increment and decrement buttons in Safari.
|
||||
*/
|
||||
|
||||
::-webkit-inner-spin-button,
|
||||
::-webkit-outer-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/*
|
||||
1. Correct the odd appearance in Chrome and Safari.
|
||||
2. Correct the outline style in Safari.
|
||||
*/
|
||||
|
||||
[type='search'] {
|
||||
-webkit-appearance: textfield;
|
||||
/* 1 */
|
||||
outline-offset: -2px;
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
/*
|
||||
Remove the inner padding in Chrome and Safari on macOS.
|
||||
*/
|
||||
|
||||
::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
/*
|
||||
1. Correct the inability to style clickable types in iOS and Safari.
|
||||
2. Change font properties to `inherit` in Safari.
|
||||
*/
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
-webkit-appearance: button;
|
||||
/* 1 */
|
||||
font: inherit;
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
/*
|
||||
Add the correct display in Chrome and Safari.
|
||||
*/
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
}
|
||||
|
||||
/*
|
||||
Removes the default spacing and border for appropriate elements.
|
||||
*/
|
||||
|
||||
blockquote,
|
||||
dl,
|
||||
dd,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
hr,
|
||||
figure,
|
||||
p,
|
||||
pre {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
legend {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul,
|
||||
menu {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Reset default styling for dialogs.
|
||||
*/
|
||||
|
||||
dialog {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Prevent resizing textareas horizontally by default.
|
||||
*/
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
/*
|
||||
1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
|
||||
2. Set the default placeholder color to the user's configured gray 400 color.
|
||||
*/
|
||||
|
||||
input::-moz-placeholder, textarea::-moz-placeholder {
|
||||
opacity: 1;
|
||||
/* 1 */
|
||||
color: #9ca3af;
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
input::placeholder,
|
||||
textarea::placeholder {
|
||||
opacity: 1;
|
||||
/* 1 */
|
||||
color: #9ca3af;
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
/*
|
||||
Set the default cursor for buttons.
|
||||
*/
|
||||
|
||||
button,
|
||||
[role="button"] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/*
|
||||
Make sure disabled buttons don't get the pointer cursor.
|
||||
*/
|
||||
|
||||
:disabled {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/*
|
||||
1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)
|
||||
2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)
|
||||
This can trigger a poorly considered lint error in some tools but is included by design.
|
||||
*/
|
||||
|
||||
img,
|
||||
svg,
|
||||
video,
|
||||
canvas,
|
||||
audio,
|
||||
iframe,
|
||||
embed,
|
||||
object {
|
||||
display: block;
|
||||
/* 1 */
|
||||
vertical-align: middle;
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
/*
|
||||
Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
|
||||
*/
|
||||
|
||||
img,
|
||||
video {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/* Make elements with the HTML hidden attribute stay hidden by default */
|
||||
|
||||
[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
*, ::before, ::after {
|
||||
--tw-border-spacing-x: 0;
|
||||
--tw-border-spacing-y: 0;
|
||||
--tw-translate-x: 0;
|
||||
--tw-translate-y: 0;
|
||||
--tw-rotate: 0;
|
||||
--tw-skew-x: 0;
|
||||
--tw-skew-y: 0;
|
||||
--tw-scale-x: 1;
|
||||
--tw-scale-y: 1;
|
||||
--tw-pan-x: ;
|
||||
--tw-pan-y: ;
|
||||
--tw-pinch-zoom: ;
|
||||
--tw-scroll-snap-strictness: proximity;
|
||||
--tw-gradient-from-position: ;
|
||||
--tw-gradient-via-position: ;
|
||||
--tw-gradient-to-position: ;
|
||||
--tw-ordinal: ;
|
||||
--tw-slashed-zero: ;
|
||||
--tw-numeric-figure: ;
|
||||
--tw-numeric-spacing: ;
|
||||
--tw-numeric-fraction: ;
|
||||
--tw-ring-inset: ;
|
||||
--tw-ring-offset-width: 0px;
|
||||
--tw-ring-offset-color: #fff;
|
||||
--tw-ring-color: rgb(59 130 246 / 0.5);
|
||||
--tw-ring-offset-shadow: 0 0 #0000;
|
||||
--tw-ring-shadow: 0 0 #0000;
|
||||
--tw-shadow: 0 0 #0000;
|
||||
--tw-shadow-colored: 0 0 #0000;
|
||||
--tw-blur: ;
|
||||
--tw-brightness: ;
|
||||
--tw-contrast: ;
|
||||
--tw-grayscale: ;
|
||||
--tw-hue-rotate: ;
|
||||
--tw-invert: ;
|
||||
--tw-saturate: ;
|
||||
--tw-sepia: ;
|
||||
--tw-drop-shadow: ;
|
||||
--tw-backdrop-blur: ;
|
||||
--tw-backdrop-brightness: ;
|
||||
--tw-backdrop-contrast: ;
|
||||
--tw-backdrop-grayscale: ;
|
||||
--tw-backdrop-hue-rotate: ;
|
||||
--tw-backdrop-invert: ;
|
||||
--tw-backdrop-opacity: ;
|
||||
--tw-backdrop-saturate: ;
|
||||
--tw-backdrop-sepia: ;
|
||||
}
|
||||
|
||||
::backdrop {
|
||||
--tw-border-spacing-x: 0;
|
||||
--tw-border-spacing-y: 0;
|
||||
--tw-translate-x: 0;
|
||||
--tw-translate-y: 0;
|
||||
--tw-rotate: 0;
|
||||
--tw-skew-x: 0;
|
||||
--tw-skew-y: 0;
|
||||
--tw-scale-x: 1;
|
||||
--tw-scale-y: 1;
|
||||
--tw-pan-x: ;
|
||||
--tw-pan-y: ;
|
||||
--tw-pinch-zoom: ;
|
||||
--tw-scroll-snap-strictness: proximity;
|
||||
--tw-gradient-from-position: ;
|
||||
--tw-gradient-via-position: ;
|
||||
--tw-gradient-to-position: ;
|
||||
--tw-ordinal: ;
|
||||
--tw-slashed-zero: ;
|
||||
--tw-numeric-figure: ;
|
||||
--tw-numeric-spacing: ;
|
||||
--tw-numeric-fraction: ;
|
||||
--tw-ring-inset: ;
|
||||
--tw-ring-offset-width: 0px;
|
||||
--tw-ring-offset-color: #fff;
|
||||
--tw-ring-color: rgb(59 130 246 / 0.5);
|
||||
--tw-ring-offset-shadow: 0 0 #0000;
|
||||
--tw-ring-shadow: 0 0 #0000;
|
||||
--tw-shadow: 0 0 #0000;
|
||||
--tw-shadow-colored: 0 0 #0000;
|
||||
--tw-blur: ;
|
||||
--tw-brightness: ;
|
||||
--tw-contrast: ;
|
||||
--tw-grayscale: ;
|
||||
--tw-hue-rotate: ;
|
||||
--tw-invert: ;
|
||||
--tw-saturate: ;
|
||||
--tw-sepia: ;
|
||||
--tw-drop-shadow: ;
|
||||
--tw-backdrop-blur: ;
|
||||
--tw-backdrop-brightness: ;
|
||||
--tw-backdrop-contrast: ;
|
||||
--tw-backdrop-grayscale: ;
|
||||
--tw-backdrop-hue-rotate: ;
|
||||
--tw-backdrop-invert: ;
|
||||
--tw-backdrop-opacity: ;
|
||||
--tw-backdrop-saturate: ;
|
||||
--tw-backdrop-sepia: ;
|
||||
}
|
||||
|
||||
.mx-auto {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.my-0 {
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.max-w-3xl {
|
||||
max-width: 48rem;
|
||||
}
|
||||
|
||||
.rounded-lg {
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.bg-amber-600 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(217 119 6 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.p-6 {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.px-10 {
|
||||
padding-left: 2.5rem;
|
||||
padding-right: 2.5rem;
|
||||
}
|
||||
|
||||
.px-5 {
|
||||
padding-left: 1.25rem;
|
||||
padding-right: 1.25rem;
|
||||
}
|
||||
|
||||
.py-3 {
|
||||
padding-top: 0.75rem;
|
||||
padding-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.pb-10 {
|
||||
padding-bottom: 2.5rem;
|
||||
}
|
||||
|
||||
.text-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.text-4xl {
|
||||
font-size: 2.25rem;
|
||||
line-height: 2.5rem;
|
||||
}
|
||||
|
||||
.text-white {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(255 255 255 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.hover\:bg-sky-700:hover {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(3 105 161 / var(--tw-bg-opacity));
|
||||
}
|
||||
@@ -15,7 +15,7 @@ console_error_panic_hook = "0.1.7"
|
||||
uuid = { version = "1", features = ["v4", "js", "serde"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
web-sys = { version = "0.3.70", features = ["Storage"] }
|
||||
web-sys = { version = "0.3.60", features = ["Storage"] }
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen-test = "0.3.0"
|
||||
|
||||
@@ -27,6 +27,3 @@ tokio = { version = "1", features = ["rt", "fs"] }
|
||||
[features]
|
||||
nonce = ["leptos/nonce"]
|
||||
experimental-islands = ["leptos_integration_utils/experimental-islands"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
|
||||
@@ -729,7 +729,10 @@ async fn stream_app(
|
||||
|
||||
build_stream_response(options, res_options, stream, runtime).await
|
||||
}
|
||||
#[cfg_attr(any(debug_assertions), instrument(level = "trace", skip_all,))]
|
||||
#[cfg_attr(
|
||||
any(debug_assertions, feature = "ssr"),
|
||||
instrument(level = "trace", skip_all,)
|
||||
)]
|
||||
async fn stream_app_in_order(
|
||||
options: &LeptosOptions,
|
||||
app: impl FnOnce() -> View + 'static,
|
||||
|
||||
@@ -37,6 +37,3 @@ nonce = ["leptos/nonce"]
|
||||
wasm = []
|
||||
default = ["tokio/fs", "tokio/sync"]
|
||||
experimental-islands = ["leptos_integration_utils/experimental-islands"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
|
||||
@@ -54,10 +54,7 @@ use leptos_meta::{generate_head_metadata_separated, MetaContext};
|
||||
use leptos_router::*;
|
||||
use once_cell::sync::OnceCell;
|
||||
use parking_lot::RwLock;
|
||||
use server_fn::{
|
||||
error::{NoCustomError, ServerFnErrorSerde},
|
||||
redirect::REDIRECT_HEADER,
|
||||
};
|
||||
use server_fn::{error::NoCustomError, redirect::REDIRECT_HEADER};
|
||||
use std::{fmt::Debug, io, pin::Pin, sync::Arc, thread::available_parallelism};
|
||||
use tokio_util::task::LocalPoolHandle;
|
||||
use tracing::Instrument;
|
||||
@@ -360,10 +357,9 @@ async fn handle_server_fns_inner(
|
||||
rx.await.unwrap_or_else(|e| {
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
ServerFnErrorSerde::ser(
|
||||
&ServerFnError::<NoCustomError>::ServerError(e.to_string()),
|
||||
)
|
||||
.unwrap_or_default(),
|
||||
ServerFnError::<NoCustomError>::ServerError(e.to_string())
|
||||
.ser()
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
.into_response()
|
||||
})
|
||||
@@ -1030,8 +1026,6 @@ where
|
||||
let full_path = format!("http://leptos.dev{path}");
|
||||
|
||||
let (tx, rx) = futures::channel::oneshot::channel();
|
||||
|
||||
let current_span = tracing::Span::current();
|
||||
spawn_task!(async move {
|
||||
let app = {
|
||||
let full_path = full_path.clone();
|
||||
@@ -1065,7 +1059,7 @@ where
|
||||
*writable = new_res_parts;
|
||||
|
||||
_ = tx.send(html);
|
||||
}.instrument(current_span));
|
||||
});
|
||||
|
||||
let html = rx.await.expect("to complete HTML rendering");
|
||||
|
||||
@@ -1862,4 +1856,3 @@ where
|
||||
.await
|
||||
.map_err(|e| ServerFnError::ServerError(format!("{e:?}")))
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,3 @@ tracing = "0.1.37"
|
||||
|
||||
[features]
|
||||
experimental-islands = []
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
|
||||
@@ -136,7 +136,7 @@ pub fn html_parts_separated(
|
||||
idle(() => {{
|
||||
import('{pkg_path}/{output_name}{js_hash}.js')
|
||||
.then(mod => {{
|
||||
mod.default({{module_or_path: '{pkg_path}/{wasm_output_name}{wasm_hash}.wasm'}}).then({import_callback});
|
||||
mod.default('{pkg_path}/{wasm_output_name}{wasm_hash}.wasm').then({import_callback});
|
||||
}})
|
||||
}});
|
||||
</script>
|
||||
|
||||
@@ -16,7 +16,7 @@ leptos_macro = { workspace = true }
|
||||
leptos_reactive = { workspace = true }
|
||||
leptos_server = { workspace = true }
|
||||
leptos_config = { workspace = true }
|
||||
leptos-spin-macro = { version = "0.2", optional = true }
|
||||
leptos-spin-macro = { version = "0.1", optional = true }
|
||||
tracing = "0.1"
|
||||
typed-builder = "0.18"
|
||||
typed-builder-macro = "0.18"
|
||||
@@ -28,7 +28,7 @@ server_fn = { workspace = true, features = [
|
||||
"url",
|
||||
"cbor",
|
||||
] }
|
||||
web-sys = { version = "0.3.70", features = [
|
||||
web-sys = { version = "0.3.63", features = [
|
||||
"ShadowRoot",
|
||||
"ShadowRootInit",
|
||||
"ShadowRootMode",
|
||||
@@ -70,7 +70,7 @@ nightly = [
|
||||
serde = ["leptos_reactive/serde"]
|
||||
serde-lite = ["leptos_reactive/serde-lite"]
|
||||
miniserde = ["leptos_reactive/miniserde"]
|
||||
rkyv = ["leptos_reactive/rkyv", "server_fn/rkyv"]
|
||||
rkyv = ["leptos_reactive/rkyv"]
|
||||
tracing = ["leptos_macro/tracing"]
|
||||
nonce = ["leptos_dom/nonce"]
|
||||
spin = ["leptos_reactive/spin", "leptos-spin-macro"]
|
||||
@@ -141,6 +141,3 @@ skip_feature_sets = [
|
||||
"rustls",
|
||||
],
|
||||
]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
|
||||
@@ -16,80 +16,8 @@ pub type ChildrenFnMut = Box<dyn FnMut() -> Fragment>;
|
||||
// This is to still support components that accept `Box<dyn Fn() -> Fragment>` as a children.
|
||||
type BoxedChildrenFn = Box<dyn Fn() -> Fragment>;
|
||||
|
||||
/// This trait can be used when constructing a component that takes children without needing
|
||||
/// to know exactly what children type the component expects. This is used internally by the
|
||||
/// `view!` macro implementation, and can also be used explicitly when using the builder syntax.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ## Without ToChildren
|
||||
///
|
||||
/// Without [ToChildren], consumers need to explicitly provide children using the type expected
|
||||
/// by the component. For example, [Provider][crate::Provider]'s children need to wrapped in
|
||||
/// a [Box], while [Show][crate::Show]'s children need to be wrapped in an [Rc].
|
||||
///
|
||||
/// ```
|
||||
/// # use leptos::{ProviderProps, ShowProps};
|
||||
/// # use leptos_dom::html::p;
|
||||
/// # use leptos_dom::IntoView;
|
||||
/// # use leptos_macro::component;
|
||||
/// # use std::rc::Rc;
|
||||
/// #
|
||||
/// #[component]
|
||||
/// fn App() -> impl IntoView {
|
||||
/// (
|
||||
/// ProviderProps::builder()
|
||||
/// .children(Box::new(|| p().child("Foo").into_view().into()))
|
||||
/// // ...
|
||||
/// # .value("Foo")
|
||||
/// # .build(),
|
||||
/// ShowProps::builder()
|
||||
/// .children(Rc::new(|| p().child("Foo").into_view().into()))
|
||||
/// // ...
|
||||
/// # .when(|| true)
|
||||
/// # .fallback(|| p().child("foo"))
|
||||
/// # .build(),
|
||||
/// )
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ## With ToChildren
|
||||
///
|
||||
/// With [ToChildren], consumers don't need to know exactly which type a component uses for
|
||||
/// its children.
|
||||
///
|
||||
/// ```
|
||||
/// # use leptos::{ProviderProps, ShowProps};
|
||||
/// # use leptos_dom::html::p;
|
||||
/// # use leptos_dom::IntoView;
|
||||
/// # use leptos_macro::component;
|
||||
/// # use std::rc::Rc;
|
||||
/// # use leptos::ToChildren;
|
||||
/// #
|
||||
/// #[component]
|
||||
/// fn App() -> impl IntoView {
|
||||
/// (
|
||||
/// ProviderProps::builder()
|
||||
/// .children(ToChildren::to_children(|| {
|
||||
/// p().child("Foo").into_view().into()
|
||||
/// }))
|
||||
/// // ...
|
||||
/// # .value("Foo")
|
||||
/// # .build(),
|
||||
/// ShowProps::builder()
|
||||
/// .children(ToChildren::to_children(|| {
|
||||
/// p().child("Foo").into_view().into()
|
||||
/// }))
|
||||
/// // ...
|
||||
/// # .when(|| true)
|
||||
/// # .fallback(|| p().child("foo"))
|
||||
/// # .build(),
|
||||
/// )
|
||||
/// }
|
||||
#[doc(hidden)]
|
||||
pub trait ToChildren<F> {
|
||||
/// Convert the provided type to (generally a closure) to Self (generally a "children" type,
|
||||
/// e.g., [Children]). See the implementations to see exactly which input types are supported
|
||||
/// and which "children" type they are converted to.
|
||||
fn to_children(f: F) -> Self;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,18 @@ use std::hash::Hash;
|
||||
/// }
|
||||
/// }
|
||||
/// />
|
||||
/// <For
|
||||
/// // a function that returns the items we're iterating over; a signal is fine
|
||||
/// each=move || counters.get()
|
||||
/// // a unique key for each item
|
||||
/// key=|counter| counter.id
|
||||
/// // renders each item to a view
|
||||
/// children=move |counter: Counter| {
|
||||
/// view! {
|
||||
/// <button>"Value: " {move || counter.count.get()}</button>
|
||||
/// }
|
||||
/// }
|
||||
/// />
|
||||
/// </div>
|
||||
/// }
|
||||
/// }
|
||||
|
||||
@@ -285,21 +285,6 @@ pub trait DynAttrs {
|
||||
|
||||
impl DynAttrs for () {}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait DynBindings {
|
||||
fn dyn_bindings<B: Into<Binding>>(
|
||||
self,
|
||||
_args: impl IntoIterator<Item = B>,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl DynBindings for () {}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait PropsOrNoPropsBuilder {
|
||||
type Builder;
|
||||
|
||||
@@ -2,11 +2,6 @@ use crate::ChildrenFn;
|
||||
use cfg_if::cfg_if;
|
||||
use leptos_dom::IntoView;
|
||||
use leptos_macro::component;
|
||||
#[cfg(all(
|
||||
target_arch = "wasm32",
|
||||
any(feature = "hydrate", feature = "csr")
|
||||
))]
|
||||
use leptos_reactive::untrack;
|
||||
|
||||
/// Renders components somewhere else in the DOM.
|
||||
///
|
||||
@@ -41,7 +36,6 @@ pub fn Portal(
|
||||
.unwrap_or_else(|| document().body().expect("body to exist").unchecked_into());
|
||||
|
||||
create_effect(move |_| {
|
||||
leptos::logging::log!("inside Portal effect");
|
||||
let tag = if is_svg { "g" } else { "div" };
|
||||
|
||||
let container = document()
|
||||
@@ -59,8 +53,7 @@ pub fn Portal(
|
||||
container.clone()
|
||||
};
|
||||
|
||||
let children = untrack(|| children().into_view().get_mountable_node());
|
||||
let _ = render_root.append_child(&children);
|
||||
let _ = render_root.append_child(&children().into_view().get_mountable_node());
|
||||
|
||||
let _ = mount.append_child(&container);
|
||||
|
||||
|
||||
@@ -20,6 +20,3 @@ typed-builder = "0.18"
|
||||
tokio = { version = "1", features = ["rt", "macros"] }
|
||||
tempfile = "3"
|
||||
temp-env = { version = "0.3.6", features = ["async_closure"] }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
|
||||
@@ -178,6 +178,3 @@ trace-component-props = []
|
||||
[package.metadata.cargo-all-features]
|
||||
denylist = ["nightly", "trace-component-props"]
|
||||
skip_feature_sets = [["web", "ssr"]]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
|
||||
@@ -112,7 +112,7 @@ pub fn request_animation_frame(cb: impl FnOnce() + 'static) {
|
||||
// Closure::once_into_js only frees the callback when it's actually
|
||||
// called, so this instead uses into_js_value, which can be freed by
|
||||
// the host JS engine's GC if it supports weak references (which all
|
||||
// modern browser engines do). The way this works is that the provided
|
||||
// modern brower engines do). The way this works is that the provided
|
||||
// callback's captured data is dropped immediately after being called,
|
||||
// as before, but it leaves behind a small stub closure rust-side that
|
||||
// will be freed "eventually" by the JS GC. If the function is never
|
||||
|
||||
@@ -1211,17 +1211,6 @@ impl IntoView for Rc<str> {
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoView for std::sync::Arc<str> {
|
||||
#[cfg_attr(
|
||||
any(debug_assertions, feature = "ssr"),
|
||||
instrument(level = "trace", name = "#text", skip_all)
|
||||
)]
|
||||
#[inline(always)]
|
||||
fn into_view(self) -> View {
|
||||
View::Text(Text::new(self.into()))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoView for Oco<'static, str> {
|
||||
#[cfg_attr(
|
||||
any(debug_assertions, feature = "ssr"),
|
||||
|
||||
@@ -46,16 +46,6 @@ pub trait IntoStyle {
|
||||
fn into_style_boxed(self: Box<Self>) -> Style;
|
||||
}
|
||||
|
||||
impl IntoStyle for Style {
|
||||
fn into_style(self) -> Style {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_style_boxed(self: Box<Self>) -> Style {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoStyle for &'static str {
|
||||
#[inline(always)]
|
||||
fn into_style(self) -> Style {
|
||||
@@ -186,7 +176,7 @@ impl Style {
|
||||
/// Converts the style to its HTML value at that moment so it can be rendered on the server.
|
||||
pub fn as_value_string(
|
||||
&self,
|
||||
style_name: &str,
|
||||
style_name: &'static str,
|
||||
) -> Option<Oco<'static, str>> {
|
||||
match self {
|
||||
Style::Value(value) => {
|
||||
|
||||
@@ -31,12 +31,10 @@ use std::cell::Cell;
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg_attr(not(debug_assertions), repr(transparent))]
|
||||
pub struct NodeRef<T: ElementDescriptor + 'static> {
|
||||
element: RwSignal<Option<HtmlElement<T>>>,
|
||||
#[cfg(debug_assertions)]
|
||||
defined_at: &'static std::panic::Location<'static>,
|
||||
}
|
||||
#[repr(transparent)]
|
||||
pub struct NodeRef<T: ElementDescriptor + 'static>(
|
||||
RwSignal<Option<HtmlElement<T>>>,
|
||||
);
|
||||
|
||||
/// Creates a shared reference to a DOM node created while using the `view`
|
||||
/// macro to create your UI.
|
||||
@@ -67,14 +65,9 @@ pub struct NodeRef<T: ElementDescriptor + 'static> {
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[track_caller]
|
||||
#[inline(always)]
|
||||
pub fn create_node_ref<T: ElementDescriptor + 'static>() -> NodeRef<T> {
|
||||
NodeRef {
|
||||
#[cfg(debug_assertions)]
|
||||
defined_at: std::panic::Location::caller(),
|
||||
element: create_rw_signal(None),
|
||||
}
|
||||
NodeRef(create_rw_signal(None))
|
||||
}
|
||||
|
||||
impl<T: ElementDescriptor + 'static> NodeRef<T> {
|
||||
@@ -127,7 +120,7 @@ impl<T: ElementDescriptor + 'static> NodeRef<T> {
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
self.element.get()
|
||||
self.0.get()
|
||||
}
|
||||
|
||||
/// Gets the element that is currently stored in the reference.
|
||||
@@ -139,7 +132,7 @@ impl<T: ElementDescriptor + 'static> NodeRef<T> {
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
self.element.get_untracked()
|
||||
self.0.get_untracked()
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
@@ -151,15 +144,13 @@ impl<T: ElementDescriptor + 'static> NodeRef<T> {
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
self.element.update(|current| {
|
||||
self.0.update(|current| {
|
||||
if current.is_some() {
|
||||
#[cfg(debug_assertions)]
|
||||
crate::debug_warn!(
|
||||
"You are setting the NodeRef defined at {}, which has \
|
||||
already been filled It’s possible this is intentional, \
|
||||
but it’s also possible that you’re accidentally using \
|
||||
the same NodeRef for multiple _ref attributes.",
|
||||
self.defined_at
|
||||
"You are setting a NodeRef that has already been filled. \
|
||||
It’s possible this is intentional, but it’s also \
|
||||
possible that you’re accidentally using the same NodeRef \
|
||||
for multiple _ref attributes."
|
||||
);
|
||||
}
|
||||
*current = Some(node.clone());
|
||||
|
||||
@@ -18,7 +18,7 @@ cfg-if = "1"
|
||||
html-escape = "0.2"
|
||||
itertools = "0.12"
|
||||
prettyplease = "0.2.4"
|
||||
proc-macro-error2 = { version = "2", default-features = false }
|
||||
proc-macro-error = { version = "1", default-features = false }
|
||||
proc-macro2 = "1"
|
||||
quote = "1"
|
||||
syn = { version = "2", features = ["full"] }
|
||||
@@ -51,6 +51,3 @@ axum = ["server_fn_macro/axum"]
|
||||
[package.metadata.cargo-all-features]
|
||||
denylist = ["nightly", "tracing", "trace-component-props"]
|
||||
skip_feature_sets = [["csr", "hydrate"], ["hydrate", "csr"], ["hydrate", "ssr"]]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
|
||||
@@ -11,13 +11,13 @@ dependencies = [
|
||||
[tasks.test-leptos_macro-example]
|
||||
description = "Tests the leptos_macro/example to check if macro handles doc comments correctly"
|
||||
command = "cargo"
|
||||
args = ["+nightly-2024-07-21", "test", "--doc"]
|
||||
args = ["+nightly-2024-04-14", "test", "--doc"]
|
||||
cwd = "example"
|
||||
install_crate = false
|
||||
|
||||
[tasks.doc-leptos_macro-example]
|
||||
description = "Docs the leptos_macro/example to check if macro handles doc comments correctly"
|
||||
command = "cargo"
|
||||
args = ["+nightly-2024-07-21", "doc"]
|
||||
args = ["+nightly-2024-04-14", "doc"]
|
||||
cwd = "example"
|
||||
install_crate = false
|
||||
|
||||
@@ -8,11 +8,10 @@ use leptos_hot_reload::parsing::value_to_string;
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
use quote::{format_ident, quote, quote_spanned, ToTokens, TokenStreamExt};
|
||||
use syn::{
|
||||
parse::Parse, parse_quote, spanned::Spanned, token::Colon,
|
||||
visit_mut::VisitMut, AngleBracketedGenericArguments, Attribute, FnArg,
|
||||
GenericArgument, GenericParam, Item, ItemFn, LitStr, Meta, Pat, PatIdent,
|
||||
Path, PathArguments, ReturnType, Signature, Stmt, Type, TypeImplTrait,
|
||||
TypeParam, TypePath, Visibility,
|
||||
parse::Parse, parse_quote, spanned::Spanned,
|
||||
AngleBracketedGenericArguments, Attribute, FnArg, GenericArgument, Item,
|
||||
ItemFn, LitStr, Meta, Pat, PatIdent, Path, PathArguments, ReturnType,
|
||||
Signature, Stmt, Type, TypePath, Visibility,
|
||||
};
|
||||
|
||||
pub struct Model {
|
||||
@@ -29,7 +28,6 @@ pub struct Model {
|
||||
impl Parse for Model {
|
||||
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||
let mut item = ItemFn::parse(input)?;
|
||||
convert_impl_trait_to_generic(&mut item.sig);
|
||||
|
||||
let docs = Docs::new(&item.attrs);
|
||||
|
||||
@@ -128,7 +126,7 @@ impl ToTokens for Model {
|
||||
_ => None,
|
||||
});
|
||||
if let Some(semi) = ends_semi {
|
||||
proc_macro_error2::emit_error!(
|
||||
proc_macro_error::emit_error!(
|
||||
semi.span(),
|
||||
"A component that ends with a `view!` macro followed by a \
|
||||
semicolon will return (), an empty view. This is usually \
|
||||
@@ -180,18 +178,6 @@ impl ToTokens for Model {
|
||||
);
|
||||
|
||||
let component_fn_prop_docs = generate_component_fn_prop_docs(props);
|
||||
let docs_and_prop_docs = if component_fn_prop_docs.is_empty() {
|
||||
// Avoid generating an empty doc line in case the component has no doc and no props.
|
||||
quote! {
|
||||
#docs
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
#docs
|
||||
#[doc = ""]
|
||||
#component_fn_prop_docs
|
||||
}
|
||||
};
|
||||
|
||||
let (
|
||||
tracing_instrument_attr,
|
||||
@@ -228,7 +214,7 @@ impl ToTokens for Model {
|
||||
|
||||
let component_id = name.to_string();
|
||||
let hydrate_fn_name =
|
||||
Ident::new(&format!("_island_{component_id}"), name.span());
|
||||
Ident::new(&format!("_island_{}", component_id), name.span());
|
||||
|
||||
let island_serialize_props = if is_island_with_other_props {
|
||||
quote! {
|
||||
@@ -416,61 +402,41 @@ impl ToTokens for Model {
|
||||
let island_props = if is_island_with_children
|
||||
|| is_island_with_other_props
|
||||
{
|
||||
let (destructure, prop_builders, optional_props) =
|
||||
if is_island_with_other_props {
|
||||
let prop_names = props
|
||||
.iter()
|
||||
.filter_map(|prop| {
|
||||
if prop.name.ident == "children" {
|
||||
None
|
||||
} else {
|
||||
let name = &prop.name.ident;
|
||||
Some(quote! { #name, })
|
||||
}
|
||||
})
|
||||
.collect::<TokenStream>();
|
||||
let destructure = quote! {
|
||||
let #props_serialized_name {
|
||||
#prop_names
|
||||
} = props;
|
||||
};
|
||||
let prop_builders = props
|
||||
.iter()
|
||||
.filter_map(|prop| {
|
||||
if prop.name.ident == "children"
|
||||
|| prop.prop_opts.optional
|
||||
{
|
||||
None
|
||||
} else {
|
||||
let name = &prop.name.ident;
|
||||
Some(quote! {
|
||||
.#name(#name)
|
||||
})
|
||||
}
|
||||
})
|
||||
.collect::<TokenStream>();
|
||||
let optional_props = props
|
||||
.iter()
|
||||
.filter_map(|prop| {
|
||||
if prop.name.ident == "children"
|
||||
|| !prop.prop_opts.optional
|
||||
{
|
||||
None
|
||||
} else {
|
||||
let name = &prop.name.ident;
|
||||
Some(quote! {
|
||||
if let Some(#name) = #name {
|
||||
props.#name = Some(#name)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
.collect::<TokenStream>();
|
||||
|
||||
(destructure, prop_builders, optional_props)
|
||||
} else {
|
||||
(quote! {}, quote! {}, quote! {})
|
||||
let (destructure, prop_builders) = if is_island_with_other_props
|
||||
{
|
||||
let prop_names = props
|
||||
.iter()
|
||||
.filter_map(|prop| {
|
||||
if prop.name.ident == "children" {
|
||||
None
|
||||
} else {
|
||||
let name = &prop.name.ident;
|
||||
Some(quote! { #name, })
|
||||
}
|
||||
})
|
||||
.collect::<TokenStream>();
|
||||
let destructure = quote! {
|
||||
let #props_serialized_name {
|
||||
#prop_names
|
||||
} = props;
|
||||
};
|
||||
let prop_builders = props
|
||||
.iter()
|
||||
.filter_map(|prop| {
|
||||
if prop.name.ident == "children" {
|
||||
None
|
||||
} else {
|
||||
let name = &prop.name.ident;
|
||||
Some(quote! {
|
||||
.#name(#name)
|
||||
})
|
||||
}
|
||||
})
|
||||
.collect::<TokenStream>();
|
||||
(destructure, prop_builders)
|
||||
} else {
|
||||
(quote! {}, quote! {})
|
||||
};
|
||||
let children = if is_island_with_children {
|
||||
quote! {
|
||||
.children(::std::boxed::Box::new(move || ::leptos::Fragment::lazy(|| ::std::vec![
|
||||
@@ -489,13 +455,10 @@ impl ToTokens for Model {
|
||||
|
||||
quote! {{
|
||||
#destructure
|
||||
let mut props = #props_name::builder()
|
||||
#props_name::builder()
|
||||
#prop_builders
|
||||
#children.build();
|
||||
|
||||
#optional_props
|
||||
|
||||
props
|
||||
#children
|
||||
.build()
|
||||
}}
|
||||
} else {
|
||||
quote! {}
|
||||
@@ -539,7 +502,9 @@ impl ToTokens for Model {
|
||||
let output = quote! {
|
||||
#[doc = #builder_name_doc]
|
||||
#[doc = ""]
|
||||
#docs_and_prop_docs
|
||||
#docs
|
||||
#[doc = ""]
|
||||
#component_fn_prop_docs
|
||||
#[derive(::leptos::typed_builder_macro::TypedBuilder #props_derive_serialize)]
|
||||
//#[builder(doc)]
|
||||
#[builder(crate_module_path=::leptos::typed_builder)]
|
||||
@@ -566,7 +531,7 @@ impl ToTokens for Model {
|
||||
}
|
||||
}
|
||||
|
||||
impl #impl_generics ::leptos::DynBindings for #props_name #generics #where_clause {
|
||||
impl #impl_generics #props_name #generics #where_clause {
|
||||
fn dyn_bindings<B: Into<::leptos::leptos_dom::html::Binding>>(mut self, bindings: impl std::iter::IntoIterator<Item = B>) -> Self {
|
||||
for binding in bindings.into_iter() {
|
||||
let binding: ::leptos::leptos_dom::html::Binding = binding.into();
|
||||
@@ -583,7 +548,9 @@ impl ToTokens for Model {
|
||||
|
||||
#into_view
|
||||
|
||||
#docs_and_prop_docs
|
||||
#docs
|
||||
#[doc = ""]
|
||||
#component_fn_prop_docs
|
||||
#[allow(non_snake_case, clippy::too_many_arguments)]
|
||||
#[allow(clippy::needless_lifetimes)]
|
||||
#tracing_instrument_attr
|
||||
@@ -1254,57 +1221,3 @@ fn is_valid_into_view_return_type(ty: &ReturnType) -> bool {
|
||||
pub fn unmodified_fn_name_from_fn_name(ident: &Ident) -> Ident {
|
||||
Ident::new(&format!("__{ident}"), ident.span())
|
||||
}
|
||||
|
||||
/// Converts all `impl Trait`s in a function signature to use generic params instead.
|
||||
fn convert_impl_trait_to_generic(sig: &mut Signature) {
|
||||
fn new_generic_ident(i: usize, span: Span) -> Ident {
|
||||
Ident::new(&format!("__ImplTrait{i}"), span)
|
||||
}
|
||||
|
||||
// First: visit all `impl Trait`s and replace them with new generic params.
|
||||
#[derive(Default)]
|
||||
struct RemoveImplTrait(Vec<TypeImplTrait>);
|
||||
impl VisitMut for RemoveImplTrait {
|
||||
fn visit_type_mut(&mut self, ty: &mut Type) {
|
||||
syn::visit_mut::visit_type_mut(self, ty);
|
||||
if matches!(ty, Type::ImplTrait(_)) {
|
||||
let ident = new_generic_ident(self.0.len(), ty.span());
|
||||
let generic_type = Type::Path(TypePath {
|
||||
qself: None,
|
||||
path: Path::from(ident),
|
||||
});
|
||||
let Type::ImplTrait(impl_trait) =
|
||||
std::mem::replace(ty, generic_type)
|
||||
else {
|
||||
unreachable!();
|
||||
};
|
||||
self.0.push(impl_trait);
|
||||
}
|
||||
}
|
||||
|
||||
// Early exits.
|
||||
fn visit_attribute_mut(&mut self, _: &mut Attribute) {}
|
||||
fn visit_pat_mut(&mut self, _: &mut Pat) {}
|
||||
}
|
||||
let mut visitor = RemoveImplTrait::default();
|
||||
for fn_arg in sig.inputs.iter_mut() {
|
||||
visitor.visit_fn_arg_mut(fn_arg);
|
||||
}
|
||||
let RemoveImplTrait(impl_traits) = visitor;
|
||||
|
||||
// Second: Add the new generic params into the signature.
|
||||
for (i, impl_trait) in impl_traits.into_iter().enumerate() {
|
||||
let span = impl_trait.span();
|
||||
let ident = new_generic_ident(i, span);
|
||||
// We can simply append to the end (only lifetime params must be first).
|
||||
// Note currently default generics are not allowed in `fn`, so not a concern.
|
||||
sig.generics.params.push(GenericParam::Type(TypeParam {
|
||||
attrs: vec![],
|
||||
ident,
|
||||
colon_token: Some(Colon { spans: [span] }),
|
||||
bounds: impl_trait.bounds,
|
||||
eq_token: None,
|
||||
default: None,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#![allow(private_macro_use)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate proc_macro_error2;
|
||||
extern crate proc_macro_error;
|
||||
|
||||
use component::DummyModel;
|
||||
use proc_macro::TokenStream;
|
||||
@@ -24,7 +24,10 @@ pub(crate) enum Mode {
|
||||
|
||||
impl Default for Mode {
|
||||
fn default() -> Self {
|
||||
if cfg!(feature = "hydrate") || cfg!(feature = "csr") {
|
||||
if cfg!(feature = "hydrate")
|
||||
|| cfg!(feature = "csr")
|
||||
|| cfg!(feature = "web")
|
||||
{
|
||||
Mode::Client
|
||||
} else {
|
||||
Mode::Ssr
|
||||
@@ -313,7 +316,7 @@ mod slot;
|
||||
/// # ;
|
||||
/// # }
|
||||
/// ```
|
||||
#[proc_macro_error2::proc_macro_error]
|
||||
#[proc_macro_error::proc_macro_error]
|
||||
#[proc_macro]
|
||||
#[cfg_attr(
|
||||
any(debug_assertions, feature = "ssr"),
|
||||
@@ -391,7 +394,7 @@ fn normalized_call_site(site: proc_macro::Span) -> Option<String> {
|
||||
/// syntax as the [view!] macro. In hydration or server-side rendering mode,
|
||||
/// behaves exactly as the `view` macro. In client-side rendering mode, uses a `<template>`
|
||||
/// node to efficiently render the element. Should only be used with a single root element.
|
||||
#[proc_macro_error2::proc_macro_error]
|
||||
#[proc_macro_error::proc_macro_error]
|
||||
#[proc_macro]
|
||||
pub fn template(tokens: TokenStream) -> TokenStream {
|
||||
if cfg!(feature = "csr") {
|
||||
@@ -583,7 +586,7 @@ pub fn template(tokens: TokenStream) -> TokenStream {
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[proc_macro_error2::proc_macro_error]
|
||||
#[proc_macro_error::proc_macro_error]
|
||||
#[proc_macro_attribute]
|
||||
pub fn component(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
|
||||
let is_transparent = if !args.is_empty() {
|
||||
@@ -699,7 +702,7 @@ pub fn component(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[proc_macro_error2::proc_macro_error]
|
||||
#[proc_macro_error::proc_macro_error]
|
||||
#[proc_macro_attribute]
|
||||
pub fn island(_args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
|
||||
let Ok(mut dummy) = syn::parse::<DummyModel>(s.clone()) else {
|
||||
@@ -839,7 +842,7 @@ pub fn island(_args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[proc_macro_error2::proc_macro_error]
|
||||
#[proc_macro_error::proc_macro_error]
|
||||
#[proc_macro_attribute]
|
||||
pub fn slot(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
|
||||
if !args.is_empty() {
|
||||
|
||||
@@ -11,7 +11,7 @@ use syn::{
|
||||
|
||||
struct SliceMacroInput {
|
||||
root: syn::Ident,
|
||||
path: Punctuated<syn::Member, Token![.]>,
|
||||
path: Punctuated<syn::Ident, Token![.]>,
|
||||
}
|
||||
|
||||
impl Parse for SliceMacroInput {
|
||||
@@ -19,7 +19,7 @@ impl Parse for SliceMacroInput {
|
||||
let root: syn::Ident = input.parse()?;
|
||||
input.parse::<Token![.]>()?;
|
||||
// do not accept trailing punctuation
|
||||
let path: Punctuated<syn::Member, Token![.]> =
|
||||
let path: Punctuated<syn::Ident, Token![.]> =
|
||||
Punctuated::parse_separated_nonempty(input)?;
|
||||
|
||||
if path.is_empty() {
|
||||
|
||||
@@ -43,6 +43,7 @@ pub(crate) fn fragment_to_tokens(
|
||||
let mut nodes = nodes
|
||||
.iter()
|
||||
.filter_map(|node| {
|
||||
let span = node.span();
|
||||
let node = node_to_tokens(
|
||||
node,
|
||||
parent_type,
|
||||
@@ -51,8 +52,12 @@ pub(crate) fn fragment_to_tokens(
|
||||
None,
|
||||
)?;
|
||||
|
||||
let node = quote_spanned! {span=>
|
||||
#[allow(unused_braces)] {#node}
|
||||
};
|
||||
|
||||
Some(quote! {
|
||||
::leptos::IntoView::into_view(#[allow(unused_braces)] { #node })
|
||||
::leptos::IntoView::into_view(#node)
|
||||
})
|
||||
})
|
||||
.peekable();
|
||||
@@ -132,7 +137,7 @@ pub(crate) fn node_to_tokens(
|
||||
Node::RawText(r) => {
|
||||
let text = r.to_string_best();
|
||||
if text == "cx," {
|
||||
proc_macro_error2::abort!(
|
||||
proc_macro_error::abort!(
|
||||
r.span(),
|
||||
"`cx,` is not used with the `view!` macro in 0.5."
|
||||
)
|
||||
@@ -185,7 +190,7 @@ pub(crate) fn element_to_tokens(
|
||||
match parent_type {
|
||||
TagType::Unknown => {
|
||||
// We decided this warning was too aggressive, but I'll leave it here in case we want it later
|
||||
/* proc_macro_error2::emit_warning!(name.span(), "The view macro is assuming this is an HTML element, \
|
||||
/* proc_macro_error::emit_warning!(name.span(), "The view macro is assuming this is an HTML element, \
|
||||
but it is ambiguous; if it is an SVG or MathML element, prefix with svg:: or math::"); */
|
||||
quote! {
|
||||
::leptos::leptos_dom::html::#name()
|
||||
@@ -282,7 +287,7 @@ pub(crate) fn element_to_tokens(
|
||||
};
|
||||
|
||||
if is_self_closing(node) && !node.children.is_empty() {
|
||||
proc_macro_error2::abort!(
|
||||
proc_macro_error::abort!(
|
||||
node.name().span(),
|
||||
format!(
|
||||
"<{tag}> is a self-closing tag and cannot have children."
|
||||
@@ -293,36 +298,34 @@ pub(crate) fn element_to_tokens(
|
||||
let children = node
|
||||
.children
|
||||
.iter()
|
||||
.filter_map(|node| match node {
|
||||
Node::Fragment(fragment) => Some(
|
||||
fragment_to_tokens(
|
||||
&fragment.children,
|
||||
true,
|
||||
parent_type,
|
||||
None,
|
||||
global_class,
|
||||
None,
|
||||
)
|
||||
.unwrap_or(quote! { ::leptos::leptos_dom::Unit }),
|
||||
),
|
||||
Node::Text(node) => Some(quote! { #node }),
|
||||
.map(|node| match node {
|
||||
Node::Fragment(fragment) => fragment_to_tokens(
|
||||
&fragment.children,
|
||||
true,
|
||||
parent_type,
|
||||
None,
|
||||
global_class,
|
||||
None,
|
||||
)
|
||||
.unwrap_or(quote_spanned! {
|
||||
Span::call_site()=> ::leptos::leptos_dom::Unit
|
||||
}),
|
||||
Node::Text(node) => quote! { #node },
|
||||
Node::RawText(node) => {
|
||||
let text = node.to_string_best();
|
||||
let text = syn::LitStr::new(&text, node.span());
|
||||
Some(quote! { #text })
|
||||
quote! { #text }
|
||||
}
|
||||
Node::Block(node) => Some(quote! { #node }),
|
||||
Node::Element(node) => Some(
|
||||
element_to_tokens(
|
||||
node,
|
||||
parent_type,
|
||||
None,
|
||||
global_class,
|
||||
None,
|
||||
)
|
||||
.unwrap_or_default(),
|
||||
),
|
||||
Node::Comment(_) | Node::Doctype(_) => None,
|
||||
Node::Block(node) => quote! { #node },
|
||||
Node::Element(node) => element_to_tokens(
|
||||
node,
|
||||
parent_type,
|
||||
None,
|
||||
global_class,
|
||||
None,
|
||||
)
|
||||
.unwrap_or_default(),
|
||||
Node::Comment(_) | Node::Doctype(_) => quote! {},
|
||||
})
|
||||
.map(|node| quote!(.child(#node)));
|
||||
|
||||
@@ -332,22 +335,20 @@ pub(crate) fn element_to_tokens(
|
||||
quote! {}
|
||||
};
|
||||
let ide_helper_close_tag = ide_helper_close_tag.into_iter();
|
||||
let result = quote! {
|
||||
Some(quote_spanned! {node.span()=>
|
||||
#[allow(unused_braces)]
|
||||
{
|
||||
#(#ide_helper_close_tag)*
|
||||
#name
|
||||
#(#attrs)*
|
||||
#(#bindings)*
|
||||
#(#class_attrs)*
|
||||
#(#style_attrs)*
|
||||
#global_class_expr
|
||||
#(#children)*
|
||||
#view_marker
|
||||
#(#ide_helper_close_tag)*
|
||||
#name
|
||||
#(#attrs)*
|
||||
#(#bindings)*
|
||||
#(#class_attrs)*
|
||||
#(#style_attrs)*
|
||||
#global_class_expr
|
||||
#(#children)*
|
||||
#view_marker
|
||||
}
|
||||
};
|
||||
|
||||
// We need to move "allow" out of "quote_spanned" because it breaks hovering in rust-analyzer
|
||||
Some(quote!(#[allow(unused_braces)] #result))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,14 +403,18 @@ pub(crate) fn attribute_to_tokens(
|
||||
let event_type = if is_custom {
|
||||
event_type
|
||||
} else if let Some(ev_name) = event_name_ident {
|
||||
quote! { #ev_name }
|
||||
quote_spanned! {
|
||||
ev_name.span()=> #ev_name
|
||||
}
|
||||
} else {
|
||||
event_type
|
||||
};
|
||||
|
||||
let event_type = if is_force_undelegated {
|
||||
let undelegated = if let Some(undelegated) = undelegated_ident {
|
||||
quote! { #undelegated }
|
||||
quote_spanned! {
|
||||
undelegated.span()=> #undelegated
|
||||
}
|
||||
} else {
|
||||
quote! { undelegated }
|
||||
};
|
||||
@@ -470,7 +475,7 @@ pub(crate) fn attribute_to_tokens(
|
||||
&& node.value().and_then(value_to_string).is_none()
|
||||
{
|
||||
let span = node.key.span();
|
||||
proc_macro_error2::emit_error!(span, "Combining a global class (view! { class = ... }) \
|
||||
proc_macro_error::emit_error!(span, "Combining a global class (view! { class = ... }) \
|
||||
and a dynamic `class=` attribute on an element causes runtime inconsistencies. You can \
|
||||
toggle individual classes dynamically with the `class:name=value` syntax. \n\nSee this issue \
|
||||
for more information and an example: https://github.com/leptos-rs/leptos/issues/773")
|
||||
|
||||
@@ -384,7 +384,7 @@ fn child_to_tokens(
|
||||
match node {
|
||||
Node::Element(node) => {
|
||||
if is_component_node(node) {
|
||||
proc_macro_error2::emit_error!(
|
||||
proc_macro_error::emit_error!(
|
||||
node.name().span(),
|
||||
"component children not allowed in template!, use view! \
|
||||
instead"
|
||||
|
||||
@@ -6,7 +6,7 @@ use super::{
|
||||
};
|
||||
use crate::view::directive_call_from_attribute_node;
|
||||
use proc_macro2::{Ident, TokenStream, TokenTree};
|
||||
use quote::{format_ident, quote, quote_spanned, ToTokens};
|
||||
use quote::{format_ident, quote, quote_spanned};
|
||||
use rstml::node::{NodeAttribute, NodeElement};
|
||||
use std::collections::HashMap;
|
||||
use syn::spanned::Spanned;
|
||||
@@ -70,8 +70,12 @@ pub(crate) fn component_to_tokens(
|
||||
})
|
||||
.unwrap_or_else(|| quote! { #name });
|
||||
|
||||
quote! {
|
||||
.#name(#[allow(unused_braces)] { #value })
|
||||
let value = quote_spanned! {value.span()=>
|
||||
#[allow(unused_braces)] {#value}
|
||||
};
|
||||
|
||||
quote_spanned! {attr.span()=>
|
||||
.#name(#value)
|
||||
}
|
||||
});
|
||||
|
||||
@@ -100,13 +104,7 @@ pub(crate) fn component_to_tokens(
|
||||
.filter(|attr| attr.key.to_string().starts_with("on:"))
|
||||
.map(|attr| {
|
||||
let (event_type, handler) = event_from_attribute_node(attr, true);
|
||||
// HACK(chrisp60): rstml and leptos has a different definition on attribute keys.
|
||||
// This retains precise span information for the "on" in "on:some_event_name".
|
||||
//
|
||||
// A similar hack is done in `event_from_attribute_node` to retain the precise
|
||||
// event name span.
|
||||
let on = attr.key.to_token_stream().into_iter().next();
|
||||
|
||||
let on = quote_spanned!(attr.key.span()=> on);
|
||||
quote! {
|
||||
.#on(#event_type, #handler)
|
||||
}
|
||||
@@ -173,7 +171,8 @@ pub(crate) fn component_to_tokens(
|
||||
items_to_bind.iter().map(|ident| quote! { #ident, });
|
||||
|
||||
let clonables = items_to_clone.iter().map(|ident| {
|
||||
quote! { let #ident = ::core::clone::Clone::clone(&#ident); }
|
||||
let ident_ref = quote_spanned!(ident.span()=> &#ident);
|
||||
quote! { let #ident = ::core::clone::Clone::clone(#ident_ref); }
|
||||
});
|
||||
|
||||
if bindables.len() > 0 {
|
||||
@@ -205,7 +204,7 @@ pub(crate) fn component_to_tokens(
|
||||
.span();
|
||||
let slot = Ident::new(&slot, span);
|
||||
let value = if values.len() > 1 {
|
||||
quote! {
|
||||
quote_spanned! {span=>
|
||||
::std::vec![
|
||||
#(#values)*
|
||||
]
|
||||
@@ -224,19 +223,39 @@ pub(crate) fn component_to_tokens(
|
||||
quote! {}
|
||||
};
|
||||
|
||||
let name_ref = quote_spanned! {name.span()=>
|
||||
&#name
|
||||
};
|
||||
|
||||
let build = quote_spanned! {name.span()=>
|
||||
.build()
|
||||
};
|
||||
|
||||
let component_props_builder = quote_spanned! {name.span()=>
|
||||
::leptos::component_props_builder(#name_ref #generics)
|
||||
};
|
||||
|
||||
#[allow(unused_mut)] // used in debug
|
||||
let mut component = quote! {
|
||||
::leptos::component_view(
|
||||
#[allow(clippy::needless_borrows_for_generic_args)]
|
||||
&#name,
|
||||
::leptos::component_props_builder(&#name #generics)
|
||||
let mut component = quote_spanned! {node.span()=>
|
||||
{
|
||||
let props = #component_props_builder
|
||||
#(#props)*
|
||||
#(#slots)*
|
||||
#children
|
||||
.build()
|
||||
#children;
|
||||
|
||||
#[allow(clippy::let_unit_value, clippy::unit_arg)]
|
||||
let props = props
|
||||
#build
|
||||
#dyn_attrs
|
||||
#(#spread_bindings)*
|
||||
)
|
||||
#(#spread_bindings)*;
|
||||
|
||||
#[allow(unreachable_code)]
|
||||
::leptos::component_view(
|
||||
#[allow(clippy::needless_borrows_for_generic_args)]
|
||||
#name_ref,
|
||||
props
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
// (Temporarily?) removed
|
||||
@@ -247,7 +266,7 @@ pub(crate) fn component_to_tokens(
|
||||
if events_and_directives.is_empty() {
|
||||
component
|
||||
} else {
|
||||
quote! {
|
||||
quote_spanned! {node.span()=>
|
||||
::leptos::IntoView::into_view(#[allow(unused_braces)] {#component})
|
||||
#(#events_and_directives)*
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ impl IdeTagHelper {
|
||||
/// Emit warning if tag is component.
|
||||
pub fn save_tag_completion(&mut self, name: &NodeName) {
|
||||
if is_component_tag_name(name) {
|
||||
proc_macro_error2::emit_warning!(
|
||||
proc_macro_error::emit_warning!(
|
||||
name.span(),
|
||||
"BUG: Component tag is used in regular tag completion."
|
||||
);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::{attribute_value, Mode};
|
||||
use convert_case::{Case::Snake, Casing};
|
||||
use proc_macro2::{Ident, Span, TokenStream, TokenTree};
|
||||
use quote::{quote, quote_spanned, ToTokens};
|
||||
use quote::{quote, quote_spanned};
|
||||
use rstml::node::{KeyedAttribute, Node, NodeElement, NodeName};
|
||||
use syn::{
|
||||
spanned::Spanned,
|
||||
@@ -439,7 +439,7 @@ fn fancy_class_name<'a>(
|
||||
}
|
||||
|
||||
_ => {
|
||||
proc_macro_error2::emit_error!(
|
||||
proc_macro_error::emit_error!(
|
||||
elem.span(),
|
||||
"class name elements must be string \
|
||||
literals"
|
||||
@@ -459,7 +459,7 @@ fn fancy_class_name<'a>(
|
||||
}
|
||||
|
||||
_ => {
|
||||
proc_macro_error2::emit_error!(
|
||||
proc_macro_error::emit_error!(
|
||||
class_name.span(),
|
||||
"class name must be a string literal or array of \
|
||||
string literals"
|
||||
@@ -475,7 +475,7 @@ fn fancy_class_name<'a>(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
proc_macro_error2::emit_error!(
|
||||
proc_macro_error::emit_error!(
|
||||
tuple.span(),
|
||||
"class tuples must have two elements."
|
||||
)
|
||||
@@ -496,7 +496,7 @@ fn ident_from_tag_name(tag_name: &NodeName) -> Ident {
|
||||
.expect("element needs to have a name"),
|
||||
NodeName::Block(_) => {
|
||||
let span = tag_name.span();
|
||||
proc_macro_error2::emit_error!(
|
||||
proc_macro_error::emit_error!(
|
||||
span,
|
||||
"blocks not allowed in tag-name position"
|
||||
);
|
||||
@@ -529,7 +529,7 @@ fn fancy_style_name<'a>(
|
||||
{
|
||||
s.value()
|
||||
} else {
|
||||
proc_macro_error2::emit_error!(
|
||||
proc_macro_error::emit_error!(
|
||||
style_name.span(),
|
||||
"style name must be a string literal"
|
||||
);
|
||||
@@ -544,7 +544,7 @@ fn fancy_style_name<'a>(
|
||||
value,
|
||||
));
|
||||
} else {
|
||||
proc_macro_error2::emit_error!(
|
||||
proc_macro_error::emit_error!(
|
||||
tuple.span(),
|
||||
"style tuples must have two elements."
|
||||
)
|
||||
@@ -567,41 +567,12 @@ pub(crate) fn event_from_attribute_node(
|
||||
|
||||
let handler = attribute_value(attr);
|
||||
|
||||
let (event_type, is_custom, name_undelegated) =
|
||||
parse_event_name(&event_name);
|
||||
|
||||
// HACK(chrisp60): in the code above, the original span information is lost
|
||||
// as the event name is parsed from a stringified version of the tokens.
|
||||
//
|
||||
// This assumes that the attribute key is structured as "on:some_event_name" and
|
||||
// just skips the "on:" part, isolating the "some_event_name" tokens. In turn,
|
||||
// we keep the span information from the original event identifier.
|
||||
//
|
||||
// .nth(2) is because syn parses follows
|
||||
// token 0: "on"
|
||||
// token 1: ":"
|
||||
// token 2: "event"
|
||||
//
|
||||
// There are cleaners ways to do this but this is a legacy branch.
|
||||
let original_tokens = attr
|
||||
.key
|
||||
.to_token_stream()
|
||||
.into_iter()
|
||||
.nth(2)
|
||||
.expect("tokens following on:"); // see previous call to .expect in this same function
|
||||
|
||||
// is_custom wraps the event type in a struct definition, so don't use
|
||||
// our original tokens.
|
||||
let absolute_ev = if is_custom {
|
||||
quote! { ::leptos::leptos_dom::ev::#event_type }
|
||||
} else {
|
||||
quote! { ::leptos::leptos_dom::ev::#original_tokens }
|
||||
};
|
||||
let (event_type, _, name_undelegated) = parse_event_name(&event_name);
|
||||
|
||||
let event_type = if force_undelegated || name_undelegated {
|
||||
quote! { ::leptos::leptos_dom::ev::undelegated(#absolute_ev) }
|
||||
quote! { ::leptos::leptos_dom::ev::undelegated(::leptos::leptos_dom::ev::#event_type) }
|
||||
} else {
|
||||
quote! { ::leptos::leptos_dom::ev::#absolute_ev }
|
||||
quote! { ::leptos::leptos_dom::ev::#event_type }
|
||||
};
|
||||
(event_type, handler)
|
||||
}
|
||||
|
||||
@@ -81,14 +81,18 @@ pub(crate) fn fragment_to_tokens_ssr(
|
||||
};
|
||||
|
||||
let nodes = nodes.iter().map(|node| {
|
||||
let span = node.span();
|
||||
let node = root_node_to_tokens_ssr(node, global_class, None);
|
||||
let node = quote_spanned! {span=>
|
||||
#[allow(unused_braces)] {#node}
|
||||
};
|
||||
|
||||
quote! {
|
||||
::leptos::IntoView::into_view(#[allow(unused_braces)] { #node })
|
||||
::leptos::IntoView::into_view(#node)
|
||||
}
|
||||
});
|
||||
|
||||
quote! {
|
||||
quote_spanned! {original_span=>
|
||||
{
|
||||
::leptos::Fragment::lazy(|| ::std::vec![
|
||||
#(#nodes),*
|
||||
@@ -464,7 +468,7 @@ fn attribute_to_tokens_ssr<'a>(
|
||||
&& attr.value().and_then(value_to_string).is_none()
|
||||
{
|
||||
let span = attr.key.span();
|
||||
proc_macro_error2::emit_error!(span, "Combining a global class (view! { class = ... }) \
|
||||
proc_macro_error::emit_error!(span, "Combining a global class (view! { class = ... }) \
|
||||
and a dynamic `class=` attribute on an element causes runtime inconsistencies. You can \
|
||||
toggle individual classes dynamically with the `class:name=value` syntax. \n\nSee this issue \
|
||||
for more information and an example: https://github.com/leptos-rs/leptos/issues/773")
|
||||
|
||||
@@ -25,7 +25,7 @@ pub(crate) fn slot_to_tokens(
|
||||
let component_name = ident_from_tag_name(node.name());
|
||||
|
||||
let Some(parent_slots) = parent_slots else {
|
||||
proc_macro_error2::emit_error!(
|
||||
proc_macro_error::emit_error!(
|
||||
node.name().span(),
|
||||
"slots cannot be used inside HTML elements"
|
||||
);
|
||||
@@ -61,8 +61,12 @@ pub(crate) fn slot_to_tokens(
|
||||
})
|
||||
.unwrap_or_else(|| quote! { #name });
|
||||
|
||||
quote! {
|
||||
.#name(#[allow(unused_braces)] { #value })
|
||||
let value = quote_spanned! {value.span()=>
|
||||
#[allow(unused_braces)] {#value}
|
||||
};
|
||||
|
||||
quote_spanned! {attr.span()=>
|
||||
.#name(#value)
|
||||
}
|
||||
});
|
||||
|
||||
@@ -166,7 +170,7 @@ pub(crate) fn slot_to_tokens(
|
||||
.span();
|
||||
let slot = Ident::new(&slot, span);
|
||||
let value = if values.len() > 1 {
|
||||
quote! {
|
||||
quote_spanned! {span=>
|
||||
::std::vec![
|
||||
#(#values)*
|
||||
]
|
||||
@@ -183,7 +187,7 @@ pub(crate) fn slot_to_tokens(
|
||||
};
|
||||
|
||||
let slot = quote_spanned! {node.span()=>
|
||||
{
|
||||
#[allow(unused_braces)] {
|
||||
let slot = #component_name::builder()
|
||||
#(#props)*
|
||||
#(#slots)*
|
||||
@@ -196,9 +200,6 @@ pub(crate) fn slot_to_tokens(
|
||||
},
|
||||
};
|
||||
|
||||
// We need to move "allow" out of "quote_spanned" because it breaks hovering in rust-analyzer
|
||||
let slot = quote!(#[allow(unused_braces)] #slot);
|
||||
|
||||
parent_slots
|
||||
.entry(name)
|
||||
.and_modify(|entry| entry.push(slot.clone()))
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
---
|
||||
source: leptos_macro/src/view/tests.rs
|
||||
assertion_line: 101
|
||||
expression: pretty(result)
|
||||
---
|
||||
fn view() {
|
||||
::leptos::component_view(
|
||||
#[allow(clippy::needless_borrows_for_generic_args)]
|
||||
&SimpleCounter,
|
||||
::leptos::component_props_builder(&SimpleCounter)
|
||||
{
|
||||
let props = ::leptos::component_props_builder(&SimpleCounter)
|
||||
.initial_value(#[allow(unused_braces)] { 0 })
|
||||
.step(#[allow(unused_braces)] { 1 })
|
||||
.build(),
|
||||
)
|
||||
.step(#[allow(unused_braces)] { 1 });
|
||||
#[allow(clippy::let_unit_value, clippy::unit_arg)]
|
||||
let props = props.build();
|
||||
#[allow(unreachable_code)]
|
||||
::leptos::component_view(
|
||||
#[allow(clippy::needless_borrows_for_generic_args)]
|
||||
&SimpleCounter,
|
||||
props,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
---
|
||||
source: leptos_macro/src/view/tests.rs
|
||||
assertion_line: 101
|
||||
expression: pretty(result)
|
||||
---
|
||||
fn view() {
|
||||
::leptos::IntoView::into_view(
|
||||
#[allow(unused_braces)]
|
||||
{
|
||||
::leptos::component_view(
|
||||
#[allow(clippy::needless_borrows_for_generic_args)]
|
||||
&ExternalComponent,
|
||||
::leptos::component_props_builder(&ExternalComponent).build(),
|
||||
)
|
||||
{
|
||||
let props = ::leptos::component_props_builder(&ExternalComponent);
|
||||
#[allow(clippy::let_unit_value, clippy::unit_arg)]
|
||||
let props = props.build();
|
||||
#[allow(unreachable_code)]
|
||||
::leptos::component_view(
|
||||
#[allow(clippy::needless_borrows_for_generic_args)]
|
||||
&ExternalComponent,
|
||||
props,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
.on(
|
||||
@@ -20,3 +27,4 @@ fn view() {
|
||||
move |_: Event| set_value(0),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,89 +1,22 @@
|
||||
---
|
||||
source: leptos_macro/src/view/tests.rs
|
||||
assertion_line: 101
|
||||
expression: result
|
||||
---
|
||||
TokenStream [
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: leptos,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: component_view,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
delimiter: Brace,
|
||||
stream: TokenStream [
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
Ident {
|
||||
sym: let,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: clippy,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: needless_borrows_for_generic_args,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '&',
|
||||
spacing: Alone,
|
||||
span: bytes(11..24),
|
||||
},
|
||||
Ident {
|
||||
sym: SimpleCounter,
|
||||
span: bytes(11..24),
|
||||
sym: props,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ',',
|
||||
char: '=',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
@@ -145,27 +78,27 @@ TokenStream [
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
span: bytes(37..52),
|
||||
span: bytes(51..52),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(37..52),
|
||||
span: bytes(51..52),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: unused_braces,
|
||||
span: bytes(37..52),
|
||||
span: bytes(51..52),
|
||||
},
|
||||
],
|
||||
span: bytes(37..52),
|
||||
span: bytes(51..52),
|
||||
},
|
||||
],
|
||||
span: bytes(37..52),
|
||||
span: bytes(51..52),
|
||||
},
|
||||
Group {
|
||||
delimiter: Brace,
|
||||
@@ -195,27 +128,27 @@ TokenStream [
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
span: bytes(65..71),
|
||||
span: bytes(70..71),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(65..71),
|
||||
span: bytes(70..71),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: unused_braces,
|
||||
span: bytes(65..71),
|
||||
span: bytes(70..71),
|
||||
},
|
||||
],
|
||||
span: bytes(65..71),
|
||||
span: bytes(70..71),
|
||||
},
|
||||
],
|
||||
span: bytes(65..71),
|
||||
span: bytes(70..71),
|
||||
},
|
||||
Group {
|
||||
delimiter: Brace,
|
||||
@@ -230,6 +163,90 @@ TokenStream [
|
||||
],
|
||||
span: bytes(65..71),
|
||||
},
|
||||
Punct {
|
||||
char: ';',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: clippy,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: let_unit_value,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ',',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: clippy,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: unit_arg,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: let,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: props,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '=',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: props,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '.',
|
||||
spacing: Alone,
|
||||
@@ -244,6 +261,127 @@ TokenStream [
|
||||
stream: TokenStream [],
|
||||
span: bytes(11..24),
|
||||
},
|
||||
Punct {
|
||||
char: ';',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: unreachable_code,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: leptos,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: component_view,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: clippy,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: needless_borrows_for_generic_args,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '&',
|
||||
spacing: Alone,
|
||||
span: bytes(11..24),
|
||||
},
|
||||
Ident {
|
||||
sym: SimpleCounter,
|
||||
span: bytes(11..24),
|
||||
},
|
||||
Punct {
|
||||
char: ',',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: props,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
source: leptos_macro/src/view/tests.rs
|
||||
assertion_line: 101
|
||||
expression: result
|
||||
---
|
||||
TokenStream [
|
||||
@@ -76,87 +77,19 @@ TokenStream [
|
||||
Group {
|
||||
delimiter: Brace,
|
||||
stream: TokenStream [
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: leptos,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: component_view,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
delimiter: Brace,
|
||||
stream: TokenStream [
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
Ident {
|
||||
sym: let,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: clippy,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: needless_borrows_for_generic_args,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '&',
|
||||
spacing: Alone,
|
||||
span: bytes(11..28),
|
||||
},
|
||||
Ident {
|
||||
sym: ExternalComponent,
|
||||
span: bytes(11..28),
|
||||
sym: props,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ',',
|
||||
char: '=',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
@@ -203,6 +136,90 @@ TokenStream [
|
||||
],
|
||||
span: bytes(11..28),
|
||||
},
|
||||
Punct {
|
||||
char: ';',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: clippy,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: let_unit_value,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ',',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: clippy,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: unit_arg,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: let,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: props,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '=',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: props,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '.',
|
||||
spacing: Alone,
|
||||
@@ -217,6 +234,127 @@ TokenStream [
|
||||
stream: TokenStream [],
|
||||
span: bytes(11..28),
|
||||
},
|
||||
Punct {
|
||||
char: ';',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: unreachable_code,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: leptos,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: component_view,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: clippy,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: needless_borrows_for_generic_args,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '&',
|
||||
spacing: Alone,
|
||||
span: bytes(11..28),
|
||||
},
|
||||
Ident {
|
||||
sym: ExternalComponent,
|
||||
span: bytes(11..28),
|
||||
},
|
||||
Punct {
|
||||
char: ',',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: props,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
---
|
||||
source: leptos_macro/src/view/tests.rs
|
||||
assertion_line: 101
|
||||
expression: pretty(result)
|
||||
---
|
||||
fn view() {
|
||||
::leptos::component_view(
|
||||
#[allow(clippy::needless_borrows_for_generic_args)]
|
||||
&SimpleCounter,
|
||||
::leptos::component_props_builder(&SimpleCounter)
|
||||
{
|
||||
let props = ::leptos::component_props_builder(&SimpleCounter)
|
||||
.initial_value(#[allow(unused_braces)] { 0 })
|
||||
.step(#[allow(unused_braces)] { 1 })
|
||||
.build(),
|
||||
)
|
||||
.step(#[allow(unused_braces)] { 1 });
|
||||
#[allow(clippy::let_unit_value, clippy::unit_arg)]
|
||||
let props = props.build();
|
||||
#[allow(unreachable_code)]
|
||||
::leptos::component_view(
|
||||
#[allow(clippy::needless_borrows_for_generic_args)]
|
||||
&SimpleCounter,
|
||||
props,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
---
|
||||
source: leptos_macro/src/view/tests.rs
|
||||
assertion_line: 101
|
||||
expression: pretty(result)
|
||||
---
|
||||
fn view() {
|
||||
::leptos::IntoView::into_view(
|
||||
#[allow(unused_braces)]
|
||||
{
|
||||
::leptos::component_view(
|
||||
#[allow(clippy::needless_borrows_for_generic_args)]
|
||||
&ExternalComponent,
|
||||
::leptos::component_props_builder(&ExternalComponent).build(),
|
||||
)
|
||||
{
|
||||
let props = ::leptos::component_props_builder(&ExternalComponent);
|
||||
#[allow(clippy::let_unit_value, clippy::unit_arg)]
|
||||
let props = props.build();
|
||||
#[allow(unreachable_code)]
|
||||
::leptos::component_view(
|
||||
#[allow(clippy::needless_borrows_for_generic_args)]
|
||||
&ExternalComponent,
|
||||
props,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
.on(
|
||||
@@ -20,3 +27,4 @@ fn view() {
|
||||
move |_: Event| set_value(0),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,89 +1,22 @@
|
||||
---
|
||||
source: leptos_macro/src/view/tests.rs
|
||||
assertion_line: 101
|
||||
expression: result
|
||||
---
|
||||
TokenStream [
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: leptos,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: component_view,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
delimiter: Brace,
|
||||
stream: TokenStream [
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
Ident {
|
||||
sym: let,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: clippy,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: needless_borrows_for_generic_args,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '&',
|
||||
spacing: Alone,
|
||||
span: bytes(11..24),
|
||||
},
|
||||
Ident {
|
||||
sym: SimpleCounter,
|
||||
span: bytes(11..24),
|
||||
sym: props,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ',',
|
||||
char: '=',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
@@ -145,27 +78,27 @@ TokenStream [
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
span: bytes(37..52),
|
||||
span: bytes(51..52),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(37..52),
|
||||
span: bytes(51..52),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: unused_braces,
|
||||
span: bytes(37..52),
|
||||
span: bytes(51..52),
|
||||
},
|
||||
],
|
||||
span: bytes(37..52),
|
||||
span: bytes(51..52),
|
||||
},
|
||||
],
|
||||
span: bytes(37..52),
|
||||
span: bytes(51..52),
|
||||
},
|
||||
Group {
|
||||
delimiter: Brace,
|
||||
@@ -195,27 +128,27 @@ TokenStream [
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
span: bytes(65..71),
|
||||
span: bytes(70..71),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(65..71),
|
||||
span: bytes(70..71),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: unused_braces,
|
||||
span: bytes(65..71),
|
||||
span: bytes(70..71),
|
||||
},
|
||||
],
|
||||
span: bytes(65..71),
|
||||
span: bytes(70..71),
|
||||
},
|
||||
],
|
||||
span: bytes(65..71),
|
||||
span: bytes(70..71),
|
||||
},
|
||||
Group {
|
||||
delimiter: Brace,
|
||||
@@ -230,6 +163,90 @@ TokenStream [
|
||||
],
|
||||
span: bytes(65..71),
|
||||
},
|
||||
Punct {
|
||||
char: ';',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: clippy,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: let_unit_value,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ',',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: clippy,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: unit_arg,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: let,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: props,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '=',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: props,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '.',
|
||||
spacing: Alone,
|
||||
@@ -244,6 +261,127 @@ TokenStream [
|
||||
stream: TokenStream [],
|
||||
span: bytes(11..24),
|
||||
},
|
||||
Punct {
|
||||
char: ';',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: unreachable_code,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: leptos,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: component_view,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: clippy,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: needless_borrows_for_generic_args,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '&',
|
||||
spacing: Alone,
|
||||
span: bytes(11..24),
|
||||
},
|
||||
Ident {
|
||||
sym: SimpleCounter,
|
||||
span: bytes(11..24),
|
||||
},
|
||||
Punct {
|
||||
char: ',',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: props,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
source: leptos_macro/src/view/tests.rs
|
||||
assertion_line: 101
|
||||
expression: result
|
||||
---
|
||||
TokenStream [
|
||||
@@ -76,87 +77,19 @@ TokenStream [
|
||||
Group {
|
||||
delimiter: Brace,
|
||||
stream: TokenStream [
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: leptos,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: component_view,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
delimiter: Brace,
|
||||
stream: TokenStream [
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
Ident {
|
||||
sym: let,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: clippy,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: needless_borrows_for_generic_args,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '&',
|
||||
spacing: Alone,
|
||||
span: bytes(11..28),
|
||||
},
|
||||
Ident {
|
||||
sym: ExternalComponent,
|
||||
span: bytes(11..28),
|
||||
sym: props,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ',',
|
||||
char: '=',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
@@ -203,6 +136,90 @@ TokenStream [
|
||||
],
|
||||
span: bytes(11..28),
|
||||
},
|
||||
Punct {
|
||||
char: ';',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: clippy,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: let_unit_value,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ',',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: clippy,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: unit_arg,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: let,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: props,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '=',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: props,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '.',
|
||||
spacing: Alone,
|
||||
@@ -217,6 +234,127 @@ TokenStream [
|
||||
stream: TokenStream [],
|
||||
span: bytes(11..28),
|
||||
},
|
||||
Punct {
|
||||
char: ';',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: unreachable_code,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: leptos,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: component_view,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: clippy,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: needless_borrows_for_generic_args,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '&',
|
||||
spacing: Alone,
|
||||
span: bytes(11..28),
|
||||
},
|
||||
Ident {
|
||||
sym: ExternalComponent,
|
||||
span: bytes(11..28),
|
||||
},
|
||||
Punct {
|
||||
char: ',',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: props,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
|
||||
@@ -1,27 +1,33 @@
|
||||
---
|
||||
source: leptos_macro/src/view/tests.rs
|
||||
assertion_line: 101
|
||||
expression: result
|
||||
---
|
||||
TokenStream [
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
span: bytes(10..331),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(10..331),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: unused_braces,
|
||||
span: bytes(10..331),
|
||||
},
|
||||
],
|
||||
span: bytes(10..331),
|
||||
},
|
||||
],
|
||||
span: bytes(10..331),
|
||||
},
|
||||
Group {
|
||||
delimiter: Brace,
|
||||
@@ -147,22 +153,27 @@ TokenStream [
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
span: bytes(28..83),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(28..83),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: unused_braces,
|
||||
span: bytes(28..83),
|
||||
},
|
||||
],
|
||||
span: bytes(28..83),
|
||||
},
|
||||
],
|
||||
span: bytes(28..83),
|
||||
},
|
||||
Group {
|
||||
delimiter: Brace,
|
||||
@@ -393,22 +404,27 @@ TokenStream [
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
span: bytes(96..176),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(96..176),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: unused_braces,
|
||||
span: bytes(96..176),
|
||||
},
|
||||
],
|
||||
span: bytes(96..176),
|
||||
},
|
||||
],
|
||||
span: bytes(96..176),
|
||||
},
|
||||
Group {
|
||||
delimiter: Brace,
|
||||
@@ -681,22 +697,27 @@ TokenStream [
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
span: bytes(189..223),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(189..223),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: unused_braces,
|
||||
span: bytes(189..223),
|
||||
},
|
||||
],
|
||||
span: bytes(189..223),
|
||||
},
|
||||
],
|
||||
span: bytes(189..223),
|
||||
},
|
||||
Group {
|
||||
delimiter: Brace,
|
||||
@@ -881,22 +902,27 @@ TokenStream [
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
span: bytes(236..316),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(236..316),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: unused_braces,
|
||||
span: bytes(236..316),
|
||||
},
|
||||
],
|
||||
span: bytes(236..316),
|
||||
},
|
||||
],
|
||||
span: bytes(236..316),
|
||||
},
|
||||
Group {
|
||||
delimiter: Brace,
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
---
|
||||
source: leptos_macro/src/view/tests.rs
|
||||
assertion_line: 101
|
||||
expression: pretty(result)
|
||||
---
|
||||
fn view() {
|
||||
::leptos::component_view(
|
||||
#[allow(clippy::needless_borrows_for_generic_args)]
|
||||
&SimpleCounter,
|
||||
::leptos::component_props_builder(&SimpleCounter)
|
||||
{
|
||||
let props = ::leptos::component_props_builder(&SimpleCounter)
|
||||
.initial_value(#[allow(unused_braces)] { 0 })
|
||||
.step(#[allow(unused_braces)] { 1 })
|
||||
.build(),
|
||||
)
|
||||
.step(#[allow(unused_braces)] { 1 });
|
||||
#[allow(clippy::let_unit_value, clippy::unit_arg)]
|
||||
let props = props.build();
|
||||
#[allow(unreachable_code)]
|
||||
::leptos::component_view(
|
||||
#[allow(clippy::needless_borrows_for_generic_args)]
|
||||
&SimpleCounter,
|
||||
props,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
---
|
||||
source: leptos_macro/src/view/tests.rs
|
||||
assertion_line: 101
|
||||
expression: pretty(result)
|
||||
---
|
||||
fn view() {
|
||||
::leptos::IntoView::into_view(
|
||||
#[allow(unused_braces)]
|
||||
{
|
||||
::leptos::component_view(
|
||||
#[allow(clippy::needless_borrows_for_generic_args)]
|
||||
&ExternalComponent,
|
||||
::leptos::component_props_builder(&ExternalComponent).build(),
|
||||
)
|
||||
{
|
||||
let props = ::leptos::component_props_builder(&ExternalComponent);
|
||||
#[allow(clippy::let_unit_value, clippy::unit_arg)]
|
||||
let props = props.build();
|
||||
#[allow(unreachable_code)]
|
||||
::leptos::component_view(
|
||||
#[allow(clippy::needless_borrows_for_generic_args)]
|
||||
&ExternalComponent,
|
||||
props,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
.on(
|
||||
@@ -20,3 +27,4 @@ fn view() {
|
||||
move |_: Event| set_value(0),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,89 +1,22 @@
|
||||
---
|
||||
source: leptos_macro/src/view/tests.rs
|
||||
assertion_line: 101
|
||||
expression: result
|
||||
---
|
||||
TokenStream [
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: leptos,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: component_view,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
delimiter: Brace,
|
||||
stream: TokenStream [
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
Ident {
|
||||
sym: let,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: clippy,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: needless_borrows_for_generic_args,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '&',
|
||||
spacing: Alone,
|
||||
span: bytes(11..24),
|
||||
},
|
||||
Ident {
|
||||
sym: SimpleCounter,
|
||||
span: bytes(11..24),
|
||||
sym: props,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ',',
|
||||
char: '=',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
@@ -145,27 +78,27 @@ TokenStream [
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
span: bytes(37..52),
|
||||
span: bytes(51..52),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(37..52),
|
||||
span: bytes(51..52),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: unused_braces,
|
||||
span: bytes(37..52),
|
||||
span: bytes(51..52),
|
||||
},
|
||||
],
|
||||
span: bytes(37..52),
|
||||
span: bytes(51..52),
|
||||
},
|
||||
],
|
||||
span: bytes(37..52),
|
||||
span: bytes(51..52),
|
||||
},
|
||||
Group {
|
||||
delimiter: Brace,
|
||||
@@ -195,27 +128,27 @@ TokenStream [
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
span: bytes(65..71),
|
||||
span: bytes(70..71),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(65..71),
|
||||
span: bytes(70..71),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: unused_braces,
|
||||
span: bytes(65..71),
|
||||
span: bytes(70..71),
|
||||
},
|
||||
],
|
||||
span: bytes(65..71),
|
||||
span: bytes(70..71),
|
||||
},
|
||||
],
|
||||
span: bytes(65..71),
|
||||
span: bytes(70..71),
|
||||
},
|
||||
Group {
|
||||
delimiter: Brace,
|
||||
@@ -230,6 +163,90 @@ TokenStream [
|
||||
],
|
||||
span: bytes(65..71),
|
||||
},
|
||||
Punct {
|
||||
char: ';',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: clippy,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: let_unit_value,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ',',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: clippy,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: unit_arg,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: let,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: props,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '=',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: props,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '.',
|
||||
spacing: Alone,
|
||||
@@ -244,6 +261,127 @@ TokenStream [
|
||||
stream: TokenStream [],
|
||||
span: bytes(11..24),
|
||||
},
|
||||
Punct {
|
||||
char: ';',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: unreachable_code,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: leptos,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: component_view,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: clippy,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: needless_borrows_for_generic_args,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '&',
|
||||
spacing: Alone,
|
||||
span: bytes(11..24),
|
||||
},
|
||||
Ident {
|
||||
sym: SimpleCounter,
|
||||
span: bytes(11..24),
|
||||
},
|
||||
Punct {
|
||||
char: ',',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: props,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
source: leptos_macro/src/view/tests.rs
|
||||
assertion_line: 101
|
||||
expression: result
|
||||
---
|
||||
TokenStream [
|
||||
@@ -76,87 +77,19 @@ TokenStream [
|
||||
Group {
|
||||
delimiter: Brace,
|
||||
stream: TokenStream [
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: leptos,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: component_view,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
delimiter: Brace,
|
||||
stream: TokenStream [
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
Ident {
|
||||
sym: let,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: clippy,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: needless_borrows_for_generic_args,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '&',
|
||||
spacing: Alone,
|
||||
span: bytes(11..28),
|
||||
},
|
||||
Ident {
|
||||
sym: ExternalComponent,
|
||||
span: bytes(11..28),
|
||||
sym: props,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ',',
|
||||
char: '=',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
@@ -203,6 +136,90 @@ TokenStream [
|
||||
],
|
||||
span: bytes(11..28),
|
||||
},
|
||||
Punct {
|
||||
char: ';',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: clippy,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: let_unit_value,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ',',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: clippy,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: unit_arg,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: let,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: props,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '=',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: props,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '.',
|
||||
spacing: Alone,
|
||||
@@ -217,6 +234,127 @@ TokenStream [
|
||||
stream: TokenStream [],
|
||||
span: bytes(11..28),
|
||||
},
|
||||
Punct {
|
||||
char: ';',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: unreachable_code,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: leptos,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: component_view,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Punct {
|
||||
char: '#',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: allow,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
sym: clippy,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Joint,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: ':',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: needless_borrows_for_generic_args,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Punct {
|
||||
char: '&',
|
||||
spacing: Alone,
|
||||
span: bytes(11..28),
|
||||
},
|
||||
Ident {
|
||||
sym: ExternalComponent,
|
||||
span: bytes(11..28),
|
||||
},
|
||||
Punct {
|
||||
char: ',',
|
||||
spacing: Alone,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
Ident {
|
||||
sym: props,
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
],
|
||||
span: bytes(10..82),
|
||||
},
|
||||
|
||||
@@ -8,27 +8,20 @@ fn Component(
|
||||
#[prop(strip_option)] strip_option: Option<u8>,
|
||||
#[prop(default = NonZeroUsize::new(10).unwrap())] default: NonZeroUsize,
|
||||
#[prop(into)] into: String,
|
||||
impl_trait: impl Fn() -> i32 + 'static,
|
||||
) -> impl IntoView {
|
||||
_ = optional;
|
||||
_ = optional_no_strip;
|
||||
_ = strip_option;
|
||||
_ = default;
|
||||
_ = into;
|
||||
_ = impl_trait;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn component() {
|
||||
let cp = ComponentProps::builder()
|
||||
.into("")
|
||||
.strip_option(9)
|
||||
.impl_trait(|| 42)
|
||||
.build();
|
||||
let cp = ComponentProps::builder().into("").strip_option(9).build();
|
||||
assert!(!cp.optional);
|
||||
assert_eq!(cp.optional_no_strip, None);
|
||||
assert_eq!(cp.strip_option, Some(9));
|
||||
assert_eq!(cp.default, NonZeroUsize::new(10).unwrap());
|
||||
assert_eq!(cp.into, "");
|
||||
assert_eq!((cp.impl_trait)(), 42);
|
||||
}
|
||||
|
||||
@@ -10,12 +10,9 @@ pub struct OuterState {
|
||||
#[derive(Clone, PartialEq, Default)]
|
||||
pub struct InnerState {
|
||||
inner_count: i32,
|
||||
inner_tuple: InnerTuple,
|
||||
inner_name: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Default)]
|
||||
pub struct InnerTuple(String);
|
||||
|
||||
#[test]
|
||||
fn green() {
|
||||
let _ = create_runtime();
|
||||
@@ -25,7 +22,7 @@ fn green() {
|
||||
let (_, _) = slice!(outer_signal.count);
|
||||
|
||||
let (_, _) = slice!(outer_signal.inner.inner_count);
|
||||
let (_, _) = slice!(outer_signal.inner.inner_tuple.0);
|
||||
let (_, _) = slice!(outer_signal.inner.inner_name);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -14,7 +14,7 @@ error: expected `.`
|
||||
|
|
||||
= note: this error originates in the macro `slice` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: unexpected end of input, expected identifier or integer
|
||||
error: unexpected end of input, expected identifier
|
||||
--> tests/slice/red.rs:25:18
|
||||
|
|
||||
25 | let (_, _) = slice!(outer_signal.);
|
||||
@@ -22,7 +22,7 @@ error: unexpected end of input, expected identifier or integer
|
||||
|
|
||||
= note: this error originates in the macro `slice` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: unexpected end of input, expected identifier or integer
|
||||
error: unexpected end of input, expected identifier
|
||||
--> tests/slice/red.rs:27:18
|
||||
|
|
||||
27 | let (_, _) = slice!(outer_signal.inner.);
|
||||
|
||||
@@ -121,6 +121,3 @@ skip_feature_sets = [
|
||||
"rkyv",
|
||||
],
|
||||
]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
|
||||
@@ -31,7 +31,7 @@ pub struct SharedContext {
|
||||
impl SharedContext {
|
||||
/// Returns IDs for all [`Resource`](crate::Resource)s found on any scope.
|
||||
#[cfg_attr(
|
||||
any(debug_assertions, feature = "ssr"),
|
||||
any(debug_assertions, features = "ssr"),
|
||||
instrument(level = "trace", skip_all,)
|
||||
)]
|
||||
pub fn all_resources() -> Vec<ResourceId> {
|
||||
@@ -41,7 +41,7 @@ impl SharedContext {
|
||||
/// Returns IDs for all [`Resource`](crate::Resource)s found on any scope that are
|
||||
/// pending from the server.
|
||||
#[cfg_attr(
|
||||
any(debug_assertions, feature = "ssr"),
|
||||
any(debug_assertions, features = "ssr"),
|
||||
instrument(level = "trace", skip_all,)
|
||||
)]
|
||||
pub fn pending_resources() -> Vec<ResourceId> {
|
||||
@@ -50,7 +50,7 @@ impl SharedContext {
|
||||
|
||||
/// Returns IDs for all [`Resource`](crate::Resource)s found on any scope.
|
||||
#[cfg_attr(
|
||||
any(debug_assertions, feature = "ssr"),
|
||||
any(debug_assertions, features = "ssr"),
|
||||
instrument(level = "trace", skip_all,)
|
||||
)]
|
||||
pub fn serialization_resolvers(
|
||||
@@ -62,7 +62,7 @@ impl SharedContext {
|
||||
/// Registers the given [`SuspenseContext`](crate::SuspenseContext) with the current scope,
|
||||
/// calling the `resolver` when its resources are all resolved.
|
||||
#[cfg_attr(
|
||||
any(debug_assertions, feature = "ssr"),
|
||||
any(debug_assertions, features = "ssr"),
|
||||
instrument(level = "trace", skip_all,)
|
||||
)]
|
||||
pub fn register_suspense(
|
||||
@@ -121,7 +121,7 @@ impl SharedContext {
|
||||
/// Returns a tuple of two pinned `Future`s that return content for out-of-order
|
||||
/// and in-order streaming, respectively.
|
||||
#[cfg_attr(
|
||||
any(debug_assertions, feature = "ssr"),
|
||||
any(debug_assertions, features = "ssr"),
|
||||
instrument(level = "trace", skip_all,)
|
||||
)]
|
||||
pub fn take_pending_fragment(id: &str) -> Option<FragmentData> {
|
||||
@@ -135,7 +135,7 @@ impl SharedContext {
|
||||
|
||||
/// A future that will resolve when all blocking fragments are ready.
|
||||
#[cfg_attr(
|
||||
any(debug_assertions, feature = "ssr"),
|
||||
any(debug_assertions, features = "ssr"),
|
||||
instrument(level = "trace", skip_all,)
|
||||
)]
|
||||
pub fn blocking_fragments_ready() -> PinnedFuture<()> {
|
||||
@@ -162,7 +162,7 @@ impl SharedContext {
|
||||
/// The keys are hydration IDs. Values are tuples of two pinned
|
||||
/// `Future`s that return content for out-of-order and in-order streaming, respectively.
|
||||
#[cfg_attr(
|
||||
any(debug_assertions, feature = "ssr"),
|
||||
any(debug_assertions, features = "ssr"),
|
||||
instrument(level = "trace", skip_all,)
|
||||
)]
|
||||
pub fn pending_fragments() -> HashMap<String, FragmentData> {
|
||||
@@ -176,7 +176,7 @@ impl SharedContext {
|
||||
/// Registers the given element as an island with the current reactive owner.
|
||||
#[cfg(all(feature = "hydrate", feature = "experimental-islands"))]
|
||||
#[cfg_attr(
|
||||
any(debug_assertions, feature = "ssr"),
|
||||
any(debug_assertions, features = "ssr"),
|
||||
instrument(level = "trace", skip_all,)
|
||||
)]
|
||||
pub fn register_island(el: &web_sys::HtmlElement) {
|
||||
@@ -190,7 +190,7 @@ impl SharedContext {
|
||||
}
|
||||
|
||||
#[cfg_attr(
|
||||
any(debug_assertions, feature = "ssr"),
|
||||
any(debug_assertions, features = "ssr"),
|
||||
instrument(level = "trace", skip_all,)
|
||||
)]
|
||||
pub fn fragment_has_local_resources(fragment: &str) -> bool {
|
||||
@@ -204,7 +204,7 @@ impl SharedContext {
|
||||
}
|
||||
|
||||
#[cfg_attr(
|
||||
any(debug_assertions, feature = "ssr"),
|
||||
any(debug_assertions, features = "ssr"),
|
||||
instrument(level = "trace", skip_all,)
|
||||
)]
|
||||
pub fn fragments_with_local_resources() -> HashSet<String> {
|
||||
@@ -216,7 +216,7 @@ impl SharedContext {
|
||||
}
|
||||
|
||||
#[cfg_attr(
|
||||
any(debug_assertions, feature = "ssr"),
|
||||
any(debug_assertions, features = "ssr"),
|
||||
instrument(level = "trace", skip_all,)
|
||||
)]
|
||||
pub fn register_local_fragment(key: String) {
|
||||
|
||||
@@ -174,7 +174,7 @@ where
|
||||
///
|
||||
/// Unlike a "derived signal," a memo comes with two guarantees:
|
||||
/// 1. The memo will only run *once* per change, no matter how many times you
|
||||
/// access its value.
|
||||
/// access its value.
|
||||
/// 2. The memo will only notify its dependents if the value of the computation changes.
|
||||
///
|
||||
/// This makes a memo the perfect tool for expensive computations.
|
||||
@@ -190,11 +190,11 @@ where
|
||||
/// - [`.get()`](#impl-SignalGet<T>-for-Memo<T>) (or calling the signal as a function) clones the current
|
||||
/// value of the signal. If you call it within an effect, it will cause that effect
|
||||
/// to subscribe to the signal, and to re-run whenever the value of the signal changes.
|
||||
/// - [`.get_untracked()`](#impl-SignalGetUntracked<T>-for-Memo<T>) clones the value of the signal
|
||||
/// - [`.get_untracked()`](#impl-SignalGetUntracked<T>-for-Memo<T>) clones the value of the signal
|
||||
/// without reactively tracking it.
|
||||
/// - [`.with()`](#impl-SignalWith<T>-for-Memo<T>) allows you to reactively access the signal’s value without
|
||||
/// cloning by applying a callback function.
|
||||
/// - [`.with_untracked()`](#impl-SignalWithUntracked<T>-for-Memo<T>) allows you to access the signal’s
|
||||
/// - [`.with_untracked()`](#impl-SignalWithUntracked<T>-for-Memo<T>) allows you to access the signal’s
|
||||
/// value without reactively tracking it.
|
||||
/// - [`.to_stream()`](#impl-SignalStream<T>-for-Memo<T>) converts the signal to an `async` stream of values.
|
||||
///
|
||||
|
||||
@@ -13,7 +13,10 @@ pub struct Disposer(pub(crate) NodeId);
|
||||
impl Drop for Disposer {
|
||||
fn drop(&mut self) {
|
||||
let id = self.0;
|
||||
_ = with_runtime(|runtime| runtime.dispose_node(id));
|
||||
_ = with_runtime(|runtime| {
|
||||
runtime.cleanup_node(id);
|
||||
runtime.dispose_node(id);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -271,16 +271,6 @@ where
|
||||
///
|
||||
/// Local resources do not load on the server, only in the client’s browser.
|
||||
///
|
||||
/// ## When to use a Local Resource
|
||||
///
|
||||
/// `create_resource` has three different features:
|
||||
/// 1. gives a synchronous API for asynchronous things
|
||||
/// 2. integrates with `Suspense`/`Transition``
|
||||
/// 3. makes your application faster by starting things like DB access or an API request on the server,
|
||||
/// rather than waiting until you've fully loaded the client
|
||||
///
|
||||
/// `create_local_resource` is useful when you can't or don't need to do #3 (serializing data from server
|
||||
/// to client), but still want #1 (synchronous API for async) and #2 (integration with `Suspense`).
|
||||
/// ```
|
||||
/// # use leptos_reactive::*;
|
||||
/// # let runtime = create_runtime();
|
||||
@@ -288,9 +278,7 @@ where
|
||||
/// struct ComplicatedUnserializableStruct {
|
||||
/// // something here that can't be serialized
|
||||
/// }
|
||||
///
|
||||
/// // an async function whose results can't be serialized from the server to the client
|
||||
/// // (for example, opening a connection to the user's device camera)
|
||||
/// // any old async function; maybe this is calling a REST API or something
|
||||
/// async fn setup_complicated_struct() -> ComplicatedUnserializableStruct {
|
||||
/// // do some work
|
||||
/// ComplicatedUnserializableStruct {}
|
||||
@@ -798,11 +786,9 @@ where
|
||||
fn try_with<O>(&self, f: impl FnOnce(&Option<T>) -> O) -> Option<O> {
|
||||
let location = std::panic::Location::caller();
|
||||
with_runtime(|runtime| {
|
||||
runtime
|
||||
.try_resource(self.id, |resource: &ResourceState<S, T>| {
|
||||
resource.with_maybe(f, location, self.id)
|
||||
})
|
||||
.flatten()
|
||||
runtime.resource(self.id, |resource: &ResourceState<S, T>| {
|
||||
resource.with_maybe(f, location, self.id)
|
||||
})
|
||||
})
|
||||
.ok()
|
||||
.flatten()
|
||||
|
||||
@@ -190,6 +190,27 @@ impl Runtime {
|
||||
self.mark_clean(node_id);
|
||||
}
|
||||
|
||||
pub(crate) fn cleanup_node(&self, node_id: NodeId) {
|
||||
// first, run our cleanups, if any
|
||||
let c = { self.on_cleanups.borrow_mut().remove(node_id) };
|
||||
// untrack around all cleanups
|
||||
let prev_observer = self.observer.take();
|
||||
if let Some(cleanups) = c {
|
||||
for cleanup in cleanups {
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
self.observer.set(prev_observer);
|
||||
|
||||
// dispose of any of our properties
|
||||
let properties = { self.node_properties.borrow_mut().remove(node_id) };
|
||||
if let Some(properties) = properties {
|
||||
for property in properties {
|
||||
self.cleanup_property(property);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn update(&self, node_id: NodeId) {
|
||||
let node = {
|
||||
let nodes = self.nodes.borrow();
|
||||
@@ -233,66 +254,53 @@ impl Runtime {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn dispose_node(&self, node_id: NodeId) {
|
||||
self.cleanup_node(node_id);
|
||||
|
||||
// each of the subs needs to remove the node from its dependencies
|
||||
// so that it doesn't try to read the (now disposed) signal
|
||||
let subs = self.node_subscribers.borrow_mut().remove(node_id);
|
||||
if let Some(subs) = subs {
|
||||
let source_map = self.node_sources.borrow();
|
||||
for effect in subs.borrow().iter() {
|
||||
if let Some(effect_sources) = source_map.get(*effect) {
|
||||
effect_sources.borrow_mut().swap_remove(&node_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.node_sources.borrow_mut().remove(node_id);
|
||||
let node = { self.nodes.borrow_mut().remove(node_id) };
|
||||
drop(node);
|
||||
}
|
||||
fn cleanup_node(&self, node_id: NodeId) {
|
||||
self.run_on_cleanups(node_id);
|
||||
self.dispose_children(node_id);
|
||||
}
|
||||
/// Dispose of all of the children of the node recursively and completely.
|
||||
fn dispose_children(&self, node_id: NodeId) {
|
||||
let properties = { self.node_properties.borrow_mut().remove(node_id) };
|
||||
if let Some(properties) = properties {
|
||||
for property in properties {
|
||||
self.dispose_property(property);
|
||||
}
|
||||
}
|
||||
}
|
||||
fn dispose_property(&self, property: ScopeProperty) {
|
||||
pub(crate) fn cleanup_property(&self, property: ScopeProperty) {
|
||||
// for signals, triggers, memos, effects, shared node cleanup
|
||||
match property {
|
||||
ScopeProperty::Signal(node)
|
||||
| ScopeProperty::Trigger(node)
|
||||
| ScopeProperty::Effect(node) => {
|
||||
self.dispose_node(node);
|
||||
// run all cleanups for this node
|
||||
let cleanups = { self.on_cleanups.borrow_mut().remove(node) };
|
||||
for cleanup in cleanups.into_iter().flatten() {
|
||||
cleanup();
|
||||
}
|
||||
|
||||
// clean up all children
|
||||
let properties =
|
||||
{ self.node_properties.borrow_mut().remove(node) };
|
||||
for property in properties.into_iter().flatten() {
|
||||
self.cleanup_property(property);
|
||||
}
|
||||
|
||||
// each of the subs needs to remove the node from its dependencies
|
||||
// so that it doesn't try to read the (now disposed) signal
|
||||
let subs = self.node_subscribers.borrow_mut().remove(node);
|
||||
|
||||
if let Some(subs) = subs {
|
||||
let source_map = self.node_sources.borrow();
|
||||
for effect in subs.borrow().iter() {
|
||||
if let Some(effect_sources) = source_map.get(*effect) {
|
||||
effect_sources.borrow_mut().swap_remove(&node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no longer needs to track its sources
|
||||
self.node_sources.borrow_mut().remove(node);
|
||||
|
||||
// remove the node from the graph
|
||||
let node = { self.nodes.borrow_mut().remove(node) };
|
||||
drop(node);
|
||||
}
|
||||
ScopeProperty::Resource(id) => {
|
||||
let value = self.resources.borrow_mut().remove(id);
|
||||
drop(value);
|
||||
self.resources.borrow_mut().remove(id);
|
||||
}
|
||||
ScopeProperty::StoredValue(id) => {
|
||||
let value = self.stored_values.borrow_mut().remove(id);
|
||||
drop(value);
|
||||
self.stored_values.borrow_mut().remove(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
fn run_on_cleanups(&self, node_id: NodeId) {
|
||||
let c = { self.on_cleanups.borrow_mut().remove(node_id) };
|
||||
let prev_observer = self.observer.take(); // untrack around all cleanups
|
||||
if let Some(cleanups) = c {
|
||||
for cleanup in cleanups {
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
self.observer.set(prev_observer);
|
||||
}
|
||||
|
||||
pub(crate) fn cleanup_sources(&self, node_id: NodeId) {
|
||||
let sources = self.node_sources.borrow();
|
||||
@@ -492,6 +500,12 @@ impl Runtime {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn dispose_node(&self, node: NodeId) {
|
||||
self.node_sources.borrow_mut().remove(node);
|
||||
self.node_subscribers.borrow_mut().remove(node);
|
||||
self.nodes.borrow_mut().remove(node);
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub(crate) fn register_property(
|
||||
&self,
|
||||
@@ -629,7 +643,7 @@ impl Runtime {
|
||||
}
|
||||
|
||||
#[cfg_attr(
|
||||
any(debug_assertions, feature = "ssr"),
|
||||
any(debug_assertions, features = "ssr"),
|
||||
instrument(level = "trace", skip_all,)
|
||||
)]
|
||||
#[track_caller]
|
||||
@@ -644,7 +658,7 @@ impl Runtime {
|
||||
}
|
||||
|
||||
#[cfg_attr(
|
||||
any(debug_assertions, feature = "ssr"),
|
||||
any(debug_assertions, features = "ssr"),
|
||||
instrument(level = "trace", skip_all,)
|
||||
)]
|
||||
#[track_caller]
|
||||
@@ -1175,7 +1189,11 @@ impl RuntimeId {
|
||||
);
|
||||
|
||||
(id, move || {
|
||||
with_runtime(|runtime| runtime.dispose_node(id)).expect(
|
||||
with_runtime(|runtime| {
|
||||
runtime.nodes.borrow_mut().remove(id);
|
||||
runtime.node_sources.borrow_mut().remove(id);
|
||||
})
|
||||
.expect(
|
||||
"tried to stop a watch in a runtime that has been disposed",
|
||||
);
|
||||
})
|
||||
@@ -1382,7 +1400,7 @@ impl Drop for SetObserverOnDrop {
|
||||
///
|
||||
/// To avoid panicking under any circumstances, use [`try_batch`].
|
||||
#[cfg_attr(
|
||||
any(debug_assertions, feature = "ssr"),
|
||||
any(debug_assertions, features = "ssr"),
|
||||
instrument(level = "trace", skip_all,)
|
||||
)]
|
||||
#[inline(always)]
|
||||
@@ -1398,7 +1416,7 @@ pub fn batch<T>(f: impl FnOnce() -> T) -> T {
|
||||
///
|
||||
/// Unlike [`batch`], this will not panic if the runtime has been disposed.
|
||||
#[cfg_attr(
|
||||
any(debug_assertions, feature = "ssr"),
|
||||
any(debug_assertions, features = "ssr"),
|
||||
instrument(level = "trace", skip_all,)
|
||||
)]
|
||||
#[inline(always)]
|
||||
@@ -1447,7 +1465,7 @@ pub fn on_cleanup(cleanup_fn: impl FnOnce() + 'static) {
|
||||
}
|
||||
|
||||
#[cfg_attr(
|
||||
any(debug_assertions, feature = "ssr"),
|
||||
any(debug_assertions, features = "ssr"),
|
||||
instrument(level = "trace", skip_all,)
|
||||
)]
|
||||
fn push_cleanup(cleanup_fn: Box<dyn FnOnce()>) {
|
||||
@@ -1509,7 +1527,7 @@ impl ScopeProperty {
|
||||
/// # runtime.dispose();
|
||||
/// ```
|
||||
#[cfg_attr(
|
||||
any(debug_assertions, feature = "ssr"),
|
||||
any(debug_assertions, features = "ssr"),
|
||||
instrument(level = "trace", skip_all,)
|
||||
)]
|
||||
#[inline(always)]
|
||||
@@ -1519,7 +1537,7 @@ pub fn untrack<T>(f: impl FnOnce() -> T) -> T {
|
||||
|
||||
#[doc(hidden)]
|
||||
#[cfg_attr(
|
||||
any(debug_assertions, feature = "ssr"),
|
||||
any(debug_assertions, features = "ssr"),
|
||||
instrument(level = "trace", skip_all,)
|
||||
)]
|
||||
#[inline(always)]
|
||||
|
||||
@@ -332,7 +332,7 @@ pub trait SignalDispose {
|
||||
/// #
|
||||
/// ```
|
||||
#[cfg_attr(
|
||||
any(debug_assertions, feature="ssr"),
|
||||
any(debug_assertions, features="ssr"),
|
||||
instrument(
|
||||
level = "trace",
|
||||
skip_all,
|
||||
@@ -354,7 +354,7 @@ pub fn create_signal<T>(value: T) -> (ReadSignal<T>, WriteSignal<T>) {
|
||||
/// **Note**: If used on the server side during server rendering, this will return `None`
|
||||
/// immediately and not begin driving the stream.
|
||||
#[cfg_attr(
|
||||
any(debug_assertions, feature = "ssr"),
|
||||
any(debug_assertions, features = "ssr"),
|
||||
instrument(level = "trace", skip_all,)
|
||||
)]
|
||||
pub fn create_signal_from_stream<T>(
|
||||
@@ -394,11 +394,11 @@ pub fn create_signal_from_stream<T>(
|
||||
/// - [`.get()`](#impl-SignalGet<T>-for-ReadSignal<T>) (or calling the signal as a function) clones the current
|
||||
/// value of the signal. If you call it within an effect, it will cause that effect
|
||||
/// to subscribe to the signal, and to re-run whenever the value of the signal changes.
|
||||
/// - [`.get_untracked()`](#impl-SignalGetUntracked<T>-for-ReadSignal<T>) clones the value of the signal
|
||||
/// - [`.get_untracked()`](#impl-SignalGetUntracked<T>-for-ReadSignal<T>) clones the value of the signal
|
||||
/// without reactively tracking it.
|
||||
/// - [`.with()`](#impl-SignalWith<T>-for-ReadSignal<T>) allows you to reactively access the signal’s value without
|
||||
/// cloning by applying a callback function.
|
||||
/// - [`.with_untracked()`](#impl-SignalWithUntracked<T>-for-ReadSignal<T>) allows you to access the signal’s
|
||||
/// - [`.with_untracked()`](#impl-SignalWithUntracked<T>-for-ReadSignal<T>) allows you to access the signal’s
|
||||
/// value without reactively tracking it.
|
||||
/// - [`.to_stream()`](#impl-SignalStream<T>-for-ReadSignal<T>) converts the signal to an `async` stream of values.
|
||||
///
|
||||
@@ -817,11 +817,11 @@ impl<T> Hash for ReadSignal<T> {
|
||||
/// - [`.set()`](#impl-SignalSet<T>-for-WriteSignal<T>) (or calling the setter as a function)
|
||||
/// sets the signal’s value, and notifies all subscribers that the signal’s value has changed.
|
||||
/// to subscribe to the signal, and to re-run whenever the value of the signal changes.
|
||||
/// - [`.set_untracked()`](#impl-SignalSetUntracked<T>-for-WriteSignal<T>) sets the signal’s value
|
||||
/// - [`.set_untracked()`](#impl-SignalSetUntracked<T>-for-WriteSignal<T>) sets the signal’s value
|
||||
/// without notifying its subscribers.
|
||||
/// - [`.update()`](#impl-SignalUpdate<T>-for-WriteSignal<T>) mutates the signal’s value in place
|
||||
/// and notifies all subscribers that the signal’s value has changed.
|
||||
/// - [`.update_untracked()`](#impl-SignalUpdateUntracked<T>-for-WriteSignal<T>) mutates the signal’s value
|
||||
/// - [`.update_untracked()`](#impl-SignalUpdateUntracked<T>-for-WriteSignal<T>) mutates the signal’s value
|
||||
/// in place without notifying its subscribers.
|
||||
///
|
||||
/// ## Examples
|
||||
@@ -1143,7 +1143,7 @@ impl<T> Hash for WriteSignal<T> {
|
||||
/// #
|
||||
/// ```
|
||||
#[cfg_attr(
|
||||
any(debug_assertions, feature="ssr"),
|
||||
any(debug_assertions, features="ssr"),
|
||||
instrument(
|
||||
level = "trace",
|
||||
skip_all,
|
||||
@@ -1165,20 +1165,20 @@ pub fn create_rw_signal<T>(value: T) -> RwSignal<T> {
|
||||
/// - [`.get()`](#impl-SignalGet<T>-for-RwSignal<T>) clones the current
|
||||
/// value of the signal. If you call it within an effect, it will cause that effect
|
||||
/// to subscribe to the signal, and to re-run whenever the value of the signal changes.
|
||||
/// - [`.get_untracked()`](#impl-SignalGetUntracked<T>-for-RwSignal<T>) clones the value of the signal
|
||||
/// - [`.get_untracked()`](#impl-SignalGetUntracked<T>-for-RwSignal<T>) clones the value of the signal
|
||||
/// without reactively tracking it.
|
||||
/// - [`.with()`](#impl-SignalWith<T>-for-RwSignal<T>) allows you to reactively access the signal’s value without
|
||||
/// cloning by applying a callback function.
|
||||
/// - [`.with_untracked()`](#impl-SignalWithUntracked<T>-for-RwSignal<T>) allows you to access the signal’s
|
||||
/// - [`.with_untracked()`](#impl-SignalWithUntracked<T>-for-RwSignal<T>) allows you to access the signal’s
|
||||
/// value without reactively tracking it.
|
||||
/// - [`.set()`](#impl-SignalSet<T>-for-RwSignal<T>) sets the signal’s value,
|
||||
/// and notifies all subscribers that the signal’s value has changed.
|
||||
/// to subscribe to the signal, and to re-run whenever the value of the signal changes.
|
||||
/// - [`.set_untracked()`](#impl-SignalSetUntracked<T>-for-RwSignal<T>) sets the signal’s value
|
||||
/// - [`.set_untracked()`](#impl-SignalSetUntracked<T>-for-RwSignal<T>) sets the signal’s value
|
||||
/// without notifying its subscribers.
|
||||
/// - [`.update()`](#impl-SignalUpdate<T>-for-RwSignal<T>) mutates the signal’s value in place
|
||||
/// and notifies all subscribers that the signal’s value has changed.
|
||||
/// - [`.update_untracked()`](#impl-SignalUpdateUntracked<T>-for-RwSignal<T>) mutates the signal’s value
|
||||
/// - [`.update_untracked()`](#impl-SignalUpdateUntracked<T>-for-RwSignal<T>) mutates the signal’s value
|
||||
/// in place without notifying its subscribers.
|
||||
/// - [`.to_stream()`](#impl-SignalStream<T>-for-RwSignal<T>) converts the signal to an `async` stream of values.
|
||||
///
|
||||
@@ -1432,17 +1432,17 @@ impl<T> SignalSetUntracked<T> for RwSignal<T> {
|
||||
|
||||
impl<T> SignalUpdateUntracked<T> for RwSignal<T> {
|
||||
#[cfg_attr(
|
||||
any(debug_assertions, feature="ssr"),
|
||||
instrument(
|
||||
level = "trace",
|
||||
name = "RwSignal::update_untracked()",
|
||||
skip_all,
|
||||
fields(
|
||||
id = ?self.id,
|
||||
defined_at = %self.defined_at,
|
||||
ty = %std::any::type_name::<T>()
|
||||
)
|
||||
any(debug_assertions, features="ssr"),
|
||||
instrument(
|
||||
level = "trace",
|
||||
name = "RwSignal::update_untracked()",
|
||||
skip_all,
|
||||
fields(
|
||||
id = ?self.id,
|
||||
defined_at = %self.defined_at,
|
||||
ty = %std::any::type_name::<T>()
|
||||
)
|
||||
)
|
||||
)]
|
||||
#[inline(always)]
|
||||
fn update_untracked(&self, f: impl FnOnce(&mut T)) {
|
||||
|
||||
@@ -46,11 +46,11 @@ where
|
||||
/// - [`.get()`](#impl-SignalGet-for-Signal<T>) (or calling the signal as a function) clones the current
|
||||
/// value of the signal. If you call it within an effect, it will cause that effect
|
||||
/// to subscribe to the signal, and to re-run whenever the value of the signal changes.
|
||||
/// - [`.get_untracked()`](#impl-SignalGetUntracked<T>-for-Signal<T>) clones the value of the signal
|
||||
/// - [`.get_untracked()`](#impl-SignalGetUntracked<T>-for-Signal<T>) clones the value of the signal
|
||||
/// without reactively tracking it.
|
||||
/// - [`.with()`](#impl-SignalWith-for-Signal<T>) allows you to reactively access the signal’s value without
|
||||
/// cloning by applying a callback function.
|
||||
/// - [`.with_untracked()`](#impl-SignalWithUntracked<T>-for-Signal<T>) allows you to access the signal’s
|
||||
/// - [`.with_untracked()`](#impl-SignalWithUntracked<T>-for-Signal<T>) allows you to access the signal’s
|
||||
/// value without reactively tracking it.
|
||||
/// - [`.to_stream()`](#impl-SignalStream<T>-for-Signal<T>) converts the signal to an `async` stream of values.
|
||||
///
|
||||
@@ -494,11 +494,11 @@ impl<T> Eq for SignalTypes<T> where T: PartialEq {}
|
||||
/// - [`.get()`](#impl-SignalGet-for-MaybeSignal<T>) (or calling the signal as a function) clones the current
|
||||
/// value of the signal. If you call it within an effect, it will cause that effect
|
||||
/// to subscribe to the signal, and to re-run whenever the value of the signal changes.
|
||||
/// - [`.get_untracked()`](#impl-SignalGetUntracked<T>-for-MaybeSignal<T>) clones the value of the signal
|
||||
/// - [`.get_untracked()`](#impl-SignalGetUntracked<T>-for-MaybeSignal<T>) clones the value of the signal
|
||||
/// without reactively tracking it.
|
||||
/// - [`.with()`](#impl-SignalWith-for-MaybeSignal<T>) allows you to reactively access the signal’s value without
|
||||
/// cloning by applying a callback function.
|
||||
/// - [`.with_untracked()`](#impl-SignalWithUntracked<T>-for-MaybeSignal<T>) allows you to access the signal’s
|
||||
/// - [`.with_untracked()`](#impl-SignalWithUntracked<T>-for-MaybeSignal<T>) allows you to access the signal’s
|
||||
/// value without reactively tracking it.
|
||||
/// - [`.to_stream()`](#impl-SignalStream<T>-for-MaybeSignal<T>) converts the signal to an `async` stream of values.
|
||||
///
|
||||
@@ -889,11 +889,11 @@ where
|
||||
/// value of the signal. If you call it within an effect, it will cause that effect
|
||||
/// to subscribe to the signal, and to re-run whenever the value of the signal changes.
|
||||
/// - [`.get_untracked()`](#impl-SignalGetUntracked<T>-for-MaybeProp<T>) clones the value of the signal
|
||||
/// without reactively tracking it.
|
||||
/// without reactively tracking it.
|
||||
/// - [`.with()`](#impl-SignalWith-for-MaybeProp<T>) allows you to reactively access the signal’s value without
|
||||
/// cloning by applying a callback function.
|
||||
/// - [`.with_untracked()`](#impl-SignalWithUntracked<T>-for-MaybeProp<T>) allows you to access the signal’s
|
||||
/// value without reactively tracking it.
|
||||
/// value without reactively tracking it.
|
||||
/// - [`.to_stream()`](#impl-SignalStream<T>-for-MaybeProp<T>) converts the signal to an `async` stream of values.
|
||||
///
|
||||
/// ## Examples
|
||||
|
||||
@@ -43,66 +43,3 @@ fn cleanup() {
|
||||
|
||||
runtime.dispose();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cleanup_on_dispose() {
|
||||
use leptos_reactive::{
|
||||
create_memo, create_runtime, create_trigger, on_cleanup, SignalDispose,
|
||||
SignalGetUntracked,
|
||||
};
|
||||
|
||||
struct ExecuteOnDrop(Option<Box<dyn FnOnce()>>);
|
||||
impl ExecuteOnDrop {
|
||||
fn new(f: impl FnOnce() + 'static) -> Self {
|
||||
Self(Some(Box::new(f)))
|
||||
}
|
||||
}
|
||||
impl Drop for ExecuteOnDrop {
|
||||
fn drop(&mut self) {
|
||||
self.0.take().unwrap()();
|
||||
}
|
||||
}
|
||||
|
||||
let runtime = create_runtime();
|
||||
|
||||
let trigger = create_trigger();
|
||||
|
||||
println!("STARTING");
|
||||
|
||||
let memo = create_memo(move |_| {
|
||||
trigger.track();
|
||||
|
||||
// An example of why you might want to do this is that
|
||||
// when something goes out of reactive scope you want it to be cleaned up.
|
||||
// The cleaning up might have side effects, and those side effects might cause
|
||||
// re-renders where new `on_cleanup` are registered.
|
||||
let on_drop = ExecuteOnDrop::new(|| {
|
||||
on_cleanup(|| println!("Nested cleanup in progress."))
|
||||
});
|
||||
|
||||
on_cleanup(move || {
|
||||
println!("Cleanup in progress.");
|
||||
drop(on_drop)
|
||||
});
|
||||
});
|
||||
println!("Memo 1: {:?}", memo);
|
||||
let _ = memo.get_untracked(); // First cleanup registered.
|
||||
|
||||
memo.dispose(); // Cleanup not run here.
|
||||
|
||||
println!("Cleanup should have been executed.");
|
||||
|
||||
let memo = create_memo(move |_| {
|
||||
// New cleanup registered. It'll panic here.
|
||||
on_cleanup(move || println!("Test passed."));
|
||||
});
|
||||
println!("Memo 2: {:?}", memo);
|
||||
println!("^ Note how the memos have the same key (different versions).");
|
||||
let _ = memo.get_untracked(); // First cleanup registered.
|
||||
|
||||
println!("Test passed.");
|
||||
|
||||
memo.dispose();
|
||||
|
||||
runtime.dispose();
|
||||
}
|
||||
|
||||
@@ -293,29 +293,3 @@ fn owning_memo_slice() {
|
||||
|
||||
runtime.dispose();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn leak_on_dispose() {
|
||||
use std::rc::Rc;
|
||||
|
||||
let runtime = create_runtime();
|
||||
|
||||
let trigger = create_trigger();
|
||||
|
||||
let value = Rc::new(());
|
||||
let weak = Rc::downgrade(&value);
|
||||
|
||||
let memo = create_memo(move |_| {
|
||||
trigger.track();
|
||||
|
||||
create_rw_signal(value.clone());
|
||||
});
|
||||
|
||||
memo.get_untracked();
|
||||
|
||||
memo.dispose();
|
||||
|
||||
assert!(weak.upgrade().is_none()); // Should have been dropped.
|
||||
|
||||
runtime.dispose();
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ fn watch_runs() {
|
||||
|
||||
move |a, prev_a, prev_ret| {
|
||||
let formatted = format!(
|
||||
"Value is {a}; Prev is {prev_a:?}; Prev return is \
|
||||
{prev_ret:?}"
|
||||
"Value is {}; Prev is {:?}; Prev return is {:?}",
|
||||
a, prev_a, prev_ret
|
||||
);
|
||||
*b.borrow_mut() = formatted;
|
||||
|
||||
@@ -72,8 +72,8 @@ fn watch_runs_immediately() {
|
||||
|
||||
move |a, prev_a, prev_ret| {
|
||||
let formatted = format!(
|
||||
"Value is {a}; Prev is {prev_a:?}; Prev return is \
|
||||
{prev_ret:?}"
|
||||
"Value is {}; Prev is {:?}; Prev return is {:?}",
|
||||
a, prev_a, prev_ret
|
||||
);
|
||||
*b.borrow_mut() = formatted;
|
||||
|
||||
|
||||
@@ -32,6 +32,3 @@ nightly = ["leptos_reactive/nightly"]
|
||||
|
||||
[package.metadata.cargo-all-features]
|
||||
denylist = ["nightly"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
|
||||
@@ -392,7 +392,7 @@ where
|
||||
let pending_dispatches = Rc::clone(&self.pending_dispatches);
|
||||
let value = self.value;
|
||||
pending.set(true);
|
||||
pending_dispatches.set(pending_dispatches.get().wrapping_add(1));
|
||||
pending_dispatches.set(pending_dispatches.get().saturating_sub(1));
|
||||
spawn_local(async move {
|
||||
let new_value = fut.await;
|
||||
let res = try_batch(move || {
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
////! HTML forms don’t support `PUT` or `DELETE`, and they don’t 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.
|
||||
////!
|
||||
////! The CBOR encoding is supported for historical reasons; an earlier version of server functions used a URL encoding that
|
||||
////! The CBOR encoding is suported for historical reasons; an earlier version of server functions used a URL encoding that
|
||||
////! didn’t 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.
|
||||
|
||||
@@ -242,7 +242,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a [MultiAction] to synchronize an imperative `async` call to the synchronous reactive system.
|
||||
/// Creates an [MultiAction] to synchronize an imperative `async` call to the synchronous reactive system.
|
||||
///
|
||||
/// If you’re trying to load data by running an `async` function reactively, you probably
|
||||
/// want to use a [create_resource](leptos_reactive::create_resource) instead. If you’re trying
|
||||
@@ -319,7 +319,7 @@ where
|
||||
}))
|
||||
}
|
||||
|
||||
/// Creates a [MultiAction] that can be used to call a server function.
|
||||
/// Creates an [MultiAction] that can be used to call a server function.
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// # use leptos::*;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "leptos_meta"
|
||||
version = "0.6.15"
|
||||
version = "0.6.11"
|
||||
edition = "2021"
|
||||
authors = ["Greg Johnston"]
|
||||
license = "MIT"
|
||||
@@ -29,6 +29,3 @@ nightly = ["leptos/nightly"]
|
||||
[package.metadata.cargo-all-features]
|
||||
denylist = ["nightly"]
|
||||
skip_feature_sets = [["csr", "ssr"], ["csr", "hydrate"], ["ssr", "hydrate"]]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
|
||||
@@ -117,7 +117,7 @@ impl core::fmt::Debug for MetaTagsContext {
|
||||
|
||||
impl MetaTagsContext {
|
||||
/// Converts metadata tags into an HTML string.
|
||||
#[cfg(any(feature = "ssr", doc))]
|
||||
#[cfg(any(feature = "ssr", docs))]
|
||||
pub fn as_string(&self) -> String {
|
||||
self.els
|
||||
.borrow()
|
||||
|
||||
@@ -42,7 +42,6 @@ use std::{
|
||||
ops::{Add, Deref},
|
||||
path::Path,
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
/// "Owned Clones Once": a smart pointer that can be either a reference,
|
||||
@@ -68,8 +67,6 @@ pub enum Oco<'a, T: ?Sized + ToOwned + 'a> {
|
||||
Borrowed(&'a T),
|
||||
/// A reference counted pointer to a value.
|
||||
Counted(Rc<T>),
|
||||
/// A reference atomically-counted pointer to a value.
|
||||
AtomicallyCounted(Arc<T>),
|
||||
/// An owned value.
|
||||
Owned(<T as ToOwned>::Owned),
|
||||
}
|
||||
@@ -80,7 +77,6 @@ impl<'a, T: ?Sized + ToOwned> Oco<'a, T> {
|
||||
match self {
|
||||
Oco::Borrowed(v) => v.to_owned(),
|
||||
Oco::Counted(v) => v.as_ref().to_owned(),
|
||||
Oco::AtomicallyCounted(v) => v.as_ref().to_owned(),
|
||||
Oco::Owned(v) => v,
|
||||
}
|
||||
}
|
||||
@@ -133,7 +129,6 @@ impl<T: ?Sized + ToOwned> Deref for Oco<'_, T> {
|
||||
Oco::Borrowed(v) => v,
|
||||
Oco::Owned(v) => v.borrow(),
|
||||
Oco::Counted(v) => v,
|
||||
Oco::AtomicallyCounted(v) => v,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -284,7 +279,6 @@ where
|
||||
match self {
|
||||
Self::Borrowed(v) => Self::Borrowed(v),
|
||||
Self::Counted(v) => Self::Counted(Rc::clone(v)),
|
||||
Self::AtomicallyCounted(v) => Self::AtomicallyCounted(Arc::clone(v)),
|
||||
Self::Owned(v) => Self::Counted(Rc::from(v.borrow())),
|
||||
}
|
||||
}
|
||||
@@ -310,7 +304,6 @@ where
|
||||
match &*self {
|
||||
Self::Borrowed(v) => Self::Borrowed(v),
|
||||
Self::Counted(v) => Self::Counted(Rc::clone(v)),
|
||||
Self::AtomicallyCounted(v) => Self::AtomicallyCounted(Arc::clone(v)),
|
||||
Self::Owned(v) => {
|
||||
let rc = Rc::from(v.borrow());
|
||||
*self = Self::Counted(rc.clone());
|
||||
@@ -420,7 +413,6 @@ where
|
||||
Oco::Borrowed(v) => Cow::Borrowed(v),
|
||||
Oco::Owned(v) => Cow::Owned(v),
|
||||
Oco::Counted(v) => Cow::Owned(v.as_ref().to_owned()),
|
||||
Oco::AtomicallyCounted(v) => Cow::Owned(v.as_ref().to_owned()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -434,15 +426,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> From<Arc<T>> for Oco<'_, T>
|
||||
where
|
||||
T: ToOwned,
|
||||
{
|
||||
fn from(v: Arc<T>) -> Self {
|
||||
Oco::AtomicallyCounted(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> From<Box<T>> for Oco<'_, T>
|
||||
where
|
||||
T: ToOwned,
|
||||
@@ -463,7 +446,6 @@ impl From<Oco<'_, str>> for String {
|
||||
match v {
|
||||
Oco::Borrowed(v) => v.to_owned(),
|
||||
Oco::Counted(v) => v.as_ref().to_owned(),
|
||||
Oco::AtomicallyCounted(v) => v.as_ref().to_owned(),
|
||||
Oco::Owned(v) => v,
|
||||
}
|
||||
}
|
||||
@@ -493,7 +475,6 @@ impl<'a> From<Oco<'a, str>> for Oco<'a, [u8]> {
|
||||
Oco::Borrowed(v) => Oco::Borrowed(v.as_bytes()),
|
||||
Oco::Owned(v) => Oco::Owned(v.into_bytes()),
|
||||
Oco::Counted(v) => Oco::Counted(v.into()),
|
||||
Oco::AtomicallyCounted(v) => Oco::AtomicallyCounted(v.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -620,9 +601,9 @@ mod tests {
|
||||
#[test]
|
||||
fn debug_fmt_should_display_quotes_for_strings() {
|
||||
let s: Oco<str> = Oco::Borrowed("hello");
|
||||
assert_eq!(format!("{s:?}"), "\"hello\"");
|
||||
assert_eq!(format!("{:?}", s), "\"hello\"");
|
||||
let s: Oco<str> = Oco::Counted(Rc::from("hello"));
|
||||
assert_eq!(format!("{s:?}"), "\"hello\"");
|
||||
assert_eq!(format!("{:?}", s), "\"hello\"");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -5,24 +5,3 @@ The `projects` directory is intended as a collective of medium-to-large-scale ex
|
||||
The `examples` directory is included in our CI, and examples are regularly linted and tested. The barrier to entry for the `projects` directory is intended to be lower: Example projects will generally be built against a particular version, and not regularly linted or updated. Hopefully this distinction allows us to accept more examples without worrying about the maintenance burden of constant updates.
|
||||
|
||||
Feel free to submit projects to this directory via PR!
|
||||
|
||||
|
||||
## Index
|
||||
|
||||
### meilisearch-searchbar
|
||||
[Meilisearch](https://www.meilisearch.com/) is a search engine built in Rust that you can self-host. This example shows how to run it alongside a leptos server and present a search bar with autocomplete to the user.
|
||||
|
||||
### nginx-mpmc
|
||||
[Nginx](https://nginx.org/) Multiple Producer Multi Consumer, this example shows how you can use Nginx to provide different clients to the user while running multiple Leptos servers that provide server functions to any of the clients.
|
||||
|
||||
### ory-kratos
|
||||
[Ory](https://www.ory.sh/docs/welcome) is a combination of different authorization services. Ory Kratos is their Identification service, which provides password storage, emailing, login and registration functionality, etc. This example shows running Ory Kratos alongside a leptos server and making use of their UI Node data types in leptos. TODO: This example needs a bit more work to show off SSO passwordless etc
|
||||
|
||||
### tauri-from-scratch
|
||||
This example walks you through in explicit detail how to use [Tauri](https://tauri.app/) to render your Leptos App on non web targets using [WebView](https://en.wikipedia.org/wiki/WebView) while communicating with your leptos server and servering an SSR supported web experience. TODO: It could be simplified since part of the readme includes copying and pasting boilerplate.
|
||||
|
||||
### counter_dwarf_debug
|
||||
This example shows how to add breakpoints within the browser or visual studio code for debugging.
|
||||
|
||||
### bevy3d_ui
|
||||
This example uses the bevy 3d game engine with leptos within webassembly.
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
[package]
|
||||
name = "bevy3d_ui"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
lto = true
|
||||
|
||||
[dependencies]
|
||||
leptos = { version = "0.6.15", features = ["csr"] }
|
||||
leptos_meta = { version = "0.6.15", features = ["csr"] }
|
||||
leptos_router = { version = "0.6.15", features = ["csr"] }
|
||||
console_log = "1"
|
||||
log = "0.4"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
bevy = "0.13.2"
|
||||
crossbeam-channel = "0.5.12"
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen = "0.2"
|
||||
wasm-bindgen-test = "0.3.0"
|
||||
web-sys = "0.3"
|
||||
|
||||
[workspace]
|
||||
# The empty workspace here is to keep rust-analyzer satisfied
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user