first commit

This commit is contained in:
Stefan Hacker
2026-04-03 09:38:48 +02:00
commit 37ad745546
47450 changed files with 3120798 additions and 0 deletions
+3035
View File
File diff suppressed because it is too large Load Diff
+15
View File
@@ -0,0 +1,15 @@
Fluent UI React - utilities
Copyright (c) Microsoft Corporation
All rights reserved.
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Note: Usage of the fonts and icons referenced in Fluent UI React is subject to the terms listed at https://aka.ms/fluentui-assets-license
+8
View File
@@ -0,0 +1,8 @@
# @fluentui/utilities
**Utilities for [Fluent UI React](https://developer.microsoft.com/en-us/fluentui)**
([formerly Office UI Fabric React](https://developer.microsoft.com/en-us/office/blogs/ui-fabric-is-evolving-into-fluent-ui/))
This package includes a number of basic utility functions required by most Fluent UI React components.
See [GitHub](https://github.com/microsoft/fluentui) for more details on the Fluent UI React project and packages within.
File diff suppressed because it is too large Load Diff
+107
View File
@@ -0,0 +1,107 @@
/**
* Bugs often appear in async code when stuff gets disposed, but async operations don't get canceled.
* This Async helper class solves these issues by tying async code to the lifetime of a disposable object.
*
* Usage: Anything class extending from BaseModel can access this helper via this.async. Otherwise create a
* new instance of the class and remember to call dispose() during your code's dispose handler.
*
* @public
*/
export declare class Async {
private _timeoutIds;
private _immediateIds;
private _intervalIds;
private _animationFrameIds;
private _isDisposed;
private _parent;
private _onErrorHandler;
private _noop;
constructor(parent?: object, onError?: (e: any) => void);
/**
* Dispose function, clears all async operations.
*/
dispose(): void;
/**
* SetTimeout override, which will auto cancel the timeout during dispose.
* @param callback - Callback to execute.
* @param duration - Duration in milliseconds.
* @returns The setTimeout id.
*/
setTimeout(callback: () => void, duration: number): number;
/**
* Clears the timeout.
* @param id - Id to cancel.
*/
clearTimeout(id: number): void;
/**
* SetImmediate override, which will auto cancel the immediate during dispose.
* @param callback - Callback to execute.
* @param targetElement - Optional target element to use for identifying the correct window.
* @returns The setTimeout id.
*/
setImmediate(callback: () => void, targetElement?: Element | null): number;
/**
* Clears the immediate.
* @param id - Id to cancel.
* @param targetElement - Optional target element to use for identifying the correct window.
*/
clearImmediate(id: number, targetElement?: Element | null): void;
/**
* SetInterval override, which will auto cancel the timeout during dispose.
* @param callback - Callback to execute.
* @param duration - Duration in milliseconds.
* @returns The setTimeout id.
*/
setInterval(callback: () => void, duration: number): number;
/**
* Clears the interval.
* @param id - Id to cancel.
*/
clearInterval(id: number): void;
/**
* Creates a function that, when executed, will only call the func function at most once per
* every wait milliseconds. Provide an options object to indicate that func should be invoked
* on the leading and/or trailing edge of the wait timeout. Subsequent calls to the throttled
* function will return the result of the last func call.
*
* Note: If leading and trailing options are true func will be called on the trailing edge of
* the timeout only if the throttled function is invoked more than once during the wait timeout.
*
* @param func - The function to throttle.
* @param wait - The number of milliseconds to throttle executions to. Defaults to 0.
* @param options - The options object.
* @returns The new throttled function.
*/
throttle<T extends (...args: any[]) => any>(func: T, wait?: number, options?: {
leading?: boolean;
trailing?: boolean;
}): T;
/**
* Creates a function that will delay the execution of func until after wait milliseconds have
* elapsed since the last time it was invoked. Provide an options object to indicate that func
* should be invoked on the leading and/or trailing edge of the wait timeout. Subsequent calls
* to the debounced function will return the result of the last func call.
*
* Note: If leading and trailing options are true func will be called on the trailing edge of
* the timeout only if the debounced function is invoked more than once during the wait
* timeout.
*
* @param func - The function to debounce.
* @param wait - The number of milliseconds to delay.
* @param options - The options object.
* @returns The new debounced function.
*/
debounce<T extends (...args: any[]) => any>(func: T, wait?: number, options?: {
leading?: boolean;
maxWait?: number;
trailing?: boolean;
}): ICancelable<T> & T;
requestAnimationFrame(callback: () => void, targetElement?: Element | null): number;
cancelAnimationFrame(id: number, targetElement?: Element | null): void;
protected _logError(e: any): void;
}
export type ICancelable<T extends (...args: any[]) => any> = {
flush: () => ReturnType<T>;
cancel: () => void;
pending: () => boolean;
};
+416
View File
@@ -0,0 +1,416 @@
define(["require", "exports", "./dom/getWindow"], function (require, exports, getWindow_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Async = void 0;
/**
* Bugs often appear in async code when stuff gets disposed, but async operations don't get canceled.
* This Async helper class solves these issues by tying async code to the lifetime of a disposable object.
*
* Usage: Anything class extending from BaseModel can access this helper via this.async. Otherwise create a
* new instance of the class and remember to call dispose() during your code's dispose handler.
*
* @public
*/
var Async = /** @class */ (function () {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function Async(parent, onError) {
this._timeoutIds = null;
this._immediateIds = null;
this._intervalIds = null;
this._animationFrameIds = null;
this._isDisposed = false;
this._parent = parent || null;
this._onErrorHandler = onError;
this._noop = function () {
/* do nothing */
};
}
/**
* Dispose function, clears all async operations.
*/
Async.prototype.dispose = function () {
var id;
this._isDisposed = true;
this._parent = null;
// Clear timeouts.
if (this._timeoutIds) {
for (id in this._timeoutIds) {
if (this._timeoutIds.hasOwnProperty(id)) {
this.clearTimeout(parseInt(id, 10));
}
}
this._timeoutIds = null;
}
// Clear immediates.
if (this._immediateIds) {
for (id in this._immediateIds) {
if (this._immediateIds.hasOwnProperty(id)) {
this.clearImmediate(parseInt(id, 10));
}
}
this._immediateIds = null;
}
// Clear intervals.
if (this._intervalIds) {
for (id in this._intervalIds) {
if (this._intervalIds.hasOwnProperty(id)) {
this.clearInterval(parseInt(id, 10));
}
}
this._intervalIds = null;
}
// Clear animation frames.
if (this._animationFrameIds) {
for (id in this._animationFrameIds) {
if (this._animationFrameIds.hasOwnProperty(id)) {
this.cancelAnimationFrame(parseInt(id, 10));
}
}
this._animationFrameIds = null;
}
};
/**
* SetTimeout override, which will auto cancel the timeout during dispose.
* @param callback - Callback to execute.
* @param duration - Duration in milliseconds.
* @returns The setTimeout id.
*/
Async.prototype.setTimeout = function (callback, duration) {
var _this = this;
var timeoutId = 0;
if (!this._isDisposed) {
if (!this._timeoutIds) {
this._timeoutIds = {};
}
timeoutId = setTimeout(function () {
// Time to execute the timeout, enqueue it as a foreground task to be executed.
try {
// Now delete the record and call the callback.
if (_this._timeoutIds) {
delete _this._timeoutIds[timeoutId];
}
callback.apply(_this._parent);
}
catch (e) {
_this._logError(e);
}
}, duration);
this._timeoutIds[timeoutId] = true;
}
return timeoutId;
};
/**
* Clears the timeout.
* @param id - Id to cancel.
*/
Async.prototype.clearTimeout = function (id) {
if (this._timeoutIds && this._timeoutIds[id]) {
clearTimeout(id);
delete this._timeoutIds[id];
}
};
/**
* SetImmediate override, which will auto cancel the immediate during dispose.
* @param callback - Callback to execute.
* @param targetElement - Optional target element to use for identifying the correct window.
* @returns The setTimeout id.
*/
Async.prototype.setImmediate = function (callback, targetElement) {
var _this = this;
var immediateId = 0;
var win = (0, getWindow_1.getWindow)(targetElement);
if (!this._isDisposed) {
if (!this._immediateIds) {
this._immediateIds = {};
}
var setImmediateCallback = function () {
// Time to execute the timeout, enqueue it as a foreground task to be executed.
try {
// Now delete the record and call the callback.
if (_this._immediateIds) {
delete _this._immediateIds[immediateId];
}
callback.apply(_this._parent);
}
catch (e) {
_this._logError(e);
}
};
immediateId = win.setTimeout(setImmediateCallback, 0);
this._immediateIds[immediateId] = true;
}
return immediateId;
};
/**
* Clears the immediate.
* @param id - Id to cancel.
* @param targetElement - Optional target element to use for identifying the correct window.
*/
Async.prototype.clearImmediate = function (id, targetElement) {
var win = (0, getWindow_1.getWindow)(targetElement);
if (this._immediateIds && this._immediateIds[id]) {
win.clearTimeout(id);
delete this._immediateIds[id];
}
};
/**
* SetInterval override, which will auto cancel the timeout during dispose.
* @param callback - Callback to execute.
* @param duration - Duration in milliseconds.
* @returns The setTimeout id.
*/
Async.prototype.setInterval = function (callback, duration) {
var _this = this;
var intervalId = 0;
if (!this._isDisposed) {
if (!this._intervalIds) {
this._intervalIds = {};
}
intervalId = setInterval(function () {
// Time to execute the interval callback, enqueue it as a foreground task to be executed.
try {
callback.apply(_this._parent);
}
catch (e) {
_this._logError(e);
}
}, duration);
this._intervalIds[intervalId] = true;
}
return intervalId;
};
/**
* Clears the interval.
* @param id - Id to cancel.
*/
Async.prototype.clearInterval = function (id) {
if (this._intervalIds && this._intervalIds[id]) {
clearInterval(id);
delete this._intervalIds[id];
}
};
/**
* Creates a function that, when executed, will only call the func function at most once per
* every wait milliseconds. Provide an options object to indicate that func should be invoked
* on the leading and/or trailing edge of the wait timeout. Subsequent calls to the throttled
* function will return the result of the last func call.
*
* Note: If leading and trailing options are true func will be called on the trailing edge of
* the timeout only if the throttled function is invoked more than once during the wait timeout.
*
* @param func - The function to throttle.
* @param wait - The number of milliseconds to throttle executions to. Defaults to 0.
* @param options - The options object.
* @returns The new throttled function.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Async.prototype.throttle = function (func, wait, options) {
var _this = this;
if (this._isDisposed) {
return this._noop;
}
var waitMS = wait || 0;
var leading = true;
var trailing = true;
var lastExecuteTime = 0;
var lastResult;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
var lastArgs;
var timeoutId = null;
if (options && typeof options.leading === 'boolean') {
leading = options.leading;
}
if (options && typeof options.trailing === 'boolean') {
trailing = options.trailing;
}
var callback = function (userCall) {
var now = Date.now();
var delta = now - lastExecuteTime;
var waitLength = leading ? waitMS - delta : waitMS;
if (delta >= waitMS && (!userCall || leading)) {
lastExecuteTime = now;
if (timeoutId) {
_this.clearTimeout(timeoutId);
timeoutId = null;
}
lastResult = func.apply(_this._parent, lastArgs);
}
else if (timeoutId === null && trailing) {
timeoutId = _this.setTimeout(callback, waitLength);
}
return lastResult;
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
var resultFunction = (function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
lastArgs = args;
return callback(true);
});
return resultFunction;
};
/**
* Creates a function that will delay the execution of func until after wait milliseconds have
* elapsed since the last time it was invoked. Provide an options object to indicate that func
* should be invoked on the leading and/or trailing edge of the wait timeout. Subsequent calls
* to the debounced function will return the result of the last func call.
*
* Note: If leading and trailing options are true func will be called on the trailing edge of
* the timeout only if the debounced function is invoked more than once during the wait
* timeout.
*
* @param func - The function to debounce.
* @param wait - The number of milliseconds to delay.
* @param options - The options object.
* @returns The new debounced function.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Async.prototype.debounce = function (func, wait, options) {
var _this = this;
if (this._isDisposed) {
var noOpFunction = (function () {
/** Do nothing */
});
noOpFunction.cancel = function () {
return;
};
noOpFunction.flush = (function () { return null; });
noOpFunction.pending = function () { return false; };
return noOpFunction;
}
var waitMS = wait || 0;
var leading = false;
var trailing = true;
var maxWait = null;
var lastCallTime = 0;
var lastExecuteTime = Date.now();
var lastResult;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
var lastArgs;
var timeoutId = null;
if (options && typeof options.leading === 'boolean') {
leading = options.leading;
}
if (options && typeof options.trailing === 'boolean') {
trailing = options.trailing;
}
if (options && typeof options.maxWait === 'number' && !isNaN(options.maxWait)) {
maxWait = options.maxWait;
}
var markExecuted = function (time) {
if (timeoutId) {
_this.clearTimeout(timeoutId);
timeoutId = null;
}
lastExecuteTime = time;
};
var invokeFunction = function (time) {
markExecuted(time);
lastResult = func.apply(_this._parent, lastArgs);
};
var callback = function (userCall) {
var now = Date.now();
var executeImmediately = false;
if (userCall) {
if (leading && now - lastCallTime >= waitMS) {
executeImmediately = true;
}
lastCallTime = now;
}
var delta = now - lastCallTime;
var waitLength = waitMS - delta;
var maxWaitDelta = now - lastExecuteTime;
var maxWaitExpired = false;
if (maxWait !== null) {
// maxWait only matters when there is a pending callback
if (maxWaitDelta >= maxWait && timeoutId) {
maxWaitExpired = true;
}
else {
waitLength = Math.min(waitLength, maxWait - maxWaitDelta);
}
}
if (delta >= waitMS || maxWaitExpired || executeImmediately) {
invokeFunction(now);
}
else if ((timeoutId === null || !userCall) && trailing) {
timeoutId = _this.setTimeout(callback, waitLength);
}
return lastResult;
};
var pending = function () {
return !!timeoutId;
};
var cancel = function () {
if (pending()) {
// Mark the debounced function as having executed
markExecuted(Date.now());
}
};
var flush = function () {
if (pending()) {
invokeFunction(Date.now());
}
return lastResult;
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
var resultFunction = (function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
lastArgs = args;
return callback(true);
});
resultFunction.cancel = cancel;
resultFunction.flush = flush;
resultFunction.pending = pending;
return resultFunction;
};
Async.prototype.requestAnimationFrame = function (callback, targetElement) {
var _this = this;
var animationFrameId = 0;
var win = (0, getWindow_1.getWindow)(targetElement);
if (!this._isDisposed) {
if (!this._animationFrameIds) {
this._animationFrameIds = {};
}
var animationFrameCallback = function () {
try {
// Now delete the record and call the callback.
if (_this._animationFrameIds) {
delete _this._animationFrameIds[animationFrameId];
}
callback.apply(_this._parent);
}
catch (e) {
_this._logError(e);
}
};
animationFrameId = win.requestAnimationFrame
? win.requestAnimationFrame(animationFrameCallback)
: win.setTimeout(animationFrameCallback, 0);
this._animationFrameIds[animationFrameId] = true;
}
return animationFrameId;
};
Async.prototype.cancelAnimationFrame = function (id, targetElement) {
var win = (0, getWindow_1.getWindow)(targetElement);
if (this._animationFrameIds && this._animationFrameIds[id]) {
win.cancelAnimationFrame ? win.cancelAnimationFrame(id) : win.clearTimeout(id);
delete this._animationFrameIds[id];
}
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Async.prototype._logError = function (e) {
if (this._onErrorHandler) {
this._onErrorHandler(e);
}
};
return Async;
}());
exports.Async = Async;
});
//# sourceMappingURL=Async.js.map
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
export {};
+93
View File
@@ -0,0 +1,93 @@
define(["require", "exports", "./Async"], function (require, exports, Async_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
describe('Async', function () {
describe('debounce', function () {
// Increase count by a specific number, to test the arguments
// of the debounced function;
var callCount = 0;
var fnMock = function (increaseCount) {
callCount += increaseCount;
return callCount;
};
var fn;
var async;
var debouncedFn;
beforeEach(function () {
jest.useFakeTimers();
fn = jest.fn(fnMock);
async = new Async_1.Async();
debouncedFn = async.debounce(fn, 100);
});
afterEach(function () {
callCount = 0;
fn.mockClear();
});
it('should debounce multiple calls', function () {
// Mock Date.now to return each call
// First one is the first debouncedFn(1)
// Second one is debouncedFn(2)
// A last one will be when the timer fires after we run pending timers in jest.
var dateMock = jest
.spyOn(Date, 'now')
.mockImplementationOnce(function () { return 10; })
.mockImplementationOnce(function () { return 11; })
.mockImplementation(function () { return 2000; });
debouncedFn(1);
expect(debouncedFn.pending()).toBeTruthy();
debouncedFn(2);
expect(debouncedFn.pending()).toBeTruthy();
jest.runOnlyPendingTimers();
expect(fn).toHaveBeenCalledTimes(1);
expect(callCount).toEqual(2);
dateMock.mockRestore();
});
it('should flush the last value', function () {
debouncedFn(10);
debouncedFn(20);
expect(debouncedFn.pending()).toBeTruthy();
expect(debouncedFn.flush()).toEqual(20);
});
it('should be marked pending as expected', function () {
debouncedFn(100);
expect(debouncedFn.pending()).toBeTruthy();
debouncedFn(200);
expect(debouncedFn.pending()).toBeTruthy();
debouncedFn.flush();
expect(debouncedFn.pending()).toBeFalsy();
});
it('should be cancellable', function () {
debouncedFn(1000);
debouncedFn.cancel();
expect(debouncedFn.pending()).toBeFalsy();
expect(debouncedFn.flush()).toBeUndefined();
});
});
describe('throttle', function () {
it('should throttle multiple calls', function () {
jest.useFakeTimers();
// Mock Date.now to return each call
// First one is the first throttledFn(1)
// Second one is throttledFn(2)
// A last one will be when the timer fires after we run pending timers in jest.
var dateMock = jest
.spyOn(Date, 'now')
.mockImplementationOnce(function () { return 10; })
.mockImplementationOnce(function () { return 11; })
.mockImplementation(function () { return 2000; });
var fn = jest.fn(function (num) { return num; });
var async = new Async_1.Async();
var throttledFn = async.throttle(fn, 1000);
var result = throttledFn(1);
expect(result).toBeUndefined();
result = throttledFn(2);
expect(result).toBeUndefined();
jest.runOnlyPendingTimers();
expect(fn).toHaveBeenCalledTimes(1);
dateMock.mockRestore();
jest.useRealTimers();
});
});
});
});
//# sourceMappingURL=Async.test.js.map
File diff suppressed because one or more lines are too long
+25
View File
@@ -0,0 +1,25 @@
/**
* AutoScroll simply hooks up mouse events given a parent element, and scrolls the container
* up/down depending on how close the mouse is to the top/bottom of the container.
*
* Once you don't want autoscroll any more, just dispose the helper and it will unhook events.
*
* @public
* {@docCategory AutoScroll}
*/
export declare class AutoScroll {
private _events;
private _scrollableParent;
private _scrollRect;
private _scrollVelocity;
private _isVerticalScroll;
private _timeoutId?;
constructor(element: HTMLElement, win?: Window);
dispose(): void;
private _onMouseMove;
private _onTouchMove;
private _computeScrollVelocity;
private _startScroll;
private _incrementScroll;
private _stopScroll;
}
+123
View File
@@ -0,0 +1,123 @@
define(["require", "exports", "./EventGroup", "./scroll", "./dom/getRect", "./dom"], function (require, exports, EventGroup_1, scroll_1, getRect_1, dom_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AutoScroll = void 0;
var SCROLL_ITERATION_DELAY = 16;
var SCROLL_GUTTER = 100;
var MAX_SCROLL_VELOCITY = 15;
/**
* AutoScroll simply hooks up mouse events given a parent element, and scrolls the container
* up/down depending on how close the mouse is to the top/bottom of the container.
*
* Once you don't want autoscroll any more, just dispose the helper and it will unhook events.
*
* @public
* {@docCategory AutoScroll}
*/
var AutoScroll = /** @class */ (function () {
function AutoScroll(element, win) {
var theWin = win !== null && win !== void 0 ? win : (0, dom_1.getWindow)(element);
this._events = new EventGroup_1.EventGroup(this);
this._scrollableParent = (0, scroll_1.findScrollableParent)(element);
this._incrementScroll = this._incrementScroll.bind(this);
this._scrollRect = (0, getRect_1.getRect)(this._scrollableParent, theWin);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if (this._scrollableParent === theWin) {
this._scrollableParent = theWin.document.body;
}
if (this._scrollableParent) {
this._events.on(theWin, 'mousemove', this._onMouseMove, true);
this._events.on(theWin, 'touchmove', this._onTouchMove, true);
}
}
AutoScroll.prototype.dispose = function () {
this._events.dispose();
this._stopScroll();
};
AutoScroll.prototype._onMouseMove = function (ev) {
this._computeScrollVelocity(ev);
};
AutoScroll.prototype._onTouchMove = function (ev) {
if (ev.touches.length > 0) {
this._computeScrollVelocity(ev);
}
};
AutoScroll.prototype._computeScrollVelocity = function (ev) {
if (!this._scrollRect) {
return;
}
var clientX;
var clientY;
if ('clientX' in ev) {
clientX = ev.clientX;
clientY = ev.clientY;
}
else {
clientX = ev.touches[0].clientX;
clientY = ev.touches[0].clientY;
}
var scrollRectTop = this._scrollRect.top;
var scrollRectLeft = this._scrollRect.left;
var scrollClientBottom = scrollRectTop + this._scrollRect.height - SCROLL_GUTTER;
var scrollClientRight = scrollRectLeft + this._scrollRect.width - SCROLL_GUTTER;
// variables to use for alternating scroll direction
var scrollRect;
var clientDirection;
var scrollClient;
// if either of these conditions are met we are scrolling vertically else horizontally
if (clientY < scrollRectTop + SCROLL_GUTTER || clientY > scrollClientBottom) {
clientDirection = clientY;
scrollRect = scrollRectTop;
scrollClient = scrollClientBottom;
this._isVerticalScroll = true;
}
else {
clientDirection = clientX;
scrollRect = scrollRectLeft;
scrollClient = scrollClientRight;
this._isVerticalScroll = false;
}
// calculate scroll velocity and direction
if (clientDirection < scrollRect + SCROLL_GUTTER) {
this._scrollVelocity = Math.max(-MAX_SCROLL_VELOCITY, -MAX_SCROLL_VELOCITY * ((SCROLL_GUTTER - (clientDirection - scrollRect)) / SCROLL_GUTTER));
}
else if (clientDirection > scrollClient) {
this._scrollVelocity = Math.min(MAX_SCROLL_VELOCITY, MAX_SCROLL_VELOCITY * ((clientDirection - scrollClient) / SCROLL_GUTTER));
}
else {
this._scrollVelocity = 0;
}
if (this._scrollVelocity) {
this._startScroll();
}
else {
this._stopScroll();
}
};
AutoScroll.prototype._startScroll = function () {
if (!this._timeoutId) {
this._incrementScroll();
}
};
AutoScroll.prototype._incrementScroll = function () {
if (this._scrollableParent) {
if (this._isVerticalScroll) {
this._scrollableParent.scrollTop += Math.round(this._scrollVelocity);
}
else {
this._scrollableParent.scrollLeft += Math.round(this._scrollVelocity);
}
}
this._timeoutId = setTimeout(this._incrementScroll, SCROLL_ITERATION_DELAY);
};
AutoScroll.prototype._stopScroll = function () {
if (this._timeoutId) {
clearTimeout(this._timeoutId);
delete this._timeoutId;
}
};
return AutoScroll;
}());
exports.AutoScroll = AutoScroll;
});
//# sourceMappingURL=AutoScroll.js.map
File diff suppressed because one or more lines are too long
+111
View File
@@ -0,0 +1,111 @@
import * as React from 'react';
import { Async } from './Async';
import { EventGroup } from './EventGroup';
import type { IDisposable } from './IDisposable';
import type { ISettingsMap } from './warn/warn';
import type { IBaseProps } from './BaseComponent.types';
import type { JSXElement } from './jsx';
/**
* BaseComponent class, which provides basic helpers for all components.
*
* @public
* {@docCategory BaseComponent}
*
* @deprecated Do not use. We are moving away from class component.
*/
export declare class BaseComponent<TProps extends IBaseProps = {}, TState extends {} = {}> extends React.Component<TProps, TState> {
/**
* @deprecated Use React's error boundaries instead.
*/
static onError: (errorMessage?: string, ex?: any) => void;
/**
* Controls whether the componentRef prop will be resolved by this component instance. If you are
* implementing a passthrough (higher-order component), you would set this to false and pass through
* the props to the inner component, allowing it to resolve the componentRef.
*/
protected _skipComponentRefResolution: boolean;
private __async;
private __events;
private __disposables;
private __resolves;
private __className;
/**
* BaseComponent constructor
* @param props - The props for the component.
* @param context - The context for the component.
*/
constructor(props: TProps, context?: any);
/**
* When the component receives props, make sure the componentRef is updated.
*/
componentDidUpdate(prevProps: TProps, prevState: TState): void;
/**
* When the component has mounted, update the componentRef.
*/
componentDidMount(): void;
/**
* If we have disposables, dispose them automatically on unmount.
*/
componentWillUnmount(): void;
/**
* Gets the object's class name.
*/
get className(): string;
/**
* Allows subclasses to push things to this._disposables to be auto disposed.
*/
protected get _disposables(): IDisposable[];
/**
* Gets the async instance associated with the component, created on demand. The async instance gives
* subclasses a way to execute setTimeout/setInterval async calls safely, where the callbacks
* will be cleared/ignored automatically after unmounting. The helpers within the async object also
* preserve the this pointer so that you don't need to "bind" the callbacks.
*/
protected get _async(): Async;
/**
* Gets the event group instance assocaited with the component, created on demand. The event instance
* provides on/off methods for listening to DOM (or regular javascript object) events. The event callbacks
* will be automatically disconnected after unmounting. The helpers within the events object also
* preserve the this reference so that you don't need to "bind" the callbacks.
*/
protected get _events(): EventGroup;
/**
* Helper to return a memoized ref resolver function.
* @param refName - Name of the member to assign the ref to.
* @returns A function instance keyed from the given refname.
* @deprecated Use `createRef` from React.createRef.
*/
protected _resolveRef(refName: string): (ref: React.ReactNode) => React.ReactNode;
/**
* Updates the componentRef (by calling it with "this" when necessary.)
*/
protected _updateComponentRef(currentProps: IBaseProps, newProps?: IBaseProps): void;
/**
* Warns when a deprecated props are being used.
*
* @param deprecationMap - The map of deprecations, where key is the prop name and the value is
* either null or a replacement prop name.
*/
protected _warnDeprecations(deprecationMap: ISettingsMap<TProps>): void;
/**
* Warns when props which are mutually exclusive with each other are both used.
*
* @param mutuallyExclusiveMap - The map of mutually exclusive props.
*/
protected _warnMutuallyExclusive(mutuallyExclusiveMap: ISettingsMap<TProps>): void;
/**
* Warns when props are required if a condition is met.
*
* @param requiredProps - The name of the props that are required when the condition is met.
* @param conditionalPropName - The name of the prop that the condition is based on.
* @param condition - Whether the condition is met.
*/
protected _warnConditionallyRequiredProps(requiredProps: string[], conditionalPropName: string, condition: boolean): void;
private _setComponentRef;
}
/**
* Simple constant function for returning null, used to render empty templates in JSX.
*
* @public
*/
export declare function nullRender(): JSXElement | null;
+240
View File
@@ -0,0 +1,240 @@
define(["require", "exports", "tslib", "react", "./Async", "./EventGroup", "./warn/warnConditionallyRequiredProps", "./warn/warnMutuallyExclusive", "./warn/warnDeprecations"], function (require, exports, tslib_1, React, Async_1, EventGroup_1, warnConditionallyRequiredProps_1, warnMutuallyExclusive_1, warnDeprecations_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseComponent = void 0;
exports.nullRender = nullRender;
/**
* BaseComponent class, which provides basic helpers for all components.
*
* @public
* {@docCategory BaseComponent}
*
* @deprecated Do not use. We are moving away from class component.
*/
var BaseComponent = /** @class */ (function (_super) {
tslib_1.__extends(BaseComponent, _super);
/**
* BaseComponent constructor
* @param props - The props for the component.
* @param context - The context for the component.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function BaseComponent(props, context) {
// eslint-disable-next-line @typescript-eslint/no-deprecated
var _this = _super.call(this, props, context) || this;
// eslint-disable-next-line @typescript-eslint/no-deprecated
_makeAllSafe(_this, BaseComponent.prototype, [
'componentDidMount',
'shouldComponentUpdate',
'getSnapshotBeforeUpdate',
'render',
'componentDidUpdate',
'componentWillUnmount',
]);
return _this;
}
/**
* When the component receives props, make sure the componentRef is updated.
*/
BaseComponent.prototype.componentDidUpdate = function (prevProps, prevState) {
this._updateComponentRef(prevProps, this.props);
};
/**
* When the component has mounted, update the componentRef.
*/
BaseComponent.prototype.componentDidMount = function () {
this._setComponentRef(this.props.componentRef, this);
};
/**
* If we have disposables, dispose them automatically on unmount.
*/
BaseComponent.prototype.componentWillUnmount = function () {
this._setComponentRef(this.props.componentRef, null);
if (this.__disposables) {
for (var i = 0, len = this._disposables.length; i < len; i++) {
var disposable = this.__disposables[i];
if (disposable.dispose) {
disposable.dispose();
}
}
this.__disposables = null;
}
};
Object.defineProperty(BaseComponent.prototype, "className", {
/**
* Gets the object's class name.
*/
get: function () {
if (!this.__className) {
var funcNameRegex = /function (.{1,})\(/;
var results = funcNameRegex.exec(this.constructor.toString());
this.__className = results && results.length > 1 ? results[1] : '';
}
return this.__className;
},
enumerable: false,
configurable: true
});
Object.defineProperty(BaseComponent.prototype, "_disposables", {
/**
* Allows subclasses to push things to this._disposables to be auto disposed.
*/
get: function () {
if (!this.__disposables) {
this.__disposables = [];
}
return this.__disposables;
},
enumerable: false,
configurable: true
});
Object.defineProperty(BaseComponent.prototype, "_async", {
/**
* Gets the async instance associated with the component, created on demand. The async instance gives
* subclasses a way to execute setTimeout/setInterval async calls safely, where the callbacks
* will be cleared/ignored automatically after unmounting. The helpers within the async object also
* preserve the this pointer so that you don't need to "bind" the callbacks.
*/
get: function () {
if (!this.__async) {
this.__async = new Async_1.Async(this);
this._disposables.push(this.__async);
}
return this.__async;
},
enumerable: false,
configurable: true
});
Object.defineProperty(BaseComponent.prototype, "_events", {
/**
* Gets the event group instance assocaited with the component, created on demand. The event instance
* provides on/off methods for listening to DOM (or regular javascript object) events. The event callbacks
* will be automatically disconnected after unmounting. The helpers within the events object also
* preserve the this reference so that you don't need to "bind" the callbacks.
*/
get: function () {
if (!this.__events) {
this.__events = new EventGroup_1.EventGroup(this);
this._disposables.push(this.__events);
}
return this.__events;
},
enumerable: false,
configurable: true
});
/**
* Helper to return a memoized ref resolver function.
* @param refName - Name of the member to assign the ref to.
* @returns A function instance keyed from the given refname.
* @deprecated Use `createRef` from React.createRef.
*/
BaseComponent.prototype._resolveRef = function (refName) {
var _this = this;
if (!this.__resolves) {
this.__resolves = {};
}
if (!this.__resolves[refName]) {
this.__resolves[refName] = function (ref) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return (_this[refName] = ref);
};
}
return this.__resolves[refName];
};
/**
* Updates the componentRef (by calling it with "this" when necessary.)
*/
BaseComponent.prototype._updateComponentRef = function (currentProps, newProps) {
if (newProps === void 0) { newProps = {}; }
// currentProps *should* always be defined, but verify that just in case a subclass is manually
// calling a lifecycle method with no parameters (which has happened) or other odd usage.
if (currentProps && newProps && currentProps.componentRef !== newProps.componentRef) {
this._setComponentRef(currentProps.componentRef, null);
this._setComponentRef(newProps.componentRef, this);
}
};
/**
* Warns when a deprecated props are being used.
*
* @param deprecationMap - The map of deprecations, where key is the prop name and the value is
* either null or a replacement prop name.
*/
BaseComponent.prototype._warnDeprecations = function (deprecationMap) {
(0, warnDeprecations_1.warnDeprecations)(this.className, this.props, deprecationMap);
};
/**
* Warns when props which are mutually exclusive with each other are both used.
*
* @param mutuallyExclusiveMap - The map of mutually exclusive props.
*/
BaseComponent.prototype._warnMutuallyExclusive = function (mutuallyExclusiveMap) {
(0, warnMutuallyExclusive_1.warnMutuallyExclusive)(this.className, this.props, mutuallyExclusiveMap);
};
/**
* Warns when props are required if a condition is met.
*
* @param requiredProps - The name of the props that are required when the condition is met.
* @param conditionalPropName - The name of the prop that the condition is based on.
* @param condition - Whether the condition is met.
*/
BaseComponent.prototype._warnConditionallyRequiredProps = function (requiredProps, conditionalPropName, condition) {
(0, warnConditionallyRequiredProps_1.warnConditionallyRequiredProps)(this.className, this.props, requiredProps, conditionalPropName, condition);
};
BaseComponent.prototype._setComponentRef = function (ref, value) {
if (!this._skipComponentRefResolution && ref) {
if (typeof ref === 'function') {
ref(value);
}
if (typeof ref === 'object') {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
ref.current = value;
}
}
};
return BaseComponent;
}(React.Component));
exports.BaseComponent = BaseComponent;
/**
* Helper to override a given method with a wrapper method that can try/catch the original, but also
* ensures that the BaseComponent's methods are called before the subclass's. This ensures that
* componentWillUnmount in the base is called and that things in the _disposables array are disposed.
*/
// eslint-disable-next-line @typescript-eslint/no-deprecated
function _makeAllSafe(obj, prototype, methodNames) {
for (var i = 0, len = methodNames.length; i < len; i++) {
_makeSafe(obj, prototype, methodNames[i]);
}
}
// eslint-disable-next-line @typescript-eslint/no-deprecated
function _makeSafe(obj, prototype, methodName) {
/* eslint-disable @typescript-eslint/no-explicit-any */
var classMethod = obj[methodName];
var prototypeMethod = prototype[methodName];
if (classMethod || prototypeMethod) {
obj[methodName] = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
/* eslint-enable @typescript-eslint/no-explicit-any */
var retVal;
if (prototypeMethod) {
retVal = prototypeMethod.apply(this, args);
}
if (classMethod !== prototypeMethod) {
retVal = classMethod.apply(this, args);
}
return retVal;
};
}
}
/**
* Simple constant function for returning null, used to render empty templates in JSX.
*
* @public
*/
function nullRender() {
return null;
}
});
//# sourceMappingURL=BaseComponent.js.map
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
export {};
+24
View File
@@ -0,0 +1,24 @@
define(["require", "exports", "tslib", "react", "@testing-library/react", "./BaseComponent"], function (require, exports, tslib_1, React, react_1, BaseComponent_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
describe('BaseComponent', function () {
it('can resolve refs', function () {
var Foo = /** @class */ (function (_super) {
tslib_1.__extends(Foo, _super);
function Foo() {
return _super !== null && _super.apply(this, arguments) || this;
}
Foo.prototype.render = function () {
return (React.createElement("div", {
// @ts-expect-error - react 18 types issue
ref: this._resolveRef('root') }));
};
return Foo;
}(BaseComponent_1.BaseComponent));
var container = (0, react_1.render)(React.createElement(Foo, null)).container;
var component = container.firstChild;
expect(component).toBeTruthy();
});
});
});
//# sourceMappingURL=BaseComponent.test.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"BaseComponent.test.js","sourceRoot":"../src/","sources":["BaseComponent.test.tsx"],"names":[],"mappings":";;;IAMA,QAAQ,CAAC,eAAe,EAAE;QACxB,EAAE,CAAC,kBAAkB,EAAE;YACrB;gBAAkB,+BAAqB;gBAAvC;;gBAWA,CAAC;gBARQ,oBAAM,GAAb;oBACE,OAAO,CACL;wBACE,0CAA0C;wBAC1C,GAAG,EAAE,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,GAC7B,CACH,CAAC;gBACJ,CAAC;gBACH,UAAC;YAAD,CAAC,AAXD,CAAkB,6BAAa,GAW9B;YAEO,IAAA,SAAS,GAAK,IAAA,cAAM,EAAC,oBAAC,GAAG,OAAG,CAAC,UAApB,CAAqB;YACtC,IAAM,SAAS,GAAG,SAAS,CAAC,UAAyB,CAAC;YAEtD,MAAM,CAAC,SAAS,CAAC,CAAC,UAAU,EAAE,CAAC;QACjC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC","sourcesContent":["import * as React from 'react';\nimport { render } from '@testing-library/react';\nimport { BaseComponent } from './BaseComponent';\n\nimport type { JSXElement } from './jsx';\n\ndescribe('BaseComponent', () => {\n it('can resolve refs', () => {\n class Foo extends BaseComponent<{}, {}> {\n public root!: HTMLElement;\n\n public render(): JSXElement {\n return (\n <div\n // @ts-expect-error - react 18 types issue\n ref={this._resolveRef('root')}\n />\n );\n }\n }\n\n const { container } = render(<Foo />);\n const component = container.firstChild as HTMLElement;\n\n expect(component).toBeTruthy();\n });\n});\n"]}
+10
View File
@@ -0,0 +1,10 @@
import type { IRefObject } from './createRef';
/**
* BaseProps interface.
*
* @public
* {@docCategory IBaseProps}
*/
export interface IBaseProps<T = any> {
componentRef?: IRefObject<T>;
}
+5
View File
@@ -0,0 +1,5 @@
define(["require", "exports"], function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
});
//# sourceMappingURL=BaseComponent.types.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"BaseComponent.types.js","sourceRoot":"../src/","sources":["BaseComponent.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { IRefObject } from './createRef';\n\n/**\n * BaseProps interface.\n *\n * @public\n * {@docCategory IBaseProps}\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport interface IBaseProps<T = any> {\n componentRef?: IRefObject<T>;\n}\n"]}
+42
View File
@@ -0,0 +1,42 @@
import * as React from 'react';
import { IReactProps } from './React.types';
/**
* DelayedRender component props.
*
* @public
*/
export interface IDelayedRenderProps extends IReactProps<{}> {
/**
* Number of milliseconds to delay rendering children.
*/
delay?: number;
}
/**
* DelayedRender component state.
*
* @internal
*/
export interface IDelayedRenderState {
/**
* Whether the component is rendered or not.
*/
isRendered: boolean;
}
/**
* Utility component for delaying the render of a child component after a given delay. This component
* requires a single child component; don't pass in many components. Wrap multiple components in a DIV
* if necessary.
*
* @public
* {@docCategory DelayedRender}
*/
export declare class DelayedRender extends React.Component<IDelayedRenderProps, IDelayedRenderState> {
static defaultProps: {
delay: number;
};
private _timeoutId;
constructor(props: IDelayedRenderProps);
componentDidMount(): void;
componentWillUnmount(): void;
render(): React.ReactElement<{}> | null;
}
+47
View File
@@ -0,0 +1,47 @@
define(["require", "exports", "tslib", "react", "./dom/getWindow"], function (require, exports, tslib_1, React, getWindow_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DelayedRender = void 0;
/**
* Utility component for delaying the render of a child component after a given delay. This component
* requires a single child component; don't pass in many components. Wrap multiple components in a DIV
* if necessary.
*
* @public
* {@docCategory DelayedRender}
*/
var DelayedRender = /** @class */ (function (_super) {
tslib_1.__extends(DelayedRender, _super);
function DelayedRender(props) {
var _this = _super.call(this, props) || this;
_this.state = {
isRendered: (0, getWindow_1.getWindow)() === undefined,
};
return _this;
}
DelayedRender.prototype.componentDidMount = function () {
var _this = this;
var delay = this.props.delay;
// eslint-disable-next-line no-restricted-globals
this._timeoutId = window.setTimeout(function () {
_this.setState({
isRendered: true,
});
}, delay);
};
DelayedRender.prototype.componentWillUnmount = function () {
if (this._timeoutId) {
clearTimeout(this._timeoutId);
}
};
DelayedRender.prototype.render = function () {
return this.state.isRendered ? React.Children.only(this.props.children) : null;
};
DelayedRender.defaultProps = {
delay: 0,
};
return DelayedRender;
}(React.Component));
exports.DelayedRender = DelayedRender;
});
//# sourceMappingURL=DelayedRender.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"DelayedRender.js","sourceRoot":"../src/","sources":["DelayedRender.tsx"],"names":[],"mappings":";;;;IA4BA;;;;;;;OAOG;IACH;QAAmC,yCAAyD;QAO1F,uBAAY,KAA0B;YACpC,YAAA,MAAK,YAAC,KAAK,CAAC,SAAC;YACb,KAAI,CAAC,KAAK,GAAG;gBACX,UAAU,EAAE,IAAA,qBAAS,GAAE,KAAK,SAAS;aACtC,CAAC;;QACJ,CAAC;QAEM,yCAAiB,GAAxB;YAAA,iBAQC;YAPO,IAAA,KAAK,GAAK,IAAI,CAAC,KAAK,MAAf,CAAgB;YAC3B,iDAAiD;YACjD,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;gBAClC,KAAI,CAAC,QAAQ,CAAC;oBACZ,UAAU,EAAE,IAAI;iBACjB,CAAC,CAAC;YACL,CAAC,EAAE,KAAK,CAAC,CAAC;QACZ,CAAC;QAEM,4CAAoB,GAA3B;YACE,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;gBACpB,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAChC,CAAC;QACH,CAAC;QAEM,8BAAM,GAAb;YACE,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAE,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAA4B,CAAC,CAAC,CAAC,IAAI,CAAC;QAC7G,CAAC;QA/Ba,0BAAY,GAAG;YAC3B,KAAK,EAAE,CAAC;SACT,CAAC;QA8BJ,oBAAC;KAAA,AAjCD,CAAmC,KAAK,CAAC,SAAS,GAiCjD;IAjCY,sCAAa","sourcesContent":["import * as React from 'react';\nimport { getWindow } from './dom/getWindow';\nimport { IReactProps } from './React.types';\n\n/**\n * DelayedRender component props.\n *\n * @public\n */\nexport interface IDelayedRenderProps extends IReactProps<{}> {\n /**\n * Number of milliseconds to delay rendering children.\n */\n delay?: number;\n}\n\n/**\n * DelayedRender component state.\n *\n * @internal\n */\nexport interface IDelayedRenderState {\n /**\n * Whether the component is rendered or not.\n */\n isRendered: boolean;\n}\n\n/**\n * Utility component for delaying the render of a child component after a given delay. This component\n * requires a single child component; don't pass in many components. Wrap multiple components in a DIV\n * if necessary.\n *\n * @public\n * {@docCategory DelayedRender}\n */\nexport class DelayedRender extends React.Component<IDelayedRenderProps, IDelayedRenderState> {\n public static defaultProps = {\n delay: 0,\n };\n\n private _timeoutId: number | undefined;\n\n constructor(props: IDelayedRenderProps) {\n super(props);\n this.state = {\n isRendered: getWindow() === undefined,\n };\n }\n\n public componentDidMount(): void {\n let { delay } = this.props;\n // eslint-disable-next-line no-restricted-globals\n this._timeoutId = window.setTimeout(() => {\n this.setState({\n isRendered: true,\n });\n }, delay);\n }\n\n public componentWillUnmount(): void {\n if (this._timeoutId) {\n clearTimeout(this._timeoutId);\n }\n }\n\n public render(): React.ReactElement<{}> | null {\n return this.state.isRendered ? (React.Children.only(this.props.children) as React.ReactElement<{}>) : null;\n }\n}\n"]}
+78
View File
@@ -0,0 +1,78 @@
/**
* @internal
*/
export interface IEventRecord {
target: any;
eventName: string;
parent: any;
callback: (args?: any) => void;
elementCallback?: (...args: any[]) => void;
objectCallback?: (args?: any) => void;
options?: boolean | AddEventListenerOptions;
}
/**
* @internal
*/
export interface IEventRecordsByName {
[eventName: string]: IEventRecordList;
}
/**
* @internal
*/
export interface IEventRecordList {
[id: string]: IEventRecord[] | number;
count: number;
}
/**
* @internal
*/
export interface IDeclaredEventsByName {
[eventName: string]: boolean;
}
/** An instance of EventGroup allows anything with a handle to it to trigger events on it.
* If the target is an HTMLElement, the event will be attached to the element and can be
* triggered as usual (like clicking for onClick).
* The event can be triggered by calling EventGroup.raise() here. If the target is an
* HTMLElement, the event gets raised and is handled by the browser. Otherwise, it gets
* handled here in EventGroup, and the handler is called in the context of the parent
* (which is passed in in the constructor).
*
* @public
* {@docCategory EventGroup}
*/
export declare class EventGroup {
private static _uniqueId;
private _parent;
private _eventRecords;
private _id;
private _isDisposed;
/** For IE8, bubbleEvent is ignored here and must be dealt with by the handler.
* Events raised here by default have bubbling set to false and cancelable set to true.
* This applies also to built-in events being raised manually here on HTMLElements,
* which may lead to unexpected behavior if it differs from the defaults.
*
*/
static raise(target: any, eventName: string, eventArgs?: any, bubbleEvent?: boolean, doc?: Document): boolean | undefined;
static isObserved(target: any, eventName: string): boolean;
/** Check to see if the target has declared support of the given event. */
static isDeclared(target: any, eventName: string): boolean;
static stopPropagation(event: any): void;
private static _isElement;
/** parent: the context in which events attached to non-HTMLElements are called */
constructor(parent: any);
dispose(): void;
/** On the target, attach a set of events, where the events object is a name to function mapping. */
onAll(target: any, events: {
[key: string]: (args?: any) => void;
}, useCapture?: boolean): void;
/**
* On the target, attach an event whose handler will be called in the context of the parent
* of this instance of EventGroup.
*/
on(target: any, eventName: string, callback: (args?: any) => void, options?: boolean | AddEventListenerOptions): void;
off(target?: any, eventName?: string, callback?: (args?: any) => void, options?: boolean | AddEventListenerOptions): void;
/** Trigger the given event in the context of this instance of EventGroup. */
raise(eventName: string, eventArgs?: any, bubbleEvent?: boolean): boolean | undefined;
/** Declare an event as being supported by this instance of EventGroup. */
declare(event: string | string[]): void;
}
+255
View File
@@ -0,0 +1,255 @@
define(["require", "exports", "./dom", "./object"], function (require, exports, dom_1, object_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.EventGroup = void 0;
/** An instance of EventGroup allows anything with a handle to it to trigger events on it.
* If the target is an HTMLElement, the event will be attached to the element and can be
* triggered as usual (like clicking for onClick).
* The event can be triggered by calling EventGroup.raise() here. If the target is an
* HTMLElement, the event gets raised and is handled by the browser. Otherwise, it gets
* handled here in EventGroup, and the handler is called in the context of the parent
* (which is passed in in the constructor).
*
* @public
* {@docCategory EventGroup}
*/
var EventGroup = /** @class */ (function () {
/** parent: the context in which events attached to non-HTMLElements are called */
function EventGroup(parent) {
this._id = EventGroup._uniqueId++;
this._parent = parent;
this._eventRecords = [];
}
/** For IE8, bubbleEvent is ignored here and must be dealt with by the handler.
* Events raised here by default have bubbling set to false and cancelable set to true.
* This applies also to built-in events being raised manually here on HTMLElements,
* which may lead to unexpected behavior if it differs from the defaults.
*
*/
EventGroup.raise = function (target, eventName, eventArgs, bubbleEvent, doc) {
var retVal;
var theDoc = doc !== null && doc !== void 0 ? doc : (0, dom_1.getDocument)();
if (EventGroup._isElement(target)) {
if (typeof theDoc !== 'undefined' && theDoc.createEvent) {
var ev = theDoc.createEvent('HTMLEvents');
// eslint-disable-next-line @typescript-eslint/no-deprecated
ev.initEvent(eventName, bubbleEvent || false, true);
(0, object_1.assign)(ev, eventArgs);
retVal = target.dispatchEvent(ev);
}
else if (typeof theDoc !== 'undefined' && theDoc.createEventObject) {
// IE8
var evObj = theDoc.createEventObject(eventArgs);
// cannot set cancelBubble on evObj, fireEvent will overwrite it
target.fireEvent('on' + eventName, evObj);
}
}
else {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore -- FIXME: strictBindCallApply error - https://github.com/microsoft/fluentui/issues/17331
while (target && retVal !== false) {
var events = target.__events__;
var eventRecords = events ? events[eventName] : null;
if (eventRecords) {
for (var id in eventRecords) {
if (eventRecords.hasOwnProperty(id)) {
var eventRecordList = eventRecords[id];
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore -- FIXME: strictBindCallApply error - https://github.com/microsoft/fluentui/issues/17331
for (var listIndex = 0; retVal !== false && listIndex < eventRecordList.length; listIndex++) {
var record = eventRecordList[listIndex];
if (record.objectCallback) {
retVal = record.objectCallback.call(record.parent, eventArgs);
}
}
}
}
}
// If the target has a parent, bubble the event up.
target = bubbleEvent ? target.parent : null;
}
}
return retVal;
};
EventGroup.isObserved = function (target, eventName) {
var events = target && target.__events__;
return !!events && !!events[eventName];
};
/** Check to see if the target has declared support of the given event. */
EventGroup.isDeclared = function (target, eventName) {
var declaredEvents = target && target.__declaredEvents;
return !!declaredEvents && !!declaredEvents[eventName];
};
EventGroup.stopPropagation = function (event) {
if (event.stopPropagation) {
event.stopPropagation();
}
else {
// IE8
event.cancelBubble = true;
}
};
EventGroup._isElement = function (target) {
return (!!target && (!!target.addEventListener || (typeof HTMLElement !== 'undefined' && target instanceof HTMLElement)));
};
EventGroup.prototype.dispose = function () {
if (!this._isDisposed) {
this._isDisposed = true;
this.off();
this._parent = null;
}
};
/** On the target, attach a set of events, where the events object is a name to function mapping. */
EventGroup.prototype.onAll = function (target, events, useCapture) {
for (var eventName in events) {
if (events.hasOwnProperty(eventName)) {
this.on(target, eventName, events[eventName], useCapture);
}
}
};
/**
* On the target, attach an event whose handler will be called in the context of the parent
* of this instance of EventGroup.
*/
EventGroup.prototype.on = function (target, eventName, callback, options) {
var _this = this;
if (eventName.indexOf(',') > -1) {
var events = eventName.split(/[ ,]+/);
for (var i = 0; i < events.length; i++) {
this.on(target, events[i], callback, options);
}
}
else {
var parent_1 = this._parent;
var eventRecord = {
target: target,
eventName: eventName,
parent: parent_1,
callback: callback,
options: options,
};
// Initialize and wire up the record on the target, so that it can call the callback if the event fires.
var events = (target.__events__ = target.__events__ || {});
events[eventName] =
events[eventName] ||
{
count: 0,
};
events[eventName][this._id] = events[eventName][this._id] || [];
events[eventName][this._id].push(eventRecord);
events[eventName].count++;
if (EventGroup._isElement(target)) {
var processElementEvent = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
if (_this._isDisposed) {
return;
}
var result;
try {
result = callback.apply(parent_1, args);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore -- FIXME: strictBindCallApply error - https://github.com/microsoft/fluentui/issues/17331
if (result === false && args[0]) {
var e = args[0];
if (e.preventDefault) {
e.preventDefault();
}
if (e.stopPropagation) {
e.stopPropagation();
}
e.cancelBubble = true;
}
}
catch (e) {
// ignore
}
return result;
};
eventRecord.elementCallback = processElementEvent;
if (target.addEventListener) {
target.addEventListener(eventName, processElementEvent, options);
}
else if (target.attachEvent) {
// IE8
target.attachEvent('on' + eventName, processElementEvent);
}
}
else {
var processObjectEvent = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
if (_this._isDisposed) {
return;
}
return callback.apply(parent_1, args);
};
eventRecord.objectCallback = processObjectEvent;
}
// Remember the record locally, so that it can be removed.
this._eventRecords.push(eventRecord);
}
};
EventGroup.prototype.off = function (target, eventName, callback, options) {
for (var i = 0; i < this._eventRecords.length; i++) {
var eventRecord = this._eventRecords[i];
if ((!target || target === eventRecord.target) &&
(!eventName || eventName === eventRecord.eventName) &&
(!callback || callback === eventRecord.callback) &&
(typeof options !== 'boolean' || options === eventRecord.options)) {
var events = eventRecord.target.__events__;
var targetArrayLookup = events[eventRecord.eventName];
var targetArray = targetArrayLookup ? targetArrayLookup[this._id] : null;
// We may have already target's entries, so check for null.
if (targetArray) {
if (targetArray.length === 1 || !callback) {
targetArrayLookup.count -= targetArray.length;
delete events[eventRecord.eventName][this._id];
}
else {
targetArrayLookup.count--;
targetArray.splice(targetArray.indexOf(eventRecord), 1);
}
if (!targetArrayLookup.count) {
delete events[eventRecord.eventName];
}
}
if (eventRecord.elementCallback) {
if (eventRecord.target.removeEventListener) {
eventRecord.target.removeEventListener(eventRecord.eventName, eventRecord.elementCallback, eventRecord.options);
}
else if (eventRecord.target.detachEvent) {
// IE8
eventRecord.target.detachEvent('on' + eventRecord.eventName, eventRecord.elementCallback);
}
}
this._eventRecords.splice(i--, 1);
}
}
};
/** Trigger the given event in the context of this instance of EventGroup. */
EventGroup.prototype.raise = function (eventName, eventArgs, bubbleEvent) {
return EventGroup.raise(this._parent, eventName, eventArgs, bubbleEvent);
};
/** Declare an event as being supported by this instance of EventGroup. */
EventGroup.prototype.declare = function (event) {
var declaredEvents = (this._parent.__declaredEvents = this._parent.__declaredEvents || {});
if (typeof event === 'string') {
declaredEvents[event] = true;
}
else {
for (var i = 0; i < event.length; i++) {
declaredEvents[event[i]] = true;
}
}
};
EventGroup._uniqueId = 0;
return EventGroup;
}());
exports.EventGroup = EventGroup;
});
//# sourceMappingURL=EventGroup.js.map
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
export {};
+207
View File
@@ -0,0 +1,207 @@
define(["require", "exports", "./EventGroup"], function (require, exports, EventGroup_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
describe('EventGroup', function () {
it('can observe an HTML element event', function () {
var timesCalled = 0;
var sourceButton = document.createElement('button');
var parent = {
cb: function () {
timesCalled++;
},
};
var eg = new EventGroup_1.EventGroup(parent);
var ev = document.createEvent('HTMLEvents');
eg.on(sourceButton, 'click', parent.cb);
ev.initEvent('click', true, true);
sourceButton.dispatchEvent(ev);
expect(timesCalled).toEqual(1);
sourceButton.dispatchEvent(ev);
expect(timesCalled).toEqual(2);
eg.dispose();
sourceButton.dispatchEvent(ev);
expect(timesCalled).toEqual(2);
});
it('can observe an object event', function () {
var timesCalled = 0;
var sourceObject = {};
var parent = {
cb: function () {
timesCalled++;
},
};
var parentEvents = new EventGroup_1.EventGroup(parent);
var sourceEvents = new EventGroup_1.EventGroup(sourceObject);
sourceEvents.declare(['foo', 'bar']);
expect(EventGroup_1.EventGroup.isDeclared(sourceObject, 'foo')).toEqual(true);
expect(EventGroup_1.EventGroup.isDeclared(sourceObject, 'bar')).toEqual(true);
expect(EventGroup_1.EventGroup.isDeclared(sourceObject, 'baz')).toEqual(false);
parentEvents.on(sourceObject, 'foo, bar', parent.cb);
expect(EventGroup_1.EventGroup.isObserved(sourceObject, 'foo')).toEqual(true);
expect(EventGroup_1.EventGroup.isObserved(sourceObject, 'bar')).toEqual(true);
expect(EventGroup_1.EventGroup.isObserved(sourceObject, 'baz')).toEqual(false);
sourceEvents.raise('foo');
expect(timesCalled).toEqual(1);
sourceEvents.raise('bar');
expect(timesCalled).toEqual(2);
parentEvents.dispose();
sourceEvents.raise('thing');
expect(timesCalled).toEqual(2);
});
it('can bubble object events', function () {
var rootCalled = 0;
var childCalled = 0;
var grandChildCalled = 0;
var childResponse = true;
var root = {
cb: function () {
rootCalled++;
},
};
var child = {
parent: root,
cb: function () {
childCalled++;
return childResponse;
},
};
var grandChild = {
parent: child,
cb: function () {
grandChildCalled++;
},
};
var rootEvents = new EventGroup_1.EventGroup(root);
var childEvents = new EventGroup_1.EventGroup(child);
var grandChildEvents = new EventGroup_1.EventGroup(grandChild);
rootEvents.on(root, 'foo', root.cb);
childEvents.on(child, 'foo', child.cb);
grandChildEvents.on(grandChild, 'foo', grandChild.cb);
// bubble up to the root.
grandChildEvents.raise('foo', null, true);
expect(rootCalled).toEqual(1);
expect(childCalled).toEqual(1);
expect(grandChildCalled).toEqual(1);
// cancel at the child.
childResponse = false;
grandChildEvents.raise('foo', null, true);
expect(rootCalled).toEqual(1);
expect(childCalled).toEqual(2);
expect(grandChildCalled).toEqual(2);
// dispose all.
rootEvents.dispose();
childEvents.dispose();
grandChildEvents.dispose();
grandChildEvents.raise('foo', null, true);
expect(rootCalled).toEqual(1);
expect(childCalled).toEqual(2);
expect(grandChildCalled).toEqual(2);
});
it('can cancelBubble/preventDefault if false is returned on an element event callback', function () {
var rootCalled = 0;
var childCalled = 0;
var childResponse = true;
var rootDiv = document.createElement('div');
var childDiv = document.createElement('div');
var grandChildButton = document.createElement('button');
var parent = {
onRootClick: function () {
rootCalled++;
},
onChildClick: function () {
childCalled++;
return childResponse;
},
};
var parentEvents = new EventGroup_1.EventGroup(parent);
parentEvents.on(childDiv, 'click', parent.onChildClick);
parentEvents.on(rootDiv, 'click', parent.onRootClick);
document.body.appendChild(rootDiv).appendChild(childDiv).appendChild(grandChildButton);
try {
var ev = document.createEvent('HTMLEvents');
ev.initEvent('click', true, true);
grandChildButton.dispatchEvent(ev);
// verify we bubble.
expect(childCalled).toEqual(1);
expect(rootCalled).toEqual(1);
// now return false at the child, shouldn't hit root.
childResponse = false;
grandChildButton.dispatchEvent(ev);
expect(childCalled).toEqual(2);
expect(rootCalled).toEqual(1);
parentEvents.dispose();
grandChildButton.dispatchEvent(ev);
expect(childCalled).toEqual(2);
expect(rootCalled).toEqual(1);
}
finally {
document.body.removeChild(rootDiv);
}
});
it('can selectively remove event handlers', function () {
var cb1Called = 0;
var cb2Called = 0;
var sourceObject = {};
var parent = {
cb1: function () {
cb1Called++;
},
cb2: function () {
cb2Called++;
},
};
var parentEvents = new EventGroup_1.EventGroup(parent);
var sourceEvents = new EventGroup_1.EventGroup(sourceObject);
parentEvents.on(sourceObject, 'foo', parent.cb1);
parentEvents.on(sourceObject, 'foo', parent.cb2);
sourceEvents.raise('foo');
expect(cb1Called).toEqual(1);
expect(cb1Called).toEqual(1);
// remove one.
parentEvents.off(sourceObject, 'foo', parent.cb1);
sourceEvents.raise('foo');
expect(cb1Called).toEqual(1);
expect(cb2Called).toEqual(2);
// attach it again.
parentEvents.on(sourceObject, 'foo', parent.cb1);
sourceEvents.raise('foo');
expect(cb1Called).toEqual(2);
expect(cb2Called).toEqual(3);
// detatch both based on event name.
parentEvents.off(sourceObject, 'foo');
sourceEvents.raise('foo');
expect(cb1Called).toEqual(2);
expect(cb2Called).toEqual(3);
// attach it again.
parentEvents.on(sourceObject, 'foo', parent.cb1);
parentEvents.on(sourceObject, 'foo', parent.cb2);
sourceEvents.raise('foo');
expect(cb1Called).toEqual(3);
expect(cb2Called).toEqual(4);
// detach based on object.
parentEvents.off(sourceObject);
sourceEvents.raise('foo');
expect(cb1Called).toEqual(3);
expect(cb2Called).toEqual(4);
});
it('can raise custom html events', function () {
var timesCalled = 0;
var sourceButton = document.createElement('button');
var parent = {
cb: function () {
timesCalled++;
},
};
var eg = new EventGroup_1.EventGroup(parent);
eg.on(sourceButton, 'foobar', parent.cb);
EventGroup_1.EventGroup.raise(sourceButton, 'foobar');
expect(timesCalled).toEqual(1);
EventGroup_1.EventGroup.raise(sourceButton, 'foobar');
expect(timesCalled).toEqual(2);
eg.dispose();
EventGroup_1.EventGroup.raise(sourceButton, 'foobar');
expect(timesCalled).toEqual(2);
});
});
});
//# sourceMappingURL=EventGroup.test.js.map
File diff suppressed because one or more lines are too long
+46
View File
@@ -0,0 +1,46 @@
/**
* PerfData interface.
*
* @internal
*/
export interface IPerfData {
duration: number;
timeStamp: number;
}
/**
* PerfMeasurement interface.
*
* @internal
*/
export interface IPerfMeasurement {
totalDuration: number;
count: number;
all: IPerfData[];
}
/**
* PerfSummary interface.
*
* @internal
*/
export interface IPerfSummary {
[key: string]: IPerfMeasurement;
}
/**
* Performance helper class for measuring things.
*
* @public
* {@docCategory FabricPerformance}
*/
export declare class FabricPerformance {
static summary: IPerfSummary;
private static _timeoutId;
/**
* Measures execution time of the given syncronous function. If the same logic is executed multiple times,
* each individual measurement will be collected as well the overall numbers.
* @param name - The name of this measurement
* @param func - The logic to be measured for execution time
*/
static measure(name: string, func: () => void): void;
static reset(): void;
static setPeriodicReset(): void;
}
+58
View File
@@ -0,0 +1,58 @@
define(["require", "exports"], function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FabricPerformance = void 0;
var now = function () {
return typeof performance !== 'undefined' && !!performance.now ? performance.now() : Date.now();
};
var RESET_INTERVAL = 3 * 60 * 1000; // auto reset every 3 minutes
/**
* Performance helper class for measuring things.
*
* @public
* {@docCategory FabricPerformance}
*/
var FabricPerformance = /** @class */ (function () {
function FabricPerformance() {
}
/**
* Measures execution time of the given syncronous function. If the same logic is executed multiple times,
* each individual measurement will be collected as well the overall numbers.
* @param name - The name of this measurement
* @param func - The logic to be measured for execution time
*/
FabricPerformance.measure = function (name, func) {
if (FabricPerformance._timeoutId) {
FabricPerformance.setPeriodicReset();
}
var start = now();
func();
var end = now();
var measurement = FabricPerformance.summary[name] || {
totalDuration: 0,
count: 0,
all: [],
};
var duration = end - start;
measurement.totalDuration += duration;
measurement.count++;
measurement.all.push({
duration: duration,
timeStamp: end,
});
FabricPerformance.summary[name] = measurement;
};
FabricPerformance.reset = function () {
FabricPerformance.summary = {};
clearTimeout(FabricPerformance._timeoutId);
FabricPerformance._timeoutId = NaN;
};
FabricPerformance.setPeriodicReset = function () {
FabricPerformance._timeoutId = setTimeout(function () { return FabricPerformance.reset(); }, RESET_INTERVAL);
};
FabricPerformance.summary = {};
return FabricPerformance;
}());
exports.FabricPerformance = FabricPerformance;
});
//# sourceMappingURL=FabricPerformance.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"FabricPerformance.js","sourceRoot":"../src/","sources":["FabricPerformance.ts"],"names":[],"mappings":";;;;IAgCA,IAAM,GAAG,GAAiB;QACxB,OAAA,OAAO,WAAW,KAAK,WAAW,IAAI,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;IAAxF,CAAwF,CAAC;IAE3F,IAAM,cAAc,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,6BAA6B;IAEnE;;;;;OAKG;IACH;QAAA;QAyCA,CAAC;QArCC;;;;;WAKG;QACW,yBAAO,GAArB,UAAsB,IAAY,EAAE,IAAgB;YAClD,IAAI,iBAAiB,CAAC,UAAU,EAAE,CAAC;gBACjC,iBAAiB,CAAC,gBAAgB,EAAE,CAAC;YACvC,CAAC;YACD,IAAM,KAAK,GAAG,GAAG,EAAE,CAAC;YACpB,IAAI,EAAE,CAAC;YACP,IAAM,GAAG,GAAG,GAAG,EAAE,CAAC;YAClB,IAAM,WAAW,GAAqB,iBAAiB,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI;gBACvE,aAAa,EAAE,CAAC;gBAChB,KAAK,EAAE,CAAC;gBACR,GAAG,EAAE,EAAE;aACR,CAAC;YACF,IAAM,QAAQ,GAAG,GAAG,GAAG,KAAK,CAAC;YAC7B,WAAW,CAAC,aAAa,IAAI,QAAQ,CAAC;YACtC,WAAW,CAAC,KAAK,EAAE,CAAC;YACpB,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;gBACnB,QAAQ,UAAA;gBACR,SAAS,EAAE,GAAG;aACf,CAAC,CAAC;YACH,iBAAiB,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC;QAChD,CAAC;QAEa,uBAAK,GAAnB;YACE,iBAAiB,CAAC,OAAO,GAAG,EAAE,CAAC;YAC/B,YAAY,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;YAC3C,iBAAiB,CAAC,UAAU,GAAG,GAAG,CAAC;QACrC,CAAC;QAEa,kCAAgB,GAA9B;YACE,iBAAiB,CAAC,UAAU,GAAG,UAAU,CAAC,cAAM,OAAA,iBAAiB,CAAC,KAAK,EAAE,EAAzB,CAAyB,EAAE,cAAc,CAAC,CAAC;QAC7F,CAAC;QAvCa,yBAAO,GAAiB,EAAE,CAAC;QAwC3C,wBAAC;KAAA,AAzCD,IAyCC;IAzCY,8CAAiB","sourcesContent":["declare const setTimeout: (cb: () => void, delay: number) => number;\n\n/**\n * PerfData interface.\n *\n * @internal\n */\nexport interface IPerfData {\n duration: number;\n timeStamp: number;\n}\n\n/**\n * PerfMeasurement interface.\n *\n * @internal\n */\nexport interface IPerfMeasurement {\n totalDuration: number;\n count: number;\n all: IPerfData[];\n}\n\n/**\n * PerfSummary interface.\n *\n * @internal\n */\nexport interface IPerfSummary {\n [key: string]: IPerfMeasurement;\n}\n\nconst now: () => number = () =>\n typeof performance !== 'undefined' && !!performance.now ? performance.now() : Date.now();\n\nconst RESET_INTERVAL = 3 * 60 * 1000; // auto reset every 3 minutes\n\n/**\n * Performance helper class for measuring things.\n *\n * @public\n * {@docCategory FabricPerformance}\n */\nexport class FabricPerformance {\n public static summary: IPerfSummary = {};\n private static _timeoutId: number;\n\n /**\n * Measures execution time of the given syncronous function. If the same logic is executed multiple times,\n * each individual measurement will be collected as well the overall numbers.\n * @param name - The name of this measurement\n * @param func - The logic to be measured for execution time\n */\n public static measure(name: string, func: () => void): void {\n if (FabricPerformance._timeoutId) {\n FabricPerformance.setPeriodicReset();\n }\n const start = now();\n func();\n const end = now();\n const measurement: IPerfMeasurement = FabricPerformance.summary[name] || {\n totalDuration: 0,\n count: 0,\n all: [],\n };\n const duration = end - start;\n measurement.totalDuration += duration;\n measurement.count++;\n measurement.all.push({\n duration,\n timeStamp: end,\n });\n FabricPerformance.summary[name] = measurement;\n }\n\n public static reset(): void {\n FabricPerformance.summary = {};\n clearTimeout(FabricPerformance._timeoutId);\n FabricPerformance._timeoutId = NaN;\n }\n\n public static setPeriodicReset(): void {\n FabricPerformance._timeoutId = setTimeout(() => FabricPerformance.reset(), RESET_INTERVAL);\n }\n}\n"]}
+13
View File
@@ -0,0 +1,13 @@
import * as React from 'react';
export type FocusRectsProviderProps = {
/**
* Ref to the root element that this is providing focus rects for.
*/
providerRef: React.RefObject<HTMLElement | null>;
/**
* Indicates that this is the root of a layer, and should not inherit the providerRef from a parent context.
*/
layerRoot?: boolean;
children?: React.ReactNode;
};
export declare const FocusRectsProvider: React.FC<FocusRectsProviderProps>;
+49
View File
@@ -0,0 +1,49 @@
define(["require", "exports", "react", "./useFocusRects"], function (require, exports, React, useFocusRects_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FocusRectsProvider = void 0;
var FocusRectsProvider = function (props) {
var providerRef = props.providerRef, layerRoot = props.layerRoot;
var registeredProviders = React.useState([])[0];
var parentContext = React.useContext(useFocusRects_1.FocusRectsContext);
// Inherit the parent context if it exists, unless this is a layer root.
// This allows the topmost provider element in the DOM tree to handle the focus events.
// Since layers are in a separate HTML tree from their parent, they shouldn't use the parent's providerRef.
var inheritParentContext = parentContext !== undefined && !layerRoot;
var context = React.useMemo(function () {
return inheritParentContext
? undefined
: {
providerRef: providerRef,
registeredProviders: registeredProviders,
registerProvider: function (ref) {
// Register this child provider with the current context, and any parent contexts
registeredProviders.push(ref);
parentContext === null || parentContext === void 0 ? void 0 : parentContext.registerProvider(ref);
},
unregisterProvider: function (ref) {
parentContext === null || parentContext === void 0 ? void 0 : parentContext.unregisterProvider(ref);
var i = registeredProviders.indexOf(ref);
if (i >= 0) {
registeredProviders.splice(i, 1);
}
},
};
}, [providerRef, registeredProviders, parentContext, inheritParentContext]);
React.useEffect(function () {
if (context) {
context.registerProvider(context.providerRef);
return function () { return context.unregisterProvider(context.providerRef); };
}
}, [context]);
// Create a new context provider if this is not inheriting from the parent.
if (context) {
return React.createElement(useFocusRects_1.FocusRectsContext.Provider, { value: context }, props.children);
}
else {
return React.createElement(React.Fragment, null, props.children);
}
};
exports.FocusRectsProvider = FocusRectsProvider;
});
//# sourceMappingURL=FocusRectsProvider.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"FocusRectsProvider.js","sourceRoot":"../src/","sources":["FocusRectsProvider.tsx"],"names":[],"mappings":";;;;IAiBO,IAAM,kBAAkB,GAAsC,UAAA,KAAK;QAChE,IAAA,WAAW,GAAgB,KAAK,YAArB,EAAE,SAAS,GAAK,KAAK,UAAV,CAAW;QAClC,IAAA,mBAAmB,GAAI,KAAK,CAAC,QAAQ,CAAwC,EAAE,CAAC,GAA7D,CAA8D;QACxF,IAAM,aAAa,GAAG,KAAK,CAAC,UAAU,CAAC,iCAAiB,CAAC,CAAC;QAE1D,wEAAwE;QACxE,uFAAuF;QACvF,2GAA2G;QAC3G,IAAM,oBAAoB,GAAG,aAAa,KAAK,SAAS,IAAI,CAAC,SAAS,CAAC;QAEvE,IAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAC3B;YACE,OAAA,oBAAoB;gBAClB,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC;oBACE,WAAW,aAAA;oBACX,mBAAmB,qBAAA;oBACnB,gBAAgB,EAAE,UAAC,GAAwC;wBACzD,iFAAiF;wBACjF,mBAAmB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;wBAC9B,aAAa,aAAb,aAAa,uBAAb,aAAa,CAAE,gBAAgB,CAAC,GAAG,CAAC,CAAC;oBACvC,CAAC;oBACD,kBAAkB,EAAE,UAAC,GAAwC;wBAC3D,aAAa,aAAb,aAAa,uBAAb,aAAa,CAAE,kBAAkB,CAAC,GAAG,CAAC,CAAC;wBACvC,IAAM,CAAC,GAAG,mBAAmB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;wBAC3C,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;4BACX,mBAAmB,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;wBACnC,CAAC;oBACH,CAAC;iBACF;QAjBL,CAiBK,EACP,CAAC,WAAW,EAAE,mBAAmB,EAAE,aAAa,EAAE,oBAAoB,CAAC,CACxE,CAAC;QAEF,KAAK,CAAC,SAAS,CAAC;YACd,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO,CAAC,gBAAgB,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;gBAC9C,OAAO,cAAM,OAAA,OAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,WAAW,CAAC,EAA/C,CAA+C,CAAC;YAC/D,CAAC;QACH,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;QAEd,2EAA2E;QAC3E,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,oBAAC,iCAAiB,CAAC,QAAQ,IAAC,KAAK,EAAE,OAAO,IAAG,KAAK,CAAC,QAAQ,CAA8B,CAAC;QACnG,CAAC;aAAM,CAAC;YACN,OAAO,0CAAG,KAAK,CAAC,QAAQ,CAAI,CAAC;QAC/B,CAAC;IACH,CAAC,CAAC;IA9CW,QAAA,kBAAkB,sBA8C7B","sourcesContent":["import * as React from 'react';\nimport { FocusRectsContext } from './useFocusRects';\n\nexport type FocusRectsProviderProps = {\n /**\n * Ref to the root element that this is providing focus rects for.\n */\n providerRef: React.RefObject<HTMLElement | null>;\n\n /**\n * Indicates that this is the root of a layer, and should not inherit the providerRef from a parent context.\n */\n layerRoot?: boolean;\n\n children?: React.ReactNode;\n};\n\nexport const FocusRectsProvider: React.FC<FocusRectsProviderProps> = props => {\n const { providerRef, layerRoot } = props;\n const [registeredProviders] = React.useState<React.RefObject<HTMLElement | null>[]>([]);\n const parentContext = React.useContext(FocusRectsContext);\n\n // Inherit the parent context if it exists, unless this is a layer root.\n // This allows the topmost provider element in the DOM tree to handle the focus events.\n // Since layers are in a separate HTML tree from their parent, they shouldn't use the parent's providerRef.\n const inheritParentContext = parentContext !== undefined && !layerRoot;\n\n const context = React.useMemo(\n () =>\n inheritParentContext\n ? undefined\n : {\n providerRef,\n registeredProviders,\n registerProvider: (ref: React.RefObject<HTMLElement | null>) => {\n // Register this child provider with the current context, and any parent contexts\n registeredProviders.push(ref);\n parentContext?.registerProvider(ref);\n },\n unregisterProvider: (ref: React.RefObject<HTMLElement | null>) => {\n parentContext?.unregisterProvider(ref);\n const i = registeredProviders.indexOf(ref);\n if (i >= 0) {\n registeredProviders.splice(i, 1);\n }\n },\n },\n [providerRef, registeredProviders, parentContext, inheritParentContext],\n );\n\n React.useEffect(() => {\n if (context) {\n context.registerProvider(context.providerRef);\n return () => context.unregisterProvider(context.providerRef);\n }\n }, [context]);\n\n // Create a new context provider if this is not inheriting from the parent.\n if (context) {\n return <FocusRectsContext.Provider value={context}>{props.children}</FocusRectsContext.Provider>;\n } else {\n return <>{props.children}</>;\n }\n};\n"]}
+35
View File
@@ -0,0 +1,35 @@
/**
* Change description used for change callbacks in GlobalSettings.
*
* @public
* {@docCategory IChangeDescription}
*/
export interface IChangeDescription {
key: string;
oldValue: any;
value: any;
}
/**
* Change event callback.
*
* @public
* {@docCategory IChangeEventCallback}
*/
export interface IChangeEventCallback {
__id__?: string;
(changeDescription?: IChangeDescription): void;
}
/**
* Global settings helper, which stores settings in the global (window) namespace.
* If window is not provided, it will store settings in module scope. Provides a
* way to observe changes as well when their values change.
*
* @public
* {@docCategory GlobalSettings}
*/
export declare class GlobalSettings {
static getValue<T>(key: string, defaultValue?: T | (() => T)): T;
static setValue<T>(key: string, value: T): T;
static addChangeListener(cb: IChangeEventCallback): void;
static removeChangeListener(cb: IChangeEventCallback): void;
}
+88
View File
@@ -0,0 +1,88 @@
define(["require", "exports", "./dom/getWindow"], function (require, exports, getWindow_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.GlobalSettings = void 0;
/**
* Storing global state in local module variables has issues when more than one copy
* if the module gets loaded on the page (due to a bundling error or simply by consuming
* a prebundled script.)
*
* This file contains helpers to deal with the getting and setting local state, and allows
* callers to get called back when it mutates.
*/
var GLOBAL_SETTINGS_PROP_NAME = '__globalSettings__';
var CALLBACK_STATE_PROP_NAME = '__callbacks__';
var _counter = 0;
/**
* Global settings helper, which stores settings in the global (window) namespace.
* If window is not provided, it will store settings in module scope. Provides a
* way to observe changes as well when their values change.
*
* @public
* {@docCategory GlobalSettings}
*/
var GlobalSettings = /** @class */ (function () {
function GlobalSettings() {
}
GlobalSettings.getValue = function (key, defaultValue) {
var globalSettings = _getGlobalSettings();
if (globalSettings[key] === undefined) {
globalSettings[key] = typeof defaultValue === 'function' ? defaultValue() : defaultValue;
}
return globalSettings[key];
};
GlobalSettings.setValue = function (key, value) {
var globalSettings = _getGlobalSettings();
var callbacks = globalSettings[CALLBACK_STATE_PROP_NAME];
var oldValue = globalSettings[key];
if (value !== oldValue) {
globalSettings[key] = value;
var changeDescription = {
oldValue: oldValue,
value: value,
key: key,
};
for (var id in callbacks) {
if (callbacks.hasOwnProperty(id)) {
callbacks[id](changeDescription);
}
}
}
return value;
};
GlobalSettings.addChangeListener = function (cb) {
// Note: we use generated ids on the callbacks to create a map of the callbacks, which optimizes removal.
// (It's faster to delete a key than it is to look up the index of an object and splice an array.)
var id = cb.__id__;
var callbacks = _getCallbacks();
if (!id) {
id = cb.__id__ = String(_counter++);
}
callbacks[id] = cb;
};
GlobalSettings.removeChangeListener = function (cb) {
var callbacks = _getCallbacks();
delete callbacks[cb.__id__];
};
return GlobalSettings;
}());
exports.GlobalSettings = GlobalSettings;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function _getGlobalSettings() {
var _a;
var win = (0, getWindow_1.getWindow)();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
var globalObj = win || {};
if (!globalObj[GLOBAL_SETTINGS_PROP_NAME]) {
globalObj[GLOBAL_SETTINGS_PROP_NAME] = (_a = {},
_a[CALLBACK_STATE_PROP_NAME] = {},
_a);
}
return globalObj[GLOBAL_SETTINGS_PROP_NAME];
}
function _getCallbacks() {
var globalSettings = _getGlobalSettings();
return globalSettings[CALLBACK_STATE_PROP_NAME];
}
});
//# sourceMappingURL=GlobalSettings.js.map
File diff suppressed because one or more lines are too long
+6
View File
@@ -0,0 +1,6 @@
/**
* @deprecated Use `IProcessedStyleSet` from `@fluentui/style-utilities` or `@fluentui/merge-styles` instead.
*/
export type IClassNames<T> = {
[key in keyof T]: string;
};
+5
View File
@@ -0,0 +1,5 @@
define(["require", "exports"], function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
});
//# sourceMappingURL=IClassNames.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"IClassNames.js","sourceRoot":"../src/","sources":["IClassNames.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * @deprecated Use `IProcessedStyleSet` from `@fluentui/style-utilities` or `@fluentui/merge-styles` instead.\n */\nexport type IClassNames<T> = { [key in keyof T]: string };\n"]}
+17
View File
@@ -0,0 +1,17 @@
import * as React from 'react';
/**
* Properties used by render function interface for providing overrideable render callbacks.
*
* @public
* {@docCategory IComponentAsProps}
*/
export type IComponentAsProps<T> = T & {
defaultRender?: React.ComponentType<T>;
};
/**
* Render function interface for providing overrideable render callbacks.
*
* @public
* {@docCategory IComponentAs}
*/
export type IComponentAs<T> = React.ComponentType<IComponentAsProps<T>>;
+5
View File
@@ -0,0 +1,5 @@
define(["require", "exports"], function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
});
//# sourceMappingURL=IComponentAs.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"IComponentAs.js","sourceRoot":"../src/","sources":["IComponentAs.ts"],"names":[],"mappings":"","sourcesContent":["import * as React from 'react';\n\n/**\n * Properties used by render function interface for providing overrideable render callbacks.\n *\n * @public\n * {@docCategory IComponentAsProps}\n */\nexport type IComponentAsProps<T> = T & { defaultRender?: React.ComponentType<T> };\n\n/**\n * Render function interface for providing overrideable render callbacks.\n *\n * @public\n * {@docCategory IComponentAs}\n */\nexport type IComponentAs<T> = React.ComponentType<IComponentAsProps<T>>;\n"]}
+9
View File
@@ -0,0 +1,9 @@
/**
* Disposable interface.
*
* @public
* {@docCategory IDisposable}
*/
export interface IDisposable {
dispose: () => void;
}
+5
View File
@@ -0,0 +1,5 @@
define(["require", "exports"], function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
});
//# sourceMappingURL=IDisposable.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"IDisposable.js","sourceRoot":"../src/","sources":["IDisposable.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Disposable interface.\n *\n * @public\n * {@docCategory IDisposable}\n */\nexport interface IDisposable {\n dispose: () => void;\n}\n"]}
+14
View File
@@ -0,0 +1,14 @@
/**
* Rectangle interface.
*
* @public
* {@docCategory IRectangle}
*/
export interface IRectangle {
left: number;
top: number;
width: number;
height: number;
right?: number;
bottom?: number;
}
+5
View File
@@ -0,0 +1,5 @@
define(["require", "exports"], function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
});
//# sourceMappingURL=IRectangle.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"IRectangle.js","sourceRoot":"../src/","sources":["IRectangle.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Rectangle interface.\n *\n * @public\n * {@docCategory IRectangle}\n */\nexport interface IRectangle {\n left: number;\n top: number;\n width: number;\n height: number;\n right?: number;\n bottom?: number;\n}\n"]}
+13
View File
@@ -0,0 +1,13 @@
import type { JSXElement } from './jsx';
/**
* An interface representing a component that will not output any DOM, will just render its children and
* pass through items to modify the children.
*
* {@docCategory IRenderComponent}
*/
export interface IRenderComponent<TProps> {
/**
* JSXElement to return in this component's render() function.
*/
children: (props: TProps) => JSXElement;
}
+5
View File
@@ -0,0 +1,5 @@
define(["require", "exports"], function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
});
//# sourceMappingURL=IRenderComponent.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"IRenderComponent.js","sourceRoot":"../src/","sources":["IRenderComponent.ts"],"names":[],"mappings":"","sourcesContent":["import type { JSXElement } from './jsx';\n\n/**\n * An interface representing a component that will not output any DOM, will just render its children and\n * pass through items to modify the children.\n *\n * {@docCategory IRenderComponent}\n */\nexport interface IRenderComponent<TProps> {\n /**\n * JSXElement to return in this component's render() function.\n */\n children: (props: TProps) => JSXElement;\n}\n"]}
+7
View File
@@ -0,0 +1,7 @@
import type { JSXElement } from './jsx';
/**
* Render function interface for providing overrideable render callbacks.
*
* @public
*/
export type IRenderFunction<P> = (props?: P, defaultRender?: (props?: P) => JSXElement | null) => JSXElement | null;
+5
View File
@@ -0,0 +1,5 @@
define(["require", "exports"], function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
});
//# sourceMappingURL=IRenderFunction.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"IRenderFunction.js","sourceRoot":"../src/","sources":["IRenderFunction.ts"],"names":[],"mappings":"","sourcesContent":["import type { JSXElement } from './jsx';\n\n/**\n * Render function interface for providing overrideable render callbacks.\n *\n * @public\n */\nexport type IRenderFunction<P> = (props?: P, defaultRender?: (props?: P) => JSXElement | null) => JSXElement | null;\n"]}
+7
View File
@@ -0,0 +1,7 @@
/**
* {@docCategory ISize}
*/
export interface ISize {
width: number;
height: number;
}
+5
View File
@@ -0,0 +1,5 @@
define(["require", "exports"], function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
});
//# sourceMappingURL=ISize.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"ISize.js","sourceRoot":"../src/","sources":["ISize.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * {@docCategory ISize}\n */\nexport interface ISize {\n width: number;\n height: number;\n}\n"]}
+1
View File
@@ -0,0 +1 @@
export type { IStyleFunction } from '@fluentui/merge-styles';
+5
View File
@@ -0,0 +1,5 @@
define(["require", "exports"], function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
});
//# sourceMappingURL=IStyleFunction.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"IStyleFunction.js","sourceRoot":"../src/","sources":["IStyleFunction.ts"],"names":[],"mappings":"","sourcesContent":["export type { IStyleFunction } from '@fluentui/merge-styles';\n"]}
+109
View File
@@ -0,0 +1,109 @@
/**
* Simulated enum for keycodes. These will get inlined by uglify when used much like an enum
*
* @public
* {@docCategory KeyCodes}
*/
export declare const KeyCodes: {
backspace: 8;
tab: 9;
enter: 13;
shift: 16;
ctrl: 17;
alt: 18;
pauseBreak: 19;
capslock: 20;
escape: 27;
space: 32;
pageUp: 33;
pageDown: 34;
end: 35;
home: 36;
left: 37;
up: 38;
right: 39;
down: 40;
insert: 45;
del: 46;
zero: 48;
one: 49;
two: 50;
three: 51;
four: 52;
five: 53;
six: 54;
seven: 55;
eight: 56;
nine: 57;
colon: 58;
a: 65;
b: 66;
c: 67;
d: 68;
e: 69;
f: 70;
g: 71;
h: 72;
i: 73;
j: 74;
k: 75;
l: 76;
m: 77;
n: 78;
o: 79;
p: 80;
q: 81;
r: 82;
s: 83;
t: 84;
u: 85;
v: 86;
w: 87;
x: 88;
y: 89;
z: 90;
leftWindow: 91;
rightWindow: 92;
select: 93;
zero_numpad: 96;
one_numpad: 97;
two_numpad: 98;
three_numpad: 99;
four_numpad: 100;
five_numpad: 101;
six_numpad: 102;
seven_numpad: 103;
eight_numpad: 104;
nine_numpad: 105;
multiply: 106;
add: 107;
subtract: 109;
decimalPoint: 110;
divide: 111;
f1: 112;
f2: 113;
f3: 114;
f4: 115;
f5: 116;
f6: 117;
f7: 118;
f8: 119;
f9: 120;
f10: 121;
f11: 122;
f12: 123;
numlock: 144;
scrollLock: 145;
semicolon: 186;
equalSign: 187;
comma: 188;
dash: 189;
period: 190;
forwardSlash: 191;
graveAccent: 192;
openBracket: 219;
backSlash: 220;
closeBracket: 221;
singleQuote: 222;
};
export type KeyCodes = number;
+116
View File
@@ -0,0 +1,116 @@
define(["require", "exports"], function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.KeyCodes = void 0;
/**
* Simulated enum for keycodes. These will get inlined by uglify when used much like an enum
*
* @public
* {@docCategory KeyCodes}
*/
exports.KeyCodes = {
backspace: 8,
tab: 9,
enter: 13,
shift: 16,
ctrl: 17,
alt: 18,
pauseBreak: 19,
capslock: 20,
escape: 27,
space: 32,
pageUp: 33,
pageDown: 34,
end: 35,
home: 36,
left: 37,
up: 38,
right: 39,
down: 40,
insert: 45,
del: 46,
zero: 48,
one: 49,
two: 50,
three: 51,
four: 52,
five: 53,
six: 54,
seven: 55,
eight: 56,
nine: 57,
colon: 58,
a: 65,
b: 66,
c: 67,
d: 68,
e: 69,
f: 70,
g: 71,
h: 72,
i: 73,
j: 74,
k: 75,
l: 76,
m: 77,
n: 78,
o: 79,
p: 80,
q: 81,
r: 82,
s: 83,
t: 84,
u: 85,
v: 86,
w: 87,
x: 88,
y: 89,
z: 90,
leftWindow: 91,
rightWindow: 92,
select: 93,
/* eslint-disable @typescript-eslint/naming-convention */
zero_numpad: 96,
one_numpad: 97,
two_numpad: 98,
three_numpad: 99,
four_numpad: 100,
five_numpad: 101,
six_numpad: 102,
seven_numpad: 103,
eight_numpad: 104,
nine_numpad: 105,
/* eslint-enable @typescript-eslint/naming-convention */
multiply: 106,
add: 107,
subtract: 109,
decimalPoint: 110,
divide: 111,
f1: 112,
f2: 113,
f3: 114,
f4: 115,
f5: 116,
f6: 117,
f7: 118,
f8: 119,
f9: 120,
f10: 121,
f11: 122,
f12: 123,
numlock: 144,
scrollLock: 145,
semicolon: 186,
equalSign: 187,
comma: 188,
dash: 189,
period: 190,
forwardSlash: 191,
graveAccent: 192,
openBracket: 219,
backSlash: 220,
closeBracket: 221,
singleQuote: 222,
};
});
//# sourceMappingURL=KeyCodes.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"KeyCodes.js","sourceRoot":"../src/","sources":["KeyCodes.ts"],"names":[],"mappings":";;;;IAAA;;;;;OAKG;IACU,QAAA,QAAQ,GAAG;QACtB,SAAS,EAAE,CAAM;QACjB,GAAG,EAAE,CAAM;QACX,KAAK,EAAE,EAAQ;QACf,KAAK,EAAE,EAAQ;QACf,IAAI,EAAE,EAAQ;QACd,GAAG,EAAE,EAAQ;QACb,UAAU,EAAE,EAAQ;QACpB,QAAQ,EAAE,EAAQ;QAClB,MAAM,EAAE,EAAQ;QAChB,KAAK,EAAE,EAAQ;QACf,MAAM,EAAE,EAAQ;QAChB,QAAQ,EAAE,EAAQ;QAClB,GAAG,EAAE,EAAQ;QACb,IAAI,EAAE,EAAQ;QACd,IAAI,EAAE,EAAQ;QACd,EAAE,EAAE,EAAQ;QACZ,KAAK,EAAE,EAAQ;QACf,IAAI,EAAE,EAAQ;QACd,MAAM,EAAE,EAAQ;QAChB,GAAG,EAAE,EAAQ;QACb,IAAI,EAAE,EAAQ;QACd,GAAG,EAAE,EAAQ;QACb,GAAG,EAAE,EAAQ;QACb,KAAK,EAAE,EAAQ;QACf,IAAI,EAAE,EAAQ;QACd,IAAI,EAAE,EAAQ;QACd,GAAG,EAAE,EAAQ;QACb,KAAK,EAAE,EAAQ;QACf,KAAK,EAAE,EAAQ;QACf,IAAI,EAAE,EAAQ;QACd,KAAK,EAAE,EAAQ;QACf,CAAC,EAAE,EAAQ;QACX,CAAC,EAAE,EAAQ;QACX,CAAC,EAAE,EAAQ;QACX,CAAC,EAAE,EAAQ;QACX,CAAC,EAAE,EAAQ;QACX,CAAC,EAAE,EAAQ;QACX,CAAC,EAAE,EAAQ;QACX,CAAC,EAAE,EAAQ;QACX,CAAC,EAAE,EAAQ;QACX,CAAC,EAAE,EAAQ;QACX,CAAC,EAAE,EAAQ;QACX,CAAC,EAAE,EAAQ;QACX,CAAC,EAAE,EAAQ;QACX,CAAC,EAAE,EAAQ;QACX,CAAC,EAAE,EAAQ;QACX,CAAC,EAAE,EAAQ;QACX,CAAC,EAAE,EAAQ;QACX,CAAC,EAAE,EAAQ;QACX,CAAC,EAAE,EAAQ;QACX,CAAC,EAAE,EAAQ;QACX,CAAC,EAAE,EAAQ;QACX,CAAC,EAAE,EAAQ;QACX,CAAC,EAAE,EAAQ;QACX,CAAC,EAAE,EAAQ;QACX,CAAC,EAAE,EAAQ;QACX,CAAC,EAAE,EAAQ;QACX,UAAU,EAAE,EAAQ;QACpB,WAAW,EAAE,EAAQ;QACrB,MAAM,EAAE,EAAQ;QAChB,yDAAyD;QACzD,WAAW,EAAE,EAAQ;QACrB,UAAU,EAAE,EAAQ;QACpB,UAAU,EAAE,EAAQ;QACpB,YAAY,EAAE,EAAQ;QACtB,WAAW,EAAE,GAAU;QACvB,WAAW,EAAE,GAAU;QACvB,UAAU,EAAE,GAAU;QACtB,YAAY,EAAE,GAAU;QACxB,YAAY,EAAE,GAAU;QACxB,WAAW,EAAE,GAAU;QACvB,wDAAwD;QACxD,QAAQ,EAAE,GAAU;QACpB,GAAG,EAAE,GAAU;QACf,QAAQ,EAAE,GAAU;QACpB,YAAY,EAAE,GAAU;QACxB,MAAM,EAAE,GAAU;QAClB,EAAE,EAAE,GAAU;QACd,EAAE,EAAE,GAAU;QACd,EAAE,EAAE,GAAU;QACd,EAAE,EAAE,GAAU;QACd,EAAE,EAAE,GAAU;QACd,EAAE,EAAE,GAAU;QACd,EAAE,EAAE,GAAU;QACd,EAAE,EAAE,GAAU;QACd,EAAE,EAAE,GAAU;QACd,GAAG,EAAE,GAAU;QACf,GAAG,EAAE,GAAU;QACf,GAAG,EAAE,GAAU;QACf,OAAO,EAAE,GAAU;QACnB,UAAU,EAAE,GAAU;QACtB,SAAS,EAAE,GAAU;QACrB,SAAS,EAAE,GAAU;QACrB,KAAK,EAAE,GAAU;QACjB,IAAI,EAAE,GAAU;QAChB,MAAM,EAAE,GAAU;QAClB,YAAY,EAAE,GAAU;QACxB,WAAW,EAAE,GAAU;QACvB,WAAW,EAAE,GAAU;QACvB,SAAS,EAAE,GAAU;QACrB,YAAY,EAAE,GAAU;QACxB,WAAW,EAAE,GAAU;KACxB,CAAC","sourcesContent":["/**\n * Simulated enum for keycodes. These will get inlined by uglify when used much like an enum\n *\n * @public\n * {@docCategory KeyCodes}\n */\nexport const KeyCodes = {\n backspace: 8 as 8,\n tab: 9 as 9,\n enter: 13 as 13,\n shift: 16 as 16,\n ctrl: 17 as 17,\n alt: 18 as 18,\n pauseBreak: 19 as 19,\n capslock: 20 as 20,\n escape: 27 as 27,\n space: 32 as 32,\n pageUp: 33 as 33,\n pageDown: 34 as 34,\n end: 35 as 35,\n home: 36 as 36,\n left: 37 as 37,\n up: 38 as 38,\n right: 39 as 39,\n down: 40 as 40,\n insert: 45 as 45,\n del: 46 as 46,\n zero: 48 as 48,\n one: 49 as 49,\n two: 50 as 50,\n three: 51 as 51,\n four: 52 as 52,\n five: 53 as 53,\n six: 54 as 54,\n seven: 55 as 55,\n eight: 56 as 56,\n nine: 57 as 57,\n colon: 58 as 58,\n a: 65 as 65,\n b: 66 as 66,\n c: 67 as 67,\n d: 68 as 68,\n e: 69 as 69,\n f: 70 as 70,\n g: 71 as 71,\n h: 72 as 72,\n i: 73 as 73,\n j: 74 as 74,\n k: 75 as 75,\n l: 76 as 76,\n m: 77 as 77,\n n: 78 as 78,\n o: 79 as 79,\n p: 80 as 80,\n q: 81 as 81,\n r: 82 as 82,\n s: 83 as 83,\n t: 84 as 84,\n u: 85 as 85,\n v: 86 as 86,\n w: 87 as 87,\n x: 88 as 88,\n y: 89 as 89,\n z: 90 as 90,\n leftWindow: 91 as 91,\n rightWindow: 92 as 92,\n select: 93 as 93,\n /* eslint-disable @typescript-eslint/naming-convention */\n zero_numpad: 96 as 96,\n one_numpad: 97 as 97,\n two_numpad: 98 as 98,\n three_numpad: 99 as 99,\n four_numpad: 100 as 100,\n five_numpad: 101 as 101,\n six_numpad: 102 as 102,\n seven_numpad: 103 as 103,\n eight_numpad: 104 as 104,\n nine_numpad: 105 as 105,\n /* eslint-enable @typescript-eslint/naming-convention */\n multiply: 106 as 106,\n add: 107 as 107,\n subtract: 109 as 109,\n decimalPoint: 110 as 110,\n divide: 111 as 111,\n f1: 112 as 112,\n f2: 113 as 113,\n f3: 114 as 114,\n f4: 115 as 115,\n f5: 116 as 116,\n f6: 117 as 117,\n f7: 118 as 118,\n f8: 119 as 119,\n f9: 120 as 120,\n f10: 121 as 121,\n f11: 122 as 122,\n f12: 123 as 123,\n numlock: 144 as 144,\n scrollLock: 145 as 145,\n semicolon: 186 as 186,\n equalSign: 187 as 187,\n comma: 188 as 188,\n dash: 189 as 189,\n period: 190 as 190,\n forwardSlash: 191 as 191,\n graveAccent: 192 as 192,\n openBracket: 219 as 219,\n backSlash: 220 as 220,\n closeBracket: 221 as 221,\n singleQuote: 222 as 222,\n};\nexport type KeyCodes = number;\n"]}
+23
View File
@@ -0,0 +1,23 @@
/**
* Point interface.
*
* @public
* {@docCategory Point}
*/
export interface Point {
left?: number;
top?: number;
/** @deprecated Use `left` instead */
x?: number;
/** @deprecated Use `top` instead */
y?: number;
}
/**
* Point interface.
*
* @public
* @deprecated Use `Point` instead.
* {@docCategory Point}
*/
export interface IPoint extends Point {
}
+5
View File
@@ -0,0 +1,5 @@
define(["require", "exports"], function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
});
//# sourceMappingURL=Point.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"Point.js","sourceRoot":"../src/","sources":["Point.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Point interface.\n *\n * @public\n * {@docCategory Point}\n */\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport interface Point {\n left?: number;\n top?: number;\n /** @deprecated Use `left` instead */\n x?: number;\n /** @deprecated Use `top` instead */\n y?: number;\n}\n\n/**\n * Point interface.\n *\n * @public\n * @deprecated Use `Point` instead.\n * {@docCategory Point}\n */\nexport interface IPoint extends Point {}\n"]}
+6
View File
@@ -0,0 +1,6 @@
import * as React from 'react';
export interface IReactProps<T> {
children?: React.ReactNode | undefined;
key?: React.Key | undefined;
ref?: React.Ref<T> | undefined;
}
+5
View File
@@ -0,0 +1,5 @@
define(["require", "exports"], function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
});
//# sourceMappingURL=React.types.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"React.types.js","sourceRoot":"../src/","sources":["React.types.ts"],"names":[],"mappings":"","sourcesContent":["import * as React from 'react';\n\n// Mirror of the removed interface React.Props<T> since React 18\nexport interface IReactProps<T> {\n children?: React.ReactNode | undefined;\n key?: React.Key | undefined;\n ref?: React.Ref<T> | undefined;\n}\n"]}
+25
View File
@@ -0,0 +1,25 @@
/**
* Rectangle helper class.
*
* @public
* {@docCategory Rectangle}
*/
export declare class Rectangle {
top: number;
bottom: number;
left: number;
right: number;
constructor(left?: number, right?: number, top?: number, bottom?: number);
/**
* Calculated automatically by subtracting the right from left
*/
get width(): number;
/**
* Calculated automatically by subtracting the bottom from top.
*/
get height(): number;
/**
* Tests if another rect is approximately equal to this rect (within 4 decimal places.)
*/
equals(rect: Rectangle): boolean;
}
+57
View File
@@ -0,0 +1,57 @@
define(["require", "exports"], function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Rectangle = void 0;
/**
* Rectangle helper class.
*
* @public
* {@docCategory Rectangle}
*/
var Rectangle = /** @class */ (function () {
function Rectangle(left, right, top, bottom) {
if (left === void 0) { left = 0; }
if (right === void 0) { right = 0; }
if (top === void 0) { top = 0; }
if (bottom === void 0) { bottom = 0; }
this.top = top;
this.bottom = bottom;
this.left = left;
this.right = right;
}
Object.defineProperty(Rectangle.prototype, "width", {
/**
* Calculated automatically by subtracting the right from left
*/
get: function () {
return this.right - this.left;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Rectangle.prototype, "height", {
/**
* Calculated automatically by subtracting the bottom from top.
*/
get: function () {
return this.bottom - this.top;
},
enumerable: false,
configurable: true
});
/**
* Tests if another rect is approximately equal to this rect (within 4 decimal places.)
*/
Rectangle.prototype.equals = function (rect) {
// Fixing to 4 decimal places because it allows enough precision and will handle cases when something
// should be rounded, like .999999 should round to 1.
return (parseFloat(this.top.toFixed(4)) === parseFloat(rect.top.toFixed(4)) &&
parseFloat(this.bottom.toFixed(4)) === parseFloat(rect.bottom.toFixed(4)) &&
parseFloat(this.left.toFixed(4)) === parseFloat(rect.left.toFixed(4)) &&
parseFloat(this.right.toFixed(4)) === parseFloat(rect.right.toFixed(4)));
};
return Rectangle;
}());
exports.Rectangle = Rectangle;
});
//# sourceMappingURL=Rectangle.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"Rectangle.js","sourceRoot":"../src/","sources":["Rectangle.ts"],"names":[],"mappings":";;;;IAAA;;;;;OAKG;IACH;QAME,mBAAY,IAAgB,EAAE,KAAiB,EAAE,GAAe,EAAE,MAAkB;YAAxE,qBAAA,EAAA,QAAgB;YAAE,sBAAA,EAAA,SAAiB;YAAE,oBAAA,EAAA,OAAe;YAAE,uBAAA,EAAA,UAAkB;YAClF,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;YACf,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;YACrB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;YACjB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACrB,CAAC;QAKD,sBAAW,4BAAK;YAHhB;;eAEG;iBACH;gBACE,OAAO,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC;YAChC,CAAC;;;WAAA;QAKD,sBAAW,6BAAM;YAHjB;;eAEG;iBACH;gBACE,OAAO,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC;YAChC,CAAC;;;WAAA;QAED;;WAEG;QACI,0BAAM,GAAb,UAAc,IAAe;YAC3B,qGAAqG;YACrG,qDAAqD;YACrD,OAAO,CACL,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;gBACnE,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;gBACzE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;gBACrE,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CACxE,CAAC;QACJ,CAAC;QACH,gBAAC;IAAD,CAAC,AAxCD,IAwCC;IAxCY,8BAAS","sourcesContent":["/**\n * Rectangle helper class.\n *\n * @public\n * {@docCategory Rectangle}\n */\nexport class Rectangle {\n public top: number;\n public bottom: number;\n public left: number;\n public right: number;\n\n constructor(left: number = 0, right: number = 0, top: number = 0, bottom: number = 0) {\n this.top = top;\n this.bottom = bottom;\n this.left = left;\n this.right = right;\n }\n\n /**\n * Calculated automatically by subtracting the right from left\n */\n public get width(): number {\n return this.right - this.left;\n }\n\n /**\n * Calculated automatically by subtracting the bottom from top.\n */\n public get height(): number {\n return this.bottom - this.top;\n }\n\n /**\n * Tests if another rect is approximately equal to this rect (within 4 decimal places.)\n */\n public equals(rect: Rectangle): boolean {\n // Fixing to 4 decimal places because it allows enough precision and will handle cases when something\n // should be rounded, like .999999 should round to 1.\n return (\n parseFloat(this.top.toFixed(4)) === parseFloat(rect.top.toFixed(4)) &&\n parseFloat(this.bottom.toFixed(4)) === parseFloat(rect.bottom.toFixed(4)) &&\n parseFloat(this.left.toFixed(4)) === parseFloat(rect.left.toFixed(4)) &&\n parseFloat(this.right.toFixed(4)) === parseFloat(rect.right.toFixed(4))\n );\n }\n}\n"]}
+5
View File
@@ -0,0 +1,5 @@
/**
* Returns a single function which will call each of the given functions in the context of the
* parent.
*/
export declare function appendFunction(parent: any, ...functions: any[]): () => void;
+27
View File
@@ -0,0 +1,27 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
define(["require", "exports"], function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.appendFunction = appendFunction;
/**
* Returns a single function which will call each of the given functions in the context of the
* parent.
*/
function appendFunction(parent) {
var functions = [];
for (var _i = 1; _i < arguments.length; _i++) {
functions[_i - 1] = arguments[_i];
}
if (functions.length < 2) {
return functions[0];
}
return function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
functions.forEach(function (f) { return f && f.apply(parent, args); });
};
}
});
//# sourceMappingURL=appendFunction.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"appendFunction.js","sourceRoot":"../src/","sources":["appendFunction.ts"],"names":[],"mappings":"AAAA,uDAAuD;;;;IAMvD,wCAQC;IAZD;;;OAGG;IACH,SAAgB,cAAc,CAAC,MAAW;QAAE,mBAAmB;aAAnB,UAAmB,EAAnB,qBAAmB,EAAnB,IAAmB;YAAnB,kCAAmB;;QAC7D,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzB,OAAO,SAAS,CAAC,CAAC,CAAe,CAAC;QACpC,CAAC;QAED,OAAO;YAAC,cAAc;iBAAd,UAAc,EAAd,qBAAc,EAAd,IAAc;gBAAd,yBAAc;;YACpB,SAAS,CAAC,OAAO,CAAC,UAAC,CAAa,IAAK,OAAA,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,EAA1B,CAA0B,CAAC,CAAC;QACnE,CAAC,CAAC;IACJ,CAAC","sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\n\n/**\n * Returns a single function which will call each of the given functions in the context of the\n * parent.\n */\nexport function appendFunction(parent: any, ...functions: any[]): () => void {\n if (functions.length < 2) {\n return functions[0] as () => void;\n }\n\n return (...args: any[]): void => {\n functions.forEach((f: () => void) => f && f.apply(parent, args));\n };\n}\n"]}
+1
View File
@@ -0,0 +1 @@
export {};
+41
View File
@@ -0,0 +1,41 @@
define(["require", "exports", "./appendFunction"], function (require, exports, appendFunction_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
describe('appendFunction', function () {
it('can append 2 functions', function () {
var counter = 0;
var function1 = function () { return counter++; };
var function2 = function () { return counter++; };
var function3 = (0, appendFunction_1.appendFunction)({}, function1, function2);
function3();
expect(counter).toEqual(2);
});
it('can deal with falsey values', function () {
var counter = 0;
var function1 = function () { return counter++; };
var function2 = function () { return counter++; };
var function3 = (0, appendFunction_1.appendFunction)({}, function1, undefined, null, function2);
function3();
expect(counter).toEqual(2);
});
it('preserves the parent', function () {
function add() {
this.counter++;
}
var Foo = /** @class */ (function () {
function Foo() {
this.counter = 0;
this.add = (0, appendFunction_1.appendFunction)(this, add, this.add);
}
Foo.prototype.add = function () {
this.counter++;
};
return Foo;
}());
var foo = new Foo();
foo.add();
expect(foo.counter).toEqual(2);
});
});
});
//# sourceMappingURL=appendFunction.test.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"appendFunction.test.js","sourceRoot":"../src/","sources":["appendFunction.test.ts"],"names":[],"mappings":";;;IAEA,QAAQ,CAAC,gBAAgB,EAAE;QACzB,EAAE,CAAC,wBAAwB,EAAE;YAC3B,IAAI,OAAO,GAAG,CAAC,CAAC;YAChB,IAAM,SAAS,GAAG,cAAM,OAAA,OAAO,EAAE,EAAT,CAAS,CAAC;YAClC,IAAM,SAAS,GAAG,cAAM,OAAA,OAAO,EAAE,EAAT,CAAS,CAAC;YAClC,IAAM,SAAS,GAAG,IAAA,+BAAc,EAAC,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;YAE3D,SAAS,EAAE,CAAC;YACZ,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6BAA6B,EAAE;YAChC,IAAI,OAAO,GAAG,CAAC,CAAC;YAChB,IAAM,SAAS,GAAG,cAAM,OAAA,OAAO,EAAE,EAAT,CAAS,CAAC;YAClC,IAAM,SAAS,GAAG,cAAM,OAAA,OAAO,EAAE,EAAT,CAAS,CAAC;YAClC,IAAM,SAAS,GAAG,IAAA,+BAAc,EAAC,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;YAE5E,SAAS,EAAE,CAAC;YACZ,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sBAAsB,EAAE;YACzB,SAAS,GAAG;gBACV,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,CAAC;YAED;gBAGE;oBAFO,YAAO,GAAG,CAAC,CAAC;oBAGjB,IAAI,CAAC,GAAG,GAAG,IAAA,+BAAc,EAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;gBACjD,CAAC;gBACM,iBAAG,GAAV;oBACE,IAAI,CAAC,OAAO,EAAE,CAAC;gBACjB,CAAC;gBACH,UAAC;YAAD,CAAC,AATD,IASC;YAED,IAAM,GAAG,GAAG,IAAI,GAAG,EAAE,CAAC;YACtB,GAAG,CAAC,GAAG,EAAE,CAAC;YAEV,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC","sourcesContent":["import { appendFunction } from './appendFunction';\n\ndescribe('appendFunction', () => {\n it('can append 2 functions', () => {\n let counter = 0;\n const function1 = () => counter++;\n const function2 = () => counter++;\n const function3 = appendFunction({}, function1, function2);\n\n function3();\n expect(counter).toEqual(2);\n });\n\n it('can deal with falsey values', () => {\n let counter = 0;\n const function1 = () => counter++;\n const function2 = () => counter++;\n const function3 = appendFunction({}, function1, undefined, null, function2);\n\n function3();\n expect(counter).toEqual(2);\n });\n\n it('preserves the parent', () => {\n function add(this: { counter: number }): void {\n this.counter++;\n }\n\n class Foo {\n public counter = 0;\n\n constructor() {\n this.add = appendFunction(this, add, this.add);\n }\n public add(): void {\n this.counter++;\n }\n }\n\n const foo = new Foo();\n foo.add();\n\n expect(foo.counter).toEqual(2);\n });\n});\n"]}
+7
View File
@@ -0,0 +1,7 @@
/**
* ARIA helper to concatenate attributes, returning undefined if all attributes
* are undefined. (Empty strings are not a valid ARIA attribute value.)
*
* @param ariaAttributes - ARIA attributes to merge
*/
export declare function mergeAriaAttributeValues(...ariaAttributes: (string | undefined | false)[]): string | undefined;
+23
View File
@@ -0,0 +1,23 @@
define(["require", "exports"], function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.mergeAriaAttributeValues = mergeAriaAttributeValues;
/**
* ARIA helper to concatenate attributes, returning undefined if all attributes
* are undefined. (Empty strings are not a valid ARIA attribute value.)
*
* @param ariaAttributes - ARIA attributes to merge
*/
function mergeAriaAttributeValues() {
var ariaAttributes = [];
for (var _i = 0; _i < arguments.length; _i++) {
ariaAttributes[_i] = arguments[_i];
}
var mergedAttribute = ariaAttributes
.filter(function (arg) { return arg; })
.join(' ')
.trim();
return mergedAttribute === '' ? undefined : mergedAttribute;
}
});
//# sourceMappingURL=aria.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"aria.js","sourceRoot":"../src/","sources":["aria.ts"],"names":[],"mappings":";;;IAMA,4DAMC;IAZD;;;;;OAKG;IACH,SAAgB,wBAAwB;QAAC,wBAAiD;aAAjD,UAAiD,EAAjD,qBAAiD,EAAjD,IAAiD;YAAjD,mCAAiD;;QACxF,IAAM,eAAe,GAAG,cAAc;aACnC,MAAM,CAAC,UAAC,GAA+B,IAAK,OAAA,GAAG,EAAH,CAAG,CAAC;aAChD,IAAI,CAAC,GAAG,CAAC;aACT,IAAI,EAAE,CAAC;QACV,OAAO,eAAe,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC;IAC9D,CAAC","sourcesContent":["/**\n * ARIA helper to concatenate attributes, returning undefined if all attributes\n * are undefined. (Empty strings are not a valid ARIA attribute value.)\n *\n * @param ariaAttributes - ARIA attributes to merge\n */\nexport function mergeAriaAttributeValues(...ariaAttributes: (string | undefined | false)[]): string | undefined {\n const mergedAttribute = ariaAttributes\n .filter((arg: string | undefined | false) => arg)\n .join(' ')\n .trim();\n return mergedAttribute === '' ? undefined : mergedAttribute;\n}\n"]}
+1
View File
@@ -0,0 +1 @@
export {};
+103
View File
@@ -0,0 +1,103 @@
define(["require", "exports", "./aria"], function (require, exports, aria_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
describe('aria utils tests', function () {
describe('mergeAriaAttributeValues tests', function () {
var mergeTestCases = [
{
description: 'returns undefined when given no args',
cases: [
{
args: [],
expected: undefined,
},
],
},
{
description: 'returns undefined when given undefined and empty args',
cases: [
{
args: [undefined],
expected: undefined,
},
{
args: [undefined, undefined],
expected: undefined,
},
{
args: [''],
expected: undefined,
},
{
args: [undefined, ''],
expected: undefined,
},
],
},
{
description: 'returns arg when given one valid arg',
cases: [
{
args: ['arg1'],
expected: 'arg1',
},
{
args: ['arg1', undefined],
expected: 'arg1',
},
{
args: [undefined, 'arg1', undefined],
expected: 'arg1',
},
{
args: ['', 'arg1', ''],
expected: 'arg1',
},
],
},
{
description: 'returns merged args when given multiple valid args',
cases: [
{
args: ['arg1', 'arg2'],
expected: 'arg1 arg2',
},
{
args: ['arg1', undefined],
expected: 'arg1',
},
{
args: [undefined, 'arg1', undefined],
expected: 'arg1',
},
{
args: ['', 'arg1', ''],
expected: 'arg1',
},
{
args: ['', 'arg1', 'arg2 '],
expected: 'arg1 arg2',
},
{
args: ['', ''],
expected: undefined,
},
{
args: [' ', ' '],
expected: undefined,
},
],
},
];
mergeTestCases.forEach(function (test) {
test.cases.forEach(function (testCase, index) {
it(test.description + ', case #' + index, function () {
var merged = aria_1.mergeAriaAttributeValues.apply(void 0, testCase.args);
expect(merged).toEqual(testCase.expected);
});
});
});
});
});
});
//# sourceMappingURL=aria.test.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"aria.test.js","sourceRoot":"../src/","sources":["aria.test.ts"],"names":[],"mappings":";;;IAYA,QAAQ,CAAC,kBAAkB,EAAE;QAC3B,QAAQ,CAAC,gCAAgC,EAAE;YACzC,IAAM,cAAc,GAAiB;gBACnC;oBACE,WAAW,EAAE,sCAAsC;oBACnD,KAAK,EAAE;wBACL;4BACE,IAAI,EAAE,EAAE;4BACR,QAAQ,EAAE,SAAS;yBACpB;qBACF;iBACF;gBACD;oBACE,WAAW,EAAE,uDAAuD;oBACpE,KAAK,EAAE;wBACL;4BACE,IAAI,EAAE,CAAC,SAAS,CAAC;4BACjB,QAAQ,EAAE,SAAS;yBACpB;wBACD;4BACE,IAAI,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC;4BAC5B,QAAQ,EAAE,SAAS;yBACpB;wBACD;4BACE,IAAI,EAAE,CAAC,EAAE,CAAC;4BACV,QAAQ,EAAE,SAAS;yBACpB;wBACD;4BACE,IAAI,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC;4BACrB,QAAQ,EAAE,SAAS;yBACpB;qBACF;iBACF;gBACD;oBACE,WAAW,EAAE,sCAAsC;oBACnD,KAAK,EAAE;wBACL;4BACE,IAAI,EAAE,CAAC,MAAM,CAAC;4BACd,QAAQ,EAAE,MAAM;yBACjB;wBACD;4BACE,IAAI,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC;4BACzB,QAAQ,EAAE,MAAM;yBACjB;wBACD;4BACE,IAAI,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,CAAC;4BACpC,QAAQ,EAAE,MAAM;yBACjB;wBACD;4BACE,IAAI,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC;4BACtB,QAAQ,EAAE,MAAM;yBACjB;qBACF;iBACF;gBACD;oBACE,WAAW,EAAE,oDAAoD;oBACjE,KAAK,EAAE;wBACL;4BACE,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC;4BACtB,QAAQ,EAAE,WAAW;yBACtB;wBACD;4BACE,IAAI,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC;4BACzB,QAAQ,EAAE,MAAM;yBACjB;wBACD;4BACE,IAAI,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,CAAC;4BACpC,QAAQ,EAAE,MAAM;yBACjB;wBACD;4BACE,IAAI,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC;4BACtB,QAAQ,EAAE,MAAM;yBACjB;wBACD;4BACE,IAAI,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC;4BAC3B,QAAQ,EAAE,WAAW;yBACtB;wBACD;4BACE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC;4BACd,QAAQ,EAAE,SAAS;yBACpB;wBACD;4BACE,IAAI,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC;4BAChB,QAAQ,EAAE,SAAS;yBACpB;qBACF;iBACF;aACF,CAAC;YAEF,cAAc,CAAC,OAAO,CAAC,UAAC,IAAgB;gBACtC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAC,QAAwB,EAAE,KAAa;oBACzD,EAAE,CAAC,IAAI,CAAC,WAAW,GAAG,UAAU,GAAG,KAAK,EAAE;wBACxC,IAAM,MAAM,GAAG,+BAAwB,eAAI,QAAQ,CAAC,IAAI,CAAC,CAAC;wBAC1D,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;oBAC5C,CAAC,CAAC,CAAC;gBACL,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC","sourcesContent":["import { mergeAriaAttributeValues } from './aria';\n\ninterface IMergeTestCase {\n args: (string | undefined)[];\n expected: string | undefined;\n}\n\ninterface IMergeTest {\n description: string;\n cases: IMergeTestCase[];\n}\n\ndescribe('aria utils tests', () => {\n describe('mergeAriaAttributeValues tests', () => {\n const mergeTestCases: IMergeTest[] = [\n {\n description: 'returns undefined when given no args',\n cases: [\n {\n args: [],\n expected: undefined,\n },\n ],\n },\n {\n description: 'returns undefined when given undefined and empty args',\n cases: [\n {\n args: [undefined],\n expected: undefined,\n },\n {\n args: [undefined, undefined],\n expected: undefined,\n },\n {\n args: [''],\n expected: undefined,\n },\n {\n args: [undefined, ''],\n expected: undefined,\n },\n ],\n },\n {\n description: 'returns arg when given one valid arg',\n cases: [\n {\n args: ['arg1'],\n expected: 'arg1',\n },\n {\n args: ['arg1', undefined],\n expected: 'arg1',\n },\n {\n args: [undefined, 'arg1', undefined],\n expected: 'arg1',\n },\n {\n args: ['', 'arg1', ''],\n expected: 'arg1',\n },\n ],\n },\n {\n description: 'returns merged args when given multiple valid args',\n cases: [\n {\n args: ['arg1', 'arg2'],\n expected: 'arg1 arg2',\n },\n {\n args: ['arg1', undefined],\n expected: 'arg1',\n },\n {\n args: [undefined, 'arg1', undefined],\n expected: 'arg1',\n },\n {\n args: ['', 'arg1', ''],\n expected: 'arg1',\n },\n {\n args: ['', 'arg1', 'arg2 '],\n expected: 'arg1 arg2',\n },\n {\n args: ['', ''],\n expected: undefined,\n },\n {\n args: [' ', ' '],\n expected: undefined,\n },\n ],\n },\n ];\n\n mergeTestCases.forEach((test: IMergeTest) => {\n test.cases.forEach((testCase: IMergeTestCase, index: number) => {\n it(test.description + ', case #' + index, () => {\n const merged = mergeAriaAttributeValues(...testCase.args);\n expect(merged).toEqual(testCase.expected);\n });\n });\n });\n });\n});\n"]}
+67
View File
@@ -0,0 +1,67 @@
/**
* Helper to find the index of an item within an array, using a callback to
* determine the match.
*
* @public
* @param array - Array to search.
* @param cb - Callback which returns true on matches.
* @param fromIndex - Optional index to start from (defaults to 0)
*/
export declare function findIndex<T>(array: T[], cb: (item: T, index: number) => boolean, fromIndex?: number): number;
/**
* Helper to find the first item within an array that satisfies the callback.
* @param array - Array to search
* @param cb - Callback which returns true on matches
*/
export declare function find<T>(array: T[], cb: (item: T, index: number) => boolean): T | undefined;
/**
* Creates an array of a given size and helper method to populate.
*
* @public
* @param size - Size of array.
* @param getItem - Callback to populate given cell index.
*/
export declare function createArray<T>(size: number, getItem: (index: number) => T): T[];
/**
* Convert the given array to a matrix with columnCount number
* of columns.
*
* @public
* @param items - The array to convert
* @param columnCount - The number of columns for the resulting matrix
* @returns A matrix of items
*/
export declare function toMatrix<T>(items: T[], columnCount: number): T[][];
/**
* Given an array, it returns a new array that does not contain the item at the given index.
* @param array - The array to operate on
* @param index - The index of the element to remove
*/
export declare function removeIndex<T>(array: T[], index: number): T[];
/**
* Given an array, this function returns a new array where the element at a given index has been replaced.
* @param array - The array to operate on
* @param newElement - The element that will be placed in the new array
* @param index - The index of the element that should be replaced
*/
export declare function replaceElement<T>(array: T[], newElement: T, index: number): T[];
/**
* Given an array, this function returns a new array where an element has been inserted at the given index.
* @param array - The array to operate on
* @param index - The index where an element should be inserted
* @param itemToAdd - The element to insert
*/
export declare function addElementAtIndex<T>(array: T[], index: number, itemToAdd: T): T[];
/**
* Given an array where each element is of type T or T[], flatten it into an array of T
* @param array - The array where each element can optionally also be an array
*/
export declare function flatten<T>(array: (T | T[])[]): T[];
/**
* Returns a boolean indicating if the two given arrays are equal in length and values.
*
* @param array1 - First array to compare
* @param array2 - Second array to compare
* @returns True if the arrays are the same length and have the same values in the same positions, false otherwise.
*/
export declare function arraysEqual<T>(array1: T[], array2: T[]): boolean;
+137
View File
@@ -0,0 +1,137 @@
define(["require", "exports"], function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.findIndex = findIndex;
exports.find = find;
exports.createArray = createArray;
exports.toMatrix = toMatrix;
exports.removeIndex = removeIndex;
exports.replaceElement = replaceElement;
exports.addElementAtIndex = addElementAtIndex;
exports.flatten = flatten;
exports.arraysEqual = arraysEqual;
/**
* Helper to find the index of an item within an array, using a callback to
* determine the match.
*
* @public
* @param array - Array to search.
* @param cb - Callback which returns true on matches.
* @param fromIndex - Optional index to start from (defaults to 0)
*/
function findIndex(array, cb, fromIndex) {
if (fromIndex === void 0) { fromIndex = 0; }
var index = -1;
for (var i = fromIndex; array && i < array.length; i++) {
if (cb(array[i], i)) {
index = i;
break;
}
}
return index;
}
/**
* Helper to find the first item within an array that satisfies the callback.
* @param array - Array to search
* @param cb - Callback which returns true on matches
*/
function find(array, cb) {
var index = findIndex(array, cb);
if (index < 0) {
return undefined;
}
return array[index];
}
/**
* Creates an array of a given size and helper method to populate.
*
* @public
* @param size - Size of array.
* @param getItem - Callback to populate given cell index.
*/
function createArray(size, getItem) {
var array = [];
for (var i = 0; i < size; i++) {
array.push(getItem(i));
}
return array;
}
/**
* Convert the given array to a matrix with columnCount number
* of columns.
*
* @public
* @param items - The array to convert
* @param columnCount - The number of columns for the resulting matrix
* @returns A matrix of items
*/
function toMatrix(items, columnCount) {
return items.reduce(function (rows, currentValue, index) {
if (index % columnCount === 0) {
rows.push([currentValue]);
}
else {
rows[rows.length - 1].push(currentValue);
}
return rows;
}, []);
}
/**
* Given an array, it returns a new array that does not contain the item at the given index.
* @param array - The array to operate on
* @param index - The index of the element to remove
*/
function removeIndex(array, index) {
return array.filter(function (_, i) { return index !== i; });
}
/**
* Given an array, this function returns a new array where the element at a given index has been replaced.
* @param array - The array to operate on
* @param newElement - The element that will be placed in the new array
* @param index - The index of the element that should be replaced
*/
function replaceElement(array, newElement, index) {
var copy = array.slice();
copy[index] = newElement;
return copy;
}
/**
* Given an array, this function returns a new array where an element has been inserted at the given index.
* @param array - The array to operate on
* @param index - The index where an element should be inserted
* @param itemToAdd - The element to insert
*/
function addElementAtIndex(array, index, itemToAdd) {
var copy = array.slice();
copy.splice(index, 0, itemToAdd);
return copy;
}
/**
* Given an array where each element is of type T or T[], flatten it into an array of T
* @param array - The array where each element can optionally also be an array
*/
function flatten(array) {
var result = [];
array.forEach(function (item) { return (result = result.concat(item)); });
return result;
}
/**
* Returns a boolean indicating if the two given arrays are equal in length and values.
*
* @param array1 - First array to compare
* @param array2 - Second array to compare
* @returns True if the arrays are the same length and have the same values in the same positions, false otherwise.
*/
function arraysEqual(array1, array2) {
if (array1.length !== array2.length) {
return false;
}
for (var i = 0; i < array1.length; i++) {
if (array1[i] !== array2[i]) {
return false;
}
}
return true;
}
});
//# sourceMappingURL=array.js.map
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
export {};
+158
View File
@@ -0,0 +1,158 @@
define(["require", "exports", "./array"], function (require, exports, array_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
describe('array utils tests', function () {
describe('findIndex tests', function () {
it('returns -1 when there is no match in the array', function () {
var array = [0, 1, 2];
var index = (0, array_1.findIndex)(array, function () { return false; });
expect(index).toEqual(-1);
});
it('should return the correct index when the predicate satisfies the condition', function () {
var array = [0, 1, 2];
var index = (0, array_1.findIndex)(array, function (elem) { return elem === 1; });
expect(index).toEqual(1);
});
it('should return the first index when repeated elements satisfy the predicate', function () {
var array = [0, 1, 2, 2];
var index = (0, array_1.findIndex)(array, function (elem) { return elem === 2; });
expect(index).toEqual(2);
});
});
describe('find tests', function () {
it('returns -1 when there is no match in the array', function () {
var array = [0, 1, 2];
var item = (0, array_1.find)(array, function () { return false; });
expect(item).toEqual(undefined);
});
it('should return the correct item when the predicate satisfies the condition', function () {
var array = [{ id: 0 }, { id: 1 }, { id: 2 }, { id: 3 }];
var item = (0, array_1.find)(array, function (elem) { return elem.id === 1; });
expect(item).toEqual(array[1]);
});
it('should return the first index when repeated elements satisfy the predicate', function () {
var array = [8, 9, 10, 11];
var item = (0, array_1.find)(array, function (elem) { return elem === 10; });
expect(item).toEqual(10);
});
});
describe('createArray tests', function () {
it('creates an array while invoking the callback', function () {
var result = (0, array_1.createArray)(4, function (index) { return String.fromCharCode('a'.charCodeAt(0) + index); });
expect(result).toEqual(['a', 'b', 'c', 'd']);
});
});
describe('removeIndex tests', function () {
it('should return a new array instead of mutating the existing array', function () {
var array = [0, 1, 2];
var result = (0, array_1.removeIndex)(array, 0);
expect(result).not.toBe(array);
});
it('should remove the first element of the array', function () {
var array = [0, 1, 2];
var result = (0, array_1.removeIndex)(array, 0);
expect(result).toEqual([1, 2]);
});
it('should remove the last element of the array', function () {
var array = [0, 1, 2];
var result = (0, array_1.removeIndex)(array, 2);
expect(result).toEqual([0, 1]);
});
it('should remove the element in the middle of the array', function () {
var array = [0, 1, 2];
var result = (0, array_1.removeIndex)(array, 1);
expect(result).toEqual([0, 2]);
});
});
describe('replaceElement tests', function () {
it('should return a new array instead of mutating the existing array', function () {
var array = [1, 2, 3];
var result = (0, array_1.replaceElement)(array, 3, 1);
expect(result).toEqual([1, 3, 3]);
expect(result).not.toBe(array);
});
it('should return a new array with the replaced element in the center', function () {
var array = ['Zero', 'One', 'Two', 'Three', 'Four'];
var result = (0, array_1.replaceElement)(array, 'owT', 2);
expect(result).toEqual(['Zero', 'One', 'owT', 'Three', 'Four']);
});
it('should return a new array with the first element replaced', function () {
var array = ['Zero', 'One', 'Two', 'Three', 'Four'];
var result = (0, array_1.replaceElement)(array, 'oreZ', 0);
expect(result).toEqual(['oreZ', 'One', 'Two', 'Three', 'Four']);
});
it('should return a new array with the last element replaced', function () {
var array = ['Zero', 'One', 'Two', 'Three', 'Four'];
var result = (0, array_1.replaceElement)(array, 'ruoF', 4);
expect(result).toEqual(['Zero', 'One', 'Two', 'Three', 'ruoF']);
});
});
describe('addElementAddIndex tests', function () {
it('should add an element at the start of the array', function () {
var array = [2, 3, 4];
var result = (0, array_1.addElementAtIndex)(array, 0, 1);
expect(result).toEqual([1, 2, 3, 4]);
});
it('should add an element at the end of the array', function () {
var array = [2, 3, 4];
var result = (0, array_1.addElementAtIndex)(array, 3, 5);
expect(result).toEqual([2, 3, 4, 5]);
});
it('should add the element in the middle of the array', function () {
var array = [2, 3, 4];
var result = (0, array_1.addElementAtIndex)(array, 2, 3.5);
expect(result).toEqual([2, 3, 3.5, 4]);
});
});
describe('flatten tests', function () {
it('does nothing for an empty array', function () {
var array = [];
var result = (0, array_1.flatten)(array);
expect(result).toEqual(array);
});
it('does nothing an array with a single element', function () {
var array = [1];
var result = (0, array_1.flatten)(array);
expect(result).toEqual(array);
});
it('does nothing for an array of numbers', function () {
var array = [1, 2, 3];
var result = (0, array_1.flatten)(array);
expect(result).toEqual(array);
});
it('flattens an array of arrays', function () {
var array = [[1, 2, 3], [4, 6, 8], [20]];
var result = (0, array_1.flatten)(array);
expect(result).toEqual([1, 2, 3, 4, 6, 8, 20]);
});
it('flattens an array with numbers and arrays of numbers', function () {
var array = [[1, 2, 3], [4, 6, 8], 20, 22, [25, 26, 28]];
var result = (0, array_1.flatten)(array);
expect(result).toEqual([1, 2, 3, 4, 6, 8, 20, 22, 25, 26, 28]);
});
});
describe('arraysEqual tests', function () {
it('two empty arrays are equal', function () {
var arr1 = [];
var arr2 = [];
expect((0, array_1.arraysEqual)(arr1, arr2)).toEqual(true);
});
it('different length arrays are not equal', function () {
var arr1 = [1, 2];
var arr2 = [1];
expect((0, array_1.arraysEqual)(arr1, arr2)).toEqual(false);
});
it('different value arrays are not equal', function () {
var arr1 = [1, 2];
var arr2 = [1, 3];
expect((0, array_1.arraysEqual)(arr1, arr2)).toEqual(false);
});
it('two exact arrays are equal', function () {
var arr1 = [1, 2, 3];
var arr2 = [1, 2, 3];
expect((0, array_1.arraysEqual)(arr1, arr2)).toEqual(true);
});
});
});
});
//# sourceMappingURL=array.test.js.map
File diff suppressed because one or more lines are too long
+38
View File
@@ -0,0 +1,38 @@
/**
* asAsync - a HOC for async loading components.
*
* Usage:
*
* const AsyncDialog = asAsync({
* load: () => import('Dialog').then(result => result.default),
* });
*
* React.render(domElement, <AsyncDialog asyncPlaceholder={ () => <Spinner/> } { ...dialogProps } />);
*
* Note the `asyncPlaceholder` prop will be respected when rendering the async component and it hasn't
* been loaded yet.
*/
import * as React from 'react';
export interface IAsAsyncOptions<TProps> {
/**
* Callback which returns a promise resolving an object which exports the component.
*/
load: () => Promise<React.ElementType<TProps>>;
/**
* Callback executed when async loading is complete.
*/
onLoad?: () => void;
/**
* Callback when async loading fails.
*/
onError?: (error: Error) => void;
}
/**
* Produces a component which internally loads the target component before first mount.
* The component passes all props through to the loaded component.
*
* This overload accepts a module with a default export for the component.
*/
export declare function asAsync<TProps extends {}>(options: IAsAsyncOptions<TProps>): React.ForwardRefExoticComponent<React.PropsWithoutRef<TProps & {
asyncPlaceholder?: React.ElementType | undefined;
}> & React.RefAttributes<React.ElementType<TProps>>>;
+75
View File
@@ -0,0 +1,75 @@
/**
* asAsync - a HOC for async loading components.
*
* Usage:
*
* const AsyncDialog = asAsync({
* load: () => import('Dialog').then(result => result.default),
* });
*
* React.render(domElement, <AsyncDialog asyncPlaceholder={ () => <Spinner/> } { ...dialogProps } />);
*
* Note the `asyncPlaceholder` prop will be respected when rendering the async component and it hasn't
* been loaded yet.
*/
define(["require", "exports", "tslib", "react"], function (require, exports, tslib_1, React) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.asAsync = asAsync;
/**
* If possible, use a WeakMap to maintain a cache of loaded components.
* This can be used to synchronously render components that have already been loaded,
* rather than having to wait for at least one async tick.
*/
var _syncModuleCache = typeof WeakMap !== 'undefined'
? // eslint-disable-next-line @typescript-eslint/no-explicit-any
new WeakMap()
: undefined;
/**
* Produces a component which internally loads the target component before first mount.
* The component passes all props through to the loaded component.
*
* This overload accepts a module with a default export for the component.
*/
function asAsync(options) {
var Async = /** @class */ (function (_super) {
tslib_1.__extends(Async, _super);
function Async() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.state = {
Component: _syncModuleCache ? _syncModuleCache.get(options.load) : undefined,
};
return _this;
}
Async.prototype.render = function () {
// Typescript issue: the rest can't be pulled without the any cast, as TypeScript fails with rest on generics.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
var _a = this.props, forwardedRef = _a.forwardedRef, Placeholder = _a.asyncPlaceholder, rest = tslib_1.__rest(_a, ["forwardedRef", "asyncPlaceholder"]);
var Component = this.state.Component;
return Component ? (React.createElement(Component, tslib_1.__assign(tslib_1.__assign({}, rest), { ref: forwardedRef }))) : Placeholder ? (React.createElement(Placeholder, null)) : null;
};
Async.prototype.componentDidMount = function () {
var _this = this;
var Component = this.state.Component;
if (!Component) {
options
.load()
.then(function (LoadedComponent) {
if (LoadedComponent) {
// Cache component for future reference.
_syncModuleCache && _syncModuleCache.set(options.load, LoadedComponent);
// Set state.
_this.setState({
Component: LoadedComponent,
}, options.onLoad);
}
})
.catch(options.onError);
}
};
return Async;
}(React.Component));
return React.forwardRef(function (props, ref) { return React.createElement(Async, tslib_1.__assign({}, props, { forwardedRef: ref })); });
}
});
//# sourceMappingURL=asAsync.js.map
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
export {};
+98
View File
@@ -0,0 +1,98 @@
define(["require", "exports", "tslib", "react", "./asAsync", "@testing-library/react"], function (require, exports, tslib_1, React, asAsync_1, react_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
describe('asAsync', function () {
it('can async load exports', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
var _resolve, _loadCalled, loadThingPromise, AsyncThing, _a, container, unmount;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
_resolve = function () { return undefined; };
_loadCalled = false;
loadThingPromise = new Promise(function (resolve) {
_resolve = resolve;
});
AsyncThing = (0, asAsync_1.asAsync)({
load: function () {
_loadCalled = true;
return loadThingPromise;
},
});
_a = (0, react_1.render)(React.createElement(AsyncThing, null)), container = _a.container, unmount = _a.unmount;
expect(_loadCalled).toBe(true);
expect(container).toBeEmptyDOMElement();
expect(_resolve).toBeTruthy();
return [4 /*yield*/, (0, react_1.act)(function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
_resolve(function () { return React.createElement("div", null, "thing"); });
// allow microtasks to flush
return [4 /*yield*/, Promise.resolve()];
case 1:
// allow microtasks to flush
_a.sent();
return [2 /*return*/];
}
});
}); })];
case 1:
_b.sent();
return [4 /*yield*/, (0, react_1.waitFor)(function () { return expect(container.firstChild).toHaveTextContent('thing'); })];
case 2:
_b.sent();
_loadCalled = false;
// Test cached case.
(0, react_1.render)(React.createElement(AsyncThing, null));
expect(_loadCalled).toBe(false);
expect(container.firstChild).toHaveTextContent('thing');
unmount();
return [2 /*return*/];
}
});
}); });
it('can async load with placeholder', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
var _resolve, _loadCalled, loadThingPromise, AsyncThing, _a, container, unmount;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
_resolve = function () { return undefined; };
_loadCalled = false;
loadThingPromise = new Promise(function (resolve) {
_resolve = resolve;
});
AsyncThing = (0, asAsync_1.asAsync)({
load: function () {
_loadCalled = true;
return loadThingPromise;
},
});
_a = (0, react_1.render)(React.createElement(AsyncThing, { asyncPlaceholder: function () { return React.createElement("div", null, "placeholder"); } })), container = _a.container, unmount = _a.unmount;
expect(_loadCalled).toBe(true);
expect(container).toHaveTextContent('placeholder');
expect(_resolve).toBeTruthy();
return [4 /*yield*/, (0, react_1.act)(function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
_resolve(function () { return React.createElement("div", null, "thing"); });
return [4 /*yield*/, Promise.resolve()];
case 1:
_a.sent();
return [2 /*return*/];
}
});
}); })];
case 1:
_b.sent();
return [4 /*yield*/, (0, react_1.waitFor)(function () { return expect(container.firstChild).toHaveTextContent('thing'); })];
case 2:
_b.sent();
unmount();
return [2 /*return*/];
}
});
}); });
});
});
//# sourceMappingURL=asAsync.test.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"asAsync.test.js","sourceRoot":"../src/","sources":["asAsync.test.tsx"],"names":[],"mappings":";;;IAIA,QAAQ,CAAC,SAAS,EAAE;QAClB,EAAE,CAAC,wBAAwB,EAAE;;;;;wBACvB,QAAQ,GAA4C,cAAM,OAAA,SAAS,EAAT,CAAS,CAAC;wBACpE,WAAW,GAAG,KAAK,CAAC;wBAElB,gBAAgB,GAAG,IAAI,OAAO,CAAM,UAAC,OAAY;4BACrD,QAAQ,GAAG,OAAO,CAAC;wBACrB,CAAC,CAAC,CAAC;wBAEG,UAAU,GAAG,IAAA,iBAAO,EAAC;4BACzB,IAAI,EAAE;gCACJ,WAAW,GAAG,IAAI,CAAC;gCACnB,OAAO,gBAAgB,CAAC;4BAC1B,CAAC;yBACF,CAAC,CAAC;wBACG,KAAyB,IAAA,cAAM,EAAC,oBAAC,UAAU,OAAG,CAAC,EAA7C,SAAS,eAAA,EAAE,OAAO,aAAA,CAA4B;wBAEtD,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;wBAC/B,MAAM,CAAC,SAAS,CAAC,CAAC,mBAAmB,EAAE,CAAC;wBACxC,MAAM,CAAC,QAAQ,CAAC,CAAC,UAAU,EAAE,CAAC;wBAE9B,qBAAM,IAAA,WAAG,EAAC;;;;4CACR,QAAQ,CAAC,cAAM,OAAA,yCAAgB,EAAhB,CAAgB,CAAC,CAAC;4CACjC,4BAA4B;4CAC5B,qBAAM,OAAO,CAAC,OAAO,EAAE,EAAA;;4CADvB,4BAA4B;4CAC5B,SAAuB,CAAC;;;;iCACzB,CAAC,EAAA;;wBAJF,SAIE,CAAC;wBAEH,qBAAM,IAAA,eAAO,EAAC,cAAM,OAAA,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,iBAAiB,CAAC,OAAO,CAAC,EAAvD,CAAuD,CAAC,EAAA;;wBAA5E,SAA4E,CAAC;wBAC7E,WAAW,GAAG,KAAK,CAAC;wBAEpB,oBAAoB;wBACpB,IAAA,cAAM,EAAC,oBAAC,UAAU,OAAG,CAAC,CAAC;wBACvB,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;wBAChC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;wBACxD,OAAO,EAAE,CAAC;;;;aACX,CAAC,CAAC;QAEH,EAAE,CAAC,iCAAiC,EAAE;;;;;wBAChC,QAAQ,GAA4C,cAAM,OAAA,SAAS,EAAT,CAAS,CAAC;wBACpE,WAAW,GAAG,KAAK,CAAC;wBAElB,gBAAgB,GAAG,IAAI,OAAO,CAAM,UAAC,OAAY;4BACrD,QAAQ,GAAG,OAAO,CAAC;wBACrB,CAAC,CAAC,CAAC;wBAEG,UAAU,GAAG,IAAA,iBAAO,EAAC;4BACzB,IAAI,EAAE;gCACJ,WAAW,GAAG,IAAI,CAAC;gCACnB,OAAO,gBAAgB,CAAC;4BAC1B,CAAC;yBACF,CAAC,CAAC;wBACG,KAAyB,IAAA,cAAM,EAAC,oBAAC,UAAU,IAAC,gBAAgB,EAAE,cAAM,OAAA,+CAAsB,EAAtB,CAAsB,GAAI,CAAC,EAA7F,SAAS,eAAA,EAAE,OAAO,aAAA,CAA4E;wBAEtG,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;wBAC/B,MAAM,CAAC,SAAS,CAAC,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAAC;wBACnD,MAAM,CAAC,QAAQ,CAAC,CAAC,UAAU,EAAE,CAAC;wBAE9B,qBAAM,IAAA,WAAG,EAAC;;;;4CACR,QAAQ,CAAC,cAAM,OAAA,yCAAgB,EAAhB,CAAgB,CAAC,CAAC;4CACjC,qBAAM,OAAO,CAAC,OAAO,EAAE,EAAA;;4CAAvB,SAAuB,CAAC;;;;iCACzB,CAAC,EAAA;;wBAHF,SAGE,CAAC;wBAEH,qBAAM,IAAA,eAAO,EAAC,cAAM,OAAA,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,iBAAiB,CAAC,OAAO,CAAC,EAAvD,CAAuD,CAAC,EAAA;;wBAA5E,SAA4E,CAAC;wBAC7E,OAAO,EAAE,CAAC;;;;aACX,CAAC,CAAC;IACL,CAAC,CAAC,CAAC","sourcesContent":["import * as React from 'react';\nimport { asAsync } from './asAsync';\nimport { act, render, waitFor } from '@testing-library/react';\n\ndescribe('asAsync', () => {\n it('can async load exports', async () => {\n let _resolve: (result: React.ElementType<{}>) => void = () => undefined;\n let _loadCalled = false;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const loadThingPromise = new Promise<any>((resolve: any) => {\n _resolve = resolve;\n });\n\n const AsyncThing = asAsync({\n load: () => {\n _loadCalled = true;\n return loadThingPromise;\n },\n });\n const { container, unmount } = render(<AsyncThing />);\n\n expect(_loadCalled).toBe(true);\n expect(container).toBeEmptyDOMElement();\n expect(_resolve).toBeTruthy();\n\n await act(async () => {\n _resolve(() => <div>thing</div>);\n // allow microtasks to flush\n await Promise.resolve();\n });\n\n await waitFor(() => expect(container.firstChild).toHaveTextContent('thing'));\n _loadCalled = false;\n\n // Test cached case.\n render(<AsyncThing />);\n expect(_loadCalled).toBe(false);\n expect(container.firstChild).toHaveTextContent('thing');\n unmount();\n });\n\n it('can async load with placeholder', async () => {\n let _resolve: (result: React.ElementType<{}>) => void = () => undefined;\n let _loadCalled = false;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const loadThingPromise = new Promise<any>((resolve: any) => {\n _resolve = resolve;\n });\n\n const AsyncThing = asAsync({\n load: () => {\n _loadCalled = true;\n return loadThingPromise;\n },\n });\n const { container, unmount } = render(<AsyncThing asyncPlaceholder={() => <div>placeholder</div>} />);\n\n expect(_loadCalled).toBe(true);\n expect(container).toHaveTextContent('placeholder');\n expect(_resolve).toBeTruthy();\n\n await act(async () => {\n _resolve(() => <div>thing</div>);\n await Promise.resolve();\n });\n\n await waitFor(() => expect(container.firstChild).toHaveTextContent('thing'));\n unmount();\n });\n});\n"]}

Some files were not shown because too many files have changed in this diff Show More