Automatic Typewriter effect in React Typescript - css

I want to apply such a Typewriting effect, I am still struggling with styled components.
I know that I need to define two animations, one for typing to animate the characters and second to blink to animate the caret.
Then I apply the :after pseudo-element inline to add the caret to the container element. With Javascript I can set the text for the inner element and set the --characters variable containing the character count. This variable is used to animate the text.
Wite-space: nowrap and overflow: hidden are needed to make content invisible as necessary.
But its not working in my App. I declared all styles and apply them inline.
App.tsx
import React from 'react';
import { Box } from '#mui/material';
const styles = {
typewriterEffect: {
display: "flex",
justifyContent: "center",
fontFamily: "monospace",
},
"typewriter-effect > text": {
maxWidth: 0,
animation: "typing 3s steps(var(--characters)) infinite",
whiteSpace: "nowrap",
overflow: "hidden",
},
"typewriter-effect:after": {
content: " |",
animation: "blink 1s infinite",
animationTimingFunction: "step-end",
},
"#keyframes typing": {
"75%",
"100%": {
maxWidth: "calc(var(--characters) * 1ch)",
},
},
"#keyframes blink": {
"0%",
"75%",
"100%": {
opacity: 1,
},
"25%": {
opacity: 0,
}
}
};
function Typewriter() {
const typeWriter: HTMLElement | null = document.getElementById('typewriter-text');
const text = 'Lorem ipsum dolor sit amet.';
typeWriter.innerHTML = text;
typeWriter.style.setProperty('--characters', text.length);
return (
<Box style={styles.typewriterEffect}>
<Box class="text" id="typewriter-text"></Box>
</Box>
);
}
export {Typewriter};

Forked into your codesandbox to recreate your issue.
You could have used styled-components i.e
import { styled } from "#mui/material/styles";
given from MUI to create styles same as Codepen Example.
Below is my solution -
https://codesandbox.io/s/automatic-typewriter-effect-stackoverflow-y546o7?file=/src/Typewriter.tsx

Related

Griffel - CSS in JS - Cannot overwrite child class rule on parent element hover

I'm using Griffel https://griffel.js.org/ for the first time and I am struggling to achieve this simple thing. By default this button is hidden and when the user hover's over the parent I want to make the child visible.
I am using React so I have this button component inside the parent div.
const styles = useStyles();
<div className={styles.userContainer}>
<Button className={styles.removeUserButton} />
</div>
CSS:
export const useStyles = makeStyles({
removeUserButton: {
display: 'none'
},
userContainer: {
backgroundColor: '#fefefe',
'&:hover': {
'& removeUserButton': {
display: 'inline-block'
}
}
}
})
I was not sure if it will know what the removeUserButton class is so I also tried by making it variable. So I added:
const removeUserClassName = 'removeUserButton';
on top of the file and then in CSS:
[removeUserClassName]: {
display: 'none'
},
userContainer: {
backgroundColor: '#fefefe',
'&:hover': {
[`& ${removeUserClassName}`]: {
display: 'inline-block'
}
}
}
But this still does not work.
And in case you are wondering I have also tried the first piece of code by adding . before removeUserButton.
Has anyone used Griffel and knows how to handle this?
Appreciate any guidance. Thank you!
Here is a sandbox I created:
https://codesandbox.io/s/griffel-hover-issue-gwx1sj
The issue is that you are attempting to use a classname that is in your configuration (removeUserClassName). Yet, Griffel uses dynamic class names. So you'll need to use a different selector.
You can see the nature of the dynamic class names in this playground example.
Here is a working StackBlitz that uses the button as selector rather than class name and it works fine.
Here is the code for reference:
import { makeStyles } from '#griffel/react';
export const useStyles = makeStyles({
removeUserButton: {
display: 'none',
},
userContainer: {
width: '150px',
height: '50px',
backgroundColor: 'black',
':hover': {
'& button': { display: 'inline-block' },
backgroundColor: 'blue',
},
},
});

React animation inline styling

I am practicing React inline animation styling. I have made one toggle button, when user press button first time, I want pop up animated card from left to right. when user press button 2nd time it will close the card from right to left. I want to learn how the animation work inline react styling. Unfortunately I am unable to do that. Seems like React inline styling, transitions and translate does not work to me. This is the animation I want to do it. I shared my code in code-sandbox.
This is my code
import { useState } from "react";
export default function App() {
const [toggle, setToggle] = useState(false);
return (
<>
<button onClick={(): void => setToggle(!toggle)}>toogle button</button>
{toggle && (
<div
style={{
display: "flex",
zIndex: 1,
marginLeft: 170,
background: "red",
width: 200,
height: 300,
opacity: 1,
backgroundColor: "tomato",
transition: "opacity 5s"
}}
>
<p style={{ margin: "0px" }}>animation</p>
</div>
)}
</>
);
}
I don't think that this is a good idea, but here is one solution.
You can control everything.
import "./styles.css";
import { useState } from "react";
export default function App() {
const transitions = ["linear", "ease", "ease-in", "ease-out", "ease-in-out"];
const [opacity, setOpacity] = useState(0);
const [right, setRight] = useState(40);
const speed = 0.5;
return (
<>
<button
onClick={() => {
setOpacity(opacity ? 0 : 1);
setRight(prev => prev === 40 ? 20 : 40);
}}
>
toogle button
</button>
<div
style={{
display: "flex",
zIndex: 1,
marginLeft: 170,
background: "red",
width: 200,
height: 300,
opacity,
backgroundColor: "tomato",
transition: `all ${transitions[1]} ${speed}s`,
transform: `translateX(-${right}%)`
}}
>
<p style={{ margin: "0px" }}>animation</p>
</div>
)
</>
);
}
You could use the inlined styles, but you cannot achieve the desired behavior without the use of CSS or a third party library doing the animations for you.
I would recommend to check out this: https://www.w3schools.com/css/css3_animations.asp
Another problem that I see:
You are displaying the content only as soon as the "toggle" property is true, but for animations you need to have different states in your markup in order to transition to different states of animation.
E.g.
<div className="opening">
<div className="opened">
<div className="closing">
<div className="closed"> (or removed from DOM)
Then you can apply the CSS #keyframes to all different stages using the corresponding CSS selectors.
Or if you don't want to dig into CSS yourself. You can use e.g. this library to do the job: https://react-spring.dev/

Material-UI style buttons on the right

How do you align buttons on the right using Material-UI's makeStyles function?
I have tried using CSS's margin-right: 0 tag, but there is an error using '-' with makeStyles.
I renamed it as 'marginRight' and it still does not work. Also mr: 0 is not valid either. (Using Material-UI's spacing).
The code is trying to make the UI similar to stackOverflow's title layout.
import React from 'react';
import { makeStyles } from "#material-ui/core/styles";
import { Box, Button } from "#material-ui/core";
const style = makeStyles({
titleItemRight: {
color: 'white',
backgroundColor: 'blue',
top: '50%',
height: 30,
align: 'right',
position: 'relative',
transform: 'translateY(-50%)',
}
});
const App = () => {
const classes = style();
return (
<div>
<Box className={classes.titleBar}>
<Button variant='text' className={classes.titleItemRight}>Sign In</Button>
</Box>
</div>
);
};
Change,
align: 'right'
To,
float: 'right'
So the code would look like,
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import { Box, Button } from "#material-ui/core";
const style = makeStyles({
titleItemRight: {
color: "white",
backgroundColor: "blue",
top: "50%",
height: 30,
float: "right",
position: "relative",
transform: "translateY(-50%)"
}
});
const App = () => {
const classes = style();
return (
<div>
<Box className={classes.titleBar}>
<Button variant="text" className={classes.titleItemRight}>
Sign In
</Button>
</Box>
</div>
);
};
Working Codesandbox
I'd suggest using a flexbox for this or just using the AppBar provided already by material ui
https://material-ui.com/components/app-bar/#app-bar
if you'd still like to use Box, just edit the titleBar styles this way and add a spacer element to seperate elements to far right or far left
const style = makeStyles({
titleBar: {
display: 'flex',
width:'100%',
flexFlow: 'row',
},
spacer: {
flex: '1 1 auto'
}
});
and then your component
<Box className={classes.titleBar}>
<LogoHere/>
<div className={classes.spacer}/>
<Button variant="text">
Sign In
</Button>
</Box>

How to make Material-UI Snackbar not take up the whole screen width using anchorOrigin?

I have a class in React which uses an input field which is part of the website header:
If the input is invalid then I want to display a snackbar. I'm using Material-UI components.
The problem is I defined anchorOrigin to be center and top as per Material-UI API. However the snackbar takes up the whole screen width while I want it to only take up the top center location of the screen. My message is quite short, for example "Value invalid" but if it's longer then I should be able to use newlines. I'm not sure if there's some setting in Material-UI API to alter this (I couldn't find one) or I need to use CSS.
This is my code:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import InputBase from '#material-ui/core/InputBase';
import Snackbar from '#material-ui/core/Snackbar';
import SnackbarMessage from './SnackbarMessage.js';
const classes = theme => ({
inputRoot: {
color: 'inherit',
width: '100%',
},
inputInput: {
paddingTop: theme.spacing.unit,
paddingRight: theme.spacing.unit,
paddingBottom: theme.spacing.unit,
paddingLeft: theme.spacing.unit * 10,
transition: theme.transitions.create('width'),
width: '100%',
[theme.breakpoints.up('sm')]: {
width: 120,
'&:focus': {
width: 200,
},
},
}
});
class Test extends Component {
state = {
appId: '',
snackBarOpen: false
}
render() {
return (
<div>
<InputBase
placeholder="Search…"
classes={{
root: classes.inputRoot,
input: classes.inputInput,
}}
value={'test'} />
<Snackbar
anchorOrigin={{
vertical: 'top',
horizontal: 'center'
}}
open={true}
autoHideDuration={5000}
>
<SnackbarMessage
variant="warning"
message={"test message"}
/>
</Snackbar>
</div>
)
}
}
Material-UI set Snackbars to full viewport-width below the breakpoint "md" (600px).
You can use overrides (https://material-ui.com/customization/overrides/) and set new values to the default CSS classes of the component described in the components API (i.e. https://material-ui.com/api/snackbar/). So you can override the class anchorOriginTopCenter as follows:
const styles = theme => ({
anchorOriginTopCenter: {
[theme.breakpoints.down('md')]: {
top: "your value/function here",
justifyContent: 'center',
},
},
root: {
[theme.breakpoints.down('md')]: {
borderRadius: 4,
minWidth: "your value / function here",
},
},
});
The first objects overrides the default class {anchorOriginTopCenter}, the second 'root' is applied to first element in your snackbar (probably a 'div').
I do not know if we can add some style to the component anchor origin field. I think the div needs to be managed using CSS. It's an anchor, not style.
<Snakbar
className = "my-snakbar"
{/*All your other stuff*/}
>
{//Stuff}
</Snakbar>
CSS
.my-snakbar {
width: 200px;
//Maybe use flexbox for positioning then
}
Let me know your thoughts
Daniel
Improved Answer
Code copied from origional question and modified
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Snackbar from '#material-ui/core/Snackbar';
const classes = theme => ({
inputRoot: {
color: 'inherit',
width: '100%',
},
inputInput: {
paddingTop: theme.spacing.unit,
paddingRight: theme.spacing.unit,
paddingBottom: theme.spacing.unit,
paddingLeft: theme.spacing.unit * 10,
transition: theme.transitions.create('width'),
width: '100%',
[theme.breakpoints.up('sm')]: {
width: 120,
'&:focus': {
width: 200,
},
},
}
});
class ComingSoon extends Component {
render() {
const styles = {
container: {
position: "fixed",
top: "0px",
width: "100%",
height: "30px"
},
snakbar: {
background: "black",
color: "white",
width: "100px",
height: "100%",
display: "flex",
justifyContent: "center",
alignContent: "center",
margin: "0 auto"
}
};
return (
<div className = "snakbar-container" style = {styles.container}>
<Snackbar
className = "my-snakbar"
style = {styles.snakbar}
anchorOrigin={{
vertical: 'top',
horizontal: 'center'
}}
open={true}
autoHideDuration={5000}
>
<span>My Message</span>
</Snackbar>
</div>
)
}
}
export default ComingSoon;
Screen shot:
Let me know if this helped
Daniel

How to removing the padding for card in and design?

I am using ant design to react UI components. I need to remove the padding given for the ant design card.
So I need to remove the padding given for the classes .ant-card-wider-padding and .ant-card-body.I am using JSS for styling the UI components.
cardStyle: {
marginTop: '30px',
boxShadow: '0px 1px 10px rgba(0,1,1,0.15)',
backgroundColor: '#ffffff',
borderStyle: 'solid',
outline: 'none',
width: '100%',
},
i am using cardStyle class to styling ant design card.Now i need to remove the padding in that card.
From the documentation of Ant Design
You need to override the style in bodyStyle not cardStyle
bodyStyle: Inline style to apply to the card content
<Card title="Card title" bodyStyle={{padding: "0"}}>Card content</Card>
use fullWidth props for removing padding..,
<Card.Section fullWidth>
<ResourceList
items={[
{
id: 341,
url: 'customers/341',
name: 'Mae Jemison',
location: 'Decatur, USA',
}
]}
renderItem={
(item) => {
const {id, url, name, location} = item;
const defaultImage = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNLS4wMi0uMDFoMTAwdjEwMGgtMTAweiIgZmlsbD0iI2ZmZTBjMyIvPjxwYXRoIGZpbGw9IiNmZjk2N2QiIGQ9Ik0wIDBoNjkuNDF2MTAwSDB6Ii8+PHBhdGggZD0iTTY5LjkyIDB2NDQuMzJMNTEuMzQgNTV2NDVIMTAwVjB6IiBmaWxsPSIjZmZlMGMzIi8+PHBhdGggZmlsbD0iIzMyY2FjNiIgZD0iTTM5LjMyIDc2YTExLjg1IDExLjg1IDAgMCAwIDEyIDExLjYyVjc2Ii8+PHBhdGggZmlsbD0iIzAwOTc5NiIgZD0iTTM5LjMyIDc2YTEyIDEyIDAgMCAxIDEyLTExLjgyVjc2Ii8+PHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmZmIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLXdpZHRoPSI1IiBkPSJNNDMuNzQgMTkuODNhMTIuODIgMTIuODIgMCAxIDEtMjUuNjQgMCIvPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS13aWR0aD0iNCIgZD0iTTI3LjM5IDMxLjZsLTEuNTggNS45Nm05LjM3LTUuNzJsMi41NSA1LjQ3bTQuMjYtOS44NWwzLjUzIDQuNW0tMjUuNDMtNC41bC0zLjUzIDQuNSIvPjwvc3ZnPgo=" ;
const media = <Thumbnail source={defaultImage} size="small" name={name} />;
return (
<ResourceList.Item id={id} url={url} media={media}>
<Stack alignment="center">
<Stack.Item fill>
<TextStyle>{name}</TextStyle>
</Stack.Item>
<Stack.Item>
<TextStyle>Last changed</TextStyle>
</Stack.Item>
<Stack.Item>
<Button>Edit Giffy</Button>
</Stack.Item>
</Stack>
</ResourceList.Item>
);
}
}
/>
</Card.Section>
very simple just add bodyStyle in Card Component
<Card bodyStyle={{ padding: "0"}}>
You can use this:
.cardStyle {
padding: 0;
}
If didn't work, use this:
.cardStyle {
padding: 0 !important;
}
I'm not too familiar with JSS but if your other styles are being applied then I assume the issue is not with that.
I was able to remove the padding from the card with the following code.
//style.less
.panelcard { ... }
.panelcard .ant-card-body {
padding: 0;
}
// panelCard.js
import { Card } from 'antd';
require('./style.less');
const PanelCard = ({ children }) => {
return (
<Card className='panelcard'>
{children} // <p>Some Child Component(s)</p>
</Card>
);
}
// invocation
<PanelCard label='Panel Title'>
<p>Some Child Component(s)</p>
</PanelCard>
This gave me the following output (card is the white box):
I am not sure if this is the preferred way of customizing antd's components but I didn't really find too much on antd's website about overriding styles, only on extending components.
Try using :global in you scss/less
div { // or any parent element/class
:global {
.ant-card-body {
passing: <number>px; // number can be 0 onwards
}
}
}

Resources