mirror of
https://github.com/adoyle0/thaw.git
synced 2025-01-22 22:09:22 -05:00
feat: improved Tooltip component
This commit is contained in:
parent
5aac76c558
commit
e4593a2bf3
7 changed files with 194 additions and 63 deletions
|
@ -14,29 +14,21 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.demo-demo__toolbar {
|
.demo-demo__toolbar {
|
||||||
display: flex;
|
height: 26px;
|
||||||
justify-content: center;
|
box-sizing: border-box;
|
||||||
align-items: center;
|
text-align: center;
|
||||||
padding: 0.4rem;
|
|
||||||
border-top: 1px dashed var(--demo-border-color);
|
border-top: 1px dashed var(--demo-border-color);
|
||||||
border-bottom: 1px dashed var(--demo-border-color);
|
border-bottom: 1px dashed var(--demo-border-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.demo-demo__toolbar > .thaw-tooltip {
|
||||||
|
height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
.demo-demo__toolbar--code {
|
.demo-demo__toolbar--code {
|
||||||
border-bottom-width: 0;
|
border-bottom-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.demo-demo__toolbar-btn {
|
|
||||||
display: flex;
|
|
||||||
cursor: pointer;
|
|
||||||
color: var(--demo-color);
|
|
||||||
transition: color .3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.demo-demo__toolbar-btn:hover {
|
|
||||||
color: var(--demo-color-hover);
|
|
||||||
}
|
|
||||||
|
|
||||||
.demo-demo__code {
|
.demo-demo__code {
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-size: 0.875em;
|
font-size: 0.875em;
|
||||||
|
|
|
@ -17,13 +17,9 @@ pub fn Demo(demo_code: DemoCode, #[prop(optional)] children: Option<Children>) -
|
||||||
let mut css_vars = String::new();
|
let mut css_vars = String::new();
|
||||||
theme.with(|theme| {
|
theme.with(|theme| {
|
||||||
if theme.color.color_scheme == "dark" {
|
if theme.color.color_scheme == "dark" {
|
||||||
css_vars.push_str("--demo-color: #ffffff60;");
|
|
||||||
css_vars.push_str("--demo-color-hover: #ffffffe0;");
|
|
||||||
css_vars.push_str("--demo-border-color: #383f52;");
|
css_vars.push_str("--demo-border-color: #383f52;");
|
||||||
css_vars.push_str("--demo-background-color: #242832;");
|
css_vars.push_str("--demo-background-color: #242832;");
|
||||||
} else {
|
} else {
|
||||||
css_vars.push_str("--demo-color: #00000060;");
|
|
||||||
css_vars.push_str("--demo-color-hover: #000000e0;");
|
|
||||||
css_vars.push_str(&format!("--demo-border-color: var(--colorNeutralStroke2);",));
|
css_vars.push_str(&format!("--demo-border-color: var(--colorNeutralStroke2);",));
|
||||||
css_vars.push_str("--demo-background-color: #f9fafb;");
|
css_vars.push_str("--demo-background-color: #f9fafb;");
|
||||||
}
|
}
|
||||||
|
@ -52,31 +48,24 @@ pub fn Demo(demo_code: DemoCode, #[prop(optional)] children: Option<Children>) -
|
||||||
view! {
|
view! {
|
||||||
<div class="demo-demo__view">{children()}</div>
|
<div class="demo-demo__view">{children()}</div>
|
||||||
<div class="demo-demo__toolbar" class=("demo-demo__toolbar--code", move || !is_show_code.get())>
|
<div class="demo-demo__toolbar" class=("demo-demo__toolbar--code", move || !is_show_code.get())>
|
||||||
<Popover appearance=PopoverAppearance::Inverted>
|
<Tooltip
|
||||||
<PopoverTrigger slot>
|
content=MaybeSignal::derive(move || if is_show_code.get() {
|
||||||
<span on:click=move |_| is_show_code.update(|show| *show = !*show) class="demo-demo__toolbar-btn">
|
"Hide code".to_string()
|
||||||
{
|
|
||||||
move || if is_show_code.get() {
|
|
||||||
view! {
|
|
||||||
<Icon icon=icondata::LuCode2/>
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
view! {
|
"Show code".to_string()
|
||||||
<Icon icon=icondata::LuCode/>
|
})
|
||||||
}
|
appearance=TooltipAppearance::Inverted
|
||||||
}
|
>
|
||||||
}
|
<Button icon=MaybeProp::derive(move || if is_show_code.get() {
|
||||||
</span>
|
Some(icondata::LuCode2)
|
||||||
</PopoverTrigger>
|
|
||||||
{
|
|
||||||
move || if is_show_code.get() {
|
|
||||||
"Hide code"
|
|
||||||
} else {
|
} else {
|
||||||
"Show code"
|
Some(icondata::LuCode)
|
||||||
}
|
})
|
||||||
}
|
on:click=move |_| is_show_code.update(|show| *show = !*show)
|
||||||
</Popover>
|
appearance=ButtonAppearance::Transparent
|
||||||
|
size=ButtonSize::Small
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
}.into()
|
}.into()
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -44,6 +44,9 @@ pub struct ColorTheme {
|
||||||
pub color_neutral_stroke_accessible_hover: String,
|
pub color_neutral_stroke_accessible_hover: String,
|
||||||
pub color_neutral_stroke_accessible_pressed: String,
|
pub color_neutral_stroke_accessible_pressed: String,
|
||||||
|
|
||||||
|
pub color_neutral_shadow_ambient: String,
|
||||||
|
pub color_neutral_shadow_key: String,
|
||||||
|
|
||||||
pub color_neutral_stencil_1: String,
|
pub color_neutral_stencil_1: String,
|
||||||
pub color_neutral_stencil_2: String,
|
pub color_neutral_stencil_2: String,
|
||||||
|
|
||||||
|
@ -160,6 +163,9 @@ impl ColorTheme {
|
||||||
color_neutral_stroke_accessible_hover: "#575757".into(),
|
color_neutral_stroke_accessible_hover: "#575757".into(),
|
||||||
color_neutral_stroke_accessible_pressed: "#4d4d4d".into(),
|
color_neutral_stroke_accessible_pressed: "#4d4d4d".into(),
|
||||||
|
|
||||||
|
color_neutral_shadow_ambient: "rgba(0,0,0,0.12)".into(),
|
||||||
|
color_neutral_shadow_key: "rgba(0,0,0,0.14)".into(),
|
||||||
|
|
||||||
color_neutral_stencil_1: "#e6e6e6".into(),
|
color_neutral_stencil_1: "#e6e6e6".into(),
|
||||||
color_neutral_stencil_2: "#fafafa".into(),
|
color_neutral_stencil_2: "#fafafa".into(),
|
||||||
|
|
||||||
|
@ -277,6 +283,9 @@ impl ColorTheme {
|
||||||
color_neutral_stroke_accessible_hover: "#bdbdbd".into(),
|
color_neutral_stroke_accessible_hover: "#bdbdbd".into(),
|
||||||
color_neutral_stroke_accessible_pressed: "#b3b3b3".into(),
|
color_neutral_stroke_accessible_pressed: "#b3b3b3".into(),
|
||||||
|
|
||||||
|
color_neutral_shadow_ambient: "rgba(0,0,0,0.24)".into(),
|
||||||
|
color_neutral_shadow_key: "rgba(0,0,0,0.28)".into(),
|
||||||
|
|
||||||
color_neutral_stencil_1: "#575757".into(),
|
color_neutral_stencil_1: "#575757".into(),
|
||||||
color_neutral_stencil_2: "#333333".into(),
|
color_neutral_stencil_2: "#333333".into(),
|
||||||
|
|
||||||
|
|
|
@ -9,3 +9,25 @@ view! {
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Appearance: inverted
|
||||||
|
|
||||||
|
```rust demo
|
||||||
|
view! {
|
||||||
|
<Tooltip content="Example tooltip" appearance=TooltipAppearance::Inverted>
|
||||||
|
<Button>
|
||||||
|
"Example"
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Textarea Props
|
||||||
|
|
||||||
|
| Name | Type | Default | Description |
|
||||||
|
| ---------- | -------------------------------- | ------------------------- | -------------------------------------- |
|
||||||
|
| class | `MaybeProp<String>` | `Default::default()` | |
|
||||||
|
| content | `Option<MaybeSignal<String>>` | `None` | The text of the tooltip. |
|
||||||
|
| position | `TooltipPosition` | `TooltipPosition::Top` | Configure the position of the tooltip. |
|
||||||
|
| appearance | `MaybeSignal<TooltipAppearance>` | `TooltipAppearance::None` | The tooltip's visual appearance. |
|
||||||
|
| children | `Children` | | |
|
||||||
|
|
|
@ -0,0 +1,130 @@
|
||||||
|
div.thaw-tooltip-content {
|
||||||
|
position: relative;
|
||||||
|
transform-origin: inherit;
|
||||||
|
|
||||||
|
padding: 4px 11px 6px;
|
||||||
|
border-radius: var(--borderRadiusMedium);
|
||||||
|
border: 1px solid var(--colorTransparentStroke);
|
||||||
|
line-height: var(--lineHeightBase200);
|
||||||
|
font-size: var(--fontSizeBase200);
|
||||||
|
font-family: var(--fontFamilyBase);
|
||||||
|
max-width: 240px;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
box-sizing: border-box;
|
||||||
|
filter: drop-shadow(0 0 2px var(--colorNeutralShadowAmbient))
|
||||||
|
drop-shadow(0 4px 8px var(--colorNeutralShadowKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
div.thaw-tooltip-content--normal {
|
||||||
|
background-color: var(--colorNeutralBackground1);
|
||||||
|
color: var(--colorNeutralForeground1);
|
||||||
|
}
|
||||||
|
|
||||||
|
div.thaw-tooltip-content--inverted {
|
||||||
|
background-color: var(--colorNeutralBackgroundStatic);
|
||||||
|
color: var(--colorNeutralForegroundStaticInverted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.thaw-tooltip-content__angle {
|
||||||
|
position: absolute;
|
||||||
|
background-color: inherit;
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thaw-tooltip {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-thaw-placement="top-start"] > .thaw-tooltip-content,
|
||||||
|
[data-thaw-placement="top-end"] > .thaw-tooltip-content,
|
||||||
|
[data-thaw-placement="top"] > .thaw-tooltip-content {
|
||||||
|
margin-bottom: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-thaw-placement="top-start"] .thaw-tooltip-content__angle,
|
||||||
|
[data-thaw-placement="top-end"] .thaw-tooltip-content__angle,
|
||||||
|
[data-thaw-placement="top"] .thaw-tooltip-content__angle {
|
||||||
|
transform: rotate(45deg) translateX(-7px);
|
||||||
|
bottom: -10px;
|
||||||
|
left: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-thaw-placement="bottom-start"] > .thaw-tooltip-content,
|
||||||
|
[data-thaw-placement="bottom-end"] > .thaw-tooltip-content,
|
||||||
|
[data-thaw-placement="bottom"] > .thaw-tooltip-content {
|
||||||
|
margin-top: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-thaw-placement="bottom-start"] .thaw-tooltip-content__angle,
|
||||||
|
[data-thaw-placement="bottom-end"] .thaw-tooltip-content__angle,
|
||||||
|
[data-thaw-placement="bottom"] .thaw-tooltip-content__angle {
|
||||||
|
transform: rotate(45deg) translateY(7px);
|
||||||
|
top: -10px;
|
||||||
|
left: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-thaw-placement="left-start"] > .thaw-tooltip-content,
|
||||||
|
[data-thaw-placement="left-end"] > .thaw-tooltip-content,
|
||||||
|
[data-thaw-placement="left"] > .thaw-tooltip-content {
|
||||||
|
margin-right: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-thaw-placement="left-start"] .thaw-tooltip-content__angle,
|
||||||
|
[data-thaw-placement="left-end"] .thaw-tooltip-content__angle,
|
||||||
|
[data-thaw-placement="left"] .thaw-tooltip-content__angle {
|
||||||
|
transform: rotate(45deg) translateX(-7px);
|
||||||
|
top: 50%;
|
||||||
|
right: -10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-thaw-placement="right-start"] > .thaw-tooltip-content,
|
||||||
|
[data-thaw-placement="right-end"] > .thaw-tooltip-content,
|
||||||
|
[data-thaw-placement="right"] > .thaw-tooltip-content {
|
||||||
|
margin-left: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-thaw-placement="right-start"] .thaw-tooltip-content__angle,
|
||||||
|
[data-thaw-placement="right-end"] .thaw-tooltip-content__angle,
|
||||||
|
[data-thaw-placement="right"] .thaw-tooltip-content__angle {
|
||||||
|
transform: rotate(45deg) translateY(-7px);
|
||||||
|
top: 50%;
|
||||||
|
left: -10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-thaw-placement="bottom-start"] .thaw-tooltip-content__angle,
|
||||||
|
[data-thaw-placement="top-start"] .thaw-tooltip-content__angle {
|
||||||
|
left: 16px;
|
||||||
|
}
|
||||||
|
[data-thaw-placement="bottom-end"] .thaw-tooltip-content__angle,
|
||||||
|
[data-thaw-placement="top-end"] .thaw-tooltip-content__angle {
|
||||||
|
left: initial;
|
||||||
|
right: 7px;
|
||||||
|
}
|
||||||
|
[data-thaw-placement="right-start"] .thaw-tooltip-content__angle,
|
||||||
|
[data-thaw-placement="left-start"] .thaw-tooltip-content__angle {
|
||||||
|
top: 16px;
|
||||||
|
}
|
||||||
|
[data-thaw-placement="right-end"] .thaw-tooltip-content__angle,
|
||||||
|
[data-thaw-placement="left-end"] .thaw-tooltip-content__angle {
|
||||||
|
top: initial;
|
||||||
|
bottom: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thaw-tooltip-content.tooltip-transition-enter-from,
|
||||||
|
.thaw-tooltip-content.tooltip-transition-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.85);
|
||||||
|
}
|
||||||
|
|
||||||
|
.thaw-tooltip-content.tooltip-transition-enter-to,
|
||||||
|
.thaw-tooltip-content.tooltip-transition-leave-from {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thaw-tooltip-content.tooltip-transition-leave-active,
|
||||||
|
.thaw-tooltip-content.tooltip-transition-enter-active {
|
||||||
|
transition: opacity var(--durationNormal) var(--curveDecelerateMid),
|
||||||
|
transform var(--durationNormal) var(--curveDecelerateMid);
|
||||||
|
}
|
|
@ -4,26 +4,18 @@ use std::time::Duration;
|
||||||
use thaw_components::{Binder, CSSTransition, Follower, FollowerPlacement};
|
use thaw_components::{Binder, CSSTransition, Follower, FollowerPlacement};
|
||||||
use thaw_utils::{class_list, mount_style};
|
use thaw_utils::{class_list, mount_style};
|
||||||
|
|
||||||
#[slot]
|
|
||||||
pub struct TooltipContent {
|
|
||||||
#[prop(optional, into)]
|
|
||||||
class: MaybeProp<String>,
|
|
||||||
children: Children,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn Tooltip(
|
pub fn Tooltip(
|
||||||
#[prop(optional, into)] class: MaybeProp<String>,
|
#[prop(optional, into)] class: MaybeProp<String>,
|
||||||
#[prop(optional)] tooltip_content: Option<TooltipContent>,
|
|
||||||
/// The text of the tooltip.
|
/// The text of the tooltip.
|
||||||
#[prop(optional, into)]
|
#[prop(optional, into)]
|
||||||
content: MaybeProp<String>,
|
content: Option<MaybeSignal<String>>,
|
||||||
/// Configure the positioning of the tooltip
|
/// Configure the position of the tooltip.
|
||||||
#[prop(optional)]
|
#[prop(optional)]
|
||||||
position: TooltipPosition,
|
position: TooltipPosition,
|
||||||
/// The tooltip's visual appearance.
|
/// The tooltip's visual appearance.
|
||||||
#[prop(optional, into)]
|
#[prop(optional, into)]
|
||||||
appearance: MaybeProp<TooltipAppearance>,
|
appearance: MaybeSignal<TooltipAppearance>,
|
||||||
children: Children,
|
children: Children,
|
||||||
) -> impl IntoView {
|
) -> impl IntoView {
|
||||||
mount_style("tooltip", include_str!("./tooltip.css"));
|
mount_style("tooltip", include_str!("./tooltip.css"));
|
||||||
|
@ -86,7 +78,7 @@ pub fn Tooltip(
|
||||||
<div
|
<div
|
||||||
class=class_list![
|
class=class_list![
|
||||||
"thaw-config-provider thaw-tooltip-content",
|
"thaw-config-provider thaw-tooltip-content",
|
||||||
move || appearance.get().map(|a| format!("thaw-tooltip-content--{}", a.as_str()))
|
move || format!("thaw-tooltip-content--{}", appearance.get().as_str())
|
||||||
]
|
]
|
||||||
data-thaw-id=config_provider.id().clone()
|
data-thaw-id=config_provider.id().clone()
|
||||||
style=move || display.get().unwrap_or_default()
|
style=move || display.get().unwrap_or_default()
|
||||||
|
@ -95,11 +87,7 @@ pub fn Tooltip(
|
||||||
on:mouseenter=on_mouse_enter
|
on:mouseenter=on_mouse_enter
|
||||||
on:mouseleave=on_mouse_leave
|
on:mouseleave=on_mouse_leave
|
||||||
>
|
>
|
||||||
{
|
{move || { content.as_ref().map(|c| c.get()).unwrap_or_default() }}
|
||||||
move || {
|
|
||||||
content.get()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
<div class="thaw-tooltip-content__angle"></div>
|
<div class="thaw-tooltip-content__angle"></div>
|
||||||
</div>
|
</div>
|
||||||
</CSSTransition>
|
</CSSTransition>
|
||||||
|
@ -108,8 +96,9 @@ pub fn Tooltip(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Default)]
|
||||||
pub enum TooltipAppearance {
|
pub enum TooltipAppearance {
|
||||||
|
#[default]
|
||||||
Normal,
|
Normal,
|
||||||
Inverted,
|
Inverted,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue