diff --git a/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/bar-chart/bar-chart.component.html b/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/bar-chart/bar-chart.component.html index 54df3cdde74..205b41ae2ae 100644 --- a/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/bar-chart/bar-chart.component.html +++ b/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/bar-chart/bar-chart.component.html @@ -1,7 +1,12 @@ -
-
-
- {{ bar.label }} -
+
+
+ {{ bar.label }}
diff --git a/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/bar-chart/bar-chart.component.ts b/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/bar-chart/bar-chart.component.ts index 9e6c0cb2b93..08b8caa8f9f 100644 --- a/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/bar-chart/bar-chart.component.ts +++ b/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/bar-chart/bar-chart.component.ts @@ -1,4 +1,5 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { trigger, style, animate, transition, stagger, query, animateChild } from '@angular/animations'; interface Data { label: string; @@ -9,6 +10,10 @@ interface Data { selector: 'ng-bar-chart', templateUrl: './bar-chart.component.html', styleUrls: ['./bar-chart.component.scss'], + animations: [ + trigger('appear', [transition(':enter', [style({ width: 0 }), animate('.3s ease', style({ width: '*' }))])]), + trigger('stagger', [transition(':enter', [query(':enter', stagger('.1s', [animateChild()]))])]), + ], }) export class BarChartComponent { @Input() set data(nodes: Data[]) { diff --git a/projects/ng-devtools/src/lib/vendor/filesaver/index.ts b/projects/ng-devtools/src/lib/vendor/filesaver/index.ts index 5cc5b4915d3..95518c1344d 100644 --- a/projects/ng-devtools/src/lib/vendor/filesaver/index.ts +++ b/projects/ng-devtools/src/lib/vendor/filesaver/index.ts @@ -1,26 +1,24 @@ // tslint:disable +/* + * FileSaver.js + * A saveAs() FileSaver implementation. + * + * By Eli Grey, http://eligrey.com + * + * License : https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md (MIT) + * source : http://purl.eligrey.com/github/FileSaver.js + */ -function bom(blob, opts) { - if (typeof opts === 'undefined') opts = { autoBom: false }; - else if (typeof opts !== 'object') { - console.warn('Deprecated: Expected third argument to be a object'); - opts = { autoBom: !opts }; - } +// The one and only way of getting global scope in all environments +// https://stackoverflow.com/q/3277182/1008999 +var _global = globalThis; - // prepend BOM for UTF-8 XML and text/* types (including HTML) - // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF - if (opts.autoBom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) { - return new Blob([String.fromCharCode(0xfeff), blob], { type: blob.type }); - } - return blob; -} - -function download(url, name, opts) { +function download(url, name) { var xhr = new XMLHttpRequest(); xhr.open('GET', url); xhr.responseType = 'blob'; xhr.onload = function () { - saveAs(xhr.response, name, opts); + saveAs(xhr.response, name); }; xhr.onerror = function () { console.error('could not download file'); @@ -39,7 +37,7 @@ function corsEnabled(url) { } // `a.click()` doesn't work for all browsers (#465) -function click(node, _?: any) { +function click(node, _?) { try { node.dispatchEvent(new MouseEvent('click')); } catch (e) { @@ -49,104 +47,35 @@ function click(node, _?: any) { } } -// Detect WebKit inside a native macOS app -var isWebKit = /AppleWebKit/.test(navigator.userAgent); +function saveAs(blob, name) { + var URL = _global.URL || _global.webkitURL; + var a = document.createElement('a'); + name = name || blob.name || 'download'; -var saveAs = - globalThis.saveAs || - // probably in some web worker - (typeof window !== 'object' || window !== globalThis - ? function saveAs() { - /* noop */ - } - : // Use download attribute first if possible (#193 Lumia mobile) unless this is a native macOS app - 'download' in HTMLAnchorElement.prototype && !isWebKit - ? function saveAs(blob, name, opts) { - var URL = globalThis.URL || globalThis.webkitURL; - var a = document.createElement('a'); - name = name || blob.name || 'download'; + a.download = name; + a.rel = 'noopener'; // tabnabbing - a.download = name; - a.rel = 'noopener'; // tabnabbing + // TODO: detect chrome extensions & packaged apps + // a.target = '_blank' - // TODO: detect chrome extensions & packaged apps - // a.target = '_blank' - - if (typeof blob === 'string') { - // Support regular links - a.href = blob; - if (a.origin !== location.origin) { - corsEnabled(a.href) ? download(blob, name, opts) : click(a, (a.target = '_blank')); - } else { - click(a); - } - } else { - // Support blobs - a.href = URL.createObjectURL(blob); - setTimeout(function () { - URL.revokeObjectURL(a.href); - }, 4e4); // 40s - setTimeout(function () { - click(a); - }, 0); - } - } - : // Use msSaveOrOpenBlob as a second approach - 'msSaveOrOpenBlob' in navigator - ? function saveAs(blob, name, opts) { - name = name || blob.name || 'download'; - - if (typeof blob === 'string') { - if (corsEnabled(blob)) { - download(blob, name, opts); - } else { - var a = document.createElement('a'); - a.href = blob; - a.target = '_blank'; - setTimeout(function () { - click(a); - }); - } - } else { - navigator.msSaveOrOpenBlob(bom(blob, opts), name); - } - } - : // Fallback to using FileReader and a popup - function saveAs(blob, name, opts, popup) { - // Open a popup immediately do go around popup blocker - // Mostly only available on user interaction and the fileReader is async so... - popup = popup || open('', '_blank'); - if (popup) { - popup.document.title = popup.document.body.innerText = 'downloading...'; - } - - if (typeof blob === 'string') return download(blob, name, opts); - - var force = blob.type === 'application/octet-stream'; - var isSafari = /constructor/i.test(globalThis.HTMLElement as any) || globalThis.safari; - var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent); - - if ((isChromeIOS || (force && isSafari) || isWebKit) && typeof FileReader !== 'undefined') { - // Safari doesn't allow downloading of blob URLs - var reader = new FileReader(); - reader.onloadend = function () { - var url = reader.result; - url = isChromeIOS ? url : (url as any).replace(/^data:[^;]*;/, 'data:attachment/file;'); - if (popup) popup.location.href = url; - else window.location = url as any; - popup = null; // reverse-tabnabbing #460 - }; - reader.readAsDataURL(blob); - } else { - var URL = globalThis.URL || globalThis.webkitURL; - var url = URL.createObjectURL(blob); - if (popup) popup.location = url; - else location.href = url; - popup = null; // reverse-tabnabbing #460 - setTimeout(function () { - URL.revokeObjectURL(url); - }, 4e4); // 40s - } - }); + if (typeof blob === 'string') { + // Support regular links + a.href = blob; + if (a.origin !== location.origin) { + corsEnabled(a.href) ? download(blob, name) : click(a, (a.target = '_blank')); + } else { + click(a); + } + } else { + // Support blobs + a.href = URL.createObjectURL(blob); + setTimeout(function () { + URL.revokeObjectURL(a.href); + }, 4e4); // 40s + setTimeout(function () { + click(a); + }, 0); + } +} export { saveAs };