snabbdom
Version:
A virtual DOM library with focus on simplicity, modularity, powerful features and performance.
87 lines (78 loc) • 2.58 kB
text/typescript
import {VNode, VNodeData} from '../vnode';
import {Module} from './module';
var raf = (typeof window !== 'undefined' && window.requestAnimationFrame) || setTimeout;
var nextFrame = function(fn: any) { raf(function() { raf(fn); }); };
function setNextFrame(obj: any, prop: string, val: any): void {
nextFrame(function() { obj[prop] = val; });
}
function updateStyle(oldVnode: VNode, vnode: VNode): void {
var cur: any, name: string, elm = vnode.elm,
oldStyle = (oldVnode.data as VNodeData).style,
style = (vnode.data as VNodeData).style;
if (!oldStyle && !style) return;
oldStyle = oldStyle || {};
style = style || {};
var oldHasDel = 'delayed' in oldStyle;
for (name in oldStyle) {
if (!style[name]) {
if (name.startsWith('--')) {
(elm as any).style.removeProperty(name);
} else {
(elm as any).style[name] = '';
}
}
}
for (name in style) {
cur = style[name];
if (name === 'delayed') {
for (name in style.delayed) {
cur = style.delayed[name];
if (!oldHasDel || cur !== oldStyle.delayed[name]) {
setNextFrame((elm as any).style, name, cur);
}
}
} else if (name !== 'remove' && cur !== oldStyle[name]) {
if (name.startsWith('--')) {
(elm as any).style.setProperty(name, cur);
} else {
(elm as any).style[name] = cur;
}
}
}
}
function applyDestroyStyle(vnode: VNode): void {
var style: any, name: string, elm = vnode.elm, s = (vnode.data as VNodeData).style;
if (!s || !(style = s.destroy)) return;
for (name in style) {
(elm as any).style[name] = style[name];
}
}
function applyRemoveStyle(vnode: VNode, rm: () => void): void {
var s = (vnode.data as VNodeData).style;
if (!s || !s.remove) {
rm();
return;
}
var name: string, elm = vnode.elm, i = 0, compStyle: CSSStyleDeclaration,
style = s.remove, amount = 0, applied: Array<string> = [];
for (name in style) {
applied.push(name);
(elm as any).style[name] = style[name];
}
compStyle = getComputedStyle(elm as Element);
var props = (compStyle as any)['transition-property'].split(', ');
for (; i < props.length; ++i) {
if(applied.indexOf(props[i]) !== -1) amount++;
}
(elm as Element).addEventListener('transitionend', function (ev: TransitionEvent) {
if (ev.target === elm) --amount;
if (amount === 0) rm();
});
}
export const styleModule = {
create: updateStyle,
update: updateStyle,
destroy: applyDestroyStyle,
remove: applyRemoveStyle
} as Module;
export default styleModule;