@swiftbrowser/swift 0.0.0-stage → 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 +214 -0
- package/README.md +10 -2
- 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 +61 -0
- 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/FoundationBridge/Bundle.swift +119 -0
- 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 +29 -0
- 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/Locale.swift +86 -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 +53 -0
- package/Sources/FoundationBridge/UITextChecker.swift +30 -0
- package/Sources/FoundationBridge/URLSession.swift +718 -0
- package/Sources/FoundationBridge/UserDefaults.swift +183 -0
- 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 +181 -0
- package/Sources/SwiftUI/API/AccessibilityExtras.swift +33 -0
- package/Sources/SwiftUI/API/AccessibilityFocus.swift +63 -0
- package/Sources/SwiftUI/API/Alert.swift +221 -0
- package/Sources/SwiftUI/API/AlignmentGuides.swift +65 -0
- package/Sources/SwiftUI/API/Animation.swift +285 -0
- package/Sources/SwiftUI/API/App.swift +87 -0
- 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 +237 -0
- 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 +300 -0
- package/Sources/SwiftUI/API/CustomLayout.swift +442 -0
- package/Sources/SwiftUI/API/CustomToolbarContent.swift +46 -0
- package/Sources/SwiftUI/API/Decorations.swift +92 -0
- package/Sources/SwiftUI/API/EditMode.swift +212 -0
- package/Sources/SwiftUI/API/Effects.swift +388 -0
- package/Sources/SwiftUI/API/Entry.swift +8 -0
- package/Sources/SwiftUI/API/Environment.swift +439 -0
- package/Sources/SwiftUI/API/EnvironmentSendable.swift +6 -0
- package/Sources/SwiftUI/API/Focus.swift +137 -0
- package/Sources/SwiftUI/API/Font.swift +131 -0
- package/Sources/SwiftUI/API/Gauge.swift +290 -0
- package/Sources/SwiftUI/API/Geometry.swift +89 -0
- package/Sources/SwiftUI/API/GeometryEffects.swift +232 -0
- package/Sources/SwiftUI/API/GeometryReader.swift +135 -0
- package/Sources/SwiftUI/API/GestureState.swift +65 -0
- package/Sources/SwiftUI/API/Gestures.swift +342 -0
- package/Sources/SwiftUI/API/Glass.swift +127 -0
- package/Sources/SwiftUI/API/Grid.swift +188 -0
- package/Sources/SwiftUI/API/GroupBoxAndControlGroup.swift +130 -0
- package/Sources/SwiftUI/API/KeyPress.swift +54 -0
- package/Sources/SwiftUI/API/LabelStyle.swift +124 -0
- package/Sources/SwiftUI/API/Layout.swift +220 -0
- package/Sources/SwiftUI/API/LazyStacks.swift +49 -0
- package/Sources/SwiftUI/API/LegacyAlert.swift +97 -0
- package/Sources/SwiftUI/API/Lists.swift +331 -0
- package/Sources/SwiftUI/API/Menu.swift +58 -0
- package/Sources/SwiftUI/API/Modifiers.swift +313 -0
- package/Sources/SwiftUI/API/MoreModifiers.swift +100 -0
- package/Sources/SwiftUI/API/Namespace.swift +44 -0
- package/Sources/SwiftUI/API/Navigation.swift +386 -0
- package/Sources/SwiftUI/API/NavigationDestinationBindings.swift +55 -0
- package/Sources/SwiftUI/API/ObservableObject.swift +293 -0
- package/Sources/SwiftUI/API/OnChange.swift +48 -0
- package/Sources/SwiftUI/API/Path.swift +543 -0
- package/Sources/SwiftUI/API/Phase8Controls.swift +411 -0
- package/Sources/SwiftUI/API/PhaseAnimator.swift +130 -0
- package/Sources/SwiftUI/API/Picker.swift +185 -0
- 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 +122 -0
- package/Sources/SwiftUI/API/PresentationExtras.swift +60 -0
- package/Sources/SwiftUI/API/Primitives.swift +517 -0
- package/Sources/SwiftUI/API/Publishers.swift +107 -0
- package/Sources/SwiftUI/API/Redaction.swift +75 -0
- package/Sources/SwiftUI/API/RowActions.swift +84 -0
- package/Sources/SwiftUI/API/Scenes.swift +131 -0
- package/Sources/SwiftUI/API/ScrollModifiers.swift +132 -0
- package/Sources/SwiftUI/API/ScrollTargets.swift +104 -0
- 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 +409 -0
- 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 +144 -0
- package/Sources/SwiftUI/API/StatusGaps.swift +121 -0
- package/Sources/SwiftUI/API/StrokeStyle.swift +30 -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 +263 -0
- package/Sources/SwiftUI/API/Tasks.swift +35 -0
- 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/Timeline.swift +212 -0
- package/Sources/SwiftUI/API/Toolbar.swift +251 -0
- 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 +215 -0
- package/Sources/SwiftUI/API/ViewModifier.swift +43 -0
- package/Sources/SwiftUI/API/VisualEffect.swift +155 -0
- package/Sources/SwiftUI/API/Windows.swift +25 -0
- package/Sources/SwiftUI/Charts/Axis.swift +325 -0
- package/Sources/SwiftUI/Charts/AxisFormatsAndRanges.swift +68 -0
- package/Sources/SwiftUI/Charts/Chart.swift +660 -0
- package/Sources/SwiftUI/Charts/ChartContent.swift +376 -0
- package/Sources/SwiftUI/Charts/ChartProxy.swift +57 -0
- package/Sources/SwiftUI/Charts/Marks.swift +204 -0
- package/Sources/SwiftUI/Charts/Plottable.swift +99 -0
- package/Sources/SwiftUI/Charts/Scales.swift +326 -0
- package/Sources/SwiftUI/Localization/Localization.swift +498 -0
- package/Sources/SwiftUI/Localization/PluralRules.swift +127 -0
- package/Sources/SwiftUI/Runtime/Executor.swift +85 -0
- package/Sources/SwiftUI/Runtime/Exports.swift +101 -0
- package/Sources/SwiftUI/Runtime/ImageSource.swift +310 -0
- package/Sources/SwiftUI/Runtime/JSON.swift +143 -0
- package/Sources/SwiftUI/Runtime/JSONParser.swift +443 -0
- package/Sources/SwiftUI/Runtime/LazyRows.swift +99 -0
- package/Sources/SwiftUI/Runtime/Measurements.swift +140 -0
- package/Sources/SwiftUI/Runtime/Ops.swift +152 -0
- package/Sources/SwiftUI/Runtime/Reconciler.swift +219 -0
- package/Sources/SwiftUI/Runtime/Replay.swift +382 -0
- package/Sources/SwiftUI/Runtime/Runtime.swift +2146 -0
- 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 +2 -0
- package/index.mjs +16 -0
- package/manifest.d.mts +2 -0
- package/manifest.mjs +39 -0
- package/package.json +30 -4
- package/sync-sources.mjs +33 -0
|
@@ -0,0 +1,660 @@
|
|
|
1
|
+
// `Chart`: kind `chart`, props `{marks, xAxis, yAxis, legend}` in unit
|
|
2
|
+
// coordinates (x left → right, y top → bottom), children `chartitem`s for
|
|
3
|
+
// annotations and view axis labels. See docs/ops-protocol.md, Phase 7.
|
|
4
|
+
|
|
5
|
+
// MARK: - Chart
|
|
6
|
+
|
|
7
|
+
public struct Chart<Content: ChartContent> {
|
|
8
|
+
let content: Content
|
|
9
|
+
|
|
10
|
+
public init(@ChartContentBuilder content: () -> Content) {
|
|
11
|
+
self.content = content()
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
extension Chart {
|
|
16
|
+
public init<Data: RandomAccessCollection, C: ChartContent>(
|
|
17
|
+
_ data: Data, @ChartContentBuilder content: @escaping (Data.Element) -> C
|
|
18
|
+
) where Data.Element: Identifiable, Content == ForEach<Data, Data.Element.ID, C> {
|
|
19
|
+
self.content = ForEach(data, content: content)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
public init<Data: RandomAccessCollection, ID: Hashable, C: ChartContent>(
|
|
23
|
+
_ data: Data, id: KeyPath<Data.Element, ID>, @ChartContentBuilder content: @escaping (Data.Element) -> C
|
|
24
|
+
) where Content == ForEach<Data, ID, C> {
|
|
25
|
+
self.content = ForEach(data, id: id, content: content)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
extension Chart: _PrimitiveView {}
|
|
30
|
+
extension Chart: _HostView {
|
|
31
|
+
var _kind: String { "chart" }
|
|
32
|
+
|
|
33
|
+
func _props(in environment: EnvironmentValues) -> _JSON {
|
|
34
|
+
_resolveChart(content, config: environment._chartConfig).props
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
var _content: [any View] {
|
|
38
|
+
// `_content` has no environment; the group reads the chart config
|
|
39
|
+
// itself and contributes the annotation and label views.
|
|
40
|
+
[_ChartItems(content: AnyChartContent(content))]
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/// Contributes the chart's `chartitem` children, resolved with the chart
|
|
45
|
+
/// configuration from the environment.
|
|
46
|
+
struct _ChartItems {
|
|
47
|
+
let content: AnyChartContent
|
|
48
|
+
@Environment(\._chartConfig) private var config
|
|
49
|
+
|
|
50
|
+
init(content: AnyChartContent) { self.content = content }
|
|
51
|
+
}
|
|
52
|
+
extension _ChartItems: _PrimitiveView {}
|
|
53
|
+
extension _ChartItems: _GroupView {
|
|
54
|
+
var _children: [any View] { _resolveChart(content, config: config).items }
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/// An annotation or a view axis label. Kind `chartitem`.
|
|
58
|
+
struct _ChartItemView {
|
|
59
|
+
let role: String
|
|
60
|
+
let x0: Double
|
|
61
|
+
let x1: Double
|
|
62
|
+
let y0: Double
|
|
63
|
+
let y1: Double
|
|
64
|
+
let position: String
|
|
65
|
+
let alignment: Alignment
|
|
66
|
+
let spacing: Double
|
|
67
|
+
let content: any View
|
|
68
|
+
}
|
|
69
|
+
extension _ChartItemView: _PrimitiveView {}
|
|
70
|
+
extension _ChartItemView: _HostView {
|
|
71
|
+
var _kind: String { "chartitem" }
|
|
72
|
+
|
|
73
|
+
func _props(in environment: EnvironmentValues) -> _JSON {
|
|
74
|
+
.object([
|
|
75
|
+
"role": .string(role),
|
|
76
|
+
"x0": .number(_unit(x0)), "x1": .number(_unit(x1)),
|
|
77
|
+
"y0": .number(_unit(y0)), "y1": .number(_unit(y1)),
|
|
78
|
+
"position": .string(position),
|
|
79
|
+
"alignment": .string(alignment._name),
|
|
80
|
+
"spacing": .number(spacing),
|
|
81
|
+
])
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
var _content: [any View] { [content] }
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// MARK: - Scales
|
|
88
|
+
|
|
89
|
+
/// A resolved scale: categories (band) or a continuous domain.
|
|
90
|
+
struct _ChartScale {
|
|
91
|
+
enum Kind {
|
|
92
|
+
case band([String])
|
|
93
|
+
case continuous(lower: Double, upper: Double, isDate: Bool)
|
|
94
|
+
}
|
|
95
|
+
var kind: Kind
|
|
96
|
+
var reversed = false
|
|
97
|
+
|
|
98
|
+
var isBand: Bool { if case .band = kind { true } else { false } }
|
|
99
|
+
var isDate: Bool { if case .continuous(_, _, let isDate) = kind { isDate } else { false } }
|
|
100
|
+
|
|
101
|
+
/// 0…1 from the lower bound (or first category's center) to the upper.
|
|
102
|
+
func unit(_ value: _PlottableValue) -> Double? {
|
|
103
|
+
let raw: Double?
|
|
104
|
+
switch kind {
|
|
105
|
+
case .band(let categories):
|
|
106
|
+
guard case .string(let s) = value, let index = categories.firstIndex(of: s) else { return nil }
|
|
107
|
+
raw = (Double(index) + 0.5) / Double(categories.count)
|
|
108
|
+
case .continuous(let lower, let upper, _):
|
|
109
|
+
guard let v = value.continuous else { return nil }
|
|
110
|
+
raw = upper > lower ? (v - lower) / (upper - lower) : 0.5
|
|
111
|
+
}
|
|
112
|
+
return raw.map { reversed ? 1 - $0 : $0 }
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/// The band of a category, `nil` on a continuous scale.
|
|
116
|
+
func band(_ value: _PlottableValue) -> (Double, Double)? {
|
|
117
|
+
guard case .band(let categories) = kind, case .string(let s) = value,
|
|
118
|
+
let index = categories.firstIndex(of: s) else { return nil }
|
|
119
|
+
let n = Double(categories.count)
|
|
120
|
+
let band = (Double(index) / n, Double(index + 1) / n)
|
|
121
|
+
return reversed ? (1 - band.1, 1 - band.0) : band
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/// The band width when every value gets one band.
|
|
125
|
+
var bandWidth: Double {
|
|
126
|
+
if case .band(let categories) = kind { return 1 / Double(max(categories.count, 1)) }
|
|
127
|
+
return 1
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/// The ticks of one `AxisMarks`, as values.
|
|
132
|
+
struct _AxisTicks {
|
|
133
|
+
var marks: AxisMarks
|
|
134
|
+
var values: [_PlottableValue]
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
struct _ResolvedAxis {
|
|
138
|
+
var scale: _ChartScale
|
|
139
|
+
var ticks: [_AxisTicks]
|
|
140
|
+
var dateFormat: _DateFormat
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/// Builds the scale and ticks of one axis from the values the marks put on it.
|
|
144
|
+
func _resolveAxis(values: [_PlottableValue], domain: _ScaleDomainSpec, axis: _AxisSpec,
|
|
145
|
+
includesZeroByDefault: Bool) -> _ResolvedAxis {
|
|
146
|
+
var reversed = false
|
|
147
|
+
var includesZero: Bool? = nil
|
|
148
|
+
var explicitDomain: [_PlottableValue]? = nil
|
|
149
|
+
switch domain {
|
|
150
|
+
case .automatic(let zero, let rev):
|
|
151
|
+
includesZero = zero
|
|
152
|
+
reversed = rev
|
|
153
|
+
case .values(let domainValues):
|
|
154
|
+
explicitDomain = domainValues
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
let allValues = explicitDomain ?? values
|
|
158
|
+
let axisMarks = axis.marks.isEmpty ? [AxisMarks()] : axis.marks
|
|
159
|
+
|
|
160
|
+
// Categories: a band scale.
|
|
161
|
+
if allValues.contains(where: \.isString) {
|
|
162
|
+
var categories: [String] = []
|
|
163
|
+
for value in allValues {
|
|
164
|
+
if case .string(let s) = value, !categories.contains(s) { categories.append(s) }
|
|
165
|
+
}
|
|
166
|
+
let scale = _ChartScale(kind: .band(categories), reversed: reversed)
|
|
167
|
+
let ticks = axisMarks.map { marks -> _AxisTicks in
|
|
168
|
+
if case .explicit(let explicit) = marks.values.spec {
|
|
169
|
+
return _AxisTicks(marks: marks, values: explicit.filter { value in
|
|
170
|
+
if case .string(let s) = value { return categories.contains(s) }
|
|
171
|
+
return false
|
|
172
|
+
})
|
|
173
|
+
}
|
|
174
|
+
return _AxisTicks(marks: marks, values: categories.map { .string($0) })
|
|
175
|
+
}
|
|
176
|
+
return _ResolvedAxis(scale: scale, ticks: ticks, dateFormat: .dayMonth)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Continuous: numbers or dates.
|
|
180
|
+
let isDate = allValues.contains(where: \.isDate)
|
|
181
|
+
let numbers = allValues.compactMap(\.continuous)
|
|
182
|
+
var lower = numbers.min() ?? 0
|
|
183
|
+
var upper = numbers.max() ?? (isDate ? lower + _secondsPerDay : 1)
|
|
184
|
+
if explicitDomain == nil, includesZero ?? includesZeroByDefault, !isDate {
|
|
185
|
+
lower = min(lower, 0)
|
|
186
|
+
upper = max(upper, 0)
|
|
187
|
+
}
|
|
188
|
+
if upper <= lower {
|
|
189
|
+
if isDate {
|
|
190
|
+
lower -= 12 * 3600
|
|
191
|
+
upper += 12 * 3600
|
|
192
|
+
} else if lower == 0 {
|
|
193
|
+
upper = 1
|
|
194
|
+
} else {
|
|
195
|
+
let pad = abs(lower) * 0.1
|
|
196
|
+
lower -= pad
|
|
197
|
+
upper += pad
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Ticks per `AxisMarks`, rounding the domain to them when asked.
|
|
202
|
+
var dateFormat = _DateFormat.dayMonth
|
|
203
|
+
var tickValues: [[Double]] = []
|
|
204
|
+
for marks in axisMarks {
|
|
205
|
+
switch marks.values.spec {
|
|
206
|
+
case .automatic(let options):
|
|
207
|
+
var ticks: [Double]
|
|
208
|
+
if isDate {
|
|
209
|
+
let dated = _niceDateTicks(lower: lower, upper: upper, options: options)
|
|
210
|
+
ticks = dated.ticks
|
|
211
|
+
dateFormat = dated.format
|
|
212
|
+
} else {
|
|
213
|
+
ticks = _niceTicks(lower: lower, upper: upper, options: options)
|
|
214
|
+
}
|
|
215
|
+
if explicitDomain == nil, let first = ticks.first, options.roundLowerBound { lower = min(lower, first) }
|
|
216
|
+
if explicitDomain == nil, let last = ticks.last, options.roundUpperBound { upper = max(upper, last) }
|
|
217
|
+
tickValues.append(ticks)
|
|
218
|
+
case .stride(let step, let roundLower, let roundUpper):
|
|
219
|
+
var ticks: [Double] = []
|
|
220
|
+
guard step > 0 else { tickValues.append([]); continue }
|
|
221
|
+
var tick = (lower / step).rounded(.down) * step
|
|
222
|
+
let last = (upper / step).rounded(.up) * step
|
|
223
|
+
while tick <= last + step * 1e-9, ticks.count < 1000 {
|
|
224
|
+
ticks.append(_cleanTick(tick, step: step))
|
|
225
|
+
tick += step
|
|
226
|
+
}
|
|
227
|
+
if explicitDomain == nil, let first = ticks.first, roundLower { lower = min(lower, first) }
|
|
228
|
+
if explicitDomain == nil, let final = ticks.last, roundUpper { upper = max(upper, final) }
|
|
229
|
+
if isDate { dateFormat = _dateFormat(forValues: ticks) }
|
|
230
|
+
tickValues.append(ticks)
|
|
231
|
+
case .explicit(let explicit):
|
|
232
|
+
let ticks = explicit.compactMap(\.continuous)
|
|
233
|
+
if isDate { dateFormat = _dateFormat(forValues: ticks) }
|
|
234
|
+
tickValues.append(ticks)
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Drop the ticks that fall outside the (unrounded) domain.
|
|
239
|
+
let epsilon = (upper - lower) * 1e-9
|
|
240
|
+
let scale = _ChartScale(kind: .continuous(lower: lower, upper: upper, isDate: isDate), reversed: reversed)
|
|
241
|
+
let ticks = zip(axisMarks, tickValues).map { marks, values in
|
|
242
|
+
let kept: [Double]
|
|
243
|
+
if case .explicit = marks.values.spec {
|
|
244
|
+
kept = values
|
|
245
|
+
} else {
|
|
246
|
+
kept = values.filter { $0 >= lower - epsilon && $0 <= upper + epsilon }
|
|
247
|
+
}
|
|
248
|
+
return _AxisTicks(marks: marks, values: kept.map { isDate ? .date($0) : .number($0) })
|
|
249
|
+
}
|
|
250
|
+
return _ResolvedAxis(scale: scale, ticks: ticks, dateFormat: dateFormat)
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// MARK: - Resolution
|
|
254
|
+
|
|
255
|
+
struct _ResolvedChart {
|
|
256
|
+
var props: _JSON
|
|
257
|
+
var items: [any View]
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/// A mark after scaling, ready to serialize.
|
|
261
|
+
private struct _OutMark {
|
|
262
|
+
var json: [String: _JSON]
|
|
263
|
+
/// Line/area grouping key, `nil` for other kinds.
|
|
264
|
+
var groupKey: _PlottableValue?
|
|
265
|
+
var groupKind: _RawMarkKind?
|
|
266
|
+
var points: [[String: Double]] = []
|
|
267
|
+
var sortKeys: [Double] = []
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
private struct _ChartResolver {
|
|
271
|
+
let x: _ResolvedAxis
|
|
272
|
+
let y: _ResolvedAxis
|
|
273
|
+
/// Palette indices for `foregroundStyle(by:)` / `symbol(by:)` values.
|
|
274
|
+
var styleIndices: [_PlottableValue: Int] = [:]
|
|
275
|
+
var symbolIndices: [_PlottableValue: Int] = [:]
|
|
276
|
+
var styleOrder: [_LabelledValue] = []
|
|
277
|
+
var symbolOrder: [_LabelledValue] = []
|
|
278
|
+
/// The default bar width on a continuous x axis: the smallest gap between bars.
|
|
279
|
+
var continuousBarBand = 1.0
|
|
280
|
+
|
|
281
|
+
init(marks: [_RawMark], config: _ChartConfig) {
|
|
282
|
+
x = _resolveAxis(values: marks.flatMap(\.xValues), domain: config.xDomain, axis: config.xAxis,
|
|
283
|
+
includesZeroByDefault: false)
|
|
284
|
+
y = _resolveAxis(values: marks.flatMap(\.yValues), domain: config.yDomain, axis: config.yAxis,
|
|
285
|
+
includesZeroByDefault: true)
|
|
286
|
+
for mark in marks {
|
|
287
|
+
if let by = mark.modifiers.styleBy, styleIndices[by.value] == nil {
|
|
288
|
+
styleIndices[by.value] = styleOrder.count
|
|
289
|
+
styleOrder.append(by)
|
|
290
|
+
}
|
|
291
|
+
if let by = mark.modifiers.symbolBy, symbolIndices[by.value] == nil {
|
|
292
|
+
symbolIndices[by.value] = symbolOrder.count
|
|
293
|
+
symbolOrder.append(by)
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
if !x.scale.isBand {
|
|
297
|
+
let centers = Set(marks.filter { ($0.kind == .bar || $0.kind == .rectangle) && $0.x != nil }
|
|
298
|
+
.compactMap { $0.x.flatMap(x.scale.unit) }).sorted()
|
|
299
|
+
var gap = 1.0
|
|
300
|
+
for (a, b) in zip(centers, centers.dropFirst()) where b - a > 1e-9 { gap = min(gap, b - a) }
|
|
301
|
+
continuousBarBand = centers.count > 1 ? gap : 1
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Unit coordinates: x left → right, y top → bottom.
|
|
306
|
+
func ux(_ value: _PlottableValue) -> Double? { x.scale.unit(value) }
|
|
307
|
+
func uy(_ value: _PlottableValue) -> Double? { y.scale.unit(value).map { 1 - $0 } }
|
|
308
|
+
|
|
309
|
+
/// The unit position of 0 on the y axis (the bar baseline), clamped to the plot.
|
|
310
|
+
var yBaseline: Double {
|
|
311
|
+
if y.scale.isBand { return 1 }
|
|
312
|
+
return 1 - max(0, min(1, y.scale.unit(.number(0)) ?? 0))
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
var xBaseline: Double {
|
|
316
|
+
if x.scale.isBand { return 0 }
|
|
317
|
+
return max(0, min(1, x.scale.unit(.number(0)) ?? 0))
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
func style(for modifiers: _MarkModifiers) -> _JSON {
|
|
321
|
+
if let style = modifiers.style { return style._json }
|
|
322
|
+
if let by = modifiers.styleBy, let index = styleIndices[by.value] {
|
|
323
|
+
return _chartColorPalette[index % _chartColorPalette.count]._json
|
|
324
|
+
}
|
|
325
|
+
return Color.blue._json
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
func symbol(for modifiers: _MarkModifiers, defaultSymbol: String?) -> String? {
|
|
329
|
+
if let symbol = modifiers.symbol { return symbol }
|
|
330
|
+
if let by = modifiers.symbolBy, let index = symbolIndices[by.value] {
|
|
331
|
+
return _chartSymbolPalette[index % _chartSymbolPalette.count]
|
|
332
|
+
}
|
|
333
|
+
return defaultSymbol
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/// The rectangle of a bar or rectangle mark.
|
|
337
|
+
func rect(of mark: _RawMark) -> (x0: Double, x1: Double, y0: Double, y1: Double, fixedWidth: Double?) {
|
|
338
|
+
var x0 = 0.0, x1 = 1.0, y0 = 0.0, y1 = 1.0
|
|
339
|
+
var fixedWidth: Double? = nil
|
|
340
|
+
|
|
341
|
+
if let start = mark.xStart, let end = mark.xEnd {
|
|
342
|
+
x0 = x.scale.band(start)?.0 ?? ux(start) ?? 0
|
|
343
|
+
x1 = x.scale.band(end)?.1 ?? ux(end) ?? 1
|
|
344
|
+
} else if let value = mark.x {
|
|
345
|
+
let center = ux(value) ?? 0.5
|
|
346
|
+
let band = x.scale.isBand ? x.scale.bandWidth : continuousBarBand
|
|
347
|
+
switch mark.width ?? .automatic {
|
|
348
|
+
case .fixed(let points):
|
|
349
|
+
fixedWidth = points
|
|
350
|
+
x0 = center
|
|
351
|
+
x1 = center
|
|
352
|
+
case .ratio(let ratio):
|
|
353
|
+
x0 = center - band * ratio / 2
|
|
354
|
+
x1 = center + band * ratio / 2
|
|
355
|
+
case .automatic, .inset:
|
|
356
|
+
x0 = center - band * 0.4
|
|
357
|
+
x1 = center + band * 0.4
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
if let start = mark.yStart, let end = mark.yEnd {
|
|
362
|
+
y0 = y.scale.band(start).map { 1 - $0.1 } ?? uy(start) ?? 0
|
|
363
|
+
y1 = y.scale.band(end).map { 1 - $0.0 } ?? uy(end) ?? 1
|
|
364
|
+
} else if let value = mark.y {
|
|
365
|
+
if let band = y.scale.band(value) {
|
|
366
|
+
let center = 1 - (band.0 + band.1) / 2
|
|
367
|
+
let width = y.scale.bandWidth
|
|
368
|
+
switch mark.height ?? .automatic {
|
|
369
|
+
case .fixed, .automatic, .inset:
|
|
370
|
+
y0 = center - width * 0.4
|
|
371
|
+
y1 = center + width * 0.4
|
|
372
|
+
case .ratio(let ratio):
|
|
373
|
+
y0 = center - width * ratio / 2
|
|
374
|
+
y1 = center + width * ratio / 2
|
|
375
|
+
}
|
|
376
|
+
} else if mark.xStart != nil, mark.xEnd != nil {
|
|
377
|
+
// A horizontal bar on a continuous y axis: a thin band around the value.
|
|
378
|
+
let center = uy(value) ?? 0.5
|
|
379
|
+
y0 = center - 0.04
|
|
380
|
+
y1 = center + 0.04
|
|
381
|
+
} else {
|
|
382
|
+
y0 = uy(value) ?? 0
|
|
383
|
+
y1 = yBaseline
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
return (min(x0, x1), max(x0, x1), min(y0, y1), max(y0, y1), fixedWidth)
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/// Scales every mark; lines and areas with the same key become one mark.
|
|
391
|
+
func outMarks(_ marks: [_RawMark], includeMasks: Bool) -> [_OutMark] {
|
|
392
|
+
var out: [_OutMark] = []
|
|
393
|
+
var groupIndex: [String: Int] = [:]
|
|
394
|
+
|
|
395
|
+
for mark in marks {
|
|
396
|
+
let m = mark.modifiers
|
|
397
|
+
var json: [String: _JSON] = [
|
|
398
|
+
"style": style(for: m),
|
|
399
|
+
"opacity": .number(m.opacity),
|
|
400
|
+
]
|
|
401
|
+
if includeMasks, let mask = m.mask, let maskJSON = resolveMask(mask) {
|
|
402
|
+
json["mask"] = maskJSON
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
switch mark.kind {
|
|
406
|
+
case .bar, .rectangle:
|
|
407
|
+
let r = rect(of: mark)
|
|
408
|
+
json["kind"] = .string("rect")
|
|
409
|
+
json["x0"] = .number(_unit(r.x0))
|
|
410
|
+
json["x1"] = .number(_unit(r.x1))
|
|
411
|
+
json["y0"] = .number(_unit(r.y0))
|
|
412
|
+
json["y1"] = .number(_unit(r.y1))
|
|
413
|
+
json["cornerRadius"] = .number(m.cornerRadius)
|
|
414
|
+
json["fixedWidth"] = r.fixedWidth.map { .number($0) } ?? .null
|
|
415
|
+
out.append(_OutMark(json: json))
|
|
416
|
+
|
|
417
|
+
case .point:
|
|
418
|
+
guard let px = mark.x.flatMap(ux), let py = mark.y.flatMap(uy) else { continue }
|
|
419
|
+
json["kind"] = .string("point")
|
|
420
|
+
json["x"] = .number(_unit(px))
|
|
421
|
+
json["y"] = .number(_unit(py))
|
|
422
|
+
json["symbol"] = .string(symbol(for: m, defaultSymbol: "circle") ?? "circle")
|
|
423
|
+
json["symbolSize"] = .number(m.symbolSize ?? 8)
|
|
424
|
+
out.append(_OutMark(json: json))
|
|
425
|
+
|
|
426
|
+
case .rule:
|
|
427
|
+
var x0 = 0.0, x1 = 1.0, y0 = 0.0, y1 = 1.0
|
|
428
|
+
if let start = mark.xStart, let end = mark.xEnd {
|
|
429
|
+
x0 = ux(start) ?? 0; x1 = ux(end) ?? 1
|
|
430
|
+
} else if let value = mark.x {
|
|
431
|
+
x0 = ux(value) ?? 0.5; x1 = x0
|
|
432
|
+
}
|
|
433
|
+
if let start = mark.yStart, let end = mark.yEnd {
|
|
434
|
+
y0 = uy(start) ?? 0; y1 = uy(end) ?? 1
|
|
435
|
+
} else if let value = mark.y {
|
|
436
|
+
y0 = uy(value) ?? 0.5; y1 = y0
|
|
437
|
+
}
|
|
438
|
+
json["kind"] = .string("rule")
|
|
439
|
+
json["x0"] = .number(_unit(x0))
|
|
440
|
+
json["x1"] = .number(_unit(x1))
|
|
441
|
+
json["y0"] = .number(_unit(y0))
|
|
442
|
+
json["y1"] = .number(_unit(y1))
|
|
443
|
+
json["lineWidth"] = .number(m.lineWidth ?? 1)
|
|
444
|
+
out.append(_OutMark(json: json))
|
|
445
|
+
|
|
446
|
+
case .line, .area:
|
|
447
|
+
guard let xValue = mark.x, let px = ux(xValue) else { continue }
|
|
448
|
+
let key = mark.series ?? m.styleBy?.value ?? m.symbolBy?.value
|
|
449
|
+
let keyName = "\(mark.kind):\(key.map { "\($0)" } ?? "")"
|
|
450
|
+
var point: [String: Double]
|
|
451
|
+
if mark.kind == .line {
|
|
452
|
+
guard let py = (mark.y ?? mark.yEnd).flatMap(uy) else { continue }
|
|
453
|
+
point = ["x": _unit(px), "y": _unit(py)]
|
|
454
|
+
} else {
|
|
455
|
+
let top: Double
|
|
456
|
+
let bottom: Double
|
|
457
|
+
if let start = mark.yStart, let end = mark.yEnd {
|
|
458
|
+
top = uy(end) ?? 0
|
|
459
|
+
bottom = uy(start) ?? yBaseline
|
|
460
|
+
} else if let value = mark.y {
|
|
461
|
+
top = uy(value) ?? 0
|
|
462
|
+
bottom = yBaseline
|
|
463
|
+
} else { continue }
|
|
464
|
+
point = ["x": _unit(px), "y0": _unit(min(top, bottom)), "y1": _unit(max(top, bottom))]
|
|
465
|
+
}
|
|
466
|
+
if let index = groupIndex[keyName] {
|
|
467
|
+
out[index].points.append(point)
|
|
468
|
+
out[index].sortKeys.append(px)
|
|
469
|
+
} else {
|
|
470
|
+
json["kind"] = .string(mark.kind == .line ? "line" : "area")
|
|
471
|
+
json["interpolation"] = .string(m.interpolation)
|
|
472
|
+
if mark.kind == .line {
|
|
473
|
+
json["lineWidth"] = .number(m.lineWidth ?? 2)
|
|
474
|
+
json["symbol"] = symbol(for: m, defaultSymbol: nil).map { .string($0) } ?? .null
|
|
475
|
+
json["symbolSize"] = .number(m.symbolSize ?? 8)
|
|
476
|
+
}
|
|
477
|
+
groupIndex[keyName] = out.count
|
|
478
|
+
out.append(_OutMark(json: json, groupKey: key, groupKind: mark.kind, points: [point], sortKeys: [px]))
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// Lines and areas connect their points in x order.
|
|
484
|
+
for index in out.indices where out[index].groupKind != nil {
|
|
485
|
+
let order = out[index].sortKeys.indices.sorted {
|
|
486
|
+
let a = out[index].sortKeys[$0], b = out[index].sortKeys[$1]
|
|
487
|
+
return a == b ? $0 < $1 : a < b
|
|
488
|
+
}
|
|
489
|
+
let points = order.map { out[index].points[$0] }
|
|
490
|
+
out[index].json["points"] = .array(points.map { point in
|
|
491
|
+
.object(point.mapValues { .number($0) })
|
|
492
|
+
})
|
|
493
|
+
}
|
|
494
|
+
return out
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/// The first area or rect mark of a mask's content, scaled like the chart.
|
|
498
|
+
func resolveMask(_ content: any ChartContent) -> _JSON? {
|
|
499
|
+
var collector = _ChartCollector()
|
|
500
|
+
content._collectAny(into: &collector, modifiers: _MarkModifiers())
|
|
501
|
+
let marks = outMarks(collector.marks, includeMasks: false)
|
|
502
|
+
guard let first = marks.first(where: {
|
|
503
|
+
if case .string(let kind)? = $0.json["kind"] { return kind == "area" || kind == "rect" }
|
|
504
|
+
return false
|
|
505
|
+
}) else { return nil }
|
|
506
|
+
return .object(first.json)
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/// The anchor rectangle of a mark's annotations.
|
|
510
|
+
func annotationRect(of mark: _RawMark) -> (x0: Double, x1: Double, y0: Double, y1: Double) {
|
|
511
|
+
switch mark.kind {
|
|
512
|
+
case .bar, .rectangle:
|
|
513
|
+
let r = rect(of: mark)
|
|
514
|
+
return (r.x0, r.x1, r.y0, r.y1)
|
|
515
|
+
case .rule:
|
|
516
|
+
var x0 = 0.0, x1 = 1.0, y0 = 0.0, y1 = 1.0
|
|
517
|
+
if let value = mark.x { x0 = ux(value) ?? 0.5; x1 = x0 }
|
|
518
|
+
if let value = mark.y { y0 = uy(value) ?? 0.5; y1 = y0 }
|
|
519
|
+
return (x0, x1, y0, y1)
|
|
520
|
+
case .line, .area, .point:
|
|
521
|
+
let px = mark.x.flatMap(ux) ?? 0.5
|
|
522
|
+
let py = (mark.y ?? mark.yEnd).flatMap(uy) ?? 0.5
|
|
523
|
+
return (px, px, py, py)
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
func axisJSON(_ axis: _ResolvedAxis, spec: _AxisSpec, isX: Bool, items: inout [any View]) -> _JSON {
|
|
528
|
+
if spec.hidden { return .null }
|
|
529
|
+
let position = spec.marks.lazy.compactMap { $0.position._name }.first ?? (isX ? "bottom" : "trailing")
|
|
530
|
+
var gridLines: [_JSON] = []
|
|
531
|
+
var ticks: [_JSON] = []
|
|
532
|
+
var labels: [_JSON] = []
|
|
533
|
+
var views: [any View] = []
|
|
534
|
+
|
|
535
|
+
for set in axis.ticks {
|
|
536
|
+
let count = set.values.count
|
|
537
|
+
for (index, value) in set.values.enumerated() {
|
|
538
|
+
let scaled = axis.scale.unit(value)
|
|
539
|
+
// A value outside the scale's domain (a date bin that starts
|
|
540
|
+
// before the data) has no mark, as in Swift Charts.
|
|
541
|
+
if let scaled, scaled < -1e-9 || scaled > 1 + 1e-9 { continue }
|
|
542
|
+
let unit = scaled ?? 0
|
|
543
|
+
let at = _unit(isX ? unit : 1 - unit)
|
|
544
|
+
// A date's label starts at its tick, as Swift Charts places it;
|
|
545
|
+
// other values are centered on theirs.
|
|
546
|
+
func label(_ text: String) -> _JSON {
|
|
547
|
+
if isX, case .date = value {
|
|
548
|
+
return .object(["at": .number(at), "text": .string(text), "anchor": .string("leading")])
|
|
549
|
+
}
|
|
550
|
+
return .object(["at": .number(at), "text": .string(text)])
|
|
551
|
+
}
|
|
552
|
+
let marks = set.marks.content?(AxisValue(index: index, count: count, value: value))._items
|
|
553
|
+
?? [.gridLine, .tick, .label(.automatic)]
|
|
554
|
+
for item in marks {
|
|
555
|
+
switch item {
|
|
556
|
+
case .gridLine:
|
|
557
|
+
gridLines.append(.number(at))
|
|
558
|
+
case .tick:
|
|
559
|
+
ticks.append(.number(at))
|
|
560
|
+
case .label(.automatic):
|
|
561
|
+
labels.append(label(defaultLabel(value, axis: axis)))
|
|
562
|
+
case .label(.text(let text)):
|
|
563
|
+
labels.append(label(text))
|
|
564
|
+
case .label(.formatted(let format)):
|
|
565
|
+
labels.append(label(format(value) ?? defaultLabel(value, axis: axis)))
|
|
566
|
+
case .label(.view(let view)):
|
|
567
|
+
let edge: Double = position == "top" || position == "leading" ? 0 : 1
|
|
568
|
+
views.append(_ChartItemView(
|
|
569
|
+
role: isX ? "xLabel" : "yLabel",
|
|
570
|
+
x0: isX ? at : edge, x1: isX ? at : edge,
|
|
571
|
+
y0: isX ? edge : at, y1: isX ? edge : at,
|
|
572
|
+
position: position, alignment: .center, spacing: 0, content: view
|
|
573
|
+
))
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
items.append(contentsOf: views)
|
|
579
|
+
return .object([
|
|
580
|
+
"position": .string(position),
|
|
581
|
+
"gridLines": .array(gridLines),
|
|
582
|
+
"ticks": .array(ticks),
|
|
583
|
+
"labels": .array(labels),
|
|
584
|
+
])
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
func defaultLabel(_ value: _PlottableValue, axis: _ResolvedAxis) -> String {
|
|
588
|
+
switch value {
|
|
589
|
+
case .date(let seconds): _formatChartDate(seconds, as: axis.dateFormat)
|
|
590
|
+
case .number(let n): _formatChartNumber(n)
|
|
591
|
+
case .string(let s): s
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
func legendJSON(config: _ChartConfig) -> _JSON {
|
|
596
|
+
guard !config.legendHidden, !styleOrder.isEmpty || !symbolOrder.isEmpty else { return .null }
|
|
597
|
+
var items: [_JSON] = []
|
|
598
|
+
var seen = Set<_PlottableValue>()
|
|
599
|
+
for by in styleOrder {
|
|
600
|
+
seen.insert(by.value)
|
|
601
|
+
let symbol = symbolIndices[by.value].map { _chartSymbolPalette[$0 % _chartSymbolPalette.count] }
|
|
602
|
+
items.append(.object([
|
|
603
|
+
"label": .string(by.value.text),
|
|
604
|
+
"style": _chartColorPalette[styleIndices[by.value]! % _chartColorPalette.count]._json,
|
|
605
|
+
"symbol": symbol.map { .string($0) } ?? .null,
|
|
606
|
+
]))
|
|
607
|
+
}
|
|
608
|
+
for by in symbolOrder where !seen.contains(by.value) {
|
|
609
|
+
items.append(.object([
|
|
610
|
+
"label": .string(by.value.text),
|
|
611
|
+
"style": Color.blue._json,
|
|
612
|
+
"symbol": .string(_chartSymbolPalette[symbolIndices[by.value]! % _chartSymbolPalette.count]),
|
|
613
|
+
]))
|
|
614
|
+
}
|
|
615
|
+
let position: String = switch config.legendPosition {
|
|
616
|
+
case .top, .topLeading, .topTrailing: "top"
|
|
617
|
+
case .leading: "leading"
|
|
618
|
+
case .trailing: "trailing"
|
|
619
|
+
default: "bottom"
|
|
620
|
+
}
|
|
621
|
+
return .object(["position": .string(position), "items": .array(items)])
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
func _resolveChart(_ content: any ChartContent, config: _ChartConfig) -> _ResolvedChart {
|
|
626
|
+
var collector = _ChartCollector()
|
|
627
|
+
content._collectAny(into: &collector, modifiers: _MarkModifiers())
|
|
628
|
+
let marks = collector.marks
|
|
629
|
+
let resolver = _ChartResolver(marks: marks, config: config)
|
|
630
|
+
|
|
631
|
+
var items: [any View] = []
|
|
632
|
+
|
|
633
|
+
// Annotations, in mark order.
|
|
634
|
+
for mark in marks where !mark.modifiers.annotations.isEmpty {
|
|
635
|
+
let r = resolver.annotationRect(of: mark)
|
|
636
|
+
for annotation in mark.modifiers.annotations {
|
|
637
|
+
let resolved = annotation.position._resolved
|
|
638
|
+
items.append(_ChartItemView(
|
|
639
|
+
role: "annotation",
|
|
640
|
+
x0: r.x0, x1: r.x1, y0: r.y0, y1: r.y1,
|
|
641
|
+
position: resolved.position,
|
|
642
|
+
alignment: resolved.alignment ?? annotation.alignment,
|
|
643
|
+
spacing: annotation.spacing,
|
|
644
|
+
content: annotation.content
|
|
645
|
+
))
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
let markJSON = resolver.outMarks(marks, includeMasks: true).map { _JSON.object($0.json) }
|
|
650
|
+
let xAxis = resolver.axisJSON(resolver.x, spec: config.xAxis, isX: true, items: &items)
|
|
651
|
+
let yAxis = resolver.axisJSON(resolver.y, spec: config.yAxis, isX: false, items: &items)
|
|
652
|
+
|
|
653
|
+
let props: _JSON = .object([
|
|
654
|
+
"marks": .array(markJSON),
|
|
655
|
+
"xAxis": xAxis,
|
|
656
|
+
"yAxis": yAxis,
|
|
657
|
+
"legend": resolver.legendJSON(config: config),
|
|
658
|
+
])
|
|
659
|
+
return _ResolvedChart(props: props, items: items)
|
|
660
|
+
}
|