Skip to content

Commit fd16af7

Browse files
committed
Renamed SearchBar to FindPanel. Styled FindPanel. Added number of matches and clear button. When text field loses focus, emphasis layers are removed. Styled example app.
1 parent 5842295 commit fd16af7

17 files changed

+973
-358
lines changed

Example/CodeEditSourceEditorExample/CodeEditSourceEditorExample/CodeEditSourceEditorExampleApp.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ struct CodeEditSourceEditorExampleApp: App {
1212
var body: some Scene {
1313
DocumentGroup(newDocument: CodeEditSourceEditorExampleDocument()) { file in
1414
ContentView(document: file.$document, fileURL: file.fileURL)
15+
.preferredColorScheme(.light)
1516
}
1617
}
1718
}

Example/CodeEditSourceEditorExample/CodeEditSourceEditorExample/Views/ContentView.swift

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -28,26 +28,7 @@ struct ContentView: View {
2828
}
2929

3030
var body: some View {
31-
VStack(spacing: 0) {
32-
HStack {
33-
Text("Language")
34-
LanguagePicker(language: $language)
35-
.frame(maxWidth: 100)
36-
Toggle("Wrap Lines", isOn: $wrapLines)
37-
if #available(macOS 14, *) {
38-
Toggle("Use System Cursor", isOn: $useSystemCursor)
39-
} else {
40-
Toggle("Use System Cursor", isOn: $useSystemCursor)
41-
.disabled(true)
42-
.help("macOS 14 required")
43-
}
44-
Spacer()
45-
Text(getLabel(cursorPositions))
46-
}
47-
.padding(4)
48-
.zIndex(2)
49-
.background(Color(NSColor.windowBackgroundColor))
50-
Divider()
31+
VStack {
5132
ZStack {
5233
if isInLongParse {
5334
VStack {
@@ -74,10 +55,41 @@ struct ContentView: View {
7455
cursorPositions: $cursorPositions,
7556
useSystemCursor: useSystemCursor
7657
)
58+
.safeAreaInset(edge: .bottom, spacing: 0) {
59+
VStack(spacing: 0) {
60+
Divider()
61+
HStack {
62+
Toggle("Wrap Lines", isOn: $wrapLines)
63+
.toggleStyle(.button)
64+
.buttonStyle(.accessoryBar)
65+
if #available(macOS 14, *) {
66+
Toggle("Use System Cursor", isOn: $useSystemCursor)
67+
.toggleStyle(.button)
68+
.buttonStyle(.accessoryBar)
69+
} else {
70+
Toggle("Use System Cursor", isOn: $useSystemCursor)
71+
.disabled(true)
72+
.help("macOS 14 required")
73+
.toggleStyle(.button)
74+
.buttonStyle(.accessoryBar)
75+
}
76+
Spacer()
77+
Text(getLabel(cursorPositions))
78+
Divider()
79+
.frame(height: 12)
80+
LanguagePicker(language: $language)
81+
.buttonStyle(.borderless)
82+
}
83+
.padding(.horizontal, 8)
84+
.frame(height: 28)
85+
}
86+
.background(.bar)
87+
.zIndex(2)
88+
}
89+
}
90+
.onAppear {
91+
self.language = detectLanguage(fileURL: fileURL) ?? .default
7792
}
78-
}
79-
.onAppear {
80-
self.language = detectLanguage(fileURL: fileURL) ?? .default
8193
}
8294
.onReceive(NotificationCenter.default.publisher(for: TreeSitterClient.Constants.longParse)) { _ in
8395
withAnimation(.easeIn(duration: 0.1)) {
@@ -105,7 +117,7 @@ struct ContentView: View {
105117
/// - Returns: A string describing the user's location in a document.
106118
func getLabel(_ cursorPositions: [CursorPosition]) -> String {
107119
if cursorPositions.isEmpty {
108-
return ""
120+
return "No cursor"
109121
}
110122

111123
// More than one selection, display the number of selections.
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
//
2+
// IconButtonStyle.swift
3+
// CodeEdit
4+
//
5+
// Created by Austin Condiff on 11/9/23.
6+
//
7+
8+
import SwiftUI
9+
10+
struct IconButtonStyle: ButtonStyle {
11+
var isActive: Bool?
12+
var font: Font?
13+
var size: CGSize?
14+
15+
init(isActive: Bool? = nil, font: Font? = nil, size: CGFloat? = nil) {
16+
self.isActive = isActive
17+
self.font = font
18+
self.size = size == nil ? nil : CGSize(width: size ?? 0, height: size ?? 0)
19+
}
20+
21+
init(isActive: Bool? = nil, font: Font? = nil, size: CGSize? = nil) {
22+
self.isActive = isActive
23+
self.font = font
24+
self.size = size
25+
}
26+
27+
init(isActive: Bool? = nil, font: Font? = nil) {
28+
self.isActive = isActive
29+
self.font = font
30+
self.size = nil
31+
}
32+
33+
func makeBody(configuration: ButtonStyle.Configuration) -> some View {
34+
IconButton(
35+
configuration: configuration,
36+
isActive: isActive,
37+
font: font,
38+
size: size
39+
)
40+
}
41+
42+
struct IconButton: View {
43+
let configuration: ButtonStyle.Configuration
44+
var isActive: Bool
45+
var font: Font
46+
var size: CGSize?
47+
@Environment(\.controlActiveState)
48+
private var controlActiveState
49+
@Environment(\.isEnabled)
50+
private var isEnabled: Bool
51+
@Environment(\.colorScheme)
52+
private var colorScheme
53+
54+
init(configuration: ButtonStyle.Configuration, isActive: Bool?, font: Font?, size: CGFloat?) {
55+
self.configuration = configuration
56+
self.isActive = isActive ?? false
57+
self.font = font ?? Font.system(size: 14.5, weight: .regular, design: .default)
58+
self.size = size == nil ? nil : CGSize(width: size ?? 0, height: size ?? 0)
59+
}
60+
61+
init(configuration: ButtonStyle.Configuration, isActive: Bool?, font: Font?, size: CGSize?) {
62+
self.configuration = configuration
63+
self.isActive = isActive ?? false
64+
self.font = font ?? Font.system(size: 14.5, weight: .regular, design: .default)
65+
self.size = size ?? nil
66+
}
67+
68+
init(configuration: ButtonStyle.Configuration, isActive: Bool?, font: Font?) {
69+
self.configuration = configuration
70+
self.isActive = isActive ?? false
71+
self.font = font ?? Font.system(size: 14.5, weight: .regular, design: .default)
72+
self.size = nil
73+
}
74+
75+
var body: some View {
76+
configuration.label
77+
.font(font)
78+
.foregroundColor(
79+
isActive
80+
? Color(.controlAccentColor)
81+
: Color(.secondaryLabelColor)
82+
)
83+
.frame(width: size?.width, height: size?.height, alignment: .center)
84+
.contentShape(Rectangle())
85+
.brightness(
86+
configuration.isPressed
87+
? colorScheme == .dark
88+
? 0.5
89+
: isActive ? -0.25 : -0.75
90+
: 0
91+
)
92+
.opacity(controlActiveState == .inactive ? 0.5 : 1)
93+
.symbolVariant(isActive ? .fill : .none)
94+
}
95+
}
96+
}
97+
98+
extension ButtonStyle where Self == IconButtonStyle {
99+
static func icon(
100+
isActive: Bool? = false,
101+
font: Font? = Font.system(size: 14.5, weight: .regular, design: .default),
102+
size: CGFloat? = 24
103+
) -> IconButtonStyle {
104+
return IconButtonStyle(isActive: isActive, font: font, size: size)
105+
}
106+
static func icon(
107+
isActive: Bool? = false,
108+
font: Font? = Font.system(size: 14.5, weight: .regular, design: .default),
109+
size: CGSize? = CGSize(width: 24, height: 24)
110+
) -> IconButtonStyle {
111+
return IconButtonStyle(isActive: isActive, font: font, size: size)
112+
}
113+
static func icon(
114+
isActive: Bool? = false,
115+
font: Font? = Font.system(size: 14.5, weight: .regular, design: .default)
116+
) -> IconButtonStyle {
117+
return IconButtonStyle(isActive: isActive, font: font)
118+
}
119+
static var icon: IconButtonStyle { .init() }
120+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
//
2+
// IconToggleStyle.swift
3+
// CodeEdit
4+
//
5+
// Created by Austin Condiff on 11/9/23.
6+
//
7+
8+
import SwiftUI
9+
10+
struct IconToggleStyle: ToggleStyle {
11+
var font: Font?
12+
var size: CGSize?
13+
14+
@State var isPressing = false
15+
16+
init(font: Font? = nil, size: CGFloat? = nil) {
17+
self.font = font
18+
self.size = size == nil ? nil : CGSize(width: size ?? 0, height: size ?? 0)
19+
}
20+
21+
init(font: Font? = nil, size: CGSize? = nil) {
22+
self.font = font
23+
self.size = size
24+
}
25+
26+
init(font: Font? = nil) {
27+
self.font = font
28+
self.size = nil
29+
}
30+
31+
func makeBody(configuration: ToggleStyle.Configuration) -> some View {
32+
Button(
33+
action: { configuration.isOn.toggle() },
34+
label: { configuration.label }
35+
)
36+
.buttonStyle(.icon(isActive: configuration.isOn, font: font, size: size))
37+
}
38+
}
39+
40+
extension ToggleStyle where Self == IconToggleStyle {
41+
static func icon(
42+
font: Font? = Font.system(size: 14.5, weight: .regular, design: .default),
43+
size: CGFloat? = 24
44+
) -> IconToggleStyle {
45+
return IconToggleStyle(font: font, size: size)
46+
}
47+
static func icon(
48+
font: Font? = Font.system(size: 14.5, weight: .regular, design: .default),
49+
size: CGSize? = CGSize(width: 24, height: 24)
50+
) -> IconToggleStyle {
51+
return IconToggleStyle(font: font, size: size)
52+
}
53+
static func icon(
54+
font: Font? = Font.system(size: 14.5, weight: .regular, design: .default)
55+
) -> IconToggleStyle {
56+
return IconToggleStyle(font: font)
57+
}
58+
static var icon: IconToggleStyle { .init() }
59+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
//
2+
// PanelStyles.swift
3+
// CodeEdit
4+
//
5+
// Created by Austin Condiff on 3/12/25.
6+
//
7+
8+
import SwiftUI
9+
10+
private struct InsideControlGroupKey: EnvironmentKey {
11+
static let defaultValue: Bool = false
12+
}
13+
14+
extension EnvironmentValues {
15+
var isInsideControlGroup: Bool {
16+
get { self[InsideControlGroupKey.self] }
17+
set { self[InsideControlGroupKey.self] = newValue }
18+
}
19+
}
20+
21+
struct PanelControlGroupStyle: ControlGroupStyle {
22+
@Environment(\.controlActiveState) private var controlActiveState
23+
24+
func makeBody(configuration: Configuration) -> some View {
25+
HStack(spacing: 0) {
26+
configuration.content
27+
.buttonStyle(PanelButtonStyle())
28+
.environment(\.isInsideControlGroup, true)
29+
.padding(.vertical, 1)
30+
}
31+
.overlay(
32+
RoundedRectangle(cornerRadius: 4)
33+
.strokeBorder(Color(nsColor: .tertiaryLabelColor), lineWidth: 1)
34+
)
35+
.cornerRadius(4)
36+
.clipped()
37+
}
38+
}
39+
40+
struct PanelButtonStyle: ButtonStyle {
41+
@Environment(\.colorScheme) var colorScheme
42+
@Environment(\.controlActiveState) private var controlActiveState
43+
@Environment(\.isEnabled) private var isEnabled
44+
@Environment(\.isInsideControlGroup) private var isInsideControlGroup
45+
46+
func makeBody(configuration: Configuration) -> some View {
47+
configuration.label
48+
.font(.system(size: 12, weight: .regular))
49+
.foregroundColor(Color(.controlTextColor))
50+
.padding(.horizontal, 6)
51+
.frame(height: isInsideControlGroup ? 16 : 18)
52+
.background(
53+
configuration.isPressed
54+
? colorScheme == .light
55+
? Color.black.opacity(0.06)
56+
: Color.white.opacity(0.24)
57+
: Color.clear
58+
)
59+
.overlay(
60+
Group {
61+
if !isInsideControlGroup {
62+
RoundedRectangle(cornerRadius: 4)
63+
.strokeBorder(Color(nsColor: .tertiaryLabelColor), lineWidth: 1)
64+
}
65+
}
66+
)
67+
.cornerRadius(isInsideControlGroup ? 0 : 4)
68+
.clipped()
69+
.contentShape(Rectangle())
70+
}
71+
}

0 commit comments

Comments
 (0)