Hello core team,
There are use-cases in which we need to react on a transition ending (or starting if with a delay) even when not part of JS.show
or JS.hide
.
One such example is transitioning the element’s max-height
or max-width
when mounted/removed to visually smoothly attach the preceding elements with the succeeding ones (filling the gap). Since when removing the element, its starting max-height
must be set to a specific value (cannot be 100% or max-h-full
for otherwise the transition won’t work), we need to be able to fetch the element’s offsetHeight
only when the phx-mounted
transition has finished (because it’s start value when mounted must be 0 because of the on-mount transition).
In order to send the events only when really needed, they can be made optional e.g.:
class="invisible max-h-0"
phx-mounted={JS.remove_class(
"invisible max-h-0 max-h-[100]",
transition: { "transition-all ease-out duration-[150ms]", "max-h-0", "max-h-[100]"},
end_event: true,
time: 150
)}
phx-remove={JS.hide(
transition: { "transition-all ease-in duration-[150ms]", "max-h-dynamic", "max-h-0"},
time: 250
)}
x-data="{ dynamicMaxHeight: '' }"
x-on:remove-class-end="dynamicMaxHeight = findClosestHeightClass( maxHClasses, $el.offsetHeight)"
x-bind:class="dynamicMaxHeight"
The current workaround that I use for this is to speculate on the timely execution of the transition by replacing the wanna-be x-on:remove-class-end
line with the following one:
x-init="setTimeout( () => { dynamicMaxHeight = findClosestHeightClass( maxHClasses, $el.offsetHeight) }, 200)"
This does work, but too many a time it was proven error prone using setTimeout
or calling liveSocket.execJS
while at the same time the user is opening/closing (the conditionally rendered) live component or switching from one LiveView instance to another.
Therefore, it is my suggestion to add the events like those in JS.hide
and JS.show
to all transition-enabled JS
functions.
Thanks