Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix sliding animation on table elements in Safari #5922

Closed
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/runtime/internal/style_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,32 @@ function hash(str: string) {
return hash >>> 0;
}

export function create_static_rule(node: Element & ElementCSSInlineStyle, rule: string) {
const className = `__svelte_${hash(rule)}`;
benmccann marked this conversation as resolved.
Show resolved Hide resolved
const doc = node.ownerDocument as ExtendedDoc;
benmccann marked this conversation as resolved.
Show resolved Hide resolved
active_docs.add(doc);
const stylesheet = doc.__svelte_stylesheet || (doc.__svelte_stylesheet = doc.head.appendChild(element('style') as HTMLStyleElement).sheet as CSSStyleSheet);
const current_rules = doc.__svelte_rules || (doc.__svelte_rules = {});

if (!current_rules[className]) {
current_rules[className] = true;
stylesheet.insertRule(`.${className} {${rule}}`, stylesheet.cssRules.length);
}

node.classList.add(className);

active += 1;
return className;
}

export function delete_static_rule(node: Element & ElementCSSInlineStyle, name: string) {
if (name) {
node.classList.remove(name); // remove specific class
}
active -= 1;
if (!active) clear_rules();
}

function create_style_information(doc: Document | ShadowRoot, node: Element & ElementCSSInlineStyle) {
const info = { stylesheet: append_empty_stylesheet(node), rules: {} };
managed_styles.set(doc, info);
Expand Down
30 changes: 26 additions & 4 deletions src/runtime/internal/transitions.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { identity as linear, is_function, noop, run_all } from './utils';
import { now } from './environment';
import { loop } from './loop';
import { create_rule, delete_rule } from './style_manager';
import { create_rule, delete_rule, create_static_rule, delete_static_rule } from './style_manager';
import { custom_event } from './dom';
import { add_render_callback } from './scheduler';
import { TransitionConfig } from '../transition';
Expand Down Expand Up @@ -93,12 +93,14 @@ export function create_in_transition(node: Element & ElementCSSInlineStyle, fn:
const options: TransitionOptions = { direction: 'in' };
let config = fn(node, params, options);
let running = false;
let static_class_name;
let animation_name;
let task;
let uid = 0;

function cleanup() {
if (animation_name) delete_rule(node, animation_name);
if (static_class_name) delete_static_rule(node, static_class_name);
}

function go() {
Expand All @@ -107,9 +109,11 @@ export function create_in_transition(node: Element & ElementCSSInlineStyle, fn:
duration = 300,
easing = linear,
tick = noop,
css
css,
static_css
} = config || null_transition;

if (static_css) static_class_name = create_static_rule(node, static_css);
if (css) animation_name = create_rule(node, 0, 1, duration, delay, easing, css, uid++);
tick(0, 1);

Expand Down Expand Up @@ -176,6 +180,7 @@ export function create_out_transition(node: Element & ElementCSSInlineStyle, fn:
const options: TransitionOptions = { direction: 'out' };
let config = fn(node, params, options);
let running = true;
let static_class_name;
let animation_name;

const group = outros;
Expand All @@ -188,9 +193,11 @@ export function create_out_transition(node: Element & ElementCSSInlineStyle, fn:
duration = 300,
easing = linear,
tick = noop,
css
css,
static_css
} = config || null_transition;

if (static_css) static_class_name = create_static_rule(node, static_css);
if (css) animation_name = create_rule(node, 1, 0, duration, delay, easing, css);

const start_time = now() + delay;
Expand Down Expand Up @@ -242,6 +249,7 @@ export function create_out_transition(node: Element & ElementCSSInlineStyle, fn:

if (running) {
if (animation_name) delete_rule(node, animation_name);
if (static_class_name) delete_static_rule(node, static_class_name);
running = false;
}
}
Expand Down Expand Up @@ -275,6 +283,14 @@ export function create_bidirectional_transition(node: Element & ElementCSSInline
let running_program: Program | null = null;
let pending_program: PendingProgram | null = null;
let animation_name = null;
let static_class_name = null;

function clear_static_css() {
if (static_class_name) {
delete_static_rule(node, static_class_name);
static_class_name = null;
}
}

function clear_animation() {
if (animation_name) delete_rule(node, animation_name);
Expand All @@ -301,7 +317,8 @@ export function create_bidirectional_transition(node: Element & ElementCSSInline
duration = 300,
easing = linear,
tick = noop,
css
css,
static_css
} = config || null_transition;

const program: PendingProgram = {
Expand All @@ -320,6 +337,9 @@ export function create_bidirectional_transition(node: Element & ElementCSSInline
} else {
// if this is an intro, and there's a delay, we need to do
// an initial tick and/or apply CSS animation immediately
if (static_css && !static_class_name) {
static_class_name = create_static_rule(node, static_css);
}
if (css) {
clear_animation();
animation_name = create_rule(node, t, b, duration, delay, easing, css);
Expand Down Expand Up @@ -353,6 +373,7 @@ export function create_bidirectional_transition(node: Element & ElementCSSInline
if (running_program.b) {
// intro — we can tidy up immediately
clear_animation();
clear_static_css();
} else {
// outro — needs to be coordinated
if (!--running_program.group.r) run_all(running_program.group.c);
Expand Down Expand Up @@ -387,6 +408,7 @@ export function create_bidirectional_transition(node: Element & ElementCSSInline

end() {
clear_animation();
clear_static_css();
running_program = pending_program = null;
}
};
Expand Down
5 changes: 4 additions & 1 deletion src/runtime/transition/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { assign, split_css_unit, is_function } from 'svelte/internal';
export type EasingFunction = (t: number) => number;

export interface TransitionConfig {
static_css?: string;
delay?: number;
duration?: number;
easing?: EasingFunction;
Expand Down Expand Up @@ -120,12 +121,14 @@ export function slide(node: Element, {
const margin_end_value = parseFloat(style[`margin${capitalized_secondary_properties[1]}`]);
const border_width_start_value = parseFloat(style[`border${capitalized_secondary_properties[0]}Width`]);
const border_width_end_value = parseFloat(style[`border${capitalized_secondary_properties[1]}Width`]);
const display_override = style.display.includes('table') ? 'display:block;' : '';

return {
delay,
duration,
easing,
static_css: display_override + 'overflow:hidden;',
css: t =>
'overflow: hidden;' +
`opacity: ${Math.min(t * 20, 1) * opacity};` +
`${primary_property}: ${t * primary_property_value}px;` +
`padding-${secondary_properties[0]}: ${t * padding_start_value}px;` +
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
export default {
test({ assert, component, target, window, raf }) {
component.visible = true;
const div = target.querySelector('div');

assert.equal(div.className, '__svelte_2375698960');
assert.equal(div.style.animation, '__svelte_3809512021_0 100ms linear 0ms 1 both');

raf.tick(50);
component.visible = false;

// both in and out styles
assert.equal(div.className, '__svelte_2375698960 __svelte_1786671888');
assert.equal(div.style.animation, '__svelte_3809512021_0 100ms linear 0ms 1 both, __svelte_3750847757_0 100ms linear 0ms 1 both');

raf.tick(75);
component.visible = true;

// reset to in styles (in transition in progress)
assert.equal(div.style.animation, '__svelte_3809512021_1 100ms linear 0ms 1 both');
assert.equal(div.className, '__svelte_2375698960');

// 100ms after in transition started at 75
raf.tick(175);

// reset original styles after in transition is complete
assert.equal(div.style.animation, '');
assert.equal(div.className, '');
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<script>
export let visible;

function foo() {
return {
duration: 100,
static_css: 'display: block',
css: t => {
return `opacity: ${t}`;
}
};
}

function bar() {
return {
duration: 100,
static_css: 'display: inline-block',
css: t => {
return `opacity: ${t}`;
}
};
}
</script>

{#if visible}
<div in:foo out:bar></div>
{/if}