Move from renderable elements to views

This commit is contained in:
david-swift 2024-07-18 16:07:37 +02:00
parent 1b4621c03a
commit 21e28344c1
23 changed files with 335 additions and 160 deletions

View File

@ -0,0 +1,59 @@
//
// ButtonCollection.swift
// TermKitBackend
//
// Created by david-swift on 18.07.2024.
//
import TermKit
/// A menu is an item of a ``MenuBar``.
public struct ButtonCollection: ButtonContext.Widget, Wrapper {
/// The content of the menu.
var content: Body
/// Initialize a menu.
/// - Parameters:
/// - label: The menu's label, displayed in the menu bar.
/// - content: The content of the menu.
public init(@ViewBuilder content: @escaping () -> Body) {
self.content = content()
}
/// The view storage.
/// - Parameters:
/// - modifiers: Modify the views before updating.
/// - type: The type of the views.
/// - Returns: The view storage.
public func container<Data>(
modifiers: [(any AnyView) -> any AnyView],
type: Data.Type
) -> ViewStorage where Data: ViewRenderData {
var buttons: [Button] = []
for element in content.storages(modifiers: modifiers, type: type) {
if let button = element.pointer as? Button {
buttons.append(button)
} else if let collection = element.pointer as? [Button] {
buttons += collection
}
}
return .init(buttons, content: [.mainContent: content.storages(modifiers: modifiers, type: type)])
}
/// Update the stored content.
/// - Parameters:
/// - storage: The storage to update.
/// - modifiers: Modify the views before updating.
/// - updateProperties: Whether to update the properties.
/// - type: The type of the views.
public func update<Data>(
_ storage: ViewStorage,
modifiers: [(AnyView) -> AnyView],
updateProperties: Bool,
type: Data.Type
) where Data: ViewRenderData {
// Buttons in dialogs cannot be updated
}
}

View File

@ -0,0 +1,21 @@
//
// ButtonContext.swift
// TermKitBackend
//
// Created by david-swift on 18.07.2024.
//
import TermKit
/// The menu items view context.
public enum ButtonContext: ViewRenderData {
/// The type of the widgets.
public typealias WidgetType = Widget
/// The wrapper type.
public typealias WrapperType = ButtonCollection
/// The type of the widgets.
public protocol Widget: Meta.Widget { }
}

View File

@ -8,48 +8,52 @@
import TermKit import TermKit
/// A menu is an item of a ``MenuBar``. /// A menu is an item of a ``MenuBar``.
public struct Menu: Renderable { public struct Menu: MenuContext.Widget {
/// The menu's label, displayed in the menu bar. /// The menu's label, displayed in the menu bar.
var label: String var label: String
/// The content of the menu. /// The content of the menu.
var content: [Button] var content: Body
/// Initialize a menu. /// Initialize a menu.
/// - Parameters: /// - Parameters:
/// - label: The menu's label, displayed in the menu bar. /// - label: The menu's label, displayed in the menu bar.
/// - content: The content of the menu. /// - content: The content of the menu.
public init(_ label: String, @Builder<Button> content: () -> [Button]) { public init(_ label: String, @ViewBuilder content: () -> Body) {
self.label = label self.label = label
self.content = content() self.content = content()
} }
/// The view storage. /// The view storage.
/// - Parameters: /// - Parameters:
/// - type: The type of the renderable elements. /// - modifiers: Modify the views before updating.
/// - fields: More information. /// - type: The type of the views.
public func container<RenderableType>(type: RenderableType.Type, fields: [String: Any]) -> RenderableStorage { /// - Returns: The view storage.
let children = (content as [Renderable]).storages(type: Button.self, fields: [:]) public func container<Data>(
modifiers: [(any AnyView) -> any AnyView],
type: Data.Type
) -> ViewStorage where Data: ViewRenderData {
let children = content.storages(modifiers: modifiers, type: type)
let menu = MenuBarItem(title: label, children: children.compactMap { $0.pointer as? MenuItem }) let menu = MenuBarItem(title: label, children: children.compactMap { $0.pointer as? MenuItem })
return .init(menu, content: [.mainContent: children]) return .init(menu, content: [.mainContent: children])
} }
/// Update the stored content. /// Update the view storage.
/// - Parameters: /// - Parameters:
/// - storage: The storage to update. /// - storage: The storage to update.
/// - modifiers: Modify the views before updating.
/// - updateProperties: Whether to update the properties. /// - updateProperties: Whether to update the properties.
/// - type: The type of the renderable elements. /// - type: The type of the views.
/// - fields: More information. public func update<Data>(
public func update<RenderableType>( _ storage: ViewStorage,
_ storage: RenderableStorage, modifiers: [(AnyView) -> AnyView],
updateProperties: Bool, updateProperties: Bool,
type: RenderableType.Type, type: Data.Type
fields: [String: Any] ) where Data: ViewRenderData {
) {
guard let storages = storage.content[.mainContent] else { guard let storages = storage.content[.mainContent] else {
return return
} }
(content as [Renderable]).update(storages, updateProperties: updateProperties, type: type, fields: [:]) content.update(storages, modifiers: modifiers, updateProperties: updateProperties, type: type)
} }
} }

View File

@ -0,0 +1,72 @@
//
// MenuCollection.swift
// TermKitBackend
//
// Created by david-swift on 13.07.2024.
//
import TermKit
/// A menu is an item of a ``MenuBar``.
public struct MenuCollection: MenuContext.Widget, Wrapper {
/// The content of the menu.
var content: Body
/// Initialize a menu.
/// - Parameters:
/// - label: The menu's label, displayed in the menu bar.
/// - content: The content of the menu.
public init(@ViewBuilder content: @escaping () -> Body) {
self.content = content()
}
/// The view storage.
/// - Parameters:
/// - modifiers: Modify the views before updating.
/// - type: The type of the views.
/// - Returns: The view storage.
public func container<Data>(
modifiers: [(any AnyView) -> any AnyView],
type: Data.Type
) -> ViewStorage where Data: ViewRenderData {
var storages: [ViewStorage] = []
forEachMenu { menu in
storages.append(menu.container(modifiers: modifiers, type: type))
}
return .init(storages.compactMap { $0.pointer }, content: [.mainContent: storages])
}
/// Update the stored content.
/// - Parameters:
/// - storage: The storage to update.
/// - modifiers: Modify the views before updating.
/// - updateProperties: Whether to update the properties.
/// - type: The type of the views.
public func update<Data>(
_ storage: ViewStorage,
modifiers: [(AnyView) -> AnyView],
updateProperties: Bool,
type: Data.Type
) where Data: ViewRenderData {
// Menus cannot be updated
}
/// Run a function for each menu.
/// - Parameter closure: The function.
func forEachMenu(closure: @escaping (Menu) -> Void) {
var index = 0
for element in content {
if let menu = element as? Menu {
closure(menu)
index += 1
} else if let collection = element as? [Menu] {
for menu in collection {
closure(menu)
index += 1
}
}
}
}
}

View File

@ -0,0 +1,21 @@
//
// MenuContext.swift
// TermKitBackend
//
// Created by david-swift on 13.07.2024.
//
import TermKit
/// The menu items view context.
public enum MenuContext: ViewRenderData {
/// The type of the widgets.
public typealias WidgetType = Widget
/// The wrapper type.
public typealias WrapperType = MenuCollection
/// The type of the widgets.
public protocol Widget: Meta.Widget { }
}

View File

@ -1,47 +0,0 @@
//
// Button.swift
// TermKitBackend
//
// Created by david-swift on 07.07.2024.
//
import TermKit
extension Button: Renderable {
/// An identifier for the button's action.
var actionID: String { "action" }
/// The view storage.
/// - Parameters:
/// - type: The type of the renderable elements.
/// - fields: More information.
public func container<RenderableType>(type: RenderableType.Type, fields: [String: Any]) -> RenderableStorage {
let storage = RenderableStorage(nil)
let menuItem = MenuItem(title: label) {
(storage.fields[actionID] as? () -> Void)?()
}
storage.pointer = menuItem
storage.fields[actionID] = action
return storage
}
/// Update the stored content.
/// - Parameters:
/// - storage: The storage to update.
/// - updateProperties: Whether to update the properties.
/// - type: The type of the renderable elements.
/// - fields: More information.
public func update<RenderableType>(
_ storage: RenderableStorage,
updateProperties: Bool,
type: RenderableType.Type,
fields: [String: Any]
) {
guard updateProperties else {
return
}
storage.fields[actionID] = action
}
}

View File

@ -18,8 +18,6 @@ public class TermKitApp: AppStorage {
/// The wrapper type of the TermKit backend. /// The wrapper type of the TermKit backend.
public typealias WrapperType = VStack public typealias WrapperType = VStack
/// The application.
public var app: () -> any App
/// The app storage. /// The app storage.
public var storage: StandardAppStorage = .init() public var storage: StandardAppStorage = .init()
@ -27,9 +25,7 @@ public class TermKitApp: AppStorage {
/// - Parameters: /// - Parameters:
/// - id: The identifier. /// - id: The identifier.
/// - app: The application. /// - app: The application.
public required init(id: String, app: @escaping () -> any App) { public required init(id: String) { }
self.app = app
}
/// Execute the app. /// Execute the app.
/// - Parameter setup: Set the scene elements up. /// - Parameter setup: Set the scene elements up.

View File

@ -0,0 +1,16 @@
//
// TermKitMainView.swift
// TermKitBackend
//
// Created by david-swift on 13.07.2024.
//
/// The type of widgets of the TermKit backend.
public enum TermKitMainView: ViewRenderData {
/// The type of the widgets.
public typealias WidgetType = TermKitWidget
/// The wrapper type.
public typealias WrapperType = VStack
}

View File

@ -13,13 +13,13 @@ public struct MenuBar: TermKitSceneElement {
/// The identifier of the menu bar. /// The identifier of the menu bar.
public var id: String public var id: String
/// The menu bar's content. /// The menu bar's content.
var content: [Menu] var content: Body
/// Initialize the menu bar. /// Initialize the menu bar.
/// - Parameters: /// - Parameters:
/// - id: The identifier of the menu bar. /// - id: The identifier of the menu bar.
/// - content: The menu bar's content. /// - content: The menu bar's content.
public init(id: String = "main-menu", @Builder<Menu> content: () -> [Menu]) { public init(id: String = "main-menu", @ViewBuilder content: () -> Body) {
self.id = id self.id = id
self.content = content() self.content = content()
} }
@ -33,8 +33,9 @@ public struct MenuBar: TermKitSceneElement {
/// The scene storage. /// The scene storage.
/// - Parameter app: The app storage. /// - Parameter app: The app storage.
public func container<Storage>(app: Storage) -> SceneStorage where Storage: AppStorage { public func container<Storage>(app: Storage) -> SceneStorage where Storage: AppStorage {
let items = MenuCollection { content }.container(modifiers: [], type: MenuContext.self)
let menubar = TermKit.MenuBar( let menubar = TermKit.MenuBar(
menus: content.compactMap { $0.container(type: Menu.self, fields: [:]).pointer as? MenuBarItem } menus: items.pointer as? [TermKit.MenuBarItem] ?? []
) )
Task { Task {
try await Task.sleep(nanoseconds: 1) try await Task.sleep(nanoseconds: 1)

View File

@ -40,7 +40,7 @@ public struct Window: TermKitSceneElement {
let win = TermKit.Window(title) let win = TermKit.Window(title)
win.fill() win.fill()
Application.top.addSubview(win) Application.top.addSubview(win)
let viewStorage = content.storage(modifiers: [], type: Storage.self) let viewStorage = content.storage(modifiers: [], type: TermKitMainView.self)
if let pointer = viewStorage.pointer as? TermKit.View { if let pointer = viewStorage.pointer as? TermKit.View {
win.addSubview(pointer) win.addSubview(pointer)
} }
@ -62,7 +62,8 @@ public struct Window: TermKitSceneElement {
guard let viewStorage = storage.content[.mainContent]?.first else { guard let viewStorage = storage.content[.mainContent]?.first else {
return return
} }
content.updateStorage(viewStorage, modifiers: [], updateProperties: updateProperties, type: Storage.self) content
.updateStorage(viewStorage, modifiers: [], updateProperties: updateProperties, type: TermKitMainView.self)
Application.refresh() Application.refresh()
} }

View File

@ -8,13 +8,16 @@
import TermKit import TermKit
/// A simple button widget. /// A simple button widget.
public struct Button: TermKitWidget { public struct Button: TermKitWidget, ButtonContext.Widget, MenuContext.Widget {
/// The button's label. /// The button's label.
var label: String var label: String
/// The action. /// The action.
var action: () -> Void var action: () -> Void
/// The identifier for the action closure.
let actionID = "action"
/// Initialize a button. /// Initialize a button.
/// - Parameters: /// - Parameters:
/// - The button's label. /// - The button's label.
@ -28,10 +31,22 @@ public struct Button: TermKitWidget {
/// - Parameters: /// - Parameters:
/// - modifiers: Modify views before being updated. /// - modifiers: Modify views before being updated.
/// - type: The type of the app storage. /// - type: The type of the app storage.
public func container<Storage>( /// - Returns: The view storage.
public func container<Data>(
modifiers: [(any AnyView) -> any AnyView], modifiers: [(any AnyView) -> any AnyView],
type: Storage.Type type: Data.Type
) -> ViewStorage where Storage: AppStorage { ) -> ViewStorage where Data: ViewRenderData {
if type == MenuContext.self {
let storage = ViewStorage(nil)
let menuItem = MenuItem(title: label) {
(storage.fields[actionID] as? () -> Void)?()
}
storage.pointer = menuItem
storage.fields[actionID] = action
return storage
} else if type == ButtonContext.self {
return ViewStorage(self)
}
let button = TermKit.Button(label, clicked: action) let button = TermKit.Button(label, clicked: action)
return .init(button) return .init(button)
} }
@ -42,12 +57,15 @@ public struct Button: TermKitWidget {
/// - modifiers: Modify views before being updated /// - modifiers: Modify views before being updated
/// - updateProperties: Whether to update the view's properties. /// - updateProperties: Whether to update the view's properties.
/// - type: The type of the app storage. /// - type: The type of the app storage.
public func update<Storage>( public func update<Data>(
_ storage: ViewStorage, _ storage: ViewStorage,
modifiers: [(any AnyView) -> any AnyView], modifiers: [(any AnyView) -> any AnyView],
updateProperties: Bool, updateProperties: Bool,
type: Storage.Type type: Data.Type
) where Storage: AppStorage { ) where Data: ViewRenderData {
if type == MenuContext.self {
storage.fields[actionID] = action
}
guard let storage = storage.pointer as? TermKit.Button else { guard let storage = storage.pointer as? TermKit.Button else {
return return
} }

View File

@ -28,10 +28,11 @@ public struct Checkbox: TermKitWidget {
/// - Parameters: /// - Parameters:
/// - modifiers: Modify views before being updated. /// - modifiers: Modify views before being updated.
/// - type: The type of the app storage. /// - type: The type of the app storage.
public func container<Storage>( /// - Returns: The view storage.
public func container<Data>(
modifiers: [(any AnyView) -> any AnyView], modifiers: [(any AnyView) -> any AnyView],
type: Storage.Type type: Data.Type
) -> ViewStorage where Storage: AppStorage { ) -> ViewStorage where Data: ViewRenderData {
let button = TermKit.Checkbox(label, checked: isOn.wrappedValue) let button = TermKit.Checkbox(label, checked: isOn.wrappedValue)
button.toggled = { _ in button.toggled = { _ in
isOn.wrappedValue = button.checked isOn.wrappedValue = button.checked
@ -45,12 +46,12 @@ public struct Checkbox: TermKitWidget {
/// - modifiers: Modify views before being updated /// - modifiers: Modify views before being updated
/// - updateProperties: Whether to update the view's properties. /// - updateProperties: Whether to update the view's properties.
/// - type: The type of the app storage. /// - type: The type of the app storage.
public func update<Storage>( public func update<Data>(
_ storage: ViewStorage, _ storage: ViewStorage,
modifiers: [(any AnyView) -> any AnyView], modifiers: [(any AnyView) -> any AnyView],
updateProperties: Bool, updateProperties: Bool,
type: Storage.Type type: Data.Type
) where Storage: AppStorage { ) where Data: ViewRenderData {
guard let storage = storage.pointer as? TermKit.Checkbox, updateProperties else { guard let storage = storage.pointer as? TermKit.Checkbox, updateProperties else {
return return
} }

View File

@ -17,7 +17,7 @@ struct Box: TermKitWidget {
/// The signal. /// The signal.
var signal: Signal var signal: Signal
/// The buttons (info box if none). /// The buttons (info box if none).
var buttons: [Button] var buttons: Body
/// The content behind the box. /// The content behind the box.
var content: AnyView var content: AnyView
/// Whether it is an error box. /// Whether it is an error box.
@ -30,16 +30,15 @@ struct Box: TermKitWidget {
/// - Parameters: /// - Parameters:
/// - modifiers: Modify views before being updated. /// - modifiers: Modify views before being updated.
/// - type: The type of the app storage. /// - type: The type of the app storage.
func container<Storage>( /// - Returns: The view storage.
func container<Data>(
modifiers: [(any AnyView) -> any AnyView], modifiers: [(any AnyView) -> any AnyView],
type: Storage.Type type: Data.Type
) -> ViewStorage where Storage: AppStorage { ) -> ViewStorage where Data: ViewRenderData {
let storage = ViewStorage(nil) let storage = ViewStorage(nil)
let contentStorage = content.storage(modifiers: modifiers, type: type) let contentStorage = content.storage(modifiers: modifiers, type: type)
storage.pointer = contentStorage.pointer storage.pointer = contentStorage.pointer
storage.content = [.mainContent: [contentStorage]] return .init(contentStorage.pointer, content: [.mainContent: [contentStorage]])
storage.fields[boxButtonsID] = buttons
return storage
} }
/// Update the stored content. /// Update the stored content.
@ -48,16 +47,18 @@ struct Box: TermKitWidget {
/// - modifiers: Modify views before being updated /// - modifiers: Modify views before being updated
/// - updateProperties: Whether to update the view's properties. /// - updateProperties: Whether to update the view's properties.
/// - type: The type of the app storage. /// - type: The type of the app storage.
func update<Storage>( func update<Data>(
_ storage: ViewStorage, _ storage: ViewStorage,
modifiers: [(any AnyView) -> any AnyView], modifiers: [(any AnyView) -> any AnyView],
updateProperties: Bool, updateProperties: Bool,
type: Storage.Type type: Data.Type
) where Storage: AppStorage { ) where Data: ViewRenderData {
guard let storage = storage.content[.mainContent]?.first else { guard let storage = storage.content[.mainContent]?.first else {
return return
} }
content.updateStorage(storage, modifiers: modifiers, updateProperties: updateProperties, type: type) content.updateStorage(storage, modifiers: modifiers, updateProperties: updateProperties, type: type)
let buttons = ButtonCollection { self.buttons }
.storage(modifiers: modifiers, type: ButtonContext.self).pointer as? [Button] ?? []
storage.fields[boxButtonsID] = buttons storage.fields[boxButtonsID] = buttons
if signal.update { if signal.update {
if buttons.isEmpty { if buttons.isEmpty {
@ -89,7 +90,7 @@ extension AnyView {
_ title: String, _ title: String,
message: String, message: String,
signal: Signal, signal: Signal,
@Builder<Button> buttons: @escaping () -> [Button] @ViewBuilder buttons: @escaping () -> Body
) -> AnyView { ) -> AnyView {
Box(title: title, message: message, signal: signal, buttons: buttons(), content: self) Box(title: title, message: message, signal: signal, buttons: buttons(), content: self)
} }
@ -105,7 +106,7 @@ extension AnyView {
_ title: String, _ title: String,
message: String, message: String,
signal: Signal, signal: Signal,
@Builder<Button> buttons: @escaping () -> [Button] @ViewBuilder buttons: @escaping () -> Body
) -> AnyView { ) -> AnyView {
Box(title: title, message: message, signal: signal, buttons: buttons(), content: self, error: true) Box(title: title, message: message, signal: signal, buttons: buttons(), content: self, error: true)
} }

View File

@ -28,10 +28,11 @@ public struct Frame: TermKitWidget {
/// - Parameters: /// - Parameters:
/// - modifiers: Modify views before being updated. /// - modifiers: Modify views before being updated.
/// - type: The type of the app storage. /// - type: The type of the app storage.
public func container<Storage>( /// - Returns: The view storage.
public func container<Data>(
modifiers: [(any AnyView) -> any AnyView], modifiers: [(any AnyView) -> any AnyView],
type: Storage.Type type: Data.Type
) -> ViewStorage where Storage: AppStorage { ) -> ViewStorage where Data: ViewRenderData {
let frame = TermKit.Frame(label) let frame = TermKit.Frame(label)
let subview = view.storage(modifiers: modifiers, type: type) let subview = view.storage(modifiers: modifiers, type: type)
if let pointer = subview.pointer as? TermKit.View { if let pointer = subview.pointer as? TermKit.View {
@ -46,12 +47,12 @@ public struct Frame: TermKitWidget {
/// - modifiers: Modify views before being updated /// - modifiers: Modify views before being updated
/// - updateProperties: Whether to update the view's properties. /// - updateProperties: Whether to update the view's properties.
/// - type: The type of the app storage. /// - type: The type of the app storage.
public func update<Storage>( public func update<Data>(
_ storage: ViewStorage, _ storage: ViewStorage,
modifiers: [(any AnyView) -> any AnyView], modifiers: [(any AnyView) -> any AnyView],
updateProperties: Bool, updateProperties: Bool,
type: Storage.Type type: Data.Type
) where Storage: AppStorage { ) where Data: ViewRenderData {
if let storage = storage.content[.mainContent]?.first { if let storage = storage.content[.mainContent]?.first {
view.updateStorage(storage, modifiers: modifiers, updateProperties: updateProperties, type: type) view.updateStorage(storage, modifiers: modifiers, updateProperties: updateProperties, type: type)
} }

View File

@ -23,10 +23,10 @@ public struct HStack: Wrapper, TermKitWidget {
/// - Parameters: /// - Parameters:
/// - modifiers: Modify views before being updated. /// - modifiers: Modify views before being updated.
/// - type: The type of the app storage. /// - type: The type of the app storage.
public func container<Storage>( public func container<Data>(
modifiers: [(any AnyView) -> any AnyView], modifiers: [(any AnyView) -> any AnyView],
type: Storage.Type type: Data.Type
) -> ViewStorage where Storage: AppStorage { ) -> ViewStorage where Data: ViewRenderData {
let storages = content.storages(modifiers: modifiers, type: type) let storages = content.storages(modifiers: modifiers, type: type)
if storages.count == 1 { if storages.count == 1 {
return .init(storages[0].pointer, content: [.mainContent: storages]) return .init(storages[0].pointer, content: [.mainContent: storages])
@ -49,12 +49,12 @@ public struct HStack: Wrapper, TermKitWidget {
/// - modifiers: Modify views before being updated /// - modifiers: Modify views before being updated
/// - updateProperties: Whether to update the view's properties. /// - updateProperties: Whether to update the view's properties.
/// - type: The type of the app storage. /// - type: The type of the app storage.
public func update<Storage>( public func update<Data>(
_ storage: ViewStorage, _ storage: ViewStorage,
modifiers: [(any AnyView) -> any AnyView], modifiers: [(any AnyView) -> any AnyView],
updateProperties: Bool, updateProperties: Bool,
type: Storage.Type type: Data.Type
) where Storage: AppStorage { ) where Data: ViewRenderData {
guard let storages = storage.content[.mainContent] else { guard let storages = storage.content[.mainContent] else {
return return
} }

View File

@ -23,10 +23,11 @@ public struct Label: TermKitWidget {
/// - Parameters: /// - Parameters:
/// - modifiers: Modify views before being updated. /// - modifiers: Modify views before being updated.
/// - type: The type of the app storage. /// - type: The type of the app storage.
public func container<Storage>( /// - Returns: The view storage.
public func container<Data>(
modifiers: [(any AnyView) -> any AnyView], modifiers: [(any AnyView) -> any AnyView],
type: Storage.Type type: Data.Type
) -> ViewStorage where Storage: AppStorage { ) -> ViewStorage where Data: ViewRenderData {
let button = TermKit.Label(label) let button = TermKit.Label(label)
return .init(button) return .init(button)
} }
@ -37,12 +38,12 @@ public struct Label: TermKitWidget {
/// - modifiers: Modify views before being updated /// - modifiers: Modify views before being updated
/// - updateProperties: Whether to update the view's properties. /// - updateProperties: Whether to update the view's properties.
/// - type: The type of the app storage. /// - type: The type of the app storage.
public func update<Storage>( public func update<Data>(
_ storage: ViewStorage, _ storage: ViewStorage,
modifiers: [(any AnyView) -> any AnyView], modifiers: [(any AnyView) -> any AnyView],
updateProperties: Bool, updateProperties: Bool,
type: Storage.Type type: Data.Type
) where Storage: AppStorage { ) where Data: ViewRenderData {
guard let storage = storage.pointer as? TermKit.Label, updateProperties else { guard let storage = storage.pointer as? TermKit.Label, updateProperties else {
return return
} }

View File

@ -28,10 +28,11 @@ public struct ListView<Element>: TermKitWidget where Element: CustomStringConver
/// - Parameters: /// - Parameters:
/// - modifiers: Modify views before being updated. /// - modifiers: Modify views before being updated.
/// - type: The type of the app storage. /// - type: The type of the app storage.
public func container<Storage>( /// - Returns: The view storage.
public func container<Data>(
modifiers: [(any AnyView) -> any AnyView], modifiers: [(any AnyView) -> any AnyView],
type: Storage.Type type: Data.Type
) -> ViewStorage where Storage: AppStorage { ) -> ViewStorage where Data: ViewRenderData {
let list = TermKit.ListView(items: items.map { $0.description }) let list = TermKit.ListView(items: items.map { $0.description })
setClosure(list: list) setClosure(list: list)
return .init(list) return .init(list)
@ -43,12 +44,12 @@ public struct ListView<Element>: TermKitWidget where Element: CustomStringConver
/// - modifiers: Modify views before being updated /// - modifiers: Modify views before being updated
/// - updateProperties: Whether to update the view's properties. /// - updateProperties: Whether to update the view's properties.
/// - type: The type of the app storage. /// - type: The type of the app storage.
public func update<Storage>( public func update<Data>(
_ storage: ViewStorage, _ storage: ViewStorage,
modifiers: [(any AnyView) -> any AnyView], modifiers: [(any AnyView) -> any AnyView],
updateProperties: Bool, updateProperties: Bool,
type: Storage.Type type: Data.Type
) where Storage: AppStorage { ) where Data: ViewRenderData {
guard let list = storage.pointer as? TermKit.ListView else { guard let list = storage.pointer as? TermKit.ListView else {
return return
} }

View File

@ -28,10 +28,11 @@ public struct ProgressBar: TermKitWidget {
/// - Parameters: /// - Parameters:
/// - modifiers: Modify views before being updated. /// - modifiers: Modify views before being updated.
/// - type: The type of the app storage. /// - type: The type of the app storage.
public func container<Storage>( /// - Returns: The view storage.
public func container<Data>(
modifiers: [(any AnyView) -> any AnyView], modifiers: [(any AnyView) -> any AnyView],
type: Storage.Type type: Data.Type
) -> ViewStorage where Storage: AppStorage { ) -> ViewStorage where Data: ViewRenderData {
let bar = TermKit.ProgressBar() let bar = TermKit.ProgressBar()
bar.fraction = .init(value / max) bar.fraction = .init(value / max)
return .init(bar) return .init(bar)
@ -43,12 +44,12 @@ public struct ProgressBar: TermKitWidget {
/// - modifiers: Modify views before being updated /// - modifiers: Modify views before being updated
/// - updateProperties: Whether to update the view's properties. /// - updateProperties: Whether to update the view's properties.
/// - type: The type of the app storage. /// - type: The type of the app storage.
public func update<Storage>( public func update<Data>(
_ storage: ViewStorage, _ storage: ViewStorage,
modifiers: [(any AnyView) -> any AnyView], modifiers: [(any AnyView) -> any AnyView],
updateProperties: Bool, updateProperties: Bool,
type: Storage.Type type: Data.Type
) where Storage: AppStorage { ) where Data: ViewRenderData {
guard let storage = storage.pointer as? TermKit.ProgressBar, updateProperties else { guard let storage = storage.pointer as? TermKit.ProgressBar, updateProperties else {
return return
} }

View File

@ -23,10 +23,11 @@ public struct ScrollView: TermKitWidget {
/// - Parameters: /// - Parameters:
/// - modifiers: Modify views before being updated. /// - modifiers: Modify views before being updated.
/// - type: The type of the app storage. /// - type: The type of the app storage.
public func container<Storage>( /// - Returns: The view storage.
public func container<Data>(
modifiers: [(any AnyView) -> any AnyView], modifiers: [(any AnyView) -> any AnyView],
type: Storage.Type type: Data.Type
) -> ViewStorage where Storage: AppStorage { ) -> ViewStorage where Data: ViewRenderData {
let storages = content.storages(modifiers: modifiers, type: type) let storages = content.storages(modifiers: modifiers, type: type)
if storages.count == 1 { if storages.count == 1 {
return .init(storages[0].pointer, content: [.mainContent: storages]) return .init(storages[0].pointer, content: [.mainContent: storages])
@ -49,12 +50,12 @@ public struct ScrollView: TermKitWidget {
/// - modifiers: Modify views before being updated /// - modifiers: Modify views before being updated
/// - updateProperties: Whether to update the view's properties. /// - updateProperties: Whether to update the view's properties.
/// - type: The type of the app storage. /// - type: The type of the app storage.
public func update<Storage>( public func update<Data>(
_ storage: ViewStorage, _ storage: ViewStorage,
modifiers: [(any AnyView) -> any AnyView], modifiers: [(any AnyView) -> any AnyView],
updateProperties: Bool, updateProperties: Bool,
type: Storage.Type type: Data.Type
) where Storage: AppStorage { ) where Data: ViewRenderData {
guard let storages = storage.content[.mainContent] else { guard let storages = storage.content[.mainContent] else {
return return
} }

View File

@ -28,10 +28,11 @@ public struct TextField: TermKitWidget {
/// - Parameters: /// - Parameters:
/// - modifiers: Modify views before being updated. /// - modifiers: Modify views before being updated.
/// - type: The type of the app storage. /// - type: The type of the app storage.
public func container<Storage>( /// - Returns: The view storage.
public func container<Data>(
modifiers: [(any AnyView) -> any AnyView], modifiers: [(any AnyView) -> any AnyView],
type: Storage.Type type: Data.Type
) -> ViewStorage where Storage: AppStorage { ) -> ViewStorage where Data: ViewRenderData {
let field = TermKit.TextField(text.wrappedValue) let field = TermKit.TextField(text.wrappedValue)
let storage = ViewStorage(field) let storage = ViewStorage(field)
field.secret = secret field.secret = secret
@ -52,12 +53,12 @@ public struct TextField: TermKitWidget {
/// - modifiers: Modify views before being updated /// - modifiers: Modify views before being updated
/// - updateProperties: Whether to update the view's properties. /// - updateProperties: Whether to update the view's properties.
/// - type: The type of the app storage. /// - type: The type of the app storage.
public func update<Storage>( public func update<Data>(
_ storage: ViewStorage, _ storage: ViewStorage,
modifiers: [(any AnyView) -> any AnyView], modifiers: [(any AnyView) -> any AnyView],
updateProperties: Bool, updateProperties: Bool,
type: Storage.Type type: Data.Type
) where Storage: AppStorage { ) where Data: ViewRenderData {
guard let field = storage.pointer as? TermKit.TextField else { guard let field = storage.pointer as? TermKit.TextField else {
return return
} }

View File

@ -23,10 +23,10 @@ public struct VStack: Wrapper, TermKitWidget {
/// - Parameters: /// - Parameters:
/// - modifiers: Modify views before being updated. /// - modifiers: Modify views before being updated.
/// - type: The type of the app storage. /// - type: The type of the app storage.
public func container<Storage>( public func container<Data>(
modifiers: [(any AnyView) -> any AnyView], modifiers: [(any AnyView) -> any AnyView],
type: Storage.Type type: Data.Type
) -> ViewStorage where Storage: AppStorage { ) -> ViewStorage where Data: ViewRenderData {
let storages = content.storages(modifiers: modifiers, type: type) let storages = content.storages(modifiers: modifiers, type: type)
if storages.count == 1 { if storages.count == 1 {
return .init(storages[0].pointer, content: [.mainContent: storages]) return .init(storages[0].pointer, content: [.mainContent: storages])
@ -49,12 +49,12 @@ public struct VStack: Wrapper, TermKitWidget {
/// - modifiers: Modify views before being updated /// - modifiers: Modify views before being updated
/// - updateProperties: Whether to update the view's properties. /// - updateProperties: Whether to update the view's properties.
/// - type: The type of the app storage. /// - type: The type of the app storage.
public func update<Storage>( public func update<Data>(
_ storage: ViewStorage, _ storage: ViewStorage,
modifiers: [(any AnyView) -> any AnyView], modifiers: [(any AnyView) -> any AnyView],
updateProperties: Bool, updateProperties: Bool,
type: Storage.Type type: Data.Type
) where Storage: AppStorage { ) where Data: ViewRenderData {
guard let storages = storage.content[.mainContent] else { guard let storages = storage.content[.mainContent] else {
return return
} }

View File

@ -23,10 +23,10 @@ public struct ZStack: Wrapper, TermKitWidget {
/// - Parameters: /// - Parameters:
/// - modifiers: Modify views before being updated. /// - modifiers: Modify views before being updated.
/// - type: The type of the app storage. /// - type: The type of the app storage.
public func container<Storage>( public func container<Data>(
modifiers: [(any AnyView) -> any AnyView], modifiers: [(any AnyView) -> any AnyView],
type: Storage.Type type: Data.Type
) -> ViewStorage where Storage: AppStorage { ) -> ViewStorage where Data: ViewRenderData {
let storages = content.reversed().storages(modifiers: modifiers, type: type) let storages = content.reversed().storages(modifiers: modifiers, type: type)
if storages.count == 1 { if storages.count == 1 {
return .init(storages[0].pointer, content: [.mainContent: storages]) return .init(storages[0].pointer, content: [.mainContent: storages])
@ -46,12 +46,12 @@ public struct ZStack: Wrapper, TermKitWidget {
/// - modifiers: Modify views before being updated /// - modifiers: Modify views before being updated
/// - updateProperties: Whether to update the view's properties. /// - updateProperties: Whether to update the view's properties.
/// - type: The type of the app storage. /// - type: The type of the app storage.
public func update<Storage>( public func update<Data>(
_ storage: ViewStorage, _ storage: ViewStorage,
modifiers: [(any AnyView) -> any AnyView], modifiers: [(any AnyView) -> any AnyView],
updateProperties: Bool, updateProperties: Bool,
type: Storage.Type type: Data.Type
) where Storage: AppStorage { ) where Data: ViewRenderData {
guard let storages = storage.content[.mainContent] else { guard let storages = storage.content[.mainContent] else {
return return
} }

View File

@ -33,20 +33,25 @@ struct TestApp: App {
var menuBar: MenuBar { var menuBar: MenuBar {
.init { .init {
Menu("File") { fileMenu
Button("_About TermKitBackend") {
about.signal()
}
Button("_Quit") {
app.quit()
}
}
Menu("_Actions") { Menu("_Actions") {
Button("_Hello, world!") { } Button("_Hello, world!") { }
} }
} }
} }
@ViewBuilder
var fileMenu: Body {
Menu("File") {
Button("_About TermKitBackend") {
about.signal()
}
Button("_Quit") {
app.quit()
}
}
}
var aboutInfo: String { var aboutInfo: String {
""" """
This is a sample backend for the Meta package of the Aparoksha project. This is a sample backend for the Meta package of the Aparoksha project.