I'm trying to focus() an input inside a modal right after it opens using the modal's componentDidUpdate().
This is the CSS I'm using for the modal root element:
.auth-modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
align-items: center;
visibility: hidden;
opacity: 0;
transition: visibility 400ms, opacity 400ms;
&.auth-modal_is-opened {
visibility: visible;
opacity: 1;
}
}
As you can see, it has visibility: hidden; and opacity: 0; at first.
Then I have this in the modal component:
componentDidMount() {
this.emailInput.focus();
}
componentDidUpdate() {
this.emailInput.focus();
}
The componentDidMount() hook works as intended, the input gets focused, but the componentDidUpdate() hook does not work (as though it gets called, only the focus() doesn't work as intended).
I've managed to find the reason and it happens to be the CSS animation. If I remove the visibility animation it works (but the animation breaks, of course). I've also managed to make it work using a setTimeout() inside the hook as bellow:
componentDidUpdate() {
setTimeout(() => {
this.emailInput.focus();
}, 100);
}
This also works, but feels super hackish.
Is there any better way to achieve this? (I'm currently setting a timeout as a hack solution)
Related
I'm working on building a responsive mobile navigation menu, and ran into an error with toggling open/close
The way I decided to go about it is to add className="show" that has a property of display: block to what's currently active, and className="hide" with a property of display: none.
This is my set up:
import {MenuOpen, MenuClose} from '../assets/AssetsIndex';
function menuActive() {
let menu = document.getElementById('mobile-menu');
let menuOpen = document.getElementById('menu-open');
let menuClose = document.getElementById('menu-close');
menu.classList.contains('active') ? open() : close();
function close() {
menu.classList.add('active');
menuClose.classList.add('show');
menuOpen.classList.add('hide');
menu.style.transform = 'translateX(0%)';
}
function open() {
menu.classList.remove('active');
menuOpen.classList.add('show');
menuClose.classList.add('hide');
menu.style.transform = 'translateX(100%)';
}
}
Initializing the menu icon with the class name:
<MenuOpen className='menu show' onClick={menuActive} id='menu-resting' />
<MenuClose className='menu hide' onClick={menuActive} id='menu-open' />
Scss:
.menu {
cursor: pointer;
margin: 0 auto;
position: absolute;
right: 2%;
z-index: 100;
&:hover path {
fill: #fff;
}
path {
fill: #fff;
}
}
.show {
display: block;
}
.hide {
display: none;
}
Error:
I went about displaying the menu container in the same way, so I'm not sure why I can't do the same with an SVG element. I've tried adding the properties with JS but ran into the same issue of the property value is null.
If anyone can tell me what I'm doing wrong that would be greatly appreciated.
There is no element with id menu-close in your code. Probably a typo. Assuming id prop of the MenuClose component is the id of the underlying element you have menu-open there.
Also, I would suggest using state hook for controlling whether the Menu is open or closed.
Where should I put react transition group style classes in my scss ? I want to animate fading. After inspecting it in action I clearly see the classes attached, but with no effect. I think I treid putting them almost everywhere.
Anyone with experience ?
#transitionGroupDiv{
// gallery styles etc.
// NOT WORKING HERE
.fade-enter {
opacity: 0;
}
.fade-enter-active {
opacity: 1;
transition: opacity 10000ms ease-out;
}
.fade-leave {
opacity: 1;
}
.fade-leave-active {
opacity: 0;
transition: opacity 10000ms ease-out;
}
.element{
// other styles etc.
}
}
I actually was not aware of scss rules. You have to use the parent selector reference &.
Example in this question: SO question.
I had a styled component that was rendering 3 times, each having a parallax effect.
const ParallaxContainer = styled.section`
position: absolute;
left: 0;
right: 0;
height: 100%;
opacity: 0.3;
bottom: ${props => props.bottomValue}px;
`;
The parallax is achieved by updating the bottom value every scrollEvent through a pretty expensive calculation. Meaning, this component is getting re-rendered very often.
Unsurprisingly, I was getting the warning Over 200 classes were generated for component styled.section. Consider using the attrs method, together with a style object for frequently changed styles. So I tried to follow the advice, and refactored the component to this:
const ParallaxContainer = styled.section.attrs(
({ bottomValue }) => ({
style: {
bottom: bottomValue + "px"
}
})
)`
position: absolute;
left: 0;
right: 0;
height: 100%;
opacity: 0.3;
`;
But I am still getting the same error. What am I doing wrong?
Sandbox demonstrating my issue: https://codesandbox.io/embed/styled-components-is-yelling-at-me-attrs-zhnof
The problem is the lines you left commented out in your style. Remember, your style is just a template string. The CSS-style commented lines are only ignored after the string has been interpolated and passed to Styled Components.
The Over 200 classes error happened in the first place because the style string needed to be re-computed on every scroll event, which results in a completely new styled component instance. Moving it to attrs is like defining the style in JS in the old-fashioned React way, so these styles don't go through Styled Components.
In parent template I'm specifying ui-view where the child view should appear, I also include animation, like this:
<div class="am-fade-and-slide-bottom" ui-view></div>
So I want animation to appear when something has been put ten in this view. And it works! And if I remove that ui-view (well, go to the previous state when using ui-router), I get animation of hiding that view.
The problem is, that when I'm changing the content of ui-view, I get repeated animations of hiding-and-showing, though I want to to stay without animation this time (as I have loading indicator on the template which goes inside ui-view).
How would I do that?
This is class .am-fade-and-slide-bottom from the Angular Motion library:
.am-fade-and-slide-bottom {
animation-duration: #fade-and-slide-duration;
animation-timing-function: #fade-and-slide-timing-function;
animation-fill-mode: backwards;
&.am-fade-and-slide-bottom-add, &.ng-hide-remove, &.ng-move {
animation-name: fadeAndSlideFromBottom;
}
&.am-fade-and-slide-bottom-remove, &.ng-hide {
animation-name: fadeAndSlideToBottom;
}
&.ng-enter {
visibility: hidden;
animation-name: fadeAndSlideFromBottom;
animation-play-state: paused;
&.ng-enter-active {
visibility: visible;
animation-play-state: running;
}
}
&.ng-leave {
animation-name: fadeAndSlideToBottom;
animation-play-state: paused;
&.ng-leave-active {
animation-play-state: running;
}
}
}
How can I add a loadmask within the launch method of the Ext.applcation to the viewport that will also covers floating components like windows when get showed?
Currently the mask work but does not cover any opened window.
I found the answer here, the trick is to increase the z-order of the mask:
Ext.getBody().mask().dom.style.zIndex = '99999';
I made a test, it works for me.
You can create custom loader that will hide itself when everything is loaded...
1.Create html holder in body:
<div id="loading-mask"></div>
<div id="loading">
<span id="loading-message">Loading. Please wait...</span>
</div>
2. Add css to properly position mask:
#loading-mask {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #ffffff;
z-index: 1;
}
#loading {
position: absolute;
top: 40%;
left: 45%;
z-index: 2;
font-family: tahoma,arial,verdana,sans-serif;
font-size: 12px;
}
#loading span {
padding: 5px 30px;
display: block;
}
3. Create js function outside Ext.onReady call:
function hidePreloader() {
var loadingMask = Ext.get('loading-mask');
var loading = Ext.get('loading');
// Hide loading message
loading.fadeOut({ duration: 0.2, remove: true });
// Hide loading mask
loadingMask.setOpacity(0.9);
loadingMask.shift({
xy: loading.getXY(),
width: loading.getWidth(),
height: loading.getHeight(),
remove: true,
duration: 1,
opacity: 0.1,
easing: 'bounceOut'
});
}
4. Call hidePreloader method when all components and tasks are completed and ready, in your case after app.js launch method is fininshed loading, for example:
listeners: {
afterrender: function(form) {
hidePreloader();
}
}
here is a example in fiddle.
I preferred my solution with CSS:
body.x-masked .x-mask {
z-index: 20000;
}
since window z-index is 19001, so 20000 is not bad.