guise-ui 1.5.2

A component library for gpui, Zed's GPU-accelerated UI framework: a themed palette, sizing tokens, 130+ composable components, a reactive state layer, and an in-app Safari-style inspector.
Documentation
//! Flexbox layout primitives, for people who think in `Row`/`Column`/
//! `Container`/`Expanded` (à la Flutter).
//!
//! These map a Flutter-like box model onto gpui's flexbox. Several names
//! (`Row`, `Column`, `Stack`, `Center`, ...) overlap with guise's own `layout`
//! module (`Stack`/`Center`), so this module is **not** glob-exported at the
//! crate root. Import it explicitly:
//!
//! ```ignore
//! use guise::flex::*;
//!
//! Column::new()
//!     .cross_axis_alignment(CrossAxisAlignment::Stretch)
//!     .child(Row::new().child(Expanded::new(header)).child(actions))
//!     .child(SizedBox::height(12.0))
//!     .child(Expanded::new(body))
//! ```

mod container;
mod flexible;
mod rowcolumn;
mod stack;
mod wrap;

pub use container::{Align, Center, Container, Padding};
pub use flexible::{Expanded, Flexible, SizedBox, Spacer};
pub use rowcolumn::{Column, Row};
pub use stack::{Positioned, Stack};
pub use wrap::Wrap;

use gpui::prelude::*;
use gpui::{px, Div};

use crate::style::FlexExt;

/// Distribution of children along the main axis.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MainAxisAlignment {
  Start,
  End,
  Center,
  SpaceBetween,
  SpaceAround,
  SpaceEvenly,
}

/// Alignment of children across the cross axis.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CrossAxisAlignment {
  Start,
  End,
  Center,
  Stretch,
  Baseline,
}

/// Whether a Row/Column shrinks to its children or fills the main axis.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MainAxisSize {
  Min,
  Max,
}

/// A 2-D alignment within a box (`Container`/`Align`/`Center`).
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Alignment {
  TopLeft,
  TopCenter,
  TopRight,
  CenterLeft,
  Center,
  CenterRight,
  BottomLeft,
  BottomCenter,
  BottomRight,
}

/// Padding/margin offsets, like Flutter's `EdgeInsets`.
#[derive(Debug, Clone, Copy, Default, PartialEq)]
pub struct EdgeInsets {
  pub top: f32,
  pub right: f32,
  pub bottom: f32,
  pub left: f32,
}

impl EdgeInsets {
  pub const fn all(value: f32) -> Self {
    EdgeInsets {
      top: value,
      right: value,
      bottom: value,
      left: value,
    }
  }

  pub const fn symmetric(horizontal: f32, vertical: f32) -> Self {
    EdgeInsets {
      top: vertical,
      right: horizontal,
      bottom: vertical,
      left: horizontal,
    }
  }

  pub const fn only(top: f32, right: f32, bottom: f32, left: f32) -> Self {
    EdgeInsets {
      top,
      right,
      bottom,
      left,
    }
  }

  pub const fn horizontal(value: f32) -> Self {
    EdgeInsets::symmetric(value, 0.0)
  }

  pub const fn vertical(value: f32) -> Self {
    EdgeInsets::symmetric(0.0, value)
  }
}

pub(crate) fn apply_main(div: Div, main: MainAxisAlignment) -> Div {
  match main {
    MainAxisAlignment::Start => div.justify_start(),
    MainAxisAlignment::End => div.justify_end(),
    MainAxisAlignment::Center => div.justify_center(),
    MainAxisAlignment::SpaceBetween => div.justify_between(),
    MainAxisAlignment::SpaceAround => div.justify_around(),
    MainAxisAlignment::SpaceEvenly => div.justify_evenly(),
  }
}

pub(crate) fn apply_cross(div: Div, cross: CrossAxisAlignment) -> Div {
  match cross {
    CrossAxisAlignment::Start => div.items_start(),
    CrossAxisAlignment::End => div.items_end(),
    CrossAxisAlignment::Center => div.items_center(),
    CrossAxisAlignment::Stretch => div.items_stretch(),
    CrossAxisAlignment::Baseline => div.items_baseline(),
  }
}

pub(crate) fn apply_alignment(div: Div, alignment: Alignment) -> Div {
  use Alignment::*;
  let div = match alignment {
    TopLeft | CenterLeft | BottomLeft => div.justify_start(),
    TopCenter | Center | BottomCenter => div.justify_center(),
    TopRight | CenterRight | BottomRight => div.justify_end(),
  };
  match alignment {
    TopLeft | TopCenter | TopRight => div.items_start(),
    CenterLeft | Center | CenterRight => div.items_center(),
    BottomLeft | BottomCenter | BottomRight => div.items_end(),
  }
}

pub(crate) fn apply_padding(div: Div, e: EdgeInsets) -> Div {
  div
    .pt(px(e.top))
    .pr(px(e.right))
    .pb(px(e.bottom))
    .pl(px(e.left))
}

pub(crate) fn apply_margin(div: Div, e: EdgeInsets) -> Div {
  div
    .mt(px(e.top))
    .mr(px(e.right))
    .mb(px(e.bottom))
    .ml(px(e.left))
}

#[cfg(test)]
mod tests {
  use super::EdgeInsets;

  #[test]
  fn edge_insets_constructors() {
    assert_eq!(EdgeInsets::all(8.0), EdgeInsets::only(8.0, 8.0, 8.0, 8.0));
    assert_eq!(
      EdgeInsets::symmetric(10.0, 4.0),
      EdgeInsets::only(4.0, 10.0, 4.0, 10.0)
    );
    assert_eq!(
      EdgeInsets::horizontal(6.0),
      EdgeInsets::only(0.0, 6.0, 0.0, 6.0)
    );
    assert_eq!(
      EdgeInsets::vertical(6.0),
      EdgeInsets::only(6.0, 0.0, 6.0, 0.0)
    );
  }
}