swiftui-native 0.0.1

SwiftUI from pure Rust — no Swift bridge, no shim, only swift-runtime calls
Documentation
//! Everything that changes how text reads: font, decoration, and input behaviour.
//!
//! Part of [`crate::view::View`]'s chainable API; Rust allows a type's
//! inherent methods to be split across modules, and 400 of them in one file
//! was a file nobody could find anything in.

use super::{Color, View};
use crate::views;

impl View {
    // ── Font ──

    /// `.font(.system(size:))`
    /// On a `Text` this is `Text.font(_:)`, which returns `Text`, so a chain of
    /// text modifiers stays one type the way Swift's does.
    pub fn font_size(self, size: f64) -> Self {
        Self::new(views::text_font(&self.handle, Some(&views::Font::system(size, None, None))))
    }

    /// `.font(.system(size:weight:design:))` — `Text.font(_:)` on a `Text`.
    pub fn font(self, size: f64, weight: Option<views::Weight>, design: Option<views::Design>) -> Self {
        Self::new(views::text_font(&self.handle, Some(&views::Font::system(size, weight, design))))
    }

    /// `.font(_:)` with a built-in text style.
    /// On a `Text` this is `Text.font(_:)`, which returns `Text` — so a chain
    /// like `.text_style(.body).bold()` stays a `Text` the way Swift's does,
    /// instead of each step wrapping the last in an environment modifier.
    pub fn text_style(self, style: views::TextStyle) -> Self {
        Self::new(views::text_font(&self.handle, Some(&views::Font::text_style(style))))
    }

    /// `.font(.custom(_:size:))`
    pub fn font_named(self, name: &str, size: f64) -> Self {
        Self::new(views::text_font(&self.handle, Some(&views::Font::custom(name, size))))
    }

    /// `.font(_:)` with a prebuilt [`views::Font`], which is far cheaper than
    /// rebuilding the font for every view.
    pub fn font_ref(self, font: &views::Font) -> Self {
        Self::new(views::text_font(&self.handle, Some(font)))
    }

    /// `.bold()`
    ///
    /// On a `Text` this is `Text.bold()`, which returns `Text` — the same type
    /// Swift produces, and the reason the documentation corpus compares equal.
    /// On anything else it is the `View` extension, which writes the environment
    /// so the text below inherits it.
    pub fn bold(self) -> Self {
        Self::new(views::text_bold(&self.handle))
    }

    /// `.italic()` — `Text.italic()` on a `Text`, the `View` extension otherwise.
    pub fn italic(self) -> Self {
        Self::new(views::text_italic(&self.handle))
    }

    /// `.monospaced()` — `Text.monospaced()` on a `Text`.
    pub fn monospaced(self) -> Self {
        Self::new(views::text_monospaced(&self.handle))
    }

    /// `.fontWeight(_:)` — `Text.fontWeight(_:)` on a `Text`, which returns
    /// `Text`, and the `View` extension otherwise.
    pub fn weight(self, weight: views::Weight) -> Self {
        Self::new(views::text_font_weight(&self.handle, Some(weight)))
    }

    /// `.foregroundStyle(_:)`
    /// On a `Text` this is `Text.foregroundColor(_:)`, which returns `Text`.
    pub fn fg(self, c: Color) -> Self {
        Self::new(views::text_foreground_color(&self.handle, c))
    }

    /// `Text.baselineOffset(_:)`
    pub fn baseline_offset(self, amount: f64) -> Self {
        Self::new(views::text_baseline_offset(&self.handle, amount))
    }

    /// `.foregroundColor(_:)` with one of SwiftUI's named colours.
    ///
    /// Not the same modifier as [`View::fg`], and not a colour that components
    /// can spell: see [`views::system_color`].
    pub fn fg_system(self, c: views::SystemColor) -> Self {
        Self::new(views::foreground_color_value(&self.handle, views::system_color_value(c)))
    }

    /// `.foregroundStyle(LinearGradient(colors:startPoint:endPoint:))` — text
    /// and symbols painted with a gradient instead of a flat colour.
    ///
    /// Unit points, as in [`View::bg_linear_gradient`].
    /// On a `Text` this is `Text.foregroundStyle(_:)`, which returns `Text`.
    pub fn fg_linear_gradient(self, colors: &[Color], start: (f64, f64), end: (f64, f64)) -> Self {
        let raw: Vec<u64> = colors.iter().map(|&c| views::color_value_of(c)).collect();
        Self::new(views::text_foreground_linear_gradient(&self.handle, &raw, start, end))
    }

    /// `.kerning(_:)` — `Text.kerning(_:)` on a `Text`, which returns `Text`.
    pub fn kerning(self, amount: f64) -> Self {
        Self::new(views::text_kerning(&self.handle, amount))
    }

    /// `.tracking(_:)` — like kerning, but not suppressed between the pairs the
    /// font has a ligature for.
    pub fn tracking(self, amount: f64) -> Self {
        Self::new(views::text_tracking(&self.handle, amount))
    }

    /// `.lineSpacing(_:)`
    pub fn line_spacing(self, amount: f64) -> Self {
        Self::new(views::line_spacing(&self.handle, amount))
    }

    /// `.lineLimit(_:)`
    pub fn line_limit(self, limit: i64) -> Self {
        Self::new(views::line_limit(&self.handle, Some(limit)))
    }

    /// `.multilineTextAlignment(_:)`
    pub fn text_align(self, align: views::TextAlign) -> Self {
        Self::new(views::multiline_alignment(&self.handle, align))
    }

    // ── Sizing and input behaviour ──

    /// `.disableAutocorrection(_:)` — `None` restores the system default.
    ///
    /// Named for the modern spelling because that is what a caller looks for,
    /// but `autocorrectionDisabled(_:)` is inlined and exports no symbol — this
    /// reaches `disableAutocorrection(_:)`, which is the same modifier and the
    /// one SwiftUI still exports.
    pub fn autocorrection_disabled(self, disable: Option<bool>) -> Self {
        Self::new(views::disable_autocorrection(&self.handle, disable))
    }

    /// `.textScale(_:isEnabled:)`
    pub fn text_scale(self, scale: views::TextScale, enabled: bool) -> Self {
        Self::new(views::text_scale(&self.handle, scale, enabled))
    }

    /// `.dynamicTypeSize(_:)` — pin the size class rather than following the
    /// system setting.
    pub fn dynamic_type_size(self, size: views::DynamicTypeSize) -> Self {
        Self::new(views::dynamic_type_size(&self.handle, size))
    }

    /// `.accentColor(_:)` — `None` restores the inherited accent.
    ///
    /// Deprecated in SwiftUI in favour of [`View::tint`], and kept because the
    /// documentation still shows it.
    pub fn accent_color(self, color: Option<Color>) -> Self {
        Self::new(views::accent_color(&self.handle, color))
    }

    // ── Decoration ──

    /// `.underline()`
    pub fn underline(self) -> Self {
        self.underline_styled(true, views::LinePattern::Solid, None)
    }

    /// `.underline(_:pattern:color:)` — `None` keeps the text's own colour.
    ///
    /// `active` is not decoration: this writes the environment, so passing
    /// `false` is how a subtree turns off an underline it would otherwise
    /// inherit. There is no other way to say that.
    pub fn underline_styled(
        self,
        active: bool,
        pattern: views::LinePattern,
        color: Option<Color>,
    ) -> Self {
        Self::new(views::underline(&self.handle, active, pattern, color))
    }

    /// `.strikethrough()`
    pub fn strikethrough(self) -> Self {
        self.strikethrough_styled(true, views::LinePattern::Solid, None)
    }

    /// `.strikethrough(_:pattern:color:)` — `active: false` turns off an
    /// inherited strikethrough, as with [`View::underline_styled`].
    pub fn strikethrough_styled(
        self,
        active: bool,
        pattern: views::LinePattern,
        color: Option<Color>,
    ) -> Self {
        Self::new(views::strikethrough(&self.handle, active, pattern, color))
    }

    /// `.truncationMode(_:)` — which end of over-long text gets the ellipsis.
    pub fn truncation_mode(self, mode: views::TruncationMode) -> Self {
        Self::new(views::truncation_mode(&self.handle, mode))
    }

    /// `.lineHeight(_:)` — `None` restores the font's own leading.
    pub fn line_height(self, height: Option<views::LineHeightKind>) -> Self {
        Self::new(views::line_height(&self.handle, height))
    }

    /// `.fontDesign(_:)` — `.monospaced` and friends, without restating the size.
    pub fn font_design(self, design: views::Design) -> Self {
        Self::new(views::font_design(&self.handle, design))
    }

    /// `.fontWidth(_:)` — `None` restores the default width.
    pub fn font_width(self, width: Option<views::FontWidth>) -> Self {
        Self::new(views::font_width(&self.handle, width))
    }

    /// `.redacted(reason:)` — the placeholder treatment, for loading states.
    pub fn redacted(self, reasons: views::RedactionReasons) -> Self {
        Self::new(views::redacted(&self.handle, reasons))
    }

    /// `.textFieldStyle(_:)` — `.roundedBorder` is the one that looks like a
    /// field rather than a line of text.
    pub fn text_field_style(self, style: views::TextFieldStyle) -> Self {
        Self::new(views::text_field_style(&self.handle, style))
    }

    /// `.submitLabel(_:)` — what the return key says.
    pub fn submit_label(self, label: views::SubmitLabel) -> Self {
        Self::new(views::submit_label(&self.handle, label))
    }

    /// `.onSubmit(of:_:)` — the return key, or a search field's, or a
    /// collection's, depending on the trigger.
    pub fn on_submit(self, trigger: views::SubmitTrigger, action: impl Fn() + 'static) -> Self {
        Self::new(views::on_submit(&self.handle, trigger, action))
    }

    /// `.textContentType(_:)` — what the field holds, which is what lets the
    /// system offer a saved password or a one-time code. `None` clears it.
    pub fn text_content_type(self, kind: Option<views::TextContentKind>) -> Self {
        Self::new(views::text_content_type(&self.handle, kind))
    }

    /// `.keyboardShortcut(_:)` — `.defaultAction` is return, `.cancelAction` is
    /// escape, which is what makes a button the one a sheet's return key hits.
    pub fn keyboard_shortcut(self, shortcut: views::KeyboardShortcut) -> Self {
        Self::new(views::keyboard_shortcut(&self.handle, shortcut))
    }

    /// `.listRowBackground(_:)` — `None` restores the default.
    pub fn list_row_background(self, background: Option<View>) -> Self {
        let bg = background.map(View::into_handle);
        Self::new(views::list_row_background(&self.handle, bg.as_ref()))
    }

}