How to transition div using Tailwindcss in React - javascript

I have a Menu panel next to my sider. I am trying to add a drawer type animation however I can't seem position open/close within the pink column
const album = ["Album1", "Album2", "Album3"];
export const Menu = () => {
const [open, setOpen] = useState(false);
return (
<div className="flex flex-1 flex-col p-3">
<h2 className="text-lg font-medium text-gray-900">Album</h2>
<div className="flex-1">
<div className="flex flex-1 flex-col space-y-3 py-3">
{album.map((name) => (
<button
key={name}
id={name}
className={`flex space-x-2 items-center`}
onClick={() => setOpen(true)}
>
<span>{name}</span>
</button>
))}
</div>
</div>
<aside
onClick={() => setOpen(false)} //temporary
className={`transform top-0 left-0 w-72 bg-blue-400 fixed h-full overflow-auto ease-in-out transition-all duration-1000 z-30 ${
open ? "translate-x-14" : "-translate-x-full"
}`}
>
hello
</aside>
</div>
);
};

Javascript. Just add a eventListener to the 'button' which will handle the actions. In the eventListener, remove or add a css class. For example, by default the position is '-100px right' with css set position to '300px right', also add a transition 'all 300ms ease'. Now you element start with no css, and when user press button add the class.
<div class="text-3xl font-bold underline transition-all duration-300" id="must-change">
Lorem Ipsu
</div>
<button class="bg-blue-500 hover:bg-blue-700 text-white font-bold p-3 rounded" id="press-me">
Button
</button>
<script>
const btn = document.querySelector("#press-me")
const mustChange = document.querySelector("#must-change")
btn.addEventListener("click", () => {
mustChange.classList.toggle("font-bold")
})
</script>
I set 'transition all' but you can use a specific transition if you want.

Related

TailwindCSS styling applies to one React Component list but not the other

Hello I have two cards but one of them is not applying it's TailwindCSS stuff to the divs at all. I hope it's just some stupid error because I'm kind of scratching my head.
Is the relevant incorrect code:
Where it's being rendered in the index page:
Dashboard.tsx:
<div className="flex flex-col border border-red-700">
{orders.map(
({ id, managerId, invoiceNumber, companyName, contact, partNumbers, partNames, quote, locationOnServer, reportType, createdAt }) => {
return (
<WorkOrderCard id={id} managerId={managerId} invoiceNumber={invoiceNumber} companyName={companyName} contact={contact} partNumbers={partNumbers} partNames={partNames} quote={quote} locationOnServer={locationOnServer} reportType={reportType} createdAt={createdAt} timesheet={[]} />
)
}
)}
And here is the component definition WorkOrderCard.tsx:
export default function WorkOrderCard(props) {
const { id, managerId, invoiceNumber, companyName, contact, partNumbers, partNames, quote, locationOnServer, reportType, createdAt, timesheet} = props;
const [manager, setManager] = React.useState<string>("");
useEffect(() => {
if (manager !== undefined) {
const res = fetch("/api/users/get/" + managerId, {
method: 'GET',
}).then((res) => {
if (res.ok) {
res.json().then((manager) => {
setManager(manager.name);
})
} else {
console.log("There was an error fetching the ticket");
// setErrorMessage(res.statusText)
}
})
}
}, [])
return (
/* Trying to draw an outline around the div but It doesn't appear */
<div className="flex outline outline-red-600">
<div className='flex flex-col'>
<div className="flex flex-row">
<div className="flex">Invoice #{invoiceNumber}</div>
<div className="flex">{companyName}</div>
</div>
<div className="card-body">
<div className="card-text">
<strong>Contact:</strong> {contact || 'N/A'}
</div>
<div className="card-text">
<strong>Part Numbers:</strong>{' '}
{partNumbers.length > 0 ? partNumbers.join(', ') : 'N/A'}
</div>
<div className="card-text">
<strong>Part Names:</strong>{' '}
{partNames.length > 0 ? partNames.join(', ') : 'N/A'}
</div>
<div className="card-text">
<strong>Quote:</strong> ${quote}
</div>
<div className="card-text">
<strong>Location on Server:</strong> {locationOnServer}
</div>
<div className="card-text">
<strong>Report Type:</strong> {reportType}
</div>
<div className="card-text">
<strong>Created At:</strong> {createdAt.toString()}
</div>
<div className="card-text">
</div>
<div className="card-text">
<strong>Manager:</strong> {manager}
</div>
{timesheet.length > 0 && (
<div className="card-text">
<strong>Time Sheet:</strong>
<ul>
{timesheet.map((time) => (
<li key={time.id}>
{new Date(time.date).toLocaleString()} - {new Date(time.date).setHours(new Date(time.date).getHours() + time.hours).toLocaleString()}
</li>
))}
</ul>
</div>
)}
</div>
</div>
</div>
);
};
The working code is called like this Dashboard.tsx:
<div className="flex flex-col justify-evenly border border-red-700">
{tickets.map(
({ id, creator, broken_item, issue_desc, loc, prio, active, creatorName, createdAt }) => {
return (
<TicketGUI className="m-3" id={id} creator={creator} broken_item={broken_item} issue_desc={issue_desc} loc={loc} prio={prio} active={active} name={creatorName} createdAt={createdAt} />
)
}
)}
<div className="flex justify-between m-2">
<button onClick={() => {
ticketPageSelect(currentSession.user.id, tickets[0].id, setTickets, true, pageSize)
}} className="justify-end px-4 py-2 text-sm text-blue-100 bg-blue-500 rounded shadow">
Prev
</button>
<button onClick={() => {
ticketPageSelect(currentSession.user.id, tickets[tickets.length - 1].id, setTickets, false, pageSize)
}} className="justify-end px-4 py-2 text-sm text-blue-100 bg-blue-500 rounded shadow">
Next
</button>
</div>
</div>
And here is the working component TicketGUI.tsx:
export default function TicketGUI(props){
const handlePress = async (e) => {
Router.push('/tickets/'+props.id)
}
return (
<div className="flex flex-col rounded-lg shadow-lg p-2 m-3 outline outline-blue-300">
<div className="flex ">
<img
className="object-cover h-12"
src={props.active ? "/inprocess.png" : "/fixed.png"}
alt="image"
/>
<h1 className=" ml-2 text-xl font-semibold tracking-tight text-blue-600 whitespace-nowrap">
{props.broken_item} - TicketID: {props.id}
</h1>
</div>
<div className="p-4">
<p className="mb-2 leading-normal">
{props.issue_desc}
</p>
<div className="flex w-full">
<button onClick={handlePress} className="px-4 py-2 text-sm text-blue-100 bg-blue-500 rounded shadow">
View Details
</button>
<p className="p-2">
{format(new Date(props.createdAt),'MM/dd/yyyy')}
</p>
</div>
</div>
</div>
);
}
Any help would be appreciated Chat-GPT suggested this but no dice and I factored out className from props:
It looks like the problem is that the className prop is being passed
to the component but it is not being used to apply classes to the
elements within the component. In the code you posted, the className
prop is only being used to specify the component's own class, but it
is not being used to apply classes to the elements within the
component.
To fix this, you can either use the className prop to specify the
classes for each element within the component, or you can use the
className prop to specify the classes for the component itself and
then use the class prop to specify the classes for the elements within
the component.
For example, you could change this line:
<div className={className}>
to this:
<div className={className}>
<div className='flex flex-col'>
<div className="flex flex-row">
...
</div>
<div className="card-body">
...
</div>
</div>
</div>

React web app : Mapping <Popover.Button> and <Popover.Panel> separately

I want to render this popover panel
<Popover.Panel className="absolute z-10 inset-x-0 transform shadow-xl pb-2 w-max">
<div>
<Dropdown subCategory={mainCatArray}/>
</div>
</Popover.Panel>
same as this popover button render in this below code. Because I want to render a separate popover panel with the popover button, please help me to do that. (I cannot render in one categoryObj because I want to render this popover button horizontally, but if I use a single map for the entire popover component popover button renders it vertically.
(Simply What I want to do is I want to render one <Popover.Panel> to one <Popover.Button>)
import { Fragment, useEffect, useState } from "react";
import { Popover, Transition } from "#headlessui/react";
import Dropdown from "./dropdown";
import { categoryObj } from "../../components/item/categoriesobj";
function classNames(...classes) {
return classes.filter(Boolean).join(" ");
}
const CatDropDown = () => {
const [mainCatArray, setMainCatArray] = useState([]);
return (
<>
<Popover className="z-0 relative">
{({ open }) => (
<>
<div>
<div className=" z-10 bg-white">
<div className="w-2/3 flex gap-5 px-4 py-6 sm:px-6 lg:px-8 ">
{categoryObj.map((singleMainCategory) => (
<Popover.Button
className={classNames(
open ? "text-gray-900" : "text-gray-900",
"group bg-white rounded-md inline-flex items-center text-sm font-susty focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-white"
)}
>
<span
key={singleMainCategory.id}
onClick={() => {
setMainCatArray(singleMainCategory.subCategory);
}}
>
<span>{singleMainCategory.name}</span>
</span>
</Popover.Button>
))}
</div>
</div>
</div>
<Transition
as={Fragment}
enter="transition ease-out duration-200"
enterFrom="opacity-0 -translate-y-1"
enterTo="opacity-100 translate-y-0"
leave="transition ease-in duration-150"
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 -translate-y-1"
>
<Popover.Panel className="absolute z-10 inset-x-0 transform shadow-lg pb-2">
<div>
<Dropdown subCategory={mainCatArray}/>
</div>
</Popover.Panel>
</Transition>
</>
)}
</Popover>
</>
);
};
export default CatDropDown;

REACT onMouseEnter/onMouseLeave PopUp flickering loop

I'm building a button that shows a PopUp when hovered. To achieve this, I'm using the state "activeToolTip" that turns true "onMouseEnter" / false "onMouseLeave", and in turn renders the PopUp ({activeToolTip ? ( <>popUp<> : null)).
However, when hovering the button, the PopUp flickers between the onMouseEnter and onMouseLeave.
Can you help me understand the problem?
My code:
import { TooltipClose } from "../../../utils/svg";
export default function CustomTooltipsRed() {
const [activeToolTip, setActiveToolTip] = useState(false);
let TooltipTimeout;
const showToolTip = () => {
TooltipTimeout = setTimeout(() => {
setActiveToolTip(true);
}, 50);
};
const hideToolTip = () => {
setActiveToolTip(false);
clearInterval(TooltipTimeout);
};
return (
<div className="flex items-center justify-center ">
<button
className="bg-pink-500 text-white font-bold uppercase text-sm px-6 py-3 rounded shadow mr-1 mb-1 "
onMouseEnter={() => showToolTip()}
onMouseLeave={() => hideToolTip()}
>
Hover button
</button>
{activeToolTip ? (
<>
<div className="justify-center items-center flex fixed inset-0 outline-none focus:outline-none ">
<div className="relative w-auto my-6 mx-auto max-w-xl">
{/*content*/}
<div className="border-0 rounded-lg shadow-lg relative flex flex-col w-full bg-[#F43F5E] outline-none">
{/*header*/}
<div className="flex items-center justify-start p-2 rounded-t">
<div className="mr-2">
<i><TooltipClose /></i>
</div>
<h3 className="text-base font-semibold text-white">
P1 - Priority Issue
</h3>
</div>
{/*body*/}
<div className="relative p-6 flex-auto bg-[#1E293B] rounded-b-lg">
<p className="text-[#E2E8F0] leading-relaxed">
We have detected that your tenant has legacy protocols enabled.
Why is this an issue? Legacy protocols can not enforce multi factor
authentication and are considered a security risk.
</p>
Read More
</div>
</div>
</div>
</div>
<div className="inset-0 z-40"></div>
</>
) : null}
</div >
);
}
Add pointer-events-none to the tooltip.

Animate conditional components in Reactjs to slide in, fade in

I am trying to add some user experience with animations. The problem is the way I have my screen set up. Currently I don't render my sidebar when it's closed, and it looks great and it's responsive, but it seems that I cannot add animations because of the layout I've chosen. As conditionally rendered components don't seem to work with animations.
export default function Layout(props) {
const [open, setOpen] = useState(false);
const isMobile = useMediaQuery({ query: "(max-width: 768px)" });
return (
<div className="relative h-screen w-screen flex">
/// SIDEBAR
{open && (
<section className={"fixed top-0 left-0 bg-white h-screen z-20 w-64 md:relative md:w-1/3 delay-400 duration-500 ease-in-out transition-all transform "
+ (open ? " translate-x-0 " : " translate-x-full ")}></section>
)}
{open && isMobile && (
<div
onClick={(ev) => {
setOpen(false);
}}
className="fixed left-0 mt-0 bg-black bg-opacity-60 w-screen h-screen z-10"
></div>
)}
<div className="relative w-full h-full">
/// TOP BAR
<div className="absolute top-0 h-16 w-full bg-blue-600 flex flex-row items-center p-2 z-5">
<MenuIcon
onClick={(ev) => {
setOpen(!open);
}}
className="text-white"
width={30}
height={30}
></MenuIcon>
</div>
/// CONTENT
<div className="pt-16 h-full w-full overflow-y-auto">{props.children}</div>
</div>
</div>
);
}
Tried using something like this delay-400 duration-500 ease-in-out transition-all transform " + (isOpen ? " translate-x-0 " : " translate-x-full ")
Is there a way to do appearing/ disappearing animations with my current setup or do I have to change the layout entirely?
This is how it currently looks like

React - Hide parent's child element on blur event

I'm working on a custom input component. so when user clicks on the input element I want to show a dropdown that will contain default ten records and if user types some keyword in the input the dropdown will be updated with the results matching the keyword.
when user clicks on the input I want to show the dropdown and If they click out the container I want to hide the dropdown.
so I've added an onBlur event to the container and now if I click somewhere else it hides the dropdown but If I try to select a record It's also hidding the dropdown which is incorrect.
How can I hide the dropdown when the clicks outside of the input container? any suggestions?
export const ListBoxInput = ({ label, data, keyName }) => {
const [selected, setSelected] = useState({ key: null, value: null });
const [showDropdown, setShowDropdown] = useState(false);
return (
<div
className='flex items-center space-x-3'
onBlur={() => setShowDropdown(false)}
>
<label className='block text-sm font-medium text-gray-700'>{label}</label>
<div className='relative group'>
<input
type='text'
value={selected.key}
onFocus={() => setShowDropdown(true)}
onChange={(e) => setSelected({ key: e.target.value, value: null })}
disabled={!data.length}
placeholder={!data.length ? 'No data...' : ''}
className='w-full py-2 pl-3 pr-10 mt-1 text-left bg-white border border-gray-300 rounded-md shadow-sm disabled:opacity-50 focus:outline-none focus:ring-1 focus:ring-brand focus:border-brand sm:text-sm'
/>
{showDropdown && (
<div className='absolute z-10 w-full py-1 mt-3 overflow-auto text-base bg-white rounded-md shadow-lg max-h-56 ring-1 ring-black ring-opacity-5 focus:outline-none '>
{data.map((r) => (
<button
key={r.id}
type='button'
onClick={() => {
setSelected({ key: r[keyName], value: r.id });
setShowDropdown(false);
}}
className='block w-full py-2 pl-3 text-left hover:bg-gray-100 pr-9'
>
{r[keyName]}
</button>
))}
</div>
)}
</div>
</div>
);
};

Categories