subbu
March 4, 2022, 11:37am
1
Tailwind has nice transitions for components like slid-overs, dropdowns, and modals. For example, these are the transitions classes for a slideover:
Slide-over panel, show/hide based on slide-over state.
Entering: "transform transition ease-in-out duration-500 sm:duration-700"
From: "translate-x-full"
To: "translate-x-0"
Leaving: "transform transition ease-in-out duration-500 sm:duration-700"
From: "translate-x-0"
To: "translate-x-full"
These are easy to get right with Alpine.js using x-transitions, but is there a way to do them using LiveView.JS? Has anybody tried?
3 Likes
c4710n
March 4, 2022, 11:45am
3
As a supplement. GitHub - petalframework/petal_components: Phoenix Live View Components has a modal component which supports transition. Check it out.
3 Likes
cmo
March 4, 2022, 12:53pm
4
5 Likes
For what itās worth, Iāve tried to transcribe multiple component from TailwindUI and had the same experience as @subbu .
With Alpine.js, everything just works. Iāve never been able to get Phoenix.LiveView.JS.transition
(or the transition
options of the other JS
functions) to work right out of the box with these Tailwind transitions.
For example, with @subbu ās original post, Iād put
JS.transition({"transform transition ease-in-out duration-500 sm:duration-700", "translate-x-full", "translate-x-0"})
But it doesnāt work right. (Again, despite working right in Alpine.)
Does anyone know whatās going on here? Or how to get the desired behavior?
Can you show the full code of where you call the transition?
@tcoopman Thanks for chiming in!
I was mostly having trouble with entrance transitions . (Elements not previously shown.) I had to add these to get Tailwind transitions to apply correctly:
style="display: none"
class="start-classes"
phx-mounted={JS.show(transition: {"transition-classes", "start-classes", "end-classes"}, time: ...)}
So for example, if a TailwindUI component has:
<!--
Entering: "ease-out duration-300"
From: "opacity-0"
To: "opacity-100"
-->
<div>
...
</div>
I had to do:
<div
style="display: none"
class="opacity-0"
phx-mounted={JS.show(
transition: {"ease-out duration-300", "opacity-0", "opacity-100"},
time: 300
)}
>
...
</div>
Without this precise configuration, I wasnāt able to get the transition to display correctly. (Notice Iām using JS.show
instead of JS.transition
. )
Hopefully someone out there finds this helpful!
Itās worth noting that Alpine.js makes this much less confusing to get right. You just take the 3 lists of classes from the TailwindUI example HTML and drop them into 3 corresponding attributes.
<div
x-show="open"
x-transition:enter="ease-out duration-300"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
>
...
</div>
Perhaps LiveView could benefit to evolve more in that direction.
5 Likes
I should note, the same issue applies with exit transitions .
With this TailwindUI specification:
<!--
Leaving: "ease-in duration-200"
From: "opacity-100"
To: "opacity-0"
-->
You can do this in Alpine.js:
<div
x-show="open"
x-transition:leave="ease-in duration-200"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
>
...
</div>
But this does not work in LiveView:
<div phx-remove={JS.transition({"ease-in duration-200", "opacity-100", "opacity-0"})}>
...
</div>
Instead, you have to do this:
<div phx-remove={JS.hide({"ease-in duration-200", "opacity-100", "opacity-0"})
...
</div>
(Again, use JS.hide
instead of JS.transition
. )
I hope this is a helpful reference to anyone else in this situation!
3 Likes
Iāve confirmed that JS.add_class
, JS.remove_class
, and JS.transition
apply the end
classes at the wrong time.
Iāve logged a bug report for LiveView here:
opened 08:19PM - 23 Feb 23 UTC
### Environment
* Elixir version (elixir -v): 1.14.3
* Phoenix version (mix ā¦ deps): 1.6.16
* Phoenix LiveView version (mix deps): 0.18.15
* Operating system: MacOS Ventura 13.2.1
* Browsers you attempted to reproduce this bug on (the more the merrier): **Chrome, Safari (desktop and mobile), Firefox**
* Does the problem persist after removing "assets/node_modules" and trying again? **Yes**
### Terminology
- `JS` refers to `Phoenix.LiveView.JS`.
- `time` refers the `:time` option given to a `JS` function.
- `transition_classes`, `start`, and `end` refer to the `{transition_classes, start, end}` tuple given as the `:transition` option for a `JS` function.
### Actual behavior
When using `JS.add_class`, `JS.remove_class`, and `JS.transition`, the `end` classes are not applied until `time` has expired. Furthermore, they are never removed from the element. In other words:
1. The `transition_classes` and `start` classes are immediately added.
2. After `time` milliseconds, the `end` classes are added and the `transition_classes` and `start` classes are removed.
### Expected behavior
When using `JS.add_class`, `JS.remove_class`, and `JS.transition`, the `end` classes are applied immediately after the `start` classes and are removed after `time` has expired. **This behavior would be consistent with `JS.show`, `JS.hide`, and `JS.toggle`.**
In other words:
1. The `start` classes are added.
2. Immediately, in the next available animation frame after [1], the `transition_classes` are added.
3. Immediately, in the next available animation frame after [2], the `end` classes are added and the `start` classes are removed.
4. After `time` milliseconds, the `transition_classes` and `end` classes are removed.
### Reference of Correct Implementation
The **Expected Behavior** is precisely how the `toggle` function in `phoenix_live_view.js` already works. This explains why `JS.show`, `JS.hide`, and `JS.toggle` behave correctly, since they all use that function behind the scenes.
https://github.com/phoenixframework/phoenix_live_view/blob/82b349278cc5ced4f0c99fe27d0988b42197d8ce/priv/static/phoenix_live_view.js#L2337-L2350
### Example LiveView
Clone [this repository](https://github.com/paulstatezny/live-view-transition-inconsistency) and run:
```
elixir live_view.exs
```
Then, open your browser to: http://localhost:5001
This runs a LiveView that demonstrates the inconsistent behavior. Note the `mount` and `render` functions in `SamplePhoenix.SampleLive` in [live_view.exs](https://github.com/paulstatezny/live-view-transition-inconsistency/blob/main/live_view.exs).
### Video Demonstration
This video shows what happens when you run the above example LiveView.
The `transition` option is identical in each example (with `start` and `end` sometimes flipped):
```elixir
{"transition-opacity duration-1000", "opacity-20", "opacity-100"}
```
However, only `JS.toggle`, `JS.show`, and `JS.hide` correctly cause the opacity to transition smoothly.
https://user-images.githubusercontent.com/4662353/221018801-1cd66976-476e-4b98-8d1f-ec79c1d4100b.mov
5 Likes
I think the answer here is that you can apply multiple classes in the 3-tuple separated by spaces. I guessed at this by looking at the linked source code, and then saw that it uses a function transition_class_names
which calls class_names
which uses String.split(" "")
(source )
For example something specified as:
Entering: "transition ease-out duration-100"
From: "transform opacity-0 scale-95"
To: "transform opacity-100 scale-100"
Leaving: "transition ease-in duration-75"
From: "transform opacity-100 scale-100"
To: "transform opacity-0 scale-95"
can be implemented as:
def show_user_menu(js \\ %JS{}) do
js
|> JS.toggle(
to: "#user_menu",
in:
{"transition ease-out duration-100", "transform opacity-0 scale-95",
"transform opacity-100 scale-100"},
out:
{"transition ease-in duration-75", "transform opacity-100 scale-100",
"transform opacity-0 scale-95"}
)
end
6 Likes
For what itās worth, this was fixed here:
phoenixframework:main
ā plastic-forks:c4710n-fix-transition
opened 08:41AM - 10 May 23 UTC
This PR is trying to close #2484.
To reproduce the problem, you can run <httpā¦ s://github.com/plastic-forks/live-view-transition-inconsistency/blob/main/live_view.exs>.
To see the solution, you can run <https://github.com/plastic-forks/live-view-transition-inconsistency/blob/main/live_view-fixed.exs> which uses the fixed `phoenix_live_view.min.js`.
I havenāt personally had a chance to confirm the patch works.
1 Like