From d8c8afee1d902c2c75c2b047a74edaaab2f717f3 Mon Sep 17 00:00:00 2001 From: tiye Date: Tue, 15 Oct 2024 13:55:05 +0800 Subject: [PATCH] reduce boilerplace code with more enum constructors --- src/lib/dialog/dialogs.mbt | 5 +- src/lib/node/alias.mbt | 16 +++--- src/lib/node/diff.mbt | 101 +++++++++++++++++-------------------- src/lib/node/element.mbt | 2 +- src/lib/node/node.mbt | 12 ++--- src/lib/node/patch.mbt | 22 ++++---- src/lib/renderer.mbt | 15 ++---- src/main/counter.mbt | 6 +-- src/main/panel.mbt | 8 ++- src/main/task.mbt | 10 ++-- 10 files changed, 86 insertions(+), 111 deletions(-) diff --git a/src/lib/dialog/dialogs.mbt b/src/lib/dialog/dialogs.mbt index e2523c3..a90e3f3 100644 --- a/src/lib/dialog/dialogs.mbt +++ b/src/lib/dialog/dialogs.mbt @@ -165,10 +165,7 @@ pub fn comp_esc_listener[T]( Keydown, fn(e, dispatch) { match e { - @node.RespoEvent::Keyboard(~key, ..) => - if key == "Escape" { - on_close(dispatch) - } + Keyboard(~key, ..) => if key == "Escape" { on_close(dispatch) } _ => () } }, diff --git a/src/lib/node/alias.mbt b/src/lib/node/alias.mbt index d3cb534..49e354c 100644 --- a/src/lib/node/alias.mbt +++ b/src/lib/node/alias.mbt @@ -8,7 +8,7 @@ pub fn div[T]( ~style : RespoStyle = RespoStyle::new(), children : Array[RespoNode[T]] ) -> RespoNode[T] { - RespoNode::Element( + Element( { name: "div", attrs, @@ -31,7 +31,7 @@ pub fn div_listed[T]( ~style : RespoStyle = RespoStyle::new(), children : Array[(RespoIndexKey, RespoNode[T])] ) -> RespoNode[T] { - RespoNode::Element({ name: "div", attrs, event, style, children }) + Element({ name: "div", attrs, event, style, children }) } pub fn span[T]( @@ -43,7 +43,7 @@ pub fn span[T]( ~style : RespoStyle = RespoStyle::new(), children : Array[RespoNode[T]] ) -> RespoNode[T] { - RespoNode::Element( + Element( { name: "span", attrs, @@ -64,7 +64,7 @@ pub fn button[T]( ] = {}, ~style : RespoStyle = RespoStyle::new() ) -> RespoNode[T] { - RespoNode::Element({ name: "button", attrs, event, style, children: [] }) + Element({ name: "button", attrs, event, style, children: [] }) } pub fn input[T]( @@ -75,7 +75,7 @@ pub fn input[T]( ] = {}, ~style : RespoStyle = RespoStyle::new() ) -> RespoNode[T] { - RespoNode::Element({ name: "input", attrs, event, style, children: [] }) + Element({ name: "input", attrs, event, style, children: [] }) } pub fn textarea[T]( @@ -86,7 +86,7 @@ pub fn textarea[T]( ] = {}, ~style : RespoStyle = RespoStyle::new() ) -> RespoNode[T] { - RespoNode::Element({ name: "textarea", attrs, event, style, children: [] }) + Element({ name: "textarea", attrs, event, style, children: [] }) } pub fn br[T]( @@ -97,7 +97,7 @@ pub fn br[T]( ] = {}, ~style : RespoStyle = RespoStyle::new() ) -> RespoNode[T] { - RespoNode::Element({ name: "br", attrs, event, style, children: [] }) + Element({ name: "br", attrs, event, style, children: [] }) } pub fn space[T](~width : Int = 1, ~height : Int = 1) -> RespoNode[T] { @@ -122,7 +122,7 @@ pub fn create_element[T]( ~style : RespoStyle = RespoStyle::new(), children : Array[RespoNode[T]] ) -> RespoNode[T] { - RespoNode::Element( + Element( { name, attrs, diff --git a/src/lib/node/diff.mbt b/src/lib/node/diff.mbt index fdbfab2..b37eb9a 100644 --- a/src/lib/node/diff.mbt +++ b/src/lib/node/diff.mbt @@ -47,14 +47,12 @@ pub fn diff_tree[T]( changes, ) // crate::util::log!("compare elements: {:?} {:?}", new_child, old_child); - changes.val.push( - DomChange::ReplaceElement(~coord, ~dom_path, node=new_child), - ) + changes.val.push(ReplaceElement(~coord, ~dom_path, node=new_child)) collect_effects_outside_in_as!( new_tree, coord, dom_path, - RespoEffectType::Mounted, + Mounted, changes, ) } @@ -64,15 +62,15 @@ pub fn diff_tree[T]( old_tree, coord, dom_path, - RespoEffectType::BeforeUnmount, + BeforeUnmount, changes, ) - changes.val.push(DomChange::ReplaceElement(~coord, ~dom_path, node=a)) + changes.val.push(ReplaceElement(~coord, ~dom_path, node=a)) collect_effects_outside_in_as!( new_tree, coord, dom_path, - RespoEffectType::Mounted, + Mounted, changes, ) } @@ -81,15 +79,15 @@ pub fn diff_tree[T]( old_tree, coord, dom_path, - RespoEffectType::BeforeUnmount, + BeforeUnmount, changes, ) - changes.val.push(DomChange::ReplaceElement(~coord, ~dom_path, node=a)) + changes.val.push(ReplaceElement(~coord, ~dom_path, node=a)) collect_effects_outside_in_as!( new_tree, coord, dom_path, - RespoEffectType::Mounted, + Mounted, changes, ) } @@ -107,7 +105,7 @@ pub fn diff_tree[T]( old_tree, coord, dom_path, - RespoEffectType::BeforeUnmount, + BeforeUnmount, changes, ) changes.val.push(DomChange::ReplaceElement(~coord, ~dom_path, node=a)) @@ -115,7 +113,7 @@ pub fn diff_tree[T]( new_tree, coord, dom_path, - RespoEffectType::Mounted, + Mounted, changes, ) } else { @@ -281,28 +279,28 @@ fn diff_children[T]( return } else { let old_entry = old_children[old_tracking_pointer] - let child_coord = [RespoCoord::Key(old_entry.0)] + let child_coord = [Key(old_entry.0)] let child_dom_path = [cursor] nested_effects_inside_out_as!( old_entry.1, child_coord, child_dom_path, - RespoEffectType::BeforeUnmount, + BeforeUnmount, operations, ) - operations.val.push(ChildDomOp::RemoveAt(cursor)) + operations.val.push(RemoveAt(cursor)) old_tracking_pointer += 1 } } else if old_tracking_pointer >= old_children.length() { let (new_key, new_child) = new_children[new_tracking_pointer] - operations.val.push(ChildDomOp::Append(new_key, new_child)) - let child_coord = [RespoCoord::Key(new_key)] + operations.val.push(Append(new_key, new_child)) + let child_coord = [Key(new_key)] let child_dom_path = [cursor] nested_effects_outside_in_as!( new_child, child_coord, child_dom_path, - RespoEffectType::Mounted, + Mounted, operations, ) new_tracking_pointer += 1 @@ -311,7 +309,7 @@ fn diff_children[T]( let old_entry = old_children[old_tracking_pointer] if new_entry.0 == old_entry.0 { let next_coord = coord.copy() - next_coord.push(RespoCoord::Key(new_entry.0)) + next_coord.push(Key(new_entry.0)) let next_dom_path = dom_path.copy() next_dom_path.push(cursor) diff_tree!(new_entry.1, old_entry.1, next_coord, next_dom_path, changes) @@ -323,64 +321,60 @@ fn diff_children[T]( Some(new_entry.0) == old_children.get(old_tracking_pointer + 2).map(fst) || Some(new_entry.0) == old_children.get(old_tracking_pointer + 3).map(fst) { // look ahead for 3 entries, if still not found, regards this as a remove - let child_coord = [RespoCoord::Key(old_entry.0)] + let child_coord = [Key(old_entry.0)] let child_dom_path = [cursor] nested_effects_inside_out_as!( old_entry.1, child_coord, child_dom_path, - RespoEffectType::BeforeUnmount, + BeforeUnmount, operations, ) - operations.val.push(ChildDomOp::RemoveAt(cursor)) + operations.val.push(RemoveAt(cursor)) old_tracking_pointer += 1 } else if Some(old_entry.0) == new_children.get(new_tracking_pointer + 1).map(fst) || Some(old_entry.0) == new_children.get(new_tracking_pointer + 2).map(fst) || Some(old_entry.0) == new_children.get(new_tracking_pointer + 3).map(fst) { if cursor == 0 { - operations.val.push(ChildDomOp::Prepend(new_entry.0, new_entry.1)) + operations.val.push(Prepend(new_entry.0, new_entry.1)) } else { - operations.val.push( - ChildDomOp::InsertAfter(cursor - 1, new_entry.0, new_entry.1), - ) + operations.val.push(InsertAfter(cursor - 1, new_entry.0, new_entry.1)) } - let child_coord = [RespoCoord::Key(new_entry.0)] + let child_coord = [Key(new_entry.0)] let child_dom_path = [cursor] nested_effects_outside_in_as!( new_entry.1, child_coord, child_dom_path, - RespoEffectType::Mounted, + Mounted, operations, ) cursor += 1 new_tracking_pointer += 1 } else { - let child_coord = [RespoCoord::Key(old_entry.0)] + let child_coord = [Key(old_entry.0)] let child_dom_path = [cursor] nested_effects_inside_out_as!( old_entry.1, child_coord, child_dom_path, - RespoEffectType::BeforeUnmount, + BeforeUnmount, operations, ) - operations.val.push(ChildDomOp::RemoveAt(cursor)) + operations.val.push(RemoveAt(cursor)) if cursor == 0 { - operations.val.push(ChildDomOp::Prepend(new_entry.0, new_entry.1)) + operations.val.push(Prepend(new_entry.0, new_entry.1)) } else { - operations.val.push( - ChildDomOp::InsertAfter(cursor - 1, new_entry.0, new_entry.1), - ) + operations.val.push(InsertAfter(cursor - 1, new_entry.0, new_entry.1)) } - let child_coord = [RespoCoord::Key(new_entry.0)] + let child_coord = [Key(new_entry.0)] let child_dom_path = [cursor] nested_effects_outside_in_as!( new_entry.1, child_coord, child_dom_path, - RespoEffectType::Mounted, + Mounted, operations, ) cursor += 1 @@ -400,30 +394,25 @@ pub fn collect_effects_outside_in_as[T]( changes : Ref[Array[DomChange[T]]] ) -> Unit!RespoCommonError { match tree { - RespoNode::Component(left) => { + Component(left) => { let { name, effects, tree } = left if not(effects.is_empty()) { changes.val.push( - DomChange::Effect( - ~coord, - ~dom_path, - ~effect_type, - skip_indexes=@hashset.new(), - ), + Effect(~coord, ~dom_path, ~effect_type, skip_indexes=@hashset.new()), ) } let next_coord = coord.copy() - next_coord.push(RespoCoord::Comp(name)) + next_coord.push(Comp(name)) collect_effects_outside_in_as!( tree, next_coord, dom_path, effect_type, changes, ) } - RespoNode::Element(right) => { + Element(right) => { let { children, .. } = right for idx, pair in children.iter2() { let (k, child) = pair let next_coord = coord.copy() - next_coord.push(RespoCoord::Key(RespoIndexKey(k.to_string()))) + next_coord.push(Key(RespoIndexKey(k.to_string()))) let next_dom_path = dom_path.copy() next_dom_path.push(idx.reinterpret_as_uint()) collect_effects_outside_in_as!( @@ -431,7 +420,7 @@ pub fn collect_effects_outside_in_as[T]( ) } } - RespoNode::Referenced(cell) => + Referenced(cell) => collect_effects_outside_in_as!( cell, coord, dom_path, effect_type, changes, ) @@ -450,7 +439,7 @@ pub fn collect_effects_inside_out_as[T]( RespoNode::Component(left) => { let { name, effects, tree } = left let next_coord = coord.copy() - next_coord.push(RespoCoord::Comp(name)) + next_coord.push(Comp(name)) collect_effects_inside_out_as!( tree, next_coord, dom_path, effect_type, changes, ) @@ -471,7 +460,7 @@ pub fn collect_effects_inside_out_as[T]( for pair in children.iter() { let (k, child) = pair let next_coord = coord.copy() - next_coord.push(RespoCoord::Key(k)) + next_coord.push(Key(k)) let next_dom_path = dom_path.copy() next_dom_path.push(idx.reinterpret_as_uint()) collect_effects_inside_out_as!( @@ -500,7 +489,7 @@ fn nested_effects_outside_in_as[T]( let { name, effects, tree } = left if not(effects.is_empty()) { operations.val.push( - ChildDomOp::NestedEffect( + NestedEffect( nested_coord=coord, nested_dom_path=dom_path, ~effect_type, @@ -509,7 +498,7 @@ fn nested_effects_outside_in_as[T]( ) } let next_coord = coord.copy() - next_coord.push(RespoCoord::Comp(name)) + next_coord.push(Comp(name)) nested_effects_outside_in_as!( tree, next_coord, dom_path, effect_type, operations, ) @@ -519,7 +508,7 @@ fn nested_effects_outside_in_as[T]( for pair in children { let (k, child) = pair let next_coord = coord.copy() - next_coord.push(RespoCoord::Key(k)) + next_coord.push(Key(k)) nested_effects_outside_in_as!( child, next_coord, dom_path, effect_type, operations, ) @@ -544,13 +533,13 @@ fn nested_effects_inside_out_as[T]( Component(left) => { let { name, effects, tree } = left let next_coord = coord.copy() - next_coord.push(RespoCoord::Comp(name)) + next_coord.push(Comp(name)) nested_effects_inside_out_as!( tree, next_coord, dom_path, effect_type, operations, ) if not(effects.is_empty()) { operations.val.push( - ChildDomOp::NestedEffect( + NestedEffect( nested_coord=coord, nested_dom_path=dom_path, ~effect_type, @@ -564,7 +553,7 @@ fn nested_effects_inside_out_as[T]( for pair in children { let (k, child) = pair let next_coord = coord.copy() - next_coord.push(RespoCoord::Key(k)) + next_coord.push(Key(k)) nested_effects_inside_out_as!( child, next_coord, dom_path, effect_type, operations, ) diff --git a/src/lib/node/element.mbt b/src/lib/node/element.mbt index 641c8b1..a37c20b 100644 --- a/src/lib/node/element.mbt +++ b/src/lib/node/element.mbt @@ -22,7 +22,7 @@ pub struct RespoElement[T] { } pub fn RespoElement::to_node[T](self : RespoElement[T]) -> RespoNode[T] { - RespoNode::Element(self) + Element(self) } pub fn op_equal[T](self : RespoElement[T], other : RespoElement[T]) -> Bool { diff --git a/src/lib/node/node.mbt b/src/lib/node/node.mbt index 1ef08f3..029a814 100644 --- a/src/lib/node/node.mbt +++ b/src/lib/node/node.mbt @@ -44,7 +44,7 @@ pub fn load_coord_target_tree[T]( // @dom_ffi.log("looking for " + coord.to_string() + tree.to_string()) if coord.length() == 0 { match tree { - RespoNode::Referenced(cell) => cell + Referenced(cell) => cell _ => tree } } else { @@ -98,12 +98,12 @@ pub fn build_dom_tree[T]( let window = @dom_ffi.window() let document = window.document() match tree { - RespoNode::Component({ name, tree: child, .. }) => { + Component({ name, tree: child, .. }) => { let next_coord = coord.copy() - next_coord.push(RespoCoord::Comp(name)) + next_coord.push(Comp(name)) build_dom_tree!(child, next_coord, handle_event) } - RespoNode::Element({ name, attrs, style, event, children }) => { + Element({ name, attrs, style, event, children }) => { let element = document.create_element(name) let mut inner_set = false for pair in attrs { @@ -146,7 +146,7 @@ pub fn build_dom_tree[T]( for pair in children { let (k, child) = pair let next_coord = coord.copy() - next_coord.push(RespoCoord::Key(k)) + next_coord.push(Key(k)) element .reinterpret_as_node() .append_child(build_dom_tree!(child, next_coord, handle_event)) @@ -160,7 +160,7 @@ pub fn build_dom_tree[T]( } element.reinterpret_as_node() } - RespoNode::Referenced(cell) => build_dom_tree!(cell, coord, handle_event) + Referenced(cell) => build_dom_tree!(cell, coord, handle_event) } } diff --git a/src/lib/node/patch.mbt b/src/lib/node/patch.mbt index 538471d..d0b9933 100644 --- a/src/lib/node/patch.mbt +++ b/src/lib/node/patch.mbt @@ -18,19 +18,19 @@ pub fn patch_tree[T]( // handle BeforeUpdate before DOM changes for op in changes { match op { - DomChange::Effect(~coord, ~effect_type, ~skip_indexes, ..) => - if effect_type == RespoEffectType::BeforeUpdate { + Effect(~coord, ~effect_type, ~skip_indexes, ..) => + if effect_type == BeforeUpdate { let target = find_coord_dom_target!( mount_target.first_child(), op.get_dom_path(), ) - let target_tree = if effect_type == RespoEffectType::BeforeUnmount { + let target_tree = if effect_type == BeforeUnmount { load_coord_target_tree!(old_tree, coord[:]) } else { load_coord_target_tree!(tree, coord[:]) } match target_tree { - RespoNode::Component(left) => { + Component(left) => { let { effects, .. } = left for idx, effect in effects.iter2() { if not(skip_indexes.contains(idx)) { @@ -145,13 +145,13 @@ pub fn patch_tree[T]( match op { Append(k, node) => { let next_coord = coord.copy() - next_coord.push(RespoCoord::Key(k)) + next_coord.push(Key(k)) let new_element = build_dom_tree!(node, next_coord, handle_event) target.append_child(new_element) } Prepend(k, node) => { let next_coord = coord.copy() - next_coord.push(RespoCoord::Key(k)) + next_coord.push(Key(k)) let new_element = build_dom_tree!(node, next_coord, handle_event) if target.child_nodes().is_empty() { target.append_child(new_element) @@ -176,7 +176,7 @@ pub fn patch_tree[T]( } else { let handler = handle_event let next_coord = coord.copy() - next_coord.push(RespoCoord::Key(k)) + next_coord.push(Key(k)) let new_element = build_dom_tree!(node, next_coord, handler) match (idx + 1).compare(children.length().reinterpret_as_uint()) { @@ -201,14 +201,14 @@ pub fn patch_tree[T]( ~effect_type, ~skip_indexes ) => { - let target_tree = if effect_type == RespoEffectType::BeforeUnmount { + let target_tree = if effect_type == BeforeUnmount { load_coord_target_tree!(old_base_tree, nested_coord[:]) } else { load_coord_target_tree!(base_tree, nested_coord[:]) } let nested_el = find_coord_dom_target!(target, nesteed_dom_path) match target_tree { - RespoNode::Component({ effects, .. }) => + Component({ effects, .. }) => for idx, effect in effects { if not(skip_indexes.contains(idx)) { let f = effect.handler @@ -225,11 +225,11 @@ pub fn patch_tree[T]( } } Effect(~coord, ~effect_type, ~skip_indexes, ..) => { - if effect_type == RespoEffectType::BeforeUpdate { + if effect_type == BeforeUpdate { // should be handled before current pass continue } - let target_tree = if effect_type == RespoEffectType::BeforeUnmount { + let target_tree = if effect_type == BeforeUnmount { load_coord_target_tree!(old_tree, coord[:]) } else { load_coord_target_tree!(tree, coord[:]) diff --git a/src/lib/renderer.mbt b/src/lib/renderer.mbt index ecc63df..d885924 100644 --- a/src/lib/renderer.mbt +++ b/src/lib/renderer.mbt @@ -52,13 +52,7 @@ pub fn render_node[T, U]( // collection mounted effects let mount_changes : Ref[Array[@node.DomChange[T]]] = Ref::new([]) - @node.collect_effects_outside_in_as!( - tree0, - [], - [], - @node.RespoEffectType::Mounted, - mount_changes, - ) + @node.collect_effects_outside_in_as!(tree0, [], [], Mounted, mount_changes) mount_target.append_child(element) // util::log!("mounted changed: {:?}", mount_changes); @node.patch_tree!( @@ -96,11 +90,11 @@ fn request_for_target_handler[T]( ((@node.RespoEvent, @node.DispatchFn[T]) -> Unit!@node.RespoCommonError)!@node.RespoCommonError { let target_node = @node.load_coord_target_tree!(tree, coord[:]) match target_node { - @node.RespoNode::Component({ name, .. }) => + Component({ name, .. }) => raise @node.RespoCommonError( "expected element, found target being a component: " + name, ) - @node.RespoNode::Element({ name: tag_name, event, .. }) => + Element({ name: tag_name, event, .. }) => match event.get(event_name) { Some(v) => v None => @@ -108,7 +102,6 @@ fn request_for_target_handler[T]( "No event handler found for event '\{event_name}' on element '\{tag_name}', available events: TODO{event.keys()}", ) } - @node.RespoNode::Referenced(cell) => - request_for_target_handler!(cell, event_name, coord) + Referenced(cell) => request_for_target_handler!(cell, event_name, coord) } } diff --git a/src/main/counter.mbt b/src/main/counter.mbt index c135017..e83aaa1 100644 --- a/src/main/counter.mbt +++ b/src/main/counter.mbt @@ -19,7 +19,7 @@ fn comp_counter( Click(~original_event, ..) => original_event.prevent_default() _ => () } - dispatch.run!(ActionOp::Increment) + dispatch.run!(Increment) let next_state : MainState = { counted: state.counted + 1 } dispatch.run_state!(cursor, next_state.to_json()) } @@ -28,7 +28,7 @@ fn comp_counter( dispatch : @respo_node.DispatchFn[ActionOp] ) -> Unit!@respo_node.RespoCommonError { @dom_ffi.warn_log("dec click: " + e.to_string()) - dispatch.run!(ActionOp::Decrement) + dispatch.run!(Decrement) let next_state : MainState = { counted: state.counted - 1 } dispatch.run_state!(cursor, next_state.to_json()) } @@ -37,7 +37,7 @@ fn comp_counter( dispatch : @respo_node.DispatchFn[ActionOp] ) -> Unit!@respo_node.RespoCommonError { @dom_ffi.warn_log("twice click: " + e.to_string()) - dispatch.run!(ActionOp::IncTwice) + dispatch.run!(IncTwice) let next_state : MainState = { counted: state.counted + 2 } dispatch.run_state!(cursor, next_state.to_json()) } diff --git a/src/main/panel.mbt b/src/main/panel.mbt index 5417842..3535dad 100644 --- a/src/main/panel.mbt +++ b/src/main/panel.mbt @@ -33,9 +33,7 @@ fn comp_panel( match e { @respo_node.RespoEvent::Input(~value, ..) => dispatch.run!( - ActionOp::StatesChange( - { cursor, data: Some({ content: value }.to_json()) }, - ), + StatesChange({ cursor, data: Some({ content: value }.to_json()) }), ) _ => () } @@ -45,9 +43,9 @@ fn comp_panel( dispatch : @respo_node.DispatchFn[ActionOp] ) -> Unit!@respo_node.RespoCommonError { @dom_ffi.log("add button: " + e.to_string()) - dispatch.run!(ActionOp::AddTask(@dom_ffi.random_id(), state.content)) + dispatch.run!(AddTask(@dom_ffi.random_id(), state.content)) dispatch.run!( - ActionOp::StatesChange({ cursor, data: Some({ content: "" }.to_json()) }), + StatesChange({ cursor, data: Some({ content: "" }.to_json()) }), ) } diff --git a/src/main/task.mbt b/src/main/task.mbt index 891a388..07203f7 100644 --- a/src/main/task.mbt +++ b/src/main/task.mbt @@ -40,9 +40,7 @@ fn comp_task( match e { Input(~value, ..) => dispatch.run!( - ActionOp::StatesChange( - { cursor, data: Some({ draft: value }.to_json()) }, - ), + StatesChange({ cursor, data: Some({ draft: value }.to_json()) }), ) _ => () } @@ -53,15 +51,15 @@ fn comp_task( dispatch : @respo_node.DispatchFn[ActionOp] ) -> Unit!@respo_node.RespoCommonError { @dom_ffi.log("remove button {}" + e.to_string()) - dispatch.run!(ActionOp::RemoveTask(tid)) + dispatch.run!(RemoveTask(tid)) } let on_update = fn( _e : @respo_node.RespoEvent, dispatch : @respo_node.DispatchFn[ActionOp] ) -> Unit!@respo_node.RespoCommonError { - dispatch.run!(ActionOp::UpdateTask(tid, state.draft)) + dispatch.run!(UpdateTask(tid, state.draft)) // dispatch.run_empty_state(&cursor)?; - dispatch.run!(ActionOp::StatesChange({ cursor, data: None })) + dispatch.run!(StatesChange({ cursor, data: None })) } // define effect