Keyframes with Inline Styles ReactJS - html

I'm trying to set the keyframes of a pulsate animation in ReactJS. I tried just setting the keyframes inside the inline style but that doesn't work.
My code
const NewRelpyheButton = ({style = {}, open, handleOPenSettings}) => {
var bar = {
color: '#000',
padding: '1em 0',
fontSize: '20px',
textAlign: 'center',
cursor: 'pointer',
position: 'fixed',
bottom: '0',
width: '100%',
zIndex: '10',
animation: 'pulse 1.2s ease-in-out',
animationIterationCount: 'infinite',
}
Object.assign(style, {});
let openModal;
if (open) {
openModal = <Modal><NewRelpyhe/></Modal>
}
return (
<div>
{openModal}
<Bar color='purple' style={bar} onClick={handleOpenSettings}>
create a new relphye site
</Bar></div>
)
}
I'm trying to mimic this in css:
.element {
width: 100%;
height: 100%;
animation: pulse 5s infinite;
}
#keyframes pulse {
0% {
background-color: #001F3F;
}
100% {
background-color: #FF4136;
}
}
html,
body {
height: 100%;
}

If you like to keep all your styling tightly coupled to your components, give Styled Components a go. They have a helper for keyframes
e.g.
import styled, { keyframes } from 'styled-components'
const pulse = keyframes`
from {
background-color: #001F3F;
}
to {
background-color: #FF4136;
}
`
const Bar = styled.div`
color: #000;
padding: 1em 0;
font-size: 20px,
text-align: center;
cursor: pointer;
position: fixed;
bottom: '0',
width: 100%;
z-index: 10;
animation: ${pulse} 1.2s ease-in-out;
animation-iteration-count: infinite;
`
Then use like so:
<Bar>I pulse</Bar>

Here's how we will achieve it without adding any dependency.
{/*Your Js File Code */}
import { StrictMode } from "react";
import ReactDOM from "react-dom";
import React from "react";
import "./test.css";
class Anim extends React.Component {
constructor(props) {
super(props);
this.state = {
animationName: ""
};
}
addStylesheetRules(rules) {
var styleEl = document.createElement("style");
document.head.appendChild(styleEl);
var styleSheet = styleEl.sheet;
styleSheet.insertRule(rules, 0);
}
clickHdl() {
let animationName = `animation${Math.round(Math.random() * 100)}`;
let keyframes = `
#-webkit-keyframes ${animationName} {
10% {-webkit-transform:translate(${Math.random() * 300}px, ${
Math.random() * 300
}px)}
90% {-webkit-transform:translate(${Math.random() * 300}px, ${
Math.random() * 300
}px)}
100% {-webkit-transform:translate(${Math.random() * 300}px, ${
Math.random() * 300
}px)}
}`;
this.addStylesheetRules(keyframes);
this.setState({
animationName: animationName
});
}
render() {
let style = {
animationName: this.state.animationName,
animationTimingFunction: "ease-in-out",
animationDuration: "0.6s",
animationDelay: "0.0s",
animationIterationCount: 1,
animationDirection: "normal",
animationFillMode: "forwards"
};
return (
<div>
<button type="button" onClick={this.clickHdl.bind(this)}>
Animation!
</button>
<div className="box" style={style}></div>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(
<StrictMode>
<Anim />
</StrictMode>,
rootElement
);
{/*Css Code test.css */}
.box {
width: 30px;
height: 30px;
background: red;
border-radius: 50%;
cursor: pointer;
}
Demo: https://codesandbox.io/s/reverent-sun-qjo91?file=/src/index.js

Related

Animate dialog overflows with visible scrolls

I have created a dialog that slides out on closing if on mobile view.
Otherwise it just scales backwards.
This component is based on the awesome work from here:
https://web.dev/building-a-dialog-component/#styling-with-open-props
With some tweeks of my own to adapt it to react and my own needs.
This will add scrollbar on html body for a breef second.
This is super annoying and only fix that works is to hide scrollbar on the html-tag.
html {
box-sizing: border-box;
margin: 0px; padding: 0px
&::-webkit-scrollbar {
display: none;
}
scrollbar-width: none;
}
I do not like this at all, are there any better solutions for this?
import { useEffect, useState, useRef } from "react";
import styled, { keyframes } from "styled-components";
import PropTypes from "prop-types";
import { shadow } from "shared/theme";
import { spacingIndex } from "shared/spacing";
const scaleDown = keyframes`
to { transform: scale(.75) }
`;
const slideOutDown = keyframes`
to { transform: translateY(100%) }
`;
const slideInUp = keyframes`
from { transform: translateY(100%) }
`;
const Container = styled.dialog`
display: ${({ open }) => (open ? "flex" : "none")};
justify-content: center;
align-items: center;
border-radius: 8px;
border: none;
max-inline-size: min(90vw, 60ch);
max-block-size: min(80vh, 100%);
overflow: hidden;
margin: auto;
padding: ${spacingIndex * 2}px;
inset: 0;
box-shadow: ${shadow.overlay};
transition: opacity 0.5s cubic-bezier(0.25, 0, 0.3, 1);
animation: ${scaleDown} 0.5s cubic-bezier(0.25, 0, 0.3, 1) forwards;
animation-timing-function: cubic-bezier(0.5, -0.5, 0.1, 1.5);
&:is([open]) {
animation: ${slideInUp} 0.5s cubic-bezier(0.25, 0, 0.3, 1) forwards;
}
&:not([open]) {
pointer-events: none;
opacity: 0;
}
::backdrop {
backdrop-filter: blur(4px);
transition: backdrop-filter 0.5s ease;
}
#media (max-width: 768px) {
animation: ${slideOutDown} 0.5s cubic-bezier(0.25, 0, 0.3, 1) forwards;
margin-block-end: 16px;
}
`;
const Dialog = ({ isOpened, onClose, children }) => {
const ref = useRef(null);
const [open, setOpen] = useState(false);
const isClickOutsideOfDialog = (dialogEl, event) => {
if (!dialogEl) return false;
const rect = dialogEl.getBoundingClientRect();
return (
event.clientY < rect.top ||
event.clientY > rect.bottom ||
event.clientX < rect.left ||
event.clientX > rect.right
);
};
const onDialogContainerClick = (event) => {
if (isClickOutsideOfDialog(ref.current, event)) onClose();
};
const handleAnimationEnd = (e) => {
if (slideInUp.name !== e.animationName) setOpen(false);
};
useEffect(() => {
ref.current?.addEventListener("animationend", handleAnimationEnd);
return () => ref.current?.removeEventListener("animationend", handleAnimationEnd);
}, []);
useEffect(() => {
if (!isOpened) ref.current?.close();
if (isOpened) {
setOpen(true);
ref.current?.showModal();
}
}, [isOpened]);
return (
<Container
{...{
ref,
open,
onClick: onDialogContainerClick,
}}>
{children}
</Container>
);
};
Dialog.propTypes = {
isOpened: PropTypes.bool,
onClose: PropTypes.func,
};
export default Dialog;
Edit: Guess I was tired and stupid..Just added position:fixed; because I then move the dialog out of the document flow.

How to add CSS animations to a ReactJs component

I'm working on a react component that would render a loading animations.
Here is the js file
import React from 'react'
import './css/CircleSpinner.css'
const CircleSpiner = () => {
return (
<div className="lds-circle" >
</div>
)
}
export default CircleSpiner
The CSS is on a separate file and the component doesn't render the animations as expected. Any help would be appreciated.
Here's the code sandbox for the above.
You need content or draw the circle:
.lds-circle > div {
display: inline-block;
width: 64px;
height: 64px;
margin: 8px;
border-radius: 50%;
border: 1px solid #000;
color: black;
animation: lds-circle 2.4s cubic-bezier(0, 0.2, 0.8, 1) infinite;
}
You are missing border: 1px solid #000; or content so you can view the circle.
Also define the CircleSpiner and use it on your app.js:
CircleSpiner.js
import React from 'react'
const CircleSpiner = () => {
return (
<div>
</div>
)
}
App.js
export default CircleSpiner
import "./styles.css";
import CircleSpiner from "./CircleSpiner"
export default function App() {
return (
<div className="App">
<div className="lds-circle">
<CircleSpiner></CircleSpiner>
</div>
</div>
);
}
Your CSS does not correspond to your html. Specifically, this rule here:
.lds-circle > div {
display: inline-block;
width: 64px;
height: 64px;
margin: 8px;
border-radius: 50%;
color: black;
animation: lds-circle 2.4s cubic-bezier(0, 0.2, 0.8, 1) infinite;
}
The .lds-circle > div selector means "any div which is a direct descendent of .lds-circle". You don't have any descendents of your class so it targets nothing. The second issue is that you are providing a color property which styles foreground elements like text, but you (presumably) want a background-color property to see the background of the div element.
So, putting those two together:
.lds-circle > div {
display: inline-block;
width: 64px;
height: 64px;
margin: 8px;
border-radius: 50%;
background-color: black;
animation: lds-circle 2.4s cubic-bezier(0, 0.2, 0.8, 1) infinite;
}
#keyframes lds-circle {
0%,
100% {
animation-timing-function: cubic-bezier(0.5, 0, 1, 0.5);
}
0% {
transform: rotateY(0deg);
}
50% {
transform: rotateY(1800deg);
animation-timing-function: cubic-bezier(0, 0.5, 0.5, 1);
}
100% {
transform: rotateY(3600deg);
}
}
<div class="lds-circle" >
<div></div>
</div>

Button Loading react-hooks-nextjs

I am doing a loading spinner button, When I press the button, the loading icon appears but does not disappear at the marked time, and continues with the load. Here is the code:
componentOne:
import React from 'react'
function Loader(){
return(
<>
<div className="loaderIcon"></div>
<style jsx>
{`
.loaderIcon{
border: 10px solid #f3f3f3;
border-radius: 50%;
border-top: 10px solid #3498bd;
width: 60px;
height: 60px;
animation: spin 2s linear infinite;
}
#keyframes spin{
0% { transform: rotate(0deg);}
100% { transform rotate(360deg);}
}
`}
</style>
</>
)
}
export default Loader;
componentTwo:
import React, {useState} from 'react';
import Loader from '../components/loader'
function ButtonLoading(){
const [loading, setLoading] = useState(false)
function loadData(){
setLoading ({loading: false})
setTimeout(()=>{
setLoading({loading: true});
}, 1000);
}
return(
<>
<div>
<button className="btnLoading" onClick={loadData} disabled={loading}>
{loading &&(<Loader/>)}
{loading && <span className="oneSpan">Loading page</span>}
{!loading && <span className="twoSpan">Load page</span>}
</button>
</div>
<style jsx>
{`
.btnLoading{
background-color: green;
}
.oneSpan{
color: red;
font-size: 20px;
}
.twoSpan{
color: black;
font-size: 20px;
}
`}
</style>
</>
)
}
export default ButtonLoading;
I think you got the loading backwards. I believe the function should look like `
function loadData(){
setLoading ({loading: true})
setTimeout(()=>{
setLoading({loading: false});
}, 1000);
}`
SetTimeout runs the function AFTER the timer is up

How to animate width using inline css

I'm trying to animate a width of an element using data from an API upon page load and I'm using Vue js. What I've done is I used inlined css and apply width value (from API data). I'm able to add the element width but it has no animation.
Vue template edited:
<li v-for="(stats, index) in teamStats[0]">
<div class="bar">
<span :style="'width:'+ stats +'%;'">
{{stats}}
</span>
</div>
</li>
Sass:
.bar {
span {
text-align: $l;
right: 0;
width: 0%;
-webkit-transition: width 1s;
-moz-transition: width 1s;
-o-transition: width 1s;
transition: width 1s;
}
}
You'll probably need to use the JavaScript transition hooks. Here's an example.
new Vue({
el: '#app',
data: {
stats: [],
},
created() {
// Simulate loading data from server
setTimeout(() => {
this.stats = [0.1, 0.15, 0.32, 0.55, 0.88, 0.96];
}, 500);
},
methods: {
onEnter(el) {
var stat = +el.dataset.stat;
var index = +el.dataset.index;
el.style.transitionDelay = index * 0.05 + 's';
el.style.width = (stat * 100) + '%';
el.style.backgroundColor = `hsl(${50 - 50 * stat | 0}, 100%, 50%)`;
},
},
});
.bars {
width: 400px;
}
.bar {
margin: 5px 0;
height: 30px;
display: flex;
align-items: center;
justify-content: flex-end;
color: white;
font-family: sans-serif;
font-weight: bold;
padding: 5px;
box-sizing: border-box;
white-space: nowrap;
overflow: hidden;
}
.bar.v-enter-active {
transition: all 1s cubic-bezier(0, 1, 0.5, 1);
}
.bar.v-enter {
/* Needs !important to override inline styles */
opacity: 0;
width: 0% !important;
background-color: hsl(50, 100%, 50%) !important;
}
<script src="https://cdn.rawgit.com/vuejs/vue/dev/dist/vue.min.js"></script>
<div id="app">
<transition-group tag="div" class="bars" #enter="onEnter">
<div class="bar" v-for="stat, index of stats" :key="stat" :data-stat="stat" :data-index="index">
{{ (stat * 100 | 0) }}%
</div>
</transition-group>
</div>

How can I get rid of these mysterious grey boxes at the margins of a div element?

I am having a mysterious problem that did not exist yesterday (you know those?). For some reason, these grey boxes are appearing at the edges of an element that appears when a user hovers over its parent element. they appear to the right and bottom. Essentially, everything below the check and x images is a div with a class of .bottom. I have set to 50% of parent height and 100% of its width. These are react components, so it may be a tad hard to follow. The EventDetail component is nested in the Event component.
.eventcontainer {
padding: 5px;
width: 960px;
margin: 20px auto;
}
.event {
margin-top: 2%;
width: 960px;
border-color:#496DD9;
border-style: dotted;
font-size: 0.5em;
height: 300px;
position: relative;
-webkit-transition: height 300ms ease-out;
}
.event:hover {
height: 400px;
-webkit-transition: height 300ms ease-in;
}
.event:hover .hidden {
display: block;
opacity: 1;
-webkit-transition: opacity 300ms ease-in 200ms;
}
.hidden {
opacity: 0;
overflow: scroll;
-webkit-transition: opacity 100ms ease-out;
}
.bottom {
position: absolute;
bottom: 0;
padding-bottom: 2%;
padding-left: 2%;
font-size: 13px;
width: 100%;
height: 50%;
}
const EventDetail = (props) => {
const options = {
color: '#DE5745',
trailWidth: 1,
strokeWidth: 10,
};
const containerStyle = {
width: '100px',
height: '20px',
};
const showUpdate = (e) => {
e.preventDefault();
props.dispatch(renderUpdate(props.id));
};
return (
<div className=" bottom hidden" >
<p>Attendance</p>
<div className="progressbar">
<Line progress={(props.attending / props.capacity)} containerStyle={containerStyle} initialAnimate options={options} containerClassName={'.progressbar'} />
<span>{props.attending}</span><span>/</span><span> {props.capacity}</span>
</div>
{/* <div>{props.attendeeHelperFunction(props.attendeeList)}</div>*/}
<p>Description:</p>
{props.description === '___' ? <p>The owner did not provide a description. So mysterious</p> : <p>{props.description}</p>}
{window.localStorage.getItem('userid') === props.owner_id ?
<div>
<Update
event_title={props.title}
event_description={props.description}
event_capacity={props.capacity}
event_id={props.event_id}
/>
</div>
: null}
</div>
);
};
const Event = (props) => {
const attendHandler = (e) => {
e.preventDefault();
props.dispatch(attendEvent(props.id))
.then(() => {
props.dispatch(fetchEvents());
});
};
const flakeHandler = (e) => {
e.preventDefault();
props.dispatch(flakeEvent(props.id))
.then(() => {
props.dispatch(fetchEvents());
})
.catch(err => console.log(err));
};
return (
<div className="event">
<section className="eventdescription">
<p>{props.title}</p>
<p>{props.date}</p>
<p>Hosted by: {props.owner}</p>
<p>{console.log('EVENT', renderEvents)}</p>
</section>
<section className="attend"><img onClick={attendHandler}className="eventgraphic" src={check} alt="" /></section>
<section className="unattend"><img onClick={flakeHandler}className="eventgraphic" src={crossout} alt="" /></section>
<EventDetail
title={props.title}
event_id={props.id}
owner_id={props.owner_id}
attending={props.attendees}
capacity={props.capacity}
description={props.description}
attendeeList={props.attendeeList}
attendeeHelperFunction={props.attendeeHelperFunction}
/>
</div>
);
};
They are scrollbars, duh! But if anyone ever stumbles onto this thread, here is a style generator for scroll bars https://mikethedj4.github.io/Webkit-Scrollbar-Generator/