From 08036a018a8bddbf9d609835463b4502b4ad44c5 Mon Sep 17 00:00:00 2001 From: Klaus Kneupner Date: Sun, 12 May 2024 19:22:29 +0200 Subject: [PATCH 01/11] added OnNewTag parameter --- Sources/TagKit/Views/TagTextField.swift | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/Sources/TagKit/Views/TagTextField.swift b/Sources/TagKit/Views/TagTextField.swift index 1b4923d..593d75e 100644 --- a/Sources/TagKit/Views/TagTextField.swift +++ b/Sources/TagKit/Views/TagTextField.swift @@ -8,6 +8,11 @@ import SwiftUI +/** + This is a type for reacting to new tag + */ +public typealias OnNewTag = (String) -> Void + /** This text field will automatically slugify any text that is entered into it. @@ -26,7 +31,8 @@ public struct TagTextField: View { public init( text: Binding, placeholder: String = "", - configuration: SlugConfiguration = .standard + configuration: SlugConfiguration = .standard, + onSubmit: OnNewTag? = nil ) { self.text = Binding( get: { text.wrappedValue.slugified() }, @@ -34,16 +40,23 @@ public struct TagTextField: View { ) self.placeholder = placeholder self.configuration = configuration + self.onSubmit = onSubmit } private let text: Binding private let placeholder: String private let configuration: SlugConfiguration + private let onSubmit: OnNewTag? public var body: some View { TextField(placeholder, text: text) .textCase(.lowercase) .withoutCapitalization() + .onSubmit { + if let onSubmit = onSubmit { + onSubmit(text.wrappedValue) + } + } } } @@ -66,7 +79,7 @@ private extension View { @State var text = "" var body: some View { - TagTextField(text: $text, placeholder: "Enter tag") + TagTextField(text: $text, placeholder: "Enter tag", onSubmit: {tag in }) #if os(iOS) .textFieldStyle(.roundedBorder) #endif From 92b224d7ed9738bcb2f47ff6941fa1f124687fe9 Mon Sep 17 00:00:00 2001 From: Klaus Kneupner Date: Sun, 12 May 2024 19:23:42 +0200 Subject: [PATCH 02/11] added OnNewTag parameter --- Sources/TagKit/Views/TagTextField.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Sources/TagKit/Views/TagTextField.swift b/Sources/TagKit/Views/TagTextField.swift index 593d75e..42e0fe9 100644 --- a/Sources/TagKit/Views/TagTextField.swift +++ b/Sources/TagKit/Views/TagTextField.swift @@ -32,7 +32,7 @@ public struct TagTextField: View { text: Binding, placeholder: String = "", configuration: SlugConfiguration = .standard, - onSubmit: OnNewTag? = nil + onNewTag: OnNewTag? = nil ) { self.text = Binding( get: { text.wrappedValue.slugified() }, @@ -40,20 +40,20 @@ public struct TagTextField: View { ) self.placeholder = placeholder self.configuration = configuration - self.onSubmit = onSubmit + self.onNewTag = onNewTag } private let text: Binding private let placeholder: String private let configuration: SlugConfiguration - private let onSubmit: OnNewTag? + private let onNewTag: OnNewTag? public var body: some View { TextField(placeholder, text: text) .textCase(.lowercase) .withoutCapitalization() .onSubmit { - if let onSubmit = onSubmit { + if let onSubmit = onNewTag { onSubmit(text.wrappedValue) } } @@ -79,7 +79,7 @@ private extension View { @State var text = "" var body: some View { - TagTextField(text: $text, placeholder: "Enter tag", onSubmit: {tag in }) + TagTextField(text: $text, placeholder: "Enter tag", onNewTag: {tag in }) #if os(iOS) .textFieldStyle(.roundedBorder) #endif From bf81f0c2aad14a3cb419fa9c56596480b83432ca Mon Sep 17 00:00:00 2001 From: Klaus Kneupner Date: Sun, 12 May 2024 21:23:40 +0200 Subject: [PATCH 03/11] adding OnSelectTag for TagList --- Sources/TagKit/Views/TagList.swift | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Sources/TagKit/Views/TagList.swift b/Sources/TagKit/Views/TagList.swift index b26fdc9..e58b031 100644 --- a/Sources/TagKit/Views/TagList.swift +++ b/Sources/TagKit/Views/TagList.swift @@ -10,6 +10,9 @@ import SwiftUI + +public typealias OnSelectTag = (String?) -> Void + /// This enum specifies supported tag list container types. public enum TagListContainer { @@ -47,7 +50,9 @@ public struct TagList: View { container: TagListContainer = .scrollView, horizontalSpacing: CGFloat = 5, verticalSpacing: CGFloat = 5, + onSelectTag: OnSelectTag? = nil, @ViewBuilder tagView: @escaping TagViewBuilder + ) { self.tags = tags self.container = container @@ -56,12 +61,14 @@ public struct TagList: View { self.tagView = tagView let initialHeight: CGFloat = container == .scrollView ? .zero : .infinity _totalHeight = State(initialValue: initialHeight) + self.onSelectTag = onSelectTag } private let tags: [String] private let container: TagListContainer private let horizontalSpacing: CGFloat private let verticalSpacing: CGFloat + private let onSelectTag: OnSelectTag? @ViewBuilder private let tagView: TagViewBuilder @@ -120,6 +127,11 @@ private extension TagList { } return result }) + .onTapGesture { + if let onSelectTag = onSelectTag { + onSelectTag(item) + } + } } } .background(viewHeightReader($totalHeight)) From f0b897dcce716bf073994750217c1995c5836ef8 Mon Sep 17 00:00:00 2001 From: Klaus Kneupner Date: Tue, 25 Jun 2024 20:43:09 +0200 Subject: [PATCH 04/11] hopefully fixed the landscape view --- Sources/TagKit/HeightReader.swift | 45 ++++++++++++++++++++++++++++++ Sources/TagKit/Views/TagList.swift | 12 +++----- 2 files changed, 49 insertions(+), 8 deletions(-) create mode 100644 Sources/TagKit/HeightReader.swift diff --git a/Sources/TagKit/HeightReader.swift b/Sources/TagKit/HeightReader.swift new file mode 100644 index 0000000..30a05fd --- /dev/null +++ b/Sources/TagKit/HeightReader.swift @@ -0,0 +1,45 @@ +// +// SwiftUIView.swift +// +// +// Created by Klaus Kneupner on 25/06/2024. +// + +import SwiftUI + +struct HeightReader: View { + @Binding var height: CGSize + + var body: some View { + GeometryReader { geo in + Color.clear + .preference(key: ViewSizeKey.self, value: geo.size) + .onPreferenceChange(ViewSizeKey.self) { value in + self.height = value + } + } + } +} + +struct ViewSizeKey: PreferenceKey { + static var defaultValue: CGSize = CGSize(width: 1, height: 1) + + static func reduce(value: inout CGSize, nextValue: () -> CGSize) { + value = nextValue() + } +} + + +#Preview { + struct ContentView: View { + @State private var viewHeight: CGSize = CGSize(width: 1, height: 1) + + var body: some View { + ZStack { + HeightReader(height: $viewHeight) + Text("View height: \(viewHeight)") + } + } + } + return ContentView() +} diff --git a/Sources/TagKit/Views/TagList.swift b/Sources/TagKit/Views/TagList.swift index e58b031..a3466ba 100644 --- a/Sources/TagKit/Views/TagList.swift +++ b/Sources/TagKit/Views/TagList.swift @@ -75,7 +75,7 @@ public struct TagList: View { /// This type defines the tag view builder for the list. public typealias TagViewBuilder = (_ tag: String) -> TagView - + @State private var viewSize: CGSize = CGSize(width: 0, height: 0) @State private var totalHeight: CGFloat @@ -89,25 +89,21 @@ public struct TagList: View { } private extension TagList { + var content: some View { - GeometryReader { geometry in - content(in: geometry) - } - } - - func content(in g: GeometryProxy) -> some View { var width = CGFloat.zero var height = CGFloat.zero var lastHeight = CGFloat.zero let itemCount = tags.count return ZStack(alignment: .topLeading) { + HeightReader(height: $viewSize) ForEach(Array(tags.enumerated()), id: \.offset) { index, item in tagView(item) .padding([.horizontal], horizontalSpacing) .padding([.vertical], verticalSpacing) .alignmentGuide(.leading, computeValue: { d in - if abs(width - d.width) > g.size.width { + if abs(width - d.width) > viewSize.width { width = 0 height -= lastHeight } From b1c192a7c83a0d80f919896e68978acbc05dc7f8 Mon Sep 17 00:00:00 2001 From: Klaus Kneupner Date: Tue, 25 Jun 2024 20:55:16 +0200 Subject: [PATCH 05/11] hopefully fixed the landscape view 2 --- Sources/TagKit/Views/TagList.swift | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/Sources/TagKit/Views/TagList.swift b/Sources/TagKit/Views/TagList.swift index a3466ba..3663966 100644 --- a/Sources/TagKit/Views/TagList.swift +++ b/Sources/TagKit/Views/TagList.swift @@ -60,7 +60,7 @@ public struct TagList: View { self.verticalSpacing = verticalSpacing self.tagView = tagView let initialHeight: CGFloat = container == .scrollView ? .zero : .infinity - _totalHeight = State(initialValue: initialHeight) + _viewSize = State(initialValue: CGSize(width: 0, height: initialHeight)) self.onSelectTag = onSelectTag } @@ -75,15 +75,14 @@ public struct TagList: View { /// This type defines the tag view builder for the list. public typealias TagViewBuilder = (_ tag: String) -> TagView - @State private var viewSize: CGSize = CGSize(width: 0, height: 0) - @State - private var totalHeight: CGFloat + @State private var viewSize: CGSize + public var body: some View { if container == .scrollView { - content.frame(height: totalHeight) + content.frame(height: viewSize.height) } else { - content.frame(maxHeight: totalHeight) + content.frame(maxHeight: viewSize.height) } } } @@ -130,17 +129,10 @@ private extension TagList { } } } - .background(viewHeightReader($totalHeight)) - } - func viewHeightReader(_ binding: Binding) -> some View { - return GeometryReader { geo -> Color in - DispatchQueue.main.async { - binding.wrappedValue = geo.frame(in: .local).size.height - } - return .clear - } } + + } #Preview { From 4fecbfd3ca733e87cd979b6839811a4d2323ddf1 Mon Sep 17 00:00:00 2001 From: Klaus Kneupner Date: Wed, 26 Jun 2024 05:12:20 +0200 Subject: [PATCH 06/11] relocated generic view --- Sources/TagKit/{ => Views/Generic}/HeightReader.swift | 0 Sources/TagKit/Views/TagList.swift | 5 +---- 2 files changed, 1 insertion(+), 4 deletions(-) rename Sources/TagKit/{ => Views/Generic}/HeightReader.swift (100%) diff --git a/Sources/TagKit/HeightReader.swift b/Sources/TagKit/Views/Generic/HeightReader.swift similarity index 100% rename from Sources/TagKit/HeightReader.swift rename to Sources/TagKit/Views/Generic/HeightReader.swift diff --git a/Sources/TagKit/Views/TagList.swift b/Sources/TagKit/Views/TagList.swift index 3663966..6148510 100644 --- a/Sources/TagKit/Views/TagList.swift +++ b/Sources/TagKit/Views/TagList.swift @@ -88,8 +88,6 @@ public struct TagList: View { } private extension TagList { - - var content: some View { var width = CGFloat.zero var height = CGFloat.zero @@ -127,12 +125,11 @@ private extension TagList { onSelectTag(item) } } + .background(.clear) } } } - - } #Preview { From b637aedbb9249290f6d81444f73bef1b6388b8cf Mon Sep 17 00:00:00 2001 From: Klaus Kneupner Date: Wed, 26 Jun 2024 07:45:15 +0200 Subject: [PATCH 07/11] removed onTapGesture --- Sources/TagKit/Views/TagList.swift | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/Sources/TagKit/Views/TagList.swift b/Sources/TagKit/Views/TagList.swift index a101db0..fbadb4a 100644 --- a/Sources/TagKit/Views/TagList.swift +++ b/Sources/TagKit/Views/TagList.swift @@ -11,8 +11,6 @@ import SwiftUI -public typealias OnSelectTag = (String?) -> Void - /// This enum specifies supported tag list container types. public enum TagListContainer { @@ -50,7 +48,6 @@ public struct TagList: View { container: TagListContainer = .scrollView, horizontalSpacing: CGFloat = 5, verticalSpacing: CGFloat = 5, - onSelectTag: OnSelectTag? = nil, @ViewBuilder tagView: @escaping TagViewBuilder ) { @@ -61,14 +58,12 @@ public struct TagList: View { self.tagView = tagView let initialHeight: CGFloat = container == .scrollView ? .zero : .infinity _viewSize = State(initialValue: CGSize(width: 0, height: initialHeight)) - self.onSelectTag = onSelectTag } private let tags: [String] private let container: TagListContainer private let horizontalSpacing: CGFloat private let verticalSpacing: CGFloat - private let onSelectTag: OnSelectTag? @ViewBuilder private let tagView: TagViewBuilder @@ -121,11 +116,6 @@ private extension TagList { } return result }) - .onTapGesture { - if let onSelectTag = onSelectTag { - onSelectTag(item) - } - } .background(.clear) } } From 6facbf236515da8171bb8f0089b718c1a2d303be Mon Sep 17 00:00:00 2001 From: Klaus Kneupner Date: Wed, 26 Jun 2024 08:06:48 +0200 Subject: [PATCH 08/11] removed onSubmit --- Sources/TagKit/Views/TagList.swift | 2 ++ Sources/TagKit/Views/TagTextField.swift | 20 +++++--------------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/Sources/TagKit/Views/TagList.swift b/Sources/TagKit/Views/TagList.swift index fbadb4a..8417bf3 100644 --- a/Sources/TagKit/Views/TagList.swift +++ b/Sources/TagKit/Views/TagList.swift @@ -32,6 +32,8 @@ public enum TagListContainer { You must specify a container type, since the list has to be rendered differently depending on if it's in a `ScrollView` or a `VerticalStack`. + + You will often want to add a ``onTapGesture(count:perform:)`` inside the `TapViewBuilder`. */ public struct TagList: View { diff --git a/Sources/TagKit/Views/TagTextField.swift b/Sources/TagKit/Views/TagTextField.swift index 42e0fe9..948e182 100644 --- a/Sources/TagKit/Views/TagTextField.swift +++ b/Sources/TagKit/Views/TagTextField.swift @@ -8,17 +8,15 @@ import SwiftUI -/** - This is a type for reacting to new tag - */ -public typealias OnNewTag = (String) -> Void - /** This text field will automatically slugify any text that is entered into it. This text field will also make it harder to type characters that are not in the configuration's allowed character set. + + You often want to add an ``onSubmit(of:_:)`` on + the use of this View in order to react on new tags. */ public struct TagTextField: View { @@ -31,8 +29,7 @@ public struct TagTextField: View { public init( text: Binding, placeholder: String = "", - configuration: SlugConfiguration = .standard, - onNewTag: OnNewTag? = nil + configuration: SlugConfiguration = .standard ) { self.text = Binding( get: { text.wrappedValue.slugified() }, @@ -40,23 +37,16 @@ public struct TagTextField: View { ) self.placeholder = placeholder self.configuration = configuration - self.onNewTag = onNewTag } private let text: Binding private let placeholder: String private let configuration: SlugConfiguration - private let onNewTag: OnNewTag? public var body: some View { TextField(placeholder, text: text) .textCase(.lowercase) .withoutCapitalization() - .onSubmit { - if let onSubmit = onNewTag { - onSubmit(text.wrappedValue) - } - } } } @@ -79,7 +69,7 @@ private extension View { @State var text = "" var body: some View { - TagTextField(text: $text, placeholder: "Enter tag", onNewTag: {tag in }) + TagTextField(text: $text, placeholder: "Enter tag") #if os(iOS) .textFieldStyle(.roundedBorder) #endif From 47577b60cae0c48ee676e87f8a0f1edbd5c2ad24 Mon Sep 17 00:00:00 2001 From: Klaus Kneupner Date: Sat, 18 Jan 2025 12:32:39 +0100 Subject: [PATCH 09/11] adding Sendable --- Sources/TagKit/Views/TagCapsuleStyle.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/TagKit/Views/TagCapsuleStyle.swift b/Sources/TagKit/Views/TagCapsuleStyle.swift index 45acdd0..cb930d2 100644 --- a/Sources/TagKit/Views/TagCapsuleStyle.swift +++ b/Sources/TagKit/Views/TagCapsuleStyle.swift @@ -96,7 +96,7 @@ public struct TagCapsuleStyle { public extension TagCapsuleStyle { - struct Border { + struct Border : Sendable { /// Create a new tag capsule border style. /// @@ -121,7 +121,7 @@ public extension TagCapsuleStyle { public extension TagCapsuleStyle { - struct Shadow { + struct Shadow : Sendable{ /// Create a new tag capsule shadow style. /// From cd700e28ed5630ee6b8a1e463d27543ce1ee32ec Mon Sep 17 00:00:00 2001 From: Klaus Kneupner Date: Sat, 6 Sep 2025 06:29:08 +0200 Subject: [PATCH 10/11] make sendable --- Sources/TagKit/Slugs.swift | 2 +- Sources/TagKit/_Deprecated/TagCapsule.swift | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/TagKit/Slugs.swift b/Sources/TagKit/Slugs.swift index a147508..b7a035f 100644 --- a/Sources/TagKit/Slugs.swift +++ b/Sources/TagKit/Slugs.swift @@ -29,7 +29,7 @@ public extension String { /// /// The standard configuration allows `a-z0-9`, and will for /// instance slugify `Hello, world!` into `hello-world`. -public struct SlugConfiguration { +public struct SlugConfiguration : @unchecked Sendable{ /// Create a new slug configurator. /// diff --git a/Sources/TagKit/_Deprecated/TagCapsule.swift b/Sources/TagKit/_Deprecated/TagCapsule.swift index 986c468..48c745a 100644 --- a/Sources/TagKit/_Deprecated/TagCapsule.swift +++ b/Sources/TagKit/_Deprecated/TagCapsule.swift @@ -10,7 +10,7 @@ import SwiftUI @available(*, deprecated, message: "Just use a regular Text element and style it as you wish.") -public struct TagCapsule: View { +public struct TagCapsule: View , Sendable{ /// Create a tag capsule. /// @@ -66,7 +66,7 @@ private extension View { } @available(*, deprecated, message: "Just use a regular Text element and style it as you wish.") -private extension TagCapsuleStyle { +private extension TagCapsuleStyle { static var spiderman: Self { .init( From 216d44f039b32403f066664e7e60ac6852a3fa14 Mon Sep 17 00:00:00 2001 From: Klaus Kneupner Date: Sat, 6 Sep 2025 06:34:14 +0200 Subject: [PATCH 11/11] more sendable --- Sources/TagKit/_Deprecated/TagCapsuleStyle.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/TagKit/_Deprecated/TagCapsuleStyle.swift b/Sources/TagKit/_Deprecated/TagCapsuleStyle.swift index 96800b4..15627d0 100644 --- a/Sources/TagKit/_Deprecated/TagCapsuleStyle.swift +++ b/Sources/TagKit/_Deprecated/TagCapsuleStyle.swift @@ -10,7 +10,7 @@ import SwiftUI @available(*, deprecated, message: "Just use a regular Text element and style it as you wish.") -public struct TagCapsuleStyle { +public struct TagCapsuleStyle :Sendable{ /// Create a new tag capsule style. ///