diff --git a/WorkflowSwiftUI/Sources/ActionModel.swift b/WorkflowSwiftUI/Sources/ActionModel.swift index 7c494bbc..10c2e5f1 100644 --- a/WorkflowSwiftUI/Sources/ActionModel.swift +++ b/WorkflowSwiftUI/Sources/ActionModel.swift @@ -1,10 +1,22 @@ /// An ``ObservableModel`` for workflows with a single action. /// -/// Rather than creating this model directly, you should use the -/// ``Workflow/RenderContext/makeActionModel(state:)`` method to create an instance of this model. +/// To create an accessor, use +/// ``Workflow/RenderContext/makeActionModel(state:)``. State writes and actions +/// will be sent to the workflow. public struct ActionModel: ObservableModel, SingleActionModel { public let accessor: StateAccessor public let sendAction: (Action) -> Void + + /// Creates a new ActionModel. + /// + /// Rather than creating this model directly, you should usually use the + /// ``Workflow/RenderContext/makeActionModel(state:)`` method to create an + /// instance of this model. If you need a static model for testing or + /// previews, you can use the ``constant(state:)`` method. + public init(accessor: StateAccessor, sendAction: @escaping (Action) -> Void) { + self.accessor = accessor + self.sendAction = sendAction + } } /// An observable model with a single action. @@ -22,3 +34,15 @@ extension ActionModel: Identifiable where State: Identifiable { accessor.id } } + +#if DEBUG + +public extension ActionModel { + /// Creates a static model which ignores all sent values, suitable for static previews + /// or testing. + static func constant(state: State) -> ActionModel { + ActionModel(accessor: .constant(state: state), sendAction: { _ in }) + } +} + +#endif diff --git a/WorkflowSwiftUI/Sources/StateAccessor.swift b/WorkflowSwiftUI/Sources/StateAccessor.swift index 24278483..c71351c2 100644 --- a/WorkflowSwiftUI/Sources/StateAccessor.swift +++ b/WorkflowSwiftUI/Sources/StateAccessor.swift @@ -13,6 +13,12 @@ public struct StateAccessor { let state: State let sendValue: (@escaping (inout State) -> Void) -> Void + /// Creates a new state accessor. + /// + /// Rather than creating this model directly, you should usually use the + /// ``Workflow/RenderContext/makeStateAccessor(state:)`` method. If you need + /// a static model for testing or previews, you can use the + /// ``constant(state:)`` method. public init( state: State, sendValue: @escaping (@escaping (inout State) -> Void) -> Void @@ -31,3 +37,15 @@ extension StateAccessor: Identifiable where State: Identifiable { state.id } } + +#if DEBUG + +public extension StateAccessor { + /// Creates a static state accessor which ignores all sent values, suitable for static previews + /// or testing. + static func constant(state: State) -> StateAccessor { + StateAccessor(state: state, sendValue: { _ in }) + } +} + +#endif diff --git a/WorkflowSwiftUI/Sources/Store+Preview.swift b/WorkflowSwiftUI/Sources/Store+Preview.swift index f31a4b24..9221174b 100644 --- a/WorkflowSwiftUI/Sources/Store+Preview.swift +++ b/WorkflowSwiftUI/Sources/Store+Preview.swift @@ -12,23 +12,17 @@ public struct StaticStorePreviewContext { } public func makeStateAccessor(state: State) -> StateAccessor { - StateAccessor( - state: state, - sendValue: { _ in } - ) + .constant(state: state) } public func makeActionModel( state: State ) -> ActionModel { - ActionModel( - accessor: makeStateAccessor(state: state), - sendAction: makeSink(of: Action.self).send - ) + .constant(state: state) } } -extension Store { +public extension Store { /// Generates a static store for previews. /// /// Previews generated with this method are static and do not update state. To generate a @@ -38,7 +32,7 @@ extension Store { /// - Parameter makeModel: A closure to create the store's model. The provided `context` param /// is a convenience to generate dummy sinks and state accessors. /// - Returns: A store for previews. - public static func preview( + static func preview( makeModel: (StaticStorePreviewContext) -> Model ) -> Store { let context = StaticStorePreviewContext() @@ -46,7 +40,7 @@ extension Store { let (store, _) = make(model: model) return store } - + /// Generates a static store for previews. /// /// Previews generated with this method are static and do not update state. To generate a @@ -55,14 +49,14 @@ extension Store { /// /// - Parameter state: The state of the view. /// - Returns: A store for previews. - public static func preview( + static func preview( state: State ) -> Store> where Model == ActionModel { preview { context in context.makeActionModel(state: state) } } - + /// Generates a static store for previews. /// /// Previews generated with this method are static and do not update state. To generate a @@ -71,7 +65,7 @@ extension Store { /// /// - Parameter state: The state of the view. /// - Returns: A store for previews. - public static func preview( + static func preview( state: State ) -> Store> where Model == StateAccessor { preview { context in