Skip to content
This repository has been archived by the owner on Oct 17, 2024. It is now read-only.

Commit

Permalink
Merge branch 'main' into 1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
david-swift committed Oct 3, 2024
2 parents 0a6f104 + c6d0fa5 commit 1060662
Show file tree
Hide file tree
Showing 10 changed files with 776 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
- name: Modify Docs
run: |
echo "<script>window.location.href += \"/documentation/adwaita\"</script>" > docs/index.html;
sed -i '' 's/#06f/#ea3358/g' docs/css/documentation-topic~topic~tutorials-overview.d6f5411c.css
sed -i '' 's/#06f/#ea3358/g' docs/css/documentation-topic~topic~tutorials-overview.*.css
sed -i '' 's/,2px/,10px/g' docs/css/index.*.css
- name: Upload Artifact
uses: actions/upload-pages-artifact@v3
Expand Down
150 changes: 150 additions & 0 deletions Sources/Adwaita/Model/Data Flow/Binding.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
//
// Binding.swift
// Adwaita
//
// Created by david-swift on 06.08.23.
//

/// A property wrapper for a property of a view that binds the property of the parent view.
///
/// ```swift
/// struct Grandparent: View {
///
/// @State private var state = false
///
/// var view: Body {
/// Parent(value: $state)
/// }
/// }
///
/// struct Parent: View {
///
/// @Binding var value: Bool
///
/// var view: Body {
/// Child(value: $value)
/// }
///
/// }
///
/// struct Child: View {
///
/// @Binding var value: Bool
///
/// var view: Body {
/// // ...
/// }
///
/// }
/// ```
@propertyWrapper
@dynamicMemberLookup
public struct Binding<Value> {

/// The value.
public var wrappedValue: Value {
get {
getValue()
}
nonmutating set {
setValue(newValue)
for handler in handlers {
handler(newValue)
}
}
}

/// Get the value as a binding using the `$` prefix.
public var projectedValue: Binding<Value> {
.init {
wrappedValue
} set: { newValue in
wrappedValue = newValue
}
}

/// The closure for getting the value.
private let getValue: () -> Value
/// The closure for settings the value.
private let setValue: (Value) -> Void
/// Handlers observing whether the binding changes.
private var handlers: [(Value) -> Void] = []

/// Get a property of any content of a `Binding` as a `Binding`.
/// - Parameter dynamicMember: The path to the member.
/// - Returns: The binding.
public subscript<Subject>(dynamicMember keyPath: WritableKeyPath<Value, Subject>) -> Binding<Subject> {
.init {
wrappedValue[keyPath: keyPath]
} set: { newValue in
wrappedValue[keyPath: keyPath] = newValue
}
}

/// Initialize a property that is bound from a parent view.
/// - Parameters:
/// - get: The closure for getting the value.
/// - set: The closure for setting the value.
public init(get: @escaping () -> Value, set: @escaping (Value) -> Void) {
self.getValue = get
self.setValue = set
}

/// Initialize a property that does not react to changes in the child view.
/// - Parameters:
/// - value: The constant value.
/// - Returns: The binding.
public static func constant(_ value: Value) -> Binding<Value> {
.init {
value
} set: { _ in
}
}

/// Observe whether data is changed over this binding.
/// - Parameter handler: The handler.
/// - Returns: The binding.
public func onSet(_ handler: @escaping (Value) -> Void) -> Self {
var newSelf = self
newSelf.handlers.append(handler)
return newSelf
}

}

/// An extension
extension Binding where Value: MutableCollection {

/// Get a child at a certain index of the array as a binding.
/// - Parameters:
/// - index: The child's index.
/// - defaultValue: The value used if the index is out of range does not exist.
/// - Returns: The child as a binding.
public subscript(safe index: Value.Index?, default defaultValue: Value.Element) -> Binding<Value.Element> {
.init {
if let index, wrappedValue.indices.contains(index) {
return wrappedValue[index]
}
return defaultValue
} set: { newValue in
if let index, wrappedValue.indices.contains(index) {
wrappedValue[index] = newValue
}
}
}

}

/// An extension
extension Binding where Value: MutableCollection, Value.Element: Identifiable {

/// Get a child of the array with a certain id as a binding.
/// - Parameters:
/// - id: The child's id.
/// - defaultValue: The value used if the index is out of range does not exist.
/// - Returns: The child as a binding.
public subscript(id id: Value.Element.ID?, default defaultValue: Value.Element) -> Binding<Value.Element> {
self[safe: wrappedValue.firstIndex { $0.id == id }, default: defaultValue]
}

}
Loading

0 comments on commit 1060662

Please sign in to comment.