hikari-components 0.2.0

Core UI components (40+) for the Hikari design system
// hi-components/src/layout/divider.rs
// Divider component for visual separation

use hikari_palette::classes::{ClassesBuilder, DividerClass};

use crate::prelude::*;
use crate::theme::use_layout_direction;

#[derive(Clone, Copy, PartialEq, Debug, Default)]
pub enum DividerOrientation {
    #[default]
    Horizontal,
    Vertical,
}

#[derive(Clone, Copy, PartialEq, Debug, Default)]
pub enum DividerType {
    #[default]
    Solid,
    Dashed,
    Dotted,
}

/// Props for the [`Divider`] component.
#[define_props]
pub struct DividerProps {
    #[default]
    pub text: Option<String>,

    #[default]
    pub orientation: DividerOrientation,

    #[default]
    pub divider_type: DividerType,

    #[default("center".to_string())]
    pub text_align: String,

    #[default]
    pub rtl: Option<bool>,

    #[default]
    pub class: String,
}

/// A visual divider line that separates content sections, with optional centered text label.
#[component]
pub fn Divider(props: DividerProps) -> Element {
    let layout_direction = use_layout_direction();
    let is_rtl = props.rtl.unwrap_or_else(|| layout_direction.is_rtl());

    let orientation_class = match props.orientation {
        DividerOrientation::Horizontal => DividerClass::Horizontal,
        DividerOrientation::Vertical => DividerClass::Vertical,
    };

    let type_class = match props.divider_type {
        DividerType::Solid => DividerClass::Solid,
        DividerType::Dashed => DividerClass::Dashed,
        DividerType::Dotted => DividerClass::Dotted,
    };

    let mut builder = ClassesBuilder::new()
        .add_typed(DividerClass::Divider)
        .add_typed(orientation_class)
        .add_typed(type_class)
        .add_typed_if(DividerClass::WithText, props.text.is_some())
        .add(&props.class);

    if is_rtl {
        builder = builder.add_typed(DividerClass::Rtl);
    }

    let divider_classes = builder.build();

    let text_align_style = if props.text.is_some() {
        match props.text_align.as_str() {
            "left" => {
                if is_rtl {
                    "text-align: right;"
                } else {
                    "text-align: left;"
                }
            }
            "right" => {
                if is_rtl {
                    "text-align: left;"
                } else {
                    "text-align: right;"
                }
            }
            _ => "text-align: center;",
        }
    } else {
        { "" }
    };

    rsx! {
        div { class: divider_classes, style: text_align_style,
            if let Some(label) = props.text {
                span { class: "hi-divider-text", "{label}" }
            }
        }
    }
}

pub struct DividerComponent;

impl crate::styled::StyledComponent for DividerComponent {
    fn styles() -> &'static str {
        r#"
.hi-divider {
  width: 100%;
  display: flex;
  align-items: center;
  color: var(--hi-border);
}

.hi-divider-horizontal {
  height: 1px;
  flex-direction: row;
}

.hi-divider-vertical {
  width: 1px;
  min-height: 100%;
  flex-direction: column;
}

.hi-divider-solid {
  border-top: 1px solid var(--hi-border);
}

.hi-divider-dashed {
  border-top: 1px dashed var(--hi-border);
}

.hi-divider-dotted {
  border-top: 1px dotted var(--hi-border);
}

.hi-divider-with-text {
  position: relative;
}

.hi-divider-text {
  background: var(--hi-surface);
  padding: 0 16px;
  font-size: 14px;
  color: var(--hi-text-secondary);
}

[data-theme="dark"] .hi-divider {
  border-color: var(--hi-border);
}

[data-theme="dark"] .hi-divider-text {
  background: var(--hi-background);
  color: var(--hi-text-secondary);
}
"#
    }

    fn name() -> &'static str {
        "divider"
    }
}