@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.
Files changed (393) hide show
  1. package/Package.swift +200 -9
  2. package/README.md +7 -9
  3. package/Sources/AVFoundation/AVFoundation.swift +131 -0
  4. package/Sources/AVFoundation/Asset.swift +487 -0
  5. package/Sources/AVFoundation/AudioSession.swift +144 -0
  6. package/Sources/AVFoundation/CMTime.swift +303 -0
  7. package/Sources/AVFoundation/Capture.swift +688 -0
  8. package/Sources/AVFoundation/Player.swift +749 -0
  9. package/Sources/AVFoundation/PlayerView.swift +117 -0
  10. package/Sources/AVKit/AVKit.swift +132 -0
  11. package/Sources/Accelerate/Accelerate.swift +122 -0
  12. package/Sources/AppIntents/AppIntents.swift +144 -0
  13. package/Sources/AppIntents/Parameters.swift +220 -0
  14. package/Sources/AppIntents/Shortcuts.swift +159 -0
  15. package/Sources/AudioToolbox/AudioToolbox.swift +55 -0
  16. package/Sources/AuthenticationServices/AuthenticationServices.swift +257 -0
  17. package/Sources/AuthenticationServices/Authorization.swift +251 -0
  18. package/Sources/Charts/Charts.swift +0 -4
  19. package/Sources/Combine/AnyCancellable.swift +65 -0
  20. package/Sources/Combine/AnyPublisher.swift +148 -0
  21. package/Sources/Combine/AnySubscriber.swift +230 -0
  22. package/Sources/Combine/Cancellable.swift +35 -0
  23. package/Sources/Combine/Codable.swift +29 -0
  24. package/Sources/Combine/CombineIdentifier.swift +45 -0
  25. package/Sources/Combine/Concurrency/ConcurrencyHelpers.swift +24 -0
  26. package/Sources/Combine/Concurrency/Future+Concurrency.swift +136 -0
  27. package/Sources/Combine/Concurrency/GENERATED-Publisher+Concurrency.swift +397 -0
  28. package/Sources/Combine/CurrentValueSubject.swift +252 -0
  29. package/Sources/Combine/CustomCombineIdentifierConvertible.swift +28 -0
  30. package/Sources/Combine/Future.swift +228 -0
  31. package/Sources/Combine/GENERATED-RootProtocols.swift +426 -0
  32. package/Sources/Combine/Helpers/ConduitBase.swift +40 -0
  33. package/Sources/Combine/Helpers/ConduitList.swift +59 -0
  34. package/Sources/Combine/Helpers/DebugHook.swift +177 -0
  35. package/Sources/Combine/Helpers/FilterProducer.swift +174 -0
  36. package/Sources/Combine/Helpers/Locking.swift +30 -0
  37. package/Sources/Combine/Helpers/PartialCompletion.swift +26 -0
  38. package/Sources/Combine/Helpers/ReduceProducer.swift +249 -0
  39. package/Sources/Combine/Helpers/SubjectSubscriber.swift +96 -0
  40. package/Sources/Combine/Helpers/SubscriberTap.swift +69 -0
  41. package/Sources/Combine/Helpers/SubscriptionStatus.swift +33 -0
  42. package/Sources/Combine/Helpers/SubscriptionTap.swift +33 -0
  43. package/Sources/Combine/Helpers/Utils.swift +30 -0
  44. package/Sources/Combine/Helpers/Violations.swift +33 -0
  45. package/Sources/Combine/ImmediateScheduler.swift +178 -0
  46. package/Sources/Combine/LICENSE +21 -0
  47. package/Sources/Combine/NotificationPublisher.swift +48 -0
  48. package/Sources/Combine/ObjectWillChange.swift +46 -0
  49. package/Sources/Combine/PassthroughSubject.swift +222 -0
  50. package/Sources/Combine/Publisher+Subscribe.swift +53 -0
  51. package/Sources/Combine/Publishers/Deferred.swift +48 -0
  52. package/Sources/Combine/Publishers/Empty.swift +54 -0
  53. package/Sources/Combine/Publishers/Fail.swift +42 -0
  54. package/Sources/Combine/Publishers/GENERATED-Publishers.Catch.swift +673 -0
  55. package/Sources/Combine/Publishers/GENERATED-Publishers.Encode.swift +388 -0
  56. package/Sources/Combine/Publishers/GENERATED-Publishers.MapKeyPath.swift +384 -0
  57. package/Sources/Combine/Publishers/Just.swift +313 -0
  58. package/Sources/Combine/Publishers/Optional.Publisher.swift +315 -0
  59. package/Sources/Combine/Publishers/Publishers.AllSatisfy.swift +217 -0
  60. package/Sources/Combine/Publishers/Publishers.AssertNoFailure.swift +158 -0
  61. package/Sources/Combine/Publishers/Publishers.Autoconnect.swift +193 -0
  62. package/Sources/Combine/Publishers/Publishers.Breakpoint.swift +231 -0
  63. package/Sources/Combine/Publishers/Publishers.Buffer.swift +356 -0
  64. package/Sources/Combine/Publishers/Publishers.Collect.swift +102 -0
  65. package/Sources/Combine/Publishers/Publishers.CollectByCount.swift +195 -0
  66. package/Sources/Combine/Publishers/Publishers.CompactMap.swift +241 -0
  67. package/Sources/Combine/Publishers/Publishers.Comparison.swift +371 -0
  68. package/Sources/Combine/Publishers/Publishers.Concatenate.swift +474 -0
  69. package/Sources/Combine/Publishers/Publishers.Contains.swift +293 -0
  70. package/Sources/Combine/Publishers/Publishers.Count.swift +87 -0
  71. package/Sources/Combine/Publishers/Publishers.Debounce.swift +332 -0
  72. package/Sources/Combine/Publishers/Publishers.Delay.swift +269 -0
  73. package/Sources/Combine/Publishers/Publishers.Drop.swift +155 -0
  74. package/Sources/Combine/Publishers/Publishers.DropUntilOutput.swift +283 -0
  75. package/Sources/Combine/Publishers/Publishers.DropWhile.swift +378 -0
  76. package/Sources/Combine/Publishers/Publishers.Filter.swift +248 -0
  77. package/Sources/Combine/Publishers/Publishers.First.swift +261 -0
  78. package/Sources/Combine/Publishers/Publishers.FlatMap.swift +533 -0
  79. package/Sources/Combine/Publishers/Publishers.HandleEvents.swift +260 -0
  80. package/Sources/Combine/Publishers/Publishers.IgnoreOutput.swift +109 -0
  81. package/Sources/Combine/Publishers/Publishers.Last.swift +252 -0
  82. package/Sources/Combine/Publishers/Publishers.MakeConnectable.swift +82 -0
  83. package/Sources/Combine/Publishers/Publishers.Map.swift +351 -0
  84. package/Sources/Combine/Publishers/Publishers.MapError.swift +140 -0
  85. package/Sources/Combine/Publishers/Publishers.MeasureInterval.swift +187 -0
  86. package/Sources/Combine/Publishers/Publishers.Multicast.swift +284 -0
  87. package/Sources/Combine/Publishers/Publishers.Output.swift +241 -0
  88. package/Sources/Combine/Publishers/Publishers.PrefixUntilOutput.swift +197 -0
  89. package/Sources/Combine/Publishers/Publishers.PrefixWhile.swift +176 -0
  90. package/Sources/Combine/Publishers/Publishers.Print.swift +206 -0
  91. package/Sources/Combine/Publishers/Publishers.ReceiveOn.swift +227 -0
  92. package/Sources/Combine/Publishers/Publishers.Reduce.swift +204 -0
  93. package/Sources/Combine/Publishers/Publishers.RemoveDuplicates.swift +264 -0
  94. package/Sources/Combine/Publishers/Publishers.ReplaceEmpty.swift +201 -0
  95. package/Sources/Combine/Publishers/Publishers.ReplaceError.swift +211 -0
  96. package/Sources/Combine/Publishers/Publishers.Retry.swift +274 -0
  97. package/Sources/Combine/Publishers/Publishers.Scan.swift +331 -0
  98. package/Sources/Combine/Publishers/Publishers.Sequence.swift +437 -0
  99. package/Sources/Combine/Publishers/Publishers.SetFailureType.swift +120 -0
  100. package/Sources/Combine/Publishers/Publishers.Share.swift +104 -0
  101. package/Sources/Combine/Publishers/Publishers.SubscribeOn.swift +197 -0
  102. package/Sources/Combine/Publishers/Publishers.SwitchToLatest.swift +444 -0
  103. package/Sources/Combine/Publishers/Publishers.Throttle.swift +359 -0
  104. package/Sources/Combine/Publishers/Publishers.Timeout.swift +301 -0
  105. package/Sources/Combine/Publishers/Publishers.Zip.swift +720 -0
  106. package/Sources/Combine/Publishers/Publishers.swift +13 -0
  107. package/Sources/Combine/Publishers/Record.swift +237 -0
  108. package/Sources/Combine/Publishers/Result.Publisher.swift +337 -0
  109. package/Sources/Combine/Result.swift +46 -0
  110. package/Sources/Combine/Scheduler.swift +89 -0
  111. package/Sources/Combine/Schedulers.swift +211 -0
  112. package/Sources/Combine/Subject+Void.swift +17 -0
  113. package/Sources/Combine/Subscriber+Void.swift +20 -0
  114. package/Sources/Combine/Subscribers/Subscribers.Assign.swift +175 -0
  115. package/Sources/Combine/Subscribers/Subscribers.Completion.swift +90 -0
  116. package/Sources/Combine/Subscribers/Subscribers.Demand.swift +476 -0
  117. package/Sources/Combine/Subscribers/Subscribers.Sink.swift +206 -0
  118. package/Sources/Combine/Subscribers/Subscribers.swift +9 -0
  119. package/Sources/Combine/Subscription.swift +22 -0
  120. package/Sources/Combine/Subscriptions.swift +42 -0
  121. package/Sources/Combine/SwiftUIObservation.swift +10 -0
  122. package/Sources/Combine/_Introspection.swift +107 -0
  123. package/Sources/CommonCrypto/CommonCrypto.swift +80 -0
  124. package/Sources/Compression/Compression.swift +365 -0
  125. package/Sources/Compression/Deflate.swift +407 -0
  126. package/Sources/Compression/Zlib.swift +179 -0
  127. package/Sources/CoreFoundationTypes/CoreFoundationTypes.swift +101 -0
  128. package/Sources/CoreGraphics/CoreGraphics.swift +411 -0
  129. package/Sources/CoreGraphics/ProjectionTransforms.swift +28 -0
  130. package/Sources/CoreHaptics/CoreHaptics.swift +399 -0
  131. package/Sources/CoreImage/CIColor.swift +41 -0
  132. package/Sources/CoreImage/CIContext.swift +31 -0
  133. package/Sources/CoreImage/CIDetector.swift +57 -0
  134. package/Sources/CoreImage/CIFilter.swift +243 -0
  135. package/Sources/CoreImage/CIFilterBuiltins.swift +136 -0
  136. package/Sources/CoreImage/CIImage.swift +162 -0
  137. package/Sources/CoreImage/QRCode.swift +393 -0
  138. package/Sources/CoreLocation/Coordinate.swift +30 -0
  139. package/Sources/CoreLocation/Location.swift +65 -0
  140. package/Sources/CoreML/Evaluation.swift +414 -0
  141. package/Sources/CoreML/FeatureValue.swift +266 -0
  142. package/Sources/CoreML/Model.swift +269 -0
  143. package/Sources/CoreML/MultiArray.swift +92 -0
  144. package/Sources/CoreML/Specification.swift +233 -0
  145. package/Sources/CoreText/CoreText.swift +64 -0
  146. package/Sources/CoreTransferable/CoreTransferable.swift +606 -0
  147. package/Sources/CryptoKit/ChaChaPoly.swift +258 -0
  148. package/Sources/CryptoKit/CryptoKit.swift +375 -0
  149. package/Sources/CryptoKit/Curve25519.swift +317 -0
  150. package/Sources/CryptoKit/P256.swift +321 -0
  151. package/Sources/FoundationBridge/AppStorage.swift +165 -0
  152. package/Sources/FoundationBridge/AssetResources.swift +90 -0
  153. package/Sources/FoundationBridge/AsyncBytes.swift +128 -0
  154. package/Sources/FoundationBridge/AsyncImage.swift +116 -0
  155. package/Sources/FoundationBridge/AttributedStrings.swift +16 -0
  156. package/Sources/{_FoundationCommon → FoundationBridge}/Bundle.swift +41 -4
  157. package/Sources/FoundationBridge/CombineExports.swift +8 -0
  158. package/Sources/FoundationBridge/CoreFoundation.swift +77 -0
  159. package/Sources/FoundationBridge/Dispatch.swift +458 -0
  160. package/Sources/FoundationBridge/EnvironmentFoundation.swift +41 -0
  161. package/Sources/FoundationBridge/FileImporter.swift +128 -0
  162. package/Sources/FoundationBridge/FileSystem.swift +68 -0
  163. package/Sources/FoundationBridge/FoundationBridge.swift +24 -72
  164. package/Sources/FoundationBridge/HostResolution.swift +31 -0
  165. package/Sources/FoundationBridge/ItemProvider.swift +655 -0
  166. package/Sources/FoundationBridge/KeyValueObserving.swift +138 -0
  167. package/Sources/FoundationBridge/Links.swift +127 -0
  168. package/Sources/FoundationBridge/ListFormatter.swift +32 -0
  169. package/Sources/FoundationBridge/Localization.swift +149 -0
  170. package/Sources/FoundationBridge/Locks.swift +50 -0
  171. package/Sources/FoundationBridge/Markdown.swift +527 -0
  172. package/Sources/FoundationBridge/MeasurementFormat.swift +95 -0
  173. package/Sources/FoundationBridge/NotificationCenter.swift +154 -0
  174. package/Sources/FoundationBridge/OpenURLHandlers.swift +60 -0
  175. package/Sources/FoundationBridge/Operation.swift +195 -0
  176. package/Sources/FoundationBridge/ProcessInfo.swift +32 -0
  177. package/Sources/FoundationBridge/RelativeDateTimeFormatter.swift +136 -0
  178. package/Sources/FoundationBridge/SceneStorage.swift +78 -0
  179. package/Sources/FoundationBridge/SecurityExports.swift +8 -0
  180. package/Sources/FoundationBridge/Selector.swift +226 -0
  181. package/Sources/FoundationBridge/StringComparators.swift +17 -0
  182. package/Sources/FoundationBridge/Table.swift +211 -0
  183. package/Sources/FoundationBridge/TextAttributes.swift +42 -0
  184. package/Sources/FoundationBridge/Timer.swift +6 -1
  185. package/Sources/FoundationBridge/URLSession.swift +718 -0
  186. package/Sources/{_FoundationCommon → FoundationBridge}/UserDefaults.swift +17 -4
  187. package/Sources/FoundationBridge/WebAuthRedirects.swift +227 -0
  188. package/Sources/FoundationBridge/WebSocket.swift +187 -0
  189. package/Sources/FoundationModels/FoundationModels.swift +1098 -0
  190. package/Sources/ImageIO/GIF.swift +72 -0
  191. package/Sources/ImageIO/ImageIO.swift +248 -0
  192. package/Sources/ImageIO/ImageTypes.swift +28 -0
  193. package/Sources/LinkPresentation/LinkPresentation.swift +249 -0
  194. package/Sources/LocalAuthentication/LAContext.swift +86 -0
  195. package/Sources/MapKit/Geometry.swift +223 -0
  196. package/Sources/MapKit/Map.swift +638 -0
  197. package/Sources/MapKit/MapView.swift +229 -0
  198. package/Sources/MobileCoreServices/MobileCoreServices.swift +28 -0
  199. package/Sources/NaturalLanguage/LanguageIdentifier.swift +317 -0
  200. package/Sources/NaturalLanguage/NaturalLanguage.swift +135 -0
  201. package/Sources/OSLog/OSLog.swift +6 -0
  202. package/Sources/Photos/Photos.swift +572 -0
  203. package/Sources/PhotosUI/PhotosPicker.swift +248 -0
  204. package/Sources/PhotosUI/PhotosPickerItem.swift +261 -0
  205. package/Sources/QuickLook/QuickLook.swift +168 -0
  206. package/Sources/SafariServices/SafariServices.swift +106 -0
  207. package/Sources/Security/Security.swift +332 -0
  208. package/Sources/StoreKit/AppStore.swift +207 -0
  209. package/Sources/StoreKit/Products.swift +280 -0
  210. package/Sources/StoreKit/RequestReview.swift +28 -0
  211. package/Sources/StoreKit/StoreKit1.swift +486 -0
  212. package/Sources/StoreKit/StoreViews.swift +428 -0
  213. package/Sources/StoreKit/Transactions.swift +197 -0
  214. package/Sources/SwiftData/Macros.swift +58 -0
  215. package/Sources/SwiftData/ModelActor.swift +38 -0
  216. package/Sources/SwiftData/ModelContainer.swift +129 -0
  217. package/Sources/SwiftData/ModelContext.swift +451 -0
  218. package/Sources/SwiftData/PersistentModel.swift +238 -0
  219. package/Sources/SwiftData/Properties.swift +261 -0
  220. package/Sources/SwiftData/Query.swift +256 -0
  221. package/Sources/SwiftData/Schema.swift +192 -0
  222. package/Sources/SwiftData/Store.swift +146 -0
  223. package/Sources/SwiftData/StringPredicates.swift +125 -0
  224. package/Sources/SwiftDataMacros/EntryMacro.swift +82 -0
  225. package/Sources/SwiftDataMacros/GenerableMacro.swift +183 -0
  226. package/Sources/SwiftDataMacros/ModelActorMacro.swift +46 -0
  227. package/Sources/SwiftDataMacros/ModelMacro.swift +260 -0
  228. package/Sources/SwiftDataMacros/Plugin.swift +18 -0
  229. package/Sources/SwiftDataMacros/PredicateMacro.swift +1244 -0
  230. package/Sources/SwiftUI/API/Accessibility.swift +55 -6
  231. package/Sources/SwiftUI/API/AccessibilityExtras.swift +33 -0
  232. package/Sources/SwiftUI/API/AccessibilityFocus.swift +63 -0
  233. package/Sources/SwiftUI/API/Alert.swift +1 -1
  234. package/Sources/SwiftUI/API/AlignmentGuides.swift +65 -0
  235. package/Sources/SwiftUI/API/Animation.swift +37 -5
  236. package/Sources/SwiftUI/API/App.swift +31 -1
  237. package/Sources/SwiftUI/API/BindingCollections.swift +35 -0
  238. package/Sources/SwiftUI/API/BindingForEach.swift +27 -0
  239. package/Sources/SwiftUI/API/Bitmaps.swift +254 -0
  240. package/Sources/SwiftUI/API/ButtonStyles.swift +96 -0
  241. package/Sources/SwiftUI/API/Canvas.swift +337 -0
  242. package/Sources/SwiftUI/API/Color.swift +104 -28
  243. package/Sources/SwiftUI/API/ColorEffects.swift +52 -0
  244. package/Sources/SwiftUI/API/ColorPickerAndLabeledContent.swift +138 -0
  245. package/Sources/SwiftUI/API/ColorSpaces.swift +161 -0
  246. package/Sources/SwiftUI/API/Commands.swift +106 -0
  247. package/Sources/SwiftUI/API/ContainerBackground.swift +28 -0
  248. package/Sources/SwiftUI/API/ContentShape.swift +33 -0
  249. package/Sources/SwiftUI/API/ContentSizeCategory.swift +35 -0
  250. package/Sources/SwiftUI/API/ContentUnavailable.swift +101 -0
  251. package/Sources/SwiftUI/API/Controls.swift +59 -27
  252. package/Sources/SwiftUI/API/CustomLayout.swift +49 -10
  253. package/Sources/SwiftUI/API/CustomToolbarContent.swift +46 -0
  254. package/Sources/SwiftUI/API/Decorations.swift +1 -1
  255. package/Sources/SwiftUI/API/EditMode.swift +25 -82
  256. package/Sources/SwiftUI/API/Effects.swift +105 -7
  257. package/Sources/SwiftUI/API/Entry.swift +8 -0
  258. package/Sources/SwiftUI/API/Environment.swift +93 -9
  259. package/Sources/SwiftUI/API/EnvironmentSendable.swift +6 -0
  260. package/Sources/SwiftUI/API/Focus.swift +11 -3
  261. package/Sources/SwiftUI/API/Gauge.swift +3 -2
  262. package/Sources/SwiftUI/API/GeometryEffects.swift +232 -0
  263. package/Sources/SwiftUI/API/GeometryReader.swift +13 -2
  264. package/Sources/SwiftUI/API/GestureState.swift +65 -0
  265. package/Sources/SwiftUI/API/Gestures.swift +1 -1
  266. package/Sources/SwiftUI/API/Glass.swift +127 -0
  267. package/Sources/SwiftUI/API/Grid.swift +1 -1
  268. package/Sources/SwiftUI/API/GroupBoxAndControlGroup.swift +130 -0
  269. package/Sources/SwiftUI/API/KeyPress.swift +54 -0
  270. package/Sources/SwiftUI/API/LabelStyle.swift +13 -6
  271. package/Sources/SwiftUI/API/Layout.swift +67 -12
  272. package/Sources/SwiftUI/API/LazyStacks.swift +49 -0
  273. package/Sources/SwiftUI/API/LegacyAlert.swift +97 -0
  274. package/Sources/SwiftUI/API/Lists.swift +61 -6
  275. package/Sources/SwiftUI/API/Menu.swift +8 -1
  276. package/Sources/SwiftUI/API/Modifiers.swift +80 -10
  277. package/Sources/SwiftUI/API/MoreModifiers.swift +100 -0
  278. package/Sources/SwiftUI/API/Namespace.swift +44 -0
  279. package/Sources/SwiftUI/API/Navigation.swift +24 -9
  280. package/Sources/SwiftUI/API/NavigationDestinationBindings.swift +55 -0
  281. package/Sources/SwiftUI/API/ObservableObject.swift +16 -2
  282. package/Sources/SwiftUI/API/Path.swift +543 -0
  283. package/Sources/SwiftUI/API/Phase8Controls.swift +48 -31
  284. package/Sources/SwiftUI/API/PhaseAnimator.swift +130 -0
  285. package/Sources/SwiftUI/API/Picker.swift +11 -2
  286. package/Sources/SwiftUI/API/PointerAndKeyboard.swift +77 -0
  287. package/Sources/SwiftUI/API/Popover.swift +41 -0
  288. package/Sources/SwiftUI/API/Preferences.swift +262 -0
  289. package/Sources/SwiftUI/API/Presentation.swift +17 -4
  290. package/Sources/SwiftUI/API/PresentationExtras.swift +60 -0
  291. package/Sources/SwiftUI/API/Primitives.swift +164 -37
  292. package/Sources/SwiftUI/API/Publishers.swift +4 -4
  293. package/Sources/SwiftUI/API/Redaction.swift +75 -0
  294. package/Sources/SwiftUI/API/RowActions.swift +3 -2
  295. package/Sources/SwiftUI/API/Scenes.swift +131 -0
  296. package/Sources/SwiftUI/API/ScrollModifiers.swift +132 -0
  297. package/Sources/SwiftUI/API/ScrollTargets.swift +3 -3
  298. package/Sources/SwiftUI/API/ScrollViewReader.swift +144 -0
  299. package/Sources/SwiftUI/API/SectionSupplements.swift +96 -0
  300. package/Sources/SwiftUI/API/Shape.swift +214 -0
  301. package/Sources/SwiftUI/API/ShapeStyle.swift +105 -7
  302. package/Sources/SwiftUI/API/ShapeTrim.swift +78 -0
  303. package/Sources/SwiftUI/API/Sharing.swift +193 -0
  304. package/Sources/SwiftUI/API/StackLayouts.swift +199 -0
  305. package/Sources/SwiftUI/API/State.swift +18 -1
  306. package/Sources/SwiftUI/API/StatusGaps.swift +121 -0
  307. package/Sources/SwiftUI/API/SymbolEffects.swift +203 -0
  308. package/Sources/SwiftUI/API/TabContent.swift +841 -0
  309. package/Sources/SwiftUI/API/Table.swift +382 -0
  310. package/Sources/SwiftUI/API/Tabs.swift +148 -4
  311. package/Sources/SwiftUI/API/Tasks.swift +2 -2
  312. package/Sources/SwiftUI/API/Text.swift +386 -0
  313. package/Sources/SwiftUI/API/TextDates.swift +61 -0
  314. package/Sources/SwiftUI/API/TextDecorations.swift +52 -0
  315. package/Sources/SwiftUI/API/TextFieldAxis.swift +103 -0
  316. package/Sources/SwiftUI/API/TextFieldCommit.swift +52 -0
  317. package/Sources/SwiftUI/API/Toolbar.swift +52 -16
  318. package/Sources/SwiftUI/API/Transfer.swift +145 -0
  319. package/Sources/SwiftUI/API/UnevenRoundedRectangle.swift +66 -0
  320. package/Sources/SwiftUI/API/Video.swift +64 -0
  321. package/Sources/SwiftUI/API/View.swift +10 -2
  322. package/Sources/SwiftUI/API/ViewModifier.swift +4 -1
  323. package/Sources/SwiftUI/API/VisualEffect.swift +74 -1
  324. package/Sources/SwiftUI/API/Windows.swift +25 -0
  325. package/Sources/SwiftUI/Charts/Axis.swift +7 -1
  326. package/Sources/SwiftUI/Charts/AxisFormatsAndRanges.swift +68 -0
  327. package/Sources/SwiftUI/Charts/Chart.swift +17 -3
  328. package/Sources/SwiftUI/Charts/ChartProxy.swift +57 -0
  329. package/Sources/SwiftUI/Localization/Localization.swift +498 -0
  330. package/Sources/SwiftUI/Localization/PluralRules.swift +127 -0
  331. package/Sources/SwiftUI/Runtime/Executor.swift +2 -0
  332. package/Sources/SwiftUI/Runtime/Exports.swift +37 -1
  333. package/Sources/SwiftUI/Runtime/ImageSource.swift +310 -0
  334. package/Sources/SwiftUI/Runtime/JSON.swift +76 -4
  335. package/Sources/SwiftUI/Runtime/LazyRows.swift +99 -0
  336. package/Sources/SwiftUI/Runtime/Measurements.swift +140 -0
  337. package/Sources/SwiftUI/Runtime/Ops.swift +58 -12
  338. package/Sources/SwiftUI/Runtime/Reconciler.swift +10 -1
  339. package/Sources/SwiftUI/Runtime/Replay.swift +382 -0
  340. package/Sources/SwiftUI/Runtime/Runtime.swift +977 -198
  341. package/Sources/SwiftUI/Runtime/Sameness.swift +152 -0
  342. package/Sources/SwiftUI/Runtime/ViewPath.swift +89 -0
  343. package/Sources/SwiftUI/Runtime/ViewTraits.swift +175 -0
  344. package/Sources/SwiftUI/Runtime/WebAuthHeadless.swift +49 -0
  345. package/Sources/Symbols/Symbols.swift +25 -0
  346. package/Sources/Translation/Translation.swift +423 -0
  347. package/Sources/UIKit/Activity.swift +213 -0
  348. package/Sources/UIKit/Alerts.swift +69 -0
  349. package/Sources/UIKit/AppDelegate.swift +222 -0
  350. package/Sources/UIKit/Appearance.swift +84 -0
  351. package/Sources/UIKit/ColorConversions.swift +70 -0
  352. package/Sources/UIKit/Controls.swift +225 -0
  353. package/Sources/UIKit/Device.swift +200 -0
  354. package/Sources/UIKit/Feedback.swift +65 -0
  355. package/Sources/UIKit/Font.swift +307 -0
  356. package/Sources/UIKit/Graphics.swift +204 -0
  357. package/Sources/UIKit/HostingController.swift +185 -0
  358. package/Sources/UIKit/Identity.swift +24 -0
  359. package/Sources/UIKit/Introspectable.swift +510 -0
  360. package/Sources/UIKit/Pasteboard.swift +363 -0
  361. package/Sources/UIKit/PhotoAlbum.swift +81 -0
  362. package/Sources/UIKit/RemoteNotifications.swift +15 -0
  363. package/Sources/UIKit/Representable.swift +288 -0
  364. package/Sources/UIKit/SafeArea.swift +12 -0
  365. package/Sources/UIKit/SceneDelegates.swift +132 -0
  366. package/Sources/UIKit/Scenes.swift +40 -0
  367. package/Sources/UIKit/ScrollView.swift +157 -0
  368. package/Sources/UIKit/ShortcutItems.swift +67 -0
  369. package/Sources/UIKit/SymbolConfiguration.swift +124 -0
  370. package/Sources/UIKit/TargetAction.swift +123 -0
  371. package/Sources/UIKit/TextPaste.swift +161 -0
  372. package/Sources/UIKit/TextView.swift +538 -0
  373. package/Sources/UIKit/UIKit.swift +292 -0
  374. package/Sources/UIKit/UIView.swift +855 -0
  375. package/Sources/UIKit/ViewTranslation.swift +311 -0
  376. package/Sources/UniformTypeIdentifiers/UTType.swift +196 -0
  377. package/Sources/UserNotifications/Content.swift +370 -0
  378. package/Sources/UserNotifications/NotificationCenter.swift +309 -0
  379. package/Sources/WeatherKit/WeatherKit.swift +228 -0
  380. package/Sources/WebKit/WebKit.swift +245 -0
  381. package/Sources/os/os.swift +376 -0
  382. package/Sources/zlib/zlib.swift +6 -0
  383. package/index.d.ts +1 -1
  384. package/index.mjs +2 -2
  385. package/manifest.d.mts +2 -0
  386. package/manifest.mjs +39 -0
  387. package/package.json +5 -3
  388. package/sync-sources.mjs +21 -7
  389. package/Sources/FoundationLite/Common.swift +0 -3
  390. package/Sources/FoundationLite/FoundationLite.swift +0 -171
  391. package/Sources/FoundationLite/Interaction.swift +0 -146
  392. package/Sources/FoundationLite/Timer.swift +0 -48
  393. package/Sources/_FoundationCommon/_FoundationCommon.swift +0 -10
@@ -0,0 +1,423 @@
1
+ // Translation (iOS 17.4 / 18): Apple's on-device translation, over the
2
+ // browser's own translator where the page has one. Chrome (138 and later,
3
+ // on desktop) has a built-in `Translator` API that translates on the device
4
+ // with models it downloads per language pair, and a `LanguageDetector`; the
5
+ // page uses them for `translate` host requests (Web/src/translation.ts). A
6
+ // browser without them, and headless runs, answer that no pair is supported,
7
+ // so `LanguageAvailability` reports `.unsupported` and a session's
8
+ // translations fail with `TranslationError.unsupportedLanguagePairing`, as on
9
+ // a device without the pair. Apps that fall back to a server (Ice Cubes
10
+ // translates with the instance or DeepL) then take that path.
11
+ //
12
+ // Exchanges, as host requests of kind `translate`:
13
+ //
14
+ // { "action": "availability", "source": "en" | null, "target": "fr", "text"?: "…" }
15
+ // → { "status": "installed" | "supported" | "unsupported" }
16
+ // { "action": "translate", "source": "en" | null, "target": "fr",
17
+ // "texts": ["…"], "allowDownload": true }
18
+ // → { "source": "en", "texts": ["…"] }, or { "status": "unsupported" }
19
+ //
20
+ // Languages travel as BCP 47 language tags ("en", "pt", "zh-Hant").
21
+
22
+ import Foundation
23
+ import FoundationBridge
24
+ import SwiftUI
25
+
26
+ // MARK: - Errors
27
+
28
+ /// Why a translation failed. Compare with `~=` (`catch TranslationError.unsupportedLanguagePairing`).
29
+ public struct TranslationError: Error, LocalizedError, Hashable, Sendable, CustomStringConvertible {
30
+ enum Code: String, Sendable { case unsupportedSourceLanguage, unsupportedTargetLanguage, unsupportedLanguagePairing,
31
+ unableToIdentifyLanguage, nothingToTranslate, internalError, notInstalled }
32
+ let code: Code
33
+
34
+ /// The source language is one the translator does not have.
35
+ public static let unsupportedSourceLanguage = TranslationError(code: .unsupportedSourceLanguage)
36
+ /// The target language is one the translator does not have.
37
+ public static let unsupportedTargetLanguage = TranslationError(code: .unsupportedTargetLanguage)
38
+ /// The translator cannot translate between the two languages: always so
39
+ /// in a browser without a built-in translator.
40
+ public static let unsupportedLanguagePairing = TranslationError(code: .unsupportedLanguagePairing)
41
+ /// The source language was not given and could not be detected.
42
+ public static let unableToIdentifyLanguage = TranslationError(code: .unableToIdentifyLanguage)
43
+ /// The text was empty.
44
+ public static let nothingToTranslate = TranslationError(code: .nothingToTranslate)
45
+ /// The translator failed.
46
+ public static let internalError = TranslationError(code: .internalError)
47
+ /// The pair's model is not downloaded and the session may not download it.
48
+ public static let notInstalled = TranslationError(code: .notInstalled)
49
+
50
+ public static func ~= (lhs: TranslationError, rhs: any Error) -> Bool {
51
+ (rhs as? TranslationError) == lhs
52
+ }
53
+
54
+ public var description: String { "TranslationError.\(code.rawValue)" }
55
+
56
+ public var errorDescription: String? {
57
+ switch code {
58
+ case .unsupportedSourceLanguage: "The source language is not supported."
59
+ case .unsupportedTargetLanguage: "The target language is not supported."
60
+ case .unsupportedLanguagePairing: "Translation between these languages is not supported."
61
+ case .unableToIdentifyLanguage: "The language of the text could not be identified."
62
+ case .nothingToTranslate: "There is nothing to translate."
63
+ case .internalError: "The translation failed."
64
+ case .notInstalled: "The languages for this translation are not downloaded."
65
+ }
66
+ }
67
+ }
68
+
69
+ // MARK: - The page
70
+
71
+ /// How the module reaches the page; tests replace `transport`.
72
+ enum _TranslationHost {
73
+ /// Performs one `translate` request.
74
+ nonisolated(unsafe) static var transport: @Sendable (_JSON) async throws -> _JSON = { params in
75
+ try await _Runtime.shared._hostRequest(kind: "translate", params: params,
76
+ headless: .object(["status": .string("unsupported")]))
77
+ }
78
+
79
+ /// A language's BCP 47 tag for the page: its language code, with the
80
+ /// script for traditional Chinese ("zh-Hant"), which translators treat as a
81
+ /// language of its own.
82
+ static func tag(_ language: Locale.Language) -> String {
83
+ let code = language.languageCode?.identifier ?? language.minimalIdentifier
84
+ if code == "zh" {
85
+ let script = language.script?.identifier
86
+ let region = language.region?.identifier
87
+ if script == "Hant" || (script == nil && ["TW", "HK", "MO"].contains(region ?? "")) { return "zh-Hant" }
88
+ }
89
+ return code
90
+ }
91
+
92
+ /// The language translations go to when a session names none: the viewer's first preferred language.
93
+ static var defaultTarget: Locale.Language {
94
+ Locale.Language(identifier: Locale.preferredLanguages.first ?? Locale.current.identifier)
95
+ }
96
+
97
+ static func status(_ value: _JSON) -> LanguageAvailability.Status {
98
+ guard case .object(let fields) = value, case .string(let status)? = fields["status"] else { return .unsupported }
99
+ switch status {
100
+ case "installed": return .installed
101
+ case "supported": return .supported
102
+ default: return .unsupported
103
+ }
104
+ }
105
+
106
+ /// The error a refused request stands for: the page's message starts with a tag.
107
+ static func error(_ error: any Error) -> TranslationError {
108
+ if let error = error as? TranslationError { return error }
109
+ let message = (error as? _HostRequestError)?.message ?? ""
110
+ if message.hasPrefix("unsupported") { return .unsupportedLanguagePairing }
111
+ if message.hasPrefix("unidentified") { return .unableToIdentifyLanguage }
112
+ if message.hasPrefix("download") { return .notInstalled }
113
+ return .internalError
114
+ }
115
+ }
116
+
117
+ // MARK: - Availability
118
+
119
+ /// Which languages can be translated, as the page's translator reports.
120
+ public final class LanguageAvailability: Sendable {
121
+ /// Whether a pair can be translated.
122
+ public enum Status: Sendable, Hashable {
123
+ /// The pair's model is on the device: translations start at once.
124
+ case installed
125
+ /// The pair is supported; its model is downloaded first.
126
+ case supported
127
+ /// The pair cannot be translated (always so without a built-in translator).
128
+ case unsupported
129
+ }
130
+
131
+ public init() {}
132
+
133
+ /// The languages Apple's translator offers. In a browser without a
134
+ /// translator the list is the same: availability is answered per pair.
135
+ public var supportedLanguages: [Locale.Language] {
136
+ get async {
137
+ ["ar", "zh-Hans", "zh-Hant", "nl", "en-US", "en-GB", "fr", "de", "hi", "id", "it", "ja", "ko", "pl",
138
+ "pt-BR", "ru", "es", "th", "tr", "uk", "vi"].map { Locale.Language(identifier: $0) }
139
+ }
140
+ }
141
+
142
+ /// Whether `source` can be translated to `target` (the viewer's language when nil).
143
+ public func status(from source: Locale.Language, to target: Locale.Language?) async throws -> Status {
144
+ try await Self.ask(source: source, target: target, text: nil)
145
+ }
146
+
147
+ /// Whether `text`, whose language the page detects, can be translated to
148
+ /// `target`. Fails with `unableToIdentifyLanguage` when it cannot tell.
149
+ public func status(for text: String, to target: Locale.Language?) async throws -> Status {
150
+ try await Self.ask(source: nil, target: target, text: text)
151
+ }
152
+
153
+ static func ask(source: Locale.Language?, target: Locale.Language?, text: String?) async throws -> Status {
154
+ var params: [String: _JSON] = [
155
+ "action": .string("availability"),
156
+ "source": source.map { .string(_TranslationHost.tag($0)) } ?? .null,
157
+ "target": .string(_TranslationHost.tag(target ?? _TranslationHost.defaultTarget)),
158
+ ]
159
+ if let text { params["text"] = .string(text) }
160
+ do {
161
+ return _TranslationHost.status(try await _TranslationHost.transport(.object(params)))
162
+ } catch {
163
+ let error = _TranslationHost.error(error)
164
+ if error == .unableToIdentifyLanguage { throw error }
165
+ return .unsupported
166
+ }
167
+ }
168
+ }
169
+
170
+ // MARK: - Sessions
171
+
172
+ /// Translates text between two languages. SwiftUI hands one to the action of
173
+ /// `.translationTask`; iOS 26's `init(installedSource:target:)` makes one
174
+ /// directly, which never downloads a model.
175
+ public final class TranslationSession: @unchecked Sendable {
176
+ /// A text to translate in a batch, with an identifier to match its response.
177
+ public struct Request: Sendable, Hashable {
178
+ public var sourceText: String
179
+ public var clientIdentifier: String?
180
+
181
+ public init(sourceText: String, clientIdentifier: String? = nil) {
182
+ self.sourceText = sourceText
183
+ self.clientIdentifier = clientIdentifier
184
+ }
185
+ }
186
+
187
+ /// A translated text.
188
+ public struct Response: Sendable, Hashable {
189
+ public var sourceLanguage: Locale.Language
190
+ public var targetLanguage: Locale.Language
191
+ public var sourceText: String
192
+ public var targetText: String
193
+ public var clientIdentifier: String?
194
+ }
195
+
196
+ /// The languages of a `.translationTask`: nil source means detected, nil
197
+ /// target the viewer's language. `invalidate()` makes the task run again
198
+ /// with the same languages.
199
+ public struct Configuration: Sendable, Hashable {
200
+ public var source: Locale.Language?
201
+ public var target: Locale.Language?
202
+ public private(set) var version = 0
203
+
204
+ public init(source: Locale.Language? = nil, target: Locale.Language? = nil) {
205
+ self.source = source
206
+ self.target = target
207
+ }
208
+
209
+ /// Runs the configuration's translation task again.
210
+ public mutating func invalidate() { version += 1 }
211
+ }
212
+
213
+ /// The responses of `translate(batch:)`, in the order of the requests.
214
+ public struct BatchResponse: AsyncSequence, Sendable {
215
+ public typealias Element = Response
216
+ let responses: @Sendable () async throws -> [Response]
217
+
218
+ public struct AsyncIterator: AsyncIteratorProtocol {
219
+ let load: @Sendable () async throws -> [Response]
220
+ var loaded: [Response]?
221
+ var index = 0
222
+
223
+ public mutating func next() async throws -> Response? {
224
+ if loaded == nil { loaded = try await load() }
225
+ guard let loaded, index < loaded.count else { return nil }
226
+ defer { index += 1 }
227
+ return loaded[index]
228
+ }
229
+ }
230
+
231
+ public func makeAsyncIterator() -> AsyncIterator { AsyncIterator(load: responses) }
232
+ }
233
+
234
+ /// The language translated from; nil when each text's language is detected.
235
+ public let sourceLanguage: Locale.Language?
236
+ /// The language translated to; nil for the viewer's language.
237
+ public let targetLanguage: Locale.Language?
238
+ /// Whether the session may download a pair's model (the page asks the
239
+ /// browser to, which Chrome allows within a tap).
240
+ public let canRequestDownloads: Bool
241
+ private var cancelled = false
242
+
243
+ init(source: Locale.Language?, target: Locale.Language?, canRequestDownloads: Bool) {
244
+ sourceLanguage = source
245
+ targetLanguage = target
246
+ self.canRequestDownloads = canRequestDownloads
247
+ }
248
+
249
+ /// A session for a pair whose model is already on the device: it never
250
+ /// downloads one, and fails with `notInstalled` when it would have to.
251
+ public convenience init(installedSource: Locale.Language, target: Locale.Language? = nil) {
252
+ self.init(source: installedSource, target: target, canRequestDownloads: false)
253
+ }
254
+
255
+ /// Whether the pair's model is on the device.
256
+ public var isReady: Bool {
257
+ get async {
258
+ guard let sourceLanguage else { return false }
259
+ return (try? await LanguageAvailability().status(from: sourceLanguage, to: targetLanguage)) == .installed
260
+ }
261
+ }
262
+
263
+ /// Downloads the pair's model ahead of the first translation, when it is
264
+ /// supported and not yet installed.
265
+ public func prepareTranslation() async throws {
266
+ guard let sourceLanguage else { return }
267
+ switch try await LanguageAvailability().status(from: sourceLanguage, to: targetLanguage) {
268
+ case .installed: return
269
+ case .unsupported: throw TranslationError.unsupportedLanguagePairing
270
+ case .supported:
271
+ guard canRequestDownloads else { throw TranslationError.notInstalled }
272
+ _ = try await translate(texts: [""])
273
+ }
274
+ }
275
+
276
+ /// Translates one text.
277
+ public func translate(_ string: String) async throws -> Response {
278
+ guard !string.isEmpty else { throw TranslationError.nothingToTranslate }
279
+ return try await translations(from: [Request(sourceText: string)])[0]
280
+ }
281
+
282
+ /// Translates the requests together, answering in their order.
283
+ public func translations(from batch: [Request]) async throws -> [Response] {
284
+ guard !batch.isEmpty else { return [] }
285
+ let (source, texts) = try await translate(texts: batch.map(\.sourceText))
286
+ let target = targetLanguage ?? _TranslationHost.defaultTarget
287
+ return zip(batch, texts).map { request, text in
288
+ Response(sourceLanguage: source, targetLanguage: target, sourceText: request.sourceText,
289
+ targetText: text, clientIdentifier: request.clientIdentifier)
290
+ }
291
+ }
292
+
293
+ /// Translates the requests, delivering each response as a sequence.
294
+ public func translate(batch: [Request]) -> BatchResponse {
295
+ BatchResponse { [self] in try await translations(from: batch) }
296
+ }
297
+
298
+ /// Stops the session: later translations fail.
299
+ public func cancel() { cancelled = true }
300
+
301
+ private func translate(texts: [String]) async throws -> (Locale.Language, [String]) {
302
+ if cancelled || Task.isCancelled { throw CancellationError() }
303
+ let params: _JSON = .object([
304
+ "action": .string("translate"),
305
+ "source": sourceLanguage.map { .string(_TranslationHost.tag($0)) } ?? .null,
306
+ "target": .string(_TranslationHost.tag(targetLanguage ?? _TranslationHost.defaultTarget)),
307
+ "texts": .array(texts.map { .string($0) }),
308
+ "allowDownload": .bool(canRequestDownloads),
309
+ ])
310
+ let value: _JSON
311
+ do {
312
+ value = try await _TranslationHost.transport(params)
313
+ } catch {
314
+ throw _TranslationHost.error(error)
315
+ }
316
+ guard case .object(let fields) = value, case .array(let items)? = fields["texts"] else {
317
+ throw _TranslationHost.status(value) == .unsupported ? TranslationError.unsupportedLanguagePairing
318
+ : TranslationError.internalError
319
+ }
320
+ let translated = items.map { item -> String in
321
+ if case .string(let text) = item { return text }
322
+ return ""
323
+ }
324
+ guard translated.count == texts.count else { throw TranslationError.internalError }
325
+ var source = sourceLanguage
326
+ if source == nil, case .string(let detected)? = fields["source"] { source = Locale.Language(identifier: detected) }
327
+ guard let source else { throw TranslationError.unableToIdentifyLanguage }
328
+ return (source, translated)
329
+ }
330
+ }
331
+
332
+ // MARK: - SwiftUI
333
+
334
+ nonisolated extension View {
335
+ /// Runs `action` with a session for `configuration` when the view appears
336
+ /// with one, and again each time it changes (`invalidate()` included). A
337
+ /// nil configuration runs nothing. The session may download a model.
338
+ public func translationTask(_ configuration: TranslationSession.Configuration?,
339
+ @_inheritActorContext action: @escaping @Sendable (TranslationSession) async -> Void) -> some View {
340
+ task(id: configuration) {
341
+ guard let configuration else { return }
342
+ await action(TranslationSession(source: configuration.source, target: configuration.target,
343
+ canRequestDownloads: true))
344
+ }
345
+ }
346
+
347
+ /// Runs `action` with a session from `source` to `target` when the view appears.
348
+ public func translationTask(source: Locale.Language? = nil, target: Locale.Language? = nil,
349
+ @_inheritActorContext action: @escaping @Sendable (TranslationSession) async -> Void) -> some View {
350
+ task {
351
+ await action(TranslationSession(source: source, target: target, canRequestDownloads: true))
352
+ }
353
+ }
354
+
355
+ /// The system translation overlay for `text`. On an iPhone it is a sheet;
356
+ /// here too: the original, its translation into the viewer's language
357
+ /// (or why there is none), a Done button and, with `replacementAction`,
358
+ /// "Replace with Translation". The popover's anchor and arrow edge are ignored.
359
+ @MainActor
360
+ public func translationPresentation(isPresented: Binding<Bool>, text: String,
361
+ attachmentAnchor: PopoverAttachmentAnchor = .rect(.bounds),
362
+ arrowEdge: Edge = .top,
363
+ replacementAction: ((String) -> Void)? = nil) -> some View {
364
+ sheet(isPresented: isPresented) {
365
+ _TranslationPresentation(text: text, replacementAction: replacementAction)
366
+ }
367
+ }
368
+ }
369
+
370
+ /// The sheet of `.translationPresentation`.
371
+ struct _TranslationPresentation: View {
372
+ let text: String
373
+ let replacementAction: ((String) -> Void)?
374
+ @Environment(\.dismiss) private var dismiss
375
+ @State private var translation: String?
376
+ @State private var failure: TranslationError?
377
+
378
+ var body: some View {
379
+ NavigationStack {
380
+ List {
381
+ Section {
382
+ Text(text)
383
+ }
384
+ Section {
385
+ if let translation {
386
+ Text(translation)
387
+ } else if let failure {
388
+ Text(failure == .unsupportedLanguagePairing || failure == .unableToIdentifyLanguage
389
+ ? "Translation is not available in this browser for this text."
390
+ : failure.errorDescription ?? "The translation failed.")
391
+ .foregroundStyle(.secondary)
392
+ } else {
393
+ ProgressView()
394
+ }
395
+ }
396
+ if let translation, let replacementAction {
397
+ Section {
398
+ Button("Replace with Translation") {
399
+ replacementAction(translation)
400
+ dismiss()
401
+ }
402
+ }
403
+ }
404
+ }
405
+ .navigationTitle("Translate")
406
+ .navigationBarTitleDisplayMode(.inline)
407
+ .toolbar {
408
+ ToolbarItem(placement: .confirmationAction) {
409
+ Button("Done") { dismiss() }
410
+ }
411
+ }
412
+ }
413
+ .translationTask(source: nil, target: nil) { session in
414
+ do {
415
+ let response = try await session.translate(text)
416
+ await MainActor.run { translation = response.targetText }
417
+ } catch {
418
+ let failure = error as? TranslationError ?? .internalError
419
+ await MainActor.run { self.failure = failure }
420
+ }
421
+ }
422
+ }
423
+ }
@@ -0,0 +1,213 @@
1
+ // UIKit's share sheet in the browser. Presenting a `UIActivityViewController`
2
+ // (any controller's `present`, or a `UIViewControllerRepresentable` that
3
+ // shows one in a sheet) shares its items through the page, as SwiftUI's
4
+ // `ShareLink` does: a `share` host request, which the page performs with the
5
+ // Web Share API, or as downloads where the browser has none
6
+ // (docs/ops-protocol.md, "Sharing"). Strings become the text, the first URL
7
+ // the link, images their files; an item source gives its item for no
8
+ // particular activity, and its link metadata's title becomes the share's
9
+ // title. The controller is done once the page answers: it dismisses itself
10
+ // and reports to `completionWithItemsHandler` (shared or not, with no
11
+ // activity type, since the browser does not say where the items went).
12
+ // Custom `UIActivity`s are kept; the browser's sheet cannot show them.
13
+
14
+ import Foundation
15
+ import FoundationBridge
16
+ import SwiftUI
17
+
18
+ // MARK: - Activities
19
+
20
+ /// A service the share sheet offers. Kept: the browser's share sheet lists
21
+ /// its own targets, so an app's activities are never shown or performed.
22
+ open class UIActivity: @unchecked Sendable {
23
+ public struct ActivityType: RawRepresentable, Hashable, Sendable {
24
+ public let rawValue: String
25
+ public init(rawValue: String) { self.rawValue = rawValue }
26
+ public init(_ rawValue: String) { self.rawValue = rawValue }
27
+
28
+ public static let postToFacebook = ActivityType("com.apple.UIKit.activity.PostToFacebook")
29
+ public static let postToTwitter = ActivityType("com.apple.UIKit.activity.PostToTwitter")
30
+ public static let postToWeibo = ActivityType("com.apple.UIKit.activity.PostToWeibo")
31
+ public static let message = ActivityType("com.apple.UIKit.activity.Message")
32
+ public static let mail = ActivityType("com.apple.UIKit.activity.Mail")
33
+ public static let print = ActivityType("com.apple.UIKit.activity.Print")
34
+ public static let copyToPasteboard = ActivityType("com.apple.UIKit.activity.CopyToPasteboard")
35
+ public static let assignToContact = ActivityType("com.apple.UIKit.activity.AssignToContact")
36
+ public static let saveToCameraRoll = ActivityType("com.apple.UIKit.activity.SaveToCameraRoll")
37
+ public static let addToReadingList = ActivityType("com.apple.UIKit.activity.AddToReadingList")
38
+ public static let postToFlickr = ActivityType("com.apple.UIKit.activity.PostToFlickr")
39
+ public static let postToVimeo = ActivityType("com.apple.UIKit.activity.PostToVimeo")
40
+ public static let postToTencentWeibo = ActivityType("com.apple.UIKit.activity.TencentWeibo")
41
+ public static let airDrop = ActivityType("com.apple.UIKit.activity.AirDrop")
42
+ public static let openInIBooks = ActivityType("com.apple.UIKit.activity.OpenInIBooks")
43
+ public static let markupAsPDF = ActivityType("com.apple.UIKit.activity.MarkupAsPDF")
44
+ public static let sharePlay = ActivityType("com.apple.UIKit.activity.SharePlay")
45
+ public static let collaborationInviteWithLink = ActivityType("com.apple.UIKit.activity.CollaborationInviteWithLink")
46
+ public static let collaborationCopyLink = ActivityType("com.apple.UIKit.activity.CollaborationCopyLink")
47
+ public static let addToHomeScreen = ActivityType("com.apple.UIKit.activity.AddToHomeScreen")
48
+ }
49
+
50
+ public enum Category: Int, Sendable { case action, share }
51
+
52
+ public init() {}
53
+
54
+ open class var activityCategory: Category { .action }
55
+ open var activityType: ActivityType? { nil }
56
+ open var activityTitle: String? { nil }
57
+ open var activityImage: UIImage? { nil }
58
+ open var activityViewController: UIViewController? { nil }
59
+ open func canPerform(withActivityItems activityItems: [Any]) -> Bool { false }
60
+ open func prepare(withActivityItems activityItems: [Any]) {}
61
+ open func perform() { activityDidFinish(false) }
62
+ open func activityDidFinish(_ completed: Bool) {}
63
+ }
64
+
65
+ /// An object that gives the share sheet an item on demand. On iOS the
66
+ /// methods after the first two are optional; here they have defaults.
67
+ @MainActor
68
+ public protocol UIActivityItemSource: AnyObject {
69
+ func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any
70
+ func activityViewController(_ activityViewController: UIActivityViewController,
71
+ itemForActivityType activityType: UIActivity.ActivityType?) -> Any?
72
+ func activityViewController(_ activityViewController: UIActivityViewController,
73
+ subjectForActivityType activityType: UIActivity.ActivityType?) -> String
74
+ func activityViewController(_ activityViewController: UIActivityViewController,
75
+ dataTypeIdentifierForActivityType activityType: UIActivity.ActivityType?) -> String
76
+ func activityViewControllerLinkMetadata(_ activityViewController: UIActivityViewController) -> LPLinkMetadata?
77
+ }
78
+
79
+ extension UIActivityItemSource {
80
+ public func activityViewController(_ activityViewController: UIActivityViewController,
81
+ subjectForActivityType activityType: UIActivity.ActivityType?) -> String { "" }
82
+ public func activityViewController(_ activityViewController: UIActivityViewController,
83
+ dataTypeIdentifierForActivityType activityType: UIActivity.ActivityType?) -> String { "" }
84
+ public func activityViewControllerLinkMetadata(_ activityViewController: UIActivityViewController) -> LPLinkMetadata? { nil }
85
+ }
86
+
87
+ /// An item source that makes its item when asked (an `Operation` on iOS):
88
+ /// the share sheet takes `item`, which defaults to the placeholder.
89
+ @MainActor
90
+ open class UIActivityItemProvider: UIActivityItemSource {
91
+ public let placeholderItem: Any?
92
+ public private(set) var activityType: UIActivity.ActivityType?
93
+
94
+ public init(placeholderItem: Any) { self.placeholderItem = placeholderItem }
95
+
96
+ open var item: Any { placeholderItem as Any }
97
+
98
+ public func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any { placeholderItem as Any }
99
+ public func activityViewController(_ activityViewController: UIActivityViewController,
100
+ itemForActivityType activityType: UIActivity.ActivityType?) -> Any? {
101
+ self.activityType = activityType
102
+ return item
103
+ }
104
+ }
105
+
106
+ /// A link's title, address and pictures, for a share sheet's header or a
107
+ /// link preview. LinkPresentation re-exports it (Sources/LinkPresentation);
108
+ /// it lives here so that `UIActivityItemSource` can name it, as on iOS.
109
+ open class LPLinkMetadata: NSObject, @unchecked Sendable {
110
+ /// The URL the metadata was asked for.
111
+ open var originalURL: URL?
112
+ /// The URL the metadata describes (after redirects).
113
+ open var url: URL?
114
+ open var title: String?
115
+ open var iconProvider: NSItemProvider?
116
+ open var imageProvider: NSItemProvider?
117
+ open var videoProvider: NSItemProvider?
118
+ open var remoteVideoURL: URL?
119
+
120
+ public override init() { super.init() }
121
+ }
122
+
123
+ // MARK: - The share sheet
124
+
125
+ /// The share sheet: presenting it shares its items through the page (see
126
+ /// the top of this file).
127
+ @MainActor
128
+ open class UIActivityViewController: UIViewController {
129
+ public typealias CompletionWithItemsHandler = (UIActivity.ActivityType?, Bool, [Any]?, (any Error)?) -> Void
130
+
131
+ /// Shares a request through the page; tests replace it.
132
+ static var shareOnPage: @MainActor (_JSON) async -> Bool = { params in
133
+ guard let answer = try? await _Runtime.shared._hostRequest(kind: "share", params: params) else { return false }
134
+ if case .object(let fields) = answer, case .string(let outcome)? = fields["outcome"] { return outcome != "cancelled" }
135
+ return true
136
+ }
137
+
138
+ public let activityItems: [Any]
139
+ public let applicationActivities: [UIActivity]?
140
+ open var excludedActivityTypes: [UIActivity.ActivityType]?
141
+ open var completionWithItemsHandler: CompletionWithItemsHandler?
142
+ open var allowsProminentActivity = true
143
+ private var shared = false
144
+
145
+ public init(activityItems: [Any], applicationActivities: [UIActivity]?) {
146
+ self.activityItems = activityItems
147
+ self.applicationActivities = applicationActivities
148
+ super.init(nibName: nil, bundle: nil)
149
+ }
150
+
151
+ public required init?(coder: NSCoder) { nil }
152
+
153
+ /// Presented: the items go to the page's share sheet; once it answers,
154
+ /// the controller dismisses itself and reports.
155
+ open override func viewDidAppear(_ animated: Bool) {
156
+ super.viewDidAppear(animated)
157
+ guard !shared else { return }
158
+ shared = true
159
+ let params = sharePayload
160
+ let items = resolvedItems
161
+ Task { @MainActor in
162
+ let completed = await Self.shareOnPage(params)
163
+ self.dismiss(animated: animated)
164
+ self.completionWithItemsHandler?(nil, completed, completed ? items : nil, nil)
165
+ }
166
+ }
167
+
168
+ /// The items as shared: an item source's item for no particular activity.
169
+ var resolvedItems: [Any] {
170
+ activityItems.compactMap { item in
171
+ if let source = item as? any UIActivityItemSource { return source.activityViewController(self, itemForActivityType: nil) }
172
+ return item
173
+ }
174
+ }
175
+
176
+ /// The `share` request's fields: `title` (an item source's link metadata
177
+ /// or subject), `text`, `url`, and the images as `files`, `bitmaps` or
178
+ /// `images`, as `ShareLink` sends them.
179
+ var sharePayload: _JSON {
180
+ var title: String?
181
+ var texts: [String] = []
182
+ var url: String?
183
+ var picture: [String: [_JSON]] = [:]
184
+ for item in activityItems {
185
+ if let source = item as? any UIActivityItemSource {
186
+ if title == nil { title = source.activityViewControllerLinkMetadata(self)?.title }
187
+ let subject = source.activityViewController(self, subjectForActivityType: nil)
188
+ if title == nil, !subject.isEmpty { title = subject }
189
+ }
190
+ }
191
+ for item in resolvedItems {
192
+ switch item {
193
+ case let string as String: texts.append(string)
194
+ case let attributed as NSAttributedString: texts.append(attributed.string)
195
+ case let link as URL:
196
+ if url == nil { url = link.absoluteString } else { texts.append(link.absoluteString) }
197
+ case let image as UIImage:
198
+ for (key, value) in _PageFiles.fields(for: image, name: title ?? "Image") {
199
+ if case .array(let entries) = value { picture[key, default: []] += entries }
200
+ }
201
+ case let data as Data:
202
+ picture["files", default: []].append(_PageFiles.entry(name: title ?? "Shared", type: "application/octet-stream", data: data))
203
+ default: break
204
+ }
205
+ }
206
+ var fields: [String: _JSON] = [:]
207
+ if let title { fields["title"] = .string(title) }
208
+ if !texts.isEmpty { fields["text"] = .string(texts.joined(separator: "\n")) }
209
+ if let url { fields["url"] = .string(url) }
210
+ for (key, entries) in picture { fields[key] = .array(entries) }
211
+ return .object(fields)
212
+ }
213
+ }