Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
c16b8be
add documentation for parameters and return values, document various …
kaascevich Dec 28, 2025
1eb4aa7
add some more missing documentation, fix broken doc links
kaascevich Dec 29, 2025
2634179
add a high-level overview of SwiftCrossUI's implementation
kaascevich Dec 29, 2025
c0cb763
add some documentation to state-related things and views
kaascevich Dec 30, 2025
de2f9f9
add some more docs
kaascevich Dec 30, 2025
9b10014
Merge branch 'main' into parameter-documentation
kaascevich Jan 1, 2026
5fd5356
document the layout performance updates
kaascevich Jan 1, 2026
fff7fbe
document the dynamic property system
kaascevich Jan 1, 2026
15d302a
rename `Environment.md` to `The environment.md` to resolve conflict w…
kaascevich Jan 1, 2026
40105fd
improve documentation for `Binding`
kaascevich Jan 1, 2026
2cd0c8b
Merge branch 'stackotter:main' into parameter-documentation
kaascevich Jan 2, 2026
6d96449
Merge branch 'stackotter:main' into parameter-documentation
kaascevich Jan 2, 2026
3ddae64
Merge branch 'main' into parameter-documentation
kaascevich Jan 5, 2026
f4355a7
update deprecated declarations
kaascevich Jan 5, 2026
3e28ac2
Merge branch 'main' into parameter-documentation
kaascevich Jan 6, 2026
c64626f
Merge branch 'main' into parameter-documentation
kaascevich Jan 6, 2026
fdaf3c1
Merge branch 'main' into parameter-documentation
kaascevich Jan 10, 2026
77ccff5
continue documenting public APIs
kaascevich Jan 11, 2026
f8fd6c6
Merge branch 'main' into parameter-documentation
kaascevich Jan 11, 2026
6c3f6dd
Merge branch 'main' into parameter-documentation
kaascevich Jan 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Sources/AppKitBackend/NSViewRepresentable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public protocol NSViewRepresentable: View where Content == Never {
///
/// This method is called after all AppKit lifecycle methods, such as
/// `nsView.didMoveToSuperview()`. The default implementation does nothing.
///
/// - Parameters:
/// - nsView: The view being dismantled.
/// - coordinator: The coordinator.
Expand Down
22 changes: 16 additions & 6 deletions Sources/SwiftCrossUI/Backend/AnyWidget.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,23 @@
/// a concrete type before use (removing the need to type-erase specific
/// methods or anything like that).
public class AnyWidget {
/// The wrapped widget
/// The wrapped widget.
var widget: Any

/// Erases the specific type of a widget (to allow storage without propagating
/// the selected backend type through the whole type system).
///
/// - Parameter widget: The widget to type-erase.
public init(_ widget: Any) {
self.widget = widget
}

/// Converts the widget back to its original concrete type. If the requested
/// type doesn't match its original type then the method will crash.
/// Converts the widget back to its original concrete type.
///
/// - Precondition: `backend` is the same backend used to create the widget.
///
/// - Parameter backend: The backend to use to convert the widget.
/// - Returns: The widget as the backend's widget type.
public func concreteWidget<Backend: AppBackend>(
for backend: Backend.Type
) -> Backend.Widget {
Expand All @@ -30,9 +36,13 @@ public class AnyWidget {
return widget
}

/// Converts the widget back to its original concrete type. If the requested
/// type doesn't match its original type then the method will crash. Often
/// more concise than using ``AnyWidget/concreteWidget(for:)``.
/// Converts the widget back to its original concrete type.
///
/// Often more concise than using ``AnyWidget/concreteWidget(for:)``.
///
/// - Precondition: `T` is the same type as the widget.
///
/// - Returns: The converted widget.
public func into<T>() -> T {
guard let widget = widget as? T else {
fatalError(
Expand Down
996 changes: 753 additions & 243 deletions Sources/SwiftCrossUI/Backend/AppBackend.swift

Large diffs are not rendered by default.

10 changes: 7 additions & 3 deletions Sources/SwiftCrossUI/Backend/CellPosition.swift
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
/// The position of a cell in a table (with row and column numbers starting from 0).
public struct CellPosition {
/// The row number starting from 0.
/// The row number (starting from 0).
public var row: Int
/// The column number starting from 0.
/// The column number (starting from 0).
public var column: Int

/// Creates a cell position from a row and column number (starting from 0).
/// Creates a cell position from a row and column number.
///
/// - Parameters:
/// - row: The row number (starting from 0).
/// - column: The column number (starting from 0).
public init(_ row: Int, _ column: Int) {
self.row = row
self.column = column
Expand Down
3 changes: 3 additions & 0 deletions Sources/SwiftCrossUI/Backend/DialogResult.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
/// The result of a dialog.
public enum DialogResult<T> {
/// The dialog succeeded with a result value.
case success(T)
/// The dialog was cancelled.
case cancelled
}
2 changes: 2 additions & 0 deletions Sources/SwiftCrossUI/Backend/FileChooserResult.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import Foundation
/// The result returned when a user either selects a file or dismisses the
/// file chooser dialog.
public enum FileChooserResult {
/// The user selected a file at the given URL.
case success(URL)
/// The user closed the file chooser dialog.
case cancelled
}
12 changes: 12 additions & 0 deletions Sources/SwiftCrossUI/Backend/FileDialogOptions.swift
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
import Foundation

/// Options for file dialogs.
public struct FileDialogOptions {
/// The dialog title.
public var title: String
/// The label of the primary button.
public var defaultButtonLabel: String
/// The content types allowed by the dialog.
public var allowedContentTypes: [ContentType]
/// Whether to show hidden files.
///
/// The definition of "hidden" is platform-specific, but typically involves
/// a special metadata flag and/or a leading period in the file name.
public var showHiddenFiles: Bool
/// Whether to allow selecting items that are not one of the types specified
/// in ``allowedContentTypes``.
public var allowOtherContentTypes: Bool
/// The directory the file dialog starts in. If `nil`, the starting
/// directory is backend-specific.
public var initialDirectory: URL?
}
15 changes: 9 additions & 6 deletions Sources/SwiftCrossUI/Backend/MenuImplementationStyle.swift
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
/// How a backend implements popover menus.
///
/// Regardless of implementation style, backends are expected to implement
/// ``AppBackend/createPopoverMenu()``, ``AppBackend/updatePopoverMenu(_:content:environment:)``,
/// and ``AppBackend/updateButton(_:label:action:environment:)``.
/// ``AppBackend/createPopoverMenu()-9qdz1``,
/// ``AppBackend/updatePopoverMenu(_:content:environment:)-6cws8``, and
/// ``AppBackend/updateButton(_:label:environment:action:)-2n3zk``.
public enum MenuImplementationStyle {
/// The backend can show popover menus arbitrarily.
///
/// Backends that use this style must implement
/// ``AppBackend/showPopoverMenu(_:at:relativeTo:closeHandler:)``. For these backends,
/// ``AppBackend/createPopoverMenu()`` is not called until after the button is tapped.
/// ``AppBackend/showPopoverMenu(_:at:relativeTo:closeHandler:)-3p1ct``. For
/// these backends, ``AppBackend/createPopoverMenu()-9qdz1`` is not called
/// until after the button is tapped.
case dynamicPopover
/// The backend requires menus to be constructed and attached to buttons ahead-of-time.
/// The backend requires menus to be constructed and attached to buttons
/// ahead of time.
///
/// Backends that use this style must implement
/// ``AppBackend/updateButton(_:label:menu:environment:)``.
/// ``AppBackend/updateButton(_:label:menu:environment:)-17ypq``.
case menuButton
}
5 changes: 5 additions & 0 deletions Sources/SwiftCrossUI/Backend/OpenDialogOptions.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
/// Options for 'open file' dialogs.
public struct OpenDialogOptions {
/// Whether to allow selecting files.
public var allowSelectingFiles: Bool
/// Whether to allow selecting directories (folders).
public var allowSelectingDirectories: Bool
/// Whether to allow multiple selections. If `false`, the user can only
/// select one item.
public var allowMultipleSelections: Bool
}
18 changes: 15 additions & 3 deletions Sources/SwiftCrossUI/Backend/ResolvedMenu.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,26 @@ public struct ResolvedMenu {
/// The menu's items.
public var items: [Item]

/// Memberwise initializer.
/// Creates a ``ResolvedMenu`` instance.
///
/// - Parameter items: The menu's items.
public init(items: [ResolvedMenu.Item]) {
self.items = items
}

/// A menu item.
public enum Item {
/// A button. A `nil` action means that the button is disabled.
/// A button.
///
/// - Parameters:
/// - label: The button's label.
/// - action: The action to perform when the button is activated. `nil`
/// means the button is disabled.
case button(_ label: String, _ action: (@MainActor () -> Void)?)
/// A toggle that manages boolean state.
///
/// Usually appears as a checkbox.
///
/// - Parameters:
/// - label: The toggle's label.
/// - value: The toggle's current state.
Expand All @@ -38,7 +46,11 @@ public struct ResolvedMenu {
/// The menu displayed when the submenu gets activated.
public var content: ResolvedMenu

/// Memberwise initializer.
/// Creates a ``Submenu`` instance.
///
/// - Parameters:
/// - label: The label of the submenu's entry in its parent menu.
/// - content: The menu displayed when the submenu gets activated.
public init(label: String, content: ResolvedMenu) {
self.label = label
self.content = content
Expand Down
5 changes: 5 additions & 0 deletions Sources/SwiftCrossUI/Backend/SaveDialogOptions.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
/// Options for 'save file' dialogs.
public struct SaveDialogOptions {
/// The placeholder label for the file name field. If `nil`, the label is
/// set to a backend-specific value.
public var nameFieldLabel: String?
/// The default file name. If `nil`, the file name will typically be empty,
/// but can be any backend-specific value.
public var defaultFileName: String?
}
6 changes: 4 additions & 2 deletions Sources/SwiftCrossUI/Builders/AlertActionsBuilder.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
/// A builder for `[AlertAction]`.
/// A result builder for `[AlertAction]`.
@resultBuilder
public struct AlertActionsBuilder {
/// If no actions are provided, return a default "OK" action.
/// Called when no actions are provided.
///
/// - Returns: A default "OK" action.
public static func buildBlock() -> [AlertAction] {
[.default]
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftCrossUI/Builders/CommandsBuilder.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/// A builder for ``Commands``.
/// A result builder for ``Commands``.
@resultBuilder
public struct CommandsBuilder {
public static func buildBlock(_ menus: CommandMenu...) -> Commands {
Expand Down
4 changes: 2 additions & 2 deletions Sources/SwiftCrossUI/Builders/MenuItemsBuilder.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/// A builder for ``[MenuItem]``.
/// A result builder for `[MenuItem]`.
@resultBuilder
public struct MenuItemsBuilder {
public static func buildBlock() -> [MenuItem] {
Expand Down Expand Up @@ -96,7 +96,7 @@ public struct MenuItemsBuilder {
Block(items: component)
}

/// An implementation detail of ``MenuItemBuilder``'s support for
/// An implementation detail of ``MenuItemsBuilder``'s support for
/// `if`/`else if`/`else` blocks.
public struct Block {
var items: [MenuItem]
Expand Down
19 changes: 14 additions & 5 deletions Sources/SwiftCrossUI/Environment/Actions/AlertAction.swift
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
/// An alert action button. Only backends should interface with this type
/// directly. See ``View/alert(_:isPresented:actions:message:)``.
/// An alert action button.
///
/// This exists to avoid having to expose internal details of ``Button``, since
/// breaking ``Button``'s API would have much more wide-reaching impacts than
/// breaking this single-purpose API.
/// Only backends should interface with this type directly. This exists to avoid
/// having to expose internal details of ``Button``, since breaking `Button`'s
/// API would have much more wide-reaching impacts than breaking this
/// single-purpose API.
///
/// # See Also
/// - ``View/alert(_:isPresented:actions:)``
public struct AlertAction: Sendable {
/// The default alert action.
///
/// Consists of a button labeled "OK" with no action (other than dismissing
/// the alert, which is implicit).
public static let `default` = AlertAction(label: "OK", action: {})

/// The button's label.
public var label: String
/// The button's action.
public var action: @MainActor @Sendable () -> Void
}
9 changes: 7 additions & 2 deletions Sources/SwiftCrossUI/Environment/Actions/OpenURLAction.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import Foundation

/// Opens a URL with the default application. May present an application picker
/// if multiple applications are registered for the given URL protocol.
/// Opens a URL with the default application.
///
/// May present an application picker if multiple applications are registered
/// for the given URL protocol.
@MainActor
public struct OpenURLAction {
let action: (URL) -> Void
Expand All @@ -21,6 +23,9 @@ public struct OpenURLAction {
}
}

/// Opens a URL with the default application.
///
/// - Parameter url: The URL to open.
public func callAsFunction(_ url: URL) {
action(url)
}
Expand Down
17 changes: 12 additions & 5 deletions Sources/SwiftCrossUI/Environment/Actions/PresentAlertAction.swift
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
/// Presents an alert to the user. Returns once an action has been selected and
/// the corresponding action handler has been run. Returns the index of the
/// selected action. By default, the alert will have a single button labelled
/// `OK`. All buttons will dismiss the alert even if you provide your own
/// actions.
/// Presents an alert to the user.
///
/// Returns once an action has been selected and the corresponding action
/// handler has been run. Returns the index of the selected action. By default,
/// the alert will have a single button labelled "OK". All buttons will dismiss
/// the alert even if you provide your own actions.
@MainActor
public struct PresentAlertAction {
let environment: EnvironmentValues

/// Presents an alert to the user.
///
/// - Parameters:
/// - title: The title of the alert.
/// - actions: A list of actions the user can perform.
/// - Returns: The index of the chosen action.
@discardableResult
public func callAsFunction(
_ title: String,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,28 @@
import Foundation

/// Presents a 'Save file' dialog fit for selecting a save destination. Returns
/// `nil` if the user cancels the operation.
/// Presents a 'Save file' dialog fit for selecting a save destination.
public struct PresentFileSaveDialogAction: Sendable {
let backend: any AppBackend
let window: MainActorBox<Any?>

/// Presents a 'Save file' dialog fit for selecting a save destination.
///
/// - Parameters:
/// - title: The dialog's title. Defaults to "Save".
/// - message: The dialog's message. Defaults to an empty string.
/// - defaultButtonLabel: The label for the dialog's default button.
/// Defaults to "Save".
/// - initialDirectory: The directory to start the dialog in. Defaults
/// to `nil`, which lets the backend choose (usually it'll be the
/// app's current working directory and/or the directory where the
/// previous dialog was dismissed in).
/// - showHiddenFiles: Whether to show hidden files. Defaults to `false`.
/// - nameFieldLabel: The placeholder label for the file name field.
/// Defaults to `nil`, which uses the backend-specific default.
/// - defaultFileName: The default file name. Defaults to `nil`, which
/// uses the backend-specific default.
/// - Returns: The URL of the user's chosen save destination, or `nil` if
/// the user cancelled the dialog.
public func callAsFunction(
title: String = "Save",
message: String = "",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,33 @@
import Foundation

/// Presents an 'Open file' dialog fit for selecting a single file. Some
/// backends only allow selecting either files or directories but not both
/// in a single dialog. Returns `nil` if the user cancels the operation.
/// Presents an 'Open file' dialog fit for selecting a single file.
@available(tvOS, unavailable, message: "tvOS does not provide file system access")
public struct PresentSingleFileOpenDialogAction: Sendable {
let backend: any AppBackend
let window: MainActorBox<Any?>

/// Presents an 'Open file' dialog fit for selecting a single file.
///
/// - Important: Some backends will only enable _either_ files or
/// directories for selection, but won't enable both types in a
/// single dialog. (TODO: which backends?)
///
/// - Parameters:
/// - title: The dialog's title. Defaults to "Open".
/// - message: The dialog's message. Defaults to an empty string.
/// - defaultButtonLabel: The label for the dialog's default button.
/// Defaults to "Open".
/// - initialDirectory: The directory to start the dialog in. Defaults
/// to `nil`, which lets the backend choose (usually it'll be the
/// app's current working directory and/or the directory where the
/// previous dialog was dismissed in).
/// - showHiddenFiles: Whether to show hidden files. Defaults to `false`.
/// - allowSelectingFiles: Whether to allow selecting files (as opposed
/// to directories) in the dialog. Defaults to `true`.
/// - allowSelectingDirectories: Whether to allow selecting directories
/// in the dialog. Defaults to `true`.
/// - Returns: The URL of the user's chosen file, or `nil` if the user
/// cancelled the dialog.
public func callAsFunction(
title: String = "Open",
message: String = "",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import Foundation

/// Reveals a file in the system's file manager. This opens
/// the file's enclosing directory and highlighting the file.
/// Reveals a file in the system's file manager.
@MainActor
public struct RevealFileAction {
let action: (URL) -> Void
Expand All @@ -25,6 +24,11 @@ public struct RevealFileAction {
}
}

/// Reveals a file in the system's file manager.
///
/// This opens the file's enclosing directory and highlights the file.
///
/// - Parameter file: The file to reveal.
public func callAsFunction(_ file: URL) {
action(file)
}
Expand Down
Loading
Loading