repose_material/material3/
surface.rs1#![allow(non_snake_case)]
2
3use std::rc::Rc;
4
5use repose_core::*;
6use repose_ui::{Box, TextStyle, ViewExt};
7
8use super::util::{apply_m3_clickable, apply_tonal_elevation};
9use super::*;
10
11#[derive(Clone, Debug)]
13pub struct SurfaceConfig {
14 pub modifier: Modifier,
15 pub enabled: bool,
16 pub color: Color,
17 pub content_color: Color,
18 pub shape_radius: f32,
19 pub tonal_elevation: f32,
20 pub shadow_elevation: f32,
21 pub border: Option<(f32, Color)>,
22 pub interaction_source: Option<MutableInteractionSource>,
23}
24
25impl Default for SurfaceConfig {
26 fn default() -> Self {
27 Self {
28 modifier: Modifier::new(),
29 enabled: true,
30 color: SurfaceDefaults::color(),
31 content_color: SurfaceDefaults::content_color(),
32 shape_radius: SurfaceDefaults::SHAPE_RADIUS,
33 tonal_elevation: SurfaceDefaults::TONAL_ELEVATION,
34 shadow_elevation: SurfaceDefaults::SHADOW_ELEVATION,
35 border: None,
36 interaction_source: None,
37 }
38 }
39}
40
41pub fn Surface(config: SurfaceConfig, content: impl FnOnce() -> View) -> View {
44 let sf_source: Rc<MutableInteractionSource> = config
45 .interaction_source
46 .clone()
47 .map(Rc::new)
48 .unwrap_or_else(|| remember(MutableInteractionSource::new));
49 let mut m = Modifier::new().background(config.color);
50 m = apply_tonal_elevation(m, config.tonal_elevation, config.color);
51 m = m
52 .clip_rounded(config.shape_radius)
53 .interaction_source(&sf_source)
54 .then(config.modifier);
55 if config.shadow_elevation > 0.0 {
56 m = m.shadow(config.shadow_elevation, 0.0);
57 }
58 if let Some((w, c)) = config.border {
59 m = m.border(w, c, config.shape_radius);
60 }
61 if !config.enabled {
62 m = m.enabled(false);
63 }
64 Box(m)
65 .color(config.content_color)
66 .child(with_content_color(config.content_color, content))
67}
68
69pub fn ClickableSurface(
71 on_click: impl Fn() + 'static,
72 config: SurfaceConfig,
73 content: impl FnOnce() -> View,
74) -> View {
75 let sf_source: Rc<MutableInteractionSource> = config
76 .interaction_source
77 .clone()
78 .map(Rc::new)
79 .unwrap_or_else(|| remember(MutableInteractionSource::new));
80 let mut m = Modifier::new()
81 .min_width(48.0)
82 .min_height(48.0)
83 .background(config.color);
84 m = apply_tonal_elevation(m, config.tonal_elevation, config.color);
85 m = m
86 .clip_rounded(config.shape_radius)
87 .interaction_source(&sf_source)
88 .then(config.modifier);
89 if config.shadow_elevation > 0.0 {
90 m = m.shadow(config.shadow_elevation, 0.0);
91 }
92 if let Some((w, c)) = config.border {
93 m = m.border(w, c, config.shape_radius);
94 }
95 m = apply_m3_clickable(
96 m,
97 &sf_source,
98 config.content_color,
99 config.enabled,
100 on_click,
101 );
102 Box(m)
103 .color(config.content_color)
104 .child(with_content_color(config.content_color, content))
105}