Skip to content

Commit d241921

Browse files
Bob Fangerbfanger
authored andcommitted
feat: Support css units in fly transition
1 parent ecb29aa commit d241921

File tree

4 files changed

+57
-7
lines changed

4 files changed

+57
-7
lines changed

site/content/docs/03-run-time.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -705,10 +705,11 @@ Animates the x and y positions and the opacity of an element. `in` transitions a
705705
* `delay` (`number`, default 0) — milliseconds before starting
706706
* `duration` (`number`, default 400) — milliseconds the transition lasts
707707
* `easing` (`function`, default `cubicOut`) — an [easing function](/docs#run-time-svelte-easing)
708-
* `x` (`number`, default 0) - the x offset to animate out to and in from
709-
* `y` (`number`, default 0) - the y offset to animate out to and in from
708+
* `x` (`number|string`, default 0) - the x offset to animate out to and in from
709+
* `y` (`number|string`, default 0) - the y offset to animate out to and in from
710710
* `opacity` (`number`, default 0) - the opacity value to animate out to and in from
711711

712+
x and y use `px` by default but support css units, for example `x: '100vw'` or `y: '50%'`.
712713
You can see the `fly` transition in action in the [transition tutorial](/tutorial/adding-parameters-to-transitions).
713714

714715
```sv

src/runtime/internal/utils.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,3 +187,15 @@ export const has_prop = (obj, prop) => Object.prototype.hasOwnProperty.call(obj,
187187
export function action_destroyer(action_result) {
188188
return action_result && is_function(action_result.destroy) ? action_result.destroy : noop;
189189
}
190+
191+
export function split_css_unit(value: number | string, fallback = 'px'): [number, string] {
192+
if (typeof value === 'number') {
193+
return [value, fallback];
194+
}
195+
const split = value?.match?.(/^\s*(-?[\d.]+)([^\s]*)\s*$/);
196+
if (split) {
197+
return [parseFloat(split[1]), split[2] || fallback];
198+
}
199+
console.warn('Failed to split', value);
200+
return [parseFloat(value), fallback];
201+
}

src/runtime/transition/index.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { cubicOut, cubicInOut, linear } from 'svelte/easing';
2-
import { assign, is_function } from 'svelte/internal';
2+
import { assign, split_css_unit, is_function } from 'svelte/internal';
33

44
export type EasingFunction = (t: number) => number;
55

@@ -65,8 +65,8 @@ export interface FlyParams {
6565
delay?: number;
6666
duration?: number;
6767
easing?: EasingFunction;
68-
x?: number;
69-
y?: number;
68+
x?: number | string;
69+
y?: number | string;
7070
opacity?: number;
7171
}
7272

@@ -83,13 +83,14 @@ export function fly(node: Element, {
8383
const transform = style.transform === 'none' ? '' : style.transform;
8484

8585
const od = target_opacity * (1 - opacity);
86-
86+
const [xValue, xUnit] = split_css_unit(x);
87+
const [yValue, yUnit] = split_css_unit(y);
8788
return {
8889
delay,
8990
duration,
9091
easing,
9192
css: (t, u) => `
92-
transform: ${transform} translate(${(1 - t) * x}px, ${(1 - t) * y}px);
93+
transform: ${transform} translate(${(1 - t) * xValue}${xUnit}, ${(1 - t) * yValue}${yUnit});
9394
opacity: ${target_opacity - (od * u)}`
9495
};
9596
}

test/utils/index.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as assert from 'assert';
22
import { trim_start, trim_end } from '../../src/compiler/utils/trim';
3+
import { split_css_unit } from '../../src/runtime/internal/utils';
34

45
describe('utils', () => {
56
describe('trim', () => {
@@ -13,4 +14,39 @@ describe('utils', () => {
1314
assert.equal(value, ' \r\n\t svelte content');
1415
});
1516
});
17+
18+
describe('split_css_unit', () => {
19+
it('should use px as default', () => {
20+
assert.deepEqual(split_css_unit(10),[10, 'px']);
21+
assert.deepEqual(split_css_unit('10'),[10, 'px']);
22+
});
23+
it('should use the fallback', () => {
24+
assert.deepEqual(split_css_unit(100, '%'),[100, '%']);
25+
assert.deepEqual(split_css_unit('100', '%'),[100, '%']);
26+
});
27+
it('should split the css notation into value and unit', () => {
28+
assert.deepEqual(split_css_unit('-50%'),[-50, '%']);
29+
assert.deepEqual(split_css_unit('0.1rem'),[0.1, 'rem']);
30+
assert.deepEqual(split_css_unit('.1rem'),[0.1, 'rem']);
31+
});
32+
33+
it('should complain for invalid input', () => {
34+
const warnings = [];
35+
const warn = console.warn;
36+
console.warn = (...args) => {
37+
warnings.push(args);
38+
};
39+
40+
split_css_unit('calc(100vw - 10rem)');
41+
split_css_unit(undefined);
42+
assert.deepEqual(split_css_unit('100 %'), [100, 'px']);
43+
assert.deepEqual(warnings, [
44+
['Failed to split', 'calc(100vw - 10rem)'],
45+
['Failed to split', undefined],
46+
['Failed to split', '100 %']
47+
]);
48+
49+
console.warn = warn;
50+
});
51+
});
1652
});

0 commit comments

Comments
 (0)