Skip to content

Commit

Permalink
Include external polyfills in shim (#184)
Browse files Browse the repository at this point in the history
* Create shims for IO, Resize, WebAnimations, pointer events and fetch

* Add runtime has checks for IO, Resize and pointer events

* Use shim implementation in framework

* Only run tests the leverage dom shims in browser

* Tweaks and units

* fix functional tests

* fix has logic for pointer events

* fix tests
  • Loading branch information
agubler committed Nov 26, 2018
1 parent 981a59e commit 68ccaa9
Show file tree
Hide file tree
Showing 17 changed files with 299 additions and 169 deletions.
12 changes: 9 additions & 3 deletions intern.json
Expand Up @@ -15,7 +15,6 @@
"./dist/dev/tests/shim/unit/all.js",
"./dist/dev/tests/core/unit/all.js",
"./dist/dev/tests/i18n/unit/all.js",
"./dist/dev/tests/widget-core/unit/all.js",
"./dist/dev/tests/stores/unit/all.js",
"./dist/dev/tests/testing/unit/all.js"
],
Expand Down Expand Up @@ -58,7 +57,8 @@
}
},
"suites+": [
"./dist/dev/tests/routing/unit/all.js"
"./dist/dev/tests/routing/unit/all.js",
"./dist/dev/tests/widget-core/unit/all.js"
],
"plugins+": [
{
Expand All @@ -76,7 +76,13 @@
"suites+": [
"./dist/dev/tests/routing/unit/**/*.js",
"!./dist/dev/tests/routing/unit/**/all.js",
"!./dist/dev/tests/routing/unit/history/StateHistory.js"
"!./dist/dev/tests/routing/unit/history/StateHistory.js",
"./dist/dev/tests/widget-core/unit/**/*.js",
"!./dist/dev/tests/widget-core/unit/all.js",
"!./dist/dev/tests/widget-core/unit/meta/all.js",
"!./dist/dev/tests/widget-core/unit/meta/Resize.js",
"!./dist/dev/tests/widget-core/unit/meta/WebAnimation.js",
"!./dist/dev/tests/widget-core/unit/meta/Intersection.js"
]
}
}
13 changes: 11 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions package.json
Expand Up @@ -54,8 +54,10 @@
"globalize": "1.3.0",
"intersection-observer": "0.4.2",
"pepjs": "0.4.2",
"resize-observer-polyfill": "1.5.0",
"tslib": "1.8.1",
"web-animations-js": "2.3.1"
"web-animations-js": "2.3.1",
"whatwg-fetch": "2.0.4"
},
"devDependencies": {
"@dojo/loader": "^2.0.0",
Expand Down Expand Up @@ -83,8 +85,7 @@
"rimraf": "~2.6.2",
"selenium-webdriver": "3.6.0",
"sinon": "~4.1.3",
"typescript": "~2.6.2",
"whatwg-fetch": "^2.0.4"
"typescript": "~2.6.2"
},
"lint-staged": {
"*.{ts,tsx}": [
Expand Down
8 changes: 8 additions & 0 deletions src/has/has.ts
Expand Up @@ -575,3 +575,11 @@ add(
add('abort-controller', () => typeof global.AbortController !== 'undefined');

add('abort-signal', () => typeof global.AbortSignal !== 'undefined');

add('dom-intersection-observer', () => has('host-browser') && global.IntersectionObserver !== undefined, true);

add('dom-resize-observer', () => has('host-browser') && global.ResizeObserver !== undefined, true);

add('dom-pointer-events', () => has('host-browser') && global.onpointerdown !== undefined, true);

add('build-elide', false);
5 changes: 5 additions & 0 deletions src/shim/IntersectionObserver.ts
@@ -0,0 +1,5 @@
import global from './global';
`!has('build-elide')`;
import 'intersection-observer';

export default global.IntersectionObserver as typeof IntersectionObserver;
12 changes: 12 additions & 0 deletions src/shim/ResizeObserver.ts
@@ -0,0 +1,12 @@
import global from './global';
import has from '../../src/has/has';
`!has('build-elide')`;
import ResizeObserver from 'resize-observer-polyfill';

if (!has('build-elide')) {
if (!global.ResizeObserver) {
global.ResizeObserver = ResizeObserver;
}
}

export default global.ResizeObserver as typeof ResizeObserver;
120 changes: 120 additions & 0 deletions src/shim/WebAnimations.ts
@@ -0,0 +1,120 @@
import global from './global';
`!has('build-elide')`;
import 'web-animations-js/web-animations-next-lite.min';

export type AnimationEffectTimingFillMode = 'none' | 'forwards' | 'backwards' | 'both' | 'auto';
export type AnimationEffectTimingPlaybackDirection = 'normal' | 'reverse' | 'alternate' | 'alternate-reverse';
export type AnimationPlayState = 'idle' | 'running' | 'paused' | 'finished';

export interface AnimationPlaybackEvent {
target: Animation;
readonly currentTime: number | null;
readonly timelineTime: number | null;
type: string;
bubbles: boolean;
cancelable: boolean;
currentTarget: Animation;
defaultPrevented: boolean;
eventPhase: number;
timeStamp: number;
}

export interface AnimationPlaybackEventInit extends EventInit {
currentTime?: number | null;
timelineTime?: number | null;
}

declare var AnimationPlaybackEvent: {
prototype: AnimationPlaybackEvent;
new (type: string, eventInitDict?: AnimationPlaybackEventInit): AnimationPlaybackEvent;
};

export interface AnimationKeyFrame {
easing?: string | string[];
offset?: number | Array<number | null> | null;
opacity?: number | number[];
transform?: string | string[];
}

export interface AnimationTimeline {
readonly currentTime: number | null;
getAnimations(): Animation[];
play(effect: KeyframeEffect): Animation;
}

export interface AnimationEffectTiming {
delay?: number;
direction?: AnimationEffectTimingPlaybackDirection;
duration?: number;
easing?: string;
endDelay?: number;
fill?: AnimationEffectTimingFillMode;
iterationStart?: number;
iterations?: number;
playbackRate?: number;
}

export interface AnimationEffectReadOnly {
readonly timing: number;
getComputedTiming(): ComputedTimingProperties;
}

export interface ComputedTimingProperties {
endTime: number;
activeDuration: number;
localTime: number | null;
progress: number | null;
currentIteration: number | null;
}

export interface KeyframeEffect extends AnimationEffectReadOnly {
activeDuration: number;
onsample: (timeFraction: number | null, effect: KeyframeEffect, animation: Animation) => void | undefined;
parent: KeyframeEffect | null;
target: HTMLElement;
timing: number;
getComputedTiming(): ComputedTimingProperties;
getFrames(): AnimationKeyFrame[];
remove(): void;
}

export interface KeyframeEffectConstructor {
prototype: KeyframeEffect;
new (
target: HTMLElement,
effect: AnimationKeyFrame | AnimationKeyFrame[],
timing: number | AnimationEffectTiming,
id?: string
): KeyframeEffect;
}

export type AnimationEventListener = (this: Animation, evt: AnimationPlaybackEvent) => any;

export interface Animation extends EventTarget {
currentTime: number | null;
id: string;
oncancel: AnimationEventListener;
onfinish: AnimationEventListener;
readonly playState: AnimationPlayState;
playbackRate: number;
startTime: number;
cancel(): void;
finish(): void;
pause(): void;
play(): void;
reverse(): void;
addEventListener(type: 'finish' | 'cancel', handler: EventListener): void;
removeEventListener(type: 'finish' | 'cancel', handler: EventListener): void;
effect: AnimationEffectReadOnly;
readonly finished: Promise<Animation>;
readonly ready: Promise<Animation>;
timeline: AnimationTimeline;
}

export interface AnimationConstructor {
prototype: Animation;
new (effect?: AnimationEffectReadOnly, timeline?: AnimationTimeline): Animation;
}

export const Animation = global.Animation as AnimationConstructor;
export const KeyframeEffect = global.KeyframeEffect as KeyframeEffectConstructor;
5 changes: 5 additions & 0 deletions src/shim/fetch.ts
@@ -0,0 +1,5 @@
import global from './global';
`!has('fetch')`;
import 'whatwg-fetch';

export default global.fetch as (input: RequestInfo, init?: RequestInit) => Promise<Response>;
2 changes: 2 additions & 0 deletions src/shim/pointerEvents.ts
@@ -0,0 +1,2 @@
`!has('build-elide')`;
import 'pepjs';
6 changes: 6 additions & 0 deletions src/shim/util/amd.ts
Expand Up @@ -22,6 +22,12 @@ function shimAmdDependencies(config: any) {
main: 'pep'
});

addIfNotPresent(packages, {
name: 'resize-observer-polyfill',
location: 'node_modules/resize-observer-polyfill/dist',
main: 'ResizeObserver'
});

addIfNotPresent(packages, {
name: 'intersection-observer',
location: 'node_modules/intersection-observer',
Expand Down
4 changes: 2 additions & 2 deletions src/widget-core/meta/Intersection.ts
@@ -1,7 +1,7 @@
import global from '../../shim/global';
import WeakMap from '../../shim/WeakMap';
import Map from '../../shim/Map';
import { Base } from './Base';
import IntersectionObserver from '../../shim/IntersectionObserver';

interface ExtendedIntersectionObserverEntry extends IntersectionObserverEntry {
readonly isIntersecting: boolean;
Expand Down Expand Up @@ -73,7 +73,7 @@ export class Intersection extends Base {

private _createDetails(options: IntersectionGetOptions, rootNode?: HTMLElement): IntersectionDetail {
const entries = new WeakMap<HTMLElement, ExtendedIntersectionObserverEntry>();
const observer = new global.IntersectionObserver(this._onIntersect(entries), { ...options, root: rootNode });
const observer = new IntersectionObserver(this._onIntersect(entries), { ...options, root: rootNode });
const details = { observer, entries, ...options };

this._details.set(JSON.stringify(options), details);
Expand Down
14 changes: 1 addition & 13 deletions src/widget-core/meta/Resize.ts
@@ -1,18 +1,6 @@
import { Base } from './Base';
import Map from '../../shim/Map';

interface Observer {
observe(node: HTMLElement): void;
}

declare const ResizeObserver: {
prototype: Observer;
new (callback: (entries: ResizeObserverEntry[]) => any): any;
};

interface ResizeObserverEntry {
contentRect: ContentRect;
}
import ResizeObserver from '../../shim/ResizeObserver';

export interface ContentRect {
readonly bottom: number;
Expand Down
31 changes: 5 additions & 26 deletions src/widget-core/meta/WebAnimation.ts
@@ -1,6 +1,7 @@
import { Base } from './Base';
import Map from '../../shim/Map';
import global from '../../shim/global';
import { Animation, KeyframeEffect, AnimationEffectTiming, AnimationKeyFrame } from '../../shim/WebAnimations';

/**
* Animation controls are used to control the web animation that has been applied
Expand All @@ -17,36 +18,14 @@ export interface AnimationControls {
startTime?: number;
currentTime?: number;
}

/**
* Animation timing properties passed to a new KeyframeEffect.
*/
export interface AnimationTimingProperties {
duration?: number;
delay?: number;
direction?: 'normal' | 'reverse' | 'alternate' | 'alternate-reverse';
easing?: string;
endDelay?: number;
fill?: 'none' | 'forwards' | 'backwards' | 'both' | 'auto';
iterations?: number;
iterationStart?: number;
}

export interface AnimationKeyFrame {
easing?: string | string[];
offset?: number | Array<number | null> | null;
opacity?: number | number[];
transform?: string | string[];
}

/**
* Animation propertiues that can be passed as vdom property `animate`
* Animation properties that can be passed as vdom property `animate`
*/
export interface AnimationProperties {
id: string;
effects: (() => AnimationKeyFrame | AnimationKeyFrame[]) | AnimationKeyFrame | AnimationKeyFrame[];
controls?: AnimationControls;
timing?: AnimationTimingProperties;
timing?: AnimationEffectTiming;
}

export type AnimationPropertiesFunction = () => AnimationProperties;
Expand Down Expand Up @@ -74,9 +53,9 @@ export class WebAnimations extends Base {

const fx = typeof effects === 'function' ? effects() : effects;

const keyframeEffect = new global.KeyframeEffect(node, fx, timing);
const keyframeEffect = new KeyframeEffect(node, fx, timing);

return new global.Animation(keyframeEffect, global.document.timeline);
return new Animation(keyframeEffect, global.document.timeline);
}

private _updatePlayer(player: any, controls: AnimationControls) {
Expand Down
3 changes: 2 additions & 1 deletion tests/shim/functional/amd.ts
Expand Up @@ -23,13 +23,14 @@ registerSuite('AMD Util', {
undefined
)
.then((config: any) => {
assert.lengthOf(config.packages, 6);
assert.lengthOf(config.packages, 7);
assert.lengthOf(config.packages.filter((p: any) => p.name === 'pepjs'), 1);
assert.lengthOf(config.packages.filter((p: any) => p.name === 'tslib'), 1);
assert.lengthOf(config.packages.filter((p: any) => p.name === 'intersection-observer'), 1);
assert.lengthOf(config.packages.filter((p: any) => p.name === '@dojo'), 1);
assert.lengthOf(config.packages.filter((p: any) => p.name === 'existingPackage'), 1);
assert.lengthOf(config.packages.filter((p: any) => p.name === 'web-animations-js'), 1);
assert.lengthOf(config.packages.filter((p: any) => p.name === 'resize-observer-polyfill'), 1);
});
},
async 'Utility does not inject dependency if it already exists'() {
Expand Down

0 comments on commit 68ccaa9

Please sign in to comment.