mirror of
https://github.com/adoyle0/leptos-use.git
synced 2025-02-02 10:54:15 -05:00
parent
ffff14ea9c
commit
84396b7675
7 changed files with 503 additions and 61 deletions
|
@ -14,6 +14,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
### Changes 🔥
|
### Changes 🔥
|
||||||
|
|
||||||
- The `UseMouseReturn` signals `x`, `y`, and `source_type` are now of type `Signal<f64>` instead of `ReadSignal<f64>`.
|
- The `UseMouseReturn` signals `x`, `y`, and `source_type` are now of type `Signal<f64>` instead of `ReadSignal<f64>`.
|
||||||
|
- You can now convert `leptos::html::HtmlElement<T>` into `Element(s)MaybeSignal`. This should make functions a lot easier to use in directives.
|
||||||
|
- There's now a chapter in the book especially for `Element(s)MaybeSignal`.
|
||||||
|
|
||||||
## [0.9.0] - 2023-12-06
|
## [0.9.0] - 2023-12-06
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
[Introduction](introduction.md)
|
[Introduction](introduction.md)
|
||||||
[Get Started](get_started.md)
|
[Get Started](get_started.md)
|
||||||
|
[Element Parameters](element_parameters.md)
|
||||||
[Server-Side Rendering](server_side_rendering.md)
|
[Server-Side Rendering](server_side_rendering.md)
|
||||||
[Changelog](changelog.md)
|
[Changelog](changelog.md)
|
||||||
[Functions](functions.md)
|
[Functions](functions.md)
|
||||||
|
|
95
docs/book/src/element_parameters.md
Normal file
95
docs/book/src/element_parameters.md
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
# Element Parameters
|
||||||
|
|
||||||
|
Many functions in this library operate on HTML/SVG elements. For example, the
|
||||||
|
function [`use_element_size`](elements/use_element_size.md) returns the width and height of an element:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
# use leptos::{*, html::Div};
|
||||||
|
# use leptos_use::{use_element_size, UseElementSizeReturn};
|
||||||
|
#
|
||||||
|
# #[component]
|
||||||
|
# pub fn Component() -> impl IntoView {
|
||||||
|
let el = create_node_ref::<Div>();
|
||||||
|
|
||||||
|
let UseElementSizeReturn { width, height } = use_element_size(el);
|
||||||
|
|
||||||
|
view! {
|
||||||
|
<div node_ref=el></div>
|
||||||
|
}
|
||||||
|
# }
|
||||||
|
```
|
||||||
|
|
||||||
|
In the example above we used a Leptos `NodeRef` to pass into the function. But that is not
|
||||||
|
the only way you can do that. All of these work as well:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use_element_size(window().body()); // Option<web_sys::Element>
|
||||||
|
use_element_size(window().body().unwrap()); // web_sys::Element
|
||||||
|
use_element_size("div > p.some-class"); // &str or String intepreted as CSS selector
|
||||||
|
|
||||||
|
pub fn some_directive(el: HtmlElement<AnyElement>) {
|
||||||
|
use_element_size(el); // leptos::html::HtmlElement<T>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Signal of Strings: `Signal<String>`, `ReadSignal<String>`, `RwSignal<String>`, `Memo<String>`; also works with `&str`:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let (str_signal, set_str_signal) = create_signal("div > p.some-class".to_string());
|
||||||
|
use_element_size(str_signal);
|
||||||
|
```
|
||||||
|
|
||||||
|
Signals of Elements: `Signal<web_sys::Element>`, `ReadSignal<web_sys::Element>`, `RwSignal<web_sys::Element>`, `Memo<web_sys::Element>`; also works with `Option<web_sys::Element>`:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let (el_signal, set_el_signal) = create_signal(document().query_selector("div > p.some-class").unwrap());
|
||||||
|
use_element_size(el_signal);
|
||||||
|
```
|
||||||
|
|
||||||
|
## How it works
|
||||||
|
|
||||||
|
Looking at the source code of `use_element_size` you'll find sth like
|
||||||
|
|
||||||
|
```rust
|
||||||
|
pub fn use_element_size(el: Into<ElementMaybeSignal<...>>) -> UseElementSizeReturn {}
|
||||||
|
```
|
||||||
|
|
||||||
|
All the above code works because there are `From` implementations for all of these
|
||||||
|
types for `ElementMaybeSignal`.
|
||||||
|
|
||||||
|
## `ElementsMaybeSignal`
|
||||||
|
|
||||||
|
Some functions work on one or more elements. Take [`use_resize_observer`](elements/use_resize_observer.md) for example.
|
||||||
|
This works very much the same way as described above but instead of `Into<ElementMaybeSignal>`
|
||||||
|
it takes an `Into<ElementsMaybeSignal>` (note the plural). This means you can use it exactly in
|
||||||
|
the same ways as you saw with the singular `ElementMaybeSignal`. Only this time, when you use
|
||||||
|
`String` or `&str` it will be interpreted as CSS selector with `query_selector_all`.
|
||||||
|
|
||||||
|
But you can also use it with containers.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// Array of Option<web_sys::Element>
|
||||||
|
use_resize_observer([window().body(), document().query_selector("div > p.some-class").unsrap()]);
|
||||||
|
|
||||||
|
// Vec of &str. All of them will be interpreted as CSS selectors with query_selector_all() and the
|
||||||
|
// results will be merged into one Vec.
|
||||||
|
use_resize_observer(vec!["div > p.some-class", "p.some-class"]);
|
||||||
|
|
||||||
|
// Slice of NodeRef
|
||||||
|
let node_ref1 = create_node_ref::<Div>();
|
||||||
|
let node_ref2 = create_node_ref::<Div>();
|
||||||
|
use_resize_observer(vec![node_ref1, node_ref2].as_slice());
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage in Options
|
||||||
|
|
||||||
|
Some functions have options that take `Element(s)MaybeSignal`.
|
||||||
|
They can be used in the same way.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use_mouse_with_options(
|
||||||
|
UseMouseOptions::default().target("div > p.some-class")
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
See also ["Excluding Elements" in `on_click_outside`](elements/on_click_outside.md#excluding-elements).
|
|
@ -8,7 +8,7 @@ async fn main() {
|
||||||
use leptos_use_ssr::app::*;
|
use leptos_use_ssr::app::*;
|
||||||
use leptos_use_ssr::fileserv::file_and_error_handler;
|
use leptos_use_ssr::fileserv::file_and_error_handler;
|
||||||
|
|
||||||
simple_logger::init_with_level(log::Level::Debug).expect("couldn't initialize logging");
|
simple_logger::init_with_level(log::Level::Info).expect("couldn't initialize logging");
|
||||||
|
|
||||||
// Setting get_configuration(None) means we'll be using cargo-leptos's env values
|
// Setting get_configuration(None) means we'll be using cargo-leptos's env values
|
||||||
// For deployment these variables are:
|
// For deployment these variables are:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{UseDocument, UseWindow};
|
use crate::{UseDocument, UseWindow};
|
||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
use leptos::html::ElementDescriptor;
|
use leptos::html::{ElementDescriptor, HtmlElement};
|
||||||
use leptos::*;
|
use leptos::*;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
@ -196,11 +196,13 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E> From<Signal<String>> for ElementMaybeSignal<web_sys::Element, E>
|
macro_rules! impl_from_signal_string {
|
||||||
|
($ty:ty) => {
|
||||||
|
impl<E> From<$ty> for ElementMaybeSignal<web_sys::Element, E>
|
||||||
where
|
where
|
||||||
E: From<web_sys::Element> + 'static,
|
E: From<web_sys::Element> + 'static,
|
||||||
{
|
{
|
||||||
fn from(signal: Signal<String>) -> Self {
|
fn from(signal: $ty) -> Self {
|
||||||
cfg_if! { if #[cfg(feature = "ssr")] {
|
cfg_if! { if #[cfg(feature = "ssr")] {
|
||||||
let _ = signal;
|
let _ = signal;
|
||||||
Self::Dynamic(Signal::derive(|| None))
|
Self::Dynamic(Signal::derive(|| None))
|
||||||
|
@ -212,6 +214,18 @@ where
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_from_signal_string!(Signal<String>);
|
||||||
|
impl_from_signal_string!(ReadSignal<String>);
|
||||||
|
impl_from_signal_string!(RwSignal<String>);
|
||||||
|
impl_from_signal_string!(Memo<String>);
|
||||||
|
|
||||||
|
impl_from_signal_string!(Signal<&str>);
|
||||||
|
impl_from_signal_string!(ReadSignal<&str>);
|
||||||
|
impl_from_signal_string!(RwSignal<&str>);
|
||||||
|
impl_from_signal_string!(Memo<&str>);
|
||||||
|
|
||||||
// From signal ///////////////////////////////////////////////////////////////
|
// From signal ///////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@ -274,3 +288,22 @@ macro_rules! impl_from_node_ref {
|
||||||
|
|
||||||
impl_from_node_ref!(web_sys::EventTarget);
|
impl_from_node_ref!(web_sys::EventTarget);
|
||||||
impl_from_node_ref!(web_sys::Element);
|
impl_from_node_ref!(web_sys::Element);
|
||||||
|
|
||||||
|
// From leptos::html::HTMLElement ///////////////////////////////////////////////
|
||||||
|
|
||||||
|
macro_rules! impl_from_html_element {
|
||||||
|
($ty:ty) => {
|
||||||
|
impl<HtmlEl> From<HtmlElement<HtmlEl>> for ElementMaybeSignal<$ty, $ty>
|
||||||
|
where
|
||||||
|
HtmlEl: ElementDescriptor + std::ops::Deref<Target = $ty>,
|
||||||
|
{
|
||||||
|
fn from(value: HtmlElement<HtmlEl>) -> Self {
|
||||||
|
let el: &$ty = value.deref();
|
||||||
|
Self::Static(Some(el.clone()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_from_html_element!(web_sys::EventTarget);
|
||||||
|
impl_from_html_element!(web_sys::Element);
|
||||||
|
|
|
@ -180,6 +180,9 @@ where
|
||||||
{
|
{
|
||||||
fn from(target: &'a str) -> Self {
|
fn from(target: &'a str) -> Self {
|
||||||
cfg_if! { if #[cfg(feature = "ssr")] {
|
cfg_if! { if #[cfg(feature = "ssr")] {
|
||||||
|
let _ = target;
|
||||||
|
Self::Static(vec![])
|
||||||
|
} else {
|
||||||
if let Ok(node_list) = document().query_selector_all(target) {
|
if let Ok(node_list) = document().query_selector_all(target) {
|
||||||
let mut list = Vec::with_capacity(node_list.length() as usize);
|
let mut list = Vec::with_capacity(node_list.length() as usize);
|
||||||
for i in 0..node_list.length() {
|
for i in 0..node_list.length() {
|
||||||
|
@ -191,9 +194,6 @@ where
|
||||||
} else {
|
} else {
|
||||||
Self::Static(vec![])
|
Self::Static(vec![])
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
let _ = target;
|
|
||||||
Self::Static(vec![])
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -207,11 +207,13 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E> From<Signal<String>> for ElementsMaybeSignal<web_sys::Node, E>
|
macro_rules! impl_from_signal_string {
|
||||||
|
($ty:ty) => {
|
||||||
|
impl<E> From<$ty> for ElementsMaybeSignal<web_sys::Node, E>
|
||||||
where
|
where
|
||||||
E: From<web_sys::Node> + 'static,
|
E: From<web_sys::Node> + 'static,
|
||||||
{
|
{
|
||||||
fn from(signal: Signal<String>) -> Self {
|
fn from(signal: $ty) -> Self {
|
||||||
cfg_if! { if #[cfg(feature = "ssr")] {
|
cfg_if! { if #[cfg(feature = "ssr")] {
|
||||||
Self::Dynamic(
|
Self::Dynamic(
|
||||||
create_memo(move |_| {
|
create_memo(move |_| {
|
||||||
|
@ -234,6 +236,18 @@ where
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_from_signal_string!(Signal<String>);
|
||||||
|
impl_from_signal_string!(ReadSignal<String>);
|
||||||
|
impl_from_signal_string!(RwSignal<String>);
|
||||||
|
impl_from_signal_string!(Memo<String>);
|
||||||
|
|
||||||
|
impl_from_signal_string!(Signal<&str>);
|
||||||
|
impl_from_signal_string!(ReadSignal<&str>);
|
||||||
|
impl_from_signal_string!(RwSignal<&str>);
|
||||||
|
impl_from_signal_string!(Memo<&str>);
|
||||||
|
|
||||||
// From single signal ///////////////////////////////////////////////////////////////
|
// From single signal ///////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@ -297,7 +311,26 @@ macro_rules! impl_from_node_ref {
|
||||||
impl_from_node_ref!(web_sys::EventTarget);
|
impl_from_node_ref!(web_sys::EventTarget);
|
||||||
impl_from_node_ref!(web_sys::Element);
|
impl_from_node_ref!(web_sys::Element);
|
||||||
|
|
||||||
// From multiple static elements //////////////////////////////////////////////////////////////
|
// From single leptos::html::HTMLElement ///////////////////////////////////////////
|
||||||
|
|
||||||
|
macro_rules! impl_from_html_element {
|
||||||
|
($ty:ty) => {
|
||||||
|
impl<HtmlEl> From<HtmlElement<HtmlEl>> for ElementsMaybeSignal<$ty, $ty>
|
||||||
|
where
|
||||||
|
HtmlEl: ElementDescriptor + std::ops::Deref<Target = $ty>,
|
||||||
|
{
|
||||||
|
fn from(value: HtmlElement<HtmlEl>) -> Self {
|
||||||
|
let el: &$ty = value.deref();
|
||||||
|
Self::Static(vec![Some(el.clone())])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_from_html_element!(web_sys::EventTarget);
|
||||||
|
impl_from_html_element!(web_sys::Element);
|
||||||
|
|
||||||
|
// From multiple static elements //////////////////////////////////////////////////////
|
||||||
|
|
||||||
impl<T, E> From<&[T]> for ElementsMaybeSignal<T, E>
|
impl<T, E> From<&[T]> for ElementsMaybeSignal<T, E>
|
||||||
where
|
where
|
||||||
|
@ -317,6 +350,105 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T, E> From<Vec<T>> for ElementsMaybeSignal<T, E>
|
||||||
|
where
|
||||||
|
T: Into<E> + Clone + 'static,
|
||||||
|
{
|
||||||
|
fn from(target: Vec<T>) -> Self {
|
||||||
|
Self::Static(target.iter().map(|t| Some(t.clone())).collect())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, E> From<Vec<Option<T>>> for ElementsMaybeSignal<T, E>
|
||||||
|
where
|
||||||
|
T: Into<E> + Clone + 'static,
|
||||||
|
{
|
||||||
|
fn from(target: Vec<Option<T>>) -> Self {
|
||||||
|
Self::Static(target.to_vec())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, E, const C: usize> From<[T; C]> for ElementsMaybeSignal<T, E>
|
||||||
|
where
|
||||||
|
T: Into<E> + Clone + 'static,
|
||||||
|
{
|
||||||
|
fn from(target: [T; C]) -> Self {
|
||||||
|
Self::Static(target.iter().map(|t| Some(t.clone())).collect())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, E, const C: usize> From<[Option<T>; C]> for ElementsMaybeSignal<T, E>
|
||||||
|
where
|
||||||
|
T: Into<E> + Clone + 'static,
|
||||||
|
{
|
||||||
|
fn from(target: [Option<T>; C]) -> Self {
|
||||||
|
Self::Static(target.to_vec())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// From multiple strings //////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
macro_rules! impl_from_strings_inner {
|
||||||
|
($el_ty:ty, $str_ty:ty, $target:ident) => {
|
||||||
|
Self::Static(
|
||||||
|
$target
|
||||||
|
.iter()
|
||||||
|
.filter_map(|sel: &$str_ty| -> Option<Vec<Option<$el_ty>>> {
|
||||||
|
cfg_if! { if #[cfg(feature = "ssr")] {
|
||||||
|
let _ = sel;
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
if let Ok(node_list) = document().query_selector_all(sel) {
|
||||||
|
let mut list = Vec::with_capacity(node_list.length() as usize);
|
||||||
|
for i in 0..node_list.length() {
|
||||||
|
let node: $el_ty = node_list.get(i).expect("checked the range").unchecked_into();
|
||||||
|
list.push(Some(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(list)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_from_strings_with_container {
|
||||||
|
($el_ty:ty, $str_ty:ty, $container_ty:ty) => {
|
||||||
|
impl From<$container_ty> for ElementsMaybeSignal<$el_ty, $el_ty> {
|
||||||
|
fn from(target: $container_ty) -> Self {
|
||||||
|
impl_from_strings_inner!($el_ty, $str_ty, target)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_from_strings {
|
||||||
|
($el_ty:ty, $str_ty:ty) => {
|
||||||
|
impl_from_strings_with_container!($el_ty, $str_ty, Vec<$str_ty>);
|
||||||
|
impl_from_strings_with_container!($el_ty, $str_ty, &[$str_ty]);
|
||||||
|
impl<const C: usize> From<[$str_ty; C]> for ElementsMaybeSignal<$el_ty, $el_ty> {
|
||||||
|
fn from(target: [$str_ty; C]) -> Self {
|
||||||
|
impl_from_strings_inner!($el_ty, $str_ty, target)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<const C: usize> From<&[$str_ty; C]> for ElementsMaybeSignal<$el_ty, $el_ty> {
|
||||||
|
fn from(target: &[$str_ty; C]) -> Self {
|
||||||
|
impl_from_strings_inner!($el_ty, $str_ty, target)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_from_strings!(web_sys::Element, &str);
|
||||||
|
impl_from_strings!(web_sys::Element, String);
|
||||||
|
impl_from_strings!(web_sys::EventTarget, &str);
|
||||||
|
impl_from_strings!(web_sys::EventTarget, String);
|
||||||
|
|
||||||
// From signal of vec ////////////////////////////////////////////////////////////////
|
// From signal of vec ////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
impl<T, E> From<Signal<Vec<T>>> for ElementsMaybeSignal<T, E>
|
impl<T, E> From<Signal<Vec<T>>> for ElementsMaybeSignal<T, E>
|
||||||
|
@ -367,19 +499,64 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// From multiple NodeRefs //////////////////////////////////////////////////////////////
|
impl<T, E> From<Vec<Signal<T>>> for ElementsMaybeSignal<T, E>
|
||||||
|
|
||||||
macro_rules! impl_from_multi_node_ref {
|
|
||||||
($ty:ty) => {
|
|
||||||
impl<R> From<&[NodeRef<R>]> for ElementsMaybeSignal<$ty, $ty>
|
|
||||||
where
|
where
|
||||||
R: ElementDescriptor + Clone + 'static,
|
T: Into<E> + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn from(node_refs: &[NodeRef<R>]) -> Self {
|
fn from(list: Vec<Signal<T>>) -> Self {
|
||||||
let node_refs = node_refs.to_vec();
|
let list = list.clone();
|
||||||
|
|
||||||
Self::Dynamic(Signal::derive(move || {
|
Self::Dynamic(Signal::derive(move || {
|
||||||
node_refs
|
list.iter().map(|t| Some(t.get())).collect()
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, E> From<Vec<Signal<Option<T>>>> for ElementsMaybeSignal<T, E>
|
||||||
|
where
|
||||||
|
T: Into<E> + Clone + 'static,
|
||||||
|
{
|
||||||
|
fn from(list: Vec<Signal<Option<T>>>) -> Self {
|
||||||
|
let list = list.clone();
|
||||||
|
|
||||||
|
Self::Dynamic(Signal::derive(move || {
|
||||||
|
list.iter().map(|t| t.get()).collect()
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, E, const C: usize> From<[Signal<T>; C]> for ElementsMaybeSignal<T, E>
|
||||||
|
where
|
||||||
|
T: Into<E> + Clone + 'static,
|
||||||
|
{
|
||||||
|
fn from(list: [Signal<T>; C]) -> Self {
|
||||||
|
let list = list.to_vec();
|
||||||
|
|
||||||
|
Self::Dynamic(Signal::derive(move || {
|
||||||
|
list.iter().map(|t| Some(t.get())).collect()
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, E, const C: usize> From<[Signal<Option<T>>; C]> for ElementsMaybeSignal<T, E>
|
||||||
|
where
|
||||||
|
T: Into<E> + Clone + 'static,
|
||||||
|
{
|
||||||
|
fn from(list: [Signal<Option<T>>; C]) -> Self {
|
||||||
|
let list = list.to_vec();
|
||||||
|
|
||||||
|
Self::Dynamic(Signal::derive(move || {
|
||||||
|
list.iter().map(|t| t.get()).collect()
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// From multiple NodeRefs //////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
macro_rules! impl_from_multi_node_ref_inner {
|
||||||
|
($ty:ty, $node_refs:ident) => {
|
||||||
|
Self::Dynamic(Signal::derive(move || {
|
||||||
|
$node_refs
|
||||||
.iter()
|
.iter()
|
||||||
.map(|node_ref| {
|
.map(|node_ref| {
|
||||||
node_ref.get().map(move |el| {
|
node_ref.get().map(move |el| {
|
||||||
|
@ -390,6 +567,38 @@ macro_rules! impl_from_multi_node_ref {
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}))
|
}))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_from_multi_node_ref {
|
||||||
|
($ty:ty) => {
|
||||||
|
impl<R> From<&[NodeRef<R>]> for ElementsMaybeSignal<$ty, $ty>
|
||||||
|
where
|
||||||
|
R: ElementDescriptor + Clone + 'static,
|
||||||
|
{
|
||||||
|
fn from(node_refs: &[NodeRef<R>]) -> Self {
|
||||||
|
let node_refs = node_refs.to_vec();
|
||||||
|
impl_from_multi_node_ref_inner!($ty, node_refs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R, const C: usize> From<[NodeRef<R>; C]> for ElementsMaybeSignal<$ty, $ty>
|
||||||
|
where
|
||||||
|
R: ElementDescriptor + Clone + 'static,
|
||||||
|
{
|
||||||
|
fn from(node_refs: [NodeRef<R>; C]) -> Self {
|
||||||
|
let node_refs = node_refs.to_vec();
|
||||||
|
impl_from_multi_node_ref_inner!($ty, node_refs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R> From<Vec<NodeRef<R>>> for ElementsMaybeSignal<$ty, $ty>
|
||||||
|
where
|
||||||
|
R: ElementDescriptor + Clone + 'static,
|
||||||
|
{
|
||||||
|
fn from(node_refs: Vec<NodeRef<R>>) -> Self {
|
||||||
|
let node_refs = node_refs.clone();
|
||||||
|
impl_from_multi_node_ref_inner!($ty, node_refs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -398,6 +607,67 @@ macro_rules! impl_from_multi_node_ref {
|
||||||
impl_from_multi_node_ref!(web_sys::EventTarget);
|
impl_from_multi_node_ref!(web_sys::EventTarget);
|
||||||
impl_from_multi_node_ref!(web_sys::Element);
|
impl_from_multi_node_ref!(web_sys::Element);
|
||||||
|
|
||||||
|
// From multiple leptos::html::HTMLElement /////////////////////////////////////////
|
||||||
|
|
||||||
|
macro_rules! impl_from_multi_html_element {
|
||||||
|
($ty:ty) => {
|
||||||
|
impl<HtmlEl> From<&[HtmlElement<HtmlEl>]> for ElementsMaybeSignal<$ty, $ty>
|
||||||
|
where
|
||||||
|
HtmlEl: ElementDescriptor + std::ops::Deref<Target = $ty>,
|
||||||
|
{
|
||||||
|
fn from(value: &[HtmlElement<HtmlEl>]) -> Self {
|
||||||
|
Self::Static(
|
||||||
|
value
|
||||||
|
.iter()
|
||||||
|
.map(|el| {
|
||||||
|
let el: &$ty = el.deref();
|
||||||
|
Some(el.clone())
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<HtmlEl, const C: usize> From<[HtmlElement<HtmlEl>; C]>
|
||||||
|
for ElementsMaybeSignal<$ty, $ty>
|
||||||
|
where
|
||||||
|
HtmlEl: ElementDescriptor + std::ops::Deref<Target = $ty>,
|
||||||
|
{
|
||||||
|
fn from(value: [HtmlElement<HtmlEl>; C]) -> Self {
|
||||||
|
Self::Static(
|
||||||
|
value
|
||||||
|
.iter()
|
||||||
|
.map(|el| {
|
||||||
|
let el: &$ty = el.deref();
|
||||||
|
Some(el.clone())
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<HtmlEl> From<Vec<HtmlElement<HtmlEl>>> for ElementsMaybeSignal<$ty, $ty>
|
||||||
|
where
|
||||||
|
HtmlEl: ElementDescriptor + std::ops::Deref<Target = $ty>,
|
||||||
|
{
|
||||||
|
fn from(value: Vec<HtmlElement<HtmlEl>>) -> Self {
|
||||||
|
Self::Static(
|
||||||
|
value
|
||||||
|
.iter()
|
||||||
|
.map(|el| {
|
||||||
|
let el: &$ty = el.deref();
|
||||||
|
Some(el.clone())
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_from_multi_html_element!(web_sys::EventTarget);
|
||||||
|
impl_from_multi_html_element!(web_sys::Element);
|
||||||
|
|
||||||
// From ElementMaybeSignal //////////////////////////////////////////////////////////////
|
// From ElementMaybeSignal //////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
impl<T, E> From<ElementMaybeSignal<T, E>> for ElementsMaybeSignal<T, E>
|
impl<T, E> From<ElementMaybeSignal<T, E>> for ElementsMaybeSignal<T, E>
|
||||||
|
|
|
@ -27,7 +27,6 @@ cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use leptos::*;
|
/// # use leptos::*;
|
||||||
/// # use leptos::ev::resize;
|
|
||||||
/// # use leptos::logging::log;
|
/// # use leptos::logging::log;
|
||||||
/// # use leptos::html::Div;
|
/// # use leptos::html::Div;
|
||||||
/// # use leptos_use::on_click_outside;
|
/// # use leptos_use::on_click_outside;
|
||||||
|
@ -50,6 +49,33 @@ cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
||||||
/// If you are targeting these browsers, we recommend you to include
|
/// If you are targeting these browsers, we recommend you to include
|
||||||
/// [this code snippet](https://gist.github.com/sibbng/13e83b1dd1b733317ce0130ef07d4efd) on your project.
|
/// [this code snippet](https://gist.github.com/sibbng/13e83b1dd1b733317ce0130ef07d4efd) on your project.
|
||||||
///
|
///
|
||||||
|
/// ## Excluding Elements
|
||||||
|
///
|
||||||
|
/// Use this to ignore clicks on certain elements.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use leptos::*;
|
||||||
|
/// # use leptos::logging::log;
|
||||||
|
/// # use leptos::html::Div;
|
||||||
|
/// # use leptos_use::{on_click_outside_with_options, OnClickOutsideOptions};
|
||||||
|
/// #
|
||||||
|
/// # #[component]
|
||||||
|
/// # fn Demo() -> impl IntoView {
|
||||||
|
/// # let target = create_node_ref::<Div>();
|
||||||
|
/// #
|
||||||
|
/// on_click_outside_with_options(
|
||||||
|
/// target,
|
||||||
|
/// move |event| { log!("{:?}", event); },
|
||||||
|
/// OnClickOutsideOptions::default().ignore(["input", "#some-id"]),
|
||||||
|
/// );
|
||||||
|
/// #
|
||||||
|
/// # view! {
|
||||||
|
/// # <div node_ref=target>"Hello World"</div>
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
/// ## Server-Side Rendering
|
/// ## Server-Side Rendering
|
||||||
///
|
///
|
||||||
/// On the server this amounts to a no-op.
|
/// On the server this amounts to a no-op.
|
||||||
|
@ -230,12 +256,13 @@ where
|
||||||
|
|
||||||
/// Options for [`on_click_outside_with_options`].
|
/// Options for [`on_click_outside_with_options`].
|
||||||
#[derive(Clone, DefaultBuilder)]
|
#[derive(Clone, DefaultBuilder)]
|
||||||
|
#[cfg_attr(feature = "ssr", allow(dead_code))]
|
||||||
pub struct OnClickOutsideOptions<T>
|
pub struct OnClickOutsideOptions<T>
|
||||||
where
|
where
|
||||||
T: Into<web_sys::EventTarget> + Clone + 'static,
|
T: Into<web_sys::EventTarget> + Clone + 'static,
|
||||||
{
|
{
|
||||||
/// List of elementss that should not trigger the callback. Defaults to `[]`.
|
/// List of elementss that should not trigger the callback. Defaults to `[]`.
|
||||||
#[cfg_attr(feature = "ssr", allow(dead_code))]
|
#[builder(skip)]
|
||||||
ignore: ElementsMaybeSignal<T, web_sys::EventTarget>,
|
ignore: ElementsMaybeSignal<T, web_sys::EventTarget>,
|
||||||
|
|
||||||
/// Use capturing phase for internal event listener. Defaults to `true`.
|
/// Use capturing phase for internal event listener. Defaults to `true`.
|
||||||
|
@ -257,3 +284,17 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> OnClickOutsideOptions<T>
|
||||||
|
where
|
||||||
|
T: Into<web_sys::EventTarget> + Clone + 'static,
|
||||||
|
{
|
||||||
|
/// List of elementss that should not trigger the callback. Defaults to `[]`.
|
||||||
|
#[cfg_attr(feature = "ssr", allow(dead_code))]
|
||||||
|
pub fn ignore(self, ignore: impl Into<ElementsMaybeSignal<T, web_sys::EventTarget>>) -> Self {
|
||||||
|
Self {
|
||||||
|
ignore: ignore.into(),
|
||||||
|
..self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue