Created
December 20, 2023 23:41
-
-
Save adam-zethraeus/2d7221e19bf204c813cfc93999ab076b to your computer and use it in GitHub Desktop.
Slice binding
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@_spi(Internals) import ComposableArchitecture | |
struct Bound<R: Reducer, S, V:View> { | |
init(store: StoreOf<R>, _ s: KeyPath<R.State, S>, _ a: @escaping (S) -> R.Action, @ViewBuilder _ vb: @escaping (Binding<S>) -> V) { | |
_state = Binding<S>{store.state.value[keyPath: s] } set:{ store.send(a($0)) } | |
self.vb = vb | |
} | |
@Binding var state: S | |
@ViewBuilder var vb: (Binding<S>) -> V | |
} | |
struct Slice<R: Reducer, S> { | |
internal init(_ select: KeyPath<R.State, S>, _ act: @escaping (S) -> R.Action) { | |
self.select = select | |
self.act = act | |
} | |
let select: KeyPath<R.State, S> | |
let act: (S) -> R.Action | |
func bind(from store: StoreOf<R>) -> Binding<S> { | |
.init(get: { store.state.value[keyPath: select]}, set: { store.send(act($0)) }) | |
} | |
} | |
struct Slicer<R:Reducer, A, B, C> { | |
let a: Slice<R, A> | |
let b: Slice<R, B> | |
let c: Slice<R, C> | |
} | |
struct WithSlices<R: Reducer, A, B, C, V:View>: View { | |
init( | |
store: StoreOf<R>, | |
a: Slice<R, A>, | |
b: Slice<R, B>, | |
c: Slice<R, C>, | |
@ViewBuilder _ vb:@escaping (_ a: Binding<A>, _ b: Binding<B>, _ c: Binding<C>) -> V | |
) { | |
self.vb = vb | |
self.slicer = .init(a: a, b: b, c: c) | |
self.store = store | |
} | |
let store: StoreOf<R> | |
let slicer: Slicer<R, A, B, C> | |
let vb: (_ a: Binding<A>, _ b: Binding<B>, _ c: Binding<C>) -> V | |
var body: some View { | |
vb(slicer.a.bind(from: store), slicer.b.bind(from: store), slicer.c.bind(from: store)) | |
} | |
} | |
extension Store { | |
func slice<RA: Reducer, A, B, C, V: View>( | |
a: Slice<RA, A>, | |
b: Slice<RA, B>, | |
c: Slice<RA, C>, | |
@ViewBuilder vb: @escaping (_ a: Binding<A>, _ b: Binding<B>, _ c: Binding<C>) -> V | |
) -> some View where State == RA.State, Action == RA.Action { | |
WithSlices<RA, A, B, C, V>(store: self, a: a, b: b, c: c, vb) | |
} | |
} | |
struct R: Reducer { | |
func reduce(into state: inout State, action: Action) -> ComposableArchitecture.Effect<Action> { | |
return .none | |
} | |
struct State: Equatable { | |
var a: Bool | |
} | |
enum Action { | |
case lol(Bool) | |
} | |
} | |
struct VB: View { | |
var x = StoreOf<R>(initialState: R.State(a: false), reducer: {R()}) | |
var body: some View { | |
x.slice(a: Slice<R, Bool>(\.a, R.Action.lol), b: .init(\.a, R.Action.lol), c: .init(\.a, R.Action.lol)) { $a, $b, $c in | |
HStack { | |
Text("Yeah").opacity(a ? 1 : 0) | |
Text("Yeah").opacity(b ? 1 : 0) | |
Text("Yeah").opacity(c ? 1 : 0) | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment