-module(dnd). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/dnd.gleam"). -export([split_at/2, after_backward/3, after_forward/3, insert_after/3, before_backward/3, rotate_items/3, before_forward/3, insert_before/3, swap_at/3, swap_items/3, get_info/1, is_touch_selecting/1, get_selected_index/1, touch_selected_styles/2, create/2]). -export_type([position/0, movement/0, input_mode/0, listen/0, operation/0, config/1, state/0, touch_state/0, touch_pending_state/0, interaction_state/0, model/0, info/0, system/2, dnd_msg/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. -type position() :: {position, float(), float()}. -type movement() :: free | horizontal | vertical. -type input_mode() :: mouse_only | touch_only | auto. -type listen() :: on_drag | on_drop. -type operation() :: insert_after | insert_before | rotate | swap | unaltered. -type config(MXO) :: {config, fun((integer(), integer(), list(MXO)) -> list(MXO)), movement(), listen(), operation(), input_mode(), integer(), integer(), integer(), integer()}. -type state() :: {state, integer(), integer(), integer(), position(), position(), binary(), binary()}. -type touch_state() :: {touch_state, integer(), binary(), gleam@option:option(position()), boolean(), gleam@option:option(position())}. -type touch_pending_state() :: {touch_pending_state, integer(), binary(), position(), boolean()}. -type interaction_state() :: idle | {mouse_dragging, state()} | {touch_pending, touch_pending_state()} | {touch_selecting, touch_state()}. -type model() :: {model, interaction_state(), integer(), boolean()}. -type info() :: {info, integer(), integer(), binary(), binary(), position(), position()}. -type system(MXP, MXQ) :: {system, model(), fun((dnd_msg(), model(), list(MXP)) -> {model(), list(MXP)}), fun((integer(), binary()) -> list(lustre@vdom@vattr:attribute(MXQ))), fun((integer(), binary()) -> list(lustre@vdom@vattr:attribute(MXQ))), fun((model()) -> list(lustre@vdom@vattr:attribute(MXQ))), fun((model()) -> gleam@option:option(info())), fun((dnd_msg(), model(), list(MXP)) -> {model(), list(MXP), lustre@effect:effect(MXQ)}), fun((integer(), binary()) -> list(lustre@vdom@vattr:attribute(MXQ))), fun((integer()) -> list(lustre@vdom@vattr:attribute(MXQ))), fun(() -> list(lustre@vdom@vattr:attribute(MXQ))), fun((model()) -> boolean()), fun((model()) -> gleam@option:option(integer())), fun((model(), integer()) -> list(lustre@vdom@vattr:attribute(MXQ)))}. -type dnd_msg() :: {drag_start, integer(), binary(), position()} | {drag, position()} | {drag_over, integer(), binary()} | {drag_enter, integer()} | drag_leave | drag_end | {touch_start, integer(), binary(), position()} | {touch_move, position()} | {touch_end, position()} | {touch_select, integer(), binary()} | {touch_drop_start, position()} | {touch_drop, integer(), position()} | touch_cancel | {touch_timeout, integer()} | {touch_duration_met, integer()} | {touch_drop_cooldown_complete, integer()}. -file("src/dnd.gleam", 915). -spec schedule_hold_duration(integer(), integer(), fun((dnd_msg()) -> MYG)) -> lustre@effect:effect(MYG). schedule_hold_duration(Duration_ms, Generation, Step_msg) -> lustre@effect:from( fun(Dispatch) -> timer_ffi:set_timeout( Duration_ms, fun() -> Dispatch(Step_msg({touch_duration_met, Generation})) end ) end ). -file("src/dnd.gleam", 927). -spec schedule_drop_cooldown(integer(), integer(), fun((dnd_msg()) -> MYI)) -> lustre@effect:effect(MYI). schedule_drop_cooldown(Cooldown_ms, Generation, Step_msg) -> lustre@effect:from( fun(Dispatch) -> timer_ffi:set_timeout( Cooldown_ms, fun() -> Dispatch( Step_msg({touch_drop_cooldown_complete, Generation}) ) end ) end ). -file("src/dnd.gleam", 939). -spec schedule_timeout(integer(), integer(), fun((dnd_msg()) -> MYK)) -> lustre@effect:effect(MYK). schedule_timeout(Timeout_ms, Generation, Step_msg) -> lustre@effect:from( fun(Dispatch) -> timer_ffi:set_timeout( Timeout_ms, fun() -> Dispatch(Step_msg({touch_timeout, Generation})) end ) end ). -file("src/dnd.gleam", 953). -spec update_state_for_operation(operation(), integer(), state()) -> state(). update_state_for_operation(Operation, Drop_index, State) -> case Operation of insert_after -> New_drag_index = case Drop_index < erlang:element(2, State) of true -> Drop_index + 1; false -> Drop_index end, {state, New_drag_index, erlang:element(3, State), 0, erlang:element(5, State), erlang:element(6, State), erlang:element(7, State), erlang:element(8, State)}; insert_before -> New_drag_index@1 = case erlang:element(2, State) < Drop_index of true -> Drop_index - 1; false -> Drop_index end, {state, New_drag_index@1, erlang:element(3, State), 0, erlang:element(5, State), erlang:element(6, State), erlang:element(7, State), erlang:element(8, State)}; rotate -> {state, Drop_index, erlang:element(3, State), 0, erlang:element(5, State), erlang:element(6, State), erlang:element(7, State), erlang:element(8, State)}; swap -> {state, Drop_index, erlang:element(3, State), 0, erlang:element(5, State), erlang:element(6, State), erlang:element(7, State), erlang:element(8, State)}; unaltered -> {state, erlang:element(2, State), erlang:element(3, State), 0, erlang:element(5, State), erlang:element(6, State), erlang:element(7, State), erlang:element(8, State)} end. -file("src/dnd.gleam", 995). -spec split_at(integer(), list(MYP)) -> {list(MYP), list(MYP)}. split_at(Index, List) -> {gleam@list:take(List, Index), gleam@list:drop(List, Index)}. -file("src/dnd.gleam", 1044). -spec after_backward(integer(), integer(), list(MZF)) -> list(MZF). after_backward(I, J, List) -> {Beginning, Rest} = split_at(J + 1, List), {Middle, End} = split_at((I - J) - 1, Rest), {Head, Tail} = split_at(1, End), lists:append(lists:append(lists:append(Beginning, Head), Middle), Tail). -file("src/dnd.gleam", 1052). -spec after_forward(integer(), integer(), list(MZI)) -> list(MZI). after_forward(I, J, List) -> {Beginning, Rest} = split_at(I, List), {Middle, End} = split_at((J - I) + 1, Rest), {Head, Tail} = split_at(1, Middle), lists:append(lists:append(lists:append(Beginning, Tail), Head), End). -file("src/dnd.gleam", 1000). -spec insert_after(integer(), integer(), list(MYT)) -> list(MYT). insert_after(Drag_index, Drop_index, List) -> case Drag_index < Drop_index of true -> after_forward(Drag_index, Drop_index, List); false -> case Drop_index < Drag_index of true -> after_backward(Drag_index, Drop_index, List); false -> List end end. -file("src/dnd.gleam", 1060). -spec before_backward(integer(), integer(), list(MZL)) -> list(MZL). before_backward(I, J, List) -> {Beginning, Rest} = split_at(J, List), {Middle, End} = split_at(I - J, Rest), {Head, Tail} = split_at(1, End), lists:append(lists:append(lists:append(Beginning, Head), Middle), Tail). -file("src/dnd.gleam", 1024). -spec rotate_items(integer(), integer(), list(MYZ)) -> list(MYZ). rotate_items(Drag_index, Drop_index, List) -> case Drag_index < Drop_index of true -> after_forward(Drag_index, Drop_index, List); false -> case Drop_index < Drag_index of true -> before_backward(Drag_index, Drop_index, List); false -> List end end. -file("src/dnd.gleam", 1068). -spec before_forward(integer(), integer(), list(MZO)) -> list(MZO). before_forward(I, J, List) -> {Beginning, Rest} = split_at(I, List), {Middle, End} = split_at(J - I, Rest), {Head, Tail} = split_at(1, Middle), lists:append(lists:append(lists:append(Beginning, Tail), Head), End). -file("src/dnd.gleam", 1012). -spec insert_before(integer(), integer(), list(MYW)) -> list(MYW). insert_before(Drag_index, Drop_index, List) -> case Drag_index < Drop_index of true -> before_forward(Drag_index, Drop_index, List); false -> case Drop_index < Drag_index of true -> before_backward(Drag_index, Drop_index, List); false -> List end end. -file("src/dnd.gleam", 1076). -spec swap_at(integer(), integer(), list(MZR)) -> list(MZR). swap_at(I, J, List) -> Item_i = begin _pipe = gleam@list:drop(List, I), gleam@list:take(_pipe, 1) end, Item_j = begin _pipe@1 = gleam@list:drop(List, J), gleam@list:take(_pipe@1, 1) end, _pipe@2 = gleam@list:index_map(List, fun(Item, Index) -> case Index of Idx when Idx =:= I -> Item_j; Idx@1 when Idx@1 =:= J -> Item_i; _ -> [Item] end end), lists:append(_pipe@2). -file("src/dnd.gleam", 1036). -spec swap_items(integer(), integer(), list(MZC)) -> list(MZC). swap_items(Drag_index, Drop_index, List) -> case Drag_index /= Drop_index of true -> swap_at(Drag_index, Drop_index, List); false -> List end. -file("src/dnd.gleam", 979). -spec update_list_for_operation(operation(), integer(), integer(), list(MYM)) -> list(MYM). update_list_for_operation(Operation, Drag_index, Drop_index, List) -> case Operation of insert_after -> insert_after(Drag_index, Drop_index, List); insert_before -> insert_before(Drag_index, Drop_index, List); rotate -> rotate_items(Drag_index, Drop_index, List); swap -> swap_items(Drag_index, Drop_index, List); unaltered -> List end. -file("src/dnd.gleam", 1092). -spec drag_events(fun((dnd_msg()) -> MZU)) -> fun((integer(), binary()) -> list(lustre@vdom@vattr:attribute(MZU))). drag_events(Step_msg) -> fun(Drag_index, Drag_element_id) -> [lustre@event:on( <<"mousedown"/utf8>>, begin gleam@dynamic@decode:field( <<"clientX"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_float/1}, fun(Client_x) -> gleam@dynamic@decode:field( <<"clientY"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_float/1}, fun(Client_y) -> gleam@dynamic@decode:success( Step_msg( {drag_start, Drag_index, Drag_element_id, {position, Client_x, Client_y}} ) ) end ) end ) end )] end. -file("src/dnd.gleam", 1112). -spec drop_events(fun((dnd_msg()) -> MZX)) -> fun((integer(), binary()) -> list(lustre@vdom@vattr:attribute(MZX))). drop_events(Step_msg) -> fun(Drop_index, Drop_element_id) -> [lustre@event:on( <<"mouseover"/utf8>>, gleam@dynamic@decode:success( Step_msg({drag_over, Drop_index, Drop_element_id}) ) ), lustre@event:on( <<"mouseenter"/utf8>>, gleam@dynamic@decode:success(Step_msg({drag_enter, Drop_index})) ), lustre@event:on( <<"mouseleave"/utf8>>, gleam@dynamic@decode:success(Step_msg(drag_leave)) )] end. -file("src/dnd.gleam", 1131). ?DOC( " Decoder for touch position from touch events.\n" " Extracts clientX/clientY from the first touch in changedTouches.\n" ). -spec decode_touch_position() -> gleam@dynamic@decode:decoder(position()). decode_touch_position() -> gleam@dynamic@decode:subfield( [<<"changedTouches"/utf8>>, <<"0"/utf8>>, <<"clientX"/utf8>>], {decoder, fun gleam@dynamic@decode:decode_float/1}, fun(X) -> gleam@dynamic@decode:subfield( [<<"changedTouches"/utf8>>, <<"0"/utf8>>, <<"clientY"/utf8>>], {decoder, fun gleam@dynamic@decode:decode_float/1}, fun(Y) -> gleam@dynamic@decode:success({position, X, Y}) end ) end ). -file("src/dnd.gleam", 1140). ?DOC( " Touch grip events - touchstart captures position, touchmove tracks movement,\n" " touchend validates tap vs scroll. Apply to the grip handle or the entire draggable item.\n" " Uses preventDefault on touchstart to stop browser from synthesizing mouse events.\n" ). -spec touch_grip_events(fun((dnd_msg()) -> NAB)) -> fun((integer(), binary()) -> list(lustre@vdom@vattr:attribute(NAB))). touch_grip_events(Step_msg) -> fun(Index, Element_id) -> [lustre@event:on( <<"touchstart"/utf8>>, begin gleam@dynamic@decode:then( decode_touch_position(), fun(Position) -> gleam@dynamic@decode:success( Step_msg( {touch_start, Index, Element_id, Position} ) ) end ) end ), lustre@event:on( <<"touchmove"/utf8>>, begin gleam@dynamic@decode:then( decode_touch_position(), fun(Position@1) -> gleam@dynamic@decode:success( Step_msg({touch_move, Position@1}) ) end ) end ), lustre@event:on( <<"touchend"/utf8>>, begin gleam@dynamic@decode:then( decode_touch_position(), fun(Position@2) -> gleam@dynamic@decode:success( Step_msg({touch_end, Position@2}) ) end ) end ), lustre@event:on( <<"touchcancel"/utf8>>, gleam@dynamic@decode:success(Step_msg(touch_cancel)) )] end. -file("src/dnd.gleam", 1170). ?DOC( " Touch drop zone events - touchstart records position, touchend validates distance.\n" " Apply to drop zone elements rendered between items.\n" ). -spec touch_drop_zone_events(fun((dnd_msg()) -> NAE)) -> fun((integer()) -> list(lustre@vdom@vattr:attribute(NAE))). touch_drop_zone_events(Step_msg) -> fun(Drop_index) -> [lustre@event:on( <<"touchstart"/utf8>>, begin gleam@dynamic@decode:then( decode_touch_position(), fun(Position) -> gleam@dynamic@decode:success( Step_msg({touch_drop_start, Position}) ) end ) end ), lustre@event:on( <<"touchend"/utf8>>, begin gleam@dynamic@decode:then( decode_touch_position(), fun(Position@1) -> gleam@dynamic@decode:success( Step_msg({touch_drop, Drop_index, Position@1}) ) end ) end )] end. -file("src/dnd.gleam", 1195). ?DOC( " Cancel events - currently returns empty list.\n" " Browser-initiated cancellation is handled by the `touchcancel` listener in\n" " `touch_grip_events`; `touch_timeout_ms` remains a backstop. This hook is for\n" " an optional explicit cancel affordance (e.g. a button) that sends TouchCancel.\n" " Note: container-level touchstart/touchend would interfere with grip/drop\n" " events due to event bubbling, so this stays empty by default.\n" ). -spec cancel_events(fun((dnd_msg()) -> NAH)) -> fun(() -> list(lustre@vdom@vattr:attribute(NAH))). cancel_events(_) -> fun() -> [] end. -file("src/dnd.gleam", 1201). -spec ghost_styles(movement()) -> fun((model()) -> list(lustre@vdom@vattr:attribute(any()))). ghost_styles(Movement) -> fun(Model) -> case erlang:element(2, Model) of {mouse_dragging, State} -> Essential_styles = [lustre@attribute:style( <<"position"/utf8>>, <<"fixed"/utf8>> ), lustre@attribute:style( <<"pointer-events"/utf8>>, <<"none"/utf8>> ), lustre@attribute:style(<<"z-index"/utf8>>, <<"1000"/utf8>>), lustre@attribute:style( <<"user-select"/utf8>>, <<"none"/utf8>> ), lustre@attribute:style( <<"-webkit-user-select"/utf8>>, <<"none"/utf8>> )], Position_styles = case Movement of free -> [lustre@attribute:style( <<"left"/utf8>>, <<(gleam_stdlib:float_to_string( erlang:element( 2, erlang:element(6, State) ) ))/binary, "px"/utf8>> ), lustre@attribute:style( <<"top"/utf8>>, <<(gleam_stdlib:float_to_string( erlang:element( 3, erlang:element(6, State) ) ))/binary, "px"/utf8>> )]; horizontal -> [lustre@attribute:style( <<"left"/utf8>>, <<(gleam_stdlib:float_to_string( erlang:element( 2, erlang:element(6, State) ) ))/binary, "px"/utf8>> ), lustre@attribute:style( <<"top"/utf8>>, <<(gleam_stdlib:float_to_string( erlang:element( 3, erlang:element(5, State) ) ))/binary, "px"/utf8>> )]; vertical -> [lustre@attribute:style( <<"left"/utf8>>, <<(gleam_stdlib:float_to_string( erlang:element( 2, erlang:element(5, State) ) ))/binary, "px"/utf8>> ), lustre@attribute:style( <<"top"/utf8>>, <<(gleam_stdlib:float_to_string( erlang:element( 3, erlang:element(6, State) ) ))/binary, "px"/utf8>> )] end, lists:append(Essential_styles, Position_styles); {touch_pending, _} -> []; {touch_selecting, _} -> []; idle -> [] end end. -file("src/dnd.gleam", 1259). -spec get_info(model()) -> gleam@option:option(info()). get_info(Model) -> case erlang:element(2, Model) of {mouse_dragging, State} -> {some, {info, erlang:element(2, State), erlang:element(3, State), erlang:element(7, State), erlang:element(8, State), erlang:element(5, State), erlang:element(6, State)}}; {touch_pending, _} -> none; {touch_selecting, _} -> none; idle -> none end. -file("src/dnd.gleam", 1280). ?DOC(" Check if the system is currently in touch selection mode.\n"). -spec is_touch_selecting(model()) -> boolean(). is_touch_selecting(Model) -> case erlang:element(2, Model) of {touch_selecting, _} -> true; _ -> false end. -file("src/dnd.gleam", 1289). ?DOC( " Get the index of the currently selected item in touch mode.\n" " Returns None if not in touch selection mode.\n" ). -spec get_selected_index(model()) -> gleam@option:option(integer()). get_selected_index(Model) -> case erlang:element(2, Model) of {touch_selecting, Touch_state} -> {some, erlang:element(2, Touch_state)}; _ -> none end. -file("src/dnd.gleam", 1306). ?DOC( " Returns pop animation styles for the selected item in touch mode.\n" " Apply these styles to the item element at the given index.\n" " Returns empty list if the index doesn't match the selected item.\n" "\n" " The animation uses CSS keyframes which must be defined in your stylesheet:\n" " ```css\n" " @keyframes dnd-pop {\n" " 50% { transform: scale(1.2); }\n" " }\n" " ```\n" ). -spec touch_selected_styles(model(), integer()) -> list(lustre@vdom@vattr:attribute(any())). touch_selected_styles(Model, Index) -> case erlang:element(2, Model) of {touch_selecting, Touch_state} when erlang:element(2, Touch_state) =:= Index -> [lustre@attribute:style( <<"animation"/utf8>>, <<"dnd-pop 0.2s ease-out"/utf8>> )]; _ -> [] end. -file("src/dnd.gleam", 1318). ?DOC(" Calculate the distance between two positions.\n"). -spec distance(position(), position()) -> float(). distance(P1, P2) -> Dx = erlang:element(2, P2) - erlang:element(2, P1), Dy = erlang:element(3, P2) - erlang:element(3, P1), _pipe = gleam@float:square_root((Dx * Dx) + (Dy * Dy)), gleam@result:unwrap(_pipe, +0.0). -file("src/dnd.gleam", 1326). ?DOC(" Check if the distance between two positions is within a threshold.\n"). -spec is_within_threshold(position(), position(), integer()) -> boolean(). is_within_threshold(P1, P2, Threshold) -> distance(P1, P2) < erlang:float(Threshold). -file("src/dnd.gleam", 382). -spec system_update(config(MXW)) -> fun((dnd_msg(), model(), list(MXW)) -> {model(), list(MXW)}). system_update(Config) -> fun(Msg, Model, List) -> case {Msg, erlang:element(2, Model)} of {{drag_start, _, _, _}, idle} when erlang:element(4, Model) -> {{model, erlang:element(2, Model), erlang:element(3, Model), false}, List}; {{drag_start, Drag_index, Drag_element_id, Position}, idle} -> New_state = {state, Drag_index, Drag_index, 0, Position, Position, Drag_element_id, Drag_element_id}, {{model, {mouse_dragging, New_state}, erlang:element(3, Model), erlang:element(4, Model)}, List}; {{drag, Position@1}, {mouse_dragging, State}} -> Updated_state = {state, erlang:element(2, State), erlang:element(3, State), erlang:element(4, State) + 1, erlang:element(5, State), Position@1, erlang:element(7, State), erlang:element(8, State)}, {{model, {mouse_dragging, Updated_state}, erlang:element(3, Model), erlang:element(4, Model)}, List}; {{drag_over, Drop_index, Drop_element_id}, {mouse_dragging, State@1}} -> Updated_state@1 = {state, erlang:element(2, State@1), Drop_index, erlang:element(4, State@1), erlang:element(5, State@1), erlang:element(6, State@1), erlang:element(7, State@1), Drop_element_id}, {{model, {mouse_dragging, Updated_state@1}, erlang:element(3, Model), erlang:element(4, Model)}, List}; {{drag_enter, Drop_index@1}, {mouse_dragging, State@2}} -> case erlang:element(4, Config) of on_drag -> case (erlang:element(4, State@2) > 1) andalso (erlang:element( 2, State@2 ) /= Drop_index@1) of true -> Updated_state@2 = update_state_for_operation( erlang:element(5, Config), Drop_index@1, State@2 ), Updated_list = update_list_for_operation( erlang:element(5, Config), erlang:element(2, State@2), Drop_index@1, List ), {{model, {mouse_dragging, Updated_state@2}, erlang:element(3, Model), erlang:element(4, Model)}, (erlang:element(2, Config))( erlang:element(2, State@2), Drop_index@1, Updated_list )}; false -> {Model, List} end; on_drop -> Updated_state@3 = {state, erlang:element(2, State@2), erlang:element(3, State@2), 0, erlang:element(5, State@2), erlang:element(6, State@2), erlang:element(7, State@2), erlang:element(8, State@2)}, {{model, {mouse_dragging, Updated_state@3}, erlang:element(3, Model), erlang:element(4, Model)}, List} end; {drag_leave, {mouse_dragging, State@3}} -> Updated_state@4 = {state, erlang:element(2, State@3), erlang:element(2, State@3), erlang:element(4, State@3), erlang:element(5, State@3), erlang:element(6, State@3), erlang:element(7, State@3), erlang:element(8, State@3)}, {{model, {mouse_dragging, Updated_state@4}, erlang:element(3, Model), erlang:element(4, Model)}, List}; {drag_end, {mouse_dragging, State@4}} -> case erlang:element(4, Config) of on_drop -> case erlang:element(2, State@4) /= erlang:element( 3, State@4 ) of true -> Updated_list@1 = update_list_for_operation( erlang:element(5, Config), erlang:element(2, State@4), erlang:element(3, State@4), List ), {{model, idle, erlang:element(3, Model), erlang:element(4, Model)}, (erlang:element(2, Config))( erlang:element(2, State@4), erlang:element(3, State@4), Updated_list@1 )}; false -> {{model, idle, erlang:element(3, Model), erlang:element(4, Model)}, List} end; on_drag -> {{model, idle, erlang:element(3, Model), erlang:element(4, Model)}, List} end; {{touch_start, _, _, _}, {touch_pending, _}} -> {{model, idle, erlang:element(3, Model), erlang:element(4, Model)}, List}; {{touch_start, Index, Id, Position@2}, idle} -> Duration_met = erlang:element(9, Config) =:= 0, Pending_state = {touch_pending_state, Index, Id, Position@2, Duration_met}, New_gen = erlang:element(3, Model) + 1, {{model, {touch_pending, Pending_state}, New_gen, true}, List}; {{touch_move, Position@3}, {touch_pending, Pending}} -> case is_within_threshold( erlang:element(4, Pending), Position@3, erlang:element(8, Config) ) of true -> {Model, List}; false -> {{model, idle, erlang:element(3, Model), erlang:element(4, Model)}, List} end; {{touch_duration_met, Gen}, {touch_pending, Pending@1}} when Gen =:= erlang:element( 3, Model ) -> Touch_state = {touch_state, erlang:element(2, Pending@1), erlang:element(3, Pending@1), none, false, none}, New_gen@1 = erlang:element(3, Model) + 1, {{model, {touch_selecting, Touch_state}, New_gen@1, erlang:element(4, Model)}, List}; {{touch_duration_met, _}, _} -> {Model, List}; {{touch_drop_cooldown_complete, Gen@1}, {touch_selecting, Touch_state@1}} when Gen@1 =:= erlang:element( 3, Model ) -> Updated_touch_state = {touch_state, erlang:element(2, Touch_state@1), erlang:element(3, Touch_state@1), erlang:element(4, Touch_state@1), true, erlang:element(6, Touch_state@1)}, {{model, {touch_selecting, Updated_touch_state}, erlang:element(3, Model), erlang:element(4, Model)}, List}; {{touch_drop_cooldown_complete, _}, _} -> {Model, List}; {{touch_end, End_position}, {touch_pending, Pending@2}} -> case erlang:element(5, Pending@2) of true -> Within_distance = is_within_threshold( erlang:element(4, Pending@2), End_position, erlang:element(8, Config) ), case Within_distance of true -> Touch_state@2 = {touch_state, erlang:element(2, Pending@2), erlang:element(3, Pending@2), none, true, none}, New_gen@2 = erlang:element(3, Model) + 1, {{model, {touch_selecting, Touch_state@2}, New_gen@2, erlang:element(4, Model)}, List}; false -> {{model, idle, erlang:element(3, Model), erlang:element(4, Model)}, List} end; false -> {{model, idle, erlang:element(3, Model), erlang:element(4, Model)}, List} end; {{touch_start, _, _, Position@4}, {touch_selecting, Touch_state@3}} -> Updated_touch_state@1 = {touch_state, erlang:element(2, Touch_state@3), erlang:element(3, Touch_state@3), {some, Position@4}, erlang:element(5, Touch_state@3), erlang:element(6, Touch_state@3)}, {{model, {touch_selecting, Updated_touch_state@1}, erlang:element(3, Model), erlang:element(4, Model)}, List}; {{touch_end, End_position@1}, {touch_selecting, Touch_state@4}} -> case erlang:element(4, Touch_state@4) of {some, Start_pos} -> case is_within_threshold( Start_pos, End_position@1, erlang:element(8, Config) ) of true -> Updated_touch_state@2 = {touch_state, erlang:element(2, Touch_state@4), erlang:element(3, Touch_state@4), none, erlang:element(5, Touch_state@4), erlang:element(6, Touch_state@4)}, {{model, {touch_selecting, Updated_touch_state@2}, erlang:element(3, Model), erlang:element(4, Model)}, List}; false -> Updated_touch_state@3 = {touch_state, erlang:element(2, Touch_state@4), erlang:element(3, Touch_state@4), none, erlang:element(5, Touch_state@4), erlang:element(6, Touch_state@4)}, New_gen@3 = erlang:element(3, Model) + 1, {{model, {touch_selecting, Updated_touch_state@3}, New_gen@3, erlang:element(4, Model)}, List} end; none -> {Model, List} end; {{touch_select, Index@1, Id@1}, idle} -> Touch_state@5 = {touch_state, Index@1, Id@1, none, true, none}, New_gen@4 = erlang:element(3, Model) + 1, {{model, {touch_selecting, Touch_state@5}, New_gen@4, erlang:element(4, Model)}, List}; {{touch_drop_start, Position@5}, {touch_selecting, Touch_state@6}} -> Updated_touch_state@4 = {touch_state, erlang:element(2, Touch_state@6), erlang:element(3, Touch_state@6), erlang:element(4, Touch_state@6), erlang:element(5, Touch_state@6), {some, Position@5}}, {{model, {touch_selecting, Updated_touch_state@4}, erlang:element(3, Model), erlang:element(4, Model)}, List}; {{touch_drop_start, _}, _} -> {Model, List}; {{touch_drop, Drop_index@2, End_position@2}, {touch_selecting, Touch_state@7}} -> case {erlang:element(5, Touch_state@7), erlang:element(6, Touch_state@7)} of {false, _} -> {Model, List}; {true, none} -> {Model, List}; {true, {some, Start_position}} -> Within_distance@1 = is_within_threshold( Start_position, End_position@2, erlang:element(8, Config) ), case Within_distance@1 of false -> Updated_touch_state@5 = {touch_state, erlang:element(2, Touch_state@7), erlang:element(3, Touch_state@7), erlang:element(4, Touch_state@7), erlang:element(5, Touch_state@7), none}, {{model, {touch_selecting, Updated_touch_state@5}, erlang:element(3, Model), erlang:element(4, Model)}, List}; true -> case erlang:element(2, Touch_state@7) /= Drop_index@2 of true -> Updated_list@2 = update_list_for_operation( erlang:element(5, Config), erlang:element(2, Touch_state@7), Drop_index@2, List ), {{model, idle, erlang:element(3, Model), erlang:element(4, Model)}, (erlang:element(2, Config))( erlang:element(2, Touch_state@7), Drop_index@2, Updated_list@2 )}; false -> {{model, idle, erlang:element(3, Model), erlang:element(4, Model)}, List} end end end; {touch_cancel, {touch_pending, _}} -> {{model, idle, erlang:element(3, Model), erlang:element(4, Model)}, List}; {touch_cancel, {touch_selecting, _}} -> {{model, idle, erlang:element(3, Model), erlang:element(4, Model)}, List}; {{touch_timeout, Gen@2}, {touch_selecting, _}} when Gen@2 =:= erlang:element( 3, Model ) -> {{model, idle, erlang:element(3, Model), erlang:element(4, Model)}, List}; {{touch_timeout, _}, _} -> {Model, List}; {{touch_start, _, _, _}, {mouse_dragging, _}} -> {{model, idle, erlang:element(3, Model), erlang:element(4, Model)}, List}; {{touch_move, _}, {mouse_dragging, _}} -> {{model, idle, erlang:element(3, Model), erlang:element(4, Model)}, List}; {{touch_end, _}, {mouse_dragging, _}} -> {{model, idle, erlang:element(3, Model), erlang:element(4, Model)}, List}; {{touch_select, _, _}, {mouse_dragging, _}} -> {{model, idle, erlang:element(3, Model), erlang:element(4, Model)}, List}; {{touch_drop, _, _}, {mouse_dragging, _}} -> {{model, idle, erlang:element(3, Model), erlang:element(4, Model)}, List}; {touch_cancel, {mouse_dragging, _}} -> {{model, idle, erlang:element(3, Model), erlang:element(4, Model)}, List}; {{drag_start, _, _, _}, {touch_pending, _}} -> {Model, List}; {{drag, _}, {touch_pending, _}} -> {Model, List}; {{drag_over, _, _}, {touch_pending, _}} -> {Model, List}; {{drag_enter, _}, {touch_pending, _}} -> {Model, List}; {drag_leave, {touch_pending, _}} -> {Model, List}; {drag_end, {touch_pending, _}} -> {Model, List}; {{drag_start, _, _, _}, {touch_selecting, _}} -> {Model, List}; {{drag, _}, {touch_selecting, _}} -> {Model, List}; {{drag_over, _, _}, {touch_selecting, _}} -> {Model, List}; {{drag_enter, _}, {touch_selecting, _}} -> {Model, List}; {drag_leave, {touch_selecting, _}} -> {Model, List}; {drag_end, {touch_selecting, _}} -> {Model, List}; {_, _} -> {Model, List} end end. -file("src/dnd.gleam", 854). -spec system_update_with_effect(config(MYA), fun((dnd_msg()) -> MYC)) -> fun((dnd_msg(), model(), list(MYA)) -> {model(), list(MYA), lustre@effect:effect(MYC)}). system_update_with_effect(Config, Step_msg) -> Base_update = system_update(Config), fun(Msg, Model, List) -> {New_model, New_list} = Base_update(Msg, Model, List), Generation_changed = erlang:element(3, New_model) /= erlang:element( 3, Model ), Hold_effect = case {erlang:element(2, New_model), Generation_changed} of {{touch_pending, _}, true} when erlang:element(9, Config) > 0 -> schedule_hold_duration( erlang:element(9, Config), erlang:element(3, New_model), Step_msg ); {_, _} -> lustre@effect:none() end, Timeout_effect = case {erlang:element(2, New_model), Generation_changed} of {{touch_selecting, _}, true} when erlang:element(7, Config) > 0 -> schedule_timeout( erlang:element(7, Config), erlang:element(3, New_model), Step_msg ); {_, _} -> lustre@effect:none() end, Cooldown_effect = case {erlang:element(2, New_model), Generation_changed} of {{touch_selecting, Touch_state}, true} when not erlang:element( 5, Touch_state ) andalso (erlang:element(10, Config) > 0) -> schedule_drop_cooldown( erlang:element(10, Config), erlang:element(3, New_model), Step_msg ); {_, _} -> lustre@effect:none() end, {New_model, New_list, lustre@effect:batch([Hold_effect, Timeout_effect, Cooldown_effect])} end. -file("src/dnd.gleam", 361). -spec create(config(MXR), fun((dnd_msg()) -> MXT)) -> system(MXR, MXT). create(Config, Step_msg) -> {system, {model, idle, 0, false}, system_update(Config), drag_events(Step_msg), drop_events(Step_msg), ghost_styles(erlang:element(3, Config)), fun get_info/1, system_update_with_effect(Config, Step_msg), touch_grip_events(Step_msg), touch_drop_zone_events(Step_msg), cancel_events(Step_msg), fun is_touch_selecting/1, fun get_selected_index/1, fun touch_selected_styles/2}.