Skip to content

Commit

Permalink
Fix sliding animation on table elements and in Safari
Browse files Browse the repository at this point in the history
This is a proof-of-concept commit for comments. It is not yet cleaned up.
  • Loading branch information
chrisirhc committed Mar 28, 2021
1 parent ddfe920 commit e4ea648
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 4 deletions.
26 changes: 26 additions & 0 deletions src/runtime/internal/style_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,32 @@ function hash(str: string) {
return hash >>> 0;
}

export function create_static_rule(node: Element & ElementCSSInlineStyle, rule: string, uid: number = 0) {
const className = `__svelte_${hash(rule)}_${uid}`;
const doc = node.ownerDocument as ExtendedDoc;
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();
}

export function create_rule(node: Element & ElementCSSInlineStyle, a: number, b: number, duration: number, delay: number, ease: (t: number) => number, fn: (t: number, u: number) => string, uid: number = 0) {
const step = 16.666 / duration;
let keyframes = '{\n';
Expand Down
24 changes: 21 additions & 3 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 @@ -72,12 +72,14 @@ type TransitionFn = (node: Element, params: any) => TransitionConfig;
export function create_in_transition(node: Element & ElementCSSInlineStyle, fn: TransitionFn, params: any) {
let config = fn(node, params);
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 @@ -86,9 +88,11 @@ export function create_in_transition(node: Element & ElementCSSInlineStyle, fn:
duration = 300,
easing = linear,
tick = noop,
css
css,
staticCss,
} = config || null_transition;

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

Expand Down Expand Up @@ -233,6 +237,14 @@ export function create_bidirectional_transition(node: Element & ElementCSSInline
let running_program = null;
let pending_program = 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 @@ -259,7 +271,8 @@ export function create_bidirectional_transition(node: Element & ElementCSSInline
duration = 300,
easing = linear,
tick = noop,
css
css,
staticCss
} = config || null_transition;

const program = {
Expand All @@ -278,6 +291,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 (staticCss && !static_class_name) {
static_class_name = create_static_rule(node, staticCss);
}
if (css) {
clear_animation();
animation_name = create_rule(node, t, b, duration, delay, easing, css);
Expand Down Expand Up @@ -311,6 +327,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 @@ -345,6 +362,7 @@ export function create_bidirectional_transition(node: Element & ElementCSSInline

end() {
clear_animation();
clear_static_css();
running_program = pending_program = null;
}
};
Expand Down
10 changes: 9 additions & 1 deletion src/runtime/transition/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export interface TransitionConfig {
duration?: number;
easing?: EasingFunction;
css?: (t: number, u: number) => string;
staticCss?: string;
tick?: (t: number, u: number) => void;
}

Expand Down Expand Up @@ -115,12 +116,19 @@ export function slide(node: Element, {
const border_top_width = parseFloat(style.borderTopWidth);
const border_bottom_width = parseFloat(style.borderBottomWidth);

let displayOverride = '';
// May want to use a whitelist instead
if (style.display.includes('table')) {
displayOverride = 'display: block;';
}

return {
// Support a custom className to be added before and cleaned up after the thing.
staticCss: displayOverride + 'overflow: hidden;',
delay,
duration,
easing,
css: t =>
'overflow: hidden;' +
`opacity: ${Math.min(t * 20, 1) * opacity};` +
`height: ${t * height}px;` +
`padding-top: ${t * padding_top}px;` +
Expand Down

0 comments on commit e4ea648

Please sign in to comment.