mirror of
https://github.com/adoyle0/thaw.git
synced 2025-01-23 14:29:22 -05:00
Compare commits
1 commit
e9d1630473
...
aa818b2823
Author | SHA1 | Date | |
---|---|---|---|
|
aa818b2823 |
31 changed files with 460 additions and 612 deletions
13
CHANGELOG.md
13
CHANGELOG.md
|
@ -1,16 +1,3 @@
|
||||||
## [0.3.4](https://github.com/thaw-ui/thaw/compare/v0.3.3...v0.3.4) (2024-09-11)
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* Adds `Flex` component.
|
|
||||||
* Update leptos to v0.6.14.
|
|
||||||
|
|
||||||
### Bug Fixs
|
|
||||||
|
|
||||||
* Allow creating custom theme [#242](https://github.com/thaw-ui/thaw/pull/242).
|
|
||||||
* `CheckboxGroup` does not display default value.
|
|
||||||
* `Binder` component display position.
|
|
||||||
|
|
||||||
## [0.4.0-beta2](https://github.com/thaw-ui/thaw/compare/v0.4.0-beta...v0.4.0-beta2) (2024-09-02)
|
## [0.4.0-beta2](https://github.com/thaw-ui/thaw/compare/v0.4.0-beta...v0.4.0-beta2) (2024-09-02)
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
|
@ -16,6 +16,6 @@ thaw_components = { version = "0.2.0-beta2", path = "./thaw_components" }
|
||||||
thaw_macro = { version = "0.1.0-beta2", path = "./thaw_macro" }
|
thaw_macro = { version = "0.1.0-beta2", path = "./thaw_macro" }
|
||||||
thaw_utils = { version = "0.1.0-beta2", path = "./thaw_utils" }
|
thaw_utils = { version = "0.1.0-beta2", path = "./thaw_utils" }
|
||||||
|
|
||||||
leptos = { version = "0.7.0-beta5" }
|
leptos = { version = "0.7.0-beta4" }
|
||||||
leptos_meta = { version = "0.7.0-beta5" }
|
leptos_meta = { version = "0.7.0-beta4" }
|
||||||
leptos_router = { version = "0.7.0-beta5" }
|
leptos_router = { version = "0.7.0-beta4" }
|
||||||
|
|
113
demo/src/app.rs
113
demo/src/app.rs
|
@ -59,59 +59,66 @@ fn TheRouter() -> impl IntoView {
|
||||||
<Route path=path!("/development/components") view=DevelopmentComponentsMdPage/>
|
<Route path=path!("/development/components") view=DevelopmentComponentsMdPage/>
|
||||||
</ParentRoute>
|
</ParentRoute>
|
||||||
<ParentRoute path=path!("/components") view=ComponentsPage>
|
<ParentRoute path=path!("/components") view=ComponentsPage>
|
||||||
<Route path=path!("/accordion") view=AccordionMdPage/>
|
{view!{
|
||||||
<Route path=path!("/anchor") view=AnchorMdPage/>
|
<Route path=path!("/accordion") view=AccordionMdPage/>
|
||||||
<Route path=path!("/auto-complete") view=AutoCompleteMdPage/>
|
<Route path=path!("/anchor") view=AnchorMdPage/>
|
||||||
<Route path=path!("/avatar") view=AvatarMdPage/>
|
<Route path=path!("/auto-complete") view=AutoCompleteMdPage/>
|
||||||
<Route path=path!("/back-top") view=BackTopMdPage/>
|
<Route path=path!("/avatar") view=AvatarMdPage/>
|
||||||
<Route path=path!("/badge") view=BadgeMdPage/>
|
<Route path=path!("/back-top") view=BackTopMdPage/>
|
||||||
<Route path=path!("/breadcrumb") view=BreadcrumbMdPage/>
|
<Route path=path!("/badge") view=BadgeMdPage/>
|
||||||
<Route path=path!("/button") view=ButtonMdPage/>
|
<Route path=path!("/breadcrumb") view=BreadcrumbMdPage/>
|
||||||
<Route path=path!("/calendar") view=CalendarMdPage/>
|
<Route path=path!("/button") view=ButtonMdPage/>
|
||||||
<Route path=path!("/card") view=CardMdPage/>
|
<Route path=path!("/calendar") view=CalendarMdPage/>
|
||||||
<Route path=path!("/checkbox") view=CheckboxMdPage/>
|
<Route path=path!("/card") view=CardMdPage/>
|
||||||
<Route path=path!("/color-picker") view=ColorPickerMdPage/>
|
<Route path=path!("/checkbox") view=CheckboxMdPage/>
|
||||||
<Route path=path!("/combobox") view=ComboboxMdPage/>
|
<Route path=path!("/color-picker") view=ColorPickerMdPage/>
|
||||||
<Route path=path!("/config-provider") view=ConfigProviderMdPage/>
|
<Route path=path!("/combobox") view=ComboboxMdPage/>
|
||||||
<Route path=path!("/date-picker") view=DatePickerMdPage/>
|
<Route path=path!("/config-provider") view=ConfigProviderMdPage/>
|
||||||
<Route path=path!("/dialog") view=DialogMdPage/>
|
}.into_inner()}
|
||||||
<Route path=path!("/divider") view=DividerMdPage/>
|
{view!{
|
||||||
<Route path=path!("/drawer") view=DrawerMdPage/>
|
<Route path=path!("/date-picker") view=DatePickerMdPage/>
|
||||||
<Route path=path!("/field") view=FieldMdPage/>
|
<Route path=path!("/dialog") view=DialogMdPage/>
|
||||||
<Route path=path!("/flex") view=FlexMdPage/>
|
<Route path=path!("/divider") view=DividerMdPage/>
|
||||||
<Route path=path!("/menu") view=MenuMdPage/>
|
<Route path=path!("/drawer") view=DrawerMdPage/>
|
||||||
<Route path=path!("/grid") view=GridMdPage/>
|
<Route path=path!("/field") view=FieldMdPage/>
|
||||||
<Route path=path!("/icon") view=IconMdPage/>
|
<Route path=path!("/menu") view=MenuMdPage/>
|
||||||
<Route path=path!("/image") view=ImageMdPage/>
|
<Route path=path!("/grid") view=GridMdPage/>
|
||||||
<Route path=path!("/input") view=InputMdPage/>
|
<Route path=path!("/icon") view=IconMdPage/>
|
||||||
<Route path=path!("/layout") view=LayoutMdPage/>
|
<Route path=path!("/image") view=ImageMdPage/>
|
||||||
<Route path=path!("/link") view=LinkMdPage/>
|
<Route path=path!("/input") view=InputMdPage/>
|
||||||
<Route path=path!("/loading-bar") view=LoadingBarMdPage/>
|
<Route path=path!("/layout") view=LayoutMdPage/>
|
||||||
<Route path=path!("/message-bar") view=MessageBarMdPage/>
|
<Route path=path!("/link") view=LinkMdPage/>
|
||||||
<Route path=path!("/nav") view=NavMdPage/>
|
<Route path=path!("/loading-bar") view=LoadingBarMdPage/>
|
||||||
<Route path=path!("/pagination") view=PaginationMdPage/>
|
<Route path=path!("/message-bar") view=MessageBarMdPage/>
|
||||||
<Route path=path!("/popover") view=PopoverMdPage/>
|
<Route path=path!("/nav") view=NavMdPage/>
|
||||||
<Route path=path!("/progress-bar") view=ProgressBarMdPage/>
|
}.into_inner()}
|
||||||
<Route path=path!("/radio") view=RadioMdPage/>
|
{view!{
|
||||||
<Route path=path!("/scrollbar") view=ScrollbarMdPage/>
|
<Route path=path!("/pagination") view=PaginationMdPage/>
|
||||||
<Route path=path!("/select") view=SelectMdPage/>
|
<Route path=path!("/popover") view=PopoverMdPage/>
|
||||||
<Route path=path!("/skeleton") view=SkeletonMdPage/>
|
<Route path=path!("/progress-bar") view=ProgressBarMdPage/>
|
||||||
<Route path=path!("/slider") view=SliderMdPage/>
|
<Route path=path!("/radio") view=RadioMdPage/>
|
||||||
<Route path=path!("/space") view=SpaceMdPage/>
|
<Route path=path!("/scrollbar") view=ScrollbarMdPage/>
|
||||||
<Route path=path!("/spin-button") view=SpinButtonMdPage/>
|
<Route path=path!("/select") view=SelectMdPage/>
|
||||||
<Route path=path!("/spinner") view=SpinnerMdPage/>
|
<Route path=path!("/skeleton") view=SkeletonMdPage/>
|
||||||
<Route path=path!("/switch") view=SwitchMdPage/>
|
<Route path=path!("/slider") view=SliderMdPage/>
|
||||||
<Route path=path!("/tab-list") view=TabListMdPage/>
|
<Route path=path!("/space") view=SpaceMdPage/>
|
||||||
<Route path=path!("/table") view=TableMdPage/>
|
<Route path=path!("/spin-button") view=SpinButtonMdPage/>
|
||||||
<Route path=path!("/tag") view=TagMdPage/>
|
<Route path=path!("/spinner") view=SpinnerMdPage/>
|
||||||
<Route path=path!("/tag-group") view=TagGroupMdPage/>
|
<Route path=path!("/switch") view=SwitchMdPage/>
|
||||||
<Route path=path!("/tag-picker") view=TagPickerMdPage/>
|
<Route path=path!("/tab-list") view=TabListMdPage/>
|
||||||
<Route path=path!("/text") view=TextMdPage/>
|
<Route path=path!("/table") view=TableMdPage/>
|
||||||
<Route path=path!("/textarea") view=TextareaMdPage/>
|
}.into_inner()}
|
||||||
<Route path=path!("/time-picker") view=TimePickerMdPage/>
|
{view!{
|
||||||
<Route path=path!("/toast") view=ToastMdPage />
|
<Route path=path!("/tag") view=TagMdPage/>
|
||||||
<Route path=path!("/tooltip") view=TooltipMdPage />
|
<Route path=path!("/tag-group") view=TagGroupMdPage/>
|
||||||
<Route path=path!("/upload") view=UploadMdPage/>
|
<Route path=path!("/tag-picker") view=TagPickerMdPage/>
|
||||||
|
<Route path=path!("/text") view=TextMdPage/>
|
||||||
|
<Route path=path!("/textarea") view=TextareaMdPage/>
|
||||||
|
<Route path=path!("/time-picker") view=TimePickerMdPage/>
|
||||||
|
<Route path=path!("/toast") view=ToastMdPage />
|
||||||
|
<Route path=path!("/tooltip") view=TooltipMdPage />
|
||||||
|
<Route path=path!("/upload") view=UploadMdPage/>
|
||||||
|
}.into_inner()}
|
||||||
</ParentRoute>
|
</ParentRoute>
|
||||||
</Routes>
|
</Routes>
|
||||||
</Router>
|
</Router>
|
||||||
|
|
|
@ -272,11 +272,6 @@ pub(crate) fn gen_nav_data() -> Vec<NavGroupOption> {
|
||||||
value: "/components/field",
|
value: "/components/field",
|
||||||
label: "Field",
|
label: "Field",
|
||||||
},
|
},
|
||||||
NavItemOption {
|
|
||||||
group: None,
|
|
||||||
value: "/components/flex",
|
|
||||||
label: "Flex",
|
|
||||||
},
|
|
||||||
NavItemOption {
|
NavItemOption {
|
||||||
group: None,
|
group: None,
|
||||||
value: "/components/grid",
|
value: "/components/grid",
|
||||||
|
|
|
@ -42,7 +42,6 @@ pub fn include_md(_token_stream: proc_macro::TokenStream) -> proc_macro::TokenSt
|
||||||
"DividerMdPage" => "../../thaw/src/divider/docs/mod.md",
|
"DividerMdPage" => "../../thaw/src/divider/docs/mod.md",
|
||||||
"DrawerMdPage" => "../../thaw/src/drawer/docs/mod.md",
|
"DrawerMdPage" => "../../thaw/src/drawer/docs/mod.md",
|
||||||
"FieldMdPage" => "../../thaw/src/field/docs/mod.md",
|
"FieldMdPage" => "../../thaw/src/field/docs/mod.md",
|
||||||
"FlexMdPage" => "../../thaw/src/flex/docs/mod.md",
|
|
||||||
"GridMdPage" => "../../thaw/src/grid/docs/mod.md",
|
"GridMdPage" => "../../thaw/src/grid/docs/mod.md",
|
||||||
"IconMdPage" => "../../thaw/src/icon/docs/mod.md",
|
"IconMdPage" => "../../thaw/src/icon/docs/mod.md",
|
||||||
"ImageMdPage" => "../../thaw/src/image/docs/mod.md",
|
"ImageMdPage" => "../../thaw/src/image/docs/mod.md",
|
||||||
|
|
|
@ -9,10 +9,10 @@ crate-type = ["cdylib", "rlib"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
axum = { version = "0.7", optional = true }
|
axum = { version = "0.7", optional = true }
|
||||||
console_error_panic_hook = "0.1"
|
console_error_panic_hook = "0.1"
|
||||||
leptos = { version = "0.7.0-beta5", features = ["experimental-islands"] }
|
leptos = { version = "0.7.0-beta4", features = ["experimental-islands"] }
|
||||||
leptos_axum = { version = "0.7.0-beta5", optional = true }
|
leptos_axum = { version = "0.7.0-beta4", optional = true }
|
||||||
leptos_meta = { version = "0.7.0-beta5" }
|
leptos_meta = { version = "0.7.0-beta4" }
|
||||||
leptos_router = { version = "0.7.0-beta5" }
|
leptos_router = { version = "0.7.0-beta4" }
|
||||||
tokio = { version = "1", features = ["rt-multi-thread"], optional = true }
|
tokio = { version = "1", features = ["rt-multi-thread"], optional = true }
|
||||||
tower = { version = "0.4", optional = true }
|
tower = { version = "0.4", optional = true }
|
||||||
tower-http = { version = "0.5", features = ["fs"], optional = true }
|
tower-http = { version = "0.5", features = ["fs"], optional = true }
|
||||||
|
|
|
@ -9,10 +9,10 @@ crate-type = ["cdylib", "rlib"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
axum = { version = "0.7.5", optional = true }
|
axum = { version = "0.7.5", optional = true }
|
||||||
console_error_panic_hook = "0.1"
|
console_error_panic_hook = "0.1"
|
||||||
leptos = { version = "0.7.0-beta5" }
|
leptos = { version = "0.7.0-beta4" }
|
||||||
leptos_axum = { version = "0.7.0-beta5", optional = true }
|
leptos_axum = { version = "0.7.0-beta4", optional = true }
|
||||||
leptos_meta = { version = "0.7.0-beta5" }
|
leptos_meta = { version = "0.7.0-beta4" }
|
||||||
leptos_router = { version = "0.7.0-beta5" }
|
leptos_router = { version = "0.7.0-beta4" }
|
||||||
tokio = { version = "1", features = ["rt-multi-thread"], optional = true }
|
tokio = { version = "1", features = ["rt-multi-thread"], optional = true }
|
||||||
tower = { version = "0.5.0", optional = true }
|
tower = { version = "0.5.0", optional = true }
|
||||||
tower-http = { version = "0.5", features = ["fs"], optional = true }
|
tower-http = { version = "0.5", features = ["fs"], optional = true }
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::{ConfigInjection, Icon};
|
||||||
use leptos::{either::Either, ev, html, prelude::*};
|
use leptos::{either::Either, ev, html, prelude::*};
|
||||||
use thaw_components::{CSSTransition, Teleport};
|
use thaw_components::{CSSTransition, Teleport};
|
||||||
use thaw_utils::{
|
use thaw_utils::{
|
||||||
add_event_listener, class_list, get_scroll_parent_element, mount_style, BoxCallback,
|
add_event_listener, class_list, get_scroll_parent, mount_style, BoxCallback,
|
||||||
EventListenerHandle,
|
EventListenerHandle,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ pub fn BackTop(
|
||||||
};
|
};
|
||||||
|
|
||||||
request_animation_frame(move || {
|
request_animation_frame(move || {
|
||||||
let scroll_el = get_scroll_parent_element(&placeholder_el)
|
let scroll_el = get_scroll_parent(&placeholder_el)
|
||||||
.unwrap_or_else(|| document().document_element().unwrap());
|
.unwrap_or_else(|| document().document_element().unwrap());
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -55,7 +55,7 @@ pub fn Combobox(
|
||||||
let Some(clear_icon_el) = clear_icon_ref.get() else {
|
let Some(clear_icon_el) = clear_icon_ref.get() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let handler = add_event_listener(clear_icon_el, ev::click, move |e| {
|
let handler = add_event_listener(clear_icon_el.into(), ev::click, move |e| {
|
||||||
if disabled.get_untracked() {
|
if disabled.get_untracked() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,110 +0,0 @@
|
||||||
# Flex
|
|
||||||
|
|
||||||
```rust demo
|
|
||||||
view! {
|
|
||||||
<Flex>
|
|
||||||
<Button>"1"</Button>
|
|
||||||
<Button>"2"</Button>
|
|
||||||
<Button>"3"</Button>
|
|
||||||
</Flex>
|
|
||||||
<Flex>
|
|
||||||
<For
|
|
||||||
each=move || 0..4
|
|
||||||
key=move |i| i.clone()
|
|
||||||
let:i
|
|
||||||
>
|
|
||||||
<Button>{i}</Button>
|
|
||||||
</For>
|
|
||||||
</Flex>
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Vertical
|
|
||||||
|
|
||||||
```rust demo
|
|
||||||
view! {
|
|
||||||
<Flex vertical=true>
|
|
||||||
<Button>"1"</Button>
|
|
||||||
<Button>"2"</Button>
|
|
||||||
<Button>"3"</Button>
|
|
||||||
</Flex>
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Gap
|
|
||||||
|
|
||||||
```rust demo
|
|
||||||
view! {
|
|
||||||
<Flex gap=FlexGap::Large>
|
|
||||||
<Button>"1"</Button>
|
|
||||||
<Button>"2"</Button>
|
|
||||||
<Button>"3"</Button>
|
|
||||||
</Flex>
|
|
||||||
<Flex gap=FlexGap::WH(36, 36)>
|
|
||||||
<Button>"1"</Button>
|
|
||||||
<Button>"2"</Button>
|
|
||||||
<Button>"3"</Button>
|
|
||||||
</Flex>
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Align
|
|
||||||
|
|
||||||
```rust demo
|
|
||||||
view! {
|
|
||||||
<Flex vertical=true>
|
|
||||||
<Flex align=FlexAlign::Start>
|
|
||||||
<Button attr:style="height: 60px">"Start"</Button>
|
|
||||||
<Button attr:style="height: 40px">"Start"</Button>
|
|
||||||
<Button>"Start"</Button>
|
|
||||||
</Flex>
|
|
||||||
<Flex align=FlexAlign::Center>
|
|
||||||
<Button attr:style="height: 60px">"Center"</Button>
|
|
||||||
<Button attr:style="height: 40px">"Center"</Button>
|
|
||||||
<Button>"Center"</Button>
|
|
||||||
</Flex>
|
|
||||||
<Flex align=FlexAlign::End>
|
|
||||||
<Button attr:style="height: 60px">"End"</Button>
|
|
||||||
<Button attr:style="height: 40px">"End"</Button>
|
|
||||||
<Button>"End"</Button>
|
|
||||||
</Flex>
|
|
||||||
</Flex>
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Justify
|
|
||||||
|
|
||||||
```rust demo
|
|
||||||
view! {
|
|
||||||
<Flex vertical=true>
|
|
||||||
<Flex justify=FlexJustify::SpaceAround>
|
|
||||||
<Button>"SpaceAround"</Button>
|
|
||||||
<Button>"SpaceAround"</Button>
|
|
||||||
<Button>"SpaceAround"</Button>
|
|
||||||
</Flex>
|
|
||||||
<Flex justify=FlexJustify::Center>
|
|
||||||
<Button>"Center"</Button>
|
|
||||||
<Button>"Center"</Button>
|
|
||||||
<Button>"Center"</Button>
|
|
||||||
</Flex>
|
|
||||||
<Flex justify=FlexJustify::End>
|
|
||||||
<Button>"End"</Button>
|
|
||||||
<Button>"End"</Button>
|
|
||||||
<Button>"End"</Button>
|
|
||||||
</Flex>
|
|
||||||
</Flex>
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Flex Props
|
|
||||||
|
|
||||||
| Name | Type | Default | Description |
|
|
||||||
| -------- | ------------------------ | -------------------- | -------------------------------------- |
|
|
||||||
| class | `MaybeProp<String>` | `Default::default()` | |
|
|
||||||
| style | `MaybeProp<String>` | `Default::default()` | |
|
|
||||||
| inline | `MaybeSignal<bool>` | `false` | Whether it's display is `inline-flex`. |
|
|
||||||
| vertical | `bool` | `false` | Whether to lay out vertically. |
|
|
||||||
| gap | `FlexGap` | `FlexGap::Medium` | Flex's gap. |
|
|
||||||
| align | `MaybeProp<FlexAlign>` | `None` | Vertical arrangement. |
|
|
||||||
| justify | `MaybeProp<FlexJustify>` | `None` | Horizontal arrangement. |
|
|
||||||
| children | `Children` | | |
|
|
|
@ -1,130 +0,0 @@
|
||||||
use leptos::prelude::*;
|
|
||||||
use thaw_utils::class_list;
|
|
||||||
|
|
||||||
#[component]
|
|
||||||
pub fn Flex(
|
|
||||||
#[prop(optional, into)] class: MaybeProp<String>,
|
|
||||||
#[prop(optional, into)] style: MaybeProp<String>,
|
|
||||||
/// Flex's gap.
|
|
||||||
#[prop(optional)]
|
|
||||||
gap: FlexGap,
|
|
||||||
/// Whether to lay out vertically.
|
|
||||||
#[prop(optional)]
|
|
||||||
vertical: bool,
|
|
||||||
/// Whether it's display is `inline-flex`.
|
|
||||||
#[prop(optional, into)]
|
|
||||||
inline: MaybeSignal<bool>,
|
|
||||||
/// Vertical arrangement.
|
|
||||||
#[prop(optional, into)]
|
|
||||||
align: MaybeProp<FlexAlign>,
|
|
||||||
/// Horizontal arrangement.
|
|
||||||
#[prop(optional, into)]
|
|
||||||
justify: MaybeProp<FlexJustify>,
|
|
||||||
children: Children,
|
|
||||||
) -> impl IntoView {
|
|
||||||
let style = Memo::new(move |_| {
|
|
||||||
let mut s = String::new();
|
|
||||||
let display = if inline.get() {
|
|
||||||
"display: inline-flex;"
|
|
||||||
} else {
|
|
||||||
"display: flex;"
|
|
||||||
};
|
|
||||||
s.push_str(display);
|
|
||||||
let direction = if vertical {
|
|
||||||
"flex-direction: column;"
|
|
||||||
} else {
|
|
||||||
"flex-direction: row;"
|
|
||||||
};
|
|
||||||
let gap = match gap {
|
|
||||||
FlexGap::Small => "gap: 4px 8px;",
|
|
||||||
FlexGap::Medium => "gap: 8px 12px;",
|
|
||||||
FlexGap::Large => "gap: 12px 16px;",
|
|
||||||
FlexGap::Size(size) => &format!("gap: {size}px {size}px;"),
|
|
||||||
FlexGap::WH(width, height) => &format!("gap: {width}px {height}px;"),
|
|
||||||
};
|
|
||||||
s.push_str(direction);
|
|
||||||
s.push_str(gap);
|
|
||||||
if let Some(align) = align.get() {
|
|
||||||
s.push_str(&format!("align-items: {};", align.as_str()));
|
|
||||||
}
|
|
||||||
if let Some(justify) = justify.get() {
|
|
||||||
s.push_str(&format!("justify-content: {};", justify.as_str()));
|
|
||||||
}
|
|
||||||
style.with(|style| {
|
|
||||||
if let Some(style) = style.as_ref() {
|
|
||||||
s.push_str(style);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
s
|
|
||||||
});
|
|
||||||
|
|
||||||
view! {
|
|
||||||
<div class=class_list!["thaw-flex", class] style=move || style.get()>
|
|
||||||
{children()}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub enum FlexGap {
|
|
||||||
Small,
|
|
||||||
#[default]
|
|
||||||
Medium,
|
|
||||||
Large,
|
|
||||||
Size(u16),
|
|
||||||
/// width and height
|
|
||||||
WH(u16, u16),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum FlexAlign {
|
|
||||||
FlexStart,
|
|
||||||
FlexEnd,
|
|
||||||
Start,
|
|
||||||
End,
|
|
||||||
Center,
|
|
||||||
Baseline,
|
|
||||||
Stretch,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FlexAlign {
|
|
||||||
fn as_str(&self) -> &'static str {
|
|
||||||
match self {
|
|
||||||
Self::FlexStart => "flex-start",
|
|
||||||
Self::FlexEnd => "flex-end",
|
|
||||||
Self::Start => "start",
|
|
||||||
Self::End => "end",
|
|
||||||
Self::Center => "center",
|
|
||||||
Self::Baseline => "baseline",
|
|
||||||
Self::Stretch => "stretch",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum FlexJustify {
|
|
||||||
FlexStart,
|
|
||||||
FlexEnd,
|
|
||||||
Start,
|
|
||||||
End,
|
|
||||||
Center,
|
|
||||||
SpaceAround,
|
|
||||||
SpaceBetween,
|
|
||||||
SpaceEvenly,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FlexJustify {
|
|
||||||
fn as_str(&self) -> &'static str {
|
|
||||||
match self {
|
|
||||||
Self::FlexStart => "flex-start",
|
|
||||||
Self::FlexEnd => "flex-end",
|
|
||||||
Self::Start => "start",
|
|
||||||
Self::End => "end",
|
|
||||||
Self::Center => "center",
|
|
||||||
Self::SpaceAround => "space-around",
|
|
||||||
Self::SpaceBetween => "space-between",
|
|
||||||
Self::SpaceEvenly => "space-evenly",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
mod flex;
|
|
||||||
|
|
||||||
pub use flex::*;
|
|
|
@ -19,7 +19,6 @@ mod dialog;
|
||||||
mod divider;
|
mod divider;
|
||||||
mod drawer;
|
mod drawer;
|
||||||
mod field;
|
mod field;
|
||||||
mod flex;
|
|
||||||
mod grid;
|
mod grid;
|
||||||
mod icon;
|
mod icon;
|
||||||
mod image;
|
mod image;
|
||||||
|
@ -74,7 +73,6 @@ pub use dialog::*;
|
||||||
pub use divider::*;
|
pub use divider::*;
|
||||||
pub use drawer::*;
|
pub use drawer::*;
|
||||||
pub use field::*;
|
pub use field::*;
|
||||||
pub use flex::*;
|
|
||||||
pub use grid::*;
|
pub use grid::*;
|
||||||
pub use icon::*;
|
pub use icon::*;
|
||||||
pub use image::*;
|
pub use image::*;
|
||||||
|
|
|
@ -77,4 +77,3 @@ view! {
|
||||||
| disabled | `MaybeSignal<bool>` | `false` | Whether the link is disabled. |
|
| disabled | `MaybeSignal<bool>` | `false` | Whether the link is disabled. |
|
||||||
| disabled_focusable | `MaybeSignal<bool>` | `false` | When set, allows the link to be focusable even when it has been disabled. |
|
| disabled_focusable | `MaybeSignal<bool>` | `false` | When set, allows the link to be focusable even when it has been disabled. |
|
||||||
| children | `Children` | | |
|
| children | `Children` | | |
|
||||||
| target | `MaybeSignal<String>` | | Specifies where to open the linked document. |
|
|
||||||
|
|
|
@ -16,9 +16,6 @@ pub fn Link(
|
||||||
#[prop(optional, into)]
|
#[prop(optional, into)]
|
||||||
disabled_focusable: MaybeSignal<bool>,
|
disabled_focusable: MaybeSignal<bool>,
|
||||||
children: Children,
|
children: Children,
|
||||||
/// Specifies where to open the linked document.
|
|
||||||
#[prop(optional, into)]
|
|
||||||
target: MaybeSignal<String>,
|
|
||||||
) -> impl IntoView {
|
) -> impl IntoView {
|
||||||
mount_style("link", include_str!("./link.css"));
|
mount_style("link", include_str!("./link.css"));
|
||||||
|
|
||||||
|
@ -49,7 +46,6 @@ pub fn Link(
|
||||||
href=href
|
href=href
|
||||||
tabindex=tabindex
|
tabindex=tabindex
|
||||||
aria-disabled=move || link_disabled.get().then_some("true")
|
aria-disabled=move || link_disabled.get().then_some("true")
|
||||||
target=target
|
|
||||||
>
|
>
|
||||||
{children()}
|
{children()}
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -80,7 +80,7 @@ pub fn Menu(
|
||||||
let Some(target_el) = target_ref.get() else {
|
let Some(target_el) = target_ref.get() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let handler = add_event_listener(target_el, ev::click, move |event| {
|
let handler = add_event_listener(target_el.into(), ev::click, move |event| {
|
||||||
if trigger_type != MenuTriggerType::Click {
|
if trigger_type != MenuTriggerType::Click {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,7 @@ pub fn Popover(
|
||||||
let Some(target_el) = target_ref.get() else {
|
let Some(target_el) = target_ref.get() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let handler = add_event_listener(target_el, ev::click, move |event| {
|
let handler = add_event_listener(target_el.into(), ev::click, move |event| {
|
||||||
if trigger_type != PopoverTriggerType::Click {
|
if trigger_type != PopoverTriggerType::Click {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,22 +23,10 @@ view! {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Custom label
|
|
||||||
|
|
||||||
```rust demo
|
|
||||||
view! {
|
|
||||||
<Spinner label="Label"/>
|
|
||||||
<Spinner>
|
|
||||||
<b style="color: blue">"Label"</b>
|
|
||||||
</Spinner>
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Spinner Props
|
### Spinner Props
|
||||||
|
|
||||||
| Name | Type | Default | Description |
|
| Name | Type | Default | Description |
|
||||||
| -------- | -------------------------- | --------------------- | ---------------------------------- |
|
| ----- | -------------------------- | --------------------- | ---------------------------------- |
|
||||||
| class | `MaybeProp<String>` | `Default::default()` | |
|
| class | `MaybeProp<String>` | `Default::default()` | |
|
||||||
| label | `MaybeProp<String>` | `Default::default()` | An optional label for the Spinner. |
|
| label | `MaybeProp<String>` | `Default::default()` | An optional label for the Spinner. |
|
||||||
| size | `MaybeSignal<SpinnerSize>` | `SpinnerSize::Medium` | The size of the spinner. |
|
| size | `MaybeSignal<SpinnerSize>` | `SpinnerSize::Medium` | The size of the spinner. |
|
||||||
| children | `Option<Children>` | `None` | |
|
|
||||||
|
|
|
@ -38,16 +38,14 @@ pub fn Spinner(
|
||||||
/// The size of the spinner.
|
/// The size of the spinner.
|
||||||
#[prop(optional, into)]
|
#[prop(optional, into)]
|
||||||
size: MaybeSignal<SpinnerSize>,
|
size: MaybeSignal<SpinnerSize>,
|
||||||
#[prop(optional)] children: Option<Children>,
|
|
||||||
) -> impl IntoView {
|
) -> impl IntoView {
|
||||||
mount_style("spinner", include_str!("./spinner.css"));
|
mount_style("spinner", include_str!("./spinner.css"));
|
||||||
let id = StoredValue::new(uuid::Uuid::new_v4().to_string());
|
let id = StoredValue::new(uuid::Uuid::new_v4().to_string());
|
||||||
|
|
||||||
let spinner_label = label.clone();
|
let spinner_label = label.clone();
|
||||||
let children_flag = children.is_some();
|
|
||||||
let labelledby = move || {
|
let labelledby = move || {
|
||||||
spinner_label.with(|label| {
|
spinner_label.with(|label| {
|
||||||
if label.is_some() || children_flag {
|
if label.is_some() {
|
||||||
Some(id.get_value())
|
Some(id.get_value())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -68,29 +66,17 @@ pub fn Spinner(
|
||||||
<span class="thaw-spinner__spinner">
|
<span class="thaw-spinner__spinner">
|
||||||
<span class="thaw-spinner__spinner-tail"></span>
|
<span class="thaw-spinner__spinner-tail"></span>
|
||||||
</span>
|
</span>
|
||||||
{if let Some(children) = children {
|
{move || {
|
||||||
view! {
|
if let Some(label) = label.get() {
|
||||||
<label class="thaw-spinner__label" id=id.get_value()>
|
view! {
|
||||||
{children()}
|
<label class="thaw-spinner__label" id=id.get_value()>
|
||||||
</label>
|
{label}
|
||||||
}
|
</label>
|
||||||
.into_any()
|
|
||||||
} else {
|
|
||||||
{
|
|
||||||
move || {
|
|
||||||
if let Some(label) = label.get() {
|
|
||||||
view! {
|
|
||||||
<label class="thaw-spinner__label" id=id.get_value()>
|
|
||||||
{label}
|
|
||||||
</label>
|
|
||||||
}
|
|
||||||
.into()
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
.into()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
.into_any()
|
|
||||||
}}
|
}}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ pub fn Upload(
|
||||||
let Some(trigger_el) = trigger_ref.get() else {
|
let Some(trigger_el) = trigger_ref.get() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let handle = add_event_listener(trigger_el, ev::click, move |_| {
|
let handle = add_event_listener(trigger_el.into(), ev::click, move |_| {
|
||||||
if let Some(input_ref) = input_ref.get_untracked() {
|
if let Some(input_ref) = input_ref.get_untracked() {
|
||||||
input_ref.click();
|
input_ref.click();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
.thaw-binder-follower {
|
.thaw-binder-follower-container {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
|
@ -9,5 +9,5 @@
|
||||||
|
|
||||||
.thaw-binder-follower-content {
|
.thaw-binder-follower-content {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 1000000;
|
z-index: 2000;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use leptos::prelude::window;
|
use leptos::prelude::window;
|
||||||
use web_sys::DomRect;
|
use web_sys::DomRect;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone)]
|
||||||
pub enum FollowerPlacement {
|
pub enum FollowerPlacement {
|
||||||
Top,
|
Top,
|
||||||
Bottom,
|
Bottom,
|
||||||
|
@ -66,151 +66,309 @@ pub fn get_follower_placement_offset(
|
||||||
placement: FollowerPlacement,
|
placement: FollowerPlacement,
|
||||||
target_rect: DomRect,
|
target_rect: DomRect,
|
||||||
follower_rect: DomRect,
|
follower_rect: DomRect,
|
||||||
content_rect: DomRect,
|
|
||||||
) -> Option<FollowerPlacementOffset> {
|
) -> Option<FollowerPlacementOffset> {
|
||||||
let (left, placement, top, transform) = match placement {
|
match placement {
|
||||||
FollowerPlacement::Top | FollowerPlacement::TopStart | FollowerPlacement::TopEnd => {
|
FollowerPlacement::Top => {
|
||||||
let Some(window_inner_height) = window_inner_height() else {
|
let left = target_rect.x() + target_rect.width() / 2.0;
|
||||||
return None;
|
let (top, placement) = {
|
||||||
};
|
let follower_height = follower_rect.height();
|
||||||
let content_height = content_rect.height();
|
let target_y = target_rect.y();
|
||||||
let target_top = target_rect.top();
|
let target_height = target_rect.height();
|
||||||
let target_bottom = target_rect.bottom();
|
let top = target_y - follower_height;
|
||||||
let top = target_top - content_height;
|
|
||||||
let (top, new_placement) =
|
let Some(inner_height) = window_inner_height() else {
|
||||||
if top < 0.0 && target_bottom + content_height <= window_inner_height {
|
return None;
|
||||||
(target_bottom, FollowerPlacement::Bottom)
|
};
|
||||||
|
|
||||||
|
if top < 0.0 && target_y + target_height + follower_height <= inner_height {
|
||||||
|
(target_y + target_height, FollowerPlacement::Bottom)
|
||||||
} else {
|
} else {
|
||||||
(top, FollowerPlacement::Top)
|
(top, FollowerPlacement::Top)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Some(FollowerPlacementOffset {
|
||||||
|
top,
|
||||||
|
left,
|
||||||
|
transform: String::from("translateX(-50%)"),
|
||||||
|
placement,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
FollowerPlacement::TopStart => {
|
||||||
|
let left = target_rect.x();
|
||||||
|
let (top, placement) = {
|
||||||
|
let follower_height = follower_rect.height();
|
||||||
|
let target_y = target_rect.y();
|
||||||
|
let target_height = target_rect.height();
|
||||||
|
let top = target_y - follower_height;
|
||||||
|
|
||||||
|
let Some(inner_height) = window_inner_height() else {
|
||||||
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
if placement == FollowerPlacement::Top {
|
if top < 0.0 && target_y + target_height + follower_height <= inner_height {
|
||||||
let left = target_rect.left() + target_rect.width() / 2.0;
|
(target_y + target_height, FollowerPlacement::BottomStart)
|
||||||
let transform = String::from("translateX(-50%)");
|
} else {
|
||||||
(left, new_placement, top, transform)
|
(top, FollowerPlacement::TopStart)
|
||||||
} else if placement == FollowerPlacement::TopStart {
|
}
|
||||||
let left = target_rect.left();
|
|
||||||
let transform = String::new();
|
|
||||||
(left, new_placement, top, transform)
|
|
||||||
} else if placement == FollowerPlacement::TopEnd {
|
|
||||||
let left = target_rect.right();
|
|
||||||
let transform = String::from("translateX(-100%)");
|
|
||||||
(left, new_placement, top, transform)
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
FollowerPlacement::Bottom
|
|
||||||
| FollowerPlacement::BottomStart
|
|
||||||
| FollowerPlacement::BottomEnd => {
|
|
||||||
let Some(window_inner_height) = window_inner_height() else {
|
|
||||||
return None;
|
|
||||||
};
|
};
|
||||||
let content_height = content_rect.height();
|
Some(FollowerPlacementOffset {
|
||||||
let target_top = target_rect.top();
|
top,
|
||||||
let target_bottom = target_rect.bottom();
|
|
||||||
let top = target_bottom;
|
|
||||||
let (top, new_placement) = if top + content_height > window_inner_height
|
|
||||||
&& target_top - content_height >= 0.0
|
|
||||||
{
|
|
||||||
(target_top - content_height, FollowerPlacement::Top)
|
|
||||||
} else {
|
|
||||||
(top, FollowerPlacement::Bottom)
|
|
||||||
};
|
|
||||||
if placement == FollowerPlacement::Bottom {
|
|
||||||
let left = target_rect.left() + target_rect.width() / 2.0;
|
|
||||||
let transform = String::from("translateX(-50%)");
|
|
||||||
(left, new_placement, top, transform)
|
|
||||||
} else if placement == FollowerPlacement::BottomStart {
|
|
||||||
let left = target_rect.left();
|
|
||||||
let transform = String::new();
|
|
||||||
(left, new_placement, top, transform)
|
|
||||||
} else if placement == FollowerPlacement::BottomEnd {
|
|
||||||
let left = target_rect.right();
|
|
||||||
let transform = String::from("translateX(-100%)");
|
|
||||||
(left, new_placement, top, transform)
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
FollowerPlacement::Left | FollowerPlacement::LeftStart | FollowerPlacement::LeftEnd => {
|
|
||||||
let Some(window_inner_width) = window_inner_width() else {
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
let content_width = content_rect.width();
|
|
||||||
let target_left = target_rect.left();
|
|
||||||
let target_right = target_rect.right();
|
|
||||||
let left = target_left - content_width;
|
|
||||||
leptos::logging::log!(
|
|
||||||
"{}-{} {} {}",
|
|
||||||
left,
|
left,
|
||||||
target_right,
|
transform: String::new(),
|
||||||
content_width,
|
placement,
|
||||||
window_inner_width
|
})
|
||||||
);
|
}
|
||||||
let (left, new_placement) =
|
FollowerPlacement::TopEnd => {
|
||||||
if left < 0.0 && target_right + content_width <= window_inner_width {
|
let left = target_rect.x() + target_rect.width();
|
||||||
(target_right, FollowerPlacement::Right)
|
let (top, placement) = {
|
||||||
|
let follower_height = follower_rect.height();
|
||||||
|
let target_y = target_rect.y();
|
||||||
|
let target_height = target_rect.height();
|
||||||
|
let top = target_y - follower_height;
|
||||||
|
|
||||||
|
let Some(inner_height) = window_inner_height() else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
if top < 0.0 && target_y + target_height + follower_height <= inner_height {
|
||||||
|
(target_y + target_height, FollowerPlacement::BottomEnd)
|
||||||
|
} else {
|
||||||
|
(top, FollowerPlacement::TopEnd)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Some(FollowerPlacementOffset {
|
||||||
|
top,
|
||||||
|
left,
|
||||||
|
transform: String::from("translateX(-100%)"),
|
||||||
|
placement,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
FollowerPlacement::Left => {
|
||||||
|
let top = target_rect.y() + target_rect.height() / 2.0;
|
||||||
|
let (left, placement) = {
|
||||||
|
let follower_width = follower_rect.width();
|
||||||
|
let target_x = target_rect.x();
|
||||||
|
let target_width = target_rect.width();
|
||||||
|
let left = target_x - follower_width;
|
||||||
|
|
||||||
|
let Some(inner_width) = window_inner_width() else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
if left < 0.0 && target_x + target_width + follower_width > inner_width {
|
||||||
|
(target_x + follower_width, FollowerPlacement::Right)
|
||||||
} else {
|
} else {
|
||||||
(left, FollowerPlacement::Left)
|
(left, FollowerPlacement::Left)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Some(FollowerPlacementOffset {
|
||||||
|
top,
|
||||||
|
left,
|
||||||
|
transform: String::from("translateY(-50%)"),
|
||||||
|
placement,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
FollowerPlacement::LeftStart => {
|
||||||
|
let top = target_rect.y();
|
||||||
|
let (left, placement) = {
|
||||||
|
let follower_width = follower_rect.width();
|
||||||
|
let target_x = target_rect.x();
|
||||||
|
let target_width = target_rect.width();
|
||||||
|
let left = target_x - follower_width;
|
||||||
|
|
||||||
|
let Some(inner_width) = window_inner_width() else {
|
||||||
|
return None;
|
||||||
};
|
};
|
||||||
if placement == FollowerPlacement::Left {
|
|
||||||
let top = target_rect.top() + target_rect.height() / 2.0;
|
if left < 0.0 && target_x + target_width + follower_width > inner_width {
|
||||||
let transform = String::from("translateY(-50%)");
|
(target_x + follower_width, FollowerPlacement::RightStart)
|
||||||
(left, new_placement, top, transform)
|
} else {
|
||||||
} else if placement == FollowerPlacement::LeftStart {
|
(left, FollowerPlacement::LeftStart)
|
||||||
let top = target_rect.top();
|
}
|
||||||
let transform = String::new();
|
|
||||||
(left, new_placement, top, transform)
|
|
||||||
} else if placement == FollowerPlacement::LeftEnd {
|
|
||||||
let top = target_rect.bottom();
|
|
||||||
let transform = String::from("translateY(-100%)");
|
|
||||||
(left, new_placement, top, transform)
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
FollowerPlacement::Right | FollowerPlacement::RightStart | FollowerPlacement::RightEnd => {
|
|
||||||
let Some(window_inner_width) = window_inner_width() else {
|
|
||||||
return None;
|
|
||||||
};
|
};
|
||||||
|
Some(FollowerPlacementOffset {
|
||||||
let content_width = content_rect.width();
|
top,
|
||||||
let target_left = target_rect.left();
|
left,
|
||||||
let target_right = target_rect.right();
|
transform: String::new(),
|
||||||
let left = target_right;
|
placement,
|
||||||
let (left, new_placement) = if left + content_width > window_inner_width
|
})
|
||||||
&& target_left - content_width >= 0.0
|
|
||||||
{
|
|
||||||
(target_left - content_width, FollowerPlacement::Left)
|
|
||||||
} else {
|
|
||||||
(left, FollowerPlacement::Right)
|
|
||||||
};
|
|
||||||
|
|
||||||
if placement == FollowerPlacement::Right {
|
|
||||||
let top = target_rect.top() + target_rect.height() / 2.0;
|
|
||||||
let transform = String::from("translateY(-50%)");
|
|
||||||
(left, new_placement, top, transform)
|
|
||||||
} else if placement == FollowerPlacement::RightStart {
|
|
||||||
let top = target_rect.top();
|
|
||||||
let transform = String::new();
|
|
||||||
(left, new_placement, top, transform)
|
|
||||||
} else if placement == FollowerPlacement::RightEnd {
|
|
||||||
let top = target_rect.bottom();
|
|
||||||
let transform = String::from("translateY(-100%)");
|
|
||||||
(left, new_placement, top, transform)
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
FollowerPlacement::LeftEnd => {
|
||||||
|
let top = target_rect.y() + target_rect.height();
|
||||||
|
let (left, placement) = {
|
||||||
|
let follower_width = follower_rect.width();
|
||||||
|
let target_x = target_rect.x();
|
||||||
|
let target_width = target_rect.width();
|
||||||
|
let left = target_x - follower_width;
|
||||||
|
|
||||||
Some(FollowerPlacementOffset {
|
let Some(inner_width) = window_inner_width() else {
|
||||||
top: top - follower_rect.top(),
|
return None;
|
||||||
left: left - follower_rect.left(),
|
};
|
||||||
placement,
|
|
||||||
transform,
|
if left < 0.0 && target_x + target_width + follower_width > inner_width {
|
||||||
})
|
(target_x + follower_width, FollowerPlacement::RightEnd)
|
||||||
|
} else {
|
||||||
|
(left, FollowerPlacement::LeftEnd)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Some(FollowerPlacementOffset {
|
||||||
|
top,
|
||||||
|
left,
|
||||||
|
transform: String::from("translateY(-100%)"),
|
||||||
|
placement,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
FollowerPlacement::Right => {
|
||||||
|
let top = target_rect.y() + target_rect.height() / 2.0;
|
||||||
|
let (left, placement) = {
|
||||||
|
let follower_width = follower_rect.width();
|
||||||
|
let target_x = target_rect.x();
|
||||||
|
let target_width = target_rect.width();
|
||||||
|
let left = target_x + target_width;
|
||||||
|
|
||||||
|
let Some(inner_width) = window_inner_width() else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
if left + follower_width > inner_width && target_x - follower_width >= 0.0 {
|
||||||
|
(target_x - follower_width, FollowerPlacement::Left)
|
||||||
|
} else {
|
||||||
|
(left, FollowerPlacement::Right)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Some(FollowerPlacementOffset {
|
||||||
|
top,
|
||||||
|
left,
|
||||||
|
transform: String::from("translateY(-50%)"),
|
||||||
|
placement,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
FollowerPlacement::RightStart => {
|
||||||
|
let top = target_rect.y();
|
||||||
|
let (left, placement) = {
|
||||||
|
let follower_width = follower_rect.width();
|
||||||
|
let target_x = target_rect.x();
|
||||||
|
let target_width = target_rect.width();
|
||||||
|
let left = target_x + target_width;
|
||||||
|
|
||||||
|
let Some(inner_width) = window_inner_width() else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
if left + follower_width > inner_width && target_x - follower_width >= 0.0 {
|
||||||
|
(target_x - follower_width, FollowerPlacement::LeftStart)
|
||||||
|
} else {
|
||||||
|
(left, FollowerPlacement::RightStart)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Some(FollowerPlacementOffset {
|
||||||
|
top,
|
||||||
|
left,
|
||||||
|
transform: String::new(),
|
||||||
|
placement,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
FollowerPlacement::RightEnd => {
|
||||||
|
let top = target_rect.y() + target_rect.height();
|
||||||
|
let (left, placement) = {
|
||||||
|
let follower_width = follower_rect.width();
|
||||||
|
let target_x = target_rect.x();
|
||||||
|
let target_width = target_rect.width();
|
||||||
|
let left = target_x + target_width;
|
||||||
|
|
||||||
|
let Some(inner_width) = window_inner_width() else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
if left + follower_width > inner_width && target_x - follower_width >= 0.0 {
|
||||||
|
(target_x - follower_width, FollowerPlacement::LeftEnd)
|
||||||
|
} else {
|
||||||
|
(left, FollowerPlacement::RightEnd)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Some(FollowerPlacementOffset {
|
||||||
|
top,
|
||||||
|
left,
|
||||||
|
transform: String::from("translateY(-100%)"),
|
||||||
|
placement,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
FollowerPlacement::Bottom => {
|
||||||
|
let left = target_rect.x() + target_rect.width() / 2.0;
|
||||||
|
let (top, placement) = {
|
||||||
|
let follower_height = follower_rect.height();
|
||||||
|
let target_y = target_rect.y();
|
||||||
|
let target_height = target_rect.height();
|
||||||
|
let top = target_y + target_height;
|
||||||
|
|
||||||
|
let Some(inner_height) = window_inner_height() else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
if top + follower_height > inner_height && target_y - follower_height >= 0.0 {
|
||||||
|
(target_y - follower_height, FollowerPlacement::Top)
|
||||||
|
} else {
|
||||||
|
(top, FollowerPlacement::Bottom)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Some(FollowerPlacementOffset {
|
||||||
|
top,
|
||||||
|
left,
|
||||||
|
transform: String::from("translateX(-50%)"),
|
||||||
|
placement,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
FollowerPlacement::BottomStart => {
|
||||||
|
let left = target_rect.x();
|
||||||
|
let (top, placement) = {
|
||||||
|
let follower_height = follower_rect.height();
|
||||||
|
let target_y = target_rect.y();
|
||||||
|
let target_height = target_rect.height();
|
||||||
|
let top = target_y + target_height;
|
||||||
|
|
||||||
|
let Some(inner_height) = window_inner_height() else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
if top + follower_height > inner_height && target_y - follower_height >= 0.0 {
|
||||||
|
(target_y - follower_height, FollowerPlacement::TopStart)
|
||||||
|
} else {
|
||||||
|
(top, FollowerPlacement::BottomStart)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Some(FollowerPlacementOffset {
|
||||||
|
top,
|
||||||
|
left,
|
||||||
|
transform: String::new(),
|
||||||
|
placement,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
FollowerPlacement::BottomEnd => {
|
||||||
|
let left = target_rect.x() + target_rect.width();
|
||||||
|
let (top, placement) = {
|
||||||
|
let follower_height = follower_rect.height();
|
||||||
|
let target_y = target_rect.y();
|
||||||
|
let target_height = target_rect.height();
|
||||||
|
let top = target_y + target_height;
|
||||||
|
|
||||||
|
let Some(inner_height) = window_inner_height() else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
if top + follower_height > inner_height && target_y - follower_height >= 0.0 {
|
||||||
|
(target_y - follower_height, FollowerPlacement::TopEnd)
|
||||||
|
} else {
|
||||||
|
(top, FollowerPlacement::BottomEnd)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Some(FollowerPlacementOffset {
|
||||||
|
top,
|
||||||
|
left,
|
||||||
|
transform: String::from("translateX(-100%)"),
|
||||||
|
placement,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn window_inner_width() -> Option<f64> {
|
fn window_inner_width() -> Option<f64> {
|
||||||
|
|
|
@ -14,7 +14,7 @@ use leptos::{
|
||||||
leptos_dom::helpers::WindowListenerHandle,
|
leptos_dom::helpers::WindowListenerHandle,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
use thaw_utils::{add_event_listener, get_scroll_parent_node, mount_style, EventListenerHandle};
|
use thaw_utils::{add_event_listener, get_scroll_parent, mount_style, EventListenerHandle};
|
||||||
|
|
||||||
#[slot]
|
#[slot]
|
||||||
pub struct Follower {
|
pub struct Follower {
|
||||||
|
@ -82,21 +82,16 @@ where
|
||||||
|
|
||||||
let scrollable_element_handle_vec = StoredValue::<Vec<EventListenerHandle>>::new(vec![]);
|
let scrollable_element_handle_vec = StoredValue::<Vec<EventListenerHandle>>::new(vec![]);
|
||||||
let resize_handle = StoredValue::new(None::<WindowListenerHandle>);
|
let resize_handle = StoredValue::new(None::<WindowListenerHandle>);
|
||||||
let follower_ref = NodeRef::<html::Div>::new();
|
|
||||||
let content_ref = NodeRef::<html::Div>::new();
|
let content_ref = NodeRef::<html::Div>::new();
|
||||||
let content_style = RwSignal::new(String::new());
|
let content_style = RwSignal::new(String::new());
|
||||||
let placement_str = RwSignal::new(follower_placement.as_str());
|
let placement_str = RwSignal::new(follower_placement.as_str());
|
||||||
let sync_position = move || {
|
let sync_position = move || {
|
||||||
let Some(follower_el) = follower_ref.get_untracked() else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
let Some(content_ref) = content_ref.get_untracked() else {
|
let Some(content_ref) = content_ref.get_untracked() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let Some(target_ref) = target_ref.get_untracked() else {
|
let Some(target_ref) = target_ref.get_untracked() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let follower_rect = follower_el.get_bounding_client_rect();
|
|
||||||
let target_rect = target_ref.get_bounding_client_rect();
|
let target_rect = target_ref.get_bounding_client_rect();
|
||||||
let content_rect = content_ref.get_bounding_client_rect();
|
let content_rect = content_ref.get_bounding_client_rect();
|
||||||
let mut style = String::new();
|
let mut style = String::new();
|
||||||
|
@ -113,12 +108,8 @@ where
|
||||||
left,
|
left,
|
||||||
transform,
|
transform,
|
||||||
placement,
|
placement,
|
||||||
}) = get_follower_placement_offset(
|
}) = get_follower_placement_offset(follower_placement, target_rect, content_rect)
|
||||||
follower_placement,
|
{
|
||||||
target_rect,
|
|
||||||
follower_rect,
|
|
||||||
content_rect,
|
|
||||||
) {
|
|
||||||
placement_str.set(placement.as_str());
|
placement_str.set(placement.as_str());
|
||||||
style.push_str(&format!(
|
style.push_str(&format!(
|
||||||
"transform-origin: {};",
|
"transform-origin: {};",
|
||||||
|
@ -141,12 +132,12 @@ where
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut handle_vec = vec![];
|
let mut handle_vec = vec![];
|
||||||
let mut cursor = get_scroll_parent_node(&el);
|
let mut cursor = get_scroll_parent(&el);
|
||||||
loop {
|
loop {
|
||||||
if let Some(node) = cursor.take() {
|
if let Some(el) = cursor.take() {
|
||||||
cursor = get_scroll_parent_node(&node);
|
cursor = get_scroll_parent(&el);
|
||||||
|
|
||||||
let handle = add_event_listener(node, ev::scroll, move |_| {
|
let handle = add_event_listener(el, ev::scroll, move |_| {
|
||||||
sync_position();
|
sync_position();
|
||||||
});
|
});
|
||||||
handle_vec.push(handle);
|
handle_vec.push(handle);
|
||||||
|
@ -206,16 +197,18 @@ where
|
||||||
view! {
|
view! {
|
||||||
{children()}
|
{children()}
|
||||||
<Teleport immediate=follower_show>
|
<Teleport immediate=follower_show>
|
||||||
<div class="thaw-binder-follower" node_ref=follower_ref>
|
<Provider value=follower_injection>
|
||||||
<div
|
<div class="thaw-binder-follower-container">
|
||||||
class="thaw-binder-follower-content"
|
<div
|
||||||
data-thaw-placement=move || placement_str.get()
|
class="thaw-binder-follower-content"
|
||||||
node_ref=content_ref
|
data-thaw-placement=move || placement_str.get()
|
||||||
style=move || content_style.get()
|
node_ref=content_ref
|
||||||
>
|
style=move || content_style.get()
|
||||||
<Provider value=follower_injection>{follower_children()}</Provider>
|
>
|
||||||
|
{follower_children()}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Provider>
|
||||||
</Teleport>
|
</Teleport>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,13 +92,13 @@ where
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let handle = match types {
|
let handle = match types {
|
||||||
AnimationTypes::Transition => {
|
AnimationTypes::Transition => add_event_listener(
|
||||||
add_event_listener(el.deref().clone(), ev::transitionend, move |_| {
|
el.deref().clone().into(),
|
||||||
event_listener()
|
ev::transitionend,
|
||||||
})
|
move |_| event_listener(),
|
||||||
}
|
),
|
||||||
AnimationTypes::Animation => {
|
AnimationTypes::Animation => {
|
||||||
add_event_listener(el.deref().clone(), ev::animationend, move |_| {
|
add_event_listener(el.deref().clone().into(), ev::animationend, move |_| {
|
||||||
event_listener()
|
event_listener()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,49 +1,39 @@
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
use wasm_bindgen::JsCast;
|
use web_sys::Element;
|
||||||
use web_sys::{Element, Node};
|
|
||||||
|
|
||||||
pub fn get_scroll_parent_node(node: &Node) -> Option<Node> {
|
pub fn get_scroll_parent(element: &Element) -> Option<Element> {
|
||||||
let parent_node = node.parent_node()?;
|
let Some(parent_element) = get_parent_element(element) else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
let node_type = parent_node.node_type();
|
if parent_element.node_type() == 9 {
|
||||||
if node_type == Node::ELEMENT_NODE {
|
return Some(parent_element);
|
||||||
let el = parent_node.clone().dyn_into::<Element>().unwrap();
|
}
|
||||||
if let Some((overflow, overflow_x, overflow_y)) = get_overflow(&el) {
|
|
||||||
|
if parent_element.node_type() == 1 {
|
||||||
|
if let Some((overflow, overflow_x, overflow_y)) = get_overflow(&parent_element) {
|
||||||
let overflow = format!("{overflow}{overflow_x}{overflow_y}");
|
let overflow = format!("{overflow}{overflow_x}{overflow_y}");
|
||||||
if overflow.contains("auto") {
|
if overflow.contains("auto") {
|
||||||
return Some(parent_node);
|
return Some(parent_element);
|
||||||
}
|
}
|
||||||
if overflow.contains("scroll") {
|
if overflow.contains("scroll") {
|
||||||
return Some(parent_node);
|
return Some(parent_element);
|
||||||
}
|
}
|
||||||
if overflow.contains("overlay") {
|
if overflow.contains("overlay") {
|
||||||
return Some(parent_node);
|
return Some(parent_element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if node_type == Node::DOCUMENT_NODE {
|
|
||||||
return Some(document().into());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get_scroll_parent_node(&parent_node)
|
get_scroll_parent(&parent_element)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_scroll_parent_element(element: &Element) -> Option<Element> {
|
fn get_parent_element(element: &Element) -> Option<Element> {
|
||||||
let parent_element = element.parent_element()?;
|
if element.node_type() == 9 {
|
||||||
|
None
|
||||||
if let Some((overflow, overflow_x, overflow_y)) = get_overflow(&parent_element) {
|
} else {
|
||||||
let overflow = format!("{overflow}{overflow_x}{overflow_y}");
|
element.parent_element()
|
||||||
if overflow.contains("auto") {
|
|
||||||
return Some(parent_element);
|
|
||||||
}
|
|
||||||
if overflow.contains("scroll") {
|
|
||||||
return Some(parent_element);
|
|
||||||
}
|
|
||||||
if overflow.contains("overlay") {
|
|
||||||
return Some(parent_element);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get_scroll_parent_element(&parent_element)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_overflow(parent_element: &Element) -> Option<(String, String, String)> {
|
fn get_overflow(parent_element: &Element) -> Option<(String, String, String)> {
|
||||||
|
|
|
@ -2,6 +2,6 @@ mod get_scroll_parent;
|
||||||
mod mount_style;
|
mod mount_style;
|
||||||
mod scroll_into_view;
|
mod scroll_into_view;
|
||||||
|
|
||||||
pub use get_scroll_parent::{get_scroll_parent_element, get_scroll_parent_node};
|
pub use get_scroll_parent::get_scroll_parent;
|
||||||
pub use mount_style::{mount_dynamic_style, mount_style};
|
pub use mount_style::{mount_dynamic_style, mount_style};
|
||||||
pub use scroll_into_view::scroll_into_view;
|
pub use scroll_into_view::scroll_into_view;
|
||||||
|
|
|
@ -3,8 +3,8 @@ use web_sys::HtmlElement;
|
||||||
|
|
||||||
pub fn scroll_into_view(el: &HtmlElement) {
|
pub fn scroll_into_view(el: &HtmlElement) {
|
||||||
cfg_if! { if #[cfg(all(target_arch = "wasm32", any(feature = "csr", feature = "hydrate")))] {
|
cfg_if! { if #[cfg(all(target_arch = "wasm32", any(feature = "csr", feature = "hydrate")))] {
|
||||||
use super::get_scroll_parent_element;
|
use super::get_scroll_parent;
|
||||||
if let Some(parent) = get_scroll_parent_element(el) {
|
if let Some(parent) = get_scroll_parent(el) {
|
||||||
let parent_rect = parent.get_bounding_client_rect();
|
let parent_rect = parent.get_bounding_client_rect();
|
||||||
let el_rect = el.get_bounding_client_rect();
|
let el_rect = el.get_bounding_client_rect();
|
||||||
if el_rect.y() < parent_rect.y() {
|
if el_rect.y() < parent_rect.y() {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use ::wasm_bindgen::{prelude::Closure, JsCast};
|
use ::wasm_bindgen::{prelude::Closure, JsCast};
|
||||||
use leptos::ev;
|
use leptos::ev;
|
||||||
use web_sys::EventTarget;
|
use web_sys::{Element, EventTarget};
|
||||||
|
|
||||||
pub fn add_event_listener<E>(
|
pub fn add_event_listener<E>(
|
||||||
target: impl Into<EventTarget>,
|
target: Element,
|
||||||
event: E,
|
event: E,
|
||||||
cb: impl Fn(E::EventType) + 'static,
|
cb: impl Fn(E::EventType) + 'static,
|
||||||
) -> EventListenerHandle
|
) -> EventListenerHandle
|
||||||
|
@ -31,12 +31,12 @@ impl EventListenerHandle {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_event_listener_untyped(
|
fn add_event_listener_untyped(
|
||||||
target: impl Into<EventTarget>,
|
target: Element,
|
||||||
event_name: &str,
|
event_name: &str,
|
||||||
cb: impl Fn(web_sys::Event) + 'static,
|
cb: impl Fn(web_sys::Event) + 'static,
|
||||||
) -> EventListenerHandle {
|
) -> EventListenerHandle {
|
||||||
fn wel(
|
fn wel(
|
||||||
target: EventTarget,
|
target: Element,
|
||||||
cb: Box<dyn FnMut(web_sys::Event)>,
|
cb: Box<dyn FnMut(web_sys::Event)>,
|
||||||
event_name: &str,
|
event_name: &str,
|
||||||
) -> EventListenerHandle {
|
) -> EventListenerHandle {
|
||||||
|
@ -54,11 +54,11 @@ fn add_event_listener_untyped(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
wel(target.into(), Box::new(cb), event_name)
|
wel(target, Box::new(cb), event_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_event_listener_with_bool<E: ev::EventDescriptor + 'static>(
|
pub fn add_event_listener_with_bool<E: ev::EventDescriptor + 'static>(
|
||||||
target: impl Into<EventTarget>,
|
target: impl IntoEventTarget,
|
||||||
event: E,
|
event: E,
|
||||||
cb: impl Fn(E::EventType) + 'static,
|
cb: impl Fn(E::EventType) + 'static,
|
||||||
use_capture: bool,
|
use_capture: bool,
|
||||||
|
@ -67,7 +67,7 @@ where
|
||||||
E::EventType: JsCast,
|
E::EventType: JsCast,
|
||||||
{
|
{
|
||||||
add_event_listener_untyped_with_bool(
|
add_event_listener_untyped_with_bool(
|
||||||
target,
|
target.into_event_target(),
|
||||||
&event.name(),
|
&event.name(),
|
||||||
move |e| cb(e.unchecked_into::<E::EventType>()),
|
move |e| cb(e.unchecked_into::<E::EventType>()),
|
||||||
use_capture,
|
use_capture,
|
||||||
|
@ -75,7 +75,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_event_listener_untyped_with_bool(
|
fn add_event_listener_untyped_with_bool(
|
||||||
target: impl Into<EventTarget>,
|
target: EventTarget,
|
||||||
event_name: &str,
|
event_name: &str,
|
||||||
cb: impl Fn(web_sys::Event) + 'static,
|
cb: impl Fn(web_sys::Event) + 'static,
|
||||||
use_capture: bool,
|
use_capture: bool,
|
||||||
|
@ -107,30 +107,24 @@ fn add_event_listener_untyped_with_bool(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
wel(target.into(), Box::new(cb), event_name, use_capture)
|
wel(target, Box::new(cb), event_name, use_capture)
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub trait IntoEventTarget {
|
pub trait IntoEventTarget {
|
||||||
// fn into_event_target(self) -> EventTarget;
|
fn into_event_target(self) -> EventTarget;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// impl IntoEventTarget for EventTarget {
|
impl IntoEventTarget for EventTarget {
|
||||||
// fn into_event_target(self) -> EventTarget {
|
fn into_event_target(self) -> EventTarget {
|
||||||
// self
|
self
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// impl IntoEventTarget for web_sys::Document {
|
impl IntoEventTarget for web_sys::Document {
|
||||||
// fn into_event_target(self) -> EventTarget {
|
fn into_event_target(self) -> EventTarget {
|
||||||
// self.into()
|
self.into()
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// impl IntoEventTarget for Element {
|
|
||||||
// fn into_event_target(self) -> EventTarget {
|
|
||||||
// self.into()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// impl IntoEventTarget for HtmlElement<AnyElement> {
|
// impl IntoEventTarget for HtmlElement<AnyElement> {
|
||||||
// fn into_event_target(self) -> EventTarget {
|
// fn into_event_target(self) -> EventTarget {
|
||||||
|
|
|
@ -4,6 +4,6 @@ mod signal_watch;
|
||||||
mod stored_maybe_signal;
|
mod stored_maybe_signal;
|
||||||
|
|
||||||
pub use component_ref::ComponentRef;
|
pub use component_ref::ComponentRef;
|
||||||
pub use model::{Model, OptionModel, OptionModelWithValue, VecModel, VecModelWithValue};
|
pub use model::{Model, OptionModel, VecModel, VecModelWithValue, OptionModelWithValue};
|
||||||
pub use signal_watch::SignalWatch;
|
pub use signal_watch::SignalWatch;
|
||||||
pub use stored_maybe_signal::StoredMaybeSignal;
|
pub use stored_maybe_signal::StoredMaybeSignal;
|
||||||
|
|
|
@ -58,9 +58,7 @@ impl<T: Send + Sync> OptionModel<T> {
|
||||||
pub fn with_untracked<O>(&self, fun: impl FnOnce(OptionModelWithValue<T>) -> O) -> O {
|
pub fn with_untracked<O>(&self, fun: impl FnOnce(OptionModelWithValue<T>) -> O) -> O {
|
||||||
match self {
|
match self {
|
||||||
Self::T(read, _, _) => read.with_untracked(|value| fun(OptionModelWithValue::T(value))),
|
Self::T(read, _, _) => read.with_untracked(|value| fun(OptionModelWithValue::T(value))),
|
||||||
Self::Option(read, _, _) => {
|
Self::Option(read, _, _) => read.with_untracked(|value| fun(OptionModelWithValue::Option(value))),
|
||||||
read.with_untracked(|value| fun(OptionModelWithValue::Option(value)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,10 @@ impl<T: Send + Sync> VecModel<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with<O>(&self, fun: impl FnOnce(VecModelWithValue<T>) -> O) -> O {
|
pub fn with<O>(
|
||||||
|
&self,
|
||||||
|
fun: impl FnOnce(VecModelWithValue<T>) -> O,
|
||||||
|
) -> O {
|
||||||
match self {
|
match self {
|
||||||
Self::T(read, _, _) => read.with(|value| fun(VecModelWithValue::T(value))),
|
Self::T(read, _, _) => read.with(|value| fun(VecModelWithValue::T(value))),
|
||||||
Self::Option(read, _, _) => read.with(|value| fun(VecModelWithValue::Option(value))),
|
Self::Option(read, _, _) => read.with(|value| fun(VecModelWithValue::Option(value))),
|
||||||
|
|
Loading…
Add table
Reference in a new issue