mirror of
https://github.com/leptos-rs/leptos.git
synced 2025-12-28 16:02:33 -05:00
Compare commits
8 Commits
clippy_jul
...
error
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1a7344ca50 | ||
|
|
921bb616b4 | ||
|
|
5bb7122b93 | ||
|
|
ec2aa3e7a4 | ||
|
|
43959a96c7 | ||
|
|
7925fc4245 | ||
|
|
2bd1ad0f11 | ||
|
|
dd730aa4ac |
6
.github/ISSUE_TEMPLATE/bug_report.md
vendored
6
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -16,10 +16,10 @@ Please copy and paste the Leptos dependencies and features from your `Cargo.toml
|
||||
|
||||
For example:
|
||||
```toml
|
||||
leptos = { version = "0.3", features = ["serde"] }
|
||||
leptos = { version = "0.3", default-features = false, features = ["serde"] }
|
||||
leptos_axum = { version = "0.3", optional = true }
|
||||
leptos_meta = { version = "0.3"}
|
||||
leptos_router = { version = "0.3"}
|
||||
leptos_meta = { version = "0.3", default-features = false }
|
||||
leptos_router = { version = "0.3", default-features = false }
|
||||
```
|
||||
|
||||
**To Reproduce**
|
||||
|
||||
30
Cargo.toml
30
Cargo.toml
@@ -1,5 +1,5 @@
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
resolver="2"
|
||||
members = [
|
||||
# core
|
||||
"leptos",
|
||||
@@ -26,22 +26,22 @@ members = [
|
||||
exclude = ["benchmarks", "examples"]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.4.0"
|
||||
version = "0.3.0"
|
||||
|
||||
[workspace.dependencies]
|
||||
leptos = { path = "./leptos", version = "0.4.0" }
|
||||
leptos_dom = { path = "./leptos_dom", version = "0.4.0" }
|
||||
leptos_hot_reload = { path = "./leptos_hot_reload", version = "0.4.0" }
|
||||
leptos_macro = { path = "./leptos_macro", version = "0.4.0" }
|
||||
leptos_reactive = { path = "./leptos_reactive", version = "0.4.0" }
|
||||
leptos_server = { path = "./leptos_server", version = "0.4.0" }
|
||||
server_fn = { path = "./server_fn", version = "0.4.0" }
|
||||
server_fn_macro = { path = "./server_fn_macro", version = "0.4.0" }
|
||||
server_fn_macro_default = { path = "./server_fn/server_fn_macro_default", version = "0.4.0" }
|
||||
leptos_config = { path = "./leptos_config", version = "0.4.0" }
|
||||
leptos_router = { path = "./router", version = "0.4.0" }
|
||||
leptos_meta = { path = "./meta", version = "0.4.0" }
|
||||
leptos_integration_utils = { path = "./integrations/utils", version = "0.4.0" }
|
||||
leptos = { path = "./leptos", default-features = false, version = "0.3.0" }
|
||||
leptos_dom = { path = "./leptos_dom", default-features = false, version = "0.3.0" }
|
||||
leptos_hot_reload = { path = "./leptos_hot_reload", version = "0.3.0" }
|
||||
leptos_macro = { path = "./leptos_macro", default-features = false, version = "0.3.0" }
|
||||
leptos_reactive = { path = "./leptos_reactive", default-features = false, version = "0.3.0" }
|
||||
leptos_server = { path = "./leptos_server", default-features = false, version = "0.3.0" }
|
||||
server_fn = { path = "./server_fn", default-features = false, version = "0.3.0" }
|
||||
server_fn_macro = { path = "./server_fn_macro", default-features = false, version = "0.3.0" }
|
||||
server_fn_macro_default = { path = "./server_fn/server_fn_macro_default", default-features = false, version = "0.3.0" }
|
||||
leptos_config = { path = "./leptos_config", default-features = false, version = "0.3.0" }
|
||||
leptos_router = { path = "./router", version = "0.3.0" }
|
||||
leptos_meta = { path = "./meta", default-features = false, version = "0.3.0" }
|
||||
leptos_integration_utils = { path = "./integrations/utils", version = "0.3.0" }
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
|
||||
10
README.md
10
README.md
@@ -68,7 +68,7 @@ Here are some resources for learning more about Leptos:
|
||||
|
||||
## `nightly` Note
|
||||
|
||||
Most of the examples assume you’re using `nightly` version of Rust and the `nightly` feature of Leptos. To use `nightly` Rust, you can either set your toolchain globally or on per-project basis.
|
||||
Most of the examples assume you’re using `nightly` version of Rust. For this, you can either set your toolchain globally or on per-project basis.
|
||||
|
||||
To set `nightly` as a default toolchain for all projects (and add the ability to compile Rust to WebAssembly, if you haven’t already):
|
||||
|
||||
@@ -86,9 +86,13 @@ channel = "nightly"
|
||||
targets = ["wasm32-unknown-unknown"]
|
||||
```
|
||||
|
||||
The `nightly` feature enables the function call syntax for accessing and setting signals, as opposed to `.get()` and `.set()`. This leads to a consistent mental model in which accessing a reactive value of any kind (a signal, memo, or derived signal) is always represented as a function call. This is only possible with nightly Rust and the `nightly` feature.
|
||||
If you’re on `stable`, note the following:
|
||||
|
||||
> Note: The `nightly` feature is present on the main branch version right now, but not in 0.3.x. For 0.3.x, nightly is the default and `stable` has a special feature.
|
||||
1. You need to enable the `"stable"` flag in `Cargo.toml`: `leptos = { version = "0.2", features = ["stable"] }`
|
||||
2. `nightly` enables the function call syntax for accessing and setting signals. If you’re using `stable`,
|
||||
you’ll just call `.get()`, `.set()`, or `.update()` manually. Check out the
|
||||
[`counters_stable` example](https://github.com/leptos-rs/leptos/blob/main/examples/counters_stable/src/main.rs)
|
||||
for examples of the correct API.
|
||||
|
||||
## `cargo-leptos`
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
l021 = { package = "leptos", version = "0.2.1" }
|
||||
leptos = { path = "../leptos", features = ["ssr"] }
|
||||
leptos = { path = "../leptos", default-features = false, features = ["ssr"] }
|
||||
sycamore = { version = "0.8", features = ["ssr"] }
|
||||
yew = { git = "https://github.com/yewstack/yew", features = ["ssr"] }
|
||||
tokio-test = "0.4"
|
||||
|
||||
@@ -31,7 +31,7 @@ cargo init leptos-tutorial
|
||||
`cd` into your new `leptos-tutorial` project and add `leptos` as a dependency
|
||||
|
||||
```bash
|
||||
cargo add leptos --features=csr,nightly # or just csr if you're using stable Rust
|
||||
cargo add leptos
|
||||
```
|
||||
|
||||
Create a simple `index.html` in the root of the `leptos-tutorial` directory
|
||||
|
||||
@@ -34,7 +34,7 @@ category = "Cleanup"
|
||||
script = '''
|
||||
for pw_dir in $(find . -name playwright.config.ts | xargs dirname)
|
||||
do
|
||||
rm -rf $pw_dir/playwright-report pw_dir/playwright pw_dir/test-results
|
||||
rm -rf $pw_dir/playwright-report
|
||||
done
|
||||
'''
|
||||
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
extend = [{ path = "../cargo-make/common.toml" }]
|
||||
|
||||
[tasks.ci]
|
||||
alias = "verify-flow"
|
||||
|
||||
[tasks.verify-flow]
|
||||
description = "Provides pre and post hooks for verify"
|
||||
dependencies = ["pre-verify", "verify", "post-verify"]
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
extend = [{ path = "../cargo-make/playwright.toml" }]
|
||||
|
||||
[tasks.test-e2e]
|
||||
dependencies = ["setup-node", "test-playwright-autostart"]
|
||||
|
||||
[tasks.clean-all]
|
||||
dependencies = ["clean-cargo", "clean-node_modules", "clean-playwright"]
|
||||
@@ -1,119 +0,0 @@
|
||||
[tasks.clean-playwright]
|
||||
description = "Delete playwright directories"
|
||||
category = "Cleanup"
|
||||
script = '''
|
||||
for pw_dir in $(find . -name playwright.config.ts | xargs dirname)
|
||||
do
|
||||
rm -rf $pw_dir/playwright-report pw_dir/playwright pw_dir/test-results
|
||||
done
|
||||
'''
|
||||
|
||||
[tasks.test-playwright-autostart]
|
||||
description = "Run playwright test with server autostart"
|
||||
category = "Test"
|
||||
command = "npm"
|
||||
args = ["run", "e2e:auto-start"]
|
||||
|
||||
[tasks.test-playwright]
|
||||
description = "Run playwright test"
|
||||
category = "Test"
|
||||
script = '''
|
||||
BOLD="\e[1m"
|
||||
GREEN="\e[0;32m"
|
||||
RED="\e[0;31m"
|
||||
RESET="\e[0m"
|
||||
|
||||
project_dir=$CARGO_MAKE_WORKING_DIRECTORY
|
||||
|
||||
# Discover commands
|
||||
if command -v pnpm; then
|
||||
PLAYWRIGHT_CMD=pnpm
|
||||
elif command -v npm; then
|
||||
PLAYWRIGHT_CMD=npx
|
||||
else
|
||||
echo "${RED}${BOLD}ERROR${RESET} - pnpm or npm is required by this task"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Run playwright command
|
||||
for pw_path in $(find . -name playwright.config.ts)
|
||||
do
|
||||
pw_dir=$(dirname $pw_path)
|
||||
cd $pw_dir
|
||||
${PLAYWRIGHT_CMD} playwright test
|
||||
cd $project_dir
|
||||
done
|
||||
'''
|
||||
|
||||
[tasks.test-playwright-ui]
|
||||
description = "Run playwright test --ui"
|
||||
category = "Test"
|
||||
script = '''
|
||||
BOLD="\e[1m"
|
||||
GREEN="\e[0;32m"
|
||||
RED="\e[0;31m"
|
||||
RESET="\e[0m"
|
||||
|
||||
project_dir=$CARGO_MAKE_WORKING_DIRECTORY
|
||||
|
||||
# Discover commands
|
||||
if command -v pnpm; then
|
||||
PLAYWRIGHT_CMD=pnpm
|
||||
elif command -v npm; then
|
||||
PLAYWRIGHT_CMD=npx
|
||||
else
|
||||
echo "${RED}${BOLD}ERROR${RESET} - pnpm or npm is required by this task"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Run playwright command
|
||||
for pw_path in $(find . -name playwright.config.ts)
|
||||
do
|
||||
pw_dir=$(dirname $pw_path)
|
||||
cd $pw_dir
|
||||
${PLAYWRIGHT_CMD} playwright test --ui
|
||||
cd $project_dir
|
||||
done
|
||||
'''
|
||||
|
||||
[tasks.test-playwright-report]
|
||||
description = "Run playwright show-report"
|
||||
category = "Test"
|
||||
script = '''
|
||||
BOLD="\e[1m"
|
||||
GREEN="\e[0;32m"
|
||||
RED="\e[0;31m"
|
||||
RESET="\e[0m"
|
||||
|
||||
project_dir=$CARGO_MAKE_WORKING_DIRECTORY
|
||||
|
||||
# Discover commands
|
||||
if command -v pnpm; then
|
||||
PLAYWRIGHT_CMD=pnpm
|
||||
elif command -v npm; then
|
||||
PLAYWRIGHT_CMD=npx
|
||||
else
|
||||
echo "${RED}${BOLD}ERROR${RESET} - pnpm or npm is required by this task"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Run playwright command
|
||||
for pw_path in $(find . -name playwright.config.ts)
|
||||
do
|
||||
pw_dir=$(dirname $pw_path)
|
||||
cd $pw_dir
|
||||
${PLAYWRIGHT_CMD} playwright show-report
|
||||
cd $project_dir
|
||||
done
|
||||
'''
|
||||
|
||||
# ALIASES
|
||||
|
||||
[tasks.pw]
|
||||
dependencies = ["test-playwright"]
|
||||
|
||||
[tasks.pw-ui]
|
||||
dependencies = ["test-playwright-ui"]
|
||||
|
||||
[tasks.pw-report]
|
||||
dependencies = ["test-playwright-report"]
|
||||
@@ -1,22 +0,0 @@
|
||||
[tasks.build]
|
||||
command = "trunk"
|
||||
args = ["build"]
|
||||
|
||||
[tasks.clean-trunk]
|
||||
command = "trunk"
|
||||
args = ["clean"]
|
||||
|
||||
[tasks.start-trunk]
|
||||
command = "trunk"
|
||||
args = ["serve", "--open"]
|
||||
|
||||
[tasks.stop-trunk]
|
||||
script = '''
|
||||
pkill -f "cargo-make"
|
||||
pkill -f "trunk"
|
||||
'''
|
||||
|
||||
# ALIASES
|
||||
|
||||
[tasks.dev]
|
||||
dependencies = ["start-trunk"]
|
||||
@@ -8,7 +8,7 @@ codegen-units = 1
|
||||
lto = true
|
||||
|
||||
[dependencies]
|
||||
leptos = { path = "../../leptos", features = ["csr", "nightly"] }
|
||||
leptos = { path = "../../leptos" }
|
||||
console_log = "1"
|
||||
log = "0.4"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
|
||||
@@ -19,17 +19,19 @@ console_error_panic_hook = "0.1"
|
||||
futures = "0.3"
|
||||
cfg-if = "1"
|
||||
lazy_static = "1"
|
||||
leptos = { path = "../../leptos" }
|
||||
leptos = { path = "../../leptos", default-features = false, features = [
|
||||
"serde",
|
||||
] }
|
||||
leptos_actix = { path = "../../integrations/actix", optional = true }
|
||||
leptos_meta = { path = "../../meta" }
|
||||
leptos_router = { path = "../../router" }
|
||||
leptos_meta = { path = "../../meta", default-features = false }
|
||||
leptos_router = { path = "../../router", default-features = false }
|
||||
log = "0.4"
|
||||
gloo-net = { git = "https://github.com/rustwasm/gloo" }
|
||||
wasm-bindgen = "=0.2.86"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
|
||||
[features]
|
||||
default = ["nightly"]
|
||||
default = []
|
||||
hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]
|
||||
ssr = [
|
||||
"dep:actix-files",
|
||||
@@ -39,10 +41,10 @@ ssr = [
|
||||
"leptos_meta/ssr",
|
||||
"leptos_router/ssr",
|
||||
]
|
||||
nightly = ["leptos/nightly", "leptos_router/nightly"]
|
||||
stable = ["leptos/stable", "leptos_router/stable"]
|
||||
|
||||
[package.metadata.cargo-all-features]
|
||||
denylist = ["actix-files", "actix-web", "leptos_actix", "nightly"]
|
||||
denylist = ["actix-files", "actix-web", "leptos_actix", "stable"]
|
||||
skip_feature_sets = [["ssr", "hydrate"]]
|
||||
|
||||
[package.metadata.leptos]
|
||||
|
||||
@@ -8,7 +8,7 @@ codegen-units = 1
|
||||
lto = true
|
||||
|
||||
[dependencies]
|
||||
leptos = { path = "../../leptos", features = ["csr"] }
|
||||
leptos = { path = "../../leptos", features = ["stable"] }
|
||||
console_log = "1"
|
||||
log = "0.4"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
|
||||
@@ -4,7 +4,7 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
leptos = { path = "../../leptos", features = ["csr", "nightly"] }
|
||||
leptos = { path = "../../leptos" }
|
||||
log = "0.4"
|
||||
console_log = "1"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
|
||||
20
examples/counters_stable/.gitignore
vendored
20
examples/counters_stable/.gitignore
vendored
@@ -1,20 +0,0 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
|
||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||
Cargo.lock
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
# Support playwright testing
|
||||
node_modules/
|
||||
test-results/
|
||||
end2end/playwright-report/
|
||||
playwright/.cache/
|
||||
pnpm-lock.yaml
|
||||
|
||||
# Support trunk
|
||||
dist
|
||||
@@ -4,7 +4,7 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
leptos = { path = "../../leptos", features = ["csr"] }
|
||||
leptos = { path = "../../leptos", features = ["stable"] }
|
||||
log = "0.4"
|
||||
console_log = "1"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
extend = [
|
||||
{ path = "../cargo-make/main.toml" },
|
||||
{ path = "../cargo-make/trunk_server.toml" },
|
||||
{ path = "../cargo-make/playwright-test.toml" },
|
||||
]
|
||||
extend = [{ path = "../cargo-make/main.toml" }]
|
||||
|
||||
[tasks.build]
|
||||
command = "cargo"
|
||||
|
||||
4
examples/counters_stable/e2e/.gitignore
vendored
4
examples/counters_stable/e2e/.gitignore
vendored
@@ -1,4 +0,0 @@
|
||||
node_modules/
|
||||
/test-results/
|
||||
/playwright-report/
|
||||
/playwright/.cache/
|
||||
83
examples/counters_stable/e2e/package-lock.json
generated
83
examples/counters_stable/e2e/package-lock.json
generated
@@ -1,83 +0,0 @@
|
||||
{
|
||||
"name": "grip",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "grip",
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.35.1"
|
||||
}
|
||||
},
|
||||
"node_modules/.pnpm/@playwright+test@1.33.0": {
|
||||
"extraneous": true
|
||||
},
|
||||
"node_modules/.pnpm/@types+node@20.2.1/node_modules/@types/node": {
|
||||
"version": "20.2.1",
|
||||
"extraneous": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/.pnpm/playwright-core@1.33.0/node_modules/playwright-core": {
|
||||
"version": "1.33.0",
|
||||
"extraneous": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@playwright/test": {
|
||||
"version": "1.35.1",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.35.1.tgz",
|
||||
"integrity": "sha512-b5YoFe6J9exsMYg0pQAobNDR85T1nLumUYgUTtKm4d21iX2L7WqKq9dW8NGJ+2vX0etZd+Y7UeuqsxDXm9+5ZA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"playwright-core": "1.35.1"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.1.tgz",
|
||||
"integrity": "sha512-EhcH/wvidPy1WeML3TtYFGR83UzjxeWRen9V402T8aUGYsCHOmfoisV3ZSg03gAFIbLq8TnWOJ0f4cALtnSEUg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright-core": {
|
||||
"version": "1.35.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.35.1.tgz",
|
||||
"integrity": "sha512-pNXb6CQ7OqmGDRspEjlxE49w+4YtR6a3X6mT1hZXeJHWmsEz7SunmvZeiG/+y1yyMZdHnnn73WKYdtV1er0Xyg==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"playwright-core": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"private": "true",
|
||||
"scripts": {},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.35.1"
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
import { defineConfig, devices } from "@playwright/test";
|
||||
|
||||
/**
|
||||
* Read environment variables from file.
|
||||
* https://github.com/motdotla/dotenv
|
||||
*/
|
||||
// require('dotenv').config();
|
||||
|
||||
/**
|
||||
* See https://playwright.dev/docs/test-configuration.
|
||||
*/
|
||||
export default defineConfig({
|
||||
testDir: "./tests",
|
||||
/* Run tests in files in parallel */
|
||||
fullyParallel: true,
|
||||
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||
forbidOnly: !process.env.DEV,
|
||||
/* Retry on CI only */
|
||||
retries: process.env.DEV ? 0 : 10,
|
||||
/* Opt out of parallel tests on CI. */
|
||||
workers: process.env.DEV ? 1 : 1,
|
||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||
reporter: [["html", { open: "never" }], ["list"]],
|
||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||
use: {
|
||||
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||
baseURL: "http://127.0.0.1:8080",
|
||||
|
||||
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||
trace: "on-first-retry",
|
||||
},
|
||||
|
||||
/* Configure projects for major browsers */
|
||||
projects: [
|
||||
{
|
||||
name: "chromium",
|
||||
use: { ...devices["Desktop Chrome"] },
|
||||
},
|
||||
|
||||
// {
|
||||
// name: "firefox",
|
||||
// use: { ...devices["Desktop Firefox"] },
|
||||
// },
|
||||
|
||||
// {
|
||||
// name: "webkit",
|
||||
// use: { ...devices["Desktop Safari"] },
|
||||
// },
|
||||
|
||||
/* Test against mobile viewports. */
|
||||
// {
|
||||
// name: 'Mobile Chrome',
|
||||
// use: { ...devices['Pixel 5'] },
|
||||
// },
|
||||
// {
|
||||
// name: 'Mobile Safari',
|
||||
// use: { ...devices['iPhone 12'] },
|
||||
// },
|
||||
|
||||
/* Test against branded browsers. */
|
||||
// {
|
||||
// name: 'Microsoft Edge',
|
||||
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
||||
// },
|
||||
// {
|
||||
// name: 'Google Chrome',
|
||||
// use: { ..devices['Desktop Chrome'], channel: 'chrome' },
|
||||
// },
|
||||
],
|
||||
|
||||
/* Run your local dev server before starting the tests */
|
||||
// webServer: {
|
||||
// command: "cd ../ && trunk serve",
|
||||
// url: "http://127.0.0.1:8080",
|
||||
// reuseExistingServer: false, //!process.env.CI,
|
||||
// },
|
||||
});
|
||||
@@ -1,20 +0,0 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
import { CountersPage } from "./fixtures/counters_page";
|
||||
|
||||
test.describe("Add 1000 Counters", () => {
|
||||
test("should increase the number of counters", async ({ page }) => {
|
||||
const ui = new CountersPage(page);
|
||||
|
||||
await Promise.all([
|
||||
await ui.goto(),
|
||||
await ui.addOneThousandCountersButton.waitFor(),
|
||||
]);
|
||||
|
||||
await ui.addOneThousandCounters();
|
||||
await ui.addOneThousandCounters();
|
||||
await ui.addOneThousandCounters();
|
||||
|
||||
await expect(ui.total).toHaveText("0");
|
||||
await expect(ui.counters).toHaveText("3000");
|
||||
});
|
||||
});
|
||||
@@ -1,16 +0,0 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
import { CountersPage } from "./fixtures/counters_page";
|
||||
|
||||
test.describe("Add Counter", () => {
|
||||
test("should increase the number of counters", async ({ page }) => {
|
||||
const ui = new CountersPage(page);
|
||||
await ui.goto();
|
||||
|
||||
await ui.addCounter();
|
||||
await ui.addCounter();
|
||||
await ui.addCounter();
|
||||
|
||||
await expect(ui.total).toHaveText("0");
|
||||
await expect(ui.counters).toHaveText("3");
|
||||
});
|
||||
});
|
||||
@@ -1,18 +0,0 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
import { CountersPage } from "./fixtures/counters_page";
|
||||
|
||||
test.describe("Clear Counters", () => {
|
||||
test("should reset the counts", async ({ page }) => {
|
||||
const ui = new CountersPage(page);
|
||||
await ui.goto();
|
||||
|
||||
await ui.addCounter();
|
||||
await ui.addCounter();
|
||||
await ui.addCounter();
|
||||
|
||||
await ui.clearCounters();
|
||||
|
||||
await expect(ui.total).toHaveText("0");
|
||||
await expect(ui.counters).toHaveText("0");
|
||||
});
|
||||
});
|
||||
@@ -1,17 +0,0 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
import { CountersPage } from "./fixtures/counters_page";
|
||||
|
||||
test.describe("Decrement Count", () => {
|
||||
test("should decrease the total count", async ({ page }) => {
|
||||
const ui = new CountersPage(page);
|
||||
await ui.goto();
|
||||
await ui.addCounter();
|
||||
|
||||
await ui.decrementCount();
|
||||
await ui.decrementCount();
|
||||
await ui.decrementCount();
|
||||
|
||||
await expect(ui.total).toHaveText("-3");
|
||||
await expect(ui.counters).toHaveText("1");
|
||||
});
|
||||
});
|
||||
@@ -1,31 +0,0 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
import { CountersPage } from "./fixtures/counters_page";
|
||||
|
||||
test.describe("Enter Count", () => {
|
||||
test("should increase the total count", async ({ page }) => {
|
||||
const ui = new CountersPage(page);
|
||||
await ui.goto();
|
||||
await ui.addCounter();
|
||||
|
||||
await ui.enterCount("5");
|
||||
|
||||
await expect(ui.total).toHaveText("5");
|
||||
await expect(ui.counters).toHaveText("1");
|
||||
});
|
||||
|
||||
test("should decrease the total count", async ({ page }) => {
|
||||
const ui = new CountersPage(page);
|
||||
await ui.goto();
|
||||
await ui.addCounter();
|
||||
await ui.addCounter();
|
||||
await ui.addCounter();
|
||||
|
||||
await ui.enterCount("100");
|
||||
await ui.enterCount("100", 1);
|
||||
await ui.enterCount("100", 2);
|
||||
await ui.enterCount("50", 1);
|
||||
|
||||
await expect(ui.total).toHaveText("250");
|
||||
await expect(ui.counters).toHaveText("3");
|
||||
});
|
||||
});
|
||||
@@ -1,98 +0,0 @@
|
||||
import { expect, Locator, Page } from "@playwright/test";
|
||||
|
||||
export class CountersPage {
|
||||
readonly page: Page;
|
||||
readonly addCounterButton: Locator;
|
||||
readonly addOneThousandCountersButton: Locator;
|
||||
readonly clearCountersButton: Locator;
|
||||
|
||||
readonly incrementCountButton: Locator;
|
||||
readonly counterInput: Locator;
|
||||
readonly decrementCountButton: Locator;
|
||||
readonly removeCountButton: Locator;
|
||||
|
||||
readonly total: Locator;
|
||||
readonly counters: Locator;
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
|
||||
this.addCounterButton = page.locator("button", { hasText: "Add Counter" });
|
||||
|
||||
this.addOneThousandCountersButton = page.locator("button", {
|
||||
hasText: "Add 1000 Counters",
|
||||
});
|
||||
|
||||
this.clearCountersButton = page.locator("button", {
|
||||
hasText: "Clear Counters",
|
||||
});
|
||||
|
||||
this.decrementCountButton = page.locator("button", {
|
||||
hasText: "-1",
|
||||
});
|
||||
|
||||
this.incrementCountButton = page.locator("button", {
|
||||
hasText: "+1",
|
||||
});
|
||||
|
||||
this.removeCountButton = page.locator("button", {
|
||||
hasText: "x",
|
||||
});
|
||||
|
||||
this.total = page.getByTestId("total");
|
||||
|
||||
this.counters = page.getByTestId("counters");
|
||||
|
||||
this.counterInput = page.getByRole("textbox");
|
||||
}
|
||||
|
||||
async goto() {
|
||||
await this.page.goto("/");
|
||||
}
|
||||
|
||||
async addCounter() {
|
||||
await Promise.all([
|
||||
this.addCounterButton.waitFor(),
|
||||
this.addCounterButton.click(),
|
||||
]);
|
||||
}
|
||||
|
||||
async addOneThousandCounters() {
|
||||
this.addOneThousandCountersButton.click();
|
||||
}
|
||||
|
||||
async decrementCount(index: number = 0) {
|
||||
await Promise.all([
|
||||
this.decrementCountButton.nth(index).waitFor(),
|
||||
this.decrementCountButton.nth(index).click(),
|
||||
]);
|
||||
}
|
||||
|
||||
async incrementCount(index: number = 0) {
|
||||
await Promise.all([
|
||||
this.incrementCountButton.nth(index).waitFor(),
|
||||
this.incrementCountButton.nth(index).click(),
|
||||
]);
|
||||
}
|
||||
|
||||
async clearCounters() {
|
||||
await Promise.all([
|
||||
this.clearCountersButton.waitFor(),
|
||||
this.clearCountersButton.click(),
|
||||
]);
|
||||
}
|
||||
|
||||
async enterCount(count: string, index: number = 0) {
|
||||
await Promise.all([
|
||||
this.counterInput.nth(index).waitFor(),
|
||||
this.counterInput.nth(index).fill(count),
|
||||
]);
|
||||
}
|
||||
|
||||
async removeCounter(index: number = 0) {
|
||||
await Promise.all([
|
||||
this.removeCountButton.nth(index).waitFor(),
|
||||
this.removeCountButton.nth(index).click(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
import { CountersPage } from "./fixtures/counters_page";
|
||||
|
||||
test.describe("Increment Count", () => {
|
||||
test("should increase the total count", async ({ page }) => {
|
||||
const ui = new CountersPage(page);
|
||||
await ui.goto();
|
||||
await ui.addCounter();
|
||||
|
||||
await ui.incrementCount();
|
||||
await ui.incrementCount();
|
||||
await ui.incrementCount();
|
||||
|
||||
await expect(ui.total).toHaveText("3");
|
||||
await expect(ui.counters).toHaveText("1");
|
||||
});
|
||||
});
|
||||
@@ -1,18 +0,0 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
import { CountersPage } from "./fixtures/counters_page";
|
||||
|
||||
test.describe("Remove Counter", () => {
|
||||
test("should decrement the number of counters", async ({ page }) => {
|
||||
const ui = new CountersPage(page);
|
||||
await ui.goto();
|
||||
|
||||
await ui.addCounter();
|
||||
await ui.addCounter();
|
||||
await ui.addCounter();
|
||||
|
||||
await ui.removeCounter(1);
|
||||
|
||||
await expect(ui.total).toHaveText("0");
|
||||
await expect(ui.counters).toHaveText("2");
|
||||
});
|
||||
});
|
||||
@@ -1,19 +0,0 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
import { CountersPage } from "./fixtures/counters_page";
|
||||
|
||||
test.describe("View Counters", () => {
|
||||
test("should see the title", async ({ page }) => {
|
||||
const ui = new CountersPage(page);
|
||||
await ui.goto();
|
||||
|
||||
await expect(page).toHaveTitle("Counters (Stable)");
|
||||
});
|
||||
|
||||
test("should see the initial counts", async ({ page }) => {
|
||||
const counters = new CountersPage(page);
|
||||
await counters.goto();
|
||||
|
||||
await expect(counters.total).toHaveText("0");
|
||||
await expect(counters.counters).toHaveText("0");
|
||||
});
|
||||
});
|
||||
@@ -1,7 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Counters (Stable)</title>
|
||||
<link data-trunk rel="rust" data-wasm-opt="z" data-weak-refs/>
|
||||
</head>
|
||||
<body></body>
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"private": "true",
|
||||
"scripts": {
|
||||
"start-server": "trunk serve",
|
||||
"e2e": "cargo make test-playwright",
|
||||
"e2e:auto-start": "start-server-and-test start-server http://127.0.0.1:8080 e2e"
|
||||
},
|
||||
"devDependencies": {
|
||||
"start-server-and-test": "^1.15.4"
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,7 @@ pub fn Counters(cx: Scope) -> impl IntoView {
|
||||
</button>
|
||||
<p>
|
||||
"Total: "
|
||||
<span data-testid="total">{move ||
|
||||
<span>{move ||
|
||||
counters.get()
|
||||
.iter()
|
||||
.map(|(_, (count, _))| count.get())
|
||||
@@ -64,7 +64,7 @@ pub fn Counters(cx: Scope) -> impl IntoView {
|
||||
.to_string()
|
||||
}</span>
|
||||
" from "
|
||||
<span data-testid="counters">{move || counters.with(|counters| counters.len()).to_string()}</span>
|
||||
<span>{move || counters.with(|counters| counters.len()).to_string()}</span>
|
||||
" counters."
|
||||
</p>
|
||||
<ul>
|
||||
@@ -99,13 +99,13 @@ fn Counter(
|
||||
|
||||
view! { cx,
|
||||
<li>
|
||||
<button id="decrement_count" on:click=move |_| set_value.update(move |value| *value -= 1)>"-1"</button>
|
||||
<button on:click=move |_| set_value.update(move |value| *value -= 1)>"-1"</button>
|
||||
<input type="text"
|
||||
prop:value={move || value.get().to_string()}
|
||||
on:input=input
|
||||
/>
|
||||
<span>{value}</span>
|
||||
<button id="increment_count" on:click=move |_| set_value.update(move |value| *value += 1)>"+1"</button>
|
||||
<span>{move || value.get().to_string()}</span>
|
||||
<button on:click=move |_| set_value.update(move |value| *value += 1)>"+1"</button>
|
||||
<button on:click=move |_| set_counters.update(move |counters| counters.retain(|(counter_id, _)| counter_id != &id))>"x"</button>
|
||||
</li>
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ codegen-units = 1
|
||||
lto = true
|
||||
|
||||
[dependencies]
|
||||
leptos = { path = "../../leptos", features = ["csr", "nightly"] }
|
||||
leptos = { path = "../../leptos" }
|
||||
console_log = "1"
|
||||
log = "0.4"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
|
||||
@@ -10,10 +10,12 @@ crate-type = ["cdylib", "rlib"]
|
||||
console_log = "1.0.0"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
cfg-if = "1.0.0"
|
||||
leptos = { path = "../../leptos", features = ["nightly"] }
|
||||
leptos_axum = { path = "../../integrations/axum", optional = true }
|
||||
leptos_meta = { path = "../../meta" }
|
||||
leptos_router = { path = "../../router" }
|
||||
leptos = { path = "../../leptos", default-features = false, features = [
|
||||
"serde",
|
||||
] }
|
||||
leptos_axum = { path = "../../integrations/axum", default-features = false, optional = true }
|
||||
leptos_meta = { path = "../../meta", default-features = false }
|
||||
leptos_router = { path = "../../router", default-features = false }
|
||||
log = "0.4.17"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
simple_logger = "4.0.0"
|
||||
|
||||
@@ -8,7 +8,7 @@ codegen-units = 1
|
||||
lto = true
|
||||
|
||||
[dependencies]
|
||||
leptos = { path = "../../leptos", features = ["csr", "nightly"] }
|
||||
leptos = { path = "../../leptos" }
|
||||
reqwasm = "0.5"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
log = "0.4"
|
||||
|
||||
@@ -4,5 +4,5 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
leptos = { path = "../../leptos", features = ["csr", "nightly"] }
|
||||
leptos = { path = "../../leptos" }
|
||||
gtk = { version = "0.5.0", package = "gtk4" }
|
||||
@@ -16,10 +16,12 @@ actix-web = { version = "4", optional = true, features = ["macros"] }
|
||||
console_log = "1"
|
||||
console_error_panic_hook = "0.1"
|
||||
cfg-if = "1"
|
||||
leptos = { path = "../../leptos", features = ["nightly"] }
|
||||
leptos_meta = { path = "../../meta", features = ["nightly"] }
|
||||
leptos_actix = { path = "../../integrations/actix", optional = true }
|
||||
leptos_router = { path = "../../router", features = ["nightly"] }
|
||||
leptos = { path = "../../leptos", default-features = false, features = [
|
||||
"serde",
|
||||
] }
|
||||
leptos_meta = { path = "../../meta", default-features = false }
|
||||
leptos_actix = { path = "../../integrations/actix", default-features = false, optional = true }
|
||||
leptos_router = { path = "../../router", default-features = false }
|
||||
log = "0.4"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
gloo-net = { version = "0.2", features = ["http"] }
|
||||
|
||||
@@ -14,10 +14,12 @@ lto = true
|
||||
console_log = "1.0.0"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
cfg-if = "1.0.0"
|
||||
leptos = { path = "../../leptos", features = ["nightly"] }
|
||||
leptos = { path = "../../leptos", default-features = false, features = [
|
||||
"serde",
|
||||
] }
|
||||
leptos_axum = { path = "../../integrations/axum", optional = true }
|
||||
leptos_meta = { path = "../../meta", features = ["nightly"] }
|
||||
leptos_router = { path = "../../router", features = ["nightly"] }
|
||||
leptos_meta = { path = "../../meta", default-features = false }
|
||||
leptos_router = { path = "../../router", default-features = false }
|
||||
log = "0.4.17"
|
||||
simple_logger = "4.0.0"
|
||||
serde = { version = "1.0.148", features = ["derive"] }
|
||||
|
||||
@@ -8,7 +8,7 @@ codegen-units = 1
|
||||
lto = true
|
||||
|
||||
[dependencies]
|
||||
leptos = { path = "../../leptos", features = ["csr", "nightly", "template_macro"] }
|
||||
leptos = { path = "../../leptos", features=["template_macro"] }
|
||||
console_log = "1"
|
||||
log = "0.4"
|
||||
# used in rand, but we need to enable js feature
|
||||
|
||||
@@ -11,10 +11,12 @@ axum = { version = "0.6.18", optional = true }
|
||||
console_error_panic_hook = "0.1.7"
|
||||
console_log = "1"
|
||||
cfg-if = "1"
|
||||
leptos = { path = "../../leptos", features = ["nightly"] }
|
||||
leptos_meta = { path = "../../meta", features = ["nightly"] }
|
||||
leptos_axum = { path = "../../integrations/axum", optional = true }
|
||||
leptos_router = { path = "../../router", features = ["nightly"] }
|
||||
leptos = { path = "../../leptos", default-features = false, features = [
|
||||
"serde",
|
||||
] }
|
||||
leptos_meta = { path = "../../meta", default-features = false }
|
||||
leptos_axum = { path = "../../integrations/axum", default-features = false, optional = true }
|
||||
leptos_router = { path = "../../router", default-features = false }
|
||||
log = "0.4.17"
|
||||
simple_logger = "4"
|
||||
tokio = { version = "1.28.1", optional = true }
|
||||
|
||||
@@ -6,6 +6,6 @@ codegen-units = 1
|
||||
lto = true
|
||||
|
||||
[patch.crates-io]
|
||||
leptos = { path = "../../leptos", features = ["nightly"] }
|
||||
leptos_router = { path = "../../router", features = ["nightly"] }
|
||||
leptos = { path = "../../leptos" }
|
||||
leptos_router = { path = "../../router" }
|
||||
api-boundary = { path = "api-boundary" }
|
||||
|
||||
@@ -7,9 +7,8 @@ publish = false
|
||||
[dependencies]
|
||||
api-boundary = "*"
|
||||
|
||||
leptos = { path = "../../../leptos", features = ["csr"] }
|
||||
leptos_meta = { path = "../../../meta", features = ["csr"] }
|
||||
leptos_router = { path = "../../../router", features = ["csr"] }
|
||||
leptos = { version = "0.2.0-alpha2", features = ["stable"] }
|
||||
leptos_router = { version = "0.2.0-alpha2", features = ["stable", "csr"] }
|
||||
|
||||
log = "0.4"
|
||||
console_error_panic_hook = "0.1"
|
||||
|
||||
@@ -8,7 +8,7 @@ codegen-units = 1
|
||||
lto = true
|
||||
|
||||
[dependencies]
|
||||
leptos = { path = "../../leptos", features = ["csr", "nightly"] }
|
||||
leptos = { path = "../../leptos" }
|
||||
console_log = "1"
|
||||
log = "0.4"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
|
||||
@@ -45,7 +45,7 @@ pub fn App(cx: Scope) -> impl IntoView {
|
||||
// Button B: pass a closure
|
||||
<ButtonB on_click=move |_| set_right.update(|value| *value = !*value)/>
|
||||
|
||||
// Button C: use a regular event listener
|
||||
// Button B: use a regular event listener
|
||||
// setting an event listener on a component like this applies it
|
||||
// to each of the top-level elements the component returns
|
||||
<ButtonC on:click=move |_| set_italics.update(|value| *value = !*value)/>
|
||||
|
||||
21
examples/router/.gitignore
vendored
21
examples/router/.gitignore
vendored
@@ -1,21 +0,0 @@
|
||||
Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
|
||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||
Cargo.lock
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
# Support playwright testing
|
||||
node_modules/
|
||||
test-results/
|
||||
end2end/playwright-report/
|
||||
playwright/.cache/
|
||||
pnpm-lock.yaml
|
||||
|
||||
# Support trunk
|
||||
dist
|
||||
|
||||
@@ -10,12 +10,12 @@ lto = true
|
||||
[dependencies]
|
||||
console_log = "1"
|
||||
log = "0.4"
|
||||
leptos = { path = "../../leptos", features = ["csr", "nightly"] }
|
||||
leptos_router = { path = "../../router", features = ["csr", "nightly"] }
|
||||
leptos = { path = "../../leptos" }
|
||||
leptos_router = { path = "../../router", features = ["csr"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
futures = "0.3"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
leptos_meta = { path = "../../meta", features = ["csr", "nightly"] }
|
||||
leptos_meta = { path = "../../meta", features = ["csr"] }
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen-test = "0.3.0"
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
extend = [
|
||||
{ path = "../cargo-make/main.toml" },
|
||||
{ path = "../cargo-make/trunk_server.toml" },
|
||||
{ path = "../cargo-make/playwright-test.toml" },
|
||||
]
|
||||
extend = { path = "../cargo-make/main.toml" }
|
||||
|
||||
[tasks.build]
|
||||
command = "cargo"
|
||||
|
||||
36
examples/router/e2e/package-lock.json
generated
36
examples/router/e2e/package-lock.json
generated
@@ -1,36 +0,0 @@
|
||||
{
|
||||
"name": "e2e",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@playwright/test": {
|
||||
"version": "1.35.1",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*",
|
||||
"fsevents": "2.3.2",
|
||||
"playwright-core": "1.35.1"
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "20.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.2.tgz",
|
||||
"integrity": "sha512-vOBLVQeCQfIcF/2Y7eKFTqrMnizK5lRNQ7ykML/5RuwVXVWxYkgwS7xbt4B6fKCUPgbSL5FSsjHQpaGQP/dQmw==",
|
||||
"dev": true
|
||||
},
|
||||
"fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"playwright-core": {
|
||||
"version": "1.35.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.35.1.tgz",
|
||||
"integrity": "sha512-pNXb6CQ7OqmGDRspEjlxE49w+4YtR6a3X6mT1hZXeJHWmsEz7SunmvZeiG/+y1yyMZdHnnn73WKYdtV1er0Xyg==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"private": "true",
|
||||
"scripts": {},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.35.1"
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
import { defineConfig, devices } from "@playwright/test";
|
||||
|
||||
/**
|
||||
* Read environment variables from file.
|
||||
* https://github.com/motdotla/dotenv
|
||||
*/
|
||||
// require('dotenv').config();
|
||||
|
||||
/**
|
||||
* See https://playwright.dev/docs/test-configuration.
|
||||
*/
|
||||
export default defineConfig({
|
||||
testDir: "./tests",
|
||||
/* Run tests in files in parallel */
|
||||
fullyParallel: true,
|
||||
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||
forbidOnly: !!process.env.CI,
|
||||
/* Retry on CI only */
|
||||
retries: process.env.CI ? 10 : 10,
|
||||
/* Opt out of parallel tests on CI. */
|
||||
workers: process.env.CI ? 1 : undefined,
|
||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||
reporter: "list",
|
||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||
use: {
|
||||
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||
baseURL: "http://127.0.0.1:8080",
|
||||
|
||||
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||
trace: "on-first-retry",
|
||||
},
|
||||
|
||||
/* Configure projects for major browsers */
|
||||
projects: [
|
||||
{
|
||||
name: "chromium",
|
||||
use: { ...devices["Desktop Chrome"] },
|
||||
},
|
||||
|
||||
// {
|
||||
// name: "firefox",
|
||||
// use: { ...devices["Desktop Firefox"] },
|
||||
// },
|
||||
|
||||
// {
|
||||
// name: "webkit",
|
||||
// use: { ...devices["Desktop Safari"] },
|
||||
// },
|
||||
|
||||
/* Test against mobile viewports. */
|
||||
// {
|
||||
// name: 'Mobile Chrome',
|
||||
// use: { ...devices['Pixel 5'] },
|
||||
// },
|
||||
// {
|
||||
// name: 'Mobile Safari',
|
||||
// use: { ...devices['iPhone 12'] },
|
||||
// },
|
||||
|
||||
/* Test against branded browsers. */
|
||||
// {
|
||||
// name: 'Microsoft Edge',
|
||||
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
||||
// },
|
||||
// {
|
||||
// name: 'Google Chrome',
|
||||
// use: { ..devices['Desktop Chrome'], channel: 'chrome' },
|
||||
// },
|
||||
],
|
||||
|
||||
/* Run your local dev server before starting the tests */
|
||||
// webServer: {
|
||||
// command: "cd ../ && trunk serve",
|
||||
// url: "http://127.0.0.1:8080",
|
||||
// reuseExistingServer: false, //!process.env.CI,
|
||||
// },
|
||||
});
|
||||
@@ -1,30 +0,0 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
|
||||
test.describe("Test Router example", () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto("/");
|
||||
});
|
||||
|
||||
const links = [
|
||||
{ label: "Bill Smith", url: "/0" },
|
||||
{ label: "Tim Jones", url: "/1" },
|
||||
{ label: "Sally Stevens", url: "/2" },
|
||||
{ label: "About", url: "/about" },
|
||||
{ label: "Settings", url: "/settings" },
|
||||
];
|
||||
links.forEach(({ label, url }) => {
|
||||
test(`Can navigate to ${label}`, async ({ page }) => {
|
||||
await page.getByRole("link", { name: label }).click();
|
||||
|
||||
await expect(page.getByRole("heading", { name: label })).toBeVisible();
|
||||
await expect(page).toHaveURL(url);
|
||||
});
|
||||
});
|
||||
|
||||
test("Can redirect to home", async ({ page }) => {
|
||||
await page.getByRole("link", { name: "About" }).click();
|
||||
|
||||
await page.getByRole("link", { name: "Redirect to Home" }).click();
|
||||
await expect(page).toHaveURL("/");
|
||||
});
|
||||
});
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start-server": "trunk serve",
|
||||
"e2e": "cargo make test-playwright",
|
||||
"e2e:auto-start": "start-server-and-test start-server http://127.0.0.1:8080 e2e"
|
||||
},
|
||||
"devDependencies": {
|
||||
"start-server-and-test": "^2.0.0"
|
||||
}
|
||||
}
|
||||
@@ -13,10 +13,12 @@ rand = { version = "0.8.5", features = ["min_const_gen"], optional = true }
|
||||
console_error_panic_hook = "0.1.7"
|
||||
futures = "0.3.25"
|
||||
cfg-if = "1.0.0"
|
||||
leptos = { path = "../../leptos", features = ["nightly"] }
|
||||
leptos_meta = { path = "../../meta", features = ["nightly"] }
|
||||
leptos = { path = "../../leptos", default-features = false, features = [
|
||||
"serde",
|
||||
] }
|
||||
leptos_meta = { path = "../../meta", default-features = false }
|
||||
leptos_axum = { path = "../../integrations/axum", optional = true }
|
||||
leptos_router = { path = "../../router", features = ["nightly"] }
|
||||
leptos_router = { path = "../../router", default-features = false }
|
||||
log = "0.4.17"
|
||||
simple_logger = "4.0.0"
|
||||
serde = { version = "1.0.148", features = ["derive"] }
|
||||
|
||||
@@ -8,7 +8,7 @@ codegen-units = 1
|
||||
lto = true
|
||||
|
||||
[dependencies]
|
||||
leptos = { path = "../../leptos", features = ["csr", "nightly"] }
|
||||
leptos = { path = "../../leptos" }
|
||||
console_log = "1"
|
||||
log = "0.4"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
|
||||
@@ -13,10 +13,12 @@ console_error_panic_hook = "0.1"
|
||||
console_log = "1"
|
||||
cfg-if = "1"
|
||||
lazy_static = "1"
|
||||
leptos = { path = "../../leptos", features = ["nightly"] }
|
||||
leptos_meta = { path = "../../meta", features = ["nightly"] }
|
||||
leptos_actix = { path = "../../integrations/actix", optional = true }
|
||||
leptos_router = { path = "../../router", features = ["nightly"] }
|
||||
leptos = { path = "../../leptos", default-features = false, features = [
|
||||
"serde",
|
||||
] }
|
||||
leptos_meta = { path = "../../meta", default-features = false }
|
||||
leptos_actix = { path = "../../integrations/actix", default-features = false, optional = true }
|
||||
leptos_router = { path = "../../router", default-features = false }
|
||||
log = "0.4"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
thiserror = "1"
|
||||
|
||||
@@ -11,10 +11,12 @@ console_error_panic_hook = "0.1"
|
||||
console_log = "1"
|
||||
cfg-if = "1"
|
||||
lazy_static = "1"
|
||||
leptos = { path = "../../leptos", features = ["nightly"] }
|
||||
leptos_meta = { path = "../../meta", features = ["nightly"] }
|
||||
leptos_axum = { path = "../../integrations/axum", optional = true }
|
||||
leptos_router = { path = "../../router", features = ["nightly"] }
|
||||
leptos = { path = "../../leptos", default-features = false, features = [
|
||||
"serde",
|
||||
] }
|
||||
leptos_meta = { path = "../../meta", default-features = false }
|
||||
leptos_axum = { path = "../../integrations/axum", default-features = false, optional = true }
|
||||
leptos_router = { path = "../../router", default-features = false }
|
||||
log = "0.4"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
thiserror = "1"
|
||||
|
||||
@@ -10,10 +10,12 @@ crate-type = ["cdylib", "rlib"]
|
||||
|
||||
|
||||
[dependencies]
|
||||
leptos = { path = "../../leptos", features = ["nightly"] }
|
||||
leptos = { path = "../../leptos", default-features = false, features = [
|
||||
"serde",
|
||||
] }
|
||||
leptos_actix = { path = "../../integrations/actix", optional = true }
|
||||
leptos_meta = { path = "../../meta", features = ["nightly"] }
|
||||
leptos_router = { path = "../../router", features = ["nightly"] }
|
||||
leptos_meta = { path = "../../meta", default-features = false }
|
||||
leptos_router = { path = "../../router", default-features = false }
|
||||
gloo-net = { version = "0.2", features = ["http"] }
|
||||
log = "0.4"
|
||||
cfg-if = "1.0"
|
||||
|
||||
@@ -4,9 +4,12 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
leptos = { path = "../../leptos", features = ["csr", "nightly"] }
|
||||
leptos_meta = { path = "../../meta", features = ["csr", "nightly"] }
|
||||
leptos_router = { path = "../../router", features = ["csr", "nightly"] }
|
||||
leptos = { version = "0.2", features = [
|
||||
"serde",
|
||||
"csr",
|
||||
] }
|
||||
leptos_meta = { version = "0.2", features = ["csr"] }
|
||||
leptos_router = { version = "0.2", features = ["csr"] }
|
||||
log = "0.4"
|
||||
gloo-net = { version = "0.2", features = ["http"] }
|
||||
|
||||
|
||||
@@ -52,9 +52,8 @@ If you're using VS Code, add the following to your `settings.json`
|
||||
|
||||
Install [Tailwind CSS Intellisense](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss).
|
||||
|
||||
Install [VS Browser](https://marketplace.visualstudio.com/items?itemName=Phu1237.vs-browser) extension (allows you to open a browser at the right window.
|
||||
|
||||
Allow vscode Ports forward: 3000, 3001.
|
||||
Install "VS Browser" extension, a browser at the right window.
|
||||
Allow vscode Ports forward: 3000, 3001.
|
||||
|
||||
## Notes about Tooling
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ codegen-units = 1
|
||||
lto = true
|
||||
|
||||
[dependencies]
|
||||
leptos = { path = "../../leptos", features = ["csr", "nightly"] }
|
||||
leptos = { path = "../../leptos" }
|
||||
console_log = "1"
|
||||
log = "0.4"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
|
||||
@@ -16,10 +16,12 @@ console_error_panic_hook = "0.1.7"
|
||||
serde = { version = "1.0.152", features = ["derive"] }
|
||||
futures = "0.3.25"
|
||||
cfg-if = "1.0.0"
|
||||
leptos = { path = "../../leptos", features = ["nightly"] }
|
||||
leptos = { path = "../../leptos", default-features = false, features = [
|
||||
"serde",
|
||||
] }
|
||||
leptos_actix = { path = "../../integrations/actix", optional = true }
|
||||
leptos_meta = { path = "../../meta", features = ["nightly"] }
|
||||
leptos_router = { path = "../../router", features = ["nightly"] }
|
||||
leptos_meta = { path = "../../meta", default-features = false }
|
||||
leptos_router = { path = "../../router", default-features = false }
|
||||
log = "0.4.17"
|
||||
simple_logger = "4.0.0"
|
||||
gloo = { git = "https://github.com/rustwasm/gloo" }
|
||||
@@ -30,6 +32,7 @@ sqlx = { version = "0.6.2", features = [
|
||||
wasm-bindgen = "0.2"
|
||||
|
||||
[features]
|
||||
default = ["ssr"]
|
||||
hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]
|
||||
ssr = [
|
||||
"dep:actix-files",
|
||||
|
||||
@@ -11,10 +11,12 @@ console_log = "1.0.0"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
futures = "0.3.25"
|
||||
cfg-if = "1.0.0"
|
||||
leptos = { path = "../../leptos", features = ["nightly"] }
|
||||
leptos_axum = { path = "../../integrations/axum", optional = true }
|
||||
leptos_meta = { path = "../../meta", features = ["nightly"] }
|
||||
leptos_router = { path = "../../router", features = ["nightly"] }
|
||||
leptos = { path = "../../leptos", default-features = false, features = [
|
||||
"serde",
|
||||
] }
|
||||
leptos_axum = { path = "../../integrations/axum", default-features = false, optional = true }
|
||||
leptos_meta = { path = "../../meta", default-features = false }
|
||||
leptos_router = { path = "../../router", default-features = false }
|
||||
log = "0.4.17"
|
||||
simple_logger = "4.0.0"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
@@ -31,6 +33,8 @@ thiserror = "1.0.38"
|
||||
wasm-bindgen = "0.2"
|
||||
|
||||
[features]
|
||||
default = ["csr"]
|
||||
csr = ["leptos/csr", "leptos_meta/csr", "leptos_router/csr"]
|
||||
hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]
|
||||
ssr = [
|
||||
"dep:axum",
|
||||
|
||||
@@ -11,11 +11,13 @@ console_log = "1.0.0"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
futures = "0.3.25"
|
||||
cfg-if = "1.0.0"
|
||||
leptos = { path = "../../leptos" }
|
||||
leptos_viz = { path = "../../integrations/viz", optional = true }
|
||||
leptos_meta = { path = "../../meta", features = ["nightly"] }
|
||||
leptos_router = { path = "../../router", features = ["nightly"] }
|
||||
leptos_reactive = { path = "../../leptos_reactive", features = ["nightly"] }
|
||||
leptos = { path = "../../leptos", default-features = false, features = [
|
||||
"serde",
|
||||
] }
|
||||
leptos_viz = { path = "../../integrations/viz", default-features = false, optional = true }
|
||||
leptos_meta = { path = "../../meta", default-features = false }
|
||||
leptos_router = { path = "../../router", default-features = false }
|
||||
leptos_reactive = { path = "../../leptos_reactive", default-features = false }
|
||||
log = "0.4.17"
|
||||
simple_logger = "4.0.0"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
@@ -30,6 +32,7 @@ thiserror = "1.0.38"
|
||||
wasm-bindgen = "0.2"
|
||||
|
||||
[features]
|
||||
default = ["csr"]
|
||||
csr = ["leptos/csr", "leptos_meta/csr", "leptos_router/csr"]
|
||||
hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]
|
||||
ssr = [
|
||||
|
||||
@@ -8,7 +8,7 @@ codegen-units = 1
|
||||
lto = true
|
||||
|
||||
[dependencies]
|
||||
leptos = { path = "../../leptos", features = ["nightly"] }
|
||||
leptos = { path = "../../leptos", default-features = false }
|
||||
log = "0.4"
|
||||
console_log = "1"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
|
||||
@@ -13,19 +13,19 @@ cfg-if = "1"
|
||||
leptos_dom = { workspace = true }
|
||||
leptos_macro = { workspace = true }
|
||||
leptos_reactive = { workspace = true }
|
||||
leptos_server = { workspace = true}
|
||||
leptos_server = { workspace = true, default-features = false }
|
||||
leptos_config = { workspace = true }
|
||||
tracing = "0.1"
|
||||
typed-builder = "0.14"
|
||||
server_fn = { workspace = true}
|
||||
server_fn = { workspace = true, default-features = false }
|
||||
web-sys = { version = "0.3.63", optional = true }
|
||||
wasm-bindgen = { version = "0.2", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
leptos = { path = "."}
|
||||
leptos = { path = ".", default-features = false }
|
||||
|
||||
[features]
|
||||
default = ["serde"]
|
||||
default = ["csr", "serde"]
|
||||
template_macro = ["leptos_dom/web", "web-sys", "wasm-bindgen"]
|
||||
csr = [
|
||||
"leptos_dom/web",
|
||||
@@ -47,11 +47,11 @@ ssr = [
|
||||
"leptos_reactive/ssr",
|
||||
"leptos_server/ssr",
|
||||
]
|
||||
nightly = [
|
||||
"leptos_dom/nightly",
|
||||
"leptos_macro/nightly",
|
||||
"leptos_reactive/nightly",
|
||||
"leptos_server/nightly",
|
||||
stable = [
|
||||
"leptos_dom/stable",
|
||||
"leptos_macro/stable",
|
||||
"leptos_reactive/stable",
|
||||
"leptos_server/stable",
|
||||
]
|
||||
serde = ["leptos_reactive/serde"]
|
||||
serde-lite = ["leptos_reactive/serde-lite"]
|
||||
@@ -60,7 +60,7 @@ rkyv = ["leptos_reactive/rkyv"]
|
||||
tracing = ["leptos_macro/tracing"]
|
||||
|
||||
[package.metadata.cargo-all-features]
|
||||
denylist = ["nightly", "tracing", "template_macro", "rustls", "default-tls", "web-sys", "wasm-bindgen"]
|
||||
denylist = ["stable", "tracing", "template_macro", "rustls", "default-tls", "web-sys", "wasm-bindgen"]
|
||||
skip_feature_sets = [
|
||||
[
|
||||
"csr",
|
||||
|
||||
@@ -16,14 +16,14 @@ use leptos_reactive::{
|
||||
/// # use leptos_dom::*; use leptos::*;
|
||||
/// # run_scope(create_runtime(), |cx| {
|
||||
/// let (value, set_value) = create_signal(cx, Ok(0));
|
||||
/// let on_input = move |ev| set_value.set(event_target_value(&ev).parse::<i32>());
|
||||
/// let on_input = move |ev| set_value(event_target_value(&ev).parse::<i32>());
|
||||
///
|
||||
/// view! { cx,
|
||||
/// <input type="text" on:input=on_input/>
|
||||
/// <ErrorBoundary
|
||||
/// fallback=move |_, _| view! { cx, <p class="error">"Enter a valid number."</p>}
|
||||
/// >
|
||||
/// <p>"Value is: " {move || value.get()}</p>
|
||||
/// <p>"Value is: " {value}</p>
|
||||
/// </ErrorBoundary>
|
||||
/// }
|
||||
/// # });
|
||||
|
||||
@@ -26,7 +26,7 @@ use std::hash::Hash;
|
||||
/// <div>
|
||||
/// <For
|
||||
/// // a function that returns the items we're iterating over; a signal is fine
|
||||
/// each=move || counters.get()
|
||||
/// each=counters
|
||||
/// // a unique key for each item
|
||||
/// key=|counter| counter.id
|
||||
/// // renders each item to a view
|
||||
|
||||
@@ -16,6 +16,14 @@
|
||||
//! Join us on our [Discord Channel](https://discord.gg/v38Eef6sWG) to see what the community is building.
|
||||
//! Explore our [Examples](https://github.com/leptos-rs/leptos/tree/main/examples) to see Leptos in action.
|
||||
//!
|
||||
//! # `nightly` Note
|
||||
//! Most of the examples assume you’re using `nightly` Rust. If you’re on stable, note the following:
|
||||
//! 1. You need to enable the `"stable"` flag in `Cargo.toml`: `leptos = { version = "0.0", features = ["stable"] }`
|
||||
//! 2. `nightly` enables the function call syntax for accessing and setting signals. If you’re using `stable`,
|
||||
//! you’ll just call `.get()`, `.set()`, or `.update()` manually. Check out the
|
||||
//! [`counters_stable` example](https://github.com/leptos-rs/leptos/blob/main/examples/counters_stable/src/main.rs)
|
||||
//! for examples of the correct API.
|
||||
//!
|
||||
//! # Learning by Example
|
||||
//!
|
||||
//! If you want to see what Leptos is capable of, check out
|
||||
@@ -76,10 +84,12 @@
|
||||
//! - **Server Functions**: the [server](crate::leptos_server) macro, [create_action], and [create_server_action]
|
||||
//!
|
||||
//! # Feature Flags
|
||||
//! - `nightly`: On `nightly` Rust, enables the function-call syntax for signal getters and setters.
|
||||
//! - `csr` Client-side rendering: Generate DOM nodes in the browser
|
||||
//! - `csr` (*Default*) Client-side rendering: Generate DOM nodes in the browser
|
||||
//! - `ssr` Server-side rendering: Generate an HTML string (typically on the server)
|
||||
//! - `hydrate` Hydration: use this to add interactivity to an SSRed Leptos app
|
||||
//! - `stable` By default, Leptos requires `nightly` Rust, which is what allows the ergonomics
|
||||
//! of calling signals as functions. If you need to use `stable`, you will need to call `.get()`
|
||||
//! and `.set()` manually.
|
||||
//! - `serde` (*Default*) In SSR/hydrate mode, uses [serde](https://docs.rs/serde/latest/serde/) to serialize resources and send them
|
||||
//! from the server to the client.
|
||||
//! - `serde-lite` In SSR/hydrate mode, uses [serde-lite](https://docs.rs/serde-lite/latest/serde_lite/) to serialize resources and send them
|
||||
@@ -112,7 +122,7 @@
|
||||
//! <div>
|
||||
//! <button on:click=clear>"Clear"</button>
|
||||
//! <button on:click=decrement>"-1"</button>
|
||||
//! <span>"Value: " {move || value.get().to_string()} "!"</span>
|
||||
//! <span>"Value: " {move || value().to_string()} "!"</span>
|
||||
//! <button on:click=increment>"+1"</button>
|
||||
//! </div>
|
||||
//! }
|
||||
|
||||
@@ -21,7 +21,7 @@ use std::{cell::RefCell, rc::Rc};
|
||||
///
|
||||
/// view! { cx,
|
||||
/// <Show
|
||||
/// when=move || value.get() < 5
|
||||
/// when=move || value() < 5
|
||||
/// fallback=|cx| view! { cx, "Big number!" }
|
||||
/// >
|
||||
/// "Small number!"
|
||||
|
||||
@@ -21,7 +21,7 @@ use std::rc::Rc;
|
||||
///
|
||||
/// let (cat_count, set_cat_count) = create_signal::<u32>(cx, 1);
|
||||
///
|
||||
/// let cats = create_resource(cx, move || cat_count.get(), |count| fetch_cats(count));
|
||||
/// let cats = create_resource(cx, cat_count, |count| fetch_cats(count));
|
||||
///
|
||||
/// view! { cx,
|
||||
/// <div>
|
||||
@@ -73,7 +73,7 @@ where
|
||||
|
||||
let child = DynChild::new({
|
||||
#[cfg(not(any(feature = "csr", feature = "hydrate")))]
|
||||
let current_id = current_id;
|
||||
let current_id = current_id.clone();
|
||||
|
||||
let children = Rc::new(orig_children(cx).into_view(cx));
|
||||
#[cfg(not(any(feature = "csr", feature = "hydrate")))]
|
||||
@@ -94,10 +94,10 @@ where
|
||||
// run the child; we'll probably throw this away, but it will register resource reads
|
||||
//let after_original_child = HydrationCtx::peek();
|
||||
|
||||
{
|
||||
let initial = {
|
||||
// no resources were read under this, so just return the child
|
||||
if context.pending_resources.get() == 0 {
|
||||
HydrationCtx::continue_from(current_id);
|
||||
HydrationCtx::continue_from(current_id.clone());
|
||||
DynChild::new({
|
||||
let children = Rc::clone(&children);
|
||||
move || (*children).clone()
|
||||
@@ -115,7 +115,9 @@ where
|
||||
{
|
||||
let orig_children = Rc::clone(&orig_children);
|
||||
move || {
|
||||
HydrationCtx::continue_from(current_id);
|
||||
HydrationCtx::continue_from(
|
||||
current_id.clone(),
|
||||
);
|
||||
DynChild::new({
|
||||
let orig_children =
|
||||
orig_children(cx).into_view(cx);
|
||||
@@ -130,7 +132,9 @@ where
|
||||
{
|
||||
let orig_children = Rc::clone(&orig_children);
|
||||
move || {
|
||||
HydrationCtx::continue_from(current_id);
|
||||
HydrationCtx::continue_from(
|
||||
current_id.clone(),
|
||||
);
|
||||
DynChild::new({
|
||||
let orig_children =
|
||||
orig_children(cx).into_view(cx);
|
||||
@@ -145,7 +149,9 @@ where
|
||||
// return the fallback for now, wrapped in fragment identifier
|
||||
fallback().into_view(cx)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
initial
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -32,8 +32,7 @@ use std::{
|
||||
/// let (cat_count, set_cat_count) = create_signal::<u32>(cx, 1);
|
||||
/// let (pending, set_pending) = create_signal(cx, false);
|
||||
///
|
||||
/// let cats =
|
||||
/// create_resource(cx, move || cat_count.get(), |count| fetch_cats(count));
|
||||
/// let cats = create_resource(cx, cat_count, |count| fetch_cats(count));
|
||||
///
|
||||
/// view! { cx,
|
||||
/// <div>
|
||||
@@ -65,7 +64,7 @@ use std::{
|
||||
any(debug_assertions, feature = "ssr"),
|
||||
tracing::instrument(level = "info", skip_all)
|
||||
)]
|
||||
#[component(transparent)]
|
||||
#[component]
|
||||
pub fn Transition<F, E>(
|
||||
cx: Scope,
|
||||
/// Will be displayed while resources are pending.
|
||||
|
||||
@@ -12,9 +12,9 @@ actix-web = { version = "4", optional = true, features = ["macros"] }
|
||||
console_error_panic_hook = "0.1"
|
||||
console_log = "1"
|
||||
cfg-if = "1"
|
||||
leptos = { path = "../../..", features = ["serde"] }
|
||||
leptos = { path = "../../..", default-features = false, features = ["serde"] }
|
||||
leptos_actix = { path = "../../../../integrations/actix", optional = true }
|
||||
leptos_router = { path = "../../../../router"}
|
||||
leptos_router = { path = "../../../../router", default-features = false }
|
||||
log = "0.4"
|
||||
simple_logger = "4"
|
||||
wasm-bindgen = "0.2.87"
|
||||
|
||||
@@ -153,30 +153,16 @@ impl TryFrom<String> for Env {
|
||||
/// If an env var is specified, like `LEPTOS_ENV`, it will override a setting in the file.
|
||||
pub fn get_config_from_str(text: &str) -> Result<ConfFile, LeptosConfigError> {
|
||||
let re: Regex = Regex::new(r#"(?m)^\[package.metadata.leptos\]"#).unwrap();
|
||||
let re_workspace: Regex =
|
||||
Regex::new(r#"(?m)^\[\[workspace.metadata.leptos\]\]"#).unwrap();
|
||||
|
||||
let metadata_name;
|
||||
let start;
|
||||
match re.find(text) {
|
||||
Some(found) => {
|
||||
metadata_name = "[package.metadata.leptos]";
|
||||
start = found.start();
|
||||
}
|
||||
None => match re_workspace.find(text) {
|
||||
Some(found) => {
|
||||
metadata_name = "[[workspace.metadata.leptos]]";
|
||||
start = found.start();
|
||||
}
|
||||
None => return Err(LeptosConfigError::ConfigSectionNotFound),
|
||||
},
|
||||
let start = match re.find(text) {
|
||||
Some(found) => found.start(),
|
||||
None => return Err(LeptosConfigError::ConfigSectionNotFound),
|
||||
};
|
||||
|
||||
// so that serde error messages have right line number
|
||||
let newlines = text[..start].matches('\n').count();
|
||||
let input = "\n".repeat(newlines) + &text[start..];
|
||||
let toml = input
|
||||
.replace(metadata_name, "[leptos_options]")
|
||||
.replace("[package.metadata.leptos]", "[leptos_options]")
|
||||
.replace('-', "_");
|
||||
let settings = Config::builder()
|
||||
// Read the "default" configuration file
|
||||
|
||||
@@ -159,8 +159,8 @@ features = [
|
||||
default = []
|
||||
web = ["leptos_reactive/csr"]
|
||||
ssr = ["leptos_reactive/ssr"]
|
||||
nightly = ["leptos_reactive/nightly"]
|
||||
stable = ["leptos_reactive/stable"]
|
||||
|
||||
[package.metadata.cargo-all-features]
|
||||
denylist = ["nightly"]
|
||||
denylist = ["stable"]
|
||||
skip_feature_sets = [["web", "ssr"]]
|
||||
|
||||
@@ -7,7 +7,7 @@ edition = "2021"
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
leptos = { path = "../../../leptos", features = ["nightly"] }
|
||||
leptos = { path = "../../../leptos", default-features = false }
|
||||
actix-web = { version = "4", optional = true }
|
||||
actix-files = { version = "0.6", optional = true }
|
||||
wasm-bindgen = { version = "0.2", optional = true }
|
||||
|
||||
@@ -6,7 +6,7 @@ edition = "2021"
|
||||
[dependencies]
|
||||
console_error_panic_hook = "0.1"
|
||||
gloo = { version = "0.8", features = ["futures"] }
|
||||
leptos = { path = "../../../leptos", features = ["nightly", "csr", "tracing"] }
|
||||
leptos = { path = "../../../leptos", features = ["tracing"] }
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = "0.3"
|
||||
tracing-subscriber-wasm = "0.1"
|
||||
|
||||
@@ -4,7 +4,7 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
leptos = { path = "../../leptos", features = ["csr", "nightly"] }
|
||||
leptos = { path = "../../leptos" }
|
||||
console_log = "1"
|
||||
log = "0.4"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#![deny(missing_docs)]
|
||||
#![forbid(unsafe_code)]
|
||||
#![cfg_attr(feature = "nightly", feature(fn_traits))]
|
||||
#![cfg_attr(feature = "nightly", feature(unboxed_closures))]
|
||||
#![cfg_attr(not(feature = "stable"), feature(fn_traits))]
|
||||
#![cfg_attr(not(feature = "stable"), feature(unboxed_closures))]
|
||||
|
||||
//! The DOM implementation for `leptos`.
|
||||
|
||||
@@ -33,7 +33,7 @@ pub use html::HtmlElement;
|
||||
use html::{AnyElement, ElementDescriptor};
|
||||
pub use hydration::{HydrationCtx, HydrationKey};
|
||||
use leptos_reactive::Scope;
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
#[cfg(feature = "stable")]
|
||||
use leptos_reactive::{
|
||||
MaybeSignal, Memo, ReadSignal, RwSignal, Signal, SignalGet,
|
||||
};
|
||||
@@ -143,7 +143,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
#[cfg(feature = "stable")]
|
||||
impl<T> IntoView for ReadSignal<T>
|
||||
where
|
||||
T: IntoView + Clone,
|
||||
@@ -156,7 +156,7 @@ where
|
||||
DynChild::new(move || self.get()).into_view(cx)
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
#[cfg(feature = "stable")]
|
||||
impl<T> IntoView for RwSignal<T>
|
||||
where
|
||||
T: IntoView + Clone,
|
||||
@@ -169,7 +169,7 @@ where
|
||||
DynChild::new(move || self.get()).into_view(cx)
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
#[cfg(feature = "stable")]
|
||||
impl<T> IntoView for Memo<T>
|
||||
where
|
||||
T: IntoView + Clone,
|
||||
@@ -182,7 +182,7 @@ where
|
||||
DynChild::new(move || self.get()).into_view(cx)
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
#[cfg(feature = "stable")]
|
||||
impl<T> IntoView for Signal<T>
|
||||
where
|
||||
T: IntoView + Clone,
|
||||
@@ -195,7 +195,7 @@ where
|
||||
DynChild::new(move || self.get()).into_view(cx)
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
#[cfg(feature = "stable")]
|
||||
impl<T> IntoView for MaybeSignal<T>
|
||||
where
|
||||
T: IntoView + Clone,
|
||||
@@ -1125,7 +1125,7 @@ viewable_primitive![
|
||||
];
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "nightly")] {
|
||||
if #[cfg(not(feature = "stable"))] {
|
||||
viewable_primitive! {
|
||||
std::backtrace::Backtrace
|
||||
}
|
||||
|
||||
@@ -154,7 +154,7 @@ impl<T: ElementDescriptor> Clone for NodeRef<T> {
|
||||
impl<T: ElementDescriptor + 'static> Copy for NodeRef<T> {}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "nightly")] {
|
||||
if #[cfg(not(feature = "stable"))] {
|
||||
impl<T: Clone + ElementDescriptor + 'static> FnOnce<()> for NodeRef<T> {
|
||||
type Output = Option<HtmlElement<T>>;
|
||||
|
||||
|
||||
@@ -296,7 +296,7 @@ fn ooo_body_stream_recurse(
|
||||
fragments.chain(resources).chain(
|
||||
futures::stream::once(async move {
|
||||
let pending = cx.pending_fragments();
|
||||
if !pending.is_empty() {
|
||||
if pending.len() > 0 {
|
||||
let fragments = FuturesUnordered::new();
|
||||
let serializers = cx.serialization_resolvers();
|
||||
for (fragment_id, data) in pending {
|
||||
|
||||
@@ -70,7 +70,7 @@ impl ViewMacros {
|
||||
let mut views = Vec::new();
|
||||
for view in visitor.views {
|
||||
let span = view.span();
|
||||
let id = span_to_stable_id(path, span.start().line);
|
||||
let id = span_to_stable_id(path, span);
|
||||
let mut tokens = view.tokens.clone().into_iter();
|
||||
tokens.next(); // cx
|
||||
tokens.next(); // ,
|
||||
@@ -148,11 +148,15 @@ impl<'ast> Visit<'ast> for ViewMacroVisitor<'ast> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn span_to_stable_id(path: impl AsRef<Path>, line: usize) -> String {
|
||||
pub fn span_to_stable_id(
|
||||
path: impl AsRef<Path>,
|
||||
site: proc_macro2::Span,
|
||||
) -> String {
|
||||
let file = path
|
||||
.as_ref()
|
||||
.to_str()
|
||||
.unwrap_or_default()
|
||||
.replace(['/', '\\'], "-");
|
||||
format!("{file}-{line}")
|
||||
let start = site.start();
|
||||
format!("{}-{:?}", file, start.line)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ function patch(json) {
|
||||
try {
|
||||
const views = JSON.parse(json);
|
||||
for (const [id, patches] of views) {
|
||||
console.log("[HOT RELOAD]", id, patches);
|
||||
console.log("[HOT RELOAD]", patches);
|
||||
const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_COMMENT),
|
||||
open = `leptos-view|${id}|open`,
|
||||
close = `leptos-view|${id}|close`;
|
||||
|
||||
@@ -39,9 +39,9 @@ default = ["ssr"]
|
||||
csr = []
|
||||
hydrate = []
|
||||
ssr = []
|
||||
nightly = ["server_fn_macro/nightly"]
|
||||
stable = ["server_fn_macro/stable"]
|
||||
tracing = []
|
||||
|
||||
[package.metadata.cargo-all-features]
|
||||
denylist = ["nightly", "tracing"]
|
||||
denylist = ["stable", "tracing"]
|
||||
skip_feature_sets = [["csr", "hydrate"], ["hydrate", "csr"], ["hydrate", "ssr"]]
|
||||
|
||||
@@ -438,18 +438,15 @@ impl Docs {
|
||||
let mut attrs = attrs
|
||||
.iter()
|
||||
.filter_map(|attr| {
|
||||
let Meta::NameValue(attr) = &attr.meta else {
|
||||
return None;
|
||||
let Meta::NameValue(attr ) = &attr.meta else {
|
||||
return None
|
||||
};
|
||||
if !attr.path.is_ident("doc") {
|
||||
return None;
|
||||
return None
|
||||
}
|
||||
|
||||
let Some(val) = value_to_string(&attr.value) else {
|
||||
abort!(
|
||||
attr,
|
||||
"expected string literal in value of doc comment"
|
||||
);
|
||||
abort!(attr, "expected string literal in value of doc comment");
|
||||
};
|
||||
|
||||
Some((val, attr.path.span()))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#![cfg_attr(feature = "nightly", feature(proc_macro_span))]
|
||||
#![cfg_attr(not(feature = "stable"), feature(proc_macro_span))]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
#[macro_use]
|
||||
@@ -94,7 +94,7 @@ mod template;
|
||||
/// Attributes can take a wide variety of primitive types that can be converted to strings. They can also
|
||||
/// take an `Option`, in which case `Some` sets the attribute and `None` removes the attribute.
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// ```rust
|
||||
/// # use leptos::*;
|
||||
/// # run_scope(create_runtime(), |cx| {
|
||||
/// # if !cfg!(any(feature = "csr", feature = "hydrate")) {
|
||||
@@ -102,11 +102,11 @@ mod template;
|
||||
///
|
||||
/// view! {
|
||||
/// cx,
|
||||
/// // ❌ not like this: `count.get()` returns an `i32`, not a function
|
||||
/// <p>{count.get()}</p>
|
||||
/// // ❌ not like this: `count()` returns an `i32`, not a function
|
||||
/// <p>{count()}</p>
|
||||
/// // ✅ this is good: Leptos sees the function and knows it's a dynamic value
|
||||
/// <p>{move || count.get()}</p>
|
||||
/// // 🔥 with the `nightly` feature, `count` is a function, so `count` itself can be passed directly into the view
|
||||
/// // 🔥 `count` is itself a function, so you can pass it directly (unless you're on `stable`)
|
||||
/// <p>{count}</p>
|
||||
/// }
|
||||
/// # ;
|
||||
@@ -147,9 +147,9 @@ mod template;
|
||||
/// <input
|
||||
/// type="text"
|
||||
/// name="user_name"
|
||||
/// value={move || name.get()} // this only sets the default value!
|
||||
/// prop:value={move || name.get()} // here's how you update values. Sorry, I didn’t invent the DOM.
|
||||
/// on:click=move |ev| set_name.set(event_target_value(&ev)) // `event_target_value` is a useful little Leptos helper
|
||||
/// value={name} // this only sets the default value!
|
||||
/// prop:value={name} // here's how you update values. Sorry, I didn’t invent the DOM.
|
||||
/// on:click=move |ev| set_name(event_target_value(&ev)) // `event_target_value` is a useful little Leptos helper
|
||||
/// />
|
||||
/// }
|
||||
/// # ;
|
||||
@@ -163,7 +163,7 @@ mod template;
|
||||
/// # run_scope(create_runtime(), |cx| {
|
||||
/// # if !cfg!(any(feature = "csr", feature = "hydrate")) {
|
||||
/// let (count, set_count) = create_signal(cx, 2);
|
||||
/// view! { cx, <div class:hidden-div={move || count.get() < 3}>"Now you see me, now you don’t."</div> }
|
||||
/// view! { cx, <div class:hidden-div={move || count() < 3}>"Now you see me, now you don’t."</div> }
|
||||
/// # ;
|
||||
/// # }
|
||||
/// # });
|
||||
@@ -176,7 +176,7 @@ mod template;
|
||||
/// # if !cfg!(any(feature = "csr", feature = "hydrate")) {
|
||||
/// let (count, set_count) = create_signal(cx, 2);
|
||||
/// // `hidden-div-25` is invalid at the moment
|
||||
/// view! { cx, <div class:hidden-div-25={move || count.get() < 3}>"Now you see me, now you don’t."</div> }
|
||||
/// view! { cx, <div class:hidden-div-25={move || count() < 3}>"Now you see me, now you don’t."</div> }
|
||||
/// # ;
|
||||
/// # }
|
||||
/// # });
|
||||
@@ -191,7 +191,7 @@ mod template;
|
||||
/// // this allows you to use CSS frameworks that include complex class names
|
||||
/// view! { cx,
|
||||
/// <div
|
||||
/// class=("is-[this_-_really]-necessary-42", move || count.get() < 3)
|
||||
/// class=("is-[this_-_really]-necessary-42", move || count() < 3)
|
||||
/// >
|
||||
/// "Now you see me, now you don’t."
|
||||
/// </div>
|
||||
@@ -211,9 +211,9 @@ mod template;
|
||||
/// view! { cx,
|
||||
/// <div
|
||||
/// style="position: absolute"
|
||||
/// style:left=move || format!("{}px", x.get())
|
||||
/// style:top=move || format!("{}px", y.get())
|
||||
/// style=("background-color", move || format!("rgb({}, {}, 100)", x.get(), y.get()))
|
||||
/// style:left=move || format!("{}px", x())
|
||||
/// style:top=move || format!("{}px", y())
|
||||
/// style=("background-color", move || format!("rgb({}, {}, 100)", x(), y()))
|
||||
/// >
|
||||
/// "Moves when coordinates change"
|
||||
/// </div>
|
||||
@@ -285,7 +285,7 @@ mod template;
|
||||
///
|
||||
/// // create event handlers for our buttons
|
||||
/// // note that `value` and `set_value` are `Copy`, so it's super easy to move them into closures
|
||||
/// let clear = move |_ev| set_value.set(0);
|
||||
/// let clear = move |_ev| set_value(0);
|
||||
/// let decrement = move |_ev| set_value.update(|value| *value -= 1);
|
||||
/// let increment = move |_ev| set_value.update(|value| *value += 1);
|
||||
///
|
||||
@@ -295,7 +295,7 @@ mod template;
|
||||
/// <div>
|
||||
/// <button on:click=clear>"Clear"</button>
|
||||
/// <button on:click=decrement>"-1"</button>
|
||||
/// <span>"Value: " {move || value.get().to_string()} "!"</span>
|
||||
/// <span>"Value: " {move || value().to_string()} "!"</span>
|
||||
/// <button on:click=increment>"+1"</button>
|
||||
/// </div>
|
||||
/// }
|
||||
@@ -381,10 +381,10 @@ pub fn view(tokens: TokenStream) -> TokenStream {
|
||||
|
||||
fn normalized_call_site(site: proc_macro::Span) -> Option<String> {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(all(debug_assertions, feature = "nightly"))] {
|
||||
if #[cfg(all(debug_assertions, not(feature = "stable")))] {
|
||||
Some(leptos_hot_reload::span_to_stable_id(
|
||||
site.source_file().path(),
|
||||
site.start().line()
|
||||
site.into()
|
||||
))
|
||||
} else {
|
||||
_ = site;
|
||||
@@ -467,7 +467,7 @@ pub fn template(tokens: TokenStream) -> TokenStream {
|
||||
/// // return the user interface, which will be automatically updated
|
||||
/// // when signal values change
|
||||
/// view! { cx,
|
||||
/// <p>"Your name is " {name} " and you are " {move || age.get()} " years old."</p>
|
||||
/// <p>"Your name is " {name} " and you are " {age} " years old."</p>
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
@@ -793,18 +793,15 @@ pub fn slot(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
|
||||
/// If you call a server function from the client (i.e., when the `csr` or `hydrate` features
|
||||
/// are enabled), it will instead make a network request to the server.
|
||||
///
|
||||
/// You can specify one, two, three, or four arguments to the server function:
|
||||
/// You can specify one, two, or three arguments to the server function:
|
||||
/// 1. **Required**: A type name that will be used to identify and register the server function
|
||||
/// (e.g., `MyServerFn`).
|
||||
/// 2. *Optional*: A URL prefix at which the function will be mounted when it’s registered
|
||||
/// (e.g., `"/api"`). Defaults to `"/"`.
|
||||
/// 3. *Optional*: The encoding for the server function (`"Url"`, `"Cbor"`, `"GetJson"`, or `"GetCbor`". See **Server Function Encodings** below.)
|
||||
/// 4. *Optional*: A specific endpoint path to be used in the URL. (By default, a unique path will be generated.)
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// // will generate a server function at `/api-prefix/hello`
|
||||
/// #[server(MyServerFnType, "/api-prefix", "Url", "hello")]
|
||||
/// ```
|
||||
/// 3. *Optional*: either `"Cbor"` (specifying that it should use the binary `cbor` format for
|
||||
/// serialization) or `"Url"` (specifying that it should be use a URL-encoded form-data string).
|
||||
/// Defaults to `"Url"`. If you want to use this server function to power a `<form>` that will
|
||||
/// work without WebAssembly, the encoding must be `"Url"`.
|
||||
///
|
||||
/// The server function itself can take any number of arguments, each of which should be serializable
|
||||
/// and deserializable with `serde`. Optionally, its first argument can be a Leptos
|
||||
@@ -824,16 +821,17 @@ pub fn slot(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
|
||||
/// ```
|
||||
///
|
||||
/// Note the following:
|
||||
/// - You must **register** the server function by calling `T::register()` somewhere in your main function.
|
||||
/// - **Server functions must be `async`.** Even if the work being done inside the function body
|
||||
/// can run synchronously on the server, from the client’s perspective it involves an asynchronous
|
||||
/// function call.
|
||||
/// - **Server functions must return `Result<T, ServerFnError>`.** Even if the work being done
|
||||
/// inside the function body can’t fail, the processes of serialization/deserialization and the
|
||||
/// network call are fallible.
|
||||
/// - **Return types must implement [`Serialize`](https://docs.rs/serde/latest/serde/trait.Serialize.html).**
|
||||
/// - **Return types must be [Serializable](https://docs.rs/leptos/latest/leptos/trait.Serializable.html).**
|
||||
/// This should be fairly obvious: we have to serialize arguments to send them to the server, and we
|
||||
/// need to deserialize the result to return it to the client.
|
||||
/// - **Arguments must implement [`Serialize`](https://docs.rs/serde/latest/serde/trait.Serialize.html)
|
||||
/// - **Arguments must be implement [`Serialize`](https://docs.rs/serde/latest/serde/trait.Serialize.html)
|
||||
/// and [`DeserializeOwned`](https://docs.rs/serde/latest/serde/de/trait.DeserializeOwned.html).**
|
||||
/// They are serialized as an `application/x-www-form-urlencoded`
|
||||
/// form data using [`serde_qs`](https://docs.rs/serde_qs/latest/serde_qs/) or as `application/cbor`
|
||||
@@ -842,9 +840,6 @@ pub fn slot(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
|
||||
/// - **The `Scope` comes from the server.** Optionally, the first argument of a server function
|
||||
/// can be a Leptos `Scope`. This scope can be used to inject dependencies like the HTTP request
|
||||
/// or response or other server-only dependencies, but it does *not* have access to reactive state that exists in the client.
|
||||
/// - Your server must be ready to handle the server functions at the API prefix you list. The easiest way to do this
|
||||
/// is to use the `handle_server_fns` function from [`leptos_actix`](https://docs.rs/leptos_actix/latest/leptos_actix/fn.handle_server_fns.html)
|
||||
/// or [`leptos_axum`](https://docs.rs/leptos_axum/latest/leptos_axum/fn.handle_server_fns.html).
|
||||
///
|
||||
/// ## Server Function Encodings
|
||||
///
|
||||
|
||||
@@ -581,14 +581,7 @@ fn attribute_to_tokens_ssr<'a>(
|
||||
|| name.strip_prefix("style:").is_some()
|
||||
{
|
||||
// ignore props for SSR
|
||||
// ignore classes and styles: we'll handle these separately
|
||||
if name.starts_with("prop:") {
|
||||
let value = attr.value();
|
||||
exprs_for_compiler.push(quote! {
|
||||
#[allow(unused_braces)]
|
||||
{ _ = #value; }
|
||||
});
|
||||
}
|
||||
// ignore classes and sdtyles: we'll handle these separately
|
||||
} else if name == "inner_html" {
|
||||
return attr.value();
|
||||
} else {
|
||||
@@ -613,9 +606,7 @@ fn attribute_to_tokens_ssr<'a>(
|
||||
if let Some(value) = value_to_string(value) {
|
||||
template.push_str(&name);
|
||||
template.push_str("=\"");
|
||||
template.push_str(&html_escape::encode_quoted_attribute(
|
||||
&value,
|
||||
));
|
||||
template.push_str(&value);
|
||||
template.push('"');
|
||||
} else {
|
||||
template.push_str("{}");
|
||||
@@ -738,9 +729,7 @@ fn set_class_attribute_ssr(
|
||||
{
|
||||
template.push_str(" class=\"");
|
||||
|
||||
template.push_str(&html_escape::encode_quoted_attribute(
|
||||
&static_class_attr,
|
||||
));
|
||||
template.push_str(&static_class_attr);
|
||||
|
||||
for (_span, value) in dyn_class_attr {
|
||||
if let Some(value) = value {
|
||||
@@ -1374,8 +1363,8 @@ pub(crate) fn parse_event_name(name: &str) -> (TokenStream, bool, bool) {
|
||||
let is_custom = event_type == "Custom";
|
||||
|
||||
let Ok(event_type) = event_type.parse::<TokenStream>() else {
|
||||
abort!(event_type, "couldn't parse event name");
|
||||
};
|
||||
abort!(event_type, "couldn't parse event name");
|
||||
};
|
||||
|
||||
let event_type = if is_custom {
|
||||
quote! { Custom::new(#name) }
|
||||
@@ -1404,10 +1393,7 @@ pub(crate) fn slot_to_tokens(
|
||||
let span = node.name().span();
|
||||
|
||||
let Some(parent_slots) = parent_slots else {
|
||||
proc_macro_error::emit_error!(
|
||||
span,
|
||||
"slots cannot be used inside HTML elements"
|
||||
);
|
||||
proc_macro_error::emit_error!(span, "slots cannot be used inside HTML elements");
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
@@ -68,14 +68,14 @@ hydrate = [
|
||||
"dep:web-sys",
|
||||
]
|
||||
ssr = ["dep:tokio"]
|
||||
nightly = []
|
||||
stable = []
|
||||
serde = []
|
||||
serde-lite = ["dep:serde-lite"]
|
||||
miniserde = ["dep:miniserde"]
|
||||
rkyv = ["dep:rkyv", "dep:bytecheck"]
|
||||
|
||||
[package.metadata.cargo-all-features]
|
||||
denylist = ["nightly"]
|
||||
denylist = ["stable"]
|
||||
skip_feature_sets = [
|
||||
[
|
||||
"csr",
|
||||
|
||||
@@ -29,20 +29,20 @@ use std::{any::Any, cell::RefCell, marker::PhantomData, rc::Rc};
|
||||
/// // ✅ use effects to interact between reactive state and the outside world
|
||||
/// create_effect(cx, move |_| {
|
||||
/// // immediately prints "Value: 0" and subscribes to `a`
|
||||
/// log::debug!("Value: {}", a.get());
|
||||
/// log::debug!("Value: {}", a());
|
||||
/// });
|
||||
///
|
||||
/// set_a.set(1);
|
||||
/// set_a(1);
|
||||
/// // ✅ because it's subscribed to `a`, the effect reruns and prints "Value: 1"
|
||||
///
|
||||
/// // ❌ don't use effects to synchronize state within the reactive system
|
||||
/// create_effect(cx, move |_| {
|
||||
/// // this technically works but can cause unnecessary re-renders
|
||||
/// // and easily lead to problems like infinite loops
|
||||
/// set_b.set(a.get() + 1);
|
||||
/// set_b(a() + 1);
|
||||
/// });
|
||||
/// # if !cfg!(feature = "ssr") {
|
||||
/// # assert_eq!(b.get(), 2);
|
||||
/// # assert_eq!(b(), 2);
|
||||
/// # }
|
||||
/// # }).dispose();
|
||||
/// ```
|
||||
@@ -88,19 +88,19 @@ where
|
||||
/// // ✅ use effects to interact between reactive state and the outside world
|
||||
/// create_isomorphic_effect(cx, move |_| {
|
||||
/// // immediately prints "Value: 0" and subscribes to `a`
|
||||
/// log::debug!("Value: {}", a.get());
|
||||
/// log::debug!("Value: {}", a());
|
||||
/// });
|
||||
///
|
||||
/// set_a.set(1);
|
||||
/// set_a(1);
|
||||
/// // ✅ because it's subscribed to `a`, the effect reruns and prints "Value: 1"
|
||||
///
|
||||
/// // ❌ don't use effects to synchronize state within the reactive system
|
||||
/// create_isomorphic_effect(cx, move |_| {
|
||||
/// // this technically works but can cause unnecessary re-renders
|
||||
/// // and easily lead to problems like infinite loops
|
||||
/// set_b.set(a.get() + 1);
|
||||
/// set_b(a() + 1);
|
||||
/// });
|
||||
/// # assert_eq!(b.get(), 2);
|
||||
/// # assert_eq!(b(), 2);
|
||||
/// # }).dispose();
|
||||
#[cfg_attr(
|
||||
any(debug_assertions, feature="ssr"),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#![deny(missing_docs)]
|
||||
#![cfg_attr(feature = "nightly", feature(fn_traits))]
|
||||
#![cfg_attr(feature = "nightly", feature(unboxed_closures))]
|
||||
#![cfg_attr(feature = "nightly", feature(type_name_of_val))]
|
||||
#![cfg_attr(not(feature = "stable"), feature(fn_traits))]
|
||||
#![cfg_attr(not(feature = "stable"), feature(unboxed_closures))]
|
||||
#![cfg_attr(not(feature = "stable"), feature(type_name_of_val))]
|
||||
|
||||
//! The reactive system for the [Leptos](https://docs.rs/leptos/latest/leptos/) Web framework.
|
||||
//!
|
||||
@@ -44,28 +44,25 @@
|
||||
//! let (count, set_count) = create_signal(cx, 0);
|
||||
//!
|
||||
//! // calling the getter gets the value
|
||||
//! // can be `count()` on nightly
|
||||
//! assert_eq!(count.get(), 0);
|
||||
//! assert_eq!(count(), 0);
|
||||
//! // calling the setter sets the value
|
||||
//! // can be `set_count(1)` on nightly
|
||||
//! set_count.set(1);
|
||||
//! set_count(1);
|
||||
//! // or we can mutate it in place with update()
|
||||
//! set_count.update(|n| *n += 1);
|
||||
//!
|
||||
//! // a derived signal: a plain closure that relies on the signal
|
||||
//! // the closure will run whenever we *access* double_count()
|
||||
//! let double_count = move || count.get() * 2;
|
||||
//! let double_count = move || count() * 2;
|
||||
//! assert_eq!(double_count(), 4);
|
||||
//!
|
||||
//! // a memo: subscribes to the signal
|
||||
//! // the closure will run only when count changes
|
||||
//! let memoized_triple_count = create_memo(cx, move |_| count.get() * 3);
|
||||
//! // can be `memoized_triple_count()` on nightly
|
||||
//! assert_eq!(memoized_triple_count.get(), 6);
|
||||
//! let memoized_triple_count = create_memo(cx, move |_| count() * 3);
|
||||
//! assert_eq!(memoized_triple_count(), 6);
|
||||
//!
|
||||
//! // this effect will run whenever `count` changes
|
||||
//! // this effect will run whenever count() changes
|
||||
//! create_effect(cx, move |_| {
|
||||
//! println!("Count = {}", count.get());
|
||||
//! println!("Count = {}", count());
|
||||
//! });
|
||||
//! });
|
||||
//! ```
|
||||
|
||||
@@ -40,12 +40,12 @@ use std::{any::Any, cell::RefCell, fmt, marker::PhantomData, rc::Rc};
|
||||
/// let (value, set_value) = create_signal(cx, 0);
|
||||
///
|
||||
/// // 🆗 we could create a derived signal with a simple function
|
||||
/// let double_value = move || value.get() * 2;
|
||||
/// set_value.set(2);
|
||||
/// let double_value = move || value() * 2;
|
||||
/// set_value(2);
|
||||
/// assert_eq!(double_value(), 4);
|
||||
///
|
||||
/// // but imagine the computation is really expensive
|
||||
/// let expensive = move || really_expensive_computation(value.get()); // lazy: doesn't run until called
|
||||
/// let expensive = move || really_expensive_computation(value()); // lazy: doesn't run until called
|
||||
/// create_effect(cx, move |_| {
|
||||
/// // 🆗 run #1: calls `really_expensive_computation` the first time
|
||||
/// log::debug!("expensive = {}", expensive());
|
||||
@@ -58,15 +58,14 @@ use std::{any::Any, cell::RefCell, fmt, marker::PhantomData, rc::Rc};
|
||||
///
|
||||
/// // instead, we create a memo
|
||||
/// // 🆗 run #1: the calculation runs once immediately
|
||||
/// let memoized = create_memo(cx, move |_| really_expensive_computation(value.get()));
|
||||
/// let memoized = create_memo(cx, move |_| really_expensive_computation(value()));
|
||||
/// create_effect(cx, move |_| {
|
||||
/// // 🆗 reads the current value of the memo
|
||||
/// // can be `memoized()` on nightly
|
||||
/// log::debug!("memoized = {}", memoized.get());
|
||||
/// // 🆗 reads the current value of the memo
|
||||
/// log::debug!("memoized = {}", memoized());
|
||||
/// });
|
||||
/// create_effect(cx, move |_| {
|
||||
/// // ✅ reads the current value **without re-running the calculation**
|
||||
/// let value = memoized.get();
|
||||
/// let value = memoized();
|
||||
/// // do something else...
|
||||
/// });
|
||||
/// # }).dispose();
|
||||
@@ -132,12 +131,12 @@ where
|
||||
/// let (value, set_value) = create_signal(cx, 0);
|
||||
///
|
||||
/// // 🆗 we could create a derived signal with a simple function
|
||||
/// let double_value = move || value.get() * 2;
|
||||
/// set_value.set(2);
|
||||
/// let double_value = move || value() * 2;
|
||||
/// set_value(2);
|
||||
/// assert_eq!(double_value(), 4);
|
||||
///
|
||||
/// // but imagine the computation is really expensive
|
||||
/// let expensive = move || really_expensive_computation(value.get()); // lazy: doesn't run until called
|
||||
/// let expensive = move || really_expensive_computation(value()); // lazy: doesn't run until called
|
||||
/// create_effect(cx, move |_| {
|
||||
/// // 🆗 run #1: calls `really_expensive_computation` the first time
|
||||
/// log::debug!("expensive = {}", expensive());
|
||||
@@ -150,15 +149,14 @@ where
|
||||
///
|
||||
/// // instead, we create a memo
|
||||
/// // 🆗 run #1: the calculation runs once immediately
|
||||
/// let memoized = create_memo(cx, move |_| really_expensive_computation(value.get()));
|
||||
/// let memoized = create_memo(cx, move |_| really_expensive_computation(value()));
|
||||
/// create_effect(cx, move |_| {
|
||||
/// // 🆗 reads the current value of the memo
|
||||
/// log::debug!("memoized = {}", memoized.get());
|
||||
/// log::debug!("memoized = {}", memoized());
|
||||
/// });
|
||||
/// create_effect(cx, move |_| {
|
||||
/// // ✅ reads the current value **without re-running the calculation**
|
||||
/// // can be `memoized()` on nightly
|
||||
/// let value = memoized.get();
|
||||
/// let value = memoized();
|
||||
/// // do something else...
|
||||
/// });
|
||||
/// # }).dispose();
|
||||
@@ -329,14 +327,13 @@ impl<T> SignalWithUntracked<T> for Memo<T> {
|
||||
/// # use leptos_reactive::*;
|
||||
/// # create_scope(create_runtime(), |cx| {
|
||||
/// let (count, set_count) = create_signal(cx, 0);
|
||||
/// let double_count = create_memo(cx, move |_| count.get() * 2);
|
||||
/// let double_count = create_memo(cx, move |_| count() * 2);
|
||||
///
|
||||
/// assert_eq!(double_count.get(), 0);
|
||||
/// set_count.set(1);
|
||||
/// set_count(1);
|
||||
///
|
||||
/// // can be `double_count()` on nightly
|
||||
/// // assert_eq!(double_count(), 2);
|
||||
/// assert_eq!(double_count.get(), 2);
|
||||
/// // double_count() is shorthand for double_count.get()
|
||||
/// assert_eq!(double_count(), 2);
|
||||
/// # }).dispose();
|
||||
/// #
|
||||
/// ```
|
||||
|
||||
@@ -51,7 +51,7 @@ use std::{
|
||||
/// # // `csr`, `hydrate`, and `ssr` all have issues here
|
||||
/// # // because we're not running in a browser or in Tokio. Let's just ignore it.
|
||||
/// # if false {
|
||||
/// let cats = create_resource(cx, move || how_many_cats.get(), fetch_cat_picture_urls);
|
||||
/// let cats = create_resource(cx, how_many_cats, fetch_cat_picture_urls);
|
||||
///
|
||||
/// // when we read the signal, it contains either
|
||||
/// // 1) None (if the Future isn't ready yet) or
|
||||
@@ -59,7 +59,7 @@ use std::{
|
||||
/// assert_eq!(cats.read(cx), Some(vec!["1".to_string()]));
|
||||
///
|
||||
/// // when the signal's value changes, the `Resource` will generate and run a new `Future`
|
||||
/// set_how_many_cats.set(2);
|
||||
/// set_how_many_cats(2);
|
||||
/// assert_eq!(cats.read(cx), Some(vec!["2".to_string()]));
|
||||
/// # }
|
||||
/// # }).dispose();
|
||||
@@ -696,7 +696,7 @@ impl<S, T> SignalSet<T> for Resource<S, T> {
|
||||
/// # // `csr`, `hydrate`, and `ssr` all have issues here
|
||||
/// # // because we're not running in a browser or in Tokio. Let's just ignore it.
|
||||
/// # if false {
|
||||
/// let cats = create_resource(cx, move || how_many_cats.get(), fetch_cat_picture_urls);
|
||||
/// let cats = create_resource(cx, how_many_cats, fetch_cat_picture_urls);
|
||||
///
|
||||
/// // when we read the signal, it contains either
|
||||
/// // 1) None (if the Future isn't ready yet) or
|
||||
@@ -704,7 +704,7 @@ impl<S, T> SignalSet<T> for Resource<S, T> {
|
||||
/// assert_eq!(cats.read(cx), Some(vec!["1".to_string()]));
|
||||
///
|
||||
/// // when the signal's value changes, the `Resource` will generate and run a new `Future`
|
||||
/// set_how_many_cats.set(2);
|
||||
/// set_how_many_cats(2);
|
||||
/// assert_eq!(cats.read(cx), Some(vec!["2".to_string()]));
|
||||
/// # }
|
||||
/// # }).dispose();
|
||||
|
||||
@@ -189,17 +189,17 @@ impl Scope {
|
||||
/// let (b, set_b) = create_signal(cx, 0);
|
||||
/// let c = create_memo(cx, move |_| {
|
||||
/// // this memo will *only* update when `a` changes
|
||||
/// a.get() + cx.untrack(move || b.get())
|
||||
/// a() + cx.untrack(move || b())
|
||||
/// });
|
||||
///
|
||||
/// assert_eq!(c.get(), 0);
|
||||
/// set_a.set(1);
|
||||
/// assert_eq!(c.get(), 1);
|
||||
/// set_b.set(1);
|
||||
/// assert_eq!(c(), 0);
|
||||
/// set_a(1);
|
||||
/// assert_eq!(c(), 1);
|
||||
/// set_b(1);
|
||||
/// // hasn't updated, because we untracked before reading b
|
||||
/// assert_eq!(c.get(), 1);
|
||||
/// set_a.set(2);
|
||||
/// assert_eq!(c.get(), 3);
|
||||
/// assert_eq!(c(), 1);
|
||||
/// set_a(2);
|
||||
/// assert_eq!(c(), 3);
|
||||
///
|
||||
/// # });
|
||||
/// ```
|
||||
|
||||
@@ -19,7 +19,7 @@ use std::{cell::RefCell, collections::HashMap, hash::Hash, rc::Rc};
|
||||
/// # use std::cell::RefCell;
|
||||
/// # create_scope(create_runtime(), |cx| {
|
||||
/// let (a, set_a) = create_signal(cx, 0);
|
||||
/// let is_selected = create_selector(cx, move || a.get());
|
||||
/// let is_selected = create_selector(cx, a);
|
||||
/// let total_notifications = Rc::new(RefCell::new(0));
|
||||
/// let not = Rc::clone(&total_notifications);
|
||||
/// create_isomorphic_effect(cx, {
|
||||
@@ -33,13 +33,13 @@ use std::{cell::RefCell, collections::HashMap, hash::Hash, rc::Rc};
|
||||
///
|
||||
/// assert_eq!(is_selected(5), false);
|
||||
/// assert_eq!(*total_notifications.borrow(), 0);
|
||||
/// set_a.set(5);
|
||||
/// set_a(5);
|
||||
/// assert_eq!(is_selected(5), true);
|
||||
/// assert_eq!(*total_notifications.borrow(), 1);
|
||||
/// set_a.set(5);
|
||||
/// set_a(5);
|
||||
/// assert_eq!(is_selected(5), true);
|
||||
/// assert_eq!(*total_notifications.borrow(), 1);
|
||||
/// set_a.set(4);
|
||||
/// set_a(4);
|
||||
/// assert_eq!(is_selected(5), false);
|
||||
/// # })
|
||||
/// # .dispose()
|
||||
|
||||
@@ -23,7 +23,7 @@ use thiserror::Error;
|
||||
macro_rules! impl_get_fn_traits {
|
||||
($($ty:ident $(($method_name:ident))?),*) => {
|
||||
$(
|
||||
#[cfg(feature = "nightly")]
|
||||
#[cfg(not(feature = "stable"))]
|
||||
impl<T: Clone> FnOnce<()> for $ty<T> {
|
||||
type Output = T;
|
||||
|
||||
@@ -33,7 +33,7 @@ macro_rules! impl_get_fn_traits {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
#[cfg(not(feature = "stable"))]
|
||||
impl<T: Clone> FnMut<()> for $ty<T> {
|
||||
#[inline(always)]
|
||||
extern "rust-call" fn call_mut(&mut self, _args: ()) -> Self::Output {
|
||||
@@ -41,7 +41,7 @@ macro_rules! impl_get_fn_traits {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
#[cfg(not(feature = "stable"))]
|
||||
impl<T: Clone> Fn<()> for $ty<T> {
|
||||
#[inline(always)]
|
||||
extern "rust-call" fn call(&self, _args: ()) -> Self::Output {
|
||||
@@ -61,7 +61,7 @@ macro_rules! impl_get_fn_traits {
|
||||
macro_rules! impl_set_fn_traits {
|
||||
($($ty:ident $($method_name:ident)?),*) => {
|
||||
$(
|
||||
#[cfg(feature = "nightly")]
|
||||
#[cfg(not(feature = "stable"))]
|
||||
impl<T> FnOnce<(T,)> for $ty<T> {
|
||||
type Output = ();
|
||||
|
||||
@@ -71,7 +71,7 @@ macro_rules! impl_set_fn_traits {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
#[cfg(not(feature = "stable"))]
|
||||
impl<T> FnMut<(T,)> for $ty<T> {
|
||||
#[inline(always)]
|
||||
extern "rust-call" fn call_mut(&mut self, args: (T,)) -> Self::Output {
|
||||
@@ -79,7 +79,7 @@ macro_rules! impl_set_fn_traits {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
#[cfg(not(feature = "stable"))]
|
||||
impl<T> Fn<(T,)> for $ty<T> {
|
||||
#[inline(always)]
|
||||
extern "rust-call" fn call(&self, args: (T,)) -> Self::Output {
|
||||
@@ -290,26 +290,24 @@ pub trait SignalDispose {
|
||||
/// let (count, set_count) = create_signal(cx, 0);
|
||||
///
|
||||
/// // ✅ calling the getter clones and returns the value
|
||||
/// // this can be `count()` on nightly
|
||||
/// assert_eq!(count.get(), 0);
|
||||
/// assert_eq!(count(), 0);
|
||||
///
|
||||
/// // ✅ calling the setter sets the value
|
||||
/// // this can be `set_count(1)` on nightly
|
||||
/// set_count.set(1);
|
||||
/// assert_eq!(count.get(), 1);
|
||||
/// set_count(1);
|
||||
/// assert_eq!(count(), 1);
|
||||
///
|
||||
/// // ❌ you could call the getter within the setter
|
||||
/// // set_count.set(count.get() + 1);
|
||||
/// // set_count(count() + 1);
|
||||
///
|
||||
/// // ✅ however it's more efficient to use .update() and mutate the value in place
|
||||
/// set_count.update(|count: &mut i32| *count += 1);
|
||||
/// assert_eq!(count.get(), 2);
|
||||
/// assert_eq!(count(), 2);
|
||||
///
|
||||
/// // ✅ you can create "derived signals" with a Fn() -> T interface
|
||||
/// let double_count = move || count.get() * 2; // signals are `Copy` so you can `move` them anywhere
|
||||
/// set_count.set(0);
|
||||
/// // ✅ you can create "derived signals" with the same Fn() -> T interface
|
||||
/// let double_count = move || count() * 2; // signals are `Copy` so you can `move` them anywhere
|
||||
/// set_count(0);
|
||||
/// assert_eq!(double_count(), 0);
|
||||
/// set_count.set(1);
|
||||
/// set_count(1);
|
||||
/// assert_eq!(double_count(), 2);
|
||||
/// # }).dispose();
|
||||
/// #
|
||||
@@ -449,24 +447,24 @@ pub fn create_signal_from_stream<T>(
|
||||
/// let (count, set_count) = create_signal(cx, 0);
|
||||
///
|
||||
/// // ✅ calling the getter clones and returns the value
|
||||
/// assert_eq!(count.get(), 0);
|
||||
/// assert_eq!(count(), 0);
|
||||
///
|
||||
/// // ✅ calling the setter sets the value
|
||||
/// set_count.set(1); // `set_count(1)` on nightly
|
||||
/// assert_eq!(count.get(), 1);
|
||||
/// set_count(1);
|
||||
/// assert_eq!(count(), 1);
|
||||
///
|
||||
/// // ❌ you could call the getter within the setter
|
||||
/// // set_count.set(count.get() + 1);
|
||||
/// // set_count(count() + 1);
|
||||
///
|
||||
/// // ✅ however it's more efficient to use .update() and mutate the value in place
|
||||
/// set_count.update(|count: &mut i32| *count += 1);
|
||||
/// assert_eq!(count.get(), 2);
|
||||
/// assert_eq!(count(), 2);
|
||||
///
|
||||
/// // ✅ you can create "derived signals" with the same Fn() -> T interface
|
||||
/// let double_count = move || count.get() * 2; // signals are `Copy` so you can `move` them anywhere
|
||||
/// set_count.set(0);
|
||||
/// let double_count = move || count() * 2; // signals are `Copy` so you can `move` them anywhere
|
||||
/// set_count(0);
|
||||
/// assert_eq!(double_count(), 0);
|
||||
/// set_count.set(1);
|
||||
/// set_count(1);
|
||||
/// assert_eq!(double_count(), 2);
|
||||
/// # }).dispose();
|
||||
/// #
|
||||
@@ -587,13 +585,13 @@ impl<T> SignalWithUntracked<T> for ReadSignal<T> {
|
||||
/// let (name, set_name) = create_signal(cx, "Alice".to_string());
|
||||
///
|
||||
/// // ❌ unnecessarily clones the string
|
||||
/// let first_char = move || name.get().chars().next().unwrap();
|
||||
/// let first_char = move || name().chars().next().unwrap();
|
||||
/// assert_eq!(first_char(), 'A');
|
||||
///
|
||||
/// // ✅ gets the first char without cloning the `String`
|
||||
/// let first_char = move || name.with(|n| n.chars().next().unwrap());
|
||||
/// assert_eq!(first_char(), 'A');
|
||||
/// set_name.set("Bob".to_string());
|
||||
/// set_name("Bob".to_string());
|
||||
/// assert_eq!(first_char(), 'B');
|
||||
/// # });
|
||||
/// ```
|
||||
@@ -664,8 +662,8 @@ impl<T> SignalWith<T> for ReadSignal<T> {
|
||||
///
|
||||
/// assert_eq!(count.get(), 0);
|
||||
///
|
||||
/// // count() is shorthand for count.get() on `nightly`
|
||||
/// // assert_eq!(count.get(), 0);
|
||||
/// // count() is shorthand for count.get()
|
||||
/// assert_eq!(count(), 0);
|
||||
/// # });
|
||||
/// ```
|
||||
impl<T: Clone> SignalGet<T> for ReadSignal<T> {
|
||||
@@ -851,16 +849,15 @@ impl<T> Hash for ReadSignal<T> {
|
||||
/// let (count, set_count) = create_signal(cx, 0);
|
||||
///
|
||||
/// // ✅ calling the setter sets the value
|
||||
/// // `set_count(1)` on nightly
|
||||
/// set_count.set(1);
|
||||
/// assert_eq!(count.get(), 1);
|
||||
/// set_count(1);
|
||||
/// assert_eq!(count(), 1);
|
||||
///
|
||||
/// // ❌ you could call the getter within the setter
|
||||
/// // set_count.set(count.get() + 1);
|
||||
/// // set_count(count() + 1);
|
||||
///
|
||||
/// // ✅ however it's more efficient to use .update() and mutate the value in place
|
||||
/// set_count.update(|count: &mut i32| *count += 1);
|
||||
/// assert_eq!(count.get(), 2);
|
||||
/// assert_eq!(count(), 2);
|
||||
/// # }).dispose();
|
||||
/// #
|
||||
/// ```
|
||||
@@ -955,13 +952,13 @@ impl<T> SignalUpdateUntracked<T> for WriteSignal<T> {
|
||||
/// let (count, set_count) = create_signal(cx, 0);
|
||||
///
|
||||
/// // notifies subscribers
|
||||
/// set_count.update(|n| *n = 1); // it's easier just to call set_count.set(1), though!
|
||||
/// assert_eq!(count.get(), 1);
|
||||
/// set_count.update(|n| *n = 1); // it's easier just to call set_count(1), though!
|
||||
/// assert_eq!(count(), 1);
|
||||
///
|
||||
/// // you can include arbitrary logic in this update function
|
||||
/// // also notifies subscribers, even though the value hasn't changed
|
||||
/// set_count.update(|n| if *n > 3 { *n += 1 });
|
||||
/// assert_eq!(count.get(), 1);
|
||||
/// assert_eq!(count(), 1);
|
||||
/// # }).dispose();
|
||||
/// ```
|
||||
impl<T> SignalUpdate<T> for WriteSignal<T> {
|
||||
@@ -1015,13 +1012,13 @@ impl<T> SignalUpdate<T> for WriteSignal<T> {
|
||||
/// let (count, set_count) = create_signal(cx, 0);
|
||||
///
|
||||
/// // notifies subscribers
|
||||
/// set_count.update(|n| *n = 1); // it's easier just to call set_count.set(1), though!
|
||||
/// assert_eq!(count.get(), 1);
|
||||
/// set_count.update(|n| *n = 1); // it's easier just to call set_count(1), though!
|
||||
/// assert_eq!(count(), 1);
|
||||
///
|
||||
/// // you can include arbitrary logic in this update function
|
||||
/// // also notifies subscribers, even though the value hasn't changed
|
||||
/// set_count.update(|n| if *n > 3 { *n += 1 });
|
||||
/// assert_eq!(count.get(), 1);
|
||||
/// assert_eq!(count(), 1);
|
||||
/// # }).dispose();
|
||||
/// ```
|
||||
impl<T> SignalSet<T> for WriteSignal<T> {
|
||||
@@ -1116,14 +1113,14 @@ impl<T> Hash for WriteSignal<T> {
|
||||
///
|
||||
/// // ✅ set the value
|
||||
/// count.set(1);
|
||||
/// assert_eq!(count.get(), 1);
|
||||
/// assert_eq!(count(), 1);
|
||||
///
|
||||
/// // ❌ you can call the getter within the setter
|
||||
/// // count.set(count.get() + 1);
|
||||
///
|
||||
/// // ✅ however, it's more efficient to use .update() and mutate the value in place
|
||||
/// count.update(|count: &mut i32| *count += 1);
|
||||
/// assert_eq!(count.get(), 2);
|
||||
/// assert_eq!(count(), 2);
|
||||
/// # }).dispose();
|
||||
/// #
|
||||
/// ```
|
||||
@@ -1176,14 +1173,14 @@ pub fn create_rw_signal<T>(cx: Scope, value: T) -> RwSignal<T> {
|
||||
///
|
||||
/// // ✅ set the value
|
||||
/// count.set(1);
|
||||
/// assert_eq!(count.get(), 1);
|
||||
/// assert_eq!(count(), 1);
|
||||
///
|
||||
/// // ❌ you can call the getter within the setter
|
||||
/// // count.set(count.get() + 1);
|
||||
///
|
||||
/// // ✅ however, it's more efficient to use .update() and mutate the value in place
|
||||
/// count.update(|count: &mut i32| *count += 1);
|
||||
/// assert_eq!(count.get(), 2);
|
||||
/// assert_eq!(count(), 2);
|
||||
/// # }).dispose();
|
||||
/// #
|
||||
/// ```
|
||||
@@ -1416,7 +1413,7 @@ impl<T> SignalUpdateUntracked<T> for RwSignal<T> {
|
||||
/// let name = create_rw_signal(cx, "Alice".to_string());
|
||||
///
|
||||
/// // ❌ unnecessarily clones the string
|
||||
/// let first_char = move || name.get().chars().next().unwrap();
|
||||
/// let first_char = move || name().chars().next().unwrap();
|
||||
/// assert_eq!(first_char(), 'A');
|
||||
///
|
||||
/// // ✅ gets the first char without cloning the `String`
|
||||
@@ -1494,8 +1491,8 @@ impl<T> SignalWith<T> for RwSignal<T> {
|
||||
///
|
||||
/// assert_eq!(count.get(), 0);
|
||||
///
|
||||
/// // count() is shorthand for count.get() on `nightly`
|
||||
/// // assert_eq!(count(), 0);
|
||||
/// // count() is shorthand for count.get()
|
||||
/// assert_eq!(count(), 0);
|
||||
/// # }).dispose();
|
||||
/// #
|
||||
/// ```
|
||||
@@ -1566,8 +1563,8 @@ impl<T: Clone> SignalGet<T> for RwSignal<T> {
|
||||
/// let count = create_rw_signal(cx, 0);
|
||||
///
|
||||
/// // notifies subscribers
|
||||
/// count.update(|n| *n = 1); // it's easier just to call set_count.set(1), though!
|
||||
/// assert_eq!(count.get(), 1);
|
||||
/// count.update(|n| *n = 1); // it's easier just to call set_count(1), though!
|
||||
/// assert_eq!(count(), 1);
|
||||
///
|
||||
/// // you can include arbitrary logic in this update function
|
||||
/// // also notifies subscribers, even though the value hasn't changed
|
||||
@@ -1576,7 +1573,7 @@ impl<T: Clone> SignalGet<T> for RwSignal<T> {
|
||||
/// *n += 1
|
||||
/// }
|
||||
/// });
|
||||
/// assert_eq!(count.get(), 1);
|
||||
/// assert_eq!(count(), 1);
|
||||
/// # }).dispose();
|
||||
/// ```
|
||||
impl<T> SignalUpdate<T> for RwSignal<T> {
|
||||
@@ -1629,9 +1626,9 @@ impl<T> SignalUpdate<T> for RwSignal<T> {
|
||||
/// # create_scope(create_runtime(), |cx| {
|
||||
/// let count = create_rw_signal(cx, 0);
|
||||
///
|
||||
/// assert_eq!(count.get(), 0);
|
||||
/// assert_eq!(count(), 0);
|
||||
/// count.set(1);
|
||||
/// assert_eq!(count.get(), 1);
|
||||
/// assert_eq!(count(), 1);
|
||||
/// # }).dispose();
|
||||
/// ```
|
||||
impl<T> SignalSet<T> for RwSignal<T> {
|
||||
@@ -1709,11 +1706,11 @@ impl<T> RwSignal<T> {
|
||||
/// # create_scope(create_runtime(), |cx| {
|
||||
/// let count = create_rw_signal(cx, 0);
|
||||
/// let read_count = count.read_only();
|
||||
/// assert_eq!(count.get(), 0);
|
||||
/// assert_eq!(read_count.get(), 0);
|
||||
/// assert_eq!(count(), 0);
|
||||
/// assert_eq!(read_count(), 0);
|
||||
/// count.set(1);
|
||||
/// assert_eq!(count.get(), 1);
|
||||
/// assert_eq!(read_count.get(), 1);
|
||||
/// assert_eq!(count(), 1);
|
||||
/// assert_eq!(read_count(), 1);
|
||||
/// # }).dispose();
|
||||
/// ```
|
||||
#[cfg_attr(
|
||||
@@ -1749,9 +1746,9 @@ impl<T> RwSignal<T> {
|
||||
/// # create_scope(create_runtime(), |cx| {
|
||||
/// let count = create_rw_signal(cx, 0);
|
||||
/// let set_count = count.write_only();
|
||||
/// assert_eq!(count.get(), 0);
|
||||
/// set_count.set(1);
|
||||
/// assert_eq!(count.get(), 1);
|
||||
/// assert_eq!(count(), 0);
|
||||
/// set_count(1);
|
||||
/// assert_eq!(count(), 1);
|
||||
/// # }).dispose();
|
||||
/// ```
|
||||
#[cfg_attr(
|
||||
@@ -1784,11 +1781,11 @@ impl<T> RwSignal<T> {
|
||||
/// # create_scope(create_runtime(), |cx| {
|
||||
/// let count = create_rw_signal(cx, 0);
|
||||
/// let (get_count, set_count) = count.split();
|
||||
/// assert_eq!(count.get(), 0);
|
||||
/// assert_eq!(get_count.get(), 0);
|
||||
/// set_count.set(1);
|
||||
/// assert_eq!(count.get(), 1);
|
||||
/// assert_eq!(get_count.get(), 1);
|
||||
/// assert_eq!(count(), 0);
|
||||
/// assert_eq!(get_count(), 0);
|
||||
/// set_count(1);
|
||||
/// assert_eq!(count(), 1);
|
||||
/// assert_eq!(get_count(), 1);
|
||||
/// # }).dispose();
|
||||
/// ```
|
||||
#[cfg_attr(
|
||||
|
||||
@@ -45,14 +45,14 @@ where
|
||||
/// # use leptos_reactive::*;
|
||||
/// # create_scope(create_runtime(), |cx| {
|
||||
/// let (count, set_count) = create_signal(cx, 2);
|
||||
/// let double_count = Signal::derive(cx, move || count.get() * 2);
|
||||
/// let memoized_double_count = create_memo(cx, move |_| count.get() * 2);
|
||||
/// let double_count = Signal::derive(cx, move || count() * 2);
|
||||
/// let memoized_double_count = create_memo(cx, move |_| count() * 2);
|
||||
///
|
||||
/// // this function takes any kind of wrapped signal
|
||||
/// fn above_3(arg: &Signal<i32>) -> bool {
|
||||
/// // ✅ calling the signal clones and returns the value
|
||||
/// // can be `arg() > 3` on nightly
|
||||
/// arg.get() > 3
|
||||
/// // it is a shorthand for arg.get()
|
||||
/// arg() > 3
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(above_3(&count.into()), false);
|
||||
@@ -210,7 +210,7 @@ impl<T> SignalWithUntracked<T> for Signal<T> {
|
||||
/// // this function takes any kind of wrapped signal
|
||||
/// fn current_len_inefficient(arg: Signal<String>) -> usize {
|
||||
/// // ❌ unnecessarily clones the string
|
||||
/// arg.get().len()
|
||||
/// arg().len()
|
||||
/// }
|
||||
///
|
||||
/// fn current_len(arg: &Signal<String>) -> usize {
|
||||
@@ -222,9 +222,9 @@ impl<T> SignalWithUntracked<T> for Signal<T> {
|
||||
/// assert_eq!(current_len(&name_upper), 5);
|
||||
/// assert_eq!(current_len(&memoized_lower.into()), 5);
|
||||
///
|
||||
/// assert_eq!(name.get(), "Alice");
|
||||
/// assert_eq!(name_upper.get(), "ALICE");
|
||||
/// assert_eq!(memoized_lower.get(), "alice");
|
||||
/// assert_eq!(name(), "Alice");
|
||||
/// assert_eq!(name_upper(), "ALICE");
|
||||
/// assert_eq!(memoized_lower(), "alice");
|
||||
/// # });
|
||||
/// ```
|
||||
impl<T> SignalWith<T> for Signal<T> {
|
||||
@@ -276,8 +276,8 @@ impl<T> SignalWith<T> for Signal<T> {
|
||||
/// # use leptos_reactive::*;
|
||||
/// # create_scope(create_runtime(), |cx| {
|
||||
/// let (count, set_count) = create_signal(cx, 2);
|
||||
/// let double_count = Signal::derive(cx, move || count.get() * 2);
|
||||
/// let memoized_double_count = create_memo(cx, move |_| count.get() * 2);
|
||||
/// let double_count = Signal::derive(cx, move || count() * 2);
|
||||
/// let memoized_double_count = create_memo(cx, move |_| count() * 2);
|
||||
///
|
||||
/// // this function takes any kind of wrapped signal
|
||||
/// fn above_3(arg: &Signal<i32>) -> bool {
|
||||
@@ -342,7 +342,7 @@ where
|
||||
/// # use leptos_reactive::*;
|
||||
/// # create_scope(create_runtime(), |cx| {
|
||||
/// let (count, set_count) = create_signal(cx, 2);
|
||||
/// let double_count = Signal::derive(cx, move || count.get() * 2);
|
||||
/// let double_count = Signal::derive(cx, move || count() * 2);
|
||||
///
|
||||
/// // this function takes any kind of wrapped signal
|
||||
/// fn above_3(arg: &Signal<i32>) -> bool {
|
||||
@@ -499,15 +499,15 @@ impl<T> Eq for SignalTypes<T> where T: PartialEq {}
|
||||
/// # use leptos_reactive::*;
|
||||
/// # create_scope(create_runtime(), |cx| {
|
||||
/// let (count, set_count) = create_signal(cx, 2);
|
||||
/// let double_count = MaybeSignal::derive(cx, move || count.get() * 2);
|
||||
/// let memoized_double_count = create_memo(cx, move |_| count.get() * 2);
|
||||
/// let double_count = MaybeSignal::derive(cx, move || count() * 2);
|
||||
/// let memoized_double_count = create_memo(cx, move |_| count() * 2);
|
||||
/// let static_value = 5;
|
||||
///
|
||||
/// // this function takes either a reactive or non-reactive value
|
||||
/// fn above_3(arg: &MaybeSignal<i32>) -> bool {
|
||||
/// // ✅ calling the signal clones and returns the value
|
||||
/// // it is a shorthand for arg.get()
|
||||
/// arg.get() > 3
|
||||
/// arg() > 3
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(above_3(&static_value.into()), true);
|
||||
@@ -550,8 +550,8 @@ impl<T: Default> Default for MaybeSignal<T> {
|
||||
/// # use leptos_reactive::*;
|
||||
/// # create_scope(create_runtime(), |cx| {
|
||||
/// let (count, set_count) = create_signal(cx, 2);
|
||||
/// let double_count = MaybeSignal::derive(cx, move || count.get() * 2);
|
||||
/// let memoized_double_count = create_memo(cx, move |_| count.get() * 2);
|
||||
/// let double_count = MaybeSignal::derive(cx, move || count() * 2);
|
||||
/// let memoized_double_count = create_memo(cx, move |_| count() * 2);
|
||||
/// let static_value: MaybeSignal<i32> = 5.into();
|
||||
///
|
||||
/// // this function takes any kind of wrapped signal
|
||||
@@ -596,7 +596,7 @@ impl<T: Clone> SignalGet<T> for MaybeSignal<T> {
|
||||
/// // this function takes any kind of wrapped signal
|
||||
/// fn current_len_inefficient(arg: &MaybeSignal<String>) -> usize {
|
||||
/// // ❌ unnecessarily clones the string
|
||||
/// arg.get().len()
|
||||
/// arg().len()
|
||||
/// }
|
||||
///
|
||||
/// fn current_len(arg: &MaybeSignal<String>) -> usize {
|
||||
@@ -609,10 +609,10 @@ impl<T: Clone> SignalGet<T> for MaybeSignal<T> {
|
||||
/// assert_eq!(current_len(&memoized_lower.into()), 5);
|
||||
/// assert_eq!(current_len(&static_value), 3);
|
||||
///
|
||||
/// assert_eq!(name.get(), "Alice");
|
||||
/// assert_eq!(name_upper.get(), "ALICE");
|
||||
/// assert_eq!(memoized_lower.get(), "alice");
|
||||
/// assert_eq!(static_value.get(), "Bob");
|
||||
/// assert_eq!(name(), "Alice");
|
||||
/// assert_eq!(name_upper(), "ALICE");
|
||||
/// assert_eq!(memoized_lower(), "alice");
|
||||
/// assert_eq!(static_value(), "Bob");
|
||||
/// # });
|
||||
/// ```
|
||||
impl<T> SignalWith<T> for MaybeSignal<T> {
|
||||
@@ -709,7 +709,7 @@ where
|
||||
/// # use leptos_reactive::*;
|
||||
/// # create_scope(create_runtime(), |cx| {
|
||||
/// let (count, set_count) = create_signal(cx, 2);
|
||||
/// let double_count = Signal::derive(cx, move || count.get() * 2);
|
||||
/// let double_count = Signal::derive(cx, move || count() * 2);
|
||||
///
|
||||
/// // this function takes any kind of wrapped signal
|
||||
/// fn above_3(arg: &MaybeSignal<i32>) -> bool {
|
||||
|
||||
@@ -36,19 +36,19 @@ where
|
||||
/// # use leptos_reactive::*;
|
||||
/// # create_scope(create_runtime(), |cx| {
|
||||
/// let (count, set_count) = create_signal(cx, 2);
|
||||
/// let set_double_input = SignalSetter::map(cx, move |n| set_count.set(n * 2));
|
||||
/// let set_double_input = SignalSetter::map(cx, move |n| set_count(n * 2));
|
||||
///
|
||||
/// // this function takes any kind of signal setter
|
||||
/// fn set_to_4(setter: &SignalSetter<i32>) {
|
||||
/// // ✅ calling the signal sets the value
|
||||
/// // can be `setter(4)` on nightly
|
||||
/// setter.set(4);
|
||||
/// // it is a shorthand for arg.set()
|
||||
/// setter(4);
|
||||
/// }
|
||||
///
|
||||
/// set_to_4(&set_count.into());
|
||||
/// assert_eq!(count.get(), 4);
|
||||
/// assert_eq!(count(), 4);
|
||||
/// set_to_4(&set_double_input);
|
||||
/// assert_eq!(count.get(), 8);
|
||||
/// assert_eq!(count(), 8);
|
||||
/// # });
|
||||
/// ```
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
@@ -121,19 +121,19 @@ where
|
||||
/// # use leptos_reactive::*;
|
||||
/// # create_scope(create_runtime(), |cx| {
|
||||
/// let (count, set_count) = create_signal(cx, 2);
|
||||
/// let set_double_count = SignalSetter::map(cx, move |n| set_count.set(n * 2));
|
||||
/// let set_double_count = SignalSetter::map(cx, move |n| set_count(n * 2));
|
||||
///
|
||||
/// // this function takes any kind of signal setter
|
||||
/// fn set_to_4(setter: &SignalSetter<i32>) {
|
||||
/// // ✅ calling the signal sets the value
|
||||
/// // can be `setter(4)` on nightly
|
||||
/// setter.set(4)
|
||||
/// // it is a shorthand for arg.set()
|
||||
/// setter(4)
|
||||
/// }
|
||||
///
|
||||
/// set_to_4(&set_count.into());
|
||||
/// assert_eq!(count.get(), 4);
|
||||
/// assert_eq!(count(), 4);
|
||||
/// set_to_4(&set_double_count);
|
||||
/// assert_eq!(count.get(), 8);
|
||||
/// assert_eq!(count(), 8);
|
||||
/// # });
|
||||
/// ```
|
||||
#[track_caller]
|
||||
@@ -164,19 +164,19 @@ where
|
||||
/// # use leptos_reactive::*;
|
||||
/// # create_scope(create_runtime(), |cx| {
|
||||
/// let (count, set_count) = create_signal(cx, 2);
|
||||
/// let set_double_count = SignalSetter::map(cx, move |n| set_count.set(n * 2));
|
||||
/// let set_double_count = SignalSetter::map(cx, move |n| set_count(n * 2));
|
||||
///
|
||||
/// // this function takes any kind of signal setter
|
||||
/// fn set_to_4(setter: &SignalSetter<i32>) {
|
||||
/// // ✅ calling the signal sets the value
|
||||
/// // can be `setter(4)` on nightly
|
||||
/// setter.set(4);
|
||||
/// // it is a shorthand for arg.set()
|
||||
/// setter(4);
|
||||
/// }
|
||||
///
|
||||
/// set_to_4(&set_count.into());
|
||||
/// assert_eq!(count.get(), 4);
|
||||
/// assert_eq!(count(), 4);
|
||||
/// set_to_4(&set_double_count);
|
||||
/// assert_eq!(count.get(), 8);
|
||||
/// assert_eq!(count(), 8);
|
||||
/// # });
|
||||
#[cfg_attr(
|
||||
any(debug_assertions, feature = "ssr"),
|
||||
|
||||
@@ -56,17 +56,17 @@ use crate::{
|
||||
///
|
||||
/// create_effect(cx, move |_| {
|
||||
/// // note: in the browser, use leptos::log! instead
|
||||
/// println!("name is {}", name.get());
|
||||
/// println!("name is {}", name());
|
||||
/// });
|
||||
/// create_effect(cx, move |_| {
|
||||
/// println!("count is {}", count.get());
|
||||
/// println!("count is {}", count());
|
||||
/// });
|
||||
///
|
||||
/// // setting count only causes count to log, not name
|
||||
/// set_count.set(42);
|
||||
/// set_count(42);
|
||||
///
|
||||
/// // setting name only causes name to log, not count
|
||||
/// set_name.set("Bob".into());
|
||||
/// set_name("Bob".into());
|
||||
/// ```
|
||||
pub fn create_slice<T, O, S>(
|
||||
cx: Scope,
|
||||
|
||||
@@ -87,8 +87,8 @@ impl<T> StoredValue<T> {
|
||||
///
|
||||
/// // calling .get_value() clones and returns the value
|
||||
/// assert_eq!(data.get_value().value, "a");
|
||||
/// // can be `data().value` on nightly
|
||||
/// // assert_eq!(data().value, "a");
|
||||
/// // there's a short-hand getter form
|
||||
/// assert_eq!(data().value, "a");
|
||||
/// # });
|
||||
/// ```
|
||||
#[track_caller]
|
||||
|
||||
@@ -77,8 +77,7 @@ impl Trigger {
|
||||
/// let o = output.clone();
|
||||
/// let e = external_data.clone();
|
||||
/// create_effect(cx, move |_| {
|
||||
/// // can be `rerun_on_data()` on nightly
|
||||
/// rerun_on_data.track();
|
||||
/// rerun_on_data(); // or rerun_on_data.track();
|
||||
/// write!(o.borrow_mut(), "{}", *e.borrow());
|
||||
/// *e.borrow_mut() += 1;
|
||||
/// });
|
||||
@@ -226,7 +225,7 @@ impl SignalSet<()> for Trigger {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
#[cfg(not(feature = "stable"))]
|
||||
impl FnOnce<()> for Trigger {
|
||||
type Output = ();
|
||||
|
||||
@@ -236,7 +235,7 @@ impl FnOnce<()> for Trigger {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
#[cfg(not(feature = "stable"))]
|
||||
impl FnMut<()> for Trigger {
|
||||
#[inline(always)]
|
||||
extern "rust-call" fn call_mut(&mut self, _args: ()) -> Self::Output {
|
||||
@@ -244,7 +243,7 @@ impl FnMut<()> for Trigger {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
#[cfg(not(feature = "stable"))]
|
||||
impl Fn<()> for Trigger {
|
||||
#[inline(always)]
|
||||
extern "rust-call" fn call(&self, _args: ()) -> Self::Output {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user