https://github.com/holistic-apps-ltda/declarativeui
A library to develop UI declaratively in Swift.
https://github.com/holistic-apps-ltda/declarativeui
declarative declarative-programming declarative-ui declarativeui swift ui-components
Last synced: 8 months ago
JSON representation
A library to develop UI declaratively in Swift.
- Host: GitHub
- URL: https://github.com/holistic-apps-ltda/declarativeui
- Owner: Holistic-Apps-LTDA
- License: mit
- Created: 2022-03-18T23:14:49.000Z (over 3 years ago)
- Default Branch: main
- Last Pushed: 2022-05-24T00:31:50.000Z (over 3 years ago)
- Last Synced: 2025-01-30T08:33:26.000Z (8 months ago)
- Topics: declarative, declarative-programming, declarative-ui, declarativeui, swift, ui-components
- Language: Swift
- Homepage:
- Size: 379 KB
- Stars: 4
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# DeclarativeUI
A library to develop UI declaratively in Swift.- [Requirements](#requirements)
- [Installation](#installation)
- [Usage](#usage)## Requirements
| Platform | Minimum Swift Version | Installation | Status |
| --- | --- | --- | --- |
| iOS 11.0+ | 5.0 | [CocoaPods](#cocoapods), [Carthage](#carthage), [Swift Package Manager](#swift-package-manager) | Partially Tested |## Installation
### CocoaPods
[CocoaPods](https://cocoapods.org) is a dependency manager for Cocoa projects. For usage and installation instructions, visit their website. To integrate DeclarativeUI into your Xcode project using CocoaPods, specify it in your `Podfile`:
```ruby
pod 'DeclarativeUUI', '~> 0.0.10'
```### Carthage
[Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. To integrate DeclarativeUI into your Xcode project using Carthage, specify it in your `Cartfile`:
```ogdl
github "Holistic-Apps-LTDA/DeclarativeUI" ~> 0.0.10
```
In terminal run:```ogdl
carthage update --use-xcframeworks
```### Swift Package Manager
The [Swift Package Manager](https://swift.org/package-manager/) is a tool for automating the distribution of Swift code and is integrated into the `swift` compiler.
Once you have your Swift package set up, adding DeclarativeUI as a dependency is as easy as adding it to the `dependencies` value of your `Package.swift`.
```swift
dependencies: [
.package(url: "https://github.com/Holistic-Apps-LTDA/DeclarativeUI.git", .upToNextMajor(from: "0.0.10"))
]
```## Usage
A demo app is available in the DemoApp folder for querying the usage of library components.
### ViewModel
```swift
enum DemoInteractionEvents {
case rowSelect(DataObject)
case iconTap
}import DeclarativeUI
final class DemoViewModel: DeclarativeViewModel {
// MARK: Attributes
let interactionEvents = Publisher()
let data: DataObject
// MARK: Life Cycleinit(data: DataObject) {
self.data = data
super.init()
}
}```
### ViewController
```swift
import DeclarativeUIfinal class DemoViewController: DeclarativeViewController {
// MARK: Attributes
public lazy var viewController = ViewController(view: view)
private let viewModel: DemoViewModel
private lazy var titlelLabel = Label(
text: viewModel.data.title,
style: .systemFont()
)
private lazy var detailLabel = Label(
text: viewModel.data.detail
style: .boldSystemFont()
)private lazy var valueLabel = Label(
text: viewModel.data.value
style: .boldSystemFont()
)private let icon = Image()
.size(width: .medium, height: .medium)
.image(viewModel.data.icon)
private lazy var view = StackView(.vertical) {
Spacer(.small)
titlelLabel
Spacer(.small)
StackView(.horizontal) {
icon
detailLabel
}.spacing(.extraSmall)
.alignment(.leading)
Spacer(.medium)
valueLabel
Spacer(.flexible)
}.padding(.uniform(.small))
// MARK: Life Cyclepublic init(viewModel: DemoViewModel) {
self.viewModel = viewModel
}
}```
### Component
```swift
import DeclarativeUIpublic class Pager: DeclarativeComponent {
public lazy var view = stackView
private lazy var stackView = StackView(.horizontal)
.distribution(.fillEqually)
.alignment(.center)
.spacing(.zero)
private var buttons = [Page]()
private var selectedIndex = Publisher()
private let initialIndexSelected: Int
public init(_ options: [String],
indexSelected: Int = 0) {
initialIndexSelected = indexSelected
options.enumerated().forEach { index, value in
let button = Page(value)
.onTap { [weak self] in
self?.selectedIndex.publish(index)
}
if index == initialIndexSelected {
button.selectLayout()
} else {
button.normalLayout()
}
buttons.append(button)
}
stackView.update {
buttons as [UIViewConvertible]
}
bindSelectedIndex()
}
private func bindSelectedIndex() {
observe(selectedIndex) { [stackView, buttons] vc, indexSelected in
vc.buttons.enumerated().forEach { index, button in
if index == indexSelected {
button.selectLayout()
} else {
button.normalLayout()
}
}
stackView.update {
buttons as [UIViewConvertible]
}
}
}
@discardableResult
public func didChangeValue(_ action: @escaping (Int?) -> Void) -> Self {
selectedIndex.subscribe().onNext { _, value in
action(value)
}.disposedBy(self)
return self
}
}private class Page: DeclarativeComponent {
public lazy var view = ContainerView { stackView }
private let title = Label(style: .systemFont())
private let line = EmptyView()
.backgroundColor(.white)
.height(.extraSmall2)
.cornerRadius(.extraSmall3)
private lazy var stackView = StackView(.vertical) {
title
.alignment(.center)
Spacer(.extraSmall)
line
}.distribution(.fill)public init(_ title: String) {
self.title.text(title)
}
public func selectLayout() {
title.style(.boldSystemFont())
line.backgroundColor(.black)
}
public func normalLayout() {
title.style(.systemFont())
line.backgroundColor(.white)
}
}```
### Preview
```swift
import SwiftUI
@available(iOS 13.0.0, *)
struct Pager_Previews: PreviewProvider {
static var previews: some View {
ViewContainer(view: pager)
.previewDevice("iPhone 12")
}static var pager = StackView(.vertical) {
Spacer(.large)
Pager(["Option 1", "Option 2", "Option 3"])
}.padding(.horizontal(.medium))
}
```### Coordinator
```swift
import DeclarativeUIpublic final class DemoCoordinator: DeclarativeCoordinator {
// MARK: Life Cycle
public init() {
super.init()
start()
}
public func start() {
navigateToDemo()
}
private func navigateToDemo() {
let viewModel = DemoViewModel(data: DataObject())
let viewController = DemoViewController(viewModel: viewModel)
.navigationBarOptions([.back, .close])
.navigationTitle("Title Navigation Bar")viewModel.interactionEvents.subscribe().onNext { event in
switch event {
case .rowSelect(let data):
self.navigateToDemoDetail(data: data)
case .iconOnTap:
self.navigateToIconTap()
}
}.disposedBy(self)navigator.push(viewController)
}
}
```