diff --git a/Cargo.toml b/Cargo.toml index 94d02b2..80efd17 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,10 +20,12 @@ wasm-bindgen = "0.2.99" web-sys = { version = "0.3.76", features = ["Window"] } yew = { version = "0.21.0", default-features = false, optional = true } dioxus = { version = "0.6.1", optional = true } +leptos = { version = "0.7.2", optional = true } [features] yew = ["dep:yew", "gloo"] dio = ["dioxus", "gloo"] +lep = ["leptos"] [profile.release] opt-level = "z" diff --git a/DIOXUS.md b/DIOXUS.md index a23f3b6..5012500 100644 --- a/DIOXUS.md +++ b/DIOXUS.md @@ -46,7 +46,6 @@ Incorporating the Dioxus Alert into your application is easy. Follow these steps body: "This is an alert message", show_alert: show_alert, timeout: 2500, - alert_class: "w-96 h-48 text-white", icon_class: "flex justify-center", confirm_button_text: "Okay", cancel_button_text: "Cancel", @@ -63,7 +62,7 @@ Incorporating the Dioxus Alert into your application is easy. Follow these steps }, position: Position::TopRight, icon_type: IconType::Success, - container_class: "flex items-center text-center justify-center bg-gray-800 text-white border border-gray-600", + alert_class: "flex items-center text-center justify-center bg-gray-800 text-white border border-gray-600", title_class: "text-white", body_class: "text-gray-300", icon_color: "", @@ -151,7 +150,6 @@ Incorporating the Dioxus Alert into your application is easy. Follow these steps | `icon_class` | `&'static str` | CSS class for styling the icon. | `""` | | `confirm_button_class` | `&'static str` | CSS class for styling the confirm button. | `""` | | `cancel_button_class` | `&'static str` | CSS class for styling the cancel button. | `""` | -| `container_class` | `&'static str` | CSS class for styling the alert container. | `""` | | `title_class` | `&'static str` | CSS class for styling the alert title. | `""` | | `message_class` | `&'static str` | CSS class for styling the message text in the alert. | `""` | diff --git a/LEPTOS.md b/LEPTOS.md new file mode 100644 index 0000000..4f662f0 --- /dev/null +++ b/LEPTOS.md @@ -0,0 +1,163 @@ +# 🌱 Leptos Alert-RS Usage + +Adding Alert-RS to your Leptos project is simple: + +1. Make sure your project is set up with **Leptos**. Refer to their [Getting Started Guide](https://book.leptos.dev/getting_started/index.html) for setup instructions. + +1. Add `alert-rs` to your dependencies: + + ```sh + cargo add alert-rs --features=lep + ``` + +1. Import the `Alert` component into your Leptos component and start showing alerts in your app. + +## 🛠️ Usage + +Incorporating Leptos Alert into your application is easy. Follow these steps: + +1. Import the Alert component into your Leptos project: + + ```rust + use leptos::prelude::*; + use alert_rs::leptos::Alert; + ``` + +1. Define the alert properties and use the Alert component in your Leptos component: + + ```rust + use leptos::prelude::*; + use alert_rs::leptos::Alert; + use alert_rs::{IconType, Position}; + + + #[component] + pub fn App() -> impl IntoView { + let show_alert = signal(true); + view! { + + } + } + ``` + +## 🔧 Props + +### Main Props + +| Property | Type | Description | Default | +| --------------------- | ---------------------- | ------------------------------------------------------------- | --------- | +| `show_alert` | `UseStateHandle` | The state handle controlling the visibility of the alert. | `false` | +| `title` | `&'static str` | The title text for the alert. | `"Info"` | +| `body` | `&'static str` | The message content of the alert. | `""` | +| `timeout` | `u32` | Timeout duration in milliseconds for the alert to auto-close. | `2500` ms | +| `show_confirm_button` | `bool` | Whether to display the confirm button. | `true` | +| `show_cancel_button` | `bool` | Whether to display the cancel button. | `true` | +| `show_close_button` | `bool` | Whether to display the close button. | `false` | + +### Callback Props + +| Property | Type | Description | Default | +| ------------ | -------------- | ------------------------------------------------------ | ------- | +| `on_confirm` | `Callback<()>` | Callback triggered when the confirm button is clicked. | No-op | +| `on_cancel` | `Callback<()>` | Callback triggered when the cancel button is clicked. | No-op | +| `on_close` | `Callback<()>` | Callback triggered when the close button is clicked. | No-op | +| `will_open` | `Callback<()>` | Callback triggered before the alert opens. | No-op | +| `did_open` | `Callback<()>` | Callback triggered after the alert opens. | No-op | +| `did_close` | `Callback<()>` | Callback triggered after the alert closes. | No-op | + +### Alert Appearance & Positioning + +| Property | Type | Description | Default | +| ------------ | -------------- | --------------------------------------------------------------------- | ---------------- | +| `native` | `bool` | Whether to use the native browser alert instead of custom one. | `false` | +| `position` | `Position` | Position of the alert on the screen (`Position::TopRight`, etc.). | `TopRight` | +| `icon_type` | `IconType` | The type of icon to display with the alert (e.g., `Info`, `Warning`). | `IconType::Info` | +| `icon_color` | `&'static str` | The color of the icon. | `""` | +| `icon_width` | `&'static str` | The width of the icon. | `"50"` | + +### Styling Props + +```sh ++-----------------------------------------------------------+ <-- `alert_class` +| | +| +-----------------------------------------------+ | <-- `close_button_style` (if `show_close_button`) +| | [X] Close Button | | +| +-----------------------------------------------+ | +| | +| +-----------------------------------------------+ | <-- `icon_class` and `icon_style` +| | [Icon] | | <-- `icon_tag` +| +-----------------------------------------------+ | +| | +| +-----------------------------------------------+ | <-- `title_class` and `title_style` +| | [Alert Title] | | <-- `props.title` +| +-----------------------------------------------+ | +| | +| +-----------------------------------------------+ | <-- `separator_style` +| | [--- Separator ---] | | +| +-----------------------------------------------+ | +| | +| +-----------------------------------------------+ | <-- `message_style` and `body_class` +| | [Alert Message] | | <-- `props.body` +| +-----------------------------------------------+ | +| | +| +-----------------------------------------------+ | <-- `confirm_button_class` and `confirm_button_style` +| | [Confirm Button] | | <-- `props.confirm_button_text` +| +-----------------------------------------------+ | +| | +| +-----------------------------------------------+ | <-- `cancel_button_class` and `cancel_button_style` +| | [Cancel Button] | | <-- `props.cancel_button_text` +| +-----------------------------------------------+ | +| | ++-----------------------------------------------------------+ +``` + +| Property | Type | Description | Default | +| ---------------------- | -------------- | ---------------------------------------------------- | ------- | +| `alert_class` | `&'static str` | CSS class for styling the alert container. | `""` | +| `icon_class` | `&'static str` | CSS class for styling the icon. | `""` | +| `confirm_button_class` | `&'static str` | CSS class for styling the confirm button. | `""` | +| `cancel_button_class` | `&'static str` | CSS class for styling the cancel button. | `""` | +| `title_class` | `&'static str` | CSS class for styling the alert title. | `""` | +| `message_class` | `&'static str` | CSS class for styling the message text in the alert. | `""` | + +### Inline Styles + +| Property | Type | Description | Default | +| ---------------------- | -------------- | ----------------------------------------- | ------------------------------ | +| `alert_style` | `&'static str` | Inline CSS styles for the alert. | `DEFAULT_ALERT_STYLE` | +| `close_button_style` | `&'static str` | Inline CSS styles for the close button. | `DEFAULT_CLOSE_BUTTON_STYLE` | +| `confirm_button_style` | `&'static str` | Inline CSS styles for the confirm button. | `DEFAULT_CONFIRM_BUTTON_STYLE` | +| `cancel_button_style` | `&'static str` | Inline CSS styles for the cancel button. | `DEFAULT_CANCEL_BUTTON_STYLE` | +| `icon_style` | `&'static str` | Inline CSS styles for the icon. | `DEFAULT_ICON_STYLE` | +| `title_style` | `&'static str` | Inline CSS styles for the title text. | `DEFAULT_TITLE_STYLE` | +| `separator_style` | `&'static str` | Inline CSS styles for the separator. | `DEFAULT_SEPARATOR_STYLE` | +| `message_style` | `&'static str` | Inline CSS styles for the message text. | `DEFAULT_MESSAGE_STYLE` | + +## 💡 Notes + +- The `native` prop can be set to `true` to use the browser's default alert behavior instead of the custom component. +- The alert is displayed based on the `show_alert` state, which should be controlled by the parent component. +- Timeout behavior can be adjusted using the `timeout` property, and alert visibility can be toggled using the `show_alert` state. +- You can customize the alert's appearance, including the icon, buttons, position, and styles. diff --git a/README.md b/README.md index e47baf3..68f9a8d 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ Refer to [our guide](YEW.md) to integrate this component into your Yew app. Refer to [our guide](DIOXUS.md) to integrate this component into your Dioxus app. -## 🌱 Leptos Usage (TODO) +## 🌱 Leptos Usage Refer to [our guide](LEPTOS.md) to integrate this component into your Leptos app. diff --git a/YEW.md b/YEW.md index 03e15c9..93d780d 100644 --- a/YEW.md +++ b/YEW.md @@ -40,7 +40,6 @@ Incorporating Yew Alert into your application is easy. Follow these steps: body={"This is an alert message"} show_alert={show_alert} timeout={2500} - alert_class={"w-96 h-48 text-white"} icon_class={"flex justify-center"} confirm_button_text={"Okay"} cancel_button_text={"Cancel"} @@ -53,7 +52,7 @@ Incorporating Yew Alert into your application is easy. Follow these steps: on_cancel={Callback::noop()} position={Position::TopRight} icon_type={IconType::Success} - container_class={"flex items-center text-center justify-center bg-gray-800 text-white border border-gray-600"} + alert_class={"flex items-center text-center justify-center bg-gray-800 text-white border border-gray-600"} title_class={"dark:text-white"} body_class={"dark:text-gray-300"} icon_color={""} @@ -140,7 +139,6 @@ Incorporating Yew Alert into your application is easy. Follow these steps: | `icon_class` | `&'static str` | CSS class for styling the icon. | `""` | | `confirm_button_class` | `&'static str` | CSS class for styling the confirm button. | `""` | | `cancel_button_class` | `&'static str` | CSS class for styling the cancel button. | `""` | -| `container_class` | `&'static str` | CSS class for styling the alert container. | `""` | | `title_class` | `&'static str` | CSS class for styling the alert title. | `""` | | `message_class` | `&'static str` | CSS class for styling the message text in the alert. | `""` | diff --git a/examples/dioxus/README.md b/examples/dioxus/README.md index 3372715..1f2536e 100644 --- a/examples/dioxus/README.md +++ b/examples/dioxus/README.md @@ -1,4 +1,4 @@ -# 📚 Alert RS Dioxus Tailwind Components +# 📚 Alert RS Dioxus Example ## 🛠️ Pre-requisites: diff --git a/examples/leptos/.gitignore b/examples/leptos/.gitignore new file mode 100644 index 0000000..cc39038 --- /dev/null +++ b/examples/leptos/.gitignore @@ -0,0 +1,2 @@ +target/**/* +dist/**/* diff --git a/examples/leptos/Cargo.toml b/examples/leptos/Cargo.toml new file mode 100755 index 0000000..f1d5dd5 --- /dev/null +++ b/examples/leptos/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "leptos-alert-rs" +version = "0.1.0" +edition = "2021" + +[dependencies] +console_error_panic_hook = "0.1.7" +alert-rs = { path = "../../", features = ["lep"] } +leptos = { version = "0.7.2", features = ["csr"] } +log = "0.4.22" +wasm-logger = "0.2.0" diff --git a/examples/leptos/README.md b/examples/leptos/README.md new file mode 100644 index 0000000..4ab09a5 --- /dev/null +++ b/examples/leptos/README.md @@ -0,0 +1,81 @@ +# 📚 Alert RS Leptos Example + +## 🛠️ Pre-requisites: + +### 🐧 **Linux Users** + +1. **Install [`rustup`](https://www.rust-lang.org/tools/install)**: + + ```sh + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh + ``` + +1. **Install [`trunk`](https://trunkrs.dev/)**: + + ```sh + cargo install --locked trunk + ``` + +1. **Add the Wasm target**: + + ```sh + rustup target add wasm32-unknown-unknown + ``` + +### 🪟 **Windows Users** + +1. **Download and install `rustup`**: Follow the installation instructions [here](https://www.rust-lang.org/tools/install). + +1. **Install [Windows Subsystem for Linux (WSL)](https://learn.microsoft.com/en-us/windows/wsl/install)**: Open PowerShell as administrator and run: + + ```sh + wsl --install + ``` + +1. **Reset Network Stack**: In PowerShell (administrator mode), run: + + ```sh + netsh int ip reset all + netsh winsock reset + ``` + +1. **Install Linux packages in WSL**: Once inside your WSL terminal, update and install required dependencies: + + ```sh + sudo apt update + sudo apt install build-essential pkg-config libudev-dev + ``` + +1. **Install `trunk`**: + + ```sh + cargo install --locked trunk + ``` + +1. **Add the Wasm target**: + + ```sh + rustup target add wasm32-unknown-unknown + ``` + +## 🚀 Building and Running + +1. Fork/Clone the GitHub repository. + + ```bash + git clone https://github.com/opensass/alert-rs + ``` + +1. Navigate to the application directory. + + ```bash + cd alert-rs/examples/leptos + ``` + +1. Run the client: + + ```sh + trunk serve --port 3000 + ``` + +Navigate to http://localhost:3000 to explore the landing page. diff --git a/examples/leptos/index.html b/examples/leptos/index.html new file mode 100755 index 0000000..064d4cb --- /dev/null +++ b/examples/leptos/index.html @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/examples/leptos/main.css b/examples/leptos/main.css new file mode 100644 index 0000000..913598f --- /dev/null +++ b/examples/leptos/main.css @@ -0,0 +1,8 @@ +body { + color: #5e5c7f; + background-color: #303030; + font-family: "Rubik", sans-serif; + font-size: 16px; + line-height: 1.7; + overflow-x: hidden; +} diff --git a/examples/leptos/src/main.rs b/examples/leptos/src/main.rs new file mode 100755 index 0000000..3169f84 --- /dev/null +++ b/examples/leptos/src/main.rs @@ -0,0 +1,521 @@ +use leptos::prelude::*; +use alert_rs::leptos::Alert; +use alert_rs::{IconType, Position}; + +#[component] +pub fn App() -> impl IntoView { + view! { + + } +} + +#[component] +pub fn Home() -> impl IntoView { + let show_alert_0 = signal(false); + let show_alert_1 = signal(false); + let show_alert_2 = signal(false); + let show_alert_3 = signal(false); + let show_alert_4 = signal(false); + let show_alert_5 = signal(false); + let show_alert_6 = signal(false); + let show_alert_7 = signal(false); + let show_alert_8 = signal(false); + let show_alert_9 = signal(false); + let show_alert_10 = signal(false); + let show_alert_11 = signal(false); + let show_alert_12 = signal(false); + + let callback_0 = { + move |_| { + show_alert_0.1.set(true); + } + }; + let callback_1 = { + move |_| { + show_alert_1.1.set(true); + } + }; + let callback_2 = { + move |_| { + show_alert_2.1.set(true); + } + }; + let callback_3 = { + move |_| { + show_alert_3.1.set(true); + } + }; + let callback_4 = { + move |_| { + show_alert_4.1.set(true); + } + }; + let callback_5 = { + move |_| { + show_alert_5.1.set(true); + } + }; + let callback_6 = { + move |_| { + show_alert_6.1.set(true); + } + }; + let callback_7 = { + move |_| { + show_alert_7.1.set(true); + } + }; + let callback_8 = { + move |_| { + show_alert_8.1.set(true); + } + }; + let callback_9 = { + move |_| { + show_alert_9.1.set(true); + } + }; + let callback_10 = { + move |_| { + show_alert_10.1.set(true); + } + }; + let callback_11 = { + move |_| { + show_alert_11.1.set(true); + } + }; + let callback_12 = { + Callback::from(move || { + show_alert_12.1.set(true); + }) + }; + + view! { +
+

{ "Alert RS Yew Examples" }

+
+ // Native Blocking Alert +
+

{ "Native Blocking Alert" }

+
+                        { r#""# }
+                    
+ + +
+ // Top Right - Error With Confirmation +
+

+ { "Top Right - Error With Confirmation" } +

+
+                        { r#""# }
+                    
+ + + +
+ // Bottom Left - Success +
+

{ "Bottom Left - Success" }

+
+                        { r#""# }
+                    
+ + +
+ // Bottom Right - Info +
+

{ "Bottom Right - Info" }

+
+                        { r#""# }
+                    
+ + +
+ // Top Left - Error +
+

{ "Top Left - Error" }

+
+                        { r#""# }
+                    
+ + +
+ // Top Right - Success +
+

{ "Top Right - Success" }

+
+                        { r#""# }
+                    
+ + +
+ // Left Center - Info +
+

{ "Left Center - Info" }

+
+                        { r#""# }
+                    
+ + +
+ // Right Center - Warning +
+

{ "Right Center - Warning" }

+
+                        { r#""# }
+                    
+ + +
+ // Top Center - Info +
+

{ "Top Center - Info" }

+
+                        { r#""# }
+                    
+ + +
+ // Center - Success +
+

{ "Center - Success" }

+
+                        { r#""# }
+                    
+ + +
+ // Bottom Center - Warning +
+

{ "Bottom Center - Warning" }

+
+                        { r#""# }
+                    
+ + +
+ // Bottom Right - Success +
+

{ "Bottom Right - Success" }

+
+                        { r#""# }
+                    
+ + +
+
+
+ } +} + +fn main() { + console_error_panic_hook::set_once(); + wasm_logger::init(wasm_logger::Config::default()); + leptos::mount::mount_to_body(|| view! { }); +} diff --git a/examples/yew/css/tailwind.css b/examples/yew/css/tailwind.css index ea0b9fe..0137e2d 100644 --- a/examples/yew/css/tailwind.css +++ b/examples/yew/css/tailwind.css @@ -1,4 +1,4 @@ -@import url('https://fonts.googleapis.com/css?family=Roboto:300,400&display=swap'); +@import url("https://fonts.googleapis.com/css?family=Roboto:300,400&display=swap"); @tailwind base; @tailwind components; @@ -6,10 +6,10 @@ @tailwind variants; body { - color: #5e5c7f; - background-color: #303030; - font-family: "Rubik", sans-serif; - font-size: 16px; - line-height: 1.7; - overflow-x: hidden; + color: #5e5c7f; + background-color: #303030; + font-family: "Rubik", sans-serif; + font-size: 16px; + line-height: 1.7; + overflow-x: hidden; } diff --git a/src/dioxus.rs b/src/dioxus.rs index af45922..a586e08 100644 --- a/src/dioxus.rs +++ b/src/dioxus.rs @@ -110,12 +110,6 @@ pub struct AlertProps { #[props(default = "")] pub cancel_button_class: &'static str, - /// Additional CSS classes for the container wrapping the alert. - /// - /// Defaults to an empty string. - #[props(default = "")] - pub container_class: &'static str, - /// Additional CSS classes for the alert title. /// /// Defaults to an empty string. @@ -245,7 +239,6 @@ pub struct AlertProps { /// - **icon_class**: Custom CSS class for the alert icon (`&'static str`). Default: `""`. /// - **confirm_button_class**: Custom CSS class for the confirm button (`&'static str`). Default: `""`. /// - **cancel_button_class**: Custom CSS class for the cancel button (`&'static str`). Default: `""`. -/// - **container_class**: Custom CSS class for the alert's container (`&'static str`). Default: `""`. /// - **title_class**: Custom CSS class for the alert title (`&'static str`). Default: `""`. /// - **body_class**: Custom CSS class for the alert body (`&'static str`). Default: `""`. /// - **alert_style**: Inline style for the alert component (`&'static str`). Default: `DEFAULT_ALERT_STYLE`. @@ -364,7 +357,7 @@ pub fn Alert(props: AlertProps) -> Element { if show_alert() && !native { props.will_open.call(()); - let handle = Timeout::new(timeout, move || { + let _ = Timeout::new(timeout, move || { show_alert.set(false); props.did_close.call(()); }) @@ -578,5 +571,7 @@ pub fn Alert(props: AlertProps) -> Element { } } } - } else {rsx!{}} + } else { + rsx! {} + } } diff --git a/src/leptos.rs b/src/leptos.rs new file mode 100644 index 0000000..297050b --- /dev/null +++ b/src/leptos.rs @@ -0,0 +1,593 @@ +use crate::common::*; +use leptos::{ev::MouseEvent, prelude::*, *}; +use std::time::Duration; +use web_sys::window; + +/// Alert Component +/// +/// A Leptos component for displaying customizable alerts with various behaviors and styling options. +/// This `Alert` component supports features like setting alert visibility, timeout durations, custom +/// icons, button visibility, alert positioning, and more. It can be used to display messages, warnings, +/// or notifications with a variety of visual elements and actions. +/// +/// # Properties +/// The component uses the `AlertProps` struct for its properties. Key properties include: +/// +/// - **show_alert**: State handle controlling the visibility of the alert (`Signal`). This is a required prop to manage alert visibility. +/// - **body**: The content of the alert message (`&'static str`). Default: `""`. +/// - **title**: The title text of the alert (`&'static str`). Default: `"Info"`. +/// - **timeout**: Timeout duration in milliseconds before the alert auto-closes (`u32`). Default: `2500`. +/// - **confirm_button_text**: Text for the confirm button (`&'static str`). Default: `"Okay"`. +/// - **cancel_button_text**: Text for the cancel button (`&'static str`). Default: `"Cancel"`. +/// - **show_confirm_button**: Whether to display the confirm button (`bool`). Default: `true`. +/// - **show_cancel_button**: Whether to display the cancel button (`bool`). Default: `true`. +/// - **show_close_button**: Whether to display the close button (`bool`). Default: `false`. +/// - **position**: The position of the alert on the screen (`Position`). Default: `Position::TopRight`. +/// - **icon_type**: The icon type displayed with the alert (`IconType`). Default: `IconType::Info`. +/// - **icon_color**: The color of the icon (`&'static str`). Default: `""`. +/// - **icon_width**: The width of the icon (`&'static str`). Default: `"50"`. +/// - **alert_class**: CSS class for styling the alert container (`&'static str`). Default: `""`. +/// - **icon_class**: CSS class for styling the icon (`&'static str`). Default: `""`. +/// - **confirm_button_class**: CSS class for styling the confirm button (`&'static str`). Default: `""`. +/// - **cancel_button_class**: CSS class for styling the cancel button (`&'static str`). Default: `""`. +/// - **title_class**: CSS class for styling the alert title (`&'static str`). Default: `""`. +/// - **body_class**: CSS class for styling the message text in the alert (`&'static str`). Default: `""`. +/// - **alert_style**: Default inline styles for the alert (`&'static str`). Default: `DEFAULT_ALERT_STYLE`. +/// - **close_button_style**: Default inline styles for the close button (`&'static str`). Default: `DEFAULT_CLOSE_BUTTON_STYLE`. +/// - **confirm_button_style**: Default inline styles for the confirm button (`&'static str`). Default: `DEFAULT_CONFIRM_BUTTON_STYLE`. +/// - **cancel_button_style**: Default inline styles for the cancel button (`&'static str`). Default: `DEFAULT_CANCEL_BUTTON_STYLE`. +/// - **icon_style**: Default inline styles for the icon (`&'static str`). Default: `DEFAULT_ICON_STYLE`. +/// - **title_style**: Default inline styles for the title text (`&'static str`). Default: `DEFAULT_TITLE_STYLE`. +/// - **separator_style**: Default inline styles for the separator (`&'static str`). Default: `DEFAULT_SEPARATOR_STYLE`. +/// - **message_style**: Default inline styles for the message text (`&'static str`). Default: `DEFAULT_MESSAGE_STYLE`. +/// - **native**: Whether to use the native alert implementation (`bool`). Default: `false`. +/// - **will_open**: Callback triggered before the alert opens (`Callback<()>`). Default: no-op. +/// - **did_open**: Callback triggered after the alert opens (`Callback<()>`). Default: no-op. +/// - **did_close**: Callback triggered after the alert closes (`Callback<()>`). Default: no-op. +/// - **on_confirm**: Callback triggered when the confirm button is clicked (`Callback<()>`). Default: no-op. +/// - **on_close**: Callback triggered when the close button is clicked (`Callback<()>`). Default: no-op. +/// - **on_cancel**: Callback triggered when the cancel button is clicked (`Callback<()>`). Default: no-op. +/// +/// # Features +/// - Customizable alert message and title. +/// - Configurable buttons (confirm, cancel, and close). +/// - Adjustable timeout duration for auto-closing. +/// - Dynamic positioning and icon customization. +/// - Supports native browser alert functionality with `native`. +/// - Callbacks for various actions, such as opening, closing, and button clicks. +/// +/// # Examples +/// +/// ## Basic Usage +/// ```rust +/// use leptos::prelude::*; +/// use alert_rs::leptos::Alert; +/// +/// #[component] +/// pub fn MyComponent() -> impl IntoView { +/// let show_alert = create_signal(false); +/// view! { +/// <> +/// +/// +/// +/// } +/// } +/// ``` +/// +/// ## Custom Alert with Buttons +/// ```rust +/// use leptos::prelude::*; +/// use alert_rs::leptos::Alert; +/// +/// #[component] +/// pub fn CustomAlert() -> impl IntoView { +/// let show_alert = create_signal(false); +/// view! { +/// <> +/// +/// +/// +/// } +/// } +/// ``` +/// +/// ## Native Alert +/// ```rust +/// use leptos::prelude::*; +/// use alert_rs::leptos::Alert; +/// +/// #[component] +/// pub fn NativeAlert() -> impl IntoView { +/// let show_alert = create_signal(false); +/// view! { +/// <> +/// +/// +/// +/// } +/// } +/// ``` +/// +/// # Behavior +/// - The component uses `create_signal` to manage the visibility of the alert. +/// - It also uses `create_effect` to handle side-effects such as displaying the alert and auto-closing after the specified timeout. +/// - Buttons trigger specific callbacks (e.g., confirm, cancel, close) when clicked. +/// +/// # Notes +/// - The `native` prop can be set to `true` to use the browser's default alert behavior instead of the custom component. +#[component] +pub fn Alert( + /// The body text of the alert. + /// + /// This defines the message content that will be displayed within the alert. + /// Defaults to an empty string if not specified. + #[prop(default = "")] + body: &'static str, + + /// The state handle controlling the visibility of the alert. + /// + /// This should be used to manage whether the alert is shown or not. It is a required prop. + show_alert: ( + ReadSignal, + WriteSignal, + ), + + /// The timeout duration in milliseconds before the alert auto-closes. + /// + /// Defines how long the alert stays visible before automatically closing. + /// Defaults to `2500` milliseconds (2.5 seconds). + #[prop(default = 2500)] + timeout: u64, + + /// The title text for the alert. + /// + /// This defines the heading or title of the alert. Defaults to `"Info"`. + #[prop(default = "Info")] + title: &'static str, + + /// Text for the confirm button. + /// + /// This defines the label for the confirm button within the alert. + /// Defaults to `"Okay"`. + #[prop(default = "Okay")] + confirm_button_text: &'static str, + + /// Text for the cancel button. + /// + /// This defines the label for the cancel button within the alert. + /// Defaults to `"Cancel"`. + #[prop(default = "Cancel")] + cancel_button_text: &'static str, + + /// Whether to show the confirm button. + /// + /// If `true`, the confirm button is displayed. Defaults to `true`. + #[prop(default = true)] + show_confirm_button: bool, + + /// Whether to show the cancel button. + /// + /// If `true`, the cancel button is displayed. Defaults to `true`. + #[prop(default = true)] + show_cancel_button: bool, + + /// Whether to show the close button. + /// + /// If `true`, a close button is included. Defaults to `false`. + #[prop(default = false)] + show_close_button: bool, + + /// The position of the alert on the screen. + /// + /// Defines where the alert will appear on the screen (e.g., top-left, top-right, bottom-left, bottom-right). + /// Defaults to `Position::TopRight`. + #[prop(default = Position::TopRight)] + position: Position, + + /// The type of icon to display in the alert. + /// + /// Defines the icon associated with the alert type (e.g., success, error, warning, info). + /// Defaults to `IconType::Info`. + #[prop(default = IconType::Info)] + icon_type: IconType, + + /// The color of the icon. + /// + /// Defines the color of the icon displayed in the alert. This value is applied as a CSS class. + /// Defaults to an empty string. + #[prop(default = "")] + icon_color: &'static str, + + /// The width of the icon. + /// + /// Defines the size of the icon in percentage or pixel values. Defaults to `"50"`. + #[prop(default = "50")] + icon_width: &'static str, + + /// Custom CSS class for styling the alert container. + /// + /// This allows for the styling of the entire alert container, including background color, padding, etc. + /// Defaults to an empty string. + #[prop(default = "")] + alert_class: &'static str, + + /// Custom CSS class for styling the icon in the alert. + /// + /// This applies additional styling to the icon inside the alert. + /// Defaults to an empty string. + #[prop(default = "")] + icon_class: &'static str, + + /// Custom CSS class for styling the confirm button. + /// + /// This applies additional styling to the confirm button within the alert. + /// Defaults to an empty string. + #[prop(default = "")] + confirm_button_class: &'static str, + + /// Custom CSS class for styling the cancel button. + /// + /// This applies additional styling to the cancel button within the alert. + /// Defaults to an empty string. + #[prop(default = "")] + cancel_button_class: &'static str, + + /// Custom CSS class for styling the title of the alert. + /// + /// This applies additional styling to the title text within the alert. + /// Defaults to an empty string. + #[prop(default = "")] + title_class: &'static str, + + /// Custom CSS class for styling the message in the alert. + /// + /// This applies additional styling to the body message inside the alert. + /// Defaults to an empty string. + #[prop(default = "")] + body_class: &'static str, + + /// Default style for the alert component. + /// + /// This defines default inline styles for the alert. + /// Defaults to `DEFAULT_ALERT_STYLE`. + #[prop(default = DEFAULT_ALERT_STYLE)] + alert_style: &'static str, + + /// Default style for the close button. + /// + /// This defines the default inline styles for the close button within the alert. + /// Defaults to `DEFAULT_CLOSE_BUTTON_STYLE`. + #[prop(default = DEFAULT_CLOSE_BUTTON_STYLE)] + close_button_style: &'static str, + + /// Default style for the confirm button. + /// + /// This defines the default inline styles for the confirm button within the alert. + /// Defaults to `DEFAULT_CONFIRM_BUTTON_STYLE`. + #[prop(default = DEFAULT_CONFIRM_BUTTON_STYLE)] + confirm_button_style: &'static str, + + /// Default style for the cancel button. + /// + /// This defines the default inline styles for the cancel button within the alert. + /// Defaults to `DEFAULT_CANCEL_BUTTON_STYLE`. + #[prop(default = DEFAULT_CANCEL_BUTTON_STYLE)] + cancel_button_style: &'static str, + + /// Default style for the icon in the alert. + /// + /// This defines the default inline styles for the icon. + /// Defaults to `DEFAULT_ICON_STYLE`. + #[prop(default = DEFAULT_ICON_STYLE)] + icon_style: &'static str, + + /// Default style for the title text in the alert. + /// + /// This defines the default inline styles for the title. + /// Defaults to `DEFAULT_TITLE_STYLE`. + #[prop(default = DEFAULT_TITLE_STYLE)] + title_style: &'static str, + + /// Default style for the separator between the title and message. + /// + /// This defines the default inline styles for the separator line. + /// Defaults to `DEFAULT_SEPARATOR_STYLE`. + #[prop(default = DEFAULT_SEPARATOR_STYLE)] + separator_style: &'static str, + + /// Default style for the message text in the alert. + /// + /// This defines the default inline styles for the message text. + /// Defaults to `DEFAULT_MESSAGE_STYLE`. + #[prop(default = DEFAULT_MESSAGE_STYLE)] + message_style: &'static str, + + /// Whether to use the native browser alert implementation. + /// + /// If `true`, it will use the native alert implementation instead of the custom alert component. + /// Defaults to `false`. + #[prop(default = false)] + native: bool, + + /// Callback triggered when the alert opens. + /// + /// This is triggered before the alert is shown to the user. Defaults to no-op. + #[prop(default = Callback::from(move || {}))] + will_open: Callback<()>, + + /// Callback triggered when the alert has fully opened. + /// + /// This is triggered after the alert is shown. Defaults to no-op. + #[prop(default = Callback::from(move || {}))] + did_open: Callback<()>, + + /// Callback triggered when the alert closes. + /// + /// This is triggered after the alert is closed. Defaults to no-op. + #[prop(default = Callback::from(move || {}))] + did_close: Callback<()>, + + /// Callback triggered when the confirm button is clicked. + /// + /// This is triggered when the user clicks the confirm button. Defaults to no-op. + #[prop(default = Callback::from(move || {}))] + on_confirm: Callback<()>, + + /// Callback triggered when the close button is clicked. + /// + /// This is triggered when the user clicks the close button. Defaults to no-op. + #[prop(default = Callback::from(move || {}))] + on_close: Callback<()>, + + /// Callback triggered when the cancel button is clicked. + /// + /// This is triggered when the user clicks the cancel button. Defaults to no-op. + #[prop(default = Callback::from(move || {}))] + on_cancel: Callback<()>, +) -> impl IntoView { + let delay = Duration::from_millis(timeout); + Effect::new(move || { + if show_alert.0.get() && !native { + will_open.run(()); + set_timeout( + move || { + show_alert.1.set(false); + did_close.run(()); + }, + delay, + ); + + did_open.run(()); + } else if show_alert.0.get() && native { + if let Some(win) = window() { + will_open.run(()); + + let full_message = if !title.is_empty() { + format!("{}\n\n{}", title, body) + } else { + body.to_string() + }; + + match (show_confirm_button, show_cancel_button, show_close_button) { + (true, true, true) => { + if win.confirm_with_message(&full_message).unwrap_or(false) { + on_confirm.run(()); + } else { + on_close.run(()); + on_cancel.run(()); + } + } + (true, true, false) => { + if win.confirm_with_message(&full_message).unwrap_or(false) { + on_confirm.run(()); + } else { + on_cancel.run(()); + } + } + (true, false, false) => { + win.alert_with_message(&full_message).ok(); + on_confirm.run(()); + } + _ => {} + } + + if timeout > 0 { + set_timeout( + move || { + show_alert.1.set(false); + did_close.run(()); + }, + delay, + ); + } else { + show_alert.1.set(false); + } + + did_open.run(()); + } + } + }); + + let on_cancel = { + move |_: MouseEvent| { + on_cancel.run(()); + show_alert.1.set(false); + } + }; + + let on_confirm = { + move |_: MouseEvent| { + on_confirm.run(()); + } + }; + + let position_style = match position { + Position::TopLeft => "top: 0; left: 0;".to_string(), + Position::TopCenter => "top: 0; left: 50%; transform: translateX(-50%);".to_string(), + Position::TopRight => "top: 0; right: 0;".to_string(), + Position::LeftCenter => "top: 50%; left: 0; transform: translateY(-50%);".to_string(), + Position::Center => "top: 50%; left: 50%; transform: translate(-50%, -50%);".to_string(), + Position::BottomCenter => "bottom: 0; left: 50%; transform: translateX(-50%);".to_string(), + Position::RightCenter => "top: 50%; right: 0; transform: translateY(-50%);".to_string(), + Position::BottomRight => "bottom: 0; right: 0;".to_string(), + Position::BottomLeft => "bottom: 0; left: 0;".to_string(), + Position::Custom(x, y) => format!("top: {}; left: {};", y, x), + }; + + let icon_color = if icon_color.is_empty() { + match icon_type { + IconType::Warning => "orange", + IconType::Error => "red", + IconType::Success => "green", + IconType::Info => "blue", + IconType::Question => "gray", + } + } else { + icon_color + }; + + view! { + {move || { + // SVGs taken from: https://fontawesome.com/icons + let icon_tag = match icon_type { + IconType::Warning => view! { + + + + }.into_any(), + IconType::Error => view! { + + + + }.into_any(), + IconType::Success => view! { + + + + }.into_any(), + IconType::Info => view! { + + + + + }.into_any(), + IconType::Question => view! { + + + + + }.into_any(), + }; + if show_alert.0.get() { + Some(view! { +
+
+ {if show_close_button { + Some(view! { + + }) + } else { + None + }} +
+ {icon_tag} +
+ + {title} + +
+

+ {body} +

+ {if show_confirm_button { + Some(view! { + + }) + } else { + None + }} + {if show_cancel_button { + Some(view! { + + }) + } else { + None + }} +
+
+ }) + } else { + None + } + }} + } +} diff --git a/src/lib.rs b/src/lib.rs index 4ab8f32..5171714 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,4 +13,7 @@ pub mod yew; #[cfg(feature = "dio")] pub mod dioxus; +#[cfg(feature = "lep")] +pub mod leptos; + pub use common::{IconType, Position}; diff --git a/src/yew.rs b/src/yew.rs index 7922ff9..16a6336 100644 --- a/src/yew.rs +++ b/src/yew.rs @@ -122,13 +122,6 @@ pub struct AlertProps { #[prop_or_default] pub cancel_button_class: &'static str, - /// Custom CSS class for styling the container around the alert. - /// - /// This is for additional styling of the alert's container, such as margins, borders, etc. - /// Defaults to an empty string. - #[prop_or_default] - pub container_class: &'static str, - /// Custom CSS class for styling the title of the alert. /// /// This applies additional styling to the title text within the alert. @@ -271,7 +264,6 @@ pub struct AlertProps { /// - **icon_class**: CSS class for styling the icon (`&'static str`). Default: `""`. /// - **confirm_button_class**: CSS class for styling the confirm button (`&'static str`). Default: `""`. /// - **cancel_button_class**: CSS class for styling the cancel button (`&'static str`). Default: `""`. -/// - **container_class**: CSS class for styling the alert container (`&'static str`). Default: `""`. /// - **title_class**: CSS class for styling the alert title (`&'static str`). Default: `""`. /// - **body_class**: CSS class for styling the message text in the alert (`&'static str`). Default: `""`. /// - **alert_style**: Default inline styles for the alert (`&'static str`). Default: `DEFAULT_ALERT_STYLE`.