1use std::sync::Arc;
2
3use fret_core::Px;
4use fret_runtime::Model;
5use fret_ui::action::{
6 OnCloseAutoFocus, OnDismissRequest, OnDismissiblePointerMove, OnOpenAutoFocus,
7};
8use fret_ui::element::AnyElement;
9use fret_ui::elements::GlobalElementId;
10
11use super::{
12 DEFAULT_VISIBLE_TOASTS, ToastPosition, ToastStore, ToastVariant, toast_layer_root_name,
13};
14
15#[derive(Debug, Clone)]
16pub enum ToastIconOverride {
17 Hidden,
19 Glyph(Arc<str>),
21 #[cfg(feature = "icons")]
23 IconId(fret_icons::IconId),
24}
25
26impl ToastIconOverride {
27 pub fn hidden() -> Self {
28 Self::Hidden
29 }
30
31 pub fn glyph(glyph: impl Into<Arc<str>>) -> Self {
32 Self::Glyph(glyph.into())
33 }
34
35 #[cfg(feature = "icons")]
36 pub fn icon(icon: fret_icons::IconId) -> Self {
37 Self::IconId(icon)
38 }
39}
40
41#[derive(Debug, Default, Clone)]
42pub struct ToastIconOverrides {
43 pub close_button: Option<ToastIconOverride>,
45 pub loading: Option<ToastIconOverride>,
47 pub success: Option<ToastIconOverride>,
49 pub info: Option<ToastIconOverride>,
51 pub warning: Option<ToastIconOverride>,
53 pub error: Option<ToastIconOverride>,
57}
58
59impl ToastIconOverrides {
60 pub fn for_variant(&self, variant: ToastVariant) -> Option<&ToastIconOverride> {
61 match variant {
62 ToastVariant::Success => self.success.as_ref(),
63 ToastVariant::Info => self.info.as_ref(),
64 ToastVariant::Warning => self.warning.as_ref(),
65 ToastVariant::Error | ToastVariant::Destructive => self.error.as_ref(),
66 ToastVariant::Loading | ToastVariant::Default => None,
67 }
68 }
69}
70
71#[derive(Debug, Default, Clone, Copy, PartialEq)]
76pub struct ToastOffset {
77 pub top: Option<Px>,
78 pub right: Option<Px>,
79 pub bottom: Option<Px>,
80 pub left: Option<Px>,
81}
82
83impl ToastOffset {
84 pub fn all(px: Px) -> Self {
85 Self {
86 top: Some(px),
87 right: Some(px),
88 bottom: Some(px),
89 left: Some(px),
90 }
91 }
92
93 pub fn top(mut self, px: Px) -> Self {
94 self.top = Some(px);
95 self
96 }
97
98 pub fn right(mut self, px: Px) -> Self {
99 self.right = Some(px);
100 self
101 }
102
103 pub fn bottom(mut self, px: Px) -> Self {
104 self.bottom = Some(px);
105 self
106 }
107
108 pub fn left(mut self, px: Px) -> Self {
109 self.left = Some(px);
110 self
111 }
112}
113
114#[derive(Debug, Clone)]
115pub struct ToastVariantColors {
116 pub bg: String,
117 pub fg: String,
118}
119
120impl ToastVariantColors {
121 pub fn new(bg: impl Into<String>, fg: impl Into<String>) -> Self {
122 Self {
123 bg: bg.into(),
124 fg: fg.into(),
125 }
126 }
127}
128
129#[derive(Debug, Clone)]
130pub struct ToastVariantPalette {
131 pub default: ToastVariantColors,
132 pub destructive: ToastVariantColors,
133 pub success: ToastVariantColors,
134 pub info: ToastVariantColors,
135 pub warning: ToastVariantColors,
136 pub error: ToastVariantColors,
137 pub loading: ToastVariantColors,
138}
139
140impl Default for ToastVariantPalette {
141 fn default() -> Self {
142 Self {
145 default: ToastVariantColors::new("popover", "popover-foreground"),
146 destructive: ToastVariantColors::new("destructive", "destructive-foreground"),
147 success: ToastVariantColors::new("success", "success-foreground"),
148 info: ToastVariantColors::new("info", "info-foreground"),
149 warning: ToastVariantColors::new("warning", "warning-foreground"),
150 error: ToastVariantColors::new("destructive", "destructive-foreground"),
151 loading: ToastVariantColors::new("popover", "popover-foreground"),
152 }
153 }
154}
155
156impl ToastVariantPalette {
157 pub fn for_variant(&self, variant: ToastVariant) -> &ToastVariantColors {
158 match variant {
159 ToastVariant::Default => &self.default,
160 ToastVariant::Destructive => &self.destructive,
161 ToastVariant::Success => &self.success,
162 ToastVariant::Info => &self.info,
163 ToastVariant::Warning => &self.warning,
164 ToastVariant::Error => &self.error,
165 ToastVariant::Loading => &self.loading,
166 }
167 }
168}
169
170#[derive(Debug, Clone, Default)]
171pub struct ToastTextStyle {
172 pub style_key: Option<String>,
173 pub color_key: Option<String>,
174}
175
176#[derive(Debug, Clone)]
177pub struct ToastButtonStyle {
178 pub label_style_key: Option<String>,
179 pub label_color_key: Option<String>,
180 pub state_layer_color_key: Option<String>,
181 pub hover_state_layer_opacity_key: Option<String>,
182 pub focus_state_layer_opacity_key: Option<String>,
183 pub pressed_state_layer_opacity_key: Option<String>,
184 pub hover_state_layer_opacity: f32,
185 pub focus_state_layer_opacity: f32,
186 pub pressed_state_layer_opacity: f32,
187 pub padding: fret_core::Edges,
188 pub radius: fret_core::Px,
189}
190
191impl Default for ToastButtonStyle {
192 fn default() -> Self {
193 Self {
194 label_style_key: None,
195 label_color_key: None,
196 state_layer_color_key: Some("muted".to_string()),
197 hover_state_layer_opacity_key: None,
198 focus_state_layer_opacity_key: None,
199 pressed_state_layer_opacity_key: None,
200 hover_state_layer_opacity: 0.6,
201 focus_state_layer_opacity: 0.6,
202 pressed_state_layer_opacity: 0.8,
203 padding: fret_core::Edges {
204 left: Px(8.0),
205 right: Px(8.0),
206 top: Px(4.0),
207 bottom: Px(4.0),
208 },
209 radius: Px(6.0),
210 }
211 }
212}
213
214#[derive(Debug, Clone)]
215pub struct ToastIconButtonStyle {
216 pub icon_color_key: Option<String>,
217 pub state_layer_color_key: Option<String>,
218 pub hover_state_layer_opacity_key: Option<String>,
219 pub focus_state_layer_opacity_key: Option<String>,
220 pub pressed_state_layer_opacity_key: Option<String>,
221 pub hover_state_layer_opacity: f32,
222 pub focus_state_layer_opacity: f32,
223 pub pressed_state_layer_opacity: f32,
224 pub padding: fret_core::Edges,
225 pub radius: fret_core::Px,
226}
227
228impl Default for ToastIconButtonStyle {
229 fn default() -> Self {
230 Self {
231 icon_color_key: None,
232 state_layer_color_key: Some("muted".to_string()),
233 hover_state_layer_opacity_key: None,
234 focus_state_layer_opacity_key: None,
235 pressed_state_layer_opacity_key: None,
236 hover_state_layer_opacity: 0.6,
237 focus_state_layer_opacity: 0.6,
238 pressed_state_layer_opacity: 0.8,
239 padding: fret_core::Edges {
240 left: Px(8.0),
241 right: Px(8.0),
242 top: Px(4.0),
243 bottom: Px(4.0),
244 },
245 radius: Px(6.0),
246 }
247 }
248}
249
250#[derive(Debug, Clone)]
251pub struct ToastLayerStyle {
252 pub palette: ToastVariantPalette,
253 pub shadow: Option<fret_ui::element::ShadowStyle>,
255 pub icons: ToastIconOverrides,
257 pub show_close_button: bool,
261 pub close_button_aria_label: Option<Arc<str>>,
263 pub open_ticks: u64,
267 pub close_ticks: u64,
268 pub easing: Option<fret_ui::theme::CubicBezier>,
269 pub slide_distance: Px,
270 pub border_color_key: Option<String>,
272 pub border_width: Px,
273 pub description_color_key: Option<String>,
274 pub icon_size: Px,
275 pub single_line_min_height: Option<Px>,
276 pub two_line_min_height: Option<Px>,
277 pub container_padding: Option<fret_core::Edges>,
278 pub container_radius: Option<fret_core::Px>,
279 pub title: ToastTextStyle,
280 pub description: ToastTextStyle,
281 pub action: ToastButtonStyle,
282 pub cancel: ToastButtonStyle,
283 pub close: ToastIconButtonStyle,
284}
285
286impl Default for ToastLayerStyle {
287 fn default() -> Self {
288 Self {
289 palette: ToastVariantPalette::default(),
290 shadow: None,
291 icons: ToastIconOverrides::default(),
292 show_close_button: true,
293 close_button_aria_label: Some(Arc::from("Close toast")),
294 open_ticks: 12,
295 close_ticks: 12,
296 easing: None,
297 slide_distance: Px(16.0),
298 border_color_key: Some("border".to_string()),
299 border_width: Px(1.0),
300 description_color_key: Some("muted-foreground".to_string()),
301 icon_size: Px(16.0),
302 single_line_min_height: None,
303 two_line_min_height: None,
304 container_padding: None,
305 container_radius: None,
306 title: ToastTextStyle::default(),
307 description: ToastTextStyle::default(),
308 action: ToastButtonStyle::default(),
309 cancel: ToastButtonStyle::default(),
310 close: ToastIconButtonStyle::default(),
311 }
312 }
313}
314
315pub struct DismissiblePopoverRequest {
316 pub id: GlobalElementId,
317 pub root_name: String,
318 pub trigger: GlobalElementId,
319 pub dismissable_branches: Vec<GlobalElementId>,
322 pub consume_outside_pointer_events: bool,
323 pub disable_outside_pointer_events: bool,
326 pub close_on_window_focus_lost: bool,
327 pub close_on_window_resize: bool,
328 pub open: Model<bool>,
329 pub present: bool,
330 pub initial_focus: Option<GlobalElementId>,
331 pub on_open_auto_focus: Option<OnOpenAutoFocus>,
332 pub on_close_auto_focus: Option<OnCloseAutoFocus>,
333 pub on_dismiss_request: Option<OnDismissRequest>,
334 pub on_pointer_move: Option<OnDismissiblePointerMove>,
335 pub children: Vec<AnyElement>,
336}
337
338#[derive(Clone)]
339pub(super) struct CachedDismissiblePopoverDecl {
340 pub owner: Option<GlobalElementId>,
341 pub id: GlobalElementId,
342 pub root_name: String,
343 pub trigger: GlobalElementId,
344 pub dismissable_branches: Vec<GlobalElementId>,
345 pub consume_outside_pointer_events: bool,
346 pub disable_outside_pointer_events: bool,
347 pub close_on_window_focus_lost: bool,
348 pub close_on_window_resize: bool,
349 pub open: Model<bool>,
350 pub initial_focus: Option<GlobalElementId>,
351 pub on_open_auto_focus: Option<OnOpenAutoFocus>,
352 pub on_close_auto_focus: Option<OnCloseAutoFocus>,
353 pub on_dismiss_request: Option<OnDismissRequest>,
354 pub on_pointer_move: Option<OnDismissiblePointerMove>,
355}
356
357impl CachedDismissiblePopoverDecl {
358 pub(super) fn from_request(
359 req: &DismissiblePopoverRequest,
360 owner: Option<GlobalElementId>,
361 ) -> Self {
362 Self {
363 owner,
364 id: req.id,
365 root_name: req.root_name.clone(),
366 trigger: req.trigger,
367 dismissable_branches: req.dismissable_branches.clone(),
368 consume_outside_pointer_events: req.consume_outside_pointer_events,
369 disable_outside_pointer_events: req.disable_outside_pointer_events,
370 close_on_window_focus_lost: req.close_on_window_focus_lost,
371 close_on_window_resize: req.close_on_window_resize,
372 open: req.open.clone(),
373 initial_focus: req.initial_focus,
374 on_open_auto_focus: req.on_open_auto_focus.clone(),
375 on_close_auto_focus: req.on_close_auto_focus.clone(),
376 on_dismiss_request: req.on_dismiss_request.clone(),
377 on_pointer_move: req.on_pointer_move.clone(),
378 }
379 }
380}
381
382impl std::fmt::Debug for DismissiblePopoverRequest {
383 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
384 f.debug_struct("DismissiblePopoverRequest")
385 .field("id", &self.id)
386 .field("root_name", &self.root_name)
387 .field("trigger", &self.trigger)
388 .field("dismissable_branches_len", &self.dismissable_branches.len())
389 .field(
390 "consume_outside_pointer_events",
391 &self.consume_outside_pointer_events,
392 )
393 .field(
394 "disable_outside_pointer_events",
395 &self.disable_outside_pointer_events,
396 )
397 .field(
398 "close_on_window_focus_lost",
399 &self.close_on_window_focus_lost,
400 )
401 .field("close_on_window_resize", &self.close_on_window_resize)
402 .field("open", &"<model>")
403 .field("present", &self.present)
404 .field("initial_focus", &self.initial_focus)
405 .field("on_open_auto_focus", &self.on_open_auto_focus.is_some())
406 .field("on_close_auto_focus", &self.on_close_auto_focus.is_some())
407 .field("on_dismiss_request", &self.on_dismiss_request.is_some())
408 .field("on_pointer_move", &self.on_pointer_move.is_some())
409 .field("children_len", &self.children.len())
410 .finish()
411 }
412}
413
414pub struct ModalRequest {
415 pub id: GlobalElementId,
416 pub root_name: String,
417 pub trigger: Option<GlobalElementId>,
418 pub close_on_window_focus_lost: bool,
419 pub close_on_window_resize: bool,
420 pub open: Model<bool>,
421 pub present: bool,
422 pub initial_focus: Option<GlobalElementId>,
423 pub on_open_auto_focus: Option<OnOpenAutoFocus>,
424 pub on_close_auto_focus: Option<OnCloseAutoFocus>,
425 pub on_dismiss_request: Option<OnDismissRequest>,
426 pub children: Vec<AnyElement>,
427}
428
429#[derive(Clone)]
430pub(super) struct CachedModalDecl {
431 pub owner: Option<GlobalElementId>,
432 pub id: GlobalElementId,
433 pub root_name: String,
434 pub trigger: Option<GlobalElementId>,
435 pub close_on_window_focus_lost: bool,
436 pub close_on_window_resize: bool,
437 pub open: Model<bool>,
438 pub initial_focus: Option<GlobalElementId>,
439 pub on_open_auto_focus: Option<OnOpenAutoFocus>,
440 pub on_close_auto_focus: Option<OnCloseAutoFocus>,
441 pub on_dismiss_request: Option<OnDismissRequest>,
442}
443
444impl CachedModalDecl {
445 pub(super) fn from_request(req: &ModalRequest, owner: Option<GlobalElementId>) -> Self {
446 Self {
447 owner,
448 id: req.id,
449 root_name: req.root_name.clone(),
450 trigger: req.trigger,
451 close_on_window_focus_lost: req.close_on_window_focus_lost,
452 close_on_window_resize: req.close_on_window_resize,
453 open: req.open.clone(),
454 initial_focus: req.initial_focus,
455 on_open_auto_focus: req.on_open_auto_focus.clone(),
456 on_close_auto_focus: req.on_close_auto_focus.clone(),
457 on_dismiss_request: req.on_dismiss_request.clone(),
458 }
459 }
460}
461
462impl std::fmt::Debug for ModalRequest {
463 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
464 f.debug_struct("ModalRequest")
465 .field("id", &self.id)
466 .field("root_name", &self.root_name)
467 .field("trigger", &self.trigger)
468 .field(
469 "close_on_window_focus_lost",
470 &self.close_on_window_focus_lost,
471 )
472 .field("close_on_window_resize", &self.close_on_window_resize)
473 .field("open", &"<model>")
474 .field("present", &self.present)
475 .field("initial_focus", &self.initial_focus)
476 .field("on_open_auto_focus", &self.on_open_auto_focus.is_some())
477 .field("on_close_auto_focus", &self.on_close_auto_focus.is_some())
478 .field("on_dismiss_request", &self.on_dismiss_request.is_some())
479 .field("children_len", &self.children.len())
480 .finish()
481 }
482}
483
484pub struct HoverOverlayRequest {
485 pub id: GlobalElementId,
486 pub root_name: String,
487 pub interactive: bool,
492 pub trigger: GlobalElementId,
493 pub open: Model<bool>,
494 pub present: bool,
495 pub on_pointer_move: Option<OnDismissiblePointerMove>,
496 pub children: Vec<AnyElement>,
497}
498
499#[derive(Clone)]
500pub(super) struct CachedHoverOverlayDecl {
501 pub owner: Option<GlobalElementId>,
502 pub id: GlobalElementId,
503 pub root_name: String,
504 pub interactive: bool,
505 pub trigger: GlobalElementId,
506 pub open: Model<bool>,
507}
508
509impl CachedHoverOverlayDecl {
510 pub(super) fn from_request(req: &HoverOverlayRequest, owner: Option<GlobalElementId>) -> Self {
511 Self {
512 owner,
513 id: req.id,
514 root_name: req.root_name.clone(),
515 interactive: req.interactive,
516 trigger: req.trigger,
517 open: req.open.clone(),
518 }
519 }
520}
521
522impl std::fmt::Debug for HoverOverlayRequest {
523 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
524 f.debug_struct("HoverOverlayRequest")
525 .field("id", &self.id)
526 .field("root_name", &self.root_name)
527 .field("interactive", &self.interactive)
528 .field("trigger", &self.trigger)
529 .field("open", &"<model>")
530 .field("present", &self.present)
531 .field("on_pointer_move", &self.on_pointer_move.is_some())
532 .field("children_len", &self.children.len())
533 .finish()
534 }
535}
536
537pub struct TooltipRequest {
538 pub id: GlobalElementId,
539 pub root_name: String,
540 pub interactive: bool,
545 pub trigger: Option<GlobalElementId>,
546 pub open: Model<bool>,
547 pub present: bool,
548 pub on_dismiss_request: Option<OnDismissRequest>,
549 pub on_pointer_move: Option<OnDismissiblePointerMove>,
550 pub children: Vec<AnyElement>,
551}
552
553#[derive(Clone)]
554pub(super) struct CachedTooltipDecl {
555 pub owner: Option<GlobalElementId>,
556 pub id: GlobalElementId,
557 pub root_name: String,
558 pub interactive: bool,
559 pub trigger: Option<GlobalElementId>,
560 pub open: Model<bool>,
561 pub on_dismiss_request: Option<OnDismissRequest>,
562 pub on_pointer_move: Option<OnDismissiblePointerMove>,
563}
564
565impl CachedTooltipDecl {
566 pub(super) fn from_request(req: &TooltipRequest, owner: Option<GlobalElementId>) -> Self {
567 Self {
568 owner,
569 id: req.id,
570 root_name: req.root_name.clone(),
571 interactive: req.interactive,
572 trigger: req.trigger,
573 open: req.open.clone(),
574 on_dismiss_request: req.on_dismiss_request.clone(),
575 on_pointer_move: req.on_pointer_move.clone(),
576 }
577 }
578}
579
580#[derive(Clone)]
581pub(super) struct CachedToastLayerDecl {
582 pub owner: Option<GlobalElementId>,
583 pub request: ToastLayerRequest,
584}
585
586impl CachedToastLayerDecl {
587 pub(super) fn from_request(req: &ToastLayerRequest, owner: Option<GlobalElementId>) -> Self {
588 Self {
589 owner,
590 request: req.clone(),
591 }
592 }
593}
594
595impl std::fmt::Debug for TooltipRequest {
596 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
597 f.debug_struct("TooltipRequest")
598 .field("id", &self.id)
599 .field("root_name", &self.root_name)
600 .field("interactive", &self.interactive)
601 .field("trigger", &self.trigger)
602 .field("open", &"<model>")
603 .field("present", &self.present)
604 .field("on_dismiss_request", &self.on_dismiss_request.is_some())
605 .field("on_pointer_move", &self.on_pointer_move.is_some())
606 .field("children_len", &self.children.len())
607 .finish()
608 }
609}
610
611#[derive(Clone)]
612pub struct ToastLayerRequest {
613 pub id: GlobalElementId,
614 pub root_name: String,
615 pub store: Model<ToastStore>,
616 pub position: ToastPosition,
617 pub style: ToastLayerStyle,
618 pub toaster_id: Option<Arc<str>>,
619 pub visible_toasts: usize,
620 pub expand_by_default: bool,
621 pub rich_colors: bool,
622 pub invert: bool,
623 pub container_aria_label: Option<Arc<str>>,
624 pub custom_aria_label: Option<Arc<str>>,
625 pub offset: Option<ToastOffset>,
626 pub mobile_offset: Option<ToastOffset>,
627 pub margin: Option<Px>,
628 pub gap: Option<Px>,
629 pub toast_min_width: Option<Px>,
630 pub toast_max_width: Option<Px>,
631}
632
633impl std::fmt::Debug for ToastLayerRequest {
634 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
635 f.debug_struct("ToastLayerRequest")
636 .field("id", &self.id)
637 .field("root_name", &self.root_name)
638 .field("store", &"<model>")
639 .field("position", &self.position)
640 .field("style", &self.style)
641 .field("toaster_id", &self.toaster_id)
642 .field("visible_toasts", &self.visible_toasts)
643 .field("expand_by_default", &self.expand_by_default)
644 .field("rich_colors", &self.rich_colors)
645 .field("invert", &self.invert)
646 .field("container_aria_label", &self.container_aria_label)
647 .field("custom_aria_label", &self.custom_aria_label)
648 .field("offset", &self.offset)
649 .field("mobile_offset", &self.mobile_offset)
650 .field("margin", &self.margin)
651 .field("gap", &self.gap)
652 .field("toast_min_width", &self.toast_min_width)
653 .field("toast_max_width", &self.toast_max_width)
654 .finish()
655 }
656}
657
658impl ToastLayerRequest {
659 pub fn new(id: GlobalElementId, store: Model<ToastStore>) -> Self {
660 Self {
661 id,
662 root_name: toast_layer_root_name(id),
663 store,
664 position: ToastPosition::default(),
665 style: ToastLayerStyle::default(),
666 toaster_id: None,
667 visible_toasts: DEFAULT_VISIBLE_TOASTS,
668 expand_by_default: false,
669 rich_colors: false,
670 invert: false,
671 container_aria_label: None,
672 custom_aria_label: None,
673 offset: None,
674 mobile_offset: None,
675 margin: None,
676 gap: None,
677 toast_min_width: None,
678 toast_max_width: None,
679 }
680 }
681
682 pub fn position(mut self, position: ToastPosition) -> Self {
683 self.position = position;
684 self
685 }
686
687 pub fn root_name(mut self, root_name: impl Into<String>) -> Self {
688 self.root_name = root_name.into();
689 self
690 }
691
692 pub fn style(mut self, style: ToastLayerStyle) -> Self {
693 self.style = style;
694 self
695 }
696
697 pub fn toaster_id_opt(mut self, id: Option<Arc<str>>) -> Self {
698 self.toaster_id = id;
699 self
700 }
701
702 pub fn visible_toasts(mut self, visible_toasts: usize) -> Self {
703 self.visible_toasts = visible_toasts.max(1);
704 self
705 }
706
707 pub fn expand_by_default(mut self, expand: bool) -> Self {
708 self.expand_by_default = expand;
709 self
710 }
711
712 pub fn rich_colors(mut self, rich_colors: bool) -> Self {
713 self.rich_colors = rich_colors;
714 self
715 }
716
717 pub fn invert(mut self, invert: bool) -> Self {
718 self.invert = invert;
719 self
720 }
721
722 pub fn container_aria_label(mut self, label: impl Into<Arc<str>>) -> Self {
724 self.container_aria_label = Some(label.into());
725 self
726 }
727
728 pub fn container_aria_label_opt(mut self, label: Option<Arc<str>>) -> Self {
729 match label {
730 Some(label) => self.container_aria_label(label),
731 None => {
732 self.container_aria_label = None;
733 self
734 }
735 }
736 }
737
738 pub fn custom_aria_label_opt(mut self, label: Option<Arc<str>>) -> Self {
740 self.custom_aria_label = label;
741 self
742 }
743
744 pub fn offset(mut self, offset: ToastOffset) -> Self {
745 self.offset = Some(offset);
746 self
747 }
748
749 pub fn mobile_offset(mut self, offset: ToastOffset) -> Self {
750 self.mobile_offset = Some(offset);
751 self
752 }
753
754 pub fn margin(mut self, margin: Px) -> Self {
755 self.margin = Some(margin);
756 self
757 }
758
759 pub fn gap(mut self, gap: Px) -> Self {
760 self.gap = Some(gap);
761 self
762 }
763
764 pub fn toast_min_width(mut self, width: Px) -> Self {
765 self.toast_min_width = Some(width);
766 self
767 }
768
769 pub fn toast_max_width(mut self, width: Px) -> Self {
770 self.toast_max_width = Some(width);
771 self
772 }
773}