orbital-base-components 0.1.1

Headless base primitives for Orbital — structure, semantics, and accessibility
Documentation
use leptos::{ev, prelude::*};

use super::item_state::CollectionItemSignals;
use crate::collection::state::{
    shift_range_in_visible, CollectionSelectionMode, CollectionState, ExpansionTrigger,
};

pub fn use_item_activation(
    state: CollectionState,
    item_id: StoredValue<String>,
    is_branch: bool,
    signals: CollectionItemSignals,
    should_ignore_click: impl Fn(ev::MouseEvent) -> bool + 'static + Clone,
    is_icon_container_click: impl Fn(ev::MouseEvent) -> bool + 'static + Clone,
) -> impl Fn(ev::MouseEvent) + Clone {
    move |event: ev::MouseEvent| {
        if signals.disabled.get_untracked() {
            return;
        }
        if should_ignore_click(event.clone()) {
            return;
        }

        let id = item_id.get_value();
        if let Some(handler) = &state.on_item_click {
            handler.run((id.clone(), event.clone()));
        }

        let icon_click = is_icon_container_click(event.clone());
        let should_toggle = is_branch
            && match state.expansion.expansion_trigger {
                ExpansionTrigger::Row => true,
                ExpansionTrigger::IconContainer => icon_click,
            };

        if should_toggle {
            state.expansion.toggle(id.clone(), is_branch);
        }

        if state.selection.mode != CollectionSelectionMode::None {
            let keep_existing = event.ctrl_key() || event.meta_key();
            let shift_range = if event.shift_key() {
                let visible = {
                    let dom_order = state.dom_registry.visible_ids_in_dom_order();
                    if dom_order.len() >= 2 {
                        dom_order
                    } else {
                        state.visible_ordered_ids()
                    }
                };
                state
                    .selection
                    .last_selected()
                    .and_then(|anchor| shift_range_in_visible(&visible, &anchor, &id))
            } else {
                None
            };
            let should_be_selected = match state.selection.mode {
                CollectionSelectionMode::Single => Some(true),
                CollectionSelectionMode::Multi if !keep_existing && shift_range.is_none() => {
                    Some(true)
                }
                _ => None,
            };
            state.selection.select_item(
                id.clone(),
                keep_existing,
                should_be_selected,
                shift_range,
                Some(&state.registry),
            );
        }

        state.focus.focus_item(id);
        state.dom_registry.focus_dom_element(&item_id.get_value());
    }
}