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
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 @@
-
+
\ 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! {
+