Vuejs css class leave not applied on nested transition - javascript

I am using VueJs 3 and I want to make a modal login form with animations.
I want the first animation to be the background opacity and the second (but at the same time) the form translating from the top to the center.
I use one transition component for the background and one nested
transition component for the form.
This is my template code
<template>
<transition name="popup">
<div v-if="showLogin" class="absolute top-0 right-0 bottom-0 left-0 bg-black bg-opacity-50 flex flex-row flex-nowrap justify-center items-center select-none" #click="toggleLoginPopup(false)">
<transition name="popup-inside" appear>
<div class="shadow-lg bg-white rounded-sm p-4 border border-gray-300" #click.stop="">
<div class="text-xl pb-4 text-center">
Sign In
</div>
<label class="block text-lg">
Username
</label>
<input type="text" class="w-full h-8 p-2 border border-black shadow-inner"/>
<label class="block text-lg pt-4">
Password
</label>
<input type="password" class="w-full h-8 p-2 border border-black shadow-inner"/>
<a class="block hover:cursor-pointer bg-purple-600 hover:bg-purple-800 text-xl w-full text-center rounded-sm text-white p-2 mt-4">
Login
</a>
</div>
</transition>
</div>
</transition>
</template>
And this is the code for the CSS
<style scoped>
.popup-enter-active, .popup-leave-active, .popup-inside-enter-active, .popup-inside-leave-active {
transition: all 5s ease;
}
.popup-enter-from, .popup-leave-to {
opacity: 0;
}
.popup-inside-enter-from, .popup-inside-leave-to {
transform: translate(0px, -100px);
}
</style>
Everything works fine when entering but when leaving the classes are not applied to the nested transition.

Related

Popover on hover vue headllessui

I'm trying to implement the popover from headlessui of vue package with hover. I try to use the mouseenter and mouseleave and the other mouse events but nothing change.
Any solution? There is a better solution? i search on internet I cant nothing about this. I search on headlessui github discussions but nothing.
<template>
<div class="fixed top-16 w-full max-w-sm px-4">
<Popover v-slot="{ open }" class="relative">
<PopoverButton
:class="open ? '' : 'text-opacity-90'"
class="group inline-flex items-center rounded-md bg-orange-700 px-3 py-2 text-base font-medium text-white hover:text-opacity-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75"
>
<span>Solutions</span>
<ChevronDownIcon
:class="open ? '' : 'text-opacity-70'"
class="ml-2 h-5 w-5 text-orange-300 transition duration-150 ease-in-out group-hover:text-opacity-80"
aria-hidden="true"
/>
</PopoverButton>
<transition
enter-active-class="transition duration-200 ease-out"
enter-from-class="translate-y-1 opacity-0"
enter-to-class="translate-y-0 opacity-100"
leave-active-class="transition duration-150 ease-in"
leave-from-class="translate-y-0 opacity-100"
leave-to-class="translate-y-1 opacity-0"
>
<PopoverPanel
class="absolute left-1/2 z-10 mt-3 w-screen max-w-sm -translate-x-1/2 transform px-4 sm:px-0 lg:max-w-3xl"
>
<div
class="overflow-hidden rounded-lg shadow-lg ring-1 ring-black ring-opacity-5"
>
<div class="relative grid gap-8 bg-white p-7 lg:grid-cols-2">
<a
v-for="item in solutions"
:key="item.name"
:href="item.href"
class="-m-3 flex items-center rounded-lg p-2 transition duration-150 ease-in-out hover:bg-gray-50 focus:outline-none focus-visible:ring focus-visible:ring-orange-500 focus-visible:ring-opacity-50"
>
<div
class="flex h-10 w-10 shrink-0 items-center justify-center text-white sm:h-12 sm:w-12"
>
<div v-html="item.icon"></div>
</div>
<div class="ml-4">
<p class="text-sm font-medium text-gray-900">
{{ item.name }}
</p>
<p class="text-sm text-gray-500">
{{ item.description }}
</p>
</div>
</a>
</div>
<div class="bg-gray-50 p-4">
<a
href="##"
class="flow-root rounded-md px-2 py-2 transition duration-150 ease-in-out hover:bg-gray-100 focus:outline-none focus-visible:ring focus-visible:ring-orange-500 focus-visible:ring-opacity-50"
>
<span class="flex items-center">
<span class="text-sm font-medium text-gray-900">
Documentation
</span>
</span>
<span class="block text-sm text-gray-500">
Start integrating products and tools
</span>
</a>
</div>
</div>
</PopoverPanel>
</transition>
</Popover>
</div>
</template>
Seems like common request in HeadlessUI community.
Another solution found this solution on Github that worked fine for me.
for vanilla vue 3 with js the original solution link Github Issue
Nuxt 3 with typescript maintaining accessibility here's the code ↓
<script setup lang="ts">
import { Popover, PopoverButton, PopoverPanel } from '#headlessui/vue'
interface Props {
label: string
hasHref?: boolean
href?: string
}
const props = defineProps<Props>()
const popoverHover = ref(false)
const popoverTimeout = ref()
const hoverPopover = (e: any, open: boolean): void => {
popoverHover.value = true
if (!open) {
e.target.parentNode.click()
}
}
const closePopover = (close: any): void => {
popoverHover.value = false
if (popoverTimeout.value) clearTimeout(popoverTimeout.value)
popoverTimeout.value = setTimeout(() => {
if (!popoverHover.value) {
close()
}
}, 100)
}
</script>
<template>
<Popover v-slot="{ open, close }" class="relative">
<PopoverButton
:class="[
open ? 'text-primary' : 'text-gray-900',
'group inline-flex items-center rounded-md bg-white text-base font-medium hover:text-primary focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2'
]"
#mouseover="(e) => hoverPopover(e, open)"
#mouseleave="closePopover(close)"
>
<span v-if="!hasHref">{{ props.label }}</span>
<span v-else>
<NuxtLink :to="href">
{{ props.label }}
</NuxtLink>
</span>
<IconsChevronDown
:class="[
open ? 'rotate-180 transform text-primary' : '',
' ml-1 h-5 w-5 text-primary transition-transform group-hover:text-primary'
]"
aria-hidden="true"
/>
</PopoverButton>
<transition
enter-active-class="transition ease-out duration-200"
enter-from-class="opacity-0 translate-y-1"
enter-to-class="opacity-100 translate-y-0"
leave-active-class="transition ease-in duration-150"
leave-from-class="opacity-100 translate-y-0"
leave-to-class="opacity-0 translate-y-1"
>
<PopoverPanel
class="absolute left-1/2 z-10 mt-3 ml-0 w-auto min-w-[15rem] -translate-x-1/2 transform px-2 sm:px-0"
#mouseover.prevent="popoverHover = true"
#mouseleave.prevent="closePopover(close)"
>
<div
class="overflow-hidden rounded-lg shadow-lg ring-1 ring-black ring-opacity-5"
>
<div class="relative grid gap-1 bg-white p-3">
<slot> put content here </slot>
</div>
</div>
</PopoverPanel>
</transition>
</Popover>
</template>
It is in the docs:showing-hiding-popover.
open is an internal state used to determine if the component is shown or hidden. To implement your own functionality, you can remove it and use the static prop to always render a component. Then you can mange the visibility with your own state ref and a v-if/v-show. The mouse-action has to be in the upper scope, so it is not triggered leaving the component, e.g. moving the mouse from button to panel.
Below is a modified example from the API documentation:
<template>
<Popover
#mouseenter="open = true"
#mouseleave="open = false"
#click="open = !open"
>
<PopoverButton #click="open = !open">
Solutions
<ChevronDownIcon :class="{ 'rotate-180 transform': open }" />
</PopoverButton>
<div v-if="open">
<PopoverPanel static>
Insights
Automations
Reports
</PopoverPanel>
</div>
</Popover>
</template>
<script setup>
import { ref } from 'vue';
import { Popover, PopoverButton, PopoverPanel } from '#headlessui/vue';
import { ChevronDownIcon } from '#heroicons/vue/20/solid';
const open = ref(false);
</script>

How to limit number of checkboxes to certain number in react?

This is the code for the checkboxes and I would like to limit the choices to 2.
This is going to be used for a pizza application, so the limit number will be different for the different sections in creating a pizza.
const LagDinEgen = () => {
return(
<div>
<form name="størrelse">
<div className="desktop:w-3/4 tablet:w-11/12 w-full mx-auto grid grid-cols-1 tablet:grid-cols-2 desktop:grid-cols-3 rounded-lg overflow-hidden desktop:mt-8 gap-2">
<div className="col-span-1 tablet:col-span-2 desktop:col-span-3 bg-mainBlue py-10 h-auto text-center text-white flex flex-col justify-center items-center">
<h1 class="mb-6 pt-6 mx-auto text-center"> VELG STØRRELSE</h1>
<div class="mx-auto max-w-sm text-center flex flex-wrap justify-center">
<div class="flex items-center mr-4 mb-4">
<input id="radio1" type="checkbox" name="radio" class="hidden"/>
<label for="radio1" class="flex items-center cursor-pointer px-3">
<span class="w-4 h-4 inline-block mr-1 border border-mainGreen rounded-full"></span>
SMALL</label> <label>129,-</label>
</div>
<div class="flex items-center mr-4 mb-4">
<input id="radio2" type="checkbox" name="radio" class="hidden" />
<label for="radio2" class="flex items-center cursor-pointer px-3">
<span class="w-4 h-4 inline-block mr-1 border border-mainGreen rounded-full"></span>
MEDIUM</label> <label>159,-</label>
</div>
<div class="flex items-center mr-4 mb-4">
<input id="radio3" type="checkbox" name="radio" class="hidden" />
<label for="radio3" class="flex items-center cursor-pointer px-3">
<span class="w-4 h-4 inline-block mr-1 border border-mainGreen rounded-full"></span>
LARGE</label> <label>189,-</label>
</div>
</div>
</div>
</div>
</form>
Assuming you plan on adding a button, you can utilize the native HTML5 disabled property on it and maintain the state of which items are currently selected to determine when it should be disabled(eg. an array of selectedItems)
You would pass the selectedItems.length > 2 to the disabled property, so it would effectively become disabled if your array is larger than 3.
Working example: https://codesandbox.io/s/xenodochial-currying-eb8kt?file=/src/Form.js
You should pass necessary datas to LagDinEgen component as props and then you should use array.map() function inside of JSX. This will be something gonna like that;
const LagDinEgen = ({title,options}) => {
return(
<div>
<form name="størrelse">
<div className="desktop:w-3/4 tablet:w-11/12 w-full mx-auto grid grid-cols-1 tablet:grid-cols-2 desktop:grid-cols-3 rounded-lg overflow-hidden desktop:mt-8 gap-2">
<div className="col-span-1 tablet:col-span-2 desktop:col-span-3 bg-mainBlue py-10 h-auto text-center text-white flex flex-col justify-center items-center">
<h1 class="mb-6 pt-6 mx-auto text-center"> {title} </h1>
<div class="mx-auto max-w-sm text-center flex flex-wrap justify-center">
{
options.map((option,index)=>(
<div class="flex items-center mr-4 mb-4">
<input type="checkbox" name="radio" class="hidden"/>
<label class="flex items-center cursor-pointer px-3">
<span class="w-4 h-4 inline-block mr-1 border border-mainGreen rounded-full"></span>
{option.name}</label> <label>{option.price},-</label>
</div>
))
}
</div>
</div>
</div>
</form>

Jquery mouseenter and mouseleave is deprecated in Next.js, Tailwind

enter image description here
I wanted to create useEffect variables and put it to true/false when user hovers on parent div.
I want to use that hover variable in a child div with image and resize image when user hovers on parent div with id="infoCard".
Code-
const [hover, setHover] = useState(false);
<div
className="flex flex-col md:flex-row font-inter py-7 px-2 border-b rounded-xl cursor-pointer hover:shadow-lg pr-6 transition duration-200 ease-out first:border-t hover:bg-red-100 mb-2"
id="infoCard"
>
<div className="relative h-40 w-64 md:h-52 md:w-80 flex-shrink-0 ml-6">
<Image
src={img}
layout="fill"
objectFit="cover"
className={`rounded-2xl scale-95 ${hover ? "scale-100" : ""
} transform transition duration-200 ease-out`}
/>
</div>
<div className="flex flex-col flex-grow pl-5 ml-2 mt-2 md:mt-0">
<div className="flex justify-between">
<p>
{location} {city}
</p>
<HeartIcon className="h-7 cursor-pointer" />
</div>
<h4 className="text-xl">{title}</h4>
<div className="border-b w-10 pt-2" />
<p className="pt-2 text-sm text-gray-500 flex-grow">
{numberOfGuest}
{description}
</p>
<div className="flex justify-between items-end">
<p className="flex items-center">
<StarIcon className="h-5 text-red-400" />
{star}
</p>
<div>
<p className="text-lg pb-2 font-semibold lg:text-2xl">{price}</p>
<p className="text-right font-light">{total}</p>
</div>
</div>
</div>
</div>
You could do this without the hover state with just CSS. Take a look at the documentation on group-hover classes here. They work like this:
<div class="group">
<img class="transform scale-95 group-hover:scale-100" />
</div>
Here's a minimal example of how you could do this. Note that you also need to extend the variants of the scale classes in the tailwind.config.js file as it's not included by default.
As a side note: You don't typically use jQuery in a React-based projects. If you need to detect hover, React has built-in mouse events. Read more here.

How to properly handle mouse events with AlpineJS for my menu?

I'm working on a mega dropdown menu component with alpine.js and Tailwind CSS. Right now I have met some difficulties and I can't make the mouse events work. Below is my code and the red block is the dropdown mega menu. As you can see, when you move the cursor on the Product menu item, the mega menu is shown. After that if you move the cursor down a little bit on the mega menu, the menu is still shown. At this state, if you move out of the mega menu, the mega menu is close. The problem is that when you move on to the Product menu and then move your cursor right to the *Pricing" menu item, the dropdown is still shown, which is not correct. When the user moves out of the Product menu, how can I test if the destination is the mega dropdown or other menu items like Pricing (and close the mega dropdown in this case) using alpine.js?
<script src="https://cdnjs.cloudflare.com/ajax/libs/alpinejs/2.8.2/alpine.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.1.2/tailwind.min.css" rel="stylesheet"/>
<div class="border-b border-gray-200 relative h-20 flex py-0 items-stretch" x-data="{isProdMenuOpen: false, isLearnMenuOpen: false}">
<div class="flex container mx-auto items-center justify-between h-20"><img class="flex-none h-6" src="https://sitebulb.com/images/icons/logo.svg" />
<ul class="flex items-center justify-between flex-none">
<li class="h-20 border-b border-l border-r border-transparent mx-6 flex items-center relative" #mouseenter="isProdMenuOpen = true">
<!--div.h-20.w-full.flex.items-center.border-b.border-transparent(class="hover:border-red")--><a class="font-semibold flex-none" href="">Product</a>
<div class="h-full absolute -left-6 -right-6 top-0 border-r border-l border-gray-200">
<div class="w-full absolute bottom-0 bg-black z-100 inset-x-0" style="transform: translate(0px, 2px); height:4px;"></div>
</div>
</li>
<li class="h-20 flex items-center mx-6"><a class="font-semibold flex-none" href="">Pricing</a></li>
<li class="h-20 flex items-center mx-6"><a class="font-semibold flex-none" href="">About</a></li>
</ul>
<div class="flex items-center justify-between flex-none"><button class="bg-white rounded border px-3 py-2 text-sm font-medium border-gray-200">Login</button><button class="bg-white rounded bg-green-400 text-white text-sm font-medium px-3 py-2 ml-2 hover:bg-green-500">Free Trial</button></div>
</div><!-- Popup Menu Items -->
<div class="flex flex-row items-start border-b border-gray-200 w-screen h-40 absolute left-0 top-20 bg-red-400" id="prodmenu" x-show="isProdMenuOpen" #mouseenter="isProdMenuOpen = true" #mouseleave="isProdMenuOpen = false"></div>
</div>
There's a solution for this that is independent of Alpine or Javascript at all. Using Tailwind's group class on the li, making the popup a child of the group li and removing relative positioning from the li so the child div can go full width will give the same effect I believe you are looking for and fully controlled by CSS.
There will need to be some fudging around to make a similar effect that you are doing with the different color underline on the li in this example I used a border and relative positioning of the anchor tag to offset the border's height. Also, you will need to extend your variants to allow display to be manipulated in group-hover in the code snippet here on SO below I'm just using the class generated by that config to fake it. Here's a Tailwind play that shows the actual config as well https://play.tailwindcss.com/EYY0alaQuB?file=config
.group:hover .group-hover\:flex {
display: flex;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.1.2/tailwind.min.css" rel="stylesheet" />
<div class="border-b border-gray-200 relative h-20 flex py-0 items-stretch">
<div class="flex container mx-auto items-center justify-between h-20"><img class="flex-none h-6" src="https://sitebulb.com/images/icons/logo.svg" />
<ul class="flex items-center justify-between flex-none">
<li class="h-20 border-b-4 border-l border-r border-gray-200 px-6 flex items-center group" style="border-bottom: 4px solid black">
<a class="font-semibold flex-none relative top-1" href="">Product</a>
<!-- Popup Menu Items -->
<div class="hidden group-hover:flex flex-row items-start border-b border-gray-200 w-screen h-40 absolute left-0 top-20 bg-red-400" id="prodmenu"></div>
</li>
<li class="h-20 flex items-center mx-6 border-b-4 border-transparent"><a class="font-semibold flex-none relative top-1" href="">Pricing</a></li>
<li class="h-20 flex items-center mx-6 border-b-4 border-transparent"><a class="font-semibold flex-none relative top-1" href="">About</a></li>
</ul>
<div class="flex items-center justify-between flex-none">
<button class="bg-white rounded border px-3 py-2 text-sm font-medium border-gray-200">Login</button>
<button class="rounded bg-green-400 text-white text-sm font-medium px-3 py-2 ml-2 hover:bg-green-500">Free Trial</button>
</div>
</div>
</div>

How to test value in x-for variable and change the CSS Style according to the value?

How can I test the value of an x-for variable and then meet an IF condition to change the CSS value?
<template x-for="item in myForData" :key="item">
<div id="jh-stats-neutral" class="flex items-center shadow hover:bg-indigo-100
hover:shadow-lg hover:rounded transition duration-150 ease-in-out transform
hover:scale-102 flex flex-col justify-center px-2 py-3 mt-0 bg-white border
border-gray-300 rounded md:mb-0"
<div class="text-md">
<p
class="text-md font-semibold text-center text-red-600 *<% if ("item.categoria.substring(3)" == 'Rec') { %> bg-blue-200 <% } %>*"
x-text="item.categoria"
></p>
<p
class="text-lg text-center text-red-700"
x-text="item.total"
></p>
</div>
</div>
</template>
Someone can help me?
You can bind to the class attribute using x-bind:class or :class for short.
x-bind:class has special syntax that means you can pass it an object whose key is the class(es) and the value is whether the class(es) is applied.
Eg. x-bind:class="{ 'hello': false, 'world': true }" will add the world class but not hello.
In your case you can do the class toggling using Alpine:
*<% if ("item.categoria.substring(3)" == 'Rec') { %> bg-blue-200 <% } %>* turns into class="...otherclasses" x-bind:class="{ 'bg-blue-200': item.categoria.substring(3) === 'Rec' }".
Your full code updated with the x-bind:class
<template x-for="item in myForData" :key="item">
<div id="jh-stats-neutral" class="flex items-center shadow hover:bg-indigo-100
hover:shadow-lg hover:rounded transition duration-150 ease-in-out transform
hover:scale-102 flex flex-col justify-center px-2 py-3 mt-0 bg-white border
border-gray-300 rounded md:mb-0"
<div class="text-md">
<p
class="text-md font-semibold text-center text-red-600 *<% if ("item.categoria.substring(3)" == 'Rec') { %> bg-blue-200 <% } %>*"
x-bind:class="{ 'bg-blue-200': item.categoria.substring(3) === 'Rec' }"
x-text="item.categoria"
></p>
<p
class="text-lg text-center text-red-700"
x-text="item.total"
></p>
</div>
</div>
</template>
I would like to answer your question - unfortunately I cannot add a comment - please provide more details - what exactly do you want to do.
First of all, x-for = "item in myForData" is not a variable but an attribute.
Fantastic Hugo!
Your explanation open my mind to a world of possibilities... I left behind some trash in original code above, but it's my code updated:
<template x-for="item in myForData" :key="item">
<div id="jh-stats-neutral" class="flex items-center shadow hover:bg-indigo-100
hover:shadow-lg hover:rounded transition duration-150 ease-in-out transform
hover:scale-102 flex flex-col justify-center px-2 py-3 mt-0 bg-white border
border-gray-300 rounded md:mb-0"
<div class="text-md">
<p
class="card text-md font-semibold text-center"
x-bind:class="{ 'text-blue-600': item.total.substring(0,4) !== 'R$ -' , 'text-red-600': item.total.substring(0,4) === 'R$ -' }"
x-text="item.conta"
></p>
<p
class="value text-lg text-center text-gray-700"
x-text="item.total"
></p>
</div>
</div>
</template>
Thanks once more time and let you know that I'm your fã!

Categories

Resources