@swiftbrowser/swift 0.1.0 → 0.2.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 +65 -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 +105 -7
- package/Sources/SwiftUI/API/Entry.swift +8 -0
- package/Sources/SwiftUI/API/Environment.swift +93 -9
- package/Sources/SwiftUI/API/EnvironmentSendable.swift +6 -0
- package/Sources/SwiftUI/API/Focus.swift +11 -3
- package/Sources/SwiftUI/API/Gauge.swift +3 -2
- 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 +67 -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 +80 -10
- 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 +11 -2
- 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 +164 -37
- 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 +96 -0
- package/Sources/SwiftUI/API/Shape.swift +214 -0
- package/Sources/SwiftUI/API/ShapeStyle.swift +105 -7
- 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 +10 -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 +498 -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 +39 -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,655 @@
|
|
|
1
|
+
// `NSItemProvider`, Foundation's carrier for content offered in several
|
|
2
|
+
// types (a drag, a paste, a share extension's input, a link preview's
|
|
3
|
+
// image), which corelibs Foundation does not have. In the browser a provider
|
|
4
|
+
// is a list of registrations kept in memory: data, a file, an object or a
|
|
5
|
+
// `Transferable` value, each under a content type. Loads run as tasks on the
|
|
6
|
+
// browser's one thread and call their completion handlers when done; a
|
|
7
|
+
// file representation is a copy in the temporary directory, removed once the
|
|
8
|
+
// handler returns, as on iOS.
|
|
9
|
+
//
|
|
10
|
+
// SwiftUI's drag-and-drop API takes providers, so it lives here (the SwiftUI
|
|
11
|
+
// shim cannot see this module): `onDrop`, `onDrag`, `DropInfo`,
|
|
12
|
+
// `DropDelegate`. The page has no drag and drop between views or apps yet,
|
|
13
|
+
// so the views are left as they are and nothing is ever dropped
|
|
14
|
+
// (docs/ops-protocol.md, "Sharing and media").
|
|
15
|
+
|
|
16
|
+
import Foundation
|
|
17
|
+
import SwiftUI
|
|
18
|
+
|
|
19
|
+
#if os(WASI)
|
|
20
|
+
/// Foundation's `Progress`, which corelibs Foundation leaves out on WASI: a
|
|
21
|
+
/// count of units done, children that count for part of their parent, and
|
|
22
|
+
/// cancelling, pausing and resuming (which run the handlers; the work itself
|
|
23
|
+
/// decides what they mean). It is an `NSObject`, so `observe(\.fractionCompleted)`
|
|
24
|
+
/// works (KeyValueObserving.swift), as ButtonKit follows one.
|
|
25
|
+
open class Progress: NSObject, @unchecked Sendable {
|
|
26
|
+
/// The units this progress itself has done; finished children add their pending units.
|
|
27
|
+
private var ownCompleted: Int64 = 0
|
|
28
|
+
private var children: [(progress: Progress, pending: Int64)] = []
|
|
29
|
+
|
|
30
|
+
open var totalUnitCount: Int64
|
|
31
|
+
|
|
32
|
+
/// Units done: this progress's own, plus each finished child's pending units.
|
|
33
|
+
open var completedUnitCount: Int64 {
|
|
34
|
+
get { ownCompleted + finishedChildUnits }
|
|
35
|
+
set { ownCompleted = newValue - finishedChildUnits }
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
open var localizedDescription: String!
|
|
39
|
+
open var localizedAdditionalDescription: String!
|
|
40
|
+
open private(set) var isCancelled = false
|
|
41
|
+
open var isCancellable = true
|
|
42
|
+
open var isPausable = false
|
|
43
|
+
open private(set) var isPaused = false
|
|
44
|
+
open var cancellationHandler: (@Sendable () -> Void)?
|
|
45
|
+
open var pausingHandler: (@Sendable () -> Void)?
|
|
46
|
+
open var resumingHandler: (@Sendable () -> Void)?
|
|
47
|
+
|
|
48
|
+
public init(totalUnitCount: Int64) {
|
|
49
|
+
self.totalUnitCount = totalUnitCount
|
|
50
|
+
super.init()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
public convenience override init() {
|
|
54
|
+
self.init(totalUnitCount: -1)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/// A progress that becomes `parent`'s child (for `pendingUnitCount` of its units, once it has a total).
|
|
58
|
+
public convenience init(totalUnitCount: Int64, parent: Progress, pendingUnitCount: Int64) {
|
|
59
|
+
self.init(totalUnitCount: totalUnitCount)
|
|
60
|
+
parent.addChild(self, withPendingUnitCount: pendingUnitCount)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
open class func discreteProgress(totalUnitCount: Int64) -> Progress {
|
|
64
|
+
Progress(totalUnitCount: totalUnitCount)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/// The progress current on this thread: none, the browser build has no implicit tree.
|
|
68
|
+
open class func current() -> Progress? { nil }
|
|
69
|
+
|
|
70
|
+
open func addChild(_ child: Progress, withPendingUnitCount inUnitCount: Int64) {
|
|
71
|
+
children.append((child, inUnitCount))
|
|
72
|
+
if isCancelled { child.cancel() }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
private var finishedChildUnits: Int64 {
|
|
76
|
+
children.reduce(0) { $0 + ($1.progress.isFinished ? $1.pending : 0) }
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/// Done units over the total, counting the unfinished children's fractions; 0 while indeterminate.
|
|
80
|
+
open var fractionCompleted: Double {
|
|
81
|
+
guard totalUnitCount > 0 else { return 0 }
|
|
82
|
+
let running = children.reduce(0.0) { $0 + ($1.progress.isFinished ? 0 : $1.progress.fractionCompleted * Double($1.pending)) }
|
|
83
|
+
return min(1, max(0, (Double(completedUnitCount) + running) / Double(totalUnitCount)))
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/// As on Apple platforms: a negative count, or both counts zero.
|
|
87
|
+
open var isIndeterminate: Bool {
|
|
88
|
+
totalUnitCount < 0 || completedUnitCount < 0 || (totalUnitCount == 0 && completedUnitCount == 0)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
open var isFinished: Bool { totalUnitCount > 0 && completedUnitCount >= totalUnitCount }
|
|
92
|
+
|
|
93
|
+
open func cancel() {
|
|
94
|
+
guard !isCancelled else { return }
|
|
95
|
+
isCancelled = true
|
|
96
|
+
cancellationHandler?()
|
|
97
|
+
for child in children { child.progress.cancel() }
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
open func pause() {
|
|
101
|
+
guard !isPaused else { return }
|
|
102
|
+
isPaused = true
|
|
103
|
+
pausingHandler?()
|
|
104
|
+
for child in children { child.progress.pause() }
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
open func resume() {
|
|
108
|
+
guard isPaused else { return }
|
|
109
|
+
isPaused = false
|
|
110
|
+
resumingHandler?()
|
|
111
|
+
for child in children { child.progress.resume() }
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
#endif
|
|
115
|
+
|
|
116
|
+
// MARK: - Reading and writing objects
|
|
117
|
+
|
|
118
|
+
/// A type an item provider can hand out as an object (`loadObject(ofClass:)`).
|
|
119
|
+
/// `String`, `URL` and `UIImage` are; on iOS the Objective-C classes behind
|
|
120
|
+
/// them are.
|
|
121
|
+
public protocol NSItemProviderReading {
|
|
122
|
+
static var readableTypeIdentifiersForItemProvider: [String] { get }
|
|
123
|
+
static func object(withItemProviderData data: Data, typeIdentifier: String) throws -> Self
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/// A type an item provider can be made from (`NSItemProvider(object:)`).
|
|
127
|
+
public protocol NSItemProviderWriting {
|
|
128
|
+
static var writableTypeIdentifiersForItemProvider: [String] { get }
|
|
129
|
+
var writableTypeIdentifiersForItemProvider: [String] { get }
|
|
130
|
+
func loadData(withTypeIdentifier typeIdentifier: String,
|
|
131
|
+
forItemProviderCompletionHandler completionHandler: @escaping @Sendable (Data?, (any Error)?) -> Void) -> Progress?
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
extension NSItemProviderWriting {
|
|
135
|
+
public var writableTypeIdentifiersForItemProvider: [String] { Self.writableTypeIdentifiersForItemProvider }
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
extension String: NSItemProviderReading, NSItemProviderWriting {
|
|
139
|
+
public static var readableTypeIdentifiersForItemProvider: [String] { [UTType.utf8PlainText.identifier, UTType.plainText.identifier, UTType.text.identifier] }
|
|
140
|
+
public static func object(withItemProviderData data: Data, typeIdentifier: String) throws -> String {
|
|
141
|
+
String(decoding: data, as: UTF8.self)
|
|
142
|
+
}
|
|
143
|
+
public static var writableTypeIdentifiersForItemProvider: [String] { [UTType.utf8PlainText.identifier] }
|
|
144
|
+
public func loadData(withTypeIdentifier typeIdentifier: String,
|
|
145
|
+
forItemProviderCompletionHandler completionHandler: @escaping @Sendable (Data?, (any Error)?) -> Void) -> Progress? {
|
|
146
|
+
completionHandler(Data(utf8), nil)
|
|
147
|
+
return nil
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
extension URL: NSItemProviderReading, NSItemProviderWriting {
|
|
152
|
+
public static var readableTypeIdentifiersForItemProvider: [String] { [UTType.url.identifier, UTType.fileURL.identifier, UTType.plainText.identifier] }
|
|
153
|
+
public static func object(withItemProviderData data: Data, typeIdentifier: String) throws -> URL {
|
|
154
|
+
let text = String(decoding: data, as: UTF8.self).trimmingCharacters(in: .whitespacesAndNewlines)
|
|
155
|
+
guard let url = URL(string: text) else { throw CocoaError(.fileReadCorruptFile) }
|
|
156
|
+
return url
|
|
157
|
+
}
|
|
158
|
+
public static var writableTypeIdentifiersForItemProvider: [String] { [UTType.url.identifier] }
|
|
159
|
+
public var writableTypeIdentifiersForItemProvider: [String] { [(isFileURL ? UTType.fileURL : UTType.url).identifier] }
|
|
160
|
+
public func loadData(withTypeIdentifier typeIdentifier: String,
|
|
161
|
+
forItemProviderCompletionHandler completionHandler: @escaping @Sendable (Data?, (any Error)?) -> Void) -> Progress? {
|
|
162
|
+
completionHandler(Data(absoluteString.utf8), nil)
|
|
163
|
+
return nil
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/// UIKit's image (the SwiftUI shim's `UIImage`, which this module sees):
|
|
168
|
+
/// read from any image file the page can draw; written as the file it was
|
|
169
|
+
/// made from, unchanged. An image with no file (a drawing, a Core Image
|
|
170
|
+
/// result, a symbol) offers no data, as it has no bytes in Swift.
|
|
171
|
+
extension UIImage: NSItemProviderReading, NSItemProviderWriting {
|
|
172
|
+
public static var readableTypeIdentifiersForItemProvider: [String] {
|
|
173
|
+
[UTType.png, .jpeg, .gif, .heic, .webP, .tiff, .bmp, .image].map(\.identifier)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
public static func object(withItemProviderData data: Data, typeIdentifier: String) throws -> Self {
|
|
177
|
+
guard let image = UIImage(data: data) as? Self else { throw CocoaError(.fileReadCorruptFile) }
|
|
178
|
+
return image
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
public static var writableTypeIdentifiersForItemProvider: [String] { [UTType.png.identifier] }
|
|
182
|
+
|
|
183
|
+
public var writableTypeIdentifiersForItemProvider: [String] {
|
|
184
|
+
guard let file = _encodedFile, let type = UTType(mimeType: file.mime) else { return [UTType.png.identifier] }
|
|
185
|
+
return [type.identifier]
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
public func loadData(withTypeIdentifier typeIdentifier: String,
|
|
189
|
+
forItemProviderCompletionHandler completionHandler: @escaping @Sendable (Data?, (any Error)?) -> Void) -> Progress? {
|
|
190
|
+
if let file = _encodedFile { completionHandler(file.data, nil) } else { completionHandler(nil, CocoaError(.fileReadNoPermission)) }
|
|
191
|
+
return nil
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// MARK: - NSItemProvider
|
|
196
|
+
|
|
197
|
+
/// Content offered in one or more types, loaded on request.
|
|
198
|
+
open class NSItemProvider: NSObject, @unchecked Sendable {
|
|
199
|
+
public enum FileOptions: Int, Sendable { case openInPlace = 1 }
|
|
200
|
+
public struct _FileOptions: OptionSet, Sendable {
|
|
201
|
+
public let rawValue: Int
|
|
202
|
+
public init(rawValue: Int) { self.rawValue = rawValue }
|
|
203
|
+
public static let openInPlace = _FileOptions(rawValue: 1)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/// Who may see a registration. Kept: the app is alone in the browser.
|
|
207
|
+
public enum RepresentationVisibility: Int, Sendable { case all = 0, team = 1, group = 2, ownProcess = 3 }
|
|
208
|
+
|
|
209
|
+
public typealias CompletionHandler = @Sendable (Any?, (any Error)?) -> Void
|
|
210
|
+
public typealias LoadHandler = @Sendable (CompletionHandler?, AnyClass?, [AnyHashable: Any]?) -> Void
|
|
211
|
+
|
|
212
|
+
public static let errorDomain = "NSItemProviderErrorDomain"
|
|
213
|
+
public enum ErrorCode: Int, Sendable {
|
|
214
|
+
case unknownError = -1, itemUnavailableError = -1000, unexpectedValueClassError = -1100, unavailableCoercionError = -1200
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
struct Registration {
|
|
218
|
+
let type: UTType
|
|
219
|
+
/// The content, when asked for; nil when it has none in this type.
|
|
220
|
+
let load: () async throws -> _TransferContent
|
|
221
|
+
/// The object it was registered from (`loadObject` and `loadItem` hand it back).
|
|
222
|
+
let object: Any?
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
private var registrations: [Registration] = []
|
|
226
|
+
|
|
227
|
+
/// The name a receiver gives the content (a file's name, without its extension).
|
|
228
|
+
open var suggestedName: String?
|
|
229
|
+
|
|
230
|
+
public override init() { super.init() }
|
|
231
|
+
|
|
232
|
+
/// A provider of `object` in each type it writes.
|
|
233
|
+
public convenience init(object: any NSItemProviderWriting) {
|
|
234
|
+
self.init()
|
|
235
|
+
registerObject(object, visibility: .all)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/// A provider of the file at `fileURL`, typed by its extension; nil for a
|
|
239
|
+
/// URL that is not a file's.
|
|
240
|
+
public convenience init?(contentsOf fileURL: URL?) {
|
|
241
|
+
guard let fileURL, fileURL.isFileURL else { return nil }
|
|
242
|
+
self.init()
|
|
243
|
+
let type = UTType(filenameExtension: fileURL.pathExtension) ?? .data
|
|
244
|
+
suggestedName = fileURL.deletingPathExtension().lastPathComponent
|
|
245
|
+
registrations.append(Registration(type: type, load: {
|
|
246
|
+
_TransferContent(contentType: type, file: fileURL, isOriginalFile: true, suggestedName: fileURL.deletingPathExtension().lastPathComponent)
|
|
247
|
+
}, object: fileURL))
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/// A provider of `item` (a string, URL, data or other value) as `typeIdentifier`.
|
|
251
|
+
public convenience init(item: Any?, typeIdentifier: String?) {
|
|
252
|
+
self.init()
|
|
253
|
+
guard let item, let typeIdentifier else { return }
|
|
254
|
+
let type = Self.type(typeIdentifier)
|
|
255
|
+
registrations.append(Registration(type: type, load: {
|
|
256
|
+
guard let data = Self.data(of: item) else { throw Self.error(.unavailableCoercionError) }
|
|
257
|
+
return _TransferContent(contentType: type, data: data)
|
|
258
|
+
}, object: item))
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// MARK: Registering
|
|
262
|
+
|
|
263
|
+
open func registerObject(_ object: any NSItemProviderWriting, visibility: RepresentationVisibility) {
|
|
264
|
+
let box = _UnsafeBox(object)
|
|
265
|
+
for identifier in object.writableTypeIdentifiersForItemProvider {
|
|
266
|
+
let type = Self.type(identifier)
|
|
267
|
+
registrations.append(Registration(type: type, load: {
|
|
268
|
+
let data = try await Self.loadData { box.value.loadData(withTypeIdentifier: identifier, forItemProviderCompletionHandler: $0) }
|
|
269
|
+
return _TransferContent(contentType: type, data: data)
|
|
270
|
+
}, object: object))
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
open func registerDataRepresentation(forTypeIdentifier typeIdentifier: String, visibility: RepresentationVisibility,
|
|
275
|
+
loadHandler: @escaping @Sendable (@escaping @Sendable (Data?, (any Error)?) -> Void) -> Progress?) {
|
|
276
|
+
registerDataRepresentation(for: Self.type(typeIdentifier), visibility: visibility, loadHandler: loadHandler)
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
open func registerDataRepresentation(for contentType: UTType, visibility: RepresentationVisibility = .all,
|
|
280
|
+
loadHandler: @escaping @Sendable (@escaping @Sendable (Data?, (any Error)?) -> Void) -> Progress?) {
|
|
281
|
+
registrations.append(Registration(type: contentType, load: {
|
|
282
|
+
_TransferContent(contentType: contentType, data: try await Self.loadData(loadHandler))
|
|
283
|
+
}, object: nil))
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
open func registerFileRepresentation(forTypeIdentifier typeIdentifier: String, fileOptions: _FileOptions = [],
|
|
287
|
+
visibility: RepresentationVisibility,
|
|
288
|
+
loadHandler: @escaping @Sendable (@escaping @Sendable (URL?, Bool, (any Error)?) -> Void) -> Progress?) {
|
|
289
|
+
registerFileRepresentation(for: Self.type(typeIdentifier), visibility: visibility,
|
|
290
|
+
openInPlace: fileOptions.contains(.openInPlace), loadHandler: loadHandler)
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
open func registerFileRepresentation(for contentType: UTType, visibility: RepresentationVisibility = .all, openInPlace: Bool = false,
|
|
294
|
+
loadHandler: @escaping @Sendable (@escaping @Sendable (URL?, Bool, (any Error)?) -> Void) -> Progress?) {
|
|
295
|
+
registrations.append(Registration(type: contentType, load: {
|
|
296
|
+
let (url, original) = try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<(URL, Bool), any Error>) in
|
|
297
|
+
_ = loadHandler { url, original, error in
|
|
298
|
+
if let url { continuation.resume(returning: (url, original)) }
|
|
299
|
+
else { continuation.resume(throwing: error ?? Self.error(.itemUnavailableError)) }
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
return _TransferContent(contentType: contentType, file: url, isOriginalFile: original)
|
|
303
|
+
}, object: nil))
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/// The old, item-based registration: `loadHandler` is asked for the item
|
|
307
|
+
/// and hands it to the completion handler it is given.
|
|
308
|
+
open func registerItem(forTypeIdentifier typeIdentifier: String, loadHandler: @escaping LoadHandler) {
|
|
309
|
+
let type = Self.type(typeIdentifier)
|
|
310
|
+
registrations.append(Registration(type: type, load: {
|
|
311
|
+
let item: Any? = try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<_UnsafeBox<Any?>, any Error>) in
|
|
312
|
+
loadHandler({ item, error in
|
|
313
|
+
if let error { continuation.resume(throwing: error) } else { continuation.resume(returning: _UnsafeBox(item)) }
|
|
314
|
+
}, nil, nil)
|
|
315
|
+
}.value
|
|
316
|
+
if let url = item as? URL, url.isFileURL { return _TransferContent(contentType: type, file: url, isOriginalFile: true) }
|
|
317
|
+
guard let item, let data = Self.data(of: item) else { throw Self.error(.unavailableCoercionError) }
|
|
318
|
+
return _TransferContent(contentType: type, data: data)
|
|
319
|
+
}, object: nil))
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/// A `Transferable` value, in every type it exports.
|
|
323
|
+
public func register<T: Transferable>(_ transferable: @autoclosure @escaping @Sendable () -> T) {
|
|
324
|
+
for type in T.exportedContentTypes() {
|
|
325
|
+
registrations.append(Registration(type: type, load: {
|
|
326
|
+
guard let content = try await _Transfer.export(transferable(), as: type) else { throw Self.error(.unavailableCoercionError) }
|
|
327
|
+
return content
|
|
328
|
+
}, object: nil))
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// MARK: What it offers
|
|
333
|
+
|
|
334
|
+
open var registeredTypeIdentifiers: [String] { registeredContentTypes.map(\.identifier) }
|
|
335
|
+
|
|
336
|
+
open var registeredContentTypes: [UTType] {
|
|
337
|
+
var seen = Set<UTType>()
|
|
338
|
+
return registrations.map(\.type).filter { seen.insert($0).inserted }
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
open func registeredTypeIdentifiers(fileOptions: _FileOptions) -> [String] { registeredTypeIdentifiers }
|
|
342
|
+
|
|
343
|
+
open func registeredContentTypes(conformingTo contentType: UTType) -> [UTType] {
|
|
344
|
+
registeredContentTypes.filter { $0.conforms(to: contentType) }
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
open var registeredContentTypesForOpenInPlace: [UTType] { [] }
|
|
348
|
+
|
|
349
|
+
open func hasItemConformingToTypeIdentifier(_ typeIdentifier: String) -> Bool {
|
|
350
|
+
let wanted = Self.type(typeIdentifier)
|
|
351
|
+
return registrations.contains { $0.type.conforms(to: wanted) }
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
open func hasRepresentationConforming(toTypeIdentifier typeIdentifier: String, fileOptions: _FileOptions = []) -> Bool {
|
|
355
|
+
hasItemConformingToTypeIdentifier(typeIdentifier)
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
open func canLoadObject(ofClass aClass: any NSItemProviderReading.Type) -> Bool {
|
|
359
|
+
registrations.contains { registration in
|
|
360
|
+
registration.object.map { Swift.type(of: $0) == aClass } ?? false
|
|
361
|
+
|| aClass.readableTypeIdentifiersForItemProvider.contains { registration.type.conforms(to: Self.type($0)) }
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// MARK: Loading
|
|
366
|
+
|
|
367
|
+
/// The content of the first registration conforming to `contentType`.
|
|
368
|
+
func content(conformingTo contentType: UTType) async throws -> _TransferContent {
|
|
369
|
+
guard let registration = registrations.first(where: { $0.type.conforms(to: contentType) }) else {
|
|
370
|
+
throw Self.error(.itemUnavailableError)
|
|
371
|
+
}
|
|
372
|
+
var content = try await registration.load()
|
|
373
|
+
if content.suggestedName == nil { content.suggestedName = suggestedName }
|
|
374
|
+
return content
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
@discardableResult
|
|
378
|
+
open func loadDataRepresentation(forTypeIdentifier typeIdentifier: String,
|
|
379
|
+
completionHandler: @escaping @Sendable (Data?, (any Error)?) -> Void) -> Progress {
|
|
380
|
+
loadDataRepresentation(for: Self.type(typeIdentifier), completionHandler: completionHandler)
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
@discardableResult
|
|
384
|
+
open func loadDataRepresentation(for contentType: UTType,
|
|
385
|
+
completionHandler: @escaping @Sendable (Data?, (any Error)?) -> Void) -> Progress {
|
|
386
|
+
run { () async throws -> Data in try await self.content(conformingTo: contentType).loadData() } done: { result in
|
|
387
|
+
switch result {
|
|
388
|
+
case .success(let data): completionHandler(data, nil)
|
|
389
|
+
case .failure(let error): completionHandler(nil, error)
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/// The content as a file: a copy in the temporary directory, removed once
|
|
395
|
+
/// `completionHandler` returns.
|
|
396
|
+
@discardableResult
|
|
397
|
+
open func loadFileRepresentation(forTypeIdentifier typeIdentifier: String,
|
|
398
|
+
completionHandler: @escaping @Sendable (URL?, (any Error)?) -> Void) -> Progress {
|
|
399
|
+
loadFileRepresentation(for: Self.type(typeIdentifier), openInPlace: false) { url, _, error in completionHandler(url, error) }
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
@discardableResult
|
|
403
|
+
open func loadFileRepresentation(for contentType: UTType, openInPlace: Bool = false,
|
|
404
|
+
completionHandler: @escaping @Sendable (URL?, Bool, (any Error)?) -> Void) -> Progress {
|
|
405
|
+
run { () async throws -> ReceivedTransferredFile in
|
|
406
|
+
try Self.receivedFile(try await self.content(conformingTo: contentType), inPlace: openInPlace)
|
|
407
|
+
} done: { result in
|
|
408
|
+
switch result {
|
|
409
|
+
case .success(let file):
|
|
410
|
+
completionHandler(file.file, file.isOriginalFile, nil)
|
|
411
|
+
if !file.isOriginalFile { try? FileManager.default.removeItem(at: file.file) }
|
|
412
|
+
case .failure(let error):
|
|
413
|
+
completionHandler(nil, false, error)
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
@discardableResult
|
|
419
|
+
open func loadInPlaceFileRepresentation(forTypeIdentifier typeIdentifier: String,
|
|
420
|
+
completionHandler: @escaping @Sendable (URL?, Bool, (any Error)?) -> Void) -> Progress {
|
|
421
|
+
loadFileRepresentation(for: Self.type(typeIdentifier), openInPlace: true, completionHandler: completionHandler)
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/// The registered object itself when it is of `aClass`, else one made
|
|
425
|
+
/// from the first readable type's data.
|
|
426
|
+
@discardableResult
|
|
427
|
+
open func loadObject<T: NSItemProviderReading>(ofClass aClass: T.Type,
|
|
428
|
+
completionHandler: @escaping @Sendable (T?, (any Error)?) -> Void) -> Progress {
|
|
429
|
+
run { () async throws -> _UnsafeBox<T> in
|
|
430
|
+
if let object = self.registrations.lazy.compactMap({ $0.object as? T }).first { return _UnsafeBox(object) }
|
|
431
|
+
for identifier in T.readableTypeIdentifiersForItemProvider {
|
|
432
|
+
let type = Self.type(identifier)
|
|
433
|
+
guard self.registrations.contains(where: { $0.type.conforms(to: type) }) else { continue }
|
|
434
|
+
let data = try await self.content(conformingTo: type).loadData()
|
|
435
|
+
return _UnsafeBox(try T.object(withItemProviderData: data, typeIdentifier: identifier))
|
|
436
|
+
}
|
|
437
|
+
throw Self.error(.unavailableCoercionError)
|
|
438
|
+
} done: { result in
|
|
439
|
+
switch result {
|
|
440
|
+
case .success(let box): completionHandler(box.value, nil)
|
|
441
|
+
case .failure(let error): completionHandler(nil, error)
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/// The old, item-based load: the registered object, a file's URL, a
|
|
447
|
+
/// string for text, a URL for a link, a `UIImage` for image data, else the data.
|
|
448
|
+
open func loadItem(forTypeIdentifier typeIdentifier: String, options: [AnyHashable: Any]? = nil,
|
|
449
|
+
completionHandler: CompletionHandler? = nil) {
|
|
450
|
+
let wanted = Self.type(typeIdentifier)
|
|
451
|
+
_ = run { () async throws -> _UnsafeBox<Any?> in
|
|
452
|
+
guard let registration = self.registrations.first(where: { $0.type.conforms(to: wanted) }) else {
|
|
453
|
+
throw Self.error(.itemUnavailableError)
|
|
454
|
+
}
|
|
455
|
+
if let object = registration.object { return _UnsafeBox(object) }
|
|
456
|
+
let content = try await registration.load()
|
|
457
|
+
if let file = content.file { return _UnsafeBox(file) }
|
|
458
|
+
let data = try content.loadData()
|
|
459
|
+
if content.contentType.conforms(to: .url) { return _UnsafeBox(try URL.object(withItemProviderData: data, typeIdentifier: typeIdentifier)) }
|
|
460
|
+
if content.contentType.conforms(to: .text) { return _UnsafeBox(String(decoding: data, as: UTF8.self)) }
|
|
461
|
+
if content.contentType.conforms(to: .image), let image = UIImage(data: data) { return _UnsafeBox(image) }
|
|
462
|
+
return _UnsafeBox(data)
|
|
463
|
+
} done: { result in
|
|
464
|
+
switch result {
|
|
465
|
+
case .success(let box): completionHandler?(box.value, nil)
|
|
466
|
+
case .failure(let error): completionHandler?(nil, error)
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/// The content as `type`, through its first importing representation
|
|
472
|
+
/// that takes a registered type.
|
|
473
|
+
@discardableResult
|
|
474
|
+
public func loadTransferable<T: Transferable>(type: T.Type,
|
|
475
|
+
completionHandler: @escaping @Sendable (Result<T, any Error>) -> Void) -> Progress {
|
|
476
|
+
run { () async throws -> _UnsafeBox<T> in _UnsafeBox(try await self.loadTransferableNow(type)) } done: { result in
|
|
477
|
+
completionHandler(result.map(\.value))
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/// `loadTransferable(type:completionHandler:)`, awaited.
|
|
482
|
+
nonisolated(nonsending) public func loadTransferable<T: Transferable>(type: T.Type) async throws -> T {
|
|
483
|
+
try await loadTransferableNow(type)
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
nonisolated(nonsending) private func loadTransferableNow<T: Transferable>(_ type: T.Type) async throws -> T {
|
|
487
|
+
for registration in registrations where _Transfer.canImport(T.self, contentType: registration.type) {
|
|
488
|
+
var content = try await registration.load()
|
|
489
|
+
if content.suggestedName == nil { content.suggestedName = suggestedName }
|
|
490
|
+
if let value = try await _Transfer.import(T.self, from: content) { return value }
|
|
491
|
+
}
|
|
492
|
+
throw Self.error(.unavailableCoercionError)
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// MARK: Helpers
|
|
496
|
+
|
|
497
|
+
/// Runs `work` as a task and reports its result to `done`; the progress
|
|
498
|
+
/// completes with it.
|
|
499
|
+
private func run<Value>(_ work: @escaping () async throws -> Value, done: @escaping (Result<Value, any Error>) -> Void) -> Progress {
|
|
500
|
+
let job = _ItemProviderJob(work: work, done: done)
|
|
501
|
+
Task { await job.perform() }
|
|
502
|
+
return job.progress
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
private static func loadData(_ handler: @escaping @Sendable (@escaping @Sendable (Data?, (any Error)?) -> Void) -> Progress?) async throws -> Data {
|
|
506
|
+
try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<Data, any Error>) in
|
|
507
|
+
_ = handler { data, error in
|
|
508
|
+
if let data { continuation.resume(returning: data) }
|
|
509
|
+
else { continuation.resume(throwing: error ?? Self.error(.itemUnavailableError)) }
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
static func type(_ identifier: String) -> UTType {
|
|
515
|
+
UTType(identifier) ?? UTType(exportedAs: identifier)
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
static func data(of item: Any) -> Data? {
|
|
519
|
+
switch item {
|
|
520
|
+
case let data as Data: data
|
|
521
|
+
case let string as String: Data(string.utf8)
|
|
522
|
+
case let url as URL: Data(url.absoluteString.utf8)
|
|
523
|
+
case let attributed as NSAttributedString: Data(attributed.string.utf8)
|
|
524
|
+
default: nil
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
static func error(_ code: ErrorCode) -> NSError {
|
|
529
|
+
NSError(domain: errorDomain, code: code.rawValue)
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
static func receivedFile(_ content: _TransferContent, inPlace: Bool) throws -> ReceivedTransferredFile {
|
|
533
|
+
if let file = content.file, inPlace { return ReceivedTransferredFile(_file: file, isOriginalFile: true) }
|
|
534
|
+
let folder = FileManager.default.temporaryDirectory.appendingPathComponent("ItemProvider-\(UUID().uuidString)", isDirectory: true)
|
|
535
|
+
try FileManager.default.createDirectory(at: folder, withIntermediateDirectories: true)
|
|
536
|
+
let copy = folder.appendingPathComponent(content.fileName)
|
|
537
|
+
if let file = content.file { try FileManager.default.copyItem(at: file, to: copy) } else { try content.loadData().write(to: copy) }
|
|
538
|
+
return ReceivedTransferredFile(_file: copy, isOriginalFile: false)
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/// One load: its work, its completion and its progress.
|
|
543
|
+
final class _ItemProviderJob<Value>: @unchecked Sendable {
|
|
544
|
+
let work: () async throws -> Value
|
|
545
|
+
let done: (Result<Value, any Error>) -> Void
|
|
546
|
+
let progress = Progress(totalUnitCount: 1)
|
|
547
|
+
|
|
548
|
+
init(work: @escaping () async throws -> Value, done: @escaping (Result<Value, any Error>) -> Void) {
|
|
549
|
+
self.work = work
|
|
550
|
+
self.done = done
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
func perform() async {
|
|
554
|
+
var result: Result<Value, any Error>
|
|
555
|
+
do {
|
|
556
|
+
let value = try await work()
|
|
557
|
+
result = .success(value)
|
|
558
|
+
} catch {
|
|
559
|
+
result = .failure(error)
|
|
560
|
+
}
|
|
561
|
+
progress.completedUnitCount = 1
|
|
562
|
+
done(result)
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
/// A value carried across a task boundary on the browser's one thread.
|
|
567
|
+
struct _UnsafeBox<Value>: @unchecked Sendable {
|
|
568
|
+
let value: Value
|
|
569
|
+
init(_ value: Value) { self.value = value }
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// MARK: - SwiftUI: drag and drop
|
|
573
|
+
|
|
574
|
+
/// What a drop offers: where it is and the providers of what was dropped.
|
|
575
|
+
/// The page has no drag and drop yet, so no drop is ever delivered.
|
|
576
|
+
public struct DropInfo {
|
|
577
|
+
public let location: SwiftUI.CGPoint
|
|
578
|
+
let providers: [NSItemProvider]
|
|
579
|
+
|
|
580
|
+
public init(_location location: SwiftUI.CGPoint, providers: [NSItemProvider]) {
|
|
581
|
+
self.location = location
|
|
582
|
+
self.providers = providers
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
public func hasItemsConforming(to contentTypes: [UTType]) -> Bool {
|
|
586
|
+
providers.contains { provider in contentTypes.contains { !provider.registeredContentTypes(conformingTo: $0).isEmpty } }
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
public func hasItemsConforming(to typeIdentifiers: [String]) -> Bool {
|
|
590
|
+
hasItemsConforming(to: typeIdentifiers.map(NSItemProvider.type))
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
public func itemProviders(for contentTypes: [UTType]) -> [NSItemProvider] {
|
|
594
|
+
providers.filter { provider in contentTypes.contains { !provider.registeredContentTypes(conformingTo: $0).isEmpty } }
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
public func itemProviders(for typeIdentifiers: [String]) -> [NSItemProvider] {
|
|
598
|
+
itemProviders(for: typeIdentifiers.map(NSItemProvider.type))
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
/// How a drop would act on what it carries.
|
|
603
|
+
public enum DropOperation: Sendable {
|
|
604
|
+
case cancel, forbidden, copy, move
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
public struct DropProposal: Sendable {
|
|
608
|
+
public let operation: DropOperation
|
|
609
|
+
public init(operation: DropOperation) { self.operation = operation }
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
/// What a drop target is told as a drag moves over it and drops. Every
|
|
613
|
+
/// method has a default, as on iOS. Never called in the browser yet.
|
|
614
|
+
@MainActor
|
|
615
|
+
public protocol DropDelegate {
|
|
616
|
+
func validateDrop(info: DropInfo) -> Bool
|
|
617
|
+
func performDrop(info: DropInfo) -> Bool
|
|
618
|
+
func dropEntered(info: DropInfo)
|
|
619
|
+
func dropUpdated(info: DropInfo) -> DropProposal?
|
|
620
|
+
func dropExited(info: DropInfo)
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
extension DropDelegate {
|
|
624
|
+
public func validateDrop(info: DropInfo) -> Bool { true }
|
|
625
|
+
public func dropEntered(info: DropInfo) {}
|
|
626
|
+
public func dropUpdated(info: DropInfo) -> DropProposal? { nil }
|
|
627
|
+
public func dropExited(info: DropInfo) {}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
extension View {
|
|
631
|
+
/// Accepted; nothing is dropped in the browser, so `action` is never called.
|
|
632
|
+
public func onDrop(of supportedContentTypes: [UTType], isTargeted: Binding<Bool>?,
|
|
633
|
+
perform action: @escaping ([NSItemProvider]) -> Bool) -> some View { self }
|
|
634
|
+
|
|
635
|
+
/// Accepted; nothing is dropped in the browser, so `action` is never called.
|
|
636
|
+
public func onDrop(of supportedContentTypes: [UTType], isTargeted: Binding<Bool>?,
|
|
637
|
+
perform action: @escaping ([NSItemProvider], SwiftUI.CGPoint) -> Bool) -> some View { self }
|
|
638
|
+
|
|
639
|
+
/// Accepted; nothing is dropped in the browser, so the delegate hears nothing.
|
|
640
|
+
public func onDrop(of supportedContentTypes: [UTType], delegate: any DropDelegate) -> some View { self }
|
|
641
|
+
|
|
642
|
+
public func onDrop(of supportedTypes: [String], isTargeted: Binding<Bool>?,
|
|
643
|
+
perform action: @escaping ([NSItemProvider]) -> Bool) -> some View { self }
|
|
644
|
+
|
|
645
|
+
public func onDrop(of supportedTypes: [String], delegate: any DropDelegate) -> some View { self }
|
|
646
|
+
|
|
647
|
+
/// Accepted; the view cannot be dragged in the browser.
|
|
648
|
+
public func onDrag(_ data: @escaping () -> NSItemProvider) -> some View { self }
|
|
649
|
+
|
|
650
|
+
/// Accepted; the view cannot be dragged in the browser.
|
|
651
|
+
public func onDrag<Preview: View>(_ data: @escaping () -> NSItemProvider, @ViewBuilder preview: () -> Preview) -> some View { self }
|
|
652
|
+
|
|
653
|
+
/// Accepted (macOS's services and iOS's drag source): nothing asks for the provider.
|
|
654
|
+
public func itemProvider(_ action: (() -> NSItemProvider?)?) -> some View { self }
|
|
655
|
+
}
|