diff --git a/Package.resolved b/Package.resolved index 1629353..58b23ed 100644 --- a/Package.resolved +++ b/Package.resolved @@ -5,8 +5,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/liveview-native/liveview-client-swiftui", "state" : { - "branch" : "content-builder", - "revision" : "b80ea68b9d2ccf9e0d695b1f89e41278f003e740" + "branch" : "main", + "revision" : "8a17e877e962e87ff6e7cdd7f0d8cfab2777aadb" } }, { @@ -27,6 +27,15 @@ "version" : "1.2.2" } }, + { + "identity" : "swift-syntax", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-syntax.git", + "state" : { + "revision" : "f1e9245226002bb134884345d4809b9543da3666", + "version" : "509.0.0-swift-DEVELOPMENT-SNAPSHOT-2023-06-17-a" + } + }, { "identity" : "swiftphoenixclient", "kind" : "remoteSourceControl", diff --git a/Package.swift b/Package.swift index da8d218..f8959e5 100644 --- a/Package.swift +++ b/Package.swift @@ -13,7 +13,7 @@ let package = Package( targets: ["LiveViewNativeCharts"]), ], dependencies: [ - .package(url: "https://github.com/liveview-native/liveview-client-swiftui", branch: "content-builder") + .package(url: "https://github.com/liveview-native/liveview-client-swiftui", branch: "main") ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. diff --git a/Sources/LiveViewNativeCharts/AxisContent/AxisMarks.swift b/Sources/LiveViewNativeCharts/AxisContent/AxisMarks.swift index e874fd6..f6a3e37 100644 --- a/Sources/LiveViewNativeCharts/AxisContent/AxisMarks.swift +++ b/Sources/LiveViewNativeCharts/AxisContent/AxisMarks.swift @@ -371,7 +371,8 @@ extension Calendar.Component: AttributeDecodable { case "nanosecond": self = .nanosecond case "calendar": self = .calendar case "time_zone": self = .timeZone - case "is_leap_month": self = .isLeapMonth +// this crashes with Xcode 15 beta, but according to the docs should exist. +// case "is_leap_month": self = .isLeapMonth default: throw AttributeDecodingError.badValue(Self.self) } } diff --git a/Sources/LiveViewNativeCharts/ChartContentBuilder.swift b/Sources/LiveViewNativeCharts/ChartContentBuilder.swift index a6df4a3..fe50e44 100644 --- a/Sources/LiveViewNativeCharts/ChartContentBuilder.swift +++ b/Sources/LiveViewNativeCharts/ChartContentBuilder.swift @@ -25,8 +25,13 @@ struct ChartContentBuilder: ContentBuilder { } enum ModifierType: String, Decodable { + case blur + case clipShape = "clip_shape" case foregroundStyle = "foreground_style" + case mask case offset + case opacity + case shadow case symbol } @@ -67,10 +72,28 @@ struct ChartContentBuilder: ContentBuilder { registry _: R.Type ) throws -> any ContentModifier { switch type { + case .blur: + if #available(iOS 16.4, macOS 13.3, tvOS 16.4, watchOS 9.4, *) { + return try BlurModifier(from: decoder) + } else { + return EmptyContentModifier() + } + case .clipShape: + return try ClipShapeModifier(from: decoder) case .foregroundStyle: return try ForegroundStyleModifier(from: decoder) + case .mask: + return try MaskModifier(from: decoder) case .offset: return try OffsetModifier(from: decoder) + case .opacity: + return try OpacityModifier(from: decoder) + case .shadow: + if #available(iOS 16.4, macOS 13.3, tvOS 16.4, watchOS 9.4, *) { + return try ShadowModifier(from: decoder) + } else { + return EmptyContentModifier() + } case .symbol: return try SymbolModifier(from: decoder) } diff --git a/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/Extensions/BlurModifier.md b/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/Extensions/BlurModifier.md new file mode 100644 index 0000000..6588cd8 --- /dev/null +++ b/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/Extensions/BlurModifier.md @@ -0,0 +1,6 @@ +# ``LiveViewNativeCharts/BlurModifier`` + +@Metadata { + @DocumentationExtension(mergeBehavior: append) + @DisplayName("blur", style: symbol) +} diff --git a/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/Extensions/ClipShapeModifier.md b/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/Extensions/ClipShapeModifier.md new file mode 100644 index 0000000..3743438 --- /dev/null +++ b/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/Extensions/ClipShapeModifier.md @@ -0,0 +1,6 @@ +# ``LiveViewNativeCharts/ClipShapeModifier`` + +@Metadata { + @DocumentationExtension(mergeBehavior: append) + @DisplayName("clip_shape", style: symbol) +} diff --git a/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/Extensions/MaskModifier.md b/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/Extensions/MaskModifier.md new file mode 100644 index 0000000..1d9f003 --- /dev/null +++ b/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/Extensions/MaskModifier.md @@ -0,0 +1,6 @@ +# ``LiveViewNativeCharts/MaskModifier`` + +@Metadata { + @DocumentationExtension(mergeBehavior: append) + @DisplayName("mask", style: symbol) +} diff --git a/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/Extensions/OpacityModifier.md b/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/Extensions/OpacityModifier.md new file mode 100644 index 0000000..e1ff25d --- /dev/null +++ b/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/Extensions/OpacityModifier.md @@ -0,0 +1,6 @@ +# ``LiveViewNativeCharts/OpacityModifier`` + +@Metadata { + @DocumentationExtension(mergeBehavior: append) + @DisplayName("opacity", style: symbol) +} diff --git a/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/Extensions/ShadowModifier.md b/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/Extensions/ShadowModifier.md new file mode 100644 index 0000000..d19b367 --- /dev/null +++ b/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/Extensions/ShadowModifier.md @@ -0,0 +1,6 @@ +# ``LiveViewNativeCharts/ShadowModifier`` + +@Metadata { + @DocumentationExtension(mergeBehavior: append) + @DisplayName("shadow", style: symbol) +} diff --git a/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/LiveViewNativeCharts.md b/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/LiveViewNativeCharts.md index a6bda87..4367335 100644 --- a/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/LiveViewNativeCharts.md +++ b/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/LiveViewNativeCharts.md @@ -4,7 +4,7 @@ ## Usage -Add this library as a package to your LiveView Native application's Xcode project using its repo URL. Then, create an `AggregateRegistry` to include the provided `ChartsRegistry` within your native app builds: +Add this library as a package to your LiveView Native application's Xcode project using its repo URL. Then, create an ``LiveViewNativeCharts/LiveViewNative/AggregateRegistry`` to include the provided ``ChartsRegistry`` within your native app builds: ```diff import SwiftUI diff --git a/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/Marks.md b/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/Marks.md index f9c0d09..e7ac3c0 100644 --- a/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/Marks.md +++ b/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/Marks.md @@ -39,5 +39,11 @@ Each mark supports different values. These attributes are detailed in their docu - ``Plot`` ### Modifiers +- ``BlurModifier`` +- ``ClipShapeModifier`` - ``ForegroundStyleModifier`` +- ``MaskModifier`` - ``OffsetModifier`` +- ``OpacityModifier`` +- ``ShadowModifier`` +- ``SymbolModifier`` diff --git a/Sources/LiveViewNativeCharts/Modifiers/BlurModifier.swift b/Sources/LiveViewNativeCharts/Modifiers/BlurModifier.swift new file mode 100644 index 0000000..32eca54 --- /dev/null +++ b/Sources/LiveViewNativeCharts/Modifiers/BlurModifier.swift @@ -0,0 +1,42 @@ +// +// BlurModifier.swift +// +// +// Created by Carson Katri on 6/27/23. +// + +import Charts +import SwiftUI +import LiveViewNative + +/// Applies a Gaussian blur to the element. +/// +/// Set the ``radius`` to control the strength of the blur. +/// +/// ```html +/// +/// ``` +/// +/// ## Arguments +/// * ``radius`` +#if swift(>=5.8) +@_documentation(visibility: public) +#endif +@available(iOS 16.4, macOS 13.3, tvOS 16.4, watchOS 9.4, *) +struct BlurModifier: ContentModifier { + typealias Builder = ChartContentBuilder + + /// The strength of the blur. + #if swift(>=5.8) + @_documentation(visibility: public) + #endif + private let radius: CGFloat + + func apply( + to content: Builder.Content, + on element: ElementNode, + in context: Builder.Context + ) -> Builder.Content where R : RootRegistry { + return content.blur(radius: radius) + } +} diff --git a/Sources/LiveViewNativeCharts/Modifiers/ClipShapeModifier.swift b/Sources/LiveViewNativeCharts/Modifiers/ClipShapeModifier.swift new file mode 100644 index 0000000..0eabe5e --- /dev/null +++ b/Sources/LiveViewNativeCharts/Modifiers/ClipShapeModifier.swift @@ -0,0 +1,77 @@ +// +// ClipShapeModifier.swift +// +// +// Created by Carson Katri on 6/27/23. +// + +import Charts +import SwiftUI +import LiveViewNative + +// this modifier is created by `liveview-client-swiftui`, and an implementation for Charts is provided here. +/// Masks an element with a given shape. +/// +/// Provide a ``LiveViewNativeCharts/LiveViewNative/ShapeReference`` to clip the element with. +/// +/// ```html +/// +/// ``` +/// +/// If the shape is not predefined, provide a ``LiveViewNativeCharts/LiveViewNative/Shape`` element with a `template` attribute. +/// This lets you apply modifiers to the clip shape. +/// +/// ```html +/// +/// +/// +/// ``` +/// +/// ## Arguments +/// * ``shape`` +/// * ``style`` +#if swift(>=5.8) +@_documentation(visibility: public) +#endif +struct ClipShapeModifier: ContentModifier { + typealias Builder = ChartContentBuilder + + /// The shape to use as a mask. + /// + /// See ``ShapeReference`` for more details on creating shape arguments. + #if swift(>=5.8) + @_documentation(visibility: public) + #endif + private let shape: ShapeReference + + /// The style to use when filling the ``shape`` for the mask. + /// + /// See ``LiveViewNative/SwiftUI/FillStyle`` for more details. + #if swift(>=5.8) + @_documentation(visibility: public) + #endif + private let style: FillStyle + + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + self.shape = try container.decode(ShapeReference.self, forKey: .shape) + self.style = try container.decodeIfPresent(FillStyle.self, forKey: .style) ?? .init() + } + + func apply( + to content: Builder.Content, + on element: ElementNode, + in context: Builder.Context + ) -> Builder.Content where R : RootRegistry { + content.clipShape( + shape.resolve(on: element), + style: style + ) + } + + enum CodingKeys: String, CodingKey { + case shape + case style + } +} diff --git a/Sources/LiveViewNativeCharts/Modifiers/MaskModifier.swift b/Sources/LiveViewNativeCharts/Modifiers/MaskModifier.swift new file mode 100644 index 0000000..4dffaca --- /dev/null +++ b/Sources/LiveViewNativeCharts/Modifiers/MaskModifier.swift @@ -0,0 +1,52 @@ +// +// MaskModifier.swift +// +// +// Created by Carson Katri on 6/27/23. +// + +import Charts +import LiveViewNative + +// this modifier is created by `liveview-client-swiftui`, and an implementation for Charts is provided here. +/// Masks this chart content using the alpha channel of the given chart content. +/// +/// ```html +/// +/// +/// +/// ``` +/// +/// ## Arguments +/// * ``content`` +#if swift(>=5.8) +@_documentation(visibility: public) +#endif +struct MaskModifier: ContentModifier { + typealias Builder = ChartContentBuilder + + /// The content to use as the mask. + #if swift(>=5.8) + @_documentation(visibility: public) + #endif + let content: String + + func apply( + to content: Builder.Content, + on element: ElementNode, + in context: Builder.Context + ) -> Builder.Content { + content.mask { + AnyChartContent(try! Builder.buildChildren(of: element, forTemplate: self.content, in: context)) + } + } +} diff --git a/Sources/LiveViewNativeCharts/Modifiers/OffsetModifier.swift b/Sources/LiveViewNativeCharts/Modifiers/OffsetModifier.swift index b98926f..8a7a93e 100644 --- a/Sources/LiveViewNativeCharts/Modifiers/OffsetModifier.swift +++ b/Sources/LiveViewNativeCharts/Modifiers/OffsetModifier.swift @@ -44,12 +44,44 @@ struct OffsetModifier: ContentModifier { #endif let y: Double? + /// The vertical offset. + #if swift(>=5.8) + @_documentation(visibility: public) + #endif + let xStart: Double? + + /// The vertical offset. + #if swift(>=5.8) + @_documentation(visibility: public) + #endif + let xEnd: Double? + + /// The vertical offset. + #if swift(>=5.8) + @_documentation(visibility: public) + #endif + let yStart: Double? + + /// The vertical offset. + #if swift(>=5.8) + @_documentation(visibility: public) + #endif + let yEnd: Double? + func apply( to content: Builder.Content, on element: ElementNode, in context: Builder.Context ) -> Builder.Content { - content.offset(x: x ?? 0, y: y ?? 0) + if (xStart != nil || xEnd != nil) && (yStart != nil || yEnd != nil) { + return content.offset(xStart: xStart ?? 0, xEnd: xEnd ?? 0, yStart: yStart ?? 0, yEnd: yEnd ?? 0) + } else if yStart != nil || yEnd != nil { + return content.offset(x: x ?? 0, yStart: yStart ?? 0, yEnd: yEnd ?? 0) + } else if xStart != nil || xEnd != nil { + return content.offset(xStart: xStart ?? 0, xEnd: xEnd ?? 0, y: y ?? 0) + } else { + return content.offset(x: x ?? 0, y: y ?? 0) + } } } diff --git a/Sources/LiveViewNativeCharts/Modifiers/OpacityModifier.swift b/Sources/LiveViewNativeCharts/Modifiers/OpacityModifier.swift new file mode 100644 index 0000000..e3efd5e --- /dev/null +++ b/Sources/LiveViewNativeCharts/Modifiers/OpacityModifier.swift @@ -0,0 +1,41 @@ +// +// OpacityModifier.swift +// +// +// Created by Carson Katri on 6/23/23. +// + +import Charts +import LiveViewNative + +// this modifier is created by `liveview-client-swiftui`, and an implementation for Charts is provided here. +/// Set the opacity for chart content. +/// +/// Use this modifier on a mark to set its opacity. +/// +/// ```html +/// +/// ``` +/// +/// ## Arguments +/// * ``opacity`` +#if swift(>=5.8) +@_documentation(visibility: public) +#endif +struct OpacityModifier: ContentModifier { + typealias Builder = ChartContentBuilder + + /// The opacity to apply. + #if swift(>=5.8) + @_documentation(visibility: public) + #endif + let opacity: Double + + func apply( + to content: Builder.Content, + on element: ElementNode, + in context: Builder.Context + ) -> Builder.Content { + content.opacity(opacity) + } +} diff --git a/Sources/LiveViewNativeCharts/Modifiers/ShadowModifier.swift b/Sources/LiveViewNativeCharts/Modifiers/ShadowModifier.swift new file mode 100644 index 0000000..cbc3e8d --- /dev/null +++ b/Sources/LiveViewNativeCharts/Modifiers/ShadowModifier.swift @@ -0,0 +1,69 @@ +// +// File.swift +// +// +// Created by Carson.Katri on 6/27/23. +// + +import Charts +import SwiftUI +import LiveViewNative + +// this modifier is created by `liveview-client-swiftui`, and an implementation for Charts is provided here. +/// Adds a shadow behind the chart content. +/// +/// Use this modifier to style a mark. +/// +/// ```html +/// +/// ``` +/// +/// ## Arguments +/// * ``color`` +/// * ``radius`` +/// * ``x`` +/// * ``y`` +#if swift(>=5.8) +@_documentation(visibility: public) +#endif +@available(iOS 16.4, macOS 13.3, tvOS 16.4, watchOS 9.4, *) +struct ShadowModifier: ContentModifier { + typealias Builder = ChartContentBuilder + + /// The shadow’s color. + #if swift(>=5.8) + @_documentation(visibility: public) + #endif + private let color: SwiftUI.Color + + /// A measure of how much to blur the shadow. Larger values result in more blur. + #if swift(>=5.8) + @_documentation(visibility: public) + #endif + private let radius: CGFloat + + /// An amount to offset the shadow horizontally from the view. Defaults to 0. + #if swift(>=5.8) + @_documentation(visibility: public) + #endif + private let x: CGFloat + + /// An amount to offset the shadow vertically from the view. Defaults to 0. + #if swift(>=5.8) + @_documentation(visibility: public) + #endif + private let y: CGFloat + + func apply( + to content: Builder.Content, + on element: ElementNode, + in context: Builder.Context + ) -> Builder.Content { + content.shadow( + color: color, + radius: radius, + x: x, + y: y + ) + } +} diff --git a/lib/live_view_native_swift_ui_charts/modifiers/offset.ex b/lib/live_view_native_swift_ui_charts/modifiers/offset.ex new file mode 100644 index 0000000..5ea3446 --- /dev/null +++ b/lib/live_view_native_swift_ui_charts/modifiers/offset.ex @@ -0,0 +1,14 @@ +defmodule LiveViewNativeSwiftUiCharts.Modifiers.Offset do + use LiveViewNativePlatform.Modifier + + modifier_schema "offset" do + field :x, :float, default: nil + field :y, :float, default: nil + + field :x_start, :float, default: nil + field :x_end, :float, default: nil + + field :y_start, :float, default: nil + field :y_end, :float, default: nil + end +end