mirror of
https://github.com/adoyle0/thaw.git
synced 2025-01-22 22:09:22 -05:00
refactor: Drawer
This commit is contained in:
parent
568e629377
commit
7eb81f32ae
7 changed files with 308 additions and 0 deletions
10
thaw/src/drawer/drawer_body.rs
Normal file
10
thaw/src/drawer/drawer_body.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
use leptos::*;
|
||||
|
||||
#[component]
|
||||
pub fn DrawerBody(children: Children) -> impl IntoView {
|
||||
view! {
|
||||
<div class="thaw-drawer-body">
|
||||
{children()}
|
||||
</div>
|
||||
}
|
||||
}
|
10
thaw/src/drawer/drawer_header.rs
Normal file
10
thaw/src/drawer/drawer_header.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
use leptos::*;
|
||||
|
||||
#[component]
|
||||
pub fn DrawerHeader(children: Children) -> impl IntoView {
|
||||
view! {
|
||||
<header class="thaw-drawer-header">
|
||||
{children()}
|
||||
</header>
|
||||
}
|
||||
}
|
26
thaw/src/drawer/drawer_header_title.rs
Normal file
26
thaw/src/drawer/drawer_header_title.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
use leptos::*;
|
||||
use thaw_components::OptionComp;
|
||||
|
||||
#[component]
|
||||
pub fn DrawerHeaderTitle(
|
||||
#[prop(optional)] drawer_header_title_action: Option<DrawerHeaderTitleAction>,
|
||||
children: Children,
|
||||
) -> impl IntoView {
|
||||
view! {
|
||||
<div class="thaw-drawer-header-title">
|
||||
<h2 class="thaw-drawer-header-title__heading">
|
||||
{children()}
|
||||
</h2>
|
||||
<OptionComp value=drawer_header_title_action let:action>
|
||||
<div class="thaw-drawer-header-title__action">
|
||||
{(action.children)()}
|
||||
</div>
|
||||
</OptionComp>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
#[slot]
|
||||
pub struct DrawerHeaderTitleAction {
|
||||
children: Children,
|
||||
}
|
51
thaw/src/drawer/inline_drawer.rs
Normal file
51
thaw/src/drawer/inline_drawer.rs
Normal file
|
@ -0,0 +1,51 @@
|
|||
use leptos::*;
|
||||
use thaw_components::CSSTransition;
|
||||
use thaw_utils::{class_list, mount_style, Model};
|
||||
|
||||
#[component]
|
||||
fn InlineDrawer(
|
||||
open: Model<bool>,
|
||||
mask_closeable: MaybeSignal<bool>,
|
||||
close_on_esc: bool,
|
||||
// placement: MaybeSignal<DrawerPlacement>,
|
||||
children: Children,
|
||||
) -> impl IntoView {
|
||||
mount_style("overlay-drawer", include_str!("./overlay-drawer.css"));
|
||||
let drawer_ref = NodeRef::<html::Div>::new();
|
||||
let placement = Memo::new(move |prev| {
|
||||
// let placement: = placement.get().as_str();
|
||||
// let Some(prev) = prev else {
|
||||
// return placement;
|
||||
// };
|
||||
|
||||
// if is_css_transition.get() {
|
||||
// prev
|
||||
// } else {
|
||||
// placement
|
||||
// }
|
||||
"left"
|
||||
});
|
||||
|
||||
view! {
|
||||
<CSSTransition
|
||||
node_ref=drawer_ref
|
||||
appear=open.get_untracked()
|
||||
show=open.signal()
|
||||
name=Memo::new(move |_| {
|
||||
format!("slide-in-from-{}-transition", placement.get())
|
||||
})
|
||||
|
||||
let:display
|
||||
>
|
||||
<div
|
||||
class=class_list![
|
||||
"thaw-overlay-drawer", move || format!("thaw-drawer--placement-{}",
|
||||
placement.get())
|
||||
]
|
||||
ref=drawer_ref
|
||||
>
|
||||
{children()}
|
||||
</div>
|
||||
</CSSTransition>
|
||||
}
|
||||
}
|
|
@ -1,3 +1,9 @@
|
|||
// mod inline_drawer;
|
||||
// mod overlay_drawer;
|
||||
|
||||
// pub use inline_drawer::*;
|
||||
// pub use overlay_drawer::*;
|
||||
|
||||
use crate::{Card, Scrollbar};
|
||||
use leptos::*;
|
||||
use thaw_components::{CSSTransition, FocusTrap, Teleport};
|
||||
|
|
97
thaw/src/drawer/overlay-drawer.css
Normal file
97
thaw/src/drawer/overlay-drawer.css
Normal file
|
@ -0,0 +1,97 @@
|
|||
.thaw-overlay-drawer-container {
|
||||
z-index: 1000000;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.thaw-overlay-drawer__backdrop {
|
||||
will-change: opacity;
|
||||
transition-timing-function: var(--curveEasyEase);
|
||||
transition-property: opacity;
|
||||
opacity: 1;
|
||||
transition-duration: var(--durationGentle);
|
||||
inset: 0px;
|
||||
position: fixed;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.thaw-overlay-drawer {
|
||||
--thaw-drawer--size: 320px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
position: fixed;
|
||||
top: 0px;
|
||||
bottom: 0px;
|
||||
right: auto;
|
||||
left: 0px;
|
||||
width: var(--thaw-drawer--size);
|
||||
max-width: 100vw;
|
||||
height: auto;
|
||||
max-height: 100vh;
|
||||
background-color: var(--colorNeutralBackground1);
|
||||
color: var(--colorNeutralForeground1);
|
||||
box-shadow: var(--shadow64);
|
||||
transform: translate3d(0px, 0px, 0px);
|
||||
opacity: 1;
|
||||
will-change: transform, box-shadow, opacity;
|
||||
transition-property: transform, box-shadow, opacity;
|
||||
transition-duration: var(--durationGentle);
|
||||
box-sizing: border-box;
|
||||
border-right: var(--strokeWidthThin) solid var(--colorTransparentStroke);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.thaw-drawer-header {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
padding: var(--spacingVerticalXXL) var(--spacingHorizontalXXL)
|
||||
var(--spacingVerticalS);
|
||||
gap: var(--spacingHorizontalS);
|
||||
align-self: stretch;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.thaw-drawer-header-title {
|
||||
column-gap: var(--spacingHorizontalS);
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.thaw-drawer-header-title__heading {
|
||||
font-family: var(--fontFamilyBase);
|
||||
font-size: var(--fontSizeBase500);
|
||||
font-weight: var(--fontWeightSemibold);
|
||||
line-height: var(--lineHeightBase500);
|
||||
margin: 0px;
|
||||
grid-area: 1 / 1 / 1 / 3;
|
||||
}
|
||||
|
||||
.thaw-drawer-header-title__action {
|
||||
margin-right: calc(var(--spacingHorizontalS)* -1);
|
||||
grid-row: 1 / 1;
|
||||
grid-column-start: 3;
|
||||
place-self: start end;
|
||||
}
|
||||
|
||||
.thaw-drawer-body {
|
||||
padding: 0 var(--spacingHorizontalXXL);
|
||||
flex: 1 1 0%;
|
||||
align-self: stretch;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.thaw-drawer-body:last-child {
|
||||
padding-bottom: calc(var(--spacingHorizontalXXL) + 1px);
|
||||
}
|
108
thaw/src/drawer/overlay_drawer.rs
Normal file
108
thaw/src/drawer/overlay_drawer.rs
Normal file
|
@ -0,0 +1,108 @@
|
|||
use crate::ConfigInjection;
|
||||
use leptos::*;
|
||||
use thaw_components::{CSSTransition, FocusTrap, Teleport};
|
||||
use thaw_utils::{class_list, mount_style, use_lock_html_scroll, Model};
|
||||
|
||||
#[component]
|
||||
fn OverlayDrawer(
|
||||
open: Model<bool>,
|
||||
mask_closeable: MaybeSignal<bool>,
|
||||
close_on_esc: bool,
|
||||
// placement: MaybeSignal<DrawerPlacement>,
|
||||
children: Children,
|
||||
) -> impl IntoView {
|
||||
mount_style("overlay-drawer", include_str!("./overlay-drawer.css"));
|
||||
let config_provider = ConfigInjection::use_();
|
||||
let drawer_ref = NodeRef::<html::Div>::new();
|
||||
|
||||
let placement = Memo::new(move |prev| {
|
||||
// let placement: = placement.get().as_str();
|
||||
// let Some(prev) = prev else {
|
||||
// return placement;
|
||||
// };
|
||||
|
||||
// if is_css_transition.get() {
|
||||
// prev
|
||||
// } else {
|
||||
// placement
|
||||
// }
|
||||
"left"
|
||||
});
|
||||
let is_css_transition = RwSignal::new(false);
|
||||
let on_after_enter = move |_| {
|
||||
is_css_transition.set(false);
|
||||
};
|
||||
|
||||
let is_lock = RwSignal::new(open.get_untracked());
|
||||
Effect::new(move |_| {
|
||||
let is_show = open.get();
|
||||
if is_show {
|
||||
is_lock.set(true);
|
||||
is_css_transition.set(true);
|
||||
}
|
||||
});
|
||||
use_lock_html_scroll(is_lock.into());
|
||||
let on_after_leave = move |_| {
|
||||
is_lock.set(false);
|
||||
is_css_transition.set(false);
|
||||
};
|
||||
|
||||
let mask_ref = NodeRef::<html::Div>::new();
|
||||
let on_mask_click = move |_| {
|
||||
if mask_closeable.get_untracked() {
|
||||
open.set(false);
|
||||
}
|
||||
};
|
||||
let on_esc = Callback::new(move |_: ev::KeyboardEvent| {
|
||||
open.set(false);
|
||||
});
|
||||
|
||||
view! {
|
||||
<Teleport immediate=open.signal()>
|
||||
<FocusTrap disabled=!close_on_esc active=open.signal() on_esc>
|
||||
<div class="thaw-config-provider thaw-overlay-drawer-container" data-thaw-id=config_provider.id().clone()>
|
||||
<CSSTransition
|
||||
node_ref=mask_ref
|
||||
appear=open.get_untracked()
|
||||
show=open.signal()
|
||||
name="fade-in-transition"
|
||||
let:display
|
||||
>
|
||||
<div
|
||||
class="thaw-overlay-drawer__backdrop"
|
||||
style=move || display.get()
|
||||
on:click=on_mask_click
|
||||
ref=mask_ref
|
||||
></div>
|
||||
</CSSTransition>
|
||||
<CSSTransition
|
||||
node_ref=drawer_ref
|
||||
appear=open.get_untracked()
|
||||
show=open.signal()
|
||||
name=Memo::new(move |_| {
|
||||
format!("slide-in-from-{}-transition", placement.get())
|
||||
})
|
||||
|
||||
on_after_enter
|
||||
on_after_leave
|
||||
let:display
|
||||
>
|
||||
<div
|
||||
class=class_list![
|
||||
"thaw-overlay-drawer", move || format!("thaw-drawer--placement-{}",
|
||||
placement.get())
|
||||
]
|
||||
|
||||
style=move || display.get()
|
||||
ref=drawer_ref
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
>
|
||||
{children()}
|
||||
</div>
|
||||
</CSSTransition>
|
||||
</div>
|
||||
</FocusTrap>
|
||||
</Teleport>
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue