woocraft 0.4.5

GPUI components lib for Woocraft design system.
Documentation
use gpui::{
  App, Axis, IntoElement, ParentElement, Pixels, Rems, RenderOnce, StyleRefinement, Styled, Window,
};

use super::{Field, FieldProps};
use crate::{Sizable, Size, StyledExt, v_flex};

#[derive(IntoElement)]
pub struct Form {
  style: StyleRefinement,
  fields: Vec<Field>,
  props: FieldProps,
}

impl Form {
  fn new() -> Self {
    Self {
      style: StyleRefinement::default(),
      fields: Vec::new(),
      props: FieldProps::default(),
    }
  }

  pub fn horizontal() -> Self {
    Self::new().layout(Axis::Horizontal)
  }

  pub fn vertical() -> Self {
    Self::new().layout(Axis::Vertical)
  }

  pub fn layout(mut self, layout: Axis) -> Self {
    self.props.layout = layout;
    self
  }

  pub fn label_width(mut self, width: Pixels) -> Self {
    self.props.label_width = Some(width);
    self
  }

  pub fn label_text_size(mut self, size: Rems) -> Self {
    self.props.label_text_size = Some(size);
    self
  }

  pub fn child(mut self, field: impl Into<Field>) -> Self {
    self.fields.push(field.into());
    self
  }

  pub fn children(mut self, fields: impl IntoIterator<Item = Field>) -> Self {
    self.fields.extend(fields);
    self
  }

  pub fn columns(mut self, columns: usize) -> Self {
    self.props.columns = columns.max(1);
    self
  }
}

impl_styled!(Form);

impl Sizable for Form {
  fn with_size(mut self, size: impl Into<Size>) -> Self {
    self.props.size = size.into();
    self
  }
}

impl RenderOnce for Form {
  fn render(self, _: &mut Window, _: &mut App) -> impl IntoElement {
    let props = self.props;
    let gap = props.size.component_gap();

    v_flex()
      .w_full()
      .grid()
      .grid_cols(props.columns as u16)
      .gap_x(gap * 2.0)
      .gap_y(gap)
      .children(
        self
          .fields
          .into_iter()
          .enumerate()
          .map(|(ix, field)| field.props(ix, props)),
      )
      .refine_style(&self.style)
  }
}