Open blackjak231 opened 2 months ago
+1
Also, the transition seems to be working fine with 1.7.16 plus vue 3.5.3. From 1.7.17 on, the enter transition breaks.
seems to be working fine with 1.7.16 plus vue 3.5.3
Also able to repro this on my end. Otherwise, 1.7.23
(latest at writing) + locking Vue to 3.4.38
does the trick as already stated.
There have been a number of transition-related changes in Vue core over the past month. Not sure where to start on this. https://github.com/vuejs/core/issues?q=transition+created%3A%3E%3D2024-08-01
GH diff link won't jump to file automatically, but was able to isolate this issue to changes made to packages/@headlessui-vue/src/components/portal/portal.ts in @headlessui/vue@v1.7.17
by pinning v1.7.17 and swapping out a built version of portal.ts@v1.7.16
locally.
Compare tailwindlabs/headlessui/vue@v1.7.16...17
``` import{Teleport as x,computed as C,defineComponent as p,h as H,inject as m,onMounted as M,onUnmounted as c,provide as g,reactive as L,ref as s,watchEffect as j}from"vue";import{render as T}from'../../utils/render.js';import{usePortalRoot as b}from'../../internal/portal-force-root.js';import{getOwnerDocument as y}from'../../utils/owner.js';import{dom as w}from'../../utils/dom.js';function E(t){let e=y(t);if(!e){if(t===null)return null;throw new Error(`[Headless UI]: Cannot find ownerDocument for contextElement: ${t}`)}let u=e.getElementById("headlessui-portal-root");if(u)return u;let r=e.createElement("div");return r.setAttribute("id","headlessui-portal-root"),e.body.appendChild(r)}let U=p({name:"Portal",props:{as:{type:[Object,String],default:"div"}},setup(t,{slots:e,attrs:u}){let r=s(null),i=C(()=>y(r)),l=b(),n=m(h,null),o=s(l===!0||n==null?E(r.value):n.resolveTarget());j(()=>{l||n!=null&&(o.value=n.resolveTarget())});let d=m(f,null);return M(()=>{let a=w(r);a&&d&&c(d.register(a))}),c(()=>{var v,P;let a=(v=i.value)==null?void 0:v.getElementById("headlessui-portal-root");a&&o.value===a&&o.value.children.length<=0&&((P=o.value.parentElement)==null||P.removeChild(o.value))}),()=>{if(o.value===null)return null;let a={ref:r,"data-headlessui-portal":""};return H(x,{to:o.value},T({ourProps:a,theirProps:t,slot:{},attrs:u,slots:e,name:"Portal"}))}}}),f=Symbol("PortalParentContext");function V(){let t=m(f,null),e=s([]);function u(l){return e.value.push(l),t&&t.register(l),()=>r(l)}function r(l){let n=e.value.indexOf(l);n!==-1&&e.value.splice(n,1),t&&t.unregister(l)}let i={register:u,unregister:r,portals:e};return[e,p({name:"PortalWrapper",setup(l,{slots:n}){return g(f,i),()=>{var o;return(o=n.default)==null?void 0:o.call(n)}}})]}let h=Symbol("PortalGroupContext"),_=p({name:"PortalGroup",props:{as:{type:[Object,String],default:"template"},target:{type:Object,default:null}},setup(t,{attrs:e,slots:u}){let r=L({resolveTarget(){return t.target}});return g(h,r),()=>{let{target:i,...l}=t;return T({theirProps:l,ourProps:{},slot:{},attrs:e,slots:u,name:"PortalGroup"})}}});export{U as Portal,_ as PortalGroup,V as useNestedPortals}; ```
``` import{computed as M,defineComponent as s,getCurrentInstance as L,h as j,inject as f,onMounted as w,onUnmounted as y,provide as T,reactive as I,ref as p,Teleport as b,watch as R,watchEffect as G}from"vue";import{usePortalRoot as O}from'../../internal/portal-force-root.js';import{dom as D}from'../../utils/dom.js';import{getOwnerDocument as E}from'../../utils/owner.js';import{render as h}from'../../utils/render.js';function x(r){let e=E(r);if(!e){if(r===null)return null;throw new Error(`[Headless UI]: Cannot find ownerDocument for contextElement: ${r}`)}let u=e.getElementById("headlessui-portal-root");if(u)return u;let t=e.createElement("div");return t.setAttribute("id","headlessui-portal-root"),e.body.appendChild(t)}let _=s({name:"Portal",props:{as:{type:[Object,String],default:"div"}},setup(r,{slots:e,attrs:u}){let t=p(null),i=M(()=>E(t)),l=O(),n=f(C,null),o=p(l===!0||n==null?x(t.value):n.resolveTarget()),d=p(!1);w(()=>{d.value=!0}),G(()=>{l||n!=null&&(o.value=n.resolveTarget())});let c=f(m,null),v=!1,H=L();return R(t,()=>{if(v||!c)return;let a=D(t);a&&(y(c.register(a),H),v=!0)}),y(()=>{var g,P;let a=(g=i.value)==null?void 0:g.getElementById("headlessui-portal-root");a&&o.value===a&&o.value.children.length<=0&&((P=o.value.parentElement)==null||P.removeChild(o.value))}),()=>{if(!d.value||o.value===null)return null;let a={ref:t,"data-headlessui-portal":""};return j(b,{to:o.value},h({ourProps:a,theirProps:r,slot:{},attrs:u,slots:e,name:"Portal"}))}}}),m=Symbol("PortalParentContext");function A(){let r=f(m,null),e=p([]);function u(l){return e.value.push(l),r&&r.register(l),()=>t(l)}function t(l){let n=e.value.indexOf(l);n!==-1&&e.value.splice(n,1),r&&r.unregister(l)}let i={register:u,unregister:t,portals:e};return[e,s({name:"PortalWrapper",setup(l,{slots:n}){return T(m,i),()=>{var o;return(o=n.default)==null?void 0:o.call(n)}}})]}let C=Symbol("PortalGroupContext"),N=s({name:"PortalGroup",props:{as:{type:[Object,String],default:"template"},target:{type:Object,default:null}},setup(r,{attrs:e,slots:u}){let t=I({resolveTarget(){return r.target}});return T(C,t),()=>{let{target:i,...l}=r;return h({theirProps:l,ourProps:{},slot:{},attrs:e,slots:u,name:"PortalGroup"})}}});export{_ as Portal,N as PortalGroup,A as useNestedPortals}; ```
I would guess that an { immediate: true }
added to the watcher might fix it (??).
Is there any news on this issue?
Same issue for me
I will add the style of class="${enterFrom}" to TransitionChild
If you don’t add it, there will be no entry animation.
I will add the style of class="${enterFrom}" to TransitionChild
This is actually working great in my case. It's clearly a temporary hack to get it working over a fix, but allows me to keep Vue up to date. Thanks for the tip @ixycej12
I will add the style of class="${enterFrom}" to TransitionChild
Sorry, I'm not finding the correct way to add this, I tried the following but didn't work:
<TransitionChild
as="template"
class="${enterFrom}"
enter="ease-in-out duration-500"
enter-from="opacity-0"
enter-to="opacity-100"
leave="ease-in-out duration-500"
leave-from="opacity-100"
leave-to="opacity-0"
>
Do I have to include enterFrom
somehow @ixycej12 @blackjak231 ?
Ahhh I just found it was a reference to the class you are passing into enter-from attribute, so in my case enterFrom = opacity-0
so I placed it like:
<TransitionChild
as="template"
class="opacity-0"
enter="ease-in-out duration-500"
enter-from="opacity-0"
enter-to="opacity-100"
leave="ease-in-out duration-500"
leave-from="opacity-100"
leave-to="opacity-0"
>
Worked like a charm!
The current temporary solution, but there will be bugs.
Thanks! That worked for me too!
Any fixed version?
Most recent Vue fixed the issue for me.
the problem is still relevant
What package within Headless UI are you using?
@headlessui/vue
What version of that package are you using?
1.7.22
What browser are you using?
Chrome and Safari (mobile versions as well)
Reproduction URL
Codepen example here
Describe your issue
After upgrading to vue 3.5.x from 3.4.38, there are no longer any transition animations on enter. Well, instead of saying "no animations" it seems to be related to the transition duration (from very random tests I've done).
In the codepen provided, sometimes, for no apparent reason, the dialog will show just fine, but 99% of the time, there are no enter transition (or an extremely brief one).
From what I can see, Vue has changed some behaviour with the native transition and teleport. Maybe it has something to do with it ? https://github.com/vuejs/core/blob/main/CHANGELOG.md
Only solution for now : downgrade to vue 3.4.x.
Hopefully you can find and fix this issue !