basecoat_core/props/popover.rs
1use crate::{AttrMap, BasecoatProps, Children, Markup};
2use std::borrow::Cow;
3
4/// Popover placement — passed to the floating-ui controller as the
5/// `placement` argument.
6///
7/// The string form matches [floating-ui's placement vocabulary](https://floating-ui.com/docs/computePosition#placement)
8/// so the WASM controller can forward it verbatim.
9#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
10pub enum PopoverPlacement {
11 Top,
12 TopStart,
13 TopEnd,
14 #[default]
15 Bottom,
16 BottomStart,
17 BottomEnd,
18 Left,
19 LeftStart,
20 LeftEnd,
21 Right,
22 RightStart,
23 RightEnd,
24}
25
26impl PopoverPlacement {
27 /// Returns the floating-ui placement token (e.g. `"bottom-start"`).
28 pub fn as_str(&self) -> &'static str {
29 match self {
30 PopoverPlacement::Top => "top",
31 PopoverPlacement::TopStart => "top-start",
32 PopoverPlacement::TopEnd => "top-end",
33 PopoverPlacement::Bottom => "bottom",
34 PopoverPlacement::BottomStart => "bottom-start",
35 PopoverPlacement::BottomEnd => "bottom-end",
36 PopoverPlacement::Left => "left",
37 PopoverPlacement::LeftStart => "left-start",
38 PopoverPlacement::LeftEnd => "left-end",
39 PopoverPlacement::Right => "right",
40 PopoverPlacement::RightStart => "right-start",
41 PopoverPlacement::RightEnd => "right-end",
42 }
43 }
44}
45
46impl std::fmt::Display for PopoverPlacement {
47 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48 f.write_str(self.as_str())
49 }
50}
51
52/// Popover — maps to CSS class `.popover` on a `<details>` element.
53///
54/// Upstream basecoat uses a `<details>` root containing a `<summary>` trigger
55/// and a `<div role="dialog">` content panel. The WASM controller wires
56/// floating-ui positioning, click-outside dismissal, and aria-expanded sync
57/// onto that markup.
58///
59/// The `id` is required by the WASM controller so trigger/content pairs can be
60/// looked up unambiguously and so accessible-name attributes (`aria-controls`,
61/// `aria-labelledby`) can target the right elements.
62#[derive(BasecoatProps, Default, Clone, Debug)]
63pub struct PopoverProps {
64 /// Unique DOM id — required for the WASM controller.
65 #[prop(optional, into)]
66 pub id: Option<Cow<'static, str>>,
67 /// Trigger content placed inside the `<summary>` element.
68 #[prop(optional)]
69 pub trigger: Option<Markup>,
70 /// Floating-ui placement (default `bottom`).
71 #[prop(default)]
72 pub placement: PopoverPlacement,
73 /// Distance in pixels between the trigger edge and the content panel.
74 #[prop(default = 8.0)]
75 pub offset_px: f64,
76 /// Whether to render a `<div data-popover-arrow>` element inside the
77 /// content. The visual arrow is CSS-positioned in v0.2 — see crate docs.
78 #[prop(default = false)]
79 pub arrow: bool,
80 /// Extra CSS classes appended after the `popover` class.
81 #[prop(optional, into)]
82 pub class: Option<Cow<'static, str>>,
83 #[prop(extend)]
84 pub attrs: AttrMap,
85 /// Popover content (rendered inside the `<div role="dialog">`).
86 pub children: Children,
87}