From 568e6293778ef05d8654b785cd6130fc7a7ff0b8 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Fri, 28 Jun 2024 15:54:20 +0800 Subject: [PATCH] refactor: Modal --- demo/src/app.rs | 2 +- demo/src/pages/components.rs | 8 +- demo_markdown/docs/{modal => dialog}/mod.md | 22 ++- demo_markdown/src/lib.rs | 2 +- thaw/src/button/mod.rs | 10 -- thaw/src/card/mod.rs | 15 --- thaw/src/dialog/dialog.css | 117 ++++++++++++++++ thaw/src/dialog/dialog.rs | 66 +++++++++ thaw/src/dialog/dialog_actions.rs | 10 ++ thaw/src/dialog/dialog_body.rs | 10 ++ thaw/src/dialog/dialog_content.rs | 10 ++ thaw/src/dialog/dialog_surface.rs | 29 ++++ thaw/src/dialog/dialog_title.rs | 10 ++ thaw/src/dialog/mod.rs | 13 ++ thaw/src/drawer/mod.rs | 2 +- thaw/src/lib.rs | 4 +- thaw/src/modal/mod.rs | 141 -------------------- thaw/src/modal/modal.css | 75 ----------- 18 files changed, 290 insertions(+), 256 deletions(-) rename demo_markdown/docs/{modal => dialog}/mod.md (68%) create mode 100644 thaw/src/dialog/dialog.css create mode 100644 thaw/src/dialog/dialog.rs create mode 100644 thaw/src/dialog/dialog_actions.rs create mode 100644 thaw/src/dialog/dialog_body.rs create mode 100644 thaw/src/dialog/dialog_content.rs create mode 100644 thaw/src/dialog/dialog_surface.rs create mode 100644 thaw/src/dialog/dialog_title.rs create mode 100644 thaw/src/dialog/mod.rs delete mode 100644 thaw/src/modal/mod.rs delete mode 100644 thaw/src/modal/modal.css diff --git a/demo/src/app.rs b/demo/src/app.rs index b366485..70fb76e 100644 --- a/demo/src/app.rs +++ b/demo/src/app.rs @@ -61,6 +61,7 @@ fn TheRouter(is_routing: RwSignal) -> impl IntoView { + @@ -71,7 +72,6 @@ fn TheRouter(is_routing: RwSignal) -> impl IntoView { // - diff --git a/demo/src/pages/components.rs b/demo/src/pages/components.rs index c356c2b..144a533 100644 --- a/demo/src/pages/components.rs +++ b/demo/src/pages/components.rs @@ -195,6 +195,10 @@ pub(crate) fn gen_menu_data() -> Vec { value: "/components/date-picker".into(), label: "Date Picker".into(), }, + MenuItemOption { + value: "/components/dialog".into(), + label: "Dialog".into(), + }, MenuItemOption { value: "/components/divider".into(), label: "Divider".into(), @@ -235,10 +239,6 @@ pub(crate) fn gen_menu_data() -> Vec { value: "/components/message-bar".into(), label: "Message Bar".into(), }, - MenuItemOption { - value: "/components/modal".into(), - label: "Modal".into(), - }, MenuItemOption { value: "/components/popover".into(), label: "Popover".into(), diff --git a/demo_markdown/docs/modal/mod.md b/demo_markdown/docs/dialog/mod.md similarity index 68% rename from demo_markdown/docs/modal/mod.md rename to demo_markdown/docs/dialog/mod.md index a62b3fa..5f340f5 100644 --- a/demo_markdown/docs/modal/mod.md +++ b/demo_markdown/docs/dialog/mod.md @@ -1,13 +1,23 @@ -# Modal +# Dialog ```rust demo -let show = create_rw_signal(false); +let open = RwSignal::new(false); view! { - - - "hello" - + + + + + "Dialog title" + + "Dialog body" + + + + + + + } ``` diff --git a/demo_markdown/src/lib.rs b/demo_markdown/src/lib.rs index 7e87c69..59fac85 100644 --- a/demo_markdown/src/lib.rs +++ b/demo_markdown/src/lib.rs @@ -44,6 +44,7 @@ pub fn include_md(_token_stream: proc_macro::TokenStream) -> proc_macro::TokenSt "ComboboxMdPage" => "../docs/combobox/mod.md", "ConfigProviderMdPage" => "../docs/config_provider/mod.md", "DatePickerMdPage" => "../docs/date_picker/mod.md", + "DialogMdPage" => "../docs/dialog/mod.md", "DividerMdPage" => "../docs/divider/mod.md", "DrawerMdPage" => "../docs/drawer/mod.md", "GridMdPage" => "../docs/grid/mod.md", @@ -54,7 +55,6 @@ pub fn include_md(_token_stream: proc_macro::TokenStream) -> proc_macro::TokenSt "LoadingBarMdPage" => "../docs/loading_bar/mod.md", // "MessageMdPage" => "../docs/message/mod.md", "MessageBarMdPage" => "../docs/message_bar/mod.md", - "ModalMdPage" => "../docs/modal/mod.md", "PopoverMdPage" => "../docs/popover/mod.md", "ProgressBarMdPage" => "../docs/progress_bar/mod.md", "RadioMdPage" => "../docs/radio/mod.md", diff --git a/thaw/src/button/mod.rs b/thaw/src/button/mod.rs index b76567f..980ab72 100644 --- a/thaw/src/button/mod.rs +++ b/thaw/src/button/mod.rs @@ -45,15 +45,6 @@ impl ButtonShape { } } -#[derive(Default, Clone)] -pub enum ButtonColor { - #[default] - Primary, - Success, - Warning, - Error, -} - #[derive(Default, PartialEq, Clone)] pub enum ButtonSize { Small, @@ -78,7 +69,6 @@ pub fn Button( #[prop(optional, into)] class: OptionalProp>, #[prop(optional, into)] appearance: MaybeSignal, #[prop(optional, into)] shape: MaybeSignal, - #[prop(optional, into)] color: MaybeSignal, #[prop(optional, into)] size: MaybeSignal, #[prop(optional, into)] block: MaybeSignal, #[prop(optional, into)] icon: OptionalMaybeSignal, diff --git a/thaw/src/card/mod.rs b/thaw/src/card/mod.rs index 05529b5..d5bf27f 100644 --- a/thaw/src/card/mod.rs +++ b/thaw/src/card/mod.rs @@ -9,25 +9,10 @@ pub use card_preview::*; use leptos::*; use thaw_utils::{class_list, mount_style, OptionalProp}; -#[slot] -pub struct CardHeaderExtra { - children: Children, -} - -#[slot] -pub struct CardFooter { - #[prop(default = leptos::MaybeSignal::Static(true), into)] - if_: MaybeSignal, - children: ChildrenFn, -} - #[component] pub fn Card( - #[prop(optional, into)] title: OptionalProp>, - #[prop(optional)] card_header_extra: Option, #[prop(optional, into)] class: OptionalProp>, children: Children, - #[prop(optional)] card_footer: Option, ) -> impl IntoView { mount_style("card", include_str!("./card.css")); diff --git a/thaw/src/dialog/dialog.css b/thaw/src/dialog/dialog.css new file mode 100644 index 0000000..ba685b3 --- /dev/null +++ b/thaw/src/dialog/dialog.css @@ -0,0 +1,117 @@ +.thaw-dialog { + z-index: 1000000; + position: absolute; + top: 0px; + left: 0px; + right: 0px; + text-align: left; +} + +.thaw-dialog-surface__backdrop { + inset: 0px; + background-color: rgba(0, 0, 0, 0.4); + position: fixed; +} + +.thaw-dialog-surface__backdrop.fade-in-transition-enter-active { + transition: opacity 0.25s cubic-bezier(0, 0, 0.2, 1); +} + +.thaw-dialog-surface__backdrop.fade-in-transition-leave-active { + transition: opacity 0.25s cubic-bezier(0, 0, 0.2, 1); +} + +.thaw-dialog-surface__backdrop.fade-in-transition-enter-from, +.thaw-dialog-surface__backdrop.fade-in-transition-leave-to { + opacity: 0; +} + +.thaw-dialog-surface__backdrop.fade-in-transition-leave-from, +.thaw-dialog-surface__backdrop.fade-in-transition-enter-to { + opacity: 1; +} + +.thaw-dialog-surface { + inset: 0px; + padding: 24px; + margin: auto; + overflow: unset; + border: 1px solid var(--colorTransparentStroke); + border-radius: var(--borderRadiusXLarge); + display: block; + user-select: unset; + visibility: unset; + position: fixed; + height: fit-content; + max-width: 600px; + max-height: 100vh; + box-sizing: border-box; + background-color: var(--colorNeutralBackground1); + color: var(--colorNeutralForeground1); +} + +.thaw-dialog-surface.fade-in-scale-up-transition-leave-active { + transition: opacity 0.25s cubic-bezier(0.4, 0, 1, 1), + transform 0.25s cubic-bezier(0.4, 0, 1, 1); +} + +.thaw-dialog-surface.fade-in-scale-up-transition-enter-active { + transition: opacity 0.25s cubic-bezier(0, 0, 0.2, 1), + transform 0.25s cubic-bezier(0, 0, 0.2, 1); +} + +.thaw-dialog-surface.fade-in-scale-up-transition-enter-from, +.thaw-dialog-surface.fade-in-scale-up-transition-leave-to { + opacity: 0; + transform: scale(0.5); +} + +.thaw-dialog-surface.fade-in-scale-up-transition-leave-from, +.thaw-dialog-surface.fade-in-scale-up-transition-enter-to { + opacity: 1; + transform: scale(1); +} + +.thaw-dialog-body { + overflow: unset; + gap: 8px; + display: grid; + max-height: calc(-48px + 100vh); + box-sizing: border-box; + grid-template-rows: auto 1fr; + grid-template-columns: 1fr 1fr auto; +} + +.thaw-dialog-title { + grid-area: 1 / 1 / 1 / 3; + grid-column-end: 4; + font-family: var(--fontFamilyBase); + font-size: var(--fontSizeBase500); + font-weight: var(--fontWeightSemibold); + line-height: var(--lineHeightBase500); + margin: 0px; +} + +.thaw-dialog-content { + padding: var(--strokeWidthThick); + margin: calc(var(--strokeWidthThick) * -1); + font-family: var(--fontFamilyBase); + font-size: var(--fontSizeBase300); + font-weight: var(--fontWeightRegular); + line-height: var(--lineHeightBase300); + overflow-y: auto; + min-height: 32px; + box-sizing: border-box; + grid-area: 2 / 1 / 2 / 4; +} + +.thaw-dialog-actions { + grid-column-start: 2; + justify-self: end; + grid-column-end: 4; + gap: 8px; + height: fit-content; + box-sizing: border-box; + display: flex; + grid-row: 3 / 3; +} diff --git a/thaw/src/dialog/dialog.rs b/thaw/src/dialog/dialog.rs new file mode 100644 index 0000000..b5efde8 --- /dev/null +++ b/thaw/src/dialog/dialog.rs @@ -0,0 +1,66 @@ +use crate::ConfigInjection; +use leptos::*; +use thaw_components::{CSSTransition, FocusTrap, Teleport}; +use thaw_utils::{mount_style, Model}; + +#[component] +pub fn Dialog( + #[prop(into)] open: Model, + #[prop(default = true.into(), into)] mask_closeable: MaybeSignal, + #[prop(default = true, into)] close_on_esc: bool, + children: Children, +) -> impl IntoView { + mount_style("dialog", include_str!("./dialog.css")); + let config_provider = ConfigInjection::use_(); + + let mask_ref = NodeRef::::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! { + + +
+ + + + + {children()} + +
+
+
+ } +} + +#[derive(Clone)] +pub(super) struct DialogInjection { + pub open: Model, +} + +impl DialogInjection { + pub fn expect_use() -> Self { + expect_context::() + } +} diff --git a/thaw/src/dialog/dialog_actions.rs b/thaw/src/dialog/dialog_actions.rs new file mode 100644 index 0000000..85cb3ad --- /dev/null +++ b/thaw/src/dialog/dialog_actions.rs @@ -0,0 +1,10 @@ +use leptos::*; + +#[component] +pub fn DialogActions(children: Children) -> impl IntoView { + view! { +
+ {children()} +
+ } +} diff --git a/thaw/src/dialog/dialog_body.rs b/thaw/src/dialog/dialog_body.rs new file mode 100644 index 0000000..e00c39f --- /dev/null +++ b/thaw/src/dialog/dialog_body.rs @@ -0,0 +1,10 @@ +use leptos::*; + +#[component] +pub fn DialogBody(children: Children) -> impl IntoView { + view! { +
+ {children()} +
+ } +} \ No newline at end of file diff --git a/thaw/src/dialog/dialog_content.rs b/thaw/src/dialog/dialog_content.rs new file mode 100644 index 0000000..8dcf9a1 --- /dev/null +++ b/thaw/src/dialog/dialog_content.rs @@ -0,0 +1,10 @@ +use leptos::*; + +#[component] +pub fn DialogContent(children: Children) -> impl IntoView { + view! { +

+ {children()} +

+ } +} \ No newline at end of file diff --git a/thaw/src/dialog/dialog_surface.rs b/thaw/src/dialog/dialog_surface.rs new file mode 100644 index 0000000..d779a47 --- /dev/null +++ b/thaw/src/dialog/dialog_surface.rs @@ -0,0 +1,29 @@ +use super::dialog::DialogInjection; +use leptos::*; +use thaw_components::CSSTransition; + +#[component] +pub fn DialogSurface(children: Children) -> impl IntoView { + let dialog = DialogInjection::expect_use(); + let surface_ref = NodeRef::::new(); + + view! { + + + + } +} diff --git a/thaw/src/dialog/dialog_title.rs b/thaw/src/dialog/dialog_title.rs new file mode 100644 index 0000000..552f1cb --- /dev/null +++ b/thaw/src/dialog/dialog_title.rs @@ -0,0 +1,10 @@ +use leptos::*; + +#[component] +pub fn DialogTitle(children: Children) -> impl IntoView { + view! { +

+ {children()} +

+ } +} \ No newline at end of file diff --git a/thaw/src/dialog/mod.rs b/thaw/src/dialog/mod.rs new file mode 100644 index 0000000..1b56a66 --- /dev/null +++ b/thaw/src/dialog/mod.rs @@ -0,0 +1,13 @@ +mod dialog; +mod dialog_actions; +mod dialog_body; +mod dialog_content; +mod dialog_surface; +mod dialog_title; + +pub use dialog::*; +pub use dialog_actions::*; +pub use dialog_body::*; +pub use dialog_content::*; +pub use dialog_surface::*; +pub use dialog_title::*; diff --git a/thaw/src/drawer/mod.rs b/thaw/src/drawer/mod.rs index aa872bf..89b8eda 100644 --- a/thaw/src/drawer/mod.rs +++ b/thaw/src/drawer/mod.rs @@ -122,7 +122,7 @@ pub fn Drawer( role="dialog" aria-modal="true" > - + {children()} diff --git a/thaw/src/lib.rs b/thaw/src/lib.rs index e96f019..3a99e67 100644 --- a/thaw/src/lib.rs +++ b/thaw/src/lib.rs @@ -14,6 +14,7 @@ mod color_picker; mod combobox; mod config_provider; mod date_picker; +mod dialog; mod divider; mod drawer; mod grid; @@ -24,7 +25,6 @@ mod layout; mod loading_bar; mod message; mod message_bar; -mod modal; mod nav; mod popover; mod progress_bar; @@ -61,6 +61,7 @@ pub use color_picker::*; pub use combobox::*; pub use config_provider::*; pub use date_picker::*; +pub use dialog::*; pub use divider::*; pub use drawer::*; pub use grid::*; @@ -71,7 +72,6 @@ pub use layout::*; pub use loading_bar::*; pub use message::*; pub use message_bar::*; -pub use modal::*; pub use nav::*; pub use popover::*; pub use progress_bar::*; diff --git a/thaw/src/modal/mod.rs b/thaw/src/modal/mod.rs deleted file mode 100644 index d25535d..0000000 --- a/thaw/src/modal/mod.rs +++ /dev/null @@ -1,141 +0,0 @@ -use crate::{Card, CardFooter, CardHeader, CardHeaderExtra, Icon, Scrollbar, ScrollbarRef}; -use leptos::*; -use thaw_components::{CSSTransition, FocusTrap, OptionComp, Teleport}; -use thaw_utils::{mount_style, use_click_position, ComponentRef, Model}; - -#[slot] -pub struct ModalFooter { - children: ChildrenFn, -} - -#[component] -pub fn Modal( - #[prop(into)] show: Model, - #[prop(default = true.into(), into)] mask_closeable: MaybeSignal, - #[prop(default = true, into)] close_on_esc: bool, - #[prop(default = 2000.into(), into)] z_index: MaybeSignal, - #[prop(default = MaybeSignal::Static("600px".to_string()), into)] width: MaybeSignal, - #[prop(optional, into)] title: MaybeSignal, - children: Children, - #[prop(optional)] modal_footer: Option, -) -> impl IntoView { - mount_style("modal", include_str!("./modal.css")); - - let displayed = RwSignal::new(show.get_untracked()); - Effect::new(move |prev| { - let is_show = show.get(); - if prev.is_some() && is_show { - displayed.set(true); - } - }); - - let on_mask_click = move |_| { - if mask_closeable.get_untracked() { - show.set(false); - } - }; - let on_esc = Callback::new(move |_: ev::KeyboardEvent| { - show.set(false); - }); - - let mask_ref = NodeRef::::new(); - let scrollbar_ref = ComponentRef::::new(); - let modal_ref = NodeRef::::new(); - - let click_position = use_click_position(); - let on_enter = Callback::new(move |_| { - let Some(position) = click_position.get_untracked() else { - return; - }; - - let Some(scroll_el) = scrollbar_ref.get_untracked() else { - return; - }; - let scroll_top = scroll_el.container_scroll_top(); - - let Some(modal_el) = modal_ref.get_untracked() else { - return; - }; - - let x = -(modal_el.offset_left() - position.0); - let y = -(modal_el.offset_top() - position.1 - scroll_top); - - let _ = modal_el.attr("style", format!("transform-origin: {}px {}px", x, y)); - }); - - view! { - - -
- - -
-
- - - -
-
-
-
- } -} diff --git a/thaw/src/modal/modal.css b/thaw/src/modal/modal.css deleted file mode 100644 index 867fc3e..0000000 --- a/thaw/src/modal/modal.css +++ /dev/null @@ -1,75 +0,0 @@ -.thaw-modal-container { - position: fixed; - top: 0; - right: 0; - left: 0; - bottom: 0; - display: flex; - min-height: 100%; - pointer-events: none; -} - -.thaw-modal-container > * { - pointer-events: auto; -} - -.thaw-modal-mask { - position: fixed; - top: 0; - right: 0; - left: 0; - bottom: 0; - background-color: #0007; -} - -.thaw-modal-mask.fade-in-transition-enter-active { - transition: all 0.25s cubic-bezier(0, 0, 0.2, 1); -} - -.thaw-modal-mask.fade-in-transition-leave-active { - transition: all 0.25s cubic-bezier(0, 0, 0.2, 1); -} - -.thaw-modal-mask.fade-in-transition-enter-from, -.thaw-modal-mask.fade-in-transition-leave-to { - opacity: 0; -} - -.thaw-modal-mask.fade-in-transition-leave-from, -.thaw-modal-mask.fade-in-transition-enter-to { - opacity: 1; -} - -.thaw-modal-body { - position: relative; - margin: auto; - width: var(--thaw-width); -} - -.thaw-model-title { - font-size: 16px; -} - -.fade-in-scale-up-transition-leave-active.thaw-modal-body { - transform-origin: inherit; - transition: opacity 0.25s cubic-bezier(0.4, 0, 1, 1), - transform 0.25s cubic-bezier(0.4, 0, 1, 1); -} - -.fade-in-scale-up-transition-enter-active.thaw-modal-body { - transform-origin: inherit; - transition: opacity 0.25s cubic-bezier(0, 0, 0.2, 1), - transform 0.25s cubic-bezier(0, 0, 0.2, 1); -} - -.fade-in-scale-up-transition-enter-from.thaw-modal-body, -.fade-in-scale-up-transition-leave-to.thaw-modal-body { - opacity: 0; - transform: scale(0.5); -} - -.fade-in-scale-up-transition-leave-from.thaw-modal-body, -.fade-in-scale-up-transition-enter-to.thaw-modal-body { - opacity: 1; - transform: scale(1); -}