fix: remove the hero module (#953)

The hero module is very specific and not really a good fit for a low
level library like snabbdom. Users that still want to use it can copy
the code from the hero example instead

ISSUES CLOSED: #517
BREAKING CHANGE:
Snabbdom does not export the hero module any more. If you require this
module, copy the code from examples/hero/hero.js and add it to your
project
pull/956/head
Jan van Brügge 4 years ago committed by GitHub
parent e313d41b37
commit 30b7df61ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -41,6 +41,12 @@ module.exports = {
node: true, node: true,
}, },
}, },
{
files: ["examples/**/*.js"],
rules: {
"@typescript-eslint/explicit-module-boundary-types": "off",
},
},
{ {
files: ["*.js"], files: ["*.js"],
excludedFiles: ["examples/**"], excludedFiles: ["examples/**"],

@ -1,24 +1,20 @@
import { VNode, VNodeData } from "../vnode";
import { Module } from "./module";
export type Hero = { id: string };
const raf = const raf =
(typeof window !== "undefined" && window.requestAnimationFrame) || setTimeout; (typeof window !== "undefined" && window.requestAnimationFrame) || setTimeout;
const nextFrame = function (fn: any) {
const nextFrame = function (fn) {
raf(function () { raf(function () {
raf(fn); raf(fn);
}); });
}; };
function setNextFrame(obj: any, prop: string, val: any): void { function setNextFrame(obj, prop, val) {
nextFrame(function () { nextFrame(function () {
obj[prop] = val; obj[prop] = val;
}); });
} }
function getTextNodeRect(textNode: Text): ClientRect | undefined { function getTextNodeRect(textNode) {
let rect: ClientRect | undefined; let rect;
if (document.createRange) { if (document.createRange) {
const range = document.createRange(); const range = document.createRange();
range.selectNodeContents(textNode); range.selectNodeContents(textNode);
@ -29,11 +25,7 @@ function getTextNodeRect(textNode: Text): ClientRect | undefined {
return rect; return rect;
} }
function calcTransformOrigin( function calcTransformOrigin(isTextNode, textRect, boundingRect) {
isTextNode: boolean,
textRect: ClientRect | undefined,
boundingRect: ClientRect
): string {
if (isTextNode) { if (isTextNode) {
if (textRect) { if (textRect) {
// calculate pixels to center of text from left edge of bounding box // calculate pixels to center of text from left edge of bounding box
@ -47,10 +39,7 @@ function calcTransformOrigin(
return "0 0"; // top left return "0 0"; // top left
} }
function getTextDx( function getTextDx(oldTextRect, newTextRect) {
oldTextRect: ClientRect | undefined,
newTextRect: ClientRect | undefined
): number {
if (oldTextRect && newTextRect) { if (oldTextRect && newTextRect) {
return ( return (
oldTextRect.left + oldTextRect.left +
@ -60,10 +49,8 @@ function getTextDx(
} }
return 0; return 0;
} }
function getTextDy(
oldTextRect: ClientRect | undefined, function getTextDy(oldTextRect, newTextRect) {
newTextRect: ClientRect | undefined
): number {
if (oldTextRect && newTextRect) { if (oldTextRect && newTextRect) {
return ( return (
oldTextRect.top + oldTextRect.top +
@ -74,77 +61,76 @@ function getTextDy(
return 0; return 0;
} }
function isTextElement(elm: Element | Text): elm is Text { function isTextElement(elm) {
return elm.childNodes.length === 1 && elm.childNodes[0].nodeType === 3; return elm.childNodes.length === 1 && elm.childNodes[0].nodeType === 3;
} }
let removed: any, created: any; let removed, created;
function pre() { function pre() {
removed = {}; removed = {};
created = []; created = [];
} }
function create(oldVnode: VNode, vnode: VNode): void { function create(oldVnode, vnode) {
const hero = (vnode.data as VNodeData).hero; const hero = vnode.data.hero;
if (hero && hero.id) { if (hero && hero.id) {
created.push(hero.id); created.push(hero.id);
created.push(vnode); created.push(vnode);
} }
} }
function destroy(vnode: VNode): void { function destroy(vnode) {
const hero = (vnode.data as VNodeData).hero; const hero = vnode.data.hero;
if (hero && hero.id) { if (hero && hero.id) {
const elm = vnode.elm; const elm = vnode.elm;
(vnode as any).isTextNode = isTextElement(elm as Element | Text); // is this a text node? vnode.isTextNode = isTextElement(elm); // is this a text node?
(vnode as any).boundingRect = (elm as Element).getBoundingClientRect(); // save the bounding rectangle to a new property on the vnode vnode.boundingRect = elm.getBoundingClientRect(); // save the bounding rectangle to a new property on the vnode
(vnode as any).textRect = (vnode as any).isTextNode vnode.textRect = vnode.isTextNode
? getTextNodeRect((elm as Element).childNodes[0] as Text) ? getTextNodeRect(elm.childNodes[0])
: null; // save bounding rect of inner text node : null; // save bounding rect of inner text node
const computedStyle = window.getComputedStyle(elm as Element, undefined); // get current styles (includes inherited properties) const computedStyle = window.getComputedStyle(elm, undefined); // get current styles (includes inherited properties)
(vnode as any).savedStyle = JSON.parse(JSON.stringify(computedStyle)); // save a copy of computed style values vnode.savedStyle = JSON.parse(JSON.stringify(computedStyle)); // save a copy of computed style values
removed[hero.id] = vnode; removed[hero.id] = vnode;
} }
} }
function post() { function post() {
let i: number, let i,
id: any, id,
newElm: Element, newElm,
oldVnode: VNode, oldVnode,
oldElm: Element, oldElm,
hRatio: number, hRatio,
wRatio: number, wRatio,
oldRect: ClientRect, oldRect,
newRect: ClientRect, newRect,
dx: number, dx,
dy: number, dy,
origTransform: string | null, origTransform,
origTransition: string | null, origTransition,
newStyle: CSSStyleDeclaration, newStyle,
oldStyle: CSSStyleDeclaration, oldStyle,
newComputedStyle: CSSStyleDeclaration, newComputedStyle,
isTextNode: boolean, isTextNode,
newTextRect: ClientRect | undefined, newTextRect,
oldTextRect: ClientRect | undefined; oldTextRect;
for (i = 0; i < created.length; i += 2) { for (i = 0; i < created.length; i += 2) {
id = created[i]; id = created[i];
newElm = created[i + 1].elm; newElm = created[i + 1].elm;
oldVnode = removed[id]; oldVnode = removed[id];
if (oldVnode) { if (oldVnode) {
isTextNode = (oldVnode as any).isTextNode && isTextElement(newElm); // Are old & new both text? isTextNode = oldVnode.isTextNode && isTextElement(newElm); // Are old & new both text?
newStyle = (newElm as HTMLElement).style; newStyle = newElm.style;
newComputedStyle = window.getComputedStyle(newElm, undefined); // get full computed style for new element newComputedStyle = window.getComputedStyle(newElm, undefined); // get full computed style for new element
oldElm = oldVnode.elm as Element; oldElm = oldVnode.elm;
oldStyle = (oldElm as HTMLElement).style; oldStyle = oldElm.style;
// Overall element bounding boxes // Overall element bounding boxes
newRect = newElm.getBoundingClientRect(); newRect = newElm.getBoundingClientRect();
oldRect = (oldVnode as any).boundingRect; // previously saved bounding rect oldRect = oldVnode.boundingRect; // previously saved bounding rect
// Text node bounding boxes & distances // Text node bounding boxes & distances
if (isTextNode) { if (isTextNode) {
newTextRect = getTextNodeRect(newElm.childNodes[0] as Text); newTextRect = getTextNodeRect(newElm.childNodes[0]);
oldTextRect = (oldVnode as any).textRect; oldTextRect = oldVnode.textRect;
dx = getTextDx(oldTextRect, newTextRect); dx = getTextDx(oldTextRect, newTextRect);
dy = getTextDy(oldTextRect, newTextRect); dy = getTextDy(oldTextRect, newTextRect);
} else { } else {
@ -175,7 +161,7 @@ function post() {
setNextFrame(newStyle, "transform", origTransform); setNextFrame(newStyle, "transform", origTransform);
setNextFrame(newStyle, "opacity", "1"); setNextFrame(newStyle, "opacity", "1");
// Animate old element // Animate old element
for (const key in (oldVnode as any).savedStyle) { for (const key in oldVnode.savedStyle) {
// re-apply saved inherited properties // re-apply saved inherited properties
if (String(parseInt(key)) !== key) { if (String(parseInt(key)) !== key) {
const ms = key.substring(0, 2) === "ms"; const ms = key.substring(0, 2) === "ms";
@ -183,7 +169,7 @@ function post() {
const webkit = key.substring(0, 6) === "webkit"; const webkit = key.substring(0, 6) === "webkit";
if (!ms && !moz && !webkit) { if (!ms && !moz && !webkit) {
// ignore prefixed style properties // ignore prefixed style properties
(oldStyle as any)[key] = (oldVnode as any).savedStyle[key]; oldStyle[key] = oldVnode.savedStyle[key];
} }
} }
} }
@ -207,9 +193,9 @@ function post() {
`translate(${-dx}px, ${-dy}px) scale(${wRatio}, ${hRatio})` `translate(${-dx}px, ${-dy}px) scale(${wRatio}, ${hRatio})`
); // scale must be on far right for translate to be correct ); // scale must be on far right for translate to be correct
setNextFrame(oldStyle, "opacity", "0"); setNextFrame(oldStyle, "opacity", "0");
oldElm.addEventListener("transitionend", function (ev: TransitionEvent) { oldElm.addEventListener("transitionend", function (ev) {
if (ev.propertyName === "transform") { if (ev.propertyName === "transform") {
document.body.removeChild(ev.target as Node); document.body.removeChild(ev.target);
} }
}); });
} }
@ -217,4 +203,4 @@ function post() {
removed = created = undefined; removed = created = undefined;
} }
export const heroModule: Module = { pre, create, destroy, post }; export const heroModule = { pre, create, destroy, post };

@ -1,12 +1,13 @@
import { import {
init, init,
classModule, classModule,
heroModule,
styleModule, styleModule,
eventListenersModule, eventListenersModule,
h, h,
} from "../../build/index.js"; } from "../../build/index.js";
import { heroModule } from "./hero";
const patch = init([ const patch = init([
classModule, classModule,
heroModule, heroModule,

@ -25,7 +25,6 @@ export { Attrs, attributesModule } from "./modules/attributes";
export { Classes, classModule } from "./modules/class"; export { Classes, classModule } from "./modules/class";
export { Dataset, datasetModule } from "./modules/dataset"; export { Dataset, datasetModule } from "./modules/dataset";
export { On, eventListenersModule } from "./modules/eventlisteners"; export { On, eventListenersModule } from "./modules/eventlisteners";
export { Hero, heroModule } from "./modules/hero";
export { Props, propsModule } from "./modules/props"; export { Props, propsModule } from "./modules/props";
export { VNodeStyle, styleModule } from "./modules/style"; export { VNodeStyle, styleModule } from "./modules/style";

@ -6,7 +6,6 @@ import { Attrs } from "./modules/attributes";
import { Classes } from "./modules/class"; import { Classes } from "./modules/class";
import { Props } from "./modules/props"; import { Props } from "./modules/props";
import { Dataset } from "./modules/dataset"; import { Dataset } from "./modules/dataset";
import { Hero } from "./modules/hero";
export type Key = string | number; export type Key = string | number;
@ -26,7 +25,6 @@ export interface VNodeData {
style?: VNodeStyle; style?: VNodeStyle;
dataset?: Dataset; dataset?: Dataset;
on?: On; on?: On;
hero?: Hero;
attachData?: AttachData; attachData?: AttachData;
hook?: Hooks; hook?: Hooks;
key?: Key; key?: Key;

Loading…
Cancel
Save