From 17dfb7eba1898a274eb4cb52f7662e959f1430f9 Mon Sep 17 00:00:00 2001 From: Dominic Carretto Date: Tue, 18 Feb 2020 07:22:04 -0500 Subject: [PATCH 1/4] fix: SSR runtime failure --- packages/dom/index.ts | 1 + packages/dom/ponyfill.ts | 21 +++++++++++++++++++++ packages/dom/public-api.ts | 1 + packages/dom/tsconfig-build.json | 15 +++++++++++++++ packages/public-api.ts | 1 + packages/ripple/ripple.service.ts | 2 +- 6 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 packages/dom/index.ts create mode 100644 packages/dom/ponyfill.ts create mode 100644 packages/dom/public-api.ts create mode 100644 packages/dom/tsconfig-build.json diff --git a/packages/dom/index.ts b/packages/dom/index.ts new file mode 100644 index 000000000..7e1a213e3 --- /dev/null +++ b/packages/dom/index.ts @@ -0,0 +1 @@ +export * from './public-api'; diff --git a/packages/dom/ponyfill.ts b/packages/dom/ponyfill.ts new file mode 100644 index 000000000..293ab19c1 --- /dev/null +++ b/packages/dom/ponyfill.ts @@ -0,0 +1,21 @@ +export function closest(element: Element, selector: string): Element | null { + if (element.closest) { + return element.closest(selector); + } + + let el: Element | null = element; + while (el) { + if (matches(el, selector)) { + return el; + } + el = el.parentElement; + } + return null; +} + +export function matches(element: Element, selector: string): boolean { + const nativeMatches = element.matches + || element.webkitMatchesSelector + || element.msMatchesSelector; + return nativeMatches.call(element, selector); +} diff --git a/packages/dom/public-api.ts b/packages/dom/public-api.ts new file mode 100644 index 000000000..3e7213055 --- /dev/null +++ b/packages/dom/public-api.ts @@ -0,0 +1 @@ +export * from './ponyfill'; diff --git a/packages/dom/tsconfig-build.json b/packages/dom/tsconfig-build.json new file mode 100644 index 000000000..f2748dd99 --- /dev/null +++ b/packages/dom/tsconfig-build.json @@ -0,0 +1,15 @@ +{ + "extends": "../tsconfig-build", + "files": [ + "public-api.ts", + "../typings.d.ts" + ], + "angularCompilerOptions": { + "annotateForClosureCompiler": true, + "strictMetadataEmit": true, + "flatModuleOutFile": "index.js", + "flatModuleId": "@angular-mdc/web/dom", + "skipTemplateCodegen": true, + "fullTemplateTypeCheck": true + } +} diff --git a/packages/public-api.ts b/packages/public-api.ts index a64b101a9..e10121bee 100644 --- a/packages/public-api.ts +++ b/packages/public-api.ts @@ -6,6 +6,7 @@ export * from '@angular-mdc/web/checkbox'; export * from '@angular-mdc/web/chips'; export * from '@angular-mdc/web/data-table'; export * from '@angular-mdc/web/dialog'; +export * from '@angular-mdc/web/dom'; export * from '@angular-mdc/web/drawer'; export * from '@angular-mdc/web/elevation'; export * from '@angular-mdc/web/fab'; diff --git a/packages/ripple/ripple.service.ts b/packages/ripple/ripple.service.ts index f44590a87..ca77ffd5b 100644 --- a/packages/ripple/ripple.service.ts +++ b/packages/ripple/ripple.service.ts @@ -8,7 +8,7 @@ import {coerceBooleanProperty} from '@angular/cdk/coercion'; import {supportsPassiveEventListeners} from '@angular/cdk/platform'; import {EventType, SpecificEventListener} from '@material/base'; -import {matches} from '@material/dom/ponyfill'; +import {matches} from '@angular-mdc/web/dom/ponyfill'; import {supportsCssVariables} from '@material/ripple/util'; import {MDCRippleFoundation, MDCRippleAdapter} from '@material/ripple'; From 09df63cea521b64f48342d20306d7d7e8fd87543 Mon Sep 17 00:00:00 2001 From: Dominic Carretto Date: Wed, 19 Feb 2020 07:35:57 -0500 Subject: [PATCH 2/4] WIP - ssr fixes --- packages/checkbox/checkbox.ts | 2 +- packages/data-table/data-table.ts | 2 +- packages/dialog/dialog.component.ts | 2 +- packages/dom/ponyfill.ts | 49 +++++++++++++++++++-------- packages/list/list.ts | 2 +- packages/menu/menu.ts | 2 +- packages/ripple/ripple.service.ts | 2 +- packages/ripple/ripple.ts | 2 +- packages/switch/switch.ts | 2 +- packages/tab-scroller/tab-scroller.ts | 2 +- tools/package-tools/rollup-globals.ts | 2 -- 11 files changed, 44 insertions(+), 25 deletions(-) diff --git a/packages/checkbox/checkbox.ts b/packages/checkbox/checkbox.ts index 927d2305d..3dfedabc4 100644 --- a/packages/checkbox/checkbox.ts +++ b/packages/checkbox/checkbox.ts @@ -20,7 +20,7 @@ import {Platform, supportsPassiveEventListeners} from '@angular/cdk/platform'; import {fromEvent, Subject} from 'rxjs'; import {takeUntil, filter} from 'rxjs/operators'; -import {matches} from '@material/dom/ponyfill'; +import {matches} from '@angular-mdc/web/dom'; import {MDCRippleFoundation, MDCRippleAdapter} from '@material/ripple'; import {MDCCheckboxFoundation, MDCCheckboxAdapter} from '@material/checkbox'; diff --git a/packages/data-table/data-table.ts b/packages/data-table/data-table.ts index 210e11263..845b27396 100644 --- a/packages/data-table/data-table.ts +++ b/packages/data-table/data-table.ts @@ -21,7 +21,7 @@ import { MDCDataTableRow, } from './data-table.directives'; -import {closest} from '@material/dom/ponyfill'; +import {closest} from '@angular-mdc/web/dom'; import { strings, MDCDataTableRowSelectionChangedEventDetail, diff --git a/packages/dialog/dialog.component.ts b/packages/dialog/dialog.component.ts index d3afa59b6..043075f9a 100644 --- a/packages/dialog/dialog.component.ts +++ b/packages/dialog/dialog.component.ts @@ -24,7 +24,7 @@ import { import {MdcDialogRef} from './dialog-ref'; import {MdcDialogConfig} from './dialog-config'; -import {closest, matches} from '@material/dom/ponyfill'; +import {closest, matches} from '@angular-mdc/web/dom'; import {MDCDialogFoundation, MDCDialogAdapter, strings, util} from '@material/dialog'; const LAYOUT_EVENTS = ['resize', 'orientationchange']; diff --git a/packages/dom/ponyfill.ts b/packages/dom/ponyfill.ts index 293ab19c1..3c8702f8b 100644 --- a/packages/dom/ponyfill.ts +++ b/packages/dom/ponyfill.ts @@ -1,21 +1,42 @@ -export function closest(element: Element, selector: string): Element | null { - if (element.closest) { - return element.closest(selector); +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +/** IE 11 compatible closest implementation that is able to start from non-Element Nodes. */ +export function closest(element: EventTarget | Element | null | undefined, selector: string): + Element | null { + if (!(element instanceof Node)) { + return null; } - let el: Element | null = element; - while (el) { - if (matches(el, selector)) { - return el; - } - el = el.parentElement; + let curr: Node | null = element; + while (curr != null && !(curr instanceof Element)) { + curr = curr.parentNode; } - return null; + + return curr && (hasNativeClosest ? + curr.closest(selector) : polyfillClosest(curr, selector)) as Element | null; } +/** Polyfill for browsers without Element.closest. */ +function polyfillClosest(element: Element, selector: string): Element | null { + let curr: Node | null = element; + while (curr != null && !(curr instanceof Element && matches(curr, selector))) { + curr = curr.parentNode; + } + + return (curr || null) as Element | null; +} + +const hasNativeClosest = typeof Element != 'undefined' && !!Element.prototype.closest; + +/** IE 11 compatible matches implementation. */ export function matches(element: Element, selector: string): boolean { - const nativeMatches = element.matches - || element.webkitMatchesSelector - || element.msMatchesSelector; - return nativeMatches.call(element, selector); + return element.matches ? + element.matches(selector) : + (element as any)['msMatchesSelector'](selector); } diff --git a/packages/list/list.ts b/packages/list/list.ts index 99c1e8c3d..9b7c3acaa 100644 --- a/packages/list/list.ts +++ b/packages/list/list.ts @@ -22,7 +22,7 @@ import {MDCComponent} from '@angular-mdc/web/base'; import {MdcListItem, MdcListSelectionChange, MDC_LIST_PARENT_COMPONENT} from './list-item'; -import {matches} from '@material/dom/ponyfill'; +import {matches} from '@angular-mdc/web/dom'; import {cssClasses, strings, MDCListFoundation, MDCListAdapter} from '@material/list'; /** Change event that is being fired whenever the selected state of an option changes. */ diff --git a/packages/menu/menu.ts b/packages/menu/menu.ts index 6d36dbfdb..e958dea16 100644 --- a/packages/menu/menu.ts +++ b/packages/menu/menu.ts @@ -16,7 +16,7 @@ import {takeUntil} from 'rxjs/operators'; import {MdcList, MdcListItem, MdcListItemAction} from '@angular-mdc/web/list'; import {MdcMenuSurfaceBase} from '@angular-mdc/web/menu-surface'; -import {closest} from '@material/dom/ponyfill'; +import {closest} from '@angular-mdc/web/dom'; import { cssClasses, DefaultFocusState, diff --git a/packages/ripple/ripple.service.ts b/packages/ripple/ripple.service.ts index ca77ffd5b..b2a082c9c 100644 --- a/packages/ripple/ripple.service.ts +++ b/packages/ripple/ripple.service.ts @@ -8,7 +8,7 @@ import {coerceBooleanProperty} from '@angular/cdk/coercion'; import {supportsPassiveEventListeners} from '@angular/cdk/platform'; import {EventType, SpecificEventListener} from '@material/base'; -import {matches} from '@angular-mdc/web/dom/ponyfill'; +import {matches} from '@angular-mdc/web/dom'; import {supportsCssVariables} from '@material/ripple/util'; import {MDCRippleFoundation, MDCRippleAdapter} from '@material/ripple'; diff --git a/packages/ripple/ripple.ts b/packages/ripple/ripple.ts index 6a66804c0..2e5d82cad 100644 --- a/packages/ripple/ripple.ts +++ b/packages/ripple/ripple.ts @@ -3,7 +3,7 @@ import {coerceBooleanProperty} from '@angular/cdk/coercion'; import {supportsPassiveEventListeners} from '@angular/cdk/platform'; import {MdcRipple, MDCRippleCapableSurface} from './ripple.service'; -import {matches} from '@material/dom/ponyfill'; +import {matches} from '@angular-mdc/web/dom'; import {MDCRippleFoundation, MDCRippleAdapter} from '@material/ripple'; @Directive({ diff --git a/packages/switch/switch.ts b/packages/switch/switch.ts index 25a111435..83bfeb00a 100644 --- a/packages/switch/switch.ts +++ b/packages/switch/switch.ts @@ -20,7 +20,7 @@ import {coerceBooleanProperty} from '@angular/cdk/coercion'; import {MDCSwitchFoundation, MDCSwitchAdapter} from '@material/switch'; import {MDCRippleAdapter, MDCRippleFoundation} from '@material/ripple'; -import {matches} from '@material/dom/ponyfill'; +import {matches} from '@angular-mdc/web/dom'; import {MDCComponent} from '@angular-mdc/web/base'; import {MdcRipple, MDCRippleCapableSurface} from '@angular-mdc/web/ripple'; diff --git a/packages/tab-scroller/tab-scroller.ts b/packages/tab-scroller/tab-scroller.ts index ae64ed227..24c80abfd 100644 --- a/packages/tab-scroller/tab-scroller.ts +++ b/packages/tab-scroller/tab-scroller.ts @@ -15,7 +15,7 @@ import {filter, takeUntil} from 'rxjs/operators'; import {MDCComponent} from '@angular-mdc/web/base'; -import {matches} from '@material/dom/ponyfill'; +import {matches} from '@angular-mdc/web/dom'; import {MDCTabScrollerFoundation, MDCTabScrollerAdapter, util} from '@material/tab-scroller'; /** Possible alignments for tab scroller content. */ diff --git a/tools/package-tools/rollup-globals.ts b/tools/package-tools/rollup-globals.ts index ba3a6f024..ec60ed5a3 100644 --- a/tools/package-tools/rollup-globals.ts +++ b/tools/package-tools/rollup-globals.ts @@ -30,8 +30,6 @@ export const rollupGlobals = { '@material/base': 'mdc.base', '@material/checkbox': 'mdc.checkbox', '@material/chips': 'mdc.chips', - '@material/dom': 'mdc.dom', - '@material/dom/ponyfill': 'mdc.dom.ponyfill', '@material/dialog': 'mdc.dialog', '@material/data-table': 'mdc.dataTable', '@material/drawer': 'mdc.drawer', From f51eb88643ac69a729f1b18f3e27e3b50407818e Mon Sep 17 00:00:00 2001 From: Dominic Carretto Date: Wed, 19 Feb 2020 07:48:51 -0500 Subject: [PATCH 3/4] WIP - ssr --- packages/dom/ponyfill.ts | 2 +- test/karma.webpack.config.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/dom/ponyfill.ts b/packages/dom/ponyfill.ts index 3c8702f8b..17fe25aa6 100644 --- a/packages/dom/ponyfill.ts +++ b/packages/dom/ponyfill.ts @@ -32,7 +32,7 @@ function polyfillClosest(element: Element, selector: string): Element | null { return (curr || null) as Element | null; } -const hasNativeClosest = typeof Element != 'undefined' && !!Element.prototype.closest; +const hasNativeClosest = typeof Element !== 'undefined' && !!Element.prototype.closest; /** IE 11 compatible matches implementation. */ export function matches(element: Element, selector: string): boolean { diff --git a/test/karma.webpack.config.js b/test/karma.webpack.config.js index 7e28b3015..cd16018ab 100644 --- a/test/karma.webpack.config.js +++ b/test/karma.webpack.config.js @@ -43,7 +43,7 @@ module.exports = { loader: 'istanbul-instrumenter-loader', options: { esModules: true }, enforce: 'post', - exclude: /(node_modules|base|testing|\.test\.ts$)/ + exclude: /(node_modules|base|testing|dom|\.test\.ts$)/ } ] } From 81e0e1c78ec4870b7323da3323fc0c9d9b2f0849 Mon Sep 17 00:00:00 2001 From: Dominic Carretto Date: Wed, 19 Feb 2020 16:55:22 -0500 Subject: [PATCH 4/4] fix: node evaluation --- packages/dom/ponyfill.ts | 6 +++--- packages/select/select.ts | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/dom/ponyfill.ts b/packages/dom/ponyfill.ts index 17fe25aa6..5341c0484 100644 --- a/packages/dom/ponyfill.ts +++ b/packages/dom/ponyfill.ts @@ -6,6 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ +const hasNativeClosest = typeof Element !== 'undefined' && !!Element.prototype.closest; + /** IE 11 compatible closest implementation that is able to start from non-Element Nodes. */ export function closest(element: EventTarget | Element | null | undefined, selector: string): Element | null { @@ -13,7 +15,7 @@ export function closest(element: EventTarget | Element | null | undefined, selec return null; } - let curr: Node | null = element; + let curr: any | null = element; while (curr != null && !(curr instanceof Element)) { curr = curr.parentNode; } @@ -32,8 +34,6 @@ function polyfillClosest(element: Element, selector: string): Element | null { return (curr || null) as Element | null; } -const hasNativeClosest = typeof Element !== 'undefined' && !!Element.prototype.closest; - /** IE 11 compatible matches implementation. */ export function matches(element: Element, selector: string): boolean { return element.matches ? diff --git a/packages/select/select.ts b/packages/select/select.ts index 852fe6eff..9c96a78ff 100644 --- a/packages/select/select.ts +++ b/packages/select/select.ts @@ -1,5 +1,4 @@ import { - AfterContentInit, AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef,