@swiftbrowser/swift 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Package.swift +200 -9
- package/README.md +7 -9
- package/Sources/AVFoundation/AVFoundation.swift +131 -0
- package/Sources/AVFoundation/Asset.swift +487 -0
- package/Sources/AVFoundation/AudioSession.swift +144 -0
- package/Sources/AVFoundation/CMTime.swift +303 -0
- package/Sources/AVFoundation/Capture.swift +688 -0
- package/Sources/AVFoundation/Player.swift +749 -0
- package/Sources/AVFoundation/PlayerView.swift +117 -0
- package/Sources/AVKit/AVKit.swift +132 -0
- package/Sources/Accelerate/Accelerate.swift +122 -0
- package/Sources/AppIntents/AppIntents.swift +144 -0
- package/Sources/AppIntents/Parameters.swift +220 -0
- package/Sources/AppIntents/Shortcuts.swift +159 -0
- package/Sources/AudioToolbox/AudioToolbox.swift +55 -0
- package/Sources/AuthenticationServices/AuthenticationServices.swift +257 -0
- package/Sources/AuthenticationServices/Authorization.swift +251 -0
- package/Sources/Charts/Charts.swift +0 -4
- package/Sources/Combine/AnyCancellable.swift +65 -0
- package/Sources/Combine/AnyPublisher.swift +148 -0
- package/Sources/Combine/AnySubscriber.swift +230 -0
- package/Sources/Combine/Cancellable.swift +35 -0
- package/Sources/Combine/Codable.swift +29 -0
- package/Sources/Combine/CombineIdentifier.swift +45 -0
- package/Sources/Combine/Concurrency/ConcurrencyHelpers.swift +24 -0
- package/Sources/Combine/Concurrency/Future+Concurrency.swift +136 -0
- package/Sources/Combine/Concurrency/GENERATED-Publisher+Concurrency.swift +397 -0
- package/Sources/Combine/CurrentValueSubject.swift +252 -0
- package/Sources/Combine/CustomCombineIdentifierConvertible.swift +28 -0
- package/Sources/Combine/Future.swift +228 -0
- package/Sources/Combine/GENERATED-RootProtocols.swift +426 -0
- package/Sources/Combine/Helpers/ConduitBase.swift +40 -0
- package/Sources/Combine/Helpers/ConduitList.swift +59 -0
- package/Sources/Combine/Helpers/DebugHook.swift +177 -0
- package/Sources/Combine/Helpers/FilterProducer.swift +174 -0
- package/Sources/Combine/Helpers/Locking.swift +30 -0
- package/Sources/Combine/Helpers/PartialCompletion.swift +26 -0
- package/Sources/Combine/Helpers/ReduceProducer.swift +249 -0
- package/Sources/Combine/Helpers/SubjectSubscriber.swift +96 -0
- package/Sources/Combine/Helpers/SubscriberTap.swift +69 -0
- package/Sources/Combine/Helpers/SubscriptionStatus.swift +33 -0
- package/Sources/Combine/Helpers/SubscriptionTap.swift +33 -0
- package/Sources/Combine/Helpers/Utils.swift +30 -0
- package/Sources/Combine/Helpers/Violations.swift +33 -0
- package/Sources/Combine/ImmediateScheduler.swift +178 -0
- package/Sources/Combine/LICENSE +21 -0
- package/Sources/Combine/NotificationPublisher.swift +48 -0
- package/Sources/Combine/ObjectWillChange.swift +46 -0
- package/Sources/Combine/PassthroughSubject.swift +222 -0
- package/Sources/Combine/Publisher+Subscribe.swift +53 -0
- package/Sources/Combine/Publishers/Deferred.swift +48 -0
- package/Sources/Combine/Publishers/Empty.swift +54 -0
- package/Sources/Combine/Publishers/Fail.swift +42 -0
- package/Sources/Combine/Publishers/GENERATED-Publishers.Catch.swift +673 -0
- package/Sources/Combine/Publishers/GENERATED-Publishers.Encode.swift +388 -0
- package/Sources/Combine/Publishers/GENERATED-Publishers.MapKeyPath.swift +384 -0
- package/Sources/Combine/Publishers/Just.swift +313 -0
- package/Sources/Combine/Publishers/Optional.Publisher.swift +315 -0
- package/Sources/Combine/Publishers/Publishers.AllSatisfy.swift +217 -0
- package/Sources/Combine/Publishers/Publishers.AssertNoFailure.swift +158 -0
- package/Sources/Combine/Publishers/Publishers.Autoconnect.swift +193 -0
- package/Sources/Combine/Publishers/Publishers.Breakpoint.swift +231 -0
- package/Sources/Combine/Publishers/Publishers.Buffer.swift +356 -0
- package/Sources/Combine/Publishers/Publishers.Collect.swift +102 -0
- package/Sources/Combine/Publishers/Publishers.CollectByCount.swift +195 -0
- package/Sources/Combine/Publishers/Publishers.CompactMap.swift +241 -0
- package/Sources/Combine/Publishers/Publishers.Comparison.swift +371 -0
- package/Sources/Combine/Publishers/Publishers.Concatenate.swift +474 -0
- package/Sources/Combine/Publishers/Publishers.Contains.swift +293 -0
- package/Sources/Combine/Publishers/Publishers.Count.swift +87 -0
- package/Sources/Combine/Publishers/Publishers.Debounce.swift +332 -0
- package/Sources/Combine/Publishers/Publishers.Delay.swift +269 -0
- package/Sources/Combine/Publishers/Publishers.Drop.swift +155 -0
- package/Sources/Combine/Publishers/Publishers.DropUntilOutput.swift +283 -0
- package/Sources/Combine/Publishers/Publishers.DropWhile.swift +378 -0
- package/Sources/Combine/Publishers/Publishers.Filter.swift +248 -0
- package/Sources/Combine/Publishers/Publishers.First.swift +261 -0
- package/Sources/Combine/Publishers/Publishers.FlatMap.swift +533 -0
- package/Sources/Combine/Publishers/Publishers.HandleEvents.swift +260 -0
- package/Sources/Combine/Publishers/Publishers.IgnoreOutput.swift +109 -0
- package/Sources/Combine/Publishers/Publishers.Last.swift +252 -0
- package/Sources/Combine/Publishers/Publishers.MakeConnectable.swift +82 -0
- package/Sources/Combine/Publishers/Publishers.Map.swift +351 -0
- package/Sources/Combine/Publishers/Publishers.MapError.swift +140 -0
- package/Sources/Combine/Publishers/Publishers.MeasureInterval.swift +187 -0
- package/Sources/Combine/Publishers/Publishers.Multicast.swift +284 -0
- package/Sources/Combine/Publishers/Publishers.Output.swift +241 -0
- package/Sources/Combine/Publishers/Publishers.PrefixUntilOutput.swift +197 -0
- package/Sources/Combine/Publishers/Publishers.PrefixWhile.swift +176 -0
- package/Sources/Combine/Publishers/Publishers.Print.swift +206 -0
- package/Sources/Combine/Publishers/Publishers.ReceiveOn.swift +227 -0
- package/Sources/Combine/Publishers/Publishers.Reduce.swift +204 -0
- package/Sources/Combine/Publishers/Publishers.RemoveDuplicates.swift +264 -0
- package/Sources/Combine/Publishers/Publishers.ReplaceEmpty.swift +201 -0
- package/Sources/Combine/Publishers/Publishers.ReplaceError.swift +211 -0
- package/Sources/Combine/Publishers/Publishers.Retry.swift +274 -0
- package/Sources/Combine/Publishers/Publishers.Scan.swift +331 -0
- package/Sources/Combine/Publishers/Publishers.Sequence.swift +437 -0
- package/Sources/Combine/Publishers/Publishers.SetFailureType.swift +120 -0
- package/Sources/Combine/Publishers/Publishers.Share.swift +104 -0
- package/Sources/Combine/Publishers/Publishers.SubscribeOn.swift +197 -0
- package/Sources/Combine/Publishers/Publishers.SwitchToLatest.swift +444 -0
- package/Sources/Combine/Publishers/Publishers.Throttle.swift +359 -0
- package/Sources/Combine/Publishers/Publishers.Timeout.swift +301 -0
- package/Sources/Combine/Publishers/Publishers.Zip.swift +720 -0
- package/Sources/Combine/Publishers/Publishers.swift +13 -0
- package/Sources/Combine/Publishers/Record.swift +237 -0
- package/Sources/Combine/Publishers/Result.Publisher.swift +337 -0
- package/Sources/Combine/Result.swift +46 -0
- package/Sources/Combine/Scheduler.swift +89 -0
- package/Sources/Combine/Schedulers.swift +211 -0
- package/Sources/Combine/Subject+Void.swift +17 -0
- package/Sources/Combine/Subscriber+Void.swift +20 -0
- package/Sources/Combine/Subscribers/Subscribers.Assign.swift +175 -0
- package/Sources/Combine/Subscribers/Subscribers.Completion.swift +90 -0
- package/Sources/Combine/Subscribers/Subscribers.Demand.swift +476 -0
- package/Sources/Combine/Subscribers/Subscribers.Sink.swift +206 -0
- package/Sources/Combine/Subscribers/Subscribers.swift +9 -0
- package/Sources/Combine/Subscription.swift +22 -0
- package/Sources/Combine/Subscriptions.swift +42 -0
- package/Sources/Combine/SwiftUIObservation.swift +10 -0
- package/Sources/Combine/_Introspection.swift +107 -0
- package/Sources/CommonCrypto/CommonCrypto.swift +80 -0
- package/Sources/Compression/Compression.swift +365 -0
- package/Sources/Compression/Deflate.swift +407 -0
- package/Sources/Compression/Zlib.swift +179 -0
- package/Sources/CoreFoundationTypes/CoreFoundationTypes.swift +101 -0
- package/Sources/CoreGraphics/CoreGraphics.swift +411 -0
- package/Sources/CoreGraphics/ProjectionTransforms.swift +28 -0
- package/Sources/CoreHaptics/CoreHaptics.swift +399 -0
- package/Sources/CoreImage/CIColor.swift +41 -0
- package/Sources/CoreImage/CIContext.swift +31 -0
- package/Sources/CoreImage/CIDetector.swift +57 -0
- package/Sources/CoreImage/CIFilter.swift +243 -0
- package/Sources/CoreImage/CIFilterBuiltins.swift +136 -0
- package/Sources/CoreImage/CIImage.swift +162 -0
- package/Sources/CoreImage/QRCode.swift +393 -0
- package/Sources/CoreLocation/Coordinate.swift +30 -0
- package/Sources/CoreLocation/Location.swift +65 -0
- package/Sources/CoreML/Evaluation.swift +414 -0
- package/Sources/CoreML/FeatureValue.swift +266 -0
- package/Sources/CoreML/Model.swift +269 -0
- package/Sources/CoreML/MultiArray.swift +92 -0
- package/Sources/CoreML/Specification.swift +233 -0
- package/Sources/CoreText/CoreText.swift +64 -0
- package/Sources/CoreTransferable/CoreTransferable.swift +606 -0
- package/Sources/CryptoKit/ChaChaPoly.swift +258 -0
- package/Sources/CryptoKit/CryptoKit.swift +375 -0
- package/Sources/CryptoKit/Curve25519.swift +317 -0
- package/Sources/CryptoKit/P256.swift +321 -0
- package/Sources/FoundationBridge/AppStorage.swift +165 -0
- package/Sources/FoundationBridge/AssetResources.swift +90 -0
- package/Sources/FoundationBridge/AsyncBytes.swift +128 -0
- package/Sources/FoundationBridge/AsyncImage.swift +116 -0
- package/Sources/FoundationBridge/AttributedStrings.swift +16 -0
- package/Sources/{_FoundationCommon → FoundationBridge}/Bundle.swift +41 -4
- package/Sources/FoundationBridge/CombineExports.swift +8 -0
- package/Sources/FoundationBridge/CoreFoundation.swift +77 -0
- package/Sources/FoundationBridge/Dispatch.swift +458 -0
- package/Sources/FoundationBridge/EnvironmentFoundation.swift +41 -0
- package/Sources/FoundationBridge/FileImporter.swift +128 -0
- package/Sources/FoundationBridge/FileSystem.swift +68 -0
- package/Sources/FoundationBridge/FoundationBridge.swift +24 -72
- package/Sources/FoundationBridge/HostResolution.swift +31 -0
- package/Sources/FoundationBridge/ItemProvider.swift +655 -0
- package/Sources/FoundationBridge/KeyValueObserving.swift +138 -0
- package/Sources/FoundationBridge/Links.swift +127 -0
- package/Sources/FoundationBridge/ListFormatter.swift +32 -0
- package/Sources/FoundationBridge/Localization.swift +149 -0
- package/Sources/FoundationBridge/Locks.swift +50 -0
- package/Sources/FoundationBridge/Markdown.swift +527 -0
- package/Sources/FoundationBridge/MeasurementFormat.swift +95 -0
- package/Sources/FoundationBridge/NotificationCenter.swift +154 -0
- package/Sources/FoundationBridge/OpenURLHandlers.swift +60 -0
- package/Sources/FoundationBridge/Operation.swift +195 -0
- package/Sources/FoundationBridge/ProcessInfo.swift +32 -0
- package/Sources/FoundationBridge/RelativeDateTimeFormatter.swift +136 -0
- package/Sources/FoundationBridge/SceneStorage.swift +78 -0
- package/Sources/FoundationBridge/SecurityExports.swift +8 -0
- package/Sources/FoundationBridge/Selector.swift +226 -0
- package/Sources/FoundationBridge/StringComparators.swift +17 -0
- package/Sources/FoundationBridge/Table.swift +211 -0
- package/Sources/FoundationBridge/TextAttributes.swift +42 -0
- package/Sources/FoundationBridge/Timer.swift +6 -1
- package/Sources/FoundationBridge/URLSession.swift +718 -0
- package/Sources/{_FoundationCommon → FoundationBridge}/UserDefaults.swift +17 -4
- package/Sources/FoundationBridge/WebAuthRedirects.swift +227 -0
- package/Sources/FoundationBridge/WebSocket.swift +187 -0
- package/Sources/FoundationModels/FoundationModels.swift +1098 -0
- package/Sources/ImageIO/GIF.swift +72 -0
- package/Sources/ImageIO/ImageIO.swift +248 -0
- package/Sources/ImageIO/ImageTypes.swift +28 -0
- package/Sources/LinkPresentation/LinkPresentation.swift +249 -0
- package/Sources/LocalAuthentication/LAContext.swift +86 -0
- package/Sources/MapKit/Geometry.swift +223 -0
- package/Sources/MapKit/Map.swift +638 -0
- package/Sources/MapKit/MapView.swift +229 -0
- package/Sources/MobileCoreServices/MobileCoreServices.swift +28 -0
- package/Sources/NaturalLanguage/LanguageIdentifier.swift +317 -0
- package/Sources/NaturalLanguage/NaturalLanguage.swift +135 -0
- package/Sources/OSLog/OSLog.swift +6 -0
- package/Sources/Photos/Photos.swift +572 -0
- package/Sources/PhotosUI/PhotosPicker.swift +248 -0
- package/Sources/PhotosUI/PhotosPickerItem.swift +261 -0
- package/Sources/QuickLook/QuickLook.swift +168 -0
- package/Sources/SafariServices/SafariServices.swift +106 -0
- package/Sources/Security/Security.swift +332 -0
- package/Sources/StoreKit/AppStore.swift +207 -0
- package/Sources/StoreKit/Products.swift +280 -0
- package/Sources/StoreKit/RequestReview.swift +28 -0
- package/Sources/StoreKit/StoreKit1.swift +486 -0
- package/Sources/StoreKit/StoreViews.swift +428 -0
- package/Sources/StoreKit/Transactions.swift +197 -0
- package/Sources/SwiftData/Macros.swift +58 -0
- package/Sources/SwiftData/ModelActor.swift +38 -0
- package/Sources/SwiftData/ModelContainer.swift +129 -0
- package/Sources/SwiftData/ModelContext.swift +451 -0
- package/Sources/SwiftData/PersistentModel.swift +238 -0
- package/Sources/SwiftData/Properties.swift +261 -0
- package/Sources/SwiftData/Query.swift +256 -0
- package/Sources/SwiftData/Schema.swift +192 -0
- package/Sources/SwiftData/Store.swift +146 -0
- package/Sources/SwiftData/StringPredicates.swift +125 -0
- package/Sources/SwiftDataMacros/EntryMacro.swift +82 -0
- package/Sources/SwiftDataMacros/GenerableMacro.swift +183 -0
- package/Sources/SwiftDataMacros/ModelActorMacro.swift +46 -0
- package/Sources/SwiftDataMacros/ModelMacro.swift +260 -0
- package/Sources/SwiftDataMacros/Plugin.swift +18 -0
- package/Sources/SwiftDataMacros/PredicateMacro.swift +1244 -0
- package/Sources/SwiftUI/API/Accessibility.swift +55 -6
- package/Sources/SwiftUI/API/AccessibilityExtras.swift +33 -0
- package/Sources/SwiftUI/API/AccessibilityFocus.swift +63 -0
- package/Sources/SwiftUI/API/Alert.swift +1 -1
- package/Sources/SwiftUI/API/AlignmentGuides.swift +68 -0
- package/Sources/SwiftUI/API/Animation.swift +37 -5
- package/Sources/SwiftUI/API/App.swift +31 -1
- package/Sources/SwiftUI/API/BindingCollections.swift +35 -0
- package/Sources/SwiftUI/API/BindingForEach.swift +27 -0
- package/Sources/SwiftUI/API/Bitmaps.swift +254 -0
- package/Sources/SwiftUI/API/ButtonStyles.swift +96 -0
- package/Sources/SwiftUI/API/Canvas.swift +337 -0
- package/Sources/SwiftUI/API/Color.swift +104 -28
- package/Sources/SwiftUI/API/ColorEffects.swift +52 -0
- package/Sources/SwiftUI/API/ColorPickerAndLabeledContent.swift +138 -0
- package/Sources/SwiftUI/API/ColorSpaces.swift +161 -0
- package/Sources/SwiftUI/API/Commands.swift +106 -0
- package/Sources/SwiftUI/API/ContainerBackground.swift +28 -0
- package/Sources/SwiftUI/API/ContentShape.swift +33 -0
- package/Sources/SwiftUI/API/ContentSizeCategory.swift +35 -0
- package/Sources/SwiftUI/API/ContentUnavailable.swift +101 -0
- package/Sources/SwiftUI/API/Controls.swift +59 -27
- package/Sources/SwiftUI/API/CustomLayout.swift +49 -10
- package/Sources/SwiftUI/API/CustomToolbarContent.swift +46 -0
- package/Sources/SwiftUI/API/Decorations.swift +1 -1
- package/Sources/SwiftUI/API/EditMode.swift +25 -82
- package/Sources/SwiftUI/API/Effects.swift +125 -10
- package/Sources/SwiftUI/API/Entry.swift +8 -0
- package/Sources/SwiftUI/API/Environment.swift +100 -9
- package/Sources/SwiftUI/API/EnvironmentSendable.swift +6 -0
- package/Sources/SwiftUI/API/Focus.swift +11 -3
- package/Sources/SwiftUI/API/Gauge.swift +26 -10
- package/Sources/SwiftUI/API/GeometryEffects.swift +232 -0
- package/Sources/SwiftUI/API/GeometryReader.swift +13 -2
- package/Sources/SwiftUI/API/GestureState.swift +65 -0
- package/Sources/SwiftUI/API/Gestures.swift +1 -1
- package/Sources/SwiftUI/API/Glass.swift +127 -0
- package/Sources/SwiftUI/API/Grid.swift +1 -1
- package/Sources/SwiftUI/API/GroupBoxAndControlGroup.swift +130 -0
- package/Sources/SwiftUI/API/KeyPress.swift +54 -0
- package/Sources/SwiftUI/API/LabelStyle.swift +13 -6
- package/Sources/SwiftUI/API/Layout.swift +71 -12
- package/Sources/SwiftUI/API/LazyStacks.swift +49 -0
- package/Sources/SwiftUI/API/LegacyAlert.swift +97 -0
- package/Sources/SwiftUI/API/Lists.swift +61 -6
- package/Sources/SwiftUI/API/Menu.swift +8 -1
- package/Sources/SwiftUI/API/Modifiers.swift +88 -12
- package/Sources/SwiftUI/API/MoreModifiers.swift +100 -0
- package/Sources/SwiftUI/API/Namespace.swift +44 -0
- package/Sources/SwiftUI/API/Navigation.swift +24 -9
- package/Sources/SwiftUI/API/NavigationDestinationBindings.swift +55 -0
- package/Sources/SwiftUI/API/ObservableObject.swift +16 -2
- package/Sources/SwiftUI/API/Path.swift +543 -0
- package/Sources/SwiftUI/API/Phase8Controls.swift +48 -31
- package/Sources/SwiftUI/API/PhaseAnimator.swift +130 -0
- package/Sources/SwiftUI/API/Picker.swift +14 -4
- package/Sources/SwiftUI/API/PointerAndKeyboard.swift +77 -0
- package/Sources/SwiftUI/API/Popover.swift +41 -0
- package/Sources/SwiftUI/API/Preferences.swift +262 -0
- package/Sources/SwiftUI/API/Presentation.swift +17 -4
- package/Sources/SwiftUI/API/PresentationExtras.swift +60 -0
- package/Sources/SwiftUI/API/Primitives.swift +168 -39
- package/Sources/SwiftUI/API/Publishers.swift +4 -4
- package/Sources/SwiftUI/API/Redaction.swift +75 -0
- package/Sources/SwiftUI/API/RowActions.swift +3 -2
- package/Sources/SwiftUI/API/Scenes.swift +131 -0
- package/Sources/SwiftUI/API/ScrollModifiers.swift +132 -0
- package/Sources/SwiftUI/API/ScrollTargets.swift +3 -3
- package/Sources/SwiftUI/API/ScrollViewReader.swift +144 -0
- package/Sources/SwiftUI/API/SectionSupplements.swift +86 -0
- package/Sources/SwiftUI/API/Shape.swift +214 -0
- package/Sources/SwiftUI/API/ShapeStyle.swift +187 -8
- package/Sources/SwiftUI/API/ShapeTrim.swift +78 -0
- package/Sources/SwiftUI/API/Sharing.swift +193 -0
- package/Sources/SwiftUI/API/StackLayouts.swift +199 -0
- package/Sources/SwiftUI/API/State.swift +18 -1
- package/Sources/SwiftUI/API/StatusGaps.swift +121 -0
- package/Sources/SwiftUI/API/SymbolEffects.swift +203 -0
- package/Sources/SwiftUI/API/TabContent.swift +841 -0
- package/Sources/SwiftUI/API/Table.swift +382 -0
- package/Sources/SwiftUI/API/Tabs.swift +148 -4
- package/Sources/SwiftUI/API/Tasks.swift +2 -2
- package/Sources/SwiftUI/API/Text.swift +386 -0
- package/Sources/SwiftUI/API/TextDates.swift +61 -0
- package/Sources/SwiftUI/API/TextDecorations.swift +52 -0
- package/Sources/SwiftUI/API/TextFieldAxis.swift +103 -0
- package/Sources/SwiftUI/API/TextFieldCommit.swift +52 -0
- package/Sources/SwiftUI/API/Toolbar.swift +52 -16
- package/Sources/SwiftUI/API/Transfer.swift +145 -0
- package/Sources/SwiftUI/API/UnevenRoundedRectangle.swift +66 -0
- package/Sources/SwiftUI/API/Video.swift +64 -0
- package/Sources/SwiftUI/API/View.swift +46 -2
- package/Sources/SwiftUI/API/ViewModifier.swift +4 -1
- package/Sources/SwiftUI/API/VisualEffect.swift +74 -1
- package/Sources/SwiftUI/API/Windows.swift +25 -0
- package/Sources/SwiftUI/Charts/Axis.swift +7 -1
- package/Sources/SwiftUI/Charts/AxisFormatsAndRanges.swift +68 -0
- package/Sources/SwiftUI/Charts/Chart.swift +17 -3
- package/Sources/SwiftUI/Charts/ChartProxy.swift +57 -0
- package/Sources/SwiftUI/Localization/Localization.swift +524 -0
- package/Sources/SwiftUI/Localization/PluralRules.swift +127 -0
- package/Sources/SwiftUI/Runtime/Executor.swift +2 -0
- package/Sources/SwiftUI/Runtime/Exports.swift +37 -1
- package/Sources/SwiftUI/Runtime/ImageSource.swift +310 -0
- package/Sources/SwiftUI/Runtime/JSON.swift +76 -4
- package/Sources/SwiftUI/Runtime/LazyRows.swift +99 -0
- package/Sources/SwiftUI/Runtime/Measurements.swift +140 -0
- package/Sources/SwiftUI/Runtime/Ops.swift +58 -12
- package/Sources/SwiftUI/Runtime/Reconciler.swift +10 -1
- package/Sources/SwiftUI/Runtime/Replay.swift +382 -0
- package/Sources/SwiftUI/Runtime/Runtime.swift +977 -198
- package/Sources/SwiftUI/Runtime/Sameness.swift +152 -0
- package/Sources/SwiftUI/Runtime/ViewPath.swift +89 -0
- package/Sources/SwiftUI/Runtime/ViewTraits.swift +175 -0
- package/Sources/SwiftUI/Runtime/WebAuthHeadless.swift +49 -0
- package/Sources/Symbols/Symbols.swift +25 -0
- package/Sources/Translation/Translation.swift +423 -0
- package/Sources/UIKit/Activity.swift +213 -0
- package/Sources/UIKit/Alerts.swift +69 -0
- package/Sources/UIKit/AppDelegate.swift +222 -0
- package/Sources/UIKit/Appearance.swift +84 -0
- package/Sources/UIKit/ColorConversions.swift +70 -0
- package/Sources/UIKit/Controls.swift +225 -0
- package/Sources/UIKit/Device.swift +200 -0
- package/Sources/UIKit/Feedback.swift +65 -0
- package/Sources/UIKit/Font.swift +307 -0
- package/Sources/UIKit/Graphics.swift +204 -0
- package/Sources/UIKit/HostingController.swift +185 -0
- package/Sources/UIKit/Identity.swift +24 -0
- package/Sources/UIKit/Introspectable.swift +510 -0
- package/Sources/UIKit/Pasteboard.swift +363 -0
- package/Sources/UIKit/PhotoAlbum.swift +81 -0
- package/Sources/UIKit/RemoteNotifications.swift +15 -0
- package/Sources/UIKit/Representable.swift +288 -0
- package/Sources/UIKit/SafeArea.swift +12 -0
- package/Sources/UIKit/SceneDelegates.swift +132 -0
- package/Sources/UIKit/Scenes.swift +40 -0
- package/Sources/UIKit/ScrollView.swift +157 -0
- package/Sources/UIKit/ShortcutItems.swift +67 -0
- package/Sources/UIKit/SymbolConfiguration.swift +124 -0
- package/Sources/UIKit/TargetAction.swift +123 -0
- package/Sources/UIKit/TextPaste.swift +161 -0
- package/Sources/UIKit/TextView.swift +538 -0
- package/Sources/UIKit/UIKit.swift +292 -0
- package/Sources/UIKit/UIView.swift +855 -0
- package/Sources/UIKit/ViewTranslation.swift +311 -0
- package/Sources/UniformTypeIdentifiers/UTType.swift +196 -0
- package/Sources/UserNotifications/Content.swift +370 -0
- package/Sources/UserNotifications/NotificationCenter.swift +309 -0
- package/Sources/WeatherKit/WeatherKit.swift +228 -0
- package/Sources/WebKit/WebKit.swift +245 -0
- package/Sources/os/os.swift +376 -0
- package/Sources/zlib/zlib.swift +6 -0
- package/index.d.ts +1 -1
- package/index.mjs +2 -2
- package/manifest.d.mts +2 -0
- package/manifest.mjs +41 -0
- package/package.json +5 -3
- package/sync-sources.mjs +21 -7
- package/Sources/FoundationLite/Common.swift +0 -3
- package/Sources/FoundationLite/FoundationLite.swift +0 -171
- package/Sources/FoundationLite/Interaction.swift +0 -146
- package/Sources/FoundationLite/Timer.swift +0 -48
- package/Sources/_FoundationCommon/_FoundationCommon.swift +0 -10
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
// `UIImage` and `CGImage`, as far as SwiftUI apps use them: made from an
|
|
4
|
+
// image file's bytes, from Core Image (Sources/CoreImage), from an SF Symbol
|
|
5
|
+
// or a catalog name, and shown with `Image(uiImage:)`. On iOS SwiftUI
|
|
6
|
+
// re-exports UIKit's `UIImage` and Core Graphics' `CGImage`, so a file that
|
|
7
|
+
// imports SwiftUI alone uses both; here they live in the shim for the same
|
|
8
|
+
// reason. Neither holds pixels: each is a recipe the page draws
|
|
9
|
+
// (Runtime/ImageSource.swift, docs/ops-protocol.md, "Bitmaps and Core Image").
|
|
10
|
+
|
|
11
|
+
/// A bitmap: `width` × `height` pixels the page produces from a recipe.
|
|
12
|
+
public final class CGImage: @unchecked Sendable {
|
|
13
|
+
public let width: Int
|
|
14
|
+
public let height: Int
|
|
15
|
+
/// The recipe, ending at this image's pixel grid (extent `(0, 0, width, height)`).
|
|
16
|
+
public let _recipe: _ImageRecipe
|
|
17
|
+
|
|
18
|
+
/// Made by Core Image (`CIContext.createCGImage`) from a rendered recipe.
|
|
19
|
+
public init(_recipe recipe: _ImageRecipe) {
|
|
20
|
+
_recipe = recipe
|
|
21
|
+
let extent = recipe.extent.isNull || recipe.extent.isInfinite ? CGRect.zero : recipe.extent
|
|
22
|
+
width = Int(extent.width)
|
|
23
|
+
height = Int(extent.height)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public var bitsPerComponent: Int { 8 }
|
|
27
|
+
public var bitsPerPixel: Int { 32 }
|
|
28
|
+
public var bytesPerRow: Int { width * 4 }
|
|
29
|
+
|
|
30
|
+
/// The part of the image inside `rect` (pixels, origin at the top left),
|
|
31
|
+
/// clipped to the image; nil when they do not overlap.
|
|
32
|
+
public func cropping(to rect: CGRect) -> CGImage? {
|
|
33
|
+
let bounds = CGRect(x: 0, y: 0, width: Double(width), height: Double(height))
|
|
34
|
+
let box = rect.integral.intersection(bounds)
|
|
35
|
+
guard !box.isNull, box.width >= 1, box.height >= 1 else { return nil }
|
|
36
|
+
// Core Image's origin is at the bottom left.
|
|
37
|
+
let flipped = CGRect(x: box.minX, y: Double(height) - box.maxY, width: box.width, height: box.height)
|
|
38
|
+
return _recipe.rendered(in: flipped).map(CGImage.init(_recipe:))
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/// UIKit's image: a bitmap with a scale (pixels per point), or an SF Symbol
|
|
43
|
+
/// or asset-catalog image the page draws by name.
|
|
44
|
+
public final class UIImage: Hashable, @unchecked Sendable {
|
|
45
|
+
public enum Orientation: Int, Sendable {
|
|
46
|
+
case up, down, left, right, upMirrored, downMirrored, leftMirrored, rightMirrored
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
enum Content {
|
|
50
|
+
case bitmap(_ImageRecipe)
|
|
51
|
+
case system(String)
|
|
52
|
+
case named(String)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
let content: Content
|
|
56
|
+
/// The size in points: pixels ÷ `scale`.
|
|
57
|
+
public let size: CGSize
|
|
58
|
+
public let scale: CGFloat
|
|
59
|
+
/// Always `.up` for decoded files: the page draws them with their EXIF
|
|
60
|
+
/// rotation applied, and their size already accounts for it.
|
|
61
|
+
public let imageOrientation: Orientation
|
|
62
|
+
/// The `CIImage` a Core Image-backed image was made from (`UIImage(ciImage:)`).
|
|
63
|
+
public let _ciImage: AnyObject?
|
|
64
|
+
/// UIKit's `renderingMode`: 0 automatic, 1 always original, 2 always template.
|
|
65
|
+
public private(set) var _renderingMode = 0
|
|
66
|
+
|
|
67
|
+
private init(content: Content, size: CGSize, scale: CGFloat, orientation: Orientation, ciImage: AnyObject?) {
|
|
68
|
+
self.content = content
|
|
69
|
+
self.size = size
|
|
70
|
+
self.scale = scale
|
|
71
|
+
imageOrientation = orientation
|
|
72
|
+
_ciImage = ciImage
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/// The same image with another rendering mode (UIKit's `withRenderingMode`),
|
|
76
|
+
/// or another bitmap of the same size (`withTintColor`).
|
|
77
|
+
public func _copy(recipe: _ImageRecipe? = nil, renderingMode: Int) -> UIImage {
|
|
78
|
+
let copy = UIImage(content: recipe.map(Content.bitmap) ?? content, size: size, scale: scale, orientation: imageOrientation,
|
|
79
|
+
ciImage: recipe == nil ? _ciImage : nil)
|
|
80
|
+
copy._renderingMode = renderingMode
|
|
81
|
+
return copy
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/// Whether the image is an SF Symbol (drawn by the page by name).
|
|
85
|
+
public var _isSymbol: Bool {
|
|
86
|
+
if case .system = content { return true }
|
|
87
|
+
return false
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/// An empty image, 0 × 0.
|
|
91
|
+
public init() {
|
|
92
|
+
content = .bitmap(.empty)
|
|
93
|
+
size = .zero
|
|
94
|
+
scale = 1
|
|
95
|
+
imageOrientation = .up
|
|
96
|
+
_ciImage = nil
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/// The image in a PNG, JPEG, GIF, WebP, BMP, HEIC or AVIF file; nil when
|
|
100
|
+
/// the data is not one. Only the header is read here; the page decodes
|
|
101
|
+
/// the file when it draws it. (Chromium and Firefox draw no HEIC.)
|
|
102
|
+
public convenience init?(data: Data) {
|
|
103
|
+
self.init(data: data, scale: 1)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
public init?(data: Data, scale: CGFloat) {
|
|
107
|
+
guard let source = _ImageSource(encoded: [UInt8](data)) else { return nil }
|
|
108
|
+
let factor = scale > 0 ? scale : 1
|
|
109
|
+
content = .bitmap(_ImageRecipe(source: source))
|
|
110
|
+
size = CGSize(width: Double(source.width) / factor, height: Double(source.height) / factor)
|
|
111
|
+
self.scale = factor
|
|
112
|
+
imageOrientation = .up
|
|
113
|
+
_ciImage = nil
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
public convenience init(cgImage: CGImage) {
|
|
117
|
+
self.init(cgImage: cgImage, scale: 1, orientation: .up)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/// `orientation` is recorded, not applied: the page draws the bitmap upright.
|
|
121
|
+
public init(cgImage: CGImage, scale: CGFloat, orientation: Orientation) {
|
|
122
|
+
let factor = scale > 0 ? scale : 1
|
|
123
|
+
content = .bitmap(cgImage._recipe)
|
|
124
|
+
size = CGSize(width: Double(cgImage.width) / factor, height: Double(cgImage.height) / factor)
|
|
125
|
+
self.scale = factor
|
|
126
|
+
imageOrientation = orientation
|
|
127
|
+
_ciImage = nil
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/// A bitmap from a recipe whose extent is its pixel grid, `(0, 0, w, h)`
|
|
131
|
+
/// (Core Image's `UIImage(ciImage:)`).
|
|
132
|
+
public init(_recipe recipe: _ImageRecipe, scale: CGFloat, ciImage: AnyObject?) {
|
|
133
|
+
let factor = scale > 0 ? scale : 1
|
|
134
|
+
let extent = recipe.extent.isNull || recipe.extent.isInfinite ? CGRect.zero : recipe.extent
|
|
135
|
+
content = .bitmap(recipe)
|
|
136
|
+
size = CGSize(width: extent.width / factor, height: extent.height / factor)
|
|
137
|
+
self.scale = factor
|
|
138
|
+
imageOrientation = .up
|
|
139
|
+
_ciImage = ciImage
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/// An SF Symbol. Never nil: the shim cannot tell which names exist, and
|
|
143
|
+
/// the page draws a placeholder for one it does not know. The size is
|
|
144
|
+
/// that of a symbol at the body text style.
|
|
145
|
+
public init?(systemName: String) {
|
|
146
|
+
content = .system(systemName)
|
|
147
|
+
size = CGSize(width: 20, height: 20)
|
|
148
|
+
scale = 1
|
|
149
|
+
imageOrientation = .up
|
|
150
|
+
_ciImage = nil
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/// An asset-catalog image. Never nil, and its size is zero: the catalog
|
|
154
|
+
/// is the page's (docs/ops-protocol.md, "Phase 5"), so only the page knows it.
|
|
155
|
+
public init?(named name: String) {
|
|
156
|
+
content = .named(name)
|
|
157
|
+
size = .zero
|
|
158
|
+
scale = 1
|
|
159
|
+
imageOrientation = .up
|
|
160
|
+
_ciImage = nil
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/// The bitmap, for an image made from data or a `CGImage`; nil for a
|
|
164
|
+
/// symbol, a catalog image, an empty image or one backed by a `CIImage`
|
|
165
|
+
/// (as on iOS).
|
|
166
|
+
public var cgImage: CGImage? {
|
|
167
|
+
guard _ciImage == nil, case .bitmap(let recipe) = content, recipe.source != nil else { return nil }
|
|
168
|
+
return CGImage(_recipe: recipe)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/// The recipe the page draws; nil for a symbol or a catalog image.
|
|
172
|
+
public var _recipe: _ImageRecipe? {
|
|
173
|
+
if case .bitmap(let recipe) = content { return recipe }
|
|
174
|
+
return nil
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
public static func == (lhs: UIImage, rhs: UIImage) -> Bool { lhs === rhs }
|
|
178
|
+
public func hash(into hasher: inout Hasher) { hasher.combine(ObjectIdentifier(self)) }
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
extension Image {
|
|
182
|
+
/// The way `Image(_:scale:orientation:label:)` takes a `CGImage`.
|
|
183
|
+
/// Recorded, not applied: the page draws the bitmap upright.
|
|
184
|
+
public enum Orientation: UInt8, CaseIterable, Hashable, Sendable {
|
|
185
|
+
case up, upMirrored, down, downMirrored, left, leftMirrored, right, rightMirrored
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/// A `UIImage`: its bitmap (drawn by the page from its recipe), or the
|
|
189
|
+
/// symbol or catalog image it names. The intrinsic size is the image's
|
|
190
|
+
/// size in points.
|
|
191
|
+
public init(uiImage: UIImage) {
|
|
192
|
+
switch uiImage.content {
|
|
193
|
+
case .system(let name): self.init(source: .system(name), isResizable: false)
|
|
194
|
+
case .named(let name): self.init(source: .named(name), isResizable: false)
|
|
195
|
+
case .bitmap(let recipe):
|
|
196
|
+
self.init(source: .bitmap(recipe, width: uiImage.size.width, height: uiImage.size.height), isResizable: false)
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
public init(_ cgImage: CGImage, scale: CGFloat, orientation: Orientation = .up, label: Text) {
|
|
201
|
+
let factor = scale > 0 ? scale : 1
|
|
202
|
+
self.init(source: .bitmap(cgImage._recipe, width: Double(cgImage.width) / factor, height: Double(cgImage.height) / factor),
|
|
203
|
+
isResizable: false)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
public init(decorative cgImage: CGImage, scale: CGFloat, orientation: Orientation = .up) {
|
|
207
|
+
self.init(cgImage, scale: scale, orientation: orientation, label: Text(""))
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/// Sends the bitmap's source to the page once (an `imagedata` op), before
|
|
211
|
+
/// the element that draws it.
|
|
212
|
+
@MainActor func _sendBitmapSource(through runtime: _Runtime) {
|
|
213
|
+
if case .bitmap(let recipe, _, _) = source, let source = recipe.source { runtime._sendImageSource(source) }
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Core Graphics' rectangle helpers that Core Image's extents need.
|
|
218
|
+
extension CGRect {
|
|
219
|
+
/// A rectangle covering the whole plane (a `clampedToExtent()` image's extent).
|
|
220
|
+
public static let infinite = CGRect(x: -Double.greatestFiniteMagnitude / 2, y: -Double.greatestFiniteMagnitude / 2,
|
|
221
|
+
width: Double.greatestFiniteMagnitude, height: Double.greatestFiniteMagnitude)
|
|
222
|
+
/// No rectangle at all (the intersection of two that do not meet).
|
|
223
|
+
public static let null = CGRect(x: Double.infinity, y: Double.infinity, width: 0, height: 0)
|
|
224
|
+
|
|
225
|
+
public var isInfinite: Bool { size.width >= Double.greatestFiniteMagnitude || size.height >= Double.greatestFiniteMagnitude }
|
|
226
|
+
public var isNull: Bool { origin.x == .infinity || origin.y == .infinity }
|
|
227
|
+
|
|
228
|
+
/// The overlap of two rectangles; `.null` when they do not overlap.
|
|
229
|
+
public func intersection(_ other: CGRect) -> CGRect {
|
|
230
|
+
if isNull || other.isNull { return .null }
|
|
231
|
+
if isInfinite { return other }
|
|
232
|
+
if other.isInfinite { return self }
|
|
233
|
+
let x0 = max(minX, other.minX), y0 = max(minY, other.minY)
|
|
234
|
+
let x1 = min(maxX, other.maxX), y1 = min(maxY, other.maxY)
|
|
235
|
+
guard x1 > x0, y1 > y0 else { return .null }
|
|
236
|
+
return CGRect(x: x0, y: y0, width: x1 - x0, height: y1 - y0)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/// The smallest rectangle containing both.
|
|
240
|
+
public func union(_ other: CGRect) -> CGRect {
|
|
241
|
+
if isNull { return other }
|
|
242
|
+
if other.isNull { return self }
|
|
243
|
+
if isInfinite || other.isInfinite { return .infinite }
|
|
244
|
+
let x0 = min(minX, other.minX), y0 = min(minY, other.minY)
|
|
245
|
+
return CGRect(x: x0, y: y0, width: max(maxX, other.maxX) - x0, height: max(maxY, other.maxY) - y0)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/// The smallest rectangle with integer coordinates containing this one.
|
|
249
|
+
public var integral: CGRect {
|
|
250
|
+
if isNull || isInfinite { return self }
|
|
251
|
+
let x0 = minX.rounded(.down), y0 = minY.rounded(.down)
|
|
252
|
+
return CGRect(x: x0, y: y0, width: maxX.rounded(.up) - x0, height: maxY.rounded(.up) - y0)
|
|
253
|
+
}
|
|
254
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/// Custom button styles: `ButtonStyle` and `.buttonStyle(_:)` with one.
|
|
2
|
+
///
|
|
3
|
+
/// A button under a custom style draws what the style's
|
|
4
|
+
/// `makeBody(configuration:)` returns in place of its label, inside the same
|
|
5
|
+
/// `button` element (the page's `plain` style: no tint and no chrome of its
|
|
6
|
+
/// own), so taps still run the action. The style's `@Environment` properties
|
|
7
|
+
/// are resolved like a view's. `isPressed` is always false: the page does not
|
|
8
|
+
/// report a press in progress, so a style's pressed look is never drawn.
|
|
9
|
+
/// A nearer `.buttonStyle` wins, custom or built in.
|
|
10
|
+
|
|
11
|
+
/// The view a style gets as `configuration.label`: the button's label.
|
|
12
|
+
public struct ButtonStyleConfiguration {
|
|
13
|
+
public struct Label {
|
|
14
|
+
let view: AnyView
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/// The button's role (`.destructive`, `.cancel`), if any.
|
|
18
|
+
public let role: ButtonRole?
|
|
19
|
+
public let label: Label
|
|
20
|
+
/// Always false in the browser (see the file comment).
|
|
21
|
+
public let isPressed: Bool
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
extension ButtonStyleConfiguration.Label: View {
|
|
25
|
+
public typealias Body = Never
|
|
26
|
+
public var body: Never { fatalError("ButtonStyleConfiguration.Label is a primitive view") }
|
|
27
|
+
}
|
|
28
|
+
extension ButtonStyleConfiguration.Label: _PrimitiveView {}
|
|
29
|
+
extension ButtonStyleConfiguration.Label: _GroupView {
|
|
30
|
+
var _children: [any View] { [view] }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/// A style that draws a button from its label.
|
|
34
|
+
@MainActor @preconcurrency
|
|
35
|
+
public protocol ButtonStyle {
|
|
36
|
+
associatedtype Body: View
|
|
37
|
+
typealias Configuration = ButtonStyleConfiguration
|
|
38
|
+
@ViewBuilder func makeBody(configuration: Configuration) -> Body
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/// The style a `.buttonStyle(_:)` put in the environment.
|
|
42
|
+
struct _CustomButtonStyle {
|
|
43
|
+
/// `_buttonStyle`'s value under a custom style; the page gets `plain`.
|
|
44
|
+
static let marker = "\u{1}custom"
|
|
45
|
+
let makeBody: @MainActor (ButtonStyleConfiguration) -> any View
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
struct _CustomButtonStyleKey: EnvironmentKey {
|
|
49
|
+
static var defaultValue: _CustomButtonStyle? { nil }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
extension EnvironmentValues {
|
|
53
|
+
var _customButtonStyle: _CustomButtonStyle? {
|
|
54
|
+
get { self[_CustomButtonStyleKey.self] }
|
|
55
|
+
set { self[_CustomButtonStyleKey.self] = newValue }
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/// Runs a style's `makeBody` as a view's body, so that the runtime resolves
|
|
60
|
+
/// the style's `@Environment` and `@State` properties (it reflects into a
|
|
61
|
+
/// stored `ButtonStyle` as into a `ViewModifier`).
|
|
62
|
+
struct _ButtonStyleBody<Style: ButtonStyle>: View {
|
|
63
|
+
let style: Style
|
|
64
|
+
let configuration: ButtonStyleConfiguration
|
|
65
|
+
var body: Style.Body { style.makeBody(configuration: configuration) }
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
extension _ButtonStyleBody: _HoldsModifier {}
|
|
69
|
+
|
|
70
|
+
nonisolated extension View {
|
|
71
|
+
/// Draws the buttons inside with `style` (see the file comment).
|
|
72
|
+
public func buttonStyle<S: ButtonStyle>(_ style: S) -> some View {
|
|
73
|
+
// Read on the main actor only, when a button's body is made.
|
|
74
|
+
nonisolated(unsafe) let style = style
|
|
75
|
+
return environment(\._buttonStyle, _CustomButtonStyle.marker)
|
|
76
|
+
.environment(\._customButtonStyle, _CustomButtonStyle { configuration in
|
|
77
|
+
_ButtonStyleBody(style: style, configuration: configuration)
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/// A host view whose children depend on the environment (a button under a
|
|
83
|
+
/// custom style); checked by the runtime ahead of `_HostView._content`.
|
|
84
|
+
protocol _EnvironmentContent {
|
|
85
|
+
func _content(in environment: EnvironmentValues) -> [any View]
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
extension Button: _EnvironmentContent {
|
|
89
|
+
func _content(in environment: EnvironmentValues) -> [any View] {
|
|
90
|
+
guard environment._buttonStyle == _CustomButtonStyle.marker, let style = environment._customButtonStyle else {
|
|
91
|
+
return [label]
|
|
92
|
+
}
|
|
93
|
+
let configuration = ButtonStyleConfiguration(role: role, label: .init(view: AnyView(label)), isPressed: false)
|
|
94
|
+
return [MainActor.assumeIsolated { style.makeBody(configuration) }]
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
// `Canvas` and its `GraphicsContext`. The renderer closure runs in Swift
|
|
2
|
+
// against a context that records what it draws (paths filled or stroked,
|
|
3
|
+
// images, text) with the context's transform, opacity, blend mode, clip and
|
|
4
|
+
// filters at that moment; the page draws the list as SVG over the canvas's
|
|
5
|
+
// box, clipped to it (Web/src/canvasDrawing.ts, docs/ops-protocol.md,
|
|
6
|
+
// "Canvas"). A canvas fills the size it is offered, which reaches Swift as a
|
|
7
|
+
// `GeometryReader`'s does: the closure runs again with the laid-out size.
|
|
8
|
+
//
|
|
9
|
+
// Not drawn: `resolveSymbol(id:)` views (none resolve), bitmaps
|
|
10
|
+
// (`Image(uiImage:)`), and filters other than blur, shadow and the color
|
|
11
|
+
// adjustments. A resolved image or text knows no size (`.zero`).
|
|
12
|
+
|
|
13
|
+
public struct Canvas<Symbols: View>: View {
|
|
14
|
+
let renderer: (inout GraphicsContext, CGSize) -> Void
|
|
15
|
+
let symbols: Symbols
|
|
16
|
+
let isOpaque: Bool
|
|
17
|
+
|
|
18
|
+
public init(opaque: Bool = false, colorMode: ColorRenderingMode = .nonLinear, rendersAsynchronously: Bool = false,
|
|
19
|
+
renderer: @escaping (inout GraphicsContext, CGSize) -> Void, @ViewBuilder symbols: () -> Symbols) {
|
|
20
|
+
self.renderer = renderer
|
|
21
|
+
self.symbols = symbols()
|
|
22
|
+
self.isOpaque = opaque
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public var body: some View {
|
|
26
|
+
GeometryReader { proxy in
|
|
27
|
+
_CanvasDrawing(size: proxy.size, renderer: renderer)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
extension Canvas where Symbols == EmptyView {
|
|
33
|
+
public init(opaque: Bool = false, colorMode: ColorRenderingMode = .nonLinear, rendersAsynchronously: Bool = false,
|
|
34
|
+
renderer: @escaping (inout GraphicsContext, CGSize) -> Void) {
|
|
35
|
+
self.init(opaque: opaque, colorMode: colorMode, rendersAsynchronously: rendersAsynchronously, renderer: renderer) { EmptyView() }
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/// The drawing of a canvas at one size: a `canvas` element whose props are the commands.
|
|
40
|
+
struct _CanvasDrawing {
|
|
41
|
+
let size: CGSize
|
|
42
|
+
let renderer: (inout GraphicsContext, CGSize) -> Void
|
|
43
|
+
}
|
|
44
|
+
extension _CanvasDrawing: _PrimitiveView {}
|
|
45
|
+
extension _CanvasDrawing: _HostView {
|
|
46
|
+
var _kind: String { "canvas" }
|
|
47
|
+
func _props(in environment: EnvironmentValues) -> _JSON {
|
|
48
|
+
let recorder = GraphicsContext._Recorder()
|
|
49
|
+
var context = GraphicsContext(recorder: recorder, environment: environment)
|
|
50
|
+
renderer(&context, size)
|
|
51
|
+
return .object([
|
|
52
|
+
"width": .number(size.width),
|
|
53
|
+
"height": .number(size.height),
|
|
54
|
+
"commands": .array(recorder.commands),
|
|
55
|
+
])
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/// What a `Canvas` draws with. A copy (as `drawLayer` gives) draws into the
|
|
60
|
+
/// same canvas with its own transform, opacity, clip and filters.
|
|
61
|
+
public struct GraphicsContext {
|
|
62
|
+
final class _Recorder {
|
|
63
|
+
var commands: [_JSON] = []
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let recorder: _Recorder
|
|
67
|
+
public var environment: EnvironmentValues
|
|
68
|
+
public var transform: CGAffineTransform = .identity
|
|
69
|
+
public var opacity: Double = 1
|
|
70
|
+
public var blendMode: BlendMode = .normal
|
|
71
|
+
/// The clip paths, already in the canvas's coordinates.
|
|
72
|
+
var clips: [Path] = []
|
|
73
|
+
var filters: [_JSON] = []
|
|
74
|
+
|
|
75
|
+
init(recorder: _Recorder, environment: EnvironmentValues) {
|
|
76
|
+
self.recorder = recorder
|
|
77
|
+
self.environment = environment
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// MARK: Transform
|
|
81
|
+
|
|
82
|
+
public mutating func translateBy(x: CGFloat, y: CGFloat) { transform = transform.translatedBy(x: x, y: y) }
|
|
83
|
+
public mutating func scaleBy(x: CGFloat, y: CGFloat) { transform = transform.scaledBy(x: x, y: y) }
|
|
84
|
+
public mutating func rotate(by angle: Angle) { transform = transform.rotated(by: angle.radians) }
|
|
85
|
+
public mutating func concatenate(_ matrix: CGAffineTransform) { transform = matrix.concatenating(transform) }
|
|
86
|
+
|
|
87
|
+
// MARK: Clip
|
|
88
|
+
|
|
89
|
+
public struct ClipOptions: OptionSet, Sendable {
|
|
90
|
+
public let rawValue: UInt32
|
|
91
|
+
public init(rawValue: UInt32) { self.rawValue = rawValue }
|
|
92
|
+
/// Clips to the outside of the path: not drawn here (the clip is left as is).
|
|
93
|
+
public static let inverse = ClipOptions(rawValue: 1)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
public mutating func clip(to path: Path, style: FillStyle = FillStyle(), options: ClipOptions = []) {
|
|
97
|
+
guard !options.contains(.inverse) else { return }
|
|
98
|
+
clips.append(path.applying(transform))
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
public var clipBoundingRect: CGRect {
|
|
102
|
+
clips.last?.boundingRect ?? CGRect(x: -.greatestFiniteMagnitude / 2, y: -.greatestFiniteMagnitude / 2,
|
|
103
|
+
width: .greatestFiniteMagnitude, height: .greatestFiniteMagnitude)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// MARK: Layers and filters
|
|
107
|
+
|
|
108
|
+
public func drawLayer(content: (inout GraphicsContext) throws -> Void) rethrows {
|
|
109
|
+
var layer = self
|
|
110
|
+
try content(&layer)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
public struct Filter: Sendable {
|
|
114
|
+
let json: _JSON
|
|
115
|
+
|
|
116
|
+
public static func blur(radius: CGFloat, options: BlurOptions = BlurOptions()) -> Filter {
|
|
117
|
+
Filter(json: .object(["blur": .number(radius)]))
|
|
118
|
+
}
|
|
119
|
+
public static func shadow(color: Color = Color(.sRGBLinear, white: 0, opacity: 0.33), radius: CGFloat,
|
|
120
|
+
x: CGFloat = 0, y: CGFloat = 0, blendMode: BlendMode = .normal, options: ShadowOptions = ShadowOptions()) -> Filter {
|
|
121
|
+
Filter(json: .object(["shadow": .object(["color": color._json, "radius": .number(radius), "x": .number(x), "y": .number(y)])]))
|
|
122
|
+
}
|
|
123
|
+
public static func grayscale(_ amount: Double) -> Filter { Filter(json: .object(["grayscale": .number(amount)])) }
|
|
124
|
+
public static func saturation(_ amount: Double) -> Filter { Filter(json: .object(["saturation": .number(amount)])) }
|
|
125
|
+
public static func brightness(_ amount: Double) -> Filter { Filter(json: .object(["brightness": .number(amount)])) }
|
|
126
|
+
public static func contrast(_ amount: Double) -> Filter { Filter(json: .object(["contrast": .number(amount)])) }
|
|
127
|
+
public static func hueRotation(_ angle: Angle) -> Filter { Filter(json: .object(["hueRotation": .number(angle.degrees)])) }
|
|
128
|
+
public static func colorInvert(_ amount: Double = 1) -> Filter { Filter(json: .object(["invert": .number(amount)])) }
|
|
129
|
+
/// Not drawn.
|
|
130
|
+
public static func colorMultiply(_ color: Color) -> Filter { Filter(json: .null) }
|
|
131
|
+
/// Not drawn.
|
|
132
|
+
public static var luminanceToAlpha: Filter { Filter(json: .null) }
|
|
133
|
+
/// Not drawn.
|
|
134
|
+
public static func alphaThreshold(min: Double, max: Double = 1, color: Color = .black) -> Filter { Filter(json: .null) }
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
public struct BlurOptions: OptionSet, Sendable {
|
|
138
|
+
public let rawValue: UInt32
|
|
139
|
+
public init(rawValue: UInt32) { self.rawValue = rawValue }
|
|
140
|
+
public static let opaque = BlurOptions(rawValue: 1)
|
|
141
|
+
public static let dithersResult = BlurOptions(rawValue: 2)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
public struct ShadowOptions: OptionSet, Sendable {
|
|
145
|
+
public let rawValue: UInt32
|
|
146
|
+
public init(rawValue: UInt32) { self.rawValue = rawValue }
|
|
147
|
+
public static let shadowAbove = ShadowOptions(rawValue: 1)
|
|
148
|
+
public static let shadowOnly = ShadowOptions(rawValue: 2)
|
|
149
|
+
public static let invertsAlpha = ShadowOptions(rawValue: 4)
|
|
150
|
+
public static let disablesGroup = ShadowOptions(rawValue: 8)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
public struct FilterOptions: OptionSet, Sendable {
|
|
154
|
+
public let rawValue: UInt32
|
|
155
|
+
public init(rawValue: UInt32) { self.rawValue = rawValue }
|
|
156
|
+
public static let linearColor = FilterOptions(rawValue: 1)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
public mutating func addFilter(_ filter: Filter, options: FilterOptions = FilterOptions()) {
|
|
160
|
+
if filter.json != .null { filters.append(filter.json) }
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// MARK: Shading
|
|
164
|
+
|
|
165
|
+
/// A paint: a color, a style, or a gradient in the context's coordinates.
|
|
166
|
+
public struct Shading: Sendable {
|
|
167
|
+
let json: _JSON
|
|
168
|
+
|
|
169
|
+
public static var foreground: Shading { Shading(json: ForegroundStyle()._json) }
|
|
170
|
+
public static func color(_ color: Color) -> Shading { Shading(json: color._json) }
|
|
171
|
+
public static func color(_ colorSpace: Color.RGBColorSpace = .sRGB, red: Double, green: Double, blue: Double, opacity: Double = 1) -> Shading {
|
|
172
|
+
.color(Color(colorSpace, red: red, green: green, blue: blue, opacity: opacity))
|
|
173
|
+
}
|
|
174
|
+
public static func color(_ colorSpace: Color.RGBColorSpace = .sRGB, white: Double, opacity: Double = 1) -> Shading {
|
|
175
|
+
.color(Color(colorSpace, white: white, opacity: opacity))
|
|
176
|
+
}
|
|
177
|
+
public static func style<S: ShapeStyle>(_ style: S) -> Shading { Shading(json: style._json) }
|
|
178
|
+
public static func palette(_ array: [Shading]) -> Shading { array.first ?? .foreground }
|
|
179
|
+
|
|
180
|
+
public static func linearGradient(_ gradient: Gradient, startPoint: CGPoint, endPoint: CGPoint, options: GradientOptions = GradientOptions()) -> Shading {
|
|
181
|
+
Shading(json: .object(["canvasLinearGradient": .object([
|
|
182
|
+
"stops": gradient._stopsJSON,
|
|
183
|
+
"start": point(startPoint), "end": point(endPoint),
|
|
184
|
+
])]))
|
|
185
|
+
}
|
|
186
|
+
public static func radialGradient(_ gradient: Gradient, center: CGPoint, startRadius: CGFloat, endRadius: CGFloat, options: GradientOptions = GradientOptions()) -> Shading {
|
|
187
|
+
Shading(json: .object(["canvasRadialGradient": .object([
|
|
188
|
+
"stops": gradient._stopsJSON,
|
|
189
|
+
"center": point(center),
|
|
190
|
+
"startRadius": .number(startRadius), "endRadius": .number(endRadius),
|
|
191
|
+
])]))
|
|
192
|
+
}
|
|
193
|
+
/// Drawn as its first color.
|
|
194
|
+
public static func conicGradient(_ gradient: Gradient, center: CGPoint, angle: Angle = Angle(), options: GradientOptions = GradientOptions()) -> Shading {
|
|
195
|
+
.color(gradient.stops.first?.color ?? .clear)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
static func point(_ p: CGPoint) -> _JSON { .object(["x": .number(p.x), "y": .number(p.y)]) }
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
public struct GradientOptions: OptionSet, Sendable {
|
|
202
|
+
public let rawValue: UInt32
|
|
203
|
+
public init(rawValue: UInt32) { self.rawValue = rawValue }
|
|
204
|
+
public static let `repeat` = GradientOptions(rawValue: 1)
|
|
205
|
+
public static let mirror = GradientOptions(rawValue: 2)
|
|
206
|
+
public static let linearColor = GradientOptions(rawValue: 4)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// MARK: Drawing
|
|
210
|
+
|
|
211
|
+
public func fill(_ path: Path, with shading: Shading, style: FillStyle = FillStyle()) {
|
|
212
|
+
var command: [String: _JSON] = ["op": .string("fill"), "path": .string(path._svg), "shading": shading.json]
|
|
213
|
+
if style.isEOFilled { command["evenOdd"] = .bool(true) }
|
|
214
|
+
record(command)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
public func stroke(_ path: Path, with shading: Shading, style: StrokeStyle) {
|
|
218
|
+
var command: [String: _JSON] = [
|
|
219
|
+
"op": .string("stroke"), "path": .string(path._svg), "shading": shading.json,
|
|
220
|
+
"lineWidth": .number(style.lineWidth),
|
|
221
|
+
]
|
|
222
|
+
command["lineCap"] = .string(style.lineCap == .round ? "round" : style.lineCap == .square ? "square" : "butt")
|
|
223
|
+
command["lineJoin"] = .string(style.lineJoin == .round ? "round" : style.lineJoin == .bevel ? "bevel" : "miter")
|
|
224
|
+
command["miterLimit"] = .number(style.miterLimit)
|
|
225
|
+
if !style.dash.isEmpty {
|
|
226
|
+
command["dash"] = .array(style.dash.map { .number($0) })
|
|
227
|
+
command["dashPhase"] = .number(style.dashPhase)
|
|
228
|
+
}
|
|
229
|
+
record(command)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
public func stroke(_ path: Path, with shading: Shading, lineWidth: CGFloat = 1) {
|
|
233
|
+
stroke(path, with: shading, style: StrokeStyle(lineWidth: lineWidth))
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/// An image or text made ready to draw (`resolve(_:)`); its size is not known here.
|
|
237
|
+
public struct ResolvedImage {
|
|
238
|
+
let image: Image
|
|
239
|
+
public var size: CGSize { .zero }
|
|
240
|
+
public var baseline: CGFloat { 0 }
|
|
241
|
+
public var shading: Shading?
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
public struct ResolvedText {
|
|
245
|
+
let text: Text
|
|
246
|
+
public var shading: Shading = .foreground
|
|
247
|
+
public func measure(in size: CGSize) -> CGSize { .zero }
|
|
248
|
+
public func firstBaseline(in size: CGSize) -> CGFloat { 0 }
|
|
249
|
+
public func lastBaseline(in size: CGSize) -> CGFloat { 0 }
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/// A view passed to `Canvas(renderer:symbols:)`; none resolve here.
|
|
253
|
+
public struct ResolvedSymbol {
|
|
254
|
+
public var size: CGSize { .zero }
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
public func resolve(_ image: Image) -> ResolvedImage { ResolvedImage(image: image) }
|
|
258
|
+
public func resolve(_ text: Text) -> ResolvedText { ResolvedText(text: text) }
|
|
259
|
+
public func resolveSymbol<ID: Hashable>(id: ID) -> ResolvedSymbol? { nil }
|
|
260
|
+
|
|
261
|
+
public func draw(_ image: ResolvedImage, at point: CGPoint, anchor: UnitPoint = .center) {
|
|
262
|
+
drawImage(image.image, at: point, anchor: anchor, shading: image.shading)
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
public func draw(_ image: ResolvedImage, in rect: CGRect, style: FillStyle = FillStyle()) {
|
|
266
|
+
drawImage(image.image, in: rect, shading: image.shading)
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
public func draw(_ image: Image, at point: CGPoint, anchor: UnitPoint = .center) {
|
|
270
|
+
drawImage(image, at: point, anchor: anchor, shading: nil)
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
public func draw(_ image: Image, in rect: CGRect, style: FillStyle = FillStyle()) {
|
|
274
|
+
drawImage(image, in: rect, shading: nil)
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
public func draw(_ text: ResolvedText, at point: CGPoint, anchor: UnitPoint = .center) {
|
|
278
|
+
drawText(text.text, at: point, anchor: anchor, shading: text.shading)
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
public func draw(_ text: ResolvedText, in rect: CGRect) {
|
|
282
|
+
drawText(text.text, at: CGPoint(x: rect.minX, y: rect.minY), anchor: .topLeading, shading: text.shading)
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
public func draw(_ text: Text, at point: CGPoint, anchor: UnitPoint = .center) {
|
|
286
|
+
drawText(text, at: point, anchor: anchor, shading: .foreground)
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
public func draw(_ text: Text, in rect: CGRect) {
|
|
290
|
+
drawText(text, at: CGPoint(x: rect.minX, y: rect.minY), anchor: .topLeading, shading: .foreground)
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
public func draw(_ symbol: ResolvedSymbol, at point: CGPoint, anchor: UnitPoint = .center) {}
|
|
294
|
+
public func draw(_ symbol: ResolvedSymbol, in rect: CGRect) {}
|
|
295
|
+
|
|
296
|
+
private func drawImage(_ image: Image, at point: CGPoint, anchor: UnitPoint, shading: Shading?) {
|
|
297
|
+
var command: [String: _JSON] = [
|
|
298
|
+
"op": .string("image"), "image": image._props(in: environment),
|
|
299
|
+
"x": .number(point.x), "y": .number(point.y), "anchor": anchor._json,
|
|
300
|
+
]
|
|
301
|
+
if let shading { command["shading"] = shading.json }
|
|
302
|
+
record(command)
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
private func drawImage(_ image: Image, in rect: CGRect, shading: Shading?) {
|
|
306
|
+
var command: [String: _JSON] = [
|
|
307
|
+
"op": .string("image"), "image": image._props(in: environment),
|
|
308
|
+
"x": .number(rect.minX), "y": .number(rect.minY), "anchor": UnitPoint.topLeading._json,
|
|
309
|
+
"width": .number(rect.width), "height": .number(rect.height),
|
|
310
|
+
]
|
|
311
|
+
if let shading { command["shading"] = shading.json }
|
|
312
|
+
record(command)
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
private func drawText(_ text: Text, at point: CGPoint, anchor: UnitPoint, shading: Shading) {
|
|
316
|
+
var command: [String: _JSON] = [
|
|
317
|
+
"op": .string("text"), "text": .string(text.content),
|
|
318
|
+
"x": .number(point.x), "y": .number(point.y), "anchor": anchor._json,
|
|
319
|
+
"shading": shading.json,
|
|
320
|
+
]
|
|
321
|
+
if let font = environment.font { command["font"] = font._json }
|
|
322
|
+
record(command)
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/// Adds the context's state to a command and records it.
|
|
326
|
+
private func record(_ command: [String: _JSON]) {
|
|
327
|
+
var command = command
|
|
328
|
+
if !transform.isIdentity {
|
|
329
|
+
command["transform"] = .array([transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty].map { .number($0) })
|
|
330
|
+
}
|
|
331
|
+
if opacity < 1 { command["opacity"] = .number(max(0, opacity)) }
|
|
332
|
+
if blendMode != .normal { command["blendMode"] = .string(blendMode._css) }
|
|
333
|
+
if !clips.isEmpty { command["clips"] = .array(clips.map { .string($0._svg) }) }
|
|
334
|
+
if !filters.isEmpty { command["filters"] = .array(filters) }
|
|
335
|
+
recorder.commands.append(.object(command))
|
|
336
|
+
}
|
|
337
|
+
}
|