patternfly_yew/components/
about.rs1use crate::prelude::{Button, ButtonVariant, Icon, use_backdrop, use_random_id};
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-v6-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-v6-c-about-modal-box__header">
124 <h1 class="pf-v6-c-title pf-m-4xl" id={*header_id}>
125 { props.product_name.clone() }
126 </h1>
127 </div>
128 ),
129 )
130 };
131
132 html!(
133 <div
134 id={props.id.clone()}
135 class={classes!("pf-v6-c-about-modal-box", props.class.clone())}
136 {style}
137 role="dialog"
138 aria-modal="true"
139 aria-labelledby={aria_labelledby}
140 aria-label={aria_label}
141 ref={node_ref}
142 >
143 if !props.brand_image_src.is_empty() {
144 <div class="pf-v6-c-about-modal-box__brand">
145 <img
146 class="pf-v6-c-about-modal-box__brand-image"
147 src={props.brand_image_src.clone()}
148 alt={props.brand_image_alt.clone()}
149 />
150 </div>
151 }
152 <div
153 class="pf-v6-c-about-modal-box__close"
154 >
155 <Button
156 variant={ButtonVariant::Plain}
157 aria_label={props.close_button_aria_label.clone()}
158 onclick={onclose.reform(|_|())}
159 >
160 { Icon::Times }
161 </Button>
162 </div>
163 { header }
164 <div class="pf-v6-c-about-modal-box__content">
165 <div class="pf-v6-c-about-modal-box__body">{ props.children.clone() }</div>
166 if !props.trademark.is_empty() {
167 <p class="pf-v6-c-about-modal-box__strapline">{ props.trademark.clone() }</p>
168 }
169 </div>
170 </div>
171 )
172}