├── .gitignore
├── OmenTextFieldExample
├── iOS-version.gif
├── macOS-version.gif
├── Shared
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ ├── AccentColor.colorset
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── OmenTextViewExampleApp.swift
│ └── ExampleView.swift
├── Package.swift
├── OmenTextFieldExample.xcodeproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── project.pbxproj
├── macOS
│ ├── macOS.entitlements
│ └── Info.plist
└── iOS
│ └── Info.plist
├── .swiftpm
└── xcode
│ ├── package.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
│ └── xcshareddata
│ └── xcschemes
│ └── OmenTextView.xcscheme
├── Package.swift
├── README.md
├── LICENSE
└── Sources
└── OmenTextField
├── OmenTextField.swift
├── iOS
└── OmenTextFieldRep-iOS.swift
└── macOS
└── OmenTextFieldRep-macOS.swift
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /.build
3 | /Packages
4 | /*.xcodeproj
5 | xcuserdata/
6 |
--------------------------------------------------------------------------------
/OmenTextFieldExample/iOS-version.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kitlangton/OmenTextField/HEAD/OmenTextFieldExample/iOS-version.gif
--------------------------------------------------------------------------------
/OmenTextFieldExample/macOS-version.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kitlangton/OmenTextField/HEAD/OmenTextFieldExample/macOS-version.gif
--------------------------------------------------------------------------------
/OmenTextFieldExample/Shared/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/OmenTextFieldExample/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.2
2 |
3 | import PackageDescription
4 |
5 | let package = Package(
6 | name: "Examples",
7 | products: [],
8 | targets: []
9 | )
10 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/OmenTextFieldExample/Shared/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/OmenTextFieldExample/OmenTextFieldExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/OmenTextFieldExample/OmenTextFieldExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/OmenTextFieldExample/macOS/macOS.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.files.user-selected.read-only
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.3
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "OmenTextField",
8 | platforms: [
9 | .iOS(.v14),
10 | .macOS(.v11),
11 | ],
12 | products: [
13 | .library(
14 | name: "OmenTextField",
15 | targets: ["OmenTextField"]
16 | ),
17 | ],
18 |
19 | targets: [
20 | .target(
21 | name: "OmenTextField",
22 | dependencies: []
23 | ),
24 | ]
25 | )
26 |
--------------------------------------------------------------------------------
/OmenTextFieldExample/Shared/OmenTextViewExampleApp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OmenTextFieldExampleApp.swift
3 | // Shared
4 | //
5 | // Created by Kit Langton on 12/22/20.
6 | //
7 |
8 | import OmenTextField
9 | import SwiftUI
10 |
11 | @main
12 | struct OmenTextFieldExampleApp: App {
13 | var body: some Scene {
14 | WindowGroup {
15 | #if os(iOS)
16 | NavigationView {
17 | ExampleView()
18 | .navigationTitle("Example")
19 | }
20 | #elseif os(macOS)
21 | ExampleView()
22 | .padding()
23 | .frame(width: 400)
24 | .frame(maxHeight: .infinity, alignment: .topLeading)
25 | #endif
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/OmenTextFieldExample/macOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleVersion
22 | 1
23 | LSMinimumSystemVersion
24 | $(MACOSX_DEPLOYMENT_TARGET)
25 |
26 |
27 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # OmenTextField
2 |
3 | A better TextField for SwiftUI. A growing, multiline, auto-focusable TextField supporting bindable focus.
4 |
5 | This has been pulled out of my flashcard app, [Omen](https://omen.cards)—in case you need some help memorizing SwiftUI overloads 😜
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 | A simple example app is included in the OmenTextFieldExample subproject.
14 |
15 | ## Installation with Swift Package Manager
16 |
17 | You can add OmenTextField to an Xcode project by adding it as a package dependency.
18 |
19 | 1. From the File menu, select Swift Packages › Add Package Dependency…
20 | 2. Paste "https://github.com/kitlangton/OmenTextField" into the package repository URL text field
21 | 3. Hit Enter!
22 |
23 | ## To-do List
24 |
25 | - [x] iOS support (using UITextView)
26 | - [x] macOS support (using NSTextView)
27 | - [x] Add overrideable `returnKey` for iOS
28 | - [x] Add `onCommit` callback
29 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Kit Langton
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/OmenTextFieldExample/iOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 |
28 | UIApplicationSupportsIndirectInputEvents
29 |
30 | UILaunchScreen
31 |
32 | UIRequiredDeviceCapabilities
33 |
34 | armv7
35 |
36 | UISupportedInterfaceOrientations
37 |
38 | UIInterfaceOrientationPortrait
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UISupportedInterfaceOrientations~ipad
43 |
44 | UIInterfaceOrientationPortrait
45 | UIInterfaceOrientationPortraitUpsideDown
46 | UIInterfaceOrientationLandscapeLeft
47 | UIInterfaceOrientationLandscapeRight
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/OmenTextFieldExample/Shared/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | },
93 | {
94 | "idiom" : "mac",
95 | "scale" : "1x",
96 | "size" : "16x16"
97 | },
98 | {
99 | "idiom" : "mac",
100 | "scale" : "2x",
101 | "size" : "16x16"
102 | },
103 | {
104 | "idiom" : "mac",
105 | "scale" : "1x",
106 | "size" : "32x32"
107 | },
108 | {
109 | "idiom" : "mac",
110 | "scale" : "2x",
111 | "size" : "32x32"
112 | },
113 | {
114 | "idiom" : "mac",
115 | "scale" : "1x",
116 | "size" : "128x128"
117 | },
118 | {
119 | "idiom" : "mac",
120 | "scale" : "2x",
121 | "size" : "128x128"
122 | },
123 | {
124 | "idiom" : "mac",
125 | "scale" : "1x",
126 | "size" : "256x256"
127 | },
128 | {
129 | "idiom" : "mac",
130 | "scale" : "2x",
131 | "size" : "256x256"
132 | },
133 | {
134 | "idiom" : "mac",
135 | "scale" : "1x",
136 | "size" : "512x512"
137 | },
138 | {
139 | "idiom" : "mac",
140 | "scale" : "2x",
141 | "size" : "512x512"
142 | }
143 | ],
144 | "info" : {
145 | "author" : "xcode",
146 | "version" : 1
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/xcshareddata/xcschemes/OmenTextView.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
44 |
45 |
47 |
53 |
54 |
55 |
56 |
57 |
67 |
68 |
74 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/Sources/OmenTextField/OmenTextField.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwiftUIView 2.swift
3 | //
4 | //
5 | // Created by Kit Langton on 12/22/20.
6 | //
7 |
8 | import SwiftUI
9 |
10 | public struct OmenTextField: View {
11 | var title: String
12 | @Binding var text: String
13 | var isFocused: Binding?
14 | @State var height: CGFloat = 0
15 | var returnKeyType: ReturnKeyType
16 | var onCommit: (() -> Void)?
17 | var onTab: (() -> Void)?
18 | var onBackTab: (() -> Void)?
19 |
20 | /// Creates a multiline text field with a text label.
21 | ///
22 | /// - Parameters:
23 | /// - title: The title of the text field.
24 | /// - text: The text to display and edit.
25 | /// - isFocused: Whether or not the field should be focused.
26 | /// - returnKeyType: The type of return key to be used on iOS.
27 | /// - onCommit: An action to perform when the user presses the
28 | /// Return key) while the text field has focus. If `nil`, a newline
29 | /// will be inserted.
30 | public init(
31 | _ title: S,
32 | text: Binding,
33 | isFocused: Binding? = nil,
34 | returnKeyType: ReturnKeyType = .default,
35 | onTab: (() -> Void)? = nil,
36 | onBackTab: (() -> Void)? = nil,
37 | onCommit: (() -> Void)? = nil
38 | ) {
39 | self.title = String(title)
40 | _text = text
41 | self.isFocused = isFocused
42 | self.returnKeyType = returnKeyType
43 | self.onCommit = onCommit
44 | self.onTab = onTab
45 | self.onBackTab = onBackTab
46 | }
47 |
48 | public var body: some View {
49 | ZStack(alignment: .topLeading) {
50 | Text(title)
51 | .foregroundColor(.secondary)
52 | .opacity(text.isEmpty ? 0.5 : 0)
53 | .animation(nil)
54 |
55 | #if os(iOS)
56 | OmenTextFieldRep(
57 | text: $text,
58 | isFocused: isFocused,
59 | height: $height,
60 | returnKeyType: returnKeyType,
61 | onCommit: onCommit
62 | )
63 | .frame(height: height)
64 | #elseif os(macOS)
65 | OmenTextFieldRep(
66 | text: $text,
67 | isFocused: isFocused,
68 | height: $height,
69 | onCommit: onCommit,
70 | onTab: onTab,
71 | onBackTab: onBackTab
72 | )
73 | .frame(height: height)
74 | #endif
75 | }
76 | }
77 | }
78 |
79 | // MARK: - ReturnKeyType
80 |
81 | public extension OmenTextField {
82 | enum ReturnKeyType: String, CaseIterable {
83 | case done
84 | case next
85 | case `default`
86 | case `continue`
87 | case go
88 | case search
89 | case send
90 |
91 | #if os(iOS)
92 | var uiReturnKey: UIReturnKeyType {
93 | switch self {
94 | case .done:
95 | return .done
96 | case .next:
97 | return .next
98 | case .default:
99 | return .default
100 | case .continue:
101 | return .continue
102 | case .go:
103 | return .go
104 | case .search:
105 | return .search
106 | case .send:
107 | return .send
108 | }
109 | }
110 | #endif
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/Sources/OmenTextField/iOS/OmenTextFieldRep-iOS.swift:
--------------------------------------------------------------------------------
1 | //
2 | // File.swift
3 | //
4 | //
5 | // Created by Kit Langton on 12/23/20.
6 | //
7 |
8 | import SwiftUI
9 |
10 | #if os(iOS)
11 | struct OmenTextFieldRep: UIViewRepresentable {
12 | @Binding var text: String
13 | var isFocused: Binding?
14 | @Binding var height: CGFloat
15 | var returnKeyType: OmenTextField.ReturnKeyType
16 | var onCommit: (() -> Void)?
17 |
18 | // MARK: - Make
19 |
20 | func makeUIView(context: Context) -> UITextView {
21 | let view = CustomUITextView(rep: self)
22 | view.font = UIFont.preferredFont(forTextStyle: .body)
23 | view.backgroundColor = .clear
24 | view.delegate = context.coordinator
25 | view.textContainerInset = .zero
26 | view.textContainer.lineFragmentPadding = 0
27 | view.keyboardDismissMode = .interactive
28 | view.returnKeyType = returnKeyType.uiReturnKey
29 | DispatchQueue.main.async {
30 | view.text = text
31 | height = view.textHeight()
32 | }
33 | return view
34 | }
35 |
36 | // MARK: - Update
37 |
38 | func updateUIView(_ view: UITextView, context: Context) {
39 | if view.returnKeyType != returnKeyType.uiReturnKey {
40 | view.returnKeyType = returnKeyType.uiReturnKey
41 | view.reloadInputViews()
42 | return
43 | }
44 |
45 | if view.text != text {
46 | view.text = text
47 | // Update the stated field in main queue.
48 | DispatchQueue.main.async {
49 | height = view.textHeight()
50 | }
51 | }
52 |
53 | updateFocus(view, context: context)
54 | }
55 |
56 | private func updateFocus(_ view: UITextView, context: Context) {
57 | guard let isFocused = isFocused?.wrappedValue else { return }
58 | if isFocused,
59 | view.window != nil,
60 | !view.isFirstResponder,
61 | view.canBecomeFirstResponder,
62 | context.environment.isEnabled
63 | {
64 | view.becomeFirstResponder()
65 | view.selectedRange = NSRange(location: view.text.count, length: 0)
66 | } else if !isFocused, view.isFirstResponder {
67 | view.resignFirstResponder()
68 | }
69 | }
70 |
71 | // MARK: - Coordinator
72 |
73 | func makeCoordinator() -> Coordinator {
74 | Coordinator(rep: self)
75 | }
76 |
77 | class Coordinator: NSObject, UITextViewDelegate {
78 | let rep: OmenTextFieldRep
79 |
80 | internal init(rep: OmenTextFieldRep) {
81 | self.rep = rep
82 | }
83 |
84 | func textView(_: UITextView, shouldChangeTextIn _: NSRange, replacementText text: String) -> Bool {
85 | guard let onCommit = rep.onCommit, text == "\n" else { return true }
86 | onCommit()
87 | return false
88 | }
89 |
90 | func textViewDidChange(_ textView: UITextView) {
91 | rep.text = textView.text
92 | rep.height = textView.textHeight()
93 | }
94 | }
95 | }
96 |
97 | // MARK: - Custom View
98 |
99 | class CustomUITextView: UITextView {
100 | let rep: OmenTextFieldRep
101 |
102 | internal init(rep: OmenTextFieldRep) {
103 | self.rep = rep
104 | super.init(frame: .zero, textContainer: nil)
105 | }
106 |
107 | @available(*, unavailable)
108 | required init?(coder _: NSCoder) {
109 | fatalError("init(coder:) has not been implemented")
110 | }
111 |
112 | override func becomeFirstResponder() -> Bool {
113 | rep.isFocused?.wrappedValue = true
114 | return super.becomeFirstResponder()
115 | }
116 |
117 | override func resignFirstResponder() -> Bool {
118 | rep.isFocused?.wrappedValue = false
119 | return super.resignFirstResponder()
120 | }
121 | }
122 |
123 | // MARK: - Useful Extensions
124 |
125 | extension UITextView {
126 | func textHeight() -> CGFloat {
127 | sizeThatFits(bounds.size).height
128 | }
129 | }
130 | #endif
131 |
--------------------------------------------------------------------------------
/Sources/OmenTextField/macOS/OmenTextFieldRep-macOS.swift:
--------------------------------------------------------------------------------
1 | //
2 | // File.swift
3 | //
4 | //
5 | // Created by Kit Langton on 12/23/20.
6 | //
7 |
8 | import SwiftUI
9 |
10 | #if os(macOS)
11 | struct OmenTextFieldRep: NSViewRepresentable {
12 | @Binding var text: String
13 | var isFocused: Binding?
14 | @Binding var height: CGFloat
15 | var onCommit: (() -> Void)?
16 | var onTab: (() -> Void)?
17 | var onBackTab: (() -> Void)?
18 |
19 | func makeNSView(context: Context) -> NSTextView {
20 | let view = CustomNSTextView(rep: self)
21 | view.font = NSFont.preferredFont(forTextStyle: .body)
22 | view.backgroundColor = .clear
23 | view.delegate = context.coordinator
24 | view.textContainerInset = .zero
25 | view.textContainer?.lineFragmentPadding = 0
26 | view.string = text
27 | DispatchQueue.main.async {
28 | height = view.textHeight()
29 | }
30 | return view
31 | }
32 |
33 | func updateNSView(_ view: NSTextView, context _: Context) {
34 | if view.string != text {
35 | view.string = text
36 | DispatchQueue.main.async {
37 | height = view.textHeight()
38 | }
39 | }
40 |
41 | if let isFocused = isFocused?.wrappedValue {
42 | DispatchQueue.main.async {
43 | let isFirstResponder = view.window?.firstResponder == view
44 | if isFocused, view.window != nil, !isFirstResponder {
45 | view.window?.makeFirstResponder(view)
46 | } else if !isFocused, isFirstResponder {
47 | view.window?.makeFirstResponder(nil)
48 | }
49 | }
50 | }
51 | }
52 |
53 | func makeCoordinator() -> Coordinator {
54 | Coordinator(rep: self)
55 | }
56 |
57 | class Coordinator: NSObject, NSTextViewDelegate {
58 | let rep: OmenTextFieldRep
59 |
60 | internal init(rep: OmenTextFieldRep) {
61 | self.rep = rep
62 | }
63 |
64 | func textDidChange(_ notification: Notification) {
65 | guard let view = notification.object as? NSTextView else { return }
66 |
67 | rep.text = view.string
68 | DispatchQueue.main.async {
69 | self.rep.height = view.textHeight()
70 | }
71 | }
72 |
73 | func textView(_: NSTextView, doCommandBy commandSelector: Selector) -> Bool {
74 | // Call `onCommit` when the Return key is pressed without Shift.
75 | // If Shift-Return is pressed, a newline will be inserted.
76 | if let onCommit = rep.onCommit,
77 | commandSelector == #selector(NSResponder.insertNewline(_:)),
78 | let event = NSApp.currentEvent,
79 | !event.modifierFlags.contains(.shift)
80 | {
81 | onCommit()
82 | return true
83 | } else if
84 | let onTab = rep.onTab,
85 | commandSelector == #selector(NSResponder.insertTab(_:))
86 | {
87 | onTab()
88 | return true
89 | } else if
90 | let onBackTab = rep.onBackTab,
91 | commandSelector == #selector(NSResponder.insertBacktab(_:))
92 | {
93 | onBackTab()
94 | return true
95 | }
96 |
97 | return false
98 | }
99 | }
100 | }
101 |
102 | /// This is necessary because `textDidBeginEditing` on `NSTextViewDelegate` only triggers once the user types.
103 | class CustomNSTextView: NSTextView {
104 | let rep: OmenTextFieldRep
105 |
106 | internal init(rep: OmenTextFieldRep) {
107 | self.rep = rep
108 |
109 | super.init(frame: .zero, textContainer: NSTextView().textContainer)
110 | }
111 |
112 | @available(*, unavailable)
113 | required init?(coder _: NSCoder) {
114 | fatalError("init(coder:) has not been implemented")
115 | }
116 |
117 | override func becomeFirstResponder() -> Bool {
118 | rep.isFocused?.wrappedValue = true
119 | return super.becomeFirstResponder()
120 | }
121 |
122 | override func resignFirstResponder() -> Bool {
123 | rep.isFocused?.wrappedValue = false
124 | return super.resignFirstResponder()
125 | }
126 | }
127 |
128 | extension NSTextView {
129 | func textHeight() -> CGFloat {
130 | if let layoutManager = layoutManager,
131 | let container = layoutManager.textContainers.first
132 | {
133 | return layoutManager.usedRect(for: container).height
134 | } else {
135 | return frame.height
136 | }
137 | }
138 | }
139 | #endif
140 |
--------------------------------------------------------------------------------
/OmenTextFieldExample/Shared/ExampleView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // Shared
4 | //
5 | // Created by Kit Langton on 12/22/20.
6 | //
7 |
8 | import OmenTextField
9 | import SwiftUI
10 |
11 | struct ExampleView: View {
12 | @State var frontText = ""
13 | @State var frontReturnKeyType = OmenTextField.ReturnKeyType.next
14 |
15 | @State var backText = ""
16 |
17 | @State var isFinished = false
18 |
19 | @State var focus: Focus?
20 |
21 | enum Focus {
22 | case front, back
23 | }
24 |
25 | var body: some View {
26 | ZStack(alignment: .bottom) {
27 | Form {
28 | Section(header: Text("Front")) {
29 | OmenTextField(
30 | "Front",
31 | text: $frontText,
32 | isFocused: $focus.equalTo(.front),
33 | returnKeyType: frontReturnKeyType,
34 | onCommit: {
35 | focus = .back
36 | }
37 | )
38 |
39 | #if os(iOS)
40 | returnKeyPicker()
41 | #endif
42 | }
43 |
44 | Section(header: Text("Back")) {
45 | OmenTextField(
46 | "Back",
47 | text: $backText,
48 | isFocused: $focus.equalTo(.back),
49 | returnKeyType: .done,
50 | onCommit: {
51 | focus = nil
52 | frontText = ""
53 | backText = ""
54 | isFinished = true
55 | }
56 | )
57 | }
58 |
59 | Section(header: Text("Focus")) {
60 | Toggle(isOn: $focus.equalTo(.front), label: {
61 | Text("Front Focused")
62 | })
63 |
64 | Toggle(isOn: $focus.equalTo(.back), label: {
65 | Text("Back Focused")
66 | })
67 | }
68 | }
69 | .onAppear {
70 | // NOTE: Unfortunately, one must occasionally muck with delays when dealing with
71 | // `becomeFirstResponder` and SwiftUI. Ideally, this can be moved into the
72 | // `OmenTextViewRep`, perhaps it can repeatedly attempt to `becomeFirstResponder`
73 | // until it succeeds. I'm just wary of infinite loops.
74 | // FURTHERMORE: This delay is only necessary when within a NavigationView.
75 | // It appears that NavigationView steals the focus on load somehow.
76 | DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) {
77 | focus = .front
78 | }
79 | }
80 |
81 | Text("FINISHED").bold()
82 | .padding()
83 | .background(Color.blue)
84 | .cornerRadius(3)
85 | .opacity(isFinished ? 1 : 0)
86 | .offset(y: isFinished ? 0 : 20)
87 | .onChange(of: isFinished, perform: { isFinished in
88 | if isFinished {
89 | DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
90 | self.isFinished = false
91 | }
92 | }
93 | })
94 | }
95 | .animation(.spring())
96 | }
97 |
98 | #if os(iOS)
99 | func returnKeyPicker() -> some View {
100 | ScrollView(.horizontal, showsIndicators: false) {
101 | HStack {
102 | ForEach(OmenTextField.ReturnKeyType.allCases, id: \.self) { returnKeyType in
103 | Text(returnKeyType.rawValue)
104 | .padding(4)
105 | .padding(.horizontal, 4)
106 | .background(frontReturnKeyType == returnKeyType ? Color.blue :
107 | Color.clear)
108 | .cornerRadius(3)
109 | .animation(.interactiveSpring())
110 | .onTapGesture {
111 | frontReturnKeyType = returnKeyType
112 | UISelectionFeedbackGenerator().selectionChanged()
113 | }
114 | }
115 | }
116 | }
117 | }
118 | #endif
119 | }
120 |
121 | extension Binding {
122 | func equalTo(_ value: A) -> Binding where Value == A? {
123 | Binding {
124 | wrappedValue == value
125 | } set: {
126 | if $0 {
127 | wrappedValue = value
128 | } else if wrappedValue == value {
129 | wrappedValue = nil
130 | }
131 | }
132 | }
133 | }
134 |
135 | struct ExampleView_Previews: PreviewProvider {
136 | static var previews: some View {
137 | NavigationView {
138 | ExampleView()
139 | .navigationTitle("Example")
140 | }
141 | .preferredColorScheme(.dark)
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/OmenTextFieldExample/OmenTextFieldExample.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 52;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 474062D52594157B00C7153C /* OmenTextField in Frameworks */ = {isa = PBXBuildFile; productRef = 474062D42594157B00C7153C /* OmenTextField */; };
11 | 479C8F9B259411990036FC14 /* OmenTextField in Frameworks */ = {isa = PBXBuildFile; productRef = 479C8F9A259411990036FC14 /* OmenTextField */; };
12 | 47BCC333259315A800405986 /* ExampleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47BCC332259315A800405986 /* ExampleView.swift */; };
13 | 47BCC334259315A800405986 /* ExampleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47BCC332259315A800405986 /* ExampleView.swift */; };
14 | 47F1D1EF2592D7F1003BABD7 /* OmenTextViewExampleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47F1D1DC2592D7F0003BABD7 /* OmenTextViewExampleApp.swift */; };
15 | 47F1D1F02592D7F1003BABD7 /* OmenTextViewExampleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47F1D1DC2592D7F0003BABD7 /* OmenTextViewExampleApp.swift */; };
16 | 47F1D1F32592D7F1003BABD7 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 47F1D1DE2592D7F1003BABD7 /* Assets.xcassets */; };
17 | 47F1D1F42592D7F1003BABD7 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 47F1D1DE2592D7F1003BABD7 /* Assets.xcassets */; };
18 | /* End PBXBuildFile section */
19 |
20 | /* Begin PBXFileReference section */
21 | 47BCC332259315A800405986 /* ExampleView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExampleView.swift; sourceTree = ""; };
22 | 47F1D1DC2592D7F0003BABD7 /* OmenTextViewExampleApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OmenTextViewExampleApp.swift; sourceTree = ""; };
23 | 47F1D1DE2592D7F1003BABD7 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
24 | 47F1D1E32592D7F1003BABD7 /* OmenTextViewExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = OmenTextViewExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
25 | 47F1D1E62592D7F1003BABD7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
26 | 47F1D1EB2592D7F1003BABD7 /* OmenTextViewExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = OmenTextViewExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
27 | 47F1D1ED2592D7F1003BABD7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
28 | 47F1D1EE2592D7F1003BABD7 /* macOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = macOS.entitlements; sourceTree = ""; };
29 | 47F1D2072592D8FD003BABD7 /* OmenTextView */ = {isa = PBXFileReference; lastKnownFileType = folder; name = OmenTextView; path = ..; sourceTree = ""; };
30 | /* End PBXFileReference section */
31 |
32 | /* Begin PBXFrameworksBuildPhase section */
33 | 47F1D1E02592D7F1003BABD7 /* Frameworks */ = {
34 | isa = PBXFrameworksBuildPhase;
35 | buildActionMask = 2147483647;
36 | files = (
37 | 474062D52594157B00C7153C /* OmenTextField in Frameworks */,
38 | );
39 | runOnlyForDeploymentPostprocessing = 0;
40 | };
41 | 47F1D1E82592D7F1003BABD7 /* Frameworks */ = {
42 | isa = PBXFrameworksBuildPhase;
43 | buildActionMask = 2147483647;
44 | files = (
45 | 479C8F9B259411990036FC14 /* OmenTextField in Frameworks */,
46 | );
47 | runOnlyForDeploymentPostprocessing = 0;
48 | };
49 | /* End PBXFrameworksBuildPhase section */
50 |
51 | /* Begin PBXGroup section */
52 | 4732BD182592DC5F001DF8B2 /* Frameworks */ = {
53 | isa = PBXGroup;
54 | children = (
55 | );
56 | name = Frameworks;
57 | sourceTree = "";
58 | };
59 | 47F1D1D62592D7F0003BABD7 = {
60 | isa = PBXGroup;
61 | children = (
62 | 47F1D2072592D8FD003BABD7 /* OmenTextView */,
63 | 47F1D1DB2592D7F0003BABD7 /* Shared */,
64 | 47F1D1E52592D7F1003BABD7 /* iOS */,
65 | 47F1D1EC2592D7F1003BABD7 /* macOS */,
66 | 47F1D1E42592D7F1003BABD7 /* Products */,
67 | 4732BD182592DC5F001DF8B2 /* Frameworks */,
68 | );
69 | sourceTree = "";
70 | };
71 | 47F1D1DB2592D7F0003BABD7 /* Shared */ = {
72 | isa = PBXGroup;
73 | children = (
74 | 47BCC332259315A800405986 /* ExampleView.swift */,
75 | 47F1D1DC2592D7F0003BABD7 /* OmenTextViewExampleApp.swift */,
76 | 47F1D1DE2592D7F1003BABD7 /* Assets.xcassets */,
77 | );
78 | path = Shared;
79 | sourceTree = "";
80 | };
81 | 47F1D1E42592D7F1003BABD7 /* Products */ = {
82 | isa = PBXGroup;
83 | children = (
84 | 47F1D1E32592D7F1003BABD7 /* OmenTextViewExample.app */,
85 | 47F1D1EB2592D7F1003BABD7 /* OmenTextViewExample.app */,
86 | );
87 | name = Products;
88 | sourceTree = "";
89 | };
90 | 47F1D1E52592D7F1003BABD7 /* iOS */ = {
91 | isa = PBXGroup;
92 | children = (
93 | 47F1D1E62592D7F1003BABD7 /* Info.plist */,
94 | );
95 | path = iOS;
96 | sourceTree = "";
97 | };
98 | 47F1D1EC2592D7F1003BABD7 /* macOS */ = {
99 | isa = PBXGroup;
100 | children = (
101 | 47F1D1ED2592D7F1003BABD7 /* Info.plist */,
102 | 47F1D1EE2592D7F1003BABD7 /* macOS.entitlements */,
103 | );
104 | path = macOS;
105 | sourceTree = "";
106 | };
107 | /* End PBXGroup section */
108 |
109 | /* Begin PBXNativeTarget section */
110 | 47F1D1E22592D7F1003BABD7 /* OmenTextFieldExample (iOS) */ = {
111 | isa = PBXNativeTarget;
112 | buildConfigurationList = 47F1D1F72592D7F1003BABD7 /* Build configuration list for PBXNativeTarget "OmenTextFieldExample (iOS)" */;
113 | buildPhases = (
114 | 47F1D1DF2592D7F1003BABD7 /* Sources */,
115 | 47F1D1E02592D7F1003BABD7 /* Frameworks */,
116 | 47F1D1E12592D7F1003BABD7 /* Resources */,
117 | );
118 | buildRules = (
119 | );
120 | dependencies = (
121 | );
122 | name = "OmenTextFieldExample (iOS)";
123 | packageProductDependencies = (
124 | 474062D42594157B00C7153C /* OmenTextField */,
125 | );
126 | productName = "OmenTextViewExample (iOS)";
127 | productReference = 47F1D1E32592D7F1003BABD7 /* OmenTextViewExample.app */;
128 | productType = "com.apple.product-type.application";
129 | };
130 | 47F1D1EA2592D7F1003BABD7 /* OmenTextFieldExample (macOS) */ = {
131 | isa = PBXNativeTarget;
132 | buildConfigurationList = 47F1D1FA2592D7F1003BABD7 /* Build configuration list for PBXNativeTarget "OmenTextFieldExample (macOS)" */;
133 | buildPhases = (
134 | 47F1D1E72592D7F1003BABD7 /* Sources */,
135 | 47F1D1E82592D7F1003BABD7 /* Frameworks */,
136 | 47F1D1E92592D7F1003BABD7 /* Resources */,
137 | );
138 | buildRules = (
139 | );
140 | dependencies = (
141 | );
142 | name = "OmenTextFieldExample (macOS)";
143 | packageProductDependencies = (
144 | 479C8F9A259411990036FC14 /* OmenTextField */,
145 | );
146 | productName = "OmenTextViewExample (macOS)";
147 | productReference = 47F1D1EB2592D7F1003BABD7 /* OmenTextViewExample.app */;
148 | productType = "com.apple.product-type.application";
149 | };
150 | /* End PBXNativeTarget section */
151 |
152 | /* Begin PBXProject section */
153 | 47F1D1D72592D7F0003BABD7 /* Project object */ = {
154 | isa = PBXProject;
155 | attributes = {
156 | LastSwiftUpdateCheck = 1230;
157 | LastUpgradeCheck = 1230;
158 | TargetAttributes = {
159 | 47F1D1E22592D7F1003BABD7 = {
160 | CreatedOnToolsVersion = 12.3;
161 | };
162 | 47F1D1EA2592D7F1003BABD7 = {
163 | CreatedOnToolsVersion = 12.3;
164 | };
165 | };
166 | };
167 | buildConfigurationList = 47F1D1DA2592D7F0003BABD7 /* Build configuration list for PBXProject "OmenTextFieldExample" */;
168 | compatibilityVersion = "Xcode 9.3";
169 | developmentRegion = en;
170 | hasScannedForEncodings = 0;
171 | knownRegions = (
172 | en,
173 | Base,
174 | );
175 | mainGroup = 47F1D1D62592D7F0003BABD7;
176 | productRefGroup = 47F1D1E42592D7F1003BABD7 /* Products */;
177 | projectDirPath = "";
178 | projectRoot = "";
179 | targets = (
180 | 47F1D1E22592D7F1003BABD7 /* OmenTextFieldExample (iOS) */,
181 | 47F1D1EA2592D7F1003BABD7 /* OmenTextFieldExample (macOS) */,
182 | );
183 | };
184 | /* End PBXProject section */
185 |
186 | /* Begin PBXResourcesBuildPhase section */
187 | 47F1D1E12592D7F1003BABD7 /* Resources */ = {
188 | isa = PBXResourcesBuildPhase;
189 | buildActionMask = 2147483647;
190 | files = (
191 | 47F1D1F32592D7F1003BABD7 /* Assets.xcassets in Resources */,
192 | );
193 | runOnlyForDeploymentPostprocessing = 0;
194 | };
195 | 47F1D1E92592D7F1003BABD7 /* Resources */ = {
196 | isa = PBXResourcesBuildPhase;
197 | buildActionMask = 2147483647;
198 | files = (
199 | 47F1D1F42592D7F1003BABD7 /* Assets.xcassets in Resources */,
200 | );
201 | runOnlyForDeploymentPostprocessing = 0;
202 | };
203 | /* End PBXResourcesBuildPhase section */
204 |
205 | /* Begin PBXSourcesBuildPhase section */
206 | 47F1D1DF2592D7F1003BABD7 /* Sources */ = {
207 | isa = PBXSourcesBuildPhase;
208 | buildActionMask = 2147483647;
209 | files = (
210 | 47F1D1EF2592D7F1003BABD7 /* OmenTextViewExampleApp.swift in Sources */,
211 | 47BCC333259315A800405986 /* ExampleView.swift in Sources */,
212 | );
213 | runOnlyForDeploymentPostprocessing = 0;
214 | };
215 | 47F1D1E72592D7F1003BABD7 /* Sources */ = {
216 | isa = PBXSourcesBuildPhase;
217 | buildActionMask = 2147483647;
218 | files = (
219 | 47F1D1F02592D7F1003BABD7 /* OmenTextViewExampleApp.swift in Sources */,
220 | 47BCC334259315A800405986 /* ExampleView.swift in Sources */,
221 | );
222 | runOnlyForDeploymentPostprocessing = 0;
223 | };
224 | /* End PBXSourcesBuildPhase section */
225 |
226 | /* Begin XCBuildConfiguration section */
227 | 47F1D1F52592D7F1003BABD7 /* Debug */ = {
228 | isa = XCBuildConfiguration;
229 | buildSettings = {
230 | ALWAYS_SEARCH_USER_PATHS = NO;
231 | CLANG_ANALYZER_NONNULL = YES;
232 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
233 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
234 | CLANG_CXX_LIBRARY = "libc++";
235 | CLANG_ENABLE_MODULES = YES;
236 | CLANG_ENABLE_OBJC_ARC = YES;
237 | CLANG_ENABLE_OBJC_WEAK = YES;
238 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
239 | CLANG_WARN_BOOL_CONVERSION = YES;
240 | CLANG_WARN_COMMA = YES;
241 | CLANG_WARN_CONSTANT_CONVERSION = YES;
242 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
243 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
244 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
245 | CLANG_WARN_EMPTY_BODY = YES;
246 | CLANG_WARN_ENUM_CONVERSION = YES;
247 | CLANG_WARN_INFINITE_RECURSION = YES;
248 | CLANG_WARN_INT_CONVERSION = YES;
249 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
250 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
251 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
252 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
253 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
254 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
255 | CLANG_WARN_STRICT_PROTOTYPES = YES;
256 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
257 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
258 | CLANG_WARN_UNREACHABLE_CODE = YES;
259 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
260 | COPY_PHASE_STRIP = NO;
261 | DEBUG_INFORMATION_FORMAT = dwarf;
262 | ENABLE_STRICT_OBJC_MSGSEND = YES;
263 | ENABLE_TESTABILITY = YES;
264 | GCC_C_LANGUAGE_STANDARD = gnu11;
265 | GCC_DYNAMIC_NO_PIC = NO;
266 | GCC_NO_COMMON_BLOCKS = YES;
267 | GCC_OPTIMIZATION_LEVEL = 0;
268 | GCC_PREPROCESSOR_DEFINITIONS = (
269 | "DEBUG=1",
270 | "$(inherited)",
271 | );
272 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
273 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
274 | GCC_WARN_UNDECLARED_SELECTOR = YES;
275 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
276 | GCC_WARN_UNUSED_FUNCTION = YES;
277 | GCC_WARN_UNUSED_VARIABLE = YES;
278 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
279 | MTL_FAST_MATH = YES;
280 | ONLY_ACTIVE_ARCH = YES;
281 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
282 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
283 | };
284 | name = Debug;
285 | };
286 | 47F1D1F62592D7F1003BABD7 /* Release */ = {
287 | isa = XCBuildConfiguration;
288 | buildSettings = {
289 | ALWAYS_SEARCH_USER_PATHS = NO;
290 | CLANG_ANALYZER_NONNULL = YES;
291 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
292 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
293 | CLANG_CXX_LIBRARY = "libc++";
294 | CLANG_ENABLE_MODULES = YES;
295 | CLANG_ENABLE_OBJC_ARC = YES;
296 | CLANG_ENABLE_OBJC_WEAK = YES;
297 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
298 | CLANG_WARN_BOOL_CONVERSION = YES;
299 | CLANG_WARN_COMMA = YES;
300 | CLANG_WARN_CONSTANT_CONVERSION = YES;
301 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
302 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
303 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
304 | CLANG_WARN_EMPTY_BODY = YES;
305 | CLANG_WARN_ENUM_CONVERSION = YES;
306 | CLANG_WARN_INFINITE_RECURSION = YES;
307 | CLANG_WARN_INT_CONVERSION = YES;
308 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
309 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
310 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
311 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
312 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
313 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
314 | CLANG_WARN_STRICT_PROTOTYPES = YES;
315 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
316 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
317 | CLANG_WARN_UNREACHABLE_CODE = YES;
318 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
319 | COPY_PHASE_STRIP = NO;
320 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
321 | ENABLE_NS_ASSERTIONS = NO;
322 | ENABLE_STRICT_OBJC_MSGSEND = YES;
323 | GCC_C_LANGUAGE_STANDARD = gnu11;
324 | GCC_NO_COMMON_BLOCKS = YES;
325 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
326 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
327 | GCC_WARN_UNDECLARED_SELECTOR = YES;
328 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
329 | GCC_WARN_UNUSED_FUNCTION = YES;
330 | GCC_WARN_UNUSED_VARIABLE = YES;
331 | MTL_ENABLE_DEBUG_INFO = NO;
332 | MTL_FAST_MATH = YES;
333 | SWIFT_COMPILATION_MODE = wholemodule;
334 | SWIFT_OPTIMIZATION_LEVEL = "-O";
335 | };
336 | name = Release;
337 | };
338 | 47F1D1F82592D7F1003BABD7 /* Debug */ = {
339 | isa = XCBuildConfiguration;
340 | buildSettings = {
341 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
342 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
343 | CODE_SIGN_STYLE = Automatic;
344 | DEVELOPMENT_TEAM = QC99C9JE59;
345 | ENABLE_PREVIEWS = YES;
346 | INFOPLIST_FILE = iOS/Info.plist;
347 | IPHONEOS_DEPLOYMENT_TARGET = 14.0;
348 | LD_RUNPATH_SEARCH_PATHS = (
349 | "$(inherited)",
350 | "@executable_path/Frameworks",
351 | );
352 | PRODUCT_BUNDLE_IDENTIFIER = com.kitlangton.OmenTextViewExample;
353 | PRODUCT_NAME = OmenTextViewExample;
354 | SDKROOT = iphoneos;
355 | SWIFT_VERSION = 5.0;
356 | TARGETED_DEVICE_FAMILY = "1,2";
357 | };
358 | name = Debug;
359 | };
360 | 47F1D1F92592D7F1003BABD7 /* Release */ = {
361 | isa = XCBuildConfiguration;
362 | buildSettings = {
363 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
364 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
365 | CODE_SIGN_STYLE = Automatic;
366 | DEVELOPMENT_TEAM = QC99C9JE59;
367 | ENABLE_PREVIEWS = YES;
368 | INFOPLIST_FILE = iOS/Info.plist;
369 | IPHONEOS_DEPLOYMENT_TARGET = 14.0;
370 | LD_RUNPATH_SEARCH_PATHS = (
371 | "$(inherited)",
372 | "@executable_path/Frameworks",
373 | );
374 | PRODUCT_BUNDLE_IDENTIFIER = com.kitlangton.OmenTextViewExample;
375 | PRODUCT_NAME = OmenTextViewExample;
376 | SDKROOT = iphoneos;
377 | SWIFT_VERSION = 5.0;
378 | TARGETED_DEVICE_FAMILY = "1,2";
379 | VALIDATE_PRODUCT = YES;
380 | };
381 | name = Release;
382 | };
383 | 47F1D1FB2592D7F1003BABD7 /* Debug */ = {
384 | isa = XCBuildConfiguration;
385 | buildSettings = {
386 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
387 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
388 | CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements;
389 | CODE_SIGN_STYLE = Automatic;
390 | COMBINE_HIDPI_IMAGES = YES;
391 | DEVELOPMENT_TEAM = QC99C9JE59;
392 | ENABLE_HARDENED_RUNTIME = YES;
393 | ENABLE_PREVIEWS = YES;
394 | INFOPLIST_FILE = macOS/Info.plist;
395 | LD_RUNPATH_SEARCH_PATHS = (
396 | "$(inherited)",
397 | "@executable_path/../Frameworks",
398 | );
399 | MACOSX_DEPLOYMENT_TARGET = 11.0;
400 | PRODUCT_BUNDLE_IDENTIFIER = com.kitlangton.OmenTextViewExample;
401 | PRODUCT_NAME = OmenTextViewExample;
402 | SDKROOT = macosx;
403 | SWIFT_VERSION = 5.0;
404 | };
405 | name = Debug;
406 | };
407 | 47F1D1FC2592D7F1003BABD7 /* Release */ = {
408 | isa = XCBuildConfiguration;
409 | buildSettings = {
410 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
411 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
412 | CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements;
413 | CODE_SIGN_STYLE = Automatic;
414 | COMBINE_HIDPI_IMAGES = YES;
415 | DEVELOPMENT_TEAM = QC99C9JE59;
416 | ENABLE_HARDENED_RUNTIME = YES;
417 | ENABLE_PREVIEWS = YES;
418 | INFOPLIST_FILE = macOS/Info.plist;
419 | LD_RUNPATH_SEARCH_PATHS = (
420 | "$(inherited)",
421 | "@executable_path/../Frameworks",
422 | );
423 | MACOSX_DEPLOYMENT_TARGET = 11.0;
424 | PRODUCT_BUNDLE_IDENTIFIER = com.kitlangton.OmenTextViewExample;
425 | PRODUCT_NAME = OmenTextViewExample;
426 | SDKROOT = macosx;
427 | SWIFT_VERSION = 5.0;
428 | };
429 | name = Release;
430 | };
431 | /* End XCBuildConfiguration section */
432 |
433 | /* Begin XCConfigurationList section */
434 | 47F1D1DA2592D7F0003BABD7 /* Build configuration list for PBXProject "OmenTextFieldExample" */ = {
435 | isa = XCConfigurationList;
436 | buildConfigurations = (
437 | 47F1D1F52592D7F1003BABD7 /* Debug */,
438 | 47F1D1F62592D7F1003BABD7 /* Release */,
439 | );
440 | defaultConfigurationIsVisible = 0;
441 | defaultConfigurationName = Release;
442 | };
443 | 47F1D1F72592D7F1003BABD7 /* Build configuration list for PBXNativeTarget "OmenTextFieldExample (iOS)" */ = {
444 | isa = XCConfigurationList;
445 | buildConfigurations = (
446 | 47F1D1F82592D7F1003BABD7 /* Debug */,
447 | 47F1D1F92592D7F1003BABD7 /* Release */,
448 | );
449 | defaultConfigurationIsVisible = 0;
450 | defaultConfigurationName = Release;
451 | };
452 | 47F1D1FA2592D7F1003BABD7 /* Build configuration list for PBXNativeTarget "OmenTextFieldExample (macOS)" */ = {
453 | isa = XCConfigurationList;
454 | buildConfigurations = (
455 | 47F1D1FB2592D7F1003BABD7 /* Debug */,
456 | 47F1D1FC2592D7F1003BABD7 /* Release */,
457 | );
458 | defaultConfigurationIsVisible = 0;
459 | defaultConfigurationName = Release;
460 | };
461 | /* End XCConfigurationList section */
462 |
463 | /* Begin XCSwiftPackageProductDependency section */
464 | 474062D42594157B00C7153C /* OmenTextField */ = {
465 | isa = XCSwiftPackageProductDependency;
466 | productName = OmenTextField;
467 | };
468 | 479C8F9A259411990036FC14 /* OmenTextField */ = {
469 | isa = XCSwiftPackageProductDependency;
470 | productName = OmenTextField;
471 | };
472 | /* End XCSwiftPackageProductDependency section */
473 | };
474 | rootObject = 47F1D1D72592D7F0003BABD7 /* Project object */;
475 | }
476 |
--------------------------------------------------------------------------------