Skip to content

Commit d3b1e4b

Browse files
committed
feat: expose helpers for static models
1 parent a29d9d1 commit d3b1e4b

File tree

3 files changed

+52
-16
lines changed

3 files changed

+52
-16
lines changed

WorkflowSwiftUI/Sources/ActionModel.swift

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,22 @@
11
/// An ``ObservableModel`` for workflows with a single action.
22
///
3-
/// Rather than creating this model directly, you should use the
4-
/// ``Workflow/RenderContext/makeActionModel(state:)`` method to create an instance of this model.
3+
/// To create an accessor, use
4+
/// ``Workflow/RenderContext/makeActionModel(state:)``. State writes and actions
5+
/// will be sent to the workflow.
56
public struct ActionModel<State: ObservableState, Action>: ObservableModel, SingleActionModel {
67
public let accessor: StateAccessor<State>
78
public let sendAction: (Action) -> Void
9+
10+
/// Creates a new ActionModel.
11+
///
12+
/// Rather than creating this model directly, you should usually use the
13+
/// ``Workflow/RenderContext/makeActionModel(state:)`` method to create an
14+
/// instance of this model. If you need a static model for testing or
15+
/// previews, you can use the ``constant(state:)`` method.
16+
public init(accessor: StateAccessor<State>, sendAction: @escaping (Action) -> Void) {
17+
self.accessor = accessor
18+
self.sendAction = sendAction
19+
}
820
}
921

1022
/// An observable model with a single action.
@@ -22,3 +34,15 @@ extension ActionModel: Identifiable where State: Identifiable {
2234
accessor.id
2335
}
2436
}
37+
38+
#if DEBUG
39+
40+
public extension ActionModel {
41+
/// Creates a static model which ignores all sent values, suitable for static previews
42+
/// or testing.
43+
static func constant(state: State) -> ActionModel<State, Action> {
44+
ActionModel(accessor: .constant(state: state), sendAction: { _ in })
45+
}
46+
}
47+
48+
#endif

WorkflowSwiftUI/Sources/StateAccessor.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ public struct StateAccessor<State: ObservableState> {
1313
let state: State
1414
let sendValue: (@escaping (inout State) -> Void) -> Void
1515

16+
/// Creates a new state accessor.
17+
///
18+
/// Rather than creating this model directly, you should usually use the
19+
/// ``Workflow/RenderContext/makeStateAccessor(state:)`` method. If you need
20+
/// a static model for testing or previews, you can use the
21+
/// ``constant(state:)`` method.
1622
public init(
1723
state: State,
1824
sendValue: @escaping (@escaping (inout State) -> Void) -> Void
@@ -31,3 +37,15 @@ extension StateAccessor: Identifiable where State: Identifiable {
3137
state.id
3238
}
3339
}
40+
41+
#if DEBUG
42+
43+
public extension StateAccessor {
44+
/// Creates a static state accessor which ignores all sent values, suitable for static previews
45+
/// or testing.
46+
static func constant(state: State) -> StateAccessor<State> {
47+
StateAccessor(state: state, sendValue: { _ in })
48+
}
49+
}
50+
51+
#endif

WorkflowSwiftUI/Sources/Store+Preview.swift

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,17 @@ public struct StaticStorePreviewContext {
1212
}
1313

1414
public func makeStateAccessor<State>(state: State) -> StateAccessor<State> {
15-
StateAccessor(
16-
state: state,
17-
sendValue: { _ in }
18-
)
15+
.constant(state: state)
1916
}
2017

2118
public func makeActionModel<State, Action>(
2219
state: State
2320
) -> ActionModel<State, Action> {
24-
ActionModel(
25-
accessor: makeStateAccessor(state: state),
26-
sendAction: makeSink(of: Action.self).send
27-
)
21+
.constant(state: state)
2822
}
2923
}
3024

31-
extension Store {
25+
public extension Store {
3226
/// Generates a static store for previews.
3327
///
3428
/// Previews generated with this method are static and do not update state. To generate a
@@ -38,15 +32,15 @@ extension Store {
3832
/// - Parameter makeModel: A closure to create the store's model. The provided `context` param
3933
/// is a convenience to generate dummy sinks and state accessors.
4034
/// - Returns: A store for previews.
41-
public static func preview(
35+
static func preview(
4236
makeModel: (StaticStorePreviewContext) -> Model
4337
) -> Store {
4438
let context = StaticStorePreviewContext()
4539
let model = makeModel(context)
4640
let (store, _) = make(model: model)
4741
return store
4842
}
49-
43+
5044
/// Generates a static store for previews.
5145
///
5246
/// Previews generated with this method are static and do not update state. To generate a
@@ -55,14 +49,14 @@ extension Store {
5549
///
5650
/// - Parameter state: The state of the view.
5751
/// - Returns: A store for previews.
58-
public static func preview<State, Action>(
52+
static func preview<State, Action>(
5953
state: State
6054
) -> Store<ActionModel<State, Action>> where Model == ActionModel<State, Action> {
6155
preview { context in
6256
context.makeActionModel(state: state)
6357
}
6458
}
65-
59+
6660
/// Generates a static store for previews.
6761
///
6862
/// Previews generated with this method are static and do not update state. To generate a
@@ -71,7 +65,7 @@ extension Store {
7165
///
7266
/// - Parameter state: The state of the view.
7367
/// - Returns: A store for previews.
74-
public static func preview<State>(
68+
static func preview<State>(
7569
state: State
7670
) -> Store<StateAccessor<State>> where Model == StateAccessor<State> {
7771
preview { context in

0 commit comments

Comments
 (0)