From 5529b005d724b52fbbc3d2e37b6a9d1840c5cf95 Mon Sep 17 00:00:00 2001 From: Ke7in Date: Fri, 8 Mar 2024 18:45:58 -0500 Subject: [PATCH 01/40] Add methods to UseDocument Added methods in the order they appear on the website discussed (for convenience) up to `preferred_style_sheet_set`. --- src/use_document.rs | 194 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 188 insertions(+), 6 deletions(-) diff --git a/src/use_document.rs b/src/use_document.rs index dfbf8b7..16cd226 100644 --- a/src/use_document.rs +++ b/src/use_document.rs @@ -1,11 +1,12 @@ use cfg_if::cfg_if; +use js_sys::Function; use std::ops::Deref; use crate::core::impl_ssr_safe_method; #[cfg(not(feature = "ssr"))] use leptos::*; use wasm_bindgen::JsValue; -use web_sys::NodeList; +use web_sys::{Document, Element, HtmlCollection, HtmlElement, HtmlHeadElement, Location, NodeList, VisibilityState, Window}; /// SSR safe `document()`. /// This returns just a new-type wrapper around `Option`. @@ -39,10 +40,10 @@ pub fn use_document() -> UseDocument { /// Return type of [`use_document`]. #[derive(Debug, Clone, PartialEq, Eq)] -pub struct UseDocument(Option); +pub struct UseDocument(Option); impl Deref for UseDocument { - type Target = Option; + type Target = Option; fn deref(&self) -> &Self::Target { &self.0 } @@ -51,22 +52,203 @@ impl Deref for UseDocument { impl UseDocument { impl_ssr_safe_method!( /// Returns `Some(Document)` in the Browser. `None` otherwise. - body(&self) -> Option; + body(&self) -> Option; .unwrap_or_default() ); impl_ssr_safe_method!( /// Returns the active (focused) `Some(web_sys::Element)` in the Browser. `None` otherwise. - active_element(&self) -> Option; + active_element(&self) -> Option; .unwrap_or_default() ); impl_ssr_safe_method!( - query_selector(&self, selector: &str) -> Result, JsValue>; + query_selector(&self, selector: &str) -> Result, JsValue>; .unwrap_or(Ok(None)) ); impl_ssr_safe_method!( query_selector_all(&self, selectors: &str) -> Option> ); + + impl_ssr_safe_method!( + url(&self) -> Option> + ); + + impl_ssr_safe_method!( + document_uri(&self) -> Option> + ); + + impl_ssr_safe_method!( + compat_mode(&self) -> Option + ); + + impl_ssr_safe_method!( + character_set(&self) -> Option + ); + + impl_ssr_safe_method!( + charset(&self) -> Option + ); + + impl_ssr_safe_method!( + input_encoding(&self) -> Option + ); + + impl_ssr_safe_method!( + content_type(&self) -> Option + ); + + impl_ssr_safe_method!( + document_element(&self) -> Option; + .unwrap_or_default() + ); + + impl_ssr_safe_method!( + location(&self) -> Option; + .unwrap_or_default() + ); + + impl_ssr_safe_method!( + referrer(&self) -> Option + ); + + impl_ssr_safe_method!( + last_modified(&self) -> Option + ); + + impl_ssr_safe_method!( + ready_state(&self) -> Option + ); + + impl_ssr_safe_method!( + title(&self) -> Option + ); + + impl_ssr_safe_method!( + dir(&self) -> Option + ); + + impl_ssr_safe_method!( + head(&self) -> Option; + .unwrap_or_default() + ); + + impl_ssr_safe_method!( + images(&self) -> Option + ); + + impl_ssr_safe_method!( + embeds(&self) -> Option + ); + + impl_ssr_safe_method!( + plugins(&self) -> Option + ); + + impl_ssr_safe_method!( + links(&self) -> Option + ); + + impl_ssr_safe_method!( + forms(&self) -> Option + ); + + impl_ssr_safe_method!( + scripts(&self) -> Option + ); + + impl_ssr_safe_method!( + default_view(&self) -> Option; + .unwrap_or_default() + ); + + impl_ssr_safe_method!( + onreadystatechange(&self) -> Option; + .unwrap_or_default() + ); + + impl_ssr_safe_method!( + onbeforescriptexecute(&self) -> Option; + .unwrap_or_default() + ); + + impl_ssr_safe_method!( + onafterscriptexecute(&self) -> Option; + .unwrap_or_default() + ); + + impl_ssr_safe_method!( + onselectionchange(&self) -> Option; + .unwrap_or_default() + ); + + impl_ssr_safe_method!( + current_script(&self) -> Option; + .unwrap_or_default() + ); + + impl_ssr_safe_method!( + anchors(&self) -> Option + ); + + impl_ssr_safe_method!( + applets(&self) -> Option + ); + + impl_ssr_safe_method!( + fullscreen(&self) -> Option + ); + + impl_ssr_safe_method!( + fullscreen_enabled(&self) -> Option + ); + + impl_ssr_safe_method!( + onfullscreenchange(&self) -> Option; + .unwrap_or_default() + ); + + impl_ssr_safe_method!( + onfullscreenerror(&self) -> Option; + .unwrap_or_default() + ); + + impl_ssr_safe_method!( + onpointerlockchange(&self) -> Option; + .unwrap_or_default() + ); + + impl_ssr_safe_method!( + onpointerlockerror(&self) -> Option; + .unwrap_or_default() + ); + + impl_ssr_safe_method!( + hidden(&self) -> Option + ); + + impl_ssr_safe_method!( + visibility_state(&self) -> Option + ); + + impl_ssr_safe_method!( + onvisibilitychange(&self) -> Option; + .unwrap_or_default() + ); + + impl_ssr_safe_method!( + selected_style_sheet_set(&self) -> Option; + .unwrap_or_default() + ); + + impl_ssr_safe_method!( + last_style_sheet_set(&self) -> Option; + .unwrap_or_default() + ); + + impl_ssr_safe_method!( + preferred_style_sheet_set(&self) -> Option; + .unwrap_or_default() + ); } From 4ec66ecbc85bbb14b485f9c7aa8955cfe720c7cc Mon Sep 17 00:00:00 2001 From: Maccesch Date: Sun, 28 Jul 2024 17:41:16 +0100 Subject: [PATCH 02/40] added function header and made use_cookie use it --- CHANGELOG.md | 10 +++- docs/book/src/SUMMARY.md | 1 + docs/book/src/utilities/header.md | 3 ++ src/use_cookie.rs | 74 +----------------------------- src/utils/header.rs | 76 +++++++++++++++++++++++++++++++ src/utils/header_macro.rs | 36 +++++++++++++++ src/utils/mod.rs | 12 +++++ 7 files changed, 138 insertions(+), 74 deletions(-) create mode 100644 docs/book/src/utilities/header.md create mode 100644 src/utils/header.rs create mode 100644 src/utils/header_macro.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index c2d7794..6516447 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ 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). +## [Unreleased] + +### New Functions 🚀 + +- `header` – Standard implementations for reading a header on the server. + ## [0.11.0] - 2024-07-27 ### New Functions 🚀 @@ -31,7 +37,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 the DOM controlled by a value from storage. This leads to hydration errors which can be fixed by setting this new option to `true`. - `cookie::SameSite` is now re-exported -- Changing the signal returned by `use_cookie` now tries and changes the headers during SSR. +- Changing the signal returned by `use_cookie` now tries and changes the headers during SSR. - New book chapter about codecs - The macro `use_derive_signal!` is now exported (thanks to @mscofield0). @@ -66,7 +72,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The new `UseWebSocketOptions::on_message` takes a `&T`. - `UseWebSocketOptions::on_error` now takes a `UseWebSocketError` instead of a `web_sys::Event`. - `use_storage` now always saves the default value to storage if the key doesn't exist yet. -- Renamed `BreakpointsSematic` to `BreakpointsSemantic` and `breakpoints_sematic` to `breakpoints_semantic` +- Renamed `BreakpointsSematic` to `BreakpointsSemantic` and `breakpoints_sematic` to `breakpoints_semantic` (note the `n`) (thanks to @mondeja). ### Fixes 🍕 diff --git a/docs/book/src/SUMMARY.md b/docs/book/src/SUMMARY.md index 502a1a6..c70b480 100644 --- a/docs/book/src/SUMMARY.md +++ b/docs/book/src/SUMMARY.md @@ -99,6 +99,7 @@ # Utilities +- [header](utilities/header.md) - [is_err](utilities/is_err.md) - [is_none](utilities/is_none.md) - [is_ok](utilities/is_ok.md) diff --git a/docs/book/src/utilities/header.md b/docs/book/src/utilities/header.md new file mode 100644 index 0000000..2bd2d1f --- /dev/null +++ b/docs/book/src/utilities/header.md @@ -0,0 +1,3 @@ +# header + + diff --git a/src/use_cookie.rs b/src/use_cookie.rs index b7773a8..2e6c894 100644 --- a/src/use_cookie.rs +++ b/src/use_cookie.rs @@ -1,6 +1,7 @@ #![allow(clippy::too_many_arguments)] use crate::core::now; +use crate::utils::get_header; use codee::{CodecError, Decoder, Encoder}; use cookie::time::{Duration, OffsetDateTime}; pub use cookie::SameSite; @@ -496,78 +497,7 @@ impl Default for UseCookieOptions { path: None, same_site: None, ssr_cookies_header_getter: Rc::new(move || { - #[cfg(feature = "ssr")] - { - #[cfg(all(feature = "actix", feature = "axum"))] - compile_error!("You can only enable one of features \"actix\" and \"axum\" at the same time"); - - #[cfg(all(feature = "actix", feature = "spin"))] - compile_error!("You can only enable one of features \"actix\" and \"spin\" at the same time"); - - #[cfg(all(feature = "axum", feature = "spin"))] - compile_error!("You can only enable one of features \"axum\" and \"spin\" at the same time"); - - #[cfg(feature = "actix")] - const COOKIE: http0_2::HeaderName = http0_2::header::COOKIE; - #[cfg(any(feature = "axum", feature = "spin"))] - const COOKIE: http1::HeaderName = http1::header::COOKIE; - - #[cfg(feature = "actix")] - type HeaderValue = http0_2::HeaderValue; - #[cfg(feature = "axum")] - type HeaderValue = http1::HeaderValue; - - #[cfg(any(feature = "axum", feature = "actix", feature = "spin"))] - let headers; - #[cfg(feature = "actix")] - { - headers = use_context::() - .map(|req| req.headers().clone()); - } - #[cfg(feature = "axum")] - { - headers = use_context::().map(|parts| parts.headers); - } - #[cfg(feature = "spin")] - { - headers = use_context::() - .map(|parts| parts.headers().clone()); - } - - #[cfg(all( - not(feature = "axum"), - not(feature = "actix"), - not(feature = "spin") - ))] - { - leptos::logging::warn!("If you're using use_cookie without the feature `axum`, `actix` or `spin` enabled, you should provide the option `ssr_cookies_header_getter`"); - None - } - - #[cfg(any(feature = "axum", feature = "actix"))] - { - headers.map(|headers| { - headers - .get(COOKIE) - .cloned() - .unwrap_or_else(|| HeaderValue::from_static("")) - .to_str() - .unwrap_or_default() - .to_owned() - }) - } - #[cfg(feature = "spin")] - { - headers.and_then(|headers| { - headers - .iter() - .find(|(key, _)| **key == COOKIE) - .and_then(|(_, value)| String::from_utf8(value.to_vec()).ok()) - }) - } - } - #[cfg(not(feature = "ssr"))] - None + get_header!(COOKIE, use_cookie, ssr_cookies_header_getter) }), ssr_set_cookie: Rc::new(|cookie: &Cookie| { #[cfg(feature = "ssr")] diff --git a/src/utils/header.rs b/src/utils/header.rs new file mode 100644 index 0000000..0e9d6cd --- /dev/null +++ b/src/utils/header.rs @@ -0,0 +1,76 @@ +#[cfg(feature = "actix")] +use http0_2::HeaderName; +#[cfg(any(feature = "axum", feature = "spin"))] +use http1::HeaderName; +use leptos::*; + +/// Get the value of the header with the given name. +/// +/// This function is only meant to be used on the server. +/// So it is only defined when the feature `"ssr"` is enabled together with one of the +/// features `"axum"`, `"actix"` or `"spin"`. +/// +/// ## Example +/// +/// ```ignore +/// # use leptos_use::utils::header; +/// # +/// let content_len = header(http::header::CONTENT_LENGTH); +/// ``` +pub fn header(name: N) -> Option +where + N: Into, +{ + let name = name.into(); + + #[cfg(all(feature = "actix", feature = "axum"))] + compile_error!("You can only enable one of features \"actix\" and \"axum\" at the same time"); + + #[cfg(all(feature = "actix", feature = "spin"))] + compile_error!("You can only enable one of features \"actix\" and \"spin\" at the same time"); + + #[cfg(all(feature = "axum", feature = "spin"))] + compile_error!("You can only enable one of features \"axum\" and \"spin\" at the same time"); + + #[cfg(feature = "actix")] + type HeaderValue = http0_2::HeaderValue; + #[cfg(feature = "axum")] + type HeaderValue = http1::HeaderValue; + + #[cfg(any(feature = "axum", feature = "actix", feature = "spin"))] + let headers; + #[cfg(feature = "actix")] + { + headers = use_context::().map(|req| req.headers().clone()); + } + #[cfg(feature = "axum")] + { + headers = use_context::().map(|parts| parts.headers); + } + #[cfg(feature = "spin")] + { + headers = use_context::().map(|parts| parts.headers().clone()); + } + + #[cfg(any(feature = "axum", feature = "actix"))] + { + headers.map(|headers| { + headers + .get(name) + .cloned() + .unwrap_or_else(|| HeaderValue::from_static("")) + .to_str() + .unwrap_or_default() + .to_owned() + }) + } + #[cfg(feature = "spin")] + { + headers.and_then(|headers| { + headers + .iter() + .find(|(key, _)| **key == name) + .and_then(|(_, value)| String::from_utf8(value.to_vec()).ok()) + }) + } +} diff --git a/src/utils/header_macro.rs b/src/utils/header_macro.rs new file mode 100644 index 0000000..2cb0b52 --- /dev/null +++ b/src/utils/header_macro.rs @@ -0,0 +1,36 @@ +macro_rules! get_header { + ( + $header_name:ident, + $function_name:ident, + $option_name:ident + $(,)? + ) => { + if cfg!(feature = "ssr") { + #[cfg(all( + not(feature = "axum"), + not(feature = "actix"), + not(feature = "spin") + ))] + { + leptos::logging::warn!( + "If you're using `{}` with SSR but without any of the features `axum`, `actix` or `spin` enabled, you have to provide the option `{}`", + stringify!($function_name), + stringify!($option_name) + ); + return None; + } + + #[cfg(feature = "actix")] + const $header_name: http0_2::HeaderName = http0_2::header::$header_name; + #[cfg(any(feature = "axum", feature = "spin"))] + const $header_name: http1::HeaderName = http1::header::$header_name; + + #[cfg(any(feature = "axum", feature = "actix", feature = "spin"))] + crate::utils::header($header_name) + } else { + None + } + }; +} + +pub(crate) use get_header; diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 906f4e1..32d43b0 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,4 +1,10 @@ mod filters; +#[cfg(all( + feature = "ssr", + any(feature = "axum", feature = "actix", feature = "spin") +))] +mod header; +mod header_macro; mod is; mod js; mod js_value_from_to_string; @@ -7,6 +13,12 @@ mod signal_filtered; mod use_derive_signal; pub use filters::*; +#[cfg(all( + feature = "ssr", + any(feature = "axum", feature = "actix", feature = "spin") +))] +pub use header::*; +pub(crate) use header_macro::*; pub use is::*; pub(crate) use js_value_from_to_string::*; pub use pausable::*; From 49bb88768c6bae8a6e2415330ae9ceee28c6b3da Mon Sep 17 00:00:00 2001 From: Maccesch Date: Sun, 28 Jul 2024 20:02:12 +0100 Subject: [PATCH 03/40] added use_locales --- .github/workflows/cd.yml | 15 +- .github/workflows/tests.yml | 27 +- .idea/leptos-use.iml | 1 + CHANGELOG.md | 1 + docs/book/src/SUMMARY.md | 1 + docs/book/src/intl/use_locales.md | 3 + examples/Cargo.toml | 1 + examples/ssr/src/app.rs | 14 +- examples/use_locales/Cargo.toml | 16 + examples/use_locales/README.md | 23 ++ examples/use_locales/Trunk.toml | 2 + examples/use_locales/index.html | 7 + examples/use_locales/input.css | 3 + examples/use_locales/rust-toolchain.toml | 2 + examples/use_locales/src/main.rs | 21 ++ examples/use_locales/style/output.css | 289 ++++++++++++++++++ examples/use_locales/tailwind.config.js | 15 + src/lib.rs | 2 + src/use_cookie.rs | 2 +- src/use_locales.rs | 114 +++++++ .../{{ function_name }}.ffizer.hbs.rs | 12 +- 21 files changed, 549 insertions(+), 22 deletions(-) create mode 100644 docs/book/src/intl/use_locales.md create mode 100644 examples/use_locales/Cargo.toml create mode 100644 examples/use_locales/README.md create mode 100644 examples/use_locales/Trunk.toml create mode 100644 examples/use_locales/index.html create mode 100644 examples/use_locales/input.css create mode 100644 examples/use_locales/rust-toolchain.toml create mode 100644 examples/use_locales/src/main.rs create mode 100644 examples/use_locales/style/output.css create mode 100644 examples/use_locales/tailwind.config.js create mode 100644 src/use_locales.rs diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index b1e6e05..e8f15e6 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -23,20 +23,27 @@ jobs: components: rustfmt, clippy, rust-src - name: Cache uses: Swatinem/rust-cache@v2 + - name: Check function count badge run: python3 docs/generate_count_badge.py --check - name: Check version in docs run: python3 docs/add_version_to_docs.py --check + - name: Check formatting run: cargo fmt --check - name: Clippy run: cargo clippy --features docs,math --tests -- -D warnings + - name: Run tests (general) run: cargo test --features math,docs,ssr - - name: Run tests (axum) - run: cargo test --features math,docs,ssr,axum --doc use_cookie::use_cookie - - name: Run tests (actix) - run: cargo test --features math,docs,ssr,actix --doc use_cookie::use_cookie + - name: Run tests (axum) use_cookie + run: cargo test --features math,docs,ssr,axum --doc use_cookie + - name: Run tests (axum) use_locales + run: cargo test --features math,docs,ssr,axum --doc use_locales + - name: Run tests (actix) use_cookie + run: cargo test --features math,docs,ssr,actix --doc use_cookie + - name: Run tests (actix) use_locales + run: cargo test --features math,docs,ssr,actix --doc use_locales #### mdbook - name: Install mdbook I diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 68ee5cf..6de613d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,5 +1,11 @@ on: pull_request: + branches: + - main + paths: + - "**" + - "!/*.md" + - "!/**.md" workflow_dispatch: name: Tests @@ -20,13 +26,18 @@ jobs: components: rustfmt, clippy, rust-src - name: Cache uses: Swatinem/rust-cache@v2 - - name: Check formatting - run: cargo fmt --check - - name: Clippy - run: cargo clippy --features docs,math --tests -- -D warnings + - name: Run tests (general) run: cargo test --features math,docs,ssr - - name: Run tests (axum) - run: cargo test --features math,docs,ssr,axum --doc use_cookie::use_cookie - - name: Run tests (actix) - run: cargo test --features math,docs,ssr,actix --doc use_cookie::use_cookie + + - name: Run tests (axum) use_cookie + run: cargo test --features math,docs,ssr,axum --doc use_cookie + + - name: Run tests (axum) use_locales + run: cargo test --features math,docs,ssr,axum --doc use_locales + + - name: Run tests (actix) use_cookie + run: cargo test --features math,docs,ssr,actix --doc use_cookie + + - name: Run tests (actix) use_locales + run: cargo test --features math,docs,ssr,actix --doc use_locales diff --git a/.idea/leptos-use.iml b/.idea/leptos-use.iml index b65a8a2..bc52064 100644 --- a/.idea/leptos-use.iml +++ b/.idea/leptos-use.iml @@ -78,6 +78,7 @@ + diff --git a/CHANGELOG.md b/CHANGELOG.md index 6516447..bfc939a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### New Functions 🚀 +- `use_locale` - `header` – Standard implementations for reading a header on the server. ## [0.11.0] - 2024-07-27 diff --git a/docs/book/src/SUMMARY.md b/docs/book/src/SUMMARY.md index c70b480..75aad32 100644 --- a/docs/book/src/SUMMARY.md +++ b/docs/book/src/SUMMARY.md @@ -114,6 +114,7 @@ # Intl - [use_intl_number_format](intl/use_intl_number_format.md) +- [use_locales](intl/use_locales.md) # @Math diff --git a/docs/book/src/intl/use_locales.md b/docs/book/src/intl/use_locales.md new file mode 100644 index 0000000..084b0fd --- /dev/null +++ b/docs/book/src/intl/use_locales.md @@ -0,0 +1,3 @@ +# use_locales + + diff --git a/examples/Cargo.toml b/examples/Cargo.toml index f428959..12466ce 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -38,6 +38,7 @@ members = [ "use_interval", "use_interval_fn", "use_intl_number_format", + "use_locales", "use_media_query", "use_mouse", "use_mouse_in_element", diff --git a/examples/ssr/src/app.rs b/examples/ssr/src/app.rs index 7db0793..9ffe5d0 100644 --- a/examples/ssr/src/app.rs +++ b/examples/ssr/src/app.rs @@ -1,15 +1,15 @@ use crate::error_template::{AppError, ErrorTemplate}; +use codee::string::FromToStringCodec; use leptos::ev::{keypress, KeyboardEvent}; use leptos::*; use leptos_meta::*; use leptos_router::*; use leptos_use::storage::{use_local_storage, use_local_storage_with_options, UseStorageOptions}; -use codee::string::FromToStringCodec; use leptos_use::{ use_color_mode_with_options, use_cookie_with_options, use_debounce_fn, use_event_listener, - use_interval, use_intl_number_format, use_preferred_dark, use_timestamp, use_window, ColorMode, - UseColorModeOptions, UseColorModeReturn, UseCookieOptions, UseIntervalReturn, - UseIntlNumberFormatOptions, + use_interval, use_intl_number_format, use_locales, use_preferred_dark, use_timestamp, + use_window, ColorMode, UseColorModeOptions, UseColorModeReturn, UseCookieOptions, + UseIntervalReturn, UseIntlNumberFormatOptions, }; #[component] @@ -83,12 +83,13 @@ fn HomePage() -> impl IntoView { .default_value(Some("Bogus string".to_owned())), ); + let locales = use_locales(); + view! {

Leptos-Use SSR Example

-

Locale zh-Hans-CN-u-nu-hanidec: {zh_count}

Press any key: {key}

Debounced called: {debounce_value}

Color mode: {move || format!("{:?}", mode.get())}

@@ -99,7 +100,10 @@ fn HomePage() -> impl IntoView {

Dark preferred: {is_dark_preferred}

Test cookie: {move || test_cookie().unwrap_or("".to_string())}

+
{move || format!("Locales:\n    {}", locales().join("\n    "))}
+

Locale zh-Hans-CN-u-nu-hanidec: {zh_count}

+ 0 }>
Greater than 0
diff --git a/examples/use_locales/Cargo.toml b/examples/use_locales/Cargo.toml new file mode 100644 index 0000000..05b5bc9 --- /dev/null +++ b/examples/use_locales/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "use_locales" +version = "0.1.0" +edition = "2021" + +[dependencies] +leptos = { version = "0.6", features = ["nightly", "csr"] } +console_error_panic_hook = "0.1" +console_log = "1" +log = "0.4" +leptos-use = { path = "../..", features = ["docs"] } +web-sys = "0.3" + +[dev-dependencies] +wasm-bindgen = "0.2" +wasm-bindgen-test = "0.3.0" diff --git a/examples/use_locales/README.md b/examples/use_locales/README.md new file mode 100644 index 0000000..f1827be --- /dev/null +++ b/examples/use_locales/README.md @@ -0,0 +1,23 @@ +A simple example for `use_locales`. + +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 +``` \ No newline at end of file diff --git a/examples/use_locales/Trunk.toml b/examples/use_locales/Trunk.toml new file mode 100644 index 0000000..3e4be08 --- /dev/null +++ b/examples/use_locales/Trunk.toml @@ -0,0 +1,2 @@ +[build] +public_url = "/demo/" \ No newline at end of file diff --git a/examples/use_locales/index.html b/examples/use_locales/index.html new file mode 100644 index 0000000..ae249a6 --- /dev/null +++ b/examples/use_locales/index.html @@ -0,0 +1,7 @@ + + + + + + + diff --git a/examples/use_locales/input.css b/examples/use_locales/input.css new file mode 100644 index 0000000..bd6213e --- /dev/null +++ b/examples/use_locales/input.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; \ No newline at end of file diff --git a/examples/use_locales/rust-toolchain.toml b/examples/use_locales/rust-toolchain.toml new file mode 100644 index 0000000..271800c --- /dev/null +++ b/examples/use_locales/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" \ No newline at end of file diff --git a/examples/use_locales/src/main.rs b/examples/use_locales/src/main.rs new file mode 100644 index 0000000..dfa206b --- /dev/null +++ b/examples/use_locales/src/main.rs @@ -0,0 +1,21 @@ +use leptos::*; +use leptos_use::docs::demo_or_body; +use leptos_use::use_locales; + +#[component] +fn Demo() -> impl IntoView { + let locales = use_locales(); + + view! { +
{move || format!("Locales:\n    {}", locales().join("\n    "))}
+ } +} + +fn main() { + _ = console_log::init_with_level(log::Level::Debug); + console_error_panic_hook::set_once(); + + mount_to(demo_or_body(), || { + view! { } + }) +} diff --git a/examples/use_locales/style/output.css b/examples/use_locales/style/output.css new file mode 100644 index 0000000..ab5191f --- /dev/null +++ b/examples/use_locales/style/output.css @@ -0,0 +1,289 @@ +[type='text'],[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, [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; +} + +::-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] { + 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"); +} + +[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"); +} + +[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; +} + +[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: ; +} + +::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: ; +} + +.block { + display: block; +} + +.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)); + } +} \ No newline at end of file diff --git a/examples/use_locales/tailwind.config.js b/examples/use_locales/tailwind.config.js new file mode 100644 index 0000000..bc09f5e --- /dev/null +++ b/examples/use_locales/tailwind.config.js @@ -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'), + ], +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index efcf708..45a0e14 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,6 +57,7 @@ mod use_intersection_observer; mod use_interval; mod use_interval_fn; mod use_intl_number_format; +mod use_locales; mod use_media_query; mod use_mouse; mod use_mouse_in_element; @@ -123,6 +124,7 @@ pub use use_intersection_observer::*; pub use use_interval::*; pub use use_interval_fn::*; pub use use_intl_number_format::*; +pub use use_locales::*; pub use use_media_query::*; pub use use_mouse::*; pub use use_mouse_in_element::*; diff --git a/src/use_cookie.rs b/src/use_cookie.rs index 2e6c894..13f36fe 100644 --- a/src/use_cookie.rs +++ b/src/use_cookie.rs @@ -100,7 +100,7 @@ use std::rc::Rc; /// /// ### Bring your own header /// -/// In case you're neither using Axum nor Actix, or the default implementation is not to your liking, +/// In case you're neither using Axum, Actix nor Spin, or the default implementation is not to your liking, /// you can provide your own way of reading and writing the cookie header value. /// /// ``` diff --git a/src/use_locales.rs b/src/use_locales.rs new file mode 100644 index 0000000..e6d6cc4 --- /dev/null +++ b/src/use_locales.rs @@ -0,0 +1,114 @@ +use crate::utils::get_header; +use default_struct_builder::DefaultBuilder; +use leptos::*; +use std::rc::Rc; + +/// Reactive accepted locales. +/// +/// If called on the client-side this function returns the value of +/// [`navigator.languages`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/languages) +/// and listens for changes to that property. +/// +/// See "Server-Side Rendering" below. +/// +/// ## Demo +/// +/// [Link to Demo](https://github.com/Synphonyte/leptos-use/tree/main/examples/use_locales) +/// +/// ## Usage +/// +/// ``` +/// # use leptos::*; +/// # use leptos_use::use_locales; +/// # +/// # #[component] +/// # fn Demo() -> impl IntoView { +/// let locales = use_locales(); +/// # +/// # view! { } +/// # } +/// ``` +/// +/// ## Server-Side Rendering +/// +/// On the server this returns the parsed value of the `accept-language` header. +/// +/// > If you're using `axum` you have to enable the `"axum"` feature in your Cargo.toml. +/// > In case it's `actix-web` enable the feature `"actix"`, for `spin` enable `"spin"`. +/// +/// ### Bring your own header +/// +/// In case you're neither using Axum, Actix nor Spin, or the default implementation is not to your liking, +/// you can provide your own way of reading and writing the cookie header value using the option +/// [`crate::UseLocalesOptions::ssr_lang_header_getter`]. +pub fn use_locales() -> Signal> { + use_locales_with_options(UseLocalesOptions::default()) +} + +/// Version of [`fn@crate::use_locales`] that takes a `UseLocalesOptions`. See [`fn@crate::use_locales`] for how to use. +pub fn use_locales_with_options(options: UseLocalesOptions) -> Signal> { + #[cfg(not(feature = "ssr"))] + { + let _ = options; + + let read_navigator_languages = || { + let window = crate::use_window(); + let navigator = window.navigator(); + navigator + .map(|navigator| navigator.languages().to_vec()) + .unwrap_or_default() + .into_iter() + .filter_map(|x| x.as_string()) + .collect::>() + }; + + let (locales, set_locales) = create_signal(read_navigator_languages()); + + let _ = crate::use_event_listener(crate::use_window(), ev::languagechange, move |_| { + set_locales.update(|locales| *locales = read_navigator_languages()); + }); + + locales.into() + } + + #[cfg(feature = "ssr")] + { + let UseLocalesOptions { + ssr_lang_header_getter, + } = options; + + let accept_language = ssr_lang_header_getter().unwrap_or_default(); + + let locales = accept_language + .split(',') + .map(|locale| { + locale + .split_once(';') + .map(|x| x.0) + .unwrap_or(locale) + .to_owned() + }) + .collect::>(); + + Signal::derive(move || locales.clone()) + } +} + +/// Options for [`fn@crate::use_locales_with_options`]. +#[derive(DefaultBuilder)] +pub struct UseLocalesOptions { + /// Getter function to return the string value of the accept languange header. + /// When you use one of the features `"axum"`, `"actix"` or `"spin"` there's a valid default implementation provided. + #[allow(dead_code)] + ssr_lang_header_getter: Rc Option>, +} + +impl Default for UseLocalesOptions { + fn default() -> Self { + Self { + ssr_lang_header_getter: Rc::new(move || { + get_header!(ACCEPT_LANGUAGE, use_locale, ssr_lang_header_getter) + }), + } + } +} diff --git a/template/src/{{ module }}/{{ function_name }}.ffizer.hbs.rs b/template/src/{{ module }}/{{ function_name }}.ffizer.hbs.rs index 0edb6ba..ef81b03 100644 --- a/template/src/{{ module }}/{{ function_name }}.ffizer.hbs.rs +++ b/template/src/{{ module }}/{{ function_name }}.ffizer.hbs.rs @@ -22,19 +22,23 @@ use leptos::*; /// # /// # view! { } /// # } -/// ```{{#if feature}} +/// ``` +/// +/// ## Server-Side Rendering +/// {{#if feature}} // #[doc(cfg(feature = "{{feature}}"))]{{/if}} + pub fn {{ function_name }}() -> {{ to_pascal_case function_name }}Return { {{ function_name }}_with_options({{ to_pascal_case function_name }}Options::default()) } -/// Version of [`{{ function_name }}`] that takes a `{{ to_pascal_case function_name }}Options`. See [`{{ function_name }}`] for how to use.{{#if feature}} +/// Version of [`fn@crate::{{ function_name }}`] that takes a `{{ to_pascal_case function_name }}Options`. See [`fn@crate::{{ function_name }}`] for how to use.{{#if feature}} // #[doc(cfg(feature = "{{feature}}"))]{{/if}} pub fn {{ function_name }}_with_options(options: {{ to_pascal_case function_name }}Options) -> {{ to_pascal_case function_name }}Return { {{ to_pascal_case function_name }}Return {} } -/// Options for [`{{ function_name }}_with_options`].{{#if feature}} +/// Options for [`fn@crate::{{ function_name }}_with_options`].{{#if feature}} // #[doc(cfg(feature = "{{feature}}"))]{{/if}} #[derive(DefaultBuilder)] pub struct {{ to_pascal_case function_name }}Options {} @@ -45,6 +49,6 @@ impl Default for {{ to_pascal_case function_name }}Options { } } -/// Return type of [`{{ function_name }}`].{{#if feature}} +/// Return type of [`fn@crate::{{ function_name }}`].{{#if feature}} // #[doc(cfg(feature = "{{feature}}"))]{{/if}} pub struct {{ to_pascal_case function_name }}Return {} \ No newline at end of file From 7aa580ace4808be8053993f143be4d34b89a4bb6 Mon Sep 17 00:00:00 2001 From: Maccesch Date: Sun, 28 Jul 2024 20:34:38 +0100 Subject: [PATCH 04/40] added use_locale --- .github/workflows/cd.yml | 14 +- .github/workflows/tests.yml | 8 +- .idea/leptos-use.iml | 1 + CHANGELOG.md | 1 + docs/book/src/SUMMARY.md | 1 + docs/book/src/intl/use_locale.md | 3 + examples/Cargo.toml | 1 + examples/use_locale/Cargo.toml | 16 ++ examples/use_locale/README.md | 23 ++ examples/use_locale/Trunk.toml | 2 + examples/use_locale/index.html | 7 + examples/use_locale/input.css | 3 + examples/use_locale/rust-toolchain.toml | 2 + examples/use_locale/src/main.rs | 21 ++ examples/use_locale/style/output.css | 330 ++++++++++++++++++++++++ examples/use_locale/tailwind.config.js | 15 ++ src/lib.rs | 2 + src/use_locale.rs | 74 ++++++ src/use_locales.rs | 4 +- 19 files changed, 515 insertions(+), 13 deletions(-) create mode 100644 docs/book/src/intl/use_locale.md create mode 100644 examples/use_locale/Cargo.toml create mode 100644 examples/use_locale/README.md create mode 100644 examples/use_locale/Trunk.toml create mode 100644 examples/use_locale/index.html create mode 100644 examples/use_locale/input.css create mode 100644 examples/use_locale/rust-toolchain.toml create mode 100644 examples/use_locale/src/main.rs create mode 100644 examples/use_locale/style/output.css create mode 100644 examples/use_locale/tailwind.config.js create mode 100644 src/use_locale.rs diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index e8f15e6..cb67468 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -23,27 +23,27 @@ jobs: components: rustfmt, clippy, rust-src - name: Cache uses: Swatinem/rust-cache@v2 - + - name: Check function count badge run: python3 docs/generate_count_badge.py --check - name: Check version in docs run: python3 docs/add_version_to_docs.py --check - + - name: Check formatting run: cargo fmt --check - name: Clippy run: cargo clippy --features docs,math --tests -- -D warnings - + - name: Run tests (general) run: cargo test --features math,docs,ssr - name: Run tests (axum) use_cookie run: cargo test --features math,docs,ssr,axum --doc use_cookie - - name: Run tests (axum) use_locales - run: cargo test --features math,docs,ssr,axum --doc use_locales + - name: Run tests (axum) use_locale + run: cargo test --features math,docs,ssr,axum --doc use_locale - name: Run tests (actix) use_cookie run: cargo test --features math,docs,ssr,actix --doc use_cookie - - name: Run tests (actix) use_locales - run: cargo test --features math,docs,ssr,actix --doc use_locales + - name: Run tests (actix) use_locale + run: cargo test --features math,docs,ssr,actix --doc use_locale #### mdbook - name: Install mdbook I diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6de613d..1ae502a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -33,11 +33,11 @@ jobs: - name: Run tests (axum) use_cookie run: cargo test --features math,docs,ssr,axum --doc use_cookie - - name: Run tests (axum) use_locales - run: cargo test --features math,docs,ssr,axum --doc use_locales + - name: Run tests (axum) use_locale + run: cargo test --features math,docs,ssr,axum --doc use_locale - name: Run tests (actix) use_cookie run: cargo test --features math,docs,ssr,actix --doc use_cookie - - name: Run tests (actix) use_locales - run: cargo test --features math,docs,ssr,actix --doc use_locales + - name: Run tests (actix) use_locale + run: cargo test --features math,docs,ssr,actix --doc use_locale diff --git a/.idea/leptos-use.iml b/.idea/leptos-use.iml index bc52064..a9c24d6 100644 --- a/.idea/leptos-use.iml +++ b/.idea/leptos-use.iml @@ -78,6 +78,7 @@ + diff --git a/CHANGELOG.md b/CHANGELOG.md index bfc939a..5deaa0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### New Functions 🚀 +- `use_locale` - `use_locale` - `header` – Standard implementations for reading a header on the server. diff --git a/docs/book/src/SUMMARY.md b/docs/book/src/SUMMARY.md index 75aad32..cd07431 100644 --- a/docs/book/src/SUMMARY.md +++ b/docs/book/src/SUMMARY.md @@ -114,6 +114,7 @@ # Intl - [use_intl_number_format](intl/use_intl_number_format.md) +- [use_locale](intl/use_locale.md) - [use_locales](intl/use_locales.md) # @Math diff --git a/docs/book/src/intl/use_locale.md b/docs/book/src/intl/use_locale.md new file mode 100644 index 0000000..56b32d7 --- /dev/null +++ b/docs/book/src/intl/use_locale.md @@ -0,0 +1,3 @@ +# use_locale + + diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 12466ce..debad03 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -38,6 +38,7 @@ members = [ "use_interval", "use_interval_fn", "use_intl_number_format", + "use_locale", "use_locales", "use_media_query", "use_mouse", diff --git a/examples/use_locale/Cargo.toml b/examples/use_locale/Cargo.toml new file mode 100644 index 0000000..eb1cdfd --- /dev/null +++ b/examples/use_locale/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "use_locale" +version = "0.1.0" +edition = "2021" + +[dependencies] +leptos = { version = "0.6", features = ["nightly", "csr"] } +console_error_panic_hook = "0.1" +console_log = "1" +log = "0.4" +leptos-use = { path = "../..", features = ["docs"] } +web-sys = "0.3" + +[dev-dependencies] +wasm-bindgen = "0.2" +wasm-bindgen-test = "0.3.0" diff --git a/examples/use_locale/README.md b/examples/use_locale/README.md new file mode 100644 index 0000000..2398484 --- /dev/null +++ b/examples/use_locale/README.md @@ -0,0 +1,23 @@ +A simple example for `use_locale`. + +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 +``` \ No newline at end of file diff --git a/examples/use_locale/Trunk.toml b/examples/use_locale/Trunk.toml new file mode 100644 index 0000000..3e4be08 --- /dev/null +++ b/examples/use_locale/Trunk.toml @@ -0,0 +1,2 @@ +[build] +public_url = "/demo/" \ No newline at end of file diff --git a/examples/use_locale/index.html b/examples/use_locale/index.html new file mode 100644 index 0000000..ae249a6 --- /dev/null +++ b/examples/use_locale/index.html @@ -0,0 +1,7 @@ + + + + + + + diff --git a/examples/use_locale/input.css b/examples/use_locale/input.css new file mode 100644 index 0000000..bd6213e --- /dev/null +++ b/examples/use_locale/input.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; \ No newline at end of file diff --git a/examples/use_locale/rust-toolchain.toml b/examples/use_locale/rust-toolchain.toml new file mode 100644 index 0000000..271800c --- /dev/null +++ b/examples/use_locale/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" \ No newline at end of file diff --git a/examples/use_locale/src/main.rs b/examples/use_locale/src/main.rs new file mode 100644 index 0000000..36ed437 --- /dev/null +++ b/examples/use_locale/src/main.rs @@ -0,0 +1,21 @@ +use leptos::*; +use leptos_use::docs::demo_or_body; +use leptos_use::use_locale; + +#[component] +fn Demo() -> impl IntoView { + let locale = use_locale(); + + view! { +

Locale: {locale}

+ } +} + +fn main() { + _ = console_log::init_with_level(log::Level::Debug); + console_error_panic_hook::set_once(); + + mount_to(demo_or_body(), || { + view! { } + }) +} diff --git a/examples/use_locale/style/output.css b/examples/use_locale/style/output.css new file mode 100644 index 0000000..6063b89 --- /dev/null +++ b/examples/use_locale/style/output.css @@ -0,0 +1,330 @@ +[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; +} + +.font-bold { + font-weight: 700; +} + +.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)); + } +} \ No newline at end of file diff --git a/examples/use_locale/tailwind.config.js b/examples/use_locale/tailwind.config.js new file mode 100644 index 0000000..bc09f5e --- /dev/null +++ b/examples/use_locale/tailwind.config.js @@ -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'), + ], +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 45a0e14..4c63f30 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,6 +25,7 @@ mod is_none; mod is_ok; mod is_some; mod on_click_outside; +mod use_locale; mod signal_debounced; mod signal_throttled; mod sync_signal; @@ -92,6 +93,7 @@ pub use is_none::*; pub use is_ok::*; pub use is_some::*; pub use on_click_outside::*; +pub use use_locale::*; pub use signal_debounced::*; pub use signal_throttled::*; pub use sync_signal::*; diff --git a/src/use_locale.rs b/src/use_locale.rs new file mode 100644 index 0000000..6e55a37 --- /dev/null +++ b/src/use_locale.rs @@ -0,0 +1,74 @@ +use crate::utils::get_header; +use crate::{use_locales_with_options, UseLocalesOptions}; +use default_struct_builder::DefaultBuilder; +use leptos::*; +use std::rc::Rc; + +/// Reactive locale. +/// +/// This is basically the same as [`fn@crate::use_locales`] but takes the first entry of the list. +/// If no locale is found then [`crate::UseLocaleOptions::fallback`] is returned which defaults +/// to `"en"`. +/// +/// ## Demo +/// +/// [Link to Demo](https://github.com/Synphonyte/leptos-use/tree/main/examples/use_locale) +/// +/// ## Usage +/// +/// ``` +/// # use leptos::*; +/// # use leptos_use::use_locale; +/// # +/// # #[component] +/// # fn Demo() -> impl IntoView { +/// let locale = use_locale(); +/// # +/// # view! { } +/// # } +/// ``` +/// +/// ## Server-Side Rendering +/// +/// See [`fn@crate::use_locales`] + +pub fn use_locale() -> Signal { + use_locale_with_options(UseLocaleOptions::default()) +} + +/// Version of [`fn@crate::use_locale`] that takes a `UseLocaleOptions`. See [`fn@crate::use_locale`] for how to use. +pub fn use_locale_with_options(options: UseLocaleOptions) -> Signal { + let UseLocaleOptions { + fallback, + ssr_lang_header_getter, + } = options; + + let locales = use_locales_with_options(UseLocalesOptions { + ssr_lang_header_getter, + }); + + Signal::derive(move || locales.get().first().cloned().unwrap_or(fallback.clone())) +} + +/// Options for [`fn@crate::use_locale_with_options`]. +#[derive(DefaultBuilder)] +pub struct UseLocaleOptions { + /// Fallback value in case no locale is found. Defaults to `"en"`. + fallback: String, + + /// Getter function to return the string value of the accept languange header. + /// When you use one of the features `"axum"`, `"actix"` or `"spin"` there's a valid default implementation provided. + #[allow(dead_code)] + ssr_lang_header_getter: Rc Option>, +} + +impl Default for UseLocaleOptions { + fn default() -> Self { + Self { + fallback: "en".to_string(), + ssr_lang_header_getter: Rc::new(move || { + get_header!(ACCEPT_LANGUAGE, use_locale, ssr_lang_header_getter) + }), + } + } +} diff --git a/src/use_locales.rs b/src/use_locales.rs index e6d6cc4..98f7e73 100644 --- a/src/use_locales.rs +++ b/src/use_locales.rs @@ -3,7 +3,7 @@ use default_struct_builder::DefaultBuilder; use leptos::*; use std::rc::Rc; -/// Reactive accepted locales. +/// Reactive locales. /// /// If called on the client-side this function returns the value of /// [`navigator.languages`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/languages) @@ -100,7 +100,7 @@ pub struct UseLocalesOptions { /// Getter function to return the string value of the accept languange header. /// When you use one of the features `"axum"`, `"actix"` or `"spin"` there's a valid default implementation provided. #[allow(dead_code)] - ssr_lang_header_getter: Rc Option>, + pub(crate) ssr_lang_header_getter: Rc Option>, } impl Default for UseLocalesOptions { From 1945e94da17a959a96c4f312db84997acb13a845 Mon Sep 17 00:00:00 2001 From: Maccesch Date: Sun, 28 Jul 2024 20:46:28 +0100 Subject: [PATCH 05/40] release 0.11.1 --- CHANGELOG.md | 6 +++--- Cargo.toml | 4 ++-- README.md | 2 +- docs/book/src/introduction.md | 2 +- src/lib.rs | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5deaa0e..33a9f73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,12 +3,12 @@ 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). -## [Unreleased] +## [0.11.1] - 2024-07-28 ### New Functions 🚀 -- `use_locale` -- `use_locale` +- `use_locale` (thanks to @BrandonDyer64) +- `use_locales` (thanks to @BrandonDyer64) - `header` – Standard implementations for reading a header on the server. ## [0.11.0] - 2024-07-27 diff --git a/Cargo.toml b/Cargo.toml index 4aa163c..7ac4ef7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,10 @@ [package] name = "leptos-use" -version = "0.11.0" +version = "0.11.1" edition = "2021" authors = ["Marc-Stefan Cassola"] categories = ["gui", "web-programming"] -description = "Collection of essential Leptos utilities inspired by SolidJS USE / VueUse" +description = "Collection of essential Leptos utilities inspired by React-Use / VueUse / SolidJS-USE" exclude = ["examples/", "tests/"] keywords = ["leptos", "utilities"] license = "MIT OR Apache-2.0" diff --git a/README.md b/README.md index 052d738..eb58418 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Crates.io SSR Docs & Demos - 79 Functions + 82 Functions


diff --git a/docs/book/src/introduction.md b/docs/book/src/introduction.md index cf0098a..8bcc1c1 100644 --- a/docs/book/src/introduction.md +++ b/docs/book/src/introduction.md @@ -12,6 +12,6 @@ Crates.io SSR Docs & Demos - 79 Functions + 82 Functions

\ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 4c63f30..9ad5b9b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,7 +25,6 @@ mod is_none; mod is_ok; mod is_some; mod on_click_outside; -mod use_locale; mod signal_debounced; mod signal_throttled; mod sync_signal; @@ -58,6 +57,7 @@ mod use_intersection_observer; mod use_interval; mod use_interval_fn; mod use_intl_number_format; +mod use_locale; mod use_locales; mod use_media_query; mod use_mouse; @@ -93,7 +93,6 @@ pub use is_none::*; pub use is_ok::*; pub use is_some::*; pub use on_click_outside::*; -pub use use_locale::*; pub use signal_debounced::*; pub use signal_throttled::*; pub use sync_signal::*; @@ -126,6 +125,7 @@ pub use use_intersection_observer::*; pub use use_interval::*; pub use use_interval_fn::*; pub use use_intl_number_format::*; +pub use use_locale::*; pub use use_locales::*; pub use use_media_query::*; pub use use_mouse::*; From 709757996ebc7dff23544e4872e87a3a19b85bbd Mon Sep 17 00:00:00 2001 From: Maccesch Date: Mon, 29 Jul 2024 01:06:00 +0100 Subject: [PATCH 06/40] locale now does matching against supported --- examples/use_locale/src/main.rs | 2 +- src/use_locale.rs | 87 +++++++++++++++++---------------- src/use_locales.rs | 2 +- 3 files changed, 47 insertions(+), 44 deletions(-) diff --git a/examples/use_locale/src/main.rs b/examples/use_locale/src/main.rs index 36ed437..36e132c 100644 --- a/examples/use_locale/src/main.rs +++ b/examples/use_locale/src/main.rs @@ -4,7 +4,7 @@ use leptos_use::use_locale; #[component] fn Demo() -> impl IntoView { - let locale = use_locale(); + let locale = use_locale(["en", "de", "fr"]); view! {

Locale: {locale}

diff --git a/src/use_locale.rs b/src/use_locale.rs index 6e55a37..ebf5423 100644 --- a/src/use_locale.rs +++ b/src/use_locale.rs @@ -1,14 +1,14 @@ -use crate::utils::get_header; use crate::{use_locales_with_options, UseLocalesOptions}; -use default_struct_builder::DefaultBuilder; use leptos::*; -use std::rc::Rc; -/// Reactive locale. +/// Reactive locale matching. /// -/// This is basically the same as [`fn@crate::use_locales`] but takes the first entry of the list. -/// If no locale is found then [`crate::UseLocaleOptions::fallback`] is returned which defaults -/// to `"en"`. +/// Returns the first matching locale given by [`fn@crate::use_locales`] that is also found in +/// the `supported` list. In case there is no match, then the first locale in `supported` will be +/// returned. If `supported` is empty, the empty string is returned. +/// +/// Matching is done by checking if an accepted locale from `use_locales` starts with a supported +/// locale. If a match is found the locale from the `supported` list is returned. /// /// ## Demo /// @@ -22,7 +22,7 @@ use std::rc::Rc; /// # /// # #[component] /// # fn Demo() -> impl IntoView { -/// let locale = use_locale(); +/// let locale = use_locale(&["en".to_string(), "de".to_string(), "fr".to_string()]); /// # /// # view! { } /// # } @@ -31,44 +31,47 @@ use std::rc::Rc; /// ## Server-Side Rendering /// /// See [`fn@crate::use_locales`] - -pub fn use_locale() -> Signal { - use_locale_with_options(UseLocaleOptions::default()) +pub fn use_locale(supported: S) -> Signal +where + S: IntoIterator, + S::Item: Into + Clone + 'static, +{ + use_locale_with_options(supported, UseLocaleOptions::default()) } /// Version of [`fn@crate::use_locale`] that takes a `UseLocaleOptions`. See [`fn@crate::use_locale`] for how to use. -pub fn use_locale_with_options(options: UseLocaleOptions) -> Signal { - let UseLocaleOptions { - fallback, - ssr_lang_header_getter, - } = options; +pub fn use_locale_with_options(supported: S, options: UseLocaleOptions) -> Signal +where + S: IntoIterator, + S::Item: Into + Clone + 'static, +{ + let locales = use_locales_with_options(options); - let locales = use_locales_with_options(UseLocalesOptions { - ssr_lang_header_getter, - }); + let supported = supported.into_iter().collect::>(); - Signal::derive(move || locales.get().first().cloned().unwrap_or(fallback.clone())) + Signal::derive(move || { + let supported = supported.clone(); + + locales.with(|locales| { + let mut first_supported = None; + + for s in supported { + let s = s.into(); + + if first_supported.is_none() { + first_supported = Some(s.clone()); + } + + for locale in locales { + if locale.starts_with(&s) { + return s; + } + } + } + + first_supported.unwrap_or_else(|| "".to_string()) + }) + }) } -/// Options for [`fn@crate::use_locale_with_options`]. -#[derive(DefaultBuilder)] -pub struct UseLocaleOptions { - /// Fallback value in case no locale is found. Defaults to `"en"`. - fallback: String, - - /// Getter function to return the string value of the accept languange header. - /// When you use one of the features `"axum"`, `"actix"` or `"spin"` there's a valid default implementation provided. - #[allow(dead_code)] - ssr_lang_header_getter: Rc Option>, -} - -impl Default for UseLocaleOptions { - fn default() -> Self { - Self { - fallback: "en".to_string(), - ssr_lang_header_getter: Rc::new(move || { - get_header!(ACCEPT_LANGUAGE, use_locale, ssr_lang_header_getter) - }), - } - } -} +pub type UseLocaleOptions = UseLocalesOptions; diff --git a/src/use_locales.rs b/src/use_locales.rs index 98f7e73..4e4f567 100644 --- a/src/use_locales.rs +++ b/src/use_locales.rs @@ -100,7 +100,7 @@ pub struct UseLocalesOptions { /// Getter function to return the string value of the accept languange header. /// When you use one of the features `"axum"`, `"actix"` or `"spin"` there's a valid default implementation provided. #[allow(dead_code)] - pub(crate) ssr_lang_header_getter: Rc Option>, + ssr_lang_header_getter: Rc Option>, } impl Default for UseLocalesOptions { From 5b8cfd4449a0af092d43ed04b666b041d3aa60f0 Mon Sep 17 00:00:00 2001 From: Maccesch Date: Mon, 29 Jul 2024 01:09:24 +0100 Subject: [PATCH 07/40] fixed tests --- src/use_locale.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/use_locale.rs b/src/use_locale.rs index ebf5423..7b31825 100644 --- a/src/use_locale.rs +++ b/src/use_locale.rs @@ -22,7 +22,7 @@ use leptos::*; /// # /// # #[component] /// # fn Demo() -> impl IntoView { -/// let locale = use_locale(&["en".to_string(), "de".to_string(), "fr".to_string()]); +/// let locale = use_locale(["en", "de", "fr"]); /// # /// # view! { } /// # } From f0d60e5d49c89087ece080197f5f90a5db646a98 Mon Sep 17 00:00:00 2001 From: Maccesch Date: Tue, 30 Jul 2024 12:49:24 +0100 Subject: [PATCH 08/40] release 0.11.2 --- CHANGELOG.md | 8 +++++++- Cargo.toml | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33a9f73..43a5e4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,13 @@ 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.11.1] - 2024-07-28 +## [0.11.2] - 2024-07-30 + +### Change 🔥 + +- `use_locale` has now a supported locale list. + +## (yanked) [0.11.1] - 2024-07-28 ### New Functions 🚀 diff --git a/Cargo.toml b/Cargo.toml index 7ac4ef7..1201482 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "leptos-use" -version = "0.11.1" +version = "0.11.2" edition = "2021" authors = ["Marc-Stefan Cassola"] categories = ["gui", "web-programming"] From da56771900a2362e266243d81478c7fa5c158b14 Mon Sep 17 00:00:00 2001 From: Maccesch Date: Wed, 31 Jul 2024 01:15:20 +0100 Subject: [PATCH 09/40] fixed use_timeout_fn to be SSR safe --- CHANGELOG.md | 6 +++ Cargo.toml | 2 +- src/use_timeout_fn.rs | 116 +++++++++++++++++++++++++----------------- 3 files changed, 76 insertions(+), 48 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43a5e4c..20fe0dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ 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.11.3] - 2024-07-31 + +### Fix 🍕 + +- Made `use_timeout_fn` SSR-safe + ## [0.11.2] - 2024-07-30 ### Change 🔥 diff --git a/Cargo.toml b/Cargo.toml index 1201482..24e568a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "leptos-use" -version = "0.11.2" +version = "0.11.3" edition = "2021" authors = ["Marc-Stefan Cassola"] categories = ["gui", "web-programming"] diff --git a/src/use_timeout_fn.rs b/src/use_timeout_fn.rs index 7ae644b..2e3d27f 100644 --- a/src/use_timeout_fn.rs +++ b/src/use_timeout_fn.rs @@ -1,9 +1,5 @@ -use leptos::leptos_dom::helpers::TimeoutHandle; use leptos::*; -use std::cell::Cell; use std::marker::PhantomData; -use std::rc::Rc; -use std::time::Duration; /// Wrapper for `setTimeout` with controls. /// @@ -31,6 +27,11 @@ use std::time::Duration; /// # view! { } /// # } /// ``` +/// +/// ## Server-Side Rendering +/// +/// On the server the callback will never be run. The returned functions are all no-ops and +/// `is_pending` will always be `false`. pub fn use_timeout_fn( callback: CbFn, delay: D, @@ -40,65 +41,86 @@ where Arg: 'static, D: Into>, { - let delay = delay.into(); - let (is_pending, set_pending) = create_signal(false); - let timer = Rc::new(Cell::new(None::)); + let start; + let stop; - let clear = { - let timer = Rc::clone(&timer); + #[cfg(not(feature = "ssr"))] + { + use leptos::leptos_dom::helpers::TimeoutHandle; + use std::cell::Cell; + use std::rc::Rc; + use std::time::Duration; - move || { - if let Some(timer) = timer.take() { - timer.clear(); + let delay = delay.into(); + + let timer = Rc::new(Cell::new(None::)); + + let clear = { + let timer = Rc::clone(&timer); + + move || { + if let Some(timer) = timer.take() { + timer.clear(); + } } - } - }; + }; - let stop = { - let clear = clear.clone(); + stop = { + let clear = clear.clone(); - move || { - set_pending.set(false); - clear(); - } - }; + move || { + set_pending.set(false); + clear(); + } + }; - let start = { - let timer = Rc::clone(&timer); - let callback = callback.clone(); + start = { + let timer = Rc::clone(&timer); + let callback = callback.clone(); - move |arg: Arg| { - set_pending.set(true); + move |arg: Arg| { + set_pending.set(true); - let handle = set_timeout_with_handle( - { - let timer = Rc::clone(&timer); - let callback = callback.clone(); + let handle = set_timeout_with_handle( + { + let timer = Rc::clone(&timer); + let callback = callback.clone(); - move || { - set_pending.set(false); - timer.set(None); + move || { + set_pending.set(false); + timer.set(None); - #[cfg(debug_assertions)] - let prev = SpecialNonReactiveZone::enter(); + #[cfg(debug_assertions)] + let prev = SpecialNonReactiveZone::enter(); - callback(arg); + callback(arg); - #[cfg(debug_assertions)] - SpecialNonReactiveZone::exit(prev); - } - }, - Duration::from_millis(delay.get_untracked() as u64), - ) - .ok(); + #[cfg(debug_assertions)] + SpecialNonReactiveZone::exit(prev); + } + }, + Duration::from_millis(delay.get_untracked() as u64), + ) + .ok(); - timer.set(handle); - } - }; + timer.set(handle); + } + }; - on_cleanup(clear); + on_cleanup(clear); + } + + #[cfg(feature = "ssr")] + { + let _ = set_pending; + let _ = callback; + let _ = delay; + + start = move |_: Arg| (); + stop = move || (); + } UseTimeoutFnReturn { is_pending: is_pending.into(), From 0b6903fcccb5ca8fca17b7154e52b5e79fddd919 Mon Sep 17 00:00:00 2001 From: Hector Candelaria Date: Wed, 31 Jul 2024 21:47:38 -0400 Subject: [PATCH 10/40] Feat: Add `renotify` field to `UseWebNotificationOptions` and `ShowOptions` Uncommented the existing `renotify` code. --- examples/use_web_notification/src/main.rs | 2 +- src/use_web_notification.rs | 33 ++++++++++++----------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/examples/use_web_notification/src/main.rs b/examples/use_web_notification/src/main.rs index bc717bb..3e06f56 100644 --- a/examples/use_web_notification/src/main.rs +++ b/examples/use_web_notification/src/main.rs @@ -14,7 +14,7 @@ fn Demo() -> impl IntoView { .title("Hello World from leptos-use") .direction(NotificationDirection::Auto) .language("en") - // .renotify(true) + .renotify(true) .tag("test"), ); diff --git a/src/use_web_notification.rs b/src/use_web_notification.rs index 11fd21a..8870a89 100644 --- a/src/use_web_notification.rs +++ b/src/use_web_notification.rs @@ -28,6 +28,7 @@ use std::rc::Rc; /// UseWebNotificationOptions::default() /// .direction(NotificationDirection::Auto) /// .language("en") +/// .renotity(true) /// .tag("test"), /// ); /// @@ -227,8 +228,7 @@ impl From for web_sys::NotificationDirection { /// See [MDN Docs](https://developer.mozilla.org/en-US/docs/Web/API/notification) for more info. /// /// The following implementations are missing: -/// - `renotify` -/// - `vibrate` +/// - `vibrate` /// - `silent` /// - `image` #[derive(DefaultBuilder, Clone)] @@ -268,10 +268,11 @@ pub struct UseWebNotificationOptions { /// user clicks or dismisses it, rather than closing automatically. require_interaction: bool, - // /// A boolean value specifying whether the user should be notified after a new notification replaces an old one. - // /// The default is `false`, which means they won't be notified. If `true`, then `tag` also must be set. - // #[builder(into)] - // renotify: bool, + /// A boolean value specifying whether the user should be notified after a new notification replaces an old one. + /// The default is `false`, which means they won't be notified. If `true`, then `tag` also must be set. + #[builder(into)] + renotify: bool, + /// Called when the user clicks on displayed `Notification`. on_click: Rc, @@ -296,7 +297,7 @@ impl Default for UseWebNotificationOptions { tag: None, icon: None, require_interaction: false, - // renotify: false, + renotify: false, on_click: Rc::new(|_| {}), on_close: Rc::new(|_| {}), on_error: Rc::new(|_| {}), @@ -311,8 +312,8 @@ impl From<&UseWebNotificationOptions> for web_sys::NotificationOptions { web_sys_options .dir(options.direction.into()) - .require_interaction(options.require_interaction); - // .renotify(options.renotify); + .require_interaction(options.require_interaction) + .renotify(options.renotify); if let Some(body) = &options.body { web_sys_options.body(body); @@ -380,10 +381,10 @@ pub struct ShowOptions { /// user clicks or dismisses it, rather than closing automatically. #[builder(into)] require_interaction: Option, - // /// A boolean value specifying whether the user should be notified after a new notification replaces an old one. - // /// The default is `false`, which means they won't be notified. If `true`, then `tag` also must be set. - // #[builder(into)] - // renotify: Option, + /// A boolean value specifying whether the user should be notified after a new notification replaces an old one. + /// The default is `false`, which means they won't be notified. If `true`, then `tag` also must be set. + #[builder(into)] + renotify: Option, } #[cfg(not(feature = "ssr"))] @@ -413,9 +414,9 @@ impl ShowOptions { options.tag(tag); } - // if let Some(renotify) = &self.renotify { - // options.renotify(renotify); - // } + if let Some(renotify) = self.renotify { + options.renotify(renotify); + } } } From 88af0e735dfdd5ae1e82ad8878dc697e0aed91fd Mon Sep 17 00:00:00 2001 From: Hector Candelaria Date: Wed, 31 Jul 2024 22:18:58 -0400 Subject: [PATCH 11/40] Feat: Add `silent` field to `UseWebNotificationOptions` and `ShowOptions` Introduced the `silent` field to the `UseWebNotificationOptions` and `ShowOptions` structures, allowing notifications to be displayed in silent. --- src/use_web_notification.rs | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/use_web_notification.rs b/src/use_web_notification.rs index 8870a89..986fcc8 100644 --- a/src/use_web_notification.rs +++ b/src/use_web_notification.rs @@ -229,7 +229,6 @@ impl From for web_sys::NotificationDirection { /// /// The following implementations are missing: /// - `vibrate` -/// - `silent` /// - `image` #[derive(DefaultBuilder, Clone)] #[cfg_attr(feature = "ssr", allow(dead_code))] @@ -273,6 +272,11 @@ pub struct UseWebNotificationOptions { #[builder(into)] renotify: bool, + /// A boolean value specifying whether the notification should be silent, regardless of the device settings. + /// The default is `false`, which means the notification is not silent. If `true`, then the notification will be silent. + #[builder(into)] + silent: Option, + /// Called when the user clicks on displayed `Notification`. on_click: Rc, @@ -298,6 +302,7 @@ impl Default for UseWebNotificationOptions { icon: None, require_interaction: false, renotify: false, + silent: None, on_click: Rc::new(|_| {}), on_close: Rc::new(|_| {}), on_error: Rc::new(|_| {}), @@ -313,7 +318,8 @@ impl From<&UseWebNotificationOptions> for web_sys::NotificationOptions { web_sys_options .dir(options.direction.into()) .require_interaction(options.require_interaction) - .renotify(options.renotify); + .renotify(options.renotify) + .silent(options.silent); if let Some(body) = &options.body { web_sys_options.body(body); @@ -340,8 +346,7 @@ impl From<&UseWebNotificationOptions> for web_sys::NotificationOptions { /// See [MDN Docs](https://developer.mozilla.org/en-US/docs/Web/API/notification) for more info. /// /// The following implementations are missing: -/// - `vibrate` -/// - `silent` +/// - `vibrate` /// - `image` #[derive(DefaultBuilder, Default)] #[cfg_attr(feature = "ssr", allow(dead_code))] @@ -381,10 +386,16 @@ pub struct ShowOptions { /// user clicks or dismisses it, rather than closing automatically. #[builder(into)] require_interaction: Option, + /// A boolean value specifying whether the user should be notified after a new notification replaces an old one. /// The default is `false`, which means they won't be notified. If `true`, then `tag` also must be set. #[builder(into)] renotify: Option, + + /// A boolean value specifying whether the notification should be silent, regardless of the device settings. + /// The default is `false`, which means the notification is not silent. If `true`, then the notification will be silent. + #[builder(into)] + silent: Option, } #[cfg(not(feature = "ssr"))] @@ -417,6 +428,10 @@ impl ShowOptions { if let Some(renotify) = self.renotify { options.renotify(renotify); } + + if let Some(silent) = self.silent { + options.silent(Some(silent)); + } } } From f37f28cfff3f6de50e36d72b4fcc9682b2ed3e90 Mon Sep 17 00:00:00 2001 From: Hector Candelaria Date: Wed, 31 Jul 2024 23:07:18 -0400 Subject: [PATCH 12/40] Feat: Add `image` field to `UseWebNotificationOptions` and `ShowOptions` Added the `image` field to the `UseWebNotificationOptions` and `ShowOptions` structures. This field allows specifying an image URL to be displayed in the notification. --- src/use_web_notification.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/use_web_notification.rs b/src/use_web_notification.rs index 986fcc8..a919052 100644 --- a/src/use_web_notification.rs +++ b/src/use_web_notification.rs @@ -229,7 +229,6 @@ impl From for web_sys::NotificationDirection { /// /// The following implementations are missing: /// - `vibrate` -/// - `image` #[derive(DefaultBuilder, Clone)] #[cfg_attr(feature = "ssr", allow(dead_code))] pub struct UseWebNotificationOptions { @@ -263,6 +262,11 @@ pub struct UseWebNotificationOptions { #[builder(into)] icon: Option, + /// The URL of the image to be displayed as part of the notification as specified + /// in the constructor's options parameter. + #[builder(into)] + image: Option, + /// A boolean value indicating that a notification should remain active until the /// user clicks or dismisses it, rather than closing automatically. require_interaction: bool, @@ -300,6 +304,7 @@ impl Default for UseWebNotificationOptions { language: None, tag: None, icon: None, + image: None, require_interaction: false, renotify: false, silent: None, @@ -329,6 +334,10 @@ impl From<&UseWebNotificationOptions> for web_sys::NotificationOptions { web_sys_options.icon(icon); } + if let Some(image) = &options.image { + web_sys_options.image(image); + } + if let Some(language) = &options.language { web_sys_options.lang(language); } @@ -347,7 +356,6 @@ impl From<&UseWebNotificationOptions> for web_sys::NotificationOptions { /// /// The following implementations are missing: /// - `vibrate` -/// - `image` #[derive(DefaultBuilder, Default)] #[cfg_attr(feature = "ssr", allow(dead_code))] pub struct ShowOptions { @@ -382,6 +390,11 @@ pub struct ShowOptions { #[builder(into)] icon: Option, + /// The URL of the image to be displayed as part of the notification as specified + /// in the constructor's options parameter. + #[builder(into)] + image: Option, + /// A boolean value indicating that a notification should remain active until the /// user clicks or dismisses it, rather than closing automatically. #[builder(into)] @@ -417,6 +430,10 @@ impl ShowOptions { options.icon(icon); } + if let Some(image) = &self.image { + options.image(image); + } + if let Some(language) = &self.language { options.lang(language); } From 2a8a2b81e4adf177c060034dfa2b52464b8ae7ff Mon Sep 17 00:00:00 2001 From: Hector Candelaria Date: Thu, 1 Aug 2024 01:15:37 -0400 Subject: [PATCH 13/40] Doc: fixed typo --- src/use_web_notification.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/use_web_notification.rs b/src/use_web_notification.rs index a919052..01098a4 100644 --- a/src/use_web_notification.rs +++ b/src/use_web_notification.rs @@ -28,7 +28,7 @@ use std::rc::Rc; /// UseWebNotificationOptions::default() /// .direction(NotificationDirection::Auto) /// .language("en") -/// .renotity(true) +/// .renotify(true) /// .tag("test"), /// ); /// From d32d72573171de58a71f8c1e0f5c0e70903617b6 Mon Sep 17 00:00:00 2001 From: Maccesch Date: Thu, 1 Aug 2024 16:16:26 +0100 Subject: [PATCH 14/40] updated changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 20fe0dc..c27f5fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ 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). +## [Unreleased] - + +### New Features 🚀 + +- `use_web_notification` now supports the options `renotify`, `silent` and `image` (thanks to @hcandelaria). + ## [0.11.3] - 2024-07-31 ### Fix 🍕 From cef0e681217b1a8d58f96fe43e2ea6ee94d8f4a5 Mon Sep 17 00:00:00 2001 From: Maccesch Date: Mon, 12 Aug 2024 12:25:07 +0100 Subject: [PATCH 15/40] added assign_ltr and assign_rtl to sync_signal --- CHANGELOG.md | 3 ++- Cargo.toml | 2 +- src/sync_signal.rs | 39 +++++++++++++++++++++++++++++++++++++-- 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c27f5fd..0b7a398 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,11 +3,12 @@ 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). -## [Unreleased] - +## [0.11.4] - 2024-08-12 ### New Features 🚀 - `use_web_notification` now supports the options `renotify`, `silent` and `image` (thanks to @hcandelaria). +- `sync_signal` no supports the options `assign_ltr` and `assign_rtl`. ## [0.11.3] - 2024-07-31 diff --git a/Cargo.toml b/Cargo.toml index 24e568a..870af1a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "leptos-use" -version = "0.11.3" +version = "0.11.4" edition = "2021" authors = ["Marc-Stefan Cassola"] categories = ["gui", "web-programming"] diff --git a/src/sync_signal.rs b/src/sync_signal.rs index e67ef3d..e20b1e3 100644 --- a/src/sync_signal.rs +++ b/src/sync_signal.rs @@ -168,6 +168,8 @@ where direction, transform_ltr, transform_rtl, + assign_ltr, + assign_rtl, } = options; let left = left.into(); @@ -183,7 +185,7 @@ where let new_value = (*transform_ltr)(new_value); if right.with_untracked(|right| right != &new_value) { - right.update(|right| *right = new_value); + right.update(|right| assign_ltr(right, new_value)); } }, immediate, @@ -197,7 +199,7 @@ where let new_value = (*transform_rtl)(new_value); if left.with_untracked(|left| left != &new_value) { - left.update(|left| *left = new_value); + left.update(|left| assign_rtl(left, new_value)); } }, immediate, @@ -221,6 +223,8 @@ pub enum SyncDirection { Both, } +pub type AssignFn = Rc; + /// Options for [`sync_signal_with_options`]. #[derive(DefaultBuilder)] pub struct SyncSignalOptions { @@ -241,6 +245,16 @@ pub struct SyncSignalOptions { /// Defaults to identity. #[builder(skip)] transform_rtl: Rc L>, + + /// Assigns the left signal to the right signal. + /// Defaults to `*r = l`. + #[builder(skip)] + assign_ltr: AssignFn, + + /// Assigns the right signal to the left signal. + /// Defaults to `*l = r`. + #[builder(skip)] + assign_rtl: AssignFn, } impl SyncSignalOptions { @@ -262,6 +276,23 @@ impl SyncSignalOptions { } } + /// Assigns the left signal to the right signal. + /// Defaults to `*r = l`. + pub fn assign_ltr(self, assign_ltr: impl Fn(&mut R, R) + 'static) -> Self { + Self { + assign_ltr: Rc::new(assign_ltr), + ..self + } + } + + /// Assigns the right signal to the left signal. + /// Defaults to `*l = r`. + pub fn assign_rtl(self, assign_rtl: impl Fn(&mut L, L) + 'static) -> Self { + Self { + assign_rtl: Rc::new(assign_rtl), + ..self + } + } /// Initializes options with transforms pub fn with_transforms( transform_ltr: impl Fn(&L) -> R + 'static, @@ -272,6 +303,8 @@ impl SyncSignalOptions { direction: SyncDirection::Both, transform_ltr: Rc::new(transform_ltr), transform_rtl: Rc::new(transform_rtl), + assign_ltr: Rc::new(|right, left| *right = left), + assign_rtl: Rc::new(|left, right| *left = right), } } } @@ -287,6 +320,8 @@ where direction: SyncDirection::Both, transform_ltr: Rc::new(|x| x.clone().into()), transform_rtl: Rc::new(|x| x.clone().into()), + assign_ltr: Rc::new(|right, left| *right = left), + assign_rtl: Rc::new(|left, right| *left = right), } } } From e795c1f8f342b48433946c0dfdb3693c06074cb8 Mon Sep 17 00:00:00 2001 From: Charles Edward Gagnon Date: Mon, 12 Aug 2024 19:55:33 -0400 Subject: [PATCH 16/40] make `UseMouseEventExtractor` not return an option This makes it so that `Movement` always returns (0., 0.) --- src/use_mouse.rs | 53 ++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/src/use_mouse.rs b/src/use_mouse.rs index 74f943f..63b4d0c 100644 --- a/src/use_mouse.rs +++ b/src/use_mouse.rs @@ -6,6 +6,7 @@ use cfg_if::cfg_if; use default_struct_builder::DefaultBuilder; use leptos::ev::{dragover, mousemove, touchend, touchmove, touchstart}; use leptos::*; +use std::convert::Infallible; use std::marker::PhantomData; use wasm_bindgen::{JsCast, JsValue}; @@ -108,7 +109,7 @@ where move |event: web_sys::MouseEvent| { let result = coord_type.extract_mouse_coords(&event); - if let Some((x, y)) = result { + if let (x, y) = result { set_x.set(x); set_y.set(y); set_source_type.set(UseMouseSourceType::Mouse); @@ -137,7 +138,7 @@ where .expect("Just checked that there's at least on touch"), ); - if let Some((x, y)) = result { + if let (x, y) = result { set_x.set(x); set_y.set(y); set_source_type.set(UseMouseSourceType::Touch); @@ -230,10 +231,10 @@ where _marker: PhantomData, } -impl Default for UseMouseOptions { +impl Default for UseMouseOptions { fn default() -> Self { Self { - coord_type: UseMouseCoordType::::default(), + coord_type: UseMouseCoordType::::default(), target: use_window(), touch: true, reset_on_touch_ends: false, @@ -245,7 +246,7 @@ impl Default for UseMouseOptions { +pub enum UseMouseCoordType { Page, Client, Screen, @@ -253,54 +254,54 @@ pub enum UseMouseCoordType { Custom(E), } -impl Default for UseMouseCoordType { +impl Default for UseMouseCoordType { fn default() -> Self { Self::Page } } /// Trait to implement if you want to specify a custom extractor -#[allow(unused_variables)] pub trait UseMouseEventExtractor { /// Return the coordinates from mouse events (`Some(x, y)`) or `None` - fn extract_mouse_coords(&self, event: &web_sys::MouseEvent) -> Option<(f64, f64)> { - None - } + fn extract_mouse_coords(&self, event: &web_sys::MouseEvent) -> (f64, f64); /// Return the coordinates from touches (`Some(x, y)`) or `None` - fn extract_touch_coords(&self, touch: &web_sys::Touch) -> Option<(f64, f64)> { - None - } + fn extract_touch_coords(&self, touch: &web_sys::Touch) -> (f64, f64); } impl UseMouseEventExtractor for UseMouseCoordType { - fn extract_mouse_coords(&self, event: &web_sys::MouseEvent) -> Option<(f64, f64)> { + fn extract_mouse_coords(&self, event: &web_sys::MouseEvent) -> (f64, f64) { match self { - UseMouseCoordType::Page => Some((event.page_x() as f64, event.page_y() as f64)), - UseMouseCoordType::Client => Some((event.client_x() as f64, event.client_y() as f64)), - UseMouseCoordType::Screen => Some((event.screen_x() as f64, event.client_y() as f64)), + UseMouseCoordType::Page => (event.page_x() as f64, event.page_y() as f64), + UseMouseCoordType::Client => (event.client_x() as f64, event.client_y() as f64), + UseMouseCoordType::Screen => (event.screen_x() as f64, event.client_y() as f64), UseMouseCoordType::Movement => { - Some((event.movement_x() as f64, event.movement_y() as f64)) + (event.movement_x() as f64, event.movement_y() as f64) } UseMouseCoordType::Custom(ref extractor) => extractor.extract_mouse_coords(event), } } - fn extract_touch_coords(&self, touch: &web_sys::Touch) -> Option<(f64, f64)> { + fn extract_touch_coords(&self, touch: &web_sys::Touch) -> (f64, f64) { match self { - UseMouseCoordType::Page => Some((touch.page_x() as f64, touch.page_y() as f64)), - UseMouseCoordType::Client => Some((touch.client_x() as f64, touch.client_y() as f64)), - UseMouseCoordType::Screen => Some((touch.screen_x() as f64, touch.client_y() as f64)), - UseMouseCoordType::Movement => None, + UseMouseCoordType::Page => (touch.page_x() as f64, touch.page_y() as f64), + UseMouseCoordType::Client => (touch.client_x() as f64, touch.client_y() as f64), + UseMouseCoordType::Screen => (touch.screen_x() as f64, touch.client_y() as f64), + UseMouseCoordType::Movement => (0., 0.), UseMouseCoordType::Custom(ref extractor) => extractor.extract_touch_coords(touch), } } } -#[derive(Clone)] -pub struct UseMouseEventExtractorDefault; +impl UseMouseEventExtractor for Infallible { + fn extract_mouse_coords(&self, _: &web_sys::MouseEvent) -> (f64, f64) { + unreachable!() + } -impl UseMouseEventExtractor for UseMouseEventExtractorDefault {} + fn extract_touch_coords(&self, _: &web_sys::Touch) -> (f64, f64) { + unreachable!() + } +} /// Return type of [`use_mouse`]. pub struct UseMouseReturn { From fe7d51c70f6a1438468c2cd4ea94750e0e60e0b3 Mon Sep 17 00:00:00 2001 From: Charles Edward Gagnon Date: Mon, 12 Aug 2024 20:01:08 -0400 Subject: [PATCH 17/40] fix building issues --- src/use_mouse.rs | 22 ++++++++++------------ src/use_mouse_in_element.rs | 7 ++++--- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/use_mouse.rs b/src/use_mouse.rs index 63b4d0c..1c65547 100644 --- a/src/use_mouse.rs +++ b/src/use_mouse.rs @@ -109,11 +109,10 @@ where move |event: web_sys::MouseEvent| { let result = coord_type.extract_mouse_coords(&event); - if let (x, y) = result { - set_x.set(x); - set_y.set(y); - set_source_type.set(UseMouseSourceType::Mouse); - } + let (x, y) = result; + set_x.set(x); + set_y.set(y); + set_source_type.set(UseMouseSourceType::Mouse); } }; @@ -138,11 +137,10 @@ where .expect("Just checked that there's at least on touch"), ); - if let (x, y) = result { - set_x.set(x); - set_y.set(y); - set_source_type.set(UseMouseSourceType::Touch); - } + let (x, y) = result; + set_x.set(x); + set_y.set(y); + set_source_type.set(UseMouseSourceType::Touch); } } }; @@ -234,7 +232,7 @@ where impl Default for UseMouseOptions { fn default() -> Self { Self { - coord_type: UseMouseCoordType::::default(), + coord_type: UseMouseCoordType::default(), target: use_window(), touch: true, reset_on_touch_ends: false, @@ -254,7 +252,7 @@ pub enum UseMouseCoordType { Custom(E), } -impl Default for UseMouseCoordType { +impl Default for UseMouseCoordType { fn default() -> Self { Self::Page } diff --git a/src/use_mouse_in_element.rs b/src/use_mouse_in_element.rs index 29ad0f9..df80b2e 100644 --- a/src/use_mouse_in_element.rs +++ b/src/use_mouse_in_element.rs @@ -1,11 +1,12 @@ use crate::core::{ElementMaybeSignal, Position}; use crate::{ use_mouse_with_options, use_window, UseMouseCoordType, UseMouseEventExtractor, - UseMouseEventExtractorDefault, UseMouseOptions, UseMouseReturn, UseMouseSourceType, UseWindow, + UseMouseOptions, UseMouseReturn, UseMouseSourceType, UseWindow, }; use cfg_if::cfg_if; use default_struct_builder::DefaultBuilder; use leptos::*; +use std::convert::Infallible; use std::marker::PhantomData; /// Reactive mouse position related to an element. @@ -196,11 +197,11 @@ where } impl Default - for UseMouseInElementOptions + for UseMouseInElementOptions { fn default() -> Self { Self { - coord_type: UseMouseCoordType::::default(), + coord_type: UseMouseCoordType::::default(), target: use_window(), touch: true, reset_on_touch_ends: false, From 0b7e8af9950a08417acb9d98c197a43bfdfe0758 Mon Sep 17 00:00:00 2001 From: Charles Edward Gagnon Date: Mon, 12 Aug 2024 20:01:53 -0400 Subject: [PATCH 18/40] chore: fmt; --- src/use_mouse.rs | 4 +--- src/use_mouse_in_element.rs | 8 +++----- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/use_mouse.rs b/src/use_mouse.rs index 1c65547..2ff9a7a 100644 --- a/src/use_mouse.rs +++ b/src/use_mouse.rs @@ -273,9 +273,7 @@ impl UseMouseEventExtractor for UseMouseCoord UseMouseCoordType::Page => (event.page_x() as f64, event.page_y() as f64), UseMouseCoordType::Client => (event.client_x() as f64, event.client_y() as f64), UseMouseCoordType::Screen => (event.screen_x() as f64, event.client_y() as f64), - UseMouseCoordType::Movement => { - (event.movement_x() as f64, event.movement_y() as f64) - } + UseMouseCoordType::Movement => (event.movement_x() as f64, event.movement_y() as f64), UseMouseCoordType::Custom(ref extractor) => extractor.extract_mouse_coords(event), } } diff --git a/src/use_mouse_in_element.rs b/src/use_mouse_in_element.rs index df80b2e..8b37f4d 100644 --- a/src/use_mouse_in_element.rs +++ b/src/use_mouse_in_element.rs @@ -1,7 +1,7 @@ use crate::core::{ElementMaybeSignal, Position}; use crate::{ - use_mouse_with_options, use_window, UseMouseCoordType, UseMouseEventExtractor, - UseMouseOptions, UseMouseReturn, UseMouseSourceType, UseWindow, + use_mouse_with_options, use_window, UseMouseCoordType, UseMouseEventExtractor, UseMouseOptions, + UseMouseReturn, UseMouseSourceType, UseWindow, }; use cfg_if::cfg_if; use default_struct_builder::DefaultBuilder; @@ -196,9 +196,7 @@ where _marker: PhantomData, } -impl Default - for UseMouseInElementOptions -{ +impl Default for UseMouseInElementOptions { fn default() -> Self { Self { coord_type: UseMouseCoordType::::default(), From 31f019a944cad089279d29c1c59de7447e24caa4 Mon Sep 17 00:00:00 2001 From: Charles Edward Gagnon Date: Mon, 12 Aug 2024 20:27:04 -0400 Subject: [PATCH 19/40] make it take Some again --- src/use_mouse.rs | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/use_mouse.rs b/src/use_mouse.rs index 2ff9a7a..e8ca691 100644 --- a/src/use_mouse.rs +++ b/src/use_mouse.rs @@ -259,42 +259,47 @@ impl Default for UseMouseCoordType { } /// Trait to implement if you want to specify a custom extractor +#[allow(unused_variables)] pub trait UseMouseEventExtractor { /// Return the coordinates from mouse events (`Some(x, y)`) or `None` - fn extract_mouse_coords(&self, event: &web_sys::MouseEvent) -> (f64, f64); + fn extract_mouse_coords(&self, event: &web_sys::MouseEvent) -> Option<(f64, f64)> { + None + } /// Return the coordinates from touches (`Some(x, y)`) or `None` - fn extract_touch_coords(&self, touch: &web_sys::Touch) -> (f64, f64); + fn extract_touch_coords(&self, touch: &web_sys::Touch) -> Option<(f64, f64)> { + None + } } impl UseMouseEventExtractor for UseMouseCoordType { - fn extract_mouse_coords(&self, event: &web_sys::MouseEvent) -> (f64, f64) { - match self { + fn extract_mouse_coords(&self, event: &web_sys::MouseEvent) -> Option<(f64, f64)> { + Some(match self { UseMouseCoordType::Page => (event.page_x() as f64, event.page_y() as f64), UseMouseCoordType::Client => (event.client_x() as f64, event.client_y() as f64), UseMouseCoordType::Screen => (event.screen_x() as f64, event.client_y() as f64), UseMouseCoordType::Movement => (event.movement_x() as f64, event.movement_y() as f64), - UseMouseCoordType::Custom(ref extractor) => extractor.extract_mouse_coords(event), - } + UseMouseCoordType::Custom(ref extractor) => return extractor.extract_mouse_coords(event), + }) } - fn extract_touch_coords(&self, touch: &web_sys::Touch) -> (f64, f64) { - match self { + fn extract_touch_coords(&self, touch: &web_sys::Touch) -> Option<(f64, f64)> { + Some(match self { UseMouseCoordType::Page => (touch.page_x() as f64, touch.page_y() as f64), UseMouseCoordType::Client => (touch.client_x() as f64, touch.client_y() as f64), UseMouseCoordType::Screen => (touch.screen_x() as f64, touch.client_y() as f64), - UseMouseCoordType::Movement => (0., 0.), - UseMouseCoordType::Custom(ref extractor) => extractor.extract_touch_coords(touch), - } + UseMouseCoordType::Movement => return None, + UseMouseCoordType::Custom(ref extractor) => return extractor.extract_touch_coords(touch), + }) } } impl UseMouseEventExtractor for Infallible { - fn extract_mouse_coords(&self, _: &web_sys::MouseEvent) -> (f64, f64) { + fn extract_mouse_coords(&self, _: &web_sys::MouseEvent) -> Option<(f64, f64)> { unreachable!() } - fn extract_touch_coords(&self, _: &web_sys::Touch) -> (f64, f64) { + fn extract_touch_coords(&self, _: &web_sys::Touch) -> Option<(f64, f64)> { unreachable!() } } From cb889066ce6947f22450fa28d379d590657c6bcc Mon Sep 17 00:00:00 2001 From: Charles Edward Gagnon Date: Mon, 12 Aug 2024 20:34:11 -0400 Subject: [PATCH 20/40] fix build issues --- src/use_mouse.rs | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/use_mouse.rs b/src/use_mouse.rs index e8ca691..8e61eaa 100644 --- a/src/use_mouse.rs +++ b/src/use_mouse.rs @@ -109,10 +109,11 @@ where move |event: web_sys::MouseEvent| { let result = coord_type.extract_mouse_coords(&event); - let (x, y) = result; - set_x.set(x); - set_y.set(y); - set_source_type.set(UseMouseSourceType::Mouse); + if let Some((x, y)) = result { + set_x.set(x); + set_y.set(y); + set_source_type.set(UseMouseSourceType::Mouse); + } } }; @@ -137,10 +138,11 @@ where .expect("Just checked that there's at least on touch"), ); - let (x, y) = result; - set_x.set(x); - set_y.set(y); - set_source_type.set(UseMouseSourceType::Touch); + if let Some((x, y)) = result { + set_x.set(x); + set_y.set(y); + set_source_type.set(UseMouseSourceType::Touch); + } } } }; @@ -244,7 +246,7 @@ impl Default for UseMouseOptions { /// Defines how to get the coordinates from the event. #[derive(Clone)] -pub enum UseMouseCoordType { +pub enum UseMouseCoordType { Page, Client, Screen, @@ -279,7 +281,9 @@ impl UseMouseEventExtractor for UseMouseCoord UseMouseCoordType::Client => (event.client_x() as f64, event.client_y() as f64), UseMouseCoordType::Screen => (event.screen_x() as f64, event.client_y() as f64), UseMouseCoordType::Movement => (event.movement_x() as f64, event.movement_y() as f64), - UseMouseCoordType::Custom(ref extractor) => return extractor.extract_mouse_coords(event), + UseMouseCoordType::Custom(ref extractor) => { + return extractor.extract_mouse_coords(event) + } }) } @@ -289,7 +293,9 @@ impl UseMouseEventExtractor for UseMouseCoord UseMouseCoordType::Client => (touch.client_x() as f64, touch.client_y() as f64), UseMouseCoordType::Screen => (touch.screen_x() as f64, touch.client_y() as f64), UseMouseCoordType::Movement => return None, - UseMouseCoordType::Custom(ref extractor) => return extractor.extract_touch_coords(touch), + UseMouseCoordType::Custom(ref extractor) => { + return extractor.extract_touch_coords(touch) + } }) } } From 5d6d55dd89edaa04a81a558ebe5e6413569769e6 Mon Sep 17 00:00:00 2001 From: Charles Edward Gagnon Date: Mon, 12 Aug 2024 20:35:51 -0400 Subject: [PATCH 21/40] update changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b7a398..2553308 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ 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). +## [Unreleased] + +### Removed 🗑 + +- Removed `UseMouseEventExtractorDefault` + ## [0.11.4] - 2024-08-12 ### New Features 🚀 From 72cc82713d315bd8bd3b45533fc4f7da072e283e Mon Sep 17 00:00:00 2001 From: Charles Edward Gagnon Date: Mon, 12 Aug 2024 20:38:58 -0400 Subject: [PATCH 22/40] remove useless code churn remove useless type --- src/use_mouse.rs | 32 +++++++++++++++----------------- src/use_mouse_in_element.rs | 2 +- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/use_mouse.rs b/src/use_mouse.rs index 8e61eaa..337523c 100644 --- a/src/use_mouse.rs +++ b/src/use_mouse.rs @@ -276,27 +276,25 @@ pub trait UseMouseEventExtractor { impl UseMouseEventExtractor for UseMouseCoordType { fn extract_mouse_coords(&self, event: &web_sys::MouseEvent) -> Option<(f64, f64)> { - Some(match self { - UseMouseCoordType::Page => (event.page_x() as f64, event.page_y() as f64), - UseMouseCoordType::Client => (event.client_x() as f64, event.client_y() as f64), - UseMouseCoordType::Screen => (event.screen_x() as f64, event.client_y() as f64), - UseMouseCoordType::Movement => (event.movement_x() as f64, event.movement_y() as f64), - UseMouseCoordType::Custom(ref extractor) => { - return extractor.extract_mouse_coords(event) + match self { + UseMouseCoordType::Page => Some((event.page_x() as f64, event.page_y() as f64)), + UseMouseCoordType::Client => Some((event.client_x() as f64, event.client_y() as f64)), + UseMouseCoordType::Screen => Some((event.screen_x() as f64, event.client_y() as f64)), + UseMouseCoordType::Movement => { + Some((event.movement_x() as f64, event.movement_y() as f64)) } - }) + UseMouseCoordType::Custom(ref extractor) => extractor.extract_mouse_coords(event), + } } fn extract_touch_coords(&self, touch: &web_sys::Touch) -> Option<(f64, f64)> { - Some(match self { - UseMouseCoordType::Page => (touch.page_x() as f64, touch.page_y() as f64), - UseMouseCoordType::Client => (touch.client_x() as f64, touch.client_y() as f64), - UseMouseCoordType::Screen => (touch.screen_x() as f64, touch.client_y() as f64), - UseMouseCoordType::Movement => return None, - UseMouseCoordType::Custom(ref extractor) => { - return extractor.extract_touch_coords(touch) - } - }) + match self { + UseMouseCoordType::Page => Some((touch.page_x() as f64, touch.page_y() as f64)), + UseMouseCoordType::Client => Some((touch.client_x() as f64, touch.client_y() as f64)), + UseMouseCoordType::Screen => Some((touch.screen_x() as f64, touch.client_y() as f64)), + UseMouseCoordType::Movement => None, + UseMouseCoordType::Custom(ref extractor) => extractor.extract_touch_coords(touch), + } } } diff --git a/src/use_mouse_in_element.rs b/src/use_mouse_in_element.rs index 8b37f4d..c3d23ae 100644 --- a/src/use_mouse_in_element.rs +++ b/src/use_mouse_in_element.rs @@ -199,7 +199,7 @@ where impl Default for UseMouseInElementOptions { fn default() -> Self { Self { - coord_type: UseMouseCoordType::::default(), + coord_type: UseMouseCoordType::default(), target: use_window(), touch: true, reset_on_touch_ends: false, From 6d0e946b5ac86eecab8f1a19085be3b342aa6132 Mon Sep 17 00:00:00 2001 From: Baptiste Date: Tue, 13 Aug 2024 02:40:46 +0200 Subject: [PATCH 23/40] fixed a error for a match on a non exhaustive enum --- src/use_web_notification.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/use_web_notification.rs b/src/use_web_notification.rs index 01098a4..9d396c9 100644 --- a/src/use_web_notification.rs +++ b/src/use_web_notification.rs @@ -481,7 +481,7 @@ impl From for NotificationPermission { web_sys::NotificationPermission::Default => Self::Default, web_sys::NotificationPermission::Granted => Self::Granted, web_sys::NotificationPermission::Denied => Self::Denied, - web_sys::NotificationPermission::__Nonexhaustive => Self::Default, + _ => Self::Default, } } } From 294cbaf222257f49104f60463a5ba858d2e0153a Mon Sep 17 00:00:00 2001 From: Maccesch Date: Tue, 13 Aug 2024 02:10:35 +0100 Subject: [PATCH 24/40] updated to latest version of web_sys --- Cargo.toml | 4 ++-- src/use_clipboard.rs | 18 ++++++++---------- src/use_event_listener.rs | 8 ++++---- src/use_event_source.rs | 4 ++-- src/use_mutation_observer.rs | 16 ++++++++-------- src/use_resize_observer.rs | 4 ++-- src/use_web_notification.rs | 21 ++++++++++----------- 7 files changed, 36 insertions(+), 39 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 870af1a..6a18c69 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "leptos-use" -version = "0.11.4" +version = "0.11.5" edition = "2021" authors = ["Marc-Stefan Cassola"] categories = ["gui", "web-programming"] @@ -37,7 +37,7 @@ wasm-bindgen = "0.2.92" wasm-bindgen-futures = "0.4" [dependencies.web-sys] -version = "0.3" +version = ">=0.3.70" features = [ "AddEventListenerOptions", "BinaryType", diff --git a/src/use_clipboard.rs b/src/use_clipboard.rs index c6f1efe..f33cfd6 100644 --- a/src/use_clipboard.rs +++ b/src/use_clipboard.rs @@ -79,10 +79,9 @@ pub fn use_clipboard_with_options( let update_text = move |_| { if is_supported.get() { spawn_local(async move { - if let Some(clipboard) = window().navigator().clipboard() { - if let Ok(text) = js_fut!(clipboard.read_text()).await { - set_text.set(text.as_string()); - } + let clipboard = window().navigator().clipboard(); + if let Ok(text) = js_fut!(clipboard.read_text()).await { + set_text.set(text.as_string()); } }) } @@ -102,12 +101,11 @@ pub fn use_clipboard_with_options( let value = value.to_owned(); spawn_local(async move { - if let Some(clipboard) = window().navigator().clipboard() { - if js_fut!(clipboard.write_text(&value)).await.is_ok() { - set_text.set(Some(value)); - set_copied.set(true); - start(()); - } + let clipboard = window().navigator().clipboard(); + if js_fut!(clipboard.write_text(&value)).await.is_ok() { + set_text.set(Some(value)); + set_copied.set(true); + start(()); } }); } diff --git a/src/use_event_listener.rs b/src/use_event_listener.rs index 68ff33d..8f35a51 100644 --- a/src/use_event_listener.rs +++ b/src/use_event_listener.rs @@ -235,11 +235,11 @@ impl UseEventListenerOptions { passive, } = self; - let mut options = web_sys::AddEventListenerOptions::new(); - options.capture(*capture); - options.once(*once); + let options = web_sys::AddEventListenerOptions::new(); + options.set_capture(*capture); + options.set_once(*once); if let Some(passive) = passive { - options.passive(*passive); + options.set_passive(*passive); } options diff --git a/src/use_event_source.rs b/src/use_event_source.rs index 7cf049b..09539e7 100644 --- a/src/use_event_source.rs +++ b/src/use_event_source.rs @@ -183,8 +183,8 @@ where return; } - let mut event_src_opts = web_sys::EventSourceInit::new(); - event_src_opts.with_credentials(with_credentials); + let event_src_opts = web_sys::EventSourceInit::new(); + event_src_opts.set_with_credentials(with_credentials); let es = web_sys::EventSource::new_with_event_source_init_dict(&url, &event_src_opts) .unwrap_throw(); diff --git a/src/use_mutation_observer.rs b/src/use_mutation_observer.rs index c165c09..813ce4f 100644 --- a/src/use_mutation_observer.rs +++ b/src/use_mutation_observer.rs @@ -214,20 +214,20 @@ impl From for web_sys::MutationObserverInit { character_data_old_value, } = val; - let mut init = Self::new(); + let init = Self::new(); - init.subtree(subtree) - .child_list(child_list) - .attributes(attributes) - .attribute_old_value(attribute_old_value) - .character_data_old_value(character_data_old_value); + init.set_subtree(subtree); + init.set_child_list(child_list); + init.set_attributes(attributes); + init.set_attribute_old_value(attribute_old_value); + init.set_character_data_old_value(character_data_old_value); if let Some(attribute_filter) = attribute_filter { let array = js_sys::Array::from_iter(attribute_filter.into_iter().map(JsValue::from)); - init.attribute_filter(array.unchecked_ref()); + init.set_attribute_filter(array.unchecked_ref()); } if let Some(character_data) = character_data { - init.character_data(character_data); + init.set_character_data(character_data); } init diff --git a/src/use_resize_observer.rs b/src/use_resize_observer.rs index 3a631ca..154f3c2 100644 --- a/src/use_resize_observer.rs +++ b/src/use_resize_observer.rs @@ -171,8 +171,8 @@ pub struct UseResizeObserverOptions { impl From for web_sys::ResizeObserverOptions { fn from(val: UseResizeObserverOptions) -> Self { - let mut options = web_sys::ResizeObserverOptions::new(); - options.box_( + let options = web_sys::ResizeObserverOptions::new(); + options.set_box( val.box_ .unwrap_or(web_sys::ResizeObserverBoxOptions::ContentBox), ); diff --git a/src/use_web_notification.rs b/src/use_web_notification.rs index 9d396c9..b73ff14 100644 --- a/src/use_web_notification.rs +++ b/src/use_web_notification.rs @@ -318,32 +318,31 @@ impl Default for UseWebNotificationOptions { impl From<&UseWebNotificationOptions> for web_sys::NotificationOptions { fn from(options: &UseWebNotificationOptions) -> Self { - let mut web_sys_options = Self::new(); + let web_sys_options = Self::new(); - web_sys_options - .dir(options.direction.into()) - .require_interaction(options.require_interaction) - .renotify(options.renotify) - .silent(options.silent); + web_sys_options.set_dir(options.direction.into()); + web_sys_options.set_require_interaction(options.require_interaction); + web_sys_options.set_renotify(options.renotify); + web_sys_options.set_silent(options.silent); if let Some(body) = &options.body { - web_sys_options.body(body); + web_sys_options.set_body(body); } if let Some(icon) = &options.icon { - web_sys_options.icon(icon); + web_sys_options.set_icon(icon); } if let Some(image) = &options.image { - web_sys_options.image(image); + web_sys_options.set_image(image); } if let Some(language) = &options.language { - web_sys_options.lang(language); + web_sys_options.set_lang(language); } if let Some(tag) = &options.tag { - web_sys_options.tag(tag); + web_sys_options.set_tag(tag); } web_sys_options From 1c9bbb6b08959f1a1600beecdf704b0a25b47ce3 Mon Sep 17 00:00:00 2001 From: Maccesch Date: Tue, 13 Aug 2024 02:17:50 +0100 Subject: [PATCH 25/40] clipboard is no longer behind unstable flags --- CHANGELOG.md | 7 +++++++ examples/use_clipboard/.cargo/config.toml | 2 -- src/lib.rs | 7 ++----- src/use_clipboard.rs | 3 --- 4 files changed, 9 insertions(+), 10 deletions(-) delete mode 100644 examples/use_clipboard/.cargo/config.toml diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b7a398..9871816 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,13 @@ 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). +## [Unreleased] - + +### Breaking Changes 🛠 + +- Updated to web_sys 0.3.70 which unfortunately is breaking some things. +- `use_clipboard` doesn't need the unstable flags anymore. + ## [0.11.4] - 2024-08-12 ### New Features 🚀 diff --git a/examples/use_clipboard/.cargo/config.toml b/examples/use_clipboard/.cargo/config.toml deleted file mode 100644 index 8467175..0000000 --- a/examples/use_clipboard/.cargo/config.toml +++ /dev/null @@ -1,2 +0,0 @@ -[build] -rustflags = ["--cfg=web_sys_unstable_apis"] diff --git a/src/lib.rs b/src/lib.rs index 9ad5b9b..efe5187 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,11 +15,6 @@ pub mod utils; // #[cfg(web_sys_unstable_apis)] // pub use use_webtransport::*; -#[cfg(web_sys_unstable_apis)] -mod use_clipboard; -#[cfg(web_sys_unstable_apis)] -pub use use_clipboard::*; - mod is_err; mod is_none; mod is_ok; @@ -31,6 +26,7 @@ mod sync_signal; mod use_active_element; mod use_breakpoints; mod use_broadcast_channel; +mod use_clipboard; mod use_color_mode; mod use_cookie; mod use_css_var; @@ -99,6 +95,7 @@ pub use sync_signal::*; pub use use_active_element::*; pub use use_breakpoints::*; pub use use_broadcast_channel::*; +pub use use_clipboard::*; pub use use_color_mode::*; pub use use_cookie::*; pub use use_css_var::*; diff --git a/src/use_clipboard.rs b/src/use_clipboard.rs index f33cfd6..0bd0e03 100644 --- a/src/use_clipboard.rs +++ b/src/use_clipboard.rs @@ -10,9 +10,6 @@ use leptos::*; /// [Permissions API](https://developer.mozilla.org/en-US/docs/Web/API/Permissions_API). /// Without user permission, reading or altering the clipboard contents is not permitted. /// -/// > This function requires `--cfg=web_sys_unstable_apis` to be activated as -/// > [described in the wasm-bindgen guide](https://rustwasm.github.io/docs/wasm-bindgen/web-sys/unstable-apis.html). -/// /// ## Demo /// /// [Link to Demo](https://github.com/Synphonyte/leptos-use/tree/main/examples/use_clipboard) From d4330c9fb17b790d46411b26697d2ea8dd531679 Mon Sep 17 00:00:00 2001 From: Maccesch Date: Tue, 13 Aug 2024 13:45:36 +0100 Subject: [PATCH 26/40] use_local now uses LanguageIdentifier and proper matching. Also removed a bunch of deprecated warnings. Closes #144 --- CHANGELOG.md | 1 + Cargo.toml | 6 +++-- examples/use_locale/Cargo.toml | 1 + examples/use_locale/src/main.rs | 5 ++-- src/storage/use_storage.rs | 4 +-- src/use_display_media.rs | 4 +-- src/use_geolocation.rs | 8 +++--- src/use_intersection_observer.rs | 7 ++--- src/use_locale.rs | 45 ++++++++++++++++++++------------ src/use_scroll.rs | 8 +++--- src/use_user_media.rs | 6 ++--- src/use_web_notification.rs | 18 ++++++------- 12 files changed, 66 insertions(+), 47 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9871816..9d114a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Updated to web_sys 0.3.70 which unfortunately is breaking some things. - `use_clipboard` doesn't need the unstable flags anymore. +- `use_local` now uses `unic_langid::LanguageIdentifier` and proper locale matching (thanks to @mondeja). ## [0.11.4] - 2024-08-12 diff --git a/Cargo.toml b/Cargo.toml index 6a18c69..cf8fd6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,8 @@ leptos-spin = { version = "0.1", optional = true } num = { version = "0.4", optional = true } paste = "1" thiserror = "1" -wasm-bindgen = "0.2.92" +unic-langid = "0.9" +wasm-bindgen = ">=0.2.93" wasm-bindgen-futures = "0.4" [dependencies.web-sys] @@ -129,11 +130,12 @@ features = [ ] [dev-dependencies] +codee = { version = "0.1", features = ["json_serde", "msgpack_serde", "base64", "prost"] } getrandom = { version = "0.2", features = ["js"] } leptos_meta = "0.6" rand = "0.8" -codee = { version = "0.1", features = ["json_serde", "msgpack_serde", "base64", "prost"] } serde = { version = "1", features = ["derive"] } +unic-langid = { version = "0.9", features = ["macros"] } [features] actix = ["dep:actix-web", "dep:leptos_actix", "dep:http0_2"] diff --git a/examples/use_locale/Cargo.toml b/examples/use_locale/Cargo.toml index eb1cdfd..1a2555a 100644 --- a/examples/use_locale/Cargo.toml +++ b/examples/use_locale/Cargo.toml @@ -9,6 +9,7 @@ console_error_panic_hook = "0.1" console_log = "1" log = "0.4" leptos-use = { path = "../..", features = ["docs"] } +unic-langid = { version = "0.9", features = ["macros"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_locale/src/main.rs b/examples/use_locale/src/main.rs index 36e132c..a0fe2a6 100644 --- a/examples/use_locale/src/main.rs +++ b/examples/use_locale/src/main.rs @@ -1,13 +1,14 @@ use leptos::*; use leptos_use::docs::demo_or_body; use leptos_use::use_locale; +use unic_langid::langid_slice; #[component] fn Demo() -> impl IntoView { - let locale = use_locale(["en", "de", "fr"]); + let locale = use_locale(langid_slice!["en", "de", "fr"]); view! { -

Locale: {locale}

+

Locale: {move || locale.get().to_string()}

} } diff --git a/src/storage/use_storage.rs b/src/storage/use_storage.rs index 0d8f903..91b56c0 100644 --- a/src/storage/use_storage.rs +++ b/src/storage/use_storage.rs @@ -215,8 +215,8 @@ where queue_microtask(move || { // TODO : better to use a BroadcastChannel (use_broadcast_channel)? // Note: we cannot construct a full StorageEvent so we _must_ rely on a custom event - let mut custom = web_sys::CustomEventInit::new(); - custom.detail(&JsValue::from_str(&key)); + let custom = web_sys::CustomEventInit::new(); + custom.set_detail(&JsValue::from_str(&key)); let result = window() .dispatch_event( &web_sys::CustomEvent::new_with_event_init_dict( diff --git a/src/use_display_media.rs b/src/use_display_media.rs index 8174fba..a89d9c2 100644 --- a/src/use_display_media.rs +++ b/src/use_display_media.rs @@ -131,9 +131,9 @@ async fn create_media(audio: bool) -> Result { .ok_or_else(|| JsValue::from_str("Failed to access window.navigator")) .and_then(|n| n.media_devices())?; - let mut constraints = web_sys::DisplayMediaStreamConstraints::new(); + let constraints = web_sys::DisplayMediaStreamConstraints::new(); if audio { - constraints.audio(&JsValue::from(true)); + constraints.set_audio(&JsValue::from(true)); } let promise = media.get_display_media_with_constraints(&constraints)?; diff --git a/src/use_geolocation.rs b/src/use_geolocation.rs index 2aeda83..7494ef3 100644 --- a/src/use_geolocation.rs +++ b/src/use_geolocation.rs @@ -186,10 +186,10 @@ impl UseGeolocationOptions { .. } = self; - let mut options = web_sys::PositionOptions::new(); - options.enable_high_accuracy(*enable_high_accuracy); - options.maximum_age(*maximum_age); - options.timeout(*timeout); + let options = web_sys::PositionOptions::new(); + options.set_enable_high_accuracy(*enable_high_accuracy); + options.set_maximum_age(*maximum_age); + options.set_timeout(*timeout); options } diff --git a/src/use_intersection_observer.rs b/src/use_intersection_observer.rs index cca3343..f17f1f3 100644 --- a/src/use_intersection_observer.rs +++ b/src/use_intersection_observer.rs @@ -154,8 +154,9 @@ where return; } - let mut options = web_sys::IntersectionObserverInit::new(); - options.root_margin(&root_margin).threshold( + let options = web_sys::IntersectionObserverInit::new(); + options.set_root_margin(&root_margin); + options.set_threshold( &thresholds .iter() .copied() @@ -165,7 +166,7 @@ where if let Some(Some(root)) = root { let root: web_sys::Element = root.clone().into(); - options.root(Some(&root)); + options.set_root(Some(&root)); } let obs = web_sys::IntersectionObserver::new_with_options( diff --git a/src/use_locale.rs b/src/use_locale.rs index 7b31825..be781a4 100644 --- a/src/use_locale.rs +++ b/src/use_locale.rs @@ -1,14 +1,16 @@ use crate::{use_locales_with_options, UseLocalesOptions}; use leptos::*; +use unic_langid::LanguageIdentifier; /// Reactive locale matching. /// /// Returns the first matching locale given by [`fn@crate::use_locales`] that is also found in /// the `supported` list. In case there is no match, then the first locale in `supported` will be -/// returned. If `supported` is empty, the empty string is returned. +/// returned. /// -/// Matching is done by checking if an accepted locale from `use_locales` starts with a supported -/// locale. If a match is found the locale from the `supported` list is returned. +/// > If `supported` is empty, this function will panic! +/// +/// Matching is done by using the [`fn@unic_langid::LanguageIdentifier::matches`] method. /// /// ## Demo /// @@ -19,10 +21,11 @@ use leptos::*; /// ``` /// # use leptos::*; /// # use leptos_use::use_locale; +/// use unic_langid::langid_slice; /// # /// # #[component] /// # fn Demo() -> impl IntoView { -/// let locale = use_locale(["en", "de", "fr"]); +/// let locale = use_locale(langid_slice!["en", "de", "fr"]); /// # /// # view! { } /// # } @@ -31,45 +34,55 @@ use leptos::*; /// ## Server-Side Rendering /// /// See [`fn@crate::use_locales`] -pub fn use_locale(supported: S) -> Signal +pub fn use_locale(supported: S) -> Signal where S: IntoIterator, - S::Item: Into + Clone + 'static, + S::Item: AsRef, { use_locale_with_options(supported, UseLocaleOptions::default()) } /// Version of [`fn@crate::use_locale`] that takes a `UseLocaleOptions`. See [`fn@crate::use_locale`] for how to use. -pub fn use_locale_with_options(supported: S, options: UseLocaleOptions) -> Signal +pub fn use_locale_with_options( + supported: S, + options: UseLocaleOptions, +) -> Signal where S: IntoIterator, - S::Item: Into + Clone + 'static, + S::Item: AsRef, { - let locales = use_locales_with_options(options); + let client_locales = use_locales_with_options(options); - let supported = supported.into_iter().collect::>(); + let supported = supported + .into_iter() + .map(|l| l.as_ref().clone()) + .collect::>(); + + const EMPTY_ERR_MSG: &'static str = "Empty supported list. You have to provide at least one locale in the `supported` parameter"; + assert!(supported.len() > 0, "{}", EMPTY_ERR_MSG); Signal::derive(move || { let supported = supported.clone(); - locales.with(|locales| { + client_locales.with(|clienht_locales| { let mut first_supported = None; for s in supported { - let s = s.into(); - if first_supported.is_none() { first_supported = Some(s.clone()); } - for locale in locales { - if locale.starts_with(&s) { + for client_locale in clienht_locales { + let client_locale: LanguageIdentifier = client_locale + .parse() + .expect("Client should provide a list of valid unicode locales"); + if client_locale.matches(&s, true, true) { return s; } } } - first_supported.unwrap_or_else(|| "".to_string()) + unreachable!("{}", EMPTY_ERR_MSG); }) }) } diff --git a/src/use_scroll.rs b/src/use_scroll.rs index 9db4ab1..8c0fc80 100644 --- a/src/use_scroll.rs +++ b/src/use_scroll.rs @@ -231,14 +231,14 @@ where if let Some(element) = element { let element = element.into(); - let mut scroll_options = web_sys::ScrollToOptions::new(); - scroll_options.behavior(behavior.get_untracked().into()); + let scroll_options = web_sys::ScrollToOptions::new(); + scroll_options.set_behavior(behavior.get_untracked().into()); if let Some(x) = x { - scroll_options.left(x); + scroll_options.set_left(x); } if let Some(y) = y { - scroll_options.top(y); + scroll_options.set_top(y); } element.scroll_to_with_scroll_to_options(&scroll_options); diff --git a/src/use_user_media.rs b/src/use_user_media.rs index 2336f38..76b1eed 100644 --- a/src/use_user_media.rs +++ b/src/use_user_media.rs @@ -136,12 +136,12 @@ async fn create_media(video: bool, audio: bool) -> Result Date: Tue, 13 Aug 2024 13:47:07 +0100 Subject: [PATCH 27/40] typo --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d114a9..3e064c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Updated to web_sys 0.3.70 which unfortunately is breaking some things. - `use_clipboard` doesn't need the unstable flags anymore. -- `use_local` now uses `unic_langid::LanguageIdentifier` and proper locale matching (thanks to @mondeja). +- `use_locale` now uses `unic_langid::LanguageIdentifier` and proper locale matching (thanks to @mondeja). ## [0.11.4] - 2024-08-12 From b1367a9f0b81d93d47105c29fef5ea0c59241dbc Mon Sep 17 00:00:00 2001 From: Maccesch Date: Tue, 13 Aug 2024 13:56:13 +0100 Subject: [PATCH 28/40] chore: clippy --- src/use_locale.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/use_locale.rs b/src/use_locale.rs index be781a4..ff69e7f 100644 --- a/src/use_locale.rs +++ b/src/use_locale.rs @@ -58,13 +58,13 @@ where .map(|l| l.as_ref().clone()) .collect::>(); - const EMPTY_ERR_MSG: &'static str = "Empty supported list. You have to provide at least one locale in the `supported` parameter"; - assert!(supported.len() > 0, "{}", EMPTY_ERR_MSG); + const EMPTY_ERR_MSG: & str = "Empty supported list. You have to provide at least one locale in the `supported` parameter"; + assert!(!supported.is_empty(), "{}", EMPTY_ERR_MSG); Signal::derive(move || { let supported = supported.clone(); - client_locales.with(|clienht_locales| { + client_locales.with(|client_locales| { let mut first_supported = None; for s in supported { @@ -72,7 +72,7 @@ where first_supported = Some(s.clone()); } - for client_locale in clienht_locales { + for client_locale in client_locales { let client_locale: LanguageIdentifier = client_locale .parse() .expect("Client should provide a list of valid unicode locales"); From 26a2dc0e4b9f267b2062215184ed3022883979a7 Mon Sep 17 00:00:00 2001 From: Maccesch Date: Tue, 13 Aug 2024 16:19:19 +0100 Subject: [PATCH 29/40] added support for Sec-CH-Prefers-Color-Scheme header. Fixes #101 Relates to #121 --- CHANGELOG.md | 1 + Cargo.toml | 4 +-- examples/ssr/Cargo.toml | 3 +- examples/ssr/src/main.rs | 11 ++++++- src/use_color_mode.rs | 47 +++++++++++++++++++++++++---- src/use_locales.rs | 2 +- src/use_preferred_dark.rs | 62 +++++++++++++++++++++++++++++++++++++-- src/utils/header_macro.rs | 15 ++++++---- 8 files changed, 127 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e064c5..8cae4d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Updated to web_sys 0.3.70 which unfortunately is breaking some things. - `use_clipboard` doesn't need the unstable flags anymore. - `use_locale` now uses `unic_langid::LanguageIdentifier` and proper locale matching (thanks to @mondeja). +- `use_preferred_dark` and `use_color_mode` now try to read the `Sec-CH-Prefers-Color-Scheme` header in SSR. ## [0.11.4] - 2024-08-12 diff --git a/Cargo.toml b/Cargo.toml index cf8fd6e..2fd0ca0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,11 +34,11 @@ num = { version = "0.4", optional = true } paste = "1" thiserror = "1" unic-langid = "0.9" -wasm-bindgen = ">=0.2.93" +wasm-bindgen = "=0.2.93" wasm-bindgen-futures = "0.4" [dependencies.web-sys] -version = ">=0.3.70" +version = "=0.3.70" features = [ "AddEventListenerOptions", "BinaryType", diff --git a/examples/ssr/Cargo.toml b/examples/ssr/Cargo.toml index 5d71626..533ce90 100644 --- a/examples/ssr/Cargo.toml +++ b/examples/ssr/Cargo.toml @@ -21,8 +21,9 @@ log = "0.4" simple_logger = "4" tokio = { version = "1", features = ["full"], optional = true } tower = { version = "0.4", optional = true } +tower-default-headers = { git = "https://github.com/banool/tower-default-headers-rs" } tower-http = { version = "0.5", features = ["fs"], optional = true } -wasm-bindgen = "0.2.92" +wasm-bindgen = "=0.2.93" thiserror = "1.0.38" tracing = { version = "0.1.37", optional = true } http = "1" diff --git a/examples/ssr/src/main.rs b/examples/ssr/src/main.rs index 4d92392..ff4f4bb 100644 --- a/examples/ssr/src/main.rs +++ b/examples/ssr/src/main.rs @@ -2,11 +2,13 @@ #[tokio::main] async fn main() { use axum::{routing::post, Router}; + use http::{HeaderMap, HeaderName, HeaderValue}; use leptos::logging::log; use leptos::*; 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::Info).expect("couldn't initialize logging"); @@ -20,12 +22,19 @@ async fn main() { let addr = leptos_options.site_addr; let routes = generate_route_list(|| view! { }); + 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); + // 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! { }) .fallback(file_and_error_handler) - .with_state(leptos_options); + .with_state(leptos_options) + .layer(DefaultHeadersLayer::new(default_headers)); let listener = tokio::net::TcpListener::bind(&addr).await.unwrap(); log!("listening on http://{}", &addr); diff --git a/src/use_color_mode.rs b/src/use_color_mode.rs index 1df636b..99a688e 100644 --- a/src/use_color_mode.rs +++ b/src/use_color_mode.rs @@ -2,7 +2,11 @@ use crate::core::url; use crate::core::StorageType; use crate::core::{ElementMaybeSignal, MaybeRwSignal}; use crate::storage::{use_storage_with_options, UseStorageOptions}; -use crate::{sync_signal_with_options, use_cookie, use_preferred_dark, SyncSignalOptions}; +use crate::utils::get_header; +use crate::{ + sync_signal_with_options, use_cookie, use_preferred_dark_with_options, + SyncSignalOptions, UsePreferredDarkOptions, +}; use codee::string::FromToStringCodec; use default_struct_builder::DefaultBuilder; use leptos::*; @@ -83,7 +87,7 @@ use wasm_bindgen::JsCast; /// # } /// ``` /// -/// ### Cookies +/// ### Cookie /// /// To persist color mode in a cookie, use `use_cookie_with_options` and specify `.cookie_enabled(true)`. /// @@ -112,9 +116,24 @@ use wasm_bindgen::JsCast; /// /// ## Server-Side Rendering /// -/// On the server this will by default return `ColorMode::Light`. Persistence with storage is disabled. +/// On the server this will try to read the +/// [`Sec-CH-Prefers-Color-Scheme` header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-CH-Prefers-Color-Scheme) +/// to determine the color mode. If the header is not present it will return `ColorMode::Light`. +/// Please have a look at the linked documentation above for that header to see browser support +/// as well as potential server requirements. /// -/// If `cookie_enabled` is set to `true`, cookies will be used and if present this value will be used +/// > If you're using `axum` you have to enable the `"axum"` feature in your Cargo.toml. +/// > In case it's `actix-web` enable the feature `"actix"`, for `spin` enable `"spin"`. +/// +/// ### Bring your own header +/// +/// In case you're neither using Axum, Actix nor Spin, or the default implementation is not to your liking, +/// you can provide your own way of reading the color scheme header value using the option +/// [`crate::UseColorModeOptions::ssr_color_header_getter`]. +/// +/// ### Cookie +/// +/// If `cookie_enabled` is set to `true`, a cookie will be used and if present this value will be used /// on the server as well as on the client. Please note that you have to add the `axum` or `actix` /// feature as described in [`fn@crate::use_cookie`]. /// @@ -151,6 +170,7 @@ where emit_auto, transition_enabled, listen_to_storage_changes, + ssr_color_header_getter, _marker, } = options; @@ -162,7 +182,9 @@ where ]) .collect(); - let preferred_dark = use_preferred_dark(); + let preferred_dark = use_preferred_dark_with_options(UsePreferredDarkOptions { + ssr_color_header_getter, + }); let system = Signal::derive(move || { if preferred_dark.get() { @@ -471,6 +493,14 @@ where /// Defaults to true. listen_to_storage_changes: bool, + /// Getter function to return the string value of the + /// [`Sec-CH-Prefers-Color-Scheme`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-CH-Prefers-Color-Scheme) + /// header. + /// When you use one of the features `"axum"`, `"actix"` or `"spin"` there's a valid default + /// implementation provided. + #[allow(dead_code)] + ssr_color_header_getter: Rc Option>, + #[builder(skip)] _marker: PhantomData, } @@ -496,6 +526,13 @@ impl Default for UseColorModeOptions<&'static str, web_sys::Element> { emit_auto: false, transition_enabled: false, listen_to_storage_changes: true, + ssr_color_header_getter: Rc::new(move || { + get_header!( + HeaderName::from_static("sec-ch-prefers-color-scheme"), + use_locale, + ssr_color_header_getter + ) + }), _marker: PhantomData, } } diff --git a/src/use_locales.rs b/src/use_locales.rs index 4e4f567..8762dc5 100644 --- a/src/use_locales.rs +++ b/src/use_locales.rs @@ -39,7 +39,7 @@ use std::rc::Rc; /// ### Bring your own header /// /// In case you're neither using Axum, Actix nor Spin, or the default implementation is not to your liking, -/// you can provide your own way of reading and writing the cookie header value using the option +/// you can provide your own way of reading the language header value using the option /// [`crate::UseLocalesOptions::ssr_lang_header_getter`]. pub fn use_locales() -> Signal> { use_locales_with_options(UseLocalesOptions::default()) diff --git a/src/use_preferred_dark.rs b/src/use_preferred_dark.rs index 18d8043..ad64f13 100644 --- a/src/use_preferred_dark.rs +++ b/src/use_preferred_dark.rs @@ -1,5 +1,7 @@ -use crate::use_media_query; +use crate::utils::get_header; +use default_struct_builder::DefaultBuilder; use leptos::*; +use std::rc::Rc; /// Reactive [dark theme preference](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme). /// @@ -20,12 +22,66 @@ use leptos::*; /// /// ## Server-Side Rendering /// -/// On the server this functions returns a Signal that is always `false`. +/// On the server this will try to read the +/// [`Sec-CH-Prefers-Color-Scheme` header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-CH-Prefers-Color-Scheme) +/// to determine the color mode. If the header is not present it will return `ColorMode::Light`. +/// Please have a look at the linked documentation above for that header to see browser support +/// as well as potential server requirements. +/// +/// > If you're using `axum` you have to enable the `"axum"` feature in your Cargo.toml. +/// > In case it's `actix-web` enable the feature `"actix"`, for `spin` enable `"spin"`. +/// +/// ### Bring your own header +/// +/// In case you're neither using Axum, Actix nor Spin, or the default implementation is not to your liking, +/// you can provide your own way of reading the color scheme header value using the option +/// [`crate::UsePreferredDarkOptions::ssr_color_header_getter`]. /// /// ## See also /// /// * [`fn@crate::use_media_query`] /// * [`fn@crate::use_preferred_contrast`] pub fn use_preferred_dark() -> Signal { - use_media_query("(prefers-color-scheme: dark)") + use_preferred_dark_with_options(Default::default()) +} + +/// Version of [`fn@crate::use_preferred_dark`] that accepts a `UsePreferredDarkOptions`. +pub fn use_preferred_dark_with_options(options: UsePreferredDarkOptions) -> Signal { + #[cfg(not(feature = "ssr"))] + { + let _ = options; + + crate::use_media_query("(prefers-color-scheme: dark)") + } + + #[cfg(feature = "ssr")] + { + Signal::derive(move || (options.ssr_color_header_getter)() == Some("dark".to_string())) + } +} + +/// Options for [`fn@crate::use_preferred_dark_with_options`]. +#[derive(DefaultBuilder)] +pub struct UsePreferredDarkOptions { + /// Getter function to return the string value of the + /// [`Sec-CH-Prefers-Color-Scheme`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-CH-Prefers-Color-Scheme) + /// header. + /// When you use one of the features `"axum"`, `"actix"` or `"spin"` there's a valid default + /// implementation provided. + #[allow(dead_code)] + pub(crate) ssr_color_header_getter: Rc Option>, +} + +impl Default for UsePreferredDarkOptions { + fn default() -> Self { + Self { + ssr_color_header_getter: Rc::new(move || { + get_header!( + HeaderName::from_static("sec-ch-prefers-color-scheme"), + use_locale, + ssr_color_header_getter + ) + }), + } + } } diff --git a/src/utils/header_macro.rs b/src/utils/header_macro.rs index 2cb0b52..59dab10 100644 --- a/src/utils/header_macro.rs +++ b/src/utils/header_macro.rs @@ -1,6 +1,6 @@ macro_rules! get_header { ( - $header_name:ident, + $header_name:expr, $function_name:ident, $option_name:ident $(,)? @@ -19,14 +19,19 @@ macro_rules! get_header { ); return None; } - + #[cfg(feature = "actix")] - const $header_name: http0_2::HeaderName = http0_2::header::$header_name; + #[allow(unused_imports)] + use http0_2::{HeaderName, header::*}; #[cfg(any(feature = "axum", feature = "spin"))] - const $header_name: http1::HeaderName = http1::header::$header_name; + #[allow(unused_imports)] + use http1::{HeaderName, header::*}; #[cfg(any(feature = "axum", feature = "actix", feature = "spin"))] - crate::utils::header($header_name) + { + let header_name = $header_name; + crate::utils::header(header_name) + } } else { None } From 16a65b100d9adb8f568fcc785bbe9fa43e1ac8d8 Mon Sep 17 00:00:00 2001 From: Maccesch Date: Tue, 13 Aug 2024 18:32:50 +0100 Subject: [PATCH 30/40] fixed the codecs chapter in the book to refer to crate codee --- docs/book/src/codecs.md | 130 ++++------------------------------------ 1 file changed, 13 insertions(+), 117 deletions(-) diff --git a/docs/book/src/codecs.md b/docs/book/src/codecs.md index 2e54fa2..45b2219 100644 --- a/docs/book/src/codecs.md +++ b/docs/book/src/codecs.md @@ -1,9 +1,9 @@ # Encoding and Decoding Data Several functions encode and decode data for storing it and/or sending it over the network. To do this, codecs -located at [`src/utils/codecs`](https://github.com/Synphonyte/leptos-use/tree/main/src/utils/codecs) are used. They -implement the traits [`Encoder`](https://github.com/Synphonyte/leptos-use/blob/main/src/utils/codecs/mod.rs#L9) with the -method `encode` and [`Decoder`](https://github.com/Synphonyte/leptos-use/blob/main/src/utils/codecs/mod.rs#L17) with the +from the crate [`codee`](https://docs.rs/codee/latest/codee/) are used. They +implement the traits [`Encoder`](https://docs.rs/codee/latest/codee/trait.Encoder.html) with the +method `encode` and [`Decoder`](https://docs.rs/codee/latest/codee/trait.Decoder.html) with the method `decode`. There are two types of codecs: One that encodes as binary data (`Vec[u8]`) and another type that encodes as @@ -11,26 +11,8 @@ strings (`String`). There is also an adapter [`Base64`](https://github.com/Synphonyte/leptos-use/blob/main/src/utils/codecs/string/base64.rs) that can be used to wrap a binary codec and make it a string codec by representing the binary data as a base64 string. -## Available Codecs - -### String Codecs - -- [**`FromToStringCodec` - **](https://github.com/Synphonyte/leptos-use/blob/main/src/utils/codecs/string/from_to_string.rs) -- [**`JsonSerdeCodec`**](https://github.com/Synphonyte/leptos-use/blob/main/src/utils/codecs/string/json_serde.rs)** - -### Binary Codecs - -- [**`FromToBytesCodec`**](https://github.com/Synphonyte/leptos-use/blob/main/src/utils/codecs/binary/from_to_bytes.rs) -- [**`BincodeSerdeCodec`**](https://github.com/Synphonyte/leptos-use/blob/main/src/utils/codecs/binary/bincode_serde.rs) -- [**`MsgpackSerdeCodec`**](https://github.com/Synphonyte/leptos-use/blob/main/src/utils/codecs/binary/msgpack_serde.rs) - -### Adapters - -- [**`Base64`**](https://github.com/Synphonyte/leptos-use/blob/main/src/utils/codecs/string/base64.rs) — - Wraps a binary codec and make it a string codec by representing the binary data as a base64 string. -- [**`OptionCodec`**](https://github.com/Synphonyte/leptos-use/blob/main/src/utils/codecs/option.rs) — - Wraps a string codec that encodes `T` to create a codec that encodes `Option`. +Please check the documentation of [`codee`](https://docs.rs/codee/latest/codee/) for more details and a list of all +available codecs. ## Example @@ -41,6 +23,7 @@ format. Since cookies can only store strings, we have to use string codecs here. # use leptos::*; # use leptos_use::use_cookie; # use serde::{Deserialize, Serialize}; +# use codee::string::JsonCodec; # #[component] # pub fn App(cx: Scope) -> impl IntoView { @@ -57,100 +40,13 @@ let (cookie, set_cookie) = use_cookie::("my-state-cookie"); ## Custom Codecs -If you don't find a suitable codecs for your needs, you can implement your own; it's straightforward! If you want to -create a string codec, you can look -at [`JsonSerdeCodec`](https://github.com/Synphonyte/leptos-use/blob/main/src/utils/codecs/string/json_serde.rs). -In case it's a binary codec, have a look -at [`BincodeSerdeCodec`](https://github.com/Synphonyte/leptos-use/blob/main/src/utils/codecs/binary/bincode_serde.rs). +If you don't find a suitable codec for your needs, you can implement your own; it's straightforward! +If you want to create a string codec, you can look at +[`JsonSerdeCodec`](https://docs.rs/codee/latest/src/codee/string/json_serde.rs.html). +In case it's a binary codec, have a look at +[`BincodeSerdeCodec`](https://docs.rs/codee/latest/src/codee/binary/bincode_serde.rs.html). ## Versioning -Versioning is the process of handling long-term data that can outlive our code. - -For example, we could have a settings struct whose members change over time. We might eventually -add timezone support, and we might then remove support for a thousands separator for numbers. -Each change results in a new possible version of the stored data. If we stored these settings -in browser storage, we would need to handle all possible versions of the data format that can -occur. If we don't offer versioning, then all settings could revert to the default every time we -encounter an old format. - -How best to handle versioning depends on the codec involved: - -- The `FromToStringCodec` can avoid versioning entirely by keeping - to primitive types. In our example above, we could have decomposed the settings struct into - separate timezone and number separator fields. These would be encoded as strings and stored as - two separate key-value fields in the browser rather than a single field. If a field is missing, - then the value intentionally would fall back to the default without interfering with the other - field. - -- The `ProstCodec` uses [Protocol buffers](https://protobuf.dev/overview/) - designed to solve the problem of long-term storage. It provides semantics for versioning that - are not present in JSON or other formats. - -- The codecs that use serde under the hood can rely on serde or by - providing their own manual version handling. See the next sections for more details. - -### Rely on `serde` - -A simple way to avoid complex versioning is to rely on serde's [field attributes](https://serde.rs/field-attrs.html) -such as [`serde(default)`](https://serde.rs/field-attrs.html#default) -and [`serde(rename = "...")`](https://serde.rs/field-attrs.html#rename). - -### Manual Version Handling - -We look at the example of the `JsonSerdeCodec` in this section. - -To implement version handling, we parse the JSON generically then transform the -resulting `JsValue` before decoding it into our struct again. - -Let's look at an example. - - ```rust,noplayground - # use leptos::*; - # use leptos_use::storage::{StorageType, use_local_storage, use_session_storage, use_storage, UseStorageOptions}; - # use serde::{Deserialize, Serialize}; - # use serde_json::json; - # use leptos_use::utils::{Encoder, Decoder}; - # - # pub fn Demo() -> impl IntoView { - #[derive(Serialize, Deserialize, Clone, Default, PartialEq)] - pub struct MyState { - pub hello: String, - // This field was added in a later version - pub greeting: String, - } - - pub struct MyStateCodec; - - impl Encoder for MyStateCodec { - type Error = serde_json::Error; - type Encoded = String; - - fn encode(val: &MyState) -> Result { - serde_json::to_string(val) - } - } - - impl Decoder for MyStateCodec { - type Error = serde_json::Error; - type Encoded = str; - - fn decode(stored_value: &Self::Encoded) -> Result { - let mut val: serde_json::Value = serde_json::from_str(stored_value)?; - // add "greeting": "Hello" to the object if it's missing - if let Some(obj) = val.as_object_mut() { - if !obj.contains_key("greeting") { - obj.insert("greeting".to_string(), json!("Hello")); - } - serde_json::from_value(val) - } else { - Ok(MyState::default()) - } - } - } - - // Then use it like the following just as any other codec. - let (get, set, remove) = use_local_storage::("my-struct-key"); - # view! { } - # } - ``` +For a discussion on how to implement versioning please refer to the +[relevant section in the docs for `codee`](https://docs.rs/codee/latest/codee/index.html#versioning). \ No newline at end of file From d2e968249b370f3fc8e3d4ae2a09f401390c596c Mon Sep 17 00:00:00 2001 From: Maccesch Date: Tue, 13 Aug 2024 18:36:18 +0100 Subject: [PATCH 31/40] updated changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cae4d0..fa0ca13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `use_locale` now uses `unic_langid::LanguageIdentifier` and proper locale matching (thanks to @mondeja). - `use_preferred_dark` and `use_color_mode` now try to read the `Sec-CH-Prefers-Color-Scheme` header in SSR. +### Fixes 🍕 + +- Fixed the codec chapter in the book to refer to crate `codee`. + ## [0.11.4] - 2024-08-12 ### New Features 🚀 From f245bf07d03135259adc664f3f72a00a11367949 Mon Sep 17 00:00:00 2001 From: Charles Edward Gagnon Date: Tue, 13 Aug 2024 22:11:43 -0400 Subject: [PATCH 32/40] fix some clippy lints --- src/use_locale.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/use_locale.rs b/src/use_locale.rs index be781a4..b423179 100644 --- a/src/use_locale.rs +++ b/src/use_locale.rs @@ -58,8 +58,8 @@ where .map(|l| l.as_ref().clone()) .collect::>(); - const EMPTY_ERR_MSG: &'static str = "Empty supported list. You have to provide at least one locale in the `supported` parameter"; - assert!(supported.len() > 0, "{}", EMPTY_ERR_MSG); + const EMPTY_ERR_MSG: &str = "Empty supported list. You have to provide at least one locale in the `supported` parameter"; + assert!(!supported.is_empty(), "{}", EMPTY_ERR_MSG); Signal::derive(move || { let supported = supported.clone(); From 8324c70742c206698104f6642062fd14dd073d4d Mon Sep 17 00:00:00 2001 From: Maccesch Date: Wed, 14 Aug 2024 03:43:00 +0100 Subject: [PATCH 33/40] release 0.12.0 --- CHANGELOG.md | 7 +++++-- Cargo.toml | 2 +- README.md | 12 ++++++------ src/use_color_mode.rs | 4 ++-- src/utils/header_macro.rs | 2 +- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0dee1f5..1586aed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,9 @@ 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). -## [Unreleased] - +## [0.12.0] - 2024-08-14 + +> Make sure you also update `cargo-leptos` to the latest version if you use that. ### Breaking Changes 🛠 @@ -11,7 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `use_clipboard` doesn't need the unstable flags anymore. - `use_locale` now uses `unic_langid::LanguageIdentifier` and proper locale matching (thanks to @mondeja). - Removed `UseMouseEventExtractorDefault` and reworked `UseMouseCoordType` (thanks to @carloskiki) -- `use_preferred_dark` and `use_color_mode` now try to read the `Sec-CH-Prefers-Color-Scheme` header in SSR. +- `use_preferred_dark` and `use_color_mode` now try to read the `Sec-CH-Prefers-Color-Scheme` header in SSR. This brings + the necessity to enable an additional feature for them (`axum` / `actix` / `spin`). ### Fixes 🍕 diff --git a/Cargo.toml b/Cargo.toml index 2fd0ca0..9ec4f61 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "leptos-use" -version = "0.11.5" +version = "0.12.0" edition = "2021" authors = ["Marc-Stefan Cassola"] categories = ["gui", "web-programming"] diff --git a/README.md b/README.md index eb58418..933f07f 100644 --- a/README.md +++ b/README.md @@ -87,9 +87,9 @@ This will create the function file in the src directory, scaffold an example dir ## Leptos compatibility -| Crate version | Compatible Leptos version | -|---------------|---------------------------| -| <= 0.3 | 0.3 | -| 0.4, 0.5, 0.6 | 0.4 | -| 0.7, 0.8, 0.9 | 0.5 | -| 0.10, 0.11 | 0.6 | +| Crate version | Compatible Leptos version | +|------------------|---------------------------| +| <= 0.3 | 0.3 | +| 0.4, 0.5, 0.6 | 0.4 | +| 0.7, 0.8, 0.9 | 0.5 | +| 0.10, 0.11, 0.12 | 0.6 | diff --git a/src/use_color_mode.rs b/src/use_color_mode.rs index 99a688e..9f3719e 100644 --- a/src/use_color_mode.rs +++ b/src/use_color_mode.rs @@ -4,8 +4,8 @@ use crate::core::{ElementMaybeSignal, MaybeRwSignal}; use crate::storage::{use_storage_with_options, UseStorageOptions}; use crate::utils::get_header; use crate::{ - sync_signal_with_options, use_cookie, use_preferred_dark_with_options, - SyncSignalOptions, UsePreferredDarkOptions, + sync_signal_with_options, use_cookie, use_preferred_dark_with_options, SyncSignalOptions, + UsePreferredDarkOptions, }; use codee::string::FromToStringCodec; use default_struct_builder::DefaultBuilder; diff --git a/src/utils/header_macro.rs b/src/utils/header_macro.rs index 59dab10..4f6f087 100644 --- a/src/utils/header_macro.rs +++ b/src/utils/header_macro.rs @@ -19,7 +19,7 @@ macro_rules! get_header { ); return None; } - + #[cfg(feature = "actix")] #[allow(unused_imports)] use http0_2::{HeaderName, header::*}; From 6d57bdf7f5ad1d68bfa22c57fe5bb845bdf12a14 Mon Sep 17 00:00:00 2001 From: Hector Candelaria Date: Sun, 18 Aug 2024 17:17:06 -0400 Subject: [PATCH 34/40] Feat: Add `prefers-reduced-motion` API implementation Implemented the `use_prefers_reduced_motion` function to create a reactive interface for detecting the user's reduced motion preference via the `prefers-reduced-motion` media query. --- CHANGELOG.md | 6 + docs/book/src/SUMMARY.md | 1 + .../src/browser/use_prefers_reduced_motion.md | 3 + examples/Cargo.toml | 1 + .../use_prefers_reduced_motion/Cargo.toml | 16 + examples/use_prefers_reduced_motion/README.md | 23 ++ .../use_prefers_reduced_motion/Trunk.toml | 2 + .../use_prefers_reduced_motion/index.html | 7 + examples/use_prefers_reduced_motion/input.css | 3 + .../rust-toolchain.toml | 2 + .../use_prefers_reduced_motion/src/main.rs | 29 ++ .../style/output.css | 326 ++++++++++++++++++ .../tailwind.config.js | 15 + src/lib.rs | 2 + src/use_prefers_reduced_motion.rs | 99 ++++++ 15 files changed, 535 insertions(+) create mode 100644 docs/book/src/browser/use_prefers_reduced_motion.md create mode 100644 examples/use_prefers_reduced_motion/Cargo.toml create mode 100644 examples/use_prefers_reduced_motion/README.md create mode 100644 examples/use_prefers_reduced_motion/Trunk.toml create mode 100644 examples/use_prefers_reduced_motion/index.html create mode 100644 examples/use_prefers_reduced_motion/input.css create mode 100644 examples/use_prefers_reduced_motion/rust-toolchain.toml create mode 100644 examples/use_prefers_reduced_motion/src/main.rs create mode 100644 examples/use_prefers_reduced_motion/style/output.css create mode 100644 examples/use_prefers_reduced_motion/tailwind.config.js create mode 100644 src/use_prefers_reduced_motion.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 1586aed..5d5315c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ 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). +## [Unreleased] - + +### New Functions 🚀 + +- `use_prefers_reduced_motion` + ## [0.12.0] - 2024-08-14 > Make sure you also update `cargo-leptos` to the latest version if you use that. diff --git a/docs/book/src/SUMMARY.md b/docs/book/src/SUMMARY.md index cd07431..ebbb19f 100644 --- a/docs/book/src/SUMMARY.md +++ b/docs/book/src/SUMMARY.md @@ -48,6 +48,7 @@ - [use_permission](browser/use_permission.md) - [use_preferred_contrast](browser/use_preferred_contrast.md) - [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_user_media](browser/use_user_media.md) - [use_web_notification](browser/use_web_notification.md) diff --git a/docs/book/src/browser/use_prefers_reduced_motion.md b/docs/book/src/browser/use_prefers_reduced_motion.md new file mode 100644 index 0000000..d6aa3ae --- /dev/null +++ b/docs/book/src/browser/use_prefers_reduced_motion.md @@ -0,0 +1,3 @@ +# use_prefers_reduced_motion + + diff --git a/examples/Cargo.toml b/examples/Cargo.toml index debad03..187bcf3 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -47,6 +47,7 @@ members = [ "use_not", "use_or", "use_permission", + "use_prefers_reduced_motion", "use_raf_fn", "use_resize_observer", "use_round", diff --git a/examples/use_prefers_reduced_motion/Cargo.toml b/examples/use_prefers_reduced_motion/Cargo.toml new file mode 100644 index 0000000..4b0d55a --- /dev/null +++ b/examples/use_prefers_reduced_motion/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "use_prefers_reduced_motion" +version = "0.1.0" +edition = "2021" + +[dependencies] +leptos = { version = "0.6", features = ["nightly", "csr"] } +console_error_panic_hook = "0.1" +console_log = "1" +log = "0.4" +leptos-use = { path = "../..", features = ["docs"] } +web-sys = "0.3" + +[dev-dependencies] +wasm-bindgen = "0.2" +wasm-bindgen-test = "0.3.0" diff --git a/examples/use_prefers_reduced_motion/README.md b/examples/use_prefers_reduced_motion/README.md new file mode 100644 index 0000000..95c5eea --- /dev/null +++ b/examples/use_prefers_reduced_motion/README.md @@ -0,0 +1,23 @@ +A simple example for `use_prefers_reduced_motion`. + +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 +``` \ No newline at end of file diff --git a/examples/use_prefers_reduced_motion/Trunk.toml b/examples/use_prefers_reduced_motion/Trunk.toml new file mode 100644 index 0000000..3e4be08 --- /dev/null +++ b/examples/use_prefers_reduced_motion/Trunk.toml @@ -0,0 +1,2 @@ +[build] +public_url = "/demo/" \ No newline at end of file diff --git a/examples/use_prefers_reduced_motion/index.html b/examples/use_prefers_reduced_motion/index.html new file mode 100644 index 0000000..ae249a6 --- /dev/null +++ b/examples/use_prefers_reduced_motion/index.html @@ -0,0 +1,7 @@ + + + + + + + diff --git a/examples/use_prefers_reduced_motion/input.css b/examples/use_prefers_reduced_motion/input.css new file mode 100644 index 0000000..b5c61c9 --- /dev/null +++ b/examples/use_prefers_reduced_motion/input.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/examples/use_prefers_reduced_motion/rust-toolchain.toml b/examples/use_prefers_reduced_motion/rust-toolchain.toml new file mode 100644 index 0000000..271800c --- /dev/null +++ b/examples/use_prefers_reduced_motion/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" \ No newline at end of file diff --git a/examples/use_prefers_reduced_motion/src/main.rs b/examples/use_prefers_reduced_motion/src/main.rs new file mode 100644 index 0000000..2a6adfc --- /dev/null +++ b/examples/use_prefers_reduced_motion/src/main.rs @@ -0,0 +1,29 @@ +use leptos::*; +use leptos_use::docs::{demo_or_body, BooleanDisplay}; +use leptos_use::use_prefers_reduced_motion; + +#[component] +fn Demo() -> impl IntoView { + let is_reduced_motion_preferred = use_prefers_reduced_motion(); + + view! { +
+

Prefers reduced motions:

+

+ Update reduce motion preference + + documentation. + +

+
+ } +} + +fn main() { + _ = console_log::init_with_level(log::Level::Debug); + console_error_panic_hook::set_once(); + + mount_to(demo_or_body(), || { + view! { } + }) +} diff --git a/examples/use_prefers_reduced_motion/style/output.css b/examples/use_prefers_reduced_motion/style/output.css new file mode 100644 index 0000000..7db8e42 --- /dev/null +++ b/examples/use_prefers_reduced_motion/style/output.css @@ -0,0 +1,326 @@ +[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; +} + +.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)); + } +} diff --git a/examples/use_prefers_reduced_motion/tailwind.config.js b/examples/use_prefers_reduced_motion/tailwind.config.js new file mode 100644 index 0000000..bc09f5e --- /dev/null +++ b/examples/use_prefers_reduced_motion/tailwind.config.js @@ -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'), + ], +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index efe5187..0e43a6b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,6 +62,7 @@ mod use_mutation_observer; mod use_permission; mod use_preferred_contrast; mod use_preferred_dark; +mod use_prefers_reduced_motion; mod use_raf_fn; mod use_resize_observer; mod use_scroll; @@ -131,6 +132,7 @@ pub use use_mutation_observer::*; pub use use_permission::*; pub use use_preferred_contrast::*; pub use use_preferred_dark::*; +pub use use_prefers_reduced_motion::*; pub use use_raf_fn::*; pub use use_resize_observer::*; pub use use_scroll::*; diff --git a/src/use_prefers_reduced_motion.rs b/src/use_prefers_reduced_motion.rs new file mode 100644 index 0000000..444e4c4 --- /dev/null +++ b/src/use_prefers_reduced_motion.rs @@ -0,0 +1,99 @@ +use crate::utils::get_header; +use default_struct_builder::DefaultBuilder; +use leptos::*; +use std::rc::Rc; + +/// Reactive [reduced motions preference](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion). +/// +/// ## Demo +/// +/// [Link to Demo](https://github.com/Synphonyte/leptos-use/tree/main/examples/use_prefers_reduced_motion) +/// +/// ## Usage +/// +/// ``` +/// # use leptos::*; +/// # use leptos_use::use_prefers_reduced_motion; +/// # +/// # #[component] +/// # fn Demo() -> impl IntoView { +/// let is_reduced_motion_preferred = use_prefers_reduced_motion(); +/// +/// view! { +///
+///

Prefers reduced motions:

+///

+/// Update reduce motion preference +/// +/// documentation. +/// +///

+///
+/// } +/// # } +/// ``` +/// +/// ## Server-Side Rendering +/// +/// On the server this will try to read the +/// [`Sec-CH-Prefers-Reduced-Motion` header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-CH-Prefers-Reduced-Motion) +/// to indicate the preference for animations to be displayed with reduced motion. +/// Please have a look at the linked documentation above to see browser support +/// as well as potential serve requirements. +/// +/// > If you're using `axum` you have to enable the `"axum"` feature in your Cargo.toml. +/// > In case it's `actix-web` enable the feature `"actix"`, for `spin` enable `"spin"`. +/// +/// ### Bring your own header +/// +/// In case you're neither using Axum, Actix nor Spin, or the default implementation is not to your +/// liking, you can provide your own way of reading the reduced motion header value using the option +/// [`crate::UsePrefersReducedMotionOptions::ssr_motion_header_getter`]. +/// +/// ## See also +/// +/// * [`fn@crate::use_media_query`] +/// * [`fn@crate::use_preferred_contrast`] +/// * [`fn@crate::use_preferred_dark`] +pub fn use_prefers_reduced_motion() -> Signal { + use_prefers_reduced_motion_with_options(UsePrefersReducedMotionOptions::default()) +} + +/// Version of [`fn@crate::use_prefers_reduced_motion`] that takes a `UsePrefersReducedMotionOptions`. See [`fn@crate::use_prefers_reduced_motion`] for how to use. +pub fn use_prefers_reduced_motion_with_options(options: UsePrefersReducedMotionOptions) -> Signal { + #[cfg(not(feature = "ssr"))] + { + let _ = options; + crate::use_media_query("(prefers-reduced-motion: reduce)") + } + #[cfg(feature = "ssr")] + { + Signal::derive(move || (options.ssr_motion_header_getter)() == Some("reduce".to_string())) + } +} + +/// Options for [`fn@crate::use_prefers_reduced_motion_with_options`]. +#[derive(DefaultBuilder)] +pub struct UsePrefersReducedMotionOptions { + /// Getter function to return the string value of the + /// [`Sec-CH-Prefers-Reduced-Motion`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-CH-Prefers-Reduced-Motion) + /// header. + /// When you use one of the features `"axum"`, `"actix"` or `"spin"` there's a valid default + /// implementation provided. + #[allow(dead_code)] + pub(crate) ssr_motion_header_getter: Rc Option>, +} + +impl Default for UsePrefersReducedMotionOptions { + fn default() -> Self { + Self { + ssr_motion_header_getter: Rc::new(move || { + get_header!( + HeaderName::from_static("sec-ch-prefers-reduced-motion"), + use_locale, + ssr_motion_header_getter + ) + }), + } + } +} From f5a37f6c7f239fad9e46032ab1f7140bc7ba978c Mon Sep 17 00:00:00 2001 From: Hector Candelaria Date: Sun, 18 Aug 2024 17:19:50 -0400 Subject: [PATCH 35/40] Docs: Update See also references in media query functions - Added `use_prefers_reduced_motion` in the documentation for `use_media_query`, `use_preferred_contrast`, and `use_preferred_dark` functions to include links to related functions. --- src/use_media_query.rs | 1 + src/use_preferred_contrast.rs | 3 ++- src/use_preferred_dark.rs | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/use_media_query.rs b/src/use_media_query.rs index 61e423c..a97a00c 100644 --- a/src/use_media_query.rs +++ b/src/use_media_query.rs @@ -38,6 +38,7 @@ use std::rc::Rc; /// /// * [`fn@crate::use_preferred_dark`] /// * [`fn@crate::use_preferred_contrast`] +/// * [`fn@crate::use_prefers_reduced_motion`] pub fn use_media_query(query: impl Into>) -> Signal { let query = query.into(); diff --git a/src/use_preferred_contrast.rs b/src/use_preferred_contrast.rs index 85fc679..d90998f 100644 --- a/src/use_preferred_contrast.rs +++ b/src/use_preferred_contrast.rs @@ -27,6 +27,7 @@ use std::fmt::Display; /// /// * [`fn@crate::use_media_query`] /// * [`fn@crate::use_preferred_dark`] +/// * [`fn@crate::use_prefers_reduced_motion`] pub fn use_preferred_contrast() -> Signal { let is_more = use_media_query("(prefers-contrast: more)"); let is_less = use_media_query("(prefers-contrast: less)"); @@ -53,8 +54,8 @@ pub enum PreferredContrast { Custom, #[default] NoPreference, -} +} impl Display for PreferredContrast { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { diff --git a/src/use_preferred_dark.rs b/src/use_preferred_dark.rs index ad64f13..c397f82 100644 --- a/src/use_preferred_dark.rs +++ b/src/use_preferred_dark.rs @@ -41,6 +41,7 @@ use std::rc::Rc; /// /// * [`fn@crate::use_media_query`] /// * [`fn@crate::use_preferred_contrast`] +/// * [`fn@crate::use_prefers_reduced_motion`] pub fn use_preferred_dark() -> Signal { use_preferred_dark_with_options(Default::default()) } From 0021e4aed5d1217e6f8d05c6fe44b03a5db2c3e7 Mon Sep 17 00:00:00 2001 From: Hector Candelaria Date: Sun, 18 Aug 2024 18:43:35 -0400 Subject: [PATCH 36/40] Docs: Add `BooleanDisplay` import to demo Included the `BooleanDisplay` import in the demo. --- src/use_prefers_reduced_motion.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/use_prefers_reduced_motion.rs b/src/use_prefers_reduced_motion.rs index 444e4c4..68a0563 100644 --- a/src/use_prefers_reduced_motion.rs +++ b/src/use_prefers_reduced_motion.rs @@ -14,6 +14,7 @@ use std::rc::Rc; /// ``` /// # use leptos::*; /// # use leptos_use::use_prefers_reduced_motion; +/// # use leptos_use::docs::BooleanDisplay; /// # /// # #[component] /// # fn Demo() -> impl IntoView { From 9f8adfc1f10d545a526bfc97177ad4940e9c154f Mon Sep 17 00:00:00 2001 From: Hector Candelaria Date: Sun, 18 Aug 2024 18:57:04 -0400 Subject: [PATCH 37/40] Chore: Apply cargo `fmt` to ensure code formatting compliance Reformatted the code to pass `cargo fmt --check` --- src/use_preferred_contrast.rs | 1 - src/use_prefers_reduced_motion.rs | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/use_preferred_contrast.rs b/src/use_preferred_contrast.rs index d90998f..9e3eb0a 100644 --- a/src/use_preferred_contrast.rs +++ b/src/use_preferred_contrast.rs @@ -54,7 +54,6 @@ pub enum PreferredContrast { Custom, #[default] NoPreference, - } impl Display for PreferredContrast { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { diff --git a/src/use_prefers_reduced_motion.rs b/src/use_prefers_reduced_motion.rs index 68a0563..b1afd55 100644 --- a/src/use_prefers_reduced_motion.rs +++ b/src/use_prefers_reduced_motion.rs @@ -61,7 +61,9 @@ pub fn use_prefers_reduced_motion() -> Signal { } /// Version of [`fn@crate::use_prefers_reduced_motion`] that takes a `UsePrefersReducedMotionOptions`. See [`fn@crate::use_prefers_reduced_motion`] for how to use. -pub fn use_prefers_reduced_motion_with_options(options: UsePrefersReducedMotionOptions) -> Signal { +pub fn use_prefers_reduced_motion_with_options( + options: UsePrefersReducedMotionOptions, +) -> Signal { #[cfg(not(feature = "ssr"))] { let _ = options; From 09b08f64f5d5b50e1560491a10da827271f123bc Mon Sep 17 00:00:00 2001 From: Ke7in <60681675+luckynumberke7in@users.noreply.github.com> Date: Tue, 20 Aug 2024 21:40:23 -0400 Subject: [PATCH 38/40] Update "hidden" in use_document Changed to hide elements by default on server. --- src/use_document.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/use_document.rs b/src/use_document.rs index 16cd226..5a3f1bc 100644 --- a/src/use_document.rs +++ b/src/use_document.rs @@ -225,7 +225,9 @@ impl UseDocument { ); impl_ssr_safe_method!( - hidden(&self) -> Option + /// Hides on server by default + hidden(&self) -> bool; + .unwrap_or(true) ); impl_ssr_safe_method!( From 44cab1027dfa64ba0602ffc4e4dd837b3dd37883 Mon Sep 17 00:00:00 2001 From: Ke7in <60681675+luckynumberke7in@users.noreply.github.com> Date: Wed, 21 Aug 2024 16:41:04 -0400 Subject: [PATCH 39/40] fix cargo fmt issues Forgot to set up "cargo fmt" on save --new system. --- src/use_document.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/use_document.rs b/src/use_document.rs index 5a3f1bc..126fcd0 100644 --- a/src/use_document.rs +++ b/src/use_document.rs @@ -6,7 +6,10 @@ use crate::core::impl_ssr_safe_method; #[cfg(not(feature = "ssr"))] use leptos::*; use wasm_bindgen::JsValue; -use web_sys::{Document, Element, HtmlCollection, HtmlElement, HtmlHeadElement, Location, NodeList, VisibilityState, Window}; +use web_sys::{ + Document, Element, HtmlCollection, HtmlElement, HtmlHeadElement, Location, NodeList, + VisibilityState, Window, +}; /// SSR safe `document()`. /// This returns just a new-type wrapper around `Option`. From b07b6b7cfd062440561c2d1923ef7776b0815ce0 Mon Sep 17 00:00:00 2001 From: Maccesch Date: Thu, 22 Aug 2024 13:37:32 +0100 Subject: [PATCH 40/40] added features for every function. fixes #152 --- Cargo.toml | 399 +++++++++++++----- examples/on_click_outside/Cargo.toml | 2 +- examples/signal_debounced/Cargo.toml | 2 +- examples/signal_throttled/Cargo.toml | 2 +- examples/ssr/Cargo.toml | 15 +- examples/sync_signal/Cargo.toml | 2 +- examples/use_active_element/Cargo.toml | 2 +- examples/use_breakpoints/Cargo.toml | 2 +- examples/use_broadcast_channel/Cargo.toml | 2 +- examples/use_clipboard/Cargo.toml | 2 +- examples/use_color_mode/Cargo.toml | 2 +- examples/use_cookie/Cargo.toml | 2 +- examples/use_css_var/Cargo.toml | 2 +- examples/use_cycle_list/Cargo.toml | 2 +- examples/use_debounce_fn/Cargo.toml | 2 +- examples/use_device_orientation/Cargo.toml | 2 +- examples/use_device_pixel_ratio/Cargo.toml | 2 +- examples/use_display_media/Cargo.toml | 2 +- examples/use_document_visibility/Cargo.toml | 2 +- examples/use_draggable/Cargo.toml | 2 +- examples/use_drop_zone/Cargo.toml | 2 +- examples/use_element_bounding/Cargo.toml | 2 +- examples/use_element_hover/Cargo.toml | 2 +- examples/use_element_size/Cargo.toml | 2 +- examples/use_element_visibility/Cargo.toml | 2 +- examples/use_event_listener/Cargo.toml | 2 +- examples/use_favicon/Cargo.toml | 2 +- examples/use_geolocation/Cargo.toml | 2 +- examples/use_idle/Cargo.toml | 2 +- examples/use_infinite_scroll/Cargo.toml | 2 +- examples/use_intersection_observer/Cargo.toml | 2 +- examples/use_interval/Cargo.toml | 2 +- examples/use_interval_fn/Cargo.toml | 2 +- examples/use_intl_number_format/Cargo.toml | 2 +- examples/use_locale/Cargo.toml | 2 +- examples/use_locales/Cargo.toml | 2 +- examples/use_media_query/Cargo.toml | 2 +- examples/use_mouse/Cargo.toml | 2 +- examples/use_mouse_in_element/Cargo.toml | 2 +- examples/use_mutation_observer/Cargo.toml | 2 +- examples/use_permission/Cargo.toml | 2 +- .../use_prefers_reduced_motion/Cargo.toml | 2 +- examples/use_raf_fn/Cargo.toml | 2 +- examples/use_resize_observer/Cargo.toml | 2 +- examples/use_scroll/Cargo.toml | 2 +- examples/use_service_worker/Cargo.toml | 2 +- examples/use_sorted/Cargo.toml | 2 +- examples/use_storage/Cargo.toml | 2 +- examples/use_throttle_fn/Cargo.toml | 2 +- examples/use_timeout_fn/Cargo.toml | 2 +- examples/use_timestamp/Cargo.toml | 2 +- examples/use_user_media/Cargo.toml | 2 +- examples/use_web_notification/Cargo.toml | 2 +- examples/use_websocket/Cargo.toml | 2 +- examples/use_webtransport/Cargo.toml | 2 +- examples/use_window_focus/Cargo.toml | 2 +- examples/use_window_scroll/Cargo.toml | 2 +- examples/watch_debounced/Cargo.toml | 2 +- examples/watch_pausable/Cargo.toml | 2 +- examples/watch_throttled/Cargo.toml | 2 +- src/core/mod.rs | 10 +- src/core/reconnect_limit.rs | 20 + src/core/ssr_safe_method.rs | 2 + src/core/storage.rs | 21 - src/lib.rs | 141 +++++++ src/storage/mod.rs | 23 +- src/storage/use_storage.rs | 5 +- src/use_color_mode.rs | 3 +- src/use_websocket.rs | 22 +- src/utils/header_macro.rs | 2 + src/utils/js_value_from_to_string.rs | 2 + src/utils/mod.rs | 5 + src/utils/signal_filtered.rs | 2 + src/watch_debounced.rs | 2 +- src/watch_throttled.rs | 2 +- 75 files changed, 580 insertions(+), 212 deletions(-) create mode 100644 src/core/reconnect_limit.rs delete mode 100644 src/core/storage.rs diff --git a/Cargo.toml b/Cargo.toml index 9ec4f61..de5940a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,14 +14,14 @@ homepage = "https://leptos-use.rs" [dependencies] actix-web = { version = "4", optional = true, default-features = false } -async-trait = "0.1" +async-trait = { version = "0.1", optional = true } cfg-if = "1" -codee = "0.1" -cookie = { version = "0.18", features = ["percent-encode"] } +codee = { version = "0.1", optional = true } +cookie = { version = "0.18", features = ["percent-encode"], optional = true } default-struct-builder = "0.5" -futures-util = "0.3" -gloo-timers = { version = "0.3.0", features = ["futures"] } -gloo-utils = { version = "0.2.0" } +futures-util = { version = "0.3", optional = true } +gloo-timers = { version = "0.3.0", optional = true, features = ["futures"] } +gloo-utils = { version = "0.2.0", optional = true } http1 = { version = "1", optional = true, package = "http" } http0_2 = { version = "0.2", optional = true, package = "http" } js-sys = "0.3" @@ -33,101 +33,10 @@ leptos-spin = { version = "0.1", optional = true } num = { version = "0.4", optional = true } paste = "1" thiserror = "1" -unic-langid = "0.9" +unic-langid = { version = "0.9", optional = true } wasm-bindgen = "=0.2.93" wasm-bindgen-futures = "0.4" - -[dependencies.web-sys] -version = "=0.3.70" -features = [ - "AddEventListenerOptions", - "BinaryType", - "BroadcastChannel", - "Coordinates", - "Clipboard", - "CloseEvent", - "CssStyleDeclaration", - "CustomEvent", - "CustomEventInit", - "DisplayMediaStreamConstraints", - "DomRect", - "DomRectReadOnly", - "DataTransfer", - "DragEvent", - "Element", - "EventListener", - "EventListenerOptions", - "EventSource", - "EventSourceInit", - "EventTarget", - "File", - "FileList", - "Geolocation", - "HtmlDocument", - "HtmlElement", - "HtmlLinkElement", - "HtmlStyleElement", - "IntersectionObserver", - "IntersectionObserverInit", - "IntersectionObserverEntry", - "Location", - "MediaDevices", - "MediaQueryList", - "MediaStream", - "MediaStreamConstraints", - "MediaStreamTrack", - "MessageEvent", - "MouseEvent", - "MutationObserver", - "MutationObserverInit", - "MutationRecord", - "Navigator", - "NodeList", - "Notification", - "NotificationDirection", - "NotificationOptions", - "NotificationPermission", - "Permissions", - "PermissionState", - "PermissionStatus", - "PointerEvent", - "Position", - "PositionError", - "PositionOptions", - "ReadableStream", - "ReadableStreamDefaultReader", - "ReadableStreamGetReaderOptions", - "ReadableStreamReaderMode", - "ResizeObserver", - "ResizeObserverBoxOptions", - "ResizeObserverEntry", - "ResizeObserverOptions", - "ResizeObserverSize", - "ScrollBehavior", - "ScrollToOptions", - "ServiceWorker", - "ServiceWorkerContainer", - "ServiceWorkerRegistration", - "ServiceWorkerState", - "Storage", - "StorageEvent", - "Touch", - "TouchEvent", - "TouchList", - "Url", - "UrlSearchParams", - "VisibilityState", - "WebSocket", - "WebTransport", - "WebTransportOptions", - "WebTransportDatagramDuplexStream", - "WebTransportBidirectionalStream", - "Window", - "WebTransportReceiveStream", - "WebTransportSendStream", - "WritableStream", - "WritableStreamDefaultWriter", -] +web-sys = { version = "=0.3.70", optional = true } [dev-dependencies] codee = { version = "0.1", features = ["json_serde", "msgpack_serde", "base64", "prost"] } @@ -138,13 +47,303 @@ serde = { version = "1", features = ["derive"] } unic-langid = { version = "0.9", features = ["macros"] } [features] +default = [ + "is_err", + "is_none", + "is_ok", + "is_some", + "on_click_outside", + "signal_debounced", + "signal_throttled", + "storage", + "sync_signal", + "use_active_element", + "use_breakpoints", + "use_broadcast_channel", + "use_clipboard", + "use_color_mode", + "use_cookie", + "use_css_var", + "use_cycle_list", + "use_debounce_fn", + "use_device_orientation", + "use_device_pixel_ratio", + "use_display_media", + "use_document", + "use_document_visibility", + "use_draggable", + "use_drop_zone", + "use_element_bounding", + "use_element_hover", + "use_element_size", + "use_element_visibility", + "use_event_listener", + "use_event_source", + "use_favicon", + "use_geolocation", + "use_idle", + "use_infinite_scroll", + "use_intersection_observer", + "use_interval", + "use_interval_fn", + "use_intl_number_format", + "use_locale", + "use_locales", + "use_media_query", + "use_mouse", + "use_mouse_in_element", + "use_mutation_observer", + "use_permission", + "use_preferred_contrast", + "use_preferred_dark", + "use_prefers_reduced_motion", + "use_raf_fn", + "use_resize_observer", + "use_scroll", + "use_service_worker", + "use_sorted", + "use_supported", + "use_throttle_fn", + "use_timeout_fn", + "use_timestamp", + "use_to_string", + "use_user_media", + "use_web_notification", + "use_websocket", + "use_window", + "use_window_focus", + "use_window_scroll", + "watch_debounced", + "watch_pausable", + "watch_throttled", + "watch_with_options", + "whenever" +] actix = ["dep:actix-web", "dep:leptos_actix", "dep:http0_2"] axum = ["dep:leptos_axum", "dep:http1"] -docs = [] +docs = ["dep:web-sys"] +element = ["use_document", "use_window", "dep:web-sys", "web-sys/EventTarget"] +is = ["use_window"] +is_err = [] +is_none = [] +is_ok = [] +is_some = [] math = ["num"] +on_click_outside = ["use_event_listener", "is"] +signal_debounced = ["use_debounce_fn"] +signal_throttled = ["use_throttle_fn"] spin = ["dep:leptos-spin", "dep:http1"] ssr = [] +storage = [ + "use_event_listener", + "use_window", + "watch_with_options", + "dep:web-sys", + "dep:codee", + "web-sys/CustomEventInit", + "web-sys/Storage" +] +sync_signal = [] +use_active_element = ["use_event_listener"] +use_breakpoints = ["use_media_query"] +use_broadcast_channel = [ + "use_event_listener", + "use_supported", + "dep:codee", + "web-sys/BroadcastChannel", +] +use_clipboard = [ + "use_event_listener", + "use_permission", + "use_supported", + "use_timeout_fn", + "web-sys/Clipboard", +] +use_color_mode = [ + "use_cookie", + "use_cycle_list", + "use_preferred_dark", + "storage", + "sync_signal" +] +use_cookie = [ + "use_broadcast_channel", + "watch_pausable", + "dep:cookie", + "web-sys/HtmlDocument", +] +use_css_var = [ + "use_mutation_observer", + "watch_with_options", +] +use_cycle_list = [] +use_debounce_fn = [] +use_device_orientation = ["use_event_listener", "use_supported"] +use_device_pixel_ratio = ["use_event_listener", "web-sys/MediaQueryList"] +use_display_media = [ + "use_window", + "web-sys/DisplayMediaStreamConstraints", + "web-sys/MediaDevices", + "web-sys/MediaStream", + "web-sys/MediaStreamTrack", +] +use_document = [ + "dep:web-sys", + "web-sys/VisibilityState", +] +use_document_visibility = ["use_event_listener", "web-sys/VisibilityState"] +use_draggable = ["use_event_listener", "web-sys/DomRect"] +use_drop_zone = [ + "use_event_listener", + "web-sys/DataTransfer", + "web-sys/File", + "web-sys/FileList" +] +use_element_bounding = [ + "use_event_listener", + "use_resize_observer", + "web-sys/DomRect", +] +use_element_hover = ["use_event_listener"] +use_element_size = [ + "use_resize_observer", + "watch_with_options", + "web-sys/ResizeObserverSize", +] +use_element_visibility = [ + "use_intersection_observer", + "web-sys/DomRect", +] +use_event_listener = [ + "element", + "watch_with_options", + "dep:web-sys", + "web-sys/EventTarget", + "web-sys/EventListenerOptions" +] +use_event_source = [ + "use_event_listener", + "web-sys/EventSource", + "web-sys/EventSourceInit", + "dep:codee", +] +use_favicon = [] +use_geolocation = [ + "use_window", + "web-sys/Coordinates", + "web-sys/Geolocation", + "web-sys/Position", + "web-sys/PositionError", + "web-sys/PositionOptions", +] +use_idle = [ + "use_event_listener", + "use_document", + "use_timestamp", +] +use_infinite_scroll = [ + "use_element_visibility", + "use_scroll", + "dep:gloo-timers", + "dep:futures-util", +] +use_intersection_observer = [ + "element", + "watch_with_options", + "web-sys/IntersectionObserver", + "web-sys/IntersectionObserverEntry", + "web-sys/IntersectionObserverInit", +] +use_interval = ["use_interval_fn"] +use_interval_fn = [] +use_intl_number_format = [] +use_locale = ["use_locales", "dep:unic-langid"] +use_locales = ["use_event_listener", "use_window"] +use_media_query = ["use_event_listener"] +use_mouse = [ + "element", + "use_event_listener", + "use_window", + "web-sys/Touch", + "web-sys/TouchList", +] +use_mouse_in_element = [ + "use_mouse", + "web-sys/DomRect", +] +use_mutation_observer = [ + "element", + "use_supported", + "web-sys/MutationObserver", + "web-sys/MutationObserverInit", + "web-sys/MutationRecord", +] +use_permission = [ + "use_event_listener", + "web-sys/Permissions", + "web-sys/PermissionState", + "web-sys/PermissionStatus", +] +use_preferred_contrast = ["use_media_query"] +use_preferred_dark = ["use_media_query"] +use_prefers_reduced_motion = ["use_media_query"] +use_raf_fn = [] +use_resize_observer = [ + "element", + "use_supported", + "web-sys/DomRectReadOnly", + "web-sys/ResizeObserver", + "web-sys/ResizeObserverBoxOptions", + "web-sys/ResizeObserverEntry", + "web-sys/ResizeObserverOptions", +] +use_scroll = [ + "element", + "use_event_listener", + "use_debounce_fn", + "use_throttle_fn", + "web-sys/ScrollBehavior", + "web-sys/ScrollToOptions", +] +use_service_worker = [ + "use_window", + "web-sys/ServiceWorker", + "web-sys/ServiceWorkerContainer", + "web-sys/ServiceWorkerRegistration" +] +use_sorted = [] +use_supported = [] +use_throttle_fn = [] +use_timeout_fn = [] +use_timestamp = ["use_interval_fn", "use_raf_fn"] +use_to_string = [] +use_user_media = [ + "use_window", + "web-sys/MediaDevices", + "web-sys/MediaStream", + "web-sys/MediaStreamConstraints", + "web-sys/MediaStreamTrack", +] +use_web_notification = [ + "use_supported", + "use_window", + "use_event_listener", + "web-sys/Notification", + "web-sys/NotificationOptions", + "web-sys/NotificationPermission", + "web-sys/NotificationDirection", + "web-sys/VisibilityState" +] +use_websocket = ["dep:codee"] +use_window = ["use_document", "dep:web-sys", "web-sys/Navigator", "web-sys/MediaQueryList"] +use_window_focus = ["use_event_listener"] +use_window_scroll = ["use_event_listener", "use_window"] wasm_ssr = [] +watch_debounced = ["watch_with_options"] +watch_pausable = ["watch_with_options"] +watch_throttled = ["watch_with_options"] +watch_with_options = [] +whenever = [] [package.metadata.docs.rs] features = ["math", "docs", "ssr"] diff --git a/examples/on_click_outside/Cargo.toml b/examples/on_click_outside/Cargo.toml index 3313bf8..c6d6279 100644 --- a/examples/on_click_outside/Cargo.toml +++ b/examples/on_click_outside/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["on_click_outside", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/signal_debounced/Cargo.toml b/examples/signal_debounced/Cargo.toml index 6f85a28..9411da3 100644 --- a/examples/signal_debounced/Cargo.toml +++ b/examples/signal_debounced/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["signal_debounced", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/signal_throttled/Cargo.toml b/examples/signal_throttled/Cargo.toml index 73b2b91..2a14d8a 100644 --- a/examples/signal_throttled/Cargo.toml +++ b/examples/signal_throttled/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["signal_throttled", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/ssr/Cargo.toml b/examples/ssr/Cargo.toml index 533ce90..33e9575 100644 --- a/examples/ssr/Cargo.toml +++ b/examples/ssr/Cargo.toml @@ -16,7 +16,6 @@ leptos = { version = "0.6", features = ["nightly"] } leptos_axum = { version = "0.6", optional = true } leptos_meta = { version = "0.6", features = ["nightly"] } leptos_router = { version = "0.6", features = ["nightly"] } -leptos-use = { path = "../.." } log = "0.4" simple_logger = "4" tokio = { version = "1", features = ["full"], optional = true } @@ -28,6 +27,20 @@ thiserror = "1.0.38" tracing = { version = "0.1.37", optional = true } http = "1" +[dependencies.leptos-use] +path = "../.." +features = [ + "use_cookie", + "use_color_mode", + "use_debounce_fn", + "use_event_listener", + "use_interval", + "use_intl_number_format", + "use_locales", + "use_timestamp", + "storage" +] + [features] hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"] ssr = [ diff --git a/examples/sync_signal/Cargo.toml b/examples/sync_signal/Cargo.toml index 0eae2b1..c072a2b 100644 --- a/examples/sync_signal/Cargo.toml +++ b/examples/sync_signal/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["sync_signal", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_active_element/Cargo.toml b/examples/use_active_element/Cargo.toml index c19c400..e5c31a5 100644 --- a/examples/use_active_element/Cargo.toml +++ b/examples/use_active_element/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_active_element", "docs"] } web-sys = { version = "0.3", features = ["HtmlElement", "DomStringMap"] } [dev-dependencies] diff --git a/examples/use_breakpoints/Cargo.toml b/examples/use_breakpoints/Cargo.toml index 22b894b..b022945 100644 --- a/examples/use_breakpoints/Cargo.toml +++ b/examples/use_breakpoints/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_breakpoints", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_broadcast_channel/Cargo.toml b/examples/use_broadcast_channel/Cargo.toml index a7bf756..3cfcd3f 100644 --- a/examples/use_broadcast_channel/Cargo.toml +++ b/examples/use_broadcast_channel/Cargo.toml @@ -9,7 +9,7 @@ codee = "0.1" console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_broadcast_channel", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_clipboard/Cargo.toml b/examples/use_clipboard/Cargo.toml index d85ad83..43cba10 100644 --- a/examples/use_clipboard/Cargo.toml +++ b/examples/use_clipboard/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_clipboard", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_color_mode/Cargo.toml b/examples/use_color_mode/Cargo.toml index ead2ef6..26874f0 100644 --- a/examples/use_color_mode/Cargo.toml +++ b/examples/use_color_mode/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_color_mode", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_cookie/Cargo.toml b/examples/use_cookie/Cargo.toml index c645550..2974155 100644 --- a/examples/use_cookie/Cargo.toml +++ b/examples/use_cookie/Cargo.toml @@ -9,7 +9,7 @@ codee = "0.1" console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_cookie", "docs"] } rand = "0.8" getrandom = { version = "0.2", features = ["js"] } web-sys = "0.3" diff --git a/examples/use_css_var/Cargo.toml b/examples/use_css_var/Cargo.toml index 267c40e..97d6fa6 100644 --- a/examples/use_css_var/Cargo.toml +++ b/examples/use_css_var/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_css_var", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_cycle_list/Cargo.toml b/examples/use_cycle_list/Cargo.toml index c59b61c..77f6c25 100644 --- a/examples/use_cycle_list/Cargo.toml +++ b/examples/use_cycle_list/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_cycle_list", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_debounce_fn/Cargo.toml b/examples/use_debounce_fn/Cargo.toml index d5f4621..c3f7b9e 100644 --- a/examples/use_debounce_fn/Cargo.toml +++ b/examples/use_debounce_fn/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_debounce_fn", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_device_orientation/Cargo.toml b/examples/use_device_orientation/Cargo.toml index 9a4c64a..5fec238 100644 --- a/examples/use_device_orientation/Cargo.toml +++ b/examples/use_device_orientation/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_device_orientation", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_device_pixel_ratio/Cargo.toml b/examples/use_device_pixel_ratio/Cargo.toml index 5874c65..98efdde 100644 --- a/examples/use_device_pixel_ratio/Cargo.toml +++ b/examples/use_device_pixel_ratio/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_device_pixel_ratio", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_display_media/Cargo.toml b/examples/use_display_media/Cargo.toml index c7ffe6a..f5f4b79 100644 --- a/examples/use_display_media/Cargo.toml +++ b/examples/use_display_media/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_display_media", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_document_visibility/Cargo.toml b/examples/use_document_visibility/Cargo.toml index cb9b8f1..8d5b019 100644 --- a/examples/use_document_visibility/Cargo.toml +++ b/examples/use_document_visibility/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_document_visibility", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_draggable/Cargo.toml b/examples/use_draggable/Cargo.toml index e2e9a61..8427afb 100644 --- a/examples/use_draggable/Cargo.toml +++ b/examples/use_draggable/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_draggable", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_drop_zone/Cargo.toml b/examples/use_drop_zone/Cargo.toml index 115dc9d..aa05fca 100644 --- a/examples/use_drop_zone/Cargo.toml +++ b/examples/use_drop_zone/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_drop_zone", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_element_bounding/Cargo.toml b/examples/use_element_bounding/Cargo.toml index 7620bcd..8ef72c3 100644 --- a/examples/use_element_bounding/Cargo.toml +++ b/examples/use_element_bounding/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_element_bounding", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_element_hover/Cargo.toml b/examples/use_element_hover/Cargo.toml index 9d90e62..9be576c 100644 --- a/examples/use_element_hover/Cargo.toml +++ b/examples/use_element_hover/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_element_hover", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_element_size/Cargo.toml b/examples/use_element_size/Cargo.toml index daf02f0..4e71f62 100644 --- a/examples/use_element_size/Cargo.toml +++ b/examples/use_element_size/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_element_size", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_element_visibility/Cargo.toml b/examples/use_element_visibility/Cargo.toml index 50ba543..3506775 100644 --- a/examples/use_element_visibility/Cargo.toml +++ b/examples/use_element_visibility/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_element_visibility", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_event_listener/Cargo.toml b/examples/use_event_listener/Cargo.toml index 653bb76..d0e75c1 100644 --- a/examples/use_event_listener/Cargo.toml +++ b/examples/use_event_listener/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../.." } +leptos-use = { path = "../..", features = ["use_event_listener"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_favicon/Cargo.toml b/examples/use_favicon/Cargo.toml index 260413a..38d4f05 100644 --- a/examples/use_favicon/Cargo.toml +++ b/examples/use_favicon/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_favicon", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_geolocation/Cargo.toml b/examples/use_geolocation/Cargo.toml index bb7c93e..4ded1d2 100644 --- a/examples/use_geolocation/Cargo.toml +++ b/examples/use_geolocation/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_geolocation", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_idle/Cargo.toml b/examples/use_idle/Cargo.toml index 1b412b4..0e8d92a 100644 --- a/examples/use_idle/Cargo.toml +++ b/examples/use_idle/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_idle", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_infinite_scroll/Cargo.toml b/examples/use_infinite_scroll/Cargo.toml index e55811a..52cafcb 100644 --- a/examples/use_infinite_scroll/Cargo.toml +++ b/examples/use_infinite_scroll/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_infinite_scroll", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_intersection_observer/Cargo.toml b/examples/use_intersection_observer/Cargo.toml index b401615..b8c5d1a 100644 --- a/examples/use_intersection_observer/Cargo.toml +++ b/examples/use_intersection_observer/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_intersection_observer", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_interval/Cargo.toml b/examples/use_interval/Cargo.toml index a49f0cd..cd02ec5 100644 --- a/examples/use_interval/Cargo.toml +++ b/examples/use_interval/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_interval", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_interval_fn/Cargo.toml b/examples/use_interval_fn/Cargo.toml index 86bc8b2..96de322 100644 --- a/examples/use_interval_fn/Cargo.toml +++ b/examples/use_interval_fn/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs", "math"] } +leptos-use = { path = "../..", features = ["use_interval_fn", "docs", "math"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_intl_number_format/Cargo.toml b/examples/use_intl_number_format/Cargo.toml index 7eadd70..5ed97da 100644 --- a/examples/use_intl_number_format/Cargo.toml +++ b/examples/use_intl_number_format/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_intl_number_format", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_locale/Cargo.toml b/examples/use_locale/Cargo.toml index 1a2555a..1c592fe 100644 --- a/examples/use_locale/Cargo.toml +++ b/examples/use_locale/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_locale", "docs"] } unic-langid = { version = "0.9", features = ["macros"] } web-sys = "0.3" diff --git a/examples/use_locales/Cargo.toml b/examples/use_locales/Cargo.toml index 05b5bc9..c98524c 100644 --- a/examples/use_locales/Cargo.toml +++ b/examples/use_locales/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_locales", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_media_query/Cargo.toml b/examples/use_media_query/Cargo.toml index 345aa87..a57d7fe 100644 --- a/examples/use_media_query/Cargo.toml +++ b/examples/use_media_query/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_media_query", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_mouse/Cargo.toml b/examples/use_mouse/Cargo.toml index 1c91a04..cb2dea3 100644 --- a/examples/use_mouse/Cargo.toml +++ b/examples/use_mouse/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_mouse", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_mouse_in_element/Cargo.toml b/examples/use_mouse_in_element/Cargo.toml index ac23964..2823591 100644 --- a/examples/use_mouse_in_element/Cargo.toml +++ b/examples/use_mouse_in_element/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_mouse_in_element", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_mutation_observer/Cargo.toml b/examples/use_mutation_observer/Cargo.toml index fcf12fd..c85533a 100644 --- a/examples/use_mutation_observer/Cargo.toml +++ b/examples/use_mutation_observer/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_mutation_observer", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_permission/Cargo.toml b/examples/use_permission/Cargo.toml index 17f2388..f03e633 100644 --- a/examples/use_permission/Cargo.toml +++ b/examples/use_permission/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_permission", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_prefers_reduced_motion/Cargo.toml b/examples/use_prefers_reduced_motion/Cargo.toml index 4b0d55a..3cdeb8d 100644 --- a/examples/use_prefers_reduced_motion/Cargo.toml +++ b/examples/use_prefers_reduced_motion/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_prefers_reduced_motion", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_raf_fn/Cargo.toml b/examples/use_raf_fn/Cargo.toml index 48b8cd9..e9c4c57 100644 --- a/examples/use_raf_fn/Cargo.toml +++ b/examples/use_raf_fn/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_raf_fn", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_resize_observer/Cargo.toml b/examples/use_resize_observer/Cargo.toml index 0ce7f4c..8ba4ed2 100644 --- a/examples/use_resize_observer/Cargo.toml +++ b/examples/use_resize_observer/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_resize_observer", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_scroll/Cargo.toml b/examples/use_scroll/Cargo.toml index ccb133a..25874cd 100644 --- a/examples/use_scroll/Cargo.toml +++ b/examples/use_scroll/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_scroll", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_service_worker/Cargo.toml b/examples/use_service_worker/Cargo.toml index 8e3b8c7..f074dd0 100644 --- a/examples/use_service_worker/Cargo.toml +++ b/examples/use_service_worker/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_service_worker", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_sorted/Cargo.toml b/examples/use_sorted/Cargo.toml index 05462ac..8ff335f 100644 --- a/examples/use_sorted/Cargo.toml +++ b/examples/use_sorted/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_sorted", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_storage/Cargo.toml b/examples/use_storage/Cargo.toml index 5174789..b8b2285 100644 --- a/examples/use_storage/Cargo.toml +++ b/examples/use_storage/Cargo.toml @@ -8,7 +8,7 @@ codee = { version = "0.1", features = ["json_serde"] } console_error_panic_hook = "0.1" console_log = "1" leptos = { version = "0.6", features = ["nightly", "csr"] } -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["storage", "docs"] } log = "0.4" serde = "1.0.163" web-sys = "0.3" diff --git a/examples/use_throttle_fn/Cargo.toml b/examples/use_throttle_fn/Cargo.toml index 04d6006..d39fc8d 100644 --- a/examples/use_throttle_fn/Cargo.toml +++ b/examples/use_throttle_fn/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_throttle_fn", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_timeout_fn/Cargo.toml b/examples/use_timeout_fn/Cargo.toml index 9b0cfa4..608afac 100644 --- a/examples/use_timeout_fn/Cargo.toml +++ b/examples/use_timeout_fn/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_timeout_fn", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_timestamp/Cargo.toml b/examples/use_timestamp/Cargo.toml index a065eb4..5e0a16f 100644 --- a/examples/use_timestamp/Cargo.toml +++ b/examples/use_timestamp/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_timestamp", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_user_media/Cargo.toml b/examples/use_user_media/Cargo.toml index ffd38b8..170c4af 100644 --- a/examples/use_user_media/Cargo.toml +++ b/examples/use_user_media/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_user_media", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_web_notification/Cargo.toml b/examples/use_web_notification/Cargo.toml index 216f31e..f499927 100644 --- a/examples/use_web_notification/Cargo.toml +++ b/examples/use_web_notification/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_web_notification", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_websocket/Cargo.toml b/examples/use_websocket/Cargo.toml index 2eb5095..26ed9a6 100644 --- a/examples/use_websocket/Cargo.toml +++ b/examples/use_websocket/Cargo.toml @@ -9,7 +9,7 @@ codee = { version = "0.1", features = ["msgpack_serde"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_websocket", "docs"] } serde = { version = "1", features = ["derive"] } web-sys = "0.3" diff --git a/examples/use_webtransport/Cargo.toml b/examples/use_webtransport/Cargo.toml index 5291647..680dc93 100644 --- a/examples/use_webtransport/Cargo.toml +++ b/examples/use_webtransport/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_web_notification", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_window_focus/Cargo.toml b/examples/use_window_focus/Cargo.toml index d157e75..ff9224a 100644 --- a/examples/use_window_focus/Cargo.toml +++ b/examples/use_window_focus/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_window_focus", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_window_scroll/Cargo.toml b/examples/use_window_scroll/Cargo.toml index d8a1c48..43092e2 100644 --- a/examples/use_window_scroll/Cargo.toml +++ b/examples/use_window_scroll/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["use_window_scroll", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/watch_debounced/Cargo.toml b/examples/watch_debounced/Cargo.toml index 8af3c77..b7d1872 100644 --- a/examples/watch_debounced/Cargo.toml +++ b/examples/watch_debounced/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["watch_debounced", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/watch_pausable/Cargo.toml b/examples/watch_pausable/Cargo.toml index a14897d..548f01a 100644 --- a/examples/watch_pausable/Cargo.toml +++ b/examples/watch_pausable/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["watch_pausable", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/watch_throttled/Cargo.toml b/examples/watch_throttled/Cargo.toml index e711c4f..d69a67a 100644 --- a/examples/watch_throttled/Cargo.toml +++ b/examples/watch_throttled/Cargo.toml @@ -8,7 +8,7 @@ leptos = { version = "0.6", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../..", features = ["watch_throttled", "docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/src/core/mod.rs b/src/core/mod.rs index 3fe5ca3..0b51baa 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -1,26 +1,32 @@ mod connection_ready_state; mod datetime; mod direction; +#[cfg(feature = "element")] mod element_maybe_signal; +#[cfg(feature = "element")] mod elements_maybe_signal; mod maybe_rw_signal; mod pointer_type; mod position; +mod reconnect_limit; mod size; mod ssr_safe_method; -mod storage; +#[cfg(feature = "use_color_mode")] pub(crate) mod url; mod use_rw_signal; pub use connection_ready_state::*; pub(crate) use datetime::*; pub use direction::*; +#[cfg(feature = "element")] pub use element_maybe_signal::*; +#[cfg(feature = "element")] pub use elements_maybe_signal::*; pub use maybe_rw_signal::*; pub use pointer_type::*; pub use position::*; +pub use reconnect_limit::*; pub use size::*; +#[allow(unused_imports)] pub(crate) use ssr_safe_method::*; -pub use storage::*; pub use use_rw_signal::*; diff --git a/src/core/reconnect_limit.rs b/src/core/reconnect_limit.rs new file mode 100644 index 0000000..5d28b2c --- /dev/null +++ b/src/core/reconnect_limit.rs @@ -0,0 +1,20 @@ +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum ReconnectLimit { + Infinite, + Limited(u64), +} + +impl Default for ReconnectLimit { + fn default() -> Self { + ReconnectLimit::Limited(3) + } +} + +impl ReconnectLimit { + pub fn is_exceeded_by(self, times: u64) -> bool { + match self { + ReconnectLimit::Infinite => false, + ReconnectLimit::Limited(limit) => times >= limit, + } + } +} diff --git a/src/core/ssr_safe_method.rs b/src/core/ssr_safe_method.rs index 9ffa513..da46452 100644 --- a/src/core/ssr_safe_method.rs +++ b/src/core/ssr_safe_method.rs @@ -1,3 +1,5 @@ +#![allow(unused_macros, unused_imports)] + macro_rules! impl_ssr_safe_method { ( $(#[$attr:meta])* diff --git a/src/core/storage.rs b/src/core/storage.rs deleted file mode 100644 index 8390217..0000000 --- a/src/core/storage.rs +++ /dev/null @@ -1,21 +0,0 @@ -use leptos::window; -use wasm_bindgen::JsValue; - -/// Local or session storage or a custom store that is a `web_sys::Storage`. -#[derive(Default)] -pub enum StorageType { - #[default] - Local, - Session, - Custom(web_sys::Storage), -} - -impl StorageType { - pub fn into_storage(self) -> Result, JsValue> { - match self { - StorageType::Local => window().local_storage(), - StorageType::Session => window().session_storage(), - StorageType::Custom(storage) => Ok(Some(storage)), - } - } -} diff --git a/src/lib.rs b/src/lib.rs index 0e43a6b..1b18ab1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,150 +7,291 @@ pub mod core; pub mod docs; #[cfg(feature = "math")] pub mod math; +#[cfg(feature = "storage")] pub mod storage; pub mod utils; +pub use core::ReconnectLimit; + // #[cfg(web_sys_unstable_apis)] // mod use_webtransport; // #[cfg(web_sys_unstable_apis)] // pub use use_webtransport::*; +#[cfg(feature = "is_err")] mod is_err; +#[cfg(feature = "is_none")] mod is_none; +#[cfg(feature = "is_ok")] mod is_ok; +#[cfg(feature = "is_some")] mod is_some; +#[cfg(feature = "on_click_outside")] mod on_click_outside; +#[cfg(feature = "signal_debounced")] mod signal_debounced; +#[cfg(feature = "signal_throttled")] mod signal_throttled; +#[cfg(feature = "sync_signal")] mod sync_signal; +#[cfg(feature = "use_active_element")] mod use_active_element; +#[cfg(feature = "use_breakpoints")] mod use_breakpoints; +#[cfg(feature = "use_broadcast_channel")] mod use_broadcast_channel; +#[cfg(feature = "use_clipboard")] mod use_clipboard; +#[cfg(feature = "use_color_mode")] mod use_color_mode; +#[cfg(feature = "use_cookie")] mod use_cookie; +#[cfg(feature = "use_css_var")] mod use_css_var; +#[cfg(feature = "use_cycle_list")] mod use_cycle_list; +#[cfg(feature = "use_debounce_fn")] mod use_debounce_fn; +#[cfg(feature = "use_device_orientation")] mod use_device_orientation; +#[cfg(feature = "use_device_pixel_ratio")] mod use_device_pixel_ratio; +#[cfg(feature = "use_display_media")] mod use_display_media; +#[cfg(feature = "use_document")] mod use_document; +#[cfg(feature = "use_document_visibility")] mod use_document_visibility; +#[cfg(feature = "use_draggable")] mod use_draggable; +#[cfg(feature = "use_drop_zone")] mod use_drop_zone; +#[cfg(feature = "use_element_bounding")] mod use_element_bounding; +#[cfg(feature = "use_element_hover")] mod use_element_hover; +#[cfg(feature = "use_element_size")] mod use_element_size; +#[cfg(feature = "use_element_visibility")] mod use_element_visibility; +#[cfg(feature = "use_event_listener")] mod use_event_listener; +#[cfg(feature = "use_event_source")] mod use_event_source; +#[cfg(feature = "use_favicon")] mod use_favicon; +#[cfg(feature = "use_geolocation")] mod use_geolocation; +#[cfg(feature = "use_idle")] mod use_idle; +#[cfg(feature = "use_infinite_scroll")] mod use_infinite_scroll; +#[cfg(feature = "use_intersection_observer")] mod use_intersection_observer; +#[cfg(feature = "use_interval")] mod use_interval; +#[cfg(feature = "use_interval_fn")] mod use_interval_fn; +#[cfg(feature = "use_intl_number_format")] mod use_intl_number_format; +#[cfg(feature = "use_locale")] mod use_locale; +#[cfg(feature = "use_locales")] mod use_locales; +#[cfg(feature = "use_media_query")] mod use_media_query; +#[cfg(feature = "use_mouse")] mod use_mouse; +#[cfg(feature = "use_mouse_in_element")] mod use_mouse_in_element; +#[cfg(feature = "use_mutation_observer")] mod use_mutation_observer; +#[cfg(feature = "use_permission")] mod use_permission; +#[cfg(feature = "use_preferred_contrast")] mod use_preferred_contrast; +#[cfg(feature = "use_preferred_dark")] mod use_preferred_dark; +#[cfg(feature = "use_prefers_reduced_motion")] mod use_prefers_reduced_motion; +#[cfg(feature = "use_raf_fn")] mod use_raf_fn; +#[cfg(feature = "use_resize_observer")] mod use_resize_observer; +#[cfg(feature = "use_scroll")] mod use_scroll; +#[cfg(feature = "use_service_worker")] mod use_service_worker; +#[cfg(feature = "use_sorted")] mod use_sorted; +#[cfg(feature = "use_supported")] mod use_supported; +#[cfg(feature = "use_throttle_fn")] mod use_throttle_fn; +#[cfg(feature = "use_timeout_fn")] mod use_timeout_fn; +#[cfg(feature = "use_timestamp")] mod use_timestamp; +#[cfg(feature = "use_to_string")] mod use_to_string; +#[cfg(feature = "use_user_media")] mod use_user_media; +#[cfg(feature = "use_web_notification")] mod use_web_notification; +#[cfg(feature = "use_websocket")] mod use_websocket; +#[cfg(feature = "use_window")] mod use_window; +#[cfg(feature = "use_window_focus")] mod use_window_focus; +#[cfg(feature = "use_window_scroll")] mod use_window_scroll; +#[cfg(feature = "watch_debounced")] mod watch_debounced; +#[cfg(feature = "watch_pausable")] mod watch_pausable; +#[cfg(feature = "watch_throttled")] mod watch_throttled; +#[cfg(feature = "watch_with_options")] mod watch_with_options; +#[cfg(feature = "whenever")] mod whenever; +#[cfg(feature = "is_err")] pub use is_err::*; +#[cfg(feature = "is_none")] pub use is_none::*; +#[cfg(feature = "is_ok")] pub use is_ok::*; +#[cfg(feature = "is_some")] pub use is_some::*; +#[cfg(feature = "on_click_outside")] pub use on_click_outside::*; +#[cfg(feature = "signal_debounced")] pub use signal_debounced::*; +#[cfg(feature = "signal_throttled")] pub use signal_throttled::*; +#[cfg(feature = "sync_signal")] pub use sync_signal::*; +#[cfg(feature = "use_active_element")] pub use use_active_element::*; +#[cfg(feature = "use_breakpoints")] pub use use_breakpoints::*; +#[cfg(feature = "use_broadcast_channel")] pub use use_broadcast_channel::*; +#[cfg(feature = "use_clipboard")] pub use use_clipboard::*; +#[cfg(feature = "use_color_mode")] pub use use_color_mode::*; +#[cfg(feature = "use_cookie")] pub use use_cookie::*; +#[cfg(feature = "use_css_var")] pub use use_css_var::*; +#[cfg(feature = "use_cycle_list")] pub use use_cycle_list::*; +#[cfg(feature = "use_debounce_fn")] pub use use_debounce_fn::*; +#[cfg(feature = "use_device_orientation")] pub use use_device_orientation::*; +#[cfg(feature = "use_device_pixel_ratio")] pub use use_device_pixel_ratio::*; +#[cfg(feature = "use_display_media")] pub use use_display_media::*; +#[cfg(feature = "use_document")] pub use use_document::*; +#[cfg(feature = "use_document_visibility")] pub use use_document_visibility::*; +#[cfg(feature = "use_draggable")] pub use use_draggable::*; +#[cfg(feature = "use_drop_zone")] pub use use_drop_zone::*; +#[cfg(feature = "use_element_bounding")] pub use use_element_bounding::*; +#[cfg(feature = "use_element_hover")] pub use use_element_hover::*; +#[cfg(feature = "use_element_size")] pub use use_element_size::*; +#[cfg(feature = "use_element_visibility")] pub use use_element_visibility::*; +#[cfg(feature = "use_event_listener")] pub use use_event_listener::*; +#[cfg(feature = "use_event_source")] pub use use_event_source::*; +#[cfg(feature = "use_favicon")] pub use use_favicon::*; +#[cfg(feature = "use_geolocation")] pub use use_geolocation::*; +#[cfg(feature = "use_idle")] pub use use_idle::*; +#[cfg(feature = "use_infinite_scroll")] pub use use_infinite_scroll::*; +#[cfg(feature = "use_intersection_observer")] pub use use_intersection_observer::*; +#[cfg(feature = "use_interval")] pub use use_interval::*; +#[cfg(feature = "use_interval_fn")] pub use use_interval_fn::*; +#[cfg(feature = "use_intl_number_format")] pub use use_intl_number_format::*; +#[cfg(feature = "use_locale")] pub use use_locale::*; +#[cfg(feature = "use_locales")] pub use use_locales::*; +#[cfg(feature = "use_media_query")] pub use use_media_query::*; +#[cfg(feature = "use_mouse")] pub use use_mouse::*; +#[cfg(feature = "use_mouse_in_element")] pub use use_mouse_in_element::*; +#[cfg(feature = "use_mutation_observer")] pub use use_mutation_observer::*; +#[cfg(feature = "use_permission")] pub use use_permission::*; +#[cfg(feature = "use_preferred_contrast")] pub use use_preferred_contrast::*; +#[cfg(feature = "use_preferred_dark")] pub use use_preferred_dark::*; +#[cfg(feature = "use_prefers_reduced_motion")] pub use use_prefers_reduced_motion::*; +#[cfg(feature = "use_raf_fn")] pub use use_raf_fn::*; +#[cfg(feature = "use_resize_observer")] pub use use_resize_observer::*; +#[cfg(feature = "use_scroll")] pub use use_scroll::*; +#[cfg(feature = "use_service_worker")] pub use use_service_worker::*; +#[cfg(feature = "use_sorted")] pub use use_sorted::*; +#[cfg(feature = "use_supported")] pub use use_supported::*; +#[cfg(feature = "use_throttle_fn")] pub use use_throttle_fn::*; +#[cfg(feature = "use_timeout_fn")] pub use use_timeout_fn::*; +#[cfg(feature = "use_timestamp")] pub use use_timestamp::*; +#[cfg(feature = "use_to_string")] pub use use_to_string::*; +#[cfg(feature = "use_user_media")] pub use use_user_media::*; +#[cfg(feature = "use_web_notification")] pub use use_web_notification::*; +#[cfg(feature = "use_websocket")] pub use use_websocket::*; +#[cfg(feature = "use_window")] pub use use_window::*; +#[cfg(feature = "use_window_focus")] pub use use_window_focus::*; +#[cfg(feature = "use_window_scroll")] pub use use_window_scroll::*; +#[cfg(feature = "watch_debounced")] pub use watch_debounced::*; +#[cfg(feature = "watch_pausable")] pub use watch_pausable::*; +#[cfg(feature = "watch_throttled")] pub use watch_throttled::*; +#[cfg(feature = "watch_with_options")] pub use watch_with_options::*; +#[cfg(feature = "whenever")] pub use whenever::*; diff --git a/src/storage/mod.rs b/src/storage/mod.rs index 54f79db..5930028 100644 --- a/src/storage/mod.rs +++ b/src/storage/mod.rs @@ -2,7 +2,28 @@ mod use_local_storage; mod use_session_storage; mod use_storage; -pub use crate::core::StorageType; pub use use_local_storage::*; pub use use_session_storage::*; pub use use_storage::*; + +use leptos::window; +use wasm_bindgen::JsValue; + +/// Local or session storage or a custom store that is a `web_sys::Storage`. +#[derive(Default)] +pub enum StorageType { + #[default] + Local, + Session, + Custom(web_sys::Storage), +} + +impl StorageType { + pub fn into_storage(self) -> Result, JsValue> { + match self { + StorageType::Local => window().local_storage(), + StorageType::Session => window().session_storage(), + StorageType::Custom(storage) => Ok(Some(storage)), + } + } +} diff --git a/src/storage/use_storage.rs b/src/storage/use_storage.rs index 91b56c0..86705e9 100644 --- a/src/storage/use_storage.rs +++ b/src/storage/use_storage.rs @@ -1,7 +1,4 @@ -use crate::{ - core::{MaybeRwSignal, StorageType}, - utils::FilterOptions, -}; +use crate::{core::MaybeRwSignal, storage::StorageType, utils::FilterOptions}; use codee::{CodecError, Decoder, Encoder}; use default_struct_builder::DefaultBuilder; use leptos::*; diff --git a/src/use_color_mode.rs b/src/use_color_mode.rs index 9f3719e..28ded80 100644 --- a/src/use_color_mode.rs +++ b/src/use_color_mode.rs @@ -1,7 +1,6 @@ use crate::core::url; -use crate::core::StorageType; use crate::core::{ElementMaybeSignal, MaybeRwSignal}; -use crate::storage::{use_storage_with_options, UseStorageOptions}; +use crate::storage::{use_storage_with_options, StorageType, UseStorageOptions}; use crate::utils::get_header; use crate::{ sync_signal_with_options, use_cookie, use_preferred_dark_with_options, SyncSignalOptions, diff --git a/src/use_websocket.rs b/src/use_websocket.rs index 48a9596..51910e7 100644 --- a/src/use_websocket.rs +++ b/src/use_websocket.rs @@ -7,7 +7,7 @@ use std::rc::Rc; use std::time::Duration; use thiserror::Error; -use crate::core::ConnectionReadyState; +use crate::{core::ConnectionReadyState, ReconnectLimit}; use codee::{ CodecError, Decoder, Encoder, HybridCoderError, HybridDecoder, HybridEncoder, IsBinary, }; @@ -608,26 +608,6 @@ where send, } } -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum ReconnectLimit { - Infinite, - Limited(u64), -} - -impl Default for ReconnectLimit { - fn default() -> Self { - ReconnectLimit::Limited(3) - } -} - -impl ReconnectLimit { - pub fn is_exceeded_by(self, times: u64) -> bool { - match self { - ReconnectLimit::Infinite => false, - ReconnectLimit::Limited(limit) => times >= limit, - } - } -} type RcFnBytes = Rc; diff --git a/src/utils/header_macro.rs b/src/utils/header_macro.rs index 4f6f087..2664f78 100644 --- a/src/utils/header_macro.rs +++ b/src/utils/header_macro.rs @@ -1,3 +1,5 @@ +#![allow(unused_macros, unused_imports)] + macro_rules! get_header { ( $header_name:expr, diff --git a/src/utils/js_value_from_to_string.rs b/src/utils/js_value_from_to_string.rs index f371c96..4149c4c 100644 --- a/src/utils/js_value_from_to_string.rs +++ b/src/utils/js_value_from_to_string.rs @@ -1,3 +1,5 @@ +#![allow(unused_macros, unused_imports)] + macro_rules! js_value_from_to_string { ($name:ident) => { impl From<$name> for JsValue { diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 32d43b0..76b179a 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -5,6 +5,7 @@ mod filters; ))] mod header; mod header_macro; +#[cfg(feature = "is")] mod is; mod js; mod js_value_from_to_string; @@ -18,8 +19,12 @@ pub use filters::*; any(feature = "axum", feature = "actix", feature = "spin") ))] pub use header::*; +#[allow(unused_imports)] pub(crate) use header_macro::*; +#[cfg(feature = "is")] pub use is::*; +#[allow(unused_imports)] pub(crate) use js_value_from_to_string::*; pub use pausable::*; +#[allow(unused_imports)] pub(crate) use signal_filtered::*; diff --git a/src/utils/signal_filtered.rs b/src/utils/signal_filtered.rs index 1e7ad03..365c871 100644 --- a/src/utils/signal_filtered.rs +++ b/src/utils/signal_filtered.rs @@ -1,3 +1,5 @@ +#![allow(unused_macros, unused_imports)] + macro_rules! signal_filtered { ( $(#[$outer:meta])* diff --git a/src/watch_debounced.rs b/src/watch_debounced.rs index 2dbe3ef..c0b12a1 100644 --- a/src/watch_debounced.rs +++ b/src/watch_debounced.rs @@ -1,4 +1,4 @@ -use crate::{watch_with_options, DebounceOptions, WatchOptions}; +use crate::{watch_with_options, utils::DebounceOptions, WatchOptions}; use default_struct_builder::DefaultBuilder; use leptos::*; diff --git a/src/watch_throttled.rs b/src/watch_throttled.rs index 5fd585f..e70f5e0 100644 --- a/src/watch_throttled.rs +++ b/src/watch_throttled.rs @@ -1,4 +1,4 @@ -use crate::{watch_with_options, ThrottleOptions, WatchOptions}; +use crate::{watch_with_options, utils::ThrottleOptions, WatchOptions}; use default_struct_builder::DefaultBuilder; /// A throttled version of `leptos::watch`.