Divs Reverse scroll with translateY() in react.js - javascript

I'm trying to create with React.js a type of scroll like this one: http://spassky-fischer.fr/, where two divs are scrolling in inverse directions. They are using transform: translateY(), and I tried to implement it as well but I don't get where I'm wrong here. Here's the architecture of the projet. The current version is also here: http://noiseless-tendency.surge.sh/
App.js:
ComponentDidMount(){
window.addEventListener("scroll", this.scrollHandler);
}
...
scrollHandler = () => {
this.setState({
scrollPositionY: window.scrollY
})
}
...
render() {
return (
<div className="App">
<MainItemsContainer {...this.state} />
</div>
);
}
MainItemsContainer.js:
render() {
let style_first = {
transform: `translateY(${this.props.scrollPositionY})`,
overflow: "hidden"
}
let style_second = {
transform: `translateY(-${this.props.scrollPositionY})`,
overflow: "hidden"
}
return (
<div className="main_items_container">
<section
style={style_first}
className="main_items_container_child">
<ItemsContainer {...this.props}/>
</section>
<section
style={style_second}
className="main_items_container_child">
<ItemsContainer {...this.props}/>
</section>
</div>
);
}
App.css:
.main_items_container {
width: 100vw;
display: flex;
align-items: center;
justify-content: center;
position: fixed;
}
.main_items_container .main_items_container_child{
width: 50%;
height: 100vh;
overflow: scroll;
}

The sample site you linked actually uses the wheel event rather than the scroll event. It looks like they use this library to accomplish it: https://swiperjs.com/demos/ . My understanding is that the scroll event only fires if there's a scrollbar, which is why your event handler didn't fire.
I've created a Code Sandbox that produces the effect you want in React. It does rely on jQuery to compute the height of the whole element, and to set the initial transformation for the left half. However, those are just convenience methods, and if you don't want jQuery as a dependency, you can find workarounds for those pretty easily.

So you could use hooks and pass a custom css var through inline styling on state change to update your translateY. I have not tested but I hope you get my drift.
let elRef = useRef(null)
let[ height, setHeight] = useState()
use useLayoutEffect hook to add the event listener
useLayoutEffect (()=>{
if(!elRef) return
elRef.current.addEventListener("scroll", setHeight(elRef.current.scrollY));
return elRef.current.removeEventListener("scroll", setHeight());
}, )
and put the ref on you outermost div perhaps , so your outer div would look like
<div className='container' ref={elRef} style{{ --height: height}} >
<div className='columOne' > </div>
<div className='columTwo' > </div>
</div>
in your css (I haven't put all that is required but just showing how you custom css var is used
.container{
display: flex;
flex-direction: row
}
And within that equal sized columns
.columnOne{
transform: `translateY(calc(var(--height) * 1px)`,
overflow: "hidden"
}
.columnTwo{
transform: `translateY(-calc(var(--height) * 1px)`,
overflow: "hidden"
}
Does that help. Let me know if I could be more clear. Or use styled components and pass a prop in to achieve the same result.

Related

How to prevent angular component to scroll page instead of table?

I have this page like image below:
The filter has a dynamic width and is an external angular component
the table is inside the "parent" component
FYI:
The table component has a [height]="something" that accepts either string or number as parameters.
The table is a pivot table using a custom component called Dev-Extreme
All i want is to assign a value inside the [height]="" in the HTML component page that is dynamic so that the height of the table resizes based on how much space there is left in the page.
Could also use TypeScript to do that and maybe calculate the height each components takes in the page except the table and do calculations on that.
Can anyone help me here, i've been stuck on this for two hours.
You could use some css for what you need.
Use display: flex to distribute the sections as you need (top section fixed and bottom section with dynamic height).
And use overflow: auto to set the scroll in the table container only.
Example:
https://codepen.io/bcngr/pen/wvXdWBE
<div class="main">
<div class="filters-container">
<span>Filters</span>
</div>
<div class="table-container">
<div class="table">
<span>Table</span>
</div>
</div>
</div>
html, body {
padding: 0;
margin: 0;
}
.main {
height: 100vh;
display: flex;
flex-direction: column;
}
.filters-container {
background-color: #edf2f4;
height: 100px;
}
.table-container {
flex: 1;
overflow: auto;
}
.table {
background-image: linear-gradient(#8d99ae, #2b2d42);
height: 600px
}
I found a solution to this here's what i did:
Creating a #ViewChild() to gather the div element in my .ts:
#ViewChild('pivotFilter', { static: false }) stickyHeader?: ElementRef;
Here:
The div has an id="pivotFilter"
Using ViewChild we can get the HTML element
Declaring getter to calculate table height:
get filterHeight() { return window.innerHeight - (this.stickyHeader?.nativeElement.offsetHeight + 88); }
Here:
window.innerHeight is the height of the page
this.stickyHeader?.nativeElement.offsetHeight is the height of my component
That + 88 is the rest of the page height (the title, and the space between filter and table)
I had to run change detection on content initialization to prevent errors like so:
ngAfterContentInit(): void {
this.cd.detectChanges();
}
Then i just applied the height to the html page.
Hope this helps someone, cheers !

Card Height adjusting on Button Click React

How to adjust this one whenever I click "Create Invoice" it will render a spinner with "Creating invoice". However the height of the card is also changing. I want it to be in fixed position
Please check GIF
https://imgur.com/a/ymJSnpy
const Loading = () => {
return (
<div className="loading" style={divStyle}>
<h4>Creating Invoice
<Spinner size="15px" color="#6491c6"/></h4>
</div>
)}```
could you share what are you putting in loading class and divStyle ?
I think you should add height of 40 and center it vertically if it's not centred on one of those classes:
display: flex;
align-items: center;
height: 40px;

how to use start and end in css position reletive or others?

I'm trying to use multiple languages in my nextjs project and MUI library, and I m setting my body element of my project direction using locale.
const App = (props: MyAppProps) => {
const {
Component,
emotionCache = clientSideEmotionCache,
pageProps,
} = props;
const router = useRouter()
const { locale } = router;
return (
<CacheProvider value={emotionCache}>
<ThemeProvider theme={getTheme(theme)}>
<CssBaseline />
<GlobalStyles styles={{
body:{
backgroundColor:getTheme(theme).palette.Background.background,
direction:locale==="fa"?"rtl":"ltr"
}
}}/>
<Component {...pageProps} />
</ThemeProvider>
</CacheProvider>
);
};
and that works fine with the text-align property
but I have a problem with positioning my elements because there are right, left, bottom, top properties in positioning, and there isn't a start and end property. for example:
width:50px;
height:50px
position: relative;
left:2px
my element with the position above, I want to position 2px from left in RTL directional language like Persian but I want to position it 2px from right in LTR directional language such as the English Language. it is usually done with start and end properties but in css i dont know because there isnt sutch a thing in position property.so my question is how can I position the elements base of start and end?
I am unable to understand your code, But question is related to CSS that's why I am providing you some idea.
Let's you have a element <div id="element" class="{{ direction:locale==='fa'?'rtl':'ltr' }}">Your contents</div>
Now, put this css in your style page->
#element.rtl {
left: 2px;
}
#element.ltr {
right: 2px;
}
Hope this will help you. If not, comment here.
display Put your element in flex mode and use the justify-content, ... capabilities.
go to
enter link description here
You have to set position relative to div element and lest or right position to nested div element.
Structure your HTML similar to this:
<div id="container">
<div class="top left"></div>
<div class="top right"></div>
</div>
CSS
#container {
position: relative;
}
#container > * {
position: absolute;
}
.left {
left: 2px;
}
.right {
right: 2px;
}

Unable to style Accordion (PrimeReact)

I have some accordions from PrimeReact which I use in my code. But there are pictures inside and I want to make them smaller. This is the current problem:
As you can see, the picture is way too big. I want to set the width to 100%.
Now I did this already before when I used Angular with PrimeNG (same library, just for Angular) and I managed to this in the css file like:
:host ::ng-deep .p-accordion-content img {
width: 100%;
}
This code did exactly what I wanted.
Now I need the same for React. But it is not working when I use:
:host .p-accordion-content img {
width: 100%;
}
This is the code I used to create the accordions. Maybe it will help:
createAccordions = () => {
const allFAQs = this.state.allFAQs;
let accordions = [];
for (const faq of allFAQs) {
const accordion = <AccordionTab key={faq.uuid} header={faq.question}><div dangerouslySetInnerHTML={{ __html: faq.answer }}></div></AccordionTab>;
accordions.push(accordion);
}
return accordions;
}
render() {
return (
<div>
<div className="p-grid">
<div className="p-col-3">
</div>
<div className="p-col-6">
<Accordion>
{this.createAccordions()}
</Accordion>
</div>
<div className="p-col-3">
</div>
</div>
</div>
)
}
Does anyone know what I did wrong? How can I style the picture inside the accordionTab?
Thanks for every help!
this is easy you just need to do some experiments with your image dimensions for example...
add height along with width(this is used in CSS with pure html similar can be used in your code also)
:host .p-accordion-content img {
width: 100%;
height: auto;
}
thankyou

Prevent elements behind from the overlay being clicked

The issue
https://streamable.com/e/9z6lev (the flickering in the video is caused by the overlay being reopened every time meal plan is selected)
It "feels" like during the initial overlay open it's not the focused element and as result is's children can be clicked through :sad:
Overlay Template
The logic for the overlay is quite simple, and allow to nest any type of content inside:
<template>
<div class='swipeableWrapper'
#click.stop.prevent // not original code, just attempt to fix the issue
#touch.stop.prevent> // not original code, just attempt to fix the issue
<slot />
</div>
</template>
.swipeableWrapper {
height: 100%;
left: 0;
min-height: 100%;
position: fixed;
top: 0;
width: 100%;
z-index: 100;
}
Items List Template
<template>
<div>
...
<ListProduct v-for='(product, index) in products'
...
:showProduct='showProduct'
:key='index' />
</div>
<template>
// List Item
<template>
<div class='listProduct'
...
#click='showProduct'>
...
</div>
</template>
Intended approaches:
The following logic added to the overlay template to prevent events from bubbling:
#click.stop.prevent
#touch.stop.prevent
Global logic that will listen to opened overlay and add the following CSS class to the body element, in order to allow click on the overlay items, but still not much luck
.overlayOpened {
& * {
pointer-events: none;
touch-action: none;
}
.swipeableWrapper {
&,
& * {
pointer-events: auto;
touch-action: auto;
}
}
}
I am a bit puzzled with this dark magic behaviour and will really appreciate your opinion on the origin of the behaviour and possible solutions :bow:
Try this
#click.self.prevent="function"
Edited:
For the list item and function as prop
:showProduct="() => showProduct(item/index)"

Categories

Resources