mirror of
https://github.com/adoyle0/thaw.git
synced 2025-01-22 22:09:22 -05:00
feat: popover appearance
This commit is contained in:
parent
c41d177782
commit
f999e252e4
6 changed files with 93 additions and 77 deletions
|
@ -68,7 +68,7 @@ pub fn Demo(demo_code: DemoCode, #[prop(optional)] children: Option<Children>) -
|
|||
view! {
|
||||
<div class="demo-demo__view">{children()}</div>
|
||||
<div class="demo-demo__toolbar" class=("demo-demo__toolbar--code", move || !is_show_code.get())>
|
||||
<Popover tooltip=true>
|
||||
<Popover appearance=PopoverAppearance::Inverted>
|
||||
<PopoverTrigger slot>
|
||||
<span on:click=move |_| is_show_code.update(|show| *show = !*show) class="demo-demo__toolbar-btn">
|
||||
{
|
||||
|
|
|
@ -54,7 +54,7 @@ view! {
|
|||
</Popover>
|
||||
</GridItem>
|
||||
<GridItem>
|
||||
<Popover placement=PopoverPlacement::LeftStart>
|
||||
<Popover placement=PopoverPlacement::LeftStart trigger_type=PopoverTriggerType::Click>
|
||||
<PopoverTrigger slot>
|
||||
<Button>"Left Start"</Button>
|
||||
</PopoverTrigger>
|
||||
|
@ -70,7 +70,7 @@ view! {
|
|||
</Popover>
|
||||
</GridItem>
|
||||
<GridItem>
|
||||
<Popover placement=PopoverPlacement::Left>
|
||||
<Popover placement=PopoverPlacement::Left trigger_type=PopoverTriggerType::Click>
|
||||
<PopoverTrigger slot>
|
||||
<Button>"Left"</Button>
|
||||
</PopoverTrigger>
|
||||
|
@ -129,12 +129,18 @@ view! {
|
|||
}
|
||||
```
|
||||
|
||||
### Tooltip
|
||||
### Appearance
|
||||
|
||||
```rust demo
|
||||
view! {
|
||||
<Space>
|
||||
<Popover tooltip=true>
|
||||
<Popover appearance=PopoverAppearance::Brand>
|
||||
<PopoverTrigger slot>
|
||||
<Button>"Hover"</Button>
|
||||
</PopoverTrigger>
|
||||
"Content"
|
||||
</Popover>
|
||||
<Popover appearance=PopoverAppearance::Inverted>
|
||||
<PopoverTrigger slot>
|
||||
<Button>"Hover"</Button>
|
||||
</PopoverTrigger>
|
||||
|
|
|
@ -1,32 +1,33 @@
|
|||
use crate::ConfigInjection;
|
||||
use leptos::{leptos_dom::helpers::TimeoutHandle, *};
|
||||
use palette::bool_mask::BoolMask;
|
||||
use std::time::Duration;
|
||||
use thaw_components::{Binder, CSSTransition, Follower, FollowerPlacement};
|
||||
use thaw_utils::{add_event_listener, class_list, mount_style, OptionalProp};
|
||||
use thaw_utils::{add_event_listener, class_list, mount_style};
|
||||
|
||||
#[slot]
|
||||
pub struct PopoverTrigger {
|
||||
#[prop(optional, into)]
|
||||
class: OptionalProp<MaybeSignal<String>>,
|
||||
class: MaybeProp<String>,
|
||||
children: Children,
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn Popover(
|
||||
#[prop(optional, into)] class: OptionalProp<MaybeSignal<String>>,
|
||||
#[prop(optional, into)] class: MaybeProp<String>,
|
||||
#[prop(optional)] trigger_type: PopoverTriggerType,
|
||||
popover_trigger: PopoverTrigger,
|
||||
#[prop(optional)] placement: PopoverPlacement,
|
||||
#[prop(optional)] tooltip: bool,
|
||||
#[prop(optional, into)] appearance: Option<MaybeSignal<PopoverAppearance>>,
|
||||
children: Children,
|
||||
) -> impl IntoView {
|
||||
mount_style("popover", include_str!("./popover.css"));
|
||||
let config_provider = ConfigInjection::use_();
|
||||
|
||||
let popover_ref = create_node_ref::<html::Div>();
|
||||
let target_ref = create_node_ref::<html::Div>();
|
||||
let is_show_popover = create_rw_signal(false);
|
||||
let show_popover_handle = store_value(None::<TimeoutHandle>);
|
||||
let popover_ref = NodeRef::<html::Div>::new();
|
||||
let target_ref = NodeRef::<html::Div>::new();
|
||||
let is_show_popover = RwSignal::new(false);
|
||||
let show_popover_handle = StoredValue::new(None::<TimeoutHandle>);
|
||||
|
||||
let on_mouse_enter = move |_| {
|
||||
if trigger_type != PopoverTriggerType::Hover {
|
||||
|
@ -63,6 +64,9 @@ pub fn Popover(
|
|||
if trigger_type != PopoverTriggerType::Click {
|
||||
return;
|
||||
}
|
||||
if !is_show_popover.get_untracked() {
|
||||
return;
|
||||
}
|
||||
let el = ev.target();
|
||||
let mut el: Option<web_sys::Element> =
|
||||
el.into_js_result().map_or(None, |el| Some(el.into()));
|
||||
|
@ -101,7 +105,7 @@ pub fn Popover(
|
|||
view! {
|
||||
<Binder target_ref>
|
||||
<div
|
||||
class=class_list!["thaw-popover-trigger", trigger_class.map(| c | move || c.get())]
|
||||
class=class_list!["thaw-popover-trigger", trigger_class]
|
||||
ref=target_ref
|
||||
on:mouseenter=on_mouse_enter
|
||||
on:mouseleave=on_mouse_leave
|
||||
|
@ -117,11 +121,11 @@ pub fn Popover(
|
|||
let:display
|
||||
>
|
||||
<div
|
||||
class=if tooltip {
|
||||
"thaw-config-provider thaw-popover-surface thaw-popover--tooltip" }
|
||||
else {
|
||||
"thaw-config-provider thaw-popover-surface"
|
||||
}
|
||||
class=class_list![
|
||||
"thaw-config-provider thaw-popover-surface",
|
||||
appearance.map(|appearance| move || format!("thaw-popover-surface--{}", appearance.get().as_str())),
|
||||
class
|
||||
]
|
||||
data-thaw-id=config_provider.id().clone()
|
||||
style=move || display.get()
|
||||
|
||||
|
@ -129,7 +133,7 @@ pub fn Popover(
|
|||
on:mouseenter=on_mouse_enter
|
||||
on:mouseleave=on_mouse_leave
|
||||
>
|
||||
<div class=class.map(|c| move || c.get())>{children()}</div>
|
||||
{children()}
|
||||
<div class="thaw-popover-surface__angle">
|
||||
</div>
|
||||
</div>
|
||||
|
@ -139,6 +143,21 @@ pub fn Popover(
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum PopoverAppearance {
|
||||
Brand,
|
||||
Inverted,
|
||||
}
|
||||
|
||||
impl PopoverAppearance {
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
PopoverAppearance::Brand => "brand",
|
||||
PopoverAppearance::Inverted => "inverted",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, PartialEq, Clone)]
|
||||
pub enum PopoverTriggerType {
|
||||
#[default]
|
||||
|
|
|
@ -14,6 +14,16 @@ div.thaw-popover-surface {
|
|||
color: var(--colorNeutralForeground1);
|
||||
}
|
||||
|
||||
div.thaw-popover-surface--brand {
|
||||
background-color: var(--colorBrandBackground);
|
||||
color: var(--colorNeutralForegroundOnBrand);
|
||||
}
|
||||
|
||||
div.thaw-popover-surface--inverted {
|
||||
background-color: var(--colorNeutralBackgroundStatic);
|
||||
color: var(--colorNeutralForegroundStaticInverted);
|
||||
}
|
||||
|
||||
.thaw-popover-surface__angle {
|
||||
position: absolute;
|
||||
background-color: inherit;
|
||||
|
@ -53,99 +63,70 @@ div.thaw-popover-surface {
|
|||
left: 50%;
|
||||
}
|
||||
|
||||
[data-thaw-placement="left-start"] > .thaw-popover,
|
||||
[data-thaw-placement="left-end"] > .thaw-popover,
|
||||
[data-thaw-placement="left"] > .thaw-popover {
|
||||
[data-thaw-placement="left-start"] > .thaw-popover-surface,
|
||||
[data-thaw-placement="left-end"] > .thaw-popover-surface,
|
||||
[data-thaw-placement="left"] > .thaw-popover-surface {
|
||||
margin-right: 10px;
|
||||
box-shadow: 3px 0 6px -4px rgba(0, 0, 0, 0.12),
|
||||
6px 0 16px 0 rgba(0, 0, 0, 0.08), 9px 0 28px 8px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
[data-thaw-placement="left-start"] .thaw-popover-surface__angle,
|
||||
[data-thaw-placement="left-end"] .thaw-popover-surface__angle,
|
||||
[data-thaw-placement="left"] .thaw-popover-surface__angle {
|
||||
width: 10px;
|
||||
height: 100%;
|
||||
right: -10px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
[data-thaw-placement="left-start"] .thaw-popover-surface__angle::before,
|
||||
[data-thaw-placement="left-end"] .thaw-popover-surface__angle::before,
|
||||
[data-thaw-placement="left"] .thaw-popover-surface__angle::before {
|
||||
top: 50%;
|
||||
transform: rotate(45deg) translateX(-7px);
|
||||
top: 50%;
|
||||
right: -10px;
|
||||
}
|
||||
|
||||
[data-thaw-placement="right-start"] > .thaw-popover,
|
||||
[data-thaw-placement="right-end"] > .thaw-popover,
|
||||
[data-thaw-placement="right"] > .thaw-popover {
|
||||
[data-thaw-placement="right-start"] > .thaw-popover-surface,
|
||||
[data-thaw-placement="right-end"] > .thaw-popover-surface,
|
||||
[data-thaw-placement="right"] > .thaw-popover-surface {
|
||||
margin-left: 10px;
|
||||
box-shadow: -3px 0 6px -4px rgba(0, 0, 0, 0.12),
|
||||
-6px 0 16px 0 rgba(0, 0, 0, 0.08), -9px 0 28px 8px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
[data-thaw-placement="right-start"] .thaw-popover-surface__angle,
|
||||
[data-thaw-placement="right-end"] .thaw-popover-surface__angle,
|
||||
[data-thaw-placement="right"] .thaw-popover-surface__angle {
|
||||
width: 10px;
|
||||
height: 100%;
|
||||
left: -10px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
[data-thaw-placement="right-start"] .thaw-popover-surface__angle::before,
|
||||
[data-thaw-placement="right-end"] .thaw-popover-surface__angle::before,
|
||||
[data-thaw-placement="right"] .thaw-popover-surface__angle::before {
|
||||
top: 50%;
|
||||
transform: rotate(45deg) translateY(-7px);
|
||||
top: 50%;
|
||||
left: -10px;
|
||||
}
|
||||
|
||||
[data-thaw-placement="bottom-start"] .thaw-popover-surface__angle,
|
||||
[data-thaw-placement="top-start"] .thaw-popover-surface__angle {
|
||||
left: 16px;
|
||||
}
|
||||
[data-thaw-placement="bottom-end"] .thaw-popover-surface__angle::before,
|
||||
[data-thaw-placement="top-end"] .thaw-popover-surface__angle::before {
|
||||
[data-thaw-placement="bottom-end"] .thaw-popover-surface__angle,
|
||||
[data-thaw-placement="top-end"] .thaw-popover-surface__angle {
|
||||
left: initial;
|
||||
right: 7px;
|
||||
}
|
||||
[data-thaw-placement="right-start"] .thaw-popover-surface__angle::before,
|
||||
[data-thaw-placement="left-start"] .thaw-popover-surface__angle::before {
|
||||
[data-thaw-placement="right-start"] .thaw-popover-surface__angle,
|
||||
[data-thaw-placement="left-start"] .thaw-popover-surface__angle {
|
||||
top: 16px;
|
||||
}
|
||||
[data-thaw-placement="right-end"] .thaw-popover-surface__angle::before,
|
||||
[data-thaw-placement="left-end"] .thaw-popover-surface__angle::before {
|
||||
[data-thaw-placement="right-end"] .thaw-popover-surface__angle,
|
||||
[data-thaw-placement="left-end"] .thaw-popover-surface__angle {
|
||||
top: initial;
|
||||
bottom: 7px;
|
||||
}
|
||||
|
||||
.thaw-popover.popover-transition-enter-from,
|
||||
.thaw-popover.popover-transition-leave-to {
|
||||
.thaw-popover-surface.popover-transition-enter-from,
|
||||
.thaw-popover-surface.popover-transition-leave-to {
|
||||
opacity: 0;
|
||||
transform: scale(0.85);
|
||||
}
|
||||
|
||||
.thaw-popover.popover-transition-enter-to,
|
||||
.thaw-popover.popover-transition-leave-from {
|
||||
.thaw-popover-surface.popover-transition-enter-to,
|
||||
.thaw-popover-surface.popover-transition-leave-from {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.thaw-popover.popover-transition-enter-active {
|
||||
transition: box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1),
|
||||
background-color 0.3s cubic-bezier(0.4, 0, 0.2, 1),
|
||||
color 0.3s cubic-bezier(0.4, 0, 0.2, 1),
|
||||
opacity 0.15s cubic-bezier(0, 0, 0.2, 1),
|
||||
transform 0.15s cubic-bezier(0, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.thaw-popover.popover-transition-leave-active {
|
||||
transition: box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1),
|
||||
background-color 0.3s cubic-bezier(0.4, 0, 0.2, 1),
|
||||
color 0.3s cubic-bezier(0.4, 0, 0.2, 1),
|
||||
opacity 0.15s cubic-bezier(0.4, 0, 1, 1),
|
||||
transform 0.15s cubic-bezier(0.4, 0, 1, 1);
|
||||
.thaw-popover-surface.popover-transition-leave-active,
|
||||
.thaw-popover-surface.popover-transition-enter-active {
|
||||
transition: box-shadow var(--durationSlow) var(--curveDecelerateMid),
|
||||
background-color var(--durationSlow) var(--curveDecelerateMid),
|
||||
color var(--durationSlow) var(--curveDecelerateMid),
|
||||
opacity var(--durationNormal) var(--curveDecelerateMid),
|
||||
transform var(--durationNormal) var(--curveDecelerateMid);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ use thaw_macro::WriteCSSVars;
|
|||
|
||||
#[derive(Clone, WriteCSSVars)]
|
||||
pub struct ColorTheme {
|
||||
pub color_neutral_background_static: String,
|
||||
pub color_neutral_background_disabled: String,
|
||||
pub color_neutral_background_1: String,
|
||||
pub color_neutral_background_1_hover: String,
|
||||
|
@ -15,6 +16,7 @@ pub struct ColorTheme {
|
|||
pub color_neutral_background_5: String,
|
||||
pub color_neutral_background_6: String,
|
||||
|
||||
pub color_neutral_foreground_static_inverted: String,
|
||||
pub color_neutral_foreground_disabled: String,
|
||||
pub color_neutral_foreground_1: String,
|
||||
pub color_neutral_foreground_1_hover: String,
|
||||
|
@ -100,6 +102,7 @@ pub struct ColorTheme {
|
|||
impl ColorTheme {
|
||||
pub fn light() -> Self {
|
||||
Self {
|
||||
color_neutral_background_static: "#333333".into(),
|
||||
color_neutral_background_disabled: "#f0f0f0".into(),
|
||||
color_neutral_background_1: "#ffffff".into(),
|
||||
color_neutral_background_1_hover: "#f5f5f5".into(),
|
||||
|
@ -113,6 +116,7 @@ impl ColorTheme {
|
|||
color_neutral_background_5: "#ebebeb".into(),
|
||||
color_neutral_background_6: "#e6e6e6".into(),
|
||||
|
||||
color_neutral_foreground_static_inverted: "#ffffff".into(),
|
||||
color_neutral_foreground_disabled: "#bdbdbd".into(),
|
||||
color_neutral_foreground_1: "#242424".into(),
|
||||
color_neutral_foreground_1_hover: "#242424".into(),
|
||||
|
@ -199,6 +203,7 @@ impl ColorTheme {
|
|||
|
||||
pub fn dark() -> Self {
|
||||
Self {
|
||||
color_neutral_background_static: "#3d3d3d".into(),
|
||||
color_neutral_background_disabled: "#141414".into(),
|
||||
color_neutral_background_1: "#292929".into(),
|
||||
color_neutral_background_1_hover: "#3d3d3d".into(),
|
||||
|
@ -212,6 +217,7 @@ impl ColorTheme {
|
|||
color_neutral_background_5: "#000000".into(),
|
||||
color_neutral_background_6: "#333333".into(),
|
||||
|
||||
color_neutral_foreground_static_inverted: "#ffffff".into(),
|
||||
color_neutral_foreground_disabled: "#5c5c5c".into(),
|
||||
color_neutral_foreground_1: "#fff".into(),
|
||||
color_neutral_foreground_1_hover: "#fff".into(),
|
||||
|
|
|
@ -260,7 +260,11 @@ fn get_timeout(mut delays: Vec<String>, durations: &Vec<String>) -> u64 {
|
|||
return 0;
|
||||
}
|
||||
|
||||
let s = s.split_at(s.len() - 1).0;
|
||||
let s = if s.ends_with("ms") {
|
||||
s.split_at(s.len() - 2).0
|
||||
} else {
|
||||
s.split_at(s.len() - 1).0
|
||||
};
|
||||
|
||||
(s.parse::<f32>().unwrap_or_default() * 1000.0).floor() as u64
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue