Current section
Files
Jump to
Current section
Files
src/dnd.erl
-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}.