mirror of
https://github.com/adoyle0/leptos-use.git
synced 2025-01-23 00:59:22 -05:00
Compare commits
23 commits
819ecd4d86
...
21b7389eb5
Author | SHA1 | Date | |
---|---|---|---|
|
21b7389eb5 | ||
|
c8236dfc37 | ||
|
0d0d4616f9 | ||
|
e35a09148f | ||
|
39f3be4015 | ||
|
0bdc8e16c9 | ||
|
31181c38d9 | ||
|
171bc334ff | ||
|
c6d22e19cb | ||
|
3f81160091 | ||
|
c4152ca358 | ||
|
49f89bcb36 | ||
|
406b7b2e16 | ||
|
10b1a8a0e8 | ||
|
68fd2d7567 | ||
|
ad186d101c | ||
|
cd88876389 | ||
|
874854857f | ||
|
bf96858d6d | ||
|
e28c480046 | ||
|
82e7655d14 | ||
|
96c907aaaa | ||
|
1a189cf7a4 |
101 changed files with 1848 additions and 1613 deletions
48
.github/workflows/cd.yml
vendored
48
.github/workflows/cd.yml
vendored
|
@ -46,30 +46,30 @@ jobs:
|
|||
run: cargo test --features math,docs,ssr,actix --doc use_locale
|
||||
|
||||
#### mdbook
|
||||
# - name: Install mdbook I
|
||||
# uses: taiki-e/install-action@v2
|
||||
# with:
|
||||
# tool: cargo-binstall,mdbook
|
||||
# - name: Install mdbook II
|
||||
# run: |
|
||||
# cargo binstall -y mdbook-cmdrun
|
||||
# cargo binstall -y trunk@0.17.5
|
||||
# rustup target add wasm32-unknown-unknown
|
||||
# - name: Setup Pages
|
||||
# id: pages
|
||||
# uses: actions/configure-pages@v3
|
||||
# - name: Build mdbook # TODO : run mdbook tests
|
||||
# run: |
|
||||
# cd docs/book
|
||||
# mdbook build
|
||||
# python3 post_build.py
|
||||
# - name: Upload artifact
|
||||
# uses: actions/upload-pages-artifact@v1
|
||||
# with:
|
||||
# path: ./docs/book/book
|
||||
# - name: Deploy book to github pages
|
||||
# id: deployment
|
||||
# uses: actions/deploy-pages@v2
|
||||
- name: Install mdbook I
|
||||
uses: taiki-e/install-action@v2
|
||||
with:
|
||||
tool: cargo-binstall,mdbook
|
||||
- name: Install mdbook II
|
||||
run: |
|
||||
cargo binstall -y mdbook-cmdrun
|
||||
cargo binstall -y trunk@0.17.5
|
||||
rustup target add wasm32-unknown-unknown
|
||||
- name: Setup Pages
|
||||
id: pages
|
||||
uses: actions/configure-pages@v3
|
||||
- name: Build mdbook # TODO : run mdbook tests
|
||||
run: |
|
||||
cd docs/book
|
||||
mdbook build
|
||||
python3 post_build.py
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v1
|
||||
with:
|
||||
path: ./docs/book/book
|
||||
- name: Deploy book to github pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v2
|
||||
##### mdbook end
|
||||
|
||||
- name: Publish crate leptos-use
|
||||
|
|
1
.idea/leptos-use.iml
generated
1
.idea/leptos-use.iml
generated
|
@ -85,6 +85,7 @@
|
|||
<sourceFolder url="file://$MODULE_DIR$/examples/use_web_lock/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/examples/use_window_size/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/examples/aaaaa/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/examples/use_textarea_autosize/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/examples/use_event_listener/target" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/docs/book/book" />
|
||||
|
|
45
CHANGELOG.md
45
CHANGELOG.md
|
@ -3,11 +3,56 @@
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.14.0-gamma1] - 2024-10-10
|
||||
|
||||
- Adapted to the latest changes in Leptos (thanks to @BakerNet and @nikessel)
|
||||
- Fixed all the examples
|
||||
- `use_active_element` ported
|
||||
- `use_drop_zone` now returns `Signal<Vec<SendSignal<web_sys::File>>>` instead of `Signal<Vec<web_sys::File>, LocalStorage>`
|
||||
to make it easier to use with `<For>`
|
||||
|
||||
## [0.14.0-beta4] - 2024-09-15
|
||||
|
||||
- Latest changes from version 0.13.4 and 0.13.5 ported
|
||||
|
||||
## [0.14.0-beta3] - 2024-09-02
|
||||
|
||||
### Breaking Changes 🛠
|
||||
|
||||
- Refactored `ElementMaybeSignal` and `ElementsMaybeSignal` to have a simpler implementation. For the vast majority
|
||||
of cases this should continue to work as before.
|
||||
|
||||
## [0.14.0-beta2] - 2024-09-09
|
||||
|
||||
### Change 🔥
|
||||
|
||||
- Latest Leptos 0.7 beta changed the trigger trait method (thanks to @BakerNet)
|
||||
- Latest changes from version 0.13.3 ported
|
||||
|
||||
## [0.14.0-beta1] - 2024-09-02
|
||||
|
||||
Ported everything to Leptos 0.7
|
||||
Some example don't run yet.
|
||||
|
||||
## [0.13.5] - 2024-09-15
|
||||
|
||||
### New Function 🚀
|
||||
|
||||
- `use_textarea_autosize`
|
||||
|
||||
## [0.13.4] - 2024-09-05
|
||||
|
||||
### Fix 🍕
|
||||
|
||||
- `use_websocket` now returns a signal for the websocket instance so the user can actually use it. Before it always
|
||||
returned `None`.
|
||||
|
||||
## [0.13.3] - 2024-09-02
|
||||
|
||||
### Fix 🍕
|
||||
|
||||
- Fixed `use_color_mode` with cookies enabled
|
||||
|
||||
## [0.13.2] - 2024-09-02
|
||||
|
||||
### Fix 🍕
|
||||
|
|
19
Cargo.toml
19
Cargo.toml
|
@ -1,9 +1,9 @@
|
|||
[package]
|
||||
name = "leptos-use"
|
||||
version = "0.14.0-beta1"
|
||||
version = "0.14.0-gamma1"
|
||||
edition = "2021"
|
||||
authors = ["Marc-Stefan Cassola"]
|
||||
categories = ["gui", "web-programming"]
|
||||
categories = ["gui", "web-programming", "wasm"]
|
||||
description = "Collection of essential Leptos utilities inspired by React-Use / VueUse / SolidJS-USE"
|
||||
exclude = ["examples/", "tests/"]
|
||||
keywords = ["leptos", "utilities"]
|
||||
|
@ -26,9 +26,9 @@ http1 = { version = "1", optional = true, package = "http" }
|
|||
http0_2 = { version = "0.2", optional = true, package = "http" }
|
||||
js-sys = "0.3"
|
||||
lazy_static = "1"
|
||||
leptos = "0.7.0-beta"
|
||||
leptos_axum = { optional = true, version = "0.7.0-beta" }
|
||||
leptos_actix = { optional = true, version = "0.7.0-beta" }
|
||||
leptos = "0.7.0-gamma2"
|
||||
leptos_axum = { version = "0.7.0-gamma2", optional = true }
|
||||
leptos_actix = { version = "0.7.0-gamma2", optional = true }
|
||||
leptos-spin = { version = "0.2", optional = true }
|
||||
num = { version = "0.4", optional = true }
|
||||
paste = "1"
|
||||
|
@ -47,13 +47,14 @@ codee = { version = "0.2", features = [
|
|||
"prost",
|
||||
] }
|
||||
getrandom = { version = "0.2", features = ["js"] }
|
||||
leptos_meta = { version = "0.7.0-beta" }
|
||||
leptos_meta = { version = "0.7.0-gamma2" }
|
||||
rand = "0.8"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
unic-langid = { version = "0.9", features = ["macros"] }
|
||||
|
||||
[features]
|
||||
default = [
|
||||
"use_textarea_autosize",
|
||||
"use_web_lock",
|
||||
"use_window_size",
|
||||
"is_err",
|
||||
|
@ -128,6 +129,12 @@ default = [
|
|||
"watch_with_options",
|
||||
"whenever"
|
||||
]
|
||||
use_textarea_autosize = [
|
||||
"use_resize_observer",
|
||||
"web-sys/CssStyleDeclaration",
|
||||
"web-sys/HtmlElement",
|
||||
"web-sys/HtmlTextAreaElement",
|
||||
]
|
||||
use_web_lock = [
|
||||
"web-sys/AbortSignal",
|
||||
"web-sys/Lock",
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<a href="https://crates.io/crates/leptos-use"><img src="https://img.shields.io/crates/v/leptos-use.svg?label=&color=%232C1275" alt="Crates.io"/></a>
|
||||
<a href="https://leptos-use.rs/server_side_rendering.html"><img src="https://img.shields.io/badge/-SSR-%236a214b" alt="SSR"></a>
|
||||
<a href="https://leptos-use.rs"><img src="https://img.shields.io/badge/-docs%20%26%20demos-%239A233F" alt="Docs & Demos"></a>
|
||||
<a href="https://leptos-use.rs"><img src="https://img.shields.io/badge/-86%20functions-%23EF3939" alt="86 Functions" /></a>
|
||||
<a href="https://leptos-use.rs"><img src="https://img.shields.io/badge/-87%20functions-%23EF3939" alt="87 Functions" /></a>
|
||||
</p>
|
||||
|
||||
<br/>
|
||||
|
@ -22,6 +22,7 @@
|
|||
|
||||
## Usage
|
||||
|
||||
![Crates.io Total Downloads](https://img.shields.io/crates/d/leptos-use)
|
||||
[![Docs](https://docs.rs/leptos-use/badge.svg)](https://docs.rs/leptos-use/)
|
||||
[![MIT/Apache 2.0](https://img.shields.io/badge/license-MIT%2FApache-blue.svg)](https://github.com/synphonyte/leptos-use#license)
|
||||
[![Build Status](https://github.com/synphonyte/leptos-use/actions/workflows/cd.yml/badge.svg)](https://github.com/synphonyte/leptos-use/actions/workflows/cd.yml)
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
- [use_preferred_dark](browser/use_preferred_dark.md)
|
||||
- [use_prefers_reduced_motion](browser/use_prefers_reduced_motion.md)
|
||||
- [use_service_worker](browser/use_service_worker.md)
|
||||
- [use_textarea_autosize](browser/use_textarea_autosize.md)
|
||||
- [use_user_media](browser/use_user_media.md)
|
||||
- [use_web_lock](browser/use_web_lock.md)
|
||||
- [use_web_notification](browser/use_web_notification.md)
|
||||
|
|
3
docs/book/src/browser/use_textarea_autosize.md
Normal file
3
docs/book/src/browser/use_textarea_autosize.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# use_textarea_autosize
|
||||
|
||||
<!-- cmdrun python3 ../extract_doc_comment.py use_textarea_autosize use_textarea_autosize -->
|
|
@ -79,7 +79,8 @@
|
|||
|
||||
.demo-container input[type="text"],
|
||||
.demo-container input[type="search"],
|
||||
.demo-container input[type="number"] {
|
||||
.demo-container input[type="number"],
|
||||
.demo-container textarea {
|
||||
display: block;
|
||||
font-size: 90%;
|
||||
padding: .5em 1em .4em;
|
||||
|
@ -96,6 +97,7 @@
|
|||
.demo-container textarea {
|
||||
background: var(--bg);
|
||||
border: 1px solid var(--theme-popup-border);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.demo-container input[type=range],
|
||||
|
|
|
@ -12,6 +12,6 @@
|
|||
<a href="https://crates.io/crates/leptos-use"><img src="https://img.shields.io/crates/v/leptos-use.svg?label=&color=%232C1275" alt="Crates.io"/></a>
|
||||
<a href="https://leptos-use.rs/server_side_rendering.html"><img src="https://img.shields.io/badge/-SSR-%236a214b" alt="SSR"></a>
|
||||
<a href="./get_started.html"><img src="https://img.shields.io/badge/-docs%20%26%20demos-%239A233F" alt="Docs & Demos"></a>
|
||||
<a href="./functions.html"><img src="https://img.shields.io/badge/-86%20functions-%23EF3939" alt="86 Functions" /></a>
|
||||
<a href="./functions.html"><img src="https://img.shields.io/badge/-87%20functions-%23EF3939" alt="87 Functions" /></a>
|
||||
</p>
|
||||
</div>
|
|
@ -7,11 +7,13 @@ members = [
|
|||
"signal_throttled",
|
||||
"sync_signal",
|
||||
"use_abs",
|
||||
"use_active_element",
|
||||
"use_and",
|
||||
"use_breakpoints",
|
||||
"use_broadcast_channel",
|
||||
"use_ceil",
|
||||
"use_clipboard",
|
||||
"use_color_mode",
|
||||
"use_cookie",
|
||||
"use_css_var",
|
||||
"use_cycle_list",
|
||||
|
@ -21,6 +23,7 @@ members = [
|
|||
"use_display_media",
|
||||
"use_document_visibility",
|
||||
"use_draggable",
|
||||
"use_drop_zone",
|
||||
"use_element_bounding",
|
||||
"use_element_hover",
|
||||
"use_element_size",
|
||||
|
@ -52,6 +55,7 @@ members = [
|
|||
"use_service_worker",
|
||||
"use_sorted",
|
||||
"use_storage",
|
||||
"use_textarea_autosize",
|
||||
"use_throttle_fn",
|
||||
"use_timeout_fn",
|
||||
"use_timestamp",
|
||||
|
@ -66,16 +70,13 @@ members = [
|
|||
"watch_debounced",
|
||||
"watch_pausable",
|
||||
"watch_throttled",
|
||||
# "use_active_element",
|
||||
# "use_color_mode",
|
||||
# "use_drop_zone",
|
||||
# "use_webtransport",
|
||||
]
|
||||
|
||||
exclude = ["ssr", "use_webtransport_with_server"]
|
||||
|
||||
[workspace.dependencies]
|
||||
leptos = "0.7.0-beta"
|
||||
leptos = "0.7.0-gamma2"
|
||||
codee = "0.2"
|
||||
console_error_panic_hook = "0.1"
|
||||
console_log = "1"
|
||||
|
|
|
@ -8,16 +8,14 @@ crate-type = ["cdylib", "rlib"]
|
|||
|
||||
[dependencies]
|
||||
axum = { version = "0.7", optional = true }
|
||||
codee.workspace = true
|
||||
codee = "0.2"
|
||||
console_error_panic_hook = "0.1"
|
||||
console_log = "1"
|
||||
cfg-if = "1"
|
||||
leptos = { workspace = true, features = ["nightly"] }
|
||||
leptos_axum = { git = "https://github.com/leptos-rs/leptos", optional = true }
|
||||
leptos_meta = { git = "https://github.com/leptos-rs/leptos", features = [
|
||||
"nightly",
|
||||
] }
|
||||
leptos_router = { git = "https://github.com/leptos-rs/leptos", features = [
|
||||
leptos = { version = "0.7.0-beta", features = ["nightly"] }
|
||||
leptos_axum = { version = "0.7.0-beta", optional = true }
|
||||
leptos_meta = "0.7.0-beta"
|
||||
leptos_router = { version = "0.7.0-beta", features = [
|
||||
"nightly",
|
||||
] }
|
||||
log = "0.4"
|
||||
|
@ -46,7 +44,7 @@ features = [
|
|||
]
|
||||
|
||||
[features]
|
||||
hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]
|
||||
hydrate = ["leptos/hydrate"]
|
||||
ssr = [
|
||||
"dep:axum",
|
||||
"dep:tokio",
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use crate::error_template::{AppError, ErrorTemplate};
|
||||
use codee::string::FromToStringCodec;
|
||||
use leptos::ev::{keypress, KeyboardEvent};
|
||||
use leptos::prelude::*;
|
||||
use leptos_meta::*;
|
||||
use leptos_router::*;
|
||||
use leptos_router::components::*;
|
||||
use leptos_router::path;
|
||||
use leptos_use::storage::{use_local_storage, use_local_storage_with_options, UseStorageOptions};
|
||||
use leptos_use::{
|
||||
use_color_mode_with_options, use_cookie_with_options, use_debounce_fn, use_event_listener,
|
||||
|
@ -12,6 +12,25 @@ use leptos_use::{
|
|||
UseIntervalReturn, UseIntlNumberFormatOptions,
|
||||
};
|
||||
|
||||
pub fn shell(options: LeptosOptions) -> impl IntoView {
|
||||
view! {
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<MetaTags/>
|
||||
<AutoReload options=options.clone()/>
|
||||
<HydrationScripts options/>
|
||||
<link rel="stylesheet" id="leptos" href="/pkg/leptos_use_ssr.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<App/>
|
||||
</body>
|
||||
</html>
|
||||
}
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn App() -> impl IntoView {
|
||||
// Provides context that manages stylesheets, titles, meta tags, etc.
|
||||
|
@ -22,14 +41,10 @@ pub fn App() -> impl IntoView {
|
|||
|
||||
<Title text="Leptos-Use SSR Example"/>
|
||||
|
||||
<Router fallback=|| {
|
||||
let mut outside_errors = Errors::default();
|
||||
outside_errors.insert_with_default_key(AppError::NotFound);
|
||||
view! { <ErrorTemplate outside_errors/> }.into_view()
|
||||
}>
|
||||
<Router>
|
||||
<main>
|
||||
<Routes>
|
||||
<Route path="" view=|| view! { <HomePage/> }/>
|
||||
<Routes fallback=|| "This page could not be found.">
|
||||
<Route path=path!("") view=|| view! { <HomePage/> }/>
|
||||
</Routes>
|
||||
</main>
|
||||
</Router>
|
||||
|
@ -86,7 +101,7 @@ fn HomePage() -> impl IntoView {
|
|||
let locales = use_locales();
|
||||
|
||||
view! {
|
||||
<Html class=move || mode.get().to_string()/>
|
||||
<Html {..} class=move || mode.get().to_string()/>
|
||||
|
||||
<h1>Leptos-Use SSR Example</h1>
|
||||
<button on:click=on_click>Click Me: {count}</button>
|
||||
|
|
|
@ -1,74 +0,0 @@
|
|||
use cfg_if::cfg_if;
|
||||
use http::status::StatusCode;
|
||||
use leptos::prelude::*;
|
||||
use thiserror::Error;
|
||||
|
||||
#[cfg(feature = "ssr")]
|
||||
use leptos_axum::ResponseOptions;
|
||||
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum AppError {
|
||||
#[error("Not Found")]
|
||||
NotFound,
|
||||
}
|
||||
|
||||
impl AppError {
|
||||
pub fn status_code(&self) -> StatusCode {
|
||||
match self {
|
||||
AppError::NotFound => StatusCode::NOT_FOUND,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A basic function to display errors served by the error boundaries.
|
||||
// Feel free to do more complicated things here than just displaying the error.
|
||||
#[component]
|
||||
pub fn ErrorTemplate(
|
||||
#[prop(optional)] outside_errors: Option<Errors>,
|
||||
#[prop(optional)] errors: Option<RwSignal<Errors>>,
|
||||
) -> impl IntoView {
|
||||
let errors = match outside_errors {
|
||||
Some(e) => create_rw_signal(e),
|
||||
None => match errors {
|
||||
Some(e) => e,
|
||||
None => panic!("No Errors found and we expected errors!"),
|
||||
},
|
||||
};
|
||||
// Get Errors from Signal
|
||||
let errors = errors.get();
|
||||
|
||||
// Downcast lets us take a type that implements `std::error::Error`
|
||||
let errors: Vec<AppError> = errors
|
||||
.into_iter()
|
||||
.filter_map(|(_k, v)| v.downcast_ref::<AppError>().cloned())
|
||||
.collect();
|
||||
println!("Errors: {errors:#?}");
|
||||
|
||||
// Only the response code for the first error is actually sent from the server
|
||||
// this may be customized by the specific application
|
||||
cfg_if! { if #[cfg(feature="ssr")] {
|
||||
let response = use_context::<ResponseOptions>();
|
||||
if let Some(response) = response {
|
||||
response.set_status(errors[0].status_code());
|
||||
}
|
||||
}}
|
||||
|
||||
view! {
|
||||
<h1>{if errors.len() > 1 { "Errors" } else { "Error" }}</h1>
|
||||
<For
|
||||
// a function that returns the items we're iterating over; a signal is fine
|
||||
each=move || { errors.clone().into_iter().enumerate() }
|
||||
// a unique key for each item as a reference
|
||||
key=|(index, _error)| *index
|
||||
// renders each item to a view
|
||||
children=move |error| {
|
||||
let error_string = error.1.to_string();
|
||||
let error_code = error.1.status_code();
|
||||
view! {
|
||||
<h2>{error_code.to_string()}</h2>
|
||||
<p>"Error: " {error_string}</p>
|
||||
}
|
||||
}
|
||||
/>
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
use cfg_if::cfg_if;
|
||||
|
||||
cfg_if! { if #[cfg(feature = "ssr")] {
|
||||
use axum::{
|
||||
body::Body,
|
||||
extract::State,
|
||||
response::IntoResponse,
|
||||
http::{Request, Response, StatusCode, Uri},
|
||||
};
|
||||
use axum::response::Response as AxumResponse;
|
||||
use tower::ServiceExt;
|
||||
use tower_http::services::ServeDir;
|
||||
use leptos::prelude::*;
|
||||
use crate::app::App;
|
||||
|
||||
pub async fn file_and_error_handler(uri: Uri, State(options): State<LeptosOptions>, req: Request<Body>) -> AxumResponse {
|
||||
let root = options.site_root.clone();
|
||||
let res = get_static_file(uri.clone(), &root).await.unwrap();
|
||||
|
||||
if res.status() == StatusCode::OK {
|
||||
res.into_response()
|
||||
} else {
|
||||
let handler = leptos_axum::render_app_to_stream(options.to_owned(), move || view!{<App/>});
|
||||
handler(req).await.into_response()
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_static_file(uri: Uri, root: &str) -> Result<Response<Body>, (StatusCode, String)> {
|
||||
let req = Request::builder().uri(uri.clone()).body(Body::empty()).unwrap();
|
||||
// `ServeDir` implements `tower::Service` so we can call it with `tower::ServiceExt::oneshot`
|
||||
// This path is relative to the cargo root
|
||||
match ServeDir::new(root).oneshot(req).await {
|
||||
Ok(res) => Ok(res.into_response()),
|
||||
Err(err) => Err((
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("Something went wrong: {err}"),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}}
|
|
@ -1,21 +1,10 @@
|
|||
use cfg_if::cfg_if;
|
||||
pub mod app;
|
||||
pub mod error_template;
|
||||
pub mod fileserv;
|
||||
|
||||
cfg_if! { if #[cfg(feature = "hydrate")] {
|
||||
use leptos::prelude::*;
|
||||
use wasm_bindgen::prelude::wasm_bindgen;
|
||||
use crate::app::*;
|
||||
#[cfg(feature = "hydrate")]
|
||||
#[wasm_bindgen::prelude::wasm_bindgen]
|
||||
pub fn hydrate() {
|
||||
use crate::app::App;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn hydrate() {
|
||||
// initializes logging using the `log` crate
|
||||
_ = console_log::init_with_level(log::Level::Debug);
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
leptos::mount_to_body(move || {
|
||||
view! { <App/> }
|
||||
});
|
||||
}
|
||||
}}
|
||||
leptos::mount::hydrate_body(App);
|
||||
}
|
||||
|
|
|
@ -1,51 +1,34 @@
|
|||
#[cfg(feature = "ssr")]
|
||||
use crate::app::*;
|
||||
use axum::Router;
|
||||
use leptos::{config::get_configuration, logging};
|
||||
use leptos_axum::{generate_route_list, LeptosRoutes};
|
||||
use leptos_use_ssr::*;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
use axum::{routing::post, Router};
|
||||
use http::{HeaderMap, HeaderName, HeaderValue};
|
||||
use leptos::logging::log;
|
||||
use leptos::prelude::*;
|
||||
use leptos_axum::{generate_route_list, LeptosRoutes};
|
||||
use leptos_use_ssr::app::*;
|
||||
use leptos_use_ssr::fileserv::file_and_error_handler;
|
||||
use tower_default_headers::DefaultHeadersLayer;
|
||||
simple_logger::init_with_level(log::Level::Error)
|
||||
.expect("couldn't initialize logging");
|
||||
|
||||
simple_logger::init_with_level(log::Level::Info).expect("couldn't initialize logging");
|
||||
|
||||
// Setting get_configuration(None) means we'll be using cargo-leptos's env values
|
||||
// For deployment these variables are:
|
||||
// <https://github.com/leptos-rs/start-axum#executing-a-server-on-a-remote-machine-without-the-toolchain>
|
||||
// Alternately a file can be specified such as Some("Cargo.toml")
|
||||
// The file would need to be included with the executable when moved to deployment
|
||||
let conf = get_configuration(None).await.unwrap();
|
||||
// Setting this to None means we'll be using cargo-leptos and its env vars
|
||||
let conf = get_configuration(None).unwrap();
|
||||
let leptos_options = conf.leptos_options;
|
||||
let addr = leptos_options.site_addr;
|
||||
let routes = generate_route_list(|| view! { <App/> });
|
||||
|
||||
let mut default_headers = HeaderMap::new();
|
||||
let color_header = HeaderValue::from_static("Sec-CH-Prefers-Color-Scheme");
|
||||
default_headers.insert(HeaderName::from_static("accept-ch"), color_header.clone());
|
||||
default_headers.insert(HeaderName::from_static("vary"), color_header.clone());
|
||||
default_headers.insert(HeaderName::from_static("critical-ch"), color_header);
|
||||
let routes = generate_route_list(App);
|
||||
|
||||
// build our application with a route
|
||||
let app = Router::new()
|
||||
.route("/api/*fn_name", post(leptos_axum::handle_server_fns))
|
||||
.leptos_routes(&leptos_options, routes, || view! { <App/> })
|
||||
.fallback(file_and_error_handler)
|
||||
.with_state(leptos_options)
|
||||
.layer(DefaultHeadersLayer::new(default_headers));
|
||||
.leptos_routes(&leptos_options, routes, {
|
||||
let leptos_options = leptos_options.clone();
|
||||
move || shell(leptos_options.clone())
|
||||
})
|
||||
.fallback(leptos_axum::file_and_error_handler(shell))
|
||||
.with_state(leptos_options);
|
||||
|
||||
// run our app with hyper
|
||||
// `axum::Server` is a re-export of `hyper::Server`
|
||||
let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
|
||||
log!("listening on http://{}", &addr);
|
||||
logging::log!("listening on http://{}", &addr);
|
||||
axum::serve(listener, app.into_make_service())
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
pub fn main() {
|
||||
// no client-side main function
|
||||
// unless we want this to work with e.g., Trunk for a purely client-side app
|
||||
// see lib.rs for hydration function instead
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use leptos::prelude::*;
|
||||
use leptos::wasm_bindgen::JsCast;
|
||||
use leptos_use::docs::{demo_or_body, Note};
|
||||
use leptos_use::use_active_element;
|
||||
|
||||
|
@ -10,7 +11,10 @@ fn Demo() -> impl IntoView {
|
|||
"{:?}",
|
||||
active_element
|
||||
.get()
|
||||
.map(|el| el.dataset().get("id"))
|
||||
.map(|el| el
|
||||
.unchecked_ref::<web_sys::HtmlElement>()
|
||||
.dataset()
|
||||
.get("id"))
|
||||
.unwrap_or_default()
|
||||
)
|
||||
};
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use leptos::html::html;
|
||||
use leptos::prelude::*;
|
||||
use leptos_use::docs::{demo_or_body, Note};
|
||||
use leptos_use::{
|
||||
|
@ -16,7 +15,13 @@ fn Demo() -> impl IntoView {
|
|||
"navy".into(),
|
||||
"ayu".into(),
|
||||
])
|
||||
.initial_value(ColorMode::from(html().class_name())),
|
||||
.initial_value(ColorMode::from(
|
||||
document()
|
||||
.query_selector("html")
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.class_name(),
|
||||
)),
|
||||
);
|
||||
|
||||
let UseCycleListReturn { state, next, .. } = use_cycle_list_with_options(
|
||||
|
|
16
examples/use_textarea_autosize/Cargo.toml
Normal file
16
examples/use_textarea_autosize/Cargo.toml
Normal file
|
@ -0,0 +1,16 @@
|
|||
[package]
|
||||
name = "use_textarea_autosize"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
leptos = { workspace = true, features = ["nightly", "csr"] }
|
||||
console_error_panic_hook = "0.1"
|
||||
console_log = "1"
|
||||
log = "0.4"
|
||||
leptos-use = { path = "../..", features = ["use_textarea_autosize", "docs"] }
|
||||
web-sys = "0.3"
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen = "0.2"
|
||||
wasm-bindgen-test = "0.3.0"
|
23
examples/use_textarea_autosize/README.md
Normal file
23
examples/use_textarea_autosize/README.md
Normal file
|
@ -0,0 +1,23 @@
|
|||
A simple example for `use_textarea_autosize`.
|
||||
|
||||
If you don't have it installed already, install [Trunk](https://trunkrs.dev/) and [Tailwind](https://tailwindcss.com/docs/installation)
|
||||
as well as the nightly toolchain for Rust and the wasm32-unknown-unknown target:
|
||||
|
||||
```bash
|
||||
cargo install trunk
|
||||
npm install -D tailwindcss @tailwindcss/forms
|
||||
rustup toolchain install nightly
|
||||
rustup target add wasm32-unknown-unknown
|
||||
```
|
||||
|
||||
Then, open two terminals. In the first one, run:
|
||||
|
||||
```
|
||||
npx tailwindcss -i ./input.css -o ./style/output.css --watch
|
||||
```
|
||||
|
||||
In the second one, run:
|
||||
|
||||
```bash
|
||||
trunk serve --open
|
||||
```
|
2
examples/use_textarea_autosize/Trunk.toml
Normal file
2
examples/use_textarea_autosize/Trunk.toml
Normal file
|
@ -0,0 +1,2 @@
|
|||
[build]
|
||||
public_url = "/demo/"
|
7
examples/use_textarea_autosize/index.html
Normal file
7
examples/use_textarea_autosize/index.html
Normal file
|
@ -0,0 +1,7 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link data-trunk rel="css" href="style/output.css">
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
3
examples/use_textarea_autosize/input.css
Normal file
3
examples/use_textarea_autosize/input.css
Normal file
|
@ -0,0 +1,3 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
2
examples/use_textarea_autosize/rust-toolchain.toml
Normal file
2
examples/use_textarea_autosize/rust-toolchain.toml
Normal file
|
@ -0,0 +1,2 @@
|
|||
[toolchain]
|
||||
channel = "nightly"
|
36
examples/use_textarea_autosize/src/main.rs
Normal file
36
examples/use_textarea_autosize/src/main.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
use leptos::prelude::*;
|
||||
use leptos_use::docs::demo_or_body;
|
||||
use leptos_use::{use_textarea_autosize, UseTextareaAutosizeReturn};
|
||||
|
||||
#[component]
|
||||
fn Demo() -> impl IntoView {
|
||||
let textarea = NodeRef::new();
|
||||
|
||||
let UseTextareaAutosizeReturn {
|
||||
content,
|
||||
set_content,
|
||||
..
|
||||
} = use_textarea_autosize(textarea);
|
||||
|
||||
view! {
|
||||
<div class="mb-4">Type, the textarea will grow:</div>
|
||||
<textarea
|
||||
prop:value=content
|
||||
on:input=move |evt| set_content.set(event_target_value(&evt))
|
||||
node_ref=textarea
|
||||
class="resize-none box-border"
|
||||
placeholder="What's on your mind?"
|
||||
/>
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
_ = console_log::init_with_level(log::Level::Debug);
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
let unmount_handle = leptos::mount::mount_to(demo_or_body(), || {
|
||||
view! { <Demo/> }
|
||||
});
|
||||
|
||||
unmount_handle.forget();
|
||||
}
|
342
examples/use_textarea_autosize/style/output.css
Normal file
342
examples/use_textarea_autosize/style/output.css
Normal file
|
@ -0,0 +1,342 @@
|
|||
[type='text'],input:where(:not([type])),[type='email'],[type='url'],[type='password'],[type='number'],[type='date'],[type='datetime-local'],[type='month'],[type='search'],[type='tel'],[type='time'],[type='week'],[multiple],textarea,select {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
background-color: #fff;
|
||||
border-color: #6b7280;
|
||||
border-width: 1px;
|
||||
border-radius: 0px;
|
||||
padding-top: 0.5rem;
|
||||
padding-right: 0.75rem;
|
||||
padding-bottom: 0.5rem;
|
||||
padding-left: 0.75rem;
|
||||
font-size: 1rem;
|
||||
line-height: 1.5rem;
|
||||
--tw-shadow: 0 0 #0000;
|
||||
}
|
||||
|
||||
[type='text']:focus, input:where(:not([type])):focus, [type='email']:focus, [type='url']:focus, [type='password']:focus, [type='number']:focus, [type='date']:focus, [type='datetime-local']:focus, [type='month']:focus, [type='search']:focus, [type='tel']:focus, [type='time']:focus, [type='week']:focus, [multiple]:focus, textarea:focus, select:focus {
|
||||
outline: 2px solid transparent;
|
||||
outline-offset: 2px;
|
||||
--tw-ring-inset: var(--tw-empty,/*!*/ /*!*/);
|
||||
--tw-ring-offset-width: 0px;
|
||||
--tw-ring-offset-color: #fff;
|
||||
--tw-ring-color: #2563eb;
|
||||
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
||||
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
||||
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||
border-color: #2563eb;
|
||||
}
|
||||
|
||||
input::-moz-placeholder, textarea::-moz-placeholder {
|
||||
color: #6b7280;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
input::placeholder,textarea::placeholder {
|
||||
color: #6b7280;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
::-webkit-datetime-edit-fields-wrapper {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-date-and-time-value {
|
||||
min-height: 1.5em;
|
||||
text-align: inherit;
|
||||
}
|
||||
|
||||
::-webkit-datetime-edit {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
::-webkit-datetime-edit,::-webkit-datetime-edit-year-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-meridiem-field {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
select {
|
||||
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
|
||||
background-position: right 0.5rem center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 1.5em 1.5em;
|
||||
padding-right: 2.5rem;
|
||||
-webkit-print-color-adjust: exact;
|
||||
print-color-adjust: exact;
|
||||
}
|
||||
|
||||
[multiple],[size]:where(select:not([size="1"])) {
|
||||
background-image: initial;
|
||||
background-position: initial;
|
||||
background-repeat: unset;
|
||||
background-size: initial;
|
||||
padding-right: 0.75rem;
|
||||
-webkit-print-color-adjust: unset;
|
||||
print-color-adjust: unset;
|
||||
}
|
||||
|
||||
[type='checkbox'],[type='radio'] {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
padding: 0;
|
||||
-webkit-print-color-adjust: exact;
|
||||
print-color-adjust: exact;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
background-origin: border-box;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
flex-shrink: 0;
|
||||
height: 1rem;
|
||||
width: 1rem;
|
||||
color: #2563eb;
|
||||
background-color: #fff;
|
||||
border-color: #6b7280;
|
||||
border-width: 1px;
|
||||
--tw-shadow: 0 0 #0000;
|
||||
}
|
||||
|
||||
[type='checkbox'] {
|
||||
border-radius: 0px;
|
||||
}
|
||||
|
||||
[type='radio'] {
|
||||
border-radius: 100%;
|
||||
}
|
||||
|
||||
[type='checkbox']:focus,[type='radio']:focus {
|
||||
outline: 2px solid transparent;
|
||||
outline-offset: 2px;
|
||||
--tw-ring-inset: var(--tw-empty,/*!*/ /*!*/);
|
||||
--tw-ring-offset-width: 2px;
|
||||
--tw-ring-offset-color: #fff;
|
||||
--tw-ring-color: #2563eb;
|
||||
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
||||
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
||||
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||
}
|
||||
|
||||
[type='checkbox']:checked,[type='radio']:checked {
|
||||
border-color: transparent;
|
||||
background-color: currentColor;
|
||||
background-size: 100% 100%;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
[type='checkbox']:checked {
|
||||
background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e");
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
[type='checkbox']:checked {
|
||||
-webkit-appearance: auto;
|
||||
-moz-appearance: auto;
|
||||
appearance: auto;
|
||||
}
|
||||
}
|
||||
|
||||
[type='radio']:checked {
|
||||
background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e");
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
[type='radio']:checked {
|
||||
-webkit-appearance: auto;
|
||||
-moz-appearance: auto;
|
||||
appearance: auto;
|
||||
}
|
||||
}
|
||||
|
||||
[type='checkbox']:checked:hover,[type='checkbox']:checked:focus,[type='radio']:checked:hover,[type='radio']:checked:focus {
|
||||
border-color: transparent;
|
||||
background-color: currentColor;
|
||||
}
|
||||
|
||||
[type='checkbox']:indeterminate {
|
||||
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3e%3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3e%3c/svg%3e");
|
||||
border-color: transparent;
|
||||
background-color: currentColor;
|
||||
background-size: 100% 100%;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
[type='checkbox']:indeterminate {
|
||||
-webkit-appearance: auto;
|
||||
-moz-appearance: auto;
|
||||
appearance: auto;
|
||||
}
|
||||
}
|
||||
|
||||
[type='checkbox']:indeterminate:hover,[type='checkbox']:indeterminate:focus {
|
||||
border-color: transparent;
|
||||
background-color: currentColor;
|
||||
}
|
||||
|
||||
[type='file'] {
|
||||
background: unset;
|
||||
border-color: inherit;
|
||||
border-width: 0;
|
||||
border-radius: 0;
|
||||
padding: 0;
|
||||
font-size: unset;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
[type='file']:focus {
|
||||
outline: 1px solid ButtonText;
|
||||
outline: 1px auto -webkit-focus-ring-color;
|
||||
}
|
||||
|
||||
*, ::before, ::after {
|
||||
--tw-border-spacing-x: 0;
|
||||
--tw-border-spacing-y: 0;
|
||||
--tw-translate-x: 0;
|
||||
--tw-translate-y: 0;
|
||||
--tw-rotate: 0;
|
||||
--tw-skew-x: 0;
|
||||
--tw-skew-y: 0;
|
||||
--tw-scale-x: 1;
|
||||
--tw-scale-y: 1;
|
||||
--tw-pan-x: ;
|
||||
--tw-pan-y: ;
|
||||
--tw-pinch-zoom: ;
|
||||
--tw-scroll-snap-strictness: proximity;
|
||||
--tw-gradient-from-position: ;
|
||||
--tw-gradient-via-position: ;
|
||||
--tw-gradient-to-position: ;
|
||||
--tw-ordinal: ;
|
||||
--tw-slashed-zero: ;
|
||||
--tw-numeric-figure: ;
|
||||
--tw-numeric-spacing: ;
|
||||
--tw-numeric-fraction: ;
|
||||
--tw-ring-inset: ;
|
||||
--tw-ring-offset-width: 0px;
|
||||
--tw-ring-offset-color: #fff;
|
||||
--tw-ring-color: rgb(59 130 246 / 0.5);
|
||||
--tw-ring-offset-shadow: 0 0 #0000;
|
||||
--tw-ring-shadow: 0 0 #0000;
|
||||
--tw-shadow: 0 0 #0000;
|
||||
--tw-shadow-colored: 0 0 #0000;
|
||||
--tw-blur: ;
|
||||
--tw-brightness: ;
|
||||
--tw-contrast: ;
|
||||
--tw-grayscale: ;
|
||||
--tw-hue-rotate: ;
|
||||
--tw-invert: ;
|
||||
--tw-saturate: ;
|
||||
--tw-sepia: ;
|
||||
--tw-drop-shadow: ;
|
||||
--tw-backdrop-blur: ;
|
||||
--tw-backdrop-brightness: ;
|
||||
--tw-backdrop-contrast: ;
|
||||
--tw-backdrop-grayscale: ;
|
||||
--tw-backdrop-hue-rotate: ;
|
||||
--tw-backdrop-invert: ;
|
||||
--tw-backdrop-opacity: ;
|
||||
--tw-backdrop-saturate: ;
|
||||
--tw-backdrop-sepia: ;
|
||||
--tw-contain-size: ;
|
||||
--tw-contain-layout: ;
|
||||
--tw-contain-paint: ;
|
||||
--tw-contain-style: ;
|
||||
}
|
||||
|
||||
::backdrop {
|
||||
--tw-border-spacing-x: 0;
|
||||
--tw-border-spacing-y: 0;
|
||||
--tw-translate-x: 0;
|
||||
--tw-translate-y: 0;
|
||||
--tw-rotate: 0;
|
||||
--tw-skew-x: 0;
|
||||
--tw-skew-y: 0;
|
||||
--tw-scale-x: 1;
|
||||
--tw-scale-y: 1;
|
||||
--tw-pan-x: ;
|
||||
--tw-pan-y: ;
|
||||
--tw-pinch-zoom: ;
|
||||
--tw-scroll-snap-strictness: proximity;
|
||||
--tw-gradient-from-position: ;
|
||||
--tw-gradient-via-position: ;
|
||||
--tw-gradient-to-position: ;
|
||||
--tw-ordinal: ;
|
||||
--tw-slashed-zero: ;
|
||||
--tw-numeric-figure: ;
|
||||
--tw-numeric-spacing: ;
|
||||
--tw-numeric-fraction: ;
|
||||
--tw-ring-inset: ;
|
||||
--tw-ring-offset-width: 0px;
|
||||
--tw-ring-offset-color: #fff;
|
||||
--tw-ring-color: rgb(59 130 246 / 0.5);
|
||||
--tw-ring-offset-shadow: 0 0 #0000;
|
||||
--tw-ring-shadow: 0 0 #0000;
|
||||
--tw-shadow: 0 0 #0000;
|
||||
--tw-shadow-colored: 0 0 #0000;
|
||||
--tw-blur: ;
|
||||
--tw-brightness: ;
|
||||
--tw-contrast: ;
|
||||
--tw-grayscale: ;
|
||||
--tw-hue-rotate: ;
|
||||
--tw-invert: ;
|
||||
--tw-saturate: ;
|
||||
--tw-sepia: ;
|
||||
--tw-drop-shadow: ;
|
||||
--tw-backdrop-blur: ;
|
||||
--tw-backdrop-brightness: ;
|
||||
--tw-backdrop-contrast: ;
|
||||
--tw-backdrop-grayscale: ;
|
||||
--tw-backdrop-hue-rotate: ;
|
||||
--tw-backdrop-invert: ;
|
||||
--tw-backdrop-opacity: ;
|
||||
--tw-backdrop-saturate: ;
|
||||
--tw-backdrop-sepia: ;
|
||||
--tw-contain-size: ;
|
||||
--tw-contain-layout: ;
|
||||
--tw-contain-paint: ;
|
||||
--tw-contain-style: ;
|
||||
}
|
||||
|
||||
.static {
|
||||
position: static;
|
||||
}
|
||||
|
||||
.mb-4 {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.box-border {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.grow {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.resize-none {
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.text-\[--brand-color\] {
|
||||
color: var(--brand-color);
|
||||
}
|
||||
|
||||
.text-green-600 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(22 163 74 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.opacity-75 {
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.dark\:text-green-500 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(34 197 94 / var(--tw-text-opacity));
|
||||
}
|
||||
}
|
15
examples/use_textarea_autosize/tailwind.config.js
Normal file
15
examples/use_textarea_autosize/tailwind.config.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: {
|
||||
files: ["*.html", "./src/**/*.rs", "../../src/docs/**/*.rs"],
|
||||
},
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
corePlugins: {
|
||||
preflight: false,
|
||||
},
|
||||
plugins: [
|
||||
require('@tailwindcss/forms'),
|
||||
],
|
||||
}
|
|
@ -4,7 +4,7 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
leptos = { version = "0.6", features = ["nightly", "csr"] }
|
||||
leptos = { workspace = true, features = ["nightly", "csr"] }
|
||||
console_error_panic_hook = "0.1"
|
||||
console_log = "1"
|
||||
log = "0.4"
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
use leptos::*;
|
||||
use leptos::prelude::*;
|
||||
use leptos_use::docs::{demo_or_body, BooleanDisplay};
|
||||
use leptos_use::{use_toggle, UseToggleReturn};
|
||||
|
||||
#[component]
|
||||
fn Demo() -> impl IntoView {
|
||||
let UseToggleReturn { toggle, value, set_value } = use_toggle(true);
|
||||
let UseToggleReturn {
|
||||
toggle,
|
||||
value,
|
||||
set_value,
|
||||
} = use_toggle(true);
|
||||
|
||||
view! {
|
||||
<p>Value: <BooleanDisplay value=value /></p>
|
||||
|
@ -18,7 +22,9 @@ fn main() {
|
|||
_ = console_log::init_with_level(log::Level::Debug);
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
mount_to(demo_or_body(), || {
|
||||
let unmount_handle = mount_to(demo_or_body(), || {
|
||||
view! { <Demo /> }
|
||||
})
|
||||
});
|
||||
|
||||
unmount_handle.forget();
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
gloo-timers = { version = "0.3", features = ["futures"] }
|
||||
leptos = { version = "0.6", features = ["nightly", "csr"] }
|
||||
leptos = { workspace = true, features = ["nightly", "csr"] }
|
||||
console_error_panic_hook = "0.1"
|
||||
console_log = "1"
|
||||
log = "0.4"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use gloo_timers::future::sleep;
|
||||
use leptos::*;
|
||||
use leptos::prelude::*;
|
||||
use leptos::task::spawn_local;
|
||||
use leptos_use::docs::demo_or_body;
|
||||
use leptos_use::use_web_lock;
|
||||
use std::time::Duration;
|
||||
|
@ -12,7 +13,7 @@ async fn my_process(_lock: web_sys::Lock) -> i32 {
|
|||
|
||||
#[component]
|
||||
fn Demo() -> impl IntoView {
|
||||
let (res, set_res) = create_signal("Not started yet".to_string());
|
||||
let (res, set_res) = signal("Not started yet".to_string());
|
||||
|
||||
let on_click = move |_| {
|
||||
set_res.set("Running...".to_string());
|
||||
|
@ -41,7 +42,9 @@ fn main() {
|
|||
_ = console_log::init_with_level(log::Level::Debug);
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
mount_to(demo_or_body(), || {
|
||||
let unmount_handle = leptos::mount::mount_to(demo_or_body(), || {
|
||||
view! { <Demo/> }
|
||||
})
|
||||
});
|
||||
|
||||
unmount_handle.forget();
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ fn Demo() -> impl IntoView {
|
|||
move |_| {
|
||||
let transport = transport.clone();
|
||||
|
||||
leptos::spawn::spawn_local(async move {
|
||||
leptos::task::spawn_local(async move {
|
||||
match transport.open_bidir_stream().await {
|
||||
Ok(bidir_stream) => {
|
||||
let i = id.get_value();
|
||||
|
|
|
@ -4,7 +4,7 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
leptos = { version = "0.6", features = ["nightly", "csr"] }
|
||||
leptos = { workspace = true, features = ["nightly", "csr"] }
|
||||
console_error_panic_hook = "0.1"
|
||||
console_log = "1"
|
||||
log = "0.4"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use leptos::*;
|
||||
use leptos::prelude::*;
|
||||
use leptos_use::docs::demo_or_body;
|
||||
use leptos_use::{use_window_size, UseWindowSizeReturn};
|
||||
|
||||
|
@ -7,7 +7,7 @@ fn Demo() -> impl IntoView {
|
|||
let UseWindowSizeReturn { width, height } = use_window_size();
|
||||
|
||||
view! {
|
||||
<p>{{ width }} x {{ height }}</p>
|
||||
<p>{ width } x { height }</p>
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,9 @@ fn main() {
|
|||
_ = console_log::init_with_level(log::Level::Debug);
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
mount_to(demo_or_body(), || {
|
||||
let unmount_handle = leptos::mount::mount_to(demo_or_body(), || {
|
||||
view! { <Demo/> }
|
||||
})
|
||||
});
|
||||
|
||||
unmount_handle.forget();
|
||||
}
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
use crate::{UseDocument, UseWindow};
|
||||
use cfg_if::cfg_if;
|
||||
use leptos::html::{CreateElement, ElementType};
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use send_wrapper::SendWrapper;
|
||||
use std::marker::PhantomData;
|
||||
use wasm_bindgen::JsCast;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
use std::ops::Deref;
|
||||
|
||||
/// Used as an argument type to make it easily possible to pass either
|
||||
///
|
||||
|
@ -16,333 +11,197 @@ use wasm_bindgen::JsCast;
|
|||
/// * a `NodeRef`
|
||||
///
|
||||
/// into a function. Used for example in [`fn@crate::use_event_listener`].
|
||||
pub enum ElementMaybeSignal<T, E>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
{
|
||||
Static(SendWrapper<Option<T>>),
|
||||
#[derive(Copy, Clone)]
|
||||
#[cfg_attr(not(debug_assertions), repr(transparent))]
|
||||
pub struct ElementMaybeSignal<T: 'static> {
|
||||
#[cfg(debug_assertions)]
|
||||
defined_at: &'static std::panic::Location<'static>,
|
||||
inner: ElementMaybeSignalType<T>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum ElementMaybeSignalType<T: 'static> {
|
||||
Static(StoredValue<Option<T>, LocalStorage>),
|
||||
Dynamic(Signal<Option<T>, LocalStorage>),
|
||||
_Phantom(PhantomData<fn() -> E>),
|
||||
}
|
||||
|
||||
impl<T, E> Default for ElementMaybeSignal<T, E>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
{
|
||||
impl<T: 'static> Default for ElementMaybeSignalType<T> {
|
||||
fn default() -> Self {
|
||||
Self::Static(SendWrapper::new(None))
|
||||
Self::Static(StoredValue::new_local(None))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> Clone for ElementMaybeSignal<T, E>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Self::Static(t) => Self::Static(t.clone()),
|
||||
Self::Dynamic(s) => Self::Dynamic(*s),
|
||||
_ => unreachable!(),
|
||||
impl<T> Default for ElementMaybeSignal<T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
inner: ElementMaybeSignalType::default(),
|
||||
#[cfg(debug_assertions)]
|
||||
defined_at: std::panic::Location::caller(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> DefinedAt for ElementMaybeSignal<T, E>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
{
|
||||
impl<T> DefinedAt for ElementMaybeSignal<T> {
|
||||
fn defined_at(&self) -> Option<&'static std::panic::Location<'static>> {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
Some(self.defined_at)
|
||||
}
|
||||
#[cfg(not(debug_assertions))]
|
||||
{
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> With for ElementMaybeSignal<T, E>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
{
|
||||
impl<T> With for ElementMaybeSignal<T> {
|
||||
type Value = Option<T>;
|
||||
|
||||
fn with<O>(&self, f: impl FnOnce(&Option<T>) -> O) -> O {
|
||||
match self {
|
||||
Self::Static(t) => f(t),
|
||||
Self::Dynamic(s) => {
|
||||
let value = s.get();
|
||||
f(&value)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_with<O>(&self, f: impl FnOnce(&Option<T>) -> O) -> Option<O> {
|
||||
match self {
|
||||
Self::Static(t) => Some(f(t)),
|
||||
Self::Dynamic(s) => s.try_with(f),
|
||||
_ => unreachable!(),
|
||||
match &self.inner {
|
||||
ElementMaybeSignalType::Static(v) => v.try_with_value(f),
|
||||
ElementMaybeSignalType::Dynamic(s) => s.try_with(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> WithUntracked for ElementMaybeSignal<T, E>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
{
|
||||
impl<T> WithUntracked for ElementMaybeSignal<T> {
|
||||
type Value = Option<T>;
|
||||
|
||||
fn with_untracked<O>(&self, f: impl FnOnce(&Option<T>) -> O) -> O {
|
||||
match self {
|
||||
Self::Static(t) => f(t),
|
||||
Self::Dynamic(s) => s.with_untracked(f),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_with_untracked<O>(&self, f: impl FnOnce(&Option<T>) -> O) -> Option<O> {
|
||||
match self {
|
||||
Self::Static(t) => Some(f(t)),
|
||||
Self::Dynamic(s) => s.try_with_untracked(f),
|
||||
_ => unreachable!(),
|
||||
match &self.inner {
|
||||
ElementMaybeSignalType::Static(t) => t.try_with_value(f),
|
||||
ElementMaybeSignalType::Dynamic(s) => s.try_with_untracked(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait IntoElementMaybeSignal<T, Marker: ?Sized> {
|
||||
fn into_element_maybe_signal(self) -> ElementMaybeSignal<T>;
|
||||
}
|
||||
|
||||
impl<El, T, Marker: ?Sized> IntoElementMaybeSignal<T, Marker> for El
|
||||
where
|
||||
El: IntoElementMaybeSignalType<T, Marker>,
|
||||
{
|
||||
fn into_element_maybe_signal(self) -> ElementMaybeSignal<T> {
|
||||
ElementMaybeSignal {
|
||||
inner: self.into_element_maybe_signal_type(),
|
||||
#[cfg(debug_assertions)]
|
||||
defined_at: std::panic::Location::caller(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait IntoElementMaybeSignalType<T, Marker: ?Sized> {
|
||||
fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T>;
|
||||
}
|
||||
|
||||
// From static element //////////////////////////////////////////////////////////////
|
||||
|
||||
impl<T, E> From<T> for ElementMaybeSignal<T, E>
|
||||
/// Handles `window()` or `document()`
|
||||
impl<T, Js> IntoElementMaybeSignalType<T, web_sys::Element> for Js
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
T: From<Js> + Clone,
|
||||
{
|
||||
fn from(value: T) -> Self {
|
||||
ElementMaybeSignal::Static(SendWrapper::new(Some(value)))
|
||||
fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T> {
|
||||
ElementMaybeSignalType::Static(StoredValue::new_local(Some(T::from(self).clone())))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> From<Option<T>> for ElementMaybeSignal<T, E>
|
||||
/// Handles `window().body()`
|
||||
impl<T, Js> IntoElementMaybeSignalType<T, Option<web_sys::Element>> for Option<Js>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
T: From<Js> + Clone,
|
||||
{
|
||||
fn from(target: Option<T>) -> Self {
|
||||
ElementMaybeSignal::Static(SendWrapper::new(target))
|
||||
fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T> {
|
||||
ElementMaybeSignalType::Static(StoredValue::new_local(self.map(|el| T::from(el).clone())))
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_from_deref_option {
|
||||
($ty:ty, $ty2:ty) => {
|
||||
impl<E> From<$ty> for ElementMaybeSignal<$ty2, E>
|
||||
where
|
||||
E: From<$ty2> + 'static,
|
||||
{
|
||||
fn from(value: $ty) -> Self {
|
||||
Self::Static(SendWrapper::new((*value).clone()))
|
||||
/// Handles `use_window()` or `use_document()`
|
||||
impl<T, E, Js> IntoElementMaybeSignalType<T, Option<Option<web_sys::Element>>> for Js
|
||||
where
|
||||
Js: Deref<Target = Option<E>>,
|
||||
E: Clone,
|
||||
T: From<E> + Clone,
|
||||
{
|
||||
fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T> {
|
||||
ElementMaybeSignalType::Static(StoredValue::new_local(
|
||||
self.as_ref().map(|e| T::from(e.clone())),
|
||||
))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_from_deref_option!(UseWindow, web_sys::Window);
|
||||
impl_from_deref_option!(UseDocument, web_sys::Document);
|
||||
|
||||
// From string (selector) ///////////////////////////////////////////////////////////////
|
||||
|
||||
impl<'a, E> From<&'a str> for ElementMaybeSignal<web_sys::Element, E>
|
||||
/// Handles `"body"` or `"#app"`
|
||||
impl<T, V> IntoElementMaybeSignalType<T, str> for V
|
||||
where
|
||||
E: From<web_sys::Element> + 'static,
|
||||
V: AsRef<str>,
|
||||
T: From<web_sys::Element> + Clone,
|
||||
{
|
||||
fn from(target: &'a str) -> Self {
|
||||
cfg_if! { if #[cfg(feature = "ssr")] {
|
||||
let _ = target;
|
||||
Self::Static(SendWrapper::new(None))
|
||||
fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T> {
|
||||
if cfg!(feature = "ssr") {
|
||||
ElementMaybeSignalType::Static(StoredValue::new_local(None))
|
||||
} else {
|
||||
Self::Static(SendWrapper::new(document().query_selector(target).unwrap_or_default()))
|
||||
}}
|
||||
ElementMaybeSignalType::Static(StoredValue::new_local(
|
||||
document()
|
||||
.query_selector(self.as_ref())
|
||||
.unwrap_or_default()
|
||||
.map(|el| T::from(el).clone()),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> From<String> for ElementMaybeSignal<web_sys::Element, E>
|
||||
pub struct SignalStrMarker;
|
||||
|
||||
/// Handles `Signal<&str>`
|
||||
impl<T, V, I> IntoElementMaybeSignalType<T, SignalStrMarker> for V
|
||||
where
|
||||
E: From<web_sys::Element> + 'static,
|
||||
V: Get<Value = I> + 'static,
|
||||
I: AsRef<str>,
|
||||
T: From<web_sys::Element> + Clone,
|
||||
{
|
||||
fn from(target: String) -> Self {
|
||||
Self::from(target.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_from_signal_string {
|
||||
($ty:ty) => {
|
||||
impl<E> From<$ty> for ElementMaybeSignal<web_sys::Element, E>
|
||||
where
|
||||
E: From<web_sys::Element> + 'static,
|
||||
{
|
||||
fn from(signal: $ty) -> Self {
|
||||
cfg_if! { if #[cfg(feature = "ssr")] {
|
||||
let _ = signal;
|
||||
Self::Dynamic(Signal::derive_local(|| None))
|
||||
fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T> {
|
||||
if cfg!(feature = "ssr") {
|
||||
ElementMaybeSignalType::Static(StoredValue::new_local(None))
|
||||
} else {
|
||||
Self::Dynamic(
|
||||
Signal::derive_local(move || document().query_selector(&signal.get()).unwrap_or_default()),
|
||||
)
|
||||
}}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_from_signal_string!(Signal<String>);
|
||||
impl_from_signal_string!(ReadSignal<String>);
|
||||
impl_from_signal_string!(RwSignal<String>);
|
||||
impl_from_signal_string!(Memo<String>);
|
||||
|
||||
impl_from_signal_string!(Signal<&'static str>);
|
||||
impl_from_signal_string!(ReadSignal<&'static str>);
|
||||
impl_from_signal_string!(RwSignal<&'static str>);
|
||||
impl_from_signal_string!(Memo<&'static str>);
|
||||
|
||||
// From signal ///////////////////////////////////////////////////////////////
|
||||
|
||||
macro_rules! impl_from_signal_option {
|
||||
($ty:ty) => {
|
||||
impl<T, E> From<$ty> for ElementMaybeSignal<T, E>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
{
|
||||
fn from(target: $ty) -> Self {
|
||||
Self::Dynamic(target.into())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_from_signal_option!(Signal<Option<T>, LocalStorage>);
|
||||
impl_from_signal_option!(ReadSignal<Option<T>, LocalStorage>);
|
||||
impl_from_signal_option!(RwSignal<Option<T>, LocalStorage>);
|
||||
impl_from_signal_option!(Memo<Option<T>, LocalStorage>);
|
||||
|
||||
macro_rules! impl_from_signal {
|
||||
($ty:ty) => {
|
||||
impl<T, E> From<$ty> for ElementMaybeSignal<T, E>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
{
|
||||
fn from(signal: $ty) -> Self {
|
||||
Self::Dynamic(Signal::derive_local(move || Some(signal.get())))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_from_signal!(Signal<T, LocalStorage>);
|
||||
impl_from_signal!(ReadSignal<T, LocalStorage>);
|
||||
impl_from_signal!(RwSignal<T, LocalStorage>);
|
||||
impl_from_signal!(Memo<T, LocalStorage>);
|
||||
|
||||
// From NodeRef //////////////////////////////////////////////////////////////
|
||||
|
||||
macro_rules! impl_from_node_ref {
|
||||
($ty:ty) => {
|
||||
impl<R> From<NodeRef<R>> for ElementMaybeSignal<$ty, $ty>
|
||||
where
|
||||
R: ElementType + CreateElement<Dom> + Clone + Send + Sync + 'static,
|
||||
R::Output: JsCast + Into<$ty> + Clone + 'static,
|
||||
{
|
||||
fn from(node_ref: NodeRef<R>) -> Self {
|
||||
Self::Dynamic(Signal::derive_local(move || {
|
||||
node_ref.get().map(move |el| {
|
||||
let el: $ty = el.clone().into();
|
||||
el
|
||||
})
|
||||
ElementMaybeSignalType::Dynamic(Signal::derive_local(move || {
|
||||
document()
|
||||
.query_selector(self.get().as_ref())
|
||||
.unwrap_or_default()
|
||||
.map(|el| T::from(el).clone())
|
||||
}))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_from_node_ref!(web_sys::EventTarget);
|
||||
impl_from_node_ref!(web_sys::Element);
|
||||
impl_from_node_ref!(web_sys::HtmlElement);
|
||||
// From signal ///////////////////////////////////////////////////////////////
|
||||
|
||||
// // From leptos::html::HTMLElement ///////////////////////////////////////////////
|
||||
//
|
||||
// macro_rules! impl_from_html_element {
|
||||
// ($ty:ty) => {
|
||||
// impl<HtmlEl> From<HtmlElement<HtmlEl>> for ElementMaybeSignal<$ty, $ty>
|
||||
// where
|
||||
// HtmlEl: ElementDescriptor + std::ops::Deref<Target = $ty>,
|
||||
// {
|
||||
// fn from(value: HtmlElement<HtmlEl>) -> Self {
|
||||
// let el: &$ty = value.deref();
|
||||
// Self::Static(Some(el.clone()))
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
//
|
||||
// impl_from_html_element!(web_sys::EventTarget);
|
||||
// impl_from_html_element!(web_sys::Element);
|
||||
// impl_from_html_element!(web_sys::HtmlElement);
|
||||
//
|
||||
// // From Signal<leptos::html::HTMLElement> /////////////////////////////////////////
|
||||
//
|
||||
// macro_rules! impl_from_signal_html_element {
|
||||
// ($signal:ty, $ty:ty) => {
|
||||
// impl<HtmlEl> From<$signal> for ElementMaybeSignal<$ty, $ty>
|
||||
// where
|
||||
// HtmlEl: ElementDescriptor + std::ops::Deref<Target = $ty> + Clone,
|
||||
// {
|
||||
// fn from(value: $signal) -> Self {
|
||||
// Self::Dynamic(Signal::derive(move || {
|
||||
// let value = value.get();
|
||||
// let el: &$ty = value.deref();
|
||||
// Some(el.clone())
|
||||
// }))
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
//
|
||||
// impl_from_signal_html_element!(Signal<HtmlElement<HtmlEl>>, web_sys::EventTarget);
|
||||
// impl_from_signal_html_element!(ReadSignal<HtmlElement<HtmlEl>>, web_sys::EventTarget);
|
||||
// impl_from_signal_html_element!(RwSignal<HtmlElement<HtmlEl>>, web_sys::EventTarget);
|
||||
// impl_from_signal_html_element!(Memo<HtmlElement<HtmlEl>>, web_sys::EventTarget);
|
||||
//
|
||||
// impl_from_signal_html_element!(Signal<HtmlElement<HtmlEl>>, web_sys::Element);
|
||||
// impl_from_signal_html_element!(ReadSignal<HtmlElement<HtmlEl>>, web_sys::Element);
|
||||
// impl_from_signal_html_element!(RwSignal<HtmlElement<HtmlEl>>, web_sys::Element);
|
||||
// impl_from_signal_html_element!(Memo<HtmlElement<HtmlEl>>, web_sys::Element);
|
||||
//
|
||||
// // From Signal<Option<leptos::html::HTMLElement>> /////////////////////////////////////////
|
||||
//
|
||||
// macro_rules! impl_from_signal_html_element {
|
||||
// ($signal:ty, $ty:ty) => {
|
||||
// impl<HtmlEl> From<$signal> for ElementMaybeSignal<$ty, $ty>
|
||||
// where
|
||||
// HtmlEl: ElementDescriptor + std::ops::Deref<Target = $ty> + Clone,
|
||||
// {
|
||||
// fn from(value: $signal) -> Self {
|
||||
// Self::Dynamic(Signal::derive(move || {
|
||||
// let el: Option<$ty> = value.get().map(|el| el.deref().clone());
|
||||
// el
|
||||
// }))
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
//
|
||||
// impl_from_signal_html_element!(Signal<Option<HtmlElement<HtmlEl>>>, web_sys::EventTarget);
|
||||
// impl_from_signal_html_element!(
|
||||
// ReadSignal<Option<HtmlElement<HtmlEl>>>,
|
||||
// web_sys::EventTarget
|
||||
// );
|
||||
// impl_from_signal_html_element!(RwSignal<Option<HtmlElement<HtmlEl>>>, web_sys::EventTarget);
|
||||
// impl_from_signal_html_element!(Memo<Option<HtmlElement<HtmlEl>>>, web_sys::EventTarget);
|
||||
//
|
||||
// impl_from_signal_html_element!(Signal<Option<HtmlElement<HtmlEl>>>, web_sys::Element);
|
||||
// impl_from_signal_html_element!(ReadSignal<Option<HtmlElement<HtmlEl>>>, web_sys::Element);
|
||||
// impl_from_signal_html_element!(RwSignal<Option<HtmlElement<HtmlEl>>>, web_sys::Element);
|
||||
// impl_from_signal_html_element!(Memo<Option<HtmlElement<HtmlEl>>>, web_sys::Element);
|
||||
//
|
||||
// impl_from_signal_html_element!(Signal<Option<HtmlElement<HtmlEl>>>, web_sys::HtmlElement);
|
||||
// impl_from_signal_html_element!(
|
||||
// ReadSignal<Option<HtmlElement<HtmlEl>>>,
|
||||
// web_sys::HtmlElement
|
||||
// );
|
||||
// impl_from_signal_html_element!(RwSignal<Option<HtmlElement<HtmlEl>>>, web_sys::HtmlElement);
|
||||
// impl_from_signal_html_element!(Memo<Option<HtmlElement<HtmlEl>>>, web_sys::HtmlElement);
|
||||
pub struct SignalMarker;
|
||||
|
||||
/// Handles `Signal<web_sys::*>`
|
||||
impl<T, V, E> IntoElementMaybeSignalType<T, SignalMarker> for V
|
||||
where
|
||||
V: Get<Value = E> + 'static,
|
||||
T: From<E> + Clone,
|
||||
{
|
||||
fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T> {
|
||||
ElementMaybeSignalType::Dynamic(Signal::derive_local(move || Some(T::from(self.get()))))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OptionSignalMarker;
|
||||
|
||||
/// Handles `Signal<Option<web_sys::*>>` and `NodeRef` and `ElementMaybeSignal`
|
||||
impl<T, V, E> IntoElementMaybeSignalType<T, OptionSignalMarker> for V
|
||||
where
|
||||
V: Get<Value = Option<E>> + 'static,
|
||||
T: From<E> + Clone,
|
||||
{
|
||||
fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T> {
|
||||
ElementMaybeSignalType::Dynamic(Signal::derive_local(move || self.get().map(T::from)))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,7 @@
|
|||
use crate::core::ElementMaybeSignal;
|
||||
use crate::{UseDocument, UseWindow};
|
||||
use cfg_if::cfg_if;
|
||||
use leptos::html::ElementType;
|
||||
use crate::core::{SignalMarker, SignalStrMarker};
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use send_wrapper::SendWrapper;
|
||||
use std::marker::PhantomData;
|
||||
use wasm_bindgen::JsCast;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
use std::ops::Deref;
|
||||
|
||||
/// Used as an argument type to make it easily possible to pass either
|
||||
///
|
||||
|
@ -17,656 +12,345 @@ use wasm_bindgen::JsCast;
|
|||
/// * a `NodeRef`
|
||||
///
|
||||
/// into a function. Used for example in [`fn@crate::use_event_listener`].
|
||||
pub enum ElementsMaybeSignal<T, E>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
{
|
||||
Static(SendWrapper<Vec<Option<T>>>),
|
||||
#[derive(Copy, Clone)]
|
||||
#[cfg_attr(not(debug_assertions), repr(transparent))]
|
||||
pub struct ElementsMaybeSignal<T: 'static> {
|
||||
#[cfg(debug_assertions)]
|
||||
defined_at: &'static std::panic::Location<'static>,
|
||||
inner: ElementsMaybeSignalType<T>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum ElementsMaybeSignalType<T: 'static> {
|
||||
Static(StoredValue<Vec<Option<T>>, LocalStorage>),
|
||||
Dynamic(Signal<Vec<Option<T>>, LocalStorage>),
|
||||
_Phantom(PhantomData<fn() -> E>),
|
||||
}
|
||||
|
||||
impl<T, E> Default for ElementsMaybeSignal<T, E>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
{
|
||||
impl<T: 'static> Default for ElementsMaybeSignalType<T> {
|
||||
fn default() -> Self {
|
||||
Self::Static(SendWrapper::new(vec![]))
|
||||
Self::Static(StoredValue::new_local(vec![]))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> Clone for ElementsMaybeSignal<T, E>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Self::Static(v) => Self::Static(v.clone()),
|
||||
Self::Dynamic(s) => Self::Dynamic(*s),
|
||||
Self::_Phantom(_) => unreachable!(),
|
||||
impl<T> Default for ElementsMaybeSignal<T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
inner: ElementsMaybeSignalType::default(),
|
||||
#[cfg(debug_assertions)]
|
||||
defined_at: std::panic::Location::caller(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> DefinedAt for ElementsMaybeSignal<T, E>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
{
|
||||
impl<T> DefinedAt for ElementsMaybeSignal<T> {
|
||||
fn defined_at(&self) -> Option<&'static std::panic::Location<'static>> {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
Some(self.defined_at)
|
||||
}
|
||||
#[cfg(not(debug_assertions))]
|
||||
{
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> With for ElementsMaybeSignal<T, E>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
{
|
||||
impl<T> With for ElementsMaybeSignal<T> {
|
||||
type Value = Vec<Option<T>>;
|
||||
|
||||
fn with<O>(&self, f: impl FnOnce(&Vec<Option<T>>) -> O) -> O {
|
||||
match self {
|
||||
Self::Static(v) => f(v),
|
||||
Self::Dynamic(s) => s.with(f),
|
||||
Self::_Phantom(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_with<O>(&self, f: impl FnOnce(&Vec<Option<T>>) -> O) -> Option<O> {
|
||||
match self {
|
||||
Self::Static(v) => Some(f(v)),
|
||||
Self::Dynamic(s) => s.try_with(f),
|
||||
Self::_Phantom(_) => unreachable!(),
|
||||
match &self.inner {
|
||||
ElementsMaybeSignalType::Static(v) => v.try_with_value(f),
|
||||
ElementsMaybeSignalType::Dynamic(s) => s.try_with(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> WithUntracked for ElementsMaybeSignal<T, E>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
{
|
||||
impl<T> WithUntracked for ElementsMaybeSignal<T> {
|
||||
type Value = Vec<Option<T>>;
|
||||
|
||||
fn with_untracked<O>(&self, f: impl FnOnce(&Vec<Option<T>>) -> O) -> O {
|
||||
match self {
|
||||
Self::Static(t) => f(t),
|
||||
Self::Dynamic(s) => s.with_untracked(f),
|
||||
Self::_Phantom(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_with_untracked<O>(&self, f: impl FnOnce(&Vec<Option<T>>) -> O) -> Option<O> {
|
||||
match self {
|
||||
Self::Static(t) => Some(f(t)),
|
||||
Self::Dynamic(s) => s.try_with_untracked(f),
|
||||
Self::_Phantom(_) => unreachable!(),
|
||||
match self.inner {
|
||||
ElementsMaybeSignalType::Static(t) => t.try_with_value(f),
|
||||
ElementsMaybeSignalType::Dynamic(s) => s.try_with_untracked(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait IntoElementsMaybeSignal<T, Marker: ?Sized> {
|
||||
fn into_elements_maybe_signal(self) -> ElementsMaybeSignal<T>;
|
||||
}
|
||||
|
||||
impl<El, T, Marker: ?Sized> IntoElementsMaybeSignal<T, Marker> for El
|
||||
where
|
||||
El: IntoElementsMaybeSignalType<T, Marker>,
|
||||
{
|
||||
fn into_elements_maybe_signal(self) -> ElementsMaybeSignal<T> {
|
||||
ElementsMaybeSignal {
|
||||
inner: self.into_elements_maybe_signal_type(),
|
||||
#[cfg(debug_assertions)]
|
||||
defined_at: std::panic::Location::caller(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait IntoElementsMaybeSignalType<T, Marker: ?Sized> {
|
||||
fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T>;
|
||||
}
|
||||
|
||||
// From single static element //////////////////////////////////////////////////////////////
|
||||
|
||||
impl<T, E> From<T> for ElementsMaybeSignal<T, E>
|
||||
/// Handles `window()` or `document()`
|
||||
impl<T, Js> IntoElementsMaybeSignalType<T, web_sys::Element> for Js
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
T: From<Js> + Clone,
|
||||
{
|
||||
fn from(value: T) -> Self {
|
||||
ElementsMaybeSignal::Static(SendWrapper::new(vec![Some(value)]))
|
||||
fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
|
||||
ElementsMaybeSignalType::Static(StoredValue::new_local(vec![Some(T::from(self).clone())]))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> From<Option<T>> for ElementsMaybeSignal<T, E>
|
||||
/// Handles `window().body()`
|
||||
impl<T, Js> IntoElementsMaybeSignalType<T, Option<web_sys::Element>> for Option<Js>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
T: From<Js> + Clone,
|
||||
{
|
||||
fn from(target: Option<T>) -> Self {
|
||||
ElementsMaybeSignal::Static(SendWrapper::new(vec![target]))
|
||||
fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
|
||||
ElementsMaybeSignalType::Static(StoredValue::new_local(vec![
|
||||
self.map(|el| T::from(el).clone())
|
||||
]))
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_from_deref_option {
|
||||
($ty:ty, $ty2:ty) => {
|
||||
impl<E> From<$ty> for ElementsMaybeSignal<$ty2, E>
|
||||
where
|
||||
E: From<$ty2> + 'static,
|
||||
{
|
||||
fn from(value: $ty) -> Self {
|
||||
Self::Static(SendWrapper::new(vec![(*value).clone()]))
|
||||
/// Handles `use_window()` or `use_document()`
|
||||
impl<T, E, Js> IntoElementsMaybeSignalType<T, Option<Option<web_sys::Element>>> for Js
|
||||
where
|
||||
Js: Deref<Target = Option<E>>,
|
||||
E: Clone,
|
||||
T: From<E> + Clone,
|
||||
{
|
||||
fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
|
||||
ElementsMaybeSignalType::Static(StoredValue::new_local(vec![self
|
||||
.as_ref()
|
||||
.map(|e| T::from(e.clone()))]))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_from_deref_option!(UseWindow, web_sys::Window);
|
||||
impl_from_deref_option!(UseDocument, web_sys::Document);
|
||||
|
||||
// From string (selector) ///////////////////////////////////////////////////////////////
|
||||
|
||||
impl<'a, E> From<&'a str> for ElementsMaybeSignal<web_sys::Node, E>
|
||||
/// Handles `"body"` or `"#app"`
|
||||
impl<T, V> IntoElementsMaybeSignalType<T, str> for V
|
||||
where
|
||||
E: From<web_sys::Node> + 'static,
|
||||
V: AsRef<str>,
|
||||
T: From<web_sys::Element> + Clone,
|
||||
{
|
||||
fn from(target: &'a str) -> Self {
|
||||
cfg_if! { if #[cfg(feature = "ssr")] {
|
||||
let _ = target;
|
||||
Self::Static(SendWrapper::new(vec![]))
|
||||
fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
|
||||
if cfg!(feature = "ssr") {
|
||||
ElementsMaybeSignalType::Static(StoredValue::new_local(vec![]))
|
||||
} else {
|
||||
if let Ok(node_list) = document().query_selector_all(target) {
|
||||
let mut list = Vec::with_capacity(node_list.length() as usize);
|
||||
for i in 0..node_list.length() {
|
||||
let node = node_list.get(i).expect("checked the range");
|
||||
list.push(Some(node));
|
||||
ElementsMaybeSignalType::Static(StoredValue::new_local(vec![document()
|
||||
.query_selector(self.as_ref())
|
||||
.unwrap_or_default()
|
||||
.map(|el| T::from(el).clone())]))
|
||||
}
|
||||
|
||||
Self::Static(SendWrapper::new(list))
|
||||
} else {
|
||||
Self::Static(SendWrapper::new(vec![]))
|
||||
}
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> From<String> for ElementsMaybeSignal<web_sys::Node, E>
|
||||
/// Handles `Signal<&str>`
|
||||
impl<T, V, I> IntoElementsMaybeSignalType<T, SignalStrMarker> for V
|
||||
where
|
||||
E: From<web_sys::Node> + 'static,
|
||||
V: Get<Value = I> + 'static,
|
||||
I: AsRef<str>,
|
||||
T: From<web_sys::Element> + Clone,
|
||||
{
|
||||
fn from(target: String) -> Self {
|
||||
Self::from(target.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_from_signal_string {
|
||||
($ty:ty) => {
|
||||
impl<E> From<$ty> for ElementsMaybeSignal<web_sys::Node, E>
|
||||
where
|
||||
E: From<web_sys::Node> + 'static,
|
||||
{
|
||||
fn from(signal: $ty) -> Self {
|
||||
cfg_if! { if #[cfg(feature = "ssr")] {
|
||||
Self::Dynamic(
|
||||
Signal::derive_local(move || {
|
||||
if let Ok(node_list) = document().query_selector_all(&signal.get()) {
|
||||
let mut list = Vec::with_capacity(node_list.length() as usize);
|
||||
for i in 0..node_list.length() {
|
||||
let node = node_list.get(i).expect("checked the range");
|
||||
list.push(Some(node));
|
||||
}
|
||||
list
|
||||
fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
|
||||
if cfg!(feature = "ssr") {
|
||||
ElementsMaybeSignalType::Static(StoredValue::new_local(vec![]))
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
}),
|
||||
)
|
||||
} else {
|
||||
let _ = signal;
|
||||
Self::Dynamic(Signal::derive_local(Vec::new))
|
||||
}}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_from_signal_string!(Signal<String>);
|
||||
impl_from_signal_string!(ReadSignal<String>);
|
||||
impl_from_signal_string!(RwSignal<String>);
|
||||
impl_from_signal_string!(Memo<String>);
|
||||
|
||||
impl_from_signal_string!(Signal<&'static str>);
|
||||
impl_from_signal_string!(ReadSignal<&'static str>);
|
||||
impl_from_signal_string!(RwSignal<&'static str>);
|
||||
impl_from_signal_string!(Memo<&'static str>);
|
||||
|
||||
// From single signal ///////////////////////////////////////////////////////////////
|
||||
|
||||
macro_rules! impl_from_signal_option {
|
||||
($ty:ty) => {
|
||||
impl<T, E> From<$ty> for ElementsMaybeSignal<T, E>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
{
|
||||
fn from(signal: $ty) -> Self {
|
||||
Self::Dynamic(Signal::derive_local(move || vec![signal.get()]))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_from_signal_option!(Signal<Option<T>, LocalStorage>);
|
||||
impl_from_signal_option!(ReadSignal<Option<T>, LocalStorage>);
|
||||
impl_from_signal_option!(RwSignal<Option<T>, LocalStorage>);
|
||||
impl_from_signal_option!(Memo<Option<T>, LocalStorage>);
|
||||
|
||||
macro_rules! impl_from_signal {
|
||||
($ty:ty) => {
|
||||
impl<T, E> From<$ty> for ElementsMaybeSignal<T, E>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
{
|
||||
fn from(signal: $ty) -> Self {
|
||||
Self::Dynamic(Signal::derive_local(move || vec![Some(signal.get())]))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_from_signal!(Signal<T, LocalStorage>);
|
||||
impl_from_signal!(ReadSignal<T, LocalStorage>);
|
||||
impl_from_signal!(RwSignal<T, LocalStorage>);
|
||||
impl_from_signal!(Memo<T, LocalStorage>);
|
||||
|
||||
// From single NodeRef //////////////////////////////////////////////////////////////
|
||||
|
||||
macro_rules! impl_from_node_ref {
|
||||
($ty:ty) => {
|
||||
impl<R> From<NodeRef<R>> for ElementsMaybeSignal<$ty, $ty>
|
||||
where
|
||||
R: ElementType + Clone + 'static,
|
||||
R::Output: JsCast + Into<$ty> + Clone + 'static,
|
||||
{
|
||||
fn from(node_ref: NodeRef<R>) -> Self {
|
||||
Self::Dynamic(Signal::derive_local(move || {
|
||||
vec![node_ref.get().map(move |el| {
|
||||
let el: $ty = el.clone().into();
|
||||
el
|
||||
})]
|
||||
ElementsMaybeSignalType::Dynamic(Signal::derive_local(move || {
|
||||
vec![document()
|
||||
.query_selector(self.get().as_ref())
|
||||
.unwrap_or_default()
|
||||
.map(|el| T::from(el).clone())]
|
||||
}))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_from_node_ref!(web_sys::EventTarget);
|
||||
impl_from_node_ref!(web_sys::Element);
|
||||
// From single signal ///////////////////////////////////////////////////////////////
|
||||
|
||||
// From single leptos::html::HTMLElement ///////////////////////////////////////////
|
||||
|
||||
// macro_rules! impl_from_html_element {
|
||||
// ($ty:ty) => {
|
||||
// impl<E, At, Ch, Rndr> From<HtmlElement<E, At, Ch, Rndr>> for ElementsMaybeSignal<$ty, $ty>
|
||||
// where
|
||||
// E: ElementType,
|
||||
// E::Output: std::ops::Deref<Target = $ty>,
|
||||
// {
|
||||
// fn from(value: HtmlElement<E, At, Ch, Rndr>) -> Self {
|
||||
// let el: &$ty = value.deref();
|
||||
// Self::Static(vec![Some(el.clone())])
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
//
|
||||
// impl_from_html_element!(web_sys::EventTarget);
|
||||
// impl_from_html_element!(web_sys::Element);
|
||||
/// Handles `Signal<web_sys::*>`
|
||||
impl<T, V, E> IntoElementsMaybeSignalType<T, SignalMarker> for V
|
||||
where
|
||||
V: Get<Value = E> + 'static,
|
||||
T: From<E> + Clone,
|
||||
{
|
||||
fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
|
||||
ElementsMaybeSignalType::Dynamic(Signal::derive_local(move || {
|
||||
vec![Some(T::from(self.get()))]
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
// From multiple static elements //////////////////////////////////////////////////////
|
||||
|
||||
impl<T, E> From<&[T]> for ElementsMaybeSignal<T, E>
|
||||
/// Handles `&[web_sys::*]`
|
||||
impl<'a, T, Js, C> IntoElementsMaybeSignalType<T, &'a [web_sys::Element]> for C
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
Js: Clone + 'a,
|
||||
T: From<Js>,
|
||||
C: IntoIterator<Item = &'a Js>,
|
||||
{
|
||||
fn from(target: &[T]) -> Self {
|
||||
Self::Static(SendWrapper::new(
|
||||
target.iter().map(|t| Some(t.clone())).collect(),
|
||||
fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
|
||||
ElementsMaybeSignalType::Static(StoredValue::new_local(
|
||||
self.into_iter().map(|t| Some(T::from(t.clone()))).collect(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> From<&[Option<T>]> for ElementsMaybeSignal<T, E>
|
||||
/// Handles `&[Option<web_sys::*>]`
|
||||
impl<'a, T, Js, C> IntoElementsMaybeSignalType<T, &'a [Option<web_sys::Element>]> for C
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
Js: Clone + 'a,
|
||||
T: From<Js>,
|
||||
C: IntoIterator<Item = &'a Option<Js>>,
|
||||
{
|
||||
fn from(target: &[Option<T>]) -> Self {
|
||||
Self::Static(SendWrapper::new(target.to_vec()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> From<Vec<T>> for ElementsMaybeSignal<T, E>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
{
|
||||
fn from(target: Vec<T>) -> Self {
|
||||
Self::Static(SendWrapper::new(
|
||||
target.iter().map(|t| Some(t.clone())).collect(),
|
||||
fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
|
||||
ElementsMaybeSignalType::Static(StoredValue::new_local(
|
||||
self.into_iter().map(|t| t.clone().map(T::from)).collect(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> From<Vec<Option<T>>> for ElementsMaybeSignal<T, E>
|
||||
/// Handles `Vec<web_sys::*>`
|
||||
impl<T, Js, C> IntoElementsMaybeSignalType<T, Vec<web_sys::Element>> for C
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
T: From<Js> + Clone,
|
||||
C: IntoIterator<Item = Js>,
|
||||
{
|
||||
fn from(target: Vec<Option<T>>) -> Self {
|
||||
Self::Static(SendWrapper::new(target.into_iter().collect()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E, const C: usize> From<[T; C]> for ElementsMaybeSignal<T, E>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
{
|
||||
fn from(target: [T; C]) -> Self {
|
||||
Self::Static(SendWrapper::new(
|
||||
target.into_iter().map(|t| Some(t)).collect(),
|
||||
fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
|
||||
ElementsMaybeSignalType::Static(StoredValue::new_local(
|
||||
self.into_iter().map(|t| Some(T::from(t))).collect(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E, const C: usize> From<[Option<T>; C]> for ElementsMaybeSignal<T, E>
|
||||
/// Handles `Vec<Option<web_sys::*>>`
|
||||
impl<T, Js, C> IntoElementsMaybeSignalType<T, Vec<Option<web_sys::Element>>> for C
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
T: From<Js> + Clone,
|
||||
C: IntoIterator<Item = Option<Js>>,
|
||||
{
|
||||
fn from(target: [Option<T>; C]) -> Self {
|
||||
Self::Static(SendWrapper::new(target.into_iter().collect()))
|
||||
fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
|
||||
ElementsMaybeSignalType::Static(StoredValue::new_local(
|
||||
self.into_iter().map(|t| t.map(T::from)).collect(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
// From multiple strings //////////////////////////////////////////////////////
|
||||
|
||||
macro_rules! impl_from_strings_inner {
|
||||
($el_ty:ty, $str_ty:ty, $target:ident) => {
|
||||
Self::Static(
|
||||
SendWrapper::new(
|
||||
$target
|
||||
.iter()
|
||||
.filter_map(|sel: &$str_ty| -> Option<Vec<Option<$el_ty>>> {
|
||||
cfg_if! { if #[cfg(feature = "ssr")] {
|
||||
let _ = sel;
|
||||
None
|
||||
} else {
|
||||
use wasm_bindgen::JsCast;
|
||||
|
||||
if let Ok(node_list) = document().query_selector_all(sel) {
|
||||
let mut list = Vec::with_capacity(node_list.length() as usize);
|
||||
for i in 0..node_list.length() {
|
||||
let node: $el_ty = node_list.get(i).expect("checked the range").unchecked_into();
|
||||
list.push(Some(node));
|
||||
}
|
||||
|
||||
Some(list)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}}
|
||||
})
|
||||
.flatten()
|
||||
.collect(),
|
||||
)
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_from_strings_with_container {
|
||||
($el_ty:ty, $str_ty:ty, $container_ty:ty) => {
|
||||
impl From<$container_ty> for ElementsMaybeSignal<$el_ty, $el_ty> {
|
||||
fn from(target: $container_ty) -> Self {
|
||||
impl_from_strings_inner!($el_ty, $str_ty, target)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_from_strings {
|
||||
($el_ty:ty, $str_ty:ty) => {
|
||||
impl_from_strings_with_container!($el_ty, $str_ty, Vec<$str_ty>);
|
||||
impl_from_strings_with_container!($el_ty, $str_ty, &[$str_ty]);
|
||||
impl<const C: usize> From<[$str_ty; C]> for ElementsMaybeSignal<$el_ty, $el_ty> {
|
||||
fn from(target: [$str_ty; C]) -> Self {
|
||||
impl_from_strings_inner!($el_ty, $str_ty, target)
|
||||
}
|
||||
}
|
||||
impl<const C: usize> From<&[$str_ty; C]> for ElementsMaybeSignal<$el_ty, $el_ty> {
|
||||
fn from(target: &[$str_ty; C]) -> Self {
|
||||
impl_from_strings_inner!($el_ty, $str_ty, target)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_from_strings!(web_sys::Element, &str);
|
||||
impl_from_strings!(web_sys::Element, String);
|
||||
impl_from_strings!(web_sys::EventTarget, &str);
|
||||
impl_from_strings!(web_sys::EventTarget, String);
|
||||
|
||||
// From signal of vec ////////////////////////////////////////////////////////////////
|
||||
|
||||
impl<T, E> From<Signal<Vec<T>, LocalStorage>> for ElementsMaybeSignal<T, E>
|
||||
/// Handles `["body", "#app"]`
|
||||
impl<T, V, C> IntoElementsMaybeSignalType<T, &[&str]> for C
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
V: AsRef<str>,
|
||||
T: From<web_sys::Element> + Clone,
|
||||
C: IntoIterator<Item = V>,
|
||||
{
|
||||
fn from(signal: Signal<Vec<T>, LocalStorage>) -> Self {
|
||||
Self::Dynamic(Signal::derive_local(move || {
|
||||
signal.get().into_iter().map(|t| Some(t)).collect()
|
||||
fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
|
||||
if cfg!(feature = "ssr") {
|
||||
ElementsMaybeSignalType::Static(StoredValue::new_local(vec![]))
|
||||
} else {
|
||||
ElementsMaybeSignalType::Static(StoredValue::new_local(
|
||||
self.into_iter()
|
||||
.map(|sel| {
|
||||
document()
|
||||
.query_selector(sel.as_ref())
|
||||
.unwrap_or_default()
|
||||
.map(|el| T::from(el).clone())
|
||||
})
|
||||
.collect(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// From signal of multiple ////////////////////////////////////////////////////////////////
|
||||
|
||||
pub struct SignalVecMarker;
|
||||
|
||||
/// Handles `Signal<Vec<web_sys::*>>` and `Signal<Option<web_sys::*>>` and `NodeRef` and `ElementMaybeSignal`
|
||||
impl<T, Js, C, G> IntoElementsMaybeSignalType<T, SignalVecMarker> for G
|
||||
where
|
||||
T: From<Js> + Clone,
|
||||
G: Get<Value = C> + 'static,
|
||||
C: IntoIterator<Item = Js>,
|
||||
{
|
||||
fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
|
||||
ElementsMaybeSignalType::Dynamic(Signal::derive_local(move || {
|
||||
self.get().into_iter().map(|t| Some(T::from(t))).collect()
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> From<Signal<Vec<Option<T>>, LocalStorage>> for ElementsMaybeSignal<T, E>
|
||||
pub struct SignalVecOptionMarker;
|
||||
|
||||
/// Handles `Signal<Vec<Option<web_sys::*>>>`
|
||||
impl<T, Js, C, G> IntoElementsMaybeSignalType<T, SignalVecOptionMarker> for G
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
T: From<Js> + Clone,
|
||||
G: Get<Value = C> + 'static,
|
||||
C: IntoIterator<Item = Option<Js>>,
|
||||
{
|
||||
fn from(target: Signal<Vec<Option<T>>, LocalStorage>) -> Self {
|
||||
Self::Dynamic(target)
|
||||
fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
|
||||
ElementsMaybeSignalType::Dynamic(Signal::derive_local(move || {
|
||||
self.get().into_iter().map(|t| t.map(T::from)).collect()
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
// From multiple signals //////////////////////////////////////////////////////////////
|
||||
|
||||
impl<T, E> From<&[Signal<T, LocalStorage>]> for ElementsMaybeSignal<T, E>
|
||||
pub struct VecSignalMarker;
|
||||
|
||||
/// Handles `Vec<Signal<web_sys::*>>`
|
||||
impl<T, Js, C, G> IntoElementsMaybeSignalType<T, VecSignalMarker> for C
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
T: From<Js> + Clone,
|
||||
C: IntoIterator<Item = G> + Clone + 'static,
|
||||
G: Get<Value = Js>,
|
||||
{
|
||||
fn from(list: &[Signal<T, LocalStorage>]) -> Self {
|
||||
let list = list.to_vec();
|
||||
fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
|
||||
let signals = self.clone();
|
||||
|
||||
Self::Dynamic(Signal::derive_local(move || {
|
||||
list.iter().map(|t| Some(t.get())).collect()
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> From<&[Signal<Option<T>, LocalStorage>]> for ElementsMaybeSignal<T, E>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
{
|
||||
fn from(list: &[Signal<Option<T>, LocalStorage>]) -> Self {
|
||||
let list = list.to_vec();
|
||||
|
||||
Self::Dynamic(Signal::derive_local(move || {
|
||||
list.iter().map(|t| t.get()).collect()
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> From<Vec<Signal<T, LocalStorage>>> for ElementsMaybeSignal<T, E>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
{
|
||||
fn from(list: Vec<Signal<T, LocalStorage>>) -> Self {
|
||||
let list = list.clone();
|
||||
|
||||
Self::Dynamic(Signal::derive_local(move || {
|
||||
list.iter().map(|t| Some(t.get())).collect()
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> From<Vec<Signal<Option<T>, LocalStorage>>> for ElementsMaybeSignal<T, E>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
{
|
||||
fn from(list: Vec<Signal<Option<T>, LocalStorage>>) -> Self {
|
||||
let list = list.clone();
|
||||
|
||||
Self::Dynamic(Signal::derive_local(move || {
|
||||
list.iter().map(|t| t.get()).collect()
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E, const C: usize> From<[Signal<T, LocalStorage>; C]> for ElementsMaybeSignal<T, E>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
{
|
||||
fn from(list: [Signal<T, LocalStorage>; C]) -> Self {
|
||||
let list = list.to_vec();
|
||||
|
||||
Self::Dynamic(Signal::derive_local(move || {
|
||||
list.iter().map(|t| Some(t.get())).collect()
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E, const C: usize> From<[Signal<Option<T>, LocalStorage>; C]> for ElementsMaybeSignal<T, E>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
{
|
||||
fn from(list: [Signal<Option<T>, LocalStorage>; C]) -> Self {
|
||||
let list = list.to_vec();
|
||||
|
||||
Self::Dynamic(Signal::derive_local(move || {
|
||||
list.iter().map(|t| t.get()).collect()
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
// From multiple NodeRefs //////////////////////////////////////////////////////////////
|
||||
|
||||
macro_rules! impl_from_multi_node_ref_inner {
|
||||
($ty:ty, $node_refs:ident) => {
|
||||
Self::Dynamic(Signal::derive_local(move || {
|
||||
$node_refs
|
||||
.iter()
|
||||
.map(|node_ref| {
|
||||
node_ref.get().map(move |el| {
|
||||
let el: $ty = el.clone().into();
|
||||
el
|
||||
})
|
||||
})
|
||||
ElementsMaybeSignalType::Dynamic(Signal::derive_local(move || {
|
||||
signals
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|t| Some(T::from(t.get())))
|
||||
.collect()
|
||||
}))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_from_multi_node_ref {
|
||||
($ty:ty) => {
|
||||
impl<R> From<&[NodeRef<R>]> for ElementsMaybeSignal<$ty, $ty>
|
||||
where
|
||||
R: ElementType + Clone + 'static,
|
||||
R::Output: JsCast + Into<$ty> + Clone + 'static,
|
||||
{
|
||||
fn from(node_refs: &[NodeRef<R>]) -> Self {
|
||||
let node_refs = node_refs.to_vec();
|
||||
impl_from_multi_node_ref_inner!($ty, node_refs)
|
||||
}
|
||||
}
|
||||
pub struct VecSignalOptionMarker;
|
||||
|
||||
impl<R, const C: usize> From<[NodeRef<R>; C]> for ElementsMaybeSignal<$ty, $ty>
|
||||
where
|
||||
R: ElementType + Clone + 'static,
|
||||
R::Output: JsCast + Into<$ty> + Clone + 'static,
|
||||
{
|
||||
fn from(node_refs: [NodeRef<R>; C]) -> Self {
|
||||
let node_refs = node_refs.to_vec();
|
||||
impl_from_multi_node_ref_inner!($ty, node_refs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> From<Vec<NodeRef<R>>> for ElementsMaybeSignal<$ty, $ty>
|
||||
where
|
||||
R: ElementType + Clone + 'static,
|
||||
R::Output: JsCast + Into<$ty> + Clone + 'static,
|
||||
{
|
||||
fn from(node_refs: Vec<NodeRef<R>>) -> Self {
|
||||
let node_refs = node_refs.clone();
|
||||
impl_from_multi_node_ref_inner!($ty, node_refs)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_from_multi_node_ref!(web_sys::EventTarget);
|
||||
impl_from_multi_node_ref!(web_sys::Element);
|
||||
|
||||
// // From multiple leptos::html::HTMLElement /////////////////////////////////////////
|
||||
//
|
||||
// macro_rules! impl_from_multi_html_element {
|
||||
// ($ty:ty) => {
|
||||
// impl<E, At, Ch, Rndr> From<&[HtmlElement<E, At, Ch, Rndr>]>
|
||||
// for ElementsMaybeSignal<$ty, $ty>
|
||||
// where
|
||||
// E: ElementType,
|
||||
// E::Output: std::ops::Deref<Target = $ty>,
|
||||
// {
|
||||
// fn from(value: &[HtmlElement<E, At, Ch, Rndr>]) -> Self {
|
||||
// Self::Static(
|
||||
// value
|
||||
// .iter()
|
||||
// .map(|el| {
|
||||
// let el: &$ty = el.deref();
|
||||
// Some(el.clone())
|
||||
// })
|
||||
// .collect(),
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl<E, At, Ch, Rndr, const C: usize> From<[HtmlElement<E, At, Ch, Rndr>; C]>
|
||||
// for ElementsMaybeSignal<$ty, $ty>
|
||||
// where
|
||||
// E: ElementType,
|
||||
// E::Output: std::ops::Deref<Target = $ty>,
|
||||
// {
|
||||
// fn from(value: [HtmlElement<E, At, Ch, Rndr>; C]) -> Self {
|
||||
// Self::Static(
|
||||
// value
|
||||
// .iter()
|
||||
// .map(|el| {
|
||||
// let el: &$ty = el.deref();
|
||||
// Some(el.clone())
|
||||
// })
|
||||
// .collect(),
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl<E, At, Ch, Rndr> From<Vec<HtmlElement<E, At, Ch, Rndr>>>
|
||||
// for ElementsMaybeSignal<$ty, $ty>
|
||||
// where
|
||||
// E: ElementType,
|
||||
// E::Output: std::ops::Deref<Target = $ty>,
|
||||
// {
|
||||
// fn from(value: Vec<HtmlElement<E, At, Ch, Rndr>>) -> Self {
|
||||
// Self::Static(
|
||||
// value
|
||||
// .iter()
|
||||
// .map(|el| {
|
||||
// let el: &$ty = el.deref();
|
||||
// Some(el.clone())
|
||||
// })
|
||||
// .collect(),
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
//
|
||||
// impl_from_multi_html_element!(web_sys::EventTarget);
|
||||
// impl_from_multi_html_element!(web_sys::Element);
|
||||
|
||||
// From ElementMaybeSignal //////////////////////////////////////////////////////////////
|
||||
|
||||
impl<T, E> From<ElementMaybeSignal<T, E>> for ElementsMaybeSignal<T, E>
|
||||
/// Handles `Vec<Signal<Option<web_sys::*>>>`, `Vec<NodeRef>`
|
||||
impl<T, Js, C, G> IntoElementsMaybeSignalType<T, VecSignalOptionMarker> for C
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
T: From<Js> + Clone,
|
||||
C: IntoIterator<Item = G> + Clone + 'static,
|
||||
G: Get<Value = Option<Js>>,
|
||||
{
|
||||
fn from(signal: ElementMaybeSignal<T, E>) -> Self {
|
||||
match signal {
|
||||
ElementMaybeSignal::Dynamic(signal) => {
|
||||
Self::Dynamic(Signal::derive_local(move || vec![signal.get()]))
|
||||
}
|
||||
ElementMaybeSignal::Static(el) => {
|
||||
Self::Static(SendWrapper::new(vec![SendWrapper::take(el)]))
|
||||
}
|
||||
ElementMaybeSignal::_Phantom(_) => unreachable!(),
|
||||
}
|
||||
fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
|
||||
let signals = self.clone();
|
||||
|
||||
ElementsMaybeSignalType::Dynamic(Signal::derive_local(move || {
|
||||
signals
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|t| t.get().map(T::from))
|
||||
.collect()
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ mod signal_throttled;
|
|||
#[cfg(feature = "sync_signal")]
|
||||
mod sync_signal;
|
||||
#[cfg(feature = "use_active_element")]
|
||||
// mod use_active_element;
|
||||
mod use_active_element;
|
||||
#[cfg(feature = "use_breakpoints")]
|
||||
mod use_breakpoints;
|
||||
#[cfg(feature = "use_broadcast_channel")]
|
||||
|
@ -126,6 +126,8 @@ mod use_service_worker;
|
|||
mod use_sorted;
|
||||
#[cfg(feature = "use_supported")]
|
||||
mod use_supported;
|
||||
#[cfg(feature = "use_textarea_autosize")]
|
||||
mod use_textarea_autosize;
|
||||
#[cfg(feature = "use_throttle_fn")]
|
||||
mod use_throttle_fn;
|
||||
#[cfg(feature = "use_timeout_fn")]
|
||||
|
@ -181,7 +183,7 @@ pub use signal_throttled::*;
|
|||
#[cfg(feature = "sync_signal")]
|
||||
pub use sync_signal::*;
|
||||
#[cfg(feature = "use_active_element")]
|
||||
// pub use use_active_element::*;
|
||||
pub use use_active_element::*;
|
||||
#[cfg(feature = "use_breakpoints")]
|
||||
pub use use_breakpoints::*;
|
||||
#[cfg(feature = "use_broadcast_channel")]
|
||||
|
@ -272,6 +274,8 @@ pub use use_service_worker::*;
|
|||
pub use use_sorted::*;
|
||||
#[cfg(feature = "use_supported")]
|
||||
pub use use_supported::*;
|
||||
#[cfg(feature = "use_textarea_autosize")]
|
||||
pub use use_textarea_autosize::*;
|
||||
#[cfg(feature = "use_throttle_fn")]
|
||||
pub use use_throttle_fn::*;
|
||||
#[cfg(feature = "use_timeout_fn")]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::math::shared::use_simple_math;
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
use num::Float;
|
||||
use paste::paste;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::math::shared::use_binary_logic;
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
use paste::paste;
|
||||
|
||||
use_binary_logic!(
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::math::shared::use_simple_math;
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
use num::Float;
|
||||
use paste::paste;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::math::shared::use_simple_math;
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
use num::Float;
|
||||
use paste::paste;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::math::shared::use_partial_cmp;
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use_partial_cmp!(
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::math::shared::use_partial_cmp;
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use_partial_cmp!(
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
|
||||
/// Reactive `NOT` condition.
|
||||
///
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::math::shared::use_binary_logic;
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
use paste::paste;
|
||||
|
||||
use_binary_logic!(
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::math::shared::use_simple_math;
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
use num::Float;
|
||||
use paste::paste;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::core::{ElementMaybeSignal, ElementsMaybeSignal};
|
||||
use crate::core::{ElementsMaybeSignal, IntoElementMaybeSignal, IntoElementsMaybeSignal};
|
||||
use cfg_if::cfg_if;
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
|
||||
|
@ -79,33 +79,24 @@ cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
|||
/// ## Server-Side Rendering
|
||||
///
|
||||
/// On the server this amounts to a no-op.
|
||||
pub fn on_click_outside<El, T, F>(target: El, handler: F) -> impl FnOnce() + Clone
|
||||
pub fn on_click_outside<El, M, F>(target: El, handler: F) -> impl FnOnce() + Clone
|
||||
where
|
||||
El: Clone,
|
||||
El: Into<ElementMaybeSignal<T, web_sys::EventTarget>>,
|
||||
T: Into<web_sys::EventTarget> + Clone + 'static,
|
||||
El: IntoElementMaybeSignal<web_sys::EventTarget, M>,
|
||||
F: FnMut(web_sys::Event) + Clone + 'static,
|
||||
{
|
||||
on_click_outside_with_options::<_, _, _, web_sys::EventTarget>(
|
||||
target,
|
||||
handler,
|
||||
OnClickOutsideOptions::default(),
|
||||
)
|
||||
on_click_outside_with_options(target, handler, OnClickOutsideOptions::default())
|
||||
}
|
||||
|
||||
/// Version of `on_click_outside` that takes an `OnClickOutsideOptions`. See `on_click_outside` for more details.
|
||||
#[cfg_attr(feature = "ssr", allow(unused_variables))]
|
||||
pub fn on_click_outside_with_options<El, T, F, I>(
|
||||
pub fn on_click_outside_with_options<El, M, F>(
|
||||
target: El,
|
||||
handler: F,
|
||||
options: OnClickOutsideOptions<I>,
|
||||
options: OnClickOutsideOptions,
|
||||
) -> impl FnOnce() + Clone
|
||||
where
|
||||
El: Clone,
|
||||
El: Into<ElementMaybeSignal<T, web_sys::EventTarget>>,
|
||||
T: Into<web_sys::EventTarget> + Clone + 'static,
|
||||
El: IntoElementMaybeSignal<web_sys::EventTarget, M>,
|
||||
F: FnMut(web_sys::Event) + Clone + 'static,
|
||||
I: Into<web_sys::EventTarget> + Clone + 'static,
|
||||
{
|
||||
#[cfg(feature = "ssr")]
|
||||
{
|
||||
|
@ -148,25 +139,21 @@ where
|
|||
let ignore = ignore.get_untracked();
|
||||
|
||||
ignore.into_iter().flatten().any(|element| {
|
||||
let element: web_sys::EventTarget = element.into();
|
||||
|
||||
event_target::<web_sys::EventTarget>(event) == element
|
||||
|| event.composed_path().includes(element.as_ref(), 0)
|
||||
})
|
||||
};
|
||||
|
||||
let target = target.into();
|
||||
let target = target.into_element_maybe_signal();
|
||||
|
||||
let listener = {
|
||||
let should_listen = Rc::clone(&should_listen);
|
||||
let mut handler = handler.clone();
|
||||
let target = target.clone();
|
||||
let should_ignore = should_ignore.clone();
|
||||
let target = target.clone();
|
||||
|
||||
move |event: web_sys::UiEvent| {
|
||||
if let Some(el) = target.get_untracked() {
|
||||
let el = el.into();
|
||||
|
||||
if el == event_target(&event) || event.composed_path().includes(el.as_ref(), 0)
|
||||
{
|
||||
return;
|
||||
|
@ -182,7 +169,7 @@ where
|
|||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
let _z = leptos::reactive_graph::diagnostics::SpecialNonReactiveZone::enter();
|
||||
let _z = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
handler(event.into());
|
||||
}
|
||||
|
@ -211,10 +198,8 @@ where
|
|||
pointerdown,
|
||||
move |event| {
|
||||
if let Some(el) = target.get_untracked() {
|
||||
should_listen.set(
|
||||
!event.composed_path().includes(el.into().as_ref(), 0)
|
||||
&& !should_ignore(&event),
|
||||
);
|
||||
should_listen
|
||||
.set(!event.composed_path().includes(&el, 0) && !should_ignore(&event));
|
||||
}
|
||||
},
|
||||
UseEventListenerOptions::default().passive(true),
|
||||
|
@ -235,7 +220,6 @@ where
|
|||
if let Some(active_element) = document().active_element() {
|
||||
if active_element.tag_name() == "IFRAME"
|
||||
&& !el
|
||||
.into()
|
||||
.unchecked_into::<web_sys::Node>()
|
||||
.contains(Some(&active_element.into()))
|
||||
{
|
||||
|
@ -265,13 +249,10 @@ where
|
|||
/// Options for [`on_click_outside_with_options`].
|
||||
#[derive(Clone, DefaultBuilder)]
|
||||
#[cfg_attr(feature = "ssr", allow(dead_code))]
|
||||
pub struct OnClickOutsideOptions<T>
|
||||
where
|
||||
T: Into<web_sys::EventTarget> + Clone + 'static,
|
||||
{
|
||||
pub struct OnClickOutsideOptions {
|
||||
/// List of elementss that should not trigger the callback. Defaults to `[]`.
|
||||
#[builder(skip)]
|
||||
ignore: ElementsMaybeSignal<T, web_sys::EventTarget>,
|
||||
ignore: ElementsMaybeSignal<web_sys::EventTarget>,
|
||||
|
||||
/// Use capturing phase for internal event listener. Defaults to `true`.
|
||||
capture: bool,
|
||||
|
@ -280,28 +261,25 @@ where
|
|||
detect_iframes: bool,
|
||||
}
|
||||
|
||||
impl<T> Default for OnClickOutsideOptions<T>
|
||||
where
|
||||
T: Into<web_sys::EventTarget> + Clone + 'static,
|
||||
{
|
||||
impl Default for OnClickOutsideOptions {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
ignore: Default::default(),
|
||||
ignore: Vec::<web_sys::EventTarget>::new().into_elements_maybe_signal(),
|
||||
capture: true,
|
||||
detect_iframes: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> OnClickOutsideOptions<T>
|
||||
where
|
||||
T: Into<web_sys::EventTarget> + Clone + 'static,
|
||||
{
|
||||
/// List of elementss that should not trigger the callback. Defaults to `[]`.
|
||||
impl OnClickOutsideOptions {
|
||||
/// List of elements that should not trigger the callback. Defaults to `[]`.
|
||||
#[cfg_attr(feature = "ssr", allow(dead_code))]
|
||||
pub fn ignore(self, ignore: impl Into<ElementsMaybeSignal<T, web_sys::EventTarget>>) -> Self {
|
||||
pub fn ignore<M: ?Sized>(
|
||||
self,
|
||||
ignore: impl IntoElementsMaybeSignal<web_sys::EventTarget, M>,
|
||||
) -> Self {
|
||||
Self {
|
||||
ignore: ignore.into(),
|
||||
ignore: ignore.into_elements_maybe_signal(),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::utils::signal_filtered;
|
||||
use crate::{use_debounce_fn_with_options, DebounceOptions};
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
use paste::paste;
|
||||
|
||||
signal_filtered!(
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::utils::signal_filtered;
|
||||
use crate::{use_throttle_fn_with_options, ThrottleOptions};
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
use paste::paste;
|
||||
|
||||
signal_filtered!(
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::{use_storage_with_options, StorageType, UseStorageOptions};
|
||||
use codee::{Decoder, Encoder};
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
|
||||
#[allow(rustdoc::bare_urls)]
|
||||
/// Reactive [LocalStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage).
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::{core::MaybeRwSignal, storage::StorageType, utils::FilterOptions};
|
|||
use codee::{CodecError, Decoder, Encoder};
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
use std::sync::Arc;
|
||||
use thiserror::Error;
|
||||
use wasm_bindgen::JsValue;
|
||||
|
|
|
@ -226,7 +226,7 @@ where
|
|||
move |new_value, _, _| {
|
||||
if !is_sync_update.get_value() {
|
||||
is_sync_update.set_value(true);
|
||||
right.update(|right| assign_ltr(right, new_value));
|
||||
right.try_update(|right| assign_ltr(right, new_value));
|
||||
is_sync_update.set_value(false);
|
||||
}
|
||||
},
|
||||
|
@ -240,7 +240,7 @@ where
|
|||
move |new_value, _, _| {
|
||||
if !is_sync_update.get_value() {
|
||||
is_sync_update.set_value(true);
|
||||
left.update(|left| assign_rtl(left, new_value));
|
||||
left.try_update(|left| assign_rtl(left, new_value));
|
||||
is_sync_update.set_value(false);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -2,9 +2,8 @@
|
|||
|
||||
use crate::{use_document, use_event_listener_with_options, use_window, UseEventListenerOptions};
|
||||
use leptos::ev::{blur, focus};
|
||||
use leptos::html::{AnyElement, ToHtmlElement};
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
|
||||
/// Reactive `document.activeElement`
|
||||
///
|
||||
|
@ -16,14 +15,13 @@ use leptos::prelude::*;
|
|||
///
|
||||
/// ```
|
||||
/// # use leptos::prelude::*;
|
||||
/// # use leptos::logging::log;
|
||||
/// use leptos_use::use_active_element;
|
||||
/// # use leptos_use::use_active_element;
|
||||
/// #
|
||||
/// # #[component]
|
||||
/// # fn Demo() -> impl IntoView {
|
||||
/// let active_element = use_active_element();
|
||||
///
|
||||
/// create_effect(move |_| {
|
||||
/// Effect::new(move || {
|
||||
/// log!("focus changed to {:?}", active_element.get());
|
||||
/// });
|
||||
/// #
|
||||
|
@ -34,14 +32,10 @@ use leptos::prelude::*;
|
|||
/// ## Server-Side Rendering
|
||||
///
|
||||
/// On the server this returns a `Signal` that always contains the value `None`.
|
||||
pub fn use_active_element() -> Signal<Option<HtmlElement<AnyElement>>> {
|
||||
let get_active_element = move || {
|
||||
use_document()
|
||||
.active_element()
|
||||
.map(|el| el.to_leptos_element())
|
||||
};
|
||||
pub fn use_active_element() -> Signal<Option<web_sys::Element>, LocalStorage> {
|
||||
let get_active_element = move || use_document().active_element();
|
||||
|
||||
let (active_element, set_active_element) = signal(get_active_element());
|
||||
let (active_element, set_active_element) = signal_local(get_active_element());
|
||||
|
||||
let listener_options = UseEventListenerOptions::default().capture(true);
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{use_media_query, use_window};
|
||||
use leptos::logging::error;
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
use paste::paste;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Debug;
|
||||
|
|
|
@ -72,13 +72,7 @@ use wasm_bindgen::JsValue;
|
|||
/// ```
|
||||
pub fn use_broadcast_channel<T, C>(
|
||||
name: &str,
|
||||
) -> UseBroadcastChannelReturn<
|
||||
T,
|
||||
impl Fn(&T) + Clone,
|
||||
impl Fn() + Clone,
|
||||
<C as Encoder<T>>::Error,
|
||||
<C as Decoder<T>>::Error,
|
||||
>
|
||||
) -> UseBroadcastChannelReturn<T, impl Fn(&T) + Clone, impl Fn() + Clone, C>
|
||||
where
|
||||
T: Send + Sync,
|
||||
C: Encoder<T, Encoded = String> + Decoder<T, Encoded = str>,
|
||||
|
@ -179,13 +173,12 @@ where
|
|||
}
|
||||
|
||||
/// Return type of [`use_broadcast_channel`].
|
||||
pub struct UseBroadcastChannelReturn<T, PFn, CFn, E, D>
|
||||
pub struct UseBroadcastChannelReturn<T, PFn, CFn, C>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
PFn: Fn(&T) + Clone,
|
||||
CFn: Fn() + Clone,
|
||||
E: Send + Sync + 'static,
|
||||
D: Send + Sync + 'static,
|
||||
C: Encoder<T> + Decoder<T>,
|
||||
{
|
||||
/// `true` if this browser supports `BroadcastChannel`s.
|
||||
pub is_supported: Signal<bool>,
|
||||
|
@ -203,12 +196,14 @@ where
|
|||
pub close: CFn,
|
||||
|
||||
/// Latest error as reported by the `messageerror` event.
|
||||
pub error: Signal<Option<UseBroadcastChannelError<E, D>>, LocalStorage>,
|
||||
pub error: Signal<Option<ErrorType<T, C>>, LocalStorage>,
|
||||
|
||||
/// Wether the channel is closed
|
||||
pub is_closed: Signal<bool>,
|
||||
}
|
||||
|
||||
type ErrorType<T, C> = UseBroadcastChannelError<<C as Encoder<T>>::Error, <C as Decoder<T>>::Error>;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum UseBroadcastChannelError<E, D> {
|
||||
#[error("failed to post message")]
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::{js, js_fut, use_event_listener, use_supported, UseTimeoutFnReturn};
|
|||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::ev::{copy, cut};
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
|
||||
/// Reactive [Clipboard API](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API).
|
||||
///
|
||||
|
@ -77,7 +77,7 @@ pub fn use_clipboard_with_options(
|
|||
|
||||
let update_text = move |_| {
|
||||
if is_supported.get() {
|
||||
leptos::spawn::spawn_local(async move {
|
||||
leptos::task::spawn_local(async move {
|
||||
let clipboard = window().navigator().clipboard();
|
||||
if let Ok(text) = js_fut!(clipboard.read_text()).await {
|
||||
set_text.set(text.as_string());
|
||||
|
@ -99,7 +99,7 @@ pub fn use_clipboard_with_options(
|
|||
let start = start.clone();
|
||||
let value = value.to_owned();
|
||||
|
||||
leptos::spawn::spawn_local(async move {
|
||||
leptos::task::spawn_local(async move {
|
||||
let clipboard = window().navigator().clipboard();
|
||||
if js_fut!(clipboard.write_text(&value)).await.is_ok() {
|
||||
set_text.set(Some(value));
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::core::url;
|
||||
use crate::core::{ElementMaybeSignal, MaybeRwSignal};
|
||||
use crate::core::{ElementMaybeSignal, IntoElementMaybeSignal, MaybeRwSignal};
|
||||
use crate::storage::{use_storage_with_options, StorageType, UseStorageOptions};
|
||||
use crate::utils::get_header;
|
||||
use crate::{
|
||||
|
@ -9,7 +9,7 @@ use crate::{
|
|||
use codee::string::FromToStringCodec;
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::marker::PhantomData;
|
||||
use std::str::FromStr;
|
||||
|
@ -147,11 +147,10 @@ pub fn use_color_mode() -> UseColorModeReturn {
|
|||
}
|
||||
|
||||
/// Version of [`use_color_mode`] that takes a `UseColorModeOptions`. See [`use_color_mode`] for how to use.
|
||||
pub fn use_color_mode_with_options<El, T>(options: UseColorModeOptions<El, T>) -> UseColorModeReturn
|
||||
pub fn use_color_mode_with_options<El, M>(options: UseColorModeOptions<El, M>) -> UseColorModeReturn
|
||||
where
|
||||
El: Clone,
|
||||
El: Into<ElementMaybeSignal<T, web_sys::Element>>,
|
||||
T: Into<web_sys::Element> + Clone + 'static,
|
||||
El: IntoElementMaybeSignal<web_sys::Element, M>,
|
||||
M: ?Sized,
|
||||
{
|
||||
let UseColorModeOptions {
|
||||
target,
|
||||
|
@ -216,11 +215,15 @@ where
|
|||
let _ = sync_signal_with_options(
|
||||
(cookie, set_cookie),
|
||||
(store, set_store),
|
||||
SyncSignalOptions::with_transforms(
|
||||
move |cookie: &Option<ColorMode>| {
|
||||
cookie.clone().unwrap_or_else(|| store.get_untracked())
|
||||
SyncSignalOptions::with_assigns(
|
||||
move |store: &mut ColorMode, cookie: &Option<ColorMode>| {
|
||||
if let Some(cookie) = cookie {
|
||||
*store = cookie.clone();
|
||||
}
|
||||
},
|
||||
move |cookie: &mut Option<ColorMode>, store: &ColorMode| {
|
||||
*cookie = Some(store.clone())
|
||||
},
|
||||
move |store: &ColorMode| Some(store.clone()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -243,17 +246,13 @@ where
|
|||
}
|
||||
});
|
||||
|
||||
let target = target.into();
|
||||
let target = target.into_element_maybe_signal();
|
||||
|
||||
let update_html_attrs = {
|
||||
move |target: ElementMaybeSignal<T, web_sys::Element>,
|
||||
attribute: String,
|
||||
value: ColorMode| {
|
||||
move |target: ElementMaybeSignal<web_sys::Element>, attribute: String, value: ColorMode| {
|
||||
let el = target.get_untracked();
|
||||
|
||||
if let Some(el) = el {
|
||||
let el = el.into();
|
||||
|
||||
let mut style: Option<web_sys::HtmlStyleElement> = None;
|
||||
if !transition_enabled {
|
||||
if let Ok(styl) = document().create_element("style") {
|
||||
|
@ -414,11 +413,10 @@ impl FromStr for ColorMode {
|
|||
}
|
||||
|
||||
#[derive(DefaultBuilder)]
|
||||
pub struct UseColorModeOptions<El, T>
|
||||
pub struct UseColorModeOptions<El, M>
|
||||
where
|
||||
El: Clone,
|
||||
El: Into<ElementMaybeSignal<T, web_sys::Element>>,
|
||||
T: Into<web_sys::Element> + Clone + 'static,
|
||||
El: IntoElementMaybeSignal<web_sys::Element, M>,
|
||||
M: ?Sized,
|
||||
{
|
||||
/// Element that the color mode will be applied to. Defaults to `"html"`.
|
||||
target: El,
|
||||
|
@ -502,12 +500,12 @@ where
|
|||
ssr_color_header_getter: Arc<dyn Fn() -> Option<String> + Send + Sync>,
|
||||
|
||||
#[builder(skip)]
|
||||
_marker: PhantomData<T>,
|
||||
_marker: PhantomData<M>,
|
||||
}
|
||||
|
||||
type OnChangedFn = Arc<dyn Fn(ColorMode, Arc<dyn Fn(ColorMode) + Send + Sync>) + Send + Sync>;
|
||||
|
||||
impl Default for UseColorModeOptions<&'static str, web_sys::Element> {
|
||||
impl Default for UseColorModeOptions<&'static str, str> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
target: "html",
|
||||
|
|
|
@ -126,6 +126,8 @@ use std::sync::Arc;
|
|||
/// {
|
||||
/// Some("Somehow get the value of the cookie header as a string".to_owned())
|
||||
/// }
|
||||
/// #[cfg(not(feature = "ssr"))]
|
||||
/// None
|
||||
/// })
|
||||
/// .ssr_set_cookie(|cookie: &Cookie| {
|
||||
/// #[cfg(feature = "ssr")]
|
||||
|
@ -233,7 +235,7 @@ where
|
|||
return;
|
||||
}
|
||||
|
||||
let value = cookie.with_untracked(|cookie| {
|
||||
let value = cookie.try_with_untracked(|cookie| {
|
||||
cookie.as_ref().and_then(|cookie| {
|
||||
C::encode(cookie)
|
||||
.map_err(|err| on_error(CodecError::Encode(err)))
|
||||
|
@ -241,6 +243,7 @@ where
|
|||
})
|
||||
});
|
||||
|
||||
if let Some(value) = value {
|
||||
if value
|
||||
== jar.with_value(|jar| jar.get(&cookie_name).map(|c| c.value().to_owned()))
|
||||
{
|
||||
|
@ -265,6 +268,7 @@ where
|
|||
|
||||
post(&value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let WatchPausableReturn {
|
||||
|
@ -272,7 +276,7 @@ where
|
|||
resume,
|
||||
stop,
|
||||
..
|
||||
} = watch_pausable(move || cookie.get(), {
|
||||
} = watch_pausable(move || cookie.track(), {
|
||||
let on_cookie_change = on_cookie_change.clone();
|
||||
|
||||
move |_, _, _| {
|
||||
|
@ -365,19 +369,17 @@ where
|
|||
let domain = domain.clone();
|
||||
let path = path.clone();
|
||||
|
||||
let value = cookie
|
||||
.with(|cookie| {
|
||||
if let Some(value) = cookie.try_with(|cookie| {
|
||||
cookie.as_ref().map(|cookie| {
|
||||
C::encode(cookie)
|
||||
.map_err(|err| on_error(CodecError::Encode(err)))
|
||||
.ok()
|
||||
})
|
||||
})
|
||||
.flatten();
|
||||
}) {
|
||||
jar.update_value(|jar| {
|
||||
write_server_cookie(
|
||||
&cookie_name,
|
||||
value,
|
||||
value.flatten(),
|
||||
jar,
|
||||
max_age,
|
||||
expires,
|
||||
|
@ -390,6 +392,7 @@ where
|
|||
)
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
#![cfg_attr(feature = "ssr", allow(unused_variables, unused_imports))]
|
||||
|
||||
use crate::core::ElementMaybeSignal;
|
||||
use crate::core::IntoElementMaybeSignal;
|
||||
use crate::{
|
||||
use_mutation_observer_with_options, watch_with_options, UseMutationObserverOptions,
|
||||
WatchOptions,
|
||||
};
|
||||
use cfg_if::cfg_if;
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::prelude::*;
|
||||
use std::marker::PhantomData;
|
||||
|
@ -85,15 +84,14 @@ pub fn use_css_var(
|
|||
}
|
||||
|
||||
/// Version of [`use_css_var`] that takes a `UseCssVarOptions`. See [`use_css_var`] for how to use.
|
||||
pub fn use_css_var_with_options<P, El, T>(
|
||||
pub fn use_css_var_with_options<P, El, M>(
|
||||
prop: P,
|
||||
options: UseCssVarOptions<El, T>,
|
||||
options: UseCssVarOptions<El, M>,
|
||||
) -> (ReadSignal<String>, WriteSignal<String>)
|
||||
where
|
||||
P: Into<MaybeSignal<String>>,
|
||||
El: Clone,
|
||||
El: Into<ElementMaybeSignal<T, web_sys::Element>>,
|
||||
T: Into<web_sys::Element> + Clone + 'static,
|
||||
El: IntoElementMaybeSignal<web_sys::Element, M>,
|
||||
{
|
||||
let UseCssVarOptions {
|
||||
target,
|
||||
|
@ -104,8 +102,9 @@ where
|
|||
|
||||
let (variable, set_variable) = signal(initial_value.clone());
|
||||
|
||||
cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
||||
let el_signal = target.into();
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
{
|
||||
let el_signal = target.into_element_maybe_signal();
|
||||
let prop = prop.into();
|
||||
|
||||
let update_css_var = {
|
||||
|
@ -116,7 +115,7 @@ where
|
|||
let key = prop.get_untracked();
|
||||
|
||||
if let Some(el) = el_signal.get_untracked() {
|
||||
if let Ok(Some(style)) = window().get_computed_style(&el.into()) {
|
||||
if let Ok(Some(style)) = window().get_computed_style(&el) {
|
||||
if let Ok(value) = style.get_property_value(&key) {
|
||||
set_variable.update(|var| *var = value.trim().to_string());
|
||||
return;
|
||||
|
@ -133,11 +132,10 @@ where
|
|||
let update_css_var = update_css_var.clone();
|
||||
let el_signal = el_signal.clone();
|
||||
|
||||
use_mutation_observer_with_options::<ElementMaybeSignal<T, web_sys::Element>, T, _>(
|
||||
use_mutation_observer_with_options(
|
||||
el_signal,
|
||||
move |_, _| update_css_var(),
|
||||
UseMutationObserverOptions::default()
|
||||
.attribute_filter(vec!["style".to_string()]),
|
||||
UseMutationObserverOptions::default().attribute_filter(vec!["style".to_string()]),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -159,25 +157,23 @@ where
|
|||
move || variable.get(),
|
||||
move |val, _, _| {
|
||||
if let Some(el) = el_signal.get() {
|
||||
let el = el.into().unchecked_into::<web_sys::HtmlElement>();
|
||||
let el = el.unchecked_into::<web_sys::HtmlElement>();
|
||||
let style = el.style();
|
||||
let _ = style.set_property(&prop.get_untracked(), val);
|
||||
}
|
||||
},
|
||||
false,
|
||||
);
|
||||
}}
|
||||
}
|
||||
|
||||
(variable, set_variable)
|
||||
}
|
||||
|
||||
/// Options for [`use_css_var_with_options`].
|
||||
#[derive(DefaultBuilder)]
|
||||
pub struct UseCssVarOptions<El, T>
|
||||
pub struct UseCssVarOptions<El, M>
|
||||
where
|
||||
El: Clone,
|
||||
El: Into<ElementMaybeSignal<T, web_sys::Element>>,
|
||||
T: Into<web_sys::Element> + Clone + 'static,
|
||||
El: IntoElementMaybeSignal<web_sys::Element, M>,
|
||||
{
|
||||
/// The target element to read the variable from and set the variable on.
|
||||
/// Defaults to the `document.documentElement`.
|
||||
|
@ -192,11 +188,14 @@ where
|
|||
observe: bool,
|
||||
|
||||
#[builder(skip)]
|
||||
_marker: PhantomData<T>,
|
||||
_marker: PhantomData<M>,
|
||||
}
|
||||
|
||||
cfg_if! { if #[cfg(feature = "ssr")] {
|
||||
impl Default for UseCssVarOptions<Option<web_sys::Element>, web_sys::Element> {
|
||||
#[cfg(feature = "ssr")]
|
||||
impl<M> Default for UseCssVarOptions<Option<web_sys::Element>, M>
|
||||
where
|
||||
Option<web_sys::Element>: IntoElementMaybeSignal<web_sys::Element, M>,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
target: None,
|
||||
|
@ -205,9 +204,13 @@ cfg_if! { if #[cfg(feature = "ssr")] {
|
|||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
impl Default for UseCssVarOptions<web_sys::Element, web_sys::Element> {
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
impl<M> Default for UseCssVarOptions<web_sys::Element, M>
|
||||
where
|
||||
web_sys::Element: IntoElementMaybeSignal<web_sys::Element, M>,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
target: document().document_element().expect("No document element"),
|
||||
|
@ -216,5 +219,4 @@ cfg_if! { if #[cfg(feature = "ssr")] {
|
|||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use cfg_if::cfg_if;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
|
||||
/// Reactive [DeviceOrientationEvent](https://developer.mozilla.org/en-US/docs/Web/API/DeviceOrientationEvent).
|
||||
///
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::core::MaybeRwSignal;
|
|||
use cfg_if::cfg_if;
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
use wasm_bindgen::{JsCast, JsValue};
|
||||
|
||||
/// Reactive [`mediaDevices.getDisplayMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia) streaming.
|
||||
|
@ -83,7 +83,7 @@ pub fn use_display_media_with_options(
|
|||
|
||||
let start = move || {
|
||||
cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
||||
leptos::spawn::spawn_local(async move {
|
||||
leptos::task::spawn_local(async move {
|
||||
_start().await;
|
||||
stream.with_untracked(move |stream| {
|
||||
if let Some(Ok(_)) = stream {
|
||||
|
@ -103,7 +103,7 @@ pub fn use_display_media_with_options(
|
|||
move || enabled.get(),
|
||||
move |enabled, _, _| {
|
||||
if *enabled {
|
||||
leptos::spawn::spawn_local(async move {
|
||||
leptos::task::spawn_local(async move {
|
||||
_start().await;
|
||||
});
|
||||
} else {
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::use_event_listener;
|
|||
use cfg_if::cfg_if;
|
||||
use leptos::ev::visibilitychange;
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
|
||||
/// Reactively track `document.visibilityState`
|
||||
///
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use crate::core::{ElementMaybeSignal, MaybeRwSignal, PointerType, Position};
|
||||
use crate::core::{IntoElementMaybeSignal, MaybeRwSignal, PointerType, Position};
|
||||
use crate::{use_event_listener_with_options, use_window, UseEventListenerOptions, UseWindow};
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::ev::{pointerdown, pointermove, pointerup};
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::Arc;
|
||||
use wasm_bindgen::JsCast;
|
||||
|
@ -45,34 +45,22 @@ use web_sys::PointerEvent;
|
|||
/// }
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn use_draggable<El, T>(target: El) -> UseDraggableReturn
|
||||
pub fn use_draggable<El, M>(target: El) -> UseDraggableReturn
|
||||
where
|
||||
El: Into<ElementMaybeSignal<T, web_sys::EventTarget>>,
|
||||
T: Into<web_sys::EventTarget> + Clone + 'static,
|
||||
El: IntoElementMaybeSignal<web_sys::EventTarget, M>,
|
||||
{
|
||||
use_draggable_with_options::<
|
||||
El,
|
||||
T,
|
||||
UseWindow,
|
||||
web_sys::Window,
|
||||
web_sys::EventTarget,
|
||||
web_sys::EventTarget,
|
||||
>(target, UseDraggableOptions::default())
|
||||
use_draggable_with_options::<El, M, _, _, _, _>(target, UseDraggableOptions::default())
|
||||
}
|
||||
|
||||
/// Version of [`use_draggable`] that takes a `UseDraggableOptions`. See [`use_draggable`] for how to use.
|
||||
pub fn use_draggable_with_options<El, T, DragEl, DragT, HandleEl, HandleT>(
|
||||
pub fn use_draggable_with_options<El, M, DragEl, DragM, HandleEl, HandleM>(
|
||||
target: El,
|
||||
options: UseDraggableOptions<DragEl, DragT, HandleEl, HandleT>,
|
||||
options: UseDraggableOptions<DragEl, DragM, HandleEl, HandleM>,
|
||||
) -> UseDraggableReturn
|
||||
where
|
||||
El: Into<ElementMaybeSignal<T, web_sys::EventTarget>>,
|
||||
T: Into<web_sys::EventTarget> + Clone + 'static,
|
||||
DragEl: Clone,
|
||||
DragEl: Into<ElementMaybeSignal<DragT, web_sys::EventTarget>>,
|
||||
DragT: Into<web_sys::EventTarget> + Clone + 'static,
|
||||
HandleEl: Into<ElementMaybeSignal<HandleT, web_sys::EventTarget>>,
|
||||
HandleT: Into<web_sys::EventTarget> + Clone + 'static,
|
||||
El: IntoElementMaybeSignal<web_sys::EventTarget, M>,
|
||||
DragEl: IntoElementMaybeSignal<web_sys::EventTarget, DragM>,
|
||||
HandleEl: IntoElementMaybeSignal<web_sys::EventTarget, HandleM>,
|
||||
{
|
||||
let UseDraggableOptions {
|
||||
exact,
|
||||
|
@ -88,14 +76,12 @@ where
|
|||
..
|
||||
} = options;
|
||||
|
||||
let target = target.into();
|
||||
let target = target.into_element_maybe_signal();
|
||||
|
||||
let dragging_handle = if let Some(handle) = handle {
|
||||
let handle: ElementMaybeSignal<_, _> = handle.into();
|
||||
Signal::derive_local(move || handle.get().map(|handle| handle.into()))
|
||||
handle.into_element_maybe_signal()
|
||||
} else {
|
||||
let target = target.clone();
|
||||
Signal::derive_local(move || target.get().map(|target| target.into()))
|
||||
target.clone()
|
||||
};
|
||||
|
||||
let (position, set_position) = initial_value.into_signal();
|
||||
|
@ -124,7 +110,7 @@ where
|
|||
}
|
||||
|
||||
if let Some(target) = target.get_untracked() {
|
||||
let target: web_sys::Element = target.into().unchecked_into();
|
||||
let target: web_sys::Element = target.unchecked_into();
|
||||
|
||||
if exact.get_untracked() && event_target::<web_sys::Element>(&event) != target {
|
||||
return;
|
||||
|
@ -137,7 +123,7 @@ where
|
|||
};
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
let zone = leptos::reactive_graph::diagnostics::SpecialNonReactiveZone::enter();
|
||||
let zone = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
if !on_start(UseDraggableCallbackArgs {
|
||||
position,
|
||||
|
@ -172,7 +158,7 @@ where
|
|||
set_position.set(position);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
let zone = leptos::reactive_graph::diagnostics::SpecialNonReactiveZone::enter();
|
||||
let zone = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
on_move(UseDraggableCallbackArgs {
|
||||
position,
|
||||
|
@ -197,7 +183,7 @@ where
|
|||
set_start_position.set(None);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
let zone = leptos::reactive_graph::diagnostics::SpecialNonReactiveZone::enter();
|
||||
let zone = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
on_end(UseDraggableCallbackArgs {
|
||||
position: position.get_untracked(),
|
||||
|
@ -210,6 +196,8 @@ where
|
|||
handle_event(event);
|
||||
};
|
||||
|
||||
let dragging_element = dragging_element.into_element_maybe_signal();
|
||||
|
||||
let listener_options = UseEventListenerOptions::default().capture(true);
|
||||
|
||||
let _ = use_event_listener_with_options(
|
||||
|
@ -246,12 +234,10 @@ where
|
|||
|
||||
/// Options for [`use_draggable_with_options`].
|
||||
#[derive(DefaultBuilder)]
|
||||
pub struct UseDraggableOptions<DragEl, DragT, HandleEl, HandleT>
|
||||
pub struct UseDraggableOptions<DragEl, DragM, HandleEl, HandleM>
|
||||
where
|
||||
DragEl: Into<ElementMaybeSignal<DragT, web_sys::EventTarget>>,
|
||||
DragT: Into<web_sys::EventTarget> + Clone + 'static,
|
||||
HandleEl: Into<ElementMaybeSignal<HandleT, web_sys::EventTarget>>,
|
||||
HandleT: Into<web_sys::EventTarget> + Clone + 'static,
|
||||
DragEl: IntoElementMaybeSignal<web_sys::EventTarget, DragM>,
|
||||
HandleEl: IntoElementMaybeSignal<web_sys::EventTarget, HandleM>,
|
||||
{
|
||||
/// Only start the dragging when click on the element directly. Defaults to `false`.
|
||||
#[builder(into)]
|
||||
|
@ -288,13 +274,16 @@ where
|
|||
on_end: Arc<dyn Fn(UseDraggableCallbackArgs) + Send + Sync>,
|
||||
|
||||
#[builder(skip)]
|
||||
_marker1: PhantomData<DragT>,
|
||||
_marker1: PhantomData<DragM>,
|
||||
#[builder(skip)]
|
||||
_marker2: PhantomData<HandleT>,
|
||||
_marker2: PhantomData<HandleM>,
|
||||
}
|
||||
|
||||
impl Default
|
||||
for UseDraggableOptions<UseWindow, web_sys::Window, web_sys::EventTarget, web_sys::EventTarget>
|
||||
impl<DragM, HandleM> Default
|
||||
for UseDraggableOptions<UseWindow, DragM, Option<web_sys::EventTarget>, HandleM>
|
||||
where
|
||||
UseWindow: IntoElementMaybeSignal<web_sys::EventTarget, DragM>,
|
||||
Option<web_sys::EventTarget>: IntoElementMaybeSignal<web_sys::EventTarget, HandleM>,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use crate::core::ElementMaybeSignal;
|
||||
use crate::core::IntoElementMaybeSignal;
|
||||
use cfg_if::cfg_if;
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
use send_wrapper::SendWrapper;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -52,31 +53,29 @@ cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
|||
///
|
||||
/// On the server the returned `file` signal always contains an empty `Vec` and
|
||||
/// `is_over_drop_zone` contains always `false`
|
||||
pub fn use_drop_zone<El, T>(target: El) -> UseDropZoneReturn
|
||||
pub fn use_drop_zone<El, M>(target: El) -> UseDropZoneReturn
|
||||
where
|
||||
El: Clone,
|
||||
El: Into<ElementMaybeSignal<T, web_sys::EventTarget>>,
|
||||
T: Into<web_sys::EventTarget> + Clone + 'static,
|
||||
El: IntoElementMaybeSignal<web_sys::EventTarget, M>,
|
||||
{
|
||||
use_drop_zone_with_options(target, UseDropZoneOptions::default())
|
||||
}
|
||||
|
||||
/// Version of [`use_drop_zone`] that takes a `UseDropZoneOptions`. See [`use_drop_zone`] for how to use.
|
||||
#[cfg_attr(feature = "ssr", allow(unused_variables))]
|
||||
pub fn use_drop_zone_with_options<El, T>(
|
||||
pub fn use_drop_zone_with_options<El, M>(
|
||||
target: El,
|
||||
options: UseDropZoneOptions,
|
||||
) -> UseDropZoneReturn
|
||||
where
|
||||
El: Clone,
|
||||
El: Into<ElementMaybeSignal<T, web_sys::EventTarget>>,
|
||||
T: Into<web_sys::EventTarget> + Clone + 'static,
|
||||
El: IntoElementMaybeSignal<web_sys::EventTarget, M>,
|
||||
{
|
||||
let (is_over_drop_zone, set_over_drop_zone) = signal(false);
|
||||
let (files, set_files) = signal_local(Vec::<web_sys::File>::new());
|
||||
let (files, set_files) = signal(Vec::<SendWrapper<web_sys::File>>::new());
|
||||
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
{
|
||||
use std::ops::Deref;
|
||||
|
||||
let UseDropZoneOptions {
|
||||
on_drop,
|
||||
on_enter,
|
||||
|
@ -94,12 +93,15 @@ where
|
|||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.map(web_sys::File::from)
|
||||
.map(SendWrapper::new)
|
||||
.collect();
|
||||
|
||||
set_files.update(move |f| *f = files);
|
||||
}
|
||||
};
|
||||
|
||||
let target = target.into_element_maybe_signal();
|
||||
|
||||
let _ = use_event_listener(target.clone(), dragenter, move |event| {
|
||||
event.prevent_default();
|
||||
counter.update_value(|counter| *counter += 1);
|
||||
|
@ -108,10 +110,11 @@ where
|
|||
update_files(&event);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
let _z = leptos::reactive_graph::diagnostics::SpecialNonReactiveZone::enter();
|
||||
let _z = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
on_enter(UseDropZoneEvent {
|
||||
files: files.get_untracked().into_iter().collect(),
|
||||
files: files
|
||||
.with_untracked(|files| files.iter().map(|f| f.deref().clone()).collect()),
|
||||
event,
|
||||
});
|
||||
});
|
||||
|
@ -121,10 +124,11 @@ where
|
|||
update_files(&event);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
let _z = leptos::reactive_graph::diagnostics::SpecialNonReactiveZone::enter();
|
||||
let _z = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
on_over(UseDropZoneEvent {
|
||||
files: files.get_untracked().into_iter().collect(),
|
||||
files: files
|
||||
.with_untracked(|files| files.iter().map(|f| f.deref().clone()).collect()),
|
||||
event,
|
||||
});
|
||||
});
|
||||
|
@ -139,10 +143,11 @@ where
|
|||
update_files(&event);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
let _z = leptos::reactive_graph::diagnostics::SpecialNonReactiveZone::enter();
|
||||
let _z = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
on_leave(UseDropZoneEvent {
|
||||
files: files.get_untracked().into_iter().collect(),
|
||||
files: files
|
||||
.with_untracked(|files| files.iter().map(|f| f.deref().clone()).collect()),
|
||||
event,
|
||||
});
|
||||
});
|
||||
|
@ -155,10 +160,11 @@ where
|
|||
update_files(&event);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
let _z = leptos::reactive_graph::diagnostics::SpecialNonReactiveZone::enter();
|
||||
let _z = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
on_drop(UseDropZoneEvent {
|
||||
files: files.get_untracked().into_iter().collect(),
|
||||
files: files
|
||||
.with_untracked(|files| files.iter().map(|f| f.deref().clone()).collect()),
|
||||
event,
|
||||
});
|
||||
});
|
||||
|
@ -213,7 +219,7 @@ pub struct UseDropZoneEvent {
|
|||
/// Return type of [`use_drop_zone`].
|
||||
pub struct UseDropZoneReturn {
|
||||
/// Files being handled
|
||||
pub files: Signal<Vec<web_sys::File>, LocalStorage>,
|
||||
pub files: Signal<Vec<SendWrapper<web_sys::File>>>,
|
||||
/// Whether the files (dragged by the pointer) are over the drop zone
|
||||
pub is_over_drop_zone: Signal<bool>,
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
use crate::core::ElementMaybeSignal;
|
||||
use cfg_if::cfg_if;
|
||||
use crate::core::IntoElementMaybeSignal;
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
|
||||
/// Reactive [bounding box](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect) of an HTML element
|
||||
///
|
||||
|
@ -30,22 +29,20 @@ use leptos::reactive_graph::wrappers::read::Signal;
|
|||
/// ## Server-Side Rendering
|
||||
///
|
||||
/// On the server the returned signals always are `0.0` and `update` is a no-op.
|
||||
pub fn use_element_bounding<El, T>(target: El) -> UseElementBoundingReturn<impl Fn() + Clone>
|
||||
pub fn use_element_bounding<El, M>(target: El) -> UseElementBoundingReturn<impl Fn() + Clone>
|
||||
where
|
||||
El: Into<ElementMaybeSignal<T, web_sys::Element>> + Clone,
|
||||
T: Into<web_sys::Element> + Clone + 'static,
|
||||
El: IntoElementMaybeSignal<web_sys::Element, M>,
|
||||
{
|
||||
use_element_bounding_with_options(target, UseElementBoundingOptions::default())
|
||||
}
|
||||
|
||||
/// Version of [`use_element_bounding`] that takes a `UseElementBoundingOptions`. See [`use_element_bounding`] for how to use.
|
||||
pub fn use_element_bounding_with_options<El, T>(
|
||||
pub fn use_element_bounding_with_options<El, M>(
|
||||
target: El,
|
||||
options: UseElementBoundingOptions,
|
||||
) -> UseElementBoundingReturn<impl Fn() + Clone>
|
||||
where
|
||||
El: Into<ElementMaybeSignal<T, web_sys::Element>> + Clone,
|
||||
T: Into<web_sys::Element> + Clone + 'static,
|
||||
El: IntoElementMaybeSignal<web_sys::Element, M>,
|
||||
{
|
||||
let (height, set_height) = signal(0.0);
|
||||
let (width, set_width) = signal(0.0);
|
||||
|
@ -56,7 +53,10 @@ where
|
|||
let (x, set_x) = signal(0.0);
|
||||
let (y, set_y) = signal(0.0);
|
||||
|
||||
cfg_if! { if #[cfg(feature = "ssr")] {
|
||||
let update;
|
||||
|
||||
#[cfg(feature = "ssr")]
|
||||
{
|
||||
let _ = target;
|
||||
let _ = options;
|
||||
|
||||
|
@ -69,8 +69,11 @@ where
|
|||
let _ = set_x;
|
||||
let _ = set_y;
|
||||
|
||||
let update = move || ();
|
||||
} else {
|
||||
update = move || ();
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
{
|
||||
use crate::{
|
||||
use_event_listener_with_options, use_resize_observer, use_window,
|
||||
UseEventListenerOptions,
|
||||
|
@ -84,16 +87,16 @@ where
|
|||
immediate,
|
||||
} = options;
|
||||
|
||||
let target = target.into();
|
||||
let target = target.into_element_maybe_signal();
|
||||
|
||||
let update = {
|
||||
update = {
|
||||
let target = target.clone();
|
||||
|
||||
move || {
|
||||
let el = target.get_untracked();
|
||||
|
||||
if let Some(el) = el {
|
||||
let rect = el.into().get_bounding_client_rect();
|
||||
let rect = el.get_bounding_client_rect();
|
||||
|
||||
set_height.set(rect.height());
|
||||
set_width.set(rect.width());
|
||||
|
@ -164,7 +167,7 @@ where
|
|||
if immediate {
|
||||
update();
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
UseElementBoundingReturn {
|
||||
height: height.into(),
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use crate::core::ElementMaybeSignal;
|
||||
use crate::core::IntoElementMaybeSignal;
|
||||
use crate::{use_event_listener_with_options, UseEventListenerOptions};
|
||||
use cfg_if::cfg_if;
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::ev::{mouseenter, mouseleave};
|
||||
use leptos::leptos_dom::helpers::TimeoutHandle;
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
|
||||
cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
||||
use std::time::Duration;
|
||||
|
@ -38,11 +38,9 @@ cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
|||
/// ## Server-Side Rendering
|
||||
///
|
||||
/// On the server this returns a `Signal` that always contains the value `false`.
|
||||
pub fn use_element_hover<El, T>(el: El) -> Signal<bool>
|
||||
pub fn use_element_hover<El, M>(el: El) -> Signal<bool>
|
||||
where
|
||||
El: Clone,
|
||||
El: Into<ElementMaybeSignal<T, web_sys::EventTarget>>,
|
||||
T: Into<web_sys::EventTarget> + Clone + 'static,
|
||||
El: IntoElementMaybeSignal<web_sys::EventTarget, M>,
|
||||
{
|
||||
use_element_hover_with_options(el, UseElementHoverOptions::default())
|
||||
}
|
||||
|
@ -50,14 +48,12 @@ where
|
|||
/// Version of [`use_element_hover`] that takes a `UseElementHoverOptions`. See [`use_element_hover`] for how to use.
|
||||
|
||||
#[cfg_attr(feature = "ssr", allow(unused_variables, unused_mut))]
|
||||
pub fn use_element_hover_with_options<El, T>(
|
||||
pub fn use_element_hover_with_options<El, M>(
|
||||
el: El,
|
||||
options: UseElementHoverOptions,
|
||||
) -> Signal<bool>
|
||||
where
|
||||
El: Clone,
|
||||
El: Into<ElementMaybeSignal<T, web_sys::EventTarget>>,
|
||||
T: Into<web_sys::EventTarget> + Clone + 'static,
|
||||
El: IntoElementMaybeSignal<web_sys::EventTarget, M>,
|
||||
{
|
||||
let UseElementHoverOptions {
|
||||
delay_enter,
|
||||
|
@ -90,6 +86,8 @@ where
|
|||
|
||||
let listener_options = UseEventListenerOptions::default().passive(true);
|
||||
|
||||
let el = el.into_element_maybe_signal();
|
||||
|
||||
let _ = use_event_listener_with_options(
|
||||
el.clone(),
|
||||
mouseenter,
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use crate::core::{ElementMaybeSignal, Size};
|
||||
use crate::core::IntoElementMaybeSignal;
|
||||
use crate::core::Size;
|
||||
use cfg_if::cfg_if;
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
|
||||
cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
||||
use crate::{use_resize_observer_with_options, UseResizeObserverOptions};
|
||||
|
@ -47,23 +48,21 @@ cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
|||
/// ## See also
|
||||
///
|
||||
/// - [`fn@crate::use_resize_observer`]
|
||||
pub fn use_element_size<El, T>(target: El) -> UseElementSizeReturn
|
||||
pub fn use_element_size<El, M>(target: El) -> UseElementSizeReturn
|
||||
where
|
||||
El: Into<ElementMaybeSignal<T, web_sys::Element>> + Clone,
|
||||
T: Into<web_sys::Element> + Clone + 'static,
|
||||
El: IntoElementMaybeSignal<web_sys::Element, M>,
|
||||
{
|
||||
use_element_size_with_options(target, UseElementSizeOptions::default())
|
||||
}
|
||||
|
||||
/// Version of [`use_element_size`] that takes a `UseElementSizeOptions`. See [`use_element_size`] for how to use.
|
||||
#[cfg_attr(feature = "ssr", allow(unused_variables))]
|
||||
pub fn use_element_size_with_options<El, T>(
|
||||
pub fn use_element_size_with_options<El, M>(
|
||||
target: El,
|
||||
options: UseElementSizeOptions,
|
||||
) -> UseElementSizeReturn
|
||||
where
|
||||
El: Into<ElementMaybeSignal<T, web_sys::Element>> + Clone,
|
||||
T: Into<web_sys::Element> + Clone + 'static,
|
||||
El: IntoElementMaybeSignal<web_sys::Element, M>,
|
||||
{
|
||||
let UseElementSizeOptions { box_, initial_size } = options;
|
||||
|
||||
|
@ -74,7 +73,7 @@ where
|
|||
{
|
||||
let box_ = box_.unwrap_or(web_sys::ResizeObserverBoxOptions::ContentBox);
|
||||
|
||||
let target = target.into();
|
||||
let target = target.into_element_maybe_signal();
|
||||
|
||||
let is_svg = {
|
||||
let target = target.clone();
|
||||
|
@ -82,7 +81,6 @@ where
|
|||
move || {
|
||||
if let Some(target) = target.get_untracked() {
|
||||
target
|
||||
.into()
|
||||
.namespace_uri()
|
||||
.map(|ns| ns.contains("svg"))
|
||||
.unwrap_or(false)
|
||||
|
@ -92,11 +90,11 @@ where
|
|||
}
|
||||
};
|
||||
|
||||
let _ = use_resize_observer_with_options(
|
||||
target.clone(),
|
||||
{
|
||||
let target = target.clone();
|
||||
|
||||
let _ = use_resize_observer_with_options::<ElementMaybeSignal<T, web_sys::Element>, _, _>(
|
||||
target.clone(),
|
||||
move |entries, _| {
|
||||
let entry = &entries[0];
|
||||
|
||||
|
@ -111,7 +109,7 @@ where
|
|||
|
||||
if is_svg() {
|
||||
if let Some(target) = target.get() {
|
||||
if let Ok(Some(styles)) = window().get_computed_style(&target.into()) {
|
||||
if let Ok(Some(styles)) = window().get_computed_style(&target) {
|
||||
set_height.set(
|
||||
styles
|
||||
.get_property_value("height")
|
||||
|
@ -155,10 +153,10 @@ where
|
|||
set_width.set(entry.content_rect().width());
|
||||
set_height.set(entry.content_rect().height())
|
||||
}
|
||||
}
|
||||
},
|
||||
UseResizeObserverOptions::default().box_(box_),
|
||||
);
|
||||
}
|
||||
|
||||
let _ = watch_with_options(
|
||||
move || target.get(),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::core::ElementMaybeSignal;
|
||||
use crate::core::IntoElementMaybeSignal;
|
||||
use cfg_if::cfg_if;
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::prelude::*;
|
||||
|
@ -6,7 +6,7 @@ use std::marker::PhantomData;
|
|||
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
use crate::{use_intersection_observer_with_options, UseIntersectionObserverOptions};
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
|
||||
/// Tracks the visibility of an element within the viewport.
|
||||
///
|
||||
|
@ -42,12 +42,11 @@ use leptos::reactive_graph::wrappers::read::Signal;
|
|||
/// ## See also
|
||||
///
|
||||
/// * [`fn@crate::use_intersection_observer`]
|
||||
pub fn use_element_visibility<El, T>(target: El) -> Signal<bool>
|
||||
pub fn use_element_visibility<El, M>(target: El) -> Signal<bool>
|
||||
where
|
||||
El: Into<ElementMaybeSignal<T, web_sys::Element>>,
|
||||
T: Into<web_sys::Element> + Clone + 'static,
|
||||
El: IntoElementMaybeSignal<web_sys::Element, M>,
|
||||
{
|
||||
use_element_visibility_with_options::<El, T, web_sys::Element, web_sys::Element>(
|
||||
use_element_visibility_with_options::<El, M, web_sys::Element, _>(
|
||||
target,
|
||||
UseElementVisibilityOptions::default(),
|
||||
)
|
||||
|
@ -55,21 +54,19 @@ where
|
|||
|
||||
/// Version of [`use_element_visibility`] with that takes a `UseElementVisibilityOptions`. See [`use_element_visibility`] for how to use.
|
||||
#[cfg_attr(feature = "ssr", allow(unused_variables))]
|
||||
pub fn use_element_visibility_with_options<El, T, ContainerEl, ContainerT>(
|
||||
pub fn use_element_visibility_with_options<El, M, ContainerEl, ContainerM>(
|
||||
target: El,
|
||||
options: UseElementVisibilityOptions<ContainerEl, ContainerT>,
|
||||
options: UseElementVisibilityOptions<ContainerEl, ContainerM>,
|
||||
) -> Signal<bool>
|
||||
where
|
||||
El: Into<ElementMaybeSignal<T, web_sys::Element>>,
|
||||
T: Into<web_sys::Element> + Clone + 'static,
|
||||
ContainerEl: Into<ElementMaybeSignal<ContainerT, web_sys::Element>>,
|
||||
ContainerT: Into<web_sys::Element> + Clone + 'static,
|
||||
El: IntoElementMaybeSignal<web_sys::Element, M>,
|
||||
ContainerEl: IntoElementMaybeSignal<web_sys::Element, ContainerM>,
|
||||
{
|
||||
let (is_visible, set_visible) = signal(false);
|
||||
|
||||
cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
||||
use_intersection_observer_with_options(
|
||||
target.into(),
|
||||
target.into_element_maybe_signal(),
|
||||
move |entries, _| {
|
||||
// In some circumstances Chrome passes a first (or only) entry which has a zero bounding client rect
|
||||
// and returns `is_intersecting` erroneously as `false`.
|
||||
|
@ -89,10 +86,9 @@ where
|
|||
|
||||
/// Options for [`use_element_visibility_with_options`].
|
||||
#[derive(DefaultBuilder)]
|
||||
pub struct UseElementVisibilityOptions<El, T>
|
||||
pub struct UseElementVisibilityOptions<El, M>
|
||||
where
|
||||
El: Into<ElementMaybeSignal<T, web_sys::Element>>,
|
||||
T: Into<web_sys::Element> + Clone + 'static,
|
||||
El: IntoElementMaybeSignal<web_sys::Element, M>,
|
||||
{
|
||||
/// A `web_sys::Element` or `web_sys::Document` object which is an ancestor of the intended `target`,
|
||||
/// whose bounding rectangle will be considered the viewport.
|
||||
|
@ -104,10 +100,13 @@ where
|
|||
viewport: Option<El>,
|
||||
|
||||
#[builder(skip)]
|
||||
_marker: PhantomData<T>,
|
||||
_marker: PhantomData<M>,
|
||||
}
|
||||
|
||||
impl Default for UseElementVisibilityOptions<web_sys::Element, web_sys::Element> {
|
||||
impl<M> Default for UseElementVisibilityOptions<web_sys::Element, M>
|
||||
where
|
||||
web_sys::Element: IntoElementMaybeSignal<web_sys::Element, M>,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
viewport: None,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::core::ElementMaybeSignal;
|
||||
use crate::core::IntoElementMaybeSignal;
|
||||
use cfg_if::cfg_if;
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::ev::EventDescriptor;
|
||||
|
@ -88,11 +88,10 @@ cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
|||
/// ## Server-Side Rendering
|
||||
///
|
||||
/// On the server this amounts to a noop.
|
||||
pub fn use_event_listener<Ev, El, T, F>(target: El, event: Ev, handler: F) -> impl Fn() + Clone
|
||||
pub fn use_event_listener<Ev, El, M, F>(target: El, event: Ev, handler: F) -> impl Fn() + Clone
|
||||
where
|
||||
Ev: EventDescriptor + 'static,
|
||||
El: Into<ElementMaybeSignal<T, web_sys::EventTarget>>,
|
||||
T: Into<web_sys::EventTarget> + Clone + 'static,
|
||||
El: IntoElementMaybeSignal<web_sys::EventTarget, M>,
|
||||
F: FnMut(<Ev as EventDescriptor>::EventType) + 'static,
|
||||
{
|
||||
use_event_listener_with_options(target, event, handler, UseEventListenerOptions::default())
|
||||
|
@ -101,7 +100,7 @@ where
|
|||
/// Version of [`use_event_listener`] that takes `web_sys::AddEventListenerOptions`. See the docs for [`use_event_listener`] for how to use.
|
||||
#[cfg_attr(feature = "ssr", allow(unused_variables))]
|
||||
#[allow(unused_mut)]
|
||||
pub fn use_event_listener_with_options<Ev, El, T, F>(
|
||||
pub fn use_event_listener_with_options<Ev, El, M, F>(
|
||||
target: El,
|
||||
event: Ev,
|
||||
mut handler: F,
|
||||
|
@ -109,8 +108,7 @@ pub fn use_event_listener_with_options<Ev, El, T, F>(
|
|||
) -> impl Fn() + Clone
|
||||
where
|
||||
Ev: EventDescriptor + 'static,
|
||||
El: Into<ElementMaybeSignal<T, web_sys::EventTarget>>,
|
||||
T: Into<web_sys::EventTarget> + Clone + 'static,
|
||||
El: IntoElementMaybeSignal<web_sys::EventTarget, M>,
|
||||
F: FnMut(<Ev as EventDescriptor>::EventType) + 'static,
|
||||
{
|
||||
#[cfg(feature = "ssr")]
|
||||
|
@ -124,7 +122,7 @@ where
|
|||
let event_name = event.name();
|
||||
let closure_js = Closure::wrap(Box::new(move |e| {
|
||||
#[cfg(debug_assertions)]
|
||||
let _z = leptos::reactive_graph::diagnostics::SpecialNonReactiveZone::enter();
|
||||
let _z = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
handler(e);
|
||||
}) as Box<dyn FnMut(_)>)
|
||||
|
@ -145,7 +143,7 @@ where
|
|||
|
||||
let event_name = event.name();
|
||||
|
||||
let signal = target.into();
|
||||
let signal = target.into_element_maybe_signal();
|
||||
|
||||
let prev_element = Rc::new(RefCell::new(None::<web_sys::EventTarget>));
|
||||
|
||||
|
@ -163,7 +161,7 @@ where
|
|||
let cleanup_prev_element = cleanup_prev_element.clone();
|
||||
|
||||
watch_with_options(
|
||||
move || signal.get().map(|e| e.into()),
|
||||
move || signal.get(),
|
||||
move |element, _, _| {
|
||||
cleanup_prev_element();
|
||||
prev_element.replace(element.clone());
|
||||
|
|
|
@ -234,9 +234,7 @@ where
|
|||
);
|
||||
} else {
|
||||
#[cfg(debug_assertions)]
|
||||
let _z =
|
||||
leptos::reactive_graph::diagnostics::SpecialNonReactiveZone::enter(
|
||||
);
|
||||
let _z = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
on_failed();
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::core::MaybeRwSignal;
|
|||
use cfg_if::cfg_if;
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
use wasm_bindgen::JsCast;
|
||||
|
||||
/// Reactive favicon.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use cfg_if::cfg_if;
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
|
||||
/// Reactive [Geolocation API](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API).
|
||||
///
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::utils::{DebounceOptions, FilterOptions, ThrottleOptions};
|
|||
use cfg_if::cfg_if;
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
|
||||
///
|
||||
///
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::core::{Direction, Directions, ElementMaybeSignal};
|
||||
use crate::core::{Direction, Directions, IntoElementMaybeSignal};
|
||||
use crate::{
|
||||
use_element_visibility, use_scroll_with_options, ScrollOffset, UseEventListenerOptions,
|
||||
UseScrollOptions, UseScrollReturn,
|
||||
|
@ -7,7 +7,7 @@ use default_struct_builder::DefaultBuilder;
|
|||
use futures_util::join;
|
||||
use gloo_timers::future::sleep;
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
use std::future::Future;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
@ -50,10 +50,9 @@ use wasm_bindgen::JsCast;
|
|||
/// ```
|
||||
///
|
||||
/// The returned signal is `true` while new data is being loaded.
|
||||
pub fn use_infinite_scroll<El, T, LFn, LFut>(el: El, on_load_more: LFn) -> Signal<bool>
|
||||
pub fn use_infinite_scroll<El, M, LFn, LFut>(el: El, on_load_more: LFn) -> Signal<bool>
|
||||
where
|
||||
El: Into<ElementMaybeSignal<T, web_sys::Element>> + Clone + 'static,
|
||||
T: Into<web_sys::Element> + Clone + 'static,
|
||||
El: IntoElementMaybeSignal<web_sys::Element, M> + 'static,
|
||||
LFn: Fn(ScrollState) -> LFut + Send + Sync + 'static,
|
||||
LFut: Future<Output = ()>,
|
||||
{
|
||||
|
@ -61,14 +60,13 @@ where
|
|||
}
|
||||
|
||||
/// Version of [`use_infinite_scroll`] that takes a `UseInfiniteScrollOptions`. See [`use_infinite_scroll`] for how to use.
|
||||
pub fn use_infinite_scroll_with_options<El, T, LFn, LFut>(
|
||||
pub fn use_infinite_scroll_with_options<El, M, LFn, LFut>(
|
||||
el: El,
|
||||
on_load_more: LFn,
|
||||
options: UseInfiniteScrollOptions,
|
||||
) -> Signal<bool>
|
||||
where
|
||||
El: Into<ElementMaybeSignal<T, web_sys::Element>> + Clone + 'static,
|
||||
T: Into<web_sys::Element> + Clone + 'static,
|
||||
El: IntoElementMaybeSignal<web_sys::Element, M> + 'static,
|
||||
LFn: Fn(ScrollState) -> LFut + Send + Sync + 'static,
|
||||
LFut: Future<Output = ()>,
|
||||
{
|
||||
|
@ -82,6 +80,8 @@ where
|
|||
|
||||
let on_load_more = StoredValue::new(on_load_more);
|
||||
|
||||
let el = el.into_element_maybe_signal();
|
||||
|
||||
let UseScrollReturn {
|
||||
x,
|
||||
y,
|
||||
|
@ -108,13 +108,10 @@ where
|
|||
|
||||
let (is_loading, set_loading) = signal(false);
|
||||
|
||||
let el = el.into();
|
||||
let observed_element = Signal::derive_local(move || {
|
||||
let el = el.get();
|
||||
|
||||
el.map(|el| {
|
||||
let el = el.into();
|
||||
|
||||
if el.is_instance_of::<web_sys::Window>() || el.is_instance_of::<web_sys::Document>() {
|
||||
document()
|
||||
.document_element()
|
||||
|
@ -157,10 +154,9 @@ where
|
|||
set_loading.set(true);
|
||||
|
||||
let measure = measure.clone();
|
||||
leptos::spawn::spawn_local(async move {
|
||||
leptos::task::spawn_local(async move {
|
||||
#[cfg(debug_assertions)]
|
||||
let zone =
|
||||
leptos::reactive_graph::diagnostics::SpecialNonReactiveZone::enter();
|
||||
let zone = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
join!(
|
||||
on_load_more.with_value(|f| f(state)),
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use crate::core::{ElementMaybeSignal, ElementsMaybeSignal};
|
||||
use crate::core::{IntoElementMaybeSignal, IntoElementsMaybeSignal};
|
||||
use cfg_if::cfg_if;
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
||||
|
@ -55,16 +55,16 @@ cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
|||
/// ## See also
|
||||
///
|
||||
/// * [`fn@crate::use_element_visibility`]
|
||||
pub fn use_intersection_observer<El, T, F>(
|
||||
target: El,
|
||||
pub fn use_intersection_observer<Els, M, F, RootM>(
|
||||
target: Els,
|
||||
callback: F,
|
||||
) -> UseIntersectionObserverReturn<impl Fn() + Clone, impl Fn() + Clone, impl Fn() + Clone>
|
||||
where
|
||||
El: Into<ElementsMaybeSignal<T, web_sys::Element>>,
|
||||
T: Into<web_sys::Element> + Clone + 'static,
|
||||
Els: IntoElementsMaybeSignal<web_sys::Element, M>,
|
||||
F: FnMut(Vec<web_sys::IntersectionObserverEntry>, web_sys::IntersectionObserver) + 'static,
|
||||
web_sys::Element: IntoElementMaybeSignal<web_sys::Element, RootM>,
|
||||
{
|
||||
use_intersection_observer_with_options::<El, T, web_sys::Element, web_sys::Element, F>(
|
||||
use_intersection_observer_with_options::<Els, M, web_sys::Element, RootM, F>(
|
||||
target,
|
||||
callback,
|
||||
UseIntersectionObserverOptions::default(),
|
||||
|
@ -73,16 +73,14 @@ where
|
|||
|
||||
/// Version of [`use_intersection_observer`] that takes a [`UseIntersectionObserverOptions`]. See [`use_intersection_observer`] for how to use.
|
||||
#[cfg_attr(feature = "ssr", allow(unused_variables, unused_mut))]
|
||||
pub fn use_intersection_observer_with_options<El, T, RootEl, RootT, F>(
|
||||
target: El,
|
||||
pub fn use_intersection_observer_with_options<Els, M, RootEl, RootM, F>(
|
||||
target: Els,
|
||||
mut callback: F,
|
||||
options: UseIntersectionObserverOptions<RootEl, RootT>,
|
||||
options: UseIntersectionObserverOptions<RootEl, RootM>,
|
||||
) -> UseIntersectionObserverReturn<impl Fn() + Clone, impl Fn() + Clone, impl Fn() + Clone>
|
||||
where
|
||||
El: Into<ElementsMaybeSignal<T, web_sys::Element>>,
|
||||
T: Into<web_sys::Element> + Clone + 'static,
|
||||
RootEl: Into<ElementMaybeSignal<RootT, web_sys::Element>>,
|
||||
RootT: Into<web_sys::Element> + Clone + 'static,
|
||||
Els: IntoElementsMaybeSignal<web_sys::Element, M>,
|
||||
RootEl: IntoElementMaybeSignal<web_sys::Element, RootM>,
|
||||
F: FnMut(Vec<web_sys::IntersectionObserverEntry>, web_sys::IntersectionObserver) + 'static,
|
||||
{
|
||||
let UseIntersectionObserverOptions {
|
||||
|
@ -105,7 +103,7 @@ where
|
|||
let closure_js = Closure::<dyn FnMut(js_sys::Array, web_sys::IntersectionObserver)>::new(
|
||||
move |entries: js_sys::Array, observer| {
|
||||
#[cfg(debug_assertions)]
|
||||
let _z = leptos::reactive_graph::diagnostics::SpecialNonReactiveZone::enter();
|
||||
let _z = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
callback(
|
||||
entries
|
||||
|
@ -132,8 +130,8 @@ where
|
|||
}
|
||||
};
|
||||
|
||||
let targets = target.into();
|
||||
let root = root.map(|root| (root).into());
|
||||
let targets = target.into_elements_maybe_signal();
|
||||
let root = root.map(|root| root.into_element_maybe_signal());
|
||||
|
||||
let stop_watch = {
|
||||
let cleanup = cleanup.clone();
|
||||
|
@ -166,7 +164,7 @@ where
|
|||
);
|
||||
|
||||
if let Some(Some(root)) = root {
|
||||
let root: web_sys::Element = root.clone().into();
|
||||
let root = root.clone();
|
||||
options.set_root(Some(&root));
|
||||
}
|
||||
|
||||
|
@ -177,7 +175,7 @@ where
|
|||
.expect("failed to create IntersectionObserver");
|
||||
|
||||
for target in targets.iter().flatten() {
|
||||
let target: web_sys::Element = target.clone().into();
|
||||
let target = target.clone();
|
||||
obs.observe(&target);
|
||||
}
|
||||
|
||||
|
@ -221,10 +219,9 @@ where
|
|||
|
||||
/// Options for [`use_intersection_observer_with_options`].
|
||||
#[derive(DefaultBuilder)]
|
||||
pub struct UseIntersectionObserverOptions<El, T>
|
||||
pub struct UseIntersectionObserverOptions<El, M>
|
||||
where
|
||||
El: Into<ElementMaybeSignal<T, web_sys::Element>>,
|
||||
T: Into<web_sys::Element> + Clone + 'static,
|
||||
El: IntoElementMaybeSignal<web_sys::Element, M>,
|
||||
{
|
||||
/// If `true`, the `IntersectionObserver` will be attached immediately. Otherwise it
|
||||
/// will only be attached after the returned `resume` closure is called. That is
|
||||
|
@ -257,10 +254,13 @@ where
|
|||
thresholds: Vec<f64>,
|
||||
|
||||
#[builder(skip)]
|
||||
_marker: PhantomData<T>,
|
||||
_marker: PhantomData<M>,
|
||||
}
|
||||
|
||||
impl Default for UseIntersectionObserverOptions<web_sys::Element, web_sys::Element> {
|
||||
impl<M> Default for UseIntersectionObserverOptions<web_sys::Element, M>
|
||||
where
|
||||
web_sys::Element: IntoElementMaybeSignal<web_sys::Element, M>,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
immediate: true,
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::utils::Pausable;
|
|||
use crate::{use_interval_fn_with_options, UseIntervalFnOptions};
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
use std::rc::Rc;
|
||||
|
||||
/// Reactive counter increases on every interval.
|
||||
|
|
|
@ -104,7 +104,7 @@ where
|
|||
|
||||
move || {
|
||||
#[cfg(debug_assertions)]
|
||||
let _z = leptos::reactive_graph::diagnostics::SpecialNonReactiveZone::enter();
|
||||
let _z = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
callback();
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::utils::js_value_from_to_string;
|
|||
use cfg_if::cfg_if;
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
use std::fmt::Display;
|
||||
use wasm_bindgen::{JsCast, JsValue};
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::use_event_listener;
|
|||
use cfg_if::cfg_if;
|
||||
use leptos::ev::change;
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
#![cfg_attr(feature = "ssr", allow(unused_variables, unused_imports))]
|
||||
|
||||
use crate::core::{ElementMaybeSignal, Position};
|
||||
use crate::core::{IntoElementMaybeSignal, Position};
|
||||
use crate::{use_event_listener_with_options, use_window, UseEventListenerOptions, UseWindow};
|
||||
use cfg_if::cfg_if;
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::ev::{dragover, mousemove, touchend, touchmove, touchstart};
|
||||
use leptos::prelude::*;
|
||||
|
@ -93,10 +92,9 @@ pub fn use_mouse() -> UseMouseReturn {
|
|||
}
|
||||
|
||||
/// Variant of [`use_mouse`] that accepts options. Please see [`use_mouse`] for how to use.
|
||||
pub fn use_mouse_with_options<El, T, Ex>(options: UseMouseOptions<El, T, Ex>) -> UseMouseReturn
|
||||
pub fn use_mouse_with_options<El, M, Ex>(options: UseMouseOptions<El, M, Ex>) -> UseMouseReturn
|
||||
where
|
||||
El: Into<ElementMaybeSignal<T, web_sys::EventTarget>> + Clone,
|
||||
T: Into<web_sys::EventTarget> + Clone + 'static,
|
||||
El: IntoElementMaybeSignal<web_sys::EventTarget, M>,
|
||||
Ex: UseMouseEventExtractor + Clone + 'static,
|
||||
{
|
||||
let (x, set_x) = signal(options.initial_value.x);
|
||||
|
@ -155,8 +153,9 @@ where
|
|||
|
||||
// TODO : event filters?
|
||||
|
||||
cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
||||
let target = options.target;
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
{
|
||||
let target = options.target.into_element_maybe_signal();
|
||||
let event_listener_options = UseEventListenerOptions::default().passive(true);
|
||||
|
||||
let _ = use_event_listener_with_options(
|
||||
|
@ -171,6 +170,7 @@ where
|
|||
drag_handler,
|
||||
event_listener_options,
|
||||
);
|
||||
|
||||
if options.touch && !matches!(options.coord_type, UseMouseCoordType::Movement) {
|
||||
let _ = use_event_listener_with_options(
|
||||
target.clone(),
|
||||
|
@ -193,7 +193,7 @@ where
|
|||
);
|
||||
}
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
UseMouseReturn {
|
||||
x: x.into(),
|
||||
|
@ -206,10 +206,9 @@ where
|
|||
|
||||
#[derive(DefaultBuilder)]
|
||||
/// Options for [`use_mouse_with_options`].
|
||||
pub struct UseMouseOptions<El, T, Ex>
|
||||
pub struct UseMouseOptions<El, M, Ex>
|
||||
where
|
||||
El: Clone + Into<ElementMaybeSignal<T, web_sys::EventTarget>>,
|
||||
T: Into<web_sys::EventTarget> + Clone + 'static,
|
||||
El: IntoElementMaybeSignal<web_sys::EventTarget, M>,
|
||||
Ex: UseMouseEventExtractor + Clone,
|
||||
{
|
||||
/// How to extract the x, y coordinates from mouse events or touches
|
||||
|
@ -228,10 +227,13 @@ where
|
|||
initial_value: Position,
|
||||
|
||||
#[builder(skip)]
|
||||
_marker: PhantomData<T>,
|
||||
_marker: PhantomData<M>,
|
||||
}
|
||||
|
||||
impl Default for UseMouseOptions<UseWindow, web_sys::Window, Infallible> {
|
||||
impl<M> Default for UseMouseOptions<UseWindow, M, Infallible>
|
||||
where
|
||||
UseWindow: IntoElementMaybeSignal<web_sys::EventTarget, M>,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
coord_type: UseMouseCoordType::default(),
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
use crate::core::{ElementMaybeSignal, Position};
|
||||
use crate::core::{IntoElementMaybeSignal, Position};
|
||||
use crate::{
|
||||
use_mouse_with_options, use_window, UseMouseCoordType, UseMouseEventExtractor, UseMouseOptions,
|
||||
UseMouseReturn, UseMouseSourceType, UseWindow,
|
||||
};
|
||||
use cfg_if::cfg_if;
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::prelude::*;
|
||||
use std::convert::Infallible;
|
||||
|
@ -39,24 +38,21 @@ use std::marker::PhantomData;
|
|||
///
|
||||
/// On the server this returns simple Signals with the `initial_value` for `x` and `y`,
|
||||
/// no-op for `stop`, `is_outside = true` and `0.0` for the rest of the signals.
|
||||
pub fn use_mouse_in_element<El, T>(target: El) -> UseMouseInElementReturn<impl Fn() + Clone>
|
||||
pub fn use_mouse_in_element<El, M>(target: El) -> UseMouseInElementReturn<impl Fn() + Clone>
|
||||
where
|
||||
El: Into<ElementMaybeSignal<T, web_sys::Element>> + Clone,
|
||||
T: Into<web_sys::Element> + Clone + 'static,
|
||||
El: IntoElementMaybeSignal<web_sys::Element, M>,
|
||||
{
|
||||
use_mouse_in_element_with_options(target, Default::default())
|
||||
}
|
||||
|
||||
/// Version of [`use_mouse_in_element`] that takes a `UseMouseInElementOptions`. See [`use_mouse_in_element`] for how to use.
|
||||
pub fn use_mouse_in_element_with_options<El, T, OptEl, OptT, OptEx>(
|
||||
pub fn use_mouse_in_element_with_options<El, M, OptEl, OptM, OptEx>(
|
||||
target: El,
|
||||
options: UseMouseInElementOptions<OptEl, OptT, OptEx>,
|
||||
options: UseMouseInElementOptions<OptEl, OptM, OptEx>,
|
||||
) -> UseMouseInElementReturn<impl Fn() + Clone>
|
||||
where
|
||||
El: Into<ElementMaybeSignal<T, web_sys::Element>> + Clone,
|
||||
T: Into<web_sys::Element> + Clone + 'static,
|
||||
OptEl: Into<ElementMaybeSignal<OptT, web_sys::EventTarget>> + Clone,
|
||||
OptT: Into<web_sys::EventTarget> + Clone + 'static,
|
||||
El: IntoElementMaybeSignal<web_sys::Element, M>,
|
||||
OptEl: IntoElementMaybeSignal<web_sys::EventTarget, OptM>,
|
||||
OptEx: UseMouseEventExtractor + Clone + 'static,
|
||||
{
|
||||
let UseMouseInElementOptions {
|
||||
|
@ -88,8 +84,11 @@ where
|
|||
let (element_height, set_element_height) = signal(0.0);
|
||||
let (is_outside, set_outside) = signal(true);
|
||||
|
||||
cfg_if! { if #[cfg(feature = "ssr")] {
|
||||
let stop = || ();
|
||||
let stop;
|
||||
|
||||
#[cfg(feature = "ssr")]
|
||||
{
|
||||
stop = || ();
|
||||
|
||||
let _ = handle_outside;
|
||||
|
||||
|
@ -101,18 +100,21 @@ where
|
|||
let _ = set_element_height;
|
||||
let _ = set_outside;
|
||||
let _ = target;
|
||||
} else {
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
{
|
||||
use crate::use_event_listener;
|
||||
use leptos::ev::mouseleave;
|
||||
|
||||
let target = target.into();
|
||||
let target = target.into_element_maybe_signal();
|
||||
let window = window();
|
||||
|
||||
let effect = Effect::watch(
|
||||
move || (target.get(), x.get(), y.get()),
|
||||
move |(el, x, y), _, _| {
|
||||
if let Some(el) = el {
|
||||
let el: web_sys::Element = el.clone().into();
|
||||
let el = el.clone();
|
||||
let rect = el.get_bounding_client_rect();
|
||||
let left = rect.left();
|
||||
let top = rect.top();
|
||||
|
@ -146,10 +148,10 @@ where
|
|||
false,
|
||||
);
|
||||
|
||||
let stop = move || effect.stop();
|
||||
stop = move || effect.stop();
|
||||
|
||||
let _ = use_event_listener(document(), mouseleave, move |_| set_outside.set(true));
|
||||
}}
|
||||
}
|
||||
|
||||
UseMouseInElementReturn {
|
||||
x,
|
||||
|
@ -168,10 +170,9 @@ where
|
|||
|
||||
/// Options for [`use_mouse_in_element_with_options`].
|
||||
#[derive(DefaultBuilder)]
|
||||
pub struct UseMouseInElementOptions<El, T, Ex>
|
||||
pub struct UseMouseInElementOptions<El, M, Ex>
|
||||
where
|
||||
El: Clone + Into<ElementMaybeSignal<T, web_sys::EventTarget>>,
|
||||
T: Into<web_sys::EventTarget> + Clone + 'static,
|
||||
El: IntoElementMaybeSignal<web_sys::EventTarget, M>,
|
||||
Ex: UseMouseEventExtractor + Clone,
|
||||
{
|
||||
/// How to extract the x, y coordinates from mouse events or touches
|
||||
|
@ -195,10 +196,13 @@ where
|
|||
handle_outside: bool,
|
||||
|
||||
#[builder(skip)]
|
||||
_marker: PhantomData<T>,
|
||||
_marker: PhantomData<M>,
|
||||
}
|
||||
|
||||
impl Default for UseMouseInElementOptions<UseWindow, web_sys::Window, Infallible> {
|
||||
impl<M> Default for UseMouseInElementOptions<UseWindow, M, Infallible>
|
||||
where
|
||||
UseWindow: IntoElementMaybeSignal<web_sys::EventTarget, M>,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
coord_type: UseMouseCoordType::default(),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::core::ElementsMaybeSignal;
|
||||
use crate::core::IntoElementsMaybeSignal;
|
||||
use cfg_if::cfg_if;
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
||||
|
@ -50,13 +50,12 @@ cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
|||
/// ## Server-Side Rendering
|
||||
///
|
||||
/// On the server this amounts to a no-op.
|
||||
pub fn use_mutation_observer<El, T, F>(
|
||||
pub fn use_mutation_observer<El, M, F>(
|
||||
target: El,
|
||||
callback: F,
|
||||
) -> UseMutationObserverReturn<impl Fn() + Clone>
|
||||
where
|
||||
El: Into<ElementsMaybeSignal<T, web_sys::Element>>,
|
||||
T: Into<web_sys::Element> + Clone + 'static,
|
||||
El: IntoElementsMaybeSignal<web_sys::Element, M>,
|
||||
F: FnMut(Vec<web_sys::MutationRecord>, web_sys::MutationObserver) + 'static,
|
||||
{
|
||||
use_mutation_observer_with_options(target, callback, UseMutationObserverOptions::default())
|
||||
|
@ -64,14 +63,13 @@ where
|
|||
|
||||
/// Version of [`use_mutation_observer`] that takes a `UseMutationObserverOptions`. See [`use_mutation_observer`] for how to use.
|
||||
#[cfg_attr(feature = "ssr", allow(unused_variables, unused_mut))]
|
||||
pub fn use_mutation_observer_with_options<El, T, F>(
|
||||
pub fn use_mutation_observer_with_options<El, M, F>(
|
||||
target: El,
|
||||
mut callback: F,
|
||||
options: UseMutationObserverOptions,
|
||||
) -> UseMutationObserverReturn<impl Fn() + Clone>
|
||||
where
|
||||
El: Into<ElementsMaybeSignal<T, web_sys::Element>>,
|
||||
T: Into<web_sys::Element> + Clone + 'static,
|
||||
El: IntoElementsMaybeSignal<web_sys::Element, M>,
|
||||
F: FnMut(Vec<web_sys::MutationRecord>, web_sys::MutationObserver) + 'static,
|
||||
{
|
||||
#[cfg(feature = "ssr")]
|
||||
|
@ -90,7 +88,7 @@ where
|
|||
let closure_js = Closure::<dyn FnMut(js_sys::Array, web_sys::MutationObserver)>::new(
|
||||
move |entries: js_sys::Array, observer| {
|
||||
#[cfg(debug_assertions)]
|
||||
let _z = leptos::reactive_graph::diagnostics::SpecialNonReactiveZone::enter();
|
||||
let _z = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
callback(
|
||||
entries
|
||||
|
@ -120,7 +118,7 @@ where
|
|||
}
|
||||
};
|
||||
|
||||
let targets = target.into();
|
||||
let targets = target.into_elements_maybe_signal();
|
||||
|
||||
let stop_watch = {
|
||||
let cleanup = cleanup.clone();
|
||||
|
@ -136,7 +134,7 @@ where
|
|||
.expect("failed to create MutationObserver");
|
||||
|
||||
for target in targets.iter().flatten() {
|
||||
let target: web_sys::Element = target.clone().into();
|
||||
let target = target.clone();
|
||||
let _ = obs.observe_with_options(&target, &options.clone().into());
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
use std::fmt::Display;
|
||||
|
||||
/// Reactive [Permissions API](https://developer.mozilla.org/en-US/docs/Web/API/Permissions_API).
|
||||
|
@ -46,7 +46,7 @@ pub fn use_permission(permission_name: &str) -> Signal<PermissionState> {
|
|||
}
|
||||
};
|
||||
|
||||
leptos::spawn::spawn_local({
|
||||
leptos::task::spawn_local({
|
||||
let permission_name = permission_name.to_owned();
|
||||
|
||||
async move {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::use_media_query;
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
use std::fmt::Display;
|
||||
|
||||
/// Reactive [prefers-contrast](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-contrast) media query.
|
||||
|
|
|
@ -14,6 +14,7 @@ use std::sync::Arc;
|
|||
/// ```
|
||||
/// # use leptos::prelude::*;
|
||||
/// # use leptos_use::use_prefers_reduced_motion;
|
||||
/// # #[cfg(feature = "docs")]
|
||||
/// # use leptos_use::docs::BooleanDisplay;
|
||||
/// #
|
||||
/// # #[component]
|
||||
|
|
|
@ -102,7 +102,7 @@ pub fn use_raf_fn_with_options(
|
|||
};
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
let zone = leptos::reactive_graph::diagnostics::SpecialNonReactiveZone::enter();
|
||||
let zone = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
callback(UseRafFnCallbackArgs { delta, timestamp });
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::core::ElementsMaybeSignal;
|
||||
use crate::core::IntoElementsMaybeSignal;
|
||||
use cfg_if::cfg_if;
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
|
||||
cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
||||
use crate::use_supported;
|
||||
|
@ -52,13 +52,12 @@ cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
|||
/// ## See also
|
||||
///
|
||||
/// * [`fn@crate::use_element_size`]
|
||||
pub fn use_resize_observer<El, T, F>(
|
||||
target: El, // TODO : multiple elements?
|
||||
pub fn use_resize_observer<Els, M, F>(
|
||||
target: Els,
|
||||
callback: F,
|
||||
) -> UseResizeObserverReturn<impl Fn() + Clone>
|
||||
where
|
||||
El: Into<ElementsMaybeSignal<T, web_sys::Element>>,
|
||||
T: Into<web_sys::Element> + Clone + 'static,
|
||||
Els: IntoElementsMaybeSignal<web_sys::Element, M>,
|
||||
F: FnMut(Vec<web_sys::ResizeObserverEntry>, web_sys::ResizeObserver) + 'static,
|
||||
{
|
||||
use_resize_observer_with_options(target, callback, UseResizeObserverOptions::default())
|
||||
|
@ -66,14 +65,13 @@ where
|
|||
|
||||
/// Version of [`use_resize_observer`] that takes a `web_sys::ResizeObserverOptions`. See [`use_resize_observer`] for how to use.
|
||||
#[cfg_attr(feature = "ssr", allow(unused_variables, unused_mut))]
|
||||
pub fn use_resize_observer_with_options<El, T, F>(
|
||||
target: El, // TODO : multiple elements?
|
||||
pub fn use_resize_observer_with_options<Els, M, F>(
|
||||
target: Els,
|
||||
mut callback: F,
|
||||
options: UseResizeObserverOptions,
|
||||
) -> UseResizeObserverReturn<impl Fn() + Clone>
|
||||
where
|
||||
El: Into<ElementsMaybeSignal<T, web_sys::Element>>,
|
||||
T: Into<web_sys::Element> + Clone + 'static,
|
||||
Els: IntoElementsMaybeSignal<web_sys::Element, M>,
|
||||
F: FnMut(Vec<web_sys::ResizeObserverEntry>, web_sys::ResizeObserver) + 'static,
|
||||
{
|
||||
#[cfg(feature = "ssr")]
|
||||
|
@ -91,7 +89,7 @@ where
|
|||
let closure_js = Closure::<dyn FnMut(js_sys::Array, web_sys::ResizeObserver)>::new(
|
||||
move |entries: js_sys::Array, observer| {
|
||||
#[cfg(debug_assertions)]
|
||||
let _z = leptos::reactive_graph::diagnostics::SpecialNonReactiveZone::enter();
|
||||
let _z = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
callback(
|
||||
entries
|
||||
|
@ -121,7 +119,7 @@ where
|
|||
}
|
||||
};
|
||||
|
||||
let targets = target.into();
|
||||
let targets = target.into_elements_maybe_signal();
|
||||
|
||||
let stop_watch = {
|
||||
let cleanup = cleanup.clone();
|
||||
|
@ -138,7 +136,7 @@ where
|
|||
.expect("failed to create ResizeObserver");
|
||||
|
||||
for target in targets.iter().flatten() {
|
||||
let target: web_sys::Element = target.clone().into();
|
||||
let target = target.clone();
|
||||
obs.observe_with_options(&target, &options.clone().into());
|
||||
}
|
||||
observer.replace(Some(obs));
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use crate::core::{Direction, Directions, ElementMaybeSignal};
|
||||
use crate::core::{Direction, Directions, IntoElementMaybeSignal};
|
||||
use crate::UseEventListenerOptions;
|
||||
use cfg_if::cfg_if;
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
use std::rc::Rc;
|
||||
|
||||
cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
||||
|
@ -176,27 +176,23 @@ const ARRIVED_STATE_THRESHOLD_PIXELS: f64 = 1.0;
|
|||
/// ## Server-Side Rendering
|
||||
///
|
||||
/// On the server this returns signals that don't change and setters that are noops.
|
||||
pub fn use_scroll<El, T>(
|
||||
pub fn use_scroll<El, M>(
|
||||
element: El,
|
||||
) -> UseScrollReturn<impl Fn(f64) + Clone, impl Fn(f64) + Clone, impl Fn() + Clone>
|
||||
where
|
||||
El: Clone,
|
||||
El: Into<ElementMaybeSignal<T, web_sys::Element>>,
|
||||
T: Into<web_sys::Element> + Clone + 'static,
|
||||
El: IntoElementMaybeSignal<web_sys::Element, M>,
|
||||
{
|
||||
use_scroll_with_options(element, Default::default())
|
||||
}
|
||||
|
||||
/// Version of [`use_scroll`] with options. See [`use_scroll`] for how to use.
|
||||
#[cfg_attr(feature = "ssr", allow(unused_variables))]
|
||||
pub fn use_scroll_with_options<El, T>(
|
||||
pub fn use_scroll_with_options<El, M>(
|
||||
element: El,
|
||||
options: UseScrollOptions,
|
||||
) -> UseScrollReturn<impl Fn(f64) + Clone, impl Fn(f64) + Clone, impl Fn() + Clone>
|
||||
where
|
||||
El: Clone,
|
||||
El: Into<ElementMaybeSignal<T, web_sys::Element>>,
|
||||
T: Into<web_sys::Element> + Clone + 'static,
|
||||
El: IntoElementMaybeSignal<web_sys::Element, M>,
|
||||
{
|
||||
let (internal_x, set_internal_x) = signal(0.0);
|
||||
let (internal_y, set_internal_y) = signal(0.0);
|
||||
|
@ -216,12 +212,20 @@ where
|
|||
bottom: false,
|
||||
});
|
||||
|
||||
cfg_if! { if #[cfg(feature = "ssr")] {
|
||||
let set_x = |_| {};
|
||||
let set_y = |_| {};
|
||||
let measure = || {};
|
||||
} else {
|
||||
let signal = element.into();
|
||||
let set_x;
|
||||
let set_y;
|
||||
let measure;
|
||||
|
||||
#[cfg(feature = "ssr")]
|
||||
{
|
||||
set_x = |_| {};
|
||||
set_y = |_| {};
|
||||
measure = || {};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
{
|
||||
let signal = element.into_element_maybe_signal();
|
||||
let behavior = options.behavior;
|
||||
|
||||
let scroll_to = {
|
||||
|
@ -231,8 +235,6 @@ where
|
|||
let element = signal.get_untracked();
|
||||
|
||||
if let Some(element) = element {
|
||||
let element = element.into();
|
||||
|
||||
let scroll_options = web_sys::ScrollToOptions::new();
|
||||
scroll_options.set_behavior(behavior.get_untracked().into());
|
||||
|
||||
|
@ -248,12 +250,12 @@ where
|
|||
}
|
||||
};
|
||||
|
||||
let set_x = {
|
||||
set_x = {
|
||||
let scroll_to = scroll_to.clone();
|
||||
move |x| scroll_to(Some(x), None)
|
||||
};
|
||||
|
||||
let set_y = move |y| scroll_to(None, Some(y));
|
||||
set_y = move |y| scroll_to(None, Some(y));
|
||||
|
||||
let on_scroll_end = {
|
||||
let on_stop = Rc::clone(&options.on_stop);
|
||||
|
@ -367,14 +369,14 @@ where
|
|||
}
|
||||
};
|
||||
|
||||
let target = {
|
||||
let target = Signal::derive_local({
|
||||
let signal = signal.clone();
|
||||
|
||||
Signal::derive_local(move || {
|
||||
move || {
|
||||
let element = signal.get();
|
||||
element.map(|element| element.into().unchecked_into::<web_sys::EventTarget>())
|
||||
})
|
||||
};
|
||||
element.map(|element| element.unchecked_into::<web_sys::EventTarget>())
|
||||
}
|
||||
});
|
||||
|
||||
if throttle >= 0.0 {
|
||||
let throttled_scroll_handler = use_throttle_fn_with_arg_and_options(
|
||||
|
@ -393,14 +395,14 @@ where
|
|||
let _ = use_event_listener_with_options::<
|
||||
_,
|
||||
Signal<Option<web_sys::EventTarget>, LocalStorage>,
|
||||
web_sys::EventTarget,
|
||||
_,
|
||||
_,
|
||||
>(target, ev::scroll, handler, options.event_listener_options);
|
||||
} else {
|
||||
let _ = use_event_listener_with_options::<
|
||||
_,
|
||||
Signal<Option<web_sys::EventTarget>, LocalStorage>,
|
||||
web_sys::EventTarget,
|
||||
_,
|
||||
_,
|
||||
>(
|
||||
target,
|
||||
|
@ -413,7 +415,7 @@ where
|
|||
let _ = use_event_listener_with_options::<
|
||||
_,
|
||||
Signal<Option<web_sys::EventTarget>, LocalStorage>,
|
||||
web_sys::EventTarget,
|
||||
_,
|
||||
_,
|
||||
>(
|
||||
target,
|
||||
|
@ -422,13 +424,12 @@ where
|
|||
options.event_listener_options,
|
||||
);
|
||||
|
||||
let measure = move || {
|
||||
measure = move || {
|
||||
if let Some(el) = signal.try_get_untracked().flatten() {
|
||||
let el = el.into();
|
||||
set_arrived_state(el);
|
||||
}
|
||||
};
|
||||
}}
|
||||
}
|
||||
|
||||
UseScrollReturn {
|
||||
x: internal_x.into(),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::actions::Action;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::actions::Action;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
use send_wrapper::SendWrapper;
|
||||
use std::sync::Arc;
|
||||
use wasm_bindgen::{prelude::Closure, JsCast, JsValue};
|
||||
|
@ -54,7 +54,7 @@ pub fn use_service_worker_with_options(
|
|||
let on_controller_change = options.on_controller_change.clone();
|
||||
let js_closure = Closure::wrap(Box::new(move |_event: JsValue| {
|
||||
#[cfg(debug_assertions)]
|
||||
let _z = leptos::reactive_graph::diagnostics::SpecialNonReactiveZone::enter();
|
||||
let _z = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
on_controller_change();
|
||||
}) as Box<dyn FnMut(JsValue)>)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
use std::cmp::Ordering;
|
||||
use std::ops::DerefMut;
|
||||
|
||||
|
|
330
src/use_textarea_autosize.rs
Normal file
330
src/use_textarea_autosize.rs
Normal file
|
@ -0,0 +1,330 @@
|
|||
use crate::core::{ElementMaybeSignal, IntoElementMaybeSignal, MaybeRwSignal};
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::prelude::*;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Automatically update the height of a textarea depending on the content.
|
||||
///
|
||||
/// ## Demo
|
||||
///
|
||||
/// [Link to Demo](https://github.com/Synphonyte/leptos-use/tree/main/examples/use_textarea_autosize)
|
||||
///
|
||||
/// ## Usage
|
||||
///
|
||||
/// ### Simple example
|
||||
///
|
||||
/// ```
|
||||
/// # use leptos::prelude::*;
|
||||
/// # use leptos::html::Textarea;
|
||||
/// # use leptos_use::{use_textarea_autosize, UseTextareaAutosizeReturn};
|
||||
/// #
|
||||
/// # #[component]
|
||||
/// # fn Demo() -> impl IntoView {
|
||||
/// let textarea = NodeRef::new();
|
||||
///
|
||||
/// let UseTextareaAutosizeReturn {
|
||||
/// content,
|
||||
/// set_content,
|
||||
/// trigger_resize
|
||||
/// } = use_textarea_autosize(textarea);
|
||||
///
|
||||
/// view! {
|
||||
/// <textarea
|
||||
/// prop:value=content
|
||||
/// on:input=move |evt| set_content.set(event_target_value(&evt))
|
||||
/// node_ref=textarea
|
||||
/// class="resize-none"
|
||||
/// placeholder="What's on your mind?"
|
||||
/// />
|
||||
/// }
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// > Make sure that you set `box-sizing: border-box` on the textarea element.
|
||||
/// >
|
||||
/// > It's also recommended to reset the scrollbar styles for the textarea element to avoid
|
||||
/// > incorrect height values for large amounts of text.
|
||||
///
|
||||
/// ```css
|
||||
/// textarea {
|
||||
/// -ms-overflow-style: none;
|
||||
/// scrollbar-width: none;
|
||||
/// }
|
||||
///
|
||||
/// textarea::-webkit-scrollbar {
|
||||
/// display: none;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ### With `rows` attribute
|
||||
///
|
||||
/// If you need support for the rows attribute on a textarea element, then you should set the
|
||||
/// `style_prop` option to `"min-height"`.
|
||||
///
|
||||
/// ```
|
||||
/// # use leptos::prelude::*;
|
||||
/// # use leptos::html::Textarea;
|
||||
/// # use leptos_use::{use_textarea_autosize_with_options, UseTextareaAutosizeOptions, UseTextareaAutosizeReturn};
|
||||
/// #
|
||||
/// # #[component]
|
||||
/// # fn Demo() -> impl IntoView {
|
||||
/// let textarea = NodeRef::new();
|
||||
///
|
||||
/// let UseTextareaAutosizeReturn {
|
||||
/// content,
|
||||
/// set_content,
|
||||
/// ..
|
||||
/// } = use_textarea_autosize_with_options(
|
||||
/// textarea,
|
||||
/// UseTextareaAutosizeOptions::default().style_prop("min-height"),
|
||||
/// );
|
||||
///
|
||||
/// view! {
|
||||
/// <textarea
|
||||
/// prop:value=content
|
||||
/// on:input=move |evt| set_content.set(event_target_value(&evt))
|
||||
/// node_ref=textarea
|
||||
/// class="resize-none"
|
||||
/// placeholder="What's on your mind?"
|
||||
/// rows="3"
|
||||
/// />
|
||||
/// }
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// ## Server-Side Rendering
|
||||
///
|
||||
/// On the server this will always return an empty string as ´content` and a no-op `trigger_resize`.
|
||||
// #[doc(cfg(feature = "use_textarea_autosize"))]
|
||||
pub fn use_textarea_autosize<El, M>(el: El) -> UseTextareaAutosizeReturn<impl Fn() + Clone>
|
||||
where
|
||||
El: IntoElementMaybeSignal<web_sys::Element, M> + Clone,
|
||||
{
|
||||
use_textarea_autosize_with_options::<El, M>(el, UseTextareaAutosizeOptions::default())
|
||||
}
|
||||
|
||||
/// Version of [`fn@crate::use_textarea_autosize`] that takes a `UseTextareaAutosizeOptions`. See [`fn@crate::use_textarea_autosize`] for how to use.
|
||||
// #[doc(cfg(feature = "use_textarea_autosize"))]
|
||||
pub fn use_textarea_autosize_with_options<El, M>(
|
||||
el: El,
|
||||
options: UseTextareaAutosizeOptions,
|
||||
) -> UseTextareaAutosizeReturn<impl Fn() + Clone>
|
||||
where
|
||||
El: IntoElementMaybeSignal<web_sys::Element, M> + Clone,
|
||||
{
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
{
|
||||
use wasm_bindgen::JsCast;
|
||||
|
||||
let el = el.into_element_maybe_signal();
|
||||
let textarea = Signal::derive_local(move || {
|
||||
el.get()
|
||||
.map(|el| el.unchecked_into::<web_sys::HtmlTextAreaElement>())
|
||||
});
|
||||
|
||||
let UseTextareaAutosizeOptions {
|
||||
content,
|
||||
watch: watch_fn,
|
||||
on_resize,
|
||||
style_target,
|
||||
style_prop,
|
||||
} = options;
|
||||
|
||||
let (content, set_content) = content.into_signal();
|
||||
|
||||
let (textarea_scroll_height, set_textarea_scroll_height) = signal(1);
|
||||
let (textarea_old_width, set_textarea_old_width) = signal(0.0);
|
||||
|
||||
let trigger_resize = move || {
|
||||
textarea.with_untracked(|textarea| {
|
||||
if let Some(textarea) = textarea {
|
||||
let mut height = "".to_string();
|
||||
|
||||
let border_offset =
|
||||
if let Ok(Some(style)) = window().get_computed_style(textarea) {
|
||||
(parse_num(
|
||||
&style
|
||||
.get_property_value("border-top-width")
|
||||
.unwrap_or_default(),
|
||||
) + parse_num(
|
||||
&style
|
||||
.get_property_value("border-bottom-width")
|
||||
.unwrap_or_default(),
|
||||
)) as i32
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
web_sys::HtmlElement::style(textarea)
|
||||
.set_property(&style_prop, "1px")
|
||||
.ok();
|
||||
set_textarea_scroll_height.set(textarea.scroll_height() + border_offset + 1);
|
||||
|
||||
if let Some(style_target) = style_target.get() {
|
||||
// If style target is provided update its height
|
||||
style_target
|
||||
.unchecked_into::<web_sys::HtmlElement>()
|
||||
.style()
|
||||
.set_property(
|
||||
&style_prop,
|
||||
&format!("{}px", textarea_scroll_height.get_untracked()),
|
||||
)
|
||||
.ok();
|
||||
} else {
|
||||
// else update textarea's height by updating height variable
|
||||
height = format!("{}px", textarea_scroll_height.get_untracked());
|
||||
}
|
||||
|
||||
web_sys::HtmlElement::style(textarea)
|
||||
.set_property(&style_prop, &height)
|
||||
.ok();
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
Effect::watch(
|
||||
move || {
|
||||
content.with(|_| ());
|
||||
textarea.with(|_| ());
|
||||
},
|
||||
{
|
||||
let trigger_resize = trigger_resize.clone();
|
||||
|
||||
move |_, _, _| {
|
||||
trigger_resize();
|
||||
}
|
||||
},
|
||||
true,
|
||||
);
|
||||
|
||||
Effect::watch(
|
||||
move || textarea_scroll_height.track(),
|
||||
move |_, _, _| {
|
||||
on_resize();
|
||||
},
|
||||
false,
|
||||
);
|
||||
|
||||
crate::use_resize_observer(textarea, {
|
||||
let trigger_resize = trigger_resize.clone();
|
||||
|
||||
move |entries, _| {
|
||||
for entry in entries {
|
||||
let width = entry.content_rect().width();
|
||||
|
||||
if width != textarea_old_width.get_untracked() {
|
||||
set_textarea_old_width.set(width);
|
||||
trigger_resize();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Effect::watch(
|
||||
move || watch_fn(),
|
||||
{
|
||||
let trigger_resize = trigger_resize.clone();
|
||||
|
||||
move |_, _, _| {
|
||||
trigger_resize();
|
||||
}
|
||||
},
|
||||
false,
|
||||
);
|
||||
|
||||
UseTextareaAutosizeReturn {
|
||||
content,
|
||||
set_content,
|
||||
trigger_resize,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ssr")]
|
||||
{
|
||||
let _ = el;
|
||||
let _ = options;
|
||||
|
||||
let (content, set_content) = signal("".to_string());
|
||||
|
||||
UseTextareaAutosizeReturn {
|
||||
content: content.into(),
|
||||
set_content,
|
||||
trigger_resize: || {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Options for [`fn@crate::use_textarea_autosize_with_options`].
|
||||
// #[doc(cfg(feature = "use_textarea_autosize"))]
|
||||
#[derive(DefaultBuilder)]
|
||||
#[cfg_attr(feature = "ssr", allow(dead_code))]
|
||||
pub struct UseTextareaAutosizeOptions {
|
||||
/// Textarea content
|
||||
#[builder(into)]
|
||||
content: MaybeRwSignal<String>,
|
||||
|
||||
/// Watch sources that should trigger a textarea resize
|
||||
watch: Arc<dyn Fn() + Send + Sync>,
|
||||
|
||||
/// Function called when the textarea size changes
|
||||
on_resize: Arc<dyn Fn() + Send + Sync>,
|
||||
|
||||
/// Specify style target to apply the height based on textarea content.
|
||||
/// If not provided it will use textarea it self.
|
||||
#[builder(skip)]
|
||||
style_target: ElementMaybeSignal<web_sys::Element>,
|
||||
|
||||
/// Specify the style property that will be used to manipulate height.
|
||||
/// Should be `"height"` or `"min-height"`. Default value is `"height"`.
|
||||
#[builder(into)]
|
||||
style_prop: String,
|
||||
}
|
||||
|
||||
impl Default for UseTextareaAutosizeOptions {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
content: MaybeRwSignal::default(),
|
||||
watch: Arc::new(|| ()),
|
||||
on_resize: Arc::new(|| ()),
|
||||
style_target: Default::default(),
|
||||
style_prop: "height".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl UseTextareaAutosizeOptions {
|
||||
/// List of elementss that should not trigger the callback. Defaults to `[]`.
|
||||
#[cfg_attr(feature = "ssr", allow(dead_code))]
|
||||
pub fn style_target<M>(
|
||||
self,
|
||||
style_target: impl IntoElementMaybeSignal<web_sys::Element, M>,
|
||||
) -> Self {
|
||||
Self {
|
||||
style_target: style_target.into_element_maybe_signal(),
|
||||
..self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return type of [`fn@crate::use_textarea_autosize`].
|
||||
// #[doc(cfg(feature = "use_textarea_autosize"))]
|
||||
pub struct UseTextareaAutosizeReturn<F>
|
||||
where
|
||||
F: Fn() + Clone,
|
||||
{
|
||||
/// The textarea content
|
||||
pub content: Signal<String>,
|
||||
|
||||
/// Set the textarea content
|
||||
pub set_content: WriteSignal<String>,
|
||||
|
||||
/// Function to trigger a textarea resize manually
|
||||
pub trigger_resize: F,
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
fn parse_num(s: &str) -> u32 {
|
||||
s.chars()
|
||||
.map_while(|c| c.to_digit(10))
|
||||
.fold(0, |acc, digit| acc * 10 + digit)
|
||||
}
|
|
@ -93,9 +93,7 @@ where
|
|||
*timer.lock().unwrap() = None;
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
let _z =
|
||||
leptos::reactive_graph::diagnostics::SpecialNonReactiveZone::enter(
|
||||
);
|
||||
let _z = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
callback(arg);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
|||
};
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
use std::rc::Rc;
|
||||
|
||||
/// Reactive current timestamp.
|
||||
|
@ -87,7 +87,7 @@ pub fn use_timestamp_with_controls_and_options(options: UseTimestampOptions) ->
|
|||
update();
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
let _z = leptos::reactive_graph::diagnostics::SpecialNonReactiveZone::enter();
|
||||
let _z = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
callback(ts.get_untracked());
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use crate::core::MaybeRwSignal;
|
||||
use cfg_if::cfg_if;
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::prelude::*;
|
||||
use wasm_bindgen::{JsCast, JsValue};
|
||||
|
@ -62,7 +61,8 @@ pub fn use_user_media_with_options(
|
|||
let (stream, set_stream) = signal_local(None::<Result<web_sys::MediaStream, JsValue>>);
|
||||
|
||||
let _start = move || async move {
|
||||
cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
{
|
||||
if stream.get_untracked().is_some() {
|
||||
return;
|
||||
}
|
||||
|
@ -70,10 +70,13 @@ pub fn use_user_media_with_options(
|
|||
let stream = create_media(video, audio).await;
|
||||
|
||||
set_stream.update(|s| *s = Some(stream));
|
||||
} else {
|
||||
}
|
||||
|
||||
#[cfg(feature = "ssr")]
|
||||
{
|
||||
let _ = video;
|
||||
let _ = audio;
|
||||
}}
|
||||
}
|
||||
};
|
||||
|
||||
let _stop = move || {
|
||||
|
@ -87,8 +90,9 @@ pub fn use_user_media_with_options(
|
|||
};
|
||||
|
||||
let start = move || {
|
||||
cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
||||
leptos::spawn::spawn_local(async move {
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
{
|
||||
leptos::task::spawn_local(async move {
|
||||
_start().await;
|
||||
stream.with_untracked(move |stream| {
|
||||
if let Some(Ok(_)) = stream {
|
||||
|
@ -96,7 +100,7 @@ pub fn use_user_media_with_options(
|
|||
}
|
||||
});
|
||||
});
|
||||
}}
|
||||
}
|
||||
};
|
||||
|
||||
let stop = move || {
|
||||
|
@ -108,7 +112,7 @@ pub fn use_user_media_with_options(
|
|||
move || enabled.get(),
|
||||
move |enabled, _, _| {
|
||||
if *enabled {
|
||||
leptos::spawn::spawn_local(async move {
|
||||
leptos::task::spawn_local(async move {
|
||||
_start().await;
|
||||
});
|
||||
} else {
|
||||
|
|
|
@ -31,7 +31,7 @@ pub use web_sys::LockMode;
|
|||
///
|
||||
/// # #[component]
|
||||
/// # fn Demo() -> impl IntoView {
|
||||
/// leptos::spawn::spawn_local(async {
|
||||
/// leptos::task::spawn_local(async {
|
||||
/// let res = use_web_lock("my_lock", my_process).await;
|
||||
/// assert!(matches!(res, Ok(42)));
|
||||
/// });
|
||||
|
@ -44,7 +44,6 @@ pub use web_sys::LockMode;
|
|||
///
|
||||
/// On the server this returns `Err(UseWebLockError::Server)` and the task is not executed.
|
||||
// #[doc(cfg(feature = "use_web_lock"))]
|
||||
|
||||
pub async fn use_web_lock<C, F, R>(name: &str, callback: C) -> Result<R, UseWebLockError>
|
||||
where
|
||||
C: FnOnce(web_sys::Lock) -> F + 'static,
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::{use_supported, use_window};
|
|||
use cfg_if::cfg_if;
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::prelude::*;
|
||||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
use std::rc::Rc;
|
||||
use wasm_bindgen::JsValue;
|
||||
|
||||
|
@ -76,7 +76,7 @@ pub fn use_web_notification_with_options(
|
|||
let on_click = Rc::clone(&options.on_click);
|
||||
move |e: web_sys::Event| {
|
||||
#[cfg(debug_assertions)]
|
||||
let _z = leptos::reactive_graph::diagnostics::SpecialNonReactiveZone::enter();
|
||||
let _z = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
on_click(e);
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ pub fn use_web_notification_with_options(
|
|||
let on_close = Rc::clone(&options.on_close);
|
||||
move |e: web_sys::Event| {
|
||||
#[cfg(debug_assertions)]
|
||||
let _z = leptos::reactive_graph::diagnostics::SpecialNonReactiveZone::enter();
|
||||
let _z = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
on_close(e);
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ pub fn use_web_notification_with_options(
|
|||
let on_error = Rc::clone(&options.on_error);
|
||||
move |e: web_sys::Event| {
|
||||
#[cfg(debug_assertions)]
|
||||
let _z = leptos::reactive_graph::diagnostics::SpecialNonReactiveZone::enter();
|
||||
let _z = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
on_error(e);
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ pub fn use_web_notification_with_options(
|
|||
let on_show = Rc::clone(&options.on_show);
|
||||
move |e: web_sys::Event| {
|
||||
#[cfg(debug_assertions)]
|
||||
let _z = leptos::reactive_graph::diagnostics::SpecialNonReactiveZone::enter();
|
||||
let _z = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
on_show(e);
|
||||
}
|
||||
|
@ -134,7 +134,7 @@ pub fn use_web_notification_with_options(
|
|||
let on_error_closure = on_error_closure.clone();
|
||||
let on_show_closure = on_show_closure.clone();
|
||||
|
||||
leptos::spawn::spawn_local(async move {
|
||||
leptos::task::spawn_local(async move {
|
||||
set_permission.set(request_web_notification_permission().await);
|
||||
|
||||
let mut notification_options = web_sys::NotificationOptions::from(&options);
|
||||
|
@ -169,7 +169,7 @@ pub fn use_web_notification_with_options(
|
|||
}
|
||||
};
|
||||
|
||||
leptos::spawn::spawn_local(async move {
|
||||
leptos::task::spawn_local(async move {
|
||||
set_permission.set(request_web_notification_permission().await);
|
||||
});
|
||||
|
||||
|
|
|
@ -285,7 +285,7 @@ where
|
|||
|
||||
let (ready_state, set_ready_state) = signal(ConnectionReadyState::Closed);
|
||||
let (message, set_message) = signal(None);
|
||||
let ws_ref: StoredValue<Option<WebSocket>, _> = StoredValue::new_local(None);
|
||||
let ws_signal = RwSignal::new_local(None::<WebSocket>);
|
||||
|
||||
let reconnect_timer_ref: StoredValue<Option<TimeoutHandle>> = StoredValue::new(None);
|
||||
|
||||
|
@ -308,8 +308,8 @@ where
|
|||
|
||||
if !manually_closed_ref.get_value()
|
||||
&& !reconnect_limit.is_exceeded_by(reconnect_times_ref.get_value())
|
||||
&& ws_ref
|
||||
.get_value()
|
||||
&& ws_signal
|
||||
.get_untracked()
|
||||
.map_or(false, |ws: WebSocket| ws.ready_state() != WebSocket::OPEN)
|
||||
{
|
||||
reconnect_timer_ref.set_value(
|
||||
|
@ -338,7 +338,7 @@ where
|
|||
Some(Arc::new(move || {
|
||||
reconnect_timer_ref.set_value(None);
|
||||
|
||||
if let Some(web_socket) = ws_ref.get_value() {
|
||||
if let Some(web_socket) = ws_signal.get_untracked() {
|
||||
let _ = web_socket.close();
|
||||
}
|
||||
|
||||
|
@ -371,7 +371,7 @@ where
|
|||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
let zone = leptos::reactive_graph::diagnostics::SpecialNonReactiveZone::enter();
|
||||
let zone = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
on_open(e);
|
||||
|
||||
|
@ -412,7 +412,7 @@ where
|
|||
let txt = String::from(&txt);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
let zone = leptos::reactive_graph::diagnostics::SpecialNonReactiveZone::enter();
|
||||
let zone = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
on_message_raw(&txt);
|
||||
|
||||
|
@ -422,7 +422,7 @@ where
|
|||
match C::decode_str(&txt) {
|
||||
Ok(val) => {
|
||||
#[cfg(debug_assertions)]
|
||||
let prev = leptos::reactive_graph::diagnostics::SpecialNonReactiveZone::enter();
|
||||
let prev = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
on_message(&val);
|
||||
|
||||
|
@ -443,7 +443,7 @@ where
|
|||
let array = array.to_vec();
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
let zone = leptos::reactive_graph::diagnostics::SpecialNonReactiveZone::enter();
|
||||
let zone = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
on_message_raw_bytes(&array);
|
||||
|
||||
|
@ -453,7 +453,7 @@ where
|
|||
match C::decode_bin(array.as_slice()) {
|
||||
Ok(val) => {
|
||||
#[cfg(debug_assertions)]
|
||||
let prev = leptos::reactive_graph::diagnostics::SpecialNonReactiveZone::enter();
|
||||
let prev = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
on_message(&val);
|
||||
|
||||
|
@ -489,7 +489,7 @@ where
|
|||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
let zone = leptos::reactive_graph::diagnostics::SpecialNonReactiveZone::enter();
|
||||
let zone = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
on_error(UseWebSocketError::Event(e));
|
||||
|
||||
|
@ -518,7 +518,7 @@ where
|
|||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
let zone = leptos::reactive_graph::diagnostics::SpecialNonReactiveZone::enter();
|
||||
let zone = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
on_close(e);
|
||||
|
||||
|
@ -532,7 +532,7 @@ where
|
|||
onclose_closure.forget();
|
||||
}
|
||||
|
||||
ws_ref.set_value(Some(web_socket));
|
||||
ws_signal.set(Some(web_socket));
|
||||
}))
|
||||
});
|
||||
}
|
||||
|
@ -541,7 +541,7 @@ where
|
|||
let send_str = {
|
||||
Box::new(move |data: &str| {
|
||||
if ready_state.get_untracked() == ConnectionReadyState::Open {
|
||||
if let Some(web_socket) = ws_ref.get_value() {
|
||||
if let Some(web_socket) = ws_signal.get_untracked() {
|
||||
let _ = web_socket.send_with_str(data);
|
||||
}
|
||||
}
|
||||
|
@ -551,7 +551,7 @@ where
|
|||
// Send bytes
|
||||
let send_bytes = move |data: &[u8]| {
|
||||
if ready_state.get_untracked() == ConnectionReadyState::Open {
|
||||
if let Some(web_socket) = ws_ref.get_value() {
|
||||
if let Some(web_socket) = ws_signal.get_untracked() {
|
||||
let _ = web_socket.send_with_u8_array(data);
|
||||
}
|
||||
}
|
||||
|
@ -589,7 +589,7 @@ where
|
|||
|
||||
move || {
|
||||
manually_closed_ref.set_value(true);
|
||||
if let Some(web_socket) = ws_ref.get_value() {
|
||||
if let Some(web_socket) = ws_signal.get_untracked() {
|
||||
let _ = web_socket.close();
|
||||
}
|
||||
}
|
||||
|
@ -611,7 +611,7 @@ where
|
|||
UseWebSocketReturn {
|
||||
ready_state: ready_state.into(),
|
||||
message: message.into(),
|
||||
ws: ws_ref.get_value(),
|
||||
ws: ws_signal.into(),
|
||||
open,
|
||||
close,
|
||||
send,
|
||||
|
@ -716,7 +716,7 @@ where
|
|||
/// Latest message received from `WebSocket`.
|
||||
pub message: Signal<Option<Rx>>,
|
||||
/// The `WebSocket` instance.
|
||||
pub ws: Option<WebSocket>,
|
||||
pub ws: Signal<Option<WebSocket>, LocalStorage>,
|
||||
/// Opens the `WebSocket` connection
|
||||
pub open: OpenFn,
|
||||
/// Closes the `WebSocket` connection
|
||||
|
|
|
@ -52,7 +52,7 @@ where
|
|||
let last_return_val = Arc::clone(&last_return_value);
|
||||
let invoke = move || {
|
||||
#[cfg(debug_assertions)]
|
||||
let zone = leptos::reactive_graph::diagnostics::SpecialNonReactiveZone::enter();
|
||||
let zone = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
let return_value = _invoke();
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ where
|
|||
let last_return_val = Arc::clone(&last_return_value);
|
||||
let invoke = move || {
|
||||
#[cfg(debug_assertions)]
|
||||
let zone = leptos::reactive_graph::diagnostics::SpecialNonReactiveZone::enter();
|
||||
let zone = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
let return_value = _invoke();
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use leptos::reactive_graph::wrappers::read::Signal;
|
||||
use leptos::reactive::wrappers::read::Signal;
|
||||
|
||||
/// Pausable effect
|
||||
pub struct Pausable<PauseFn, ResumeFn>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue