diff --git a/Package.resolved b/Package.resolved index bb082b0cc..c33879ff3 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,12 +1,13 @@ { + "originHash" : "0f982a9a5aaa830e0f6007c6ab531cd25dc6cda4fc85a52cec7f5d6741d54c28", "pins" : [ { - "identity" : "liveview-native-core-swift", + "identity" : "liveview-native-core", "kind" : "remoteSourceControl", - "location" : "https://github.com/liveview-native/liveview-native-core-swift.git", + "location" : "https://github.com/liveview-native/liveview-native-core", "state" : { - "revision" : "339594b395938e38f1fb2216a31c8791030ec9ba", - "version" : "0.2.1" + "revision" : "b3fd4e2d49a58e95aa2f8d46af3bb67a8193aa97", + "version" : "0.4.0-alpha-11" } }, { @@ -14,8 +15,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-argument-parser", "state" : { - "revision" : "fee6933f37fde9a5e12a1e4aeaa93fe60116ff2a", - "version" : "1.2.2" + "revision" : "41982a3656a71c768319979febd796c6fd111d5c", + "version" : "1.5.0" } }, { @@ -23,8 +24,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-async-algorithms", "state" : { - "revision" : "9cfed92b026c524674ed869a4ff2dcfdeedf8a2a", - "version" : "0.1.0" + "revision" : "5c8bd186f48c16af0775972700626f0b74588278", + "version" : "1.0.2" } }, { @@ -32,8 +33,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/swift-case-paths", "state" : { - "revision" : "40773cbaf8d71ed5357f297b1ba4073f5b24faaa", - "version" : "1.1.0" + "revision" : "bc92c4b27f9a84bfb498cdbfdf35d5a357e9161f", + "version" : "1.5.6" } }, { @@ -50,8 +51,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-collections.git", "state" : { - "revision" : "937e904258d22af6e447a0b72c0bc67583ef64a2", - "version" : "1.0.4" + "revision" : "671108c96644956dddcd89dd59c203dcdb36cec7", + "version" : "1.1.4" } }, { @@ -77,8 +78,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/swiftlang/swift-syntax.git", "state" : { - "revision" : "64889f0c732f210a935a0ad7cda38f77f876262d", - "version" : "509.1.1" + "revision" : "0687f71944021d616d34d922343dcef086855920", + "version" : "600.0.1" } }, { @@ -104,10 +105,10 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/xctest-dynamic-overlay", "state" : { - "revision" : "23cbf2294e350076ea4dbd7d5d047c1e76b03631", - "version" : "1.0.2" + "revision" : "770f990d3e4eececb57ac04a6076e22f8c97daeb", + "version" : "1.4.2" } } ], - "version" : 2 + "version" : 3 } diff --git a/Package.swift b/Package.swift index 39e451c3d..2169233e1 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version: 5.9 +// swift-tools-version: 6.0 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription @@ -26,13 +26,13 @@ let package = Package( // Dependencies declare other packages that this package depends on. .package(url: "https://github.com/scinfu/SwiftSoup.git", from: "2.3.2"), .package(url: "https://github.com/davidstump/SwiftPhoenixClient.git", .upToNextMinor(from: "5.3.2")), - .package(url: "https://github.com/apple/swift-async-algorithms", from: "0.1.0"), - .package(url: "https://github.com/liveview-native/liveview-native-core-swift.git", exact: "0.2.1"), + .package(url: "https://github.com/apple/swift-async-algorithms", from: "1.0.0"), + .package(url: "https://github.com/liveview-native/liveview-native-core", exact: "0.4.0-alpha-11"), - .package(url: "https://github.com/apple/swift-argument-parser", from: "1.2.2"), + .package(url: "https://github.com/apple/swift-argument-parser", from: "1.5.0"), .package(url: "https://github.com/swiftlang/swift-markdown.git", from: "0.2.0"), - .package(url: "https://github.com/swiftlang/swift-syntax.git", from: "509.0.2"), + .package(url: "https://github.com/swiftlang/swift-syntax.git", from: "600.0.1"), .package(url: "https://github.com/pointfreeco/swift-parsing", from: "0.13.0"), ], @@ -45,7 +45,7 @@ let package = Package( "SwiftSoup", "SwiftPhoenixClient", .product(name: "AsyncAlgorithms", package: "swift-async-algorithms"), - .product(name: "LiveViewNativeCore", package: "liveview-native-core-swift"), + .product(name: "LiveViewNativeCore", package: "liveview-native-core"), "LiveViewNativeMacros", "LiveViewNativeStylesheet" ], @@ -146,7 +146,7 @@ let package = Package( name: "LiveViewNativeStylesheet", dependencies: [ "LiveViewNativeStylesheetMacros", - .product(name: "LiveViewNativeCore", package: "liveview-native-core-swift"), + .product(name: "LiveViewNativeCore", package: "liveview-native-core"), .product(name: "Parsing", package: "swift-parsing"), ] ), diff --git a/Plugins/BuiltinRegistryGeneratorPlugin/BuiltinRegistryGeneratorPlugin.swift b/Plugins/BuiltinRegistryGeneratorPlugin/BuiltinRegistryGeneratorPlugin.swift index cc5fa73ce..8449dfb64 100644 --- a/Plugins/BuiltinRegistryGeneratorPlugin/BuiltinRegistryGeneratorPlugin.swift +++ b/Plugins/BuiltinRegistryGeneratorPlugin/BuiltinRegistryGeneratorPlugin.swift @@ -11,32 +11,36 @@ import Foundation @main struct BuiltinRegistryGeneratorPlugin: BuildToolPlugin { func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] { - guard let target = target as? SourceModuleTarget else { return [] } + guard let target = target as? SwiftSourceModuleTarget else { return [] } let tool = try context.tool(named: "BuiltinRegistryGenerator") - let output = context.pluginWorkDirectory.appending("BuiltinRegistry+Views.swift") + let output = context.pluginWorkDirectoryURL.appending(path: "BuiltinRegistry+Views.swift") let viewFiles = target.sourceFiles - .filter({ $0.path.string.starts(with: target.directory.appending("Views").string) }) + .filter({ $0.url.pathComponents.starts(with: target.directoryURL.appending(path: "Views").pathComponents) }) .filter({ $0.type == .source }) - .map(\.path) + .map(\.url) let modifierFiles = target.sourceFiles - .filter({ $0.path.string.hasSuffix("_GeneratedModifiers.swift") }) + .filter({ $0.url.lastPathComponent == "_GeneratedModifiers.swift" }) .filter({ $0.type == .source }) - .map(\.path) + .map(\.url) + let arguments: [String] = [target.directoryURL.path(percentEncoded: false), output.path(percentEncoded: false)] + + viewFiles + .reduce(into: [String]()) { partialResult, url in + partialResult.append("--view") + partialResult.append(url.path(percentEncoded: false)) + } + + modifierFiles + .reduce(into: [String]()) { partialResult, url in + partialResult.append("--modifier") + partialResult.append(url.path(percentEncoded: false)) + } + print(viewFiles) + print(modifierFiles) + print(arguments) return [ .buildCommand( displayName: tool.name, - executable: tool.path, - arguments: [target.directory.string, output.string] + - viewFiles - .reduce(into: [String]()) { partialResult, path in - partialResult.append("--view") - partialResult.append(path.string) - } - + modifierFiles - .reduce(into: [String]()) { partialResult, path in - partialResult.append("--modifier") - partialResult.append(path.string) - }, + executable: tool.url, + arguments: arguments, environment: [:], inputFiles: viewFiles + modifierFiles, outputFiles: [output] diff --git a/Plugins/DocumentationExtensionGeneratorPlugin/DocumentationExtensionGeneratorPlugin.swift b/Plugins/DocumentationExtensionGeneratorPlugin/DocumentationExtensionGeneratorPlugin.swift index 884c7a96d..fb50b8cdd 100644 --- a/Plugins/DocumentationExtensionGeneratorPlugin/DocumentationExtensionGeneratorPlugin.swift +++ b/Plugins/DocumentationExtensionGeneratorPlugin/DocumentationExtensionGeneratorPlugin.swift @@ -5,19 +5,19 @@ import Foundation struct DocumentationExtensionGeneratorPlugin: CommandPlugin { func performCommand(context: PluginContext, arguments: [String]) throws { let process = Process() - process.executableURL = URL(fileURLWithPath: try context.tool(named: "DocumentationExtensionGenerator").path.string) + process.executableURL = try context.tool(named: "DocumentationExtensionGenerator").url - let target = context.package.targets.first(where: { $0.name == "LiveViewNative" })! as! SourceModuleTarget + let target = context.package.targets.first(where: { $0.name == "LiveViewNative" })! as! SwiftSourceModuleTarget let viewFiles = target.sourceFiles - .filter({ $0.path.string.starts(with: target.directory.appending("Views").string) }) + .filter({ $0.url.pathComponents.starts(with: target.directoryURL.appending(path: "Views").pathComponents) }) .filter({ $0.type == .source }) - .map(\.path) + .map(\.url) process.arguments = arguments + viewFiles - .reduce(into: [String]()) { partialResult, path in + .reduce(into: [String]()) { partialResult, url in partialResult.append("--view") - partialResult.append(path.string) + partialResult.append(url.path()) } try process.run() diff --git a/Sources/BuiltinRegistryGenerator/BuiltinRegistryGenerator.swift b/Sources/BuiltinRegistryGenerator/BuiltinRegistryGenerator.swift index 01fa70c12..e4cd846e0 100644 --- a/Sources/BuiltinRegistryGenerator/BuiltinRegistryGenerator.swift +++ b/Sources/BuiltinRegistryGenerator/BuiltinRegistryGenerator.swift @@ -43,7 +43,9 @@ struct BuiltinRegistryGenerator: ParsableCommand { "RoundedRectangle": "Shape(shape: RoundedRectangle(from: element))", "Color": "ColorView()", "Image": "ImageView()", - "phx-main": "PhxMain()" + + // FIXME: The server should send a platform-specific tag name, or core should have the ability to split the dead render from the main app. + "div": "PhxMain()" ] var platformFamilyName: String? { @@ -66,6 +68,9 @@ struct BuiltinRegistryGenerator: ParsableCommand { let generated = """ import SwiftUI import LiveViewNativeStylesheet + import OSLog + + private let logger = Logger(subsystem: "LiveViewNative", category: "BuiltinRegistry") // This switch can't be inlined into BuiltinRegistry.lookup because it results in that method's return type // being a massive pile of nested _ConditionalContents. Instead, lift it out into a separate View type @@ -80,7 +85,8 @@ struct BuiltinRegistryGenerator: ParsableCommand { \(Self.additionalViews.map(additionalViewCase(name:initializer:)).joined(separator: "\n")) default: // log here that view type cannot be found - EmptyView() + let _ = logger.error("'<\\(name)>' is not a known element.") + Group() } } } diff --git a/Sources/LiveViewNative/BuiltinRegistry+applyBinding.swift b/Sources/LiveViewNative/BuiltinRegistry+applyBinding.swift index 776ecc696..c36ea2b39 100644 --- a/Sources/LiveViewNative/BuiltinRegistry+applyBinding.swift +++ b/Sources/LiveViewNative/BuiltinRegistry+applyBinding.swift @@ -17,6 +17,7 @@ public enum _EventBinding: String { } extension BuiltinRegistry { + @MainActor @ViewBuilder static func applyBinding( _ binding: _EventBinding, diff --git a/Sources/LiveViewNative/Coordinators/LiveConnectionError.swift b/Sources/LiveViewNative/Coordinators/LiveConnectionError.swift index 8650afbeb..74eca4be2 100644 --- a/Sources/LiveViewNative/Coordinators/LiveConnectionError.swift +++ b/Sources/LiveViewNative/Coordinators/LiveConnectionError.swift @@ -6,7 +6,7 @@ // import Foundation -import SwiftPhoenixClient +@preconcurrency import SwiftPhoenixClient /// An error that occurred when connecting to a live view. public enum LiveConnectionError: Error, LocalizedError { @@ -43,7 +43,7 @@ public enum LiveConnectionError: Error, LocalizedError { } } - public enum InitialParseComponent: CustomStringConvertible { + public enum InitialParseComponent: CustomStringConvertible, Sendable { case document case csrfToken case phxMain diff --git a/Sources/LiveViewNative/Coordinators/LiveSessionConfiguration.swift b/Sources/LiveViewNative/Coordinators/LiveSessionConfiguration.swift index 70f313500..b35f9d887 100644 --- a/Sources/LiveViewNative/Coordinators/LiveSessionConfiguration.swift +++ b/Sources/LiveViewNative/Coordinators/LiveSessionConfiguration.swift @@ -51,10 +51,10 @@ public struct LiveSessionConfiguration { self.reconnectBehavior = reconnectBehavior } - public struct ReconnectBehavior { - let delay: ((_ tries: Int) -> TimeInterval)? + public struct ReconnectBehavior: Sendable { + let delay: (@Sendable (_ tries: Int) -> TimeInterval)? - public init(_ delay: @escaping (_ tries: Int) -> TimeInterval) { + public init(_ delay: @escaping @Sendable (_ tries: Int) -> TimeInterval) { self.delay = delay } diff --git a/Sources/LiveViewNative/Coordinators/LiveSessionCoordinator.swift b/Sources/LiveViewNative/Coordinators/LiveSessionCoordinator.swift index c284af983..4e1220a6f 100644 --- a/Sources/LiveViewNative/Coordinators/LiveSessionCoordinator.swift +++ b/Sources/LiveViewNative/Coordinators/LiveSessionCoordinator.swift @@ -8,7 +8,6 @@ import Foundation import SwiftSoup import SwiftUI -import SwiftPhoenixClient import Combine import OSLog import LiveViewNativeCore @@ -42,34 +41,24 @@ public class LiveSessionCoordinator: ObservableObject { @Published public internal(set) var navigationPath = [LiveNavigationEntry]() internal let configuration: LiveSessionConfiguration - + @Published private(set) var rootLayout: LiveViewNativeCore.Document? @Published private(set) var stylesheet: Stylesheet? - + // Socket connection - var socket: Socket? - - private var domValues: DOMValues! - - private var liveReloadSocket: Socket? - private var liveReloadChannel: Channel? + var liveSocket: LiveViewNativeCore.LiveSocket? + var socket: LiveViewNativeCore.Socket? + + private var liveReloadChannel: LiveViewNativeCore.LiveChannel? + private var liveReloadListener: Channel.EventStream? + private var liveReloadListenerLoop: Task<(), any Error>? private var cancellables = Set() - + private var mergedEventSubjects: AnyCancellable? private var eventSubject = PassthroughSubject<(LiveViewCoordinator, (String, Payload)), Never>() private var eventHandlers = Set() - /// Delegate for the ``urlSession``. - /// - /// This delegate will add the `_format` and other necessary query params to any redirects. - private var urlSessionDelegate: LiveSessionURLSessionDelegate - - /// The ``URLSession`` instance to use for all HTTP requests. - /// - /// This session is created using the ``LiveSessionConfiguration/urlSessionConfiguration``. - private var urlSession: URLSession - private var reconnectAttempts = 0 /// Positions for `` elements with an explicit ID. @@ -92,33 +81,27 @@ public class LiveSessionCoordinator: ObservableObject { public convenience init(_ host: some LiveViewHost, config: LiveSessionConfiguration = .init(), customRegistryType: R.Type = R.self) { self.init(host.url, config: config, customRegistryType: customRegistryType) } - + /// Creates a new coordinator with a custom registry. /// - Parameter url: The URL of the page to establish the connection to. /// - Parameter config: The configuration for this coordinator. /// - Parameter customRegistryType: The type of the registry of custom views this coordinator will use when building the SwiftUI view tree from the DOM. This can generally be inferred automatically. public init(_ url: URL, config: LiveSessionConfiguration = .init(), customRegistryType _: R.Type = R.self) { self.url = url.appending(path: "").absoluteURL - + self.configuration = config - + config.urlSessionConfiguration.httpCookieStorage = .shared - self.urlSessionDelegate = .init() - self.urlSession = .init( - configuration: config.urlSessionConfiguration, - delegate: self.urlSessionDelegate, - delegateQueue: nil - ) self.navigationPath = [.init(url: url, coordinator: .init(session: self, url: self.url), navigationTransition: nil)] - + self.mergedEventSubjects = self.navigationPath.first!.coordinator.eventSubject.compactMap({ [weak self] value in self.map({ ($0.navigationPath.first!.coordinator, value) }) }) .sink(receiveValue: { [weak self] value in self?.eventSubject.send(value) }) - + $navigationPath.scan(([LiveNavigationEntry](), [LiveNavigationEntry]()), { ($0.1, $1) }).sink { [weak self] prev, next in guard let self else { return } let isDisconnected = switch next.last!.coordinator.state { @@ -128,21 +111,31 @@ public class LiveSessionCoordinator: ObservableObject { false } if next.last!.coordinator.url != next.last!.url || isDisconnected { - if prev.count > next.count { - // back navigation - Task(priority: .userInitiated) { - try await next.last!.coordinator.connect(domValues: self.domValues, redirect: true) - } - } else if next.count > prev.count && prev.count > 0 { - // forward navigation (from `redirect` or ``) - Task { - await prev.last?.coordinator.disconnect() - } - Task(priority: .userInitiated) { - try await next.last?.coordinator.connect(domValues: self.domValues, redirect: true) - // reset the scroll positions for a freshly navigated route. - // scroll restoration should only happen on back navigation. - self.scrollPositions[next.count] = [:] + Task { + if prev.count > next.count { + // back navigation + print("Back navigate", next.last!.url) + try await prev.last?.coordinator.disconnect() + let liveChannel = try await self.liveSocket!.joinLiveviewChannel( + .some([ + "_format": .str(string: LiveSessionParameters.platform), + "_interface": .object(object: LiveSessionParameters.platformParams) + ]), + next.last!.url.absoluteString + ) + try await next.last!.coordinator.join(liveChannel) + } else if next.count > prev.count && prev.count > 0 { + print("Forward navigation to \(next.last!.url)") + // forward navigation (from `redirect` or ``) + try await prev.last?.coordinator.disconnect() + let liveChannel = try await self.liveSocket!.joinLiveviewChannel( + .some([ + "_format": .str(string: LiveSessionParameters.platform), + "_interface": .object(object: LiveSessionParameters.platformParams) + ]), + next.last!.url.absoluteString + ) + try await next.last?.coordinator.join(liveChannel) } } } @@ -164,7 +157,7 @@ public class LiveSessionCoordinator: ObservableObject { } }.store(in: &cancellables) } - + /// Creates a new coordinator without a custom registry. /// - Parameter url: The URL of the page to establish the connection to. /// - Parameter config: The configuration for this coordinator. @@ -172,6 +165,10 @@ public class LiveSessionCoordinator: ObservableObject { self.init(url, config: config, customRegistryType: EmptyRegistry.self) } + deinit { + self.liveReloadListenerLoop?.cancel() + } + /// Connects this coordinator to the LiveView channel. /// /// You generally do not call this function yourself. It is called automatically when the ``LiveView`` appears. @@ -183,138 +180,130 @@ public class LiveSessionCoordinator: ObservableObject { /// - Parameter httpMethod: The HTTP method to use for the dead render. Defaults to `GET`. /// - Parameter httpBody: The HTTP body to send when requesting the dead render. public func connect(httpMethod: String? = nil, httpBody: Data? = nil) async { - switch state { - case .setup, .disconnected, .connectionFailed: - break - default: - return - } - - let originalURL = self.navigationPath.last!.url - - logger.debug("Connecting to \(originalURL.absoluteString)") - - state = .connecting - do { - var request = URLRequest(url: originalURL) - request.httpMethod = httpMethod - request.httpBody = httpBody - let (html, response) = try await deadRender(for: request, domValues: self.domValues) - - // update the URL if redirects happened. - let url: URL - if let responseURL = response.url { - if self.navigationPath.count == 1 { - self.url = responseURL - } - self.navigationPath.last!.coordinator.url = responseURL - self.navigationPath[self.navigationPath.endIndex - 1] = .init( - url: responseURL, - coordinator: self.navigationPath.last!.coordinator, - navigationTransition: nil - ) - url = responseURL - } else { - url = originalURL + switch state { + case .setup, .disconnected, .connectionFailed: + break + default: + return } - - let doc = try SwiftSoup.parse(html, url.absoluteString, SwiftSoup.Parser.xmlParser().settings(.init(true, true))) - self.domValues = try self.extractDOMValues(doc) - // extract the root layout, removing anything within the `
`. - let mainDiv = try doc.select("div[data-phx-main]")[0] - try mainDiv.replaceWith(doc.createElement("phx-main")) + let originalURL = self.navigationPath.last!.url - self.rootLayout = try LiveViewNativeCore.Document.parse(doc.outerHtml()) - - async let stylesheet = withThrowingTaskGroup(of: Stylesheet.self) { group in - for style in try doc.select("Style") { - guard let url = URL(string: try style.attr("url"), relativeTo: url) + logger.debug("Connecting to \(originalURL.absoluteString)") + + state = .connecting + + self.liveSocket = try await LiveSocket(originalURL.absoluteString, 10, LiveSessionParameters.platform) + self.socket = self.liveSocket?.socket() + + let liveChannel = try await self.liveSocket!.joinLiveviewChannel( + .some([ + "_format": .str(string: LiveSessionParameters.platform), + "_interface": .object(object: LiveSessionParameters.platformParams) + ]), + nil + ) + + self.rootLayout = self.liveSocket!.deadRender() + let styleURLs = self.liveSocket!.styleUrls() + + self.stylesheet = try await withThrowingTaskGroup(of: Stylesheet.self) { @Sendable group in + for style in styleURLs { + guard let url = await URL(string: style, relativeTo: self.url) else { continue } group.addTask { - if let cachedStylesheet = await StylesheetCache.shared.read(for: url, registry: R.self) { - return cachedStylesheet + if let cached = await StylesheetCache.shared.read(for: url, registry: R.self) { + return cached } else { - let (data, _) = try await self.urlSession.data(from: url) + let (data, _) = try await URLSession.shared.data(from: url) guard let contents = String(data: data, encoding: .utf8) - else { return Stylesheet(content: [], classes: [:]) } - let stylesheet = try Stylesheet(from: contents, in: .init()) - await StylesheetCache.shared.write(stylesheet, for: url, registry: R.self) - return stylesheet + else { return await Stylesheet(content: [], classes: [:]) } + return try await Stylesheet(from: contents, in: .init()) } } } + return try await group.reduce(Stylesheet(content: [], classes: [:])) { result, next in - return result.merge(with: next) + return await result.merge(with: next) } } - if socket == nil { - try await self.connectSocket(domValues) - } - - self.stylesheet = try await stylesheet + self.navigationPath.last!.coordinator.join(liveChannel) - try await navigationPath.last!.coordinator.connect(domValues: domValues, redirect: false) + self.state = .connected - reconnectAttempts = 0 + if self.liveSocket!.hasLiveReload() { + self.liveReloadChannel = try await self.liveSocket!.joinLivereloadChannel() + bindLiveReloadListener() + } } catch { self.state = .connectionFailed(error) - logger.log(level: .error, "\(error.localizedDescription)") - if let delay = configuration.reconnectBehavior.delay?(reconnectAttempts) { - logger.log(level: .debug, "Reconnecting in \(delay) seconds") - Task { [weak self] in - try await Task.sleep(nanoseconds: UInt64(delay * 1_000_000_000)) - guard let self, - case .connectionFailed = self.state - else { return } // already connected - reconnectAttempts += 1 - await self.connect(httpMethod: httpMethod, httpBody: httpBody) + } + } + + func bindLiveReloadListener() { + let eventListener = self.liveReloadChannel!.channel().eventStream() + self.liveReloadListener = eventListener + self.liveReloadListenerLoop = Task { @MainActor [weak self] in + for try await event in eventListener { + guard let self else { return } + switch event.event { + case .user(user: "assets_change"): + try await self.reconnect() + default: + continue } } - return } } - + private func disconnect(preserveNavigationPath: Bool = false) async { - // disconnect all views - await withTaskGroup(of: Void.self) { group in + do { for entry in self.navigationPath { - group.addTask { - await entry.coordinator.disconnect() + try await entry.coordinator.disconnect() + if !preserveNavigationPath { + entry.coordinator.document = nil } } - } - // reset all documents if navigation path is being reset. - if !preserveNavigationPath { - for entry in self.navigationPath { - entry.coordinator.document = nil + // reset all documents if navigation path is being reset. + if !preserveNavigationPath { + for entry in self.navigationPath { + entry.coordinator.document = nil + } + + self.navigationPath = [self.navigationPath.first!] } - - self.navigationPath = [self.navigationPath.first!] + try await self.liveReloadChannel?.channel().leave() + self.liveReloadChannel = nil + try await self.socket?.disconnect() + self.socket = nil + self.state = .disconnected + } catch { + self.state = .connectionFailed(error) } - self.socket?.disconnect() - self.socket = nil - self.state = .disconnected } - + /// Forces the session to disconnect then connect. /// /// All state will be lost when the reload occurs, as an entirely new LiveView is mounted. /// /// This can be used to force the LiveView to reset, for example after an unrecoverable error occurs. public func reconnect(url: URL? = nil, httpMethod: String? = nil, httpBody: Data? = nil) async { - if let url { - await self.disconnect(preserveNavigationPath: false) - self.url = url - self.navigationPath = [.init(url: self.url, coordinator: self.navigationPath.first!.coordinator, navigationTransition: nil)] - } else { - await self.disconnect(preserveNavigationPath: true) + do { + if let url { + try await self.disconnect(preserveNavigationPath: false) + self.url = url + self.navigationPath = [.init(url: self.url, coordinator: self.navigationPath.first!.coordinator, navigationTransition: nil)] + } else { + try await self.disconnect(preserveNavigationPath: true) + } + try await self.connect(httpMethod: httpMethod, httpBody: httpBody) + } catch { + self.state = .connectionFailed(error) } - await self.connect(httpMethod: httpMethod, httpBody: httpBody) } - + /// Creates a publisher that can be used to listen for server-sent LiveView events. /// /// - Parameter event: The event name that is being listened for. @@ -328,7 +317,7 @@ public class LiveSessionCoordinator: ObservableObject { .filter { $0.1.0 == event } .map({ ($0.0, $0.1.1) }) } - + /// Permanently registers a handler for a server-sent LiveView event. /// /// - Parameter event: The event name that is being listened for. @@ -342,188 +331,7 @@ public class LiveSessionCoordinator: ObservableObject { .sink(receiveValue: handler) .store(in: &eventHandlers) } - - /// Request the dead render with the given `request`. - /// - /// Returns the dead render HTML and the HTTP response information (including the final URL after redirects). - nonisolated func deadRender( - for request: URLRequest, - domValues: DOMValues? - ) async throws -> (String, HTTPURLResponse) { - - var request = request - request.url = request.url!.appendingLiveViewItems() - request.allHTTPHeaderFields = await configuration.headers - - if let domValues { - request.setValue(domValues.phxCSRFToken, forHTTPHeaderField: "x-csrf-token") - } - - let data: Data - let response: URLResponse - do { - (data, response) = try await urlSession.data(for: request) - } catch { - throw LiveConnectionError.initialFetchError(error) - } - - guard let response = response as? HTTPURLResponse, - response.statusCode == 200, - let html = String(data: data, encoding: .utf8) - else { - if let html = String(data: data, encoding: .utf8) - { - if try extractLiveReloadFrame(SwiftSoup.parse(html)) { - await connectLiveReloadSocket(urlSessionConfiguration: urlSession.configuration) - } - throw LiveConnectionError.initialFetchUnexpectedResponse(response, html) - } else { - throw LiveConnectionError.initialFetchUnexpectedResponse(response) - } - } - return (html, response) - } - - struct DOMValues { - let phxCSRFToken: String - let phxSession: String - let phxStatic: String - let phxView: String - let phxID: String - let liveReloadEnabled: Bool - } - - nonisolated private func extractLiveReloadFrame(_ doc: SwiftSoup.Document) throws -> Bool { - !(try doc.select("iframe[src=\"/phoenix/live_reload/frame\"]").isEmpty()) - } - - private func extractDOMValues(_ doc: SwiftSoup.Document) throws -> DOMValues { - let csrfToken = try doc.select("csrf-token") - guard !csrfToken.isEmpty() else { - throw LiveConnectionError.initialParseError(missingOrInvalid: .csrfToken) - } - - let mainDivRes = try doc.select("div[data-phx-main]") - guard !mainDivRes.isEmpty() else { - throw LiveConnectionError.initialParseError(missingOrInvalid: .phxMain) - } - let mainDiv = mainDivRes[0] - return .init( - phxCSRFToken: try csrfToken[0].attr("value"), - phxSession: try mainDiv.attr("data-phx-session"), - phxStatic: try mainDiv.attr("data-phx-static"), - phxView: try mainDiv.attr("data-phx-view"), - phxID: try mainDiv.attr("id"), - liveReloadEnabled: try extractLiveReloadFrame(doc) - ) - } - private func connectSocket(_ domValues: DOMValues) async throws { - self.socket = try await withCheckedThrowingContinuation { [weak self] continuation in - guard let self else { - return continuation.resume(throwing: LiveConnectionError.sessionCoordinatorReleased) - } - - var wsEndpoint = URLComponents(url: self.url, resolvingAgainstBaseURL: true)! - wsEndpoint.scheme = self.url.scheme == "https" ? "wss" : "ws" - wsEndpoint.path = "/live/websocket" - let configuration = self.urlSession.configuration - let socket = Socket( - endPoint: wsEndpoint.string!, - transport: { - URLSessionTransport(url: $0, configuration: configuration) - }, - paramsClosure: { - [ - "_csrf_token": domValues.phxCSRFToken, - "_format": "swiftui" - ] - } - ) - - // set to `reconnecting` when the socket asks for the delay duration. - socket.reconnectAfter = { [weak self] tries in - Task { - await MainActor.run { - self?.state = .reconnecting - } - } - return Defaults.reconnectSteppedBackOff(tries) - } - socket.onOpen { [weak self] in - guard case .reconnecting = self?.state else { return } - Task { - await MainActor.run { - self?.state = .connected - } - } - } - - var refs = [String]() - - refs.append(socket.onOpen { [weak self, weak socket] in - guard let socket else { return } - guard self != nil else { - socket.disconnect() - return - } - logger.debug("[Socket] Opened") - socket.off(refs) - continuation.resume(returning: socket) - }) - refs.append(socket.onError { [weak self, weak socket] (error, response) in - guard let socket else { return } - guard self != nil else { - socket.disconnect() - return - } - logger.error("[Socket] Error: \(String(describing: error))") - socket.off(refs) - continuation.resume(throwing: LiveConnectionError.socketError(error)) - }) - socket.connect() - } - self.socket?.onClose { logger.debug("[Socket] Closed") } - self.socket?.logger = { message in logger.debug("[Socket] \(message)") } - - self.state = .connected - - if domValues.liveReloadEnabled { - await self.connectLiveReloadSocket(urlSessionConfiguration: urlSession.configuration) - } - } - - private func connectLiveReloadSocket(urlSessionConfiguration: URLSessionConfiguration) async { - if let liveReloadSocket = self.liveReloadSocket { - liveReloadSocket.disconnect() - self.liveReloadSocket = nil - } - - logger.debug("[LiveReload] attempting to connect...") - - var liveReloadEndpoint = URLComponents(url: self.url, resolvingAgainstBaseURL: true)! - liveReloadEndpoint.scheme = self.url.scheme == "https" ? "wss" : "ws" - liveReloadEndpoint.path = "/phoenix/live_reload/socket" - self.liveReloadSocket = Socket(endPoint: liveReloadEndpoint.string!, transport: { - URLSessionTransport(url: $0, configuration: urlSessionConfiguration) - }) - liveReloadSocket!.connect() - self.liveReloadChannel = liveReloadSocket!.channel("phoenix:live_reload") - self.liveReloadChannel!.join().receive("ok") { msg in - logger.debug("[LiveReload] connected to channel") - }.receive("error") { msg in - logger.debug("[LiveReload] error connecting to channel: \(msg.payload)") - } - self.liveReloadChannel!.on("assets_change") { [weak self] _ in - logger.debug("[LiveReload] assets changed, reloading") - Task { - await StylesheetCache.shared.removeAll() - // need to fully reconnect (rather than just re-join channel) because the elixir code reloader only triggers on http reqs - await self?.reconnect() - } - } - } - func redirect(_ redirect: LiveRedirect) async throws { switch redirect.mode { case .replaceTop: @@ -538,9 +346,9 @@ public class LiveSessionCoordinator: ObservableObject { self.url = redirect.to } coordinator.document = navigationPath.last!.coordinator.document - await navigationPath.last?.coordinator.disconnect() +// await navigationPath.last?.coordinator.disconnect() navigationPath[navigationPath.count - 1] = entry - try await coordinator.connect(domValues: self.domValues, redirect: true) +// try await coordinator.connect(domValues: self.domValues, redirect: true) } } case .patch: @@ -560,46 +368,34 @@ public class LiveSessionCoordinator: ObservableObject { } } -/// A delegate that adds the `_format` query parameter to any redirects. -class LiveSessionURLSessionDelegate: NSObject, URLSessionTaskDelegate { - func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest) async -> URLRequest? { - guard let url = request.url else { - return request - } - - var newRequest = request - newRequest.url = url.appendingLiveViewItems() - return newRequest - } -} - +@MainActor enum LiveSessionParameters { static var platform: String { "swiftui" } - static var platformParams: [String:Any] { + static var platformParams: [String:LiveViewNativeCore.Json] { [ - "app_version": getAppVersion(), - "app_build": getAppBuild(), - "bundle_id": getBundleID(), - "os": getOSName(), - "os_version": getOSVersion(), - "target": getTarget(), + "app_version": .str(string: getAppVersion()), + "app_build": .str(string: getAppBuild()), + "bundle_id": .str(string: getBundleID()), + "os": .str(string: getOSName()), + "os_version": .str(string: getOSVersion()), + "target": .str(string: getTarget()), "l10n": getLocalization(), "i18n": getInternationalization() ] } - + private static func getAppVersion() -> String { let dictionary = Bundle.main.infoDictionary! return dictionary["CFBundleShortVersionString"] as! String } - + private static func getAppBuild() -> String { let dictionary = Bundle.main.infoDictionary! return dictionary["CFBundleVersion"] as! String } - + private static func getBundleID() -> String { let dictionary = Bundle.main.infoDictionary! @@ -630,7 +426,7 @@ enum LiveSessionParameters { let majorVersion = operatingSystemVersion.majorVersion let minorVersion = operatingSystemVersion.minorVersion let patchVersion = operatingSystemVersion.patchVersion - + return "\(majorVersion).\(minorVersion).\(patchVersion)" #else return UIDevice.current.systemVersion @@ -664,27 +460,27 @@ enum LiveSessionParameters { #endif } - private static func getLocalization() -> [String:Any] { - [ - "locale": Locale.autoupdatingCurrent.identifier, - ] + private static func getLocalization() -> Json { + .object(object: [ + "locale": .str(string: Locale.autoupdatingCurrent.identifier), + ]) } - private static func getInternationalization() -> [String:Any] { - [ - "time_zone": TimeZone.autoupdatingCurrent.identifier, - ] + private static func getInternationalization() -> Json { + .object(object: [ + "time_zone": .str(string: TimeZone.autoupdatingCurrent.identifier), + ]) } static var queryItems: [URLQueryItem] = { /// Create a nested structure of query items. /// /// `_root[key][nested_key]=value` - func queryParameters(for object: [String:Any]) -> [(name: String, value: String?)] { + func queryParameters(for object: [String:Json]) -> [(name: String, value: String?)] { object.reduce(into: [(name: String, value: String?)]()) { (result, pair) in if let value = pair.value as? String { result.append((name: "[\(pair.key)]", value: value)) - } else if let nested = pair.value as? [String:Any] { + } else if case let .object(nested) = pair.value { result.append(contentsOf: queryParameters(for: nested).map { return (name: "[\(pair.key)]\($0.name)", value: $0.value) }) @@ -701,7 +497,8 @@ enum LiveSessionParameters { } fileprivate extension URL { - nonisolated func appendingLiveViewItems() -> Self { + @MainActor + func appendingLiveViewItems() -> Self { var result = self let components = URLComponents(url: self, resolvingAgainstBaseURL: false) let existingQueryItems = (components?.queryItems ?? []).reduce(into: Set()) { $0.insert($1) } @@ -712,3 +509,6 @@ fileprivate extension URL { return result } } + +extension Socket: @unchecked Sendable {} +extension Channel: @unchecked Sendable {} diff --git a/Sources/LiveViewNative/Coordinators/LiveViewCoordinator.swift b/Sources/LiveViewNative/Coordinators/LiveViewCoordinator.swift index 307c04ae3..0d15cc9b1 100644 --- a/Sources/LiveViewNative/Coordinators/LiveViewCoordinator.swift +++ b/Sources/LiveViewNative/Coordinators/LiveViewCoordinator.swift @@ -1,19 +1,19 @@ // // LiveViewCoordinator.swift -// +// // // Created by Carson Katri on 1/6/23. // import Foundation -import SwiftPhoenixClient import SwiftSoup import SwiftUI import Combine import LiveViewNativeCore +import AsyncAlgorithms import OSLog -private var PUSH_TIMEOUT: Double = 30000 +private let PUSH_TIMEOUT: Double = 30000 private let logger = Logger(subsystem: "LiveViewNative", category: "LiveViewCoordinator") @@ -33,10 +33,12 @@ public class LiveViewCoordinator: ObservableObject { } @_spi(LiveForm) public private(set) weak var session: LiveSessionCoordinator! - var url: URL - - private var channel: Channel? + var url: URL + + private(set) var liveChannel: LiveViewNativeCore.LiveChannel? + private var channel: LiveViewNativeCore.Channel? + @Published var document: LiveViewNativeCore.Document? private var elementChangedSubjects = [NodeRef:ObjectWillChangePublisher]() func elementChanged(_ ref: NodeRef) -> ObjectWillChangePublisher { @@ -47,35 +49,28 @@ public class LiveViewCoordinator: ObservableObject { } return subject } - internal var rendered: Root! internal let builder = ViewTreeBuilder() - - private var currentConnectionToken: ConnectionAttemptToken? - private var currentConnectionTask: Task? - + private(set) internal var eventSubject = PassthroughSubject<(String, Payload), Never>() private(set) internal var eventHandlers = Set() + private var eventListener: Channel.EventStream? + private var eventListenerLoop: Task<(), any Error>? + private var statusListener: Channel.StatusStream? + private var statusListenerLoop: Task<(), any Error>? + private(set) internal var liveViewModel = LiveViewModel() - - init( - session: LiveSessionCoordinator, - url: URL - ) { + + init(session: LiveSessionCoordinator, url: URL) { self.session = session self.url = url - - self.handleEvent("native_redirect") { [weak self] payload in - guard let self, - let redirect = LiveRedirect(from: payload, relativeTo: self.url), - let session = self.session - else { return } - Task { - try await session.redirect(redirect) - } - } } + deinit { + self.eventListenerLoop?.cancel() + self.statusListenerLoop?.cancel() + } + /// Pushes a LiveView event with the given name and payload to the server. /// /// This is an asynchronous function that completes when the server finishes processing the event and returns a response. @@ -87,68 +82,44 @@ public class LiveViewCoordinator: ObservableObject { /// - Parameter target: The value of the `phx-target` attribute. /// - Throws: ``LiveConnectionError/eventError(_:)`` if an error is encountered sending the event or processing it on the backend, `CancellationError` if the coordinator navigates to a different page while the event is being handled @discardableResult - public func pushEvent(type: String, event: String, value: Any, target: Int? = nil) async throws -> [String:Any]? { - // isValidJSONObject only accepts objects, but we want to check that the value can be serialized as a field of an object - precondition(JSONSerialization.isValidJSONObject(["a": value])) - return try await doPushEvent("event", payload: [ - "type": type, - "event": event, - "value": value, - "cid": target as Any - ]) + public func pushEvent(type: String, event: String, value: some Encodable, target: Int? = nil) async throws -> [String:Any]? { + return try await doPushEvent("event", payload: .jsonPayload(json: .object(object: [ + "type": .str(string: type), + "event": .str(string: event), + "value": try JsonEncoder().encode(value), + "cid": target.flatMap({ .numb(number: .posInt(pos: UInt64($0))) }) ?? .null + ]))) } @discardableResult - public func pushEvent(type: String, event: String, value: some Encodable, target: Int? = nil) async throws -> [String:Any]? { - try await pushEvent( - type: type, - event: event, - value: try JSONSerialization.jsonObject(with: JSONEncoder().encode(value)), - target: target - ) + public func pushEvent(type: String, event: String, value: Any, target: Int? = nil) async throws -> [String:Any]? { + return try await doPushEvent("event", payload: .jsonPayload(json: .object(object: [ + "type": .str(string: type), + "event": .str(string: event), + "value": try JSONDecoder().decode(Json.self, from: JSONSerialization.data(withJSONObject: value, options: .fragmentsAllowed)), + "cid": target.flatMap({ .numb(number: .posInt(pos: UInt64($0))) }) ?? .null + ]))) + } + + struct ReplyPayload: @unchecked Sendable { + let payload: [String: Any] } @discardableResult - internal func doPushEvent(_ event: String, payload: Payload) async throws -> [String:Any]? { + internal func doPushEvent(_ event: String, payload: LiveViewNativeCore.Payload) async throws -> [String:Any]? { guard let channel = channel else { return nil } - let token = self.currentConnectionToken - - let replyPayload: [String:Any] = try await withCheckedThrowingContinuation({ [weak channel] continuation in - guard channel?.isJoined == true else { - return continuation.resume(throwing: LiveConnectionError.viewCoordinatorReleased) - } - channel?.push(event, payload: payload, timeout: PUSH_TIMEOUT) - .receive("ok") { reply in - continuation.resume(returning: reply.payload) - } - .receive("error") { message in - continuation.resume(throwing: LiveConnectionError.eventError(message)) - } - }) - - guard currentConnectionToken === token else { - // TODO: maybe this should just silently fail? - throw CancellationError() + guard case .joined = channel.status() else { + throw LiveConnectionError.viewCoordinatorReleased } - if let diffPayload = replyPayload["diff"] as? Payload { - try self.handleDiff(payload: diffPayload, baseURL: self.url) - if let reply = diffPayload["r"] as? [String:Any] { - return reply - } - } else if let redirect = (replyPayload["live_redirect"] as? Payload).flatMap({ LiveRedirect(from: $0, relativeTo: self.url) }) { - try await session.redirect(redirect) - } else if let redirect = (replyPayload["redirect"] as? Payload), - let destination = (redirect["to"] as? String).flatMap({ URL.init(string: $0, relativeTo: self.url) }) - { - try await session.redirect(.init(kind: .push, to: destination, mode: .replaceTop)) - } - return nil + let replyPayload = try await channel.call(event: .user(user: event), payload: payload, timeout: PUSH_TIMEOUT) + + return try await handleEventReplyPayload(replyPayload) } - + /// Creates a publisher that can be used to listen for server-sent LiveView events. /// /// - Parameter event: The event name that is being listened for. @@ -194,7 +165,7 @@ public class LiveViewCoordinator: ObservableObject { .filter { $0.0 == event } .map(\.1) } - + /// Permanently registers a handler for a server-sent LiveView event. /// /// - Parameter event: The event name that is being listened for. @@ -207,19 +178,50 @@ public class LiveViewCoordinator: ObservableObject { .sink(receiveValue: handler) .store(in: &eventHandlers) } - - private func handleDiff(payload: Payload, baseURL: URL) throws { - handleEvents(payload: payload) - let diff = try RootDiff(from: FragmentDecoder(data: payload)) - self.rendered = try self.rendered.merge(with: diff) - self.document?.merge(with: try Document.parse(self.rendered.buildString())) + + private func handleDiff(payload: LiveViewNativeCore.Json, baseURL: URL) throws { + handleEvents(payload) + try self.document?.mergeFragmentJson(String(data: try JSONEncoder().encode(payload), encoding: .utf8)!) } - private func handleEvents(payload: Payload) { - guard let events = payload["e"] as? [[Any]] else { + func handleEventReplyPayload(_ replyPayload: LiveViewNativeCore.Payload) async throws -> [String:Any]? { + switch replyPayload { + case let .jsonPayload(json): + switch json { + case let .object(object): + if case let .object(diff) = object["diff"] { + try self.handleDiff(payload: .object(object: diff), baseURL: self.url) + if case let .object(reply) = diff["r"] { + return reply + } + } else if case let .object(redirectObject) = object["live_redirect"], + let redirect = LiveRedirect(from: redirectObject, relativeTo: self.url) + { + try await session.redirect(redirect) + } else if case let .object(redirectObject) = object["redirect"], + case let .str(destinationString) = redirectObject["to"], + let destination = URL(string: destinationString, relativeTo: self.url) + { + try await session.redirect(.init(kind: .push, to: destination, mode: .replaceTop)) + } else { + return nil + } + default: + fatalError("unsupported message type \(replyPayload)") + } + default: + fatalError("unsupported message type \(replyPayload)") + } + return nil + } + + private func handleEvents(_ json: LiveViewNativeCore.Json) { + guard case let .object(object) = json, + case let .array(array: events) = object["e"] + else { return } - for event in events { + for case let .array(event) in events { guard let name = event[0] as? String, let value = event[1] as? Payload else { continue @@ -227,212 +229,115 @@ public class LiveViewCoordinator: ObservableObject { eventSubject.send((name, value)) } } - - private nonisolated func parseDOM(html: String, baseURL: URL) throws -> Elements { - let document = try Parser.htmlParser().parseInput(html, baseURL.absoluteString) - return document.children() - } - - func connect(domValues: LiveSessionCoordinator.DOMValues, redirect: Bool) async throws { - await self.disconnect() - - self.internalState = .connecting - - guard let socket = session.socket else { return } - - var connectParams = session.configuration.connectParams?(self.url) ?? [:] - connectParams["_mounts"] = 0 - connectParams["_format"] = "swiftui" - connectParams["_csrf_token"] = domValues.phxCSRFToken - connectParams["_interface"] = LiveSessionParameters.platformParams - - let params: Payload = [ - "session": domValues.phxSession, - "static": domValues.phxStatic, - (redirect ? "redirect": "url"): self.url.absoluteString, - "params": connectParams, - ] - let channel = socket.channel("lv:\(domValues.phxID)", params: params) - self.channel = channel - channel.onError { message in - logger.error("[Channel] Error: \(String(describing: message))") - } - channel.onClose { message in - logger.info("[Channel] Closed") - } - channel.on("diff") { [weak self, weak channel] message in - Task { @MainActor in - guard let self, - channel === self.channel - else { return } - try! self.handleDiff(payload: message.payload, baseURL: self.url) - } - } - channel.on("live_redirect") { [weak self] message in - Task { - guard let self, - let redirect = LiveRedirect(from: message.payload, relativeTo: self.url) - else { return } - try await self.session.redirect(redirect) - } - } - channel.on("live_patch") { [weak self] message in - Task { - guard let self, - let redirect = LiveRedirect(from: message.payload, relativeTo: self.url, mode: .patch) - else { return } - try await self.session.redirect(redirect) - } - } - channel.on("redirect") { [weak self] message in - Task { - guard let self, - let destination = (message.payload["to"] as? String).flatMap({ URL.init(string: $0, relativeTo: self.url) }) - else { return } - try await self.session.redirect(.init(kind: .push, to: destination, mode: .replaceTop)) - } - } - channel.on("phx_close") { [weak self, weak channel] message in - Task { @MainActor in - guard channel === self?.channel else { return } - self?.internalState = .disconnected - } - } - - let joinTask = Task { - for try await joinResult in join(channel: channel) { - switch joinResult { - case .rendered(let payload): - await MainActor.run { - self.handleJoinPayload(renderedPayload: payload) - self.internalState = .connected + func bindEventListener() { + let eventListener = self.channel!.eventStream() + self.eventListener = eventListener + self.eventListenerLoop = Task { [weak self] in + for try await event in eventListener { + guard let self else { return } + do { + switch event.event { + case .user(user: "diff"): + switch event.payload { + case let .jsonPayload(json): + try self.handleDiff(payload: json, baseURL: self.url) + case .binary: + fatalError() + } + case .user(user: "live_redirect"): + guard case let .jsonPayload(json) = event.payload, + case let .object(payload) = json, + let redirect = LiveRedirect(from: payload, relativeTo: self.url) + else { break } + try await self.session.redirect(redirect) + case .user(user: "live_patch"): + guard case let .jsonPayload(json) = event.payload, + case let .object(payload) = json, + let redirect = LiveRedirect(from: payload, relativeTo: self.url, mode: .patch) + else { return } + try await self.session.redirect(redirect) + case .user(user: "redirect"): + guard case let .jsonPayload(json) = event.payload, + case let .object(payload) = json, + let destination = (payload["to"] as? String).flatMap({ URL.init(string: $0, relativeTo: self.url) }) + else { return } + try await self.session.redirect(.init(kind: .push, to: destination, mode: .replaceTop)) + default: + print("Unhandled event: \(event)") } - case .redirect(let liveRedirect): - self.url = liveRedirect.to - try await self.connect(domValues: domValues, redirect: true) + } catch { + print("Event handling error: \(error)") } } } - - channel.onClose { _ in - joinTask.cancel() - } } - func disconnect() async { - if let channel, - !channel.isClosed - { - await withCheckedContinuation { continuation in - channel.leave() - .receive("ok") { _ in - continuation.resume() - } - } - await MainActor.run { [weak self] in - self?.channel = nil - self?.internalState = .disconnected + func bindDocumentListener() { + self.document?.on(.changed) { [weak self] nodeRef, nodeData, parent in + guard let self else { return } + switch nodeData { + case .root: + // when the root changes, update the `NavStackEntry` itself. + self.objectWillChange.send() + case .leaf: + // text nodes don't have their own views, changes to them need to be handled by the parent Text view + if let parent { + self.elementChanged(nodeRef).send() + } else { + self.elementChanged(nodeRef).send() + } + case .nodeElement: + // when a single element changes, send an update only to that element. + self.elementChanged(nodeRef).send() } } } - - enum JoinResult { - case rendered(Payload) - case redirect(LiveRedirect) - } - - private func join(channel: Channel) -> AsyncThrowingStream { - return AsyncThrowingStream { [weak channel] (continuation: AsyncThrowingStream.Continuation) -> Void in - channel?.join() - .receive("ok") { [weak self, weak channel] message in - guard let channel else { - continuation.finish(throwing: LiveConnectionError.viewCoordinatorReleased) - return - } - guard self != nil else { - // leave the channel so we don't get any more messages/automatic rejoins - if channel.isJoined { - channel.leave() - } - continuation.finish(throwing: LiveConnectionError.viewCoordinatorReleased) - return - } - let renderedPayload = (message.payload["rendered"] as! Payload) - continuation.yield(.rendered(renderedPayload)) - } - .receive("error") { [weak self, weak channel] message in - guard channel != nil else { - continuation.finish(throwing: LiveConnectionError.viewCoordinatorReleased) - return - } - - Task { [weak self] in - guard let self else { - continuation.finish(throwing: LiveConnectionError.viewCoordinatorReleased) - return - } - - switch message.payload["reason"] as? String { - case "unauthorized", "stale": - await self.session.reconnect() - default: - await self.disconnect() - } - if let redirect = (message.payload["live_redirect"] as? Payload).flatMap({ LiveRedirect(from: $0, relativeTo: self.url) }) { - continuation.yield(.redirect(redirect)) - } else { - continuation.finish(throwing: LiveConnectionError.joinError(message)) - } - } + func join(_ liveChannel: LiveViewNativeCore.LiveChannel) { + self.liveChannel = liveChannel + let channel = liveChannel.channel() + self.channel = channel + + let statusListener = channel.statusStream() + self.statusListener = statusListener + statusListenerLoop = Task { @MainActor [weak self] in + for try await status in statusListener { + self?.internalState = switch status { + case .joined: + .connected + case .joining, .waitingForSocketToConnect, .waitingToJoin: + .connecting + case .waitingToRejoin: + .reconnecting + case .leaving, .left, .shuttingDown, .shutDown: + .disconnected } - channel?.onClose { _ in - continuation.finish() - } - continuation.onTermination = { [weak channel] termination in - channel?.leave() } } - } - - private func handleJoinPayload(renderedPayload: Payload) { - // todo: what should happen if decoding or parsing fails? - self.rendered = try! Root(from: FragmentDecoder(data: renderedPayload)) - // FIXME: LiveForm should send change event when restored from `liveViewModel`. - // For now, we just clear the forms whenever the page reconnects. - self.liveViewModel.clearForms() + self.bindEventListener() - self.document = try! LiveViewNativeCore.Document.parse(rendered.buildString()) + self.document = liveChannel.document() + self.bindDocumentListener() - self.document?.on(.changed) { [unowned self] doc, nodeRef in - switch doc[nodeRef].data { - case .root: - // when the root changes, update the `NavStackEntry` itself. - self.objectWillChange.send() - case .leaf: - self.elementChanged(nodeRef).send() - case .element: - // when a single element changes, send an update only to that element. - self.elementChanged(nodeRef).send() - } + switch liveChannel.joinPayload() { + case let .jsonPayload(.object(payload)): + self.handleEvents(payload["rendered"]!) + default: + fatalError() } - self.handleEvents(payload: renderedPayload) + + self.internalState = .connected + } + + func disconnect() async throws { + try await self.channel?.leave() + self.eventListenerLoop = nil + self.statusListenerLoop = nil + self.liveChannel = nil + self.channel = nil + + self.internalState = .setup } -} - -extension LiveViewCoordinator { - /// This token represents an individual attempt at connecting to a particular Live View. - /// - /// If a new navigation/connection attempt interrupts an in-progress one, the token allows - /// dangling completion handlers to detect that they've been preempted and cancel themselves. - /// - /// The URL cannot be used for this purpose, because the previous and new URLs may be the same - /// (e.g., due to live reload). - /// - /// This class deliberately does not implement `Equatable` and reference equality (`===`) is used to - /// check token validatity. A token is constructed at the beginning of a connection attempt, set as the coordinator's - /// current token, and compared to the then-current one in asynchronous callbacks. - class ConnectionAttemptToken {} } diff --git a/Sources/LiveViewNative/Environment.swift b/Sources/LiveViewNative/Environment.swift index 566076e3e..e52fc01d9 100644 --- a/Sources/LiveViewNative/Environment.swift +++ b/Sources/LiveViewNative/Environment.swift @@ -9,11 +9,13 @@ import SwiftUI import LiveViewNativeCore import Combine -private struct FormModelKey: EnvironmentKey { +@MainActor +private struct FormModelKey: @preconcurrency EnvironmentKey { static let defaultValue: FormModel? = nil } -private struct ModifierChangeTrackingContextKey: EnvironmentKey { +@MainActor +private struct ModifierChangeTrackingContextKey: @preconcurrency EnvironmentKey { static let defaultValue: ModifierChangeTrackingContext? = nil } @@ -39,11 +41,13 @@ final class ModifierChangeTrackingContext { } } -private struct ElementKey: EnvironmentKey { +@MainActor +private struct ElementKey: @preconcurrency EnvironmentKey { static let defaultValue: ElementNode? = nil } -private struct LiveContextStorageKey: EnvironmentKey { +@MainActor +private struct LiveContextStorageKey: @preconcurrency EnvironmentKey { static var defaultValue: Any? = nil } @@ -53,7 +57,7 @@ struct CoordinatorEnvironment { private final class Storage { let pushEvent: @MainActor (String, String, Any, Int?) async throws -> [String:Any]? let elementChanged: @MainActor (NodeRef) -> ObservableObjectPublisher - let document: Document + weak var document: Document? init(_ coordinator: LiveViewCoordinator, document: Document) { self.pushEvent = coordinator.pushEvent @@ -69,7 +73,7 @@ struct CoordinatorEnvironment { var elementChanged: @MainActor (NodeRef) -> ObservableObjectPublisher { storage.elementChanged } - var document: Document { + var document: Document? { storage.document } @@ -78,7 +82,8 @@ struct CoordinatorEnvironment { self.storage = .init(coordinator, document: document) } - fileprivate struct Key: EnvironmentKey { + @MainActor + fileprivate struct Key: @preconcurrency EnvironmentKey { static var defaultValue: CoordinatorEnvironment? = nil } } diff --git a/Sources/LiveViewNative/Fragment+Merge.swift b/Sources/LiveViewNative/Fragment+Merge.swift deleted file mode 100644 index 030864819..000000000 --- a/Sources/LiveViewNative/Fragment+Merge.swift +++ /dev/null @@ -1,186 +0,0 @@ -// -// Fragment+Merge.swift -// LiveViewNative -// -// Created by Shadowfacts on 3/4/22. -// - -import Foundation - -extension Root { - - func merge(with diff: RootDiff) throws -> Root { - let newFragment = try self.fragment.merge(with: diff.fragment) - var newComponents: [Int: Component]? - switch (self.components, diff.components) { - case (nil, nil): - newComponents = nil - case let (.some(components), nil): - newComponents = components - case let (.some(components), .some(compDiff)): - newComponents = try components.merge(with: compDiff) - case let (nil, .some(compDiff)): - newComponents = try compDiff.mapValues { - try $0.toNewComponent() - } - } - return Root(fragment: newFragment, components: newComponents) - } - -} - -extension Fragment { - func merge(with diff: FragmentDiff) throws -> Fragment { - switch (self, diff) { - case let (_, .replaceCurrent(newFragment)): - return newFragment - case let (.regular(children: currentChildren, statics: currentStatics), .updateRegular(children: childrenDiffs)): - let newChildren = try currentChildren.merge(with: childrenDiffs) - return .regular(children: newChildren, statics: currentStatics) - case let (.comprehension(dynamics: _, statics: currentStatics, templates: currentTemplates), .updateComprehension(dynamics: dynamicDiffs, templates: newTemplates)): - // todo: double check that dynamics in diff always completely replace existing dynamics - let newDynamics = try dynamicDiffs.map { - try $0.map { try $0.toNewChild() } - } - return .comprehension(dynamics: newDynamics, statics: currentStatics, templates: currentTemplates.merge(with: newTemplates)) - default: - throw MergeError.fragmentTypeMismatch - } - } -} - -extension Optional where Wrapped == Templates { - func merge(with newTemplates: Templates?) -> Templates? { - guard let self = self else { - return newTemplates - } - guard let newTemplates = newTemplates else { - return self - } - // todo: not clear whether keeping the old ones is the right behavior, or whether they should be overwritten entirely - return Templates(templates: self.templates.merging(newTemplates.templates, uniquingKeysWith: { old, new in new })) - } -} - -extension Array where Element == Child { - func merge(with childrenDiffs: [Int: ChildDiff]) throws -> [Child] { - var newChildren = self - for (index, childDiff) in childrenDiffs { - // we cannot add a child to this array, as doing so would change the expected - // number of statics - // if that were to happen, this diff would need to be a replaceCurrent - if index >= self.count { - throw MergeError.addChildToExisting - } - try newChildren[index].merge(with: childDiff) - } - return newChildren - } -} - -extension Dictionary where Key == Int, Value == Component { - func merge(with diff: [Int: ComponentDiff]) throws -> [Int: Component] { - var newComps = self - for (cid, compDiff) in diff { - if newComps.keys.contains(cid) { - try newComps[cid]!.merge(with: compDiff) - } else { - newComps[cid] = try compDiff.toNewComponent() - } - } - return newComps - } -} - -extension ComponentDiff { - func toNewComponent() throws -> Component { - switch self { - case .replaceCurrent(let component): - return component.fixStatics() - case .updateRegular(_): - throw MergeError.createComponentFromUpdate - } - } - -} - -extension Component { - mutating func merge(with diff: ComponentDiff) throws { - switch diff { - case .replaceCurrent(let component): - self = component.fixStatics() - - case .updateRegular(let childrenDiffs): - let newChildren = try self.children.merge(with: childrenDiffs) - self = Component(children: newChildren, statics: self.statics) - } - } - - fileprivate func fixStatics() -> Component { - // In diffs, he backend sends negative cids as x-refs for component statics to indicate that it - // refers to a component that already exists on the client (and positives are x-refs to component statics - // that are only now being sent in the diff). - // The JS client cares about this distinction because it replaces static refs with the actual array of strings - // from the referenced component. - // We do not; we always look up the refrenced component when building strings (see `ComponentStatics.effectiveValue(in:)`) - // So, we change the cid to be non-negative: - switch self.statics { - case .componentRef(let cid) where cid < 0: - let fixedStatics = ComponentStatics.componentRef(-cid) - return Component(children: self.children, statics: fixedStatics) - default: - return self - } - } -} - -extension Child { - mutating func merge(with diff: ChildDiff) throws { - switch (self, diff) { - case let (.fragment(currentFragment), .fragment(fragmentDiff)): - self = .fragment(try currentFragment.merge(with: fragmentDiff)) - case let (_, .componentID(id)): - self = .componentID(id) - case let (_, .string(str)): - self = .string(str) - case let (_, .fragment(fragmentDiff)): - // we can only create a new fragment child from a complete fragment (i.e., one that includes statics, i.e., .replaceCurrent) - switch fragmentDiff { - case .replaceCurrent(let fragment): - self = .fragment(fragment) - default: - throw MergeError.createChildFromUpdateFragment - } - } - } -} - -extension ChildDiff { - func toNewChild() throws -> Child { - switch self { - case .string(let s): - return .string(s) - case .componentID(let cid): - return .componentID(cid) - case .fragment(let fragDiff): - // we can only create a new fragment child from a complete fragment (i.e., one that includes statics, i.e., .replaceCurrent) - switch fragDiff { - case .replaceCurrent(let fragment): - return .fragment(fragment) - default: - throw MergeError.createChildFromUpdateFragment - } - } - } -} - -enum MergeError: Error { - /// Thrown when trying to perform a fragment merge on incompatible types (e.g. `.updateComprehension` into a `.regular`) - case fragmentTypeMismatch - /// Thrown when trying to create a new component from an update diff - case createComponentFromUpdate - /// Thrown when trying to create a new child (or update a non-fragment one) from a component diff that's not `.replaceCurrent` - case createChildFromUpdateFragment - /// Thrown if a diff attempts to add a child rather than only updating exsitign ones - case addChildToExisting -} diff --git a/Sources/LiveViewNative/Fragment.swift b/Sources/LiveViewNative/Fragment.swift deleted file mode 100644 index 63604841e..000000000 --- a/Sources/LiveViewNative/Fragment.swift +++ /dev/null @@ -1,334 +0,0 @@ -// -// Fragment.swift -// LiveViewNative -// -// Created by Shadowfacts on 2/28/22. -// - -import Foundation - -enum Child: Decodable, Equatable { - case fragment(Fragment) - case componentID(Int) - case string(String) - - init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() - - if let id = try? container.decode(Int.self) { - self = .componentID(id) - } else if let str = try? container.decode(String.self) { - self = .string(str) - } else { - self = .fragment(try container.decode(Fragment.self)) - } - } - - fileprivate func buildStringInternal(buffer: inout String, root: Root, templates: Templates?, componentStatics: ComponentStatics?, childIndex: Int?) { - switch self { - case .fragment(let frag): - frag.buildStringInternal(buffer: &buffer, root: root, templates: templates, componentStatics: componentStatics, childIndex: childIndex) - case .string(let s): - buffer += s - case .componentID(let cid): - guard let component = root.components?[cid] else { - fatalError("Cannot reference missing commponent") - } - // todo: apply data-phx-component to root element? - component.buildStringInternal(buffer: &buffer, root: root) - } - } -} - -struct Root: Decodable, Equatable { - let fragment: Fragment - let components: [Int: Component]? - - init(fragment: Fragment, components: [Int: Component]?) { - self.fragment = fragment - self.components = components - } - - init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - self.fragment = try decoder.singleValueContainer().decode(Fragment.self) - - if let componentsContainer = try? container.nestedContainer(keyedBy: IntKey.self, forKey: .components) { - self.components = try componentsContainer.allKeys.reduce(into: [:], { partialResult, key in - partialResult[key.intValue!] = try componentsContainer.decode(Component.self, forKey: key) - }) - } else { - self.components = nil - } - } - - func buildString() -> String { - return fragment.buildString(root: self) - } - - enum CodingKeys: String, CodingKey { - case components = "c" - } -} - -// note: this is distinct from a Fragment, because a Component must have an HTML tag at the top level and thus must be "regular" and not a comprehension -struct Component: Decodable, Equatable { - typealias CodingKeys = Fragment.CodingKeys - - let children: [Child] - let statics: ComponentStatics - - init(children: [Child], statics: ComponentStatics) { - self.children = children - self.statics = statics - } - - init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - // validate our assumption that components can't be dynamic - assert(!container.contains(.dynamics)) - - self.statics = try container.decode(ComponentStatics.self, forKey: .statics) - let count = container.allKeys.filter(\.isChild).count - self.children = try (0.. [String] { - switch self { - case .statics(let statics): - return statics - case .componentRef(let cid): - guard let component = root.components?[cid] else { - fatalError("Cannot reference missing component") - } - return component.statics.effectiveValue(in: root) - } - } -} - -enum Fragment: Decodable, Equatable { - case regular(children: [Child], statics: Statics) - case comprehension(dynamics: [[Child]], statics: Statics, templates: Templates?) - - var statics: Statics { - switch self { - case .regular(children: _, statics: let s): - return s - case .comprehension(dynamics: _, statics: let s, templates: _): - return s - } - } - - init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - let statics = try container.decodeIfPresent(Statics.self, forKey: .statics) ?? .componentRef - - if container.contains(.dynamics) { - let dynamics = try container.decode([[Child]].self, forKey: .dynamics) - let templates = try container.decodeIfPresent(Templates.self, forKey: .templates) - self = .comprehension(dynamics: dynamics, statics: statics, templates: templates) - } else { - let count = container.allKeys.filter(\.isChild).count - // we assume there is a key present for every value in [0,count) - // because we need to be able to intersperse the children in the statics - let children = try (0.. String { - var s = "" - buildStringInternal(buffer: &s, root: root, templates: nil, componentStatics: nil, childIndex: nil) - return s - } - - // todo: track which components are used so we can notify the backend of deleted ones - fileprivate func buildStringInternal(buffer: inout String, root: Root, templates: Templates?, componentStatics: ComponentStatics?, childIndex: Int?) { - let effectiveStatics = statics.effectiveValue(in: templates, root: root, componentStatics: componentStatics, childIndex: childIndex) - - switch self { - case .regular(let children, statics: _): - assert(effectiveStatics.count == children.count + 1) - buffer += effectiveStatics[0] - for i in children.indices { - children[i].buildStringInternal(buffer: &buffer, root: root, templates: templates, componentStatics: componentStatics, childIndex: childIndex) - buffer += effectiveStatics[i + 1] - } - - case .comprehension(let dynamics, statics: _, let compTemplates): - for dynamicComponents in dynamics { - assert(effectiveStatics.count == dynamicComponents.count + 1) - - buffer += effectiveStatics[0] - for i in dynamicComponents.indices { - dynamicComponents[i].buildStringInternal(buffer: &buffer, root: root, templates: compTemplates ?? templates, componentStatics: componentStatics, childIndex: childIndex) - buffer += effectiveStatics[i + 1] - } - } - } - } - - enum CodingKeys: CodingKey { - case statics - case dynamics - case templates - case child(Int) - - var isChild: Bool { - switch self { - case .child(_): - return true - default: - return false - } - } - - var stringValue: String { - switch self { - case .statics: - return "s" - case .dynamics: - return "d" - case .templates: - return "p" - case .child(let index): - return index.description - } - } - - var intValue: Int? { - switch self { - case .child(let index): - return index - default: - return nil - } - } - - init?(stringValue: String) { - if let index = Int(stringValue) { - self = .child(index) - } else { - switch stringValue { - case "s": - self = .statics - case "d": - self = .dynamics - case "p": - self = .templates - default: - return nil - } - } - } - - init?(intValue: Int) { - self = .child(intValue) - } - } -} - -enum Statics: Decodable, Equatable { - case statics([String]) - case templateRef(Int) - case componentRef - - init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() - if let number = try? container.decode(Int.self) { - self = .templateRef(number) - } else { - self = .statics(try container.decode([String].self)) - } - } - - func effectiveValue(in templates: Templates?, root: Root, componentStatics: ComponentStatics?, childIndex: Int?) -> [String] { - switch self { - case .statics(let statics): - return statics - case .templateRef(let i): - guard let templates = templates?.templates[i] else { - preconditionFailure("Static cannot reference template when templates are not provided") - } - - return templates - case .componentRef: - guard case let .componentRef(componentId) = componentStatics, - let component = root.components?[componentId], - let childIndex, - case let .fragment(fragment) = component.children[childIndex] - else { - preconditionFailure("Static cannot reference non-existent component") - } - return fragment.statics.effectiveValue(in: templates, root: root, componentStatics: component.statics, childIndex: childIndex) - } - } -} - -struct Templates: Decodable, Equatable { - let templates: [Int: [String]] - - init(templates: [Int: [String]]) { - self.templates = templates - } - - init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: IntKey.self) - self.templates = try container.allKeys.reduce(into: [:], { partialResult, key in - partialResult[key.intValue!] = try container.decode([String].self, forKey: key) - }) - } - -} - -struct IntKey: CodingKey { - let intValue: Int? - - var stringValue: String { - intValue!.description - } - - init?(intValue: Int) { - self.intValue = intValue - } - - init?(stringValue: String) { - if let i = Int(stringValue) { - self.intValue = i - } else { - return nil - } - } -} diff --git a/Sources/LiveViewNative/FragmentDecoder.swift b/Sources/LiveViewNative/FragmentDecoder.swift deleted file mode 100644 index 1916fa2e8..000000000 --- a/Sources/LiveViewNative/FragmentDecoder.swift +++ /dev/null @@ -1,580 +0,0 @@ -// -// FragmentDecoder.swift -// LiveViewNative -// -// Created by Shadowfacts on 3/14/22. -// - -import Foundation - -/// A ``Decoder`` implementation that lets us decode something that has already been deserialized by ``JSONSerialization``. -struct FragmentDecoder: Decoder { - let data: Any - - var codingPath: [CodingKey] - - var userInfo: [CodingUserInfoKey : Any] = [:] - - init(data: Any, codingPath: [CodingKey] = []) { - self.data = data - self.codingPath = codingPath - } - - func container(keyedBy type: Key.Type) throws -> KeyedDecodingContainer where Key : CodingKey { - guard let dict = data as? [String: Any] else { - throw DecodingError.typeMismatch([String: Any].self, .init(codingPath: codingPath, debugDescription: "expected [String: Any]")) - } - return KeyedDecodingContainer(KeyedFragmentDecodingContainer(data: dict, codingPath: codingPath)) - } - - func unkeyedContainer() throws -> UnkeyedDecodingContainer { - guard let array = data as? [Any] else { - throw DecodingError.typeMismatch([String: Any].self, .init(codingPath: codingPath, debugDescription: "expected [Any]")) - } - return UnkeyedFragmentDecodingContainer(value: array, codingPath: codingPath) - } - - func singleValueContainer() throws -> SingleValueDecodingContainer { - return SingleValueFragmentDecodingContainer(value: data, codingPath: codingPath) - } -} - -struct KeyedFragmentDecodingContainer: KeyedDecodingContainerProtocol { - let data: [String: Any] - let codingPath: [CodingKey] - - var allKeys: [Key] { - data.keys.compactMap { - Key(stringValue: $0) - } - } - - private func notFound(_ key: Key) -> DecodingError { - return .keyNotFound(key, .init(codingPath: codingPath + [key], debugDescription: "\(key) not found")) - } - - private func typeMismatch(_ expected: Any.Type, _ key: Key) -> DecodingError { - return .typeMismatch(expected, .init(codingPath: codingPath + [key], debugDescription: "expected \(key) to be \(expected)")) - } - - func contains(_ key: Key) -> Bool { - data.keys.contains(key.stringValue) - } - - func decodeNil(forKey key: Key) throws -> Bool { - guard let value = data[key.stringValue] else { - throw notFound(key) - } - return value is NSNull - } - - func decode(_ type: Bool.Type, forKey key: Key) throws -> Bool { - guard let value = data[key.stringValue] else { - throw notFound(key) - } - guard let number = value as? NSNumber else { - throw typeMismatch(NSNumber.self, key) - } - return number.boolValue - } - - func decode(_ type: String.Type, forKey key: Key) throws -> String { - guard let value = data[key.stringValue] else { - throw notFound(key) - } - guard let str = value as? NSString else { - throw typeMismatch(NSString.self, key) - } - return str as String - } - - func decode(_ type: Double.Type, forKey key: Key) throws -> Double { - guard let value = data[key.stringValue] else { - throw notFound(key) - } - guard let number = value as? NSNumber else { - throw typeMismatch(NSNumber.self, key) - } - return number.doubleValue - } - - func decode(_ type: Float.Type, forKey key: Key) throws -> Float { - guard let value = data[key.stringValue] else { - throw notFound(key) - } - guard let number = value as? NSNumber else { - throw typeMismatch(NSNumber.self, key) - } - return number.floatValue - } - - func decode(_ type: Int.Type, forKey key: Key) throws -> Int { - guard let value = data[key.stringValue] else { - throw notFound(key) - } - guard let number = value as? NSNumber else { - throw typeMismatch(NSNumber.self, key) - } - return number.intValue - } - - func decode(_ type: Int8.Type, forKey key: Key) throws -> Int8 { - guard let value = data[key.stringValue] else { - throw notFound(key) - } - guard let number = value as? NSNumber else { - throw typeMismatch(NSNumber.self, key) - } - return number.int8Value - } - - func decode(_ type: Int16.Type, forKey key: Key) throws -> Int16 { - guard let value = data[key.stringValue] else { - throw notFound(key) - } - guard let number = value as? NSNumber else { - throw typeMismatch(NSNumber.self, key) - } - return number.int16Value - } - - func decode(_ type: Int32.Type, forKey key: Key) throws -> Int32 { - guard let value = data[key.stringValue] else { - throw notFound(key) - } - guard let number = value as? NSNumber else { - throw typeMismatch(NSNumber.self, key) - } - return number.int32Value - } - - func decode(_ type: Int64.Type, forKey key: Key) throws -> Int64 { - guard let value = data[key.stringValue] else { - throw notFound(key) - } - guard let number = value as? NSNumber else { - throw typeMismatch(NSNumber.self, key) - } - return number.int64Value - } - - func decode(_ type: UInt.Type, forKey key: Key) throws -> UInt { - guard let value = data[key.stringValue] else { - throw notFound(key) - } - guard let number = value as? NSNumber else { - throw typeMismatch(NSNumber.self, key) - } - return number.uintValue - } - - func decode(_ type: UInt8.Type, forKey key: Key) throws -> UInt8 { - guard let value = data[key.stringValue] else { - throw notFound(key) - } - guard let number = value as? NSNumber else { - throw typeMismatch(NSNumber.self, key) - } - return number.uint8Value - } - - func decode(_ type: UInt16.Type, forKey key: Key) throws -> UInt16 { - guard let value = data[key.stringValue] else { - throw notFound(key) - } - guard let number = value as? NSNumber else { - throw typeMismatch(NSNumber.self, key) - } - return number.uint16Value - } - - func decode(_ type: UInt32.Type, forKey key: Key) throws -> UInt32 { - guard let value = data[key.stringValue] else { - throw notFound(key) - } - guard let number = value as? NSNumber else { - throw typeMismatch(NSNumber.self, key) - } - return number.uint32Value - } - - func decode(_ type: UInt64.Type, forKey key: Key) throws -> UInt64 { - guard let value = data[key.stringValue] else { - throw notFound(key) - } - guard let number = value as? NSNumber else { - throw typeMismatch(NSNumber.self, key) - } - return number.uint64Value - } - - func decode(_ type: T.Type, forKey key: Key) throws -> T where T : Decodable { - guard let value = data[key.stringValue] else { - throw notFound(key) - } - return try T(from: FragmentDecoder(data: value, codingPath: codingPath + [key])) - } - - func nestedContainer(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer where NestedKey : CodingKey { - guard let value = data[key.stringValue] else { - throw notFound(key) - } - guard let dict = value as? [String: Any] else { - throw typeMismatch([String: Any].self, key) - } - return KeyedDecodingContainer(KeyedFragmentDecodingContainer(data: dict, codingPath: codingPath + [key])) - } - - func nestedUnkeyedContainer(forKey key: Key) throws -> UnkeyedDecodingContainer { - guard let value = data[key.stringValue] else { - throw notFound(key) - } - guard let array = value as? [Any] else { - throw typeMismatch([Any].self, key) - } - return UnkeyedFragmentDecodingContainer(value: array, codingPath: codingPath + [key]) - } - - func superDecoder() throws -> Decoder { - fatalError("unimplemented") - } - - func superDecoder(forKey key: Key) throws -> Decoder { - fatalError("unimplemented") - } -} - -struct UnkeyedFragmentDecodingContainer: UnkeyedDecodingContainer { - - let value: [Any] - let codingPath: [CodingKey] - - var count: Int? { - value.count - } - - var isAtEnd: Bool { - currentIndex >= value.count - } - - var currentIndex: Int = 0 - - init(value: [Any], codingPath: [CodingKey]) { - self.value = value - self.codingPath = codingPath - } - - private func typeMismatch(_ expected: Any.Type) -> DecodingError { - return .typeMismatch(expected, .init(codingPath: codingPath + [IntKey(intValue: currentIndex)!], debugDescription: "expected type \(expected)")) - } - - mutating func decodeNil() throws -> Bool { - guard !isAtEnd else { - throw DecodingError.valueNotFound(NSNull.self, .init(codingPath: codingPath, debugDescription: "unkeyed container reached end")) - } - currentIndex += 1 - return value[currentIndex - 1] is NSNull - } - - mutating func decode(_ type: Bool.Type) throws -> Bool { - guard !isAtEnd else { - throw DecodingError.valueNotFound(Bool.self, .init(codingPath: codingPath, debugDescription: "unkeyed container reached end")) - } - guard let num = value[currentIndex] as? NSNumber else { - throw typeMismatch(NSNumber.self) - } - currentIndex += 1 - return num.boolValue - } - - mutating func decode(_ type: String.Type) throws -> String { - guard !isAtEnd else { - throw DecodingError.valueNotFound(String.self, .init(codingPath: codingPath, debugDescription: "unkeyed container reached end")) - } - guard let s = value[currentIndex] as? String else { - throw typeMismatch(String.self) - } - currentIndex += 1 - return s - } - - mutating func decode(_ type: Double.Type) throws -> Double { - guard !isAtEnd else { - throw DecodingError.valueNotFound(Double.self, .init(codingPath: codingPath, debugDescription: "unkeyed container reached end")) - } - guard let num = value[currentIndex] as? NSNumber else { - throw typeMismatch(NSNumber.self) - } - currentIndex += 1 - return num.doubleValue - } - - mutating func decode(_ type: Float.Type) throws -> Float { - guard !isAtEnd else { - throw DecodingError.valueNotFound(Float.self, .init(codingPath: codingPath, debugDescription: "unkeyed container reached end")) - } - guard let num = value[currentIndex] as? NSNumber else { - throw typeMismatch(NSNumber.self) - } - currentIndex += 1 - return num.floatValue - } - - mutating func decode(_ type: Int.Type) throws -> Int { - guard !isAtEnd else { - throw DecodingError.valueNotFound(Int.self, .init(codingPath: codingPath, debugDescription: "unkeyed container reached end")) - } - guard let num = value[currentIndex] as? NSNumber else { - throw typeMismatch(NSNumber.self) - } - currentIndex += 1 - return num.intValue - } - - mutating func decode(_ type: Int8.Type) throws -> Int8 { - guard !isAtEnd else { - throw DecodingError.valueNotFound(Int8.self, .init(codingPath: codingPath, debugDescription: "unkeyed container reached end")) - } - guard let num = value[currentIndex] as? NSNumber else { - throw typeMismatch(NSNumber.self) - } - currentIndex += 1 - return num.int8Value - } - - mutating func decode(_ type: Int16.Type) throws -> Int16 { - guard !isAtEnd else { - throw DecodingError.valueNotFound(Int16.self, .init(codingPath: codingPath, debugDescription: "unkeyed container reached end")) - } - guard let num = value[currentIndex] as? NSNumber else { - throw typeMismatch(NSNumber.self) - } - currentIndex += 1 - return num.int16Value - } - - mutating func decode(_ type: Int32.Type) throws -> Int32 { - guard !isAtEnd else { - throw DecodingError.valueNotFound(Int32.self, .init(codingPath: codingPath, debugDescription: "unkeyed container reached end")) - } - guard let num = value[currentIndex] as? NSNumber else { - throw typeMismatch(NSNumber.self) - } - currentIndex += 1 - return num.int32Value - } - - mutating func decode(_ type: Int64.Type) throws -> Int64 { - guard !isAtEnd else { - throw DecodingError.valueNotFound(Int64.self, .init(codingPath: codingPath, debugDescription: "unkeyed container reached end")) - } - guard let num = value[currentIndex] as? NSNumber else { - throw typeMismatch(NSNumber.self) - } - currentIndex += 1 - return num.int64Value - } - - mutating func decode(_ type: UInt.Type) throws -> UInt { - guard !isAtEnd else { - throw DecodingError.valueNotFound(UInt.self, .init(codingPath: codingPath, debugDescription: "unkeyed container reached end")) - } - guard let num = value[currentIndex] as? NSNumber else { - throw typeMismatch(NSNumber.self) - } - currentIndex += 1 - return num.uintValue - } - - mutating func decode(_ type: UInt8.Type) throws -> UInt8 { - guard !isAtEnd else { - throw DecodingError.valueNotFound(UInt8.self, .init(codingPath: codingPath, debugDescription: "unkeyed container reached end")) - } - guard let num = value[currentIndex] as? NSNumber else { - throw typeMismatch(NSNumber.self) - } - currentIndex += 1 - return num.uint8Value - } - - mutating func decode(_ type: UInt16.Type) throws -> UInt16 { - guard !isAtEnd else { - throw DecodingError.valueNotFound(UInt16.self, .init(codingPath: codingPath, debugDescription: "unkeyed container reached end")) - } - guard let num = value[currentIndex] as? NSNumber else { - throw typeMismatch(NSNumber.self) - } - currentIndex += 1 - return num.uint16Value - } - - mutating func decode(_ type: UInt32.Type) throws -> UInt32 { - guard !isAtEnd else { - throw DecodingError.valueNotFound(UInt32.self, .init(codingPath: codingPath, debugDescription: "unkeyed container reached end")) - } - guard let num = value[currentIndex] as? NSNumber else { - throw typeMismatch(NSNumber.self) - } - currentIndex += 1 - return num.uint32Value - } - - mutating func decode(_ type: UInt64.Type) throws -> UInt64 { - guard !isAtEnd else { - throw DecodingError.valueNotFound(UInt64.self, .init(codingPath: codingPath, debugDescription: "unkeyed container reached end")) - } - guard let num = value[currentIndex] as? NSNumber else { - throw typeMismatch(NSNumber.self) - } - currentIndex += 1 - return num.uint64Value - } - - mutating func decode(_ type: T.Type) throws -> T where T : Decodable { - guard !isAtEnd else { - throw DecodingError.valueNotFound(T.self, .init(codingPath: codingPath, debugDescription: "unkeyed container reached end")) - } - let value = value[currentIndex] - currentIndex += 1 - return try T(from: FragmentDecoder(data: value, codingPath: codingPath)) - } - - mutating func nestedContainer(keyedBy type: NestedKey.Type) throws -> KeyedDecodingContainer where NestedKey : CodingKey { - guard !isAtEnd else { - throw DecodingError.valueNotFound([String: Any].self, .init(codingPath: codingPath, debugDescription: "unkeyed container reached end")) - } - guard let dict = value[currentIndex] as? [String: Any] else { - throw DecodingError.typeMismatch([String: Any].self, .init(codingPath: codingPath, debugDescription: "expected [String: Any]")) - } - currentIndex += 1 - return KeyedDecodingContainer(KeyedFragmentDecodingContainer(data: dict, codingPath: codingPath + [IntKey(intValue: currentIndex - 1)!])) - } - - mutating func nestedUnkeyedContainer() throws -> UnkeyedDecodingContainer { - guard !isAtEnd else { - throw DecodingError.valueNotFound([Any].self, .init(codingPath: codingPath, debugDescription: "unkeyed container reached end")) - } - guard let array = value[currentIndex] as? [Any] else { - throw DecodingError.typeMismatch([Any].self, .init(codingPath: codingPath, debugDescription: "expected [Any]")) - } - currentIndex += 1 - return UnkeyedFragmentDecodingContainer(value: array, codingPath: codingPath + [IntKey(intValue: currentIndex - 1)!]) - } - - mutating func superDecoder() throws -> Decoder { - fatalError("unimplemented") - } - -} - -struct SingleValueFragmentDecodingContainer: SingleValueDecodingContainer { - let value: Any - let codingPath: [CodingKey] - - func decodeNil() -> Bool { - return value is NSNull - } - - func decode(_ type: Bool.Type) throws -> Bool { - guard let num = value as? NSNumber else { - throw DecodingError.typeMismatch(NSNumber.self, .init(codingPath: codingPath, debugDescription: "expected NSNumber")) - } - return num.boolValue - } - - func decode(_ type: String.Type) throws -> String { - guard let s = value as? String else { - throw DecodingError.typeMismatch(NSNumber.self, .init(codingPath: codingPath, debugDescription: "expected String")) - } - return s - } - - func decode(_ type: Double.Type) throws -> Double { - guard let num = value as? NSNumber else { - throw DecodingError.typeMismatch(NSNumber.self, .init(codingPath: codingPath, debugDescription: "expected NSNumber")) - } - return num.doubleValue - } - - func decode(_ type: Float.Type) throws -> Float { - guard let num = value as? NSNumber else { - throw DecodingError.typeMismatch(NSNumber.self, .init(codingPath: codingPath, debugDescription: "expected NSNumber")) - } - return num.floatValue - } - - func decode(_ type: Int.Type) throws -> Int { - guard let num = value as? NSNumber else { - throw DecodingError.typeMismatch(NSNumber.self, .init(codingPath: codingPath, debugDescription: "expected NSNumber")) - } - return num.intValue - } - - func decode(_ type: Int8.Type) throws -> Int8 { - guard let num = value as? NSNumber else { - throw DecodingError.typeMismatch(NSNumber.self, .init(codingPath: codingPath, debugDescription: "expected NSNumber")) - } - return num.int8Value - } - - func decode(_ type: Int16.Type) throws -> Int16 { - guard let num = value as? NSNumber else { - throw DecodingError.typeMismatch(NSNumber.self, .init(codingPath: codingPath, debugDescription: "expected NSNumber")) - } - return num.int16Value - } - - func decode(_ type: Int32.Type) throws -> Int32 { - guard let num = value as? NSNumber else { - throw DecodingError.typeMismatch(NSNumber.self, .init(codingPath: codingPath, debugDescription: "expected NSNumber")) - } - return num.int32Value - } - - func decode(_ type: Int64.Type) throws -> Int64 { - guard let num = value as? NSNumber else { - throw DecodingError.typeMismatch(NSNumber.self, .init(codingPath: codingPath, debugDescription: "expected NSNumber")) - } - return num.int64Value - } - - func decode(_ type: UInt.Type) throws -> UInt { - guard let num = value as? NSNumber else { - throw DecodingError.typeMismatch(NSNumber.self, .init(codingPath: codingPath, debugDescription: "expected NSNumber")) - } - return num.uintValue - } - - func decode(_ type: UInt8.Type) throws -> UInt8 { - guard let num = value as? NSNumber else { - throw DecodingError.typeMismatch(NSNumber.self, .init(codingPath: codingPath, debugDescription: "expected NSNumber")) - } - return num.uint8Value - } - - func decode(_ type: UInt16.Type) throws -> UInt16 { - guard let num = value as? NSNumber else { - throw DecodingError.typeMismatch(NSNumber.self, .init(codingPath: codingPath, debugDescription: "expected NSNumber")) - } - return num.uint16Value - } - - func decode(_ type: UInt32.Type) throws -> UInt32 { - guard let num = value as? NSNumber else { - throw DecodingError.typeMismatch(NSNumber.self, .init(codingPath: codingPath, debugDescription: "expected NSNumber")) - } - return num.uint32Value - } - - func decode(_ type: UInt64.Type) throws -> UInt64 { - guard let num = value as? NSNumber else { - throw DecodingError.typeMismatch(NSNumber.self, .init(codingPath: codingPath, debugDescription: "expected NSNumber")) - } - return num.uint64Value - } - - func decode(_ type: T.Type) throws -> T where T : Decodable { - return try T(from: FragmentDecoder(data: value, codingPath: codingPath)) - } - -} diff --git a/Sources/LiveViewNative/FragmentDiff.swift b/Sources/LiveViewNative/FragmentDiff.swift deleted file mode 100644 index 74f47fd62..000000000 --- a/Sources/LiveViewNative/FragmentDiff.swift +++ /dev/null @@ -1,99 +0,0 @@ -// -// FragmentDiff.swift -// LiveViewNative -// -// Created by Shadowfacts on 3/4/22. -// - -import Foundation - -struct RootDiff: Decodable, Equatable { - let fragment: FragmentDiff - let components: [Int: ComponentDiff]? - - init(fragment: FragmentDiff, components: [Int: ComponentDiff]?) { - self.fragment = fragment - self.components = components - } - - init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: Root.CodingKeys.self) - self.fragment = try decoder.singleValueContainer().decode(FragmentDiff.self) - - if let componentsContainer = try? container.nestedContainer(keyedBy: IntKey.self, forKey: .components) { - self.components = try componentsContainer.allKeys.reduce(into: [Int: ComponentDiff](minimumCapacity: container.allKeys.count), { partialResult, key in - partialResult[key.intValue!] = try componentsContainer.decode(ComponentDiff.self, forKey: key) - }) - } else { - self.components = nil - } - } -} - -enum FragmentDiff: Decodable, Equatable { - case replaceCurrent(Fragment) - case updateRegular(children: [Int: ChildDiff]) - // note: when updating a comprehension, all dynamics are always sent - case updateComprehension(dynamics: [[ChildDiff]], templates: Templates?) - - init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: Fragment.CodingKeys.self) - - // statics are static and don't change, thus the presence of them indicates this diff is a complete overwrite - if container.contains(.statics) { - self = .replaceCurrent(try decoder.singleValueContainer().decode(Fragment.self)) - } else if container.contains(.dynamics) { - let dynamics = try container.decode([[ChildDiff]].self, forKey: .dynamics) - let templates = try container.decodeIfPresent(Templates.self, forKey: .templates) - self = .updateComprehension(dynamics: dynamics, templates: templates) - } else { - let children = try container.allKeys - .filter(\.isChild) - .reduce(into: [:]) { partialResult, key in - partialResult[key.intValue!] = try container.decode(ChildDiff.self, forKey: key) - } - self = .updateRegular(children: children) - } - } -} - -enum ComponentDiff: Decodable, Equatable { - case replaceCurrent(Component) - case updateRegular(children: [Int: ChildDiff]) - // note: component diffs don't have comprehensions, because the Component can't be a comprehension - - init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: Component.CodingKeys.self) - // validate our assumption that components can't be dynamic - assert(!container.contains(.dynamics)) - - if container.contains(.statics) { - self = .replaceCurrent(try decoder.singleValueContainer().decode(Component.self)) - } else { - let children = try container.allKeys - .filter(\.isChild) - .reduce(into: [:], { partialResult, key in - partialResult[key.intValue!] = try container.decode(ChildDiff.self, forKey: key) - }) - self = .updateRegular(children: children) - } - } -} - -enum ChildDiff: Decodable, Equatable { - case fragment(FragmentDiff) - case componentID(Int) - case string(String) - - init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() - - if let id = try? container.decode(Int.self) { - self = .componentID(id) - } else if let str = try? container.decode(String.self) { - self = .string(str) - } else { - self = .fragment(try container.decode(FragmentDiff.self)) - } - } -} diff --git a/Sources/LiveViewNative/Live/LiveElement.swift b/Sources/LiveViewNative/Live/LiveElement.swift index 6e857a453..ad84e1cda 100644 --- a/Sources/LiveViewNative/Live/LiveElement.swift +++ b/Sources/LiveViewNative/Live/LiveElement.swift @@ -77,7 +77,9 @@ public protocol _LiveElementTrackedContent { init(from element: ElementNode) throws } -@propertyWrapper public struct _LiveElementTracked: DynamicProperty { +@MainActor +@propertyWrapper +public struct _LiveElementTracked: @preconcurrency DynamicProperty { /// The ``ElementNode`` used to build a live element. @ObservedElement public var element /// The ``LiveContext`` for a live element. @@ -114,8 +116,9 @@ public extension _LiveElementTracked { /// You can provide a custom `predicate` to filter different elements. /// /// - Parameter predicate: The filter used to select child nodes for render. + @MainActor func children(_ predicate: (Node) -> Bool = { node in - !node.attributes.contains(where: { $0.name.namespace == nil && $0.name.name == "template" }) + !node.attributes().contains(where: { $0.name.namespace == nil && $0.name.name == "template" }) }) -> some View { context.coordinator.builder.fromNodes(_element.children.filter(predicate), context: context.storage) } @@ -124,11 +127,12 @@ public extension _LiveElementTracked { /// /// - Parameter template: The ``Template`` used to filter child elements. A String literal can be provided for simple template values. /// - Parameter includeDefault: Whether elements without a `template` attribute should be included in the filter. Defaults to `false`. + @MainActor func children(in template: Template, default includeDefault: Bool = false) -> some View { children { - $0.attributes.contains(where: { + $0.attributes().contains(where: { $0 == template - }) || (includeDefault && !$0.attributes.contains(where: { $0.name.namespace == nil && $0.name.name == "template" })) + }) || (includeDefault && !$0.attributes().contains(where: { $0.name.namespace == nil && $0.name.name == "template" })) } } @@ -136,9 +140,10 @@ public extension _LiveElementTracked { /// /// - Parameter template: The ``Template`` used to filter child elements. A String literal can be provided for simple template values. /// - Parameter includeDefault: Whether elements without a `template` attribute should be included in the filter. Defaults to `false`. + @MainActor func hasTemplate(_ template: Template, default includeDefault: Bool = false) -> Bool { _element.children.contains(where: { - for attribute in $0.attributes { + for attribute in $0.attributes() { if attribute == template { return true } else if includeDefault && attribute.name.namespace == nil && attribute.name.name == "template" { @@ -149,20 +154,23 @@ public extension _LiveElementTracked { }) } + @MainActor func hasTemplate(_ name: String, value: String) -> Bool { hasTemplate(.init(name, value: value)) } /// Array containing children of the ``ElementNode``. + @MainActor var childNodes: [LiveViewNativeCore.Node] { _element.children } + @MainActor func childNodes(in template: Template, default includeDefault: Bool = false) -> [LiveViewNativeCore.Node] { _element.children.filter { - $0.attributes.contains(where: { + $0.attributes().contains(where: { $0 == template - }) || (includeDefault && !$0.attributes.contains(where: { $0.name.namespace == nil && $0.name.name == "template" })) + }) || (includeDefault && !$0.attributes().contains(where: { $0.name.namespace == nil && $0.name.name == "template" })) } } } diff --git a/Sources/LiveViewNative/Live/LiveView.swift b/Sources/LiveViewNative/Live/LiveView.swift index 9291c736b..01bbf1c9d 100644 --- a/Sources/LiveViewNative/Live/LiveView.swift +++ b/Sources/LiveViewNative/Live/LiveView.swift @@ -131,6 +131,7 @@ public macro LiveView< /// - ``body`` /// ### See Also /// - ``LiveViewModel`` +@MainActor public struct LiveView< R: RootRegistry, PhaseView: View, @@ -149,6 +150,7 @@ public struct LiveView< let reconnectingView: (_ConnectedContent, Bool) -> ReconnectingView let errorView: (Error) -> ErrorView + @MainActor @ViewBuilder func buildPhaseView(_ phase: LiveViewPhase) -> some View { if PhaseView.self != Never.self { @@ -208,6 +210,7 @@ public struct LiveView< } } + @MainActor public var body: some View { SwiftUI.Group { buildPhaseView(phase) @@ -221,14 +224,16 @@ public struct LiveView< .environment(\.stylesheet, session.stylesheet ?? .init(content: [], classes: [:])) .environment(\.reconnectLiveView, .init(baseURL: session.url, action: session.reconnect)) .environmentObject(session) - .task(priority: .userInitiated) { + .task { await session.connect() } .onChange(of: scenePhase) { newValue in - guard case .active = newValue, - session.socket?.isConnected == false + guard case .active = newValue else { return } - Task(priority: .userInitiated) { + if case .connected = session.socket?.status() { + return + } + Task { await session.connect() } } @@ -267,10 +272,10 @@ public struct _ConnectedContent: View { extension EnvironmentValues { enum LiveViewStateViewsKey: EnvironmentKey { - static let defaultValue: [ObjectIdentifier:(Any) -> AnyView] = [:] + static let defaultValue: [ObjectIdentifier: @MainActor (Any) -> AnyView] = [:] } - var liveViewStateViews: [ObjectIdentifier:(Any) -> AnyView] { + var liveViewStateViews: [ObjectIdentifier: @MainActor (Any) -> AnyView] { get { self[LiveViewStateViewsKey.self] } set { self[LiveViewStateViewsKey.self] = newValue } } diff --git a/Sources/LiveViewNative/Live/ReconnectLiveViewAction.swift b/Sources/LiveViewNative/Live/ReconnectLiveViewAction.swift index 51d99b470..371c543ab 100644 --- a/Sources/LiveViewNative/Live/ReconnectLiveViewAction.swift +++ b/Sources/LiveViewNative/Live/ReconnectLiveViewAction.swift @@ -8,6 +8,7 @@ import SwiftUI /// Calls ``LiveSessionCoordinator/reconnect(url:httpMethod:httpBody:)`` in the current context. +@MainActor public struct ReconnectLiveViewAction { let baseURL: URL? let action: (_ url: URL?, _ httpMethod: String?, _ httpBody: Data?) async -> () @@ -30,7 +31,8 @@ public struct ReconnectLiveViewAction { } extension EnvironmentValues { - private enum ReconnectLiveViewActionKey: EnvironmentKey { + @MainActor + private enum ReconnectLiveViewActionKey: @preconcurrency EnvironmentKey { static let defaultValue: ReconnectLiveViewAction = .init(baseURL: nil, action: { _, _, _ in }) } diff --git a/Sources/LiveViewNative/Navigation/LiveRedirect.swift b/Sources/LiveViewNative/Navigation/LiveRedirect.swift index 7c68bd125..79d47d603 100644 --- a/Sources/LiveViewNative/Navigation/LiveRedirect.swift +++ b/Sources/LiveViewNative/Navigation/LiveRedirect.swift @@ -6,6 +6,7 @@ // import Foundation +import LiveViewNativeCore struct LiveRedirect: Hashable { let kind: Kind @@ -44,12 +45,21 @@ struct LiveRedirect: Hashable { self.mode = mode } - init?(from payload: Payload, relativeTo rootURL: URL, mode: Mode = .replaceTop) { - guard let kind = (payload["kind"] as? String).flatMap(Kind.init), - let to = (payload["to"] as? String).flatMap({ URL.init(string: $0, relativeTo: rootURL) }) + init?(from object: [String:LiveViewNativeCore.Json], relativeTo rootURL: URL, mode: Mode = .replaceTop) { + guard case .str(string: let kindString) = object["kind"], + let kind = Kind(rawValue: kindString), + case .str(string: let toString) = object["to"], + let to = URL(string: toString, relativeTo: rootURL) else { return nil } self.kind = kind self.to = to.appending(path: "").absoluteURL - self.mode = (payload["mode"] as? String).flatMap(Mode.init) ?? mode + self.mode = if + case let .str(string: modeString) = object["mode"], + let mode = Mode(rawValue: modeString) + { + mode + } else { + mode + } } } diff --git a/Sources/LiveViewNative/Property Wrappers/ChangeTracked.swift b/Sources/LiveViewNative/Property Wrappers/ChangeTracked.swift index ba17e57f6..605eb86cf 100644 --- a/Sources/LiveViewNative/Property Wrappers/ChangeTracked.swift +++ b/Sources/LiveViewNative/Property Wrappers/ChangeTracked.swift @@ -30,7 +30,8 @@ import Combine /// def handle_event("update-value", new_value, socket), do: ... /// ``` @propertyWrapper -public struct ChangeTracked: DynamicProperty { +@MainActor +public struct ChangeTracked: @preconcurrency DynamicProperty, Sendable { @StateObject private var localValue: LocalValue @ObservedElement var element @Environment(\.coordinatorEnvironment) var coordinator @@ -181,7 +182,7 @@ extension ChangeTracked where Value: FormValue { guard let self, self.sendChangeEvent else { return } - try await pushChangeEvent(to: changeTracked) + try await self.pushChangeEvent(to: changeTracked) } } }) @@ -213,10 +214,6 @@ extension ChangeTracked where Value: FormValue { try await changeTracked.event(value: JSONSerialization.jsonObject(with: JSONEncoder().encode([self.attribute.rawValue: encodedValue]), options: .fragmentsAllowed)) } } - - func pushChangeEvent() async throws { - try await (self.localValue as? FormLocalValue)?.pushChangeEvent(to: self) - } } private protocol LocalValueProtocol: ObservableObject { diff --git a/Sources/LiveViewNative/Property Wrappers/Event.swift b/Sources/LiveViewNative/Property Wrappers/Event.swift index d74f6f727..80e153da1 100644 --- a/Sources/LiveViewNative/Property Wrappers/Event.swift +++ b/Sources/LiveViewNative/Property Wrappers/Event.swift @@ -65,8 +65,9 @@ import AsyncAlgorithms ///- ``wrappedValue`` ///### Supporting Types ///- ``EventHandler`` +@MainActor @propertyWrapper -public struct Event: DynamicProperty, Decodable { +public struct Event: @preconcurrency DynamicProperty, @preconcurrency Decodable { @ObservedElement private var element: ElementNode @Environment(\.coordinatorEnvironment) private var coordinatorEnvironment @StateObject var handler = Handler() @@ -123,8 +124,16 @@ public struct Event: DynamicProperty, Decodable { } } + @MainActor final class Handler: ObservableObject { - let channel = AsyncChannel<(String, String, Any, Int?)>() + let channel = AsyncChannel() + + struct EventPayload: @unchecked Sendable { + let type: String + let event: String + let payload: Any + let target: Int? + } private var handlerTask: Task<(), Error>? @@ -135,30 +144,38 @@ public struct Event: DynamicProperty, Decodable { init() {} + deinit { + self.handlerTask?.cancel() + } + func update(coordinator: CoordinatorEnvironment?, debounce: Double?, throttle: Double?) { guard handlerTask == nil || debounce != self.debounce || throttle != self.throttle else { return } handlerTask?.cancel() self.debounce = debounce self.throttle = throttle + let pushEvent = coordinator?.pushEvent if let debounce = debounce { - handlerTask = Task { [weak didSendSubject] in + handlerTask = Task { [weak channel, weak didSendSubject, pushEvent] in + guard let channel else { return } for await event in channel.debounce(for: .milliseconds(debounce)) { - _ = try await coordinator?.pushEvent(event.0, event.1, event.2, event.3) + _ = try await pushEvent?(event.type, event.event, event.payload, event.target) didSendSubject?.send() } } } else if let throttle = throttle { - handlerTask = Task { [weak didSendSubject] in - for await event in channel.throttle(for: .milliseconds(throttle)) { - _ = try await coordinator?.pushEvent(event.0, event.1, event.2, event.3) + handlerTask = Task { @MainActor [weak channel, weak didSendSubject, pushEvent] in + guard let channel else { return } + for await event in channel._throttle(for: .milliseconds(throttle)) { + _ = try await pushEvent?(event.type, event.event, event.payload, event.target) didSendSubject?.send() } } } else { - handlerTask = Task { [weak didSendSubject] in + handlerTask = Task { @MainActor [weak channel, weak didSendSubject, pushEvent] in + guard let channel else { return } for await event in channel { - _ = try await coordinator?.pushEvent(event.0, event.1, event.2, event.3) + _ = try await pushEvent?(event.type, event.event, event.payload, event.target) didSendSubject?.send() } } @@ -327,7 +344,12 @@ public struct Event: DynamicProperty, Decodable { guard let event else { return } - await owner.handler.channel.send((owner.type, event, owner.params ?? value, owner.target ?? owner.element.attributeValue(for: "phx-target").flatMap(Int.init))) + await owner.handler.channel.send(.init( + type: owner.type, + event: event, + payload: owner.params ?? value, + target: owner.target ?? owner.element.attributeValue(for: "phx-target").flatMap(Int.init) + )) } public func callAsFunction(value: Any = [String:String](), in context: LiveContext) async throws { @@ -340,7 +362,12 @@ public struct Event: DynamicProperty, Decodable { debounce: owner.debounce, throttle: owner.throttle ) - await handler.channel.send((owner.type, event, owner.params ?? value, owner.target)) + await handler.channel.send(.init( + type: owner.type, + event: event, + payload: owner.params ?? value, + target: owner.target + )) } } } diff --git a/Sources/LiveViewNative/Property Wrappers/FormState.swift b/Sources/LiveViewNative/Property Wrappers/FormState.swift index 809ee790b..742ea2a02 100644 --- a/Sources/LiveViewNative/Property Wrappers/FormState.swift +++ b/Sources/LiveViewNative/Property Wrappers/FormState.swift @@ -54,6 +54,7 @@ private let logger = Logger(subsystem: "LiveViewNative", category: "FormState") /// } /// } /// ``` +@MainActor @propertyWrapper public struct FormState { private let defaultValue: Value @@ -236,7 +237,7 @@ public struct FormState { } } -extension FormState: DynamicProperty { +extension FormState: @preconcurrency DynamicProperty { public func update() { resolveMode() } @@ -244,6 +245,7 @@ extension FormState: DynamicProperty { // This class contains any data that may need to change during a view update (since @State can't be used). // It also serves to notify SwiftUI when this @FormState's particular field has changed (as opposed to updates for other fields). +@MainActor private class FormStateData: ObservableObject { var mode: Mode = .unknown diff --git a/Sources/LiveViewNative/Property Wrappers/LiveContext.swift b/Sources/LiveViewNative/Property Wrappers/LiveContext.swift index 6be675a15..4a74ed8df 100644 --- a/Sources/LiveViewNative/Property Wrappers/LiveContext.swift +++ b/Sources/LiveViewNative/Property Wrappers/LiveContext.swift @@ -20,6 +20,7 @@ import LiveViewNativeCore /// } /// } /// ``` +@MainActor @propertyWrapper public struct LiveContext: DynamicProperty { @Environment(\.anyLiveContextStorage) private var anyStorage @@ -81,7 +82,7 @@ public struct LiveContext: DynamicProperty { /// Ignores any children with a `template` attribute. public func buildChildren(of element: ElementNode) -> some View { return coordinator.builder.fromNodes(element.children().filter({ - if case let .element(element) = $0.data { + if case let .nodeElement(element) = $0.data() { return !element.attributes.contains(where: { $0.name == "template" }) } else { return true @@ -93,7 +94,7 @@ public struct LiveContext: DynamicProperty { _ template: String ) -> (NodeChildrenSequence.Element) -> Bool { { child in - if case let .element(element) = child.data, + if case let .nodeElement(element) = child.data(), element.attributes.first(where: { $0.name == "template" })?.value == template { return true @@ -104,7 +105,7 @@ public struct LiveContext: DynamicProperty { } private static func hasTemplateAttribute(_ child: NodeChildrenSequence.Element) -> Bool { - if case let .element(element) = child.data, + if case let .nodeElement(element) = child.data(), element.attributes.contains(where: { $0.name == "template" }) { return true @@ -150,7 +151,7 @@ public struct LiveContext: DynamicProperty { let namedSlotChildren = children.filter(Self.isTemplateElement(template)) if namedSlotChildren.isEmpty && includeDefaultSlot { let defaultSlotChildren = children.filter({ - if case let .element(element) = $0.data { + if case let .nodeElement(element) = $0.data() { return !element.attributes.contains(where: { $0.name.rawValue == "template" }) @@ -192,7 +193,7 @@ public struct LiveContext: DynamicProperty { of element: ElementNode ) -> [NodeChildrenSequence.Element] { element.children().filter { - !$0.attributes.contains(where: { $0.name.rawValue == "template" }) + !$0.attributes().contains(where: { $0.name.rawValue == "template" }) } } } diff --git a/Sources/LiveViewNative/Property Wrappers/ObservedElement.swift b/Sources/LiveViewNative/Property Wrappers/ObservedElement.swift index 77c73f01e..93da5cf66 100644 --- a/Sources/LiveViewNative/Property Wrappers/ObservedElement.swift +++ b/Sources/LiveViewNative/Property Wrappers/ObservedElement.swift @@ -49,11 +49,12 @@ import Combine /// } /// } /// ``` +@MainActor @propertyWrapper public struct ObservedElement { @Environment(\.coordinatorEnvironment) private var coordinator: CoordinatorEnvironment? @EnvironmentObject private var observer: Observer - + private let observeChildren: Bool private let overrideElement: ElementNode? @@ -62,42 +63,42 @@ public struct ObservedElement { var isConstant: Bool { overrideElement != nil } - + /// Creates an `ObservedElement` that observes changes to the view's element. public init(observeChildren: Bool = false) { self.overrideElement = nil self.observeChildren = observeChildren } - + public init(element: ElementNode, observeChildren: Bool = false) { self.overrideElement = element self.observeChildren = observeChildren } - + public init() { self.overrideElement = nil self.observeChildren = false } - + /// The observed element in the document, with all current data. public var wrappedValue: ElementNode { overrideElement ?? observer.resolvedElement } - + /// A publisher that publishes when the observed element changes. public var projectedValue: some Publisher { observer.elementChangedPublisher } - + var children: [Node] { overrideElement.flatMap({ Array($0.children()) }) ?? observer.resolvedChildren } } -extension ObservedElement: DynamicProperty { +extension ObservedElement: @preconcurrency DynamicProperty { public mutating func update() { guard let coordinator else { fatalError("Cannot use @ObservedElement on view that does not have an element and coordinator in the environment") } - + self.observer.update( coordinator, observeChildren: observeChildren @@ -108,8 +109,9 @@ extension ObservedElement: DynamicProperty { extension ObservedElement { final class Observer: ObservableObject { private var cancellable: AnyCancellable? - + let id: NodeRef + var observedChildIDs: Set = [] var resolvedElement: ElementNode! @@ -119,7 +121,7 @@ extension ObservedElement { if let _resolvedChildIDs { return _resolvedChildIDs } else { - let result = Set(self.resolvedChildren.map(\.id)) + let result = Set(self.resolvedChildren.map({ $0.id() })) _resolvedChildIDs = result return result } @@ -128,18 +130,17 @@ extension ObservedElement { var objectWillChange = ObjectWillChangePublisher() var elementChangedPublisher: AnyPublisher! - init(_ id: NodeRef) { self.id = id } - + @MainActor fileprivate func update( _ context: CoordinatorEnvironment, observeChildren: Bool ) { guard cancellable == nil || (observeChildren && self.observedChildIDs != self.resolvedChildIDs) else { return } - self.resolvedElement = context.document[id].asElement() + self.resolvedElement = context.document?[id].asElement() self.resolvedChildren = Array(self.resolvedElement.children()) self._resolvedChildIDs = nil @@ -160,22 +161,22 @@ extension ObservedElement { cancellable = self.elementChangedPublisher .sink { [weak self] _ in guard let self else { return } - self.resolvedElement = context.document[id].asElement() + self.resolvedElement = context.document?[id].asElement() self.resolvedChildren = Array(self.resolvedElement.children()) self._resolvedChildIDs = nil self.objectWillChange.send() } } - + struct Applicator: View { @StateObject private var observer: Observer let content: Content - + init(_ id: NodeRef, @ViewBuilder content: () -> Content) { self._observer = .init(wrappedValue: .init(id)) self.content = content() } - + var body: some View { content .environmentObject(observer) @@ -183,3 +184,9 @@ extension ObservedElement { } } } + +private extension Optional where Wrapped == ElementNode { + var nodeRef: NodeRef? { + self?.node.id() + } +} diff --git a/Sources/LiveViewNative/Protocols/ContentBuilder.swift b/Sources/LiveViewNative/Protocols/ContentBuilder.swift index e09f768de..793460e5a 100644 --- a/Sources/LiveViewNative/Protocols/ContentBuilder.swift +++ b/Sources/LiveViewNative/Protocols/ContentBuilder.swift @@ -215,6 +215,7 @@ import LiveViewNativeStylesheet /// } /// } /// ``` +@MainActor public protocol ContentBuilder { /// An enum with the supported element names. associatedtype TagName: RawRepresentable @@ -309,8 +310,9 @@ public extension ContentBuilder { /// } /// } /// ``` +@MainActor @propertyWrapper -public struct ContentBuilderContext: DynamicProperty { +public struct ContentBuilderContext: @preconcurrency DynamicProperty { @Environment(\.coordinatorEnvironment) private var coordinatorEnvironment @LiveContext private var context @Environment(\.stylesheet) private var stylesheet @@ -333,6 +335,7 @@ public struct ContentBuilderContext: D ) } + @MainActor public struct Value { let coordinatorEnvironment: CoordinatorEnvironment? public let context: LiveContext @@ -501,14 +504,14 @@ public extension ContentBuilder { return try build( element .children() - .filter({ $0.attributes.contains(where: { $0.name == "template" && $0.value == template }) }), + .filter({ $0.attributes().contains(where: { $0.name == "template" && $0.value == template }) }), in: context ) } else { return try build( element .children() - .filter({ !$0.attributes.contains(where: { $0.name == "template" }) }), + .filter({ !$0.attributes().contains(where: { $0.name == "template" }) }), in: context ) } @@ -522,7 +525,7 @@ public extension ContentBuilder { return try build( element .children() - .filter({ $0.attributes.contains(where: { $0.name == "template" && template.value.contains($0.value ?? "") }) }), + .filter({ $0.attributes().contains(where: { $0.name == "template" && template.value.contains($0.value ?? "") }) }), in: context ) } @@ -569,7 +572,7 @@ public extension ContentBuilder { if let template { ViewTreeBuilder().fromNodes( element.children() - .filter({ $0.attributes.contains(where: { $0.name == "template" && $0.value == template }) }), + .filter({ $0.attributes().contains(where: { $0.name == "template" && $0.value == template }) }), context: context.context.storage ) .environment(\.coordinatorEnvironment, context.coordinatorEnvironment) @@ -577,7 +580,7 @@ public extension ContentBuilder { } else { ViewTreeBuilder().fromNodes( element.children() - .filter({ !$0.attributes.contains(where: { $0.name == "template" }) }), + .filter({ !$0.attributes().contains(where: { $0.name == "template" }) }), context: context.context.storage ) .environment(\.coordinatorEnvironment, context.coordinatorEnvironment) @@ -593,7 +596,7 @@ public extension ContentBuilder { ) -> some View { ViewTreeBuilder().fromNodes( element.children() - .filter({ $0.attributes.contains(where: { $0.name == "template" && template.value.contains($0.value ?? "") }) }), + .filter({ $0.attributes().contains(where: { $0.name == "template" && template.value.contains($0.value ?? "") }) }), context: context.context.storage ) .environment(\.coordinatorEnvironment, context.coordinatorEnvironment) @@ -608,7 +611,7 @@ public extension ContentBuilder { ) -> SwiftUI.Text { element.children() .lazy - .filter({ $0.attributes.contains(where: { $0.name == "template" && template.value.contains($0.value ?? "") }) }) + .filter({ $0.attributes().contains(where: { $0.name == "template" && template.value.contains($0.value ?? "") }) }) .first?.asElement().flatMap({ Text(element: $0, overrideStylesheet: context.stylesheet).body }) ?? SwiftUI.Text("") } diff --git a/Sources/LiveViewNative/Registries/AggregateRegistry.swift b/Sources/LiveViewNative/Registries/AggregateRegistry.swift index 30c16f4a2..fba12bea8 100644 --- a/Sources/LiveViewNative/Registries/AggregateRegistry.swift +++ b/Sources/LiveViewNative/Registries/AggregateRegistry.swift @@ -135,7 +135,8 @@ public enum _EitherCustomModifier _ParserType(context: context) } - public struct _ParserType: Parser { + @MainActor + public struct _ParserType: @preconcurrency Parser { let context: ParseableModifierContext public func parse(_ input: inout Substring.UTF8View) throws -> _EitherCustomModifier { diff --git a/Sources/LiveViewNative/Registries/BuiltinRegistry.swift b/Sources/LiveViewNative/Registries/BuiltinRegistry.swift index 0c7e912b4..9afd3447c 100644 --- a/Sources/LiveViewNative/Registries/BuiltinRegistry.swift +++ b/Sources/LiveViewNative/Registries/BuiltinRegistry.swift @@ -15,6 +15,7 @@ protocol BuiltinRegistryProtocol { associatedtype BuiltinModifier: ViewModifier & ParseableModifierValue } +@MainActor struct BuiltinRegistry: BuiltinRegistryProtocol { static func lookup(_ name: String, _ element: ElementNode) -> some View { return BuiltinElement(name: name, element: element) diff --git a/Sources/LiveViewNative/Registries/CustomRegistry.swift b/Sources/LiveViewNative/Registries/CustomRegistry.swift index 2478e29ef..03c270da3 100644 --- a/Sources/LiveViewNative/Registries/CustomRegistry.swift +++ b/Sources/LiveViewNative/Registries/CustomRegistry.swift @@ -71,6 +71,7 @@ public macro Addon() = #externalMacro(module: "LiveViewNativeMacros", type: "Add /// ### Supporting Types /// - ``EmptyRegistry`` /// - ``ViewModifierBuilder`` +@MainActor public protocol CustomRegistry { /// The root custom registry type that the live view coordinator and context use. /// @@ -247,7 +248,8 @@ extension CustomRegistry where TagName == EmptyRegistry.None, CustomView == Neve public protocol RootRegistry: CustomRegistry where Root == Self { } -public struct CustomModifierGroupParser: Parser where P.Input == Substring.UTF8View, P.Output == Output { +@MainActor +public struct CustomModifierGroupParser: @preconcurrency Parser where P.Input == Substring.UTF8View, P.Output == Output { public let parser: P @inlinable diff --git a/Sources/LiveViewNative/Stylesheets/AttributeReference.swift b/Sources/LiveViewNative/Stylesheets/AttributeReference.swift index d3bf08233..ac34a99e5 100644 --- a/Sources/LiveViewNative/Stylesheets/AttributeReference.swift +++ b/Sources/LiveViewNative/Stylesheets/AttributeReference.swift @@ -22,6 +22,7 @@ import LiveViewNativeCore /// ``` /// /// The attribute will be automatically decoded to the correct type using the conformance to ``AttributeDecodable``. +@MainActor public struct AttributeReference: ParseableModifierValue { enum Storage { case constant(Value) diff --git a/Sources/LiveViewNative/Stylesheets/Modifiers/Files/FileImporterModifier.swift b/Sources/LiveViewNative/Stylesheets/Modifiers/Files/FileImporterModifier.swift new file mode 100644 index 000000000..c27498ae0 --- /dev/null +++ b/Sources/LiveViewNative/Stylesheets/Modifiers/Files/FileImporterModifier.swift @@ -0,0 +1,104 @@ +// +// FileImporterModifier.swift +// +// +// Created by Carson Katri on 10/23/24. +// + +import SwiftUI +import LiveViewNativeCore +import LiveViewNativeStylesheet +import UniformTypeIdentifiers +import OSLog + +private let logger = Logger(subsystem: "LiveViewNative", category: "_FileImporterModifier") + +/// See [`SwiftUI.View/fileImporter(isPresented:allowedContentTypes:allowsMultipleSelection:onCompletion:)`](https://developer.apple.com/documentation/swiftui/view/fileimporter(ispresented:allowedcontenttypes:allowsmultipleselection:oncompletion:)) for more details on this ViewModifier. +/// +/// ### fileImporter(isPresented:allowedContentTypes:allowsMultipleSelection:onCompletion:) +/// - `isPresented`: `attr("...")` (required) +/// - `allowedContentTypes`: `attr("...")` or list of ``UniformTypeIdentifiers/UTType`` (required) +/// - `allowsMultipleSelection`: `attr("...")` or ``Swift/Bool`` (required) +/// +/// See [`SwiftUI.View/fileImporter(isPresented:allowedContentTypes:allowsMultipleSelection:onCompletion:)`](https://developer.apple.com/documentation/swiftui/view/fileimporter(ispresented:allowedcontenttypes:allowsmultipleselection:oncompletion:)) for more details on this ViewModifier. +/// +/// Example: +/// +/// ```heex +/// <.live_file_input upload={@uploads.avatar} /> +/// ``` +@_documentation(visibility: public) +@ParseableExpression +struct _FileImporterModifier: ViewModifier { + static var name: String { "fileImporter" } + + @Environment(\.formModel) private var formModel + + private let id: AttributeReference + private let name: AttributeReference + @ChangeTracked private var isPresented: Bool + private let allowedContentTypes: AttributeReference + private let allowsMultipleSelection: AttributeReference + + @ObservedElement private var element + @LiveContext private var context + + @available(iOS 14.0, macOS 11.0, visionOS 1.0, *) + init( + id: AttributeReference, + name: AttributeReference, + isPresented: ChangeTracked, + allowedContentTypes: AttributeReference, + allowsMultipleSelection: AttributeReference + ) { + self.id = id + self.name = name + self._isPresented = isPresented + self.allowedContentTypes = allowedContentTypes + self.allowsMultipleSelection = allowsMultipleSelection + } + + func body(content: Content) -> some View { + #if os(iOS) || os(macOS) || os(visionOS) + content.fileImporter( + isPresented: $isPresented, + allowedContentTypes: allowedContentTypes.resolve(on: element, in: context).values, + allowsMultipleSelection: allowsMultipleSelection.resolve(on: element, in: context) + ) { result in + let id = id.resolve(on: element, in: context) + + Task { + do { + for url in try result.get() { + try await formModel?.queueFileUpload(id: id, url: url, coordinator: context.coordinator) + } + } catch { + logger.log(level: .error, "\(error.localizedDescription)") + } + } + } + #else + content + #endif + } +} + +extension UTType: AttributeDecodable { + struct ResolvableSet: AttributeDecodable, ParseableModifierValue { + nonisolated let values: [UTType] + + init(values: [UTType]) { + self.values = values + } + + nonisolated init(from attribute: LiveViewNativeCore.Attribute?, on element: ElementNode) throws { + guard let value = attribute?.value + else { throw AttributeDecodingError.missingAttribute(Self.self) } + self.values = value.split(separator: ",").compactMap({ UTType(filenameExtension: String($0.dropFirst())) }) + } + + static func parser(in context: ParseableModifierContext) -> some Parser { + Array.parser(in: context).compactMap({ Self.init(values: $0.compactMap(UTType.init)) }) + } + } +} diff --git a/Sources/LiveViewNative/Stylesheets/Modifiers/Shapes/ShapeModifier.swift b/Sources/LiveViewNative/Stylesheets/Modifiers/Shapes/ShapeModifier.swift index 9ce9ba36d..f2d8ac9f6 100644 --- a/Sources/LiveViewNative/Stylesheets/Modifiers/Shapes/ShapeModifier.swift +++ b/Sources/LiveViewNative/Stylesheets/Modifiers/Shapes/ShapeModifier.swift @@ -9,6 +9,7 @@ import SwiftUI import LiveViewNativeStylesheet /// A `ViewModifier` that can be applied directly to `Shape`. +@MainActor protocol ShapeModifier { associatedtype Root: RootRegistry associatedtype ModifiedShape: SwiftUI.Shape @@ -17,6 +18,7 @@ protocol ShapeModifier { } /// A `ViewModifier` that can be applied directly to `Shape`. +@MainActor protocol ShapeFinalizerModifier { associatedtype Root: RootRegistry associatedtype FinalizedShape: SwiftUI.View diff --git a/Sources/LiveViewNative/Stylesheets/ParseableTypes/AnyCoordinateSpaceProtocol.swift b/Sources/LiveViewNative/Stylesheets/ParseableTypes/AnyCoordinateSpaceProtocol.swift index 06f72c943..20293b56c 100644 --- a/Sources/LiveViewNative/Stylesheets/ParseableTypes/AnyCoordinateSpaceProtocol.swift +++ b/Sources/LiveViewNative/Stylesheets/ParseableTypes/AnyCoordinateSpaceProtocol.swift @@ -9,7 +9,7 @@ import SwiftUI import LiveViewNativeStylesheet @available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *) -extension AnyCoordinateSpaceProtocol: CoordinateSpaceProtocol {} +extension AnyCoordinateSpaceProtocol: @preconcurrency CoordinateSpaceProtocol {} /// See [`SwiftUI.CoordinateSpaceProtocol`](https://developer.apple.com/documentation/swiftui/CoordinateSpaceProtocol) for more details. /// @@ -30,6 +30,7 @@ extension AnyCoordinateSpaceProtocol: CoordinateSpaceProtocol {} /// .scrollView(axis: .horizontal) /// ``` @_documentation(visibility: public) +@MainActor struct AnyCoordinateSpaceProtocol: ParseableModifierValue { let coordinateSpace: CoordinateSpace diff --git a/Sources/LiveViewNative/Stylesheets/ParseableTypes/AnyGesture+ParseableModifierValue.swift b/Sources/LiveViewNative/Stylesheets/ParseableTypes/AnyGesture+ParseableModifierValue.swift index ce4687cd2..c460c4279 100644 --- a/Sources/LiveViewNative/Stylesheets/ParseableTypes/AnyGesture+ParseableModifierValue.swift +++ b/Sources/LiveViewNative/Stylesheets/ParseableTypes/AnyGesture+ParseableModifierValue.swift @@ -208,6 +208,7 @@ struct _AnyGesture: ParseableModifierValue { case .onEnded(let onEnded): return AnyGesture(gesture.onEnded({ value in Task { + @MainActor func sendEventValue(_ eventValue: [String:Any]) async throws { let eventValue = eventValue.merging(element.buildPhxValuePayload(), uniquingKeysWith: { $1 }) try await onEnded.action(value: eventValue, in: context) @@ -311,6 +312,7 @@ struct _AnyGesture: ParseableModifierValue { } #if !os(tvOS) + @MainActor @ParseableExpression struct Drag { static let name = "DragGesture" @@ -339,6 +341,7 @@ struct _AnyGesture: ParseableModifierValue { } #if os(iOS) || os(macOS) || os(visionOS) + @MainActor @ParseableExpression struct Magnify { static let name = "MagnifyGesture" @@ -353,6 +356,7 @@ struct _AnyGesture: ParseableModifierValue { } } + @MainActor @ParseableExpression struct Rotate { static let name = "RotateGesture" @@ -369,6 +373,7 @@ struct _AnyGesture: ParseableModifierValue { #endif #if !os(tvOS) + @MainActor @ParseableExpression struct SpatialTap { static let name = "SpatialTapGesture" @@ -380,6 +385,7 @@ struct _AnyGesture: ParseableModifierValue { } #endif + @MainActor @ParseableExpression struct Tap { static let name = "TapGesture" @@ -392,7 +398,8 @@ struct _AnyGesture: ParseableModifierValue { } extension EnvironmentValues { - private enum GestureStateKey: EnvironmentKey { + @MainActor + private enum GestureStateKey: @preconcurrency EnvironmentKey { static let defaultValue: GestureState<[String:Any]> = .init(initialValue: [:]) } diff --git a/Sources/LiveViewNative/Stylesheets/ParseableTypes/AnyPresentationSizing.swift b/Sources/LiveViewNative/Stylesheets/ParseableTypes/AnyPresentationSizing.swift index e7f169ab3..e6fb533f6 100644 --- a/Sources/LiveViewNative/Stylesheets/ParseableTypes/AnyPresentationSizing.swift +++ b/Sources/LiveViewNative/Stylesheets/ParseableTypes/AnyPresentationSizing.swift @@ -21,7 +21,8 @@ import LiveViewNativeStylesheet /// - `sticky(horizontal: Bool, vertical: Bool)` @_documentation(visibility: public) @available(iOS 18.0, watchOS 11.0, tvOS 18.0, macOS 15.0, visionOS 2.0, *) -struct AnyPresentationSizing: PresentationSizing, ParseableModifierValue { +@MainActor +struct AnyPresentationSizing: @preconcurrency PresentationSizing, ParseableModifierValue { let value: any PresentationSizing func proposedSize(for root: PresentationSizingRoot, context: PresentationSizingContext) -> ProposedViewSize { diff --git a/Sources/LiveViewNative/Stylesheets/ParseableTypes/AnyScrollTargetBehavior.swift b/Sources/LiveViewNative/Stylesheets/ParseableTypes/AnyScrollTargetBehavior.swift index 7a926e085..c08e034fe 100644 --- a/Sources/LiveViewNative/Stylesheets/ParseableTypes/AnyScrollTargetBehavior.swift +++ b/Sources/LiveViewNative/Stylesheets/ParseableTypes/AnyScrollTargetBehavior.swift @@ -23,7 +23,8 @@ import LiveViewNativeStylesheet /// ``` @_documentation(visibility: public) @available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *) -struct AnyScrollTargetBehavior: ParseableModifierValue, ScrollTargetBehavior { +@MainActor +struct AnyScrollTargetBehavior: ParseableModifierValue, @preconcurrency ScrollTargetBehavior { let _updateTarget: (inout ScrollTarget, ScrollTargetBehaviorContext) -> () func updateTarget(_ target: inout ScrollTarget, context: Self.TargetContext) { diff --git a/Sources/LiveViewNative/Stylesheets/ParseableTypes/ParseableRangeExpression.swift b/Sources/LiveViewNative/Stylesheets/ParseableTypes/ParseableRangeExpression.swift index e19a10988..038cfc451 100644 --- a/Sources/LiveViewNative/Stylesheets/ParseableTypes/ParseableRangeExpression.swift +++ b/Sources/LiveViewNative/Stylesheets/ParseableTypes/ParseableRangeExpression.swift @@ -45,7 +45,7 @@ import LiveViewNativeStylesheet /// 1..<10 /// ``` @_documentation(visibility: public) -struct ParseableRangeExpression: RangeExpression, ParseableModifierValue { +struct ParseableRangeExpression: @preconcurrency RangeExpression, ParseableModifierValue { let value: any RangeExpression func relative(to collection: C) -> Range where C : Collection, Bound == C.Index { diff --git a/Sources/LiveViewNative/Stylesheets/ParseableTypes/PointerStyle+ParseableModifierValue.swift b/Sources/LiveViewNative/Stylesheets/ParseableTypes/PointerStyle+ParseableModifierValue.swift index 398eed80d..37d6f3579 100644 --- a/Sources/LiveViewNative/Stylesheets/ParseableTypes/PointerStyle+ParseableModifierValue.swift +++ b/Sources/LiveViewNative/Stylesheets/ParseableTypes/PointerStyle+ParseableModifierValue.swift @@ -10,7 +10,7 @@ import LiveViewNativeStylesheet #if os(macOS) || os(visionOS) @available(macOS 15, visionOS 2, *) -extension PointerStyle: @retroactive ParseableModifierValue { +extension PointerStyle: ParseableModifierValue { public static func parser(in context: ParseableModifierContext) -> some Parser { ImplicitStaticMember { OneOf { @@ -118,7 +118,16 @@ extension PointerStyle: @retroactive ParseableModifierValue { extension HorizontalDirection.Set: ParseableModifierValue { public static func parser(in context: ParseableModifierContext) -> some Parser { OneOf { - Array.parser(in: context).map({ Self.init($0) }) + // this fails to compile in release mode in Xcode 16: + // Array.parser(in: context).map({ Self.init($0) }) + ListLiteral { + ImplicitStaticMember([ + "all": Self.all, + "leading": Self.leading, + "trailing": Self.trailing, + ]) + } + .map(Self.init(_:)) ImplicitStaticMember([ "all": Self.all, "leading": Self.leading, @@ -132,7 +141,16 @@ extension HorizontalDirection.Set: ParseableModifierValue { extension VerticalDirection.Set: ParseableModifierValue { public static func parser(in context: ParseableModifierContext) -> some Parser { OneOf { - Array.parser(in: context).map({ Self.init($0) }) + // this fails to compile in release mode in Xcode 16: + // Array.parser(in: context).map({ Self.init($0) }) + ListLiteral { + ImplicitStaticMember([ + "all": Self.all, + "up": Self.up, + "down": Self.down, + ]) + } + .map(Self.init(_:)) ImplicitStaticMember([ "all": Self.all, "up": Self.up, @@ -144,10 +162,19 @@ extension VerticalDirection.Set: ParseableModifierValue { #if os(macOS) @available(macOS 15.0, *) -extension FrameResizeDirection.Set: @retroactive ParseableModifierValue { +extension FrameResizeDirection.Set: ParseableModifierValue { public static func parser(in context: ParseableModifierContext) -> some Parser { OneOf { - Array.parser(in: context).map({ Self.init($0) }) + // this fails to compile in release mode in Xcode 16: + // Array.parser(in: context).map({ Self.init($0) }) + ListLiteral { + ImplicitStaticMember([ + "all": Self.all, + "inward": Self.inward, + "outward": Self.outward, + ]) + } + .map(Self.init(_:)) ImplicitStaticMember([ "all": Self.all, "inward": Self.inward, diff --git a/Sources/LiveViewNative/Stylesheets/ParseableTypes/ShapeStyles/AnyShapeStyle+ParseableModifierValue.swift b/Sources/LiveViewNative/Stylesheets/ParseableTypes/ShapeStyles/AnyShapeStyle+ParseableModifierValue.swift index feb6b58d6..34bb78a49 100644 --- a/Sources/LiveViewNative/Stylesheets/ParseableTypes/ShapeStyles/AnyShapeStyle+ParseableModifierValue.swift +++ b/Sources/LiveViewNative/Stylesheets/ParseableTypes/ShapeStyles/AnyShapeStyle+ParseableModifierValue.swift @@ -229,7 +229,8 @@ public extension AnyShapeStyle { BaseParser(context: context) } - private struct BaseParser: Parser { + @MainActor + private struct BaseParser: @preconcurrency Parser { let context: ParseableModifierContext func parse(_ input: inout Substring.UTF8View) throws -> Storage { @@ -287,6 +288,7 @@ public extension AnyShapeStyle { } } + @MainActor @ParseableExpression enum _angularGradient { static let name = "angularGradient" @@ -346,6 +348,7 @@ public extension AnyShapeStyle { } } + @MainActor @ParseableExpression enum _conicGradient { static let name = "conicGradient" @@ -385,6 +388,7 @@ public extension AnyShapeStyle { } } + @MainActor @ParseableExpression enum _ellipticalGradient { static let name = "ellipticalGradient" @@ -424,6 +428,7 @@ public extension AnyShapeStyle { } } + @MainActor @ParseableExpression enum _linearGradient { static let name = "linearGradient" @@ -463,6 +468,7 @@ public extension AnyShapeStyle { } } + @MainActor @ParseableExpression enum _radialGradient { static let name = "radialGradient" diff --git a/Sources/LiveViewNative/Stylesheets/ParseableTypes/ShapeStyles/Color+ParseableModifierValue.swift b/Sources/LiveViewNative/Stylesheets/ParseableTypes/ShapeStyles/Color+ParseableModifierValue.swift index a9e86ec0c..f093059a9 100644 --- a/Sources/LiveViewNative/Stylesheets/ParseableTypes/ShapeStyles/Color+ParseableModifierValue.swift +++ b/Sources/LiveViewNative/Stylesheets/ParseableTypes/ShapeStyles/Color+ParseableModifierValue.swift @@ -65,28 +65,30 @@ import LiveViewNativeCore /// ``` @_documentation(visibility: public) public extension SwiftUI.Color { + @MainActor struct Resolvable: ParseableModifierValue { + @MainActor enum Storage { case reference(AttributeName) case constant(SwiftUI.Color) case named(AttributeReference) case components( - colorSpace: AttributeReference = .init(storage: .constant(.sRGB)), + colorSpace: AttributeReference?, red: AttributeReference, green: AttributeReference, blue: AttributeReference, - opacity: AttributeReference = .init(storage: .constant(1)) + opacity: AttributeReference? ) case monochrome( - colorSpace: AttributeReference = .init(storage: .constant(.sRGB)), + colorSpace: AttributeReference?, white: AttributeReference, - opacity: AttributeReference = .init(storage: .constant(1)) + opacity: AttributeReference? ) case hsb( hue: AttributeReference, saturation: AttributeReference, brightness: AttributeReference, - opacity: AttributeReference = .init(storage: .constant(1)) + opacity: AttributeReference? ) } @@ -113,24 +115,24 @@ public extension SwiftUI.Color { SwiftUI.Color.init(name.resolve(on: element, in: context), bundle: nil) case let .components(colorSpace, red, green, blue, opacity): SwiftUI.Color( - colorSpace.resolve(on: element, in: context), + colorSpace?.resolve(on: element, in: context) ?? .sRGB, red: red.resolve(on: element, in: context), green: green.resolve(on: element, in: context), blue: blue.resolve(on: element, in: context), - opacity: opacity.resolve(on: element, in: context) + opacity: opacity?.resolve(on: element, in: context) ?? 1 ) case let .monochrome(colorSpace, white, opacity): SwiftUI.Color( - colorSpace.resolve(on: element, in: context), + colorSpace?.resolve(on: element, in: context) ?? .sRGB, white: white.resolve(on: element, in: context), - opacity: opacity.resolve(on: element, in: context) + opacity: opacity?.resolve(on: element, in: context) ?? 1 ) case let .hsb(hue, saturation, brightness, opacity): SwiftUI.Color( hue: hue.resolve(on: element, in: context), saturation: saturation.resolve(on: element, in: context), brightness: brightness.resolve(on: element, in: context), - opacity: opacity.resolve(on: element, in: context) + opacity: opacity?.resolve(on: element, in: context) ?? 1 ) } return modifiers.reduce(into: base) { @@ -148,24 +150,24 @@ public extension SwiftUI.Color { SwiftUI.Color.init(name.constant(default: ""), bundle: nil) case let .components(colorSpace, red, green, blue, opacity): SwiftUI.Color( - colorSpace.constant(default: .sRGB), + colorSpace?.constant(default: .sRGB) ?? .sRGB, red: red.constant(default: 0), green: green.constant(default: 0), blue: blue.constant(default: 0), - opacity: opacity.constant(default: 1) + opacity: opacity?.constant(default: 1) ?? 1 ) case let .monochrome(colorSpace, white, opacity): SwiftUI.Color( - colorSpace.constant(default: .sRGB), + colorSpace?.constant(default: .sRGB) ?? .sRGB, white: white.constant(default: 0), - opacity: opacity.constant(default: 1) + opacity: opacity?.constant(default: 1) ?? 1 ) case let .hsb(hue, saturation, brightness, opacity): SwiftUI.Color( hue: hue.constant(default: 0), saturation: saturation.constant(default: 0), brightness: brightness.constant(default: 0), - opacity: opacity.constant(default: 1) + opacity: opacity?.constant(default: 1) ?? 1 ) } } @@ -175,6 +177,7 @@ public extension SwiftUI.Color { .map(\.base) } + @MainActor @ParseableExpression struct CustomColor { static let name = "Color" @@ -261,7 +264,8 @@ public extension SwiftUI.Color { } } -struct _ColorParser: Parser where Members.Input == Substring.UTF8View { +@MainActor +struct _ColorParser: @preconcurrency Parser where Members.Input == Substring.UTF8View { let context: ParseableModifierContext @ParserBuilder let members: Members @@ -321,15 +325,18 @@ struct _ColorParser: Parser where Members.Input == Substring.UT } } + @MainActor private enum AnyColorModifier { case colorModifier(ColorModifier) case member(Members.Output) } } +@MainActor enum ColorModifier { case opacity(Opacity) + @MainActor @ParseableExpression struct Opacity { static let name = "opacity" diff --git a/Sources/LiveViewNative/Stylesheets/ParseableTypes/ShapeStyles/ShadowStyle+ParseableModifierValue.swift b/Sources/LiveViewNative/Stylesheets/ParseableTypes/ShapeStyles/ShadowStyle+ParseableModifierValue.swift index 79b2dd1b0..c429119bc 100644 --- a/Sources/LiveViewNative/Stylesheets/ParseableTypes/ShapeStyles/ShadowStyle+ParseableModifierValue.swift +++ b/Sources/LiveViewNative/Stylesheets/ParseableTypes/ShapeStyles/ShadowStyle+ParseableModifierValue.swift @@ -38,6 +38,7 @@ import LiveViewNativeStylesheet /// .inner(color: .red, radius: 8, x: 10, y: -8) /// ``` @_documentation(visibility: public) +@MainActor enum _ShadowStyle: ParseableModifierValue { case drop(_drop) case inner(_inner) @@ -70,6 +71,7 @@ enum _ShadowStyle: ParseableModifierValue { } } + @MainActor @ParseableExpression struct _drop { static let name = "drop" @@ -92,6 +94,7 @@ enum _ShadowStyle: ParseableModifierValue { } } + @MainActor @ParseableExpression struct _inner { static let name = "inner" diff --git a/Sources/LiveViewNative/Stylesheets/ParseableTypes/Styles/AnyNavigationViewStyle+ParseableModifierValue.swift b/Sources/LiveViewNative/Stylesheets/ParseableTypes/Styles/AnyNavigationViewStyle+ParseableModifierValue.swift deleted file mode 100644 index 3b2837129..000000000 --- a/Sources/LiveViewNative/Stylesheets/ParseableTypes/Styles/AnyNavigationViewStyle+ParseableModifierValue.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// AnyNavigationViewStyle+ParseableModifierValue.swift -// -// -// Created by Carson Katri on 6/20/24. -// - -import SwiftUI -import LiveViewNativeStylesheet - -/// See [`SwiftUI.NavigationViewStyle`](https://developer.apple.com/documentation/swiftui/NavigationViewStyle) for more details. -/// -/// - Note: This type is deprecated and should no longer be used. -@_documentation(visibility: public) -enum AnyNavigationViewStyle: String, CaseIterable, ParseableModifierValue, NavigationViewStyle { - typealias _ParserType = ImplicitStaticMember> - - case __never - - @ViewBuilder - func _body(configuration: _NavigationViewStyleConfiguration) -> some View { - fatalError("This type is deprecated and should no longer be used.") - } -} diff --git a/Sources/LiveViewNative/Stylesheets/ParseableTypes/Styles/AnyTextFieldStyle+ParseableModifierValue.swift b/Sources/LiveViewNative/Stylesheets/ParseableTypes/Styles/AnyTextFieldStyle+ParseableModifierValue.swift index ae4d1e0e5..0fb610743 100644 --- a/Sources/LiveViewNative/Stylesheets/ParseableTypes/Styles/AnyTextFieldStyle+ParseableModifierValue.swift +++ b/Sources/LiveViewNative/Stylesheets/ParseableTypes/Styles/AnyTextFieldStyle+ParseableModifierValue.swift @@ -15,7 +15,8 @@ import LiveViewNativeStylesheet /// - `.roundedBorder` /// - `.plain` @_documentation(visibility: public) -enum AnyTextFieldStyle: String, CaseIterable, ParseableModifierValue, TextFieldStyle { +@MainActor +enum AnyTextFieldStyle: String, CaseIterable, ParseableModifierValue, @preconcurrency TextFieldStyle { typealias _ParserType = ImplicitStaticMember> case automatic diff --git a/Sources/LiveViewNative/Stylesheets/Stylesheet.swift b/Sources/LiveViewNative/Stylesheets/Stylesheet.swift index e37692047..ad0a150e1 100644 --- a/Sources/LiveViewNative/Stylesheets/Stylesheet.swift +++ b/Sources/LiveViewNative/Stylesheets/Stylesheet.swift @@ -8,7 +8,8 @@ private let logger = Logger(subsystem: "LiveViewNative", category: "Stylesheet") /// A type that stores a map between classes and an array of modifiers. /// /// The raw content of the stylesheet is retained so it can re-parsed in a different context. -public struct Stylesheet { +@MainActor +public struct Stylesheet: Sendable { let content: [String] let classes: [String:[BuiltinRegistry.BuiltinModifier]] @@ -45,7 +46,7 @@ actor StylesheetCache { } } -extension Stylesheet: AttributeDecodable { +extension Stylesheet: @preconcurrency AttributeDecodable { public init(from attribute: LiveViewNativeCore.Attribute?, on element: ElementNode) throws { guard let value = attribute?.value else { throw AttributeDecodingError.missingAttribute(Self.self) } diff --git a/Sources/LiveViewNative/Stylesheets/StylesheetParser.swift b/Sources/LiveViewNative/Stylesheets/StylesheetParser.swift index 50621a0a9..220396850 100644 --- a/Sources/LiveViewNative/Stylesheets/StylesheetParser.swift +++ b/Sources/LiveViewNative/Stylesheets/StylesheetParser.swift @@ -5,7 +5,8 @@ import OSLog private let logger = Logger(subsystem: "LiveViewNative", category: "Stylesheet") -struct StylesheetParser: Parser { +@MainActor +struct StylesheetParser: @preconcurrency Parser { let context: ParseableModifierContext func parse(_ input: inout Substring.UTF8View) throws -> Dictionary> { @@ -52,7 +53,8 @@ struct StylesheetParser: Parser { return classes } - struct RecoverableModifier: Parser { + @MainActor + struct RecoverableModifier: @preconcurrency Parser { let className: String let context: ParseableModifierContext diff --git a/Sources/LiveViewNative/Stylesheets/ViewReference.swift b/Sources/LiveViewNative/Stylesheets/ViewReference.swift index 59d0e26c5..e8864ee79 100644 --- a/Sources/LiveViewNative/Stylesheets/ViewReference.swift +++ b/Sources/LiveViewNative/Stylesheets/ViewReference.swift @@ -232,7 +232,9 @@ private enum FromNodeValue { } /// A builder for `ToolbarContent`. +@MainActor struct ToolbarTreeBuilder { + @MainActor func fromNodes(_ e: Nodes, context c: LiveContextStorage) -> some ToolbarContent where Nodes: RandomAccessCollection, Nodes.Index == Int, Nodes.Element == Node { @@ -262,19 +264,21 @@ struct ToolbarTreeBuilder { return ToolbarContentBuilder.buildBlock(f(.e(ToolbarError.badChildCount(e.count)), c), f(nil, c), f(nil, c), f(nil, c), f(nil, c), f(nil, c), f(nil, c), f(nil, c), f(nil, c), f(nil, c)) } } - + // alias for typing + @MainActor @inline(__always) fileprivate func f(_ n: FromNodeValue?, _ c: LiveContextStorage) -> some ToolbarContent { return n.flatMap({ fromNode($0, context: c) }) } + @MainActor @ToolbarContentBuilder fileprivate func fromNode(_ node: FromNodeValue, context: LiveContextStorage) -> some ToolbarContent { // ToolbarTreeBuilder.fromNode may not be called with a root or leaf node switch node { case let .n(node): - if case .element(let element) = node.data { + if case .nodeElement(let element) = node.data() { Self.lookup(ElementNode(node: node, data: element)) } case let .e(error): @@ -284,6 +288,7 @@ struct ToolbarTreeBuilder { } } + @MainActor @ToolbarContentBuilder static func lookup(_ node: ElementNode) -> some ToolbarContent { switch node.tag { @@ -302,7 +307,9 @@ struct ToolbarTreeBuilder { } /// A builder for `CustomizableToolbarContent`. +@MainActor struct CustomizableToolbarTreeBuilder { + @MainActor func fromNodes(_ e: Nodes, context c: LiveContextStorage) -> some CustomizableToolbarContent where Nodes: RandomAccessCollection, Nodes.Index == Int, Nodes.Element == Node { @@ -332,19 +339,21 @@ struct CustomizableToolbarTreeBuilder { return ToolbarContentBuilder.buildBlock(f(.e(ToolbarError.badChildCount(e.count)), c), f(nil, c), f(nil, c), f(nil, c), f(nil, c), f(nil, c), f(nil, c), f(nil, c), f(nil, c), f(nil, c)) } } - + // alias for typing + @MainActor @inline(__always) fileprivate func f(_ n: FromNodeValue?, _ c: LiveContextStorage) -> some CustomizableToolbarContent { return n.flatMap({ fromNode($0, context: c) }) } + @MainActor @ToolbarContentBuilder fileprivate func fromNode(_ node: FromNodeValue, context: LiveContextStorage) -> some CustomizableToolbarContent { // CustomizableToolbarTreeBuilder.fromNode may not be called with a root or leaf node switch node { case let .n(node): - if case .element(let element) = node.data { + if case .nodeElement(let element) = node.data() { Self.lookup(ElementNode(node: node, data: element)) } case let .e(error): @@ -354,6 +363,7 @@ struct CustomizableToolbarTreeBuilder { } } + @MainActor @ToolbarContentBuilder static func lookup(_ node: ElementNode) -> some CustomizableToolbarContent { switch node.tag { diff --git a/Sources/LiveViewNative/Utils/DOM.swift b/Sources/LiveViewNative/Utils/DOM.swift index f7df38639..24f502a9f 100644 --- a/Sources/LiveViewNative/Utils/DOM.swift +++ b/Sources/LiveViewNative/Utils/DOM.swift @@ -25,14 +25,14 @@ import LiveViewNativeCore /// - ``innerText()`` public struct ElementNode: Identifiable { public let node: Node - public let data: ElementData + public let data: Element - init(node: Node, data: ElementData) { + init(node: Node, data: Element) { self.node = node self.data = data } - public var id: NodeRef { node.id } + public var id: NodeRef { node.id() } /// A sequence representing this element's direct children. public func children() -> NodeChildrenSequence { node.children() } @@ -40,11 +40,11 @@ public struct ElementNode: Identifiable { public func depthFirstChildren() -> NodeDepthFirstChildrenSequence { node.depthFirstChildren() } /// A sequence representing this element's direct children that are elements. public func elementChildren() -> [ElementNode] { node.children().compactMap({ $0.asElement() }) } - + /// The namespace of the element. - public var namespace: String? { data.namespace } + public var namespace: String? { data.name.namespace } /// The tag name of the element. - public var tag: String { data.tag } + public var tag: String { data.name.name } /// The list of attributes present on this element. public var attributes: [LiveViewNativeCore.Attribute] { data.attributes } /// The attribute with the given name, or `nil` if there is no such attribute. @@ -93,7 +93,7 @@ public struct ElementNode: Identifiable { public func innerText() -> String { // TODO: should follow the spec and insert/collapse whitespace around elements self.children().compactMap { node in - if case .leaf(let content) = node.data { + if case .leaf(let content) = node.data() { return content } else { return nil @@ -114,8 +114,8 @@ public struct ElementNode: Identifiable { } extension Node { - public func asElement() -> ElementNode? { - if case .element(let data) = self.data { + func asElement() -> ElementNode? { + if case .nodeElement(let data) = self.data() { return ElementNode(node: self, data: data) } else { return nil diff --git a/Sources/LiveViewNative/Utils/ElixirDateFormats.swift b/Sources/LiveViewNative/Utils/ElixirDateFormats.swift index 78d7a952c..797b21438 100644 --- a/Sources/LiveViewNative/Utils/ElixirDateFormats.swift +++ b/Sources/LiveViewNative/Utils/ElixirDateFormats.swift @@ -8,7 +8,7 @@ import Foundation /// A formatter that parses ISO8601 dates as produced by Elixir's `DateTime`. -fileprivate let dateTimeFormatter: ISO8601DateFormatter = { +nonisolated(unsafe) fileprivate let dateTimeFormatter: ISO8601DateFormatter = { let formatter = ISO8601DateFormatter() formatter.formatOptions = [.withFullDate, .withFullTime, .withFractionalSeconds] return formatter diff --git a/Sources/LiveViewNative/ViewModel.swift b/Sources/LiveViewNative/ViewModel.swift index 200a59bfe..0522ad6a8 100644 --- a/Sources/LiveViewNative/ViewModel.swift +++ b/Sources/LiveViewNative/ViewModel.swift @@ -9,15 +9,17 @@ import Foundation import Combine import SwiftUI import LiveViewNativeCore +import UniformTypeIdentifiers /// The working-copy data model for a ``LiveView``. /// /// In a view in the LiveView tree, a model can be obtained using `@EnvironmentObject`. +@MainActor public class LiveViewModel: ObservableObject { private var forms = [String: FormModel]() - + init() {} - + /// Get or create a ``FormModel`` for the given ``. /// /// - Important: The element parameter must be the form element. To get the form model for an element within a form, use the ``LiveContext`` or the `\.formModel` environment value. @@ -34,22 +36,32 @@ public class LiveViewModel: ObservableObject { func clearForms() { self.forms.removeAll() } + + func fileUpload(id: String) -> FormModel.FileUpload? { + for (_, form) in forms { + guard let file = form.fileUploads.first(where: { $0.id == id }) + else { continue } + return file + } + return nil + } } /// A form model stores the working copy of the data for a specific `
` element. /// /// To obtain a form model, use ``LiveViewModel/getForm(elementID:)`` or the `\.formModel` environment key. +@MainActor public class FormModel: ObservableObject, CustomDebugStringConvertible { let elementID: String - @_spi(LiveForm) public var pushEventImpl: ((String, String, Any, Int?) async throws -> [String:Any]?)! + @_spi(LiveForm) public var pushEventImpl: (@MainActor (String, String, Any, Int?) async throws -> [String:Any]?)! - var changeEvent: ((Any) -> ())? + var changeEvent: ((Any) async throws -> ())? var submitEvent: String? /// An action called when no `phx-submit` event is present. /// /// This typically performs a HTTP request and reconnects the LiveView. var submitAction: (() -> ())? - + /// The form data for this form. @Published internal private(set) var data = [String: any FormValue]() var formFieldWillChange = PassthroughSubject() @@ -57,48 +69,60 @@ public class FormModel: ObservableObject, CustomDebugStringConvertible { /// A publisher that emits a value before sending the form submission event. var formWillSubmit = PassthroughSubject<(), Never>() + var fileUploads: [FileUpload] = [] + struct FileUpload { + let id: String + let data: Data + let upload: () async throws -> () + } + init(elementID: String) { self.elementID = elementID } - + @_spi(LiveForm) public func updateFromElement(_ element: ElementNode, submitAction: @escaping () -> ()) { + self.fileUploads.removeAll() + let pushEventImpl = pushEventImpl! self.changeEvent = element.attributeValue(for: .init(name: "phx-change")).flatMap({ event in { value in - Task { [weak self] in try await self?.pushEventImpl("form", event, value, nil) } + Task { + _ = try await pushEventImpl("form", event, value, nil) + } } }) self.submitEvent = element.attributeValue(for: .init(name: "phx-submit")) self.submitAction = submitAction } - + /// Sends a phx-change event (if configured) to the server with the current form data. /// /// This method has no effect if the `` does not have a `phx-change` event configured. /// /// See ``LiveViewCoordinator/pushEvent(type:event:value:target:)`` for more information. - @MainActor public func sendChangeEvent(_ value: any FormValue, for name: String, event: Event?) async throws { guard let event = sendChangeEventForFormElement(value, for: name, event?.wrappedValue.callAsFunction) ?? sendChangeEventForForm(for: name, changeEvent) else { return } try await event() } - + /// Sends a phx-submit event (if configured) to the server with the current form data. /// /// This method has no effect if the `` does not have a `phx-submit` event configured. /// /// See ``LiveViewCoordinator/pushEvent(type:event:value:target:)`` for more information. - @MainActor public func sendSubmitEvent() async throws { formWillSubmit.send(()) + for fileUpload in fileUploads { + try await fileUpload.upload() + } if let submitEvent = submitEvent { try await pushFormEvent(submitEvent) } else if let submitAction { submitAction() } } - + /// Create a URL encoded body from the data in the form. public func buildFormQuery() throws -> String { return try buildFormURLComponents().formEncodedQuery! @@ -144,7 +168,7 @@ public class FormModel: ObservableObject, CustomDebugStringConvertible { return try value.formQueryEncoded() } } - + var components = URLComponents() components.queryItems = data.map { URLQueryItem(name: $0.key, value: $0.value) @@ -152,17 +176,17 @@ public class FormModel: ObservableObject, CustomDebugStringConvertible { return components } - + @MainActor private func pushFormEvent(_ event: String) async throws { // the `form` event type expects a URL encoded payload (e.g., `a=b&c=d`) _ = try await pushEventImpl("form", event, try buildFormQuery(), nil) } - - public var debugDescription: String { + + public nonisolated var debugDescription: String { return "FormModel(element: #\(elementID), id: \(ObjectIdentifier(self))" } - + /// Access the stored value, if there is one, for the form field of the given name. /// /// Setting a field to `nil` removes it. @@ -209,7 +233,7 @@ public class FormModel: ObservableObject, CustomDebugStringConvertible { else { return } data[name] = value } - + /// Clears all data in this form. public func clear() { for field in data.keys { @@ -217,7 +241,45 @@ public class FormModel: ObservableObject, CustomDebugStringConvertible { } data = [:] } + + public func queueFileUpload( + id: String, + url: URL, + coordinator: LiveViewCoordinator + ) async throws { + return try await queueFileUpload( + id: id, + contents: try Data(contentsOf: url), + fileType: UTType(filenameExtension: url.pathExtension)!, + name: url.lastPathComponent, + coordinator: coordinator + ) + } + public func queueFileUpload( + id: String, + contents: Data, + fileType: UTType, + name: String, + coordinator: LiveViewCoordinator + ) async throws { + guard let liveChannel = coordinator.liveChannel + else { return } + + let file = LiveFile( + contents, + fileType.preferredMIMEType!, + name, + id + ) + let replyPayload = try await liveChannel.validateUpload(file) + try await coordinator.handleEventReplyPayload(replyPayload) + self.fileUploads.append(.init( + id: id, + data: contents, + upload: { try await liveChannel.uploadFile(file) } + )) + } } private extension URLComponents { diff --git a/Sources/LiveViewNative/ViewTree.swift b/Sources/LiveViewNative/ViewTree.swift index 00436e0c2..82a440784 100644 --- a/Sources/LiveViewNative/ViewTree.swift +++ b/Sources/LiveViewNative/ViewTree.swift @@ -10,36 +10,37 @@ import SwiftUI import LiveViewNativeCore import LiveViewNativeStylesheet +@MainActor struct ViewTreeBuilder { func fromNodes(_ nodes: NodeChildrenSequence, coordinator: LiveViewCoordinator, url: URL) -> some View { let context = LiveContextStorage(coordinator: coordinator, url: url) return fromNodes(nodes, context: context) .environment(\.anyLiveContextStorage, context) } - + @ViewBuilder func fromNodes(_ nodes: Nodes, context: LiveContextStorage) -> some View where Nodes: RandomAccessCollection, Nodes.Index == Int, Nodes.Element == Node { forEach(nodes: nodes, context: context) } - + struct NodeView: View { let node: Node let context: LiveContextStorage - + var body: some View { - switch node.data { + switch node.data() { case .root: fatalError("ViewTreeBuilder.fromNode may not be called with the root node") case .leaf(let content): SwiftUI.Text(content) - case .element(let element): + case .nodeElement(let element): context.coordinator.builder.fromElement(ElementNode(node: node, data: element), context: context) } } } - + func fromElement(_ element: ElementNode, context: LiveContextStorage) -> some View { let view = createView(element, context: context) @@ -48,7 +49,7 @@ struct ViewTreeBuilder { let withID = applyID(element: element, to: bound) let withIDAndTag = applyTag(element: element, to: withID) - return ObservedElement.Observer.Applicator(element.node.id) { + return ObservedElement.Observer.Applicator(element.node.id()) { withIDAndTag .environment(\.element, element) } @@ -72,7 +73,7 @@ struct ViewTreeBuilder { view } } - + @ViewBuilder private func createView(_ element: ElementNode, context: LiveContextStorage) -> some View { if let tagName = R.TagName(rawValue: element.tag) { @@ -81,7 +82,7 @@ struct ViewTreeBuilder { BuiltinRegistry.lookup(element.tag, element) } } - + @ViewBuilder private func applyBindings( to view: some View, @@ -105,7 +106,7 @@ struct ViewTreeBuilder { extension ViewTreeBuilder { enum Error: Swift.Error { case unknownModifierType - + var localizedDescription: String { switch self { case .unknownModifierType: @@ -119,29 +120,30 @@ extension CodingUserInfoKey { static var modifierAnimationScale: Self { .init(rawValue: "modifierAnimationScale")! } } +@MainActor @propertyWrapper @LiveElement -struct ClassModifiers: DynamicProperty { +struct ClassModifiers: @preconcurrency DynamicProperty { @LiveAttribute(.init(name: "class")) private var `class`: String? @LiveAttribute(.init(name: "style")) private var style: String? - + @LiveElementIgnored @Environment(\.stylesheet) var stylesheet - + @LiveElementIgnored let overrideStylesheet: Stylesheet? - + init(element: ElementNode, overrideStylesheet: Stylesheet?) { self._liveElement = .init(element: element) self.overrideStylesheet = overrideStylesheet } - + init(overrideStylesheet: Stylesheet? = nil) { self._liveElement = .init(wrappedValue: .init()) self.overrideStylesheet = overrideStylesheet } - + @LiveElementIgnored var wrappedValue: ArraySlice.BuiltinModifier> { if _liveElement.isConstant { @@ -163,10 +165,10 @@ struct ClassModifiers: DynamicProperty { return resolvedModifiers } } - + @LiveElementIgnored var resolvedModifiers: ArraySlice.BuiltinModifier> = .init() - + mutating func update() { resolvedModifiers.removeAll() guard let sheet = overrideStylesheet ?? (stylesheet as? Stylesheet) @@ -211,17 +213,18 @@ struct ClassModifiers: DynamicProperty { private struct ModifierObserver: View { let parent: Parent @ClassModifiers private var modifiers - + var body: some View { ModifierApplicator(parent: parent, modifiers: modifiers) } } extension EnvironmentValues { - private enum StylesheetKey: EnvironmentKey { + private enum StylesheetKey: @preconcurrency EnvironmentKey { + @MainActor static let defaultValue: Any = Stylesheet(content: [], classes: [:]) } - + var stylesheet: Any { get { self[StylesheetKey.self] } set { self[StylesheetKey.self] = newValue } @@ -252,7 +255,7 @@ private struct BindingApplicator: View { private struct ModifierApplicator: View { let parent: Parent let modifiers: ArraySlice.BuiltinModifier> - + var body: some View { if modifiers.isEmpty { parent @@ -284,16 +287,16 @@ extension View { enum ForEachElement: Identifiable { case keyed(Node, id: String) case unkeyed(Node) - + var id: String { switch self { case let .keyed(_, id): return id case let .unkeyed(node): - return "\(node.id)" + return "\(node.id().ref())" } } - + var node: Node { switch self { case let .keyed(node, _), @@ -303,6 +306,7 @@ enum ForEachElement: Identifiable { } } // not fileprivate because List needs to use it so it has access to ForEach modifiers +@MainActor func forEach(nodes: some Collection, context: LiveContextStorage) -> some DynamicViewContent { let elements = nodes.map { (node) -> ForEachElement in if let element = node.asElement(), @@ -321,7 +325,7 @@ func forEach(nodes: some Collection, context: LiveConte enum ForEachViewError: LocalizedError { case invalidNode case missingID - + var errorDescription: String? { switch self { case .invalidNode: diff --git a/Sources/LiveViewNative/Views/Controls and Indicators/Links/ShareLink.swift b/Sources/LiveViewNative/Views/Controls and Indicators/Links/ShareLink.swift index ea5b00291..d1ea2ddad 100644 --- a/Sources/LiveViewNative/Views/Controls and Indicators/Links/ShareLink.swift +++ b/Sources/LiveViewNative/Views/Controls and Indicators/Links/ShareLink.swift @@ -98,24 +98,24 @@ struct ShareLink: View { self.value = try itemsDecoder.decode([String].self, from: data) } } - + /// A string to share. @_documentation(visibility: public) private var item: String? - + public var body: some View { #if !os(tvOS) let useDefaultLabel = $liveElement.childNodes.filter({ - guard case let .element(data) = $0.data else { return true } - return data.tag != "SharePreview" + guard case let .nodeElement(data) = $0.data() else { return true } + return data.name.name != "SharePreview" }).isEmpty - + let subject = self.subject.flatMap(SwiftUI.Text.init) let message = self.message.flatMap(SwiftUI.Text.init) - + if let items = items?.value { let previews = previews(for: items) - + if useDefaultLabel { switch previews { case nil: diff --git a/Sources/LiveViewNative/Views/Images/ImageView.swift b/Sources/LiveViewNative/Views/Images/ImageView.swift index 40ec9dbd9..b5c08ea36 100644 --- a/Sources/LiveViewNative/Views/Images/ImageView.swift +++ b/Sources/LiveViewNative/Views/Images/ImageView.swift @@ -68,29 +68,35 @@ struct ImageView: View { /// The name of an image in the app's asset catalog. @_documentation(visibility: public) private var name: String? - + /// The value represented by this image, in the range `0.0` to `1.0`. @_documentation(visibility: public) private var variableValue: Double? - + @LiveElementIgnored @ClassModifiers private var modifiers let overrideImage: SwiftUI.Image? + @LiveAttribute("data-phx-upload-ref") + private var phxUploadRef: String? + + @LiveElementIgnored + @EnvironmentObject private var liveViewModel: LiveViewModel + init() { self.overrideImage = nil } - + init(image: SwiftUI.Image? = nil) { self.overrideImage = image } - + init(element: ElementNode, overrideStylesheet: Stylesheet?, overrideImage: SwiftUI.Image? = nil) { self._liveElement = .init(element: element) self._modifiers = .init(element: element, overrideStylesheet: overrideStylesheet) self.overrideImage = overrideImage } - + public var body: SwiftUI.Image? { image.flatMap({ (image: SwiftUI.Image) -> SwiftUI.Image in return modifiers.reduce(image) { result, modifier in @@ -103,9 +109,27 @@ struct ImageView: View { }) } + var fileUploadImage: SwiftUI.Image? { + guard let phxUploadRef + else { return nil } + #if os(macOS) + return liveViewModel + .fileUpload(id: phxUploadRef) + .flatMap({ NSImage(data: $0.data) }) + .flatMap(Image.init(nsImage:)) + #else + return liveViewModel + .fileUpload(id: phxUploadRef) + .flatMap({ UIImage(data: $0.data) }) + .flatMap(Image.init(uiImage:)) + #endif + } + var image: SwiftUI.Image? { if let overrideImage { return overrideImage + } else if let fileUploadImage { + return fileUploadImage } else if let systemName { return SwiftUI.Image(systemName: systemName, variableValue: variableValue) } else if let name { @@ -126,11 +150,11 @@ struct ImageView: View { return nil } } - + var label: SwiftUI.Text? { if let labelNode = $liveElement.childNodes.first { - switch labelNode.data { - case let .element(element): + switch labelNode.data() { + case let .nodeElement(element): return Text(element: ElementNode(node: labelNode, data: element), overrideStylesheet: _modifiers.overrideStylesheet).body case let .leaf(label): return .init(label) diff --git a/Sources/LiveViewNative/Views/Layout Containers/Collection Containers/List.swift b/Sources/LiveViewNative/Views/Layout Containers/Collection Containers/List.swift index 2b77f5c51..6d7a02ae8 100644 --- a/Sources/LiveViewNative/Views/Layout Containers/Collection Containers/List.swift +++ b/Sources/LiveViewNative/Views/Layout Containers/Collection Containers/List.swift @@ -219,11 +219,11 @@ struct List: View { } } } - + private var content: some View { let elements = $liveElement.childNodes .filter { - !$0.attributes.contains(where: { $0.name.namespace == nil && $0.name.name == "template" }) + !$0.attributes().contains(where: { $0.name.namespace == nil && $0.name.name == "template" }) } .map { (node) -> ForEachElement in if let element = node.asElement(), @@ -235,8 +235,8 @@ struct List: View { } } return ForEach(elements) { childNode in - if case let .element(element) = childNode.node.data, - element.tag == "Section" + if case let .nodeElement(element) = childNode.node.data(), + element.name.name == "Section" { // `Section` will apply tracking to its own children ViewTreeBuilder.NodeView(node: childNode.node, context: $liveElement.context.storage) @@ -248,7 +248,7 @@ struct List: View { .onDelete(perform: onDeleteHandler) .onMove(perform: onMoveHandler) } - + private var onDeleteHandler: ((IndexSet) -> Void)? { guard delete.event != nil else { return nil } return { indices in diff --git a/Sources/LiveViewNative/Views/Layout Containers/Presentation Containers/TabView.swift b/Sources/LiveViewNative/Views/Layout Containers/Presentation Containers/TabView.swift index 05d60dea3..5427a6892 100644 --- a/Sources/LiveViewNative/Views/Layout Containers/Presentation Containers/TabView.swift +++ b/Sources/LiveViewNative/Views/Layout Containers/Presentation Containers/TabView.swift @@ -28,6 +28,7 @@ private let logger = Logger(subsystem: "LiveViewNative", category: "TabView") /// ## Bindings /// * ``selection`` @_documentation(visibility: public) +@MainActor @LiveElement struct TabView: View { /// Synchronizes the selected tab with the server. @@ -42,8 +43,8 @@ struct TabView: View { var body: some View { if #available(iOS 18.0, macOS 15.0, tvOS 18.0, watchOS 11.0, visionOS 2.0, *), $liveElement.childNodes.contains(where: { - guard case let .element(element) = $0.data else { return false } - return element.tag == "Tab" + guard case let .nodeElement(element) = $0.data() else { return false } + return element.name.namespace == nil && element.name.name == "Tab" }) { if selectionAttribute != nil || changeAttribute != nil { @@ -67,6 +68,7 @@ struct TabView: View { /// A builder for `TabContent`. @available(iOS 18.0, macOS 15.0, tvOS 18.0, watchOS 11.0, visionOS 2.0, *) +@MainActor struct TabTreeBuilder { func fromNodes(_ nodes: Nodes, context: LiveContextStorage) -> some TabContent where Nodes: RandomAccessCollection, Nodes.Index == Int, Nodes.Element == Node @@ -79,7 +81,7 @@ struct TabTreeBuilder { @TabContentBuilder fileprivate func fromNode(_ node: Node, context: LiveContextStorage) -> some TabContent { // ToolbarTreeBuilder.fromNode may not be called with a root or leaf node - if case .element(let element) = node.data { + if case .nodeElement(let element) = node.data() { Self.lookup(ElementNode(node: node, data: element)) } } @@ -95,6 +97,7 @@ struct TabTreeBuilder { } @available(iOS 18.0, macOS 15.0, tvOS 18.0, watchOS 11.0, visionOS 2.0, *) +@MainActor struct Tab: TabContent { @ObservedElement private var element: ElementNode @LiveContext private var context diff --git a/Sources/LiveViewNative/Views/Text Input and Output/Text.swift b/Sources/LiveViewNative/Views/Text Input and Output/Text.swift index fea3968d6..d63130def 100644 --- a/Sources/LiveViewNative/Views/Text Input and Output/Text.swift +++ b/Sources/LiveViewNative/Views/Text Input and Output/Text.swift @@ -213,14 +213,14 @@ struct Text: View { } } else { return $liveElement.childNodes.reduce(into: SwiftUI.Text("")) { prev, next in - switch next.data { - case let .element(data): + switch next.data() { + case let .nodeElement(data): guard !data.attributes.contains(where: { $0.name.namespace == nil && $0.name.name == "template" }) else { return } let element = ElementNode(node: next, data: data) - switch data.tag { + switch data.name.name { case "Text": prev = prev + Self( element: element, diff --git a/Sources/LiveViewNative/_GeneratedModifiers.swift b/Sources/LiveViewNative/_GeneratedModifiers.swift index 876831753..85103e3f5 100644 --- a/Sources/LiveViewNative/_GeneratedModifiers.swift +++ b/Sources/LiveViewNative/_GeneratedModifiers.swift @@ -59,7 +59,7 @@ struct _accessibilityActionModifier: ViewModifier { enum Value { case _never - indirect case _0(label: ViewReference=ViewReference(value: [])) + indirect case _0(label: ViewReference) } @@ -109,7 +109,7 @@ struct _accessibilityActionsModifier: ViewModifier { indirect case _0(category: Any,content: Any) #endif - indirect case _1(content: ViewReference=ViewReference(value: [])) + indirect case _1(content: ViewReference) } @@ -125,7 +125,7 @@ struct _accessibilityActionsModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(tvOS 18.0,macOS 15.0,visionOS 2.0,iOS 18.0,watchOS 11.0, *) + @available(visionOS 2.0,macOS 15.0,iOS 18.0,watchOS 11.0,tvOS 18.0, *) init(category: SwiftUI.AccessibilityActionCategory,content content: ViewReference=ViewReference(value: [])) { self.value = ._0(category: category, content: content) @@ -145,7 +145,7 @@ struct _accessibilityActionsModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(category, content): - if #available(tvOS 18.0,macOS 15.0,visionOS 2.0,iOS 18.0,watchOS 11.0, *) { + if #available(visionOS 2.0,macOS 15.0,iOS 18.0,watchOS 11.0,tvOS 18.0, *) { let category = category as! SwiftUI.AccessibilityActionCategory let content = content as! ViewReference @@ -177,7 +177,7 @@ struct _accessibilityChildrenModifier: ViewModifier { enum Value { case _never - indirect case _0(children: ViewReference=ViewReference(value: [])) + indirect case _0(children: ViewReference) } @@ -224,7 +224,7 @@ struct _accessibilityIgnoresInvertColorsModifier: ViewModifier enum Value { case _never - indirect case _0(active: AttributeReference = .init(storage: .constant(true)) ) + indirect case _0(active: AttributeReference) } @@ -271,7 +271,7 @@ struct _accessibilityRepresentationModifier: ViewModifier { enum Value { case _never - indirect case _0(representation: ViewReference=ViewReference(value: [])) + indirect case _0(representation: ViewReference) } @@ -318,7 +318,7 @@ struct _accessibilityShowsLargeContentViewerModifier: ViewModif enum Value { case _never - indirect case _0(largeContentView: ViewReference=ViewReference(value: [])) + indirect case _0(largeContentView: ViewReference) case _1 @@ -388,25 +388,25 @@ struct _alertModifier: ViewModifier { enum Value { case _never - indirect case _0(titleKey: SwiftUICore.LocalizedStringKey,actions: ViewReference=ViewReference(value: [])) + indirect case _0(titleKey: SwiftUICore.LocalizedStringKey,actions: ViewReference) - indirect case _1(title: AttributeReference,actions: ViewReference=ViewReference(value: [])) + indirect case _1(title: AttributeReference,actions: ViewReference) - indirect case _2(title: TextReference,actions: ViewReference=ViewReference(value: [])) + indirect case _2(title: TextReference,actions: ViewReference) - indirect case _3(titleKey: SwiftUICore.LocalizedStringKey,actions: ViewReference=ViewReference(value: []),message: ViewReference=ViewReference(value: [])) + indirect case _3(titleKey: SwiftUICore.LocalizedStringKey,actions: ViewReference,message: ViewReference) - indirect case _4(title: AttributeReference,actions: ViewReference=ViewReference(value: []),message: ViewReference=ViewReference(value: [])) + indirect case _4(title: AttributeReference,actions: ViewReference,message: ViewReference) - indirect case _5(title: TextReference,actions: ViewReference=ViewReference(value: []),message: ViewReference=ViewReference(value: [])) + indirect case _5(title: TextReference,actions: ViewReference,message: ViewReference) - indirect case _6(error: AnyLocalizedError,actions: ViewReference=ViewReference(value: [])) + indirect case _6(error: AnyLocalizedError,actions: ViewReference) } @@ -681,7 +681,7 @@ struct _allowsWindowActivationEventsModifier: ViewModifier { #if os(iOS) || os(macOS) || os(visionOS) - @available(iOS 18.0,visionOS 2.0,macOS 15.0, *) + @available(visionOS 2.0,iOS 18.0,macOS 15.0, *) init(_ value: AttributeReference? = .init(storage: .constant(true)) ) { self.value = ._0(value: value) @@ -694,7 +694,7 @@ struct _allowsWindowActivationEventsModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(visionOS) case let ._0(value): - if #available(iOS 18.0,visionOS 2.0,macOS 15.0, *) { + if #available(visionOS 2.0,iOS 18.0,macOS 15.0, *) { let value = value as? AttributeReference __content @@ -784,7 +784,7 @@ struct _aspectRatioModifier: ViewModifier { enum Value { case _never - indirect case _0(aspectRatio: AttributeReference? = .init(storage: .constant(nil)), contentMode: SwiftUICore.ContentMode) + indirect case _0(aspectRatio: AttributeReference?, contentMode: SwiftUICore.ContentMode) indirect case _1(aspectRatio: CoreFoundation.CGSize,contentMode: SwiftUICore.ContentMode) @@ -868,7 +868,7 @@ struct _autocapitalizationModifier: ViewModifier { #if os(iOS) || os(tvOS) || os(visionOS) - @available(iOS 16.0,visionOS 1.0,tvOS 16.0, *) + @available(iOS 16.0,tvOS 16.0,visionOS 1.0, *) init(_ style: UIKit.UITextAutocapitalizationType) { self.value = ._0(style: style) @@ -881,7 +881,7 @@ struct _autocapitalizationModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(tvOS) || os(visionOS) case let ._0(style): - if #available(iOS 16.0,visionOS 1.0,tvOS 16.0, *) { + if #available(iOS 16.0,tvOS 16.0,visionOS 1.0, *) { let style = style as! UIKit.UITextAutocapitalizationType __content @@ -901,7 +901,7 @@ struct _autocorrectionDisabledModifier: ViewModifier { enum Value { case _never - indirect case _0(disable: AttributeReference = .init(storage: .constant(true)) ) + indirect case _0(disable: AttributeReference) } @@ -948,28 +948,28 @@ struct _backgroundModifier: ViewModifier { enum Value { case _never - indirect case _0(background: InlineViewReference,alignment: AttributeReference = .init(storage: .constant(.center)) ) + indirect case _0(background: InlineViewReference,alignment: AttributeReference) - indirect case _1(alignment: AttributeReference = .init(storage: .constant(.center)), content: ViewReference=ViewReference(value: [])) + indirect case _1(alignment: AttributeReference, content: ViewReference) - indirect case _2(edges: SwiftUICore.Edge.Set = .all ) + indirect case _2(edges: SwiftUICore.Edge.Set ) - indirect case _3(style: AnyShapeStyle.Resolvable,edges: SwiftUICore.Edge.Set = .all ) + indirect case _3(style: AnyShapeStyle.Resolvable,edges: SwiftUICore.Edge.Set ) - indirect case _4(shape: AnyShape,fillStyle: SwiftUICore.FillStyle = FillStyle() ) + indirect case _4(shape: AnyShape,fillStyle: SwiftUICore.FillStyle ) - indirect case _5(style: AnyShapeStyle.Resolvable,shape: AnyShape,fillStyle: SwiftUICore.FillStyle = FillStyle() ) + indirect case _5(style: AnyShapeStyle.Resolvable,shape: AnyShape,fillStyle: SwiftUICore.FillStyle ) - indirect case _6(shape: AnyInsettableShape,fillStyle: SwiftUICore.FillStyle = FillStyle() ) + indirect case _6(shape: AnyInsettableShape,fillStyle: SwiftUICore.FillStyle ) - indirect case _7(style: AnyShapeStyle.Resolvable,shape: AnyInsettableShape,fillStyle: SwiftUICore.FillStyle = FillStyle() ) + indirect case _7(style: AnyShapeStyle.Resolvable,shape: AnyInsettableShape,fillStyle: SwiftUICore.FillStyle ) } @@ -1232,28 +1232,28 @@ struct _badgeModifier: ViewModifier { #if os(iOS) || os(macOS) || os(visionOS) - @available(iOS 15.0,visionOS 1.0,macOS 12.0, *) + @available(visionOS 1.0,iOS 15.0,macOS 12.0, *) init(_ count: AttributeReference) { self.value = ._0(count: count) } #endif #if os(iOS) || os(macOS) || os(visionOS) - @available(iOS 15.0,visionOS 1.0,macOS 12.0, *) + @available(visionOS 1.0,iOS 15.0,macOS 12.0, *) init(_ label: TextReference?) { self.value = ._1(label: label) } #endif #if os(iOS) || os(macOS) || os(visionOS) - @available(iOS 15.0,visionOS 1.0,macOS 12.0, *) + @available(iOS 15.0,macOS 12.0,visionOS 1.0, *) init(_ key: SwiftUICore.LocalizedStringKey?) { self.value = ._2(key: key) } #endif #if os(iOS) || os(macOS) || os(visionOS) - @available(iOS 15.0,visionOS 1.0,macOS 12.0, *) + @available(iOS 15.0,macOS 12.0,visionOS 1.0, *) init(_ label: AttributeReference) { self.value = ._3(label: label) @@ -1266,7 +1266,7 @@ struct _badgeModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(visionOS) case let ._0(count): - if #available(iOS 15.0,visionOS 1.0,macOS 12.0, *) { + if #available(visionOS 1.0,iOS 15.0,macOS 12.0, *) { let count = count as! AttributeReference __content @@ -1277,7 +1277,7 @@ struct _badgeModifier: ViewModifier { #endif #if os(iOS) || os(macOS) || os(visionOS) case let ._1(label): - if #available(iOS 15.0,visionOS 1.0,macOS 12.0, *) { + if #available(visionOS 1.0,iOS 15.0,macOS 12.0, *) { let label = label as? TextReference __content._observeTextReference(label, on: element, in: context) { __content in __content @@ -1288,7 +1288,7 @@ struct _badgeModifier: ViewModifier { #endif #if os(iOS) || os(macOS) || os(visionOS) case let ._2(key): - if #available(iOS 15.0,visionOS 1.0,macOS 12.0, *) { + if #available(iOS 15.0,macOS 12.0,visionOS 1.0, *) { let key = key as? SwiftUICore.LocalizedStringKey __content @@ -1299,7 +1299,7 @@ struct _badgeModifier: ViewModifier { #endif #if os(iOS) || os(macOS) || os(visionOS) case let ._3(label): - if #available(iOS 15.0,visionOS 1.0,macOS 12.0, *) { + if #available(iOS 15.0,macOS 12.0,visionOS 1.0, *) { let label = label as! AttributeReference __content @@ -1413,7 +1413,7 @@ struct _blurModifier: ViewModifier { enum Value { case _never - indirect case _0(radius: AttributeReference,opaque: AttributeReference = .init(storage: .constant(false)) ) + indirect case _0(radius: AttributeReference,opaque: AttributeReference) } @@ -1460,7 +1460,7 @@ struct _borderModifier: ViewModifier { enum Value { case _never - indirect case _0(content: AnyShapeStyle.Resolvable,width: AttributeReference = .init(storage: .constant(1)) ) + indirect case _0(content: AnyShapeStyle.Resolvable,width: AttributeReference) } @@ -1671,7 +1671,7 @@ struct _clipShapeModifier: ViewModifier { enum Value { case _never - indirect case _0(shape: AnyShape,style: SwiftUICore.FillStyle = FillStyle() ) + indirect case _0(shape: AnyShape,style: SwiftUICore.FillStyle ) } @@ -1718,7 +1718,7 @@ struct _clippedModifier: ViewModifier { enum Value { case _never - indirect case _0(antialiased: AttributeReference = .init(storage: .constant(false)) ) + indirect case _0(antialiased: AttributeReference) } @@ -1953,22 +1953,22 @@ struct _confirmationDialogModifier: ViewModifier { enum Value { case _never - indirect case _0(titleKey: SwiftUICore.LocalizedStringKey,titleVisibility: AttributeReference = .init(storage: .constant(.automatic)), actions: ViewReference=ViewReference(value: [])) + indirect case _0(titleKey: SwiftUICore.LocalizedStringKey,titleVisibility: AttributeReference, actions: ViewReference) - indirect case _1(title: AttributeReference,titleVisibility: AttributeReference = .init(storage: .constant(.automatic)), actions: ViewReference=ViewReference(value: [])) + indirect case _1(title: AttributeReference,titleVisibility: AttributeReference, actions: ViewReference) - indirect case _2(title: TextReference,titleVisibility: AttributeReference = .init(storage: .constant(.automatic)), actions: ViewReference=ViewReference(value: [])) + indirect case _2(title: TextReference,titleVisibility: AttributeReference, actions: ViewReference) - indirect case _3(titleKey: SwiftUICore.LocalizedStringKey,titleVisibility: AttributeReference = .init(storage: .constant(.automatic)), actions: ViewReference=ViewReference(value: []),message: ViewReference=ViewReference(value: [])) + indirect case _3(titleKey: SwiftUICore.LocalizedStringKey,titleVisibility: AttributeReference, actions: ViewReference,message: ViewReference) - indirect case _4(title: AttributeReference,titleVisibility: AttributeReference = .init(storage: .constant(.automatic)), actions: ViewReference=ViewReference(value: []),message: ViewReference=ViewReference(value: [])) + indirect case _4(title: AttributeReference,titleVisibility: AttributeReference, actions: ViewReference,message: ViewReference) - indirect case _5(title: TextReference,titleVisibility: AttributeReference = .init(storage: .constant(.automatic)), actions: ViewReference=ViewReference(value: []),message: ViewReference=ViewReference(value: [])) + indirect case _5(title: TextReference,titleVisibility: AttributeReference, actions: ViewReference,message: ViewReference) } @@ -2134,14 +2134,14 @@ struct _containerRelativeFrameModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 17.0,tvOS 17.0,watchOS 10.0,visionOS 1.0,macOS 14.0, *) + @available(tvOS 17.0,macOS 14.0,visionOS 1.0,iOS 17.0,watchOS 10.0, *) init(_ axes: SwiftUICore.Axis.Set,alignment: AttributeReference = .init(storage: .constant(.center)) ) { self.value = ._0(axes: axes, alignment: alignment) } #endif #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 17.0,tvOS 17.0,watchOS 10.0,visionOS 1.0,macOS 14.0, *) + @available(tvOS 17.0,macOS 14.0,visionOS 1.0,iOS 17.0,watchOS 10.0, *) init(_ axes: SwiftUICore.Axis.Set,count: AttributeReference,span: AttributeReference = .init(storage: .constant(1)), spacing: AttributeReference,alignment: AttributeReference = .init(storage: .constant(.center)) ) { self.value = ._1(axes: axes, count: count, span: span, spacing: spacing, alignment: alignment) @@ -2154,7 +2154,7 @@ struct _containerRelativeFrameModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(axes, alignment): - if #available(iOS 17.0,tvOS 17.0,watchOS 10.0,visionOS 1.0,macOS 14.0, *) { + if #available(tvOS 17.0,macOS 14.0,visionOS 1.0,iOS 17.0,watchOS 10.0, *) { let axes = axes as! SwiftUICore.Axis.Set let alignment = alignment as! AttributeReference @@ -2166,7 +2166,7 @@ let alignment = alignment as! AttributeReference #endif #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._1(axes, count, span, spacing, alignment): - if #available(iOS 17.0,tvOS 17.0,watchOS 10.0,visionOS 1.0,macOS 14.0, *) { + if #available(tvOS 17.0,macOS 14.0,visionOS 1.0,iOS 17.0,watchOS 10.0, *) { let axes = axes as! SwiftUICore.Axis.Set let count = count as! AttributeReference let span = span as! AttributeReference @@ -2261,21 +2261,21 @@ struct _contentMarginsModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 17.0,watchOS 10.0,macOS 14.0,tvOS 17.0,visionOS 1.0, *) + @available(tvOS 17.0,macOS 14.0,visionOS 1.0,iOS 17.0,watchOS 10.0, *) init(_ edges: SwiftUICore.Edge.Set = .all, _ insets: SwiftUICore.EdgeInsets,for placement: SwiftUI.ContentMarginPlacement = .automatic ) { self.value = ._0(edges: edges, insets: insets, placement: placement) } #endif #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 17.0,watchOS 10.0,macOS 14.0,tvOS 17.0,visionOS 1.0, *) + @available(tvOS 17.0,macOS 14.0,visionOS 1.0,iOS 17.0,watchOS 10.0, *) init(_ edges: SwiftUICore.Edge.Set = .all, _ length: AttributeReference?,for placement: SwiftUI.ContentMarginPlacement = .automatic ) { self.value = ._1(edges: edges, length: length, placement: placement) } #endif #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 17.0,watchOS 10.0,macOS 14.0,tvOS 17.0,visionOS 1.0, *) + @available(macOS 14.0,watchOS 10.0,iOS 17.0,tvOS 17.0,visionOS 1.0, *) init(_ length: AttributeReference,for placement: SwiftUI.ContentMarginPlacement = .automatic ) { self.value = ._2(length: length, placement: placement) @@ -2288,7 +2288,7 @@ struct _contentMarginsModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(edges, insets, placement): - if #available(iOS 17.0,watchOS 10.0,macOS 14.0,tvOS 17.0,visionOS 1.0, *) { + if #available(tvOS 17.0,macOS 14.0,visionOS 1.0,iOS 17.0,watchOS 10.0, *) { let edges = edges as! SwiftUICore.Edge.Set let insets = insets as! SwiftUICore.EdgeInsets let placement = placement as! SwiftUI.ContentMarginPlacement @@ -2301,7 +2301,7 @@ let placement = placement as! SwiftUI.ContentMarginPlacement #endif #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._1(edges, length, placement): - if #available(iOS 17.0,watchOS 10.0,macOS 14.0,tvOS 17.0,visionOS 1.0, *) { + if #available(tvOS 17.0,macOS 14.0,visionOS 1.0,iOS 17.0,watchOS 10.0, *) { let edges = edges as! SwiftUICore.Edge.Set let length = length as? AttributeReference let placement = placement as! SwiftUI.ContentMarginPlacement @@ -2314,7 +2314,7 @@ let placement = placement as! SwiftUI.ContentMarginPlacement #endif #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._2(length, placement): - if #available(iOS 17.0,watchOS 10.0,macOS 14.0,tvOS 17.0,visionOS 1.0, *) { + if #available(macOS 14.0,watchOS 10.0,iOS 17.0,tvOS 17.0,visionOS 1.0, *) { let length = length as! AttributeReference let placement = placement as! SwiftUI.ContentMarginPlacement @@ -2335,10 +2335,10 @@ struct _contentShapeModifier: ViewModifier { enum Value { case _never - indirect case _0(kind: SwiftUICore.ContentShapeKinds,shape: AnyShape,eoFill: AttributeReference = .init(storage: .constant(false)) ) + indirect case _0(kind: SwiftUICore.ContentShapeKinds,shape: AnyShape,eoFill: AttributeReference) - indirect case _1(shape: AnyShape,eoFill: AttributeReference = .init(storage: .constant(false)) ) + indirect case _1(shape: AnyShape,eoFill: AttributeReference) } @@ -2452,7 +2452,7 @@ struct _contextMenuModifier: ViewModifier { enum Value { case _never - indirect case _0(menuItems: ViewReference=ViewReference(value: [])) + indirect case _0(menuItems: ViewReference) #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) indirect case _1(menuItems: Any,preview: Any) @@ -2478,7 +2478,7 @@ struct _contextMenuModifier: ViewModifier { } #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) - @available(iOS 16.0,macOS 13.0,tvOS 16.0,visionOS 1.0, *) + @available(tvOS 16.0,macOS 13.0,iOS 16.0,visionOS 1.0, *) init(menuItems: ViewReference=ViewReference(value: []),preview: ViewReference=ViewReference(value: [])) { self.value = ._1(menuItems: menuItems, preview: preview) @@ -2502,7 +2502,7 @@ struct _contextMenuModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) case let ._1(menuItems, preview): - if #available(iOS 16.0,macOS 13.0,tvOS 16.0,visionOS 1.0, *) { + if #available(tvOS 16.0,macOS 13.0,iOS 16.0,visionOS 1.0, *) { let menuItems = menuItems as! ViewReference let preview = preview as! ViewReference @@ -2584,7 +2584,7 @@ struct _controlGroupStyleModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) - @available(iOS 15.0,macOS 12.0,tvOS 17.0,visionOS 1.0, *) + @available(macOS 12.0,iOS 15.0,tvOS 17.0,visionOS 1.0, *) init(_ style: AnyControlGroupStyle) { self.value = ._0(style: style) @@ -2597,7 +2597,7 @@ struct _controlGroupStyleModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) case let ._0(style): - if #available(iOS 15.0,macOS 12.0,tvOS 17.0,visionOS 1.0, *) { + if #available(macOS 12.0,iOS 15.0,tvOS 17.0,visionOS 1.0, *) { let style = style as! AnyControlGroupStyle __content @@ -2631,7 +2631,7 @@ struct _controlSizeModifier: ViewModifier { #if os(iOS) || os(macOS) || os(visionOS) || os(watchOS) - @available(visionOS 1.0,watchOS 9.0,macOS 10.15,iOS 15.0, *) + @available(macOS 10.15,watchOS 9.0,iOS 15.0,visionOS 1.0, *) init(_ controlSize: SwiftUICore.ControlSize) { self.value = ._0(controlSize: controlSize) @@ -2644,7 +2644,7 @@ struct _controlSizeModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(visionOS) || os(watchOS) case let ._0(controlSize): - if #available(visionOS 1.0,watchOS 9.0,macOS 10.15,iOS 15.0, *) { + if #available(macOS 10.15,watchOS 9.0,iOS 15.0,visionOS 1.0, *) { let controlSize = controlSize as! SwiftUICore.ControlSize __content @@ -2690,7 +2690,7 @@ struct _coordinateSpaceModifier: ViewModifier { } #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 17.0,tvOS 17.0,watchOS 10.0,visionOS 1.0,macOS 14.0, *) + @available(macOS 14.0,watchOS 10.0,iOS 17.0,tvOS 17.0,visionOS 1.0, *) init(_ name: SwiftUICore.NamedCoordinateSpace) { self.value = ._1(name: name) @@ -2714,7 +2714,7 @@ struct _coordinateSpaceModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._1(name): - if #available(iOS 17.0,tvOS 17.0,watchOS 10.0,visionOS 1.0,macOS 14.0, *) { + if #available(macOS 14.0,watchOS 10.0,iOS 17.0,tvOS 17.0,visionOS 1.0, *) { let name = name as! SwiftUICore.NamedCoordinateSpace __content @@ -2734,7 +2734,7 @@ struct _cornerRadiusModifier: ViewModifier { enum Value { case _never - indirect case _0(radius: AttributeReference,antialiased: AttributeReference = .init(storage: .constant(true)) ) + indirect case _0(radius: AttributeReference,antialiased: AttributeReference) } @@ -2795,7 +2795,7 @@ struct _datePickerStyleModifier: ViewModifier { #if os(iOS) || os(macOS) || os(visionOS) || os(watchOS) - @available(visionOS 1.0,watchOS 10.0,iOS 13.0,macOS 10.15, *) + @available(macOS 10.15,watchOS 10.0,iOS 13.0,visionOS 1.0, *) init(_ style: AnyDatePickerStyle) { self.value = ._0(style: style) @@ -2808,7 +2808,7 @@ struct _datePickerStyleModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(visionOS) || os(watchOS) case let ._0(style): - if #available(visionOS 1.0,watchOS 10.0,iOS 13.0,macOS 10.15, *) { + if #available(macOS 10.15,watchOS 10.0,iOS 13.0,visionOS 1.0, *) { let style = style as! AnyDatePickerStyle __content @@ -2889,7 +2889,7 @@ struct _defaultHoverEffectModifier: ViewModifier { #if os(iOS) || os(tvOS) || os(visionOS) - @available(iOS 17.0,visionOS 1.0,tvOS 17.0, *) + @available(iOS 17.0,tvOS 17.0,visionOS 1.0, *) init(_ effect: SwiftUI.HoverEffect?) { self.value = ._0(effect: effect) @@ -2902,7 +2902,7 @@ struct _defaultHoverEffectModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(tvOS) || os(visionOS) case let ._0(effect): - if #available(iOS 17.0,visionOS 1.0,tvOS 17.0, *) { + if #available(iOS 17.0,tvOS 17.0,visionOS 1.0, *) { let effect = effect as? SwiftUI.HoverEffect __content @@ -2941,14 +2941,14 @@ struct _defaultScrollAnchorModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(tvOS 17.0,watchOS 10.0,iOS 17.0,visionOS 1.0,macOS 14.0, *) + @available(macOS 14.0,watchOS 10.0,iOS 17.0,tvOS 17.0,visionOS 1.0, *) init(_ anchor: AttributeReference?) { self.value = ._0(anchor: anchor) } #endif #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(tvOS 18.0,watchOS 11.0,iOS 18.0,visionOS 2.0,macOS 15.0, *) + @available(macOS 15.0,visionOS 2.0,tvOS 18.0,iOS 18.0,watchOS 11.0, *) init(_ anchor: AttributeReference?,for role: SwiftUI.ScrollAnchorRole) { self.value = ._1(anchor: anchor, role: role) @@ -2961,7 +2961,7 @@ struct _defaultScrollAnchorModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(anchor): - if #available(tvOS 17.0,watchOS 10.0,iOS 17.0,visionOS 1.0,macOS 14.0, *) { + if #available(macOS 14.0,watchOS 10.0,iOS 17.0,tvOS 17.0,visionOS 1.0, *) { let anchor = anchor as? AttributeReference __content @@ -2972,7 +2972,7 @@ struct _defaultScrollAnchorModifier: ViewModifier { #endif #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._1(anchor, role): - if #available(tvOS 18.0,watchOS 11.0,iOS 18.0,visionOS 2.0,macOS 15.0, *) { + if #available(macOS 15.0,visionOS 2.0,tvOS 18.0,iOS 18.0,watchOS 11.0, *) { let anchor = anchor as? AttributeReference let role = role as! SwiftUI.ScrollAnchorRole @@ -3007,7 +3007,7 @@ struct _defaultWheelPickerItemHeightModifier: ViewModifier { #if os(visionOS) || os(watchOS) - @available(visionOS 1.0,watchOS 6.0, *) + @available(watchOS 6.0,visionOS 1.0, *) init(_ height: AttributeReference) { self.value = ._0(height: height) @@ -3020,7 +3020,7 @@ struct _defaultWheelPickerItemHeightModifier: ViewModifier { fatalError("unreachable") #if os(visionOS) || os(watchOS) case let ._0(height): - if #available(visionOS 1.0,watchOS 6.0, *) { + if #available(watchOS 6.0,visionOS 1.0, *) { let height = height as! AttributeReference __content @@ -3163,28 +3163,28 @@ struct _dialogSuppressionToggleModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 17.0,macOS 14.0,tvOS 17.0,watchOS 10.0,visionOS 1.0, *) + @available(tvOS 17.0,macOS 14.0,visionOS 1.0,iOS 17.0,watchOS 10.0, *) init(_ titleKey: SwiftUICore.LocalizedStringKey,isSuppressed: ChangeTracked) { self.value = ._0(titleKey: titleKey) self.__0_isSuppressed = isSuppressed } #endif #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 17.0,macOS 14.0,tvOS 17.0,watchOS 10.0,visionOS 1.0, *) + @available(tvOS 17.0,macOS 14.0,visionOS 1.0,iOS 17.0,watchOS 10.0, *) init(_ title: AttributeReference,isSuppressed: ChangeTracked) { self.value = ._1(title: title) self.__1_isSuppressed = isSuppressed } #endif #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 17.0,macOS 14.0,tvOS 17.0,watchOS 10.0,visionOS 1.0, *) + @available(tvOS 17.0,macOS 14.0,visionOS 1.0,iOS 17.0,watchOS 10.0, *) init(_ label: TextReference,isSuppressed: ChangeTracked) { self.value = ._2(label: label) self.__2_isSuppressed = isSuppressed } #endif #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 17.0,macOS 14.0,tvOS 17.0,watchOS 10.0,visionOS 1.0, *) + @available(tvOS 17.0,macOS 14.0,visionOS 1.0,iOS 17.0,watchOS 10.0, *) init(isSuppressed: ChangeTracked) { self.value = ._3 self.__3_isSuppressed = isSuppressed @@ -3197,7 +3197,7 @@ struct _dialogSuppressionToggleModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(titleKey): - if #available(iOS 17.0,macOS 14.0,tvOS 17.0,watchOS 10.0,visionOS 1.0, *) { + if #available(tvOS 17.0,macOS 14.0,visionOS 1.0,iOS 17.0,watchOS 10.0, *) { let titleKey = titleKey as! SwiftUICore.LocalizedStringKey __content @@ -3208,7 +3208,7 @@ struct _dialogSuppressionToggleModifier: ViewModifier { #endif #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._1(title): - if #available(iOS 17.0,macOS 14.0,tvOS 17.0,watchOS 10.0,visionOS 1.0, *) { + if #available(tvOS 17.0,macOS 14.0,visionOS 1.0,iOS 17.0,watchOS 10.0, *) { let title = title as! AttributeReference __content @@ -3219,7 +3219,7 @@ struct _dialogSuppressionToggleModifier: ViewModifier { #endif #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._2(label): - if #available(iOS 17.0,macOS 14.0,tvOS 17.0,watchOS 10.0,visionOS 1.0, *) { + if #available(tvOS 17.0,macOS 14.0,visionOS 1.0,iOS 17.0,watchOS 10.0, *) { let label = label as! TextReference __content._observeTextReference(label, on: element, in: context) { __content in __content @@ -3230,7 +3230,7 @@ struct _dialogSuppressionToggleModifier: ViewModifier { #endif #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case ._3: - if #available(iOS 17.0,macOS 14.0,tvOS 17.0,watchOS 10.0,visionOS 1.0, *) { + if #available(tvOS 17.0,macOS 14.0,visionOS 1.0,iOS 17.0,watchOS 10.0, *) { __content @@ -3403,53 +3403,6 @@ struct _disabledModifier: ViewModifier { - } - } -} -@_documentation(visibility: public) -@ParseableExpression -struct _disclosureGroupStyleModifier: ViewModifier { - static var name: String { "disclosureGroupStyle" } - - enum Value { - case _never - #if os(iOS) || os(macOS) || os(visionOS) - indirect case _0(style: Any) - #endif - } - - let value: Value - - - - - - - - - #if os(iOS) || os(macOS) || os(visionOS) - @available(iOS 16.0,macOS 13.0,visionOS 1.0, *) - init(_ style: AnyDisclosureGroupStyle) { - self.value = ._0(style: style) - - } - #endif - - func body(content __content: Content) -> some View { - switch value { - case ._never: - fatalError("unreachable") - #if os(iOS) || os(macOS) || os(visionOS) - case let ._0(style): - if #available(iOS 16.0,macOS 13.0,visionOS 1.0, *) { - let style = style as! AnyDisclosureGroupStyle - - __content - .disclosureGroupStyle(style) - - - } else { __content } - #endif } } } @@ -3638,7 +3591,7 @@ struct _drawingGroupModifier: ViewModifier { enum Value { case _never - indirect case _0(opaque: AttributeReference = .init(storage: .constant(false)), colorMode: SwiftUICore.ColorRenderingMode = .nonLinear ) + indirect case _0(opaque: AttributeReference, colorMode: SwiftUICore.ColorRenderingMode ) } @@ -3816,7 +3769,7 @@ struct _fileDialogCustomizationIDModifier: ViewModifier { #if os(iOS) || os(macOS) || os(visionOS) - @available(iOS 17.0,visionOS 1.0,macOS 14.0, *) + @available(visionOS 1.0,iOS 17.0,macOS 14.0, *) init(_ id: AttributeReference) { self.value = ._0(id: id) @@ -3829,7 +3782,7 @@ struct _fileDialogCustomizationIDModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(visionOS) case let ._0(id): - if #available(iOS 17.0,visionOS 1.0,macOS 14.0, *) { + if #available(visionOS 1.0,iOS 17.0,macOS 14.0, *) { let id = id as! AttributeReference __content @@ -3863,7 +3816,7 @@ struct _fileDialogImportsUnresolvedAliasesModifier: ViewModifie #if os(iOS) || os(macOS) || os(visionOS) - @available(iOS 17.0,visionOS 1.0,macOS 14.0, *) + @available(visionOS 1.0,iOS 17.0,macOS 14.0, *) init(_ imports: AttributeReference) { self.value = ._0(imports: imports) @@ -3876,7 +3829,7 @@ struct _fileDialogImportsUnresolvedAliasesModifier: ViewModifie fatalError("unreachable") #if os(iOS) || os(macOS) || os(visionOS) case let ._0(imports): - if #available(iOS 17.0,visionOS 1.0,macOS 14.0, *) { + if #available(visionOS 1.0,iOS 17.0,macOS 14.0, *) { let imports = imports as! AttributeReference __content @@ -4121,7 +4074,7 @@ struct _focusEffectDisabledModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 17.0,macOS 14.0,watchOS 10.0,tvOS 17.0,visionOS 1.0, *) + @available(macOS 14.0,watchOS 10.0,iOS 17.0,tvOS 17.0,visionOS 1.0, *) init(_ disabled: AttributeReference = .init(storage: .constant(true)) ) { self.value = ._0(disabled: disabled) @@ -4134,7 +4087,7 @@ struct _focusEffectDisabledModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(disabled): - if #available(iOS 17.0,macOS 14.0,watchOS 10.0,tvOS 17.0,visionOS 1.0, *) { + if #available(macOS 14.0,watchOS 10.0,iOS 17.0,tvOS 17.0,visionOS 1.0, *) { let disabled = disabled as! AttributeReference __content @@ -4225,21 +4178,21 @@ struct _focusableModifier: ViewModifier { @Event private var _2_onFocusChange__1: Event.EventHandler #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 17.0,macOS 12.0,tvOS 15.0,watchOS 8.0,visionOS 1.0, *) + @available(macOS 12.0,watchOS 8.0,iOS 17.0,tvOS 15.0,visionOS 1.0, *) init(_ isFocusable: AttributeReference = .init(storage: .constant(true)) ) { self.value = ._0(isFocusable: isFocusable) } #endif #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 17.0,macOS 14.0,tvOS 17.0,watchOS 10.0,visionOS 1.0, *) + @available(macOS 14.0,watchOS 10.0,iOS 17.0,tvOS 17.0,visionOS 1.0, *) init(_ isFocusable: AttributeReference = .init(storage: .constant(true)), interactions: SwiftUI.FocusInteractions) { self.value = ._1(isFocusable: isFocusable, interactions: interactions) } #endif #if os(macOS) || os(tvOS) || os(watchOS) - @available(tvOS 16.0,macOS 13.0,watchOS 9.0, *) + @available(watchOS 9.0,macOS 13.0,tvOS 16.0, *) init(_ isFocusable: AttributeReference = .init(storage: .constant(true)), onFocusChange onFocusChange__1: Event ) { self.value = ._2(isFocusable: isFocusable) self.__2_onFocusChange__1 = onFocusChange__1 @@ -4252,7 +4205,7 @@ struct _focusableModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(isFocusable): - if #available(iOS 17.0,macOS 12.0,tvOS 15.0,watchOS 8.0,visionOS 1.0, *) { + if #available(macOS 12.0,watchOS 8.0,iOS 17.0,tvOS 15.0,visionOS 1.0, *) { let isFocusable = isFocusable as! AttributeReference __content @@ -4263,7 +4216,7 @@ struct _focusableModifier: ViewModifier { #endif #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._1(isFocusable, interactions): - if #available(iOS 17.0,macOS 14.0,tvOS 17.0,watchOS 10.0,visionOS 1.0, *) { + if #available(macOS 14.0,watchOS 10.0,iOS 17.0,tvOS 17.0,visionOS 1.0, *) { let isFocusable = isFocusable as! AttributeReference let interactions = interactions as! SwiftUI.FocusInteractions @@ -4275,7 +4228,7 @@ let interactions = interactions as! SwiftUI.FocusInteractions #endif #if os(macOS) || os(tvOS) || os(watchOS) case let ._2(isFocusable): - if #available(tvOS 16.0,macOS 13.0,watchOS 9.0, *) { + if #available(watchOS 9.0,macOS 13.0,tvOS 16.0, *) { let isFocusable = isFocusable as! AttributeReference __content @@ -4395,13 +4348,13 @@ struct _frameModifier: ViewModifier { indirect case _1(minDepth: Any?, idealDepth: Any?, maxDepth: Any?, alignment: Any) #endif - indirect case _2(width: AttributeReference? = .init(storage: .constant(nil)), height: AttributeReference? = .init(storage: .constant(nil)), alignment: AttributeReference = .init(storage: .constant(.center)) ) + indirect case _2(width: AttributeReference?, height: AttributeReference?, alignment: AttributeReference) case _3 - indirect case _4(minWidth: AttributeReference? = .init(storage: .constant(nil)), idealWidth: AttributeReference? = .init(storage: .constant(nil)), maxWidth: AttributeReference? = .init(storage: .constant(nil)), minHeight: AttributeReference? = .init(storage: .constant(nil)), idealHeight: AttributeReference? = .init(storage: .constant(nil)), maxHeight: AttributeReference? = .init(storage: .constant(nil)), alignment: AttributeReference = .init(storage: .constant(.center)) ) + indirect case _4(minWidth: AttributeReference?, idealWidth: AttributeReference?, maxWidth: AttributeReference?, minHeight: AttributeReference?, idealHeight: AttributeReference?, maxHeight: AttributeReference?, alignment: AttributeReference) } @@ -4546,7 +4499,7 @@ struct _fullScreenCoverModifier: ViewModifier { @Event private var _0_onDismiss__0: Event.EventHandler #if os(iOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 14.0,visionOS 1.0,watchOS 7.0,tvOS 14.0, *) + @available(watchOS 7.0,iOS 14.0,tvOS 14.0,visionOS 1.0, *) init(isPresented: ChangeTracked,onDismiss onDismiss__0: Event=Event(), content: ViewReference=ViewReference(value: [])) { self.value = ._0(content: content) self.__0_isPresented = isPresented @@ -4560,7 +4513,7 @@ self.__0_onDismiss__0 = onDismiss__0 fatalError("unreachable") #if os(iOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(content): - if #available(iOS 14.0,visionOS 1.0,watchOS 7.0,tvOS 14.0, *) { + if #available(watchOS 7.0,iOS 14.0,tvOS 14.0,visionOS 1.0, *) { let content = content as! ViewReference __content @@ -4594,7 +4547,7 @@ struct _gaugeStyleModifier: ViewModifier { #if os(iOS) || os(macOS) || os(visionOS) || os(watchOS) - @available(iOS 16.0,macOS 13.0,watchOS 7.0,visionOS 1.0, *) + @available(macOS 13.0,watchOS 7.0,iOS 16.0,visionOS 1.0, *) init(_ style: AnyGaugeStyle) { self.value = ._0(style: style) @@ -4607,7 +4560,7 @@ struct _gaugeStyleModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(visionOS) || os(watchOS) case let ._0(style): - if #available(iOS 16.0,macOS 13.0,watchOS 7.0,visionOS 1.0, *) { + if #available(macOS 13.0,watchOS 7.0,iOS 16.0,visionOS 1.0, *) { let style = style as! AnyGaugeStyle __content @@ -4641,7 +4594,7 @@ struct _geometryGroupModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(tvOS 17.0,watchOS 10.0,visionOS 1.0,macOS 14.0,iOS 17.0, *) + @available(macOS 14.0,tvOS 17.0,iOS 17.0,watchOS 10.0,visionOS 1.0, *) init() { self.value = ._0 @@ -4654,7 +4607,7 @@ struct _geometryGroupModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case ._0: - if #available(tvOS 17.0,watchOS 10.0,visionOS 1.0,macOS 14.0,iOS 17.0, *) { + if #available(macOS 14.0,tvOS 17.0,iOS 17.0,watchOS 10.0,visionOS 1.0, *) { __content @@ -4674,7 +4627,7 @@ struct _gestureModifier: ViewModifier { enum Value { case _never - indirect case _0(gesture: _AnyGesture,mask: SwiftUICore.GestureMask = .all ) + indirect case _0(gesture: _AnyGesture,mask: SwiftUICore.GestureMask ) indirect case _1(gesture: _AnyGesture,isEnabled: AttributeReference) @@ -4712,7 +4665,7 @@ struct _gestureModifier: ViewModifier { } #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 18.0,macOS 15.0,tvOS 18.0,watchOS 11.0,visionOS 2.0, *) + @available(visionOS 2.0,iOS 18.0,tvOS 18.0,watchOS 11.0,macOS 15.0, *) init(_ gesture: _AnyGesture,name: AttributeReference,isEnabled: AttributeReference = .init(storage: .constant(true)) ) { self.value = ._2(gesture: gesture, name: name, isEnabled: isEnabled) @@ -4747,7 +4700,7 @@ struct _gestureModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._2(gesture, name, isEnabled): - if #available(iOS 18.0,macOS 15.0,tvOS 18.0,watchOS 11.0,visionOS 2.0, *) { + if #available(visionOS 2.0,iOS 18.0,tvOS 18.0,watchOS 11.0,macOS 15.0, *) { let gesture = gesture as! _AnyGesture let name = name as! AttributeReference let isEnabled = isEnabled as! AttributeReference @@ -5089,7 +5042,7 @@ struct _groupBoxStyleModifier: ViewModifier { #if os(iOS) || os(macOS) || os(visionOS) - @available(iOS 14.0,visionOS 1.0,macOS 11.0, *) + @available(iOS 14.0,macOS 11.0,visionOS 1.0, *) init(_ style: AnyGroupBoxStyle) { self.value = ._0(style: style) @@ -5102,7 +5055,7 @@ struct _groupBoxStyleModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(visionOS) case let ._0(style): - if #available(iOS 14.0,visionOS 1.0,macOS 11.0, *) { + if #available(iOS 14.0,macOS 11.0,visionOS 1.0, *) { let style = style as! AnyGroupBoxStyle __content @@ -5404,7 +5357,7 @@ struct _highPriorityGestureModifier: ViewModifier { enum Value { case _never - indirect case _0(gesture: _AnyGesture,mask: SwiftUICore.GestureMask = .all ) + indirect case _0(gesture: _AnyGesture,mask: SwiftUICore.GestureMask ) indirect case _1(gesture: _AnyGesture,isEnabled: AttributeReference) @@ -5442,7 +5395,7 @@ struct _highPriorityGestureModifier: ViewModifier { } #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 18.0,macOS 15.0,tvOS 18.0,watchOS 11.0,visionOS 2.0, *) + @available(visionOS 2.0,iOS 18.0,tvOS 18.0,watchOS 11.0,macOS 15.0, *) init(_ gesture: _AnyGesture,name: AttributeReference,isEnabled: AttributeReference = .init(storage: .constant(true)) ) { self.value = ._2(gesture: gesture, name: name, isEnabled: isEnabled) @@ -5477,7 +5430,7 @@ struct _highPriorityGestureModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._2(gesture, name, isEnabled): - if #available(iOS 18.0,macOS 15.0,tvOS 18.0,watchOS 11.0,visionOS 2.0, *) { + if #available(visionOS 2.0,iOS 18.0,tvOS 18.0,watchOS 11.0,macOS 15.0, *) { let gesture = gesture as! _AnyGesture let name = name as! AttributeReference let isEnabled = isEnabled as! AttributeReference @@ -5565,14 +5518,14 @@ struct _hoverEffectModifier: ViewModifier { #if os(iOS) || os(tvOS) || os(visionOS) - @available(iOS 13.4,visionOS 1.0,tvOS 16.0, *) + @available(visionOS 1.0,iOS 13.4,tvOS 16.0, *) init(_ effect: SwiftUI.HoverEffect = .automatic ) { self.value = ._0(effect: effect) } #endif #if os(iOS) || os(tvOS) || os(visionOS) - @available(iOS 17.0,visionOS 1.0,tvOS 17.0, *) + @available(iOS 17.0,tvOS 17.0,visionOS 1.0, *) init(_ effect: SwiftUI.HoverEffect = .automatic, isEnabled: AttributeReference = .init(storage: .constant(true)) ) { self.value = ._1(effect: effect, isEnabled: isEnabled) @@ -5585,7 +5538,7 @@ struct _hoverEffectModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(tvOS) || os(visionOS) case let ._0(effect): - if #available(iOS 13.4,visionOS 1.0,tvOS 16.0, *) { + if #available(visionOS 1.0,iOS 13.4,tvOS 16.0, *) { let effect = effect as! SwiftUI.HoverEffect __content @@ -5596,7 +5549,7 @@ struct _hoverEffectModifier: ViewModifier { #endif #if os(iOS) || os(tvOS) || os(visionOS) case let ._1(effect, isEnabled): - if #available(iOS 17.0,visionOS 1.0,tvOS 17.0, *) { + if #available(iOS 17.0,tvOS 17.0,visionOS 1.0, *) { let effect = effect as! SwiftUI.HoverEffect let isEnabled = isEnabled as! AttributeReference @@ -5631,7 +5584,7 @@ struct _hoverEffectDisabledModifier: ViewModifier { #if os(iOS) || os(tvOS) || os(visionOS) - @available(iOS 17.0,visionOS 1.0,tvOS 17.0, *) + @available(tvOS 17.0,visionOS 1.0,iOS 17.0, *) init(_ disabled: AttributeReference = .init(storage: .constant(true)) ) { self.value = ._0(disabled: disabled) @@ -5644,7 +5597,7 @@ struct _hoverEffectDisabledModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(tvOS) || os(visionOS) case let ._0(disabled): - if #available(iOS 17.0,visionOS 1.0,tvOS 17.0, *) { + if #available(tvOS 17.0,visionOS 1.0,iOS 17.0, *) { let disabled = disabled as! AttributeReference __content @@ -5806,7 +5759,7 @@ struct _ignoresSafeAreaModifier: ViewModifier { enum Value { case _never - indirect case _0(regions: SwiftUICore.SafeAreaRegions = .all, edges: SwiftUICore.Edge.Set = .all ) + indirect case _0(regions: SwiftUICore.SafeAreaRegions , edges: SwiftUICore.Edge.Set ) } @@ -5961,7 +5914,7 @@ struct _indexViewStyleModifier: ViewModifier { #if os(iOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 14.0,watchOS 8.0,tvOS 14.0,visionOS 1.0, *) + @available(watchOS 8.0,iOS 14.0,tvOS 14.0,visionOS 1.0, *) init(_ style: AnyIndexViewStyle) { self.value = ._0(style: style) @@ -5974,7 +5927,7 @@ struct _indexViewStyleModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(style): - if #available(iOS 14.0,watchOS 8.0,tvOS 14.0,visionOS 1.0, *) { + if #available(watchOS 8.0,iOS 14.0,tvOS 14.0,visionOS 1.0, *) { let style = style as! AnyIndexViewStyle __content @@ -6160,7 +6113,7 @@ struct _interactiveDismissDisabledModifier: ViewModifier { enum Value { case _never - indirect case _0(isDisabled: AttributeReference = .init(storage: .constant(true)) ) + indirect case _0(isDisabled: AttributeReference) } @@ -6221,7 +6174,7 @@ struct _invalidatableContentModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(watchOS 10.0,macOS 14.0,tvOS 17.0,iOS 17.0,visionOS 1.0, *) + @available(tvOS 17.0,macOS 14.0,visionOS 1.0,iOS 17.0,watchOS 10.0, *) init(_ invalidatable: AttributeReference = .init(storage: .constant(true)) ) { self.value = ._0(invalidatable: invalidatable) @@ -6234,7 +6187,7 @@ struct _invalidatableContentModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(invalidatable): - if #available(watchOS 10.0,macOS 14.0,tvOS 17.0,iOS 17.0,visionOS 1.0, *) { + if #available(tvOS 17.0,macOS 14.0,visionOS 1.0,iOS 17.0,watchOS 10.0, *) { let invalidatable = invalidatable as! AttributeReference __content @@ -6283,28 +6236,28 @@ struct _keyboardShortcutModifier: ViewModifier { #if os(iOS) || os(macOS) || os(visionOS) - @available(iOS 14.0,visionOS 1.0,macOS 11.0, *) + @available(visionOS 1.0,iOS 14.0,macOS 11.0, *) init(_ key: SwiftUI.KeyEquivalent,modifiers: SwiftUICore.EventModifiers = .command ) { self.value = ._0(key: key, modifiers: modifiers) } #endif #if os(iOS) || os(macOS) || os(visionOS) - @available(iOS 14.0,visionOS 1.0,macOS 11.0, *) + @available(visionOS 1.0,iOS 14.0,macOS 11.0, *) init(_ shortcut: SwiftUI.KeyboardShortcut) { self.value = ._1(shortcut: shortcut) } #endif #if os(iOS) || os(macOS) || os(visionOS) - @available(iOS 15.4,visionOS 1.0,macOS 12.3, *) + @available(iOS 15.4,macOS 12.3,visionOS 1.0, *) init(_ shortcut: SwiftUI.KeyboardShortcut?) { self.value = ._2(shortcut: shortcut) } #endif #if os(iOS) || os(macOS) || os(visionOS) - @available(iOS 15.0,visionOS 1.0,macOS 12.0, *) + @available(iOS 15.0,macOS 12.0,visionOS 1.0, *) init(_ key: SwiftUI.KeyEquivalent,modifiers: SwiftUICore.EventModifiers = .command, localization: SwiftUI.KeyboardShortcut.Localization) { self.value = ._3(key: key, modifiers: modifiers, localization: localization) @@ -6317,7 +6270,7 @@ struct _keyboardShortcutModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(visionOS) case let ._0(key, modifiers): - if #available(iOS 14.0,visionOS 1.0,macOS 11.0, *) { + if #available(visionOS 1.0,iOS 14.0,macOS 11.0, *) { let key = key as! SwiftUI.KeyEquivalent let modifiers = modifiers as! SwiftUICore.EventModifiers @@ -6329,7 +6282,7 @@ let modifiers = modifiers as! SwiftUICore.EventModifiers #endif #if os(iOS) || os(macOS) || os(visionOS) case let ._1(shortcut): - if #available(iOS 14.0,visionOS 1.0,macOS 11.0, *) { + if #available(visionOS 1.0,iOS 14.0,macOS 11.0, *) { let shortcut = shortcut as! SwiftUI.KeyboardShortcut __content @@ -6340,7 +6293,7 @@ let modifiers = modifiers as! SwiftUICore.EventModifiers #endif #if os(iOS) || os(macOS) || os(visionOS) case let ._2(shortcut): - if #available(iOS 15.4,visionOS 1.0,macOS 12.3, *) { + if #available(iOS 15.4,macOS 12.3,visionOS 1.0, *) { let shortcut = shortcut as? SwiftUI.KeyboardShortcut __content @@ -6351,7 +6304,7 @@ let modifiers = modifiers as! SwiftUICore.EventModifiers #endif #if os(iOS) || os(macOS) || os(visionOS) case let ._3(key, modifiers, localization): - if #available(iOS 15.0,visionOS 1.0,macOS 12.0, *) { + if #available(iOS 15.0,macOS 12.0,visionOS 1.0, *) { let key = key as! SwiftUI.KeyEquivalent let modifiers = modifiers as! SwiftUICore.EventModifiers let localization = localization as! SwiftUI.KeyboardShortcut.Localization @@ -6387,7 +6340,7 @@ struct _keyboardTypeModifier: ViewModifier { #if os(iOS) || os(tvOS) || os(visionOS) - @available(iOS 13.0,tvOS 13.0,visionOS 1.0, *) + @available(tvOS 13.0,visionOS 1.0,iOS 13.0, *) init(_ type: UIKit.UIKeyboardType) { self.value = ._0(type: type) @@ -6400,7 +6353,7 @@ struct _keyboardTypeModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(tvOS) || os(visionOS) case let ._0(type): - if #available(iOS 13.0,tvOS 13.0,visionOS 1.0, *) { + if #available(tvOS 13.0,visionOS 1.0,iOS 13.0, *) { let type = type as! UIKit.UIKeyboardType __content @@ -6575,7 +6528,7 @@ struct _labelsVisibilityModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(tvOS 18.0,watchOS 11.0,visionOS 2.0,macOS 15.0,iOS 18.0, *) + @available(visionOS 2.0,iOS 18.0,tvOS 18.0,watchOS 11.0,macOS 15.0, *) init(_ visibility: AttributeReference) { self.value = ._0(visibility: visibility) @@ -6588,7 +6541,7 @@ struct _labelsVisibilityModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(visibility): - if #available(tvOS 18.0,watchOS 11.0,visionOS 2.0,macOS 15.0,iOS 18.0, *) { + if #available(visionOS 2.0,iOS 18.0,tvOS 18.0,watchOS 11.0,macOS 15.0, *) { let visibility = visibility as! AttributeReference __content @@ -7160,7 +7113,7 @@ struct _listRowSeparatorModifier: ViewModifier { #if os(iOS) || os(macOS) || os(visionOS) - @available(iOS 15.0,visionOS 1.0,macOS 13.0, *) + @available(visionOS 1.0,iOS 15.0,macOS 13.0, *) init(_ visibility: AttributeReference,edges: SwiftUICore.VerticalEdge.Set = .all ) { self.value = ._0(visibility: visibility, edges: edges) @@ -7173,7 +7126,7 @@ struct _listRowSeparatorModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(visionOS) case let ._0(visibility, edges): - if #available(iOS 15.0,visionOS 1.0,macOS 13.0, *) { + if #available(visionOS 1.0,iOS 15.0,macOS 13.0, *) { let visibility = visibility as! AttributeReference let edges = edges as! SwiftUICore.VerticalEdge.Set @@ -7208,7 +7161,7 @@ struct _listRowSeparatorTintModifier: ViewModifier { #if os(iOS) || os(macOS) || os(visionOS) - @available(iOS 15.0,visionOS 1.0,macOS 13.0, *) + @available(visionOS 1.0,iOS 15.0,macOS 13.0, *) init(_ color: Color.Resolvable?,edges: SwiftUICore.VerticalEdge.Set = .all ) { self.value = ._0(color: color, edges: edges) @@ -7221,7 +7174,7 @@ struct _listRowSeparatorTintModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(visionOS) case let ._0(color, edges): - if #available(iOS 15.0,visionOS 1.0,macOS 13.0, *) { + if #available(visionOS 1.0,iOS 15.0,macOS 13.0, *) { let color = color as? Color.Resolvable let edges = edges as! SwiftUICore.VerticalEdge.Set @@ -7303,7 +7256,7 @@ struct _listSectionSeparatorModifier: ViewModifier { #if os(iOS) || os(macOS) || os(visionOS) - @available(iOS 15.0,visionOS 1.0,macOS 13.0, *) + @available(visionOS 1.0,iOS 15.0,macOS 13.0, *) init(_ visibility: AttributeReference,edges: SwiftUICore.VerticalEdge.Set = .all ) { self.value = ._0(visibility: visibility, edges: edges) @@ -7316,7 +7269,7 @@ struct _listSectionSeparatorModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(visionOS) case let ._0(visibility, edges): - if #available(iOS 15.0,visionOS 1.0,macOS 13.0, *) { + if #available(visionOS 1.0,iOS 15.0,macOS 13.0, *) { let visibility = visibility as! AttributeReference let edges = edges as! SwiftUICore.VerticalEdge.Set @@ -7351,7 +7304,7 @@ struct _listSectionSeparatorTintModifier: ViewModifier { #if os(iOS) || os(macOS) || os(visionOS) - @available(iOS 15.0,visionOS 1.0,macOS 13.0, *) + @available(visionOS 1.0,iOS 15.0,macOS 13.0, *) init(_ color: Color.Resolvable?,edges: SwiftUICore.VerticalEdge.Set = .all ) { self.value = ._0(color: color, edges: edges) @@ -7364,7 +7317,7 @@ struct _listSectionSeparatorTintModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(visionOS) case let ._0(color, edges): - if #available(iOS 15.0,visionOS 1.0,macOS 13.0, *) { + if #available(visionOS 1.0,iOS 15.0,macOS 13.0, *) { let color = color as? Color.Resolvable let edges = edges as! SwiftUICore.VerticalEdge.Set @@ -7404,14 +7357,14 @@ struct _listSectionSpacingModifier: ViewModifier { #if os(iOS) || os(visionOS) || os(watchOS) - @available(iOS 17.0,watchOS 10.0,visionOS 1.0, *) + @available(visionOS 1.0,iOS 17.0,watchOS 10.0, *) init(_ spacing: SwiftUI.ListSectionSpacing) { self.value = ._0(spacing: spacing) } #endif #if os(iOS) || os(visionOS) || os(watchOS) - @available(iOS 17.0,watchOS 10.0,visionOS 1.0, *) + @available(visionOS 1.0,iOS 17.0,watchOS 10.0, *) init(_ spacing: AttributeReference) { self.value = ._1(spacing: spacing) @@ -7424,7 +7377,7 @@ struct _listSectionSpacingModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(visionOS) || os(watchOS) case let ._0(spacing): - if #available(iOS 17.0,watchOS 10.0,visionOS 1.0, *) { + if #available(visionOS 1.0,iOS 17.0,watchOS 10.0, *) { let spacing = spacing as! SwiftUI.ListSectionSpacing __content @@ -7435,7 +7388,7 @@ struct _listSectionSpacingModifier: ViewModifier { #endif #if os(iOS) || os(visionOS) || os(watchOS) case let ._1(spacing): - if #available(iOS 17.0,watchOS 10.0,visionOS 1.0, *) { + if #available(visionOS 1.0,iOS 17.0,watchOS 10.0, *) { let spacing = spacing as! AttributeReference __content @@ -7563,7 +7516,7 @@ struct _materialActiveAppearanceModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(tvOS 18.0,watchOS 11.0,visionOS 2.0,macOS 15.0,iOS 18.0, *) + @available(macOS 15.0,watchOS 11.0,iOS 18.0,tvOS 18.0,visionOS 2.0, *) init(_ appearance: SwiftUICore.MaterialActiveAppearance) { self.value = ._0(appearance: appearance) @@ -7576,7 +7529,7 @@ struct _materialActiveAppearanceModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(appearance): - if #available(tvOS 18.0,watchOS 11.0,visionOS 2.0,macOS 15.0,iOS 18.0, *) { + if #available(macOS 15.0,watchOS 11.0,iOS 18.0,tvOS 18.0,visionOS 2.0, *) { let appearance = appearance as! SwiftUICore.MaterialActiveAppearance __content @@ -7704,7 +7657,7 @@ struct _menuStyleModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) - @available(tvOS 17.0,visionOS 1.0,macOS 11.0,iOS 14.0, *) + @available(macOS 11.0,tvOS 17.0,visionOS 1.0,iOS 14.0, *) init(_ style: AnyMenuStyle) { self.value = ._0(style: style) @@ -7717,7 +7670,7 @@ struct _menuStyleModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) case let ._0(style): - if #available(tvOS 17.0,visionOS 1.0,macOS 11.0,iOS 14.0, *) { + if #available(macOS 11.0,tvOS 17.0,visionOS 1.0,iOS 14.0, *) { let style = style as! AnyMenuStyle __content @@ -7798,7 +7751,7 @@ struct _modifierKeyAlternateModifier: ViewModifier { #if os(macOS) || os(visionOS) - @available(visionOS 1.0,macOS 15.0, *) + @available(macOS 15.0,visionOS 1.0, *) init(_ modifiers: SwiftUICore.EventModifiers,_ alternate: ViewReference=ViewReference(value: [])) { self.value = ._0(modifiers: modifiers, alternate: alternate) @@ -7811,7 +7764,7 @@ struct _modifierKeyAlternateModifier: ViewModifier { fatalError("unreachable") #if os(macOS) || os(visionOS) case let ._0(modifiers, alternate): - if #available(visionOS 1.0,macOS 15.0, *) { + if #available(macOS 15.0,visionOS 1.0, *) { let modifiers = modifiers as! SwiftUICore.EventModifiers let alternate = alternate as! ViewReference @@ -7926,7 +7879,7 @@ struct _navigationBarBackButtonHiddenModifier: ViewModifier { enum Value { case _never - indirect case _0(hidesBackButton: AttributeReference = .init(storage: .constant(true)) ) + indirect case _0(hidesBackButton: AttributeReference) } @@ -7987,7 +7940,7 @@ struct _navigationBarHiddenModifier: ViewModifier { #if os(iOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 13.0,macOS 13.0,tvOS 13.0,watchOS 6.0,visionOS 1.0, *) + @available(tvOS 13.0,macOS 13.0,iOS 13.0,watchOS 6.0,visionOS 1.0, *) init(_ hidden: AttributeReference) { self.value = ._0(hidden: hidden) @@ -8000,7 +7953,7 @@ struct _navigationBarHiddenModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(hidden): - if #available(iOS 13.0,macOS 13.0,tvOS 13.0,watchOS 6.0,visionOS 1.0, *) { + if #available(tvOS 13.0,macOS 13.0,iOS 13.0,watchOS 6.0,visionOS 1.0, *) { let hidden = hidden as! AttributeReference __content @@ -8044,21 +7997,21 @@ struct _navigationBarItemsModifier: ViewModifier { #if os(iOS) || os(tvOS) || os(visionOS) - @available(iOS 16.0,visionOS 1.0,tvOS 16.0, *) + @available(visionOS 1.0,iOS 16.0,tvOS 16.0, *) init(leading: InlineViewReference,trailing: InlineViewReference) { self.value = ._0(leading: leading, trailing: trailing) } #endif #if os(iOS) || os(tvOS) || os(visionOS) - @available(iOS 16.0,visionOS 1.0,tvOS 16.0, *) + @available(visionOS 1.0,iOS 16.0,tvOS 16.0, *) init(leading: InlineViewReference) { self.value = ._1(leading: leading) } #endif #if os(iOS) || os(tvOS) || os(visionOS) - @available(iOS 16.0,visionOS 1.0,tvOS 16.0, *) + @available(visionOS 1.0,iOS 16.0,tvOS 16.0, *) init(trailing: InlineViewReference) { self.value = ._2(trailing: trailing) @@ -8071,7 +8024,7 @@ struct _navigationBarItemsModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(tvOS) || os(visionOS) case let ._0(leading, trailing): - if #available(iOS 16.0,visionOS 1.0,tvOS 16.0, *) { + if #available(visionOS 1.0,iOS 16.0,tvOS 16.0, *) { let leading = leading as! InlineViewReference let trailing = trailing as! InlineViewReference @@ -8083,7 +8036,7 @@ let trailing = trailing as! InlineViewReference #endif #if os(iOS) || os(tvOS) || os(visionOS) case let ._1(leading): - if #available(iOS 16.0,visionOS 1.0,tvOS 16.0, *) { + if #available(visionOS 1.0,iOS 16.0,tvOS 16.0, *) { let leading = leading as! InlineViewReference __content @@ -8094,7 +8047,7 @@ let trailing = trailing as! InlineViewReference #endif #if os(iOS) || os(tvOS) || os(visionOS) case let ._2(trailing): - if #available(iOS 16.0,visionOS 1.0,tvOS 16.0, *) { + if #available(visionOS 1.0,iOS 16.0,tvOS 16.0, *) { let trailing = trailing as! InlineViewReference __content @@ -8153,42 +8106,42 @@ struct _navigationBarTitleModifier: ViewModifier { #if os(iOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 13.0,macOS 13.0,tvOS 13.0,watchOS 6.0,visionOS 1.0, *) + @available(tvOS 13.0,macOS 13.0,iOS 13.0,watchOS 6.0,visionOS 1.0, *) init(_ title: TextReference) { self.value = ._0(title: title) } #endif #if os(iOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 13.0,macOS 13.0,tvOS 13.0,watchOS 6.0,visionOS 1.0, *) + @available(tvOS 13.0,macOS 13.0,iOS 13.0,watchOS 6.0,visionOS 1.0, *) init(_ titleKey: SwiftUICore.LocalizedStringKey) { self.value = ._1(titleKey: titleKey) } #endif #if os(iOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 13.0,macOS 13.0,tvOS 13.0,watchOS 6.0,visionOS 1.0, *) + @available(tvOS 13.0,macOS 13.0,visionOS 1.0,iOS 13.0,watchOS 6.0, *) init(_ title: AttributeReference) { self.value = ._2(title: title) } #endif #if os(iOS) || os(visionOS) - @available(iOS 13.0,macOS 13.0,tvOS 13.0,watchOS 6.0,visionOS 1.0, *) + @available(tvOS 13.0,macOS 13.0,visionOS 1.0,iOS 13.0,watchOS 6.0, *) init(_ title: TextReference,displayMode: SwiftUI.NavigationBarItem.TitleDisplayMode) { self.value = ._3(title: title, displayMode: displayMode) } #endif #if os(iOS) || os(visionOS) - @available(iOS 13.0,macOS 13.0,tvOS 13.0,watchOS 6.0,visionOS 1.0, *) + @available(macOS 13.0,watchOS 6.0,iOS 13.0,tvOS 13.0,visionOS 1.0, *) init(_ titleKey: SwiftUICore.LocalizedStringKey,displayMode: SwiftUI.NavigationBarItem.TitleDisplayMode) { self.value = ._4(titleKey: titleKey, displayMode: displayMode) } #endif #if os(iOS) || os(visionOS) - @available(iOS 13.0,macOS 13.0,tvOS 13.0,watchOS 6.0,visionOS 1.0, *) + @available(tvOS 13.0,iOS 13.0,watchOS 6.0,macOS 13.0,visionOS 1.0, *) init(_ title: AttributeReference,displayMode: SwiftUI.NavigationBarItem.TitleDisplayMode) { self.value = ._5(title: title, displayMode: displayMode) @@ -8201,7 +8154,7 @@ struct _navigationBarTitleModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(title): - if #available(iOS 13.0,macOS 13.0,tvOS 13.0,watchOS 6.0,visionOS 1.0, *) { + if #available(tvOS 13.0,macOS 13.0,iOS 13.0,watchOS 6.0,visionOS 1.0, *) { let title = title as! TextReference __content._observeTextReference(title, on: element, in: context) { __content in __content @@ -8212,7 +8165,7 @@ struct _navigationBarTitleModifier: ViewModifier { #endif #if os(iOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._1(titleKey): - if #available(iOS 13.0,macOS 13.0,tvOS 13.0,watchOS 6.0,visionOS 1.0, *) { + if #available(tvOS 13.0,macOS 13.0,iOS 13.0,watchOS 6.0,visionOS 1.0, *) { let titleKey = titleKey as! SwiftUICore.LocalizedStringKey __content @@ -8223,7 +8176,7 @@ struct _navigationBarTitleModifier: ViewModifier { #endif #if os(iOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._2(title): - if #available(iOS 13.0,macOS 13.0,tvOS 13.0,watchOS 6.0,visionOS 1.0, *) { + if #available(tvOS 13.0,macOS 13.0,visionOS 1.0,iOS 13.0,watchOS 6.0, *) { let title = title as! AttributeReference __content @@ -8234,7 +8187,7 @@ struct _navigationBarTitleModifier: ViewModifier { #endif #if os(iOS) || os(visionOS) case let ._3(title, displayMode): - if #available(iOS 13.0,macOS 13.0,tvOS 13.0,watchOS 6.0,visionOS 1.0, *) { + if #available(tvOS 13.0,macOS 13.0,visionOS 1.0,iOS 13.0,watchOS 6.0, *) { let title = title as! TextReference let displayMode = displayMode as! SwiftUI.NavigationBarItem.TitleDisplayMode __content._observeTextReference(title, on: element, in: context) { __content in @@ -8246,7 +8199,7 @@ let displayMode = displayMode as! SwiftUI.NavigationBarItem.TitleDisplayMode #endif #if os(iOS) || os(visionOS) case let ._4(titleKey, displayMode): - if #available(iOS 13.0,macOS 13.0,tvOS 13.0,watchOS 6.0,visionOS 1.0, *) { + if #available(macOS 13.0,watchOS 6.0,iOS 13.0,tvOS 13.0,visionOS 1.0, *) { let titleKey = titleKey as! SwiftUICore.LocalizedStringKey let displayMode = displayMode as! SwiftUI.NavigationBarItem.TitleDisplayMode @@ -8258,7 +8211,7 @@ let displayMode = displayMode as! SwiftUI.NavigationBarItem.TitleDisplayMode #endif #if os(iOS) || os(visionOS) case let ._5(title, displayMode): - if #available(iOS 13.0,macOS 13.0,tvOS 13.0,watchOS 6.0,visionOS 1.0, *) { + if #available(tvOS 13.0,iOS 13.0,watchOS 6.0,macOS 13.0,visionOS 1.0, *) { let title = title as! AttributeReference let displayMode = displayMode as! SwiftUI.NavigationBarItem.TitleDisplayMode @@ -8326,7 +8279,7 @@ struct _navigationDestinationModifier: ViewModifier { enum Value { case _never - indirect case _0(destination: ViewReference=ViewReference(value: [])) + indirect case _0(destination: ViewReference) } @@ -8376,7 +8329,7 @@ struct _navigationSplitViewColumnWidthModifier: ViewModifier { indirect case _0(width: AttributeReference) - indirect case _1(min: AttributeReference? = .init(storage: .constant(nil)), ideal: AttributeReference,max: AttributeReference? = .init(storage: .constant(nil)) ) + indirect case _1(min: AttributeReference?, ideal: AttributeReference,max: AttributeReference?) } @@ -8638,7 +8591,7 @@ struct _navigationTitleModifier: ViewModifier { } #if os(watchOS) - @available(tvOS 14.0,watchOS 7.0,macOS 11.0,iOS 14.0, *) + @available(iOS 14.0,watchOS 7.0,macOS 11.0,tvOS 14.0, *) init(_ title: ViewReference=ViewReference(value: [])) { self.value = ._3(title: title) @@ -8691,7 +8644,7 @@ struct _navigationTitleModifier: ViewModifier { #if os(watchOS) case let ._3(title): - if #available(tvOS 14.0,watchOS 7.0,macOS 11.0,iOS 14.0, *) { + if #available(iOS 14.0,watchOS 7.0,macOS 11.0,tvOS 14.0, *) { let title = title as! ViewReference __content @@ -8711,53 +8664,6 @@ struct _navigationTitleModifier: ViewModifier { - } - } -} -@_documentation(visibility: public) -@ParseableExpression -struct _navigationViewStyleModifier: ViewModifier { - static var name: String { "navigationViewStyle" } - - enum Value { - case _never - - indirect case _0(style: AnyNavigationViewStyle) - - } - - let value: Value - - - - - - - - - - - init(_ style: AnyNavigationViewStyle) { - self.value = ._0(style: style) - - } - - - func body(content __content: Content) -> some View { - switch value { - case ._never: - fatalError("unreachable") - - case let ._0(style): - - - - __content - .navigationViewStyle(style) - - - - } } } @@ -8775,7 +8681,7 @@ struct _offsetModifier: ViewModifier { indirect case _1(offset: CoreFoundation.CGSize) - indirect case _2(x: AttributeReference = .init(storage: .constant(0)), y: AttributeReference = .init(storage: .constant(0)) ) + indirect case _2(x: AttributeReference, y: AttributeReference) } @@ -8923,7 +8829,7 @@ struct _onDeleteCommandModifier: ViewModifier { @Event private var _0_action__0: Event.EventHandler #if os(macOS) - @available(macOS 10.15,tvOS 13.0, *) + @available(tvOS 13.0,macOS 10.15, *) init(perform action__0: Event=Event()) { self.value = ._0 self.__0_action__0 = action__0 @@ -8936,7 +8842,7 @@ struct _onDeleteCommandModifier: ViewModifier { fatalError("unreachable") #if os(macOS) case ._0: - if #available(macOS 10.15,tvOS 13.0, *) { + if #available(tvOS 13.0,macOS 10.15, *) { __content @@ -9017,7 +8923,7 @@ struct _onExitCommandModifier: ViewModifier { @Event private var _0_action__0: Event.EventHandler #if os(macOS) || os(tvOS) - @available(macOS 10.15,tvOS 13.0, *) + @available(tvOS 13.0,macOS 10.15, *) init(perform action__0: Event=Event()) { self.value = ._0 self.__0_action__0 = action__0 @@ -9030,7 +8936,7 @@ struct _onExitCommandModifier: ViewModifier { fatalError("unreachable") #if os(macOS) || os(tvOS) case ._0: - if #available(macOS 10.15,tvOS 13.0, *) { + if #available(tvOS 13.0,macOS 10.15, *) { __content @@ -9064,7 +8970,7 @@ struct _onHoverModifier: ViewModifier { @Event private var _0_action__1: Event.EventHandler #if os(iOS) || os(macOS) || os(visionOS) - @available(iOS 13.4,visionOS 1.0,macOS 10.15, *) + @available(visionOS 1.0,iOS 13.4,macOS 10.15, *) init(perform action__1: Event) { self.value = ._0 self.__0_action__1 = action__1 @@ -9077,7 +8983,7 @@ struct _onHoverModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(visionOS) case ._0: - if #available(iOS 13.4,visionOS 1.0,macOS 10.15, *) { + if #available(visionOS 1.0,iOS 13.4,macOS 10.15, *) { __content @@ -9177,7 +9083,7 @@ struct _onLongPressGestureModifier: ViewModifier { @Event private var _3_action__0: Event.EventHandler #if os(iOS) || os(macOS) || os(visionOS) || os(watchOS) - @available(tvOS 14.0,iOS 13.0,macOS 10.15,visionOS 1.0,watchOS 6.0, *) + @available(watchOS 6.0,tvOS 14.0,visionOS 1.0,macOS 10.15,iOS 13.0, *) init(minimumDuration: AttributeReference = .init(storage: .constant(0.5)), maximumDistance: AttributeReference = .init(storage: .constant(10)), perform action__0: Event,onPressingChanged onPressingChanged__1: Event=Event() ) { self.value = ._0(minimumDuration: minimumDuration, maximumDistance: maximumDistance) self.__0_action__0 = action__0 @@ -9185,7 +9091,7 @@ self.__0_onPressingChanged__1 = onPressingChanged__1 } #endif #if os(tvOS) - @available(tvOS 14.0,iOS 13.0,macOS 10.15,watchOS 6.0, *) + @available(macOS 10.15,watchOS 6.0,iOS 13.0,tvOS 14.0, *) init(minimumDuration: AttributeReference = .init(storage: .constant(0.5)), perform action__0: Event,onPressingChanged onPressingChanged__1: Event=Event() ) { self.value = ._1(minimumDuration: minimumDuration) self.__1_action__0 = action__0 @@ -9193,7 +9099,7 @@ self.__1_onPressingChanged__1 = onPressingChanged__1 } #endif #if os(iOS) || os(macOS) || os(visionOS) || os(watchOS) - @available(tvOS 14.0,iOS 13.0,macOS 10.15,visionOS 1.0,watchOS 6.0, *) + @available(macOS 10.15,watchOS 6.0,iOS 13.0,tvOS 14.0,visionOS 1.0, *) init(minimumDuration: AttributeReference = .init(storage: .constant(0.5)), maximumDistance: AttributeReference = .init(storage: .constant(10)), pressing pressing__1: Event=Event(), perform action__0: Event) { self.value = ._2(minimumDuration: minimumDuration, maximumDistance: maximumDistance) self.__2_pressing__1 = pressing__1 @@ -9201,7 +9107,7 @@ self.__2_action__0 = action__0 } #endif #if os(tvOS) - @available(tvOS 14.0,iOS 13.0,macOS 10.15,watchOS 6.0, *) + @available(macOS 10.15,watchOS 6.0,iOS 13.0,tvOS 14.0, *) init(minimumDuration: AttributeReference = .init(storage: .constant(0.5)), pressing pressing__1: Event=Event(), perform action__0: Event) { self.value = ._3(minimumDuration: minimumDuration) self.__3_pressing__1 = pressing__1 @@ -9215,7 +9121,7 @@ self.__3_action__0 = action__0 fatalError("unreachable") #if os(iOS) || os(macOS) || os(visionOS) || os(watchOS) case let ._0(minimumDuration, maximumDistance): - if #available(tvOS 14.0,iOS 13.0,macOS 10.15,visionOS 1.0,watchOS 6.0, *) { + if #available(watchOS 6.0,tvOS 14.0,visionOS 1.0,macOS 10.15,iOS 13.0, *) { let minimumDuration = minimumDuration as! AttributeReference let maximumDistance = maximumDistance as! AttributeReference @@ -9227,7 +9133,7 @@ let maximumDistance = maximumDistance as! AttributeReference __content @@ -9238,7 +9144,7 @@ let maximumDistance = maximumDistance as! AttributeReference let maximumDistance = maximumDistance as! AttributeReference @@ -9250,7 +9156,7 @@ let maximumDistance = maximumDistance as! AttributeReference __content @@ -9333,7 +9239,7 @@ struct _onModifierKeysChangedModifier: ViewModifier { @Event private var _0_action__2: Event.EventHandler #if os(macOS) || os(visionOS) - @available(visionOS 1.0,macOS 15.0, *) + @available(macOS 15.0,visionOS 1.0, *) init(mask: SwiftUICore.EventModifiers = .all, initial: AttributeReference = .init(storage: .constant(true)), action action__2: Event) { self.value = ._0(mask: mask, initial: initial) self.__0_action__2 = action__2 @@ -9346,7 +9252,7 @@ struct _onModifierKeysChangedModifier: ViewModifier { fatalError("unreachable") #if os(macOS) || os(visionOS) case let ._0(mask, initial): - if #available(visionOS 1.0,macOS 15.0, *) { + if #available(macOS 15.0,visionOS 1.0, *) { let mask = mask as! SwiftUICore.EventModifiers let initial = initial as! AttributeReference @@ -9381,7 +9287,7 @@ struct _onMoveCommandModifier: ViewModifier { @Event private var _0_action__1: Event.EventHandler #if os(macOS) || os(tvOS) - @available(macOS 10.15,tvOS 13.0, *) + @available(tvOS 13.0,macOS 10.15, *) init(perform action__1: Event=Event()) { self.value = ._0 self.__0_action__1 = action__1 @@ -9394,7 +9300,7 @@ struct _onMoveCommandModifier: ViewModifier { fatalError("unreachable") #if os(macOS) || os(tvOS) case ._0: - if #available(macOS 10.15,tvOS 13.0, *) { + if #available(tvOS 13.0,macOS 10.15, *) { __content @@ -9522,7 +9428,7 @@ struct _onPlayPauseCommandModifier: ViewModifier { @Event private var _0_action__0: Event.EventHandler #if os(tvOS) - @available(macOS 10.15,tvOS 13.0, *) + @available(tvOS 13.0,macOS 10.15, *) init(perform action__0: Event=Event()) { self.value = ._0 self.__0_action__0 = action__0 @@ -9535,7 +9441,7 @@ struct _onPlayPauseCommandModifier: ViewModifier { fatalError("unreachable") #if os(tvOS) case ._0: - if #available(macOS 10.15,tvOS 13.0, *) { + if #available(tvOS 13.0,macOS 10.15, *) { __content @@ -9569,7 +9475,7 @@ struct _onScrollPhaseChangeModifier: ViewModifier { @Event private var _0_action__2: Event.EventHandler #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(tvOS 18.0,visionOS 2.0,watchOS 11.0,macOS 15.0,iOS 18.0, *) + @available(visionOS 2.0,tvOS 18.0,macOS 15.0,watchOS 11.0,iOS 18.0, *) init(_ action__2: Event) { self.value = ._0 self.__0_action__2 = action__2 @@ -9582,7 +9488,7 @@ struct _onScrollPhaseChangeModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case ._0: - if #available(tvOS 18.0,visionOS 2.0,watchOS 11.0,macOS 15.0,iOS 18.0, *) { + if #available(visionOS 2.0,tvOS 18.0,macOS 15.0,watchOS 11.0,iOS 18.0, *) { __content @@ -9616,7 +9522,7 @@ struct _onScrollVisibilityChangeModifier: ViewModifier { @Event private var _0_action__1: Event.EventHandler #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(tvOS 18.0,watchOS 11.0,iOS 18.0,visionOS 2.0,macOS 15.0, *) + @available(tvOS 18.0,macOS 15.0,iOS 18.0,watchOS 11.0,visionOS 2.0, *) init(threshold: AttributeReference = .init(storage: .constant(0.5)), action action__1: Event) { self.value = ._0(threshold: threshold) self.__0_action__1 = action__1 @@ -9629,7 +9535,7 @@ struct _onScrollVisibilityChangeModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(threshold): - if #available(tvOS 18.0,watchOS 11.0,iOS 18.0,visionOS 2.0,macOS 15.0, *) { + if #available(tvOS 18.0,macOS 15.0,iOS 18.0,watchOS 11.0,visionOS 2.0, *) { let threshold = threshold as! AttributeReference __content @@ -9652,7 +9558,7 @@ struct _onTapGestureModifier: ViewModifier { indirect case _0(count: Any, coordinateSpace: Any) #endif - indirect case _1(count: AttributeReference = .init(storage: .constant(1))) + indirect case _1(count: AttributeReference) } @@ -9668,7 +9574,7 @@ struct _onTapGestureModifier: ViewModifier { @Event private var _1_action__0: Event.EventHandler #if os(iOS) || os(macOS) || os(visionOS) || os(watchOS) - @available(iOS 17.0,visionOS 1.0,watchOS 10.0,macOS 14.0, *) + @available(macOS 14.0,watchOS 10.0,iOS 17.0,visionOS 1.0, *) init(count: AttributeReference = .init(storage: .constant(1)), coordinateSpace: AnyCoordinateSpaceProtocol = .local, perform action__1: Event) { self.value = ._0(count: count, coordinateSpace: coordinateSpace) self.__0_action__1 = action__1 @@ -9688,7 +9594,7 @@ struct _onTapGestureModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(visionOS) || os(watchOS) case let ._0(count, coordinateSpace): - if #available(iOS 17.0,visionOS 1.0,watchOS 10.0,macOS 14.0, *) { + if #available(macOS 14.0,watchOS 10.0,iOS 17.0,visionOS 1.0, *) { let count = count as! AttributeReference let coordinateSpace = coordinateSpace as! AnyCoordinateSpaceProtocol @@ -9865,16 +9771,16 @@ struct _overlayModifier: ViewModifier { enum Value { case _never - indirect case _0(overlay: InlineViewReference,alignment: AttributeReference = .init(storage: .constant(.center)) ) + indirect case _0(overlay: InlineViewReference,alignment: AttributeReference) - indirect case _1(alignment: AttributeReference = .init(storage: .constant(.center)), content: ViewReference=ViewReference(value: [])) + indirect case _1(alignment: AttributeReference, content: ViewReference) - indirect case _2(style: AnyShapeStyle.Resolvable,edges: SwiftUICore.Edge.Set = .all ) + indirect case _2(style: AnyShapeStyle.Resolvable,edges: SwiftUICore.Edge.Set ) - indirect case _3(style: AnyShapeStyle.Resolvable,shape: AnyShape,fillStyle: SwiftUICore.FillStyle = FillStyle() ) + indirect case _3(style: AnyShapeStyle.Resolvable,shape: AnyShape,fillStyle: SwiftUICore.FillStyle ) } @@ -9984,7 +9890,7 @@ struct _paddingModifier: ViewModifier { indirect case _0(insets: SwiftUICore.EdgeInsets) - indirect case _1(edges: SwiftUICore.Edge.Set = .all, length: AttributeReference? = .init(storage: .constant(nil)) ) + indirect case _1(edges: SwiftUICore.Edge.Set , length: AttributeReference?) indirect case _2(length: AttributeReference) @@ -10276,7 +10182,7 @@ struct _pointerStyleModifier: ViewModifier { #if os(macOS) || os(visionOS) - @available(visionOS 2.0,macOS 15.0, *) + @available(macOS 15.0,visionOS 2.0, *) init(_ style: SwiftUI.PointerStyle?) { self.value = ._0(style: style) @@ -10289,7 +10195,7 @@ struct _pointerStyleModifier: ViewModifier { fatalError("unreachable") #if os(macOS) || os(visionOS) case let ._0(style): - if #available(visionOS 2.0,macOS 15.0, *) { + if #available(macOS 15.0,visionOS 2.0, *) { let style = style as? SwiftUI.PointerStyle __content @@ -10375,14 +10281,14 @@ struct _popoverModifier: ViewModifier { #if os(iOS) || os(macOS) || os(visionOS) - @available(macOS 10.15,visionOS 1.0,iOS 13.0, *) + @available(visionOS 1.0,iOS 13.0,macOS 10.15, *) init(isPresented: ChangeTracked,attachmentAnchor: SwiftUI.PopoverAttachmentAnchor = .rect(.bounds), arrowEdge: SwiftUICore.Edge = .top, content: ViewReference=ViewReference(value: [])) { self.value = ._0(attachmentAnchor: attachmentAnchor, arrowEdge: arrowEdge, content: content) self.__0_isPresented = isPresented } #endif #if os(iOS) || os(macOS) || os(visionOS) - @available(macOS 15.0,visionOS 2.0,iOS 18.0, *) + @available(visionOS 2.0,iOS 18.0,macOS 15.0, *) init(isPresented: ChangeTracked,attachmentAnchor: SwiftUI.PopoverAttachmentAnchor = .rect(.bounds), content: ViewReference=ViewReference(value: [])) { self.value = ._1(attachmentAnchor: attachmentAnchor, content: content) self.__1_isPresented = isPresented @@ -10395,7 +10301,7 @@ struct _popoverModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(visionOS) case let ._0(attachmentAnchor, arrowEdge, content): - if #available(macOS 10.15,visionOS 1.0,iOS 13.0, *) { + if #available(visionOS 1.0,iOS 13.0,macOS 10.15, *) { let attachmentAnchor = attachmentAnchor as! SwiftUI.PopoverAttachmentAnchor let arrowEdge = arrowEdge as! SwiftUICore.Edge let content = content as! ViewReference @@ -10408,7 +10314,7 @@ let content = content as! ViewReference #endif #if os(iOS) || os(macOS) || os(visionOS) case let ._1(attachmentAnchor, content): - if #available(macOS 15.0,visionOS 2.0,iOS 18.0, *) { + if #available(visionOS 2.0,iOS 18.0,macOS 15.0, *) { let attachmentAnchor = attachmentAnchor as! SwiftUI.PopoverAttachmentAnchor let content = content as! ViewReference @@ -10432,7 +10338,7 @@ struct _positionModifier: ViewModifier { indirect case _0(position: CoreFoundation.CGPoint) - indirect case _1(x: AttributeReference = .init(storage: .constant(0)), y: AttributeReference = .init(storage: .constant(0)) ) + indirect case _1(x: AttributeReference, y: AttributeReference) } @@ -10612,14 +10518,14 @@ struct _presentationBackgroundModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(tvOS 16.4,iOS 16.4,visionOS 1.0,macOS 13.3,watchOS 9.4, *) + @available(macOS 13.3,watchOS 9.4,iOS 16.4,tvOS 16.4,visionOS 1.0, *) init(_ style: AnyShapeStyle.Resolvable) { self.value = ._0(style: style) } #endif #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(tvOS 16.4,iOS 16.4,visionOS 1.0,macOS 13.3,watchOS 9.4, *) + @available(visionOS 1.0,watchOS 9.4,tvOS 16.4,iOS 16.4,macOS 13.3, *) init(alignment: AttributeReference = .init(storage: .constant(.center)), content: ViewReference=ViewReference(value: [])) { self.value = ._1(alignment: alignment, content: content) @@ -10632,7 +10538,7 @@ struct _presentationBackgroundModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(style): - if #available(tvOS 16.4,iOS 16.4,visionOS 1.0,macOS 13.3,watchOS 9.4, *) { + if #available(macOS 13.3,watchOS 9.4,iOS 16.4,tvOS 16.4,visionOS 1.0, *) { let style = style as! AnyShapeStyle.Resolvable __content @@ -10643,7 +10549,7 @@ struct _presentationBackgroundModifier: ViewModifier { #endif #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._1(alignment, content): - if #available(tvOS 16.4,iOS 16.4,visionOS 1.0,macOS 13.3,watchOS 9.4, *) { + if #available(visionOS 1.0,watchOS 9.4,tvOS 16.4,iOS 16.4,macOS 13.3, *) { let alignment = alignment as! AttributeReference let content = content as! ViewReference @@ -10678,7 +10584,7 @@ struct _presentationBackgroundInteractionModifier: ViewModifier #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 16.4,macOS 13.3,tvOS 16.4,watchOS 9.4,visionOS 1.0, *) + @available(macOS 13.3,watchOS 9.4,iOS 16.4,tvOS 16.4,visionOS 1.0, *) init(_ interaction: SwiftUI.PresentationBackgroundInteraction) { self.value = ._0(interaction: interaction) @@ -10691,7 +10597,7 @@ struct _presentationBackgroundInteractionModifier: ViewModifier fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(interaction): - if #available(iOS 16.4,macOS 13.3,tvOS 16.4,watchOS 9.4,visionOS 1.0, *) { + if #available(macOS 13.3,watchOS 9.4,iOS 16.4,tvOS 16.4,visionOS 1.0, *) { let interaction = interaction as! SwiftUI.PresentationBackgroundInteraction __content @@ -10730,14 +10636,14 @@ struct _presentationCompactAdaptationModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 16.4,macOS 13.3,tvOS 16.4,watchOS 9.4,visionOS 1.0, *) + @available(macOS 13.3,watchOS 9.4,iOS 16.4,tvOS 16.4,visionOS 1.0, *) init(_ adaptation: SwiftUI.PresentationAdaptation) { self.value = ._0(adaptation: adaptation) } #endif #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 16.4,macOS 13.3,tvOS 16.4,watchOS 9.4,visionOS 1.0, *) + @available(macOS 13.3,watchOS 9.4,iOS 16.4,tvOS 16.4,visionOS 1.0, *) init(horizontal horizontalAdaptation: SwiftUI.PresentationAdaptation,vertical verticalAdaptation: SwiftUI.PresentationAdaptation) { self.value = ._1(horizontalAdaptation: horizontalAdaptation, verticalAdaptation: verticalAdaptation) @@ -10750,7 +10656,7 @@ struct _presentationCompactAdaptationModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(adaptation): - if #available(iOS 16.4,macOS 13.3,tvOS 16.4,watchOS 9.4,visionOS 1.0, *) { + if #available(macOS 13.3,watchOS 9.4,iOS 16.4,tvOS 16.4,visionOS 1.0, *) { let adaptation = adaptation as! SwiftUI.PresentationAdaptation __content @@ -10761,7 +10667,7 @@ struct _presentationCompactAdaptationModifier: ViewModifier { #endif #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._1(horizontalAdaptation, verticalAdaptation): - if #available(iOS 16.4,macOS 13.3,tvOS 16.4,watchOS 9.4,visionOS 1.0, *) { + if #available(macOS 13.3,watchOS 9.4,iOS 16.4,tvOS 16.4,visionOS 1.0, *) { let horizontalAdaptation = horizontalAdaptation as! SwiftUI.PresentationAdaptation let verticalAdaptation = verticalAdaptation as! SwiftUI.PresentationAdaptation @@ -10796,7 +10702,7 @@ struct _presentationContentInteractionModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 16.4,macOS 13.3,tvOS 16.4,watchOS 9.4,visionOS 1.0, *) + @available(visionOS 1.0,iOS 16.4,tvOS 16.4,watchOS 9.4,macOS 13.3, *) init(_ behavior: SwiftUI.PresentationContentInteraction) { self.value = ._0(behavior: behavior) @@ -10809,7 +10715,7 @@ struct _presentationContentInteractionModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(behavior): - if #available(iOS 16.4,macOS 13.3,tvOS 16.4,watchOS 9.4,visionOS 1.0, *) { + if #available(visionOS 1.0,iOS 16.4,tvOS 16.4,watchOS 9.4,macOS 13.3, *) { let behavior = behavior as! SwiftUI.PresentationContentInteraction __content @@ -10843,7 +10749,7 @@ struct _presentationCornerRadiusModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 16.4,macOS 13.3,tvOS 16.4,watchOS 9.4,visionOS 1.0, *) + @available(macOS 13.3,watchOS 9.4,iOS 16.4,tvOS 16.4,visionOS 1.0, *) init(_ cornerRadius: AttributeReference?) { self.value = ._0(cornerRadius: cornerRadius) @@ -10856,7 +10762,7 @@ struct _presentationCornerRadiusModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(cornerRadius): - if #available(iOS 16.4,macOS 13.3,tvOS 16.4,watchOS 9.4,visionOS 1.0, *) { + if #available(macOS 13.3,watchOS 9.4,iOS 16.4,tvOS 16.4,visionOS 1.0, *) { let cornerRadius = cornerRadius as? AttributeReference __content @@ -10937,7 +10843,7 @@ struct _presentationSizingModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(tvOS 18.0,visionOS 2.0,watchOS 11.0,macOS 15.0,iOS 18.0, *) + @available(visionOS 2.0,tvOS 18.0,macOS 15.0,watchOS 11.0,iOS 18.0, *) init(_ sizing: AnyPresentationSizing) { self.value = ._0(sizing: sizing) @@ -10950,7 +10856,7 @@ struct _presentationSizingModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(sizing): - if #available(tvOS 18.0,visionOS 2.0,watchOS 11.0,macOS 15.0,iOS 18.0, *) { + if #available(visionOS 2.0,tvOS 18.0,macOS 15.0,watchOS 11.0,iOS 18.0, *) { let sizing = sizing as! AnyPresentationSizing __content @@ -11017,7 +10923,7 @@ struct _privacySensitiveModifier: ViewModifier { enum Value { case _never - indirect case _0(sensitive: AttributeReference = .init(storage: .constant(true)) ) + indirect case _0(sensitive: AttributeReference) } @@ -11346,7 +11252,7 @@ struct _rotationEffectModifier: ViewModifier { enum Value { case _never - indirect case _0(angle: AttributeReference,anchor: AttributeReference = .init(storage: .constant(.center)) ) + indirect case _0(angle: AttributeReference,anchor: AttributeReference) } @@ -11393,10 +11299,10 @@ struct _safeAreaInsetModifier: ViewModifier { enum Value { case _never - indirect case _0(edge: SwiftUICore.VerticalEdge,alignment: AttributeReference = .init(storage: .constant(.center)), spacing: AttributeReference? = .init(storage: .constant(nil)), content: ViewReference=ViewReference(value: [])) + indirect case _0(edge: SwiftUICore.VerticalEdge,alignment: AttributeReference, spacing: AttributeReference?, content: ViewReference) - indirect case _1(edge: SwiftUICore.HorizontalEdge,alignment: AttributeReference = .init(storage: .constant(.center)), spacing: AttributeReference? = .init(storage: .constant(nil)), content: ViewReference=ViewReference(value: [])) + indirect case _1(edge: SwiftUICore.HorizontalEdge,alignment: AttributeReference, spacing: AttributeReference?, content: ViewReference) } @@ -11487,21 +11393,21 @@ struct _safeAreaPaddingModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 17.0,macOS 14.0,tvOS 17.0,watchOS 10.0,visionOS 1.0, *) + @available(tvOS 17.0,macOS 14.0,visionOS 1.0,iOS 17.0,watchOS 10.0, *) init(_ insets: SwiftUICore.EdgeInsets) { self.value = ._0(insets: insets) } #endif #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 17.0,macOS 14.0,tvOS 17.0,watchOS 10.0,visionOS 1.0, *) + @available(tvOS 17.0,macOS 14.0,visionOS 1.0,iOS 17.0,watchOS 10.0, *) init(_ edges: SwiftUICore.Edge.Set = .all, _ length: AttributeReference? = .init(storage: .constant(nil)) ) { self.value = ._1(edges: edges, length: length) } #endif #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 17.0,macOS 14.0,tvOS 17.0,watchOS 10.0,visionOS 1.0, *) + @available(tvOS 17.0,macOS 14.0,visionOS 1.0,iOS 17.0,watchOS 10.0, *) init(_ length: AttributeReference) { self.value = ._2(length: length) @@ -11514,7 +11420,7 @@ struct _safeAreaPaddingModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(insets): - if #available(iOS 17.0,macOS 14.0,tvOS 17.0,watchOS 10.0,visionOS 1.0, *) { + if #available(tvOS 17.0,macOS 14.0,visionOS 1.0,iOS 17.0,watchOS 10.0, *) { let insets = insets as! SwiftUICore.EdgeInsets __content @@ -11525,7 +11431,7 @@ struct _safeAreaPaddingModifier: ViewModifier { #endif #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._1(edges, length): - if #available(iOS 17.0,macOS 14.0,tvOS 17.0,watchOS 10.0,visionOS 1.0, *) { + if #available(tvOS 17.0,macOS 14.0,visionOS 1.0,iOS 17.0,watchOS 10.0, *) { let edges = edges as! SwiftUICore.Edge.Set let length = length as? AttributeReference @@ -11537,7 +11443,7 @@ let length = length as? AttributeReference #endif #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._2(length): - if #available(iOS 17.0,macOS 14.0,tvOS 17.0,watchOS 10.0,visionOS 1.0, *) { + if #available(tvOS 17.0,macOS 14.0,visionOS 1.0,iOS 17.0,watchOS 10.0, *) { let length = length as! AttributeReference __content @@ -11613,13 +11519,13 @@ struct _scaleEffectModifier: ViewModifier { indirect case _2(x: Any, y: Any, z: Any, anchor: Any) #endif - indirect case _3(scale: CoreFoundation.CGSize,anchor: AttributeReference = .init(storage: .constant(.center)) ) + indirect case _3(scale: CoreFoundation.CGSize,anchor: AttributeReference) - indirect case _4(s: AttributeReference,anchor: AttributeReference = .init(storage: .constant(.center)) ) + indirect case _4(s: AttributeReference,anchor: AttributeReference) - indirect case _5(x: AttributeReference = .init(storage: .constant(1.0)), y: AttributeReference = .init(storage: .constant(1.0)), anchor: AttributeReference = .init(storage: .constant(.center)) ) + indirect case _5(x: AttributeReference, y: AttributeReference, anchor: AttributeReference) } @@ -11865,10 +11771,10 @@ struct _scenePaddingModifier: ViewModifier { enum Value { case _never - indirect case _0(edges: SwiftUICore.Edge.Set = .all ) + indirect case _0(edges: SwiftUICore.Edge.Set ) - indirect case _1(padding: SwiftUI.ScenePadding,edges: SwiftUICore.Edge.Set = .all ) + indirect case _1(padding: SwiftUI.ScenePadding,edges: SwiftUICore.Edge.Set ) } @@ -11949,7 +11855,7 @@ struct _scrollBounceBehaviorModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(tvOS 16.4,watchOS 9.4,iOS 16.4,visionOS 1.0,macOS 13.3, *) + @available(tvOS 16.4,macOS 13.3,iOS 16.4,watchOS 9.4,visionOS 1.0, *) init(_ behavior: SwiftUI.ScrollBounceBehavior,axes: SwiftUICore.Axis.Set = [.vertical] ) { self.value = ._0(behavior: behavior, axes: axes) @@ -11962,7 +11868,7 @@ struct _scrollBounceBehaviorModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(behavior, axes): - if #available(tvOS 16.4,watchOS 9.4,iOS 16.4,visionOS 1.0,macOS 13.3, *) { + if #available(tvOS 16.4,macOS 13.3,iOS 16.4,watchOS 9.4,visionOS 1.0, *) { let behavior = behavior as! SwiftUI.ScrollBounceBehavior let axes = axes as! SwiftUICore.Axis.Set @@ -11997,7 +11903,7 @@ struct _scrollClipDisabledModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(tvOS 17.0,watchOS 10.0,iOS 17.0,visionOS 1.0,macOS 14.0, *) + @available(macOS 14.0,watchOS 10.0,iOS 17.0,tvOS 17.0,visionOS 1.0, *) init(_ disabled: AttributeReference = .init(storage: .constant(true)) ) { self.value = ._0(disabled: disabled) @@ -12010,7 +11916,7 @@ struct _scrollClipDisabledModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(disabled): - if #available(tvOS 17.0,watchOS 10.0,iOS 17.0,visionOS 1.0,macOS 14.0, *) { + if #available(macOS 14.0,watchOS 10.0,iOS 17.0,tvOS 17.0,visionOS 1.0, *) { let disabled = disabled as! AttributeReference __content @@ -12044,7 +11950,7 @@ struct _scrollContentBackgroundModifier: ViewModifier { #if os(iOS) || os(macOS) || os(visionOS) || os(watchOS) - @available(visionOS 1.0,watchOS 9.0,macOS 13.0,iOS 16.0, *) + @available(visionOS 1.0,macOS 13.0,watchOS 9.0,iOS 16.0, *) init(_ visibility: AttributeReference) { self.value = ._0(visibility: visibility) @@ -12057,7 +11963,7 @@ struct _scrollContentBackgroundModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(visionOS) || os(watchOS) case let ._0(visibility): - if #available(visionOS 1.0,watchOS 9.0,macOS 13.0,iOS 16.0, *) { + if #available(visionOS 1.0,macOS 13.0,watchOS 9.0,iOS 16.0, *) { let visibility = visibility as! AttributeReference __content @@ -12138,7 +12044,7 @@ struct _scrollDismissesKeyboardModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) - @available(tvOS 16.0,watchOS 9.0,iOS 16.0,macOS 13.0, *) + @available(macOS 13.0,watchOS 9.0,iOS 16.0,tvOS 16.0, *) init(_ mode: SwiftUI.ScrollDismissesKeyboardMode) { self.value = ._0(mode: mode) @@ -12151,7 +12057,7 @@ struct _scrollDismissesKeyboardModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) case let ._0(mode): - if #available(tvOS 16.0,watchOS 9.0,iOS 16.0,macOS 13.0, *) { + if #available(macOS 13.0,watchOS 9.0,iOS 16.0,tvOS 16.0, *) { let mode = mode as! SwiftUI.ScrollDismissesKeyboardMode __content @@ -12171,7 +12077,7 @@ struct _scrollIndicatorsModifier: ViewModifier { enum Value { case _never - indirect case _0(visibility: SwiftUI.ScrollIndicatorVisibility,axes: SwiftUICore.Axis.Set = [.vertical, .horizontal] ) + indirect case _0(visibility: SwiftUI.ScrollIndicatorVisibility,axes: SwiftUICore.Axis.Set ) } @@ -12237,14 +12143,14 @@ struct _scrollIndicatorsFlashModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(tvOS 17.0,watchOS 10.0,iOS 17.0,visionOS 1.0,macOS 14.0, *) + @available(visionOS 1.0,tvOS 17.0,macOS 14.0,watchOS 10.0,iOS 17.0, *) init(trigger value: AttributeReference) { self.value = ._0(value: value) } #endif #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(tvOS 17.0,watchOS 10.0,iOS 17.0,visionOS 1.0,macOS 14.0, *) + @available(visionOS 1.0,tvOS 17.0,macOS 14.0,watchOS 10.0,iOS 17.0, *) init(onAppear: AttributeReference) { self.value = ._1(onAppear: onAppear) @@ -12257,7 +12163,7 @@ struct _scrollIndicatorsFlashModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(value): - if #available(tvOS 17.0,watchOS 10.0,iOS 17.0,visionOS 1.0,macOS 14.0, *) { + if #available(visionOS 1.0,tvOS 17.0,macOS 14.0,watchOS 10.0,iOS 17.0, *) { let value = value as! AttributeReference __content @@ -12268,7 +12174,7 @@ struct _scrollIndicatorsFlashModifier: ViewModifier { #endif #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._1(onAppear): - if #available(tvOS 17.0,watchOS 10.0,iOS 17.0,visionOS 1.0,macOS 14.0, *) { + if #available(visionOS 1.0,tvOS 17.0,macOS 14.0,watchOS 10.0,iOS 17.0, *) { let onAppear = onAppear as! AttributeReference __content @@ -12302,7 +12208,7 @@ struct _scrollPositionModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 17.0,macOS 14.0,tvOS 17.0,watchOS 10.0,visionOS 1.0, *) + @available(macOS 14.0,watchOS 10.0,iOS 17.0,tvOS 17.0,visionOS 1.0, *) init(id: ChangeTracked,anchor: AttributeReference? = .init(storage: .constant(nil)) ) { self.value = ._0(anchor: anchor) self.__0_id = id @@ -12315,7 +12221,7 @@ struct _scrollPositionModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(anchor): - if #available(iOS 17.0,macOS 14.0,tvOS 17.0,watchOS 10.0,visionOS 1.0, *) { + if #available(macOS 14.0,watchOS 10.0,iOS 17.0,tvOS 17.0,visionOS 1.0, *) { let anchor = anchor as? AttributeReference __content @@ -12349,7 +12255,7 @@ struct _scrollTargetBehaviorModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 17.0,tvOS 17.0,watchOS 10.0,visionOS 1.0,macOS 14.0, *) + @available(tvOS 17.0,macOS 14.0,visionOS 1.0,iOS 17.0,watchOS 10.0, *) init(_ behavior: AnyScrollTargetBehavior) { self.value = ._0(behavior: behavior) @@ -12362,7 +12268,7 @@ struct _scrollTargetBehaviorModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(behavior): - if #available(iOS 17.0,tvOS 17.0,watchOS 10.0,visionOS 1.0,macOS 14.0, *) { + if #available(tvOS 17.0,macOS 14.0,visionOS 1.0,iOS 17.0,watchOS 10.0, *) { let behavior = behavior as! AnyScrollTargetBehavior __content @@ -12396,7 +12302,7 @@ struct _scrollTargetLayoutModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 17.0,tvOS 17.0,watchOS 10.0,visionOS 1.0,macOS 14.0, *) + @available(tvOS 17.0,macOS 14.0,visionOS 1.0,iOS 17.0,watchOS 10.0, *) init(isEnabled: AttributeReference = .init(storage: .constant(true)) ) { self.value = ._0(isEnabled: isEnabled) @@ -12409,7 +12315,7 @@ struct _scrollTargetLayoutModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(isEnabled): - if #available(iOS 17.0,tvOS 17.0,watchOS 10.0,visionOS 1.0,macOS 14.0, *) { + if #available(tvOS 17.0,macOS 14.0,visionOS 1.0,iOS 17.0,watchOS 10.0, *) { let isEnabled = isEnabled as! AttributeReference __content @@ -12443,7 +12349,7 @@ struct _searchDictationBehaviorModifier: ViewModifier { #if os(iOS) || os(visionOS) - @available(iOS 17.0,visionOS 1.0, *) + @available(visionOS 1.0,iOS 17.0, *) init(_ dictationBehavior: SwiftUI.TextInputDictationBehavior) { self.value = ._0(dictationBehavior: dictationBehavior) @@ -12456,7 +12362,7 @@ struct _searchDictationBehaviorModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(visionOS) case let ._0(dictationBehavior): - if #available(iOS 17.0,visionOS 1.0, *) { + if #available(visionOS 1.0,iOS 17.0, *) { let dictationBehavior = dictationBehavior as! SwiftUI.TextInputDictationBehavior __content @@ -12490,7 +12396,7 @@ struct _searchPresentationToolbarBehaviorModifier: ViewModifier #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(tvOS 17.1,watchOS 10.1,visionOS 1.0,macOS 14.1,iOS 17.1, *) + @available(visionOS 1.0,iOS 17.1,tvOS 17.1,watchOS 10.1,macOS 14.1, *) init(_ behavior: SwiftUI.SearchPresentationToolbarBehavior) { self.value = ._0(behavior: behavior) @@ -12503,7 +12409,7 @@ struct _searchPresentationToolbarBehaviorModifier: ViewModifier fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(behavior): - if #available(tvOS 17.1,watchOS 10.1,visionOS 1.0,macOS 14.1,iOS 17.1, *) { + if #available(visionOS 1.0,iOS 17.1,tvOS 17.1,watchOS 10.1,macOS 14.1, *) { let behavior = behavior as! SwiftUI.SearchPresentationToolbarBehavior __content @@ -12523,7 +12429,7 @@ struct _searchSuggestionsModifier: ViewModifier { enum Value { case _never - indirect case _0(suggestions: ViewReference=ViewReference(value: [])) + indirect case _0(suggestions: ViewReference) indirect case _1(visibility: AttributeReference,placements: SwiftUI.SearchSuggestionsPlacement.Set) @@ -12593,13 +12499,13 @@ struct _searchableModifier: ViewModifier { enum Value { case _never - indirect case _0(placement: SwiftUI.SearchFieldPlacement = .automatic, prompt: TextReference? = nil ) + indirect case _0(placement: SwiftUI.SearchFieldPlacement , prompt: TextReference? ) - indirect case _1(placement: SwiftUI.SearchFieldPlacement = .automatic, prompt: SwiftUICore.LocalizedStringKey) + indirect case _1(placement: SwiftUI.SearchFieldPlacement , prompt: SwiftUICore.LocalizedStringKey) - indirect case _2(placement: SwiftUI.SearchFieldPlacement = .automatic, prompt: AttributeReference) + indirect case _2(placement: SwiftUI.SearchFieldPlacement , prompt: AttributeReference) #if os(iOS) || os(macOS) || os(visionOS) indirect case _3(placement: Any, prompt: Any?) @@ -12611,13 +12517,13 @@ struct _searchableModifier: ViewModifier { indirect case _5(placement: Any, prompt: Any) #endif - indirect case _6(placement: SwiftUI.SearchFieldPlacement = .automatic, prompt: TextReference? = nil, suggestions: ViewReference=ViewReference(value: [])) + indirect case _6(placement: SwiftUI.SearchFieldPlacement , prompt: TextReference? , suggestions: ViewReference) - indirect case _7(placement: SwiftUI.SearchFieldPlacement = .automatic, prompt: SwiftUICore.LocalizedStringKey,suggestions: ViewReference=ViewReference(value: [])) + indirect case _7(placement: SwiftUI.SearchFieldPlacement , prompt: SwiftUICore.LocalizedStringKey,suggestions: ViewReference) - indirect case _8(placement: SwiftUI.SearchFieldPlacement = .automatic, prompt: AttributeReference,suggestions: ViewReference=ViewReference(value: [])) + indirect case _8(placement: SwiftUI.SearchFieldPlacement , prompt: AttributeReference,suggestions: ViewReference) } @@ -12847,7 +12753,7 @@ struct _sectionActionsModifier: ViewModifier { #if os(iOS) || os(macOS) || os(visionOS) - @available(iOS 18.0,visionOS 2.0,macOS 15.0, *) + @available(iOS 18.0,macOS 15.0,visionOS 2.0, *) init(content: ViewReference=ViewReference(value: [])) { self.value = ._0(content: content) @@ -12860,7 +12766,7 @@ struct _sectionActionsModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(visionOS) case let ._0(content): - if #available(iOS 18.0,visionOS 2.0,macOS 15.0, *) { + if #available(iOS 18.0,macOS 15.0,visionOS 2.0, *) { let content = content as! ViewReference __content @@ -12894,7 +12800,7 @@ struct _selectionDisabledModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 17.0,tvOS 17.0,watchOS 10.0,visionOS 1.0,macOS 14.0, *) + @available(macOS 14.0,visionOS 1.0,tvOS 17.0,iOS 17.0,watchOS 10.0, *) init(_ isDisabled: AttributeReference = .init(storage: .constant(true)) ) { self.value = ._0(isDisabled: isDisabled) @@ -12907,7 +12813,7 @@ struct _selectionDisabledModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(isDisabled): - if #available(iOS 17.0,tvOS 17.0,watchOS 10.0,visionOS 1.0,macOS 14.0, *) { + if #available(macOS 14.0,visionOS 1.0,tvOS 17.0,iOS 17.0,watchOS 10.0, *) { let isDisabled = isDisabled as! AttributeReference __content @@ -12927,7 +12833,7 @@ struct _shadowModifier: ViewModifier { enum Value { case _never - indirect case _0(color: Color.Resolvable = .init(Color(.sRGBLinear, white: 0, opacity: 0.33)), radius: AttributeReference,x: AttributeReference = .init(storage: .constant(0)), y: AttributeReference = .init(storage: .constant(0)) ) + indirect case _0(color: Color.Resolvable , radius: AttributeReference,x: AttributeReference, y: AttributeReference) } @@ -12974,7 +12880,7 @@ struct _sheetModifier: ViewModifier { enum Value { case _never - indirect case _0(content: ViewReference=ViewReference(value: [])) + indirect case _0(content: ViewReference) } @@ -13022,7 +12928,7 @@ struct _simultaneousGestureModifier: ViewModifier { enum Value { case _never - indirect case _0(gesture: _AnyGesture,mask: SwiftUICore.GestureMask = .all ) + indirect case _0(gesture: _AnyGesture,mask: SwiftUICore.GestureMask ) indirect case _1(gesture: _AnyGesture,isEnabled: AttributeReference) @@ -13060,7 +12966,7 @@ struct _simultaneousGestureModifier: ViewModifier { } #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 18.0,macOS 15.0,tvOS 18.0,watchOS 11.0,visionOS 2.0, *) + @available(macOS 15.0,tvOS 18.0,iOS 18.0,watchOS 11.0,visionOS 2.0, *) init(_ gesture: _AnyGesture,name: AttributeReference,isEnabled: AttributeReference = .init(storage: .constant(true)) ) { self.value = ._2(gesture: gesture, name: name, isEnabled: isEnabled) @@ -13095,7 +13001,7 @@ struct _simultaneousGestureModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._2(gesture, name, isEnabled): - if #available(iOS 18.0,macOS 15.0,tvOS 18.0,watchOS 11.0,visionOS 2.0, *) { + if #available(macOS 15.0,tvOS 18.0,iOS 18.0,watchOS 11.0,visionOS 2.0, *) { let gesture = gesture as! _AnyGesture let name = name as! AttributeReference let isEnabled = isEnabled as! AttributeReference @@ -13164,7 +13070,7 @@ struct _speechAlwaysIncludesPunctuationModifier: ViewModifier { enum Value { case _never - indirect case _0(value: AttributeReference = .init(storage: .constant(true)) ) + indirect case _0(value: AttributeReference) } @@ -13211,7 +13117,7 @@ struct _speechAnnouncementsQueuedModifier: ViewModifier { enum Value { case _never - indirect case _0(value: AttributeReference = .init(storage: .constant(true)) ) + indirect case _0(value: AttributeReference) } @@ -13258,7 +13164,7 @@ struct _speechSpellsOutCharactersModifier: ViewModifier { enum Value { case _never - indirect case _0(value: AttributeReference = .init(storage: .constant(true)) ) + indirect case _0(value: AttributeReference) } @@ -13446,7 +13352,7 @@ struct _submitScopeModifier: ViewModifier { enum Value { case _never - indirect case _0(isBlocking: AttributeReference = .init(storage: .constant(true)) ) + indirect case _0(isBlocking: AttributeReference) } @@ -13554,7 +13460,7 @@ struct _swipeActionsModifier: ViewModifier { #if os(iOS) || os(macOS) || os(visionOS) || os(watchOS) - @available(iOS 15.0,watchOS 8.0,visionOS 1.0,macOS 12.0, *) + @available(macOS 12.0,watchOS 8.0,iOS 15.0,visionOS 1.0, *) init(edge: SwiftUICore.HorizontalEdge = .trailing, allowsFullSwipe: AttributeReference = .init(storage: .constant(true)), content: ViewReference=ViewReference(value: [])) { self.value = ._0(edge: edge, allowsFullSwipe: allowsFullSwipe, content: content) @@ -13567,7 +13473,7 @@ struct _swipeActionsModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(visionOS) || os(watchOS) case let ._0(edge, allowsFullSwipe, content): - if #available(iOS 15.0,watchOS 8.0,visionOS 1.0,macOS 12.0, *) { + if #available(macOS 12.0,watchOS 8.0,iOS 15.0,visionOS 1.0, *) { let edge = edge as! SwiftUICore.HorizontalEdge let allowsFullSwipe = allowsFullSwipe as! AttributeReference let content = content as! ViewReference @@ -13608,14 +13514,14 @@ struct _symbolEffectModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 17.0,watchOS 10.0,macOS 14.0,tvOS 17.0,visionOS 1.0, *) + @available(macOS 14.0,visionOS 1.0,tvOS 17.0,iOS 17.0,watchOS 10.0, *) init(_ effect: AnyIndefiniteSymbolEffect,options: Symbols.SymbolEffectOptions = .default, isActive: AttributeReference = .init(storage: .constant(true)) ) { self.value = ._0(effect: effect, options: options, isActive: isActive) } #endif #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 17.0,watchOS 10.0,macOS 14.0,tvOS 17.0,visionOS 1.0, *) + @available(macOS 14.0,visionOS 1.0,tvOS 17.0,iOS 17.0,watchOS 10.0, *) init(_ effect: AnyDiscreteSymbolEffect,options: Symbols.SymbolEffectOptions = .default, value: AttributeReference) { self.value = ._1(effect: effect, options: options, value: value) @@ -13628,7 +13534,7 @@ struct _symbolEffectModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(effect, options, isActive): - if #available(iOS 17.0,watchOS 10.0,macOS 14.0,tvOS 17.0,visionOS 1.0, *) { + if #available(macOS 14.0,visionOS 1.0,tvOS 17.0,iOS 17.0,watchOS 10.0, *) { let effect = effect as! AnyIndefiniteSymbolEffect let options = options as! Symbols.SymbolEffectOptions let isActive = isActive as! AttributeReference @@ -13641,7 +13547,7 @@ let isActive = isActive as! AttributeReference #endif #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._1(effect, options, value): - if #available(iOS 17.0,watchOS 10.0,macOS 14.0,tvOS 17.0,visionOS 1.0, *) { + if #available(macOS 14.0,visionOS 1.0,tvOS 17.0,iOS 17.0,watchOS 10.0, *) { let effect = effect as! AnyDiscreteSymbolEffect let options = options as! Symbols.SymbolEffectOptions let value = value as! AttributeReference @@ -13677,7 +13583,7 @@ struct _symbolEffectsRemovedModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 17.0,tvOS 17.0,watchOS 10.0,visionOS 1.0,macOS 14.0, *) + @available(tvOS 17.0,macOS 14.0,visionOS 1.0,watchOS 10.0,iOS 17.0, *) init(_ isEnabled: AttributeReference = .init(storage: .constant(true)) ) { self.value = ._0(isEnabled: isEnabled) @@ -13690,7 +13596,7 @@ struct _symbolEffectsRemovedModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(isEnabled): - if #available(iOS 17.0,tvOS 17.0,watchOS 10.0,visionOS 1.0,macOS 14.0, *) { + if #available(tvOS 17.0,macOS 14.0,visionOS 1.0,watchOS 10.0,iOS 17.0, *) { let isEnabled = isEnabled as! AttributeReference __content @@ -13804,7 +13710,7 @@ struct _tabItemModifier: ViewModifier { enum Value { case _never - indirect case _0(label: ViewReference=ViewReference(value: [])) + indirect case _0(label: ViewReference) } @@ -13912,7 +13818,7 @@ struct _tabViewSidebarFooterModifier: ViewModifier { #if os(iOS) || os(macOS) || os(visionOS) - @available(iOS 18.0,macOS 15.0,visionOS 2.0, *) + @available(visionOS 2.0,iOS 18.0,macOS 15.0, *) init(content: ViewReference=ViewReference(value: [])) { self.value = ._0(content: content) @@ -13925,7 +13831,7 @@ struct _tabViewSidebarFooterModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(visionOS) case let ._0(content): - if #available(iOS 18.0,macOS 15.0,visionOS 2.0, *) { + if #available(visionOS 2.0,iOS 18.0,macOS 15.0, *) { let content = content as! ViewReference __content @@ -13959,7 +13865,7 @@ struct _tabViewSidebarHeaderModifier: ViewModifier { #if os(iOS) || os(macOS) || os(visionOS) - @available(iOS 18.0,macOS 15.0,visionOS 2.0, *) + @available(visionOS 2.0,iOS 18.0,macOS 15.0, *) init(content: ViewReference=ViewReference(value: [])) { self.value = ._0(content: content) @@ -13972,7 +13878,7 @@ struct _tabViewSidebarHeaderModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(visionOS) case let ._0(content): - if #available(iOS 18.0,macOS 15.0,visionOS 2.0, *) { + if #available(visionOS 2.0,iOS 18.0,macOS 15.0, *) { let content = content as! ViewReference __content @@ -14053,7 +13959,7 @@ struct _tableStyleModifier: ViewModifier { #if os(iOS) || os(macOS) || os(visionOS) - @available(iOS 16.0,visionOS 1.0,macOS 12.0, *) + @available(visionOS 1.0,iOS 16.0,macOS 12.0, *) init(_ style: AnyTableStyle) { self.value = ._0(style: style) @@ -14066,7 +13972,7 @@ struct _tableStyleModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(visionOS) case let ._0(style): - if #available(iOS 16.0,visionOS 1.0,macOS 12.0, *) { + if #available(visionOS 1.0,iOS 16.0,macOS 12.0, *) { let style = style as! AnyTableStyle __content @@ -14147,7 +14053,7 @@ struct _textContentTypeModifier: ViewModifier { #if os(iOS) || os(tvOS) || os(visionOS) - @available(iOS 13.0,tvOS 13.0,visionOS 1.0, *) + @available(tvOS 13.0,visionOS 1.0,iOS 13.0, *) init(_ textContentType: UIKit.UITextContentType?) { self.value = ._0(textContentType: textContentType) @@ -14160,7 +14066,7 @@ struct _textContentTypeModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(tvOS) || os(visionOS) case let ._0(textContentType): - if #available(iOS 13.0,tvOS 13.0,visionOS 1.0, *) { + if #available(tvOS 13.0,visionOS 1.0,iOS 13.0, *) { let textContentType = textContentType as? UIKit.UITextContentType __content @@ -14288,7 +14194,7 @@ struct _textInputAutocapitalizationModifier: ViewModifier { #if os(iOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 15.0,watchOS 8.0,tvOS 15.0,visionOS 1.0, *) + @available(watchOS 8.0,iOS 15.0,tvOS 15.0,visionOS 1.0, *) init(_ autocapitalization: SwiftUI.TextInputAutocapitalization?) { self.value = ._0(autocapitalization: autocapitalization) @@ -14301,7 +14207,7 @@ struct _textInputAutocapitalizationModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(autocapitalization): - if #available(iOS 15.0,watchOS 8.0,tvOS 15.0,visionOS 1.0, *) { + if #available(watchOS 8.0,iOS 15.0,tvOS 15.0,visionOS 1.0, *) { let autocapitalization = autocapitalization as? SwiftUI.TextInputAutocapitalization __content @@ -14429,7 +14335,7 @@ struct _textSelectionModifier: ViewModifier { #if os(iOS) || os(macOS) || os(visionOS) - @available(macOS 12.0,visionOS 1.0,iOS 15.0, *) + @available(iOS 15.0,macOS 12.0,visionOS 1.0, *) init(_ selectability: AnyTextSelectability) { self.value = ._0(selectability: selectability) @@ -14442,7 +14348,7 @@ struct _textSelectionModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(visionOS) case let ._0(selectability): - if #available(macOS 12.0,visionOS 1.0,iOS 15.0, *) { + if #available(iOS 15.0,macOS 12.0,visionOS 1.0, *) { let selectability = selectability as! AnyTextSelectability __content @@ -14476,7 +14382,7 @@ struct _textSelectionAffinityModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(tvOS 18.0,watchOS 11.0,visionOS 2.0,macOS 15.0,iOS 18.0, *) + @available(macOS 15.0,watchOS 11.0,iOS 18.0,tvOS 18.0,visionOS 2.0, *) init(_ affinity: SwiftUI.TextSelectionAffinity) { self.value = ._0(affinity: affinity) @@ -14489,7 +14395,7 @@ struct _textSelectionAffinityModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(affinity): - if #available(tvOS 18.0,watchOS 11.0,visionOS 2.0,macOS 15.0,iOS 18.0, *) { + if #available(macOS 15.0,watchOS 11.0,iOS 18.0,tvOS 18.0,visionOS 2.0, *) { let affinity = affinity as! SwiftUI.TextSelectionAffinity __content @@ -14632,10 +14538,10 @@ struct _toolbarModifier: ViewModifier { indirect case _1(defaultItemKind: Any?) #endif - indirect case _3(content: ToolbarContentReference=ToolbarContentReference(value: [])) + indirect case _3(content: ToolbarContentReference) - indirect case _4(id: AttributeReference,content: CustomizableToolbarContentReference=CustomizableToolbarContentReference(value: [])) + indirect case _4(id: AttributeReference,content: CustomizableToolbarContentReference) } @@ -14662,7 +14568,7 @@ struct _toolbarModifier: ViewModifier { } #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(watchOS 10.0,iOS 17.0,macOS 14.0,visionOS 1.0,tvOS 17.0, *) + @available(macOS 14.0,watchOS 10.0,visionOS 1.0,tvOS 17.0,iOS 17.0, *) init(removing defaultItemKind: SwiftUI.ToolbarDefaultItemKind?) { self.value = ._1(defaultItemKind: defaultItemKind) @@ -14700,7 +14606,7 @@ struct _toolbarModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._1(defaultItemKind): - if #available(watchOS 10.0,iOS 17.0,macOS 14.0,visionOS 1.0,tvOS 17.0, *) { + if #available(macOS 14.0,watchOS 10.0,visionOS 1.0,tvOS 17.0,iOS 17.0, *) { let defaultItemKind = defaultItemKind as? SwiftUI.ToolbarDefaultItemKind __content @@ -14826,7 +14732,7 @@ struct _toolbarBackgroundVisibilityModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 18.0,macOS 15.0,tvOS 18.0,watchOS 11.0,visionOS 2.0, *) + @available(macOS 15.0,watchOS 11.0,iOS 18.0,tvOS 18.0,visionOS 2.0, *) init(_ visibility: AttributeReference,for bars: SwiftUI.ToolbarPlacement) { self.value = ._0(visibility: visibility, bars: bars) @@ -14839,7 +14745,7 @@ struct _toolbarBackgroundVisibilityModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(visibility, bars): - if #available(iOS 18.0,macOS 15.0,tvOS 18.0,watchOS 11.0,visionOS 2.0, *) { + if #available(macOS 15.0,watchOS 11.0,iOS 18.0,tvOS 18.0,visionOS 2.0, *) { let visibility = visibility as! AttributeReference let bars = bars as! SwiftUI.ToolbarPlacement @@ -15015,7 +14921,7 @@ struct _toolbarTitleDisplayModeModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 17.0,macOS 14.0,tvOS 17.0,watchOS 10.0,visionOS 1.0, *) + @available(tvOS 17.0,macOS 14.0,iOS 17.0,watchOS 10.0,visionOS 1.0, *) init(_ mode: SwiftUI.ToolbarTitleDisplayMode) { self.value = ._0(mode: mode) @@ -15028,7 +14934,7 @@ struct _toolbarTitleDisplayModeModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(mode): - if #available(iOS 17.0,macOS 14.0,tvOS 17.0,watchOS 10.0,visionOS 1.0, *) { + if #available(tvOS 17.0,macOS 14.0,iOS 17.0,watchOS 10.0,visionOS 1.0, *) { let mode = mode as! SwiftUI.ToolbarTitleDisplayMode __content @@ -15048,7 +14954,7 @@ struct _toolbarTitleMenuModifier: ViewModifier { enum Value { case _never - indirect case _0(content: ViewReference=ViewReference(value: [])) + indirect case _0(content: ViewReference) } @@ -15109,7 +15015,7 @@ struct _toolbarVisibilityModifier: ViewModifier { #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 18.0,macOS 15.0,tvOS 18.0,watchOS 11.0,visionOS 2.0, *) + @available(macOS 15.0,watchOS 11.0,iOS 18.0,tvOS 18.0,visionOS 2.0, *) init(_ visibility: AttributeReference,for bars: SwiftUI.ToolbarPlacement) { self.value = ._0(visibility: visibility, bars: bars) @@ -15122,7 +15028,7 @@ struct _toolbarVisibilityModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(visibility, bars): - if #available(iOS 18.0,macOS 15.0,tvOS 18.0,watchOS 11.0,visionOS 2.0, *) { + if #available(macOS 15.0,watchOS 11.0,iOS 18.0,tvOS 18.0,visionOS 2.0, *) { let visibility = visibility as! AttributeReference let bars = bars as! SwiftUI.ToolbarPlacement @@ -15768,7 +15674,7 @@ struct _windowToolbarFullScreenVisibilityModifier: ViewModifier #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) - @available(iOS 18.0,macOS 15.0,tvOS 18.0,watchOS 11.0,visionOS 2.0, *) + @available(tvOS 18.0,iOS 18.0,watchOS 11.0,macOS 15.0,visionOS 2.0, *) init(_ visibility: SwiftUI.WindowToolbarFullScreenVisibility) { self.value = ._0(visibility: visibility) @@ -15781,7 +15687,7 @@ struct _windowToolbarFullScreenVisibilityModifier: ViewModifier fatalError("unreachable") #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) case let ._0(visibility): - if #available(iOS 18.0,macOS 15.0,tvOS 18.0,watchOS 11.0,visionOS 2.0, *) { + if #available(tvOS 18.0,iOS 18.0,watchOS 11.0,macOS 15.0,visionOS 2.0, *) { let visibility = visibility as! SwiftUI.WindowToolbarFullScreenVisibility __content @@ -15815,7 +15721,7 @@ struct _writingToolsBehaviorModifier: ViewModifier { #if os(iOS) || os(macOS) - @available(macOS 15.0,iOS 18.0, *) + @available(iOS 18.0,macOS 15.0, *) init(_ behavior: SwiftUI.WritingToolsBehavior) { self.value = ._0(behavior: behavior) @@ -15828,7 +15734,7 @@ struct _writingToolsBehaviorModifier: ViewModifier { fatalError("unreachable") #if os(iOS) || os(macOS) case let ._0(behavior): - if #available(macOS 15.0,iOS 18.0, *) { + if #available(iOS 18.0,macOS 15.0, *) { let behavior = behavior as! SwiftUI.WritingToolsBehavior __content @@ -16055,8 +15961,8 @@ indirect case dialogSuppressionToggle(_dialogSuppressionToggleModifier) indirect case digitalCrownAccessory(_digitalCrownAccessoryModifier) indirect case disableAutocorrection(_disableAutocorrectionModifier) indirect case disabled(_disabledModifier) -indirect case disclosureGroupStyle(_disclosureGroupStyleModifier) indirect case dismissalConfirmationDialog(_dismissalConfirmationDialogModifier) +indirect case drawingGroup(_drawingGroupModifier) func body(content: Content) -> some View { switch self { @@ -16084,9 +15990,9 @@ case let .disableAutocorrection(modifier): content.modifier(modifier) case let .disabled(modifier): content.modifier(modifier) -case let .disclosureGroupStyle(modifier): - content.modifier(modifier) case let .dismissalConfirmationDialog(modifier): + content.modifier(modifier) +case let .drawingGroup(modifier): content.modifier(modifier) } } @@ -16094,8 +16000,7 @@ case let .dismissalConfirmationDialog(modifier): } extension BuiltinRegistry { enum _BuiltinModifierChunk4: ViewModifier { - indirect case drawingGroup(_drawingGroupModifier) -indirect case dynamicTypeSize(_dynamicTypeSizeModifier) + indirect case dynamicTypeSize(_dynamicTypeSizeModifier) indirect case edgesIgnoringSafeArea(_edgesIgnoringSafeAreaModifier) indirect case fileDialogCustomizationID(_fileDialogCustomizationIDModifier) indirect case fileDialogImportsUnresolvedAliases(_fileDialogImportsUnresolvedAliasesModifier) @@ -16108,12 +16013,11 @@ indirect case focusSection(_focusSectionModifier) indirect case focusable(_focusableModifier) indirect case foregroundColor(_foregroundColorModifier) indirect case formStyle(_formStyleModifier) +indirect case frame(_frameModifier) func body(content: Content) -> some View { switch self { - case let .drawingGroup(modifier): - content.modifier(modifier) -case let .dynamicTypeSize(modifier): + case let .dynamicTypeSize(modifier): content.modifier(modifier) case let .edgesIgnoringSafeArea(modifier): content.modifier(modifier) @@ -16138,6 +16042,8 @@ case let .focusable(modifier): case let .foregroundColor(modifier): content.modifier(modifier) case let .formStyle(modifier): + content.modifier(modifier) +case let .frame(modifier): content.modifier(modifier) } } @@ -16145,8 +16051,7 @@ case let .formStyle(modifier): } extension BuiltinRegistry { enum _BuiltinModifierChunk5: ViewModifier { - indirect case frame(_frameModifier) -indirect case fullScreenCover(_fullScreenCoverModifier) + indirect case fullScreenCover(_fullScreenCoverModifier) indirect case gaugeStyle(_gaugeStyleModifier) indirect case geometryGroup(_geometryGroupModifier) indirect case gesture(_gestureModifier) @@ -16159,12 +16064,11 @@ indirect case gridColumnAlignment(_gridColumnAlignmentModifier) indirect case groupBoxStyle(_groupBoxStyleModifier) indirect case handGestureShortcut(_handGestureShortcutModifier) indirect case handPointerBehavior(_handPointerBehaviorModifier) +indirect case headerProminence(_headerProminenceModifier) func body(content: Content) -> some View { switch self { - case let .frame(modifier): - content.modifier(modifier) -case let .fullScreenCover(modifier): + case let .fullScreenCover(modifier): content.modifier(modifier) case let .gaugeStyle(modifier): content.modifier(modifier) @@ -16189,6 +16093,8 @@ case let .groupBoxStyle(modifier): case let .handGestureShortcut(modifier): content.modifier(modifier) case let .handPointerBehavior(modifier): + content.modifier(modifier) +case let .headerProminence(modifier): content.modifier(modifier) } } @@ -16196,8 +16102,7 @@ case let .handPointerBehavior(modifier): } extension BuiltinRegistry { enum _BuiltinModifierChunk6: ViewModifier { - indirect case headerProminence(_headerProminenceModifier) -indirect case help(_helpModifier) + indirect case help(_helpModifier) indirect case hidden(_hiddenModifier) indirect case highPriorityGesture(_highPriorityGestureModifier) indirect case horizontalRadioGroupLayout(_horizontalRadioGroupLayoutModifier) @@ -16210,12 +16115,11 @@ indirect case imageScale(_imageScaleModifier) indirect case immersiveEnvironmentPicker(_immersiveEnvironmentPickerModifier) indirect case indexViewStyle(_indexViewStyleModifier) indirect case inspector(_inspectorModifier) +indirect case inspectorColumnWidth(_inspectorColumnWidthModifier) func body(content: Content) -> some View { switch self { - case let .headerProminence(modifier): - content.modifier(modifier) -case let .help(modifier): + case let .help(modifier): content.modifier(modifier) case let .hidden(modifier): content.modifier(modifier) @@ -16240,6 +16144,8 @@ case let .immersiveEnvironmentPicker(modifier): case let .indexViewStyle(modifier): content.modifier(modifier) case let .inspector(modifier): + content.modifier(modifier) +case let .inspectorColumnWidth(modifier): content.modifier(modifier) } } @@ -16247,8 +16153,7 @@ case let .inspector(modifier): } extension BuiltinRegistry { enum _BuiltinModifierChunk7: ViewModifier { - indirect case inspectorColumnWidth(_inspectorColumnWidthModifier) -indirect case interactionActivityTrackingTag(_interactionActivityTrackingTagModifier) + indirect case interactionActivityTrackingTag(_interactionActivityTrackingTagModifier) indirect case interactiveDismissDisabled(_interactiveDismissDisabledModifier) indirect case invalidatableContent(_invalidatableContentModifier) indirect case keyboardShortcut(_keyboardShortcutModifier) @@ -16261,12 +16166,11 @@ indirect case layoutPriority(_layoutPriorityModifier) indirect case lineLimit(_lineLimitModifier) indirect case lineSpacing(_lineSpacingModifier) indirect case listItemTint(_listItemTintModifier) +indirect case listRowBackground(_listRowBackgroundModifier) func body(content: Content) -> some View { switch self { - case let .inspectorColumnWidth(modifier): - content.modifier(modifier) -case let .interactionActivityTrackingTag(modifier): + case let .interactionActivityTrackingTag(modifier): content.modifier(modifier) case let .interactiveDismissDisabled(modifier): content.modifier(modifier) @@ -16291,6 +16195,8 @@ case let .lineLimit(modifier): case let .lineSpacing(modifier): content.modifier(modifier) case let .listItemTint(modifier): + content.modifier(modifier) +case let .listRowBackground(modifier): content.modifier(modifier) } } @@ -16298,8 +16204,7 @@ case let .listItemTint(modifier): } extension BuiltinRegistry { enum _BuiltinModifierChunk8: ViewModifier { - indirect case listRowBackground(_listRowBackgroundModifier) -indirect case listRowHoverEffect(_listRowHoverEffectModifier) + indirect case listRowHoverEffect(_listRowHoverEffectModifier) indirect case listRowHoverEffectDisabled(_listRowHoverEffectDisabledModifier) indirect case listRowInsets(_listRowInsetsModifier) indirect case listRowPlatterColor(_listRowPlatterColorModifier) @@ -16312,12 +16217,11 @@ indirect case listSectionSpacing(_listSectionSpacingModifier) indirect case listStyle(_listStyleModifier) indirect case luminanceToAlpha(_luminanceToAlphaModifier) indirect case materialActiveAppearance(_materialActiveAppearanceModifier) +indirect case menuIndicator(_menuIndicatorModifier) func body(content: Content) -> some View { switch self { - case let .listRowBackground(modifier): - content.modifier(modifier) -case let .listRowHoverEffect(modifier): + case let .listRowHoverEffect(modifier): content.modifier(modifier) case let .listRowHoverEffectDisabled(modifier): content.modifier(modifier) @@ -16342,6 +16246,8 @@ case let .listStyle(modifier): case let .luminanceToAlpha(modifier): content.modifier(modifier) case let .materialActiveAppearance(modifier): + content.modifier(modifier) +case let .menuIndicator(modifier): content.modifier(modifier) } } @@ -16349,8 +16255,7 @@ case let .materialActiveAppearance(modifier): } extension BuiltinRegistry { enum _BuiltinModifierChunk9: ViewModifier { - indirect case menuIndicator(_menuIndicatorModifier) -indirect case menuOrder(_menuOrderModifier) + indirect case menuOrder(_menuOrderModifier) indirect case menuStyle(_menuStyleModifier) indirect case minimumScaleFactor(_minimumScaleFactorModifier) indirect case modifierKeyAlternate(_modifierKeyAlternateModifier) @@ -16363,12 +16268,11 @@ indirect case navigationBarTitle(_navigationBarTitleModifier) indirect case navigationBarTitleDisplayMode(_navigationBarTitleDisplayModeModifier) indirect case navigationDestination(_navigationDestinationModifier) indirect case navigationSplitViewColumnWidth(_navigationSplitViewColumnWidthModifier) +indirect case navigationSplitViewStyle(_navigationSplitViewStyleModifier) func body(content: Content) -> some View { switch self { - case let .menuIndicator(modifier): - content.modifier(modifier) -case let .menuOrder(modifier): + case let .menuOrder(modifier): content.modifier(modifier) case let .menuStyle(modifier): content.modifier(modifier) @@ -16393,6 +16297,8 @@ case let .navigationBarTitleDisplayMode(modifier): case let .navigationDestination(modifier): content.modifier(modifier) case let .navigationSplitViewColumnWidth(modifier): + content.modifier(modifier) +case let .navigationSplitViewStyle(modifier): content.modifier(modifier) } } @@ -16400,10 +16306,8 @@ case let .navigationSplitViewColumnWidth(modifier): } extension BuiltinRegistry { enum _BuiltinModifierChunk10: ViewModifier { - indirect case navigationSplitViewStyle(_navigationSplitViewStyleModifier) -indirect case navigationSubtitle(_navigationSubtitleModifier) + indirect case navigationSubtitle(_navigationSubtitleModifier) indirect case navigationTitle(_navigationTitleModifier) -indirect case navigationViewStyle(_navigationViewStyleModifier) indirect case offset(_offsetModifier) indirect case onAppear(_onAppearModifier) indirect case onDeleteCommand(_onDeleteCommandModifier) @@ -16414,17 +16318,15 @@ indirect case onImmersionChange(_onImmersionChangeModifier) indirect case onLongPressGesture(_onLongPressGestureModifier) indirect case onLongTouchGesture(_onLongTouchGestureModifier) indirect case onModifierKeysChanged(_onModifierKeysChangedModifier) +indirect case onMoveCommand(_onMoveCommandModifier) +indirect case onPencilDoubleTap(_onPencilDoubleTapModifier) func body(content: Content) -> some View { switch self { - case let .navigationSplitViewStyle(modifier): - content.modifier(modifier) -case let .navigationSubtitle(modifier): + case let .navigationSubtitle(modifier): content.modifier(modifier) case let .navigationTitle(modifier): content.modifier(modifier) -case let .navigationViewStyle(modifier): - content.modifier(modifier) case let .offset(modifier): content.modifier(modifier) case let .onAppear(modifier): @@ -16444,6 +16346,10 @@ case let .onLongPressGesture(modifier): case let .onLongTouchGesture(modifier): content.modifier(modifier) case let .onModifierKeysChanged(modifier): + content.modifier(modifier) +case let .onMoveCommand(modifier): + content.modifier(modifier) +case let .onPencilDoubleTap(modifier): content.modifier(modifier) } } @@ -16451,9 +16357,7 @@ case let .onModifierKeysChanged(modifier): } extension BuiltinRegistry { enum _BuiltinModifierChunk11: ViewModifier { - indirect case onMoveCommand(_onMoveCommandModifier) -indirect case onPencilDoubleTap(_onPencilDoubleTapModifier) -indirect case onPencilSqueeze(_onPencilSqueezeModifier) + indirect case onPencilSqueeze(_onPencilSqueezeModifier) indirect case onPlayPauseCommand(_onPlayPauseCommandModifier) indirect case onScrollPhaseChange(_onScrollPhaseChangeModifier) indirect case onScrollVisibilityChange(_onScrollVisibilityChangeModifier) @@ -16465,14 +16369,12 @@ indirect case overlay(_overlayModifier) indirect case padding(_paddingModifier) indirect case padding3D(_padding3DModifier) indirect case persistentSystemOverlays(_persistentSystemOverlaysModifier) +indirect case pickerStyle(_pickerStyleModifier) +indirect case pointerStyle(_pointerStyleModifier) func body(content: Content) -> some View { switch self { - case let .onMoveCommand(modifier): - content.modifier(modifier) -case let .onPencilDoubleTap(modifier): - content.modifier(modifier) -case let .onPencilSqueeze(modifier): + case let .onPencilSqueeze(modifier): content.modifier(modifier) case let .onPlayPauseCommand(modifier): content.modifier(modifier) @@ -16495,6 +16397,10 @@ case let .padding(modifier): case let .padding3D(modifier): content.modifier(modifier) case let .persistentSystemOverlays(modifier): + content.modifier(modifier) +case let .pickerStyle(modifier): + content.modifier(modifier) +case let .pointerStyle(modifier): content.modifier(modifier) } } @@ -16502,9 +16408,7 @@ case let .persistentSystemOverlays(modifier): } extension BuiltinRegistry { enum _BuiltinModifierChunk12: ViewModifier { - indirect case pickerStyle(_pickerStyleModifier) -indirect case pointerStyle(_pointerStyleModifier) -indirect case pointerVisibility(_pointerVisibilityModifier) + indirect case pointerVisibility(_pointerVisibilityModifier) indirect case popover(_popoverModifier) indirect case position(_positionModifier) indirect case preferredColorScheme(_preferredColorSchemeModifier) @@ -16516,14 +16420,12 @@ indirect case presentationContentInteraction(_presentationContentInteractionModi indirect case presentationCornerRadius(_presentationCornerRadiusModifier) indirect case presentationDragIndicator(_presentationDragIndicatorModifier) indirect case presentationSizing(_presentationSizingModifier) +indirect case previewDisplayName(_previewDisplayNameModifier) +indirect case privacySensitive(_privacySensitiveModifier) func body(content: Content) -> some View { switch self { - case let .pickerStyle(modifier): - content.modifier(modifier) -case let .pointerStyle(modifier): - content.modifier(modifier) -case let .pointerVisibility(modifier): + case let .pointerVisibility(modifier): content.modifier(modifier) case let .popover(modifier): content.modifier(modifier) @@ -16546,6 +16448,10 @@ case let .presentationCornerRadius(modifier): case let .presentationDragIndicator(modifier): content.modifier(modifier) case let .presentationSizing(modifier): + content.modifier(modifier) +case let .previewDisplayName(modifier): + content.modifier(modifier) +case let .privacySensitive(modifier): content.modifier(modifier) } } @@ -16553,9 +16459,7 @@ case let .presentationSizing(modifier): } extension BuiltinRegistry { enum _BuiltinModifierChunk13: ViewModifier { - indirect case previewDisplayName(_previewDisplayNameModifier) -indirect case privacySensitive(_privacySensitiveModifier) -indirect case progressViewStyle(_progressViewStyleModifier) + indirect case progressViewStyle(_progressViewStyleModifier) indirect case projectionEffect(_projectionEffectModifier) indirect case redacted(_redactedModifier) indirect case refreshable(_refreshableModifier) @@ -16567,14 +16471,12 @@ indirect case safeAreaPadding(_safeAreaPaddingModifier) indirect case saturation(_saturationModifier) indirect case scaleEffect(_scaleEffectModifier) indirect case scaledToFill(_scaledToFillModifier) +indirect case scaledToFit(_scaledToFitModifier) +indirect case scenePadding(_scenePaddingModifier) func body(content: Content) -> some View { switch self { - case let .previewDisplayName(modifier): - content.modifier(modifier) -case let .privacySensitive(modifier): - content.modifier(modifier) -case let .progressViewStyle(modifier): + case let .progressViewStyle(modifier): content.modifier(modifier) case let .projectionEffect(modifier): content.modifier(modifier) @@ -16597,6 +16499,10 @@ case let .saturation(modifier): case let .scaleEffect(modifier): content.modifier(modifier) case let .scaledToFill(modifier): + content.modifier(modifier) +case let .scaledToFit(modifier): + content.modifier(modifier) +case let .scenePadding(modifier): content.modifier(modifier) } } @@ -16604,9 +16510,7 @@ case let .scaledToFill(modifier): } extension BuiltinRegistry { enum _BuiltinModifierChunk14: ViewModifier { - indirect case scaledToFit(_scaledToFitModifier) -indirect case scenePadding(_scenePaddingModifier) -indirect case scrollBounceBehavior(_scrollBounceBehaviorModifier) + indirect case scrollBounceBehavior(_scrollBounceBehaviorModifier) indirect case scrollClipDisabled(_scrollClipDisabledModifier) indirect case scrollContentBackground(_scrollContentBackgroundModifier) indirect case scrollDisabled(_scrollDisabledModifier) @@ -16618,14 +16522,12 @@ indirect case scrollTargetBehavior(_scrollTargetBehaviorModifier) indirect case scrollTargetLayout(_scrollTargetLayoutModifier) indirect case searchDictationBehavior(_searchDictationBehaviorModifier) indirect case searchPresentationToolbarBehavior(_searchPresentationToolbarBehaviorModifier) +indirect case searchSuggestions(_searchSuggestionsModifier) +indirect case searchable(_searchableModifier) func body(content: Content) -> some View { switch self { - case let .scaledToFit(modifier): - content.modifier(modifier) -case let .scenePadding(modifier): - content.modifier(modifier) -case let .scrollBounceBehavior(modifier): + case let .scrollBounceBehavior(modifier): content.modifier(modifier) case let .scrollClipDisabled(modifier): content.modifier(modifier) @@ -16648,6 +16550,10 @@ case let .scrollTargetLayout(modifier): case let .searchDictationBehavior(modifier): content.modifier(modifier) case let .searchPresentationToolbarBehavior(modifier): + content.modifier(modifier) +case let .searchSuggestions(modifier): + content.modifier(modifier) +case let .searchable(modifier): content.modifier(modifier) } } @@ -16655,9 +16561,7 @@ case let .searchPresentationToolbarBehavior(modifier): } extension BuiltinRegistry { enum _BuiltinModifierChunk15: ViewModifier { - indirect case searchSuggestions(_searchSuggestionsModifier) -indirect case searchable(_searchableModifier) -indirect case sectionActions(_sectionActionsModifier) + indirect case sectionActions(_sectionActionsModifier) indirect case selectionDisabled(_selectionDisabledModifier) indirect case shadow(_shadowModifier) indirect case sheet(_sheetModifier) @@ -16669,14 +16573,12 @@ indirect case speechSpellsOutCharacters(_speechSpellsOutCharactersModifier) indirect case statusBar(_statusBarModifier) indirect case statusBarHidden(_statusBarHiddenModifier) indirect case submitLabel(_submitLabelModifier) +indirect case submitScope(_submitScopeModifier) +indirect case supportedVolumeViewpoints(_supportedVolumeViewpointsModifier) func body(content: Content) -> some View { switch self { - case let .searchSuggestions(modifier): - content.modifier(modifier) -case let .searchable(modifier): - content.modifier(modifier) -case let .sectionActions(modifier): + case let .sectionActions(modifier): content.modifier(modifier) case let .selectionDisabled(modifier): content.modifier(modifier) @@ -16699,6 +16601,10 @@ case let .statusBar(modifier): case let .statusBarHidden(modifier): content.modifier(modifier) case let .submitLabel(modifier): + content.modifier(modifier) +case let .submitScope(modifier): + content.modifier(modifier) +case let .supportedVolumeViewpoints(modifier): content.modifier(modifier) } } @@ -16706,9 +16612,7 @@ case let .submitLabel(modifier): } extension BuiltinRegistry { enum _BuiltinModifierChunk16: ViewModifier { - indirect case submitScope(_submitScopeModifier) -indirect case supportedVolumeViewpoints(_supportedVolumeViewpointsModifier) -indirect case swipeActions(_swipeActionsModifier) + indirect case swipeActions(_swipeActionsModifier) indirect case symbolEffect(_symbolEffectModifier) indirect case symbolEffectsRemoved(_symbolEffectsRemovedModifier) indirect case symbolRenderingMode(_symbolRenderingModeModifier) @@ -16720,14 +16624,12 @@ indirect case tabViewSidebarHeader(_tabViewSidebarHeaderModifier) indirect case tabViewStyle(_tabViewStyleModifier) indirect case tableStyle(_tableStyleModifier) indirect case textCase(_textCaseModifier) +indirect case textContentType(_textContentTypeModifier) +indirect case textEditorStyle(_textEditorStyleModifier) func body(content: Content) -> some View { switch self { - case let .submitScope(modifier): - content.modifier(modifier) -case let .supportedVolumeViewpoints(modifier): - content.modifier(modifier) -case let .swipeActions(modifier): + case let .swipeActions(modifier): content.modifier(modifier) case let .symbolEffect(modifier): content.modifier(modifier) @@ -16750,6 +16652,10 @@ case let .tabViewStyle(modifier): case let .tableStyle(modifier): content.modifier(modifier) case let .textCase(modifier): + content.modifier(modifier) +case let .textContentType(modifier): + content.modifier(modifier) +case let .textEditorStyle(modifier): content.modifier(modifier) } } @@ -16757,9 +16663,7 @@ case let .textCase(modifier): } extension BuiltinRegistry { enum _BuiltinModifierChunk17: ViewModifier { - indirect case textContentType(_textContentTypeModifier) -indirect case textEditorStyle(_textEditorStyleModifier) -indirect case textFieldStyle(_textFieldStyleModifier) + indirect case textFieldStyle(_textFieldStyleModifier) indirect case textInputAutocapitalization(_textInputAutocapitalizationModifier) indirect case textInputCompletion(_textInputCompletionModifier) indirect case textInputSuggestions(_textInputSuggestionsModifier) @@ -16771,14 +16675,12 @@ indirect case toolbar(_toolbarModifier) indirect case toolbarBackground(_toolbarBackgroundModifier) indirect case toolbarBackgroundVisibility(_toolbarBackgroundVisibilityModifier) indirect case toolbarColorScheme(_toolbarColorSchemeModifier) +indirect case toolbarItemHidden(_toolbarItemHiddenModifier) +indirect case toolbarRole(_toolbarRoleModifier) func body(content: Content) -> some View { switch self { - case let .textContentType(modifier): - content.modifier(modifier) -case let .textEditorStyle(modifier): - content.modifier(modifier) -case let .textFieldStyle(modifier): + case let .textFieldStyle(modifier): content.modifier(modifier) case let .textInputAutocapitalization(modifier): content.modifier(modifier) @@ -16801,6 +16703,10 @@ case let .toolbarBackground(modifier): case let .toolbarBackgroundVisibility(modifier): content.modifier(modifier) case let .toolbarColorScheme(modifier): + content.modifier(modifier) +case let .toolbarItemHidden(modifier): + content.modifier(modifier) +case let .toolbarRole(modifier): content.modifier(modifier) } } @@ -16808,9 +16714,7 @@ case let .toolbarColorScheme(modifier): } extension BuiltinRegistry { enum _BuiltinModifierChunk18: ViewModifier { - indirect case toolbarItemHidden(_toolbarItemHiddenModifier) -indirect case toolbarRole(_toolbarRoleModifier) -indirect case toolbarTitleDisplayMode(_toolbarTitleDisplayModeModifier) + indirect case toolbarTitleDisplayMode(_toolbarTitleDisplayModeModifier) indirect case toolbarTitleMenu(_toolbarTitleMenuModifier) indirect case toolbarVisibility(_toolbarVisibilityModifier) indirect case touchBarCustomizationLabel(_touchBarCustomizationLabelModifier) @@ -16822,14 +16726,12 @@ indirect case truncationMode(_truncationModeModifier) indirect case unredacted(_unredactedModifier) indirect case upperLimbVisibility(_upperLimbVisibilityModifier) indirect case volumeBaseplateVisibility(_volumeBaseplateVisibilityModifier) +indirect case windowDismissBehavior(_windowDismissBehaviorModifier) +indirect case windowFullScreenBehavior(_windowFullScreenBehaviorModifier) func body(content: Content) -> some View { switch self { - case let .toolbarItemHidden(modifier): - content.modifier(modifier) -case let .toolbarRole(modifier): - content.modifier(modifier) -case let .toolbarTitleDisplayMode(modifier): + case let .toolbarTitleDisplayMode(modifier): content.modifier(modifier) case let .toolbarTitleMenu(modifier): content.modifier(modifier) @@ -16852,6 +16754,10 @@ case let .unredacted(modifier): case let .upperLimbVisibility(modifier): content.modifier(modifier) case let .volumeBaseplateVisibility(modifier): + content.modifier(modifier) +case let .windowDismissBehavior(modifier): + content.modifier(modifier) +case let .windowFullScreenBehavior(modifier): content.modifier(modifier) } } @@ -16859,9 +16765,7 @@ case let .volumeBaseplateVisibility(modifier): } extension BuiltinRegistry { enum _BuiltinModifierChunk19: ViewModifier { - indirect case windowDismissBehavior(_windowDismissBehaviorModifier) -indirect case windowFullScreenBehavior(_windowFullScreenBehaviorModifier) -indirect case windowMinimizeBehavior(_windowMinimizeBehaviorModifier) + indirect case windowMinimizeBehavior(_windowMinimizeBehaviorModifier) indirect case windowResizeBehavior(_windowResizeBehaviorModifier) indirect case windowToolbarFullScreenVisibility(_windowToolbarFullScreenVisibilityModifier) indirect case writingToolsBehavior(_writingToolsBehaviorModifier) @@ -16869,11 +16773,7 @@ indirect case zIndex(_zIndexModifier) func body(content: Content) -> some View { switch self { - case let .windowDismissBehavior(modifier): - content.modifier(modifier) -case let .windowFullScreenBehavior(modifier): - content.modifier(modifier) -case let .windowMinimizeBehavior(modifier): + case let .windowMinimizeBehavior(modifier): content.modifier(modifier) case let .windowResizeBehavior(modifier): content.modifier(modifier) @@ -16909,17 +16809,18 @@ indirect case chunk16(_BuiltinModifierChunk16) indirect case chunk17(_BuiltinModifierChunk17) indirect case chunk18(_BuiltinModifierChunk18) indirect case chunk19(_BuiltinModifierChunk19) - indirect case _OnSubmitModifier(LiveViewNative._OnSubmitModifier) -indirect case _PerspectiveRotationEffectModifier(LiveViewNative._PerspectiveRotationEffectModifier) -indirect case _MaskModifier(LiveViewNative._MaskModifier) + indirect case _MatchedTransitionSourceModifier(LiveViewNative._MatchedTransitionSourceModifier) +indirect case _FileImporterModifier(LiveViewNative._FileImporterModifier) +indirect case _FocusScopeModifier(LiveViewNative._FocusScopeModifier) indirect case _SearchScopesModifier(LiveViewNative._SearchScopesModifier) -indirect case _NavigationTransitionModifier(LiveViewNative._NavigationTransitionModifier) -indirect case _MatchedGeometryEffectModifier(LiveViewNative._MatchedGeometryEffectModifier) +indirect case _MaskModifier(LiveViewNative._MaskModifier) +indirect case _PerspectiveRotationEffectModifier(LiveViewNative._PerspectiveRotationEffectModifier) indirect case _PresentationDetentsModifier(LiveViewNative._PresentationDetentsModifier) -indirect case _Rotation3DEffectModifier(LiveViewNative._Rotation3DEffectModifier) -indirect case _FocusScopeModifier(LiveViewNative._FocusScopeModifier) indirect case _PrefersDefaultFocusModifier(LiveViewNative._PrefersDefaultFocusModifier) -indirect case _MatchedTransitionSourceModifier(LiveViewNative._MatchedTransitionSourceModifier) +indirect case _MatchedGeometryEffectModifier(LiveViewNative._MatchedGeometryEffectModifier) +indirect case _NavigationTransitionModifier(LiveViewNative._NavigationTransitionModifier) +indirect case _OnSubmitModifier(LiveViewNative._OnSubmitModifier) +indirect case _Rotation3DEffectModifier(LiveViewNative._Rotation3DEffectModifier) indirect case _SearchCompletionModifier(LiveViewNative._SearchCompletionModifier) indirect case _customRegistryModifier(R.CustomModifier) indirect case _anyTextModifier(_AnyTextModifier) @@ -16969,27 +16870,29 @@ case let .chunk18(chunk): content.modifier(chunk) case let .chunk19(chunk): content.modifier(chunk) - case let ._OnSubmitModifier(modifier): + case let ._MatchedTransitionSourceModifier(modifier): content.modifier(modifier) -case let ._PerspectiveRotationEffectModifier(modifier): +case let ._FileImporterModifier(modifier): content.modifier(modifier) -case let ._MaskModifier(modifier): +case let ._FocusScopeModifier(modifier): content.modifier(modifier) case let ._SearchScopesModifier(modifier): content.modifier(modifier) -case let ._NavigationTransitionModifier(modifier): +case let ._MaskModifier(modifier): content.modifier(modifier) -case let ._MatchedGeometryEffectModifier(modifier): +case let ._PerspectiveRotationEffectModifier(modifier): content.modifier(modifier) case let ._PresentationDetentsModifier(modifier): content.modifier(modifier) -case let ._Rotation3DEffectModifier(modifier): +case let ._PrefersDefaultFocusModifier(modifier): content.modifier(modifier) -case let ._FocusScopeModifier(modifier): +case let ._MatchedGeometryEffectModifier(modifier): content.modifier(modifier) -case let ._PrefersDefaultFocusModifier(modifier): +case let ._NavigationTransitionModifier(modifier): content.modifier(modifier) -case let ._MatchedTransitionSourceModifier(modifier): +case let ._OnSubmitModifier(modifier): + content.modifier(modifier) +case let ._Rotation3DEffectModifier(modifier): content.modifier(modifier) case let ._SearchCompletionModifier(modifier): content.modifier(modifier) @@ -17010,7 +16913,8 @@ case let ._SearchCompletionModifier(modifier): .init(context: context) } - struct _ParserType: Parser { + @MainActor + struct _ParserType: @preconcurrency Parser { typealias Input = Substring.UTF8View typealias Output = BuiltinModifier @@ -17072,9 +16976,8 @@ _dialogSuppressionToggleModifier.name: _dialogSuppressionToggleModifier.pa _digitalCrownAccessoryModifier.name: _digitalCrownAccessoryModifier.parser(in: context).map({ Output.chunk3(.digitalCrownAccessory($0)) }).eraseToAnyParser(), _disableAutocorrectionModifier.name: _disableAutocorrectionModifier.parser(in: context).map({ Output.chunk3(.disableAutocorrection($0)) }).eraseToAnyParser(), _disabledModifier.name: _disabledModifier.parser(in: context).map({ Output.chunk3(.disabled($0)) }).eraseToAnyParser(), -_disclosureGroupStyleModifier.name: _disclosureGroupStyleModifier.parser(in: context).map({ Output.chunk3(.disclosureGroupStyle($0)) }).eraseToAnyParser(), _dismissalConfirmationDialogModifier.name: _dismissalConfirmationDialogModifier.parser(in: context).map({ Output.chunk3(.dismissalConfirmationDialog($0)) }).eraseToAnyParser(), -_drawingGroupModifier.name: _drawingGroupModifier.parser(in: context).map({ Output.chunk4(.drawingGroup($0)) }).eraseToAnyParser(), +_drawingGroupModifier.name: _drawingGroupModifier.parser(in: context).map({ Output.chunk3(.drawingGroup($0)) }).eraseToAnyParser(), _dynamicTypeSizeModifier.name: _dynamicTypeSizeModifier.parser(in: context).map({ Output.chunk4(.dynamicTypeSize($0)) }).eraseToAnyParser(), _edgesIgnoringSafeAreaModifier.name: _edgesIgnoringSafeAreaModifier.parser(in: context).map({ Output.chunk4(.edgesIgnoringSafeArea($0)) }).eraseToAnyParser(), _fileDialogCustomizationIDModifier.name: _fileDialogCustomizationIDModifier.parser(in: context).map({ Output.chunk4(.fileDialogCustomizationID($0)) }).eraseToAnyParser(), @@ -17088,7 +16991,7 @@ _focusSectionModifier.name: _focusSectionModifier.parser(in: context).map( _focusableModifier.name: _focusableModifier.parser(in: context).map({ Output.chunk4(.focusable($0)) }).eraseToAnyParser(), _foregroundColorModifier.name: _foregroundColorModifier.parser(in: context).map({ Output.chunk4(.foregroundColor($0)) }).eraseToAnyParser(), _formStyleModifier.name: _formStyleModifier.parser(in: context).map({ Output.chunk4(.formStyle($0)) }).eraseToAnyParser(), -_frameModifier.name: _frameModifier.parser(in: context).map({ Output.chunk5(.frame($0)) }).eraseToAnyParser(), +_frameModifier.name: _frameModifier.parser(in: context).map({ Output.chunk4(.frame($0)) }).eraseToAnyParser(), _fullScreenCoverModifier.name: _fullScreenCoverModifier.parser(in: context).map({ Output.chunk5(.fullScreenCover($0)) }).eraseToAnyParser(), _gaugeStyleModifier.name: _gaugeStyleModifier.parser(in: context).map({ Output.chunk5(.gaugeStyle($0)) }).eraseToAnyParser(), _geometryGroupModifier.name: _geometryGroupModifier.parser(in: context).map({ Output.chunk5(.geometryGroup($0)) }).eraseToAnyParser(), @@ -17102,7 +17005,7 @@ _gridColumnAlignmentModifier.name: _gridColumnAlignmentModifier.parser(in: _groupBoxStyleModifier.name: _groupBoxStyleModifier.parser(in: context).map({ Output.chunk5(.groupBoxStyle($0)) }).eraseToAnyParser(), _handGestureShortcutModifier.name: _handGestureShortcutModifier.parser(in: context).map({ Output.chunk5(.handGestureShortcut($0)) }).eraseToAnyParser(), _handPointerBehaviorModifier.name: _handPointerBehaviorModifier.parser(in: context).map({ Output.chunk5(.handPointerBehavior($0)) }).eraseToAnyParser(), -_headerProminenceModifier.name: _headerProminenceModifier.parser(in: context).map({ Output.chunk6(.headerProminence($0)) }).eraseToAnyParser(), +_headerProminenceModifier.name: _headerProminenceModifier.parser(in: context).map({ Output.chunk5(.headerProminence($0)) }).eraseToAnyParser(), _helpModifier.name: _helpModifier.parser(in: context).map({ Output.chunk6(.help($0)) }).eraseToAnyParser(), _hiddenModifier.name: _hiddenModifier.parser(in: context).map({ Output.chunk6(.hidden($0)) }).eraseToAnyParser(), _highPriorityGestureModifier.name: _highPriorityGestureModifier.parser(in: context).map({ Output.chunk6(.highPriorityGesture($0)) }).eraseToAnyParser(), @@ -17116,7 +17019,7 @@ _imageScaleModifier.name: _imageScaleModifier.parser(in: context).map({ Ou _immersiveEnvironmentPickerModifier.name: _immersiveEnvironmentPickerModifier.parser(in: context).map({ Output.chunk6(.immersiveEnvironmentPicker($0)) }).eraseToAnyParser(), _indexViewStyleModifier.name: _indexViewStyleModifier.parser(in: context).map({ Output.chunk6(.indexViewStyle($0)) }).eraseToAnyParser(), _inspectorModifier.name: _inspectorModifier.parser(in: context).map({ Output.chunk6(.inspector($0)) }).eraseToAnyParser(), -_inspectorColumnWidthModifier.name: _inspectorColumnWidthModifier.parser(in: context).map({ Output.chunk7(.inspectorColumnWidth($0)) }).eraseToAnyParser(), +_inspectorColumnWidthModifier.name: _inspectorColumnWidthModifier.parser(in: context).map({ Output.chunk6(.inspectorColumnWidth($0)) }).eraseToAnyParser(), _interactionActivityTrackingTagModifier.name: _interactionActivityTrackingTagModifier.parser(in: context).map({ Output.chunk7(.interactionActivityTrackingTag($0)) }).eraseToAnyParser(), _interactiveDismissDisabledModifier.name: _interactiveDismissDisabledModifier.parser(in: context).map({ Output.chunk7(.interactiveDismissDisabled($0)) }).eraseToAnyParser(), _invalidatableContentModifier.name: _invalidatableContentModifier.parser(in: context).map({ Output.chunk7(.invalidatableContent($0)) }).eraseToAnyParser(), @@ -17130,7 +17033,7 @@ _layoutPriorityModifier.name: _layoutPriorityModifier.parser(in: context). _lineLimitModifier.name: _lineLimitModifier.parser(in: context).map({ Output.chunk7(.lineLimit($0)) }).eraseToAnyParser(), _lineSpacingModifier.name: _lineSpacingModifier.parser(in: context).map({ Output.chunk7(.lineSpacing($0)) }).eraseToAnyParser(), _listItemTintModifier.name: _listItemTintModifier.parser(in: context).map({ Output.chunk7(.listItemTint($0)) }).eraseToAnyParser(), -_listRowBackgroundModifier.name: _listRowBackgroundModifier.parser(in: context).map({ Output.chunk8(.listRowBackground($0)) }).eraseToAnyParser(), +_listRowBackgroundModifier.name: _listRowBackgroundModifier.parser(in: context).map({ Output.chunk7(.listRowBackground($0)) }).eraseToAnyParser(), _listRowHoverEffectModifier.name: _listRowHoverEffectModifier.parser(in: context).map({ Output.chunk8(.listRowHoverEffect($0)) }).eraseToAnyParser(), _listRowHoverEffectDisabledModifier.name: _listRowHoverEffectDisabledModifier.parser(in: context).map({ Output.chunk8(.listRowHoverEffectDisabled($0)) }).eraseToAnyParser(), _listRowInsetsModifier.name: _listRowInsetsModifier.parser(in: context).map({ Output.chunk8(.listRowInsets($0)) }).eraseToAnyParser(), @@ -17144,7 +17047,7 @@ _listSectionSpacingModifier.name: _listSectionSpacingModifier.parser(in: c _listStyleModifier.name: _listStyleModifier.parser(in: context).map({ Output.chunk8(.listStyle($0)) }).eraseToAnyParser(), _luminanceToAlphaModifier.name: _luminanceToAlphaModifier.parser(in: context).map({ Output.chunk8(.luminanceToAlpha($0)) }).eraseToAnyParser(), _materialActiveAppearanceModifier.name: _materialActiveAppearanceModifier.parser(in: context).map({ Output.chunk8(.materialActiveAppearance($0)) }).eraseToAnyParser(), -_menuIndicatorModifier.name: _menuIndicatorModifier.parser(in: context).map({ Output.chunk9(.menuIndicator($0)) }).eraseToAnyParser(), +_menuIndicatorModifier.name: _menuIndicatorModifier.parser(in: context).map({ Output.chunk8(.menuIndicator($0)) }).eraseToAnyParser(), _menuOrderModifier.name: _menuOrderModifier.parser(in: context).map({ Output.chunk9(.menuOrder($0)) }).eraseToAnyParser(), _menuStyleModifier.name: _menuStyleModifier.parser(in: context).map({ Output.chunk9(.menuStyle($0)) }).eraseToAnyParser(), _minimumScaleFactorModifier.name: _minimumScaleFactorModifier.parser(in: context).map({ Output.chunk9(.minimumScaleFactor($0)) }).eraseToAnyParser(), @@ -17158,10 +17061,9 @@ _navigationBarTitleModifier.name: _navigationBarTitleModifier.parser(in: c _navigationBarTitleDisplayModeModifier.name: _navigationBarTitleDisplayModeModifier.parser(in: context).map({ Output.chunk9(.navigationBarTitleDisplayMode($0)) }).eraseToAnyParser(), _navigationDestinationModifier.name: _navigationDestinationModifier.parser(in: context).map({ Output.chunk9(.navigationDestination($0)) }).eraseToAnyParser(), _navigationSplitViewColumnWidthModifier.name: _navigationSplitViewColumnWidthModifier.parser(in: context).map({ Output.chunk9(.navigationSplitViewColumnWidth($0)) }).eraseToAnyParser(), -_navigationSplitViewStyleModifier.name: _navigationSplitViewStyleModifier.parser(in: context).map({ Output.chunk10(.navigationSplitViewStyle($0)) }).eraseToAnyParser(), +_navigationSplitViewStyleModifier.name: _navigationSplitViewStyleModifier.parser(in: context).map({ Output.chunk9(.navigationSplitViewStyle($0)) }).eraseToAnyParser(), _navigationSubtitleModifier.name: _navigationSubtitleModifier.parser(in: context).map({ Output.chunk10(.navigationSubtitle($0)) }).eraseToAnyParser(), _navigationTitleModifier.name: _navigationTitleModifier.parser(in: context).map({ Output.chunk10(.navigationTitle($0)) }).eraseToAnyParser(), -_navigationViewStyleModifier.name: _navigationViewStyleModifier.parser(in: context).map({ Output.chunk10(.navigationViewStyle($0)) }).eraseToAnyParser(), _offsetModifier.name: _offsetModifier.parser(in: context).map({ Output.chunk10(.offset($0)) }).eraseToAnyParser(), _onAppearModifier.name: _onAppearModifier.parser(in: context).map({ Output.chunk10(.onAppear($0)) }).eraseToAnyParser(), _onDeleteCommandModifier.name: _onDeleteCommandModifier.parser(in: context).map({ Output.chunk10(.onDeleteCommand($0)) }).eraseToAnyParser(), @@ -17172,8 +17074,8 @@ _onImmersionChangeModifier.name: _onImmersionChangeModifier.parser(in: con _onLongPressGestureModifier.name: _onLongPressGestureModifier.parser(in: context).map({ Output.chunk10(.onLongPressGesture($0)) }).eraseToAnyParser(), _onLongTouchGestureModifier.name: _onLongTouchGestureModifier.parser(in: context).map({ Output.chunk10(.onLongTouchGesture($0)) }).eraseToAnyParser(), _onModifierKeysChangedModifier.name: _onModifierKeysChangedModifier.parser(in: context).map({ Output.chunk10(.onModifierKeysChanged($0)) }).eraseToAnyParser(), -_onMoveCommandModifier.name: _onMoveCommandModifier.parser(in: context).map({ Output.chunk11(.onMoveCommand($0)) }).eraseToAnyParser(), -_onPencilDoubleTapModifier.name: _onPencilDoubleTapModifier.parser(in: context).map({ Output.chunk11(.onPencilDoubleTap($0)) }).eraseToAnyParser(), +_onMoveCommandModifier.name: _onMoveCommandModifier.parser(in: context).map({ Output.chunk10(.onMoveCommand($0)) }).eraseToAnyParser(), +_onPencilDoubleTapModifier.name: _onPencilDoubleTapModifier.parser(in: context).map({ Output.chunk10(.onPencilDoubleTap($0)) }).eraseToAnyParser(), _onPencilSqueezeModifier.name: _onPencilSqueezeModifier.parser(in: context).map({ Output.chunk11(.onPencilSqueeze($0)) }).eraseToAnyParser(), _onPlayPauseCommandModifier.name: _onPlayPauseCommandModifier.parser(in: context).map({ Output.chunk11(.onPlayPauseCommand($0)) }).eraseToAnyParser(), _onScrollPhaseChangeModifier.name: _onScrollPhaseChangeModifier.parser(in: context).map({ Output.chunk11(.onScrollPhaseChange($0)) }).eraseToAnyParser(), @@ -17186,8 +17088,8 @@ _overlayModifier.name: _overlayModifier.parser(in: context).map({ Output.c _paddingModifier.name: _paddingModifier.parser(in: context).map({ Output.chunk11(.padding($0)) }).eraseToAnyParser(), _padding3DModifier.name: _padding3DModifier.parser(in: context).map({ Output.chunk11(.padding3D($0)) }).eraseToAnyParser(), _persistentSystemOverlaysModifier.name: _persistentSystemOverlaysModifier.parser(in: context).map({ Output.chunk11(.persistentSystemOverlays($0)) }).eraseToAnyParser(), -_pickerStyleModifier.name: _pickerStyleModifier.parser(in: context).map({ Output.chunk12(.pickerStyle($0)) }).eraseToAnyParser(), -_pointerStyleModifier.name: _pointerStyleModifier.parser(in: context).map({ Output.chunk12(.pointerStyle($0)) }).eraseToAnyParser(), +_pickerStyleModifier.name: _pickerStyleModifier.parser(in: context).map({ Output.chunk11(.pickerStyle($0)) }).eraseToAnyParser(), +_pointerStyleModifier.name: _pointerStyleModifier.parser(in: context).map({ Output.chunk11(.pointerStyle($0)) }).eraseToAnyParser(), _pointerVisibilityModifier.name: _pointerVisibilityModifier.parser(in: context).map({ Output.chunk12(.pointerVisibility($0)) }).eraseToAnyParser(), _popoverModifier.name: _popoverModifier.parser(in: context).map({ Output.chunk12(.popover($0)) }).eraseToAnyParser(), _positionModifier.name: _positionModifier.parser(in: context).map({ Output.chunk12(.position($0)) }).eraseToAnyParser(), @@ -17200,8 +17102,8 @@ _presentationContentInteractionModifier.name: _presentationContentInteraction _presentationCornerRadiusModifier.name: _presentationCornerRadiusModifier.parser(in: context).map({ Output.chunk12(.presentationCornerRadius($0)) }).eraseToAnyParser(), _presentationDragIndicatorModifier.name: _presentationDragIndicatorModifier.parser(in: context).map({ Output.chunk12(.presentationDragIndicator($0)) }).eraseToAnyParser(), _presentationSizingModifier.name: _presentationSizingModifier.parser(in: context).map({ Output.chunk12(.presentationSizing($0)) }).eraseToAnyParser(), -_previewDisplayNameModifier.name: _previewDisplayNameModifier.parser(in: context).map({ Output.chunk13(.previewDisplayName($0)) }).eraseToAnyParser(), -_privacySensitiveModifier.name: _privacySensitiveModifier.parser(in: context).map({ Output.chunk13(.privacySensitive($0)) }).eraseToAnyParser(), +_previewDisplayNameModifier.name: _previewDisplayNameModifier.parser(in: context).map({ Output.chunk12(.previewDisplayName($0)) }).eraseToAnyParser(), +_privacySensitiveModifier.name: _privacySensitiveModifier.parser(in: context).map({ Output.chunk12(.privacySensitive($0)) }).eraseToAnyParser(), _progressViewStyleModifier.name: _progressViewStyleModifier.parser(in: context).map({ Output.chunk13(.progressViewStyle($0)) }).eraseToAnyParser(), _projectionEffectModifier.name: _projectionEffectModifier.parser(in: context).map({ Output.chunk13(.projectionEffect($0)) }).eraseToAnyParser(), _redactedModifier.name: _redactedModifier.parser(in: context).map({ Output.chunk13(.redacted($0)) }).eraseToAnyParser(), @@ -17214,8 +17116,8 @@ _safeAreaPaddingModifier.name: _safeAreaPaddingModifier.parser(in: context _saturationModifier.name: _saturationModifier.parser(in: context).map({ Output.chunk13(.saturation($0)) }).eraseToAnyParser(), _scaleEffectModifier.name: _scaleEffectModifier.parser(in: context).map({ Output.chunk13(.scaleEffect($0)) }).eraseToAnyParser(), _scaledToFillModifier.name: _scaledToFillModifier.parser(in: context).map({ Output.chunk13(.scaledToFill($0)) }).eraseToAnyParser(), -_scaledToFitModifier.name: _scaledToFitModifier.parser(in: context).map({ Output.chunk14(.scaledToFit($0)) }).eraseToAnyParser(), -_scenePaddingModifier.name: _scenePaddingModifier.parser(in: context).map({ Output.chunk14(.scenePadding($0)) }).eraseToAnyParser(), +_scaledToFitModifier.name: _scaledToFitModifier.parser(in: context).map({ Output.chunk13(.scaledToFit($0)) }).eraseToAnyParser(), +_scenePaddingModifier.name: _scenePaddingModifier.parser(in: context).map({ Output.chunk13(.scenePadding($0)) }).eraseToAnyParser(), _scrollBounceBehaviorModifier.name: _scrollBounceBehaviorModifier.parser(in: context).map({ Output.chunk14(.scrollBounceBehavior($0)) }).eraseToAnyParser(), _scrollClipDisabledModifier.name: _scrollClipDisabledModifier.parser(in: context).map({ Output.chunk14(.scrollClipDisabled($0)) }).eraseToAnyParser(), _scrollContentBackgroundModifier.name: _scrollContentBackgroundModifier.parser(in: context).map({ Output.chunk14(.scrollContentBackground($0)) }).eraseToAnyParser(), @@ -17228,8 +17130,8 @@ _scrollTargetBehaviorModifier.name: _scrollTargetBehaviorModifier.parser(i _scrollTargetLayoutModifier.name: _scrollTargetLayoutModifier.parser(in: context).map({ Output.chunk14(.scrollTargetLayout($0)) }).eraseToAnyParser(), _searchDictationBehaviorModifier.name: _searchDictationBehaviorModifier.parser(in: context).map({ Output.chunk14(.searchDictationBehavior($0)) }).eraseToAnyParser(), _searchPresentationToolbarBehaviorModifier.name: _searchPresentationToolbarBehaviorModifier.parser(in: context).map({ Output.chunk14(.searchPresentationToolbarBehavior($0)) }).eraseToAnyParser(), -_searchSuggestionsModifier.name: _searchSuggestionsModifier.parser(in: context).map({ Output.chunk15(.searchSuggestions($0)) }).eraseToAnyParser(), -_searchableModifier.name: _searchableModifier.parser(in: context).map({ Output.chunk15(.searchable($0)) }).eraseToAnyParser(), +_searchSuggestionsModifier.name: _searchSuggestionsModifier.parser(in: context).map({ Output.chunk14(.searchSuggestions($0)) }).eraseToAnyParser(), +_searchableModifier.name: _searchableModifier.parser(in: context).map({ Output.chunk14(.searchable($0)) }).eraseToAnyParser(), _sectionActionsModifier.name: _sectionActionsModifier.parser(in: context).map({ Output.chunk15(.sectionActions($0)) }).eraseToAnyParser(), _selectionDisabledModifier.name: _selectionDisabledModifier.parser(in: context).map({ Output.chunk15(.selectionDisabled($0)) }).eraseToAnyParser(), _shadowModifier.name: _shadowModifier.parser(in: context).map({ Output.chunk15(.shadow($0)) }).eraseToAnyParser(), @@ -17242,8 +17144,8 @@ _speechSpellsOutCharactersModifier.name: _speechSpellsOutCharactersModifier.name: _statusBarModifier.parser(in: context).map({ Output.chunk15(.statusBar($0)) }).eraseToAnyParser(), _statusBarHiddenModifier.name: _statusBarHiddenModifier.parser(in: context).map({ Output.chunk15(.statusBarHidden($0)) }).eraseToAnyParser(), _submitLabelModifier.name: _submitLabelModifier.parser(in: context).map({ Output.chunk15(.submitLabel($0)) }).eraseToAnyParser(), -_submitScopeModifier.name: _submitScopeModifier.parser(in: context).map({ Output.chunk16(.submitScope($0)) }).eraseToAnyParser(), -_supportedVolumeViewpointsModifier.name: _supportedVolumeViewpointsModifier.parser(in: context).map({ Output.chunk16(.supportedVolumeViewpoints($0)) }).eraseToAnyParser(), +_submitScopeModifier.name: _submitScopeModifier.parser(in: context).map({ Output.chunk15(.submitScope($0)) }).eraseToAnyParser(), +_supportedVolumeViewpointsModifier.name: _supportedVolumeViewpointsModifier.parser(in: context).map({ Output.chunk15(.supportedVolumeViewpoints($0)) }).eraseToAnyParser(), _swipeActionsModifier.name: _swipeActionsModifier.parser(in: context).map({ Output.chunk16(.swipeActions($0)) }).eraseToAnyParser(), _symbolEffectModifier.name: _symbolEffectModifier.parser(in: context).map({ Output.chunk16(.symbolEffect($0)) }).eraseToAnyParser(), _symbolEffectsRemovedModifier.name: _symbolEffectsRemovedModifier.parser(in: context).map({ Output.chunk16(.symbolEffectsRemoved($0)) }).eraseToAnyParser(), @@ -17256,8 +17158,8 @@ _tabViewSidebarHeaderModifier.name: _tabViewSidebarHeaderModifier.parser(i _tabViewStyleModifier.name: _tabViewStyleModifier.parser(in: context).map({ Output.chunk16(.tabViewStyle($0)) }).eraseToAnyParser(), _tableStyleModifier.name: _tableStyleModifier.parser(in: context).map({ Output.chunk16(.tableStyle($0)) }).eraseToAnyParser(), _textCaseModifier.name: _textCaseModifier.parser(in: context).map({ Output.chunk16(.textCase($0)) }).eraseToAnyParser(), -_textContentTypeModifier.name: _textContentTypeModifier.parser(in: context).map({ Output.chunk17(.textContentType($0)) }).eraseToAnyParser(), -_textEditorStyleModifier.name: _textEditorStyleModifier.parser(in: context).map({ Output.chunk17(.textEditorStyle($0)) }).eraseToAnyParser(), +_textContentTypeModifier.name: _textContentTypeModifier.parser(in: context).map({ Output.chunk16(.textContentType($0)) }).eraseToAnyParser(), +_textEditorStyleModifier.name: _textEditorStyleModifier.parser(in: context).map({ Output.chunk16(.textEditorStyle($0)) }).eraseToAnyParser(), _textFieldStyleModifier.name: _textFieldStyleModifier.parser(in: context).map({ Output.chunk17(.textFieldStyle($0)) }).eraseToAnyParser(), _textInputAutocapitalizationModifier.name: _textInputAutocapitalizationModifier.parser(in: context).map({ Output.chunk17(.textInputAutocapitalization($0)) }).eraseToAnyParser(), _textInputCompletionModifier.name: _textInputCompletionModifier.parser(in: context).map({ Output.chunk17(.textInputCompletion($0)) }).eraseToAnyParser(), @@ -17270,8 +17172,8 @@ _toolbarModifier.name: _toolbarModifier.parser(in: context).map({ Output.c _toolbarBackgroundModifier.name: _toolbarBackgroundModifier.parser(in: context).map({ Output.chunk17(.toolbarBackground($0)) }).eraseToAnyParser(), _toolbarBackgroundVisibilityModifier.name: _toolbarBackgroundVisibilityModifier.parser(in: context).map({ Output.chunk17(.toolbarBackgroundVisibility($0)) }).eraseToAnyParser(), _toolbarColorSchemeModifier.name: _toolbarColorSchemeModifier.parser(in: context).map({ Output.chunk17(.toolbarColorScheme($0)) }).eraseToAnyParser(), -_toolbarItemHiddenModifier.name: _toolbarItemHiddenModifier.parser(in: context).map({ Output.chunk18(.toolbarItemHidden($0)) }).eraseToAnyParser(), -_toolbarRoleModifier.name: _toolbarRoleModifier.parser(in: context).map({ Output.chunk18(.toolbarRole($0)) }).eraseToAnyParser(), +_toolbarItemHiddenModifier.name: _toolbarItemHiddenModifier.parser(in: context).map({ Output.chunk17(.toolbarItemHidden($0)) }).eraseToAnyParser(), +_toolbarRoleModifier.name: _toolbarRoleModifier.parser(in: context).map({ Output.chunk17(.toolbarRole($0)) }).eraseToAnyParser(), _toolbarTitleDisplayModeModifier.name: _toolbarTitleDisplayModeModifier.parser(in: context).map({ Output.chunk18(.toolbarTitleDisplayMode($0)) }).eraseToAnyParser(), _toolbarTitleMenuModifier.name: _toolbarTitleMenuModifier.parser(in: context).map({ Output.chunk18(.toolbarTitleMenu($0)) }).eraseToAnyParser(), _toolbarVisibilityModifier.name: _toolbarVisibilityModifier.parser(in: context).map({ Output.chunk18(.toolbarVisibility($0)) }).eraseToAnyParser(), @@ -17284,24 +17186,25 @@ _truncationModeModifier.name: _truncationModeModifier.parser(in: context). _unredactedModifier.name: _unredactedModifier.parser(in: context).map({ Output.chunk18(.unredacted($0)) }).eraseToAnyParser(), _upperLimbVisibilityModifier.name: _upperLimbVisibilityModifier.parser(in: context).map({ Output.chunk18(.upperLimbVisibility($0)) }).eraseToAnyParser(), _volumeBaseplateVisibilityModifier.name: _volumeBaseplateVisibilityModifier.parser(in: context).map({ Output.chunk18(.volumeBaseplateVisibility($0)) }).eraseToAnyParser(), -_windowDismissBehaviorModifier.name: _windowDismissBehaviorModifier.parser(in: context).map({ Output.chunk19(.windowDismissBehavior($0)) }).eraseToAnyParser(), -_windowFullScreenBehaviorModifier.name: _windowFullScreenBehaviorModifier.parser(in: context).map({ Output.chunk19(.windowFullScreenBehavior($0)) }).eraseToAnyParser(), +_windowDismissBehaviorModifier.name: _windowDismissBehaviorModifier.parser(in: context).map({ Output.chunk18(.windowDismissBehavior($0)) }).eraseToAnyParser(), +_windowFullScreenBehaviorModifier.name: _windowFullScreenBehaviorModifier.parser(in: context).map({ Output.chunk18(.windowFullScreenBehavior($0)) }).eraseToAnyParser(), _windowMinimizeBehaviorModifier.name: _windowMinimizeBehaviorModifier.parser(in: context).map({ Output.chunk19(.windowMinimizeBehavior($0)) }).eraseToAnyParser(), _windowResizeBehaviorModifier.name: _windowResizeBehaviorModifier.parser(in: context).map({ Output.chunk19(.windowResizeBehavior($0)) }).eraseToAnyParser(), _windowToolbarFullScreenVisibilityModifier.name: _windowToolbarFullScreenVisibilityModifier.parser(in: context).map({ Output.chunk19(.windowToolbarFullScreenVisibility($0)) }).eraseToAnyParser(), _writingToolsBehaviorModifier.name: _writingToolsBehaviorModifier.parser(in: context).map({ Output.chunk19(.writingToolsBehavior($0)) }).eraseToAnyParser(), _zIndexModifier.name: _zIndexModifier.parser(in: context).map({ Output.chunk19(.zIndex($0)) }).eraseToAnyParser(), - LiveViewNative._OnSubmitModifier.name: LiveViewNative._OnSubmitModifier.parser(in: context).map(Output._OnSubmitModifier).eraseToAnyParser(), -LiveViewNative._PerspectiveRotationEffectModifier.name: LiveViewNative._PerspectiveRotationEffectModifier.parser(in: context).map(Output._PerspectiveRotationEffectModifier).eraseToAnyParser(), -LiveViewNative._MaskModifier.name: LiveViewNative._MaskModifier.parser(in: context).map(Output._MaskModifier).eraseToAnyParser(), + LiveViewNative._MatchedTransitionSourceModifier.name: LiveViewNative._MatchedTransitionSourceModifier.parser(in: context).map(Output._MatchedTransitionSourceModifier).eraseToAnyParser(), +LiveViewNative._FileImporterModifier.name: LiveViewNative._FileImporterModifier.parser(in: context).map(Output._FileImporterModifier).eraseToAnyParser(), +LiveViewNative._FocusScopeModifier.name: LiveViewNative._FocusScopeModifier.parser(in: context).map(Output._FocusScopeModifier).eraseToAnyParser(), LiveViewNative._SearchScopesModifier.name: LiveViewNative._SearchScopesModifier.parser(in: context).map(Output._SearchScopesModifier).eraseToAnyParser(), -LiveViewNative._NavigationTransitionModifier.name: LiveViewNative._NavigationTransitionModifier.parser(in: context).map(Output._NavigationTransitionModifier).eraseToAnyParser(), -LiveViewNative._MatchedGeometryEffectModifier.name: LiveViewNative._MatchedGeometryEffectModifier.parser(in: context).map(Output._MatchedGeometryEffectModifier).eraseToAnyParser(), +LiveViewNative._MaskModifier.name: LiveViewNative._MaskModifier.parser(in: context).map(Output._MaskModifier).eraseToAnyParser(), +LiveViewNative._PerspectiveRotationEffectModifier.name: LiveViewNative._PerspectiveRotationEffectModifier.parser(in: context).map(Output._PerspectiveRotationEffectModifier).eraseToAnyParser(), LiveViewNative._PresentationDetentsModifier.name: LiveViewNative._PresentationDetentsModifier.parser(in: context).map(Output._PresentationDetentsModifier).eraseToAnyParser(), -LiveViewNative._Rotation3DEffectModifier.name: LiveViewNative._Rotation3DEffectModifier.parser(in: context).map(Output._Rotation3DEffectModifier).eraseToAnyParser(), -LiveViewNative._FocusScopeModifier.name: LiveViewNative._FocusScopeModifier.parser(in: context).map(Output._FocusScopeModifier).eraseToAnyParser(), LiveViewNative._PrefersDefaultFocusModifier.name: LiveViewNative._PrefersDefaultFocusModifier.parser(in: context).map(Output._PrefersDefaultFocusModifier).eraseToAnyParser(), -LiveViewNative._MatchedTransitionSourceModifier.name: LiveViewNative._MatchedTransitionSourceModifier.parser(in: context).map(Output._MatchedTransitionSourceModifier).eraseToAnyParser(), +LiveViewNative._MatchedGeometryEffectModifier.name: LiveViewNative._MatchedGeometryEffectModifier.parser(in: context).map(Output._MatchedGeometryEffectModifier).eraseToAnyParser(), +LiveViewNative._NavigationTransitionModifier.name: LiveViewNative._NavigationTransitionModifier.parser(in: context).map(Output._NavigationTransitionModifier).eraseToAnyParser(), +LiveViewNative._OnSubmitModifier.name: LiveViewNative._OnSubmitModifier.parser(in: context).map(Output._OnSubmitModifier).eraseToAnyParser(), +LiveViewNative._Rotation3DEffectModifier.name: LiveViewNative._Rotation3DEffectModifier.parser(in: context).map(Output._Rotation3DEffectModifier).eraseToAnyParser(), LiveViewNative._SearchCompletionModifier.name: LiveViewNative._SearchCompletionModifier.parser(in: context).map(Output._SearchCompletionModifier).eraseToAnyParser(), ] @@ -17498,7 +17401,7 @@ ConstantAtomLiteral("content").map({ () -> Self in /// * `.tabBar` /// * `.sidebar` @_documentation(visibility: public) -@available(watchOS 11.0,iOS 18.0,macOS 15.0,visionOS 2.0,tvOS 18.0, *) +@available(tvOS 18.0,macOS 15.0,visionOS 2.0,iOS 18.0,watchOS 11.0, *) extension AdaptableTabBarPlacement: ParseableModifierValue { public static func parser(in context: ParseableModifierContext) -> some Parser { ImplicitStaticMember { @@ -17616,7 +17519,7 @@ ConstantAtomLiteral("vertical").map({ () -> Self in /// * `.standard` /// * `.increased` @_documentation(visibility: public) -@available(iOS 17.0,macOS 14.0,visionOS 1.0, *) +@available(visionOS 1.0,iOS 17.0,macOS 14.0, *) extension BadgeProminence: ParseableModifierValue { public static func parser(in context: ParseableModifierContext) -> some Parser { ImplicitStaticMember { @@ -17844,7 +17747,7 @@ ConstantAtomLiteral("plusLighter").map({ () -> Self in /// * `.enabled` /// * `.disabled` @_documentation(visibility: public) -@available(watchOS 10.0,iOS 17.0,macOS 14.0,visionOS 1.0,tvOS 17.0, *) +@available(iOS 17.0,watchOS 10.0,tvOS 17.0,macOS 14.0,visionOS 1.0, *) extension ButtonRepeatBehavior: ParseableModifierValue { public static func parser(in context: ParseableModifierContext) -> some Parser { ImplicitStaticMember { @@ -17963,35 +17866,35 @@ ConstantAtomLiteral("dark").map({ () -> Self in /// * `.navigationSplitView` /// * `.window` @_documentation(visibility: public) -@available(tvOS 17.0,iOS 17.0,watchOS 10.0,visionOS 1.0,macOS 14.0, *) +@available(tvOS 17.0,visionOS 1.0,watchOS 10.0,iOS 17.0,macOS 14.0, *) extension ContainerBackgroundPlacement: ParseableModifierValue { public static func parser(in context: ParseableModifierContext) -> some Parser { ImplicitStaticMember { OneOf { #if os(watchOS) ConstantAtomLiteral("tabView").map({ () -> Self in -if #available(tvOS 17.0,iOS 17.0,watchOS 10.0,macOS 14.0, *) { +if #available(tvOS 17.0,watchOS 10.0,iOS 17.0,macOS 14.0, *) { return Self.tabView } else { fatalError("'tabView' is not available in this OS version") } }) #endif #if os(iOS) || os(watchOS) ConstantAtomLiteral("navigation").map({ () -> Self in -if #available(tvOS 17.0,iOS 18.0,watchOS 10.0,macOS 14.0, *) { +if #available(tvOS 17.0,watchOS 10.0,iOS 18.0,macOS 14.0, *) { return Self.navigation } else { fatalError("'navigation' is not available in this OS version") } }) #endif #if os(iOS) || os(watchOS) ConstantAtomLiteral("navigationSplitView").map({ () -> Self in -if #available(tvOS 17.0,iOS 18.0,watchOS 11.0,macOS 14.0, *) { +if #available(tvOS 17.0,watchOS 11.0,iOS 18.0,macOS 14.0, *) { return Self.navigationSplitView } else { fatalError("'navigationSplitView' is not available in this OS version") } }) #endif #if os(macOS) ConstantAtomLiteral("window").map({ () -> Self in -if #available(tvOS 17.0,iOS 17.0,watchOS 10.0,macOS 15.0, *) { +if #available(tvOS 17.0,watchOS 10.0,iOS 17.0,macOS 15.0, *) { return Self.window } else { fatalError("'window' is not available in this OS version") } }) @@ -18071,35 +17974,35 @@ ConstantAtomLiteral("interaction").map({ () -> Self in #if os(iOS) || os(macOS) || os(visionOS) ConstantAtomLiteral("dragPreview").map({ () -> Self in -if #available(macOS 12.0,visionOS 1.0,watchOS 8.0,tvOS 15.0,iOS 15.0, *) { +if #available(tvOS 15.0,iOS 15.0,visionOS 1.0,macOS 12.0,watchOS 8.0, *) { return Self.dragPreview } else { fatalError("'dragPreview' is not available in this OS version") } }) #endif #if os(iOS) || os(tvOS) || os(visionOS) ConstantAtomLiteral("contextMenuPreview").map({ () -> Self in -if #available(macOS 12.0,visionOS 1.0,watchOS 8.0,tvOS 17.0,iOS 15.0, *) { +if #available(tvOS 17.0,iOS 15.0,visionOS 1.0,macOS 12.0,watchOS 8.0, *) { return Self.contextMenuPreview } else { fatalError("'contextMenuPreview' is not available in this OS version") } }) #endif #if os(iOS) || os(tvOS) || os(visionOS) ConstantAtomLiteral("hoverEffect").map({ () -> Self in -if #available(macOS 12.0,visionOS 1.0,watchOS 8.0,tvOS 18.0,iOS 15.0, *) { +if #available(tvOS 18.0,iOS 15.0,visionOS 1.0,macOS 12.0,watchOS 8.0, *) { return Self.hoverEffect } else { fatalError("'hoverEffect' is not available in this OS version") } }) #endif #if os(macOS) || os(watchOS) ConstantAtomLiteral("focusEffect").map({ () -> Self in -if #available(macOS 12.0,watchOS 8.0,tvOS 15.0,iOS 15.0, *) { +if #available(tvOS 15.0,iOS 15.0,macOS 12.0,watchOS 8.0, *) { return Self.focusEffect } else { fatalError("'focusEffect' is not available in this OS version") } }) #endif #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) ConstantAtomLiteral("accessibility").map({ () -> Self in -if #available(watchOS 10.0,iOS 17.0,tvOS 17.0,macOS 14.0,visionOS 1.0, *) { +if #available(iOS 17.0,tvOS 17.0,macOS 14.0,watchOS 10.0,visionOS 1.0, *) { return Self.accessibility } else { fatalError("'accessibility' is not available in this OS version") } }) @@ -18122,7 +18025,7 @@ if #available(watchOS 10.0,iOS 17.0,tvOS 17.0,macOS 14.0,visionOS 1.0, *) { /// * `.large` /// * `.extraLarge` @_documentation(visibility: public) -@available(watchOS 9.0,iOS 15.0,macOS 10.15,visionOS 1.0, *) +@available(iOS 15.0,macOS 10.15,watchOS 9.0,visionOS 1.0, *) extension ControlSize: ParseableModifierValue { public static func parser(in context: ParseableModifierContext) -> some Parser { ImplicitStaticMember { @@ -18150,14 +18053,14 @@ ConstantAtomLiteral("regular").map({ () -> Self in #endif #if os(iOS) || os(macOS) || os(visionOS) || os(watchOS) ConstantAtomLiteral("large").map({ () -> Self in -if #available(watchOS 9.0,iOS 15.0,macOS 11.0,visionOS 1.0, *) { +if #available(iOS 15.0,macOS 11.0,watchOS 9.0,visionOS 1.0, *) { return Self.large } else { fatalError("'large' is not available in this OS version") } }) #endif #if os(iOS) || os(macOS) || os(visionOS) || os(watchOS) ConstantAtomLiteral("extraLarge").map({ () -> Self in -if #available(watchOS 10.0,iOS 17.0,macOS 14.0,visionOS 1.0, *) { +if #available(iOS 17.0,macOS 14.0,watchOS 10.0,visionOS 1.0, *) { return Self.extraLarge } else { fatalError("'extraLarge' is not available in this OS version") } }) @@ -18212,7 +18115,7 @@ ConstantAtomLiteral("userInitiated").map({ () -> Self in /// * `.critical` /// * `.standard` @_documentation(visibility: public) -@available(tvOS 17.0,iOS 17.0,watchOS 10.0,visionOS 1.0,macOS 13.0, *) +@available(tvOS 17.0,visionOS 1.0,watchOS 10.0,iOS 17.0,macOS 13.0, *) extension DialogSeverity: ParseableModifierValue { public static func parser(in context: ParseableModifierContext) -> some Parser { ImplicitStaticMember { @@ -18233,7 +18136,7 @@ ConstantAtomLiteral("critical").map({ () -> Self in #endif #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) ConstantAtomLiteral("standard").map({ () -> Self in -if #available(tvOS 17.0,iOS 17.0,watchOS 10.0,visionOS 1.0,macOS 14.0, *) { +if #available(tvOS 17.0,visionOS 1.0,watchOS 10.0,iOS 17.0,macOS 14.0, *) { return Self.standard } else { fatalError("'standard' is not available in this OS version") } }) @@ -18404,7 +18307,7 @@ ConstantAtomLiteral("all").map({ () -> Self in /// * `.includeHiddenFiles` /// * `.displayFileExtensions` @_documentation(visibility: public) -@available(iOS 17.0,macOS 14.0,visionOS 1.0, *) +@available(visionOS 1.0,iOS 17.0,macOS 14.0, *) extension FileDialogBrowserOptions: ParseableModifierValue { public static func parser(in context: ParseableModifierContext) -> some Parser { ImplicitStaticMember { @@ -18446,7 +18349,7 @@ ConstantAtomLiteral("displayFileExtensions").map({ () -> Self in /// * `.edit` /// * `.automatic` @_documentation(visibility: public) -@available(watchOS 10.0,iOS 17.0,macOS 14.0,visionOS 1.0,tvOS 17.0, *) +@available(iOS 17.0,watchOS 10.0,tvOS 17.0,macOS 14.0,visionOS 1.0, *) extension FocusInteractions: ParseableModifierValue { public static func parser(in context: ParseableModifierContext) -> some Parser { ImplicitStaticMember { @@ -18705,14 +18608,14 @@ extension HorizontalAlignment: ParseableModifierValue { OneOf { #if os(iOS) || os(macOS) || os(visionOS) ConstantAtomLiteral("listRowSeparatorLeading").map({ () -> Self in -if #available(iOS 16.0,macOS 13.0,visionOS 1.0, *) { +if #available(visionOS 1.0,iOS 16.0,macOS 13.0, *) { return Self.listRowSeparatorLeading } else { fatalError("'listRowSeparatorLeading' is not available in this OS version") } }) #endif #if os(iOS) || os(macOS) || os(visionOS) ConstantAtomLiteral("listRowSeparatorTrailing").map({ () -> Self in -if #available(iOS 16.0,macOS 13.0,visionOS 1.0, *) { +if #available(visionOS 1.0,iOS 16.0,macOS 13.0, *) { return Self.listRowSeparatorTrailing } else { fatalError("'listRowSeparatorTrailing' is not available in this OS version") } }) @@ -18753,7 +18656,7 @@ ConstantAtomLiteral("trailing").map({ () -> Self in /// * `.leading` /// * `.trailing` @_documentation(visibility: public) -@available(macOS 15.0,visionOS 2.0,watchOS 11.0,tvOS 18.0,iOS 18.0, *) +@available(tvOS 18.0,iOS 18.0,visionOS 2.0,macOS 15.0,watchOS 11.0, *) extension HorizontalDirection: ParseableModifierValue { public static func parser(in context: ParseableModifierContext) -> some Parser { ImplicitStaticMember { @@ -18822,7 +18725,7 @@ ConstantAtomLiteral("trailing").map({ () -> Self in /// * `.highlight` /// * `.lift` @_documentation(visibility: public) -@available(iOS 13.4,tvOS 16.0,visionOS 1.0, *) +@available(tvOS 16.0,visionOS 1.0,iOS 13.4, *) extension HoverEffect: ParseableModifierValue { public static func parser(in context: ParseableModifierContext) -> some Parser { ImplicitStaticMember { @@ -18836,7 +18739,7 @@ ConstantAtomLiteral("automatic").map({ () -> Self in #endif #if os(iOS) || os(tvOS) || os(visionOS) ConstantAtomLiteral("highlight").map({ () -> Self in -if #available(iOS 13.4,tvOS 17.0,visionOS 1.0, *) { +if #available(tvOS 17.0,visionOS 1.0,iOS 13.4, *) { return Self.highlight } else { fatalError("'highlight' is not available in this OS version") } }) @@ -18954,7 +18857,7 @@ ConstantAtomLiteral("automatic").map({ () -> Self in #if os(iOS) || os(visionOS) ConstantAtomLiteral("priority").map({ () -> Self in -if #available(tvOS 16.0,iOS 16.0,watchOS 9.0,visionOS 1.0,macOS 13.0, *) { +if #available(iOS 16.0,visionOS 1.0,macOS 13.0,tvOS 16.0,watchOS 9.0, *) { return Self.priority } else { fatalError("'priority' is not available in this OS version") } }) @@ -19040,7 +18943,7 @@ ConstantAtomLiteral("fullScreenCover").map({ () -> Self in /// * `.resizes` /// * `.scrolls` @_documentation(visibility: public) -@available(watchOS 9.4,iOS 16.4,macOS 13.3,visionOS 1.0,tvOS 16.4, *) +@available(iOS 16.4,watchOS 9.4,tvOS 16.4,macOS 13.3,visionOS 1.0, *) extension PresentationContentInteraction: ParseableModifierValue { public static func parser(in context: ParseableModifierContext) -> some Parser { ImplicitStaticMember { @@ -19137,7 +19040,7 @@ ConstantAtomLiteral("privacy").map({ () -> Self in #if os(iOS) || os(macOS) || os(tvOS) || os(visionOS) || os(watchOS) ConstantAtomLiteral("invalidated").map({ () -> Self in -if #available(watchOS 10.0,iOS 17.0,tvOS 17.0,macOS 14.0,visionOS 1.0, *) { +if #available(iOS 17.0,tvOS 17.0,macOS 14.0,watchOS 10.0,visionOS 1.0, *) { return Self.invalidated } else { fatalError("'invalidated' is not available in this OS version") } }) @@ -19247,7 +19150,7 @@ ConstantAtomLiteral("minimum").map({ () -> Self in #if os(watchOS) ConstantAtomLiteral("navigationBar").map({ () -> Self in -if #available(macOS 13.0,watchOS 9.0,iOS 16.0,tvOS 16.0, *) { +if #available(iOS 16.0,macOS 13.0,tvOS 16.0,watchOS 9.0, *) { return Self.navigationBar } else { fatalError("'navigationBar' is not available in this OS version") } }) @@ -19310,7 +19213,7 @@ ConstantAtomLiteral("alignment").map({ () -> Self in /// * `.always` /// * `.basedOnSize` @_documentation(visibility: public) -@available(tvOS 16.4,iOS 16.4,watchOS 9.4,visionOS 1.0,macOS 13.3, *) +@available(tvOS 16.4,visionOS 1.0,watchOS 9.4,iOS 16.4,macOS 13.3, *) extension ScrollBounceBehavior: ParseableModifierValue { public static func parser(in context: ParseableModifierContext) -> some Parser { ImplicitStaticMember { @@ -19494,7 +19397,7 @@ ConstantAtomLiteral("disabled").map({ () -> Self in /// * `.onTextEntry` /// * `.onSearchPresentation` @_documentation(visibility: public) -@available(tvOS 16.4,iOS 16.4,watchOS 9.4,visionOS 1.0,macOS 13.3, *) +@available(watchOS 9.4,tvOS 16.4,iOS 16.4,macOS 13.3,visionOS 1.0, *) extension SearchScopeActivation: ParseableModifierValue { public static func parser(in context: ParseableModifierContext) -> some Parser { ImplicitStaticMember { @@ -19578,7 +19481,7 @@ ConstantAtomLiteral("content").map({ () -> Self in /// * `.enabled` /// * `.disabled` @_documentation(visibility: public) -@available(visionOS 1.0,macOS 14.0,watchOS 10.0,iOS 17.0,tvOS 17.0, *) +@available(tvOS 17.0,macOS 14.0,visionOS 1.0,iOS 17.0,watchOS 10.0, *) extension SpringLoadingBehavior: ParseableModifierValue { public static func parser(in context: ParseableModifierContext) -> some Parser { ImplicitStaticMember { @@ -19785,7 +19688,7 @@ ConstantAtomLiteral("downstream").map({ () -> Self in /// * `.sidebarToggle` /// * `.title` @_documentation(visibility: public) -@available(tvOS 17.0,iOS 17.0,watchOS 10.0,visionOS 1.0,macOS 14.0, *) +@available(tvOS 17.0,visionOS 1.0,watchOS 10.0,iOS 17.0,macOS 14.0, *) extension ToolbarDefaultItemKind: ParseableModifierValue { public static func parser(in context: ParseableModifierContext) -> some Parser { ImplicitStaticMember { @@ -19799,7 +19702,7 @@ ConstantAtomLiteral("sidebarToggle").map({ () -> Self in #endif #if os(iOS) || os(macOS) || os(visionOS) ConstantAtomLiteral("title").map({ () -> Self in -if #available(tvOS 17.0,iOS 18.0,watchOS 10.0,visionOS 2.0,macOS 15.0, *) { +if #available(tvOS 17.0,visionOS 2.0,watchOS 10.0,iOS 18.0,macOS 15.0, *) { return Self.title } else { fatalError("'title' is not available in this OS version") } }) @@ -19835,21 +19738,21 @@ ConstantAtomLiteral("automatic").map({ () -> Self in #if os(iOS) || os(tvOS) || os(visionOS) || os(watchOS) ConstantAtomLiteral("navigationStack").map({ () -> Self in -if #available(watchOS 9.0,iOS 16.0,macOS 13.0,visionOS 1.0,tvOS 16.0, *) { +if #available(iOS 16.0,watchOS 9.0,tvOS 16.0,macOS 13.0,visionOS 1.0, *) { return Self.navigationStack } else { fatalError("'navigationStack' is not available in this OS version") } }) #endif #if os(iOS) || os(visionOS) ConstantAtomLiteral("browser").map({ () -> Self in -if #available(watchOS 9.0,iOS 16.0,macOS 13.0,visionOS 1.0,tvOS 16.0, *) { +if #available(iOS 16.0,watchOS 9.0,tvOS 16.0,macOS 13.0,visionOS 1.0, *) { return Self.browser } else { fatalError("'browser' is not available in this OS version") } }) #endif #if os(iOS) || os(macOS) || os(visionOS) ConstantAtomLiteral("editor").map({ () -> Self in -if #available(watchOS 9.0,iOS 16.0,macOS 13.0,visionOS 1.0,tvOS 16.0, *) { +if #available(iOS 16.0,watchOS 9.0,tvOS 16.0,macOS 13.0,visionOS 1.0, *) { return Self.editor } else { fatalError("'editor' is not available in this OS version") } }) @@ -19977,7 +19880,7 @@ ConstantAtomLiteral("lastTextBaseline").map({ () -> Self in /// * `.up` /// * `.down` @_documentation(visibility: public) -@available(macOS 15.0,visionOS 2.0,watchOS 11.0,tvOS 18.0,iOS 18.0, *) +@available(tvOS 18.0,iOS 18.0,visionOS 2.0,macOS 15.0,watchOS 11.0, *) extension VerticalDirection: ParseableModifierValue { public static func parser(in context: ParseableModifierContext) -> some Parser { ImplicitStaticMember { @@ -20173,7 +20076,7 @@ ConstantAtomLiteral("onHover").map({ () -> Self in /// * `.limited` /// * `.disabled` @_documentation(visibility: public) -@available(iOS 18.0,macOS 15.0, *) +@available(macOS 15.0,iOS 18.0, *) extension WritingToolsBehavior: ParseableModifierValue { public static func parser(in context: ParseableModifierContext) -> some Parser { ImplicitStaticMember { diff --git a/Sources/LiveViewNative/__CoreExtensions.swift b/Sources/LiveViewNative/__CoreExtensions.swift new file mode 100644 index 000000000..570197923 --- /dev/null +++ b/Sources/LiveViewNative/__CoreExtensions.swift @@ -0,0 +1,1765 @@ +// +// __CoreExtensions.swift +// +// +// Created by Carson Katri on 9/5/24. +// + +import LiveViewNativeCore +import Foundation + +extension LiveViewNativeCore.ChannelStatus: @unchecked Sendable {} +extension LiveViewNativeCore.PhoenixEvent: @unchecked Sendable {} +extension LiveViewNativeCore.Event: @unchecked Sendable {} +extension LiveViewNativeCore.Json: @unchecked Sendable {} +extension LiveViewNativeCore.Payload: @unchecked Sendable {} +extension LiveViewNativeCore.EventPayload: @unchecked Sendable {} + +extension LiveViewNativeCore.LiveChannel: @unchecked Sendable {} +extension LiveViewNativeCore.LiveSocket: @unchecked Sendable {} + +extension LiveViewNativeCore.Events: @unchecked Sendable {} +extension LiveViewNativeCore.ChannelStatuses: @unchecked Sendable {} + +extension LiveViewNativeCore.LiveFile: @unchecked Sendable {} + +extension Node: Identifiable { + public var id: NodeRef { + self.id() + } +} + +extension Channel { + struct EventStream: AsyncSequence { + let events: Events + + init(for channel: Channel) { + self.events = channel.events() + } + + func makeAsyncIterator() -> AsyncIterator { + .init(events: events) + } + + struct AsyncIterator: AsyncIteratorProtocol { + let events: Events + + func next() async throws -> EventPayload? { + try await events.event() + } + } + } + + func eventStream() -> EventStream { + return EventStream(for: self) + } + + final class StatusStream: AsyncSequence { + let statuses: ChannelStatuses + + init(for channel: Channel) { + self.statuses = channel.statuses() + } + + func makeAsyncIterator() -> AsyncIterator { + .init(statuses: statuses) + } + + struct AsyncIterator: AsyncIteratorProtocol { + let statuses: ChannelStatuses + + func next() async throws -> ChannelStatus? { + try await statuses.status() + } + } + } + + func statusStream() -> StatusStream { + StatusStream(for: self) + } +} + +extension Json: Encodable, Decodable { + public func encode(to encoder: any Encoder) throws { + switch self { + case .null: + var container = try encoder.singleValueContainer() + try container.encodeNil() + case .bool(let bool): + var container = try encoder.singleValueContainer() + try container.encode(bool) + case .numb(let number): + var container = try encoder.singleValueContainer() + switch number { + case .posInt(let pos): + try container.encode(pos) + case .negInt(let neg): + try container.encode(neg) + case .float(let float): + try container.encode(float) + } + case .str(let string): + var container = try encoder.singleValueContainer() + try container.encode(string) + case .array(let array): + var container = try encoder.unkeyedContainer() + for element in array { + try container.encode(element) + } + case .object(let object): + var container = try encoder.container(keyedBy: CodingKeys.self) + for (key, value) in object { + try container.encode(value, forKey: .init(stringValue: key)!) + } + } + } + + public init(from decoder: any Decoder) throws { + if var unkeyedContainer = try? decoder.unkeyedContainer() { + var array = [Self]() + while !unkeyedContainer.isAtEnd { + array.append(try unkeyedContainer.decode(Self.self)) + } + self = .array(array: array) + } else if var keyedContainer = try? decoder.container(keyedBy: CodingKeys.self) { + var object = [String:Self]() + for key in keyedContainer.allKeys { + object[key.stringValue] = try keyedContainer.decode(Self.self, forKey: key) + } + self = .object(object: object) + } else { + var container = try decoder.singleValueContainer() + if let bool = try? container.decode(Bool.self) { + self = .bool(bool: bool) + } else if let float = try? container.decode(Double.self) { + self = .numb(number: .float(float: float)) + } else if let int = try? container.decode(UInt64.self) { + self = .numb(number: .posInt(pos: int)) + } else if let int = try? container.decode(Int64.self) { + self = .numb(number: .negInt(neg: int)) + } else if let string = try? container.decode(String.self) { + self = .str(string: string) + } else { + container.decodeNil() + self = .null + } + } + } + + struct CodingKeys: CodingKey { + var stringValue: String + var intValue: Int? + + init?(stringValue: String) { + self.stringValue = stringValue + } + + init?(intValue: Int) { + self.stringValue = String(intValue) + self.intValue = intValue + } + } +} + +// MARK: JSONEncoder + +// Based on `JSONEncoder` from `apple/swift-foundation` +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception + +/// A reference type box that stores a mutable version of `Json`. +final class JsonReference { + private(set) var backing: Backing + + /// Underlying JSON values. + enum Backing { + case null + case bool(bool: Bool) + case numb(number: Number) + case str(string: String) + case array(array: [JsonReference]) + case object(object: [String:JsonReference]) + + /// Convert this node and any children to ``LiveViewNativeCore/Json``. + var jsonValue: Json { + switch self { + case .null: + .null + case .bool(let bool): + .bool(bool: bool) + case .numb(let number): + .numb(number: number) + case .str(let string): + .str(string: string) + case .array(let array): + .array(array: array.map(\.backing.jsonValue)) + case .object(let object): + .object(object: object.mapValues(\.backing.jsonValue)) + } + } + } + + init(_ value: Backing) { + self.backing = value + } + + @inline(__always) + var isObject: Bool { + guard case .object = backing else { return false } + return true + } + + @inline(__always) + var isArray: Bool { + guard case .array = backing else { return false } + return true + } + + /// Add a value to an ``Backing/object``. + @inline(__always) + func insert(_ value: JsonReference, for key: CodingKey) { + guard case .object(var object) = backing else { + preconditionFailure("Wrong Json type") + } + backing = .null + object[key.stringValue] = value + backing = .object(object: object) + } + + /// Insert a value into an ``Backing/array``. + @inline(__always) + func insert(_ value: JsonReference, at index: Int) { + guard case .array(var array) = backing else { + preconditionFailure("Wrong Json type") + } + backing = .null + array.insert(value, at: index) + backing = .array(array: array) + } + + /// Append a value to a ``Backing/array``. + @inline(__always) + func insert(_ value: JsonReference) { + guard case .array(var array) = backing else { + preconditionFailure("Wrong Json type") + } + backing = .null + array.append(value) + backing = .array(array: array) + } + + /// `count` from an ``Backing/array`` or ``Backing/object``. + @inline(__always) + var count: Int { + switch backing { + case .array(let array): return array.count + case .object(let dict): return dict.count + default: preconditionFailure("Count does not apply to \(self)") + } + } + + @inline(__always) + subscript(_ key: CodingKey) -> JsonReference? { + switch backing { + case .object(let dict): + return dict[key.stringValue] + default: + preconditionFailure("Wrong underlying JSON reference type") + } + } + + @inline(__always) + subscript(_ index: Int) -> JsonReference { + switch backing { + case .array(let array): + return array[index] + default: + preconditionFailure("Wrong underlying JSON reference type") + } + } +} + +/// A type that encodes `Encodable` values into ``LiveViewNativeCore/Json``. +open class JsonEncoder { + open var userInfo: [CodingUserInfoKey : Any] { + get { options.userInfo } + set { options.userInfo = newValue } + } + + open var dateEncodingStrategy: JSONEncoder.DateEncodingStrategy { + get { self.options.dateEncodingStrategy } + set { self.options.dateEncodingStrategy = newValue } + } + + open var dataEncodingStrategy: JSONEncoder.DataEncodingStrategy { + get { self.options.dataEncodingStrategy } + set { self.options.dataEncodingStrategy = newValue } + } + + var options = Options() + + struct Options { + var userInfo: [CodingUserInfoKey : Any] = [:] + var dateEncodingStrategy: JSONEncoder.DateEncodingStrategy = .deferredToDate + var dataEncodingStrategy: JSONEncoder.DataEncodingStrategy = .deferredToData + } + + public init() {} + + /// Encode `value` to ``LiveViewNativeCore/Json``. + open func encode(_ value: T) throws -> Json { + let encoder = __JsonEncoder(options: self.options, codingPathDepth: 0) + try value.encode(to: encoder) + return encoder.storage.popReference().backing.jsonValue + } +} + +/// The internal `Encoder` used by ``JsonEncoder``. +private class __JsonEncoder : Encoder { + var storage: _JsonEncodingStorage + + let options: JsonEncoder.Options + + var codingPath: [CodingKey] + + public var userInfo: [CodingUserInfoKey : Any] { + self.options.userInfo + } + + public var dateEncodingStrategy: JSONEncoder.DateEncodingStrategy { + self.options.dateEncodingStrategy + } + + public var dataEncodingStrategy: JSONEncoder.DataEncodingStrategy { + self.options.dataEncodingStrategy + } + + var codingPathDepth: Int = 0 + + init(options: JsonEncoder.Options, codingPath: [CodingKey] = [], codingPathDepth: Int) { + self.options = options + self.storage = _JsonEncodingStorage() + self.codingPath = codingPath + self.codingPathDepth = codingPathDepth + } + + /// Returns whether a new element can be encoded at this coding path. + /// + /// `true` if an element has not yet been encoded at this coding path; `false` otherwise. + var canEncodeNewValue: Bool { + // Every time a new value gets encoded, the key it's encoded for is pushed onto the coding path (even if it's a nil key from an unkeyed container). + // At the same time, every time a container is requested, a new value gets pushed onto the storage stack. + // If there are more values on the storage stack than on the coding path, it means the value is requesting more than one container, which violates the precondition. + // + // This means that anytime something that can request a new container goes onto the stack, we MUST push a key onto the coding path. + // Things which will not request containers do not need to have the coding path extended for them (but it doesn't matter if it is, because they will not reach here). + return self.storage.count == self.codingPathDepth + } + + public func container(keyedBy: Key.Type) -> KeyedEncodingContainer { + let topRef: JsonReference + if self.canEncodeNewValue { + topRef = self.storage.pushKeyedContainer() + } else { + guard let ref = self.storage.refs.last, ref.isObject else { + preconditionFailure("Attempt to push new keyed encoding container when already previously encoded at this path.") + } + topRef = ref + } + + let container = _JsonKeyedEncodingContainer(referencing: self, codingPath: self.codingPath, wrapping: topRef) + return KeyedEncodingContainer(container) + } + + public func unkeyedContainer() -> UnkeyedEncodingContainer { + let topRef: JsonReference + if self.canEncodeNewValue { + topRef = self.storage.pushUnkeyedContainer() + } else { + guard let ref = self.storage.refs.last, ref.isArray else { + preconditionFailure("Attempt to push new unkeyed encoding container when already previously encoded at this path.") + } + topRef = ref + } + + return _JsonUnkeyedEncodingContainer(referencing: self, codingPath: self.codingPath, wrapping: topRef) + } + + public func singleValueContainer() -> SingleValueEncodingContainer { + self + } + + /// Temporarily modifies the Encoder to use a new `[CodingKey]` path while encoding a nested value. + /// + /// The original path/depth is restored after `closure` completes. + @inline(__always) + func with(path: [CodingKey]?, perform closure: () throws -> T) rethrows -> T { + let oldPath = codingPath + let oldDepth = codingPathDepth + + if let path { + self.codingPath = path + self.codingPathDepth = path.count + } + + defer { + if path != nil { + self.codingPath = oldPath + self.codingPathDepth = oldDepth + } + } + + return try closure() + } +} + +/// Storage for a ``__JsonEncoder``. +private struct _JsonEncodingStorage { + var refs = [JsonReference]() + + init() {} + + var count: Int { + return self.refs.count + } + + mutating func pushKeyedContainer() -> JsonReference { + let object = JsonReference(.object(object: [:])) + self.refs.append(object) + return object + } + + mutating func pushUnkeyedContainer() -> JsonReference { + let object = JsonReference(.array(array: [])) + self.refs.append(object) + return object + } + + mutating func push(ref: __owned JsonReference) { + self.refs.append(ref) + } + + mutating func popReference() -> JsonReference { + precondition(!self.refs.isEmpty, "Empty reference stack.") + return self.refs.popLast().unsafelyUnwrapped + } +} + +/// A type-erased ``Swift/CodingKey``. +private struct AnyCodingKey: CodingKey { + var stringValue: String + var intValue: Int? + + init(stringValue: String) { + self.stringValue = stringValue + self.intValue = nil + } + + init(intValue: Int) { + self.stringValue = "\(intValue)" + self.intValue = intValue + } + + init(stringValue: String, intValue: Int?) { + self.stringValue = stringValue + self.intValue = intValue + } + + init(index: Int) { + self.stringValue = "Index \(index)" + self.intValue = index + } +} + +/// Container for encoding an object. +private struct _JsonKeyedEncodingContainer : KeyedEncodingContainerProtocol { + private let encoder: __JsonEncoder + + private let reference: JsonReference + + public var codingPath: [CodingKey] + + init(referencing encoder: __JsonEncoder, codingPath: [CodingKey], wrapping ref: JsonReference) { + self.encoder = encoder + self.codingPath = codingPath + self.reference = ref + } + + public mutating func encodeNil(forKey key: Key) throws { + reference.insert(.init(.null), for: key) + } + public mutating func encode(_ value: Bool, forKey key: Key) throws { + reference.insert(self.encoder.wrap(value), for: key) + } + public mutating func encode(_ value: Int, forKey key: Key) throws { + reference.insert(self.encoder.wrap(value), for: key) + } + public mutating func encode(_ value: Int8, forKey key: Key) throws { + reference.insert(self.encoder.wrap(value), for: key) + } + public mutating func encode(_ value: Int16, forKey key: Key) throws { + reference.insert(self.encoder.wrap(value), for: key) + } + public mutating func encode(_ value: Int32, forKey key: Key) throws { + reference.insert(self.encoder.wrap(value), for: key) + } + public mutating func encode(_ value: Int64, forKey key: Key) throws { + reference.insert(self.encoder.wrap(value), for: key) + } + public mutating func encode(_ value: UInt, forKey key: Key) throws { + reference.insert(self.encoder.wrap(value), for: key) + } + public mutating func encode(_ value: UInt8, forKey key: Key) throws { + reference.insert(self.encoder.wrap(value), for: key) + } + public mutating func encode(_ value: UInt16, forKey key: Key) throws { + reference.insert(self.encoder.wrap(value), for: key) + } + public mutating func encode(_ value: UInt32, forKey key: Key) throws { + reference.insert(self.encoder.wrap(value), for: key) + } + public mutating func encode(_ value: UInt64, forKey key: Key) throws { + reference.insert(self.encoder.wrap(value), for: key) + } + public mutating func encode(_ value: String, forKey key: Key) throws { + reference.insert(self.encoder.wrap(value), for: key) + } + + public mutating func encode(_ value: Float, forKey key: Key) throws { + reference.insert(self.encoder.wrap(value), for: key) + } + + public mutating func encode(_ value: Double, forKey key: Key) throws { + reference.insert(self.encoder.wrap(value), for: key) + } + + public mutating func encode(_ value: T, forKey key: Key) throws { + let wrapped = try self.encoder.wrap(value, for: self.encoder.codingPath, key) + reference.insert(wrapped, for: key) + } + + public mutating func nestedContainer(keyedBy keyType: NestedKey.Type, forKey key: Key) -> KeyedEncodingContainer { + let containerKey = key + let nestedRef: JsonReference + if let existingRef = self.reference[containerKey] { + precondition( + existingRef.isObject, + "Attempt to re-encode into nested KeyedEncodingContainer<\(Key.self)> for key \"\(containerKey)\" is invalid: non-keyed container already encoded for this key" + ) + nestedRef = existingRef + } else { + nestedRef = .init(.object(object: [:])) + self.reference.insert(nestedRef, for: containerKey) + } + + let container = _JsonKeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath + [key], wrapping: nestedRef) + return KeyedEncodingContainer(container) + } + + public mutating func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer { + let containerKey = key + let nestedRef: JsonReference + if let existingRef = self.reference[containerKey] { + precondition( + existingRef.isArray, + "Attempt to re-encode into nested UnkeyedEncodingContainer for key \"\(containerKey)\" is invalid: keyed container/single value already encoded for this key" + ) + nestedRef = existingRef + } else { + nestedRef = .init(.array(array: [])) + self.reference.insert(nestedRef, for: containerKey) + } + + return _JsonUnkeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath + [key], wrapping: nestedRef) + } + + public mutating func superEncoder() -> Encoder { + return __JsonReferencingEncoder(referencing: self.encoder, key: AnyCodingKey(stringValue: "super"), convertedKey: "super", codingPath: self.encoder.codingPath, wrapping: self.reference) + } + + public mutating func superEncoder(forKey key: Key) -> Encoder { + return __JsonReferencingEncoder(referencing: self.encoder, key: key, convertedKey: key.stringValue, codingPath: self.encoder.codingPath, wrapping: self.reference) + } +} + +/// Container for encoding an array. +private struct _JsonUnkeyedEncodingContainer : UnkeyedEncodingContainer { + private let encoder: __JsonEncoder + + private let reference: JsonReference + + var codingPath: [CodingKey] + + public var count: Int { + self.reference.count + } + + init(referencing encoder: __JsonEncoder, codingPath: [CodingKey], wrapping ref: JsonReference) { + self.encoder = encoder + self.codingPath = codingPath + self.reference = ref + } + + public mutating func encodeNil() throws { self.reference.insert(.init(.null)) } + public mutating func encode(_ value: Bool) throws { self.reference.insert(self.encoder.wrap(value)) } + public mutating func encode(_ value: Int) throws { self.reference.insert(self.encoder.wrap(value)) } + public mutating func encode(_ value: Int8) throws { self.reference.insert(self.encoder.wrap(value)) } + public mutating func encode(_ value: Int16) throws { self.reference.insert(self.encoder.wrap(value)) } + public mutating func encode(_ value: Int32) throws { self.reference.insert(self.encoder.wrap(value)) } + public mutating func encode(_ value: Int64) throws { self.reference.insert(self.encoder.wrap(value)) } + public mutating func encode(_ value: UInt) throws { self.reference.insert(self.encoder.wrap(value)) } + public mutating func encode(_ value: UInt8) throws { self.reference.insert(self.encoder.wrap(value)) } + public mutating func encode(_ value: UInt16) throws { self.reference.insert(self.encoder.wrap(value)) } + public mutating func encode(_ value: UInt32) throws { self.reference.insert(self.encoder.wrap(value)) } + public mutating func encode(_ value: UInt64) throws { self.reference.insert(self.encoder.wrap(value)) } + public mutating func encode(_ value: String) throws { self.reference.insert(self.encoder.wrap(value)) } + public mutating func encode(_ value: Float) throws { self.reference.insert(self.encoder.wrap(value)) } + public mutating func encode(_ value: Double) throws { self.reference.insert(self.encoder.wrap(value)) } + + public mutating func encode(_ value: T) throws { + let wrapped = try self.encoder.wrap(value, for: self.encoder.codingPath, AnyCodingKey(stringValue: "Index \(self.count)", intValue: self.count)) + self.reference.insert(wrapped) + } + + public mutating func nestedContainer(keyedBy keyType: NestedKey.Type) -> KeyedEncodingContainer { + let key = AnyCodingKey(index: self.count) + let nestedRef = JsonReference(.object(object: [:])) + self.reference.insert(nestedRef) + let container = _JsonKeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath + [key], wrapping: nestedRef) + return KeyedEncodingContainer(container) + } + + public mutating func nestedUnkeyedContainer() -> UnkeyedEncodingContainer { + let key = AnyCodingKey(index: self.count) + let nestedRef = JsonReference(.array(array: [])) + self.reference.insert(nestedRef) + return _JsonUnkeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath + [key], wrapping: nestedRef) + } + + public mutating func superEncoder() -> Encoder { + return __JsonReferencingEncoder(referencing: self.encoder, at: self.reference.count, codingPath: self.encoder.codingPath, wrapping: self.reference) + } +} + +/// Container for encoding a single value. +extension __JsonEncoder : SingleValueEncodingContainer { + private func assertCanEncodeNewValue() { + precondition(self.canEncodeNewValue, "Attempt to encode value through single value container when previously value already encoded.") + } + + public func encodeNil() throws { + assertCanEncodeNewValue() + self.storage.push(ref: .init(.null)) + } + + public func encode(_ value: Bool) throws { + assertCanEncodeNewValue() + self.storage.push(ref: wrap(value)) + } + + public func encode(_ value: Int) throws { + assertCanEncodeNewValue() + self.storage.push(ref: wrap(value)) + } + + public func encode(_ value: Int8) throws { + assertCanEncodeNewValue() + self.storage.push(ref: wrap(value)) + } + + public func encode(_ value: Int16) throws { + assertCanEncodeNewValue() + self.storage.push(ref: wrap(value)) + } + + public func encode(_ value: Int32) throws { + assertCanEncodeNewValue() + self.storage.push(ref: wrap(value)) + } + + public func encode(_ value: Int64) throws { + assertCanEncodeNewValue() + self.storage.push(ref: wrap(value)) + } + + public func encode(_ value: UInt) throws { + assertCanEncodeNewValue() + self.storage.push(ref: wrap(value)) + } + + public func encode(_ value: UInt8) throws { + assertCanEncodeNewValue() + self.storage.push(ref: wrap(value)) + } + + public func encode(_ value: UInt16) throws { + assertCanEncodeNewValue() + self.storage.push(ref: wrap(value)) + } + + public func encode(_ value: UInt32) throws { + assertCanEncodeNewValue() + self.storage.push(ref: wrap(value)) + } + + public func encode(_ value: UInt64) throws { + assertCanEncodeNewValue() + self.storage.push(ref: wrap(value)) + } + + public func encode(_ value: String) throws { + assertCanEncodeNewValue() + self.storage.push(ref: wrap(value)) + } + + public func encode(_ value: Float) throws { + assertCanEncodeNewValue() + let wrapped = try self.wrap(value) + self.storage.push(ref: wrapped) + } + + public func encode(_ value: Double) throws { + assertCanEncodeNewValue() + let wrapped = try self.wrap(value) + self.storage.push(ref: wrapped) + } + + public func encode(_ value: T) throws { + assertCanEncodeNewValue() + try self.storage.push(ref: self.wrap(value, for: self.codingPath)) + } +} + +/// Extensions for converting a value into a ``JsonReference``. +private extension __JsonEncoder { + @inline(__always) func wrap(_ value: Bool) -> JsonReference { .init(.bool(bool: value)) } + @inline(__always) func wrap(_ value: Int) -> JsonReference { + if value >= 0 { + .init(.numb(number: .posInt(pos: UInt64(value)))) + } else { + .init(.numb(number: .negInt(neg: Int64(value)))) + } + } + @inline(__always) func wrap(_ value: Int8) -> JsonReference { + if value >= 0 { + .init(.numb(number: .posInt(pos: UInt64(value)))) + } else { + .init(.numb(number: .negInt(neg: Int64(value)))) + } + } + @inline(__always) func wrap(_ value: Int16) -> JsonReference { + if value >= 0 { + .init(.numb(number: .posInt(pos: UInt64(value)))) + } else { + .init(.numb(number: .negInt(neg: Int64(value)))) + } + } + @inline(__always) func wrap(_ value: Int32) -> JsonReference { + if value >= 0 { + .init(.numb(number: .posInt(pos: UInt64(value)))) + } else { + .init(.numb(number: .negInt(neg: Int64(value)))) + } + } + @inline(__always) func wrap(_ value: Int64) -> JsonReference { + if value >= 0 { + .init(.numb(number: .posInt(pos: UInt64(value)))) + } else { + .init(.numb(number: .negInt(neg: Int64(value)))) + } + } + @inline(__always) func wrap(_ value: UInt) -> JsonReference { .init(.numb(number: .posInt(pos: UInt64(value)))) } + @inline(__always) func wrap(_ value: UInt8) -> JsonReference { .init(.numb(number: .posInt(pos: UInt64(value)))) } + @inline(__always) func wrap(_ value: UInt16) -> JsonReference { .init(.numb(number: .posInt(pos: UInt64(value)))) } + @inline(__always) func wrap(_ value: UInt32) -> JsonReference { .init(.numb(number: .posInt(pos: UInt64(value)))) } + @inline(__always) func wrap(_ value: UInt64) -> JsonReference { .init(.numb(number: .posInt(pos: UInt64(value)))) } + @inline(__always) func wrap(_ value: String) -> JsonReference { .init(.str(string: value)) } + + @inline(__always) func wrap(_ float: Float) -> JsonReference { .init(.numb(number: .float(float: Double(float)))) } + + @inline(__always) func wrap(_ double: Double) -> JsonReference { .init(.numb(number: .float(float: double))) } + + func wrap(_ date: Date, for codingPath: [CodingKey], _ additionalKey: (some CodingKey)? = AnyCodingKey?.none) throws -> JsonReference { + switch self.options.dateEncodingStrategy { + case .deferredToDate: + try with(path: codingPath + (additionalKey.map({ [$0] }) ?? [])) { + try date.encode(to: self) + } + return self.storage.popReference() + case .secondsSince1970: + return self.wrap(date.timeIntervalSince1970) + case .millisecondsSince1970: + return self.wrap(1000.0 * date.timeIntervalSince1970) + case .iso8601: + return self.wrap(date.formatted(.iso8601)) + case .formatted(let formatter): + return self.wrap(formatter.string(from: date)) + case .custom(let closure): + let depth = self.storage.count + do { + try with(path: codingPath + (additionalKey.map({ [$0] }) ?? [])) { + try closure(date, self) + } + } catch { + // If the value pushed a container before throwing, pop it back off to restore state. + if self.storage.count > depth { + let _ = self.storage.popReference() + } + + throw error + } + + guard self.storage.count > depth else { + // The closure didn't encode anything. Return the default keyed container. + return .init(.object(object: [:])) + } + + // We can pop because the closure encoded something. + return self.storage.popReference() + @unknown default: + try with(path: codingPath + (additionalKey.map({ [$0] }) ?? [])) { + try date.encode(to: self) + } + return self.storage.popReference() + } + } + + func wrap(_ data: Data, for codingPath: [CodingKey], _ additionalKey: (some CodingKey)? = AnyCodingKey?.none) throws -> JsonReference { + switch self.options.dataEncodingStrategy { + case .deferredToData: + let depth = self.storage.count + do { + try with(path: codingPath + (additionalKey.map({ [$0] }) ?? [])) { + try data.encode(to: self) + } + } catch { + // If the value pushed a container before throwing, pop it back off to restore state. + // This shouldn't be possible for Data (which encodes as an array of bytes), but it can't hurt to catch a failure. + if self.storage.count > depth { + let _ = self.storage.popReference() + } + + throw error + } + + return self.storage.popReference() + + case .base64: + return self.wrap(data.base64EncodedString()) + + case .custom(let closure): + let depth = self.storage.count + do { + try with(path: codingPath + (additionalKey.map({ [$0] }) ?? [])) { + try closure(data, self) + } + } catch { + // If the value pushed a container before throwing, pop it back off to restore state. + if self.storage.count > depth { + let _ = self.storage.popReference() + } + + throw error + } + + guard self.storage.count > depth else { + // The closure didn't encode anything. Return the default keyed container. + return .init(.object(object: [:])) + } + + // We can pop because the closure encoded something. + return self.storage.popReference() + @unknown default: + let depth = self.storage.count + do { + try with(path: codingPath + (additionalKey.map({ [$0] }) ?? [])) { + try data.encode(to: self) + } + } catch { + // If the value pushed a container before throwing, pop it back off to restore state. + // This shouldn't be possible for Data (which encodes as an array of bytes), but it can't hurt to catch a failure. + if self.storage.count > depth { + let _ = self.storage.popReference() + } + + throw error + } + + return self.storage.popReference() + } + } + + func wrap(_ dict: [String : Encodable], for codingPath: [CodingKey], _ additionalKey: (some CodingKey)? = AnyCodingKey?.none) throws -> JsonReference? { + let depth = self.storage.count + let result = self.storage.pushKeyedContainer() + let rootPath = codingPath + (additionalKey.flatMap({ [$0] }) ?? []) + do { + for (key, value) in dict { + result.insert(try wrap(value, for: rootPath, AnyCodingKey(stringValue: key)), for: AnyCodingKey(stringValue: key)) + } + } catch { + // If the value pushed a container before throwing, pop it back off to restore state. + if self.storage.count > depth { + let _ = self.storage.popReference() + } + + throw error + } + + // The top container should be a new container. + guard self.storage.count > depth else { + return nil + } + + return self.storage.popReference() + } + + func wrap(_ value: Encodable, for codingPath: [CodingKey], _ additionalKey: (some CodingKey)? = AnyCodingKey?.none) throws -> JsonReference { + return try self.wrapGeneric(value, for: codingPath, additionalKey) ?? .init(.object(object: [:])) + } + + func wrapGeneric(_ value: T, for codingPath: [CodingKey], _ additionalKey: (some CodingKey)? = AnyCodingKey?.none) throws -> JsonReference? { + switch T.self { + case is Date.Type: + return try self.wrap(value as! Date, for: codingPath, additionalKey) + case is Data.Type: + return try self.wrap(value as! Data, for: codingPath, additionalKey) + case is URL.Type: + let url = value as! URL + return self.wrap(url.absoluteString) + case is Decimal.Type: + let decimal = value as! Decimal + return self.wrap(Double(truncating: decimal as NSDecimalNumber)) + case is _JsonStringDictionaryEncodableMarker.Type: + return try self.wrap(value as! [String:Encodable], for: codingPath, additionalKey) + default: + break + } + + return try _wrapGeneric({ + try value.encode(to: $0) + }, for: codingPath, additionalKey) + } + + func _wrapGeneric(_ encode: (__JsonEncoder) throws -> (), for codingPath: [CodingKey], _ additionalKey: (some CodingKey)? = AnyCodingKey?.none) throws -> JsonReference? { + // The value should request a container from the __JSONEncoder. + let depth = self.storage.count + do { + try self.with(path: codingPath + (additionalKey.flatMap({ [$0] }) ?? [])) { + try encode(self) + } + } catch { + // If the value pushed a container before throwing, pop it back off to restore state. + if self.storage.count > depth { + let _ = self.storage.popReference() + } + + throw error + } + + // The top container should be a new container. + guard self.storage.count > depth else { + return nil + } + + return self.storage.popReference() + } +} + +/// Type that references a `superEncoder`. +private class __JsonReferencingEncoder : __JsonEncoder { + /// The referenced container + private enum Reference { + case array(JsonReference, Int) + case dictionary(JsonReference, String) + } + + let encoder: __JsonEncoder + + private let reference: Reference + + init(referencing encoder: __JsonEncoder, at index: Int, codingPath: [CodingKey], wrapping ref: JsonReference) { + self.encoder = encoder + self.reference = .array(ref, index) + super.init(options: encoder.options, codingPath: codingPath + [AnyCodingKey(index: index)], codingPathDepth: codingPath.count + 1) + } + + init(referencing encoder: __JsonEncoder, key: CodingKey, convertedKey: String, codingPath: [CodingKey], wrapping dictionary: JsonReference) { + self.encoder = encoder + self.reference = .dictionary(dictionary, convertedKey) + super.init(options: encoder.options, codingPath: codingPath + [key], codingPathDepth: codingPath.count + 1) + } + + override var canEncodeNewValue: Bool { + self.storage.count == self.codingPath.count - self.encoder.codingPath.count - 1 + } + + // Merge this storage into the referenced container. + deinit { + let ref: JsonReference + switch self.storage.count { + case 0: ref = .init(.object(object: [:])) + case 1: ref = self.storage.popReference() + default: fatalError("Referencing encoder deallocated with multiple containers on stack.") + } + + switch self.reference { + case .array(let arrayRef, let index): + arrayRef.insert(ref, at: index) + case .dictionary(let dictionaryRef, let key): + dictionaryRef.insert(ref, for: AnyCodingKey(stringValue: key)) + } + } +} + +extension JsonEncoder : @unchecked Sendable {} + +/// Protocol that references a `[String:Encodable]` dictionary, to avoid converting string keys. +private protocol _JsonStringDictionaryEncodableMarker { } + +extension Dictionary : _JsonStringDictionaryEncodableMarker where Key == String, Value: Encodable { } + + +// MARK: JsonDecoder + +/// A type that decodes `Json` to a `Decodable` type. +open class JsonDecoder { + open var userInfo: [CodingUserInfoKey : Any] { + get { options.userInfo } + set { options.userInfo = newValue } + } + + open var dateEncodingStrategy: JSONDecoder.DateDecodingStrategy { + get { self.options.dateDecodingStrategy } + set { self.options.dateDecodingStrategy = newValue } + } + + open var dataEncodingStrategy: JSONDecoder.DataDecodingStrategy { + get { self.options.dataDecodingStrategy } + set { self.options.dataDecodingStrategy = newValue } + } + + var options = Options() + + struct Options { + var userInfo: [CodingUserInfoKey : Any] = [:] + var dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .deferredToDate + var dataDecodingStrategy: JSONDecoder.DataDecodingStrategy = .deferredToData + } + + public init() {} + + open func decode(_ type: T.Type, from json: Json) throws -> T { + let decoder = __JsonDecoder(userInfo: userInfo, from: json, codingPath: [], options: self.options) + return try type.init(from: decoder) + } +} + +final class __JsonDecoder: Decoder { + var values: [Json] + + var json: Json { + values.last! + } + + let userInfo: [CodingUserInfoKey:Any] + let options: JsonDecoder.Options + + public var codingPath: [CodingKey] + + init(userInfo: [CodingUserInfoKey:Any], from json: Json, codingPath: [CodingKey], options: JsonDecoder.Options) { + self.userInfo = userInfo + self.codingPath = codingPath + self.values = [json] + self.options = options + } + + func container(keyedBy type: Key.Type) throws -> KeyedDecodingContainer where Key : CodingKey { + switch json { + case let .object(object): + return KeyedDecodingContainer(KeyedContainer(decoder: self, for: object, codingPath: codingPath)) + case .null: + throw DecodingError.valueNotFound( + [String:Json].self, + .init( + codingPath: codingPath, + debugDescription: "Cannot get keyed decoding container -- found null value instead" + ) + ) + default: + throw DecodingError.makeTypeMismatchError( + type: [String:Json].self, + for: codingPath, + value: json + ) + } + } + + func unkeyedContainer() throws -> any UnkeyedDecodingContainer { + switch json { + case let .array(array): + return UnkeyedContainer(decoder: self, for: array, codingPath: codingPath) + case .null: + throw DecodingError.valueNotFound( + [String:Json].self, + .init( + codingPath: codingPath, + debugDescription: "Cannot get unkeyed decoding container -- found null value instead" + ) + ) + default: + throw DecodingError.makeTypeMismatchError( + type: [Json].self, + for: codingPath, + value: json + ) + } + } + + func singleValueContainer() throws -> any SingleValueDecodingContainer { + self + } +} + +extension __JsonDecoder: SingleValueDecodingContainer { + func decodeNil() -> Bool { + switch json { + case .null: + true + default: + false + } + } + + func decode(_ type: Bool.Type) throws -> Bool { + guard case let .bool(bool) = json else { + throw DecodingError.makeTypeMismatchError(type: type, for: codingPath, value: json) + } + return bool + } + + func decode(_ type: String.Type) throws -> String { + guard case let .str(string) = json else { + throw DecodingError.makeTypeMismatchError(type: type, for: codingPath, value: json) + } + return string + } + + func decode(_ type: Double.Type) throws -> Double { + guard case let .numb(.float(float)) = json else { + throw DecodingError.makeTypeMismatchError(type: type, for: codingPath, value: json) + } + return float + } + + func decode(_ type: Float.Type) throws -> Float { + guard case let .numb(.float(float)) = json else { + throw DecodingError.makeTypeMismatchError(type: type, for: codingPath, value: json) + } + return Float(float) + } + + func decode(_ type: Int.Type) throws -> Int { + guard case let .numb(number) = json else { + throw DecodingError.makeTypeMismatchError(type: type, for: codingPath, value: json) + } + switch number { + case .posInt(let pos): + return Int(pos) + case .negInt(let neg): + return Int(neg) + case .float: + throw DecodingError.makeTypeMismatchError(type: type, for: codingPath, value: json) + } + } + + func decode(_ type: Int8.Type) throws -> Int8 { + Int8(try decode(Int.self)) + } + + func decode(_ type: Int16.Type) throws -> Int16 { + Int16(try decode(Int.self)) + } + + func decode(_ type: Int32.Type) throws -> Int32 { + Int32(try decode(Int.self)) + } + + func decode(_ type: Int64.Type) throws -> Int64 { + Int64(try decode(Int.self)) + } + + func decode(_ type: UInt.Type) throws -> UInt { + guard case let .numb(.posInt(pos)) = json else { + throw DecodingError.makeTypeMismatchError(type: type, for: codingPath, value: json) + } + return UInt(pos) + } + + func decode(_ type: UInt8.Type) throws -> UInt8 { + UInt8(try decode(UInt.self)) + } + + func decode(_ type: UInt16.Type) throws -> UInt16 { + UInt16(try decode(UInt.self)) + } + + func decode(_ type: UInt32.Type) throws -> UInt32 { + UInt32(try decode(UInt.self)) + } + + func decode(_ type: UInt64.Type) throws -> UInt64 { + UInt64(try decode(UInt.self)) + } + + func decode(_ type: T.Type) throws -> T where T : Decodable { + try self.unwrap(json, as: type, for: codingPath) + } +} + +extension __JsonDecoder { + @inline(__always) + func with(value: Json, path: [CodingKey]?, perform closure: () throws -> T) rethrows -> T { + let oldPath = self.codingPath + if let path { + self.codingPath = path + } + self.values.append(value) + + defer { + if path != nil { + self.codingPath = oldPath + } + self.values.removeLast() + } + + return try closure() + } + + func unwrap(_ value: Json, as type: T.Type, for codingPath: [CodingKey], _ additionalKey: (some CodingKey)? = AnyCodingKey?.none) throws -> T { + if type == Date.self { + return try self.unwrapDate(from: value, for: codingPath, additionalKey) as! T + } + if type == Data.self { + return try self.unwrapData(from: value, for: codingPath, additionalKey) as! T + } + if type == URL.self { + return try self.unwrapURL(from: value, for: codingPath, additionalKey) as! T + } + if type == Decimal.self { + return Decimal(try self.unwrap(value, as: Double.self, for: codingPath, additionalKey)) as! T + } + + return try with(value: value, path: codingPath) { + try type.init(from: self) + } + } + + func unwrapDate(from value: Json, for codingPath: [CodingKey], _ additionalKey: K? = nil) throws -> Date { + switch self.options.dateDecodingStrategy { + case .deferredToDate: + return try with(value: value, path: codingPath + (additionalKey.map({ [$0] }) ?? [])) { + try Date(from: self) + } + case .secondsSince1970: + let double = try self.unwrap(value, as: Double.self, for: codingPath, additionalKey) + return Date(timeIntervalSince1970: double) + case .millisecondsSince1970: + let double = try self.unwrap(value, as: Double.self, for: codingPath, additionalKey) + return Date(timeIntervalSince1970: double / 1000.0) + case .iso8601: + let string = try self.unwrap(value, as: String.self, for: codingPath, additionalKey) + guard let date = try? Date.ISO8601FormatStyle().parse(string) + else { + throw DecodingError.dataCorrupted(.init( + codingPath: codingPath, + debugDescription: "Expected date string to be ISO8601-formatted." + )) + } + return date + case .formatted(let formatter): + let string = try self.unwrap(value, as: String.self, for: codingPath, additionalKey) + guard let date = formatter.date(from: string) + else { + throw DecodingError.dataCorrupted(.init( + codingPath: codingPath + (additionalKey.map({ [$0] }) ?? []), + debugDescription: "Date string does not match format expected by formatter." + )) + } + return date + case .custom(let closure): + return try with(value: value, path: codingPath + (additionalKey.map({ [$0] }) ?? [])) { + try closure(self) + } + @unknown default: + return try with(value: value, path: codingPath + (additionalKey.map({ [$0] }) ?? [])) { + try Date(from: self) + } + } + } + + func unwrapData(from value: Json, for codingPath: [CodingKey], _ additionalKey: K? = nil) throws -> Data { + switch self.options.dataDecodingStrategy { + case .deferredToData: + return try with(value: value, path: codingPath + (additionalKey.map({ [$0] }) ?? [])) { + try Data(from: self) + } + case .base64: + let string = try self.unwrap(value, as: String.self, for: codingPath, additionalKey) + guard let data = Data(base64Encoded: string) + else { + throw DecodingError.dataCorrupted(.init( + codingPath: codingPath + (additionalKey.map({ [$0] }) ?? []), + debugDescription: "Encountered Data is not valid Base64." + )) + } + return data + case .custom(let closure): + return try with(value: value, path: codingPath + (additionalKey.map({ [$0] }) ?? [])) { + try closure(self) + } + @unknown default: + return try with(value: value, path: codingPath + (additionalKey.map({ [$0] }) ?? [])) { + try Data(from: self) + } + } + } + + func unwrapURL(from value: Json, for codingPath: [CodingKey], _ additionalKey: K? = nil) throws -> URL { + let string = try self.unwrap(value, as: String.self, for: codingPath, additionalKey) + guard let url = URL(string: string) + else { + throw DecodingError.dataCorrupted(.init( + codingPath: codingPath + (additionalKey.map({ [$0] }) ?? []), + debugDescription: "Invalid URL string." + )) + } + return url + } +} + +extension __JsonDecoder { + struct KeyedContainer: KeyedDecodingContainerProtocol { + let decoder: __JsonDecoder + let object: [String:Json] + var allKeys: [Key] { + object.keys.compactMap(Key.init(stringValue:)) + } + var codingPath: [any CodingKey] + + init( + decoder: __JsonDecoder, + for object: [String:Json], + codingPath: [any CodingKey] + ) { + self.decoder = decoder + self.object = object + self.codingPath = codingPath + } + + @inline(__always) + func value(forKey key: some CodingKey) throws -> Json { + guard let value = object[key.stringValue] + else { + throw DecodingError.keyNotFound( + key, + .init(codingPath: codingPath, debugDescription: #"No value associated with key \#(key) ("\#(key.stringValue)")"#) + ) + } + return value + } + + func contains(_ key: Key) -> Bool { + object.keys.contains(key.stringValue) + } + + func decodeNil(forKey key: Key) throws -> Bool { + guard case .null = try value(forKey: key) + else { return false } + return true + } + + func decode(_ type: Bool.Type, forKey key: Key) throws -> Bool { + let value = try value(forKey: key) + guard case let .bool(bool) = value + else { throw DecodingError.makeTypeMismatchError(type: type, for: codingPath, value: value) } + return bool + } + + func decode(_ type: String.Type, forKey key: Key) throws -> String { + let value = try value(forKey: key) + guard case let .str(string) = value + else { throw DecodingError.makeTypeMismatchError(type: type, for: codingPath, value: value) } + return string + } + + func decode(_ type: Double.Type, forKey key: Key) throws -> Double { + let value = try value(forKey: key) + guard case let .numb(.float(float)) = value + else { throw DecodingError.makeTypeMismatchError(type: type, for: codingPath, value: value) } + return float + } + + func decode(_ type: Float.Type, forKey key: Key) throws -> Float { + let value = try value(forKey: key) + guard case let .numb(.float(float)) = value + else { throw DecodingError.makeTypeMismatchError(type: type, for: codingPath, value: value) } + return Float(float) + } + + func decode(_ type: Int.Type, forKey key: Key) throws -> Int { + let value = try value(forKey: key) + if case let .numb(.posInt(pos)) = value { + return Int(pos) + } else if case let .numb(.negInt(neg)) = value { + return Int(neg) + } else { + throw DecodingError.makeTypeMismatchError(type: type, for: codingPath, value: value) + } + } + + func decode(_ type: Int8.Type, forKey key: Key) throws -> Int8 { + let value = try value(forKey: key) + if case let .numb(.posInt(pos)) = value { + return Int8(pos) + } else if case let .numb(.negInt(neg)) = value { + return Int8(neg) + } else { + throw DecodingError.makeTypeMismatchError(type: type, for: codingPath, value: value) + } + } + + func decode(_ type: Int16.Type, forKey key: Key) throws -> Int16 { + let value = try value(forKey: key) + if case let .numb(.posInt(pos)) = value { + return Int16(pos) + } else if case let .numb(.negInt(neg)) = value { + return Int16(neg) + } else { + throw DecodingError.makeTypeMismatchError(type: type, for: codingPath, value: value) + } + } + + func decode(_ type: Int32.Type, forKey key: Key) throws -> Int32 { + let value = try value(forKey: key) + if case let .numb(.posInt(pos)) = value { + return Int32(pos) + } else if case let .numb(.negInt(neg)) = value { + return Int32(neg) + } else { + throw DecodingError.makeTypeMismatchError(type: type, for: codingPath, value: value) + } + } + + func decode(_ type: Int64.Type, forKey key: Key) throws -> Int64 { + let value = try value(forKey: key) + if case let .numb(.posInt(pos)) = value { + return Int64(pos) + } else if case let .numb(.negInt(neg)) = value { + return Int64(neg) + } else { + throw DecodingError.makeTypeMismatchError(type: type, for: codingPath, value: value) + } + } + + func decode(_ type: UInt.Type, forKey key: Key) throws -> UInt { + let value = try value(forKey: key) + guard case let .numb(.posInt(int)) = value + else { throw DecodingError.makeTypeMismatchError(type: type, for: codingPath, value: value) } + return UInt(int) + } + + func decode(_ type: UInt8.Type, forKey key: Key) throws -> UInt8 { + let value = try value(forKey: key) + guard case let .numb(.posInt(int)) = value + else { throw DecodingError.makeTypeMismatchError(type: type, for: codingPath, value: value) } + return UInt8(int) + } + + func decode(_ type: UInt16.Type, forKey key: Key) throws -> UInt16 { + let value = try value(forKey: key) + guard case let .numb(.posInt(int)) = value + else { throw DecodingError.makeTypeMismatchError(type: type, for: codingPath, value: value) } + return UInt16(int) + } + + func decode(_ type: UInt32.Type, forKey key: Key) throws -> UInt32 { + let value = try value(forKey: key) + guard case let .numb(.posInt(int)) = value + else { throw DecodingError.makeTypeMismatchError(type: type, for: codingPath, value: value) } + return UInt32(int) + } + + func decode(_ type: UInt64.Type, forKey key: Key) throws -> UInt64 { + let value = try value(forKey: key) + guard case let .numb(.posInt(int)) = value + else { throw DecodingError.makeTypeMismatchError(type: type, for: codingPath, value: value) } + return UInt64(int) + } + + func decode(_ type: T.Type, forKey key: Key) throws -> T where T : Decodable { + try self.decoder.unwrap(try value(forKey: key), as: type, for: codingPath, key) + } + + func nestedContainer(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer where NestedKey : CodingKey { + let value = try value(forKey: key) + return try decoder.with(value: value, path: codingPath + [key]) { + try decoder.container(keyedBy: type) + } + } + + func nestedUnkeyedContainer(forKey key: Key) throws -> any UnkeyedDecodingContainer { + let value = try value(forKey: key) + return try decoder.with(value: value, path: codingPath + [key]) { + try decoder.unkeyedContainer() + } + } + + func superDecoder() throws -> any Decoder { + let value = (try? value(forKey: AnyCodingKey(stringValue: "super"))) ?? .null + let decoder = __JsonDecoder(userInfo: self.decoder.userInfo, from: self.decoder.values.first!, codingPath: codingPath + [AnyCodingKey(stringValue: "super")], options: self.decoder.options) + decoder.values.append(value) + return decoder + } + + func superDecoder(forKey key: Key) throws -> any Decoder { + let value = (try? value(forKey: key)) ?? .null + let decoder = __JsonDecoder(userInfo: self.decoder.userInfo, from: self.decoder.values.first!, codingPath: codingPath + [key], options: self.decoder.options) + decoder.values.append(value) + return decoder + } + } +} + +extension __JsonDecoder { + struct UnkeyedContainer: UnkeyedDecodingContainer { + let decoder: __JsonDecoder + private var iterator: Array.Iterator + private var peekedValue: Json? + + let count: Int? + var currentIndex: Int = 0 + var isAtEnd: Bool { + self.currentIndex >= self.count! + } + + var codingPath: [any CodingKey] + + @inline(__always) + private var currentIndexKey: AnyCodingKey { + .init(index: currentIndex) + } + + @inline(__always) + private var currentCodingPath: [any CodingKey] { + codingPath + [currentIndexKey] + } + + init( + decoder: __JsonDecoder, + for array: [Json], + codingPath: [CodingKey] + ) { + self.decoder = decoder + self.iterator = array.makeIterator() + self.count = array.count + self.codingPath = codingPath + } + + @inline(__always) + mutating func peek(_ type: T.Type) throws -> Json { + if let value = peekedValue { + return value + } + guard let nextValue = iterator.next() + else { + var message = "Unkeyed container is at end." + if T.self == UnkeyedContainer.self { + message = "Cannot get nested unkeyed container -- unkeyed container is at end." + } + if T.self == Decoder.self { + message = "Cannot get superDecoder() -- unkeyed container is at end." + } + + throw DecodingError.valueNotFound( + type, + .init( + codingPath: currentCodingPath, + debugDescription: message + ) + ) + } + peekedValue = nextValue + return nextValue + } + + mutating func advance() { + currentIndex += 1 + peekedValue = nil + } + + mutating func decodeNil() throws -> Bool { + let value = try self.peek(Never.self) + switch value { + case .null: + advance() + return true + default: + return false + } + } + + mutating func decode(_ type: Bool.Type) throws -> Bool { + let value = try peek(type) + guard case .bool(let bool) = value else { + throw DecodingError.makeTypeMismatchError(type: type, for: currentCodingPath, value: value) + } + advance() + return bool + } + + mutating func decode(_ type: String.Type) throws -> String { + let value = try peek(type) + guard case .str(let string) = value else { + throw DecodingError.makeTypeMismatchError(type: type, for: currentCodingPath, value: value) + } + advance() + return string + } + + mutating func decode(_ type: Double.Type) throws -> Double { + let value = try peek(type) + guard case let .numb(.float(float)) = value else { + throw DecodingError.makeTypeMismatchError(type: type, for: currentCodingPath, value: value) + } + advance() + return float + } + + mutating func decode(_ type: Float.Type) throws -> Float { + let value = try peek(type) + guard case let .numb(.float(float)) = value else { + throw DecodingError.makeTypeMismatchError(type: type, for: currentCodingPath, value: value) + } + advance() + return Float(float) + } + + mutating func decode(_ type: Int.Type) throws -> Int { + let value = try peek(type) + guard case let .numb(number) = value else { + throw DecodingError.makeTypeMismatchError(type: type, for: currentCodingPath, value: value) + } + switch number { + case .posInt(let pos): + advance() + return Int(pos) + case .negInt(let neg): + advance() + return Int(neg) + case .float: + throw DecodingError.makeTypeMismatchError(type: type, for: currentCodingPath, value: value) + } + } + + mutating func decode(_ type: Int8.Type) throws -> Int8 { + return try type.init(decode(Int.self)) + } + + mutating func decode(_ type: Int16.Type) throws -> Int16 { + return try type.init(decode(Int.self)) + } + + mutating func decode(_ type: Int32.Type) throws -> Int32 { + return try type.init(decode(Int.self)) + } + + mutating func decode(_ type: Int64.Type) throws -> Int64 { + return try type.init(decode(Int.self)) + } + + mutating func decode(_ type: UInt.Type) throws -> UInt { + let value = try peek(type) + guard case let .numb(number) = value else { + throw DecodingError.makeTypeMismatchError(type: type, for: currentCodingPath, value: value) + } + switch number { + case .posInt(let pos): + advance() + return UInt(pos) + default: + throw DecodingError.makeTypeMismatchError(type: type, for: currentCodingPath, value: value) + } + } + + mutating func decode(_ type: UInt8.Type) throws -> UInt8 { + return try type.init(decode(UInt.self)) + } + + mutating func decode(_ type: UInt16.Type) throws -> UInt16 { + return try type.init(decode(UInt.self)) + } + + mutating func decode(_ type: UInt32.Type) throws -> UInt32 { + return try type.init(decode(UInt.self)) + } + + mutating func decode(_ type: UInt64.Type) throws -> UInt64 { + return try type.init(decode(UInt.self)) + } + + mutating func decode(_ type: T.Type) throws -> T where T : Decodable { + let value = try peek(type) + let result = try decoder.unwrap(value, as: type, for: codingPath, currentIndexKey) + + advance() + return result + } + + mutating func nestedContainer(keyedBy type: NestedKey.Type) throws -> KeyedDecodingContainer where NestedKey : CodingKey { + let value = try peek(KeyedDecodingContainer.self) + let container = try decoder.with(value: value, path: currentCodingPath) { + try decoder.container(keyedBy: type) + } + advance() + return container + } + + mutating func nestedUnkeyedContainer() throws -> any UnkeyedDecodingContainer { + let value = try peek(UnkeyedDecodingContainer.self) + let container = try decoder.with(value: value, path: currentCodingPath) { + try decoder.unkeyedContainer() + } + advance() + return container + } + + mutating func superDecoder() throws -> any Decoder { + let value = try peek(Decoder.self) + + let decoder = __JsonDecoder( + userInfo: decoder.userInfo, + from: decoder.values.first!, + codingPath: currentCodingPath, + options: decoder.options + ) + + decoder.values.append(value) + + advance() + return decoder + } + } +} + +private extension DecodingError { + static func makeTypeMismatchError(type: Any.Type, for path: [CodingKey], value: Json) -> DecodingError { + return DecodingError.typeMismatch( + type, + .init( + codingPath: path, + debugDescription: "Expected to decode \(type) but found \(value) instead." + ) + ) + } +} diff --git a/Sources/LiveViewNativeStylesheet/ModifierParseError.swift b/Sources/LiveViewNativeStylesheet/ModifierParseError.swift index 0e8c5b12f..e31becf24 100644 --- a/Sources/LiveViewNativeStylesheet/ModifierParseError.swift +++ b/Sources/LiveViewNativeStylesheet/ModifierParseError.swift @@ -7,7 +7,8 @@ import Foundation -public struct ModifierParseError: Error, CustomDebugStringConvertible { +@MainActor +public struct ModifierParseError: Error, @preconcurrency CustomDebugStringConvertible { public let error: ErrorType public let metadata: Metadata @@ -107,10 +108,12 @@ public struct ModifierParseError: Error, CustomDebugStringConvertible { } } + @MainActor public var debugDescription: String { localizedDescription } + @MainActor public var localizedDescription: String { let indentation = String(repeating: " ", count: String(metadata.line).count) return """ diff --git a/Sources/LiveViewNativeStylesheet/Parsing/External/AnyNodeParser.swift b/Sources/LiveViewNativeStylesheet/Parsing/External/AnyNodeParser.swift index 7763db4d2..733968751 100644 --- a/Sources/LiveViewNativeStylesheet/Parsing/External/AnyNodeParser.swift +++ b/Sources/LiveViewNativeStylesheet/Parsing/External/AnyNodeParser.swift @@ -7,7 +7,8 @@ import Parsing -public struct _AnyNodeParser: Parser { +@MainActor +public struct _AnyNodeParser: @preconcurrency Parser { let context: ParseableModifierContext public init(context: ParseableModifierContext) { @@ -33,7 +34,8 @@ public struct _AnyNodeParser: Parser { "}".utf8 } - public struct AnyArgument: Parser { + @MainActor + public struct AnyArgument: @preconcurrency Parser { let context: ParseableModifierContext public init(context: ParseableModifierContext) { diff --git a/Sources/LiveViewNativeStylesheet/Parsing/External/Metadata.swift b/Sources/LiveViewNativeStylesheet/Parsing/External/Metadata.swift index 74c4af14b..b5cf857d4 100644 --- a/Sources/LiveViewNativeStylesheet/Parsing/External/Metadata.swift +++ b/Sources/LiveViewNativeStylesheet/Parsing/External/Metadata.swift @@ -1,6 +1,6 @@ import Parsing -public struct Metadata: Equatable { +public struct Metadata: Equatable, Sendable { public let file: String public let line: Int public let module: String diff --git a/Sources/LiveViewNativeStylesheet/Parsing/External/ParseableModifier.swift b/Sources/LiveViewNativeStylesheet/Parsing/External/ParseableModifier.swift index 3196b5d43..4dea7b843 100644 --- a/Sources/LiveViewNativeStylesheet/Parsing/External/ParseableModifier.swift +++ b/Sources/LiveViewNativeStylesheet/Parsing/External/ParseableModifier.swift @@ -56,7 +56,8 @@ public enum ArgumentParseError: LocalizedError { } } -public struct StandardExpressionParser: Parser { +@MainActor +public struct StandardExpressionParser: @preconcurrency Parser { let context: ParseableModifierContext public var body: some Parser { @@ -73,6 +74,7 @@ public class ParseableModifierContext { public init() {} } +@MainActor public protocol ParseableModifierValue { associatedtype _ParserType: Parser static func parser(in context: ParseableModifierContext) -> _ParserType diff --git a/Sources/LiveViewNativeStylesheetMacros/ParseableExpressionMacro.swift b/Sources/LiveViewNativeStylesheetMacros/ParseableExpressionMacro.swift index 874383aa5..42bee1564 100644 --- a/Sources/LiveViewNativeStylesheetMacros/ParseableExpressionMacro.swift +++ b/Sources/LiveViewNativeStylesheetMacros/ParseableExpressionMacro.swift @@ -19,7 +19,7 @@ public enum ParseableExpressionMacro: ExtensionMacro { }).flatMap({ [$0] }) ?? [] let signatures = declaration.memberBlock.members .compactMap({ member -> (FunctionParameterListSyntax, availability: AvailabilityArgumentListSyntax?, ifConfig: ExprSyntax?)? in - let ifConfig: IfConfigClauseSyntax? = member.decl.as(IfConfigDeclSyntax.self)?.clauses.first?.as(IfConfigClauseSyntax.self) + let ifConfig: IfConfigClauseSyntax? = member.decl.as(IfConfigDeclSyntax.self)?.clauses.first guard let decl: InitializerDeclSyntax = member.decl.as(InitializerDeclSyntax.self) ?? ifConfig?.elements?.as(MemberBlockItemListSyntax.self)?.first?.decl.as(InitializerDeclSyntax.self), diagnoseParameters(decl.signature.parameterClause.parameters, in: context) @@ -33,7 +33,7 @@ public enum ParseableExpressionMacro: ExtensionMacro { return [ try ExtensionDeclSyntax.init("extension \(type.trimmed): ParseableExpressionProtocol") { try TypeAliasDeclSyntax("\(accessLevel) typealias _ParserType = StandardExpressionParser") - try StructDeclSyntax("\(accessLevel) struct ExpressionArgumentsBody: Parser") { + try StructDeclSyntax("@MainActor \(accessLevel) struct ExpressionArgumentsBody: @preconcurrency Parser") { VariableDeclSyntax(.let, name: "context", type: TypeAnnotationSyntax(type: TypeSyntax("ParseableModifierContext"))) try FunctionDeclSyntax("func parse(_ input: inout Substring.UTF8View) throws -> \(type.trimmed)") { #"try "[".utf8.parse(&input)"# diff --git a/Sources/ModifierGenerator/ModifierGenerator.swift b/Sources/ModifierGenerator/ModifierGenerator.swift index 8f902bba4..bf025bcef 100644 --- a/Sources/ModifierGenerator/ModifierGenerator.swift +++ b/Sources/ModifierGenerator/ModifierGenerator.swift @@ -29,6 +29,7 @@ struct ModifierGenerator: ParsableCommand { "_PrefersDefaultFocusModifier", "_MatchedTransitionSourceModifier", "_NavigationTransitionModifier", + "_FileImporterModifier", ] static let requiredTypes: Set = [ @@ -139,6 +140,10 @@ struct ModifierGenerator: ParsableCommand { "tabViewCustomization", "menuButtonStyle", + + "navigationViewStyle", + + "disclosureGroupStyle", // manually implemented due to argument order edge cases "searchScopes", @@ -330,32 +335,34 @@ struct ModifierGenerator: ParsableCommand { else { return true } return !$0.parameters.contains(where: { $0.type.as(IdentifierTypeSyntax.self)?.name.text == "ViewReference" }) }) - let requiresContext = signatures.contains(where: { - $0.parameters.contains(where: { - ["ViewReference", "TextReference", "AttributeReference", "InlineViewReference", "AnyShapeStyle", "Color", "ListItemTint", "_AnyGesture"].contains( - $0.type.as(IdentifierTypeSyntax.self)?.name.text - ?? $0.type.as(OptionalTypeSyntax.self)?.wrappedType.as(IdentifierTypeSyntax.self)?.name.text - ?? $0.type.as(MemberTypeSyntax.self)?.baseType.as(IdentifierTypeSyntax.self)?.name.text - ?? $0.type.as(OptionalTypeSyntax.self)?.wrappedType - .as(MemberTypeSyntax.self)?.baseType.as(IdentifierTypeSyntax.self)?.name.text - ) + let contextRequiredTypes: Set = ["ViewReference", "TextReference", "AttributeReference", "InlineViewReference", "AnyShapeStyle", "Color", "ListItemTint", "_AnyGesture"] + let typeNames: [String] = signatures.flatMap({ + $0.parameters.compactMap({ + $0.type.identifierType?.name.text }) }) + let requiresContext = typeNames.contains(where: { contextRequiredTypes.contains($0) }) - let requiresGestureState = signatures.contains(where: { - $0.parameters.contains(where: { - ["_AnyGesture"].contains( - $0.type.as(IdentifierTypeSyntax.self)?.name.text - ?? $0.type.as(OptionalTypeSyntax.self)?.wrappedType.as(IdentifierTypeSyntax.self)?.name.text - ?? $0.type.as(MemberTypeSyntax.self)?.baseType.as(IdentifierTypeSyntax.self)?.name.text - ?? $0.type.as(OptionalTypeSyntax.self)?.wrappedType - .as(MemberTypeSyntax.self)?.baseType.as(IdentifierTypeSyntax.self)?.name.text - ) - }) - }) + let gestureStateRequiredTypes: [String?] = ["_AnyGesture"] + let requiresGestureState = typeNames.contains(where: { gestureStateRequiredTypes.contains($0) }) modifierList[modifier] = (signatures, requiresContext: requiresContext, requiresGestureState: requiresGestureState) } return (modifiers: modifierList, deprecations: visitor.deprecations) } } + +fileprivate extension TypeSyntaxProtocol { + var identifierType: IdentifierTypeSyntax? { + if let identifierType = self.as(IdentifierTypeSyntax.self) { + return identifierType + } + if let memberIdentifierType = self.as(MemberTypeSyntax.self)?.baseType.as(IdentifierTypeSyntax.self) { + return memberIdentifierType + } + if let optionalIdentifierType = self.as(OptionalTypeSyntax.self)?.wrappedType.identifierType { + return optionalIdentifierType + } + return nil + } +} diff --git a/Sources/ModifierGenerator/Signature.swift b/Sources/ModifierGenerator/Signature.swift index 1a3c54a44..f059e3388 100644 --- a/Sources/ModifierGenerator/Signature.swift +++ b/Sources/ModifierGenerator/Signature.swift @@ -86,7 +86,7 @@ struct Signature { \#(platformAvailability) \#(boundParameters.isEmpty ? "" : "indirect") case _\#(offset)\#(boundParameters.isEmpty ? "" : "(")\#(FunctionParameterListSyntax(boundParameters.map({ if availability.isEmpty { - return $0 + return $0.with(\.defaultValue, nil) } else { return $0 .with(\.type, $0.type.is(OptionalTypeSyntax.self) ? TypeSyntax("Any?") : TypeSyntax("Any")) @@ -323,10 +323,11 @@ extension FunctionParameterSyntax { } // Types that support `attr` should be wrapped in an `AttributeReference`. - if let typeName = (self.type.as(MemberTypeSyntax.self)?.name + let typeName = self.type.as(MemberTypeSyntax.self)?.name ?? self.type.as(OptionalTypeSyntax.self)?.wrappedType.as(IdentifierTypeSyntax.self)?.name ?? self.type.as(OptionalTypeSyntax.self)?.wrappedType.as(MemberTypeSyntax.self)?.name - ?? self.type.as(IdentifierTypeSyntax.self)?.name)?.text, + ?? self.type.as(IdentifierTypeSyntax.self)?.name + if let typeName = typeName?.text, [ // Primitives "String", @@ -348,7 +349,7 @@ extension FunctionParameterSyntax { { self = self .with(\.type, TypeSyntax("AttributeReference<\(self.type.trimmed)>\(raw: self.type.is(OptionalTypeSyntax.self) ? "?" : "")")) - .with(\.defaultValue, self.defaultValue?.as(InitializerClauseSyntax.self).flatMap({ InitializerClauseSyntax.init(equal: .equalToken(leadingTrivia: .space, trailingTrivia: .space), value: ExprSyntax(".init(storage: .constant(\($0.value)))")) })) + .with(\.defaultValue, self.defaultValue.flatMap({ InitializerClauseSyntax.init(equal: .equalToken(leadingTrivia: .space, trailingTrivia: .space), value: ExprSyntax(".init(storage: .constant(\($0.value)))")) })) } self = self diff --git a/Sources/ModifierGenerator/Subcommands/DocumentationExtensions.swift b/Sources/ModifierGenerator/Subcommands/DocumentationExtensions.swift index 2471a78f2..6c2073b80 100644 --- a/Sources/ModifierGenerator/Subcommands/DocumentationExtensions.swift +++ b/Sources/ModifierGenerator/Subcommands/DocumentationExtensions.swift @@ -11,6 +11,20 @@ import SwiftSyntax import SwiftSyntaxBuilder import SwiftParser +@propertyWrapper +struct DecodableIgnored: Decodable { + var storage: Value! + + init() {} + + init(from decoder: Decoder) throws {} + + var wrappedValue: Value { + get { storage } + set { storage = newValue } + } +} + extension ModifierGenerator { struct DocumentationExtensions: ParsableCommand { static let configuration = CommandConfiguration(abstract: "Output a list of the names of all available modifiers.") @@ -27,15 +41,18 @@ extension ModifierGenerator { ) private var output: URL - private static let typeVisitor = EnumTypeVisitor(typeNames: ModifierGenerator.requiredTypes) + @DecodableIgnored + private var typeVisitor: EnumTypeVisitor - func run() throws { + mutating func run() async throws { + typeVisitor = EnumTypeVisitor(typeNames: ModifierGenerator.requiredTypes) + let source = try String(contentsOf: interface, encoding: .utf8) let sourceFile = Parser.parse(source: source) let (modifiers, _) = ModifierGenerator.modifiers(from: sourceFile) - Self.typeVisitor.walk(sourceFile) + typeVisitor.walk(sourceFile) for (name, (signatures, _, _)) in modifiers { let firstSignatureDescription = signatureDescription(for: signatures.first!, on: name) @@ -145,7 +162,7 @@ extension ModifierGenerator { } else if parameter.type.isTextReference { value = #":\#(displayName)"# templates.append(#"..."#) - } else if let enumType = Self.typeVisitor.types[parameter.type.nestedTypeName]?.first { + } else if let enumType = typeVisitor.types[parameter.type.nestedTypeName]?.first { value = ".\(enumType.0)" } else { value = parameter.type.exampleValue diff --git a/Sources/ModifierGenerator/Subcommands/Source.swift b/Sources/ModifierGenerator/Subcommands/Source.swift index 869716994..338e79db1 100644 --- a/Sources/ModifierGenerator/Subcommands/Source.swift +++ b/Sources/ModifierGenerator/Subcommands/Source.swift @@ -142,7 +142,8 @@ extension ModifierGenerator { .init(context: context) } - struct _ParserType: Parser { + @MainActor + struct _ParserType: @preconcurrency Parser { typealias Input = Substring.UTF8View typealias Output = BuiltinModifier diff --git a/Sources/ModifierGenerator/Visitors/ParseableModifierVisitor.swift b/Sources/ModifierGenerator/Visitors/ParseableModifierVisitor.swift index c4cdc8a04..8c3ff2f47 100644 --- a/Sources/ModifierGenerator/Visitors/ParseableModifierVisitor.swift +++ b/Sources/ModifierGenerator/Visitors/ParseableModifierVisitor.swift @@ -11,7 +11,7 @@ final class ParseableModifierVisitor: SyntaxVisitor { guard node.attributes.contains(where: { $0.as(AttributeSyntax.self)?.attributeName.as(IdentifierTypeSyntax.self)?.name.text == "ParseableExpression" }), let name: String = node.memberBlock.members.lazy.compactMap({ guard let decl: VariableDeclSyntax = $0.decl.as(VariableDeclSyntax.self), - let binding: PatternBindingSyntax = decl.bindings.first?.as(PatternBindingSyntax.self), + let binding: PatternBindingSyntax = decl.bindings.first, binding.pattern.as(IdentifierPatternSyntax.self)?.identifier.text == "name", let name = ( binding.initializer?.value.as(StringLiteralExprSyntax.self)