portico/Sources/Portico/Widgets/Label.swift

60 lines
1.7 KiB
Swift

import Gtk
// MARK: - Label
/// A text label backed by `Gtk.Label` with three source modes:
/// constant text, explicit ``Binding``, and a tracked closure.
///
/// Reactive forms (`Binding` and closure) update the label in place
/// the widget is never recreated on state change.
@MainActor public struct Label: View {
private enum Source {
case constant(String)
case binding(Binding<String>)
case dynamic(() -> String)
}
private let source: Source
public var body: Never { fatalError() }
/// Creates a static label that never changes.
public init(_ text: String) {
source = .constant(text)
}
/// Creates a label that updates when the binding changes.
public init(_ text: Binding<String>) {
source = .binding(text)
}
/// Creates a label whose text is recomputed via a tracked closure
/// whenever any state read inside it changes.
public init(_ make: @escaping () -> String) {
source = .dynamic(make)
}
}
// MARK: - Mountable
@_spi(Portico) extension Label: Mountable {
@_spi(Portico) public func mount(_ ctx: MountContext) -> Gtk.Widget {
let label = Gtk.Label(str: "")
switch source {
case .constant(let s):
label.setText(str: s)
case .binding(let b):
label.setText(str: b.wrappedValue)
ctx.registry.add(b.subscribe { [label] v in
label.setText(str: v)
})
case .dynamic(let make):
let tracker = DependencyTracker { [label] in
label.setText(str: make())
}
tracker.run()
ctx.registry.add(tracker)
}
return label
}
}