@tylertech/forge-core 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +32 -0
  3. package/esm/a11y/a11y.js +17 -0
  4. package/esm/a11y/index.js +1 -0
  5. package/esm/constants/date-constants.js +52 -0
  6. package/esm/constants/index.js +1 -0
  7. package/esm/custom-elements/component-utils.js +262 -0
  8. package/esm/custom-elements/decorators/custom-element.js +52 -0
  9. package/esm/custom-elements/decorators/foundation-property.js +147 -0
  10. package/esm/custom-elements/decorators/index.js +2 -0
  11. package/esm/custom-elements/index.js +2 -0
  12. package/esm/events/event-aware.js +34 -0
  13. package/esm/events/index.js +1 -0
  14. package/esm/index.js +13 -0
  15. package/esm/message-list/index.js +2 -0
  16. package/esm/message-list/message-list-entry.js +10 -0
  17. package/esm/message-list/message-list.js +112 -0
  18. package/esm/scroll/index.js +2 -0
  19. package/esm/scroll/scroll-axis-observer.js +114 -0
  20. package/esm/scroll/scroll-types.js +14 -0
  21. package/esm/services/index.js +1 -0
  22. package/esm/services/service-adapter.js +12 -0
  23. package/esm/utils/a11y.js +17 -0
  24. package/esm/utils/clipboard.js +38 -0
  25. package/esm/utils/dom-utils.js +780 -0
  26. package/esm/utils/event-utils.js +30 -0
  27. package/esm/utils/http-utils.js +26 -0
  28. package/esm/utils/index.js +11 -0
  29. package/esm/utils/item-manager.js +82 -0
  30. package/esm/utils/object-utils.js +101 -0
  31. package/esm/utils/platform.js +60 -0
  32. package/esm/utils/position-utils.js +59 -0
  33. package/esm/utils/string-utils.js +12 -0
  34. package/esm/utils/utils.js +261 -0
  35. package/package.json +19 -0
  36. package/typings/a11y/a11y.d.ts +5 -0
  37. package/typings/a11y/index.d.ts +1 -0
  38. package/typings/constants/date-constants.d.ts +6 -0
  39. package/typings/constants/index.d.ts +1 -0
  40. package/typings/custom-elements/component-utils.d.ts +125 -0
  41. package/typings/custom-elements/decorators/custom-element.d.ts +21 -0
  42. package/typings/custom-elements/decorators/foundation-property.d.ts +20 -0
  43. package/typings/custom-elements/decorators/index.d.ts +2 -0
  44. package/typings/custom-elements/index.d.ts +13 -0
  45. package/typings/events/event-aware.d.ts +16 -0
  46. package/typings/events/index.d.ts +1 -0
  47. package/typings/index.d.ts +13 -0
  48. package/typings/message-list/index.d.ts +2 -0
  49. package/typings/message-list/message-list-entry.d.ts +9 -0
  50. package/typings/message-list/message-list.d.ts +54 -0
  51. package/typings/scroll/index.d.ts +2 -0
  52. package/typings/scroll/scroll-axis-observer.d.ts +44 -0
  53. package/typings/scroll/scroll-types.d.ts +28 -0
  54. package/typings/services/index.d.ts +1 -0
  55. package/typings/services/service-adapter.d.ts +25 -0
  56. package/typings/utils/a11y.d.ts +2 -0
  57. package/typings/utils/clipboard.d.ts +2 -0
  58. package/typings/utils/dom-utils.d.ts +254 -0
  59. package/typings/utils/event-utils.d.ts +10 -0
  60. package/typings/utils/http-utils.d.ts +5 -0
  61. package/typings/utils/index.d.ts +11 -0
  62. package/typings/utils/item-manager.d.ts +42 -0
  63. package/typings/utils/object-utils.d.ts +43 -0
  64. package/typings/utils/platform.d.ts +26 -0
  65. package/typings/utils/position-utils.d.ts +56 -0
  66. package/typings/utils/string-utils.d.ts +6 -0
  67. package/typings/utils/utils.d.ts +104 -0
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Gets the node path from where the event originated from.
3
+ * @param evt The event.
4
+ */
5
+ export function getEventPath(evt) {
6
+ return evt.path || (evt.composedPath && evt.composedPath()) || composedPath(evt.target);
7
+ }
8
+ /**
9
+ * Equivalent to path/composedPath.
10
+ * Note: Slots and shadow roots are detected, but aren't needed as they are virtually invisible anyway...
11
+ */
12
+ export function composedPath(el) {
13
+ const path = [];
14
+ while (el) {
15
+ if (el.shadowRoot) {
16
+ if (el.shadowRoot.activeElement) {
17
+ path.push(el.shadowRoot.activeElement);
18
+ }
19
+ path.push(el.shadowRoot);
20
+ }
21
+ path.push(el);
22
+ if (el.tagName === 'HTML') {
23
+ path.push(document);
24
+ path.push(window);
25
+ break;
26
+ }
27
+ el = el.parentElement;
28
+ }
29
+ return path;
30
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Converts a JavaScript object to a URI encoded query string.
3
+ * @param {any} obj The parameters for the query string.
4
+ */
5
+ export function createQueryString(obj) {
6
+ if (!obj || obj.length === 0) {
7
+ return null;
8
+ }
9
+ const params = [];
10
+ for (const property in obj) {
11
+ if (!obj.hasOwnProperty(property)) {
12
+ continue;
13
+ }
14
+ if (obj[property] instanceof Array) {
15
+ for (const index in obj[property]) {
16
+ if (obj[property].hasOwnProperty(index)) {
17
+ params.push(encodeURIComponent(property) + '=' + (obj[property][index] !== null && typeof obj[property][index] !== 'undefined' ? encodeURIComponent(obj[property][index]) : ''));
18
+ }
19
+ }
20
+ }
21
+ else {
22
+ params.push(encodeURIComponent(property) + '=' + (obj[property] !== null && typeof obj[property] !== 'undefined' ? encodeURIComponent(obj[property]) : ''));
23
+ }
24
+ }
25
+ return '?' + params.join('&');
26
+ }
@@ -0,0 +1,11 @@
1
+ export * from './a11y';
2
+ export * from './clipboard';
3
+ export * from './dom-utils';
4
+ export * from './event-utils';
5
+ export * from './http-utils';
6
+ export * from './item-manager';
7
+ export * from './object-utils';
8
+ export * from './platform';
9
+ export * from './position-utils';
10
+ export * from './string-utils';
11
+ export * from './utils';
@@ -0,0 +1,82 @@
1
+ import { findWhere, createPredicate } from './object-utils';
2
+ export class ItemManager {
3
+ constructor(_key) {
4
+ this._key = _key;
5
+ this._items = [];
6
+ }
7
+ /**
8
+ * Returns all items.
9
+ */
10
+ getItems() {
11
+ return [...this._items];
12
+ }
13
+ /**
14
+ * Returns the number of items.
15
+ */
16
+ count() {
17
+ return this._items.length;
18
+ }
19
+ /**
20
+ * Sets the item key.
21
+ * @param key The item key(s).
22
+ */
23
+ setKey(key) {
24
+ this._key = key;
25
+ }
26
+ /**
27
+ * Addes the provided items.
28
+ * @param data The item data.
29
+ */
30
+ add(data) {
31
+ if (!(data instanceof Array)) {
32
+ data = [data];
33
+ }
34
+ data.forEach(item => {
35
+ if (!this.exists(item)) {
36
+ this._items.push(item);
37
+ }
38
+ });
39
+ return this;
40
+ }
41
+ /**
42
+ * Removes an item from the selections.
43
+ * @param data The data to be deselected.
44
+ */
45
+ remove(data) {
46
+ if (!(data instanceof Array)) {
47
+ data = [data];
48
+ }
49
+ for (let i = data.length - 1; i >= 0; i--) {
50
+ if (this.exists(data[i])) {
51
+ this._items.splice(this._items.indexOf(this._getItem(data[i])), 1);
52
+ }
53
+ }
54
+ return this;
55
+ }
56
+ /**
57
+ * Removes all selected items.
58
+ */
59
+ clear() {
60
+ this._items = [];
61
+ return this;
62
+ }
63
+ /**
64
+ * Determines if the provided item exists in the selections or not.
65
+ * @param data The data value.
66
+ */
67
+ exists(data) {
68
+ return this._getItem(data) !== null;
69
+ }
70
+ /**
71
+ * Gets the item from the items collection, or null if not found.
72
+ * @param data The data value.
73
+ */
74
+ _getItem(data) {
75
+ if (this._key) {
76
+ return findWhere(this._items, createPredicate(this._key, data)) || null;
77
+ }
78
+ else {
79
+ return this._items.find(item => item === data) || null;
80
+ }
81
+ }
82
+ }
@@ -0,0 +1,101 @@
1
+ /**
2
+ * This method will find a value in a JavaScript object using a string path.
3
+ * Example:
4
+ * var obj = { one: 1, two: { twoOne: 21, twoTwo: 22, twoThree: [{ threeOne: 31 }] } };
5
+ * getPropertyValue(obj, 'two.twoOne'); // 21
6
+ * getPropertyValue(obj, 'one'); // 1
7
+ * getPropertyValue(obj, 'two.twoThree[0].threeOne'); // 31
8
+ *
9
+ * Inspired by "Alnitak"'s answer on stack overflow:
10
+ * http://stackoverflow.com/questions/6491463/accessing-nested-javascript-objects-with-string-key
11
+ */
12
+ export function getPropertyValue(obj, inPath) {
13
+ let path = inPath.replace(/\[(\w+)\]/g, '.$1'); // Convert indexes to properties
14
+ path = path.replace(/^\./, ''); // Strip a leading dot
15
+ const ary = path.split('.');
16
+ // eslint-disable-next-line @typescript-eslint/prefer-for-of
17
+ for (let i = 0; i < ary.length; ++i) {
18
+ const property = ary[i];
19
+ if (obj && typeof obj === 'object' && property in obj) {
20
+ obj = obj[property];
21
+ }
22
+ else {
23
+ obj = '';
24
+ break;
25
+ }
26
+ }
27
+ return obj;
28
+ }
29
+ /**
30
+ * A wrapper around Array.prototype.find to allow for passing in a predicate.
31
+ * @param {any[]} ary The array to search.
32
+ * @param {any} predicate The predicate.
33
+ */
34
+ export function findWhere(ary, predicate) {
35
+ return ary.find(item => matchesPredicate(item, predicate));
36
+ }
37
+ /**
38
+ * A wrapper around Array.prototype.findIndex to allow for passing in a predicate.
39
+ * @param {any[]} ary The array to search.
40
+ * @param {any} predicate The predicate.
41
+ */
42
+ export function findIndexWhere(ary, predicate) {
43
+ return ary.findIndex(item => matchesPredicate(item, predicate));
44
+ }
45
+ /**
46
+ * This function will create a predicate in the form of "{ [property name]: [value] }" where the square brackets are
47
+ * replaced with the actual property name and value for the data.
48
+ */
49
+ export function createPredicate(key, data) {
50
+ if (!key || !key.length) {
51
+ throw new Error('Invalid key');
52
+ }
53
+ const predicate = {};
54
+ for (const propertyName of key) {
55
+ if (Object.prototype.hasOwnProperty.call(data, propertyName)) {
56
+ predicate[propertyName] = data[propertyName];
57
+ }
58
+ else {
59
+ throw new Error(`Invalid key. The property "${propertyName}" does not exist in the data.`);
60
+ }
61
+ }
62
+ return predicate;
63
+ }
64
+ /**
65
+ * Determines if an object matches a predicate.
66
+ */
67
+ export function matchesPredicate(obj, predicate) {
68
+ return Object.keys(predicate).every(key => obj[key] === predicate[key]);
69
+ }
70
+ /**
71
+ * Decorates an object by overriding its property descriptor to add a listener invocation in its dynamically created setter.
72
+ * Note: This does retain existing functionality, and will only work with configurable properties.
73
+ * @param context The `this` context to use for the listener.
74
+ * @param obj The object to decorate.
75
+ * @param prop The property to override.
76
+ * @param listener The listener function that will be executed when the property values changes.
77
+ * @returns A function that can be invoked to return the property to its original property descriptor.
78
+ */
79
+ export function listenOwnProperty(context, obj, prop, listener) {
80
+ let propObj = obj;
81
+ if (!obj.hasOwnProperty(prop)) {
82
+ propObj = Object.getPrototypeOf(obj);
83
+ }
84
+ const originalValueDescriptor = Object.getOwnPropertyDescriptor(propObj, prop);
85
+ if (!originalValueDescriptor) {
86
+ throw new Error(`Property ${prop} does not exist.`);
87
+ }
88
+ Object.defineProperty(obj, prop, {
89
+ configurable: true,
90
+ get() {
91
+ return originalValueDescriptor.get ? originalValueDescriptor.get.apply(this, arguments) : undefined;
92
+ },
93
+ set() {
94
+ if (originalValueDescriptor.set) {
95
+ originalValueDescriptor.set.apply(this, arguments);
96
+ }
97
+ listener.apply(context, arguments);
98
+ }
99
+ });
100
+ return () => Object.defineProperty(obj, prop, originalValueDescriptor);
101
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * @license
3
+ * Copyright Google LLC All Rights Reserved.
4
+ *
5
+ * Use of this source code is governed by an MIT-style license that can be
6
+ * found in the LICENSE file at https://angular.io/license
7
+ */
8
+ // Whether the current platform supports the V8 Break Iterator. The V8 check
9
+ // is necessary to detect all Blink based browsers.
10
+ const hasV8BreakIterator = typeof Intl !== 'undefined' && Intl.v8BreakIterator;
11
+ /**
12
+ * Class used to detect the current platform by comparing the userAgent strings and
13
+ * checking browser-specific global properties.
14
+ * @docs-private
15
+ */
16
+ export class Platform {
17
+ static get isBrowser() {
18
+ return typeof document === 'object' && !!document;
19
+ }
20
+ static get isMobile() {
21
+ return Platform.isBrowser && /Mobi/.test(navigator.userAgent);
22
+ }
23
+ /** Layout Engines */
24
+ static get EDGE() {
25
+ return Platform.isBrowser && /(edge)/i.test(navigator.userAgent);
26
+ }
27
+ static get TRIDENT() {
28
+ return Platform.isBrowser && /(msie|trident)/i.test(navigator.userAgent);
29
+ }
30
+ // EdgeHTML and Trident mock Blink specific things and need to be excluded from this check.
31
+ static get BLINK() {
32
+ return Platform.isBrowser && (!!(window.chrome || hasV8BreakIterator) && !!CSS && !Platform.EDGE && !Platform.TRIDENT);
33
+ }
34
+ // Webkit is part of the userAgent in EdgeHTML, Blink and Trident. Therefore we need to
35
+ // ensure that Webkit runs standalone and is not used as another engine's base.
36
+ static get WEBKIT() {
37
+ return Platform.isBrowser && /AppleWebKit/i.test(navigator.userAgent) && !Platform.BLINK && !Platform.EDGE && !Platform.TRIDENT;
38
+ }
39
+ /** Browsers and Platform Types */
40
+ static get IOS() {
41
+ return Platform.isBrowser && /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
42
+ }
43
+ // It's difficult to detect the plain Gecko engine, because most of the browsers identify
44
+ // them self as Gecko-like browsers and modify the userAgent's according to that.
45
+ // Since we only cover one explicit Firefox case, we can simply check for Firefox
46
+ // instead of having an unstable check for Gecko.
47
+ static get FIREFOX() {
48
+ return Platform.isBrowser && /(firefox|minefield)/i.test(navigator.userAgent);
49
+ }
50
+ // Trident on mobile adds the android platform to the userAgent to trick detections.
51
+ static get ANDROID() {
52
+ return Platform.isBrowser && /android/i.test(navigator.userAgent) && !Platform.TRIDENT;
53
+ }
54
+ // Safari browsers will include the Safari keyword in their userAgent. Some browsers may fake
55
+ // this and just place the Safari keyword in the userAgent. To be more safe about Safari every
56
+ // Safari browser should also use Webkit as its layout engine.
57
+ SAFARI() {
58
+ return Platform.isBrowser && /safari/i.test(navigator.userAgent) && Platform.WEBKIT;
59
+ }
60
+ }
@@ -0,0 +1,59 @@
1
+ import { computePosition, flip as flipMiddleware, hide as hideMiddleware, shift as shiftMiddleware, autoPlacement as autoPlacementMiddleware } from '@floating-ui/dom';
2
+ /** Adjusts the x and y axes by a specified offset amount. */
3
+ export const positionOffsetMiddleware = ({ x: offsetX, y: offsetY }) => ({
4
+ name: 'positionOffset',
5
+ fn({ x, y }) {
6
+ return {
7
+ x: x + offsetX,
8
+ y: y + offsetY
9
+ };
10
+ }
11
+ });
12
+ /**
13
+ * Calculates an elements position relative to another element.
14
+ * @param {IPositionElementConfig} config Configuration to provide when positioning the element.
15
+ * @returns {IElementPositionResult} The result of the positioning logic.
16
+ */
17
+ export async function positionElementAsync({ element, targetElement, placement = 'bottom-start', offset, strategy = 'absolute', apply = true, flip = true, flipOptions = {
18
+ fallbackPlacements: ['top-start', 'top', 'top-end', 'left-start', 'left', 'left-end', 'right-start', 'right', 'right-end'],
19
+ fallbackStrategy: 'initialPlacement'
20
+ }, auto = false, autoOptions, shift = true, shiftOptions, hide = false, hideOptions, transform = true, translateFunction = 'translate3d' }) {
21
+ var _a;
22
+ const middleware = [];
23
+ // Order of the following middleware is **important**
24
+ if (offset) {
25
+ middleware.push(positionOffsetMiddleware(offset));
26
+ }
27
+ if (shift) {
28
+ middleware.push(shiftMiddleware(shiftOptions));
29
+ }
30
+ if (flip && !auto) { // flip and auto placement middleware cannot be used together
31
+ middleware.push(flipMiddleware(flipOptions));
32
+ }
33
+ if (auto) {
34
+ middleware.push(autoPlacementMiddleware(autoOptions));
35
+ }
36
+ if (hide) {
37
+ middleware.push(hideMiddleware(hideOptions));
38
+ }
39
+ const { x, y, middlewareData } = await computePosition(targetElement, element, { strategy, placement, middleware });
40
+ const visibility = ((_a = middlewareData.hide) === null || _a === void 0 ? void 0 : _a.referenceHidden) ? 'hidden' : 'visible';
41
+ // Should we apply the position information to the element?
42
+ if (apply) {
43
+ const styles = {
44
+ left: transform ? '0' : `${x}px`,
45
+ top: transform ? '0' : `${y}px`,
46
+ visibility
47
+ };
48
+ if (transform) {
49
+ if (translateFunction === 'translate') {
50
+ styles.transform = `translate(${Math.round(x)}px, ${Math.round(y)}px)`;
51
+ }
52
+ else {
53
+ styles.transform = `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`;
54
+ }
55
+ }
56
+ Object.assign(element.style, styles);
57
+ }
58
+ return { x, y, visibility };
59
+ }
@@ -0,0 +1,12 @@
1
+ import { isDefined, isString } from './utils';
2
+ /**
3
+ * Converts a string value to dash-case.
4
+ * Ex. someTestValue => some-test-value
5
+ * @param {string} value The string to convert
6
+ */
7
+ export function dashify(value) {
8
+ if (!isDefined(value) || !isString(value)) {
9
+ return value;
10
+ }
11
+ return value.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
12
+ }
@@ -0,0 +1,261 @@
1
+ /** Generates random characters. Defaults to a length of 5. */
2
+ export function randomChars(length = 5) {
3
+ const skip = 2; // Skip the first two chars which are always "0."
4
+ return Math.random().toString(36).substring(skip, skip + length);
5
+ }
6
+ /**
7
+ * Checks if an object is undefined or null.
8
+ * @param {object} obj The object to test.
9
+ * @returns {boolean}
10
+ */
11
+ export function isDefined(obj) {
12
+ return typeof obj !== 'undefined' && obj !== null;
13
+ }
14
+ /**
15
+ * Checks if an object is a string.
16
+ * @param {object} obj The object to test.
17
+ * @returns {boolean}
18
+ */
19
+ export function isString(obj) {
20
+ return typeof obj === 'string';
21
+ }
22
+ /**
23
+ * Checks if an object is a boolean.
24
+ * @param {object} obj The object to test.
25
+ * @returns {boolean}
26
+ */
27
+ export function isBoolean(obj) {
28
+ return typeof obj === 'boolean';
29
+ }
30
+ /**
31
+ * Checks if an object is a number.
32
+ * @param {object} obj The object to test.
33
+ * @returns {boolean}
34
+ */
35
+ export function isNumber(obj) {
36
+ return typeof obj === 'number';
37
+ }
38
+ /** Determines if the provided string value can be parsed into a valid numeric value. */
39
+ export function isNumeric(str) {
40
+ if (typeof str !== 'string') {
41
+ return false;
42
+ }
43
+ return !isNaN(str) && !isNaN(parseFloat(str));
44
+ }
45
+ /**
46
+ * Checks if an object is a date.
47
+ * @param {object} obj The object to test.
48
+ * @returns {boolean}
49
+ */
50
+ export function isDate(obj) {
51
+ return obj instanceof Date;
52
+ }
53
+ /**
54
+ * Checks if an object is a date and is a valid date.
55
+ * @param {object} obj The object to test.
56
+ * @returns {boolean}
57
+ */
58
+ export function isValidDate(obj) {
59
+ if (!isDate(obj)) {
60
+ return false;
61
+ }
62
+ return !isNaN(obj.getTime());
63
+ }
64
+ /**
65
+ * Checks if an object is a function.
66
+ * @param {object} obj The object to test.
67
+ * @returns {boolean}
68
+ */
69
+ export function isFunction(obj) {
70
+ return typeof obj === 'function';
71
+ }
72
+ /**
73
+ * Checks if an object is an array.
74
+ * @param {object} obj The object to test.
75
+ * @returns {boolean}
76
+ */
77
+ export function isArray(obj) {
78
+ return obj instanceof Array;
79
+ }
80
+ /**
81
+ * Checks if an object is an object.
82
+ * @param {object} obj The object to test.
83
+ * @returns {boolean}
84
+ */
85
+ export function isObject(obj) {
86
+ return obj instanceof Object;
87
+ }
88
+ /**
89
+ * Coerces a string to a boolean.
90
+ * @param {string} value The value to convert.
91
+ * @returns {boolean}
92
+ */
93
+ export function coerceBoolean(value) {
94
+ return value != null && '' + value !== 'false';
95
+ }
96
+ /**
97
+ * Coerces a string to a number.
98
+ * @param {string} value The value to convert.
99
+ * @returns {number}
100
+ */
101
+ export function coerceNumber(value) {
102
+ return +value;
103
+ }
104
+ /** Coerces a string representation of an array of numbers, for example: `"[1,2,3]"`, to an array instance. */
105
+ export function coerceNumberArray(strOrNumOrArray) {
106
+ if (!strOrNumOrArray) {
107
+ return [];
108
+ }
109
+ if (typeof strOrNumOrArray === 'string') {
110
+ return strOrNumOrArray.replace(/ |\[|]|\"/g, '').split(',').map(n => Number(n));
111
+ }
112
+ else if (typeof strOrNumOrArray === 'number') {
113
+ return [strOrNumOrArray];
114
+ }
115
+ else {
116
+ return strOrNumOrArray.map(n => Number(n));
117
+ }
118
+ }
119
+ /**
120
+ * Compares two objects for deep equality.
121
+ * @param a
122
+ * @param b
123
+ */
124
+ export function isDeepEqual(a, b) {
125
+ return a === b || (typeof a === 'object' && typeof b === 'object' && JSON.stringify(a) === JSON.stringify(b));
126
+ }
127
+ /**
128
+ * Debounce method.
129
+ * @param {function} func The function to call.
130
+ * @param {number} wait The amount of time (milliseconds) to wait.
131
+ * @param {boolean} [immediate=false] Should the callback be executed once immeadiately.
132
+ */
133
+ export function debounce(func, wait, immediate = false) {
134
+ let context;
135
+ let args;
136
+ let result;
137
+ let timeout;
138
+ let timestamp = 0;
139
+ const later = () => {
140
+ const last = Date.now() - timestamp;
141
+ if (last < wait && last >= 0) {
142
+ timeout = setTimeout(later, wait - last);
143
+ }
144
+ else {
145
+ timeout = null;
146
+ if (!immediate) {
147
+ result = func.apply(context, args);
148
+ if (!timeout) {
149
+ context = args = null;
150
+ }
151
+ }
152
+ }
153
+ };
154
+ return function () {
155
+ context = this;
156
+ args = arguments;
157
+ timestamp = Date.now();
158
+ const callNow = immediate && !timeout;
159
+ if (!timeout) {
160
+ timeout = setTimeout(later, wait);
161
+ }
162
+ if (callNow) {
163
+ result = func.apply(context, args);
164
+ context = args = null;
165
+ }
166
+ return result;
167
+ };
168
+ }
169
+ /**
170
+ * Throttle method.
171
+ * @param {function} func The function to call.
172
+ * @param {number} wait The amount of time (milliseconds) to wait.
173
+ * @param {object=} options An options object with the following properties
174
+ * <ul>
175
+ * <li>**leading**: Should the callback be executed once immeadiately.</li>
176
+ * <li>**trailing**: Should the callback be executed once after the throttle completes.</li>
177
+ * </ul>
178
+ */
179
+ export function throttle(func, wait, options) {
180
+ let context;
181
+ let args;
182
+ let result;
183
+ let timeout;
184
+ let timestamp = 0;
185
+ options = options || {};
186
+ const later = () => {
187
+ timestamp = options.leading === false ? 0 : Date.now();
188
+ timeout = null;
189
+ result = func.apply(context, args);
190
+ if (!timeout) {
191
+ context = args = null;
192
+ }
193
+ };
194
+ return function () {
195
+ const now = Date.now();
196
+ if (!timestamp && options.leading === false) {
197
+ timestamp = now;
198
+ }
199
+ const remaining = wait - (now - timestamp);
200
+ context = this;
201
+ args = arguments;
202
+ if (remaining <= 0 || remaining > wait) {
203
+ if (timeout) {
204
+ clearTimeout(timeout);
205
+ timeout = null;
206
+ }
207
+ timestamp = now;
208
+ result = func.apply(context, args);
209
+ if (!timeout) {
210
+ context = args = null;
211
+ }
212
+ }
213
+ else if (!timeout && options.trailing !== false) {
214
+ timeout = setTimeout(later, remaining);
215
+ }
216
+ return result;
217
+ };
218
+ }
219
+ /**
220
+ * A minification-safe nameof function for retrieving the name of a property or method at runtime.
221
+ * Note: this function only works with properties/methods on an object. To get the name of a variable,
222
+ * you will need to wrap it within an object.
223
+ * @param {Function} fn A function the returns a property or method that will be stringified.
224
+ */
225
+ export function nameof(fn) {
226
+ const fnString = fn.toString();
227
+ // fnString should look something like: function () { return _this.canActivate; }
228
+ // When minified fnString will look something like: function(){return a.canActivate}
229
+ const nameofRegExp = /[^.]\.([^;}\s]+)(?:[;}\s])/; // Get everything after first dot and before the end of the statement
230
+ const match = nameofRegExp.exec(fnString);
231
+ if (!match) {
232
+ throw new Error(`Could not parse nameof string: ${fnString}`);
233
+ }
234
+ return match[1];
235
+ }
236
+ /*
237
+ * Watches for user events to detect if browser is idle.
238
+ *
239
+ * @param callback The function to call when the browser becomes idle.
240
+ * @param timespan The time to wait before the browser is considered idle.
241
+ */
242
+ export function idleWatch(callback, timespan) {
243
+ const events = [
244
+ 'mousedown',
245
+ 'mousemove',
246
+ 'touchstart',
247
+ 'touchmove',
248
+ 'keydown',
249
+ 'wheel',
250
+ 'resize'
251
+ ];
252
+ events.forEach(e => {
253
+ window.addEventListener(e, throttle((event) => {
254
+ if (timeoutId) {
255
+ window.clearTimeout(timeoutId);
256
+ }
257
+ timeoutId = window.setTimeout(callback, timespan);
258
+ }, 1000, true), true);
259
+ });
260
+ let timeoutId = window.setTimeout(callback, timespan);
261
+ }
package/package.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "@tylertech/forge-core",
3
+ "version": "2.0.0",
4
+ "description": "A library of core web utilities that support Forge Web Component libraries.",
5
+ "author": "Tyler Technologies, Inc.",
6
+ "license": "Apache-2.0",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/tyler-technologies-oss/forge-core.git"
10
+ },
11
+ "main": "esm/index.js",
12
+ "module": "esm/index.js",
13
+ "typings": "typings/index.d.ts",
14
+ "sideEffects": false,
15
+ "dependencies": {
16
+ "@floating-ui/dom": "^0.5.0",
17
+ "tslib": "^2.3.1"
18
+ }
19
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Hides an element from the user visually, while keeping it in the DOM.
3
+ * @param element The element to hide from view.
4
+ */
5
+ export declare function hideElementVisually(element: HTMLElement): void;
@@ -0,0 +1 @@
1
+ export * from './a11y';
@@ -0,0 +1,6 @@
1
+ export declare const DATE_CONSTANTS: {
2
+ days: string[];
3
+ daysLong: string[];
4
+ months: string[];
5
+ monthsLong: string[];
6
+ };
@@ -0,0 +1 @@
1
+ export * from './date-constants';