fluidattacks-designs 0.12.0

Fluid Attacks design system, GPUI variant: desktop widgets over the shared tokens
//! The Fluid Attacks design system for GPUI desktop apps, over the tokens in
//! [`tokens`]. Widgets are macOS-gated with their toolkit.
//!
//! They style against the semantic [`Theme`], read via [`ActiveTheme`] at
//! render time, in either light or dark. An app picks its mode at
//! [`Theme::init`] and may switch it whenever it likes: the colors resolve when
//! painting, so nothing below has to be told.
//!
//! Preview the catalog with `cargo run --example gallery`, whose header carries
//! the switch.

pub use fluidattacks_designs_domain as tokens;

/// The toolkit, re-exported so consuming apps build against the exact gpui
/// version the widgets were compiled with.
#[cfg(target_os = "macos")]
pub use gpui;

#[cfg(target_os = "macos")]
mod alert;
#[cfg(target_os = "macos")]
mod assets;
#[cfg(target_os = "macos")]
mod avatar;
#[cfg(target_os = "macos")]
mod button;
#[cfg(target_os = "macos")]
mod checkbox;
#[cfg(target_os = "macos")]
mod cloud_image;
#[cfg(target_os = "macos")]
mod container;
#[cfg(target_os = "macos")]
mod empty_state;
#[cfg(target_os = "macos")]
pub mod file_picker;
#[cfg(target_os = "macos")]
mod icon;
#[cfg(target_os = "macos")]
mod image_view;
#[cfg(target_os = "macos")]
mod link;
#[cfg(target_os = "macos")]
mod list;
#[cfg(target_os = "macos")]
mod loading;
#[cfg(target_os = "macos")]
mod markdown;
#[cfg(target_os = "macos")]
mod modal;
#[cfg(target_os = "macos")]
mod notification_sign;
#[cfg(target_os = "macos")]
mod scrollbar;
#[cfg(target_os = "macos")]
mod search_dropdown;
#[cfg(target_os = "macos")]
mod select;
#[cfg(target_os = "macos")]
mod table;
#[cfg(target_os = "macos")]
mod tabs;
#[cfg(target_os = "macos")]
mod tag;
#[cfg(target_os = "macos")]
mod text;
#[cfg(target_os = "macos")]
mod text_area;
#[cfg(target_os = "macos")]
mod text_input;
#[cfg(target_os = "macos")]
mod theme;
#[cfg(target_os = "macos")]
mod tooltip;
#[cfg(target_os = "macos")]
mod widget;

#[cfg(target_os = "macos")]
pub use alert::{Alert, AlertDialog};
#[cfg(target_os = "macos")]
pub use assets::Assets;
#[cfg(target_os = "macos")]
pub use avatar::Avatar;
#[cfg(target_os = "macos")]
pub use button::Button;
#[cfg(target_os = "macos")]
pub use checkbox::Checkbox;
#[cfg(target_os = "macos")]
pub use cloud_image::CloudImage;
#[cfg(target_os = "macos")]
pub use container::Container;
#[cfg(target_os = "macos")]
pub use empty_state::EmptyState;
#[cfg(target_os = "macos")]
pub use icon::Icon;
#[cfg(target_os = "macos")]
pub use image_view::{ImageView, ImageViewer};
#[cfg(target_os = "macos")]
pub use link::{IconPosition, Link};
#[cfg(target_os = "macos")]
pub use list::{List, ListItem, ListState};
#[cfg(target_os = "macos")]
pub use loading::Loading;
#[cfg(target_os = "macos")]
pub use markdown::Markdown;
#[cfg(target_os = "macos")]
pub use modal::{ConfirmDialog, Modal};
#[cfg(target_os = "macos")]
pub use notification_sign::NotificationSign;
#[cfg(target_os = "macos")]
pub use scrollbar::{stop_dominant_axis, ScrollAxis, Scrollbar};
#[cfg(target_os = "macos")]
pub use search_dropdown::{SearchDropdown, SearchDropdownEvent, SearchDropdownState};
#[cfg(target_os = "macos")]
pub use select::{Select, SelectOption, SelectState};
#[cfg(target_os = "macos")]
pub use table::{Column, Table, TableState};
#[cfg(target_os = "macos")]
pub use tabs::{TabItem, Tabs};
#[cfg(target_os = "macos")]
pub use tag::Tag;
#[cfg(target_os = "macos")]
pub use text::{Heading, Span, Text};
#[cfg(target_os = "macos")]
pub use text_area::{TextArea, TextAreaState};
#[cfg(target_os = "macos")]
pub use text_input::{TextInput, TextInputState};
#[cfg(target_os = "macos")]
pub use theme::{ActiveTheme, Theme};
#[cfg(target_os = "macos")]
pub use tooltip::Tooltip;

#[cfg(test)]
mod tests {
    const GATE: &str = "#[cfg(target_os = \"macos\")]";

    /// A module declaration, `pub` or not, with its trailing semicolon gone.
    fn declared(line: &str) -> Option<&str> {
        line.strip_prefix("pub mod ")
            .or_else(|| line.strip_prefix("mod "))?
            .strip_suffix(';')
    }

    /// Whether this line declares or re-exports one of our widget modules, and
    /// so has to sit under the gate.
    fn needs_gate(line: &str, modules: &[&str]) -> bool {
        let declares = declared(line).is_some();
        // a re-export of one of our own modules, not of a dependency
        let re_exports = line
            .strip_prefix("pub use ")
            .and_then(|rest| rest.split("::").next())
            .is_some_and(|head| modules.contains(&head));
        declares || re_exports
    }

    #[test]
    fn every_widget_module_is_gated_with_its_toolkit() {
        let source = include_str!("lib.rs");
        let modules: Vec<&str> = source.lines().filter_map(declared).collect();
        assert!(
            !modules.is_empty(),
            "the scan found no modules, so it is not reading this file"
        );
        let mut ungated: Vec<&str> = Vec::new();
        let mut previous = "";
        for line in source.lines() {
            if needs_gate(line, &modules) && previous != GATE {
                ungated.push(line);
            }
            if !line.trim().is_empty() {
                previous = line;
            }
        }
        assert!(ungated.is_empty(), "these need the macOS gate: {ungated:?}");
    }
}