1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
use std::sync::Arc;
use parking_lot::Mutex;
use crate::{components::Any as AnyComponent, state::State};
static FUNCS: Mutex<Option<Funcs>> = Mutex::new(None);
/// A structure returned by [`use_modal`] that controls the hiding/showing of a modal.
///
/// [`use_modal`]: fn.use_modal.html
#[derive(Clone)]
pub struct Funcs {
modal: State<Option<AnyComponent>>,
show: Arc<dyn Fn(AnyComponent) + Send + Sync>,
hide: Arc<dyn Fn() + Send + Sync>,
}
impl Funcs {
pub(crate) fn new(modal: State<Option<AnyComponent>>) -> Self {
let show_modal = modal.clone();
let hide_modal = modal.clone();
Self {
modal,
show: Arc::new(move |component| show_modal.set(Some(component))),
hide: Arc::new(move || hide_modal.set(None)),
}
}
/// Return whether if the modal is shown.
pub fn is_shown(&self) -> bool {
self.modal.inspect(Option::is_some)
}
/// Set `component` to be shown by the modal.
pub fn show(&self, component: AnyComponent) {
(self.show)(component);
}
/// Hide the showing modal, if any.
pub fn hide(&self) {
(self.hide)();
}
}
/// A hook that can control the hiding/showing of a modal.
///
/// Like [`use_state`], calls to `use_modal` may only be within a call to
/// [`Component::render`]. Unlike [`use_state`], calls to `use_modal` may only be within
/// a component that is a child component of some [`Modal`]. The [`Funcs`] returned by
/// `use_modal` will then refer to the nearest ancestor [`Modal`]. For example, if we
/// have the following layout:
/// ```rust
/// # use intuitive::{render, component, components::{Empty, experimental::modal::{use_modal, Modal}}};
/// #
/// #[component(MyComponent)]
/// fn render() {
/// let modal = use_modal();
///
/// render! {
/// Empty()
/// }
/// }
///
/// #[component(Root)]
/// fn render() {
/// render! {
/// Modal() { // modal 1
/// Modal() { // modal 2
/// Modal() { // modal 3
/// MyComponent()
/// }
/// }
/// }
/// }
/// }
/// ```
/// and `use_modal` is called within `MyComponent`, then it will return a [`Funcs`] struct
/// that acts on `modal 3`. The other two ancestor modals are inaccessible.
///
/// [`Component::render`]: trait.Component.html#tymethod.render
/// [`Modal`]: struct.Modal.html
/// [`Funcs`]: struct.Funcs.html
/// [`use_state`]: ../../state/fn.use_state.html
pub fn use_modal() -> Funcs {
FUNCS
.lock()
.clone()
.expect("use modal called outside of a Modal or outside of render")
}
pub fn set_modal_funcs(funcs: Funcs) {
*FUNCS.lock() = Some(funcs);
}