mirror of
https://github.com/adoyle0/thaw.git
synced 2025-03-12 21:49:49 -04:00
feat: binder component add width
This commit is contained in:
parent
c57910948f
commit
012ab684ba
7 changed files with 91 additions and 106 deletions
|
@ -1,7 +1,7 @@
|
|||
mod theme;
|
||||
|
||||
use crate::{
|
||||
components::{Binder, Follower, FollowerPlacement},
|
||||
components::{Binder, Follower, FollowerPlacement, FollowerWidth},
|
||||
mount_style, use_theme,
|
||||
utils::StoredMaybeSignal,
|
||||
Input, Theme,
|
||||
|
@ -61,7 +61,7 @@ pub fn AutoComplete(
|
|||
allow_value
|
||||
/>
|
||||
</div>
|
||||
<Follower slot show=is_show_menu placement=FollowerPlacement::BottomStart>
|
||||
<Follower slot show=is_show_menu placement=FollowerPlacement::BottomStart width=FollowerWidth::Target>
|
||||
<div
|
||||
class="thaw-auto-complete__menu"
|
||||
style=move || menu_css_vars.get()
|
||||
|
|
|
@ -18,10 +18,6 @@
|
|||
}
|
||||
|
||||
.thaw-color-picker-popover {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 240px;
|
||||
padding: 12px;
|
||||
background-color: var(--thaw-background-color);
|
||||
|
@ -29,7 +25,6 @@
|
|||
box-sizing: border-box;
|
||||
box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.12),
|
||||
0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 9px 28px 8px rgba(0, 0, 0, 0.05);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.thaw-color-picker-popover__panel {
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
mod color;
|
||||
mod theme;
|
||||
|
||||
use crate::{mount_style, teleport::Teleport, use_theme, Theme};
|
||||
use crate::components::{Binder, Follower, FollowerPlacement};
|
||||
use crate::{mount_style, use_theme, Theme};
|
||||
pub use color::*;
|
||||
use leptos::*;
|
||||
use leptos::{leptos_dom::helpers::WindowListenerHandle, wasm_bindgen::__rt::IntoJsResult};
|
||||
|
@ -62,18 +63,7 @@ pub fn ColorPicker(#[prop(optional, into)] value: RwSignal<RGBA>) -> impl IntoVi
|
|||
let trigger_ref = create_node_ref::<html::Div>();
|
||||
let popover_ref = create_node_ref::<html::Div>();
|
||||
let show_popover = move |_| {
|
||||
let rect = trigger_ref.get().unwrap().get_bounding_client_rect();
|
||||
is_show_popover.set(true);
|
||||
if let Some(popover_ref) = popover_ref.get() {
|
||||
_ = popover_ref.style(
|
||||
"transform",
|
||||
format!(
|
||||
"translateX({}px) translateY({}px)",
|
||||
rect.x(),
|
||||
rect.y() + rect.height()
|
||||
),
|
||||
);
|
||||
}
|
||||
};
|
||||
let timer = window_event_listener(ev::click, move |ev| {
|
||||
let el = ev.target();
|
||||
|
@ -96,28 +86,24 @@ pub fn ColorPicker(#[prop(optional, into)] value: RwSignal<RGBA>) -> impl IntoVi
|
|||
on_cleanup(move || timer.remove());
|
||||
|
||||
view! {
|
||||
<div class="thaw-color-picker-trigger" on:click=show_popover ref=trigger_ref>
|
||||
<div class="thaw-color-picker-trigger__content" style=move || style.get()>
|
||||
{move || label.get()}
|
||||
<Binder target_ref=trigger_ref>
|
||||
<div class="thaw-color-picker-trigger" on:click=show_popover ref=trigger_ref>
|
||||
<div class="thaw-color-picker-trigger__content" style=move || style.get()>
|
||||
{move || label.get()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Teleport>
|
||||
<div
|
||||
class="thaw-color-picker-popover"
|
||||
ref=popover_ref
|
||||
style=move || {
|
||||
if is_show_popover.get() {
|
||||
popover_css_vars.get()
|
||||
} else {
|
||||
"display: none".to_string()
|
||||
}
|
||||
}
|
||||
>
|
||||
<Follower slot show=is_show_popover placement=FollowerPlacement::BottomStart>
|
||||
<div
|
||||
class="thaw-color-picker-popover"
|
||||
ref=popover_ref
|
||||
style=move || popover_css_vars.get()
|
||||
>
|
||||
|
||||
<ColorPanel hue=hue.read_only() sv/>
|
||||
<HueSlider hue/>
|
||||
</div>
|
||||
</Teleport>
|
||||
<ColorPanel hue=hue.read_only() sv/>
|
||||
<HueSlider hue/>
|
||||
</div>
|
||||
</Follower>
|
||||
</Binder>
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -32,19 +32,17 @@ pub fn get_follower_placement_style(
|
|||
let follower_height = follower_rect.height();
|
||||
let target_y = target_rect.y();
|
||||
let target_height = target_rect.height();
|
||||
let mut top = target_y + target_height;
|
||||
let top = target_y + target_height;
|
||||
|
||||
let Some(inner_height) = window_inner_height() else {
|
||||
return None;
|
||||
};
|
||||
|
||||
if top + follower_height > inner_height {
|
||||
if target_y - follower_height >= 0.0 {
|
||||
top = target_y - follower_height
|
||||
}
|
||||
if top + follower_height > inner_height && target_y - follower_height >= 0.0 {
|
||||
target_y - follower_height
|
||||
} else {
|
||||
top
|
||||
}
|
||||
|
||||
top
|
||||
};
|
||||
|
||||
style.push_str(&format!(
|
||||
|
|
|
@ -17,10 +17,20 @@ use leptos::{
|
|||
pub struct Follower {
|
||||
#[prop(into)]
|
||||
show: MaybeSignal<bool>,
|
||||
#[prop(optional)]
|
||||
width: Option<FollowerWidth>,
|
||||
placement: FollowerPlacement,
|
||||
children: Children,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum FollowerWidth {
|
||||
Target,
|
||||
Px(u32),
|
||||
}
|
||||
|
||||
impl Copy for FollowerWidth {}
|
||||
|
||||
#[component]
|
||||
pub fn Binder<El: ElementDescriptor + Clone + 'static>(
|
||||
#[prop(into)] target_ref: NodeRef<El>,
|
||||
|
@ -30,6 +40,7 @@ pub fn Binder<El: ElementDescriptor + Clone + 'static>(
|
|||
mount_style("binder", include_str!("./binder.css"));
|
||||
let Follower {
|
||||
show: follower_show,
|
||||
width: follower_width,
|
||||
placement: follower_placement,
|
||||
children: follower_children,
|
||||
} = follower;
|
||||
|
@ -73,7 +84,7 @@ pub fn Binder<El: ElementDescriptor + Clone + 'static>(
|
|||
|
||||
let remove_scroll_listener = move |_| {
|
||||
scrollable_element_handle_vec.update_value(|vec| {
|
||||
vec.drain(..).into_iter().for_each(|handle| handle.remove());
|
||||
vec.drain(..).for_each(|handle| handle.remove());
|
||||
});
|
||||
scroll_listener.set_value(None);
|
||||
};
|
||||
|
@ -108,6 +119,7 @@ pub fn Binder<El: ElementDescriptor + Clone + 'static>(
|
|||
<FollowerContainer
|
||||
show=follower_show
|
||||
target_ref
|
||||
width=follower_width
|
||||
placement=follower_placement
|
||||
add_scroll_listener
|
||||
remove_scroll_listener
|
||||
|
@ -123,6 +135,7 @@ pub fn Binder<El: ElementDescriptor + Clone + 'static>(
|
|||
fn FollowerContainer<El: ElementDescriptor + Clone + 'static>(
|
||||
show: MaybeSignal<bool>,
|
||||
target_ref: NodeRef<El>,
|
||||
width: Option<FollowerWidth>,
|
||||
placement: FollowerPlacement,
|
||||
#[prop(into)] add_scroll_listener: Callback<Callback<()>>,
|
||||
#[prop(into)] remove_scroll_listener: Callback<()>,
|
||||
|
@ -142,7 +155,13 @@ fn FollowerContainer<El: ElementDescriptor + Clone + 'static>(
|
|||
let target_rect = target_ref.get_bounding_client_rect();
|
||||
let content_rect = content_ref.get_bounding_client_rect();
|
||||
let mut style = String::new();
|
||||
style.push_str(&format!("width: {}px;", target_rect.width()));
|
||||
if let Some(width) = width {
|
||||
let width = match width {
|
||||
FollowerWidth::Target => format!("width: {}px;", target_rect.width()),
|
||||
FollowerWidth::Px(width) => format!("width: {width}px;"),
|
||||
};
|
||||
style.push_str(&width);
|
||||
}
|
||||
if let Some(placement_style) =
|
||||
get_follower_placement_style(placement, target_rect, content_rect)
|
||||
{
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
mod theme;
|
||||
|
||||
use crate::{teleport::Teleport, theme::use_theme, utils::mount_style::mount_style, Theme};
|
||||
use crate::{
|
||||
components::{Binder, Follower, FollowerPlacement, FollowerWidth},
|
||||
theme::use_theme,
|
||||
utils::mount_style::mount_style,
|
||||
Theme,
|
||||
};
|
||||
use leptos::wasm_bindgen::__rt::IntoJsResult;
|
||||
use leptos::*;
|
||||
use std::hash::Hash;
|
||||
|
@ -66,20 +71,7 @@ where
|
|||
let trigger_ref = create_node_ref::<html::Div>();
|
||||
let menu_ref = create_node_ref::<html::Div>();
|
||||
let show_menu = move |_| {
|
||||
let rect = trigger_ref.get().unwrap().get_bounding_client_rect();
|
||||
is_show_menu.set(true);
|
||||
if let Some(menu_ref) = menu_ref.get() {
|
||||
_ = menu_ref
|
||||
.style("width", format!("{}px", rect.width()))
|
||||
.style(
|
||||
"transform",
|
||||
format!(
|
||||
"translateX({}px) translateY({}px) translateX(-50%)",
|
||||
rect.x() + rect.width() / 2.0,
|
||||
rect.y() + rect.height()
|
||||
),
|
||||
);
|
||||
}
|
||||
};
|
||||
let timer = window_event_listener(ev::click, move |ev| {
|
||||
let el = ev.target();
|
||||
|
@ -111,47 +103,46 @@ where
|
|||
None => String::new(),
|
||||
});
|
||||
view! {
|
||||
<div class="thaw-select" ref=trigger_ref on:click=show_menu style=move || css_vars.get()>
|
||||
<Binder target_ref=trigger_ref>
|
||||
<div class="thaw-select" ref=trigger_ref on:click=show_menu style=move || css_vars.get()>
|
||||
|
||||
{move || select_option_label.get()}
|
||||
|
||||
</div>
|
||||
<Teleport>
|
||||
<div
|
||||
class="thaw-select-menu"
|
||||
style=move || {
|
||||
if is_show_menu.get() { menu_css_vars.get() } else { "display: none;".into() }
|
||||
}
|
||||
|
||||
ref=menu_ref
|
||||
>
|
||||
<For
|
||||
each=move || options.get()
|
||||
key=move |item| item.value.clone()
|
||||
children=move |item| {
|
||||
let item = store_value(item);
|
||||
let onclick = move |_| {
|
||||
let SelectOption { value: item_value, label: _ } = item.get_value();
|
||||
value.set(Some(item_value));
|
||||
is_show_menu.set(false);
|
||||
};
|
||||
view! {
|
||||
<div
|
||||
class="thaw-select-menu__item"
|
||||
class=(
|
||||
"thaw-select-menu__item-selected",
|
||||
move || value.get() == Some(item.get_value().value),
|
||||
)
|
||||
|
||||
on:click=onclick
|
||||
>
|
||||
{item.get_value().label}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
/>
|
||||
{move || select_option_label.get()}
|
||||
|
||||
</div>
|
||||
</Teleport>
|
||||
<Follower slot show=is_show_menu placement=FollowerPlacement::BottomStart width=FollowerWidth::Target>
|
||||
<div
|
||||
class="thaw-select-menu"
|
||||
style=move || menu_css_vars.get()
|
||||
ref=menu_ref
|
||||
>
|
||||
<For
|
||||
each=move || options.get()
|
||||
key=move |item| item.value.clone()
|
||||
children=move |item| {
|
||||
let item = store_value(item);
|
||||
let onclick = move |_| {
|
||||
let SelectOption { value: item_value, label: _ } = item.get_value();
|
||||
value.set(Some(item_value));
|
||||
is_show_menu.set(false);
|
||||
};
|
||||
view! {
|
||||
<div
|
||||
class="thaw-select-menu__item"
|
||||
class=(
|
||||
"thaw-select-menu__item-selected",
|
||||
move || value.get() == Some(item.get_value().value),
|
||||
)
|
||||
|
||||
on:click=onclick
|
||||
>
|
||||
{item.get_value().label}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
/>
|
||||
|
||||
</div>
|
||||
</Follower>
|
||||
</Binder>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,16 +21,12 @@
|
|||
background-color: var(--thaw-background-color);
|
||||
box-sizing: border-box;
|
||||
padding: 5px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
max-height: 200px;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.12),
|
||||
0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 9px 28px 8px rgba(0, 0, 0, 0.05);
|
||||
overflow: auto;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.thaw-select-menu__item {
|
||||
|
|
Loading…
Add table
Reference in a new issue