swiftui-native 0.0.1

SwiftUI from pure Rust — no Swift bridge, no shim, only swift-runtime calls
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
//! Colour, background, effects and animation — what a view looks like.
//!
//! 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 {
    // ── Colour and background ──

    /// Apply `.background(_:)` with a color.
    pub fn bg(self, c: Color) -> Self {
        Self::new(views::background(&self.handle, c.r, c.g, c.b, c.a))
    }

    /// `.background { … }` — an arbitrary view behind this one, centred.
    ///
    /// SwiftUI has two `background` overloads and they are different
    /// modifiers, not one with a convenience: [`View::bg`] reaches the one
    /// generic over `ShapeStyle`, this reaches the one generic over `View`.
    /// So the argument here can be a whole subtree, not only a colour.
    pub fn bg_view(self, content: View) -> Self {
        self.bg_view_aligned(content, views::Alignment::Center)
    }

    /// `.background(alignment:) { … }`
    pub fn bg_view_aligned(self, content: View, alignment: views::Alignment) -> Self {
        Self::new(views::background_content(&self.handle, content.handle(), alignment))
    }

    /// `.background(.regularMaterial)` and its neighbours — a blur of
    /// whatever is behind the view rather than a colour over it.
    pub fn bg_material(self, kind: views::MaterialKind) -> Self {
        Self::new(views::background_material(&self.handle, kind))
    }

    /// `.background(LinearGradient(colors:startPoint:endPoint:))`
    ///
    /// The points are unit points: `(0, 0)` is top-leading and `(1, 1)`
    /// bottom-trailing, so a top-to-bottom gradient is `(0.5, 0)`→`(0.5, 1)`.
    pub fn bg_linear_gradient(self, colors: &[Color], start: (f64, f64), end: (f64, f64)) -> Self {
        Self::new(views::background_linear_gradient(&self.handle, colors, start, end))
    }

    /// `.background(RadialGradient(colors:center:startRadius:endRadius:))`
    pub fn bg_radial_gradient(
        self,
        colors: &[Color],
        center: (f64, f64),
        start_radius: f64,
        end_radius: f64,
    ) -> Self {
        Self::new(views::background_radial_gradient(
            &self.handle,
            colors,
            center,
            start_radius,
            end_radius,
        ))
    }

    /// Apply `.opacity(_:)`.
    ///
    /// On a `Color` this is `Color.opacity(_:)`, which returns `Color` — the
    /// same concrete-overload story as `Text.bold()`.
    pub fn opacity(self, value: f64) -> Self {
        Self::new(views::view_opacity(&self.handle, value))
    }

    /// Apply `.cornerRadius(_:)`.
    pub fn rounded(self, radius: f64) -> Self {
        Self::new(views::corner_radius(&self.handle, radius))
    }

    /// Apply `.border(_:width:)`.
    ///
    /// Through [`views::border_value`] rather than [`views::border`], because
    /// the latter takes components and pins alpha to 1 — so a translucent border
    /// came out opaque and nothing said so.
    pub fn border(self, c: Color, width: f64) -> Self {
        Self::new(views::border_value(&self.handle, views::color_value_of(c), width))
    }

    /// `.border(_:width:)` with one of SwiftUI's own colours.
    pub fn border_system(self, c: views::SystemColor, width: f64) -> Self {
        Self::new(views::border_value(&self.handle, views::system_color_value(c), width))
    }

    /// Apply `f` only when `condition` holds.
    ///
    /// Modifier chains often need a branch, and an `if` in the middle of a
    /// builder chain otherwise forces a temporary binding.
    ///
    /// ```ignore
    /// text("hi").when(selected, |v| v.bold().fg(Color::RED))
    /// ```
    pub fn when(self, condition: bool, f: impl FnOnce(Self) -> Self) -> Self {
        if condition { f(self) } else { self }
    }

    /// Apply `f` with the contained value when `value` is `Some`.
    pub fn when_some<T>(self, value: Option<T>, f: impl FnOnce(Self, T) -> Self) -> Self {
        match value {
            Some(v) => f(self, v),
            None => self,
        }
    }

    /// Apply one of two branches.
    pub fn either(
        self,
        condition: bool,
        yes: impl FnOnce(Self) -> Self,
        no: impl FnOnce(Self) -> Self,
    ) -> Self {
        if condition { yes(self) } else { no(self) }
    }

    /// Shorthand: padding + background + corner radius.
    pub fn card(self, pad: f64, bg: Color, radius: f64) -> Self {
        self.padding(pad).bg(bg).rounded(radius)
    }

    // ── Effects ──

    /// `.shadow(color:radius:x:y:)`
    pub fn shadow(self, c: Color, radius: f64, dx: f64, dy: f64) -> Self {
        Self::new(views::shadow(&self.handle, c, radius, dx, dy))
    }

    /// `.blur(radius:)`
    pub fn blur(self, radius: f64) -> Self {
        Self::new(views::blur(&self.handle, radius))
    }

    /// `.rotationEffect(.degrees(_))` about the centre.
    pub fn rotate(self, degrees: f64) -> Self {
        self.rotate_anchored(degrees, (0.5, 0.5))
    }

    /// `.rotationEffect(.degrees(_), anchor:)` — the point the view turns
    /// about, as a unit point: `(0, 0)` is top-leading, `(0.5, 0.5)` the centre.
    ///
    /// Not a detail: a dial hand turns about its base and a card flips about an
    /// edge, and neither is expressible by rotating about the middle.
    pub fn rotate_anchored(self, degrees: f64, anchor: (f64, f64)) -> Self {
        Self::new(views::rotation(&self.handle, degrees, anchor.0, anchor.1))
    }

    /// `.scaleEffect(_:)` about the centre.
    pub fn scale(self, sx: f64, sy: f64) -> Self {
        self.scale_anchored(sx, sy, (0.5, 0.5))
    }

    /// `.scaleEffect(_:anchor:)` — grow from a unit point rather than the middle.
    pub fn scale_anchored(self, sx: f64, sy: f64, anchor: (f64, f64)) -> Self {
        Self::new(views::scale(&self.handle, sx, sy, anchor.0, anchor.1))
    }

    /// `.offset(x:y:)`
    pub fn offset(self, dx: f64, dy: f64) -> Self {
        Self::new(views::offset(&self.handle, dx, dy))
    }

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

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

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

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

    // ── Materials and glass ──

    /// `.background(_: Material)`
    pub fn material(self, kind: views::MaterialKind) -> Self {
        Self::new(views::background_material(&self.handle, kind))
    }

    /// `.glassEffect()` — Liquid Glass.
    pub fn glass(self) -> Self {
        Self::new(views::glass_effect(&self.handle))
    }

    /// `.background(LinearGradient(…))`
    pub fn gradient(self, colors: &[Color], start: (f64, f64), end: (f64, f64)) -> Self {
        Self::new(views::background_linear_gradient(&self.handle, colors, start, end))
    }

    /// `.background(RadialGradient(…))`
    pub fn radial_gradient(
        self,
        colors: &[Color],
        center: (f64, f64),
        start_radius: f64,
        end_radius: f64,
    ) -> Self {
        Self::new(views::background_radial_gradient(
            &self.handle, colors, center, start_radius, end_radius,
        ))
    }

    /// `.tint(_:)`
    pub fn tint(self, c: Color) -> Self {
        Self::new(views::tint(&self.handle, c))
    }

    /// `.preferredColorScheme(_:)`
    pub fn color_scheme(self, scheme: views::ColorScheme) -> Self {
        Self::new(views::preferred_color_scheme(&self.handle, scheme))
    }

    /// `.controlSize(_:)`
    pub fn control_size(self, size: views::ControlSize) -> Self {
        Self::new(views::control_size(&self.handle, size))
    }

    /// `.buttonStyle(_:)`
    pub fn button_style(self, style: views::ButtonStyle) -> Self {
        Self::new(views::button_style(&self.handle, style))
    }

    /// `.backgroundStyle(_:)` with one of SwiftUI's semantic styles.
    pub fn background_shape_style(self, style: views::ShapeStyle) -> Self {
        Self::new(views::background_shape_style(&self.handle, style))
    }

    /// `.background(_.gradient)` — the automatic gradient derived from a colour.
    pub fn bg_auto_gradient(self, c: Color) -> Self {
        Self::new(views::background_any_gradient(&self.handle, views::color_value_of(c)))
    }

    /// `.background(in: .circle)`
    pub fn bg_in_circle(self) -> Self {
        Self::new(views::background_in_circle(&self.handle))
    }

    /// `.containerBackground(for:alignment:content:)` — the background a
    /// container hands to its whole area, not just this view's bounds.
    ///
    /// See [`views::ContainerBackgroundPlacement`]: two of its cases trap on
    /// macOS, which is SwiftUI's own availability rather than anything here.
    pub fn container_background(
        self,
        placement: views::ContainerBackgroundPlacement,
        alignment: views::Alignment,
        content: View,
    ) -> Self {
        Self::new(views::container_background(
            &self.handle,
            placement,
            alignment,
            content.handle(),
        ))
    }

    /// `.foregroundStyle(_:)` with an already-built colour, which is how a
    /// system colour is passed — see [`views::system_color_value`].
    pub fn fg_value(self, color: u64) -> Self {
        Self::new(views::foreground_style_value(&self.handle, color))
    }

    /// `.foregroundStyle(_:_:)` — primary and secondary, for a symbol drawn in
    /// two tones.
    pub fn fg_pair(self, primary: u64, secondary: u64) -> Self {
        Self::new(views::foreground_style_pair(&self.handle, primary, secondary))
    }

    /// `.foregroundStyle(_:_:_:)` — three tones.
    ///
    /// A palette symbol takes its layers from successive styles.
    /// [`fg_pair`](Self::fg_pair) covers the two-layer symbols; the three-layer
    /// ones — and there are plenty in SF Symbols — drew their third layer in
    /// the secondary colour, because there was no way to say what it should be.
    pub fn fg_triple(self, primary: u64, secondary: u64, tertiary: u64) -> Self {
        Self::new(views::foreground_style_triple(
            &self.handle,
            primary,
            secondary,
            tertiary,
        ))
    }

    /// `.tint(_:)` with an already-built colour.
    pub fn tint_value(self, tint: u64) -> Self {
        Self::new(views::tint_value(&self.handle, tint))
    }

    /// `.colorScheme(_:)` — force light or dark for this subtree, as distinct
    /// from [`View::color_scheme`]'s *preferred* scheme, which asks the whole
    /// window.
    pub fn color_scheme_forced(self, value: views::ColorScheme) -> Self {
        Self::new(views::color_scheme(&self.handle, value))
    }

    /// `.edgesIgnoringSafeArea(_:)` — the older spelling; see
    /// [`View::ignores_safe_area`] for the one that takes regions too.
    pub fn edges_ignoring_safe_area(self, edges: views::EdgeSet) -> Self {
        Self::new(views::edges_ignoring_safe_area(&self.handle, edges))
    }

    /// `.persistentSystemOverlays(_:)` — the home indicator and its neighbours.
    pub fn persistent_system_overlays(self, visibility: views::Visibility) -> Self {
        Self::new(views::persistent_system_overlays(&self.handle, visibility))
    }

    // ── Symbols ──

    /// `.symbolVariant(_:)` — `.fill`, `.circle` and so on, without renaming the
    /// symbol.
    pub fn symbol_variant(self, variant: views::SymbolVariants) -> Self {
        Self::new(views::symbol_variant(&self.handle, variant))
    }

    /// `.symbolRenderingMode(_:)` — `None` restores the default.
    pub fn symbol_rendering_mode(self, mode: Option<views::SymbolRenderingMode>) -> Self {
        Self::new(views::symbol_rendering_mode(&self.handle, mode))
    }

    /// `.labelStyle(_:)` — icon only, title only, or both.
    pub fn label_style(self, style: views::LabelStyle) -> Self {
        Self::new(views::label_style(&self.handle, style))
    }

    /// `.menuStyle(_:)`
    pub fn menu_style(self, style: views::MenuStyle) -> Self {
        Self::new(views::menu_style(&self.handle, style))
    }

    /// `.buttonBorderShape(_:)`
    pub fn button_border_shape(self, shape: views::ButtonBorderShape) -> Self {
        Self::new(views::button_border_shape(&self.handle, shape))
    }

    /// `.scrollTargetBehavior(_:)` — `.paging` and friends.
    pub fn scroll_target_behavior(self, behavior: views::ScrollTargetBehavior) -> Self {
        Self::new(views::scroll_target_behavior(&self.handle, behavior))
    }

    /// `.scrollContentBackground(_:)` — hiding it is how a `List` loses its
    /// grouped backdrop.
    pub fn scroll_content_background(self, visibility: views::Visibility) -> Self {
        Self::new(views::scroll_content_background(&self.handle, visibility))
    }

    /// `.symbolEffect(.pulse)`
    pub fn symbol_effect_pulse(self) -> Self {
        Self::new(views::symbol_effect_pulse(&self.handle))
    }

    /// `.symbolEffectsRemoved(_:)` — stop inherited effects at this view.
    pub fn symbol_effects_removed(self, removed: bool) -> Self {
        Self::new(views::symbol_effects_removed(&self.handle, removed))
    }

    /// `.symbolColorRenderingMode(.flat)`
    pub fn symbol_color_rendering_mode_flat(self) -> Self {
        Self::new(views::symbol_color_rendering_mode_flat(&self.handle))
    }

    /// `.symbolVariableValueMode(.color)`
    pub fn symbol_variable_value_mode_color(self) -> Self {
        Self::new(views::symbol_variable_value_mode_color(&self.handle))
    }

    // ── Animation ──

    /// `.keyframeAnimator(initialValue:repeating:content:)` — drive a value
    /// through keyframes and rebuild the content from it.
    pub fn keyframe_animator(
        self,
        initial: f64,
        to: f64,
        repeating: bool,
        content: View,
    ) -> Self {
        Self::new(views::keyframe_animator(
            &self.handle,
            initial,
            to,
            repeating,
            content.handle(),
        ))
    }

    /// `.phaseAnimator(_:content:)` — step through phases, rebuilding at each.
    pub fn phase_animator(self, phases: &[i64], content: View, animated: bool) -> Self {
        Self::new(views::phase_animator(&self.handle, phases, content.handle(), animated))
    }

    /// `.transaction(_:)` — reach the transaction driving the current change,
    /// which is how an animation is suppressed for one update.
    pub fn transaction(self, action: impl Fn(views::TransactionRef) + 'static) -> Self {
        Self::new(views::transaction(&self.handle, action))
    }

    /// `.geometryGroup()` — animate this subtree's geometry as one, rather than
    /// letting each child interpolate independently and pull apart.
    pub fn geometry_group(self) -> Self {
        Self::new(views::geometry_group(&self.handle))
    }

    /// `.transformEffect(_:)` — an affine transform, as `[a b c d tx ty]`.
    pub fn transform_effect(self, a: f64, b: f64, c: f64, d: f64, tx: f64, ty: f64) -> Self {
        Self::new(views::transform_effect(&self.handle, a, b, c, d, tx, ty))
    }

    /// `.visualEffect(_:)`
    pub fn visual_effect(self) -> Self {
        Self::new(views::visual_effect(&self.handle))
    }

}