Svelte transition 'jumps' animation - javascript

I have a SvelteKit application with a two divs with text. My goal is to add a in:fly animation to the text divs along with an easing function. However, at the end of the easing animation, the animation 'skips' or something weird happened. The ease function does not complete the animation. Here's a gif of the animation
This is the code I have for this
<script>
import { fly } from 'svelte/transition';
import { onMount } from 'svelte';
import { circOut } from 'svelte/easing';
let mounted = false;
onMount(() => {
mounted = true;
});
</script>
{#if mounted}
<main class="w-full h-screen flex items-center justify-center">
<div class="w-full max-w-7xl flex">
<div class="w-3/4 flex flex-col gap-3">
<!-- Text 1 -->
<div class="h-40 relative overflow-hidden">
<div
class="absolute inset-0 text-9xl"
in:fly={{ y: 150, duration: 1100, easing: circOut }}
>
Some
</div>
</div>
<!-- Text 1 -->
<div class="h-40 relative overflow-hidden">
<div
class="absolute inset-0 text-9xl"
in:fly={{ y: 150, duration: 1000, delay: 100, easing: circOut }}
>
Title
</div>
</div>
</div>
<div class="w-1/4 bg-blue-300" />
</div>
</main>
{/if}
This does not happen when the page is hot-refreshed after saving the file.
I've tried using other ease functions as well but the result is the same
I've tried removing the absolute positioning of the divs with no luck as well
Edit: I tried it with just one text element but the issue persists.
<script>
import { fly } from 'svelte/transition';
import { onMount } from 'svelte';
import { circOut } from 'svelte/easing';
let mounted = false;
onMount(() => {
mounted = true;
});
</script>
{#if mounted}
<div class="text-9xl" in:fly={{ y: 150, duration: 1100, easing: circOut }}>Text</div>
{/if}
Edit 2:
I added a MRE to this repository. (Hosted)
Issue persists on Chrome, Chrome guest mode, Chrome for Android.
Does NOT happen on Firefox
Edit 3
It happens even without the easing function. (Initially thought it was caused by the ease function)

Related

javascript - How to start update scroll percentage when element is on the top of viewport

When entering the website, this is the first UI you'll see.
Then, if you scroll down to the very beginning of section B
I expect the section B will become sticky and the currentPercentage state will start increasing from 0% gradually if you scroll.
When the currentPercentage state reach 100%, the sticky effect will no longer apply to sectionB, then you can scroll down to section C or the bottom of the page.
It's kind of like circle-ci homepage
You can try to scroll in this section.
I think there are a few things we need to figure out for the solution
How to make section B become sticky when scroll position arrives section B
How to scroll and increase the percentage when arriving section B
I've tried thinking in both css and javascript way, still cannot find the solution
I've also done lots of research for this problem for a few days but still not figuring it out.
I believe a lots of developers would like to know how to do this kind of effect in their frontend, and it will be beneficial for other developers to have quicker solution to deal with this kind of UX in the future, since from what I've noticed no one has mentioned this kind of UX handling.
I would be appreciated if someone can answer this question with an example, for the reference for other developers.
App.js
import "./styles.css";
import "bootstrap/dist/css/bootstrap.min.css";
import ProgressBar from "react-bootstrap/ProgressBar";
import { useState } from "react";
export default function App() {
const [currentProgress, setCurrentProgress] = useState(100);
return (
<div className="App">
<div className="sectionA">Section A</div>
<div className="sectionB">
Section B
<ProgressBar
now={currentProgress}
label={`${currentProgress}%`}
style={{ marginBottom: "16px" }}
/>
</div>
<div className="sectionC">Section C</div>
</div>
);
}
Codesandbox
https://codesandbox.io/s/mutable-fire-sz19b?file=/src/App.js:0-619
Update 1
I updated the code and can be able to make container B sticky, but dont know how to continue for the UX
App.js
import "./styles.css";
import "bootstrap/dist/css/bootstrap.min.css";
import ProgressBar from "react-bootstrap/ProgressBar";
import { useState } from "react";
export default function App() {
const [currentProgress, setCurrentProgress] = useState(3);
return (
<div className="App">
<div className="sectionA">Section A</div>
<div style={{ position: "sticky", top: 0 }}>
<div className="sectionB">
Section B
<ProgressBar
now={currentProgress}
label={`${currentProgress}%`}
style={{ marginBottom: "16px" }}
/>
</div>
<div className="sectionC">Section C</div>
</div>
<div style={{ minHeight: "400vh", maxHeight: "calc(200vh - 466px)" }} />
</div>
);
}
Codesandbox
https://codesandbox.io/s/elated-hawking-n3rvw?file=/src/App.js:0-778
Update 2
Added library react-scroll-percentage to scroll to update
currentProgress
However, when the whole containerB exposed in the viewport, the currentProgress will start updating, which is not what I want

What I want is when SectionB reach the top of the viewport, the scrolling will make user feel sticky and then currentProgress will start updating from 0%
App.js
import "./styles.css";
import "bootstrap/dist/css/bootstrap.min.css";
import React, { useState, useEffect } from "react";
import { useScrollPercentage } from "react-scroll-percentage";
import ProgressBar from "react-bootstrap/ProgressBar";
export default function App() {
const [currentProgress, setCurrentProgress] = useState(0);
const [ref, percentage] = useScrollPercentage({
threshold: 1.0
});
useEffect(() => {
setCurrentProgress(percentage * 100);
}, [percentage]);
return (
<div className="App">
<div className="sectionA">Section A</div>
<div style={{ position: "sticky", top: 0 }}>
<div className="sectionB" ref={ref}>
Section B
<ProgressBar
now={currentProgress}
label={`(${currentProgress})%`}
style={{ marginBottom: "16px" }}
/>
</div>
<div className="sectionC">Section C</div>
</div>
<div style={{ minHeight: "400vh", maxHeight: "calc(200vh - 466px)" }} />
</div>
);
}
Codesandbox
https://codesandbox.io/s/elated-hawking-n3rvw?file=/src/App.js:0-1029
You need to listen to scroll events, check scrollTop of the scrolling element, and decide what the css and currentProgress need to be. This is easiest when the height of each section is known and constant. The outer element also needs a large predetermined height, to leave room for scrolling.
The code might just be
if (scrollTop > heightofSectionA) {
//set sectionB css to {position: fixed, top: 0, ...}
currentProgress = (scrollTop-heightofSectionA)/lengthofSectionB*100
} else {
//set sectionB css to {position: static}
currentProgress = 0
}
There is a number of ways the html and css could look. With position: sticky you might not need to change css at all. But as long as you know what the css at any stage of the scroll should look like, you should have no problems switching between them.
try this
getScrollPercentage(el){
const percentage = (window.scrollY - el.offsetTop + el.scrollHeight) / el.scrollHeight;
return percentage < 0 ? 0 : Math.min(percentage, 1)
}

Hiding Popover on internal click

I'm currently using Vue-PopperJS, and have pretty much set it up as they have on the attached link with some slight changes:
<template>
<Popper
ref="popover"
trigger="clickToToggle"
:options="{
placement: position,
}"
>
<slot
slot="reference"
name="activator"
/>
<div class="base-dropdown--dropdown popper">
<slot name="popover" />
</div>
</Popper>
</template>
<script>
import Popper from 'vue-popperjs'
import 'vue-popperjs/dist/vue-popper.css'
export default {
name: 'BaseDropdown',
components: {
Popper
},
props: {
position: {
type: String,
default: 'bottom'
}
}
}
</script>
<style scoped lang="sass">
.base-dropdown
&--dropdown
min-width: 180px
#apply rounded-large shadow-sm
</style>
And for the items inside the popover we created another component like so:
<template>
<div
class="base-dropdown-item"
:class="getDropdownItemClass"
#click="$emit('click')"
>
<slot />
</div>
</template>
<script>
export default {
name: 'BaseDropdownItem',
props: {
hoverable: {
type: Boolean,
required: false
}
},
computed: {
getDropdownItemClass () {
if (this.hoverable) return ['hover:bg-blue']
return []
}
}
}
</script>
<style scoped lang="sass">
.base-dropdown-item
text-overflow: ellipsis
padding: 12px 0 12px 12px
#apply cursor-pointer body-3 flex items-center overflow-hidden text-grey-800 transition-all whitespace-nowrap
&:hover
#apply text-black
</style>
My question is, say I click on the popover content (ie, a button that does something), how can I trigger it to close the popover too?
I know there is an event to hide it but I'm not sure how to use it.
Should you need more information please don't hesitate to ask!
Not sure how 'efficient' this solution is. However, Chase DeAnda's comment gave me an idea for an elegant solution.
I ended up using the EventBus that would $emit('close-popver'). This emit would be from whatever (in this case a <BaseDropDownItem /> component) that calls this method on a #click.
methods: {
handleClick() {
this.$emit('click')
EventBus.$emit('close-popover')
}
}
And to close the popover:
closePopover(){
const { popover } = this.$refs
popover.doClose()
}

How to add styles to a React component? [duplicate]

Currently I'm using react.js and I'm trying to get two div's to be side by side.
Currently I'm trying to
<div id="sidebar" style = "display:inline-block;" >
<script src="build/sidebar.js"></script>
</div>
<div id="map-canvas" style="display: inline-block; width: 20%; height: 50%; "></div>
with sidebar.js as the where react is stored. This unfortunately doesnt work however as it just moves map-canvas to the side while sidebar isn't to the left of it; its on top. I've tried many various combinations w/ float as well and none of them seem to work
Another option is to edit the sidebar.js code where I currently have
return <div>
<input type="text" value={this.state.searchString} onChange={this.handleChange} placeholder="Type here" />
<ul>
{ libraries.map(function(l){
return <li>{l.name} </li>
}) }
</ul>
</div>;
in which I try doing return <div style ="display: inline-block;">
However, in this case the generated html doesnt show up at all. I'm perplex to what I should try but react seems like it doesnt want to play nice with other div elements.
That's because in React, the style prop takes an object instead of a semicolon-separated string.
<div id="sidebar" style={{display : 'inline-block'}} >
<script src="build/sidebar.js"></script>
</div>
<div id="map-canvas" style={{display: 'inline-block', width: '20%', height: '50%'}}>
</div>
Edit:
So this:
return <div style="display: inline-block;">
Would become this:
return <div style={{display: 'inline-block'}}>
const styles = {
container: {
backgroundColor: '#ff9900',
...
...
textAlign: 'center'
}
}
export default class App extends React.Component {
render() {
return(
<div className="container" style={styles.container}>
// your other codes here...
</div>
);
}
}

Flickity not hiding on desktop

I want the flickity slider to hide on desktop and larger devices. I think I'm following the instructions in the documentation, they seem pretty straightforward, however, It's not working.
Div looks something like this:
<div class="w-full flex pl-4 pb-16 overflow-x-auto lg:justify-center">
<flickity class="main-carousel mx-20 mt-5 sm:my-10 w-10/12" ref="flickity" :options="{ lazyLoad: 3, watchCss: true, cellAlign: 'left', wrapAround: true, pageDots: true, pauseAutoPlayOnHover: true, arrowShape: { x0: 0, x1: 75, y1: 50, x2: 90, y2: 50, x3: 15 } }">
<PlanesCard v-for="(plan, index) in getTiers" :key="index" :value="plan.value" :name="plan.name" />
</flickity>
</div>
Styling like this:
.main-carousel:after {
content: 'flickity';
display: none;
}
#media (min-width: 1024px) {
.main-carousel:after {
content: '';
}
}
which is the component that gets "flicked", looks something like this, even though I think it's not important:
<article :class="planText()" class="py-8 flex-shrink-0">
<h2>
<span>{{ value }}</span>
</h2>
<ul class="text-left pl-6 pr-4">
<PlanList v-for="pl in getFeatures" :key="pl.title" :plan="name" />
</ul>
</article>
Also, I don't know if this is important, but when I inspect the element on Chrome, I have this:
Thanks in advance!
I think you misspelled a property. I reproduced your problem and fixed it by changing the property "watchCss" to "watchCSS".

React: Resizing a div including handlers, different cursors i.e ns-resize - no jquery

I am looking for an easy way of allow a user to resize a div using handles and all relevant cursors. I see lots of examples using jquery but I would like to use it in react and jquery isn't required.
Does anyone know a easy way of doing this ? I presume pure js, css. I don't really want to use a react component for this, as I need to enable resizing on standard divs.
Of course it is for use with reactjs, is there a more modern way of doing this without jquery ?
** EDIT **
These are the cursors that could be used for each resizable point
e-resize ne-resize n-resize nw-resize s-resize se-resize
w-resize sw-resize
You can only with CSS, resize property allows you to make that!
.resize {
border: 1px solid black;
overflow:auto;
}
.resize.horizontal {
resize: horizontal;
}
.resize.vertical {
resize: vertical;
}
.resize.both {
resize: both;
}
.wrap {
max-width: 80%;
}
<div class="wrap">
<div class="resize horizontal">Resize me!</div>
<div class="resize vertical">Resize me!</div>
<div class="resize both">Resize me!</div>
</div>
Requirements
overflow different than visible (initial) is required and you can apply it to all elements whos overflow is setted with auto, scroll and hidden.
I call this property marvellous!
Heres an example of a great solution using react-resize-panel library
https://www.npmjs.com/package/react-resize-panel
Put anything you want to show inside the divs, you can customize the handler too.
import ResizePanel from "react-resize-panel";
...
<div style={{
width: '80%',
height: '500px',
border: '1px solid black',
display: 'flex',
flexDirection: 'column'}}>
<ResizePanel direction='s' style={{backgroundColor: 'black', height: '50%'}}>
<div style={{backgroundColor: 'orange', height: '100%'}}>panel</div>
</ResizePanel>
<div style={{backgroundColor: 'purple', flexGrow: '1'}}>panel</div>
</div>
...
Hope this can help someone else
A few days ago I wanted to build something like this but with 2 div elements.
using resize property from css made it's width 0 when there are multiple elements so I tried javascript.
I saw an example using onMouseMove event but there are many problems with this example so I made a new sandbox in which I use the onDarg event.
Here is the important code:
const dragHandler = useCallback(
(e) => {
const w =
((e.clientX -
e.currentTarget.parentElement.parentElement.getBoundingClientRect()
.left) /
e.currentTarget.parentElement.parentElement.getBoundingClientRect()
.width) *
100;
if (w > 0 && w !== width) {
setWidth(w);
}
},
[width]
);
and
<Box width={width} />
<div
draggable
onDrag={dragHandler}
className="flex justify-center items-center p-1 h-full bg-slate-800 cursor-col-resize"
>
<div className="w-1 border-x border-white h-1/6" />
</div>
<Box width={100 - width} />
Hope it helps \(^_^)/

Categories