patternfly_yew/components/
about.rs1use crate::prelude::{use_backdrop, use_random_id, Button, ButtonVariant, Icon};
3use yew::prelude::*;
4use yew_hooks::{use_click_away, use_event_with_window};
5
6#[derive(Clone, PartialEq, Properties)]
8pub struct AboutModalProperties {
9 pub brand_image_src: AttrValue,
11 pub brand_image_alt: AttrValue,
12 pub children: Html,
13
14 #[prop_or(AttrValue::from("About Dialog"))]
16 pub aria_label: AttrValue,
17 #[prop_or_default]
18 pub background_image_src: AttrValue,
19 #[prop_or_default]
20 pub class: Classes,
21 #[prop_or(AttrValue::from("Close dialog"))]
22 pub close_button_aria_label: AttrValue,
23 #[prop_or_default]
24 pub product_name: AttrValue,
25 #[prop_or_default]
26 pub trademark: AttrValue,
27 #[prop_or_default]
28 pub onclose: Option<Callback<()>>,
29
30 #[prop_or_default]
33 pub disable_close_escape: bool,
34 #[prop_or_default]
36 pub disable_close_click_outside: bool,
37 #[prop_or_default]
39 pub id: Option<AttrValue>,
40}
41
42#[function_component(AboutModal)]
61pub fn about_modal(props: &AboutModalProperties) -> Html {
62 let backdrop = use_backdrop();
63
64 let onclose = use_memo(
65 (props.onclose.clone(), backdrop.clone()),
66 |(onclose, backdrop)| {
67 let onclose = onclose.clone();
68 let backdrop = backdrop.clone();
69 Callback::from(move |()| {
70 if let Some(onclose) = &onclose {
71 onclose.emit(());
72 } else if let Some(backdrop) = &backdrop {
73 backdrop.close();
74 }
75 })
76 },
77 );
78
79 {
81 let disabled = props.disable_close_escape;
82 let onclose = onclose.clone();
83 use_event_with_window("keydown", move |e: KeyboardEvent| {
84 if !disabled && e.key() == "Escape" {
85 onclose.emit(());
86 }
87 });
88 }
89
90 let node_ref = use_node_ref();
92
93 {
94 let disabled = props.disable_close_click_outside;
95 let onclose = onclose.clone();
96 use_click_away(node_ref.clone(), move |_: Event| {
97 if !disabled {
98 onclose.emit(());
99 }
100 });
101 }
102
103 let style = if props.background_image_src.is_empty() {
104 None
105 } else {
106 Some(format!(
107 "--pf-v5-c-about-modal-box--BackgroundImage: url({});",
108 &props.background_image_src
109 ))
110 };
111
112 let header_id = use_random_id();
113
114 let (aria_labelledby, aria_label, header) = if props.product_name.is_empty() {
115 (None::<String>, Some(props.aria_label.clone()), html!())
117 } else {
118 (
120 Some((*header_id).to_string()),
121 None,
122 html!(
123 <div class="pf-v5-c-about-modal-box__header">
124 <h1 class="pf-v5-c-title pf-m-4xl" id={*header_id}>{ props.product_name.clone() }</h1>
125 </div>
126 ),
127 )
128 };
129
130 html!(
131 <div
132 id={props.id.clone()}
133 class={classes!("pf-v5-c-about-modal-box", props.class.clone())}
134 {style}
135 role="dialog"
136 aria-modal="true"
137 aria-labelledby={aria_labelledby}
138 aria-label={aria_label}
139 ref={node_ref}
140 >
141 if !props.brand_image_src.is_empty() {
142 <div class="pf-v5-c-about-modal-box__brand">
143 <img
144 class="pf-v5-c-about-modal-box__brand-image"
145 src={props.brand_image_src.clone()}
146 alt={props.brand_image_alt.clone()}
147 />
148 </div>
149 }
150
151 <div class="pf-v5-c-about-modal-box__close">
152 <Button
153 variant={ButtonVariant::Plain}
154 aria_label={props.close_button_aria_label.clone()}
155 onclick={onclose.reform(|_|())}
156 >
157 { Icon::Times }
158 </Button>
159 </div>
160
161 { header }
162
163 <div class="pf-v5-c-about-modal-box__content">
164 <div class="pf-v5-c-about-modal-box__body">
165 { props.children.clone() }
166 </div>
167 if !props.trademark.is_empty() {
168 <p class="pf-v5-c-about-modal-box__strapline">{ props.trademark.clone() }</p>
169 }
170 </div>
171 </div>
172 )
173}