Skip to content

Commit e79ce19

Browse files
authored
Merge pull request #15 from VanishMax/improvement/transition
Improve transitions
2 parents af329cc + 2c7abc1 commit e79ce19

File tree

18 files changed

+466
-86
lines changed

18 files changed

+466
-86
lines changed

src/docs/containers/Modals.vue

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,29 @@
22
<section class="w-full rounded shadow-lg p-4">
33
<h2 class="text-xl mb-2">Modal window</h2>
44
<Button @click.native="open = true" is:primary>Open simple modal</Button>
5-
<Button
6-
@click.native="open1 = true"
7-
is:danger
8-
class="mt-4"
9-
>
5+
<Button @click.native="open1 = true" is:primary class="mt-4">
6+
Open high-transitioned modal
7+
</Button>
8+
<Button @click.native="open2 = true" is:danger class="mt-4">
109
Open destroyable non-closable modal
1110
</Button>
1211

12+
<Modal v-model="open">
13+
<h2>Simple modal</h2>
14+
</Modal>
15+
1316
<Modal
14-
v-model="open"
15-
:transition-options="{animation: animationOptions}"
17+
v-model="open1"
18+
:transition-props="{animation: animationOptions}"
19+
transition="blur"
1620
>
1721
<template #default="{close}">
18-
<h2>Hello, world</h2>
22+
<h2>High-transitioned modal</h2>
1923
<Button @click.native="close" is:danger>Close modal</Button>
2024
</template>
2125
</Modal>
2226

23-
<Modal v-model="open1" destroyable non-closable>
27+
<Modal v-model="open2" destroyable non-closable>
2428
<template #default="{close}">
2529
<Counter :close="close" />
2630
</template>
@@ -41,6 +45,7 @@
4145
return {
4246
open: false,
4347
open1: false,
48+
open2: false,
4449
animationOptions: {
4550
delay: 300,
4651
duration: 1000,
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<template>
2+
<section class="w-full rounded shadow-lg p-4">
3+
<h2 class="text-xl mb-2">Transition</h2>
4+
<Toggle v-model="shown" />
5+
<Transition name="fade" appear mode="out-in">
6+
<Button v-if="shown" key="on" is:primary>Hello</Button>
7+
<Button v-else key="off" is:danger>Good bye</Button>
8+
</Transition>
9+
10+
<br>
11+
<br class="mt-4">
12+
<Toggle v-model="shown1" />
13+
<Transition name="slide" appear :animation="{easing: 'easeInOutBack', duration: 500}">
14+
<Button v-if="shown1" key="on" is:primary>Slide with easeInOutBack easing</Button>
15+
</Transition>
16+
</section>
17+
</template>
18+
19+
<script lang="ts">
20+
import Vue from 'vue';
21+
import Button from '@/lib/components/Button.vue';
22+
import Transition from '@/lib/components/Transition.vue';
23+
import Toggle from '@/lib/components/Toggle.vue';
24+
25+
export default Vue.extend({
26+
name: 'Radios',
27+
components: {
28+
Button,
29+
Transition,
30+
Toggle,
31+
},
32+
data () {
33+
return {
34+
shown: true,
35+
shown1: true,
36+
};
37+
},
38+
});
39+
</script>

src/docs/views/index.vue

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
<div class="w-full">
2525
<Toggles />
2626
</div>
27+
<div class="w-full">
28+
<Transitions />
29+
</div>
2730
</div>
2831
</template>
2932

@@ -37,6 +40,7 @@
3740
import Modals from '../containers/Modals.vue';
3841
import Tabs from '../containers/Tabs.vue';
3942
import Toggles from '../containers/Toggles.vue';
43+
import Transitions from '../containers/Transitions.vue';
4044
4145
export default Vue.extend({
4246
name: 'Home',
@@ -49,6 +53,7 @@
4953
Modals,
5054
Tabs,
5155
Toggles,
56+
Transitions,
5257
},
5358
});
5459
</script>

src/lib/components/Dropdown.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
:value="val"
2121
/>
2222
</div>
23-
<Transition :name="transitionName" :options="transitionOptions">
23+
<Transition :name="transitionName" v-bind="transitionProps">
2424
<div v-show="val" v-check-position="{position, positionRelative}" :class="dropdownClasses">
2525
<slot :open="open" :close="close" :value="val" />
2626
</div>
@@ -113,7 +113,7 @@
113113
},
114114
115115
transition: String,
116-
transitionOptions: Object as PropType<TransitionOptions>,
116+
transitionProps: Object as PropType<TransitionOptions>,
117117
},
118118
data () {
119119
return {

src/lib/components/Modal.vue

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<template>
2-
<Transition :name="transitionName" :options="transitionOptions">
2+
<Transition :name="transitionName" v-bind="transitionProps">
33
<dialog
44
v-show="val"
55
:class="overlayClasses"
@@ -64,7 +64,7 @@
6464
bodyClass: String,
6565
6666
transition: String,
67-
transitionOptions: Object as PropType<TransitionOptions>,
67+
transitionProps: Object as PropType<TransitionOptions>,
6868
},
6969
data () {
7070
return {
@@ -118,8 +118,8 @@
118118
}
119119
},
120120
bodyClasses (val: string|null) {
121-
if (val && typeof window !== 'undefined') {
122-
document.body.setAttribute('class', composeClasses(this.body, val) || '');
121+
if (typeof window !== 'undefined') {
122+
document.body.setAttribute('class', composeClasses(this.body, val || '') || '');
123123
}
124124
},
125125
},

src/lib/components/Transition.vue

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010

1111
<script lang="ts">
1212
import Vue, {PropType} from 'vue';
13-
import {TransitionOptions} from '@/lib/types';
13+
import {AnimationOptions, TransitionOptions} from '@/lib/types';
1414
1515
interface TransitionType extends Partial<TransitionOptions> {
16-
name: 'fade'|string|null,
16+
name: 'fade'|'blur'|'scale'|'slide'|'fly'|string|null,
1717
hooks?: any,
1818
options: {
1919
appear?: boolean,
@@ -30,7 +30,31 @@
3030
default: null,
3131
},
3232
33-
options: Object as PropType<TransitionOptions>,
33+
/**
34+
* Following properties are well-explained in the official Vue documentation:
35+
* https://vuejs.org/v2/guide/transitions.html#Transition-Modes
36+
*
37+
* Shortly:
38+
* * Appear – show transition on initial Transition mount
39+
* * Mode – how to switch between if-else_if-else components. Supported: in-out, out-in
40+
*/
41+
appear: {
42+
type: Boolean,
43+
default: false,
44+
},
45+
mode: {
46+
type: String as PropType<'in-out'|'out-in'|null>,
47+
default: null,
48+
},
49+
50+
/**
51+
* Animation object to configure such properties as:
52+
* delay, duration, type (only in or only out), easing etc.
53+
*/
54+
animation: {
55+
type: Object as PropType<AnimationOptions>,
56+
default: null,
57+
},
3458
},
3559
computed: {
3660
transition (): TransitionType {
@@ -47,15 +71,19 @@
4771
} else {
4872
return {
4973
...transition,
50-
animation: this.options?.animation || transition.animation,
74+
animation: {...transition.animation, ...this.animation},
5175
options: {
52-
appear: !!this.options?.appear,
53-
mode: this.options?.mode || null,
54-
css: !this.options?.animation,
76+
appear: this.appear,
77+
mode: this.mode || null,
78+
css: !this.animation,
5579
},
5680
};
5781
}
5882
},
83+
84+
/**
85+
* Transition hooks are JS-functions that are mapped as events. They draw the animation
86+
*/
5987
hooks () {
6088
const hooks = this.transition?.hooks;
6189
const newHooks: any = {};

src/lib/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Default IUI configuration. Read more about it here: https://industrial-ui.com/docs/configuration
33
*/
44
import { Config } from './types';
5-
import transitions from './utils/transitions';
5+
import transitions from './transitions';
66

77
const config: Config = {
88
stylesheets: [],
Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
import {EasingFunction, Easings} from '@/lib/types';
2+
import easings from '@/lib/transitions/easings';
3+
4+
const isString = (str: any): str is string => typeof str === 'string';
5+
16
const animate = ({
27
easing,
38
draw,
@@ -6,7 +11,7 @@ const animate = ({
611
}: {
712
duration: number,
813
draw: (fraction: number) => void,
9-
easing?: (fraction: number) => number,
14+
easing?: Extract<keyof Easings, string> | EasingFunction,
1015
callback?: () => void,
1116
}) => {
1217
const start = performance.now();
@@ -17,7 +22,11 @@ const animate = ({
1722
if (timeFraction > 1) timeFraction = 1;
1823

1924
// calculate the current animation state with timing function: linear, ease-in, ease-out etc
20-
const progress = easing ? easing(timeFraction) : timeFraction;
25+
let progress = timeFraction;
26+
if (easing) {
27+
if (isString(easing)) progress = easings[easing]?.(timeFraction) || timeFraction;
28+
else progress = easing(timeFraction) || timeFraction;
29+
}
2130

2231
draw(progress);
2332

src/lib/transitions/blur.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import {Transition} from '@/lib/types';
2+
import tick from '@/lib/transitions/hook';
3+
4+
const blurTransition: Transition = {
5+
name: 'blur',
6+
7+
// Animation object goes straight to hook functions as argument
8+
animation: {
9+
delay: 0,
10+
duration: 300,
11+
type: 'both',
12+
amount: 5,
13+
},
14+
15+
hooks: {
16+
beforeEnter ({el}) {
17+
el.style.filter = 'initial';
18+
el.style.opacity = '0';
19+
},
20+
21+
enter({el, done}, animation) {
22+
if (animation.type === 'both' || animation.type === 'only-in') {
23+
tick({...animation, done}, (fraction) => {
24+
el.style.opacity = fraction.toString();
25+
el.style.filter = `blur(${(1 - fraction) * animation.amount}px)`;
26+
});
27+
} else done();
28+
},
29+
30+
afterEnter ({el}) {
31+
el.style.opacity = '1';
32+
el.style.filter = 'inherit';
33+
},
34+
35+
beforeLeave ({el}) {
36+
el.style.filter = 'initial';
37+
el.style.opacity = '1';
38+
},
39+
40+
leave ({el, done}, animation) {
41+
if (animation.type === 'both' || animation.type === 'only-out') {
42+
tick({...animation, done}, (fraction) => {
43+
el.style.opacity = (1 - fraction).toString();
44+
el.style.filter = `blur(${fraction * animation.amount}px)`;
45+
});
46+
} else done();
47+
},
48+
49+
afterLeave ({el}) {
50+
el.style.filter = 'initial';
51+
el.style.opacity = '0';
52+
},
53+
},
54+
};
55+
56+
export default blurTransition;

src/lib/transitions/easings.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import {Easings} from '@/lib/types';
2+
3+
const easings: Easings = {
4+
linear: (x: number) => x,
5+
easeIn: (x: number) => 1 - Math.cos((x * Math.PI) / 2),
6+
easeOut: (x: number) => Math.sin((x * Math.PI) / 2),
7+
easeInOut: (x: number) => -(Math.cos(Math.PI * x) - 1) / 2,
8+
easeInBack: (x: number) => 2.70158 * x ** 3 - 1.70158 * x * x,
9+
easeOutBack: (x: number) => 1 + 2.70158 * (x - 1) ** 3 + 1.70158 * (x - 1) ** 2,
10+
easeInOutBack: (x: number) => {
11+
const c1 = 1.70158;
12+
const c2 = c1 * 1.525;
13+
14+
return x < 0.5
15+
? ((2 * x) ** 2 * ((c2 + 1) * 2 * x - c2)) / 2
16+
: ((2 * x - 2) ** 2 * ((c2 + 1) * (x * 2 - 2) + c2) + 2) / 2;
17+
},
18+
};
19+
20+
export default easings;

0 commit comments

Comments
 (0)