Slide page up to make room for iOS keyboard - reactjs

In React (not React Native), how can I slide the page-content up to make room for the iOS keyboard when a textarea element gains focus?
Below please find my attempt. This now works fine. However, I am curious if this is considered good practice, or if there is an existing solution?
// When the textarea element gains focus,
// scroll the content up (to make room for the iOS keyboard)
scrollContent = () => {
console.log("Gained focus");
this.scrollViewRef.current.style.marginTop = '-250px';
}
// When the textarea element loses focus,
// scroll the content back down (since the iOS keyboard is gone now)
unScrollContent = () => {
console.log("Lost focus");
this.scrollViewRef.current.style.marginTop = '0px';
// The textarea's onBlur is causing the button's onClick not to fire
// so need to manually call the button's onClick
if(e.relatedTarget === this.buttonRef.current) {
this.buttonRef.current.click();
}
}
render() {
return (
<div
ref={this.scrollViewRef}
>
<textarea
onFocus={this.scrollContent}
onBlur={this.unScrollContent}
/>
<div
ref={this.buttonRef}
onClick={this.handleSubmitForm}
tabIndex="1"
>
Save
</div>
</div>
)
}
In particular, if the user tries to click on the form's submit button while the textarea element has the focus, it will only trigger the textarea's onBlur (and scroll the page-content up again), but it won't call the submit button's onClick. Hence the need to check what element was clicked on in the if statement, and if it was the button, manually trigger the click.
Is there a better way?

Related

react / react-draft-wysiwyg: How to determine truly is blurred?

The attached graphic shows my issue. If I click outside of the content, but inside the textarea, which you can see a light grey border around, the onBlur event is fired.
I've tried to capture the event and prevent this behaviour using target, but the event looks the same if you click way outside the box - where I want onBlur to fire.
So far using a ref has not worked either. I was hoping that would be the solution. Any ideas on how to allow a user to click anywhere within what they are seeing as the component react-draft-wysiwyg and NOT fire onBlur?
My fix, though feeling a bit hacky because of needing to handle the first onClickAway, was to elevate the onBlur call to a ClickAwayListener wrapping the Editor component like so:
<ClickAwayListener onClickAway={() => {
// Moving onBlur up to support clicking anywhere in component w/o blurring.
// Handle onClickAway firing once on focus of editor textarea.
if (firstClick) {
setFirstClick(false);
} else {
onBlur();
}
}}
>
<Editor
// do not use here: onBlur={onBlur}
// other props
/>
</ClickAwayListener>

Detect mouse click and change state in React

I have a div which is displayed depending upon a variable- eg: showDiv. After i set showDiv= true, div will appear.
{showDiv && <div id="someid"> text</div>}
Have set a timeout to change variable value so that div will disappear after a time (7 seconds)
thisState.setState({showDiv:true});
setTimeout(function(){
thisState.setState({false});
}.bind(this),7000);
How can i add a code to detect any mouse click and change variable based on that ? Requirement is that, div should disappear either
1. after 7 seconds (already done)
2. based on a click event (if user just clicks on the screen)
Any thoughts ?
You are looking for a window event-listener essentially.
componentDidMount(){
window.addEventListener("click", this.hideDiv)
}
hideDiv = () => {
if(this.state.showDiv){
this.setState({
showDiv: false
})
}
}
Also remember to remove that listener before the component unmounts:
componentWillUnmount{
window.removeEventListener("click", this.hideDiv)
}
See working sandbox: https://codesandbox.io/s/stupefied-silence-snhnw

Use return key to toggle checkbox

I have built a navigation hamburger using a checkbox toggle to reveal/hide the menu so the menu works if the user is on a non-JS browser.
However, this means that keyboard users have to know to press space to toggle the menu, when the expected functionality for buttons would be the return key.
Is there an efficient way to toggle the checkbox with the return key if the user is focussed on it or shall I just leave it with the spacebar?
I think that the simplest way would be to write script to get all bubbled keypress events and toggle inputs.
<input type="checkbox" class="js-toggle-enter" />
document.addEventListener('keypress', (e) => {
if( e.key === "Enter" && e.target.classList.contains('js-toggle-enter')){
e.target.checked = !e.target.checked;
}
})

Angular Material Limit toggling of MatExapansionPanel to only clicking arrow

I'm using Angular Material to create my toggling panels. I still want my panel to expand and contract when clicking the arrow, but I not when I click anywhere in the panel header because I want to add a checkbox at the top. Currently, when I click on my checkbox, the toggling event of the panel fires when I click the checkbox. The 'change' event of the checkbox still fires afterward.
I don't mind to have the panel toggles only when clicking its arrow, how do I stop the toggling of the panel from firing when clicking anywhere in the top?
HTML
<mat-expansion-panel #panel
(opened)="togglePanel()"
(closed)="togglePanel()">
<mat-expansion-panel-header>
<mat-panel-title>
<mat-checkbox (change)="onCheckChanged($event)">
<label>Options 1</label>
</mat-checkbox>
</mat-panel-title>
<mat-panel-description></mat-panel-description>
</mat-expansion-panel-header>
</mat-expansion-panel>
TypeScript
togglePanel() {
// this event fires before the onCheckChanged event
}
onCheckChanged(event: MatCheckboxChange) {
// this event fires after the togglePanel event
}
There is currently a feature request in for this, about a year old so not sure of the ETA... seems to be some workarounds people are playing with that might help but appear to have mixed reviews.
https://github.com/angular/material2/issues/8190
Revision
I tested the following in stackblitz and it seems to work.
HTML
<mat-accordion>
<mat-expansion-panel #expansionPanel>
<mat-expansion-panel-header (click)="expandPanel(expansionPanel, $event)">
Component
expandPanel(matExpansionPanel, event): void {
event.stopPropagation(); // Preventing event bubbling
if (!this._isExpansionIndicator(event.target)) {
matExpansionPanel.close(); // Here's the magic
}
}
private _isExpansionIndicator(target: EventTarget): boolean {
const expansionIndicatorClass = 'mat-expansion-indicator';
return (target['classList'] && target['classList'].contains(expansionIndicatorClass) );
}
Stackblitz
https://stackblitz.com/edit/angular-5kugm3?embed=1&file=app/expansion-overview-example.html

Can we trigger KeyPress on Div Tag in react

I have component where it displays questions . Each question is react component. On press of Enter it should navigate to next question. I have wired onKeyPress to Div element , but event gets captured sometimes , and sometimes it doesn't.
<div className="-" onKeyPress={(e) => this.navigateToNext(e)}>
<div className="preview-head">
//Other stuff here
</div>{/* preview-container*/}
</div>
navigateToNext(e) {
if (option.get('selected') === true && e.charCode === 13) {
this.goToNextQuestion();
}
}
Can anyone tell me any other way to handle this problem.
I would wire up an event listener in componentWillMount for the keyup event and check it's the enter key. Just remember to remove the event listener in componentWillUnmount.
I would guess the issue is around the div having focus or not. If it is not focused the key press event doesn't fire on that element and thus nothing happens
As said by #spirift, your div has not the focus. Try this :
Add ref={(c) => { this.ref = c }} to your div and focus in a lifecycle method :
componentDidMount() {
this.ref.focus();
}

Resources