Skip to content

Commit

Permalink
Merge pull request #69 from Babylonpartners/search-bar-component
Browse files Browse the repository at this point in the history
Added search bar component
  • Loading branch information
sergdort committed Nov 8, 2018
2 parents bd7b2b6 + 63c6edc commit 07f73ec
Show file tree
Hide file tree
Showing 11 changed files with 210 additions and 0 deletions.
8 changes: 8 additions & 0 deletions BentoKit/BentoKit.xcodeproj/project.pbxproj
Expand Up @@ -80,6 +80,8 @@
A6EC2DBB218B2912002B128F /* Bool+Assertions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6EC2DB8218B2912002B128F /* Bool+Assertions.swift */; };
A6EC2DBD218B298B002B128F /* HostWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6EC2DBC218B298A002B128F /* HostWindow.swift */; };
B5234D63216EB0060061AD8B /* ImageOrLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5234D62216EB0060061AD8B /* ImageOrLabel.swift */; };
B5BD11C6219301D500DC6A51 /* Search.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BD11C5219301D500DC6A51 /* Search.swift */; };
B5BD11C821930A2400DC6A51 /* SearchSnapshotTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BD11C721930A2400DC6A51 /* SearchSnapshotTests.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -184,6 +186,8 @@
A6EC2DB8218B2912002B128F /* Bool+Assertions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Bool+Assertions.swift"; sourceTree = "<group>"; };
A6EC2DBC218B298A002B128F /* HostWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HostWindow.swift; sourceTree = "<group>"; };
B5234D62216EB0060061AD8B /* ImageOrLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageOrLabel.swift; sourceTree = "<group>"; };
B5BD11C5219301D500DC6A51 /* Search.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Search.swift; sourceTree = "<group>"; };
B5BD11C721930A2400DC6A51 /* SearchSnapshotTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchSnapshotTests.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -273,6 +277,7 @@
580B6127215D2F6800A69E87 /* TextInput.swift */,
580B612B215D2F6800A69E87 /* TitledDescription.swift */,
580B6122215D2F6700A69E87 /* Toggle.swift */,
B5BD11C5219301D500DC6A51 /* Search.swift */,
);
path = Components;
sourceTree = "<group>";
Expand Down Expand Up @@ -402,6 +407,7 @@
58801186216271DA0084EE07 /* TitledDescriptionSnapshotTests.swift */,
5880118A216271DA0084EE07 /* TitledDescriptionLegacySnapshotTests.swift */,
58801187216271DA0084EE07 /* ToggleSnapshotTests.swift */,
B5BD11C721930A2400DC6A51 /* SearchSnapshotTests.swift */,
);
path = Components;
sourceTree = "<group>";
Expand Down Expand Up @@ -624,6 +630,7 @@
580B612F215D2F6800A69E87 /* Toggle.swift in Sources */,
580B612E215D2F6800A69E87 /* Component.swift in Sources */,
580B614A215D353B00A69E87 /* InputNodes.swift in Sources */,
B5BD11C6219301D500DC6A51 /* Search.swift in Sources */,
580B6134215D2F6800A69E87 /* TextInput.swift in Sources */,
A6EC2DB0218B28AA002B128F /* BoxViewModel.swift in Sources */,
580B611F215D2F6100A69E87 /* HeightCustomizing.swift in Sources */,
Expand Down Expand Up @@ -671,6 +678,7 @@
58801197216271DB0084EE07 /* ActivityComponentSnapshotTests.swift in Sources */,
58801191216271DB0084EE07 /* TitledDescriptionSnapshotTests.swift in Sources */,
58801192216271DB0084EE07 /* ToggleSnapshotTests.swift in Sources */,
B5BD11C821930A2400DC6A51 /* SearchSnapshotTests.swift in Sources */,
A6EC2DB5218B28BF002B128F /* BoxViewControllerSnapshotTests.swift in Sources */,
58801193216271DB0084EE07 /* ButtonComponentSnapshotTests.swift in Sources */,
);
Expand Down
@@ -0,0 +1,28 @@
import UIKit
import Bento
import BentoKit
import BentoKitPlaygroundSupport
import PlaygroundSupport
import StyleSheets

let bundle = Bundle(for: Component.TextInput.self)
let styleSheet = Component.Search.StyleSheet()
.compose(\.searchBar.textInputBackgroundColor, UIColor.gray.withAlphaComponent(0.25))
.compose(\.searchBar.showsCancelButton, true)
let component = Component.Search(
placeholder: "Placeholder",
keyboardType: .default,
didBeginEditing: { _ in
print("didBeginEditing")
},
textDidChange: { _, text in
print("textDidChange", text)
},
cancelButtonClicked: {
print("cancelButtonClicked")
$0.endEditing(true)
},
styleSheet: styleSheet
)

PlaygroundPage.current.liveView = renderInTableView(component: component)
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Timeline
version = "3.0">
<TimelineItems>
</TimelineItems>
</Timeline>
Expand Up @@ -9,5 +9,6 @@
<page name='MultilineTextInput'/>
<page name='TextInput'/>
<page name='TitledDescription'/>
<page name='Search'/>
</pages>
</playground>
82 changes: 82 additions & 0 deletions BentoKit/BentoKit/Components/Search.swift
@@ -0,0 +1,82 @@
import Bento
import StyleSheets

extension Component {
public final class Search: AutoRenderable {
public let configurator: (View) -> Void
public let styleSheet: StyleSheet

public init(
placeholder: String? = nil,
keyboardType: UIKeyboardType = .default,
didBeginEditing: Optional<(UISearchBar) -> Void> = nil,
textDidChange: Optional<(UISearchBar, String) -> Void> = nil,
cancelButtonClicked: Optional<(UISearchBar) -> Void> = nil,
styleSheet: StyleSheet = StyleSheet()
) {
self.configurator = { view in
view.searchBar.placeholder = placeholder
view.searchBar.keyboardType = keyboardType
view.didBeginEditing = didBeginEditing
view.textDidChange = textDidChange
view.cancelButtonClicked = cancelButtonClicked
view.searchBar.height(styleSheet.searchBar.height)
}
self.styleSheet = styleSheet
}
}
}

extension Component.Search {
public final class View: BaseView, UISearchBarDelegate {

let searchBar = UISearchBar()

var textDidChange: Optional<(UISearchBar, String) -> Void> = nil
var cancelButtonClicked: Optional<(UISearchBar) -> Void> = nil
var didBeginEditing: Optional<(UISearchBar) -> Void> = nil

public override init(frame: CGRect) {
super.init(frame: frame)

searchBar.add(to: self)
.pinEdges(to: layoutMarginsGuide)

searchBar.delegate = self
}

@available(*, unavailable)
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

public func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
self.didBeginEditing?(searchBar)
}

public func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
searchBar.endEditing(true)
}

public func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
self.textDidChange?(searchBar, searchText)
}

public func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
self.cancelButtonClicked?(searchBar)
}
}
}

extension Component.Search {
public final class StyleSheet: BaseViewStyleSheet<View> {
public let searchBar = SearchBarStyleSheet()

public init() {}

public override func apply(to element: View) {
super.apply(to: element)
searchBar.apply(to: element.searchBar)
}
}
}
@@ -0,0 +1,24 @@
import BentoKit
import StyleSheets
import UIKit
@testable import BentoKitPlaygroundSupport

final class SearchSnapshotTests: SnapshotTestCase {
let placeholder = "Search for address or a postcode"

override func setUp() {
super.setUp()
self.recordMode = false
}

func testSearch() {
let styleSheet = Component.Search.StyleSheet()
.compose(\.searchBar.textInputBackgroundColor, UIColor.gray.withAlphaComponent(0.25))
.compose(\.searchBar.showsCancelButton, true)

let component = Component.Search(placeholder: placeholder, styleSheet: styleSheet)

verifyComponentForAllSizes(component: component)
}

}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions StyleSheets/StyleSheets.xcodeproj/project.pbxproj
Expand Up @@ -21,6 +21,7 @@
6554A9ED21369CA900D84BD4 /* TextAlignment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6554A9EC21369CA900D84BD4 /* TextAlignment.swift */; };
6554A9F72136A1FB00D84BD4 /* StyleSheets.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6554A9D0213699B600D84BD4 /* StyleSheets.framework */; };
6554A9FE2136A20B00D84BD4 /* StyleSheetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6554A9FD2136A20A00D84BD4 /* StyleSheetTests.swift */; };
B5BD13022194405400DC6A51 /* SearchBarStyleSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BD13012194405400DC6A51 /* SearchBarStyleSheet.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -54,6 +55,7 @@
A6C9C8DB21807A1D00261906 /* Framework.Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Framework.Debug.xcconfig; sourceTree = "<group>"; };
A6C9C8DC21807A1D00261906 /* Framework.Base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Framework.Base.xcconfig; sourceTree = "<group>"; };
A6C9C8DD21807A1D00261906 /* Framework.Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Framework.Release.xcconfig; sourceTree = "<group>"; };
B5BD13012194405400DC6A51 /* SearchBarStyleSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchBarStyleSheet.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -110,6 +112,7 @@
25EFC89D217BA8390056D4B9 /* TextBoundComputing.swift */,
25EFC89F217BA85B0056D4B9 /* TextViewStyleSheet.swift */,
25EFC891217BA6450056D4B9 /* ViewStyleSheet.swift */,
B5BD13012194405400DC6A51 /* SearchBarStyleSheet.swift */,
);
path = StyleSheets;
sourceTree = "<group>";
Expand Down Expand Up @@ -248,6 +251,7 @@
25EFC8A2217BA8750056D4B9 /* TableViewStyleSheet.swift in Sources */,
25EFC892217BA6450056D4B9 /* ViewStyleSheet.swift in Sources */,
25EFC896217BA6830056D4B9 /* LabelStyleSheet.swift in Sources */,
B5BD13022194405400DC6A51 /* SearchBarStyleSheet.swift in Sources */,
25EFC89E217BA8390056D4B9 /* TextBoundComputing.swift in Sources */,
25EFC898217BA6D10056D4B9 /* ButtonStyleSheet.swift in Sources */,
25EFC89C217BA8050056D4B9 /* ImageViewStyleSheet.swift in Sources */,
Expand Down
48 changes: 48 additions & 0 deletions StyleSheets/StyleSheets/SearchBarStyleSheet.swift
@@ -0,0 +1,48 @@
import UIKit

open class SearchBarStyleSheet: ViewStyleSheet<UISearchBar> {
public var textInputBackgroundColor: UIColor = .white
public var textInputCornerRaidus: CGFloat = 10
public var height: CGFloat = 36
public var showsCancelButton: Bool = false
public var searchTextPositionAdjustment: UIOffset = UIOffset(horizontal: 8, vertical: 0)
public var keyboardType: UIKeyboardType = .default
public var returnKeyType: UIReturnKeyType = .search
public var enablesReturnKeyAutomatically: Bool = true

open override func apply(to element: UISearchBar) {
super.apply(to: element)
element.setTextInputBackgroundColor(color: textInputBackgroundColor,
height: height,
cornerRadius: textInputCornerRaidus)
element.showsCancelButton = showsCancelButton
element.searchTextPositionAdjustment = searchTextPositionAdjustment
element.keyboardType = keyboardType
element.returnKeyType = returnKeyType
element.enablesReturnKeyAutomatically = enablesReturnKeyAutomatically
element.barTintColor = tintColor
// remove system background
element.backgroundImage = UIImage()
}

}

extension UISearchBar {
func setTextInputBackgroundColor(color: UIColor, height: CGFloat, cornerRadius: CGFloat) {
// creates an image with rounded corners from background color
let size = CGSize(width: cornerRadius * 2, height: height)
let backgroundImage = UIGraphicsImageRenderer(size: size)
.image { imageContext in
let path = UIBezierPath(roundedRect: CGRect(origin: .zero, size: size), cornerRadius: cornerRadius)

imageContext.cgContext.beginPath()
imageContext.cgContext.addPath(path.cgPath)
imageContext.cgContext.closePath()
imageContext.cgContext.clip()

imageContext.cgContext.setFillColor(color.cgColor)
imageContext.cgContext.fill(CGRect(origin: .zero, size: size))
}
setSearchFieldBackgroundImage(backgroundImage, for: .normal)
}
}

0 comments on commit 07f73ec

Please sign in to comment.