So I am trying to display a transition with ReactCSSTransitionGroup on load of the home page. It is to display a list of items below the jumbotron. This items come from Redux store. They are passed from a container component called home_index.js that is aware of Redux Store. The component itself 'poll-list.js' contains poll-links, the items to be transitioned in; it (and its child) is a DUMB component. Meaning, it has no state nor is it aware of redux store. (Can these components even use ReactCSSTransitionGroup?)
In any case, I cannot, for the life of me, get this fade in transition to work. I know I must be doing something wrong...but cannot figure it out.
const appearTransition = {
transitionName: "fade",
transitionLeave: false,
transitionEnter: false,
transitionAppear: true,
transitionAppearTimeout: 2500
};
let polls;
if (props.pollsList) {
polls = props.pollsList.map((poll, ind) => {
return (
<PollLink
className='poll-link'
title={poll.title}
index={ind}
id={poll.id}
key={ind}
/>
)
});
}
return (
<div className='poll-list'>
<ReactCSSTransitionGroup {...appearTransition}>
{props.pollsList.length > 0 ? polls : null}
</ReactCSSTransitionGroup>
</div>
)
}
And here is the CSS (note I am not doing a Leave, and I have set Appear to true, i just want this to happen on initial load of the home page)
.fade-appear {
opacity: 0.01;
#include prefix(transition, (opacity 2500ms), webkit ms moz o);
}
.fade-appear.fade-appear-active {
opacity: 1;
}
Also, putting ReactCSSTransitionGroup at this level, in this element, makes my flexbox get all weird. The components are no longer in columns of 4 (or however many based on screen width), they are in one single column down the center...
Where do I put the transition group HOC?
Hierarchy:
<HomeIndex>
<Poll-List>
<Poll-Links>
You can simply add this style in your css file, try to remove the hyphen between class name and make it in camelcasing:
.fadeAppear {
opacity: 1;
transition: opacity 0.3s ease-in;-webkit-transition: opacity 0.3s ease-in;
}
import your css file in your redux code,
#import mycss from '../path/style.css'
and add the given class in css in wherever needed.
as:
return (
<div className='poll-list'>
<ReactCSSTransitionGroup className={mycss.fadeAppear} >
{props.pollsList.length > 0 ? polls : null}
</ReactCSSTransitionGroup>
</div>
)
Hope this works!
Related
I want to realize a simple page (route) transition in Sapper. Something that is easily achievable with Nuxt for example. Does anyone have an idea how to realize that with Sapper?
I already wrapped my page content into a div with a transition:fade directive. This works. Yet, the two pages transition at the same time, meaning while one page transitions out the other one already transitions in. It would be great if someone pointed me in the right direction. Thanks!
Let me just start of by saying I don't know if this is the most effective way to do it. This is the way I solved it and it works great for me.
I first made my own custom variation of the 'fade' transition and put it in 'components/pageFade.js'
import { sineOut } from "svelte/easing";
let duration = 250;
let delay = duration;
let delayZero = 0;
export const fadeIn = _ => ({
duration,
delay,
easing: sineOut,
css: t => `opacity: ${t}`
});
export const fadeOut = _ => ({
duration,
delay: delayZero,
easing: sineOut,
css: t => `opacity: ${t}`
});
The delayZero variable is there because for some reason it won't take '0' directly and will break.
The duration variable is the length of the fade in milliseconds
Then for all files I wanted to have this transition on I did the following:
<script>
import { fadeIn, fadeOut } from "../components/pageFade";
// All your other JS goes here
</script>
<style>
/* Styles go here */
</style>
<main in:fadeIn out:fadeOut>
<!-- All the normal HTML goes here -->
</main>
I would then use that as a template on almost every single one of the pages, which seems like a lot but it's not too bad.
Hope it helps and let me know if you have any other questions!
Max
If you want to include transition in _layout.svelte and don't need to include them in every route here is an alternative.
Here is a simple fly in/out from top transition.
<!-- src/component/PageTransitions.svelte -->
<script>
import { fly } from 'svelte/transition';
export let refresh = '';
</script>
{#key refresh}
<div
in:fly="{{ y: -50, duration: 250, delay: 300 }}"
out:fly="{{ y: -50, duration: 250 }}"
>
<slot/>
</div>
{/key}
And here is the Sapper layout component
<!-- src/routes/_layout.svelte for Sapper -->
<script>
import { page } from '$app/stores'; // svelte#next
import Nav from '../components/Nav';
import PageTransitions from '../components/PageTransitions';
export let segment;
</script>
<Nav {segment}/>
<PageTransitions refresh={segment}>
<slot/>
</PageTransitions>
And here is the SvelteKit (svelte#next) layout component
<!-- src/routes/$layout.svelte for Svelte#next -->
<script>
import { page } from '$app/stores'; // svelte#next
import Nav from '../components/Nav';
import PageTransitions from '../components/PageTransitions';
</script>
<Nav segment={$page.path}/>
<PageTransitions refresh={$page.path}>
<slot/>
</PageTransitions>
And for completeness here is a simple Nav component
<!-- src/component/Nav.svelte -->
<script>
export let segment;
</script>
<style>
a {
text-decoration: none;
}
.current {
text-decoration: underline;
}
</style>
<div>
<a href="/" class='{segment === undefined ? "current" : ""}'>Home</a>
<a href="/about" class='{segment === "about" ? "current" : ""}'>About</a>
</div>
NOTES:
We make the component reactive by creating a refresh prop and using key directive which means that when the key changes, svelte removes the component and adds a new one, therefore triggering the transition.
In the layout component we pass the segment (route) as refresh prop and therefore the refresh key changes as the route changes.
Here is a demo of the sample code above and the github repo
FYI #max-larsson, from your code, fadeIn is defined as a function which needs no arguments and returns an object having a duration property equal to the value of the duration variable at this scope. same with delay. Note easing is defined as the name, with the value of sineOut.
This may be your issue if you just tried to put a literal 0 where delay was. I see you tried making delayZero, but used it likely in a different way than you intended. You probably meant to write this:
export const fadeOut = _ => ({
duration,
delay: 0,
easing: sineOut,
css: t => `opacity: ${t}`
});
When I tried this, it works just fine for me. Thanks for sharing your example.
I guess Svelte Kit has changed since #GiorgosK answer, because I cannot make it work with the code in his answer.
But fortunately, his github repo has been update with the solution, thanks !
The page.path properties much be used in module context
This is my version without a specific component for page transition :
<!-- src/route/__layout.svelte -->
<script context="module">
export const load = async ({ page }) => ({
props: {
key: page.path,
},
});
</script>
<script>
import { fly } from "svelte/transition";
export let key;
</script>
<nav>
foo
bar
</nav>
{#key key}
<div
in:fly={{ x: 50, duration: 2500 }}
out:fly={{ y: -50, duration: 2500 }}
>
<slot />
</div>
{/key}
Maybe #GiorgosK can share some insight about that change.
I have multiple instances of CKEditor 5 and I want to add button which will change the height of texteditor. In order to do so I have to change height of a single instance, is that possible and if yes, how?
Side note:
I want to make maximize button like in CKEditor 4. Is there plugin for that or I have to make it myself?
Maximize Feature - From what I have checked it has not been implemented yet. CKEditor has a ticket ofr it: https://github.com/ckeditor/ckeditor5/issues/1235
Editor Height - This link explains How to set the height of CKEditor 5 (Classic Editor) explains how to do this permanently. If however you want to do change editor height dynamically with a button, you need to use a small trick where you assign a CSS class not directly to content area but to its container (notice .ck-small-editor .ck-content in css class and document.getElementsByClassName( 'ck-editor' )[ 0 ] in JavaScript ):
ClassicEditor
.create( document.querySelector( '#editor' ), {
} )
.then( editor => {
window.editor = editor;
// Assign small size to editor using CSS class in styles and button in HTML
const editable = editor.ui.getEditableElement();
document.getElementById( 'change-height' ).addEventListener( 'click', () => {
document.getElementsByClassName( 'ck-editor' )[ 0 ].classList.toggle( 'ck-small-editor' );
} );
} )
.catch( err => {
console.error( err.stack );
} );
.ck-small-editor .ck-content {
min-height: 50px !important;
height: 50px;
overflow: scroll !important;
}
<script src="https://cdn.ckeditor.com/ckeditor5/12.0.0/classic/ckeditor.js"></script>
<div id="editor">
<h2>The three greatest things you learn from traveling</h2>
<p>Like all the great things on earth traveling teaches us by example. Here are some of the most precious lessons I’ve learned over the years of traveling.</p>
<h3>Appreciation of diversity</h3>
<p>Getting used to an entirely different culture can be challenging. While it’s also nice to learn about cultures online or from books, nothing comes close to experiencing cultural diversity in person. You learn to appreciate each and every single one of the differences while you become more culturally fluid.</p>
<h3>Confidence</h3>
<p>Going to a new place can be quite terrifying. While change and uncertainty makes us scared, traveling teaches us how ridiculous it is to be afraid of something before it happens. The moment you face your fear and see there was nothing to be afraid of, is the moment you discover bliss.</p>
</div>
<div>
<button type="button" id="change-height">Change Height</button>
</div>
Angular 1 handles enter, leave and move animations. The Angular 2 documentation describes how to do enter and leave animations (void => * and * => void), but how can one implement move animations in Angular 2?
Read Angular's official guide for animations if you haven't already.
You define animation states and the transitions between them. For instance:
animations: [
trigger('heroState', [
state('inactive', style({
backgroundColor: '#eee',
transform: 'scale(1)'
})),
state('active', style({
backgroundColor: '#cfd8dc',
transform: 'scale(1.1)'
})),
transition('inactive => active', animate('100ms ease-in')),
transition('active => inactive', animate('100ms ease-out'))
])
]
inactive and active can be replaced with any arbitrary strings and you can have as many unique states as you wish, but there must be a valid transition to each one or else the animation won't happen. void is a special case for when elements aren't yet attached to the view and * is a wildcard, applying to any of the defined states.
EDIT:
Hmm... well, for one thing, you might be able to use this Sortable library. It claims to support Angular 2 and is pure Javascript (no jQuery) so theoretically, it should work well but I have not used it myself.
Otherwise, I am certain it would be possible purely inside Angular 2, but it would probably require some fairly clever code. Relative motion (irrespective of a component or element's particular position) is easy with transform: translateY() property. The problem is that Angular 2 animation states only apply if the component is in that state so if you give it a translateY(-20px) to move an element up a position, it's not going to keep that position if you want to want to move it up again.
See this plunker for the solution I have come up with.
template: `
<div #thisElement>
<div class="div-box" #moveState="state">Click buttons to move <div>
</div>
<button (click)="moveUp()">Up</button>
<button (click)="moveDown()">Down</button>
`,
I defined animation states for 'moveUp' and 'moveDown' that ONLY apply during the actual animation and a 'static' state that is applied when the component isn't moving.
animations: [
trigger('moveState', [
state('moveUp', style({
transform: 'translateY(-30px)';
})),
state('moveDown', style({
transform: 'translateY(30px)';
})),
state('static', style({
transform: 'translateY(0)';
})),
transition('* => moveUp', animate('100ms ease-in')),
transition('* => moveDown', animate('100ms ease-out')),
transition('* => static', animate('0ms linear'))
])
]
For the function that actually initiates the animation, it applies the 'moveUp' or 'moveDown' state and then starts a timeout that triggers a callback after an amount of time equal to the length of the transition. In the callback, it sets the animation state to 'static' (the transition to the 'static' state is set to 0 ms so we don't actually animate it moving back to a static position). Then we use Renderer to apply a translation for where we want it to ultimately end up (calculated using a position property that would define it's position relative to where it was initially, not it's position in the array). The Renderer applies its styles separately from the animation so we can apply both without them conflicting with each other.
export class MyComponent {
state = 'static';
#ViewChild('thisElement') thisBox: ElementRef;
position: number = 0;
//...
moveUp() {
this.state = 'moveUp';
this.position--;
setTimeout(() => {
this.state = 'static';
this.renderer.setElementStyle(this.thisBox.nativeElement, 'transform', 'translateY(' + String(this.position * 30) + 'px)');
}, 100)
}
moveDown() {
this.state = 'moveDown';
this.position++;
setTimeout(() => {
this.state = 'static';
this.renderer.setElementStyle(this.thisBox.nativeElement, 'transform', 'translateY(' + String(this.position * 30) + 'px)');
}, 100)
}
//...
}
This is only an example of how you can animate moves without having to define states for each possible position it could be in. As far as triggering the animations on array manipulation, you'll have to figure that out for yourself. I would use some kind of implementation with EventEmitters or Subjects to send events to the components that would then decide on whether or not they need to animate or not.
I have a carousel that takes a state of {pages: [...], currentPage: 0}. If I set currentPage = 1 I want the carousel to slide left. The same thing should happen if I increase the number again, and it should slide right I decrease it.
I can't work out how this should be done with immutable data. The animation shouldn't be represented in the state object (should it?), but storing a property on the React component removes its "pure" functional nature.
What's the best way to approach this problem?
Just show me an example
This doesn't use Immutable.js, but the current property is just a number, which is immutable in JS, so in some regards it's the same idea:
http://jsbin.com/ligejacolo/edit?js,output
IMO the best option is ReactCSSTransitionGroup
+1 for the unnecessarily snarky reference to ReactCSSTransitionGroup in the comments, if you can use that.
After that, let the browser manage state via CSS transitions
I would store the pages and currentPage as props, regardless of whether the values are Immutable.js instances (props are a stateful part of your UI, just like state, don't let the name fool you!). When they're stored as props, it provides a useful API to the users of your component.
If you're using CSS transitions then at any given moment you should be able to render the markup and classes based on this information.
For example, given the (over-simplified markup):
<div class=container>
<!-- set the class to something like "inner pane2" to go to the second pane -->
<div class=inner>
<span class=pane>...</span>
<span class=pane>...</span>
<span class=pane>...</span>
</div>
</div>
And some CSS like:
.container {
position: relative;
}
.inner {
position: absolute;
left: 0;
transition: left 0.3s ease-in-out;
}
.pane {
width: 100px;
}
.inner.pane2 {
left: -100px;
}
.inner.pane3 {
left: -200px;
}
The browser takes care of mid-transition changes to the properties.
Often times you'll need to know when the animation is done, which you can accomplish with a transitionend listener and isAnimating flag (which I would store in the state, not the props). Set isAnimating when currentPage changes and clear it on transitionend.
You'll also often need to know which direction you're transitioning, which you can accomplish with a previousPage prop.
Finally, if you're just using JavaScript
Keep a reference to the current transition in the state (possibly the jQuery selection used to start the animation, if that's what you're using). When the transition is done, remove the reference. If the currentPage changes mid-transition, call .stop() on the selection (or whatever API you're using).
Is there a way of manually loading the view from within the controller, after say some animation was triggered first? The scenario I have is the previous page content sliding up, after that the view would be updated when being off-the screen and once ready - slides back down with the new view from the new controller.
I've got already the router set up, but it just instantly replaces the view whenever the new controller is called.
Any fiddle if possible please?
Code in Controller shouldn't manipulate DOM, directives should. Here is directive to prevent preloading content of element with "src" (by browser's parser) and show content of element only after loading, and before loading show splash with spinner:
directive('onloadSrc', function($compile) {
return function(scope, element, attrs) {
element.bind('load', function() {
var parent = $compile(element[0].parentElement)(scope);
if (!element.attr('src') && attrs.onloadSrc) {
element.attr("src", attrs.onloadSrc);
// replace this dirty hardcode with your template for splash spinner
var spinner_div = $compile('<div style="z-index: 100; width: '+element.attr('width')+'px; height: '+element.attr('height')+'px; display:block; vertical-align:middle;"><img src="/img/spinner.gif" style="position: absolute; left: 50%; top: 50%; margin: -8px 0 0 -8px;"/></div>')(scope);
attrs.onloadSrc = "";
parent.prepend(spinner_div);
element.css("display", 'none');
attrs.xloading = spinner_div;
}
else {
if (attrs.xloading) {
attrs.xloading.remove();
attrs.xloading = false;
element.css("display", 'block');
}
}
}
);
}});
To use this directive, leave empty attribute src of element and fill attribute onload-src.
Angular has animations build in in unstable branch, which should perfectly fit your scenario.
Just check out http://www.nganimate.org/angularjs/tutorial/how-to-make-animations-with-angularjs.
ng-view directive has build in 'enter' and 'leave' animations.
Check you this sample: http://jsfiddle.net/nFhX8/18/ which does more less what you'd like to achieve.